Remove the fcontext field from all contexts.

Before: every context cached the nearest enclosing function context.  This
assumed that for nested contexts (i.e., with and catch contexts) the
enclosing function had a materialized link in the context chain.

Now: when necessary, we loop up the context chain to find such a context.
This enables catch contexts without forcing the enclosing function to
allocate its own context.

R=ager@chromium.org
BUG=
TEST=

Review URL: http://codereview.chromium.org/7230047

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8452 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2011-06-28 15:22:08 +00:00
parent 2760bd2927
commit 5e7da7f04f
14 changed files with 91 additions and 136 deletions

View File

@ -165,7 +165,6 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
// Setup the fixed slots. // Setup the fixed slots.
__ mov(r1, Operand(Smi::FromInt(0))); __ mov(r1, Operand(Smi::FromInt(0)));
__ str(r3, MemOperand(r0, Context::SlotOffset(Context::CLOSURE_INDEX))); __ str(r3, MemOperand(r0, Context::SlotOffset(Context::CLOSURE_INDEX)));
__ str(r0, MemOperand(r0, Context::SlotOffset(Context::FCONTEXT_INDEX)));
__ str(cp, MemOperand(r0, Context::SlotOffset(Context::PREVIOUS_INDEX))); __ str(cp, MemOperand(r0, Context::SlotOffset(Context::PREVIOUS_INDEX)));
__ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX))); __ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX)));

View File

@ -713,10 +713,12 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
// context. // context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
if (FLAG_debug_code) { if (FLAG_debug_code) {
// Check that we're not inside a 'with'. // Check that we're not inside a with or catch context.
__ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX)); __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset));
__ cmp(r1, cp); __ CompareRoot(r1, Heap::kWithContextMapRootIndex);
__ Check(eq, "Unexpected declaration in current context."); __ Check(ne, "Declaration in with context.");
__ CompareRoot(r1, Heap::kCatchContextMapRootIndex);
__ Check(ne, "Declaration in catch context.");
} }
if (mode == Variable::CONST) { if (mode == Variable::CONST) {
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
@ -1867,18 +1869,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ b(ne, &skip); __ b(ne, &skip);
__ str(result_register(), MemOperand(fp, SlotOffset(slot))); __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
break; break;
case Slot::CONTEXT: { case Slot::CONTEXT:
__ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX));
__ ldr(r2, ContextOperand(r1, slot->index()));
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ cmp(r2, ip);
__ b(ne, &skip);
__ str(r0, ContextOperand(r1, slot->index()));
int offset = Context::SlotOffset(slot->index());
__ mov(r3, r0); // Preserve the stored value in r0.
__ RecordWrite(r1, Operand(offset), r3, r2);
break;
}
case Slot::LOOKUP: case Slot::LOOKUP:
__ push(r0); __ push(r0);
__ mov(r0, Operand(slot->var()->name())); __ mov(r0, Operand(slot->var()->name()));

View File

@ -2562,17 +2562,6 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
// cannot be allowed to destroy the context in esi). // cannot be allowed to destroy the context in esi).
mov(dst, cp); mov(dst, cp);
} }
// We should not have found a 'with' context by walking the context chain
// (i.e., the static scope chain and runtime context chain do not agree).
// A variable occurring in such a scope should have slot type LOOKUP and
// not CONTEXT.
if (emit_debug_code()) {
ldr(ip, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
cmp(dst, ip);
Check(eq, "Yo dawg, I heard you liked function contexts "
"so I put function contexts in all your contexts");
}
} }

View File

@ -814,7 +814,6 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
// --- G l o b a l C o n t e x t --- // --- G l o b a l C o n t e x t ---
// Use the empty function as closure (no scope info). // Use the empty function as closure (no scope info).
global_context()->set_closure(*empty_function); global_context()->set_closure(*empty_function);
global_context()->set_fcontext(*global_context());
global_context()->set_previous(NULL); global_context()->set_previous(NULL);
// Set extension and global object. // Set extension and global object.
global_context()->set_extension(*inner_global); global_context()->set_extension(*inner_global);

