Type in Chakra
Javascript是一個無型別的語言。
我們要討論的型別是指Chakra內建的一些資料結構,這些結構維護了Object的資訊。
Type在一類Object中共享資料,使用執行時型別的目的就是為了效率。
Chakra具有兩類型別,static和dynamic。
static型別是提供給簡單object的,這些object不會在裡面儲存屬性。static型別有string("HELLO")、boolean(true\false)、number。
而Dynamic Object是動態型別的,它們會儲存屬性,比如{}。
每個RecyclableObject都維持著一個指向type的指標。Chakra中每個物件的Class都繼承自RecyclableObject除了tagged float。
var greeting = "hello";
var message = "open source";
這兩個字串中chakra中定義為JavascriptString類,這個類繼承自JavascriptString。greeting和message指向一個共享的type。
這兩個JavascriptString都設定為TypeIds_String,並且這個Type是被兩個字串共享的(type指標指向同一個)。
事實上type物件中含有大量的值域,typeld只是其中一個。
type Js::Type
{
typeId Js::TypeId
flags TypeFlagMask
javascriptLibrary Js::JavascriptLibrary *
prototype Js::RecyclableObject * {Js::DynamicObject}
entryPoint void *(*)(Js::RecyclableObject *, Js::CallInfo)
propertyCache Js::TypePropertyCache *
}
JavascriptString是一個靜態的型別,但是相比之下Dynamic型別的Dynamic object提供了許多可以共享資訊的機會。(DynamicObject和StaticOject都是繼承自RecyclableObject的)
以下程式碼建立的是Dynamic Object
function Point(x, y)
{
this.x = x;
this.y = y;
}
var one = new Point(10,20);
var two = new Point(40,50);
print(one.x);
print(two.x);
建立了2個Point Object,有x、y兩個屬性,Chakra需要在runtime中儲存以下這些資訊。
1.1、2號物件有x、y兩個屬性
2.1號物件的x屬性為10,y屬性為20
3.2號物件的x屬性為40,y屬性為50
當指令碼要get和set屬性值的時候,上述的資訊就需要獲取了。
(1)是可以在多個物件之間共享的
(2、3)是每個Dynamic Object特有的,彼此不同
解決方法是建立property map和slot array。
Property map, maps between a property and a slot number. Example:
Property x is present at slot 0.
Slot array stores the values. Example slots[0] contains the value of
property x.
就是說Property map表示一個屬性對應於一個slot,而slot實際儲存資料值。
Property map是儲存在dynamic type物件中的。當訪問1.x的時候,chakra在1->type取出property map找到相應的slot number,圖中是0。然後透過1->slots[0]取出實際的值10。
(就是說property map是Type Object中共享的,儲存下標。slot array是每個物件自己的,儲存實際值)
所有從建構函式Point建立的物件都可以共享一個型別。
即使你創造了一百萬個,你也只需要一個型別代表它們。
透過型別的概念可以實現大量的最佳化,比如
Inline Cache
Object type specialization in JIT
Function specialization
想要更深入地進行最佳化需要一個單獨的結構。 Typehanlder是Dynamic type的一部分,負責處理property map儲存和一個Dynamic Object獲取它的型別的方式。
Typehandler
Typehandler是一個Dynamic type負責兩個目標。
1.負責維護一個property map
2.維護successor type
var one = {};
var two = {};
//Objects one and two points to Type1
one.x = 10;
//Object one points to Type2 and object two points to Type1
starwars1(one, two);
one.y = 20;
//Object one points to Type3 and object two points to Type1
starwars2(one, two);
two.x = 40;
//Object one points to Type3 and object two points to Type2
starwars3(one, two);
two.y = 50;
//Object one and two points to Type3
starwars4(one, two);
starwars可以為one和two在建立的時候共享相同的屬性。
one和two這兩個物件最後都具有了x和y兩個屬性。
所以在starwars4執行之後,他們可以共享同一個type object。
如果在不同的時間點建立了相同屬性的物件,如何確定所有具有相同屬性的物件呢?
typehanlder中的successor type解決了這個問題。每個typehandler都儲存有一個successor type,如果一個物件獲得了一個新屬性那麼就由它來指派一個新的type物件。這個過程通常叫做型別提升或是型別轉變。
因為typehandler儲存有指向後繼型別的指標,因此型別轉換會很快的發生。
https://github.com/Microsoft/ChakraCore/blob/master/lib/Runtime/Types/PathTypeHandler.h#L207
SimpleTypeHanlder擁有一個叫做typePath的property map,它擁有一個[tiny dictionary]去對映property Id 到slot number。同樣存在維護著下一個型別指標的successorTypeWeakRef。SimpleTypeHandler的一個比較有名的變種是 [PathTypeHandler]維持著 PropertySuccessorsMap 到多個successors。
這篇文章討論瞭如下幾個問題
1.為啥所有物件都要存在type物件
2.type物件是怎麼實現多物件共享的
3.為啥typehandler會指向successor type,注意還存在有許多不同的typehandlers 在共享不同的資料。
http://abchatra.github.io/Type/