| Index: src/ia32/full-codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/full-codegen-ia32.cc (revision 5429)
|
| +++ src/ia32/full-codegen-ia32.cc (working copy)
|
| @@ -514,7 +514,7 @@
|
| int context_chain_length =
|
| scope()->ContextChainLength(slot->var()->scope());
|
| __ LoadContext(scratch, context_chain_length);
|
| - return CodeGenerator::ContextOperand(scratch, slot->index());
|
| + return ContextOperand(scratch, slot->index());
|
| }
|
| case Slot::LOOKUP:
|
| UNREACHABLE();
|
| @@ -574,19 +574,17 @@
|
| ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
|
| if (FLAG_debug_code) {
|
| // Check if we have the correct context pointer.
|
| - __ mov(ebx,
|
| - CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX));
|
| + __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX));
|
| __ cmp(ebx, Operand(esi));
|
| __ Check(equal, "Unexpected declaration in current context.");
|
| }
|
| if (mode == Variable::CONST) {
|
| - __ mov(CodeGenerator::ContextOperand(esi, slot->index()),
|
| + __ mov(ContextOperand(esi, slot->index()),
|
| Immediate(Factory::the_hole_value()));
|
| // No write barrier since the hole value is in old space.
|
| } else if (function != NULL) {
|
| VisitForValue(function, kAccumulator);
|
| - __ mov(CodeGenerator::ContextOperand(esi, slot->index()),
|
| - result_register());
|
| + __ mov(ContextOperand(esi, slot->index()), result_register());
|
| int offset = Context::SlotOffset(slot->index());
|
| __ mov(ebx, esi);
|
| __ RecordWrite(ebx, offset, result_register(), ecx);
|
| @@ -885,6 +883,70 @@
|
| }
|
|
|
|
|
| +void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
|
| + Slot* slot,
|
| + TypeofState typeof_state,
|
| + Label* slow) {
|
| + Register context = esi;
|
| + Register temp = edx;
|
| +
|
| + Scope* s = scope();
|
| + while (s != NULL) {
|
| + if (s->num_heap_slots() > 0) {
|
| + if (s->calls_eval()) {
|
| + // Check that extension is NULL.
|
| + __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
|
| + Immediate(0));
|
| + __ j(not_equal, slow);
|
| + }
|
| + // Load next context in chain.
|
| + __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
|
| + __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
|
| + // Walk the rest of the chain using a single register without
|
| + // clobbering esi.
|
| + context = temp;
|
| + }
|
| + // If no outer scope calls eval, we do not need to check more
|
| + // context extensions. If we have reached an eval scope, we check
|
| + // all extensions from this point.
|
| + if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
|
| + s = s->outer_scope();
|
| + }
|
| +
|
| + if (s != NULL && s->is_eval_scope()) {
|
| + // Loop up the context chain. There is no frame effect so it is
|
| + // safe to use raw labels here.
|
| + Label next, fast;
|
| + if (!context.is(temp)) {
|
| + __ mov(temp, context);
|
| + }
|
| + __ bind(&next);
|
| + // Terminate at global context.
|
| + __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
|
| + Immediate(Factory::global_context_map()));
|
| + __ j(equal, &fast);
|
| + // Check that extension is NULL.
|
| + __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
|
| + __ j(not_equal, slow);
|
| + // Load next context in chain.
|
| + __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX));
|
| + __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
|
| + __ jmp(&next);
|
| + __ bind(&fast);
|
| + }
|
| +
|
| + // All extension objects were empty and it is safe to use a global
|
| + // load IC call.
|
| + __ mov(eax, CodeGenerator::GlobalObject());
|
| + __ mov(ecx, slot->var()->name());
|
| + Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
| + RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
|
| + ? RelocInfo::CODE_TARGET
|
| + : RelocInfo::CODE_TARGET_CONTEXT;
|
| + __ call(ic, mode);
|
| +}
|
| +
|
| +
|
| void FullCodeGenerator::EmitVariableLoad(Variable* var,
|
| Expression::Context context) {
|
| // Four cases: non-this global variables, lookup slots, all other
|
| @@ -909,11 +971,26 @@
|
| Apply(context, eax);
|
|
|
| } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
|
| + Label done, slow;
|
| +
|
| + // Generate fast-case code for variables that might be shadowed by
|
| + // eval-introduced variables. Eval is used a lot without
|
| + // introducing variables. In those cases, we do not want to
|
| + // perform a runtime call for all variables in the scope
|
| + // containing the eval.
|
| + if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
|
| + EmitLoadGlobalSlotCheckExtensions(slot, NOT_INSIDE_TYPEOF, &slow);
|
| + Apply(context, eax);
|
| + __ jmp(&done);
|
| + }
|
| +
|
| + __ bind(&slow);
|
| Comment cmnt(masm_, "Lookup slot");
|
| __ push(esi); // Context.
|
| __ push(Immediate(var->name()));
|
| __ CallRuntime(Runtime::kLoadContextSlot, 2);
|
| Apply(context, eax);
|
| + __ bind(&done);
|
|
|
| } else if (slot != NULL) {
|
| Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
|
| @@ -2781,13 +2858,11 @@
|
| Register key = eax;
|
| Register cache = ebx;
|
| Register tmp = ecx;
|
| - __ mov(cache, CodeGenerator::ContextOperand(esi, Context::GLOBAL_INDEX));
|
| + __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX));
|
| __ mov(cache,
|
| FieldOperand(cache, GlobalObject::kGlobalContextOffset));
|
| + __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
|
| __ mov(cache,
|
| - CodeGenerator::ContextOperand(
|
| - cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
|
| - __ mov(cache,
|
| FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
|
|
|
| Label done, not_found;
|
| @@ -3512,7 +3587,7 @@
|
|
|
|
|
| void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
|
| - __ mov(dst, CodeGenerator::ContextOperand(esi, context_index));
|
| + __ mov(dst, ContextOperand(esi, context_index));
|
| }
|
|
|
|
|
|
|