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:
kmillikin@chromium.org 2011-06-29 07:41:42 +00:00
parent 5e7da7f04f
commit 96bbcaf416
11 changed files with 130 additions and 29 deletions

View File

@ -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.

View File

@ -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);
}

View File

@ -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.

View File

@ -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());
}

View File

@ -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)

View File

@ -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());

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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) \

View File

@ -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.