Index: src/x64/stub-cache-x64.cc |
=================================================================== |
--- src/x64/stub-cache-x64.cc (revision 4423) |
+++ src/x64/stub-cache-x64.cc (working copy) |
@@ -649,6 +649,26 @@ |
}; |
+// Generate code to check that a global property cell is empty. Create |
+// the property cell at compilation time if no cell exists for the |
+// property. |
+static Object* GenerateCheckPropertyCell(MacroAssembler* masm, |
+ GlobalObject* global, |
+ String* name, |
+ Register scratch, |
+ Label* miss) { |
+ Object* probe = global->EnsurePropertyCell(name); |
+ if (probe->IsFailure()) return probe; |
+ JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); |
+ ASSERT(cell->value()->IsTheHole()); |
+ __ Move(scratch, Handle<Object>(cell)); |
+ __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), |
+ Factory::the_hole_value()); |
+ __ j(not_equal, miss); |
+ return cell; |
+} |
+ |
+ |
#undef __ |
#define __ ACCESS_MASM((masm())) |
@@ -1144,6 +1164,48 @@ |
} |
+Object* LoadStubCompiler::CompileLoadNonexistent(String* name, |
+ JSObject* object, |
+ JSObject* last) { |
+ // ----------- S t a t e ------------- |
+ // -- rcx : name |
+ // -- rsp[0] : return address |
+ // -- rsp[8] : receiver |
+ // ----------------------------------- |
+ Label miss; |
+ |
+ // Load receiver. |
+ __ movq(rax, Operand(rsp, kPointerSize)); |
+ |
+ // Check the maps of the full prototype chain. Also check that |
+ // global property cells up to (but not including) the last object |
+ // in the prototype chain are empty. |
+ CheckPrototypes(object, rax, last, rbx, rdx, name, &miss); |
+ |
+ // If the last object in the prototype chain is a global object, |
+ // check that the global property cell is empty. |
+ if (last->IsGlobalObject()) { |
+ Object* cell = GenerateCheckPropertyCell(masm(), |
+ GlobalObject::cast(last), |
+ name, |
+ rdx, |
+ &miss); |
+ if (cell->IsFailure()) return cell; |
+ } |
+ |
+ // Return undefined if maps of the full prototype chain is still the |
+ // same and no global property with this name contains a value. |
+ __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
+ __ ret(0); |
+ |
+ __ bind(&miss); |
+ GenerateLoadMiss(masm(), Code::LOAD_IC); |
+ |
+ // Return the generated code. |
+ return GetCode(NONEXISTENT, Heap::empty_string()); |
+} |
+ |
+ |
Object* LoadStubCompiler::CompileLoadField(JSObject* object, |
JSObject* holder, |
int index, |
@@ -1765,21 +1827,19 @@ |
__ 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. |
+ // that their maps haven't changed. We also need to check that the |
+ // property cell for the property is still empty. |
while (object != holder) { |
if (object->IsGlobalObject()) { |
- GlobalObject* global = GlobalObject::cast(object); |
- Object* probe = global->EnsurePropertyCell(name); |
- if (probe->IsFailure()) { |
- set_failure(Failure::cast(probe)); |
+ Object* cell = GenerateCheckPropertyCell(masm(), |
+ GlobalObject::cast(object), |
+ name, |
+ scratch, |
+ miss); |
+ if (cell->IsFailure()) { |
+ set_failure(Failure::cast(cell)); |
return result; |
} |
- JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); |
- ASSERT(cell->value()->IsTheHole()); |
- __ Move(scratch, Handle<Object>(cell)); |
- __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), |
- Factory::the_hole_value()); |
- __ j(not_equal, miss); |
} |
object = JSObject::cast(object->GetPrototype()); |
} |