Explicitly pass the closure when allocating a catch or with context.
Before: allocation of a catch or with context fetched the closure to store in the context from the previous context in the context chain. Now: the closure is passed explicitly. R=ager@chromium.org BUG= TEST= Review URL: http://codereview.chromium.org/7275022 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8453 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
5e7da7f04f
commit
96bbcaf416
@ -4262,6 +4262,26 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
|
||||
if (scope()->is_global_scope()) {
|
||||
// Contexts nested in the global context have a canonical empty function
|
||||
// as their closure, not the anonymous closure containing the global
|
||||
// code. Pass a smi sentinel and let the runtime look up the empty
|
||||
// function.
|
||||
__ mov(ip, Operand(Smi::FromInt(0)));
|
||||
} else if (scope()->is_eval_scope()) {
|
||||
// Contexts created by a call to eval have the same closure as the
|
||||
// context calling eval, not the anonymous closure containing the eval
|
||||
// code. Fetch it from the context.
|
||||
__ ldr(ip, ContextOperand(cp, Context::CLOSURE_INDEX));
|
||||
} else {
|
||||
ASSERT(scope()->is_function_scope());
|
||||
__ ldr(ip, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
}
|
||||
__ push(ip);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Non-local control flow support.
|
||||
|
||||
|
@ -251,29 +251,34 @@ Handle<Context> Factory::NewGlobalContext() {
|
||||
|
||||
|
||||
Handle<Context> Factory::NewFunctionContext(int length,
|
||||
Handle<JSFunction> closure) {
|
||||
Handle<JSFunction> function) {
|
||||
CALL_HEAP_FUNCTION(
|
||||
isolate(),
|
||||
isolate()->heap()->AllocateFunctionContext(length, *closure),
|
||||
isolate()->heap()->AllocateFunctionContext(length, *function),
|
||||
Context);
|
||||
}
|
||||
|
||||
|
||||
Handle<Context> Factory::NewCatchContext(Handle<Context> previous,
|
||||
Handle<Context> Factory::NewCatchContext(Handle<JSFunction> function,
|
||||
Handle<Context> previous,
|
||||
Handle<String> name,
|
||||
Handle<Object> thrown_object) {
|
||||
CALL_HEAP_FUNCTION(
|
||||
isolate(),
|
||||
isolate()->heap()->AllocateCatchContext(*previous, *name, *thrown_object),
|
||||
isolate()->heap()->AllocateCatchContext(*function,
|
||||
*previous,
|
||||
*name,
|
||||
*thrown_object),
|
||||
Context);
|
||||
}
|
||||
|
||||
|
||||
Handle<Context> Factory::NewWithContext(Handle<Context> previous,
|
||||
Handle<Context> Factory::NewWithContext(Handle<JSFunction> function,
|
||||
Handle<Context> previous,
|
||||
Handle<JSObject> extension) {
|
||||
CALL_HEAP_FUNCTION(
|
||||
isolate(),
|
||||
isolate()->heap()->AllocateWithContext(*previous, *extension),
|
||||
isolate()->heap()->AllocateWithContext(*function, *previous, *extension),
|
||||
Context);
|
||||
}
|
||||
|
||||
|
@ -152,15 +152,17 @@ class Factory {
|
||||
|
||||
// Create a function context.
|
||||
Handle<Context> NewFunctionContext(int length,
|
||||
Handle<JSFunction> closure);
|
||||
Handle<JSFunction> function);
|
||||
|
||||
// Create a catch context.
|
||||
Handle<Context> NewCatchContext(Handle<Context> previous,
|
||||
Handle<Context> NewCatchContext(Handle<JSFunction> function,
|
||||
Handle<Context> previous,
|
||||
Handle<String> name,
|
||||
Handle<Object> thrown_object);
|
||||
|
||||
// Create a 'with' context.
|
||||
Handle<Context> NewWithContext(Handle<Context> previous,
|
||||
Handle<Context> NewWithContext(Handle<JSFunction> function,
|
||||
Handle<Context> previous,
|
||||
Handle<JSObject> extension);
|
||||
|
||||
// Return the Symbol matching the passed in string.
|
||||
|
@ -956,7 +956,8 @@ void FullCodeGenerator::VisitEnterWithContextStatement(
|
||||
SetStatementPosition(stmt);
|
||||
|
||||
VisitForStackValue(stmt->expression());
|
||||
__ CallRuntime(Runtime::kPushWithContext, 1);
|
||||
PushFunctionArgumentForContextAllocation();
|
||||
__ CallRuntime(Runtime::kPushWithContext, 2);
|
||||
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
|
||||
}
|
||||
|
||||
@ -1107,7 +1108,8 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
|
||||
{ Comment cmnt(masm_, "[ Extend catch context");
|
||||
__ Push(stmt->name());
|
||||
__ push(result_register());
|
||||
__ CallRuntime(Runtime::kPushCatchContext, 2);
|
||||
PushFunctionArgumentForContextAllocation();
|
||||
__ CallRuntime(Runtime::kPushCatchContext, 3);
|
||||
StoreToFrameField(StandardFrameConstants::kContextOffset,
|
||||
context_register());
|
||||
}
|
||||
|
@ -556,6 +556,10 @@ class FullCodeGenerator: public AstVisitor {
|
||||
// in v8::internal::Context.
|
||||
void LoadContextField(Register dst, int context_index);
|
||||
|
||||
// Push the function argument for the runtime functions PushWithContext
|
||||
// and PushCatchContext.
|
||||
void PushFunctionArgumentForContextAllocation();
|
||||
|
||||
// AST node visit functions.
|
||||
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
|
||||
AST_NODE_LIST(DECLARE_VISIT)
|
||||
|
10
src/heap.cc
10
src/heap.cc
@ -3939,7 +3939,8 @@ MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Heap::AllocateCatchContext(Context* previous,
|
||||
MaybeObject* Heap::AllocateCatchContext(JSFunction* function,
|
||||
Context* previous,
|
||||
String* name,
|
||||
Object* thrown_object) {
|
||||
STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX);
|
||||
@ -3950,7 +3951,7 @@ MaybeObject* Heap::AllocateCatchContext(Context* previous,
|
||||
}
|
||||
Context* context = reinterpret_cast<Context*>(result);
|
||||
context->set_map(catch_context_map());
|
||||
context->set_closure(previous->closure());
|
||||
context->set_closure(function);
|
||||
context->set_previous(previous);
|
||||
context->set_extension(name);
|
||||
context->set_global(previous->global());
|
||||
@ -3959,7 +3960,8 @@ MaybeObject* Heap::AllocateCatchContext(Context* previous,
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Heap::AllocateWithContext(Context* previous,
|
||||
MaybeObject* Heap::AllocateWithContext(JSFunction* function,
|
||||
Context* previous,
|
||||
JSObject* extension) {
|
||||
Object* result;
|
||||
{ MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
|
||||
@ -3967,7 +3969,7 @@ MaybeObject* Heap::AllocateWithContext(Context* previous,
|
||||
}
|
||||
Context* context = reinterpret_cast<Context*>(result);
|
||||
context->set_map(with_context_map());
|
||||
context->set_closure(previous->closure());
|
||||
context->set_closure(function);
|
||||
context->set_previous(previous);
|
||||
context->set_extension(extension);
|
||||
context->set_global(previous->global());
|
||||
|
@ -647,14 +647,16 @@ class Heap {
|
||||
|
||||
// Allocate a function context.
|
||||
MUST_USE_RESULT MaybeObject* AllocateFunctionContext(int length,
|
||||
JSFunction* closure);
|
||||
JSFunction* function);
|
||||
|
||||
// Allocate a catch context.
|
||||
MUST_USE_RESULT MaybeObject* AllocateCatchContext(Context* previous,
|
||||
MUST_USE_RESULT MaybeObject* AllocateCatchContext(JSFunction* function,
|
||||
Context* previous,
|
||||
String* name,
|
||||
Object* thrown_object);
|
||||
// Allocate a 'with' context.
|
||||
MUST_USE_RESULT MaybeObject* AllocateWithContext(Context* previous,
|
||||
MUST_USE_RESULT MaybeObject* AllocateWithContext(JSFunction* function,
|
||||
Context* previous,
|
||||
JSObject* extension);
|
||||
|
||||
// Allocates a new utility object in the old generation.
|
||||
|
@ -4211,6 +4211,25 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
|
||||
if (scope()->is_global_scope()) {
|
||||
// Contexts nested in the global context have a canonical empty function
|
||||
// as their closure, not the anonymous closure containing the global
|
||||
// code. Pass a smi sentinel and let the runtime look up the empty
|
||||
// function.
|
||||
__ push(Immediate(Smi::FromInt(0)));
|
||||
} else if (scope()->is_eval_scope()) {
|
||||
// Contexts created by a call to eval have the same closure as the
|
||||
// context calling eval, not the anonymous closure containing the eval
|
||||
// code. Fetch it from the context.
|
||||
__ push(ContextOperand(esi, Context::CLOSURE_INDEX));
|
||||
} else {
|
||||
ASSERT(scope()->is_function_scope());
|
||||
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Non-local control flow support.
|
||||
|
||||
|
@ -8049,7 +8049,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
ASSERT(args.length() == 2);
|
||||
JSObject* extension_object;
|
||||
if (args[0]->IsJSObject()) {
|
||||
extension_object = JSObject::cast(args[0]);
|
||||
@ -8070,9 +8070,20 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
|
||||
}
|
||||
}
|
||||
|
||||
JSFunction* function;
|
||||
if (args[1]->IsSmi()) {
|
||||
// A smi sentinel indicates a context nested inside global code rather
|
||||
// than some function. There is a canonical empty function that can be
|
||||
// gotten from the global context.
|
||||
function = isolate->context()->global_context()->closure();
|
||||
} else {
|
||||
function = JSFunction::cast(args[1]);
|
||||
}
|
||||
|
||||
Context* context;
|
||||
MaybeObject* maybe_context =
|
||||
isolate->heap()->AllocateWithContext(isolate->context(),
|
||||
isolate->heap()->AllocateWithContext(function,
|
||||
isolate->context(),
|
||||
extension_object);
|
||||
if (!maybe_context->To(&context)) return maybe_context;
|
||||
isolate->set_context(context);
|
||||
@ -8082,12 +8093,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 2);
|
||||
ASSERT(args.length() == 3);
|
||||
String* name = String::cast(args[0]);
|
||||
Object* thrown_object = args[1];
|
||||
JSFunction* function;
|
||||
if (args[2]->IsSmi()) {
|
||||
// A smi sentinel indicates a context nested inside global code rather
|
||||
// than some function. There is a canonical empty function that can be
|
||||
// gotten from the global context.
|
||||
function = isolate->context()->global_context()->closure();
|
||||
} else {
|
||||
function = JSFunction::cast(args[2]);
|
||||
}
|
||||
Context* context;
|
||||
MaybeObject* maybe_context =
|
||||
isolate->heap()->AllocateCatchContext(isolate->context(),
|
||||
isolate->heap()->AllocateCatchContext(function,
|
||||
isolate->context(),
|
||||
name,
|
||||
thrown_object);
|
||||
if (!maybe_context->To(&context)) return maybe_context;
|
||||
@ -10967,6 +10988,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
|
||||
// Creates a copy of the with context chain. The copy of the context chain is
|
||||
// is linked to the function context supplied.
|
||||
static Handle<Context> CopyWithContextChain(Isolate* isolate,
|
||||
Handle<JSFunction> function,
|
||||
Handle<Context> current,
|
||||
Handle<Context> base) {
|
||||
// At the end of the chain. Return the base context to link to.
|
||||
@ -10977,17 +10999,21 @@ static Handle<Context> CopyWithContextChain(Isolate* isolate,
|
||||
// Recursively copy the with and catch contexts.
|
||||
HandleScope scope(isolate);
|
||||
Handle<Context> previous(current->previous());
|
||||
Handle<Context> new_previous = CopyWithContextChain(isolate, previous, base);
|
||||
Handle<Context> new_previous =
|
||||
CopyWithContextChain(isolate, function, previous, base);
|
||||
Handle<Context> new_current;
|
||||
if (current->IsCatchContext()) {
|
||||
Handle<String> name(String::cast(current->extension()));
|
||||
Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
|
||||
new_current =
|
||||
isolate->factory()->NewCatchContext(new_previous, name, thrown_object);
|
||||
isolate->factory()->NewCatchContext(function,
|
||||
new_previous,
|
||||
name,
|
||||
thrown_object);
|
||||
} else {
|
||||
Handle<JSObject> extension(JSObject::cast(current->extension()));
|
||||
new_current =
|
||||
isolate->factory()->NewWithContext(new_previous, extension);
|
||||
isolate->factory()->NewWithContext(function, new_previous, extension);
|
||||
}
|
||||
return scope.CloseAndEscape(new_current);
|
||||
}
|
||||
@ -11118,11 +11144,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
|
||||
// Copy any with contexts present and chain them in front of this context.
|
||||
Handle<Context> frame_context(Context::cast(frame->context()));
|
||||
Handle<Context> function_context(frame_context->declaration_context());
|
||||
context = CopyWithContextChain(isolate, frame_context, context);
|
||||
context = CopyWithContextChain(isolate, go_between, frame_context, context);
|
||||
|
||||
if (additional_context->IsJSObject()) {
|
||||
Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
|
||||
context = isolate->factory()->NewWithContext(context, extension);
|
||||
context = isolate->factory()->NewWithContext(go_between, context, extension);
|
||||
}
|
||||
|
||||
// Wrap the evaluation statement in a new function compiled in the newly
|
||||
|
@ -298,8 +298,8 @@ namespace internal {
|
||||
\
|
||||
/* Contexts */ \
|
||||
F(NewFunctionContext, 1, 1) \
|
||||
F(PushWithContext, 1, 1) \
|
||||
F(PushCatchContext, 2, 1) \
|
||||
F(PushWithContext, 2, 1) \
|
||||
F(PushCatchContext, 3, 1) \
|
||||
F(DeleteContextSlot, 2, 1) \
|
||||
F(LoadContextSlot, 2, 2) \
|
||||
F(LoadContextSlotNoReferenceError, 2, 2) \
|
||||
|
@ -4190,6 +4190,25 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
|
||||
if (scope()->is_global_scope()) {
|
||||
// Contexts nested in the global context have a canonical empty function
|
||||
// as their closure, not the anonymous closure containing the global
|
||||
// code. Pass a smi sentinel and let the runtime look up the empty
|
||||
// function.
|
||||
__ Push(Smi::FromInt(0));
|
||||
} else if (scope()->is_eval_scope()) {
|
||||
// Contexts created by a call to eval have the same closure as the
|
||||
// context calling eval, not the anonymous closure containing the eval
|
||||
// code. Fetch it from the context.
|
||||
__ push(ContextOperand(rsi, Context::CLOSURE_INDEX));
|
||||
} else {
|
||||
ASSERT(scope()->is_function_scope());
|
||||
__ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Non-local control flow support.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user