Commit a54a4ada authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Changed the global object representation.The global object is now always in...

Changed the global object representation.The global object is now always in dictionary (slow) mode with each of its properties stored in a cell object. A cell object has one field containing the actual value for the property. Inline caches for access to global properties which uses direct to the cell are now created for load, store and call to properties of the global object. When properties of the global object are deleted the cell for that property is kept with an indcation of that the property is deleted.Added counters to track the use of the global property inline caches.Added additional information on IC's in the disassembler.
Review URL: http://codereview.chromium.org/151019

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2300 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 9f252dad
...@@ -67,11 +67,15 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, ...@@ -67,11 +67,15 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
// Load the map into t0. // Load the map into t0.
__ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset)); __ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset));
// Test the has_named_interceptor bit in the map. // Test the has_named_interceptor bit in the map.
__ ldr(t0, FieldMemOperand(t1, Map::kInstanceAttributesOffset)); __ ldr(r3, FieldMemOperand(t0, Map::kInstanceAttributesOffset));
__ tst(t0, Operand(1 << (Map::kHasNamedInterceptor + (3 * 8)))); __ tst(r3, Operand(1 << (Map::kHasNamedInterceptor + (3 * 8))));
// Jump to miss if the interceptor bit is set. // Jump to miss if the interceptor bit is set.
__ b(ne, miss); __ b(ne, miss);
// Bail out if we have a JS global object.
__ ldrb(r3, FieldMemOperand(t0, Map::kInstanceTypeOffset));
__ cmp(r3, Operand(JS_GLOBAL_OBJECT_TYPE));
__ b(eq, miss);
// Check that the properties array is a dictionary. // Check that the properties array is a dictionary.
__ ldr(t0, FieldMemOperand(t1, JSObject::kPropertiesOffset)); __ ldr(t0, FieldMemOperand(t1, JSObject::kPropertiesOffset));
......
...@@ -648,6 +648,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -648,6 +648,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
// Jump to the cached code (tail call). // Jump to the cached code (tail call).
ASSERT(function->is_compiled());
Handle<Code> code(function->code()); Handle<Code> code(function->code());
ParameterCount expected(function->shared()->formal_parameter_count()); ParameterCount expected(function->shared()->formal_parameter_count());
__ InvokeCode(code, expected, arguments(), __ InvokeCode(code, expected, arguments(),
...@@ -687,6 +688,61 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, ...@@ -687,6 +688,61 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
} }
Object* CallStubCompiler::CompileCallGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
// ----------- S t a t e -------------
// -- lr: return address
// -----------------------------------
Label miss;
__ IncrementCounter(&Counters::call_global_inline, 1, r1, r3);
// Get the number of arguments.
const int argc = arguments().immediate();
// Check that the map of the global has not changed.
__ ldr(r2, MemOperand(sp, argc * kPointerSize));
__ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
__ cmp(r3, Operand(Handle<Map>(object->map())));
__ b(ne, &miss);
// Get the value from the cell.
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
__ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
// Check that the cell contains the same function.
__ cmp(r1, Operand(Handle<JSFunction>(function)));
__ b(ne, &miss);
// Patch the receiver on the stack with the global proxy if
// necessary.
__ ldr(r3, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
__ str(r3, MemOperand(sp, argc * kPointerSize));
// Setup the context (function already in r1).
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
// Jump to the cached code (tail call).
ASSERT(function->is_compiled());
Handle<Code> code(function->code());
ParameterCount expected(function->shared()->formal_parameter_count());
__ InvokeCode(code, expected, arguments(),
RelocInfo::CODE_TARGET, JUMP_FUNCTION);
// Handle call cache miss.
__ bind(&miss);
__ DecrementCounter(&Counters::call_global_inline, 1, r1, r3);
__ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
Handle<Code> ic = ComputeCallMiss(arguments().immediate());
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode(NORMAL, name);
}
Object* StoreStubCompiler::CompileStoreField(JSObject* object, Object* StoreStubCompiler::CompileStoreField(JSObject* object,
int index, int index,
Map* transition, Map* transition,
...@@ -827,6 +883,45 @@ Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, ...@@ -827,6 +883,45 @@ Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
} }
Object* StoreStubCompiler::CompileStoreGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
String* name) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
// -----------------------------------
Label miss;
__ IncrementCounter(&Counters::named_store_global_inline, 1, r1, r3);
// Check that the map of the global has not changed.
__ ldr(r1, MemOperand(sp, 0 * kPointerSize));
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
__ cmp(r3, Operand(Handle<Map>(object->map())));
__ b(ne, &miss);
// Store the value in the cell.
__ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
__ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
__ mov(r1, Operand(JSGlobalPropertyCell::kValueOffset));
__ RecordWrite(r2, r1, r3);
__ Ret();
// Handle store cache miss.
__ bind(&miss);
__ DecrementCounter(&Counters::named_store_global_inline, 1, r1, r3);
__ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r1, r3);
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode(NORMAL, name);
}
Object* LoadStubCompiler::CompileLoadField(JSObject* object, Object* LoadStubCompiler::CompileLoadField(JSObject* object,
JSObject* holder, JSObject* holder,
int index, int index,
...@@ -921,6 +1016,44 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object, ...@@ -921,6 +1016,44 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
} }
Object* LoadStubCompiler::CompileLoadGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
String* name) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
// -----------------------------------
Label miss;
__ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
// Check that the map of the global has not changed.
__ ldr(r1, MemOperand(sp, 0 * kPointerSize));
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
__ cmp(r3, Operand(Handle<Map>(object->map())));
__ b(ne, &miss);
// Get the value from the cell.
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
__ ldr(r0, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
// Check for deleted property.
__ cmp(r0, Operand(Factory::the_hole_value()));
__ b(eq, &miss);
__ Ret();
__ bind(&miss);
__ DecrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
__ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
return GetCode(NORMAL, name);
}
// TODO(1224671): IC stubs for keyed loads have not been implemented // TODO(1224671): IC stubs for keyed loads have not been implemented
// for ARM. // for ARM.
Object* KeyedLoadStubCompiler::CompileLoadField(String* name, Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
......
...@@ -580,8 +580,7 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template, ...@@ -580,8 +580,7 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
js_global_function->initial_map()->set_is_hidden_prototype(); js_global_function->initial_map()->set_is_hidden_prototype();
SetExpectedNofProperties(js_global_function, 100); SetExpectedNofProperties(js_global_function, 100);
object = Handle<JSGlobalObject>::cast( object = Factory::NewJSGlobalObject(js_global_function);
Factory::NewJSObject(js_global_function, TENURED));
} }
// Set the global context for the global object. // Set the global context for the global object.
...@@ -1445,6 +1444,9 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from, ...@@ -1445,6 +1444,9 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
// Set the property. // Set the property.
Handle<String> key = Handle<String>(String::cast(raw_key)); Handle<String> key = Handle<String>(String::cast(raw_key));
Handle<Object> value = Handle<Object>(properties->ValueAt(i)); Handle<Object> value = Handle<Object>(properties->ValueAt(i));
if (value->IsJSGlobalPropertyCell()) {
value = Handle<Object>(JSGlobalPropertyCell::cast(*value)->value());
}
PropertyDetails details = properties->DetailsAt(i); PropertyDetails details = properties->DetailsAt(i);
SetProperty(to, key, value, details.attributes()); SetProperty(to, key, value, details.attributes());
} }
......
...@@ -239,6 +239,10 @@ static int DecodeIt(FILE* f, ...@@ -239,6 +239,10 @@ static int DecodeIt(FILE* f,
InlineCacheState ic_state = code->ic_state(); InlineCacheState ic_state = code->ic_state();
out.AddFormatted(" %s, %s", Code::Kind2String(kind), out.AddFormatted(" %s, %s", Code::Kind2String(kind),
Code::ICState2String(ic_state)); Code::ICState2String(ic_state));
if (ic_state == MONOMORPHIC) {
PropertyType type = code->type();
out.AddFormatted(", %s", Code::PropertyType2String(type));
}
if (kind == Code::CALL_IC) { if (kind == Code::CALL_IC) {
out.AddFormatted(", argc = %d", code->arguments_count()); out.AddFormatted(", argc = %d", code->arguments_count());
} }
......
...@@ -619,6 +619,14 @@ Handle<JSObject> Factory::NewJSObject(Handle<JSFunction> constructor, ...@@ -619,6 +619,14 @@ Handle<JSObject> Factory::NewJSObject(Handle<JSFunction> constructor,
} }
Handle<JSGlobalObject> Factory::NewJSGlobalObject(
Handle<JSFunction> constructor) {
CALL_HEAP_FUNCTION(Heap::AllocateJSGlobalObject(*constructor),
JSGlobalObject);
}
Handle<JSObject> Factory::NewJSObjectFromMap(Handle<Map> map) { Handle<JSObject> Factory::NewJSObjectFromMap(Handle<Map> map) {
CALL_HEAP_FUNCTION(Heap::AllocateJSObjectFromMap(*map, NOT_TENURED), CALL_HEAP_FUNCTION(Heap::AllocateJSObjectFromMap(*map, NOT_TENURED),
JSObject); JSObject);
......
...@@ -183,6 +183,10 @@ class Factory : public AllStatic { ...@@ -183,6 +183,10 @@ class Factory : public AllStatic {
static Handle<JSObject> NewJSObject(Handle<JSFunction> constructor, static Handle<JSObject> NewJSObject(Handle<JSFunction> constructor,
PretenureFlag pretenure = NOT_TENURED); PretenureFlag pretenure = NOT_TENURED);
// JS global objects are pretenured.
static Handle<JSGlobalObject> NewJSGlobalObject(
Handle<JSFunction> constructor);
// JS objects are pretenured when allocated by the bootstrapper and // JS objects are pretenured when allocated by the bootstrapper and
// runtime. // runtime.
static Handle<JSObject> NewJSObjectFromMap(Handle<Map> map); static Handle<JSObject> NewJSObjectFromMap(Handle<Map> map);
......
...@@ -1070,6 +1070,11 @@ bool Heap::CreateInitialMaps() { ...@@ -1070,6 +1070,11 @@ bool Heap::CreateInitialMaps() {
if (obj->IsFailure()) return false; if (obj->IsFailure()) return false;
oddball_map_ = Map::cast(obj); oddball_map_ = Map::cast(obj);
obj = AllocatePartialMap(JS_GLOBAL_PROPERTY_CELL_TYPE,
JSGlobalPropertyCell::kSize);
if (obj->IsFailure()) return false;
global_property_cell_map_ = Map::cast(obj);
// Allocate the empty array // Allocate the empty array
obj = AllocateEmptyFixedArray(); obj = AllocateEmptyFixedArray();
if (obj->IsFailure()) return false; if (obj->IsFailure()) return false;
...@@ -1095,6 +1100,10 @@ bool Heap::CreateInitialMaps() { ...@@ -1095,6 +1100,10 @@ bool Heap::CreateInitialMaps() {
oddball_map()->set_instance_descriptors(empty_descriptor_array()); oddball_map()->set_instance_descriptors(empty_descriptor_array());
oddball_map()->set_code_cache(empty_fixed_array()); oddball_map()->set_code_cache(empty_fixed_array());
global_property_cell_map()->set_instance_descriptors(
empty_descriptor_array());
global_property_cell_map()->set_code_cache(empty_fixed_array());
// Fix prototype object for existing maps. // Fix prototype object for existing maps.
meta_map()->set_prototype(null_value()); meta_map()->set_prototype(null_value());
meta_map()->set_constructor(null_value()); meta_map()->set_constructor(null_value());
...@@ -1104,6 +1113,9 @@ bool Heap::CreateInitialMaps() { ...@@ -1104,6 +1113,9 @@ bool Heap::CreateInitialMaps() {
oddball_map()->set_prototype(null_value()); oddball_map()->set_prototype(null_value());
oddball_map()->set_constructor(null_value()); oddball_map()->set_constructor(null_value());
global_property_cell_map()->set_prototype(null_value());
global_property_cell_map()->set_constructor(null_value());
obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize); obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
if (obj->IsFailure()) return false; if (obj->IsFailure()) return false;
heap_number_map_ = Map::cast(obj); heap_number_map_ = Map::cast(obj);
...@@ -1230,6 +1242,17 @@ Object* Heap::AllocateHeapNumber(double value) { ...@@ -1230,6 +1242,17 @@ Object* Heap::AllocateHeapNumber(double value) {
} }
Object* Heap::AllocateJSGlobalPropertyCell(Object* value) {
Object* result = AllocateRaw(JSGlobalPropertyCell::kSize,
OLD_POINTER_SPACE,
OLD_POINTER_SPACE);
if (result->IsFailure()) return result;
HeapObject::cast(result)->set_map(global_property_cell_map());
JSGlobalPropertyCell::cast(result)->set_value(value);
return result;
}
Object* Heap::CreateOddball(Map* map, Object* Heap::CreateOddball(Map* map,
const char* to_string, const char* to_string,
Object* to_number) { Object* to_number) {
...@@ -2055,7 +2078,34 @@ Object* Heap::AllocateJSObject(JSFunction* constructor, ...@@ -2055,7 +2078,34 @@ Object* Heap::AllocateJSObject(JSFunction* constructor,
Map::cast(initial_map)->set_constructor(constructor); Map::cast(initial_map)->set_constructor(constructor);
} }
// Allocate the object based on the constructors initial map. // Allocate the object based on the constructors initial map.
return AllocateJSObjectFromMap(constructor->initial_map(), pretenure); Object* result =
AllocateJSObjectFromMap(constructor->initial_map(), pretenure);
// Make sure result is NOT a JS global object if valid.
ASSERT(result->IsFailure() || !result->IsJSGlobalObject());
return result;
}
Object* Heap::AllocateJSGlobalObject(JSFunction* constructor) {
ASSERT(constructor->has_initial_map());
// Make sure no field properties are described in the initial map.
// This guarantees us that normalizing the properties does not
// require us to change property values to JSGlobalPropertyCells.
ASSERT(constructor->initial_map()->NextFreePropertyIndex() == 0);
// Allocate the object based on the constructors initial map.
Object* result = AllocateJSObjectFromMap(constructor->initial_map(), TENURED);
if (result->IsFailure()) return result;
// Normalize the result.
JSObject* global = JSObject::cast(result);
result = global->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
if (result->IsFailure()) return result;
// Make sure result is a JS global object with properties in dictionary.
ASSERT(global->IsJSGlobalObject());
ASSERT(!global->HasFastProperties());
return global;
} }
......
...@@ -99,6 +99,7 @@ namespace internal { ...@@ -99,6 +99,7 @@ namespace internal {
V(Map, global_context_map) \ V(Map, global_context_map) \
V(Map, code_map) \ V(Map, code_map) \
V(Map, oddball_map) \ V(Map, oddball_map) \
V(Map, global_property_cell_map) \
V(Map, boilerplate_function_map) \ V(Map, boilerplate_function_map) \
V(Map, shared_function_info_map) \ V(Map, shared_function_info_map) \
V(Map, proxy_map) \ V(Map, proxy_map) \
...@@ -288,6 +289,12 @@ class Heap : public AllStatic { ...@@ -288,6 +289,12 @@ class Heap : public AllStatic {
static Object* AllocateJSObject(JSFunction* constructor, static Object* AllocateJSObject(JSFunction* constructor,
PretenureFlag pretenure = NOT_TENURED); PretenureFlag pretenure = NOT_TENURED);
// Allocates and initializes a new JS global object based on a constructor.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
static Object* AllocateJSGlobalObject(JSFunction* constructor);
// Returns a deep copy of the JavaScript object. // Returns a deep copy of the JavaScript object.
// Properties and elements are copied too. // Properties and elements are copied too.
// Returns failure if allocation failed. // Returns failure if allocation failed.
...@@ -408,6 +415,12 @@ class Heap : public AllStatic { ...@@ -408,6 +415,12 @@ class Heap : public AllStatic {
// Please note this does not perform a garbage collection. // Please note this does not perform a garbage collection.
static Object* AllocateByteArray(int length); static Object* AllocateByteArray(int length);
// Allocate a tenured JS global property cell.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
static Object* AllocateJSGlobalPropertyCell(Object* value);
// Allocates a fixed array initialized with undefined values // Allocates a fixed array initialized with undefined values
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed. // failed.
......
...@@ -66,9 +66,15 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label, ...@@ -66,9 +66,15 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
// Test the has_named_interceptor bit in the map. // Test the has_named_interceptor bit in the map.
__ test(FieldOperand(r0, Map::kInstanceAttributesOffset), __ test(FieldOperand(r0, Map::kInstanceAttributesOffset),
Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8)))); Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
// Jump to miss if the interceptor bit is set. // Jump to miss if the interceptor bit is set.
__ j(not_zero, miss_label, not_taken); __ j(not_zero, miss_label, not_taken);
// Bail out if we have a JS global object.
__ movzx_b(r0, FieldOperand(r0, Map::kInstanceTypeOffset));
__ cmp(r0, JS_GLOBAL_PROXY_TYPE);
__ j(equal, miss_label, not_taken);
// Check that the properties array is a dictionary. // Check that the properties array is a dictionary.
__ mov(r0, FieldOperand(r1, JSObject::kPropertiesOffset)); __ mov(r0, FieldOperand(r1, JSObject::kPropertiesOffset));
__ cmp(FieldOperand(r0, HeapObject::kMapOffset), __ cmp(FieldOperand(r0, HeapObject::kMapOffset),
......
...@@ -627,6 +627,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -627,6 +627,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
// Jump to the cached code (tail call). // Jump to the cached code (tail call).
ASSERT(function->is_compiled());
Handle<Code> code(function->code()); Handle<Code> code(function->code());
ParameterCount expected(function->shared()->formal_parameter_count()); ParameterCount expected(function->shared()->formal_parameter_count());
__ InvokeCode(code, expected, arguments(), __ InvokeCode(code, expected, arguments(),
...@@ -718,6 +719,59 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, ...@@ -718,6 +719,59 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
} }
Object* CallStubCompiler::CompileCallGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
// ----------- S t a t e -------------
// -----------------------------------
Label miss;
__ IncrementCounter(&Counters::call_global_inline, 1);
// Get the number of arguments.
const int argc = arguments().immediate();
// Check that the map of the global has not changed.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
Immediate(Handle<Map>(object->map())));
__ j(not_equal, &miss, not_taken);
// Get the value from the cell.
__ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
__ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
// Check that the cell contains the same function.
__ cmp(Operand(edi), Immediate(Handle<JSFunction>(function)));
__ j(not_equal, &miss, not_taken);
// Patch the receiver on the stack with the global proxy.
__ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
__ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
// Setup the context (function already in edi).
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
// Jump to the cached code (tail call).
ASSERT(function->is_compiled());
Handle<Code> code(function->code());
ParameterCount expected(function->shared()->formal_parameter_count());
__ InvokeCode(code, expected, arguments(),
RelocInfo::CODE_TARGET, JUMP_FUNCTION);
// Handle call cache miss.
__ bind(&miss);
__ DecrementCounter(&Counters::call_global_inline, 1);
__ IncrementCounter(&Counters::call_global_inline_miss, 1);
Handle<Code> ic = ComputeCallMiss(arguments().immediate());
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode(NORMAL, name);
}
Object* StoreStubCompiler::CompileStoreField(JSObject* object, Object* StoreStubCompiler::CompileStoreField(JSObject* object,
int index, int index,
Map* transition, Map* transition,
...@@ -861,6 +915,49 @@ Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, ...@@ -861,6 +915,49 @@ Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
} }
Object* StoreStubCompiler::CompileStoreGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
String* name) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
Label miss;
__ IncrementCounter(&Counters::named_store_global_inline, 1);
// Check that the map of the global has not changed.
__ mov(ebx, (Operand(esp, kPointerSize)));
__ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
Immediate(Handle<Map>(object->map())));
__ j(not_equal, &miss, not_taken);
// Store the value in the cell.
__ mov(ecx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
__ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax);
// RecordWrite clobbers the value register. Pass the value being stored in
// edx.
__ mov(edx, eax);
__ RecordWrite(ecx, JSGlobalPropertyCell::kValueOffset, edx, ebx);
// Return the value (register eax).
__ ret(0);
// Handle store cache miss.
__ bind(&miss);
__ DecrementCounter(&Counters::named_store_global_inline, 1);
__ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode(NORMAL, name);
}
Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
int index, int index,
Map* transition, Map* transition,
...@@ -999,6 +1096,44 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, ...@@ -999,6 +1096,44 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
} }
Object* LoadStubCompiler::CompileLoadGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
String* name) {
// ----------- S t a t e -------------
// -- ecx : name
// -- esp[0] : return address
// -- esp[4] : receiver
// -----------------------------------
Label miss;
__ IncrementCounter(&Counters::named_load_global_inline, 1);
// Check that the map of the global has not changed.
__ mov(eax, (Operand(esp, kPointerSize)));
__ cmp(FieldOperand(eax, HeapObject::kMapOffset),
Immediate(Handle<Map>(object->map())));
__ j(not_equal, &miss, not_taken);
// Get the value from the cell.
__ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
__ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
// Check for deleted property.
__ cmp(eax, Factory::the_hole_value());
__ j(equal, &miss, not_taken);
__ ret(0);
__ bind(&miss);
__ DecrementCounter(&Counters::named_load_global_inline, 1);
__ IncrementCounter(&Counters::named_load_global_inline_miss, 1);
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
return GetCode(NORMAL, name);
}
Object* KeyedLoadStubCompiler::CompileLoadField(String* name, Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
JSObject* receiver, JSObject* receiver,
JSObject* holder, JSObject* holder,
......
...@@ -423,14 +423,29 @@ void CallIC::UpdateCaches(LookupResult* lookup, ...@@ -423,14 +423,29 @@ void CallIC::UpdateCaches(LookupResult* lookup,
break; break;
} }
case NORMAL: { case NORMAL: {
// There is only one shared stub for calling normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the receiver for the stub to be
// applicable.
if (!object->IsJSObject()) return; if (!object->IsJSObject()) return;
Handle<JSObject> receiver = Handle<JSObject>::cast(object); if (object->IsJSGlobalObject()) {
if (lookup->holder() != *receiver) return; // The stub generated for the global object picks the value directly
code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver); // from the property cell. So the property must be directly on the
// global object.
Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
if (lookup->holder() != *global) return;
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
if (cell->value()->IsJSFunction()) {
JSFunction* function = JSFunction::cast(cell->value());
code = StubCache::ComputeCallGlobal(argc, in_loop, *name, *global,
cell, function);
}
} else {
// There is only one shared stub for calling normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the receiver for the stub to be
// applicable.
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
if (lookup->holder() != *receiver) return;
code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver);
}
break; break;
} }
case INTERCEPTOR: { case INTERCEPTOR: {
...@@ -614,12 +629,23 @@ void LoadIC::UpdateCaches(LookupResult* lookup, ...@@ -614,12 +629,23 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
break; break;
} }
case NORMAL: { case NORMAL: {
// There is only one shared stub for loading normalized if (object->IsJSGlobalObject()) {
// properties. It does not traverse the prototype chain, so the // The stub generated for the global object picks the value directly
// property must be found in the receiver for the stub to be // from the property cell. So the property must be directly on the
// applicable. // global object.
if (lookup->holder() != *receiver) return; Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
code = StubCache::ComputeLoadNormal(*name, *receiver); if (lookup->holder() != *global) return;
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
code = StubCache::ComputeLoadGlobal(*name, *global, cell);
} else {
// There is only one shared stub for loading normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the receiver for the stub to be
// applicable.
if (lookup->holder() != *receiver) return;
code = StubCache::ComputeLoadNormal(*name, *receiver);
}
break; break;
} }
case CALLBACKS: { case CALLBACKS: {
...@@ -953,6 +979,19 @@ void StoreIC::UpdateCaches(LookupResult* lookup, ...@@ -953,6 +979,19 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
code = StubCache::ComputeStoreField(*name, *receiver, index, *transition); code = StubCache::ComputeStoreField(*name, *receiver, index, *transition);
break; break;
} }
case NORMAL: {
if (!receiver->IsJSGlobalObject()) {
return;
}
// The stub generated for the global object picks the value directly
// from the property cell. So the property must be directly on the
// global object.
Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver);
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
code = StubCache::ComputeStoreGlobal(*name, *global, cell);
break;
}
case CALLBACKS: { case CALLBACKS: {
if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
......
...@@ -152,7 +152,9 @@ void HeapObject::HeapObjectPrint() { ...@@ -152,7 +152,9 @@ void HeapObject::HeapObjectPrint() {
case SHARED_FUNCTION_INFO_TYPE: case SHARED_FUNCTION_INFO_TYPE:
SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(); SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint();
break; break;
case JS_GLOBAL_PROPERTY_CELL_TYPE:
JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint();
break;
#define MAKE_STRUCT_CASE(NAME, Name, name) \ #define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \ case NAME##_TYPE: \
Name::cast(this)->Name##Print(); \ Name::cast(this)->Name##Print(); \
...@@ -214,6 +216,9 @@ void HeapObject::HeapObjectVerify() { ...@@ -214,6 +216,9 @@ void HeapObject::HeapObjectVerify() {
case JS_BUILTINS_OBJECT_TYPE: case JS_BUILTINS_OBJECT_TYPE:
JSBuiltinsObject::cast(this)->JSBuiltinsObjectVerify(); JSBuiltinsObject::cast(this)->JSBuiltinsObjectVerify();
break; break;
case JS_GLOBAL_PROPERTY_CELL_TYPE:
JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellVerify();
break;
case JS_ARRAY_TYPE: case JS_ARRAY_TYPE:
JSArray::cast(this)->JSArrayVerify(); JSArray::cast(this)->JSArrayVerify();
break; break;
...@@ -392,6 +397,7 @@ static const char* TypeToString(InstanceType type) { ...@@ -392,6 +397,7 @@ static const char* TypeToString(InstanceType type) {
case JS_OBJECT_TYPE: return "JS_OBJECT"; case JS_OBJECT_TYPE: return "JS_OBJECT";
case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return "JS_CONTEXT_EXTENSION_OBJECT"; case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return "JS_CONTEXT_EXTENSION_OBJECT";
case ODDBALL_TYPE: return "ODDBALL"; case ODDBALL_TYPE: return "ODDBALL";
case JS_GLOBAL_PROPERTY_CELL_TYPE: return "JS_GLOBAL_PROPERTY_CELL";
case SHARED_FUNCTION_INFO_TYPE: return "SHARED_FUNCTION_INFO"; case SHARED_FUNCTION_INFO_TYPE: return "SHARED_FUNCTION_INFO";
case JS_FUNCTION_TYPE: return "JS_FUNCTION"; case JS_FUNCTION_TYPE: return "JS_FUNCTION";
case CODE_TYPE: return "CODE"; case CODE_TYPE: return "CODE";
...@@ -428,6 +434,9 @@ void Map::MapPrint() { ...@@ -428,6 +434,9 @@ void Map::MapPrint() {
if (is_undetectable()) { if (is_undetectable()) {
PrintF(" - undetectable\n"); PrintF(" - undetectable\n");
} }
if (needs_loading()) {
PrintF(" - needs_loading\n");
}
if (has_instance_call_handler()) { if (has_instance_call_handler()) {
PrintF(" - instance_call_handler\n"); PrintF(" - instance_call_handler\n");
} }
...@@ -653,6 +662,17 @@ void Oddball::OddballVerify() { ...@@ -653,6 +662,17 @@ void Oddball::OddballVerify() {
} }
void JSGlobalPropertyCell::JSGlobalPropertyCellVerify() {
CHECK(IsJSGlobalPropertyCell());
VerifyObjectField(kValueOffset);
}
void JSGlobalPropertyCell::JSGlobalPropertyCellPrint() {
HeapObject::PrintHeader("JSGlobalPropertyCell");
}
void Code::CodePrint() { void Code::CodePrint() {
HeapObject::PrintHeader("Code"); HeapObject::PrintHeader("Code");
#ifdef ENABLE_DISASSEMBLER #ifdef ENABLE_DISASSEMBLER
......
...@@ -53,6 +53,13 @@ Smi* PropertyDetails::AsSmi() { ...@@ -53,6 +53,13 @@ Smi* PropertyDetails::AsSmi() {
} }
PropertyDetails PropertyDetails::AsDeleted() {
PropertyDetails d(DONT_ENUM, NORMAL);
Smi* smi = Smi::FromInt(AsSmi()->value() | DeletedField::encode(1));
return PropertyDetails(smi);
}
#define CAST_ACCESSOR(type) \ #define CAST_ACCESSOR(type) \
type* type::cast(Object* object) { \ type* type::cast(Object* object) { \
ASSERT(object->Is##type()); \ ASSERT(object->Is##type()); \
...@@ -409,6 +416,13 @@ bool Object::IsOddball() { ...@@ -409,6 +416,13 @@ bool Object::IsOddball() {
} }
bool Object::IsJSGlobalPropertyCell() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type()
== JS_GLOBAL_PROPERTY_CELL_TYPE;
}
bool Object::IsSharedFunctionInfo() { bool Object::IsSharedFunctionInfo() {
return Object::IsHeapObject() && return Object::IsHeapObject() &&
(HeapObject::cast(this)->map()->instance_type() == (HeapObject::cast(this)->map()->instance_type() ==
...@@ -1046,6 +1060,8 @@ ACCESSORS(Oddball, to_string, String, kToStringOffset) ...@@ -1046,6 +1060,8 @@ ACCESSORS(Oddball, to_string, String, kToStringOffset)
ACCESSORS(Oddball, to_number, Object, kToNumberOffset) ACCESSORS(Oddball, to_number, Object, kToNumberOffset)
ACCESSORS(JSGlobalPropertyCell, value, Object, kValueOffset)
int JSObject::GetHeaderSize() { int JSObject::GetHeaderSize() {
switch (map()->instance_type()) { switch (map()->instance_type()) {
case JS_GLOBAL_PROXY_TYPE: case JS_GLOBAL_PROXY_TYPE:
...@@ -1403,6 +1419,7 @@ CAST_ACCESSOR(Failure) ...@@ -1403,6 +1419,7 @@ CAST_ACCESSOR(Failure)
CAST_ACCESSOR(HeapObject) CAST_ACCESSOR(HeapObject)
CAST_ACCESSOR(HeapNumber) CAST_ACCESSOR(HeapNumber)
CAST_ACCESSOR(Oddball) CAST_ACCESSOR(Oddball)
CAST_ACCESSOR(JSGlobalPropertyCell)
CAST_ACCESSOR(SharedFunctionInfo) CAST_ACCESSOR(SharedFunctionInfo)
CAST_ACCESSOR(Map) CAST_ACCESSOR(Map)
CAST_ACCESSOR(JSFunction) CAST_ACCESSOR(JSFunction)
......
This diff is collapsed.
...@@ -153,20 +153,23 @@ class PropertyDetails BASE_EMBEDDED { ...@@ -153,20 +153,23 @@ class PropertyDetails BASE_EMBEDDED {
int index() { return IndexField::decode(value_); } int index() { return IndexField::decode(value_); }
inline PropertyDetails AsDeleted();
static bool IsValidIndex(int index) { return IndexField::is_valid(index); } static bool IsValidIndex(int index) { return IndexField::is_valid(index); }
bool IsReadOnly() { return (attributes() & READ_ONLY) != 0; } bool IsReadOnly() { return (attributes() & READ_ONLY) != 0; }
bool IsDontDelete() { return (attributes() & DONT_DELETE) != 0; } bool IsDontDelete() { return (attributes() & DONT_DELETE) != 0; }
bool IsDontEnum() { return (attributes() & DONT_ENUM) != 0; } bool IsDontEnum() { return (attributes() & DONT_ENUM) != 0; }
bool IsDeleted() { return DeletedField::decode(value_) != 0;}
// Bit fields in value_ (type, shift, size). Must be public so the // Bit fields in value_ (type, shift, size). Must be public so the
// constants can be embedded in generated code. // constants can be embedded in generated code.
class TypeField: public BitField<PropertyType, 0, 3> {}; class TypeField: public BitField<PropertyType, 0, 3> {};
class AttributesField: public BitField<PropertyAttributes, 3, 3> {}; class AttributesField: public BitField<PropertyAttributes, 3, 3> {};
class IndexField: public BitField<uint32_t, 6, 32-6> {}; class DeletedField: public BitField<uint32_t, 6, 1> {};
class IndexField: public BitField<uint32_t, 7, 31-7> {};
static const int kInitialIndex = 1; static const int kInitialIndex = 1;
private: private:
uint32_t value_; uint32_t value_;
}; };
...@@ -263,6 +266,7 @@ enum PropertyNormalizationMode { ...@@ -263,6 +266,7 @@ enum PropertyNormalizationMode {
V(HEAP_NUMBER_TYPE) \ V(HEAP_NUMBER_TYPE) \
V(FIXED_ARRAY_TYPE) \ V(FIXED_ARRAY_TYPE) \
V(CODE_TYPE) \ V(CODE_TYPE) \
V(JS_GLOBAL_PROPERTY_CELL_TYPE) \
V(ODDBALL_TYPE) \ V(ODDBALL_TYPE) \
V(PROXY_TYPE) \ V(PROXY_TYPE) \
V(BYTE_ARRAY_TYPE) \ V(BYTE_ARRAY_TYPE) \
...@@ -547,6 +551,7 @@ enum InstanceType { ...@@ -547,6 +551,7 @@ enum InstanceType {
FIXED_ARRAY_TYPE, FIXED_ARRAY_TYPE,
CODE_TYPE, CODE_TYPE,
ODDBALL_TYPE, ODDBALL_TYPE,
JS_GLOBAL_PROPERTY_CELL_TYPE,
PROXY_TYPE, PROXY_TYPE,
BYTE_ARRAY_TYPE, BYTE_ARRAY_TYPE,
FILLER_TYPE, FILLER_TYPE,
...@@ -684,6 +689,7 @@ class Object BASE_EMBEDDED { ...@@ -684,6 +689,7 @@ class Object BASE_EMBEDDED {
inline bool IsJSGlobalProxy(); inline bool IsJSGlobalProxy();
inline bool IsUndetectableObject(); inline bool IsUndetectableObject();
inline bool IsAccessCheckNeeded(); inline bool IsAccessCheckNeeded();
inline bool IsJSGlobalPropertyCell();
// Returns true if this object is an instance of the specified // Returns true if this object is an instance of the specified
// function template. // function template.
...@@ -1193,6 +1199,8 @@ class HeapNumber: public HeapObject { ...@@ -1193,6 +1199,8 @@ class HeapNumber: public HeapObject {
// caching. // caching.
class JSObject: public HeapObject { class JSObject: public HeapObject {
public: public:
enum DeleteMode { NORMAL_DELETION, FORCE_DELETION };
// [properties]: Backing storage for properties. // [properties]: Backing storage for properties.
// properties is a FixedArray in the fast case, and a Dictionary in the // properties is a FixedArray in the fast case, and a Dictionary in the
// slow case. // slow case.
...@@ -1243,6 +1251,23 @@ class JSObject: public HeapObject { ...@@ -1243,6 +1251,23 @@ class JSObject: public HeapObject {
Object* value, Object* value,
PropertyAttributes attributes); PropertyAttributes attributes);
// Retrieve a value in a normalized object given a lookup result.
// Handles the special representation of JS global objects.
Object* GetNormalizedProperty(LookupResult* result);
// Sets the property value in a normalized object given a lookup result.
// Handles the special representation of JS global objects.
Object* SetNormalizedProperty(LookupResult* result, Object* value);
// Sets the property value in a normalized object given (key, value, details).
// Handles the special representation of JS global objects.
Object* SetNormalizedProperty(String* name,
Object* value,
PropertyDetails details);
// Deletes the named property in a normalized object.
Object* DeleteNormalizedProperty(String* name, DeleteMode mode);
// Sets a property that currently has lazy loading. // Sets a property that currently has lazy loading.
Object* SetLazyProperty(LookupResult* result, Object* SetLazyProperty(LookupResult* result,
String* name, String* name,
...@@ -1293,7 +1318,6 @@ class JSObject: public HeapObject { ...@@ -1293,7 +1318,6 @@ class JSObject: public HeapObject {
return GetLocalPropertyAttribute(name) != ABSENT; return GetLocalPropertyAttribute(name) != ABSENT;
} }
enum DeleteMode { NORMAL_DELETION, FORCE_DELETION };
Object* DeleteProperty(String* name, DeleteMode mode); Object* DeleteProperty(String* name, DeleteMode mode);
Object* DeleteElement(uint32_t index, DeleteMode mode); Object* DeleteElement(uint32_t index, DeleteMode mode);
Object* DeleteLazyProperty(LookupResult* result, Object* DeleteLazyProperty(LookupResult* result,
...@@ -1930,6 +1954,9 @@ class HashTable: public FixedArray { ...@@ -1930,6 +1954,9 @@ class HashTable: public FixedArray {
static const int kElementsStartOffset = static const int kElementsStartOffset =
kHeaderSize + kElementsStartIndex * kPointerSize; kHeaderSize + kElementsStartIndex * kPointerSize;
// Constant used for denoting a absent entry.
static const int kNotFound = -1;
protected: protected:
// Find entry for key otherwise return -1. // Find entry for key otherwise return -1.
int FindEntry(HashTableKey* key); int FindEntry(HashTableKey* key);
...@@ -2027,7 +2054,9 @@ class DictionaryBase: public HashTable<2, 3> {}; ...@@ -2027,7 +2054,9 @@ class DictionaryBase: public HashTable<2, 3> {};
class Dictionary: public DictionaryBase { class Dictionary: public DictionaryBase {
public: public:
// Returns the value at entry. // Returns the value at entry.
Object* ValueAt(int entry) { return get(EntryToIndex(entry)+1); } Object* ValueAt(int entry) {
return get(EntryToIndex(entry)+1);
}
// Set the value for entry. // Set the value for entry.
void ValueAtPut(int entry, Object* value) { void ValueAtPut(int entry, Object* value) {
...@@ -2064,16 +2093,16 @@ class Dictionary: public DictionaryBase { ...@@ -2064,16 +2093,16 @@ class Dictionary: public DictionaryBase {
Object* DeleteProperty(int entry, JSObject::DeleteMode mode); Object* DeleteProperty(int entry, JSObject::DeleteMode mode);
// Type specific at put (default NONE attributes is used when adding). // Type specific at put (default NONE attributes is used when adding).
Object* AtStringPut(String* key, Object* value);
Object* AtNumberPut(uint32_t key, Object* value); Object* AtNumberPut(uint32_t key, Object* value);
Object* AddStringEntry(String* key, Object* value, PropertyDetails details); Object* AddStringEntry(String* key, Object* value, PropertyDetails details);
Object* AddNumberEntry(uint32_t key, Object* value, PropertyDetails details); Object* AddNumberEntry(uint32_t key, Object* value, PropertyDetails details);
// Set an existing entry or add a new one if needed. // Set an existing entry or add a new one if needed.
Object* SetOrAddStringEntry(String* key, Object* SetStringEntry(int entry,
Object* value, String* key,
PropertyDetails details); Object* value,
PropertyDetails details);
Object* SetOrAddNumberEntry(uint32_t key, Object* SetOrAddNumberEntry(uint32_t key,
Object* value, Object* value,
...@@ -2252,6 +2281,7 @@ class Code: public HeapObject { ...@@ -2252,6 +2281,7 @@ class Code: public HeapObject {
// Printing // Printing
static const char* Kind2String(Kind kind); static const char* Kind2String(Kind kind);
static const char* ICState2String(InlineCacheState state); static const char* ICState2String(InlineCacheState state);
static const char* PropertyType2String(PropertyType type);
void Disassemble(const char* name); void Disassemble(const char* name);
#endif // ENABLE_DISASSEMBLER #endif // ENABLE_DISASSEMBLER
...@@ -2274,7 +2304,7 @@ class Code: public HeapObject { ...@@ -2274,7 +2304,7 @@ class Code: public HeapObject {
// [flags]: Access to specific code flags. // [flags]: Access to specific code flags.
inline Kind kind(); inline Kind kind();
inline InlineCacheState ic_state(); // Only valid for IC stubs. inline InlineCacheState ic_state(); // Only valid for IC stubs.
inline InLoopFlag ic_in_loop(); // Only valid for IC stubs.. inline InLoopFlag ic_in_loop(); // Only valid for IC stubs.
inline PropertyType type(); // Only valid for monomorphic IC stubs. inline PropertyType type(); // Only valid for monomorphic IC stubs.
inline int arguments_count(); // Only valid for call IC stubs. inline int arguments_count(); // Only valid for call IC stubs.
...@@ -3048,6 +3078,10 @@ class GlobalObject: public JSObject { ...@@ -3048,6 +3078,10 @@ class GlobalObject: public JSObject {
// JavaScript global object. // JavaScript global object.
class JSGlobalObject: public GlobalObject { class JSGlobalObject: public GlobalObject {
public: public:
// Retrieve the property cell used to store a property.
Object* GetPropertyCell(LookupResult* result);
// Casting. // Casting.
static inline JSGlobalObject* cast(Object* obj); static inline JSGlobalObject* cast(Object* obj);
...@@ -3936,6 +3970,31 @@ class Oddball: public HeapObject { ...@@ -3936,6 +3970,31 @@ class Oddball: public HeapObject {
}; };
class JSGlobalPropertyCell: public HeapObject {
public:
// [value]: value of the global property.
DECL_ACCESSORS(value, Object)
// Casting.
static inline JSGlobalPropertyCell* cast(Object* obj);
// Dispatched behavior.
void JSGlobalPropertyCellIterateBody(ObjectVisitor* v);
#ifdef DEBUG
void JSGlobalPropertyCellVerify();
void JSGlobalPropertyCellPrint();
#endif
// Layout description.
static const int kValueOffset = HeapObject::kHeaderSize;
static const int kSize = kValueOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSGlobalPropertyCell);
};
// Proxy describes objects pointing from JavaScript to C structures. // Proxy describes objects pointing from JavaScript to C structures.
// Since they cannot contain references to JS HeapObjects they can be // Since they cannot contain references to JS HeapObjects they can be
// placed in old_data_space. // placed in old_data_space.
......
...@@ -230,6 +230,7 @@ class LookupResult BASE_EMBEDDED { ...@@ -230,6 +230,7 @@ class LookupResult BASE_EMBEDDED {
bool IsReadOnly() { return details_.IsReadOnly(); } bool IsReadOnly() { return details_.IsReadOnly(); }
bool IsDontDelete() { return details_.IsDontDelete(); } bool IsDontDelete() { return details_.IsDontDelete(); }
bool IsDontEnum() { return details_.IsDontEnum(); } bool IsDontEnum() { return details_.IsDontEnum(); }
bool IsDeleted() { return details_.IsDeleted(); }
bool IsValid() { return lookup_type_ != NOT_FOUND; } bool IsValid() { return lookup_type_ != NOT_FOUND; }
bool IsNotFound() { return lookup_type_ == NOT_FOUND; } bool IsNotFound() { return lookup_type_ == NOT_FOUND; }
...@@ -256,8 +257,14 @@ class LookupResult BASE_EMBEDDED { ...@@ -256,8 +257,14 @@ class LookupResult BASE_EMBEDDED {
switch (type()) { switch (type()) {
case FIELD: case FIELD:
return holder()->FastPropertyAt(GetFieldIndex()); return holder()->FastPropertyAt(GetFieldIndex());
case NORMAL: case NORMAL: {
return holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); Object* value;
value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
if (holder()->IsJSGlobalObject()) {
value = JSGlobalPropertyCell::cast(value)->value();
}
return value;
}
case CONSTANT_FUNCTION: case CONSTANT_FUNCTION:
return GetConstantFunction(); return GetConstantFunction();
default: default:
...@@ -306,7 +313,7 @@ class LookupResult BASE_EMBEDDED { ...@@ -306,7 +313,7 @@ class LookupResult BASE_EMBEDDED {
} }
// In the dictionary case, the data is held in the value field. // In the dictionary case, the data is held in the value field.
ASSERT(lookup_type_ == DICTIONARY_TYPE); ASSERT(lookup_type_ == DICTIONARY_TYPE);
return holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); return holder()->GetNormalizedProperty(this);
} }
private: private:
......
...@@ -576,9 +576,6 @@ static Object* Runtime_DeclareGlobals(Arguments args) { ...@@ -576,9 +576,6 @@ static Object* Runtime_DeclareGlobals(Arguments args) {
// property as read-only, so we don't either. // property as read-only, so we don't either.
PropertyAttributes base = is_eval ? NONE : DONT_DELETE; PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
// Only optimize the object if we intend to add more than 5 properties.
OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5);
// Traverse the name/value pairs and set the properties. // Traverse the name/value pairs and set the properties.
int length = pairs->length(); int length = pairs->length();
for (int i = 0; i < length; i += 2) { for (int i = 0; i < length; i += 2) {
...@@ -890,10 +887,8 @@ static Object* Runtime_InitializeConstGlobal(Arguments args) { ...@@ -890,10 +887,8 @@ static Object* Runtime_InitializeConstGlobal(Arguments args) {
properties->set(index, *value); properties->set(index, *value);
} }
} else if (type == NORMAL) { } else if (type == NORMAL) {
Dictionary* dictionary = global->property_dictionary(); if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
int entry = lookup.GetDictionaryEntry(); global->SetNormalizedProperty(&lookup, *value);
if (dictionary->ValueAt(entry)->IsTheHole()) {
dictionary->ValueAtPut(entry, *value);
} }
} else { } else {
// Ignore re-initialization of constants that have already been // Ignore re-initialization of constants that have already been
...@@ -983,10 +978,8 @@ static Object* Runtime_InitializeConstContextSlot(Arguments args) { ...@@ -983,10 +978,8 @@ static Object* Runtime_InitializeConstContextSlot(Arguments args) {
properties->set(index, *value); properties->set(index, *value);
} }
} else if (type == NORMAL) { } else if (type == NORMAL) {
Dictionary* dictionary = context_ext->property_dictionary(); if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
int entry = lookup.GetDictionaryEntry(); context_ext->SetNormalizedProperty(&lookup, *value);
if (dictionary->ValueAt(entry)->IsTheHole()) {
dictionary->ValueAtPut(entry, *value);
} }
} else { } else {
// We should not reach here. Any real, named property should be // We should not reach here. Any real, named property should be
...@@ -2598,9 +2591,13 @@ static Object* Runtime_KeyedGetProperty(Arguments args) { ...@@ -2598,9 +2591,13 @@ static Object* Runtime_KeyedGetProperty(Arguments args) {
// Attempt dictionary lookup. // Attempt dictionary lookup.
Dictionary* dictionary = receiver->property_dictionary(); Dictionary* dictionary = receiver->property_dictionary();
int entry = dictionary->FindStringEntry(key); int entry = dictionary->FindStringEntry(key);
if ((entry != DescriptorArray::kNotFound) && if ((entry != Dictionary::kNotFound) &&
(dictionary->DetailsAt(entry).type() == NORMAL)) { (dictionary->DetailsAt(entry).type() == NORMAL)) {
return dictionary->ValueAt(entry); Object* value = dictionary->ValueAt(entry);
if (receiver->IsJSGlobalObject()) {
value = JSGlobalPropertyCell::cast(value)->value();
}
return value;
} }
} }
} }
...@@ -5518,15 +5515,12 @@ static Object* DebugLookupResultValue(Object* receiver, String* name, ...@@ -5518,15 +5515,12 @@ static Object* DebugLookupResultValue(Object* receiver, String* name,
bool* caught_exception) { bool* caught_exception) {
Object* value; Object* value;
switch (result->type()) { switch (result->type()) {
case NORMAL: { case NORMAL:
Dictionary* dict = value = result->holder()->GetNormalizedProperty(result);
JSObject::cast(result->holder())->property_dictionary();
value = dict->ValueAt(result->GetDictionaryEntry());
if (value->IsTheHole()) { if (value->IsTheHole()) {
return Heap::undefined_value(); return Heap::undefined_value();
} }
return value; return value;
}
case FIELD: case FIELD:
value = value =
JSObject::cast( JSObject::cast(
......
...@@ -172,6 +172,23 @@ Object* StubCache::ComputeLoadNormal(String* name, JSObject* receiver) { ...@@ -172,6 +172,23 @@ Object* StubCache::ComputeLoadNormal(String* name, JSObject* receiver) {
} }
Object* StubCache::ComputeLoadGlobal(String* name,
JSGlobalObject* receiver,
JSGlobalPropertyCell* cell) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
LoadStubCompiler compiler;
code = compiler.CompileLoadGlobal(receiver, cell, name);
if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code;
}
return Set(name, receiver->map(), Code::cast(code));
}
Object* StubCache::ComputeKeyedLoadField(String* name, Object* StubCache::ComputeKeyedLoadField(String* name,
JSObject* receiver, JSObject* receiver,
JSObject* holder, JSObject* holder,
...@@ -317,6 +334,23 @@ Object* StubCache::ComputeStoreField(String* name, ...@@ -317,6 +334,23 @@ Object* StubCache::ComputeStoreField(String* name,
} }
Object* StubCache::ComputeStoreGlobal(String* name,
JSGlobalObject* receiver,
JSGlobalPropertyCell* cell) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
StoreStubCompiler compiler;
code = compiler.CompileStoreGlobal(receiver, cell, name);
if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code;
}
return Set(name, receiver->map(), Code::cast(code));
}
Object* StubCache::ComputeStoreCallback(String* name, Object* StubCache::ComputeStoreCallback(String* name,
JSObject* receiver, JSObject* receiver,
AccessorInfo* callback) { AccessorInfo* callback) {
...@@ -496,6 +530,31 @@ Object* StubCache::ComputeCallNormal(int argc, ...@@ -496,6 +530,31 @@ Object* StubCache::ComputeCallNormal(int argc,
} }
Object* StubCache::ComputeCallGlobal(int argc,
InLoopFlag in_loop,
String* name,
JSGlobalObject* receiver,
JSGlobalPropertyCell* cell,
JSFunction* function) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, NORMAL);
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
// If the function hasn't been compiled yet, we cannot do it now
// because it may cause GC. To avoid this issue, we return an
// internal error which will make sure we do not update any
// caches.
if (!function->is_compiled()) return Failure::InternalError();
CallStubCompiler compiler(argc);
code = compiler.CompileCallGlobal(receiver, cell, function, name);
if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code;
}
return Set(name, receiver->map(), Code::cast(code));
}
static Object* GetProbeValue(Code::Flags flags) { static Object* GetProbeValue(Code::Flags flags) {
Dictionary* dictionary = Heap::non_monomorphic_cache(); Dictionary* dictionary = Heap::non_monomorphic_cache();
int entry = dictionary->FindNumberEntry(flags); int entry = dictionary->FindNumberEntry(flags);
......
...@@ -78,6 +78,11 @@ class StubCache : public AllStatic { ...@@ -78,6 +78,11 @@ class StubCache : public AllStatic {
static Object* ComputeLoadNormal(String* name, JSObject* receiver); static Object* ComputeLoadNormal(String* name, JSObject* receiver);
static Object* ComputeLoadGlobal(String* name,
JSGlobalObject* receiver,
JSGlobalPropertyCell* cell);
// --- // ---
static Object* ComputeKeyedLoadField(String* name, static Object* ComputeKeyedLoadField(String* name,
...@@ -112,6 +117,10 @@ class StubCache : public AllStatic { ...@@ -112,6 +117,10 @@ class StubCache : public AllStatic {
int field_index, int field_index,
Map* transition = NULL); Map* transition = NULL);
static Object* ComputeStoreGlobal(String* name,
JSGlobalObject* receiver,
JSGlobalPropertyCell* cell);
static Object* ComputeStoreCallback(String* name, static Object* ComputeStoreCallback(String* name,
JSObject* receiver, JSObject* receiver,
AccessorInfo* callback); AccessorInfo* callback);
...@@ -151,6 +160,13 @@ class StubCache : public AllStatic { ...@@ -151,6 +160,13 @@ class StubCache : public AllStatic {
Object* object, Object* object,
JSObject* holder); JSObject* holder);
static Object* ComputeCallGlobal(int argc,
InLoopFlag in_loop,
String* name,
JSGlobalObject* receiver,
JSGlobalPropertyCell* cell,
JSFunction* function);
// --- // ---
static Object* ComputeCallInitialize(int argc, InLoopFlag in_loop); static Object* ComputeCallInitialize(int argc, InLoopFlag in_loop);
...@@ -416,6 +432,10 @@ class LoadStubCompiler: public StubCompiler { ...@@ -416,6 +432,10 @@ class LoadStubCompiler: public StubCompiler {
JSObject* holder, JSObject* holder,
String* name); String* name);
Object* CompileLoadGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* holder,
String* name);
private: private:
Object* GetCode(PropertyType type, String* name); Object* GetCode(PropertyType type, String* name);
}; };
...@@ -457,6 +477,10 @@ class StoreStubCompiler: public StubCompiler { ...@@ -457,6 +477,10 @@ class StoreStubCompiler: public StubCompiler {
AccessorInfo* callbacks, AccessorInfo* callbacks,
String* name); String* name);
Object* CompileStoreInterceptor(JSObject* object, String* name); Object* CompileStoreInterceptor(JSObject* object, String* name);
Object* CompileStoreGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* holder,
String* name);
private: private:
Object* GetCode(PropertyType type, String* name); Object* GetCode(PropertyType type, String* name);
...@@ -492,6 +516,10 @@ class CallStubCompiler: public StubCompiler { ...@@ -492,6 +516,10 @@ class CallStubCompiler: public StubCompiler {
Object* CompileCallInterceptor(Object* object, Object* CompileCallInterceptor(Object* object,
JSObject* holder, JSObject* holder,
String* name); String* name);
Object* CompileCallGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name);
private: private:
const ParameterCount arguments_; const ParameterCount arguments_;
......
...@@ -130,9 +130,15 @@ namespace internal { ...@@ -130,9 +130,15 @@ namespace internal {
SC(keyed_load_inline_miss, V8.KeyedLoadInlineMiss) \ SC(keyed_load_inline_miss, V8.KeyedLoadInlineMiss) \
SC(named_load_inline, V8.NamedLoadInline) \ SC(named_load_inline, V8.NamedLoadInline) \
SC(named_load_inline_miss, V8.NamedLoadInlineMiss) \ SC(named_load_inline_miss, V8.NamedLoadInlineMiss) \
SC(named_load_global_inline, V8.NamedLoadGlobalInline) \
SC(named_load_global_inline_miss, V8.NamedLoadGlobalInlineMiss) \
SC(keyed_store_field, V8.KeyedStoreField) \ SC(keyed_store_field, V8.KeyedStoreField) \
SC(keyed_store_inline, V8.KeyedStoreInline) \ SC(keyed_store_inline, V8.KeyedStoreInline) \
SC(keyed_store_inline_miss, V8.KeyedStoreInlineMiss) \ SC(keyed_store_inline_miss, V8.KeyedStoreInlineMiss) \
SC(named_store_global_inline, V8.NamedStoreGlobalInline) \
SC(named_store_global_inline_miss, V8.NamedStoreGlobalInlineMiss) \
SC(call_global_inline, V8.CallGlobalInline) \
SC(call_global_inline_miss, V8.CallGlobalInlineMiss) \
SC(for_in, V8.ForIn) \ SC(for_in, V8.ForIn) \
SC(enum_cache_hits, V8.EnumCacheHits) \ SC(enum_cache_hits, V8.EnumCacheHits) \
SC(enum_cache_misses, V8.EnumCacheMisses) \ SC(enum_cache_misses, V8.EnumCacheMisses) \
......
...@@ -67,6 +67,15 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* a, ...@@ -67,6 +67,15 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* a,
Object* CallStubCompiler::CompileCallGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
UNIMPLEMENTED();
return NULL;
}
Object* LoadStubCompiler::CompileLoadCallback(JSObject* a, Object* LoadStubCompiler::CompileLoadCallback(JSObject* a,
JSObject* b, JSObject* b,
AccessorInfo* c, AccessorInfo* c,
...@@ -102,6 +111,14 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* a, ...@@ -102,6 +111,14 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* a,
} }
Object* LoadStubCompiler::CompileLoadGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
String* name) {
UNIMPLEMENTED();
return NULL;
}
Object* StoreStubCompiler::CompileStoreCallback(JSObject* a, Object* StoreStubCompiler::CompileStoreCallback(JSObject* a,
AccessorInfo* b, AccessorInfo* b,
String* c) { String* c) {
...@@ -125,6 +142,14 @@ Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* a, String* b) { ...@@ -125,6 +142,14 @@ Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* a, String* b) {
} }
Object* StoreStubCompiler::CompileStoreGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
String* name) {
UNIMPLEMENTED();
return NULL;
}
// TODO(1241006): Avoid having lazy compile stubs specialized by the // TODO(1241006): Avoid having lazy compile stubs specialized by the
// number of arguments. It is not needed anymore. // number of arguments. It is not needed anymore.
Object* StubCompiler::CompileLazyCompile(Code::Flags flags) { Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
......
...@@ -6040,6 +6040,7 @@ THREADED_TEST(DisableAccessChecksWhileConfiguring) { ...@@ -6040,6 +6040,7 @@ THREADED_TEST(DisableAccessChecksWhileConfiguring) {
CHECK(value->BooleanValue()); CHECK(value->BooleanValue());
} }
static bool NamedGetAccessBlocker(Local<v8::Object> obj, static bool NamedGetAccessBlocker(Local<v8::Object> obj,
Local<Value> name, Local<Value> name,
v8::AccessType type, v8::AccessType type,
...@@ -6093,6 +6094,7 @@ THREADED_TEST(AccessChecksReenabledCorrectly) { ...@@ -6093,6 +6094,7 @@ THREADED_TEST(AccessChecksReenabledCorrectly) {
CHECK(value_2->IsUndefined()); CHECK(value_2->IsUndefined());
} }
// This tests that access check information remains on the global // This tests that access check information remains on the global
// object template when creating contexts. // object template when creating contexts.
THREADED_TEST(AccessControlRepeatedContextCreation) { THREADED_TEST(AccessControlRepeatedContextCreation) {
...@@ -6111,6 +6113,71 @@ THREADED_TEST(AccessControlRepeatedContextCreation) { ...@@ -6111,6 +6113,71 @@ THREADED_TEST(AccessControlRepeatedContextCreation) {
} }
THREADED_TEST(TurnOnAccessCheck) {
v8::HandleScope handle_scope;
// Create an environment with access check to the global object disabled by
// default.
v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
IndexedGetAccessBlocker,
v8::Handle<v8::Value>(),
false);
v8::Persistent<Context> context = Context::New(NULL, global_template);
Context::Scope context_scope(context);
// Set up a property and a number of functions.
context->Global()->Set(v8_str("a"), v8_num(1));
CompileRun("function f1() {return a;}"
"function f2() {return a;}"
"function g1() {return h();}"
"function g2() {return h();}"
"function h() {return 1;}");
Local<Function> f1 =
Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
Local<Function> f2 =
Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
Local<Function> g1 =
Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
Local<Function> g2 =
Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
Local<Function> h =
Local<Function>::Cast(context->Global()->Get(v8_str("h")));
// Get the global object.
v8::Handle<v8::Object> global = context->Global();
// Call f1 one time and f2 a number of times. This will ensure that f1 still
// uses the runtime system to retreive property a whereas f2 uses global load
// inline cache is used.
CHECK(!f1->Call(global, 0, NULL)->IsUndefined());
for (int i = 0; i < 4; i++) {
CHECK(!f2->Call(global, 0, NULL)->IsUndefined());
}
// Same for g1 and g2.
CHECK(!g1->Call(global, 0, NULL)->IsUndefined());
for (int i = 0; i < 4; i++) {
CHECK(!g2->Call(global, 0, NULL)->IsUndefined());
}
// Detach the global and turn on access check.
context->DetachGlobal();
context->Global()->TurnOnAccessCheck();
// Failing access check to property get results in undefined.
CHECK(f1->Call(global, 0, NULL)->IsUndefined());
CHECK(f2->Call(global, 0, NULL)->IsUndefined());
// Failing access check to function call results in exception.
CHECK(g1->Call(global, 0, NULL).IsEmpty());
CHECK(g2->Call(global, 0, NULL).IsEmpty());
// No failing access check when just returning a constant.
CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
}
// This test verifies that pre-compilation (aka preparsing) can be called // This test verifies that pre-compilation (aka preparsing) can be called
// without initializing the whole VM. Thus we cannot run this test in a // without initializing the whole VM. Thus we cannot run this test in a
// multi-threaded setup. // multi-threaded setup.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment