| Index: src/ia32/stub-cache-ia32.cc
|
| ===================================================================
|
| --- src/ia32/stub-cache-ia32.cc (revision 4423)
|
| +++ src/ia32/stub-cache-ia32.cc (working copy)
|
| @@ -950,6 +950,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());
|
| + __ mov(scratch, Immediate(Handle<Object>(cell)));
|
| + __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
|
| + Immediate(Factory::the_hole_value()));
|
| + __ j(not_equal, miss, not_taken);
|
| + return cell;
|
| +}
|
| +
|
| +
|
| #undef __
|
| #define __ ACCESS_MASM(masm())
|
|
|
| @@ -968,21 +988,19 @@
|
| push_at_depth, 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());
|
| - __ 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());
|
| }
|
| @@ -1948,7 +1966,45 @@
|
| }
|
|
|
|
|
| +Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
|
| + JSObject* object,
|
| + JSObject* last) {
|
| + // ----------- S t a t e -------------
|
| + // -- eax : receiver
|
| + // -- ecx : name
|
| + // -- esp[0] : return address
|
| + // -----------------------------------
|
| + Label miss;
|
|
|
| + // 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, eax, last, ebx, edx, 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,
|
| + edx,
|
| + &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.
|
| + __ mov(eax, Factory::undefined_value());
|
| + __ 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,
|
|
|