ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JavaScript Engine Part 2
    카테고리 없음 2023. 3. 6. 23:03

    Optimizing property access

    Object가 많아질 수록 property에 빠르게 접근하는 것이 중요해졌다.

    같은 형태의 Object를 연결하는 Shape과 property를 추가할 때마다 변경되는 Shape을 관리하기 위한 chain, tree 개념, 또 Shape을 사용하는 주된 이유인 Inline Caches(ICs)에 대해 알아본다.

     

     

    1. Shapes

    property에 빠르게 접근하기 위한 개념으로 객체간 동일한 key가 존재할 경우 Shape이 같다고 말한다.(V8에서는 Map이라 불린다.)

    const a = { x: 5, y: 6 };
    const b = { x: 7, y: 8 };
    // 객체 a와 b는 Shape이 같음
    
    const c = { y: 9, x: 10 };
    // 객체 c는 a, b와 Shape이 다름(key의 순서도 동일해야함)
    
    const d = { x: 11 };
    // 객체 d 역시 a, b와 다른 Shape을 갖음('y' property도 존재해야함)

    예를 들어 위와 같이 a, b라는 이름을 갖는 객체가 선언되었다고 가정했을 때 두 객체는 Shape이 같다.

    Shape이 같은 객체a, b

    property information을 객체별로 저장할 경우 메모리 사용량이 많아지기 때문에 같은 property key를 갖고 있을시 동일 Shape으로 구분하여 value를 JSObject에, 기존 property information의 [[Value]] 위치에는 property key에 대한 Offset 정보가 위치하도록 설계되었다.

     

    이로인해 여러개의 object가 있더라도 property information은 한번만 저장하면 되어 메모리 효율을 높였다.

     

     

    2. Transition chains and trees

    const o = {};
    o.x = 5;
    o.y = 6;

    Object o는 빈 객체 선언 -> 'x' property 추가 -> 'y' property 추가 순으로 객체가 변경되었을 때 Shape은 다음과 같은 구조를 갖게 된다.

    (empty) -> add 'x' property -> add 'y' property

    빈 객체 o를 선언한 후 'x', 'y' property를 차례로 생성하여 값을 넣어줬는데, 각각의 property를 생성할 때 마다 property information이 생성되고 Shape도 변하게 된다.

     

    'x'에 대한 정보는 'y'가 추가되기 전인 바로 앞의 Shape에 있기 때문에 마지막 Shape에는 저장할 필요가 없다.

    이를 가능하게 하기 위해 Shape은 이전 Shape과 연결되어있고, 이를 transition chain이라고 한다.

     

    transition chain에서 'x'를 찾을 때 JavaScript 엔진은 'x'가 포함된 Shape을 찾기 위해 transition chain을 아래에서 위로 탐색한다.

    property 탐색 시 방향

    Transition Chain외에도 tree 형태의 개념이 존재하는데, 이는 같은 Shape을 공유하다가 property가 달라져 transition chain으로 관리할 수 없을 때 사용된다.

    const a = {};
    a.x = 5;
    const b = {};
    b.y = 6;
    // a, b 두 객체 모두 빈 객체로 선언되어 초기 shape이 같지만 각자 다른 Property key를 갖으며 다른 shape을 갖게됨

    tree

    예시 코드 처럼 객체 a와 b는 빈 객체를 선언하여 초기 Shape이 같지만 각각 다른 property를 추가함으로써 Shape이 tree 형태로 나눠진다. 이러한 최적화는 transition chain을 단축하고 literal에서 object를 보다 효율적으로 생성할 수 있도록 한다.

     

     

    3. Inline Caches(ICs)

    Inline Caches(ICs)는 Shape을 사용하는 주된 이유이기도 한데, JavaScript를 빠르게 실행할 수 있도록 하는 핵심 요소다.

    JavaScript 엔진은 ICs를 사용하여 property를 찾을 수 있는 위치에 대한 정보를 기억하여 동일한 Shape의 Object에서 값을 가져올 때 드는 시간을 단축하는 역할을 한다.

    getX() 호출 -> 'x'가 포함된 Shape 검색 -> Shape의 Property Information에서 offset 검색 -> 값 가져오기
    Inline Caches(ICs)로 인해 property information에 접근할 필요가 없어짐 / Shape 비교 후 Offset 0을 찾아가면됨

    function getX() 함수는 객체를 매개변수로 받아 해당 객체의 x property를 return하는 역할을 한다.

    위는 getX() 함수의 bytecode로 Interpreter를 거쳐 생성된 명령문이다.

     

    첫번째 명령문 get_by_id는 매개변수 arg1에서 property 'x'를 로드한 결과를 loc0에 저장한다.

    'x' property가 저장된 loc0를 반환한다.

     

    get_by_id 명령문에 포함된 ICs가 이전 호출로 인해 property가 발견된 Shape과 offset을 기억한다.

    ICs는 Shape을 비교하고, 이전에 기록한 offset의 value를 가져오면 되기 때문에 Property information 정보 조회를 완전히 생략할 수 있기 때문에 처리 속도를 높인다.

     

    Storing arrays efficiently

    Array의 경우, array indices를 저장하는 것이 일반적이며 각 property의 값들은 array element라고 부른다.

    array element에 대한 property attribute들은 wirtable, enumberable, configurable하기 때문에 JavaScript 엔진이 이에 대한 정보를 저장할 필요가 없다.

    Array의 Elements 저장 방식

     


    Reference

    반응형
Designed by Tistory.