모든 시스템은 마이크로프로세서(CPU)를 포함한다.
마이크로프로세서는 전자적인 신호로 동작하는 작은 기계다. 궁극적으로는 job을 수행한다.
마이크로프로세서들에게 지시(instruction)를 준다.(지시란 마이크로프로세서가 해석(interpret)할 수 있는 언어로 되어있는 것을 의미)
다른 마이크로프로세서들은 다른 언어로 말한다. 가장 일반적인 언어로는 IA-32, x86-64, MIPS, ARM이 있다. 이러한 언어들은 직접 하드웨어와 소통한다. 그래서 거기에 쓰여진 코드는 기계어라 불린다. 우리가 컴퓨터에 쓴 코드는 변형되거나 컴파일되어 기계어가 되는 것이다.
기계어는 아래와 같이 생겼다.
위 코드는 시스템에서 낮은 레벨의 어떤 메모리 위에 올려져 동작하는 지시(instruction)가 들어있다. 프로그램을 동작시키기 위해 이러한 것들을 직접 작성해야할 필요는 없다.
높은 수준의 언어는 기계어에서 많은 추상화가 이루어져 있다. 아래 추상화의 수준에서 자바스크립트가 기계어로부터 얼마나 추상화가 되었는지 알 수 있다. C/C++는 상대적으로 하드웨어의 언어와 가깝고 다른 높은 수준의 언어들보다 훨씬 빠르다.
V8은 구글이 제공하는 강력한 오픈소스 자바스크립트 엔진이다. 자바스크립트 엔진이란 무엇일까?
자바스크립트 엔진이란 자바스크립트 코드를 마이크로프로세서가 이해할 수 있는 더 낮은 수준의 언어 혹은 기계어로 변환해주는 역할을 한다.
Rhino, JavaScriptCore, SpiderMonkey와 같은 다양한 종류의 자바스크립트 엔진이 존재한다. 이 엔진들은 ECMAScript 표준을 따른다.
ECMAScript는 스크립팅 언어를 위한 표준을 정의한다.
자바스크립트는 ECMAScript 표준을 기반으로 한다.
이러한 표준은 언어가 어떻게 동작할지, 어떤 특성을 가져야 하는지를 정의한다.
(해당 사이트에서 ECMAScript에 대해 더 배울 수 있다고 하는데 영어로 되어있다.)
크롬 V8엔진의 특성은 다음과 같다.
마지막 항목을 좀 더 깊이 이해해보자.
V8엔진은 standalone으로 동작할 수 있고, 동시에 C++로 구현된 함수를 자바스크립트의 새로운 특성으로 넣을 수 있다.
예를 들면, print('hello world')
는 Node.js에서 유효한 구문이 아니다. 컴파일하면 에러를 송출할 것이다. 하지만 우리는 깃허브에 오픈소스로 제공된 V8엔진의 멘 위에 프린트 문을 추가할 수 있다. 그래서 print함수가 native로 동작하게 만들 수 있다. 이러한 행위는 자바스크립트가 ECMAScript 표준이 정의하는 자바스크립트 동작보다 더 많은 동작을 하도록 허용해준다.
이것은 강력한 기능이다.
C++은 자바스크립트에 비교했을 때, 더 많은 특성을 갖고 있다. C++은 하드 드라이브에 있는 파일과 폴더를 다룰 때 하드웨어와 훨씬 더 가까이 있다.
C++로 된 코드를 작성하도록 허용하고 자바스크립트에서 동작 가능하게 만드는 것이 가능하다. 그렇기 때문에 자바스크립트에 더 많은 특성을 추가할 수 있다.
Node.js 자체는 V8엔진이며 C++구현이다. C++로 구현된 V8엔진은 서버사이드 프로그래밍과 네트워킹 어플리케이션을 다룰 수 있게 해준다.
엔진 내부의 오픈소스 코드를 살펴보자.
(소스코드를 보기 위해 이 페이지로 들어가자)
C++ 코드에서 print
와 Read
와 같은 함수들의 구현을 볼 수 있다. 이 함수들은 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엔진은 뒤에서 이러한 많은 양의 일을 한다.