[JS] let의 호이스팅 with byte code

bluejoy·2023년 2월 23일
0

Javascript

목록 보기
4/4

서론

다들 var,let,const의 차이에 대해 한번쯤 들어봤을 것이다.

var은 호이스팅이 되지만 나머지는 안된다.

하지만 조금 더 자세히 알아보면 호이스팅 비슷하게 되고, 해당 값을 TDZ라고 흔히 부른다.

참조: TOAST UI의 TDZ 관련 글

실제로 인터프리터가 어떻게 let 혹은 const에 대해서 호이스팅을 진행하는지 알아보려 한다(둘 다 동일).

시작 전에

  • 인터프리터는 계속 바뀌어서 바이트 코드에 대한 명세를 찾으려면 소스 코드를 봐야한다.
  • 바이트 코드로의 변환은 노드에서는 --print-bytecode 옵션을 붙여 변환 가능

호이스팅 간단히 보기

var

function test(){
    x = 1;
    var x;
}

test();

에러 없음

let

function test(){
    x = 1;
    let x;
}

test();

ReferenceError: Cannot access 'x' before initialization 에러 발생

바이트 코드로

해당 함수에 해당하는 코드만 발췌했다.

var

   21 S> 0x16e0b5891a50 @    0 : 0d 01             LdaSmi [1]
         0x16e0b5891a52 @    2 : c4                Star0 
         0x16e0b5891a53 @    3 : 0e                LdaUndefined 
   39 S> 0x16e0b5891a54 @    4 : a9                Return 

단 4줄로 간단하게 변환되었다, 밑의 2줄의 경우 리턴값이 없기에 undefined를 리턴하는 과정이다.

  1. acc 레지스터에 1을 로드한다
  2. 0 레지스터로 1을 저장한다(acc 레지스터의 값을).

두 줄이 끝이다.


  • 만약 호이스팅이 일어나지 않았다면 r0 레지스터에 undefined 값을 먼저 넣어줘야 했지만 호이스팅 덕분에 잘 해결됐다.

let

         0xfe43d7d1a68 @    0 : 10                LdaTheHole 
         0xfe43d7d1a69 @    1 : c4                Star0 
   21 S> 0xfe43d7d1a6a @    2 : 0d 01             LdaSmi [1]
         0xfe43d7d1a6c @    4 : c3                Star1 
         0xfe43d7d1a6d @    5 : 0b fa             Ldar r0
   23 E> 0xfe43d7d1a6f @    7 : aa 00             ThrowReferenceErrorIfHole [0]
         0xfe43d7d1a71 @    9 : 19 f9 fa          Mov r1, r0
   36 S> 0xfe43d7d1a74 @   12 : 0e                LdaUndefined 
         0xfe43d7d1a75 @   13 : c4                Star0 
         0xfe43d7d1a76 @   14 : 0e                LdaUndefined 
   39 S> 0xfe43d7d1a77 @   15 : a9                Return 

var보다 꽤나 복잡하게 되어있는데, 마지막 2줄은 이전과 마찬가지이다.

  1. 우선 acc 레지스터에 Hole을 로드한다.
  2. acc 레지스터의 값을 r0 레지스터로 저장한다.
  3. acc 레지스터에 1을 로드한다.
  4. acc 레지스터의 값을 r1 레지스터로 저장한다.
  5. r0 레지스터의 값을 acc 레지스터로 로드한다.
  6. r0 레지스터가 Hole 이면 에러를 Throw 한다 (0이라는 정보를 같이 던진다 아래 참조).

… 아래 생략. 왜 저렇게 바이트 코드가 생성되는지에 대해서는 잘 모르겠다. 아무래도 런타임에 타입이 바뀌는 자바스크립트의 특성 때문이라고 추정.

ThrowReferenceErrorIfHole [0]에서 [0]은?

바이트 코드 변환 결과 전체를 보면 Constant pool에 식별자 이름이 string으로 저장되어 있다. 그것을 의미.

[generated bytecode for function: test (0x35810c611031 <SharedFunctionInfo test>)]
Bytecode length: 16
Parameter count 1
Register count 2
Frame size 16
OSR urgency: 0
Bytecode age: 0
         0x35810c611a68 @    0 : 10                LdaTheHole 
         0x35810c611a69 @    1 : c4                Star0 
   26 S> 0x35810c611a6a @    2 : 0d 01             LdaSmi [1]
         0x35810c611a6c @    4 : c3                Star1 
         0x35810c611a6d @    5 : 0b fa             Ldar r0
   28 E> 0x35810c611a6f @    7 : aa 00             ThrowReferenceErrorIfHole [0]
         0x35810c611a71 @    9 : 19 f9 fa          Mov r1, r0
   41 S> 0x35810c611a74 @   12 : 0e                LdaUndefined 
         0x35810c611a75 @   13 : c4                Star0 
         0x35810c611a76 @   14 : 0e                LdaUndefined 
   44 S> 0x35810c611a77 @   15 : a9                Return 
Constant pool (size = 1)
0x35810c611a19: [FixedArray] in OldSpace
 - map: 0x23c01ce012e1 <Map>
 - length: 1
           0: 0x09b1cacda561 <String[1]: #x>
Handler Table (size = 0)
Source Position Table (size = 10)
0x35810c611a79 <ByteArray[10]>

결론

호이스팅이 잘 일어나긴 하며, Hole이라는 값으로 초기화한다.

profile
개발자 지망생입니다.

0개의 댓글