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,
// Load the map into t0.
__ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset));
// Test the has_named_interceptor bit in the map.
__ ldr(t0, FieldMemOperand(t1, Map::kInstanceAttributesOffset));
__ tst(t0, Operand(1 << (Map::kHasNamedInterceptor + (3 * 8))));
__ ldr(r3, FieldMemOperand(t0, Map::kInstanceAttributesOffset));
__ tst(r3, Operand(1 << (Map::kHasNamedInterceptor + (3 * 8))));
// Jump to miss if the interceptor bit is set.
__ 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.
__ ldr(t0, FieldMemOperand(t1, JSObject::kPropertiesOffset));
......
......@@ -648,6 +648,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ 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(),
......@@ -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,
int index,
Map* transition,
......@@ -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,
JSObject* holder,
int index,
......@@ -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
// for ARM.
Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
......
......@@ -580,8 +580,7 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
js_global_function->initial_map()->set_is_hidden_prototype();
SetExpectedNofProperties(js_global_function, 100);
object = Handle<JSGlobalObject>::cast(
Factory::NewJSObject(js_global_function, TENURED));
object = Factory::NewJSGlobalObject(js_global_function);
}
// Set the global context for the global object.
......@@ -1445,6 +1444,9 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
// Set the property.
Handle<String> key = Handle<String>(String::cast(raw_key));
Handle<Object> value = Handle<Object>(properties->ValueAt(i));
if (value->IsJSGlobalPropertyCell()) {
value = Handle<Object>(JSGlobalPropertyCell::cast(*value)->value());
}
PropertyDetails details = properties->DetailsAt(i);
SetProperty(to, key, value, details.attributes());
}
......
......@@ -239,6 +239,10 @@ static int DecodeIt(FILE* f,
InlineCacheState ic_state = code->ic_state();
out.AddFormatted(" %s, %s", Code::Kind2String(kind),
Code::ICState2String(ic_state));
if (ic_state == MONOMORPHIC) {
PropertyType type = code->type();
out.AddFormatted(", %s", Code::PropertyType2String(type));
}
if (kind == Code::CALL_IC) {
out.AddFormatted(", argc = %d", code->arguments_count());
}
......
......@@ -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) {
CALL_HEAP_FUNCTION(Heap::AllocateJSObjectFromMap(*map, NOT_TENURED),
JSObject);
......
......@@ -183,6 +183,10 @@ class Factory : public AllStatic {
static Handle<JSObject> NewJSObject(Handle<JSFunction> constructor,
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
// runtime.
static Handle<JSObject> NewJSObjectFromMap(Handle<Map> map);
......
......@@ -1070,6 +1070,11 @@ bool Heap::CreateInitialMaps() {
if (obj->IsFailure()) return false;
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
obj = AllocateEmptyFixedArray();
if (obj->IsFailure()) return false;
......@@ -1095,6 +1100,10 @@ bool Heap::CreateInitialMaps() {
oddball_map()->set_instance_descriptors(empty_descriptor_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.
meta_map()->set_prototype(null_value());
meta_map()->set_constructor(null_value());
......@@ -1104,6 +1113,9 @@ bool Heap::CreateInitialMaps() {
oddball_map()->set_prototype(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);
if (obj->IsFailure()) return false;
heap_number_map_ = Map::cast(obj);
......@@ -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,
const char* to_string,
Object* to_number) {
......@@ -2055,7 +2078,34 @@ Object* Heap::AllocateJSObject(JSFunction* constructor,
Map::cast(initial_map)->set_constructor(constructor);
}
// 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 {
V(Map, global_context_map) \
V(Map, code_map) \
V(Map, oddball_map) \
V(Map, global_property_cell_map) \
V(Map, boilerplate_function_map) \
V(Map, shared_function_info_map) \
V(Map, proxy_map) \
......@@ -288,6 +289,12 @@ class Heap : public AllStatic {
static Object* AllocateJSObject(JSFunction* constructor,
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.
// Properties and elements are copied too.
// Returns failure if allocation failed.
......@@ -408,6 +415,12 @@ class Heap : public AllStatic {
// Please note this does not perform a garbage collection.
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
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
......
......@@ -66,9 +66,15 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
// Test the has_named_interceptor bit in the map.
__ test(FieldOperand(r0, Map::kInstanceAttributesOffset),
Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
// Jump to miss if the interceptor bit is set.
__ 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.
__ mov(r0, FieldOperand(r1, JSObject::kPropertiesOffset));
__ cmp(FieldOperand(r0, HeapObject::kMapOffset),
......
......@@ -627,6 +627,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ 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(),
......@@ -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,
int index,
Map* transition,
......@@ -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,
int index,
Map* transition,
......@@ -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,
JSObject* receiver,
JSObject* holder,
......
......@@ -423,14 +423,29 @@ void CallIC::UpdateCaches(LookupResult* lookup,
break;
}
case NORMAL: {
if (!object->IsJSObject()) return;
if (object->IsJSGlobalObject()) {
// 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(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.
if (!object->IsJSObject()) return;
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
if (lookup->holder() != *receiver) return;
code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver);
}
break;
}
case INTERCEPTOR: {
......@@ -614,12 +629,23 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
break;
}
case NORMAL: {
if (object->IsJSGlobalObject()) {
// 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(object);
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;
}
case CALLBACKS: {
......@@ -953,6 +979,19 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
code = StubCache::ComputeStoreField(*name, *receiver, index, *transition);
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: {
if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
......
......@@ -152,7 +152,9 @@ void HeapObject::HeapObjectPrint() {
case SHARED_FUNCTION_INFO_TYPE:
SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint();
break;
case JS_GLOBAL_PROPERTY_CELL_TYPE:
JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint();
break;
#define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \
Name::cast(this)->Name##Print(); \
......@@ -214,6 +216,9 @@ void HeapObject::HeapObjectVerify() {
case JS_BUILTINS_OBJECT_TYPE:
JSBuiltinsObject::cast(this)->JSBuiltinsObjectVerify();
break;
case JS_GLOBAL_PROPERTY_CELL_TYPE:
JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellVerify();
break;
case JS_ARRAY_TYPE:
JSArray::cast(this)->JSArrayVerify();
break;
......@@ -392,6 +397,7 @@ static const char* TypeToString(InstanceType type) {
case JS_OBJECT_TYPE: return "JS_OBJECT";
case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return "JS_CONTEXT_EXTENSION_OBJECT";
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 JS_FUNCTION_TYPE: return "JS_FUNCTION";
case CODE_TYPE: return "CODE";
......@@ -428,6 +434,9 @@ void Map::MapPrint() {
if (is_undetectable()) {
PrintF(" - undetectable\n");
}
if (needs_loading()) {
PrintF(" - needs_loading\n");
}
if (has_instance_call_handler()) {
PrintF(" - instance_call_handler\n");
}
......@@ -653,6 +662,17 @@ void Oddball::OddballVerify() {
}
void JSGlobalPropertyCell::JSGlobalPropertyCellVerify() {
CHECK(IsJSGlobalPropertyCell());
VerifyObjectField(kValueOffset);
}
void JSGlobalPropertyCell::JSGlobalPropertyCellPrint() {
HeapObject::PrintHeader("JSGlobalPropertyCell");
}
void Code::CodePrint() {
HeapObject::PrintHeader("Code");
#ifdef ENABLE_DISASSEMBLER
......
......@@ -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) \
type* type::cast(Object* object) { \
ASSERT(object->Is##type()); \
......@@ -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() {
return Object::IsHeapObject() &&
(HeapObject::cast(this)->map()->instance_type() ==
......@@ -1046,6 +1060,8 @@ ACCESSORS(Oddball, to_string, String, kToStringOffset)
ACCESSORS(Oddball, to_number, Object, kToNumberOffset)
ACCESSORS(JSGlobalPropertyCell, value, Object, kValueOffset)
int JSObject::GetHeaderSize() {
switch (map()->instance_type()) {
case JS_GLOBAL_PROXY_TYPE:
......@@ -1403,6 +1419,7 @@ CAST_ACCESSOR(Failure)
CAST_ACCESSOR(HeapObject)
CAST_ACCESSOR(HeapNumber)
CAST_ACCESSOR(Oddball)
CAST_ACCESSOR(JSGlobalPropertyCell)
CAST_ACCESSOR(SharedFunctionInfo)
CAST_ACCESSOR(Map)
CAST_ACCESSOR(JSFunction)
......
......@@ -138,7 +138,7 @@ void Object::Lookup(String* name, LookupResult* result) {
} else if (IsBoolean()) {
holder = global_context->boolean_function()->instance_prototype();
}
ASSERT(holder != NULL); // cannot handle null or undefined.
ASSERT(holder != NULL); // Cannot handle null or undefined.
JSObject::cast(holder)->Lookup(name, result);
}
......@@ -399,6 +399,88 @@ Object* JSObject::DeleteLazyProperty(LookupResult* result,
}
Object* JSObject::GetNormalizedProperty(LookupResult* result) {
ASSERT(!HasFastProperties());
Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
if (IsJSGlobalObject()) {
value = JSGlobalPropertyCell::cast(value)->value();
}
ASSERT(!value->IsJSGlobalPropertyCell());
return value;
}
Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
ASSERT(!HasFastProperties());
if (IsJSGlobalObject()) {
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(
property_dictionary()->ValueAt(result->GetDictionaryEntry()));
cell->set_value(value);
} else {
property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
}
return value;
}
Object* JSObject::SetNormalizedProperty(String* name,
Object* value,
PropertyDetails details) {
ASSERT(!HasFastProperties());
int entry = property_dictionary()->FindStringEntry(name);
if (entry == Dictionary::kNotFound) {
Object* store_value = value;
if (IsJSGlobalObject()) {
store_value = Heap::AllocateJSGlobalPropertyCell(value);
if (store_value->IsFailure()) return store_value;
}
Object* dict =
property_dictionary()->AddStringEntry(name, store_value, details);
if (dict->IsFailure()) return dict;
set_properties(Dictionary::cast(dict));
return value;
}
// Preserve enumeration index.
details = PropertyDetails(details.attributes(),
details.type(),
property_dictionary()->DetailsAt(entry).index());
if (IsJSGlobalObject()) {
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
cell->set_value(value);
// Please note we have to update the property details.
property_dictionary()->DetailsAtPut(entry, details);
} else {
property_dictionary()->SetStringEntry(entry, name, value, details);
}
return value;
}
Object* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
ASSERT(!HasFastProperties());
Dictionary* dictionary = property_dictionary();
int entry = dictionary->FindStringEntry(name);
if (entry != Dictionary::kNotFound) {
// If we have a global object set the cell to the hole.
if (IsJSGlobalObject()) {
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.IsDontDelete() && mode != FORCE_DELETION) {
return Heap::false_value();
}
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
cell->set_value(Heap::the_hole_value());
dictionary->DetailsAtPut(entry, details.AsDeleted());
} else {
return dictionary->DeleteProperty(entry, mode);
}
}
return Heap::true_value();
}
Object* Object::GetProperty(Object* receiver,
LookupResult* result,
String* name,
......@@ -449,8 +531,7 @@ Object* Object::GetProperty(Object* receiver,
JSObject* holder = result->holder();
switch (result->type()) {
case NORMAL:
value =
holder->property_dictionary()->ValueAt(result->GetDictionaryEntry());
value = holder->GetNormalizedProperty(result);
ASSERT(!value->IsTheHole() || result->IsReadOnly());
return value->IsTheHole() ? Heap::undefined_value() : value;
case FIELD:
......@@ -949,6 +1030,10 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
case PROXY_TYPE:
accumulator->Add("<Proxy>");
break;
case JS_GLOBAL_PROPERTY_CELL_TYPE:
accumulator->Add("Cell for ");
JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
break;
default:
accumulator->Add("<Other heap object (%d)>", map()->instance_type());
break;
......@@ -1042,6 +1127,10 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
case CODE_TYPE:
reinterpret_cast<Code*>(this)->CodeIterateBody(v);
break;
case JS_GLOBAL_PROPERTY_CELL_TYPE:
reinterpret_cast<JSGlobalPropertyCell*>(this)
->JSGlobalPropertyCellIterateBody(v);
break;
case HEAP_NUMBER_TYPE:
case FILLER_TYPE:
case BYTE_ARRAY_TYPE:
......@@ -1250,12 +1339,27 @@ Object* JSObject::AddConstantFunctionProperty(String* name,
Object* JSObject::AddSlowProperty(String* name,
Object* value,
PropertyAttributes attributes) {
ASSERT(!HasFastProperties());
Dictionary* dict = property_dictionary();
Object* store_value = value;
if (IsJSGlobalObject()) {
// In case name is an orphaned property reuse the cell.
int entry = dict->FindStringEntry(name);
if (entry != Dictionary::kNotFound) {
store_value = dict->ValueAt(entry);
JSGlobalPropertyCell::cast(store_value)->set_value(value);
PropertyDetails details = PropertyDetails(attributes, NORMAL);
Object* result = property_dictionary()->AddStringEntry(name, value, details);
if (result->IsFailure()) return result;
if (property_dictionary() != result) {
set_properties(Dictionary::cast(result));
dict->SetStringEntry(entry, name, store_value, details);
return value;
}
store_value = Heap::AllocateJSGlobalPropertyCell(value);
if (store_value->IsFailure()) return store_value;
JSGlobalPropertyCell::cast(store_value)->set_value(value);
}
PropertyDetails details = PropertyDetails(attributes, NORMAL);
Object* result = dict->AddStringEntry(name, store_value, details);
if (result->IsFailure()) return result;
if (dict != result) set_properties(Dictionary::cast(result));
return value;
}
......@@ -1311,13 +1415,7 @@ Object* JSObject::ReplaceSlowProperty(String* name,
}
PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
Object* result =
dictionary->SetOrAddStringEntry(name, value, new_details);
if (result->IsFailure()) return result;
if (dictionary != result) {
set_properties(Dictionary::cast(result));
}
return value;
return SetNormalizedProperty(name, value, new_details);
}
Object* JSObject::ConvertDescriptorToFieldAndMapTransition(
......@@ -1550,7 +1648,7 @@ Object* JSObject::LookupCallbackSetterInPrototypes(uint32_t index) {
if (JSObject::cast(pt)->HasFastElements()) continue;
Dictionary* dictionary = JSObject::cast(pt)->element_dictionary();
int entry = dictionary->FindNumberEntry(index);
if (entry != -1) {
if (entry != Dictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) {
......@@ -1601,10 +1699,20 @@ void JSObject::LocalLookupRealNamedProperty(String* name,
}
} else {
int entry = property_dictionary()->FindStringEntry(name);
if (entry != DescriptorArray::kNotFound) {
if (entry != Dictionary::kNotFound) {
// Make sure to disallow caching for uninitialized constants
// found in the dictionary-mode objects.
if (property_dictionary()->ValueAt(entry)->IsTheHole()) {
Object* value = property_dictionary()->ValueAt(entry);
if (IsJSGlobalObject()) {
PropertyDetails d = property_dictionary()->DetailsAt(entry);
if (d.IsDeleted()) {
result->NotFound();
return;
}
value = JSGlobalPropertyCell::cast(value)->value();
ASSERT(result->IsLoaded());
}
if (value->IsTheHole()) {
result->DisallowCaching();
}
result->DictionaryResult(this, entry);
......@@ -1736,8 +1844,7 @@ Object* JSObject::SetProperty(LookupResult* result,
// transition or null descriptor and there are no setters in the prototypes.
switch (result->type()) {
case NORMAL:
property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
return value;
return SetNormalizedProperty(result, value);
case FIELD:
return FastPropertyAtPut(result->GetFieldIndex(), value);
case MAP_TRANSITION:
......@@ -1819,8 +1926,7 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty(
// Check of IsReadOnly removed from here in clone.
switch (result->type()) {
case NORMAL:
property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
return value;
return SetNormalizedProperty(result, value);
case FIELD:
return FastPropertyAtPut(result->GetFieldIndex(), value);
case MAP_TRANSITION:
......@@ -2008,6 +2114,10 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) {
PropertyDetails d =
PropertyDetails(details.attributes(), NORMAL, details.index());
Object* value = r.GetConstantFunction();
if (IsJSGlobalObject()) {
value = Heap::AllocateJSGlobalPropertyCell(value);
if (value->IsFailure()) return value;
}
Object* result = dictionary->AddStringEntry(r.GetKey(), value, d);
if (result->IsFailure()) return result;
dictionary = Dictionary::cast(result);
......@@ -2017,6 +2127,10 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) {
PropertyDetails d =
PropertyDetails(details.attributes(), NORMAL, details.index());
Object* value = FastPropertyAt(r.GetFieldIndex());
if (IsJSGlobalObject()) {
value = Heap::AllocateJSGlobalPropertyCell(value);
if (value->IsFailure()) return value;
}
Object* result = dictionary->AddStringEntry(r.GetKey(), value, d);
if (result->IsFailure()) return result;
dictionary = Dictionary::cast(result);
......@@ -2026,6 +2140,10 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) {
PropertyDetails d =
PropertyDetails(details.attributes(), CALLBACKS, details.index());
Object* value = r.GetCallbacksObject();
if (IsJSGlobalObject()) {
value = Heap::AllocateJSGlobalPropertyCell(value);
if (value->IsFailure()) return value;
}
Object* result = dictionary->AddStringEntry(r.GetKey(), value, d);
if (result->IsFailure()) return result;
dictionary = Dictionary::cast(result);
......@@ -2085,6 +2203,7 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) {
Object* JSObject::TransformToFastProperties(int unused_property_fields) {
if (HasFastProperties()) return this;
ASSERT(!IsJSGlobalObject());
return property_dictionary()->
TransformPropertiesToFastFor(this, unused_property_fields);
}
......@@ -2139,12 +2258,7 @@ Object* JSObject::DeletePropertyPostInterceptor(String* name, DeleteMode mode) {
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
if (obj->IsFailure()) return obj;
ASSERT(!HasFastProperties());
// Attempt to remove the property from the property dictionary.
Dictionary* dictionary = property_dictionary();
int entry = dictionary->FindStringEntry(name);
if (entry != -1) return dictionary->DeleteProperty(entry, mode);
return Heap::true_value();
return DeleteNormalizedProperty(name, mode);
}
......@@ -2194,7 +2308,9 @@ Object* JSObject::DeleteElementPostInterceptor(uint32_t index,
ASSERT(!HasFastElements());
Dictionary* dictionary = element_dictionary();
int entry = dictionary->FindNumberEntry(index);
if (entry != -1) return dictionary->DeleteProperty(entry, mode);
if (entry != Dictionary::kNotFound) {
return dictionary->DeleteProperty(entry, mode);
}
return Heap::true_value();
}
......@@ -2266,7 +2382,9 @@ Object* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
} else {
Dictionary* dictionary = element_dictionary();
int entry = dictionary->FindNumberEntry(index);
if (entry != -1) return dictionary->DeleteProperty(entry, mode);
if (entry != Dictionary::kNotFound) {
return dictionary->DeleteProperty(entry, mode);
}
}
return Heap::true_value();
}
......@@ -2318,10 +2436,7 @@ Object* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
if (obj->IsFailure()) return obj;
// Make sure the properties are normalized before removing the entry.
Dictionary* dictionary = property_dictionary();
int entry = dictionary->FindStringEntry(name);
if (entry != -1) return dictionary->DeleteProperty(entry, mode);
return Heap::true_value();
return DeleteNormalizedProperty(name, mode);
}
}
......@@ -2574,7 +2689,7 @@ Object* JSObject::DefineGetterSetter(String* name,
if (!HasFastElements()) {
Dictionary* dictionary = element_dictionary();
int entry = dictionary->FindNumberEntry(index);
if (entry != -1) {
if (entry != Dictionary::kNotFound) {
Object* result = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.IsReadOnly()) return Heap::undefined_value();
......@@ -2624,12 +2739,7 @@ Object* JSObject::DefineGetterSetter(String* name,
if (ok->IsFailure()) return ok;
// Update the dictionary with the new CALLBACKS property.
Object* dict =
property_dictionary()->SetOrAddStringEntry(name, structure, details);
if (dict->IsFailure()) return dict;
// Set the potential new dictionary on the object.
set_properties(Dictionary::cast(dict));
return SetNormalizedProperty(name, structure, details);
}
return structure;
......@@ -2683,7 +2793,7 @@ Object* JSObject::LookupAccessor(String* name, bool is_getter) {
if (!jsObject->HasFastElements()) {
Dictionary* dictionary = jsObject->element_dictionary();
int entry = dictionary->FindNumberEntry(index);
if (entry != -1) {
if (entry != Dictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) {
......@@ -3974,6 +4084,11 @@ void ConsString::ConsStringIterateBody(ObjectVisitor* v) {
}
void JSGlobalPropertyCell::JSGlobalPropertyCellIterateBody(ObjectVisitor* v) {
IteratePointers(v, kValueOffset, kValueOffset + kPointerSize);
}
uint16_t ConsString::ConsStringGet(int index) {
ASSERT(index >= 0 && index < this->length());
......@@ -4897,8 +5012,30 @@ const char* Code::ICState2String(InlineCacheState state) {
}
const char* Code::PropertyType2String(PropertyType type) {
switch (type) {
case NORMAL: return "NORMAL";
case FIELD: return "FIELD";
case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
case CALLBACKS: return "CALLBACKS";
case INTERCEPTOR: return "INTERCEPTOR";
case MAP_TRANSITION: return "MAP_TRANSITION";
case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
}
UNREACHABLE();
return NULL;
}
void Code::Disassemble(const char* name) {
PrintF("kind = %s\n", Kind2String(kind()));
if (is_inline_cache_stub()) {
PrintF("ic_state = %s\n", ICState2String(ic_state()));
PrintF("ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
if (ic_state() == MONOMORPHIC) {
PrintF("type = %s\n", PropertyType2String(type()));
}
}
if ((name != NULL) && (name[0] != '\0')) {
PrintF("name = %s\n", name);
}
......@@ -5095,7 +5232,9 @@ bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) {
return true;
}
} else {
if (element_dictionary()->FindNumberEntry(index) != -1) return true;
if (element_dictionary()->FindNumberEntry(index) != Dictionary::kNotFound) {
return true;
}
}
// Handle [] on String objects.
......@@ -5170,7 +5309,8 @@ bool JSObject::HasLocalElement(uint32_t index) {
return (index < length) &&
!FixedArray::cast(elements())->get(index)->IsTheHole();
} else {
return element_dictionary()->FindNumberEntry(index) != -1;
return element_dictionary()->FindNumberEntry(index)
!= Dictionary::kNotFound;
}
}
......@@ -5196,7 +5336,9 @@ bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
if ((index < length) &&
!FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
} else {
if (element_dictionary()->FindNumberEntry(index) != -1) return true;
if (element_dictionary()->FindNumberEntry(index) != Dictionary::kNotFound) {
return true;
}
}
// Handle [] on String objects.
......@@ -5332,7 +5474,7 @@ Object* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value) {
Dictionary* dictionary = Dictionary::cast(elms);
int entry = dictionary->FindNumberEntry(index);
if (entry != -1) {
if (entry != Dictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) {
......@@ -5426,7 +5568,7 @@ Object* JSObject::GetElementPostInterceptor(JSObject* receiver,
} else {
Dictionary* dictionary = element_dictionary();
int entry = dictionary->FindNumberEntry(index);
if (entry != -1) {
if (entry != Dictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) {
......@@ -5510,7 +5652,7 @@ Object* JSObject::GetElementWithReceiver(JSObject* receiver, uint32_t index) {
} else {
Dictionary* dictionary = element_dictionary();
int entry = dictionary->FindNumberEntry(index);
if (entry != -1) {
if (entry != Dictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) {
......@@ -5803,7 +5945,8 @@ bool JSObject::HasRealElementProperty(uint32_t index) {
return (index < length) &&
!FixedArray::cast(elements())->get(index)->IsTheHole();
}
return element_dictionary()->FindNumberEntry(index) != -1;
return element_dictionary()->FindNumberEntry(index)
!= Dictionary::kNotFound;
}
......@@ -6328,7 +6471,7 @@ Object* HashTable<prefix_size, element_size>::Allocate(int at_least_space_for) {
template <int prefix_size, int element_size>
int HashTable<prefix_size, element_size>::FindEntry(HashTableKey* key) {
uint32_t nof = NumberOfElements();
if (nof == 0) return -1; // Bail out if empty.
if (nof == 0) return kNotFound; // Bail out if empty.
uint32_t capacity = Capacity();
uint32_t hash = key->Hash();
......@@ -6338,17 +6481,17 @@ int HashTable<prefix_size, element_size>::FindEntry(HashTableKey* key) {
uint32_t passed_elements = 0;
if (!element->IsNull()) {
if (!element->IsUndefined() && key->IsMatch(element)) return entry;
if (++passed_elements == nof) return -1;
if (++passed_elements == nof) return kNotFound;
}
for (uint32_t i = 1; !element->IsUndefined(); i++) {
entry = GetProbe(hash, i, capacity);
element = KeyAt(entry);
if (!element->IsNull()) {
if (!element->IsUndefined() && key->IsMatch(element)) return entry;
if (++passed_elements == nof) return -1;
if (++passed_elements == nof) return kNotFound;
}
}
return -1;
return kNotFound;
}
......@@ -6588,6 +6731,14 @@ Object* JSObject::PrepareElementsForSort(uint32_t limit) {
}
Object* JSGlobalObject::GetPropertyCell(LookupResult* result) {
ASSERT(!HasFastProperties());
Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
ASSERT(value->IsJSGlobalPropertyCell());
return value;
}
Object* SymbolTable::LookupString(String* string, Object** s) {
SymbolKey key(string);
return LookupKey(&key, s);
......@@ -6597,7 +6748,7 @@ Object* SymbolTable::LookupString(String* string, Object** s) {
bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
SymbolKey key(string);
int entry = FindEntry(&key);
if (entry == -1) {
if (entry == kNotFound) {
return false;
} else {
String* result = String::cast(KeyAt(entry));
......@@ -6618,7 +6769,7 @@ Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
int entry = FindEntry(key);
// Symbol already in table.
if (entry != -1) {
if (entry != kNotFound) {
*s = KeyAt(entry);
return this;
}
......@@ -6648,7 +6799,7 @@ Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Object* CompilationCacheTable::Lookup(String* src) {
StringKey key(src);
int entry = FindEntry(&key);
if (entry == -1) return Heap::undefined_value();
if (entry == kNotFound) return Heap::undefined_value();
return get(EntryToIndex(entry) + 1);
}
......@@ -6656,7 +6807,7 @@ Object* CompilationCacheTable::Lookup(String* src) {
Object* CompilationCacheTable::LookupEval(String* src, Context* context) {
StringSharedKey key(src, context->closure()->shared());
int entry = FindEntry(&key);
if (entry == -1) return Heap::undefined_value();
if (entry == kNotFound) return Heap::undefined_value();
return get(EntryToIndex(entry) + 1);
}
......@@ -6665,7 +6816,7 @@ Object* CompilationCacheTable::LookupRegExp(String* src,
JSRegExp::Flags flags) {
RegExpKey key(src, flags);
int entry = FindEntry(&key);
if (entry == -1) return Heap::undefined_value();
if (entry == kNotFound) return Heap::undefined_value();
return get(EntryToIndex(entry) + 1);
}
......@@ -6764,7 +6915,7 @@ class SymbolsKey : public HashTableKey {
Object* MapCache::Lookup(FixedArray* array) {
SymbolsKey key(array);
int entry = FindEntry(&key);
if (entry == -1) return Heap::undefined_value();
if (entry == kNotFound) return Heap::undefined_value();
return get(EntryToIndex(entry) + 1);
}
......@@ -6915,7 +7066,7 @@ Object* Dictionary::AtPut(HashTableKey* key, Object* value) {
int entry = FindEntry(key);
// If the entry is present set the value;
if (entry != -1) {
if (entry != kNotFound) {
ValueAtPut(entry, value);
return this;
}
......@@ -6988,7 +7139,7 @@ Object* Dictionary::AddStringEntry(String* key,
Object* value,
PropertyDetails details) {
StringKey k(key);
SLOW_ASSERT(FindEntry(&k) == -1);
SLOW_ASSERT(FindEntry(&k) == kNotFound);
return Add(&k, value, details);
}
......@@ -6998,17 +7149,11 @@ Object* Dictionary::AddNumberEntry(uint32_t key,
PropertyDetails details) {
NumberKey k(key);
UpdateMaxNumberKey(key);
SLOW_ASSERT(FindEntry(&k) == -1);
SLOW_ASSERT(FindEntry(&k) == kNotFound);
return Add(&k, value, details);
}
Object* Dictionary::AtStringPut(String* key, Object* value) {
StringKey k(key);
return AtPut(&k, value);
}
Object* Dictionary::AtNumberPut(uint32_t key, Object* value) {
NumberKey k(key);
UpdateMaxNumberKey(key);
......@@ -7016,12 +7161,10 @@ Object* Dictionary::AtNumberPut(uint32_t key, Object* value) {
}
Object* Dictionary::SetOrAddStringEntry(String* key,
Object* Dictionary::SetStringEntry(int entry,
String* key,
Object* value,
PropertyDetails details) {
StringKey k(key);
int entry = FindEntry(&k);
if (entry == -1) return AddStringEntry(key, value, details);
// Preserve enumeration index.
details = PropertyDetails(details.attributes(),
details.type(),
......@@ -7124,8 +7267,12 @@ Object* Dictionary::SlowReverseLookup(Object* value) {
int capacity = Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = KeyAt(i);
if (IsKey(k) && ValueAt(i) == value) {
return k;
if (IsKey(k)) {
Object* e = ValueAt(i);
if (e->IsJSGlobalPropertyCell()) {
e = JSGlobalPropertyCell::cast(e)->value();
}
if (e == value) return k;
}
}
return Heap::undefined_value();
......
......@@ -153,20 +153,23 @@ class PropertyDetails BASE_EMBEDDED {
int index() { return IndexField::decode(value_); }
inline PropertyDetails AsDeleted();
static bool IsValidIndex(int index) { return IndexField::is_valid(index); }
bool IsReadOnly() { return (attributes() & READ_ONLY) != 0; }
bool IsDontDelete() { return (attributes() & DONT_DELETE) != 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
// constants can be embedded in generated code.
class TypeField: public BitField<PropertyType, 0, 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;
private:
uint32_t value_;
};
......@@ -263,6 +266,7 @@ enum PropertyNormalizationMode {
V(HEAP_NUMBER_TYPE) \
V(FIXED_ARRAY_TYPE) \
V(CODE_TYPE) \
V(JS_GLOBAL_PROPERTY_CELL_TYPE) \
V(ODDBALL_TYPE) \
V(PROXY_TYPE) \
V(BYTE_ARRAY_TYPE) \
......@@ -547,6 +551,7 @@ enum InstanceType {
FIXED_ARRAY_TYPE,
CODE_TYPE,
ODDBALL_TYPE,
JS_GLOBAL_PROPERTY_CELL_TYPE,
PROXY_TYPE,
BYTE_ARRAY_TYPE,
FILLER_TYPE,
......@@ -684,6 +689,7 @@ class Object BASE_EMBEDDED {
inline bool IsJSGlobalProxy();
inline bool IsUndetectableObject();
inline bool IsAccessCheckNeeded();
inline bool IsJSGlobalPropertyCell();
// Returns true if this object is an instance of the specified
// function template.
......@@ -1193,6 +1199,8 @@ class HeapNumber: public HeapObject {
// caching.
class JSObject: public HeapObject {
public:
enum DeleteMode { NORMAL_DELETION, FORCE_DELETION };
// [properties]: Backing storage for properties.
// properties is a FixedArray in the fast case, and a Dictionary in the
// slow case.
......@@ -1243,6 +1251,23 @@ class JSObject: public HeapObject {
Object* value,
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.
Object* SetLazyProperty(LookupResult* result,
String* name,
......@@ -1293,7 +1318,6 @@ class JSObject: public HeapObject {
return GetLocalPropertyAttribute(name) != ABSENT;
}
enum DeleteMode { NORMAL_DELETION, FORCE_DELETION };
Object* DeleteProperty(String* name, DeleteMode mode);
Object* DeleteElement(uint32_t index, DeleteMode mode);
Object* DeleteLazyProperty(LookupResult* result,
......@@ -1930,6 +1954,9 @@ class HashTable: public FixedArray {
static const int kElementsStartOffset =
kHeaderSize + kElementsStartIndex * kPointerSize;
// Constant used for denoting a absent entry.
static const int kNotFound = -1;
protected:
// Find entry for key otherwise return -1.
int FindEntry(HashTableKey* key);
......@@ -2027,7 +2054,9 @@ class DictionaryBase: public HashTable<2, 3> {};
class Dictionary: public DictionaryBase {
public:
// 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.
void ValueAtPut(int entry, Object* value) {
......@@ -2064,14 +2093,14 @@ class Dictionary: public DictionaryBase {
Object* DeleteProperty(int entry, JSObject::DeleteMode mode);
// 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* AddStringEntry(String* 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.
Object* SetOrAddStringEntry(String* key,
Object* SetStringEntry(int entry,
String* key,
Object* value,
PropertyDetails details);
......@@ -2252,6 +2281,7 @@ class Code: public HeapObject {
// Printing
static const char* Kind2String(Kind kind);
static const char* ICState2String(InlineCacheState state);
static const char* PropertyType2String(PropertyType type);
void Disassemble(const char* name);
#endif // ENABLE_DISASSEMBLER
......@@ -2274,7 +2304,7 @@ class Code: public HeapObject {
// [flags]: Access to specific code flags.
inline Kind kind();
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 int arguments_count(); // Only valid for call IC stubs.
......@@ -3048,6 +3078,10 @@ class GlobalObject: public JSObject {
// JavaScript global object.
class JSGlobalObject: public GlobalObject {
public:
// Retrieve the property cell used to store a property.
Object* GetPropertyCell(LookupResult* result);
// Casting.
static inline JSGlobalObject* cast(Object* obj);
......@@ -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.
// Since they cannot contain references to JS HeapObjects they can be
// placed in old_data_space.
......
......@@ -230,6 +230,7 @@ class LookupResult BASE_EMBEDDED {
bool IsReadOnly() { return details_.IsReadOnly(); }
bool IsDontDelete() { return details_.IsDontDelete(); }
bool IsDontEnum() { return details_.IsDontEnum(); }
bool IsDeleted() { return details_.IsDeleted(); }
bool IsValid() { return lookup_type_ != NOT_FOUND; }
bool IsNotFound() { return lookup_type_ == NOT_FOUND; }
......@@ -256,8 +257,14 @@ class LookupResult BASE_EMBEDDED {
switch (type()) {
case FIELD:
return holder()->FastPropertyAt(GetFieldIndex());
case NORMAL:
return holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
case NORMAL: {
Object* value;
value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
if (holder()->IsJSGlobalObject()) {
value = JSGlobalPropertyCell::cast(value)->value();
}
return value;
}
case CONSTANT_FUNCTION:
return GetConstantFunction();
default:
......@@ -306,7 +313,7 @@ class LookupResult BASE_EMBEDDED {
}
// In the dictionary case, the data is held in the value field.
ASSERT(lookup_type_ == DICTIONARY_TYPE);
return holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
return holder()->GetNormalizedProperty(this);
}
private:
......
......@@ -576,9 +576,6 @@ static Object* Runtime_DeclareGlobals(Arguments args) {
// property as read-only, so we don't either.
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.
int length = pairs->length();
for (int i = 0; i < length; i += 2) {
......@@ -890,10 +887,8 @@ static Object* Runtime_InitializeConstGlobal(Arguments args) {
properties->set(index, *value);
}
} else if (type == NORMAL) {
Dictionary* dictionary = global->property_dictionary();
int entry = lookup.GetDictionaryEntry();
if (dictionary->ValueAt(entry)->IsTheHole()) {
dictionary->ValueAtPut(entry, *value);
if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
global->SetNormalizedProperty(&lookup, *value);
}
} else {
// Ignore re-initialization of constants that have already been
......@@ -983,10 +978,8 @@ static Object* Runtime_InitializeConstContextSlot(Arguments args) {
properties->set(index, *value);
}
} else if (type == NORMAL) {
Dictionary* dictionary = context_ext->property_dictionary();
int entry = lookup.GetDictionaryEntry();
if (dictionary->ValueAt(entry)->IsTheHole()) {
dictionary->ValueAtPut(entry, *value);
if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
context_ext->SetNormalizedProperty(&lookup, *value);
}
} else {
// We should not reach here. Any real, named property should be
......@@ -2598,9 +2591,13 @@ static Object* Runtime_KeyedGetProperty(Arguments args) {
// Attempt dictionary lookup.
Dictionary* dictionary = receiver->property_dictionary();
int entry = dictionary->FindStringEntry(key);
if ((entry != DescriptorArray::kNotFound) &&
if ((entry != Dictionary::kNotFound) &&
(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,
bool* caught_exception) {
Object* value;
switch (result->type()) {
case NORMAL: {
Dictionary* dict =
JSObject::cast(result->holder())->property_dictionary();
value = dict->ValueAt(result->GetDictionaryEntry());
case NORMAL:
value = result->holder()->GetNormalizedProperty(result);
if (value->IsTheHole()) {
return Heap::undefined_value();
}
return value;
}
case FIELD:
value =
JSObject::cast(
......
......@@ -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,
JSObject* receiver,
JSObject* holder,
......@@ -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,
JSObject* receiver,
AccessorInfo* callback) {
......@@ -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) {
Dictionary* dictionary = Heap::non_monomorphic_cache();
int entry = dictionary->FindNumberEntry(flags);
......
......@@ -78,6 +78,11 @@ class StubCache : public AllStatic {
static Object* ComputeLoadNormal(String* name, JSObject* receiver);
static Object* ComputeLoadGlobal(String* name,
JSGlobalObject* receiver,
JSGlobalPropertyCell* cell);
// ---
static Object* ComputeKeyedLoadField(String* name,
......@@ -112,6 +117,10 @@ class StubCache : public AllStatic {
int field_index,
Map* transition = NULL);
static Object* ComputeStoreGlobal(String* name,
JSGlobalObject* receiver,
JSGlobalPropertyCell* cell);
static Object* ComputeStoreCallback(String* name,
JSObject* receiver,
AccessorInfo* callback);
......@@ -151,6 +160,13 @@ class StubCache : public AllStatic {
Object* object,
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);
......@@ -416,6 +432,10 @@ class LoadStubCompiler: public StubCompiler {
JSObject* holder,
String* name);
Object* CompileLoadGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* holder,
String* name);
private:
Object* GetCode(PropertyType type, String* name);
};
......@@ -457,6 +477,10 @@ class StoreStubCompiler: public StubCompiler {
AccessorInfo* callbacks,
String* name);
Object* CompileStoreInterceptor(JSObject* object, String* name);
Object* CompileStoreGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* holder,
String* name);
private:
Object* GetCode(PropertyType type, String* name);
......@@ -492,6 +516,10 @@ class CallStubCompiler: public StubCompiler {
Object* CompileCallInterceptor(Object* object,
JSObject* holder,
String* name);
Object* CompileCallGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name);
private:
const ParameterCount arguments_;
......
......@@ -130,9 +130,15 @@ namespace internal {
SC(keyed_load_inline_miss, V8.KeyedLoadInlineMiss) \
SC(named_load_inline, V8.NamedLoadInline) \
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_inline, V8.KeyedStoreInline) \
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(enum_cache_hits, V8.EnumCacheHits) \
SC(enum_cache_misses, V8.EnumCacheMisses) \
......
......@@ -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,
JSObject* b,
AccessorInfo* c,
......@@ -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,
AccessorInfo* b,
String* c) {
......@@ -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
// number of arguments. It is not needed anymore.
Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
......
......@@ -6040,6 +6040,7 @@ THREADED_TEST(DisableAccessChecksWhileConfiguring) {
CHECK(value->BooleanValue());
}
static bool NamedGetAccessBlocker(Local<v8::Object> obj,
Local<Value> name,
v8::AccessType type,
......@@ -6093,6 +6094,7 @@ THREADED_TEST(AccessChecksReenabledCorrectly) {
CHECK(value_2->IsUndefined());
}
// This tests that access check information remains on the global
// object template when creating contexts.
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
// without initializing the whole VM. Thus we cannot run this test in a
// 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