exploring js vm in js
Vyacheslav Egorov
navigate with cursor keys ←→ or space bar
jsconf.eu 2012
Vyacheslav Egorov
This talk was originally given in the special build of Chromium which allowed JavaScript to deeply inspect the state of the underlying virtual machine (V8). You are viewing "shimed" version that uses data serialized from that build.
var ics =
$Scripts()[0].inline_caches;
while (i < ics.length) {
switch (ics[i++]) {
case kIC: // ...
case kPosition: // ...
case kFunction: // ...
}
}
MaybeObject* Accessors::ScriptGetInlineCaches(Object* object, void*) {
Isolate* isolate = JSValue::cast(object)->GetIsolate();
Zone zone(isolate);
ZoneScope zone_scope(&zone, DELETE_ON_EXIT);
HandleScope handle_scope(isolate);
Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask, "ScriptGetInlineCaches");
ZoneList<Object*>* ic_data_list = NULL;
{
AssertNoAllocation no_allocation;
HeapIterator iterator(HeapIterator::kFilterUnreachable);
CodeSet set(&zone);
for (HeapObject* obj = iterator.next();
obj != NULL;
obj = iterator.next()) {
if (obj->IsJSFunction() && JSFunction::cast(obj)->shared()->script() == *script) {
JSFunction* func = JSFunction::cast(obj);
SharedFunctionInfo* shared = func->shared();
set.Add(shared->code(), shared);
set.Add(func->code(), func);
}
}
ic_data_list = set.FindICs();
}
Handle<FixedArray> ic_data = isolate->factory()->NewFixedArray(ic_data_list->length());
for (int i = 0; i < ic_data_list->length(); i++) {
ic_data->set(i, ic_data_list->at(i));
}
return *isolate->factory()->NewJSArrayWithElements(ic_data);
}
// Valid JavaScript!
var Page = struct({
next_chunk: addr,
prev_chunk: addr,
size: u32,
flags: i32,
area_start: addr,
area_end: addr
});
var HeapObject = struct({
// tagged pointer to Map
map: tptr('Map')
});
var Map = struct(HeapObject, {
instance_size: u32,
instance_type: u8
});
var Code = struct(HeapObject, {
instruction_size: i32,
reloc_info: tptr(HeapObject),
handlers: tptr(HeapObject),
deopt_data: tptr(HeapObject),
type_feedback: tptr(HeapObject),
gc_metadata: tptr(HeapObject),
ic_age: i32,
flags: i32,
kind_flags1: u32,
kind_flags2: u32
});
// raw view into V8 heap!
var page = $Heap().code_space[0];
for (var it = ObjectIterator(
page.area_start,
page.area_end);
!it.done();
it.next()) {
// raw view into an object.
var obj = it.object;
console.log(obj.Size());
}
var p = Page($Heap().code_space[0]);
var start = p.area_start & (kPageSize - 1);
var end = p.area_end & (kPageSize - 1);
var m = "\xCCHello JSConfEU";
for (var i = start; i < end; i++) {
p.memory[i] = m.charCodeAt(i % m.length);
}
Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
int index) {
// ----------- S t a t e -------------
// -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
Counters* counters = isolate()->counters();
__ IncrementCounter(counters->keyed_load_field(), 1);
// Check that the name has not changed.
__ cmp(ecx, Immediate(name));
__ j(not_equal, &miss);
GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss);
__ bind(&miss);
__ DecrementCounter(counters->keyed_load_field(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
return GetCode(FIELD, name);
}
GenerateLoadField(receiver,
holder,
edx,
ebx,
ecx,
edi,
index,
name,
&miss);
GenerateLoadField(receiver,
holder,
edx,
ebx,
ecx,
edi,
index,
name,
&miss);
GenerateLoadField(receiver,
holder,
edx,
ebx,
eax,
edi,
index,
name,
&miss);
function CompileLoadField(name, receiver_obj,
holder_obj, index) {
return specialize(function (key, receiver) {
"STUB (ecx, edx)";
counters.keyed_load_field().inc();
if (key === name) {
return LoadFieldFastPath(
receiver, index, receiver_obj, holder_obj);
}
counters.keyed_load_field().dec();
return KeyedLoad_Miss(key, receiver);
});
}