View File

@ -34,6 +34,16 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
Context* Context::declaration_context() {
Context* current = this;
while (!current->IsFunctionContext() && !current->IsGlobalContext()) {
current = current->previous();
ASSERT(current->closure() == closure());
}
return current;
}
JSBuiltinsObject* Context::builtins() { JSBuiltinsObject* Context::builtins() {
GlobalObject* object = global(); GlobalObject* object = global();
if (object->IsJSGlobalObject()) { if (object->IsJSGlobalObject()) {
@ -246,20 +256,22 @@ void Context::ComputeEvalScopeInfo(bool* outer_scope_calls_eval,
bool* outer_scope_calls_non_strict_eval) { bool* outer_scope_calls_non_strict_eval) {
// Skip up the context chain checking all the function contexts to see // Skip up the context chain checking all the function contexts to see
// whether they call eval. // whether they call eval.
Context* context = fcontext(); Context* context = this;
while (!context->IsGlobalContext()) { while (!context->IsGlobalContext()) {
Handle<SerializedScopeInfo> scope_info( if (context->IsFunctionContext()) {
context->closure()->shared()->scope_info()); Handle<SerializedScopeInfo> scope_info(
if (scope_info->CallsEval()) { context->closure()->shared()->scope_info());
*outer_scope_calls_eval = true; if (scope_info->CallsEval()) {
if (!scope_info->IsStrictMode()) { *outer_scope_calls_eval = true;
// No need to go further since the answers will not change if (!scope_info->IsStrictMode()) {
// from here. // No need to go further since the answers will not change from
*outer_scope_calls_non_strict_eval = true; // here.
return; *outer_scope_calls_non_strict_eval = true;
return;
}
} }
} }
context = context->previous()->fcontext(); context = context->previous();
} }
} }

View File

@ -130,13 +130,6 @@ enum ContextLookupFlags {
// statically allocated context slots. The names are needed // statically allocated context slots. The names are needed
// for dynamic lookups in the presence of 'with' or 'eval'. // for dynamic lookups in the presence of 'with' or 'eval'.
// //
// [ fcontext ] A pointer to the innermost enclosing function context.
// It is the same for all contexts *allocated* inside a
// function, and the function context's fcontext points
// to itself. It is only needed for fast access of the
// function context (used for declarations, and static
// context slot access).
//
// [ previous ] A pointer to the previous context. It is NULL for // [ previous ] A pointer to the previous context. It is NULL for
// function contexts, and non-NULL for 'with' contexts. // function contexts, and non-NULL for 'with' contexts.
// Used to implement the 'with' statement. // Used to implement the 'with' statement.
@ -158,16 +151,6 @@ enum ContextLookupFlags {
// (via static context addresses) or through 'eval' (dynamic context lookups). // (via static context addresses) or through 'eval' (dynamic context lookups).
// Finally, the global context contains additional slots for fast access to // Finally, the global context contains additional slots for fast access to
// global properties. // global properties.
//
// We may be able to simplify the implementation:
//
// - We may be able to get rid of 'fcontext': We can always use the fact that
// previous == NULL for function contexts and so we can search for them. They
// are only needed when doing dynamic declarations, and the context chains
// tend to be very very short (depth of nesting of 'with' statements). At
// the moment we also use it in generated code for context slot accesses -
// and there we don't want a loop because of code bloat - but we may not
// need it there after all (see comment in codegen_*.cc).
class Context: public FixedArray { class Context: public FixedArray {
public: public:
@ -181,7 +164,6 @@ class Context: public FixedArray {
enum { enum {
// These slots are in all contexts. // These slots are in all contexts.
CLOSURE_INDEX, CLOSURE_INDEX,
FCONTEXT_INDEX,
PREVIOUS_INDEX, PREVIOUS_INDEX,
// The extension slot is used for either the global object (in global // The extension slot is used for either the global object (in global
// contexts), eval extension object (function contexts), subject of with // contexts), eval extension object (function contexts), subject of with
@ -264,9 +246,6 @@ class Context: public FixedArray {
JSFunction* closure() { return JSFunction::cast(get(CLOSURE_INDEX)); } JSFunction* closure() { return JSFunction::cast(get(CLOSURE_INDEX)); }
void set_closure(JSFunction* closure) { set(CLOSURE_INDEX, closure); } void set_closure(JSFunction* closure) { set(CLOSURE_INDEX, closure); }
Context* fcontext() { return Context::cast(get(FCONTEXT_INDEX)); }
void set_fcontext(Context* context) { set(FCONTEXT_INDEX, context); }
Context* previous() { Context* previous() {
Object* result = unchecked_previous(); Object* result = unchecked_previous();
ASSERT(IsBootstrappingOrContext(result)); ASSERT(IsBootstrappingOrContext(result));
@ -278,6 +257,10 @@ class Context: public FixedArray {
Object* extension() { return get(EXTENSION_INDEX); } Object* extension() { return get(EXTENSION_INDEX); }
void set_extension(Object* object) { set(EXTENSION_INDEX, object); } void set_extension(Object* object) { set(EXTENSION_INDEX, object); }
// Get the context where var declarations will be hoisted to, which
// may be the context itself.
Context* declaration_context();
GlobalObject* global() { GlobalObject* global() {
Object* result = get(GLOBAL_INDEX); Object* result = get(GLOBAL_INDEX);
ASSERT(IsBootstrappingOrGlobalObject(result)); ASSERT(IsBootstrappingOrGlobalObject(result));

View File

@ -3932,7 +3932,6 @@ MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
Context* context = reinterpret_cast<Context*>(result); Context* context = reinterpret_cast<Context*>(result);
context->set_map(function_context_map()); context->set_map(function_context_map());
context->set_closure(function); context->set_closure(function);
context->set_fcontext(context);
context->set_previous(function->context()); context->set_previous(function->context());
context->set_extension(NULL); context->set_extension(NULL);
context->set_global(function->context()->global()); context->set_global(function->context()->global());
@ -3952,7 +3951,6 @@ MaybeObject* Heap::AllocateCatchContext(Context* previous,
Context* context = reinterpret_cast<Context*>(result); Context* context = reinterpret_cast<Context*>(result);
context->set_map(catch_context_map()); context->set_map(catch_context_map());
context->set_closure(previous->closure()); context->set_closure(previous->closure());
context->set_fcontext(previous->fcontext());
context->set_previous(previous); context->set_previous(previous);
context->set_extension(name); context->set_extension(name);
context->set_global(previous->global()); context->set_global(previous->global());
@ -3970,7 +3968,6 @@ MaybeObject* Heap::AllocateWithContext(Context* previous,
Context* context = reinterpret_cast<Context*>(result); Context* context = reinterpret_cast<Context*>(result);
context->set_map(with_context_map()); context->set_map(with_context_map());
context->set_closure(previous->closure()); context->set_closure(previous->closure());
context->set_fcontext(previous->fcontext());
context->set_previous(previous); context->set_previous(previous);
context->set_extension(extension); context->set_extension(extension);
context->set_global(previous->global()); context->set_global(previous->global());

View File

@ -136,7 +136,6 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
// Setup the fixed slots. // Setup the fixed slots.
__ Set(ebx, Immediate(0)); // Set to NULL. __ Set(ebx, Immediate(0)); // Set to NULL.
__ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx); __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx);
__ mov(Operand(eax, Context::SlotOffset(Context::FCONTEXT_INDEX)), eax);
__ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), esi); __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), esi);
__ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx); __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx);

View File

@ -687,10 +687,12 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
// context. // context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
if (FLAG_debug_code) { if (FLAG_debug_code) {
// Check that we're not inside a 'with'. // Check that we're not inside a with or catch context.
__ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX)); __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
__ cmp(ebx, Operand(esi)); __ cmp(ebx, isolate()->factory()->with_context_map());
__ Check(equal, "Unexpected declaration in current context."); __ Check(not_equal, "Declaration in with context.");
__ cmp(ebx, isolate()->factory()->catch_context_map());
__ Check(not_equal, "Declaration in catch context.");
} }
if (mode == Variable::CONST) { if (mode == Variable::CONST) {
__ mov(ContextOperand(esi, slot->index()), __ mov(ContextOperand(esi, slot->index()),
@ -1818,17 +1820,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ j(not_equal, &skip); __ j(not_equal, &skip);
__ mov(Operand(ebp, SlotOffset(slot)), eax); __ mov(Operand(ebp, SlotOffset(slot)), eax);
break; break;
case Slot::CONTEXT: { case Slot::CONTEXT:
__ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX));
__ mov(edx, ContextOperand(ecx, slot->index()));
__ cmp(edx, isolate()->factory()->the_hole_value());
__ j(not_equal, &skip);
__ mov(ContextOperand(ecx, slot->index()), eax);
int offset = Context::SlotOffset(slot->index());
__ mov(edx, eax); // Preserve the stored value in eax.
__ RecordWrite(ecx, offset, edx, ebx);
break;
}
case Slot::LOOKUP: case Slot::LOOKUP:
__ push(eax); __ push(eax);
__ push(esi); __ push(esi);

View File

@ -1766,14 +1766,17 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
mov(dst, esi); mov(dst, esi);
} }
// We should not have found a 'with' context by walking the context chain // We should not have found a with or catch context by walking the context
// (i.e., the static scope chain and runtime context chain do not agree). // chain (i.e., the static scope chain and runtime context chain do not
// A variable occurring in such a scope should have slot type LOOKUP and // agree). A variable occurring in such a scope should have slot type
// not CONTEXT. // LOOKUP and not CONTEXT.
if (emit_debug_code()) { if (emit_debug_code()) {
cmp(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); cmp(FieldOperand(dst, HeapObject::kMapOffset),
Check(equal, "Yo dawg, I heard you liked function contexts " isolate()->factory()->with_context_map());
"so I put function contexts in all your contexts"); Check(not_equal, "Variable resolved to with context.");
cmp(FieldOperand(dst, HeapObject::kMapOffset),
isolate()->factory()->with_context_map());
Check(not_equal, "Variable resolved to catch context.");
} }
} }

View File

@ -1236,9 +1236,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE); RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
Handle<Object> initial_value(args[3], isolate); Handle<Object> initial_value(args[3], isolate);
// Declarations are always done in the function context. // Declarations are always done in a function or global context.
context = Handle<Context>(context->fcontext()); context = Handle<Context>(context->declaration_context());
ASSERT(context->IsFunctionContext() || context->IsGlobalContext());
int index; int index;
PropertyAttributes attributes; PropertyAttributes attributes;
@ -1525,8 +1524,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
CONVERT_ARG_CHECKED(Context, context, 1); CONVERT_ARG_CHECKED(Context, context, 1);
Handle<String> name(String::cast(args[2])); Handle<String> name(String::cast(args[2]));
// Initializations are always done in the function context. // Initializations are always done in a function or global context.
context = Handle<Context>(context->fcontext()); context = Handle<Context>(context->declaration_context());
int index; int index;
PropertyAttributes attributes; PropertyAttributes attributes;
@ -1547,14 +1546,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
// In that case, the initialization behaves like a normal assignment // In that case, the initialization behaves like a normal assignment
// to property 'x'. // to property 'x'.
if (index >= 0) { if (index >= 0) {
// Property was found in a context.
if (holder->IsContext()) { if (holder->IsContext()) {
// The holder cannot be the function context. If it is, there // Property was found in a context. Perform the assignment if we
// should have been a const redeclaration error when declaring // found some non-constant or an uninitialized constant.
// the const property. Handle<Context> context = Handle<Context>::cast(holder);
ASSERT(!holder.is_identical_to(context)); if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
if ((attributes & READ_ONLY) == 0) { context->set(index, *value);
Handle<Context>::cast(holder)->set(index, *value);
} }
} else { } else {
// The holder is an arguments object. // The holder is an arguments object.
@ -9986,9 +9983,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info()); Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ScopeInfo<> info(*scope_info); ScopeInfo<> info(*scope_info);
// Get the nearest enclosing function context.
Handle<Context> context(Context::cast(it.frame()->context())->fcontext());
// Get the locals names and values into a temporary array. // Get the locals names and values into a temporary array.
// //
// TODO(1240907): Hide compiler-introduced stack variables // TODO(1240907): Hide compiler-introduced stack variables
@ -9997,11 +9991,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
Handle<FixedArray> locals = Handle<FixedArray> locals =
isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2); isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
// Fill in the names of the locals.
for (int i = 0; i < info.NumberOfLocals(); i++) {
locals->set(i * 2, *info.LocalName(i));
}
// Fill in the values of the locals. // Fill in the values of the locals.
if (is_optimized_frame) { if (is_optimized_frame) {
// If we are inspecting an optimized frame use undefined as the // If we are inspecting an optimized frame use undefined as the
@ -10010,15 +9999,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
// TODO(1140): We should be able to get the correct values // TODO(1140): We should be able to get the correct values
// for locals in optimized frames. // for locals in optimized frames.
for (int i = 0; i < info.NumberOfLocals(); i++) { for (int i = 0; i < info.NumberOfLocals(); i++) {
locals->set(i * 2, *info.LocalName(i));
locals->set(i * 2 + 1, isolate->heap()->undefined_value()); locals->set(i * 2 + 1, isolate->heap()->undefined_value());
} }
} else { } else {
for (int i = 0; i < info.number_of_stack_slots(); i++) { int i = 0;
// Get the value from the stack. for (; i < info.number_of_stack_slots(); ++i) {
// Use the value from the stack.
locals->set(i * 2, *info.LocalName(i));
locals->set(i * 2 + 1, it.frame()->GetExpression(i)); locals->set(i * 2 + 1, it.frame()->GetExpression(i));
} }
for (int i = info.number_of_stack_slots(); i < info.NumberOfLocals(); i++) { // Get the context containing declarations.
Handle<Context> context(
Context::cast(it.frame()->context())->declaration_context());
for (; i < info.NumberOfLocals(); ++i) {
Handle<String> name = info.LocalName(i); Handle<String> name = info.LocalName(i);
locals->set(i * 2, *name);
locals->set(i * 2 + 1, locals->set(i * 2 + 1,
context->get(scope_info->ContextSlotIndex(*name, NULL))); context->get(scope_info->ContextSlotIndex(*name, NULL)));
} }
@ -10239,7 +10235,7 @@ static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
// Third fill all context locals. // Third fill all context locals.
Handle<Context> frame_context(Context::cast(frame->context())); Handle<Context> frame_context(Context::cast(frame->context()));
Handle<Context> function_context(frame_context->fcontext()); Handle<Context> function_context(frame_context->declaration_context());
if (!CopyContextLocalsToScopeObject(isolate, if (!CopyContextLocalsToScopeObject(isolate,
serialized_scope_info, scope_info, serialized_scope_info, scope_info,
function_context, local_scope)) { function_context, local_scope)) {
@ -11121,7 +11117,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
context->set_extension(*local_scope); context->set_extension(*local_scope);
// Copy any with contexts present and chain them in front of this context. // Copy any with contexts present and chain them in front of this context.
Handle<Context> frame_context(Context::cast(frame->context())); Handle<Context> frame_context(Context::cast(frame->context()));
Handle<Context> function_context(frame_context->fcontext()); Handle<Context> function_context(frame_context->declaration_context());
context = CopyWithContextChain(isolate, frame_context, context); context = CopyWithContextChain(isolate, frame_context, context);
if (additional_context->IsJSObject()) { if (additional_context->IsJSObject()) {

View File

@ -132,7 +132,6 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
// Setup the fixed slots. // Setup the fixed slots.
__ Set(rbx, 0); // Set to NULL. __ Set(rbx, 0); // Set to NULL.
__ movq(Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)), rcx); __ movq(Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)), rcx);
__ movq(Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX)), rax);
__ movq(Operand(rax, Context::SlotOffset(Context::PREVIOUS_INDEX)), rsi); __ movq(Operand(rax, Context::SlotOffset(Context::PREVIOUS_INDEX)), rsi);
__ movq(Operand(rax, Context::SlotOffset(Context::EXTENSION_INDEX)), rbx); __ movq(Operand(rax, Context::SlotOffset(Context::EXTENSION_INDEX)), rbx);

View File

@ -680,13 +680,16 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
// We bypass the general EmitSlotSearch because we know more about // We bypass the general EmitSlotSearch because we know more about
// this specific context. // this specific context.
// The variable in the decl always resides in the current context. // The variable in the decl always resides in the current function
// context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
if (FLAG_debug_code) { if (FLAG_debug_code) {
// Check if we have the correct context pointer. // Check that we're not inside a with or catch context.
__ movq(rbx, ContextOperand(rsi, Context::FCONTEXT_INDEX)); __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
__ cmpq(rbx, rsi); __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
__ Check(equal, "Unexpected declaration in current context."); __ Check(not_equal, "Declaration in with context.");
__ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
__ Check(not_equal, "Declaration in catch context.");
} }
if (mode == Variable::CONST) { if (mode == Variable::CONST) {
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
@ -1778,17 +1781,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ j(not_equal, &skip); __ j(not_equal, &skip);
__ movq(Operand(rbp, SlotOffset(slot)), rax); __ movq(Operand(rbp, SlotOffset(slot)), rax);
break; break;
case Slot::CONTEXT: { case Slot::CONTEXT:
__ movq(rcx, ContextOperand(rsi, Context::FCONTEXT_INDEX));
__ movq(rdx, ContextOperand(rcx, slot->index()));
__ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
__ j(not_equal, &skip);
__ movq(ContextOperand(rcx, slot->index()), rax);
int offset = Context::SlotOffset(slot->index());
__ movq(rdx, rax); // Preserve the stored value in eax.
__ RecordWrite(rcx, offset, rdx, rbx);
break;
}
case Slot::LOOKUP: case Slot::LOOKUP:
__ push(rax); __ push(rax);
__ push(rsi); __ push(rsi);

View File

@ -3628,14 +3628,17 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
movq(dst, rsi); movq(dst, rsi);
} }
// We should not have found a 'with' context by walking the context chain // We should not have found a with or catch context by walking the context
// (i.e., the static scope chain and runtime context chain do not agree). // chain (i.e., the static scope chain and runtime context chain do not
// A variable occurring in such a scope should have slot type LOOKUP and // agree). A variable occurring in such a scope should have slot type
// not CONTEXT. // LOOKUP and not CONTEXT.
if (emit_debug_code()) { if (emit_debug_code()) {
cmpq(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); CompareRoot(FieldOperand(dst, HeapObject::kMapOffset),
Check(equal, "Yo dawg, I heard you liked function contexts " Heap::kWithContextMapRootIndex);
"so I put function contexts in all your contexts"); Check(not_equal, "Variable resolved to with context.");
CompareRoot(FieldOperand(dst, HeapObject::kMapOffset),
Heap::kCatchContextMapRootIndex);
Check(not_equal, "Variable resolved to catch context.");
} }
} }