Commit 875dbe65 authored by kasperl@chromium.org's avatar kasperl@chromium.org

Re-enable ICs for loads and calls that skips a global object during

lookup through the prototype chain.
Review URL: http://codereview.chromium.org/155344

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2425 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 15754c6f
......@@ -171,110 +171,6 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
}
void StubCompiler::GenerateLoadField(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
int index,
Label* miss_label) {
// Check that the receiver isn't a smi.
__ tst(receiver, Operand(kSmiTagMask));
__ b(eq, miss_label);
// Check that the maps haven't changed.
Register reg =
masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
GenerateFastPropertyLoad(masm, r0, reg, holder, index);
__ Ret();
}
void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
Object* value,
Label* miss_label) {
// Check that the receiver isn't a smi.
__ tst(receiver, Operand(kSmiTagMask));
__ b(eq, miss_label);
// Check that the maps haven't changed.
Register reg =
masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Return the constant value.
__ mov(r0, Operand(Handle<Object>(value)));
__ Ret();
}
void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
Register receiver,
Register name,
Register scratch1,
Register scratch2,
AccessorInfo* callback,
Label* miss_label) {
// Check that the receiver isn't a smi.
__ tst(receiver, Operand(kSmiTagMask));
__ b(eq, miss_label);
// Check that the maps haven't changed.
Register reg =
masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Push the arguments on the JS stack of the caller.
__ push(receiver); // receiver
__ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
__ push(ip);
__ push(name); // name
__ push(reg); // holder
// Do tail-call to the runtime system.
ExternalReference load_callback_property =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallRuntime(load_callback_property, 4);
}
void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
Smi* lookup_hint,
Register receiver,
Register name,
Register scratch1,
Register scratch2,
Label* miss_label) {
// Check that the receiver isn't a smi.
__ tst(receiver, Operand(kSmiTagMask));
__ b(eq, miss_label);
// Check that the maps haven't changed.
Register reg =
masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Push the arguments on the JS stack of the caller.
__ push(receiver); // receiver
__ push(reg); // holder
__ push(name); // name
__ mov(scratch1, Operand(lookup_hint));
__ push(scratch1);
// Do tail-call to the runtime system.
ExternalReference load_ic_property =
ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
__ TailCallRuntime(load_ic_property, 4);
}
void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
Register receiver,
Register scratch,
......@@ -462,6 +358,147 @@ void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
#define __ ACCESS_MASM(masm())
Register StubCompiler::CheckPrototypes(JSObject* object,
Register object_reg,
JSObject* holder,
Register holder_reg,
Register scratch,
String* name,
Label* miss) {
// Check that the maps haven't changed.
Register result =
masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
// If we've skipped any global objects, it's not enough to verify
// that their maps haven't changed.
while (object != holder) {
if (object->IsGlobalObject()) {
GlobalObject* global = GlobalObject::cast(object);
Object* probe = global->EnsurePropertyCell(name);
if (probe->IsFailure()) {
set_failure(Failure::cast(probe));
return result;
}
JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
ASSERT(cell->value()->IsTheHole());
__ mov(scratch, Operand(Handle<Object>(cell)));
__ ldr(scratch,
FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
__ cmp(scratch, Operand(Factory::the_hole_value()));
__ b(ne, miss);
}
object = JSObject::cast(object->GetPrototype());
}
// Return the register containin the holder.
return result;
}
void StubCompiler::GenerateLoadField(JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
int index,
String* name,
Label* miss) {
// Check that the receiver isn't a smi.
__ tst(receiver, Operand(kSmiTagMask));
__ b(eq, miss);
// Check that the maps haven't changed.
Register reg =
CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
__ Ret();
}
void StubCompiler::GenerateLoadConstant(JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
Object* value,
String* name,
Label* miss) {
// Check that the receiver isn't a smi.
__ tst(receiver, Operand(kSmiTagMask));
__ b(eq, miss);
// Check that the maps haven't changed.
Register reg =
CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
// Return the constant value.
__ mov(r0, Operand(Handle<Object>(value)));
__ Ret();
}
void StubCompiler::GenerateLoadCallback(JSObject* object,
JSObject* holder,
Register receiver,
Register name_reg,
Register scratch1,
Register scratch2,
AccessorInfo* callback,
String* name,
Label* miss) {
// Check that the receiver isn't a smi.
__ tst(receiver, Operand(kSmiTagMask));
__ b(eq, miss);
// Check that the maps haven't changed.
Register reg =
CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
// Push the arguments on the JS stack of the caller.
__ push(receiver); // receiver
__ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
__ push(ip);
__ push(name_reg); // name
__ push(reg); // holder
// Do tail-call to the runtime system.
ExternalReference load_callback_property =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallRuntime(load_callback_property, 4);
}
void StubCompiler::GenerateLoadInterceptor(JSObject* object,
JSObject* holder,
Smi* lookup_hint,
Register receiver,
Register name_reg,
Register scratch1,
Register scratch2,
String* name,
Label* miss) {
// Check that the receiver isn't a smi.
__ tst(receiver, Operand(kSmiTagMask));
__ b(eq, miss);
// Check that the maps haven't changed.
Register reg =
CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
// Push the arguments on the JS stack of the caller.
__ push(receiver); // receiver
__ push(reg); // holder
__ push(name_reg); // name
__ mov(scratch1, Operand(lookup_hint));
__ push(scratch1);
// Do tail-call to the runtime system.
ExternalReference load_ic_property =
ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
__ TailCallRuntime(load_ic_property, 4);
}
Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
// ----------- S t a t e -------------
// -- r1: function
......@@ -513,7 +550,7 @@ Object* CallStubCompiler::CompileCallField(Object* object,
// Do the right check and compute the holder register.
Register reg =
masm()->CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss);
CheckPrototypes(JSObject::cast(object), r0, holder, r3, r2, name, &miss);
GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
// Check that the function really is a function.
......@@ -546,6 +583,7 @@ Object* CallStubCompiler::CompileCallField(Object* object,
Object* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
String* name,
CheckType check) {
// ----------- S t a t e -------------
// -- lr: return address
......@@ -569,7 +607,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
switch (check) {
case RECEIVER_MAP_CHECK:
// Check that the maps haven't changed.
__ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
// Patch the receiver on the stack with the global proxy if
// necessary.
......@@ -587,8 +625,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
GenerateLoadGlobalFunctionPrototype(masm(),
Context::STRING_FUNCTION_INDEX,
r2);
__ CheckMaps(JSObject::cast(object->GetPrototype()),
r2, holder, r3, r1, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
r1, name, &miss);
break;
case NUMBER_CHECK: {
......@@ -603,8 +641,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
GenerateLoadGlobalFunctionPrototype(masm(),
Context::NUMBER_FUNCTION_INDEX,
r2);
__ CheckMaps(JSObject::cast(object->GetPrototype()),
r2, holder, r3, r1, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
r1, name, &miss);
break;
}
......@@ -620,13 +658,13 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
GenerateLoadGlobalFunctionPrototype(masm(),
Context::BOOLEAN_FUNCTION_INDEX,
r2);
__ CheckMaps(JSObject::cast(object->GetPrototype()),
r2, holder, r3, r1, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
r1, name, &miss);
break;
}
case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
__ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
// Make sure object->elements()->map() != Heap::hash_table_map()
// Get the elements array of the object.
__ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
......@@ -712,7 +750,7 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
}
// Check that the maps haven't changed.
masm()->CheckMaps(object, r0, holder, r3, r2, &miss);
CheckPrototypes(object, r0, holder, r3, r2, name, &miss);
// Get the value from the cell.
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
......@@ -941,7 +979,7 @@ Object* LoadStubCompiler::CompileLoadField(JSObject* object,
__ ldr(r0, MemOperand(sp, 0));
GenerateLoadField(masm(), object, holder, r0, r3, r1, index, &miss);
GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
......@@ -962,7 +1000,7 @@ Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
Label miss;
__ ldr(r0, MemOperand(sp, 0));
GenerateLoadCallback(masm(), object, holder, r0, r2, r3, r1, callback, &miss);
GenerateLoadCallback(object, holder, r0, r2, r3, r1, callback, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
......@@ -984,7 +1022,7 @@ Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
__ ldr(r0, MemOperand(sp, 0));
GenerateLoadConstant(masm(), object, holder, r0, r3, r1, value, &miss);
GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
......@@ -1005,14 +1043,14 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
__ ldr(r0, MemOperand(sp, 0));
GenerateLoadInterceptor(masm(),
object,
GenerateLoadInterceptor(object,
holder,
holder->InterceptorPropertyLookupHint(name),
r0,
r2,
r3,
r1,
name,
&miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
......@@ -1048,7 +1086,7 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
}
// Check that the map of the global has not changed.
masm()->CheckMaps(object, r1, holder, r3, r0, &miss);
CheckPrototypes(object, r1, holder, r3, r0, name, &miss);
// Get the value from the cell.
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
......@@ -1091,7 +1129,7 @@ Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
__ cmp(r2, Operand(Handle<String>(name)));
__ b(ne, &miss);
GenerateLoadField(masm(), receiver, holder, r0, r3, r1, index, &miss);
GenerateLoadField(receiver, holder, r0, r3, r1, index, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
......@@ -1116,8 +1154,7 @@ Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
__ cmp(r2, Operand(Handle<String>(name)));
__ b(ne, &miss);
GenerateLoadCallback(masm(), receiver, holder, r0, r2, r3,
r1, callback, &miss);
GenerateLoadCallback(receiver, holder, r0, r2, r3, r1, callback, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
......@@ -1143,7 +1180,7 @@ Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
__ cmp(r2, Operand(Handle<String>(name)));
__ b(ne, &miss);
GenerateLoadConstant(masm(), receiver, holder, r0, r3, r1, value, &miss);
GenerateLoadConstant(receiver, holder, r0, r3, r1, value, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
......@@ -1169,14 +1206,14 @@ Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
__ cmp(r2, Operand(Handle<String>(name)));
__ b(ne, &miss);
GenerateLoadInterceptor(masm(),
receiver,
GenerateLoadInterceptor(receiver,
holder,
Smi::FromInt(JSObject::kLookupInHolder),
r0,
r2,
r3,
r1,
name,
&miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
......
......@@ -273,114 +273,6 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
}
void StubCompiler::GenerateLoadField(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
int index,
Label* miss_label) {
// Check that the receiver isn't a smi.
__ test(receiver, Immediate(kSmiTagMask));
__ j(zero, miss_label, not_taken);
// Check that the maps haven't changed.
Register reg =
masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Get the value from the properties.
GenerateFastPropertyLoad(masm, eax, reg, holder, index);
__ ret(0);
}
void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
Register receiver,
Register name,
Register scratch1,
Register scratch2,
AccessorInfo* callback,
Label* miss_label) {
// Check that the receiver isn't a smi.
__ test(receiver, Immediate(kSmiTagMask));
__ j(zero, miss_label, not_taken);
// Check that the maps haven't changed.
Register reg =
masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Push the arguments on the JS stack of the caller.
__ pop(scratch2); // remove return address
__ push(receiver); // receiver
__ push(Immediate(Handle<AccessorInfo>(callback))); // callback data
__ push(name); // name
__ push(reg); // holder
__ push(scratch2); // restore return address
// Do tail-call to the runtime system.
ExternalReference load_callback_property =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallRuntime(load_callback_property, 4);
}
void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
Object* value,
Label* miss_label) {
// Check that the receiver isn't a smi.
__ test(receiver, Immediate(kSmiTagMask));
__ j(zero, miss_label, not_taken);
// Check that the maps haven't changed.
Register reg =
masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Return the constant value.
__ mov(eax, Handle<Object>(value));
__ ret(0);
}
void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
Smi* lookup_hint,
Register receiver,
Register name,
Register scratch1,
Register scratch2,
Label* miss_label) {
// Check that the receiver isn't a smi.
__ test(receiver, Immediate(kSmiTagMask));
__ j(zero, miss_label, not_taken);
// Check that the maps haven't changed.
Register reg =
masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
// Push the arguments on the JS stack of the caller.
__ pop(scratch2); // remove return address
__ push(receiver); // receiver
__ push(reg); // holder
__ push(name); // name
// TODO(367): Maybe don't push lookup_hint for LOOKUP_IN_HOLDER and/or
// LOOKUP_IN_PROTOTYPE, but use a special version of lookup method?
__ push(Immediate(lookup_hint));
__ push(scratch2); // restore return address
// Do tail-call to the runtime system.
ExternalReference load_ic_property =
ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
__ TailCallRuntime(load_ic_property, 4);
}
void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
......@@ -474,10 +366,159 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
#undef __
#define __ ACCESS_MASM(masm())
Register StubCompiler::CheckPrototypes(JSObject* object,
Register object_reg,
JSObject* holder,
Register holder_reg,
Register scratch,
String* name,
Label* miss) {
// Check that the maps haven't changed.
Register result =
masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
// If we've skipped any global objects, it's not enough to verify
// that their maps haven't changed.
while (object != holder) {
if (object->IsGlobalObject()) {
GlobalObject* global = GlobalObject::cast(object);
Object* probe = global->EnsurePropertyCell(name);
if (probe->IsFailure()) {
set_failure(Failure::cast(probe));
return result;
}
JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
ASSERT(cell->value()->IsTheHole());
__ mov(scratch, Immediate(Handle<Object>(cell)));
__ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
Immediate(Factory::the_hole_value()));
__ j(not_equal, miss, not_taken);
}
object = JSObject::cast(object->GetPrototype());
}
// Return the register containin the holder.
return result;
}
void StubCompiler::GenerateLoadField(JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
int index,
String* name,
Label* miss) {
// Check that the receiver isn't a smi.
__ test(receiver, Immediate(kSmiTagMask));
__ j(zero, miss, not_taken);
// Check the prototype chain.
Register reg =
CheckPrototypes(object, receiver, holder,
scratch1, scratch2, name, miss);
// Get the value from the properties.
GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
__ ret(0);
}
void StubCompiler::GenerateLoadCallback(JSObject* object,
JSObject* holder,
Register receiver,
Register name_reg,
Register scratch1,
Register scratch2,
AccessorInfo* callback,
String* name,
Label* miss) {
// Check that the receiver isn't a smi.
__ test(receiver, Immediate(kSmiTagMask));
__ j(zero, miss, not_taken);
// Check that the maps haven't changed.
Register reg =
CheckPrototypes(object, receiver, holder,
scratch1, scratch2, name, miss);
// Push the arguments on the JS stack of the caller.
__ pop(scratch2); // remove return address
__ push(receiver); // receiver
__ push(Immediate(Handle<AccessorInfo>(callback))); // callback data
__ push(name_reg); // name
__ push(reg); // holder
__ push(scratch2); // restore return address
// Do tail-call to the runtime system.
ExternalReference load_callback_property =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallRuntime(load_callback_property, 4);
}
void StubCompiler::GenerateLoadConstant(JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
Object* value,
String* name,
Label* miss) {
// Check that the receiver isn't a smi.
__ test(receiver, Immediate(kSmiTagMask));
__ j(zero, miss, not_taken);
// Check that the maps haven't changed.
Register reg =
CheckPrototypes(object, receiver, holder,
scratch1, scratch2, name, miss);
// Return the constant value.
__ mov(eax, Handle<Object>(value));
__ ret(0);
}
void StubCompiler::GenerateLoadInterceptor(JSObject* object,
JSObject* holder,
Smi* lookup_hint,
Register receiver,
Register name_reg,
Register scratch1,
Register scratch2,
String* name,
Label* miss) {
// Check that the receiver isn't a smi.
__ test(receiver, Immediate(kSmiTagMask));
__ j(zero, miss, not_taken);
// Check that the maps haven't changed.
Register reg =
CheckPrototypes(object, receiver, holder,
scratch1, scratch2, name, miss);
// Push the arguments on the JS stack of the caller.
__ pop(scratch2); // remove return address
__ push(receiver); // receiver
__ push(reg); // holder
__ push(name_reg); // name
// TODO(367): Maybe don't push lookup_hint for LOOKUP_IN_HOLDER and/or
// LOOKUP_IN_PROTOTYPE, but use a special version of lookup method?
__ push(Immediate(lookup_hint));
__ push(scratch2); // restore return address
// Do tail-call to the runtime system.
ExternalReference load_ic_property =
ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
__ TailCallRuntime(load_ic_property, 4);
}
// TODO(1241006): Avoid having lazy compile stubs specialized by the
// number of arguments. It is not needed anymore.
Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
......@@ -520,7 +561,8 @@ Object* CallStubCompiler::CompileCallField(Object* object,
// Do the right check and compute the holder register.
Register reg =
masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
CheckPrototypes(JSObject::cast(object), edx, holder,
ebx, ecx, name, &miss);
GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
......@@ -553,6 +595,7 @@ Object* CallStubCompiler::CompileCallField(Object* object,
Object* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
String* name,
CheckType check) {
// ----------- S t a t e -------------
// -----------------------------------
......@@ -575,7 +618,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
switch (check) {
case RECEIVER_MAP_CHECK:
// Check that the maps haven't changed.
__ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
CheckPrototypes(JSObject::cast(object), edx, holder,
ebx, ecx, name, &miss);
// Patch the receiver on the stack with the global proxy if
// necessary.
......@@ -595,8 +639,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
GenerateLoadGlobalFunctionPrototype(masm(),
Context::STRING_FUNCTION_INDEX,
ecx);
__ CheckMaps(JSObject::cast(object->GetPrototype()),
ecx, holder, ebx, edx, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
ebx, edx, name, &miss);
break;
case NUMBER_CHECK: {
......@@ -611,8 +655,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
GenerateLoadGlobalFunctionPrototype(masm(),
Context::NUMBER_FUNCTION_INDEX,
ecx);
__ CheckMaps(JSObject::cast(object->GetPrototype()),
ecx, holder, ebx, edx, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
ebx, edx, name, &miss);
break;
}
......@@ -628,13 +672,14 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
GenerateLoadGlobalFunctionPrototype(masm(),
Context::BOOLEAN_FUNCTION_INDEX,
ecx);
__ CheckMaps(JSObject::cast(object->GetPrototype()),
ecx, holder, ebx, edx, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
ebx, edx, name, &miss);
break;
}
case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
__ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
CheckPrototypes(JSObject::cast(object), edx, holder,
ebx, ecx, name, &miss);
// Make sure object->elements()->map() != Heap::dictionary_array_map()
// Get the elements array of the object.
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
......@@ -692,7 +737,8 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
// Check that maps have not changed and compute the holder register.
Register reg =
masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
CheckPrototypes(JSObject::cast(object), edx, holder,
ebx, ecx, name, &miss);
// Enter an internal frame.
__ EnterInternalFrame();
......@@ -771,7 +817,7 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
}
// Check that the maps haven't changed.
masm()->CheckMaps(object, edx, holder, ebx, ecx, &miss);
CheckPrototypes(object, edx, holder, ebx, ecx, name, &miss);
// Get the value from the cell.
__ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
......@@ -1033,6 +1079,7 @@ Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
}
Object* LoadStubCompiler::CompileLoadField(JSObject* object,
JSObject* holder,
int index,
......@@ -1045,7 +1092,7 @@ Object* LoadStubCompiler::CompileLoadField(JSObject* object,
Label miss;
__ mov(eax, (Operand(esp, kPointerSize)));
GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss);
GenerateLoadField(object, holder, eax, ebx, edx, index, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
......@@ -1066,8 +1113,8 @@ Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
Label miss;
__ mov(eax, (Operand(esp, kPointerSize)));
GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx,
edx, callback, &miss);
GenerateLoadCallback(object, holder, eax, ecx, ebx, edx,
callback, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
......@@ -1088,7 +1135,7 @@ Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
Label miss;
__ mov(eax, (Operand(esp, kPointerSize)));
GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss);
GenerateLoadConstant(object, holder, eax, ebx, edx, value, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
......@@ -1110,14 +1157,14 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
__ mov(eax, (Operand(esp, kPointerSize)));
// TODO(368): Compile in the whole chain: all the interceptors in
// prototypes and ultimate answer.
GenerateLoadInterceptor(masm(),
receiver,
GenerateLoadInterceptor(receiver,
holder,
holder->InterceptorPropertyLookupHint(name),
eax,
ecx,
edx,
ebx,
name,
&miss);
__ bind(&miss);
......@@ -1154,7 +1201,7 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
}
// Check that the maps haven't changed.
masm()->CheckMaps(object, eax, holder, ebx, edx, &miss);
CheckPrototypes(object, eax, holder, ebx, edx, name, &miss);
// Get the value from the cell.
__ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
......@@ -1200,7 +1247,8 @@ Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
__ j(not_equal, &miss, not_taken);
GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss);
GenerateLoadField(receiver, holder, ecx, ebx, edx, index, name, &miss);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_field, 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
......@@ -1229,8 +1277,8 @@ Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
__ j(not_equal, &miss, not_taken);
GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx,
callback, &miss);
GenerateLoadCallback(receiver, holder, ecx, eax, ebx, edx,
callback, name, &miss);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_callback, 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
......@@ -1259,7 +1307,8 @@ Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
__ j(not_equal, &miss, not_taken);
GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss);
GenerateLoadConstant(receiver, holder, ecx, ebx, edx,
value, name, &miss);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_constant_function, 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
......@@ -1287,14 +1336,14 @@ Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
__ j(not_equal, &miss, not_taken);
GenerateLoadInterceptor(masm(),
receiver,
GenerateLoadInterceptor(receiver,
holder,
Smi::FromInt(JSObject::kLookupInHolder),
ecx,
eax,
edx,
ebx,
name,
&miss);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_interceptor, 1);
......
......@@ -2653,7 +2653,7 @@ void Dictionary<Shape, Key>::SetEntry(int entry,
Object* key,
Object* value,
PropertyDetails details) {
ASSERT(!key->IsString() || details.index() > 0);
ASSERT(!key->IsString() || details.IsDeleted() || details.index() > 0);
int index = HashTable<Shape, Key>::EntryToIndex(entry);
WriteBarrierMode mode = FixedArray::GetWriteBarrierMode();
FixedArray::set(index, key, mode);
......
......@@ -436,8 +436,7 @@ Object* JSObject::SetNormalizedProperty(String* name,
store_value = Heap::AllocateJSGlobalPropertyCell(value);
if (store_value->IsFailure()) return store_value;
}
Object* dict =
property_dictionary()->Add(name, store_value, details);
Object* dict = property_dictionary()->Add(name, store_value, details);
if (dict->IsFailure()) return dict;
set_properties(StringDictionary::cast(dict));
return value;
......@@ -1712,30 +1711,24 @@ void JSObject::LocalLookupRealNamedProperty(String* name,
} else {
int entry = property_dictionary()->FindEntry(name);
if (entry != StringDictionary::kNotFound) {
// Make sure to disallow caching for uninitialized constants
// found in the dictionary-mode objects.
Object* value = property_dictionary()->ValueAt(entry);
if (IsGlobalObject()) {
PropertyDetails d = property_dictionary()->DetailsAt(entry);
if (d.IsDeleted()) {
// We've skipped a global object during lookup, so we cannot
// use inline caching because the map of the global object
// doesn't change if the property should be re-added.
result->DisallowCaching();
result->NotFound();
return;
}
value = JSGlobalPropertyCell::cast(value)->value();
ASSERT(result->IsLoaded());
}
if (value->IsTheHole()) {
result->DisallowCaching();
}
// Make sure to disallow caching for uninitialized constants
// found in the dictionary-mode objects.
if (value->IsTheHole()) result->DisallowCaching();
result->DictionaryResult(this, entry);
return;
}
// Slow case object skipped during lookup. Do not use inline caching.
result->DisallowCaching();
if (!IsGlobalObject()) result->DisallowCaching();
}
result->NotFound();
}
......@@ -6841,6 +6834,26 @@ Object* GlobalObject::GetPropertyCell(LookupResult* result) {
}
Object* GlobalObject::EnsurePropertyCell(String* name) {
ASSERT(!HasFastProperties());
int entry = property_dictionary()->FindEntry(name);
if (entry == StringDictionary::kNotFound) {
Object* cell = Heap::AllocateJSGlobalPropertyCell(Heap::the_hole_value());
if (cell->IsFailure()) return cell;
PropertyDetails details(NONE, NORMAL);
details = details.AsDeleted();
Object* dictionary = property_dictionary()->Add(name, cell, details);
if (dictionary->IsFailure()) return dictionary;
set_properties(StringDictionary::cast(dictionary));
return cell;
} else {
Object* value = property_dictionary()->ValueAt(entry);
ASSERT(value->IsJSGlobalPropertyCell());
return value;
}
}
Object* SymbolTable::LookupString(String* string, Object** s) {
SymbolKey key(string);
return LookupKey(&key, s);
......@@ -7200,7 +7213,7 @@ Object* Dictionary<Shape, Key>::AddEntry(Key key,
uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
// Insert element at empty or deleted entry
if (details.index() == 0 && Shape::kIsEnumerable) {
if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
// Assign an enumeration index to the property and update
// SetNextEnumerationIndex.
int index = NextEnumerationIndex();
......@@ -7273,7 +7286,9 @@ int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
for (int i = 0; i < capacity; i++) {
Object* k = HashTable<Shape, Key>::KeyAt(i);
if (HashTable<Shape, Key>::IsKey(k)) {
PropertyAttributes attr = DetailsAt(i).attributes();
PropertyDetails details = DetailsAt(i);
if (details.IsDeleted()) continue;
PropertyAttributes attr = details.attributes();
if ((attr & filter) == 0) result++;
}
}
......@@ -7297,7 +7312,9 @@ void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage,
for (int i = 0; i < capacity; i++) {
Object* k = HashTable<Shape, Key>::KeyAt(i);
if (HashTable<Shape, Key>::IsKey(k)) {
PropertyAttributes attr = DetailsAt(i).attributes();
PropertyDetails details = DetailsAt(i);
if (details.IsDeleted()) continue;
PropertyAttributes attr = details.attributes();
if ((attr & filter) == 0) storage->set(index++, k);
}
}
......@@ -7315,13 +7332,12 @@ void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
Object* k = KeyAt(i);
if (IsKey(k)) {
PropertyDetails details = DetailsAt(i);
if (!details.IsDontEnum()) {
storage->set(index, k);
sort_array->set(index,
Smi::FromInt(details.index()),
SKIP_WRITE_BARRIER);
index++;
}
if (details.IsDeleted() || details.IsDontEnum()) continue;
storage->set(index, k);
sort_array->set(index,
Smi::FromInt(details.index()),
SKIP_WRITE_BARRIER);
index++;
}
}
storage->SortPairs(sort_array, sort_array->length());
......@@ -7338,6 +7354,8 @@ void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage) {
for (int i = 0; i < capacity; i++) {
Object* k = HashTable<Shape, Key>::KeyAt(i);
if (HashTable<Shape, Key>::IsKey(k)) {
PropertyDetails details = DetailsAt(i);
if (details.IsDeleted()) continue;
storage->set(index++, k);
}
}
......
......@@ -3240,6 +3240,9 @@ class GlobalObject: public JSObject {
// Retrieve the property cell used to store a property.
Object* GetPropertyCell(LookupResult* result);
// Ensure that the global object has a cell for the given property name.
Object* EnsurePropertyCell(String* name);
// Casting.
static inline GlobalObject* cast(Object* obj);
......
......@@ -450,7 +450,7 @@ Object* StubCache::ComputeCallConstant(int argc,
if (!function->is_compiled()) return Failure::InternalError();
// Compile the stub - only create stubs for fully compiled functions.
CallStubCompiler compiler(argc, in_loop);
code = compiler.CompileCallConstant(object, holder, function, check);
code = compiler.CompileCallConstant(object, holder, function, name, check);
if (code->IsFailure()) return code;
ASSERT_EQ(flags, Code::cast(code)->flags());
LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
......@@ -957,6 +957,10 @@ Object* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, const char* name) {
// Check for allocation failures during stub compilation.
if (failure_->IsFailure()) return failure_;
// Create code object in the heap.
CodeDesc desc;
masm_.GetCode(&desc);
Object* result = Heap::CreateCode(desc, NULL, flags, masm_.CodeObject());
......
......@@ -324,7 +324,7 @@ class StubCompiler BASE_EMBEDDED {
JSARRAY_HAS_FAST_ELEMENTS_CHECK
};
StubCompiler() : scope_(), masm_(NULL, 256) { }
StubCompiler() : scope_(), masm_(NULL, 256), failure_(NULL) { }
Object* CompileCallInitialize(Code::Flags flags);
Object* CompileCallPreMonomorphic(Code::Flags flags);
......@@ -344,40 +344,7 @@ class StubCompiler BASE_EMBEDDED {
static void GenerateFastPropertyLoad(MacroAssembler* masm,
Register dst, Register src,
JSObject* holder, int index);
static void GenerateLoadField(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
int index,
Label* miss_label);
static void GenerateLoadCallback(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
Register receiver,
Register name,
Register scratch1,
Register scratch2,
AccessorInfo* callback,
Label* miss_label);
static void GenerateLoadConstant(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
Object* value,
Label* miss_label);
static void GenerateLoadInterceptor(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
Smi* lookup_hint,
Register receiver,
Register name,
Register scratch1,
Register scratch2,
Label* miss_label);
static void GenerateLoadArrayLength(MacroAssembler* masm,
Register receiver,
Register scratch,
......@@ -412,10 +379,60 @@ class StubCompiler BASE_EMBEDDED {
Object* GetCodeWithFlags(Code::Flags flags, String* name);
MacroAssembler* masm() { return &masm_; }
void set_failure(Failure* failure) { failure_ = failure; }
// Check the integrity of the prototype chain to make sure that the
// current IC is still valid.
Register CheckPrototypes(JSObject* object,
Register object_reg,
JSObject* holder,
Register holder_reg,
Register scratch,
String* name,
Label* miss);
void GenerateLoadField(JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
int index,
String* name,
Label* miss);
void GenerateLoadCallback(JSObject* object,
JSObject* holder,
Register receiver,
Register name_reg,
Register scratch1,
Register scratch2,
AccessorInfo* callback,
String* name,
Label* miss);
void GenerateLoadConstant(JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
Object* value,
String* name,
Label* miss);
void GenerateLoadInterceptor(JSObject* object,
JSObject* holder,
Smi* lookup_hint,
Register receiver,
Register name_reg,
Register scratch1,
Register scratch2,
String* name,
Label* miss);
private:
HandleScope scope_;
MacroAssembler masm_;
Failure* failure_;
};
......@@ -518,6 +535,7 @@ class CallStubCompiler: public StubCompiler {
Object* CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
String* name,
CheckType check);
Object* CompileCallInterceptor(Object* object,
JSObject* holder,
......
......@@ -42,7 +42,8 @@ namespace internal {
Object* CallStubCompiler::CompileCallConstant(Object* a,
JSObject* b,
JSFunction* c,
StubCompiler::CheckType d) {
String* d,
StubCompiler::CheckType e) {
UNIMPLEMENTED();
return NULL;
}
......
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