V8 엔진이 JS를 기계 코드로 바꾸는 방법

fromzoo·2020년 12월 15일
0

크롬 V8엔진 배우기 전 기초잡기

우리의 모든 시스템은 마이크로프로세서(CPU)를 포함한다. 지금 컴퓨터 안에 들어있는게 그것이다. 우리가 이 글을 읽는 것도 그 덕분이다.

마이크로프로세서는 전자적인 신호로 동작하는 작은 기계다. 그리고 궁극적으로는 job을 수행한다. 우리는 마이크로프로세서들에게 지시(instruction)을 준다. 여기서 지시란 것은 마이크로프로세서가 해석할 수 있는 언어로 되어 있는 것. 다른 마이크로프로세서들은 다른 언어로 말한다. 가장 일반적인 언어로는 IA-32, x86-64, MIPS 그리고 ARM이 있다. 이러한 언어들은 직접 하드웨어와 소통한다. 그래서 거기에 쓰여진 코드는 기계어라고 불린다. 우리가 컴퓨터에 쓴 코드는 변형되거나 컴파일되어 기계어가 된다.

기계어는 다음과 같이 생겼다

위 코드는 우리 시스템에서 낮은 레벨의 어떤 메모리 위에 올려져 동작하는 지시가 들어있다. 프로그램을 동작시키기 위해 이러한 것들을 작성해야할 필요가 없다는 것은 행운이다.

고수준의 언어는 기계어에서 많은 추상화가 이루어져있다. 아래 추상화의 수준에서, 자바스크립트가 기계어로부터 얼마나 추상화가 됐는지 알 수 있다. C/C++는 상대적으로 하드웨어 언어와 가깝고 다른 고수준 언어들보다 훨씬 빠르다.

이제 자바스크립트 V8엔진으로 다시 돌아가보자. V8은 구글이 제공하는 강력한 오픈소스 자바스크립트 엔진이다.

자바스크립트엔진이란 무엇일까?
자바스크립트 엔진이란 자바스크립트 코드를 마이크로프로세서가 이해할 수 있는 더 낮은 수준의 언어 혹은 기계어로 변환해주는 역할을 한다.

Rhino, JavaScriptCore, SpiderMonkey와 같은 다양한 종류의 자바스크립트 엔진이 존재한다. 이 엔진들은 ECMAScript 표준을 따른다. ECMAScript는 스크립팅 언어를 위한 표준을 정의한다. 자바스크립트는 ECMAScript 표준을 기반으로 한다. 이러한 표준은 언어가 어떻게 동작할지 그리고 어떤 특성을 가져야 하는지를 정의한다.

크롬 V8엔진의 특성은 다음과 같다.

  • V8엔진은 C++로 작성됐고 Chrome과 Node.js에서 사용된다.
  • V8엔진은 ECMA-262에 기재된 ECMAScript를 구현했다.
  • V8엔진은 standalone으로 동작할 수 있어서 우리는 자바스크립트 엔진을 C++프로그램에 내장시킬 수 있다.

마지막 항목을 좀 더 깊이 이해해보자.
V8엔진은 standalone으로 동작할 수 이고 동시에 우리는 C++로 구현된 함수를 자바스크립트의 새로운 특성으로 넣을 수 있다.

그래서예를 드면, print('hello world')는 Node.js에서 유효한 구문이 아니다. 컴파일하면 에러를 송출할 것이다. 하지만 우리는 깃허브 오픈소스로 제공된 V8엔진의 맨위에 프린트물을 추가할 수 있다. 그래서 print함수가 native로 동작하게 만들 수 있다. 이러한 행위는 자바스크립트가 ECMAScript 표준이 정의하는 자바스크립트 동작보다 더 많은 동작을 하도록 허용한다.

이것은 강력한 기능이다. C++은 자바스크립트에 비교했을때, 더 많은 특성을 갖고있기 때문이다. C++은 하드 드라이브에 있는 파일과 폴더를 다룰때 하드웨어와 훨씬 더 가까이 있다.

우리가 C++로 된 코드를 작성하도록 허용하고 자바스크립트에서 동작 가능하게 만드는 것이 가능하고 그래서 우리는 자바스크립트에 더 많은 특성을 추가할 수 있다.

Node.js자체는 V8엔진, C++ 구현이다. C++로 구현된 V8엔진은 서버사이드 프로그래밍과 네트워킹 어플리케이션을 다룰 수 있게 해준다.

엔진 내부의 오픈소스 코드를 보자. 소스코드를 보기 위해서 v8/samples/shell.cc 링크에서 확인하면 된다.

C++코드에서 printRead와 같은 함수들의 구현을 볼 수 있다. 이 함수들은 Node.js에서 네이티브로는 불가능하다.

아래에서, Print 함수의 구현을 볼 수 있다. Print()가 Node.js에서 호출될 때마다, 이 함수는 콜백을 만들고 그 함수가 실행된다.

// 자바스크립트에서 'print' 함수가 호출될 때마다, v8엔진에 의해 콜백이 호출된다.


// 스페이스와 새로운 라인을 기준으로 분리된 stdout에 있는 인자들을 프린트한다.
void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
  bool first = true;
  for (int i=0; i<args.length(); i++) {
    v8::HandleScope handle_scope(args.GetIsolate());
    if (first) {
      first = false;
    } else {
      print(" ");
    }
    v8::String::Utf8Value str(args.GetIsolate(), args[i]);
    const char* cstr = ToCString(str);
    printf("%s", cstr);
  }
  printf("\n");
  fflush(stdout);
}

비슷하게, 우리도 C++내부에 다른 함수를 추가적으로 구현하여 Node.js에서 인식되도록 할 수 있다.

이건 확실히 간단한 서술로 끝내기에는 많은 양이다. V8엔진은 뒤에서 이러한 많은 양의 일을 한다.

🔍 출처 블로그
자바스크립트 개발자라면 알아야 할 33가지 개념 #11 V8 엔진이 JS를 기계 코드로 바꾸는 방법

profile
프론트엔드 주니어 개발자 🚀

0개의 댓글