A collection of context-related refactoring changes.
Introduce separate maps for function and with contexts. Use the function context map for testing whether a context is a function context (global contexts are no longer function contexts). Split the paths for allocating with and catch contexts. Rename some functions. Generally refactor code to make it simpler. R=ager@chromium.org BUG= TEST= Review URL: http://codereview.chromium.org/7003058 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8231 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
68eab4a8d8
commit
371af773cf
@ -158,7 +158,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
|
||||
__ ldr(r3, MemOperand(sp, 0));
|
||||
|
||||
// Setup the object header.
|
||||
__ LoadRoot(r2, Heap::kContextMapRootIndex);
|
||||
__ LoadRoot(r2, Heap::kFunctionContextMapRootIndex);
|
||||
__ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
|
||||
__ mov(r2, Operand(Smi::FromInt(length)));
|
||||
__ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset));
|
||||
@ -187,7 +187,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
// Need to collect. Call into runtime system.
|
||||
__ bind(&gc);
|
||||
__ TailCallRuntime(Runtime::kNewContext, 1, 1);
|
||||
__ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -182,7 +182,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
|
||||
FastNewContextStub stub(heap_slots);
|
||||
__ CallStub(&stub);
|
||||
} else {
|
||||
__ CallRuntime(Runtime::kNewContext, 1);
|
||||
__ CallRuntime(Runtime::kNewFunctionContext, 1);
|
||||
}
|
||||
function_in_register = false;
|
||||
// Context is returned in both r0 and cp. It replaces the context
|
||||
|
@ -189,7 +189,7 @@ bool LCodeGen::GeneratePrologue() {
|
||||
FastNewContextStub stub(heap_slots);
|
||||
__ CallStub(&stub);
|
||||
} else {
|
||||
__ CallRuntime(Runtime::kNewContext, 1);
|
||||
__ CallRuntime(Runtime::kNewFunctionContext, 1);
|
||||
}
|
||||
RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
|
||||
// Context is returned in both r0 and cp. It replaces the context
|
||||
|
@ -362,12 +362,12 @@ bool ForInStatement::IsInlineable() const {
|
||||
}
|
||||
|
||||
|
||||
bool WithEnterStatement::IsInlineable() const {
|
||||
bool EnterWithContextStatement::IsInlineable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool WithExitStatement::IsInlineable() const {
|
||||
bool ExitContextStatement::IsInlineable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
16
src/ast.h
16
src/ast.h
@ -60,8 +60,8 @@ namespace internal {
|
||||
V(ContinueStatement) \
|
||||
V(BreakStatement) \
|
||||
V(ReturnStatement) \
|
||||
V(WithEnterStatement) \
|
||||
V(WithExitStatement) \
|
||||
V(EnterWithContextStatement) \
|
||||
V(ExitContextStatement) \
|
||||
V(SwitchStatement) \
|
||||
V(DoWhileStatement) \
|
||||
V(WhileStatement) \
|
||||
@ -611,12 +611,12 @@ class ReturnStatement: public Statement {
|
||||
};
|
||||
|
||||
|
||||
class WithEnterStatement: public Statement {
|
||||
class EnterWithContextStatement: public Statement {
|
||||
public:
|
||||
explicit WithEnterStatement(Expression* expression)
|
||||
explicit EnterWithContextStatement(Expression* expression)
|
||||
: expression_(expression) { }
|
||||
|
||||
DECLARE_NODE_TYPE(WithEnterStatement)
|
||||
DECLARE_NODE_TYPE(EnterWithContextStatement)
|
||||
|
||||
Expression* expression() const { return expression_; }
|
||||
|
||||
@ -627,13 +627,11 @@ class WithEnterStatement: public Statement {
|
||||
};
|
||||
|
||||
|
||||
class WithExitStatement: public Statement {
|
||||
class ExitContextStatement: public Statement {
|
||||
public:
|
||||
WithExitStatement() { }
|
||||
|
||||
virtual bool IsInlineable() const;
|
||||
|
||||
DECLARE_NODE_TYPE(WithExitStatement)
|
||||
DECLARE_NODE_TYPE(ExitContextStatement)
|
||||
};
|
||||
|
||||
|
||||
|
@ -96,7 +96,7 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
|
||||
PrintF("\n");
|
||||
}
|
||||
|
||||
// check extension/with object
|
||||
// Check extension/with/global object.
|
||||
if (context->has_extension()) {
|
||||
Handle<JSObject> extension = Handle<JSObject>(context->extension(),
|
||||
isolate);
|
||||
@ -119,7 +119,8 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
|
||||
}
|
||||
}
|
||||
|
||||
if (context->is_function_context()) {
|
||||
// Only functions can have locals, parameters, and a function name.
|
||||
if (context->IsFunctionContext()) {
|
||||
// we have context-local slots
|
||||
|
||||
// check non-parameter locals in context
|
||||
@ -189,9 +190,8 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
|
||||
// proceed with enclosing context
|
||||
if (context->IsGlobalContext()) {
|
||||
follow_context_chain = false;
|
||||
} else if (context->is_function_context()) {
|
||||
context = Handle<Context>(Context::cast(context->closure()->context()),
|
||||
isolate);
|
||||
} else if (context->IsFunctionContext()) {
|
||||
context = Handle<Context>(context->closure()->context(), isolate);
|
||||
} else {
|
||||
context = Handle<Context>(context->previous(), isolate);
|
||||
}
|
||||
@ -212,11 +212,12 @@ bool Context::GlobalIfNotShadowedByEval(Handle<String> name) {
|
||||
// before the global context and check that there are no context
|
||||
// extension objects (conservative check for with statements).
|
||||
while (!context->IsGlobalContext()) {
|
||||
// Check if the context is a potentially a with context.
|
||||
// Check if the context is a catch or with context, or has called
|
||||
// non-strict eval.
|
||||
if (context->has_extension()) return false;
|
||||
|
||||
// Not a with context so it must be a function context.
|
||||
ASSERT(context->is_function_context());
|
||||
ASSERT(context->IsFunctionContext());
|
||||
|
||||
// Check non-parameter locals.
|
||||
Handle<SerializedScopeInfo> scope_info(
|
||||
|
@ -289,8 +289,17 @@ class Context: public FixedArray {
|
||||
// Compute the global context by traversing the context chain.
|
||||
Context* global_context();
|
||||
|
||||
// Tells if this is a function context (as opposed to a 'with' context).
|
||||
bool is_function_context() { return unchecked_previous() == NULL; }
|
||||
// Predicates for context types. IsGlobalContext is defined on Object
|
||||
// because we frequently have to know if arbitrary objects are global
|
||||
// contexts.
|
||||
bool IsFunctionContext() {
|
||||
Map* map = this->map();
|
||||
return map == map->GetHeap()->function_context_map();
|
||||
}
|
||||
bool IsCatchContext() {
|
||||
Map* map = this->map();
|
||||
return map == map->GetHeap()->catch_context_map();
|
||||
}
|
||||
|
||||
// Tells whether the global context is marked with out of memory.
|
||||
inline bool has_out_of_memory();
|
||||
|
@ -249,14 +249,20 @@ Handle<Context> Factory::NewFunctionContext(int length,
|
||||
}
|
||||
|
||||
|
||||
Handle<Context> Factory::NewWithContext(Handle<Context> previous,
|
||||
Handle<JSObject> extension,
|
||||
bool is_catch_context) {
|
||||
Handle<Context> Factory::NewCatchContext(Handle<Context> previous,
|
||||
Handle<JSObject> extension) {
|
||||
CALL_HEAP_FUNCTION(
|
||||
isolate(),
|
||||
isolate()->heap()->AllocateWithContext(*previous,
|
||||
*extension,
|
||||
is_catch_context),
|
||||
isolate()->heap()->AllocateCatchContext(*previous, *extension),
|
||||
Context);
|
||||
}
|
||||
|
||||
|
||||
Handle<Context> Factory::NewWithContext(Handle<Context> previous,
|
||||
Handle<JSObject> extension) {
|
||||
CALL_HEAP_FUNCTION(
|
||||
isolate(),
|
||||
isolate()->heap()->AllocateWithContext(*previous, *extension),
|
||||
Context);
|
||||
}
|
||||
|
||||
|
@ -149,10 +149,13 @@ class Factory {
|
||||
Handle<Context> NewFunctionContext(int length,
|
||||
Handle<JSFunction> closure);
|
||||
|
||||
// Create a catch context.
|
||||
Handle<Context> NewCatchContext(Handle<Context> previous,
|
||||
Handle<JSObject> extension);
|
||||
|
||||
// Create a 'with' context.
|
||||
Handle<Context> NewWithContext(Handle<Context> previous,
|
||||
Handle<JSObject> extension,
|
||||
bool is_catch_context);
|
||||
Handle<JSObject> extension);
|
||||
|
||||
// Return the Symbol matching the passed in string.
|
||||
Handle<String> SymbolFromString(Handle<String> value);
|
||||
|
@ -90,14 +90,14 @@ void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) {
|
||||
}
|
||||
|
||||
|
||||
void BreakableStatementChecker::VisitWithEnterStatement(
|
||||
WithEnterStatement* stmt) {
|
||||
void BreakableStatementChecker::VisitEnterWithContextStatement(
|
||||
EnterWithContextStatement* stmt) {
|
||||
Visit(stmt->expression());
|
||||
}
|
||||
|
||||
|
||||
void BreakableStatementChecker::VisitWithExitStatement(
|
||||
WithExitStatement* stmt) {
|
||||
void BreakableStatementChecker::VisitExitContextStatement(
|
||||
ExitContextStatement* stmt) {
|
||||
}
|
||||
|
||||
|
||||
@ -952,18 +952,19 @@ void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
|
||||
Comment cmnt(masm_, "[ WithEnterStatement");
|
||||
void FullCodeGenerator::VisitEnterWithContextStatement(
|
||||
EnterWithContextStatement* stmt) {
|
||||
Comment cmnt(masm_, "[ EnterWithContextStatement");
|
||||
SetStatementPosition(stmt);
|
||||
|
||||
VisitForStackValue(stmt->expression());
|
||||
__ CallRuntime(Runtime::kPushContext, 1);
|
||||
__ CallRuntime(Runtime::kPushWithContext, 1);
|
||||
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
|
||||
Comment cmnt(masm_, "[ WithExitStatement");
|
||||
void FullCodeGenerator::VisitExitContextStatement(ExitContextStatement* stmt) {
|
||||
Comment cmnt(masm_, "[ ExitContextStatement");
|
||||
SetStatementPosition(stmt);
|
||||
|
||||
// Pop context.
|
||||
|
45
src/heap.cc
45
src/heap.cc
@ -1894,7 +1894,7 @@ bool Heap::CreateInitialMaps() {
|
||||
AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
|
||||
if (!maybe_obj->ToObject(&obj)) return false;
|
||||
}
|
||||
set_context_map(Map::cast(obj));
|
||||
set_function_context_map(Map::cast(obj));
|
||||
|
||||
{ MaybeObject* maybe_obj =
|
||||
AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
|
||||
@ -1902,6 +1902,12 @@ bool Heap::CreateInitialMaps() {
|
||||
}
|
||||
set_catch_context_map(Map::cast(obj));
|
||||
|
||||
{ MaybeObject* maybe_obj =
|
||||
AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
|
||||
if (!maybe_obj->ToObject(&obj)) return false;
|
||||
}
|
||||
set_with_context_map(Map::cast(obj));
|
||||
|
||||
{ MaybeObject* maybe_obj =
|
||||
AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
|
||||
if (!maybe_obj->ToObject(&obj)) return false;
|
||||
@ -3919,38 +3925,47 @@ MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
|
||||
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||
}
|
||||
Context* context = reinterpret_cast<Context*>(result);
|
||||
context->set_map(context_map());
|
||||
context->set_map(function_context_map());
|
||||
context->set_closure(function);
|
||||
context->set_fcontext(context);
|
||||
context->set_previous(NULL);
|
||||
context->set_extension(NULL);
|
||||
context->set_global(function->context()->global());
|
||||
ASSERT(!context->IsGlobalContext());
|
||||
ASSERT(context->is_function_context());
|
||||
ASSERT(result->IsContext());
|
||||
return result;
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Heap::AllocateWithContext(Context* previous,
|
||||
JSObject* extension,
|
||||
bool is_catch_context) {
|
||||
MaybeObject* Heap::AllocateCatchContext(Context* previous,
|
||||
JSObject* extension) {
|
||||
Object* result;
|
||||
{ MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
|
||||
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||
}
|
||||
Context* context = reinterpret_cast<Context*>(result);
|
||||
context->set_map(is_catch_context ? catch_context_map() :
|
||||
context_map());
|
||||
context->set_map(catch_context_map());
|
||||
context->set_closure(previous->closure());
|
||||
context->set_fcontext(previous->fcontext());
|
||||
context->set_previous(previous);
|
||||
context->set_extension(extension);
|
||||
context->set_global(previous->global());
|
||||
ASSERT(!context->IsGlobalContext());
|
||||
ASSERT(!context->is_function_context());
|
||||
ASSERT(result->IsContext());
|
||||
return result;
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Heap::AllocateWithContext(Context* previous,
|
||||
JSObject* extension) {
|
||||
Object* result;
|
||||
{ MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
|
||||
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||
}
|
||||
Context* context = reinterpret_cast<Context*>(result);
|
||||
context->set_map(with_context_map());
|
||||
context->set_closure(previous->closure());
|
||||
context->set_fcontext(previous->fcontext());
|
||||
context->set_previous(previous);
|
||||
context->set_extension(extension);
|
||||
context->set_global(previous->global());
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
|
@ -107,8 +107,9 @@ inline Heap* _inline_get_heap_();
|
||||
V(Map, external_unsigned_int_array_map, ExternalUnsignedIntArrayMap) \
|
||||
V(Map, external_float_array_map, ExternalFloatArrayMap) \
|
||||
V(Map, external_double_array_map, ExternalDoubleArrayMap) \
|
||||
V(Map, context_map, ContextMap) \
|
||||
V(Map, function_context_map, FunctionContextMap) \
|
||||
V(Map, catch_context_map, CatchContextMap) \
|
||||
V(Map, with_context_map, WithContextMap) \
|
||||
V(Map, code_map, CodeMap) \
|
||||
V(Map, oddball_map, OddballMap) \
|
||||
V(Map, global_property_cell_map, GlobalPropertyCellMap) \
|
||||
@ -645,10 +646,12 @@ class Heap {
|
||||
MUST_USE_RESULT MaybeObject* AllocateFunctionContext(int length,
|
||||
JSFunction* closure);
|
||||
|
||||
// Allocate a catch context.
|
||||
MUST_USE_RESULT MaybeObject* AllocateCatchContext(Context* previous,
|
||||
JSObject* extension);
|
||||
// Allocate a 'with' context.
|
||||
MUST_USE_RESULT MaybeObject* AllocateWithContext(Context* previous,
|
||||
JSObject* extension,
|
||||
bool is_catch_context);
|
||||
JSObject* extension);
|
||||
|
||||
// Allocates a new utility object in the old generation.
|
||||
MUST_USE_RESULT MaybeObject* AllocateStruct(InstanceType type);
|
||||
|
@ -2551,19 +2551,20 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
|
||||
void HGraphBuilder::VisitEnterWithContextStatement(
|
||||
EnterWithContextStatement* stmt) {
|
||||
ASSERT(!HasStackOverflow());
|
||||
ASSERT(current_block() != NULL);
|
||||
ASSERT(current_block()->HasPredecessor());
|
||||
return Bailout("WithEnterStatement");
|
||||
return Bailout("EnterWithContextStatement");
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
|
||||
void HGraphBuilder::VisitExitContextStatement(ExitContextStatement* stmt) {
|
||||
ASSERT(!HasStackOverflow());
|
||||
ASSERT(current_block() != NULL);
|
||||
ASSERT(current_block()->HasPredecessor());
|
||||
return Bailout("WithExitStatement");
|
||||
return Bailout("ExitContextStatement");
|
||||
}
|
||||
|
||||
|
||||
|
@ -129,7 +129,8 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
// Setup the object header.
|
||||
Factory* factory = masm->isolate()->factory();
|
||||
__ mov(FieldOperand(eax, HeapObject::kMapOffset), factory->context_map());
|
||||
__ mov(FieldOperand(eax, HeapObject::kMapOffset),
|
||||
factory->function_context_map());
|
||||
__ mov(FieldOperand(eax, Context::kLengthOffset),
|
||||
Immediate(Smi::FromInt(length)));
|
||||
|
||||
@ -159,7 +160,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
// Need to collect. Call into runtime system.
|
||||
__ bind(&gc);
|
||||
__ TailCallRuntime(Runtime::kNewContext, 1, 1);
|
||||
__ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -175,7 +175,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
|
||||
FastNewContextStub stub(heap_slots);
|
||||
__ CallStub(&stub);
|
||||
} else {
|
||||
__ CallRuntime(Runtime::kNewContext, 1);
|
||||
__ CallRuntime(Runtime::kNewFunctionContext, 1);
|
||||
}
|
||||
function_in_register = false;
|
||||
// Context is returned in both eax and esi. It replaces the context
|
||||
|
@ -184,7 +184,7 @@ bool LCodeGen::GeneratePrologue() {
|
||||
FastNewContextStub stub(heap_slots);
|
||||
__ CallStub(&stub);
|
||||
} else {
|
||||
__ CallRuntime(Runtime::kNewContext, 1);
|
||||
__ CallRuntime(Runtime::kNewFunctionContext, 1);
|
||||
}
|
||||
RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
|
||||
// Context is returned in both eax and esi. It replaces the context
|
||||
|
@ -672,8 +672,9 @@ class StaticMarkingVisitor : public StaticVisitorBase {
|
||||
|
||||
Map* map = SafeMap(ctx);
|
||||
Heap* heap = map->heap();
|
||||
if (!(map == heap->raw_unchecked_context_map() ||
|
||||
if (!(map == heap->raw_unchecked_function_context_map() ||
|
||||
map == heap->raw_unchecked_catch_context_map() ||
|
||||
map == heap->raw_unchecked_with_context_map() ||
|
||||
map == heap->raw_unchecked_global_context_map())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -534,22 +534,17 @@ bool Object::IsDeoptimizationOutputData() {
|
||||
|
||||
bool Object::IsContext() {
|
||||
if (Object::IsHeapObject()) {
|
||||
Heap* heap = HeapObject::cast(this)->GetHeap();
|
||||
return (HeapObject::cast(this)->map() == heap->context_map() ||
|
||||
HeapObject::cast(this)->map() == heap->catch_context_map() ||
|
||||
HeapObject::cast(this)->map() == heap->global_context_map());
|
||||
Map* map = HeapObject::cast(this)->map();
|
||||
Heap* heap = map->GetHeap();
|
||||
return (map == heap->function_context_map() ||
|
||||
map == heap->catch_context_map() ||
|
||||
map == heap->with_context_map() ||
|
||||
map == heap->global_context_map());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsCatchContext() {
|
||||
return Object::IsHeapObject() &&
|
||||
HeapObject::cast(this)->map() ==
|
||||
HeapObject::cast(this)->GetHeap()->catch_context_map();
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsGlobalContext() {
|
||||
return Object::IsHeapObject() &&
|
||||
HeapObject::cast(this)->map() ==
|
||||
|
@ -735,7 +735,6 @@ class MaybeObject BASE_EMBEDDED {
|
||||
V(FixedArray) \
|
||||
V(FixedDoubleArray) \
|
||||
V(Context) \
|
||||
V(CatchContext) \
|
||||
V(GlobalContext) \
|
||||
V(JSFunction) \
|
||||
V(Code) \
|
||||
|
@ -1922,7 +1922,7 @@ Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) {
|
||||
Block* result = new(zone()) Block(NULL, 2, false);
|
||||
|
||||
if (result != NULL) {
|
||||
result->AddStatement(new(zone()) WithEnterStatement(obj));
|
||||
result->AddStatement(new(zone()) EnterWithContextStatement(obj));
|
||||
|
||||
// Create body block.
|
||||
Block* body = new(zone()) Block(NULL, 1, false);
|
||||
@ -1930,7 +1930,7 @@ Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) {
|
||||
|
||||
// Create exit block.
|
||||
Block* exit = new(zone()) Block(NULL, 1, false);
|
||||
exit->AddStatement(new(zone()) WithExitStatement());
|
||||
exit->AddStatement(new(zone()) ExitContextStatement());
|
||||
|
||||
// Return a try-finally statement.
|
||||
TryFinallyStatement* wrapper = new(zone()) TryFinallyStatement(body, exit);
|
||||
@ -2089,8 +2089,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
|
||||
if (peek() == Token::LBRACE) {
|
||||
// Rewrite the catch body B to a single statement block
|
||||
// { try B finally { PopContext }}.
|
||||
// Rewrite the catch body B to a single statement block
|
||||
// { try B finally { PopContext }}.
|
||||
Block* inner_body;
|
||||
// We need to collect escapes from the body for both the inner
|
||||
// try/finally used to pop the catch context and any possible outer
|
||||
@ -2107,7 +2107,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
||||
|
||||
// Create exit block.
|
||||
Block* inner_finally = new(zone()) Block(NULL, 1, false);
|
||||
inner_finally->AddStatement(new(zone()) WithExitStatement());
|
||||
inner_finally->AddStatement(new(zone()) ExitContextStatement());
|
||||
|
||||
// Create a try/finally statement.
|
||||
TryFinallyStatement* inner_try_finally =
|
||||
|
@ -123,15 +123,16 @@ void PrettyPrinter::VisitReturnStatement(ReturnStatement* node) {
|
||||
}
|
||||
|
||||
|
||||
void PrettyPrinter::VisitWithEnterStatement(WithEnterStatement* node) {
|
||||
Print("<enter with> (");
|
||||
void PrettyPrinter::VisitEnterWithContextStatement(
|
||||
EnterWithContextStatement* node) {
|
||||
Print("<enter with context> (");
|
||||
Visit(node->expression());
|
||||
Print(") ");
|
||||
}
|
||||
|
||||
|
||||
void PrettyPrinter::VisitWithExitStatement(WithExitStatement* node) {
|
||||
Print("<exit with>");
|
||||
void PrettyPrinter::VisitExitContextStatement(ExitContextStatement* node) {
|
||||
Print("<exit context>");
|
||||
}
|
||||
|
||||
|
||||
@ -797,13 +798,14 @@ void AstPrinter::VisitReturnStatement(ReturnStatement* node) {
|
||||
}
|
||||
|
||||
|
||||
void AstPrinter::VisitWithEnterStatement(WithEnterStatement* node) {
|
||||
PrintIndentedVisit("WITH ENTER", node->expression());
|
||||
void AstPrinter::VisitEnterWithContextStatement(
|
||||
EnterWithContextStatement* node) {
|
||||
PrintIndentedVisit("ENTER WITH CONTEXT", node->expression());
|
||||
}
|
||||
|
||||
|
||||
void AstPrinter::VisitWithExitStatement(WithExitStatement* node) {
|
||||
PrintIndented("WITH EXIT\n");
|
||||
void AstPrinter::VisitExitContextStatement(ExitContextStatement* node) {
|
||||
PrintIndented("EXIT CONTEXT\n");
|
||||
}
|
||||
|
||||
|
||||
@ -1191,14 +1193,15 @@ void JsonAstBuilder::VisitReturnStatement(ReturnStatement* stmt) {
|
||||
}
|
||||
|
||||
|
||||
void JsonAstBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
|
||||
TagScope tag(this, "WithEnterStatement");
|
||||
void JsonAstBuilder::VisitEnterWithContextStatement(
|
||||
EnterWithContextStatement* stmt) {
|
||||
TagScope tag(this, "EnterWithContextStatement");
|
||||
Visit(stmt->expression());
|
||||
}
|
||||
|
||||
|
||||
void JsonAstBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
|
||||
TagScope tag(this, "WithExitStatement");
|
||||
void JsonAstBuilder::VisitExitContextStatement(ExitContextStatement* stmt) {
|
||||
TagScope tag(this, "ExitContextStatement");
|
||||
}
|
||||
|
||||
|
||||
|
129
src/rewriter.cc
129
src/rewriter.cc
@ -197,131 +197,18 @@ void Processor::VisitBreakStatement(BreakStatement* node) {
|
||||
void Processor::VisitDeclaration(Declaration* node) {}
|
||||
void Processor::VisitEmptyStatement(EmptyStatement* node) {}
|
||||
void Processor::VisitReturnStatement(ReturnStatement* node) {}
|
||||
void Processor::VisitWithEnterStatement(WithEnterStatement* node) {}
|
||||
void Processor::VisitWithExitStatement(WithExitStatement* node) {}
|
||||
void Processor::VisitEnterWithContextStatement(
|
||||
EnterWithContextStatement* node) {
|
||||
}
|
||||
void Processor::VisitExitContextStatement(ExitContextStatement* node) {}
|
||||
void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
|
||||
|
||||
|
||||
// Expressions are never visited yet.
|
||||
void Processor::VisitFunctionLiteral(FunctionLiteral* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitSharedFunctionInfoLiteral(
|
||||
SharedFunctionInfoLiteral* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitConditional(Conditional* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitVariableProxy(VariableProxy* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitLiteral(Literal* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitRegExpLiteral(RegExpLiteral* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitArrayLiteral(ArrayLiteral* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitObjectLiteral(ObjectLiteral* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitAssignment(Assignment* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitThrow(Throw* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitProperty(Property* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitCall(Call* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitCallNew(CallNew* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitCallRuntime(CallRuntime* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitUnaryOperation(UnaryOperation* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitCountOperation(CountOperation* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitBinaryOperation(BinaryOperation* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitCompareOperation(CompareOperation* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitCompareToNull(CompareToNull* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitThisFunction(ThisFunction* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
#define DEF_VISIT(type) \
|
||||
void Processor::Visit##type(type* expr) { UNREACHABLE(); }
|
||||
EXPRESSION_NODE_LIST(DEF_VISIT)
|
||||
#undef DEF_VISIT
|
||||
|
||||
|
||||
// Assumes code has been parsed and scopes have been analyzed. Mutates the
|
||||
|
146
src/runtime.cc
146
src/runtime.cc
@ -7883,7 +7883,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
|
||||
@ -7901,50 +7901,50 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
|
||||
}
|
||||
|
||||
|
||||
MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
|
||||
Object* object,
|
||||
bool is_catch_context) {
|
||||
// Convert the object to a proper JavaScript object.
|
||||
Object* js_object = object;
|
||||
if (!js_object->IsJSObject()) {
|
||||
MaybeObject* maybe_js_object = js_object->ToObject();
|
||||
if (!maybe_js_object->ToObject(&js_object)) {
|
||||
if (!Failure::cast(maybe_js_object)->IsInternalError()) {
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
JSObject* extension_object;
|
||||
if (args[0]->IsJSObject()) {
|
||||
extension_object = JSObject::cast(args[0]);
|
||||
} else {
|
||||
// Convert the object to a proper JavaScript object.
|
||||
MaybeObject* maybe_js_object = args[0]->ToObject();
|
||||
if (!maybe_js_object->To(&extension_object)) {
|
||||
if (Failure::cast(maybe_js_object)->IsInternalError()) {
|
||||
HandleScope scope(isolate);
|
||||
Handle<Object> handle = args.at<Object>(0);
|
||||
Handle<Object> result =
|
||||
isolate->factory()->NewTypeError("with_expression",
|
||||
HandleVector(&handle, 1));
|
||||
return isolate->Throw(*result);
|
||||
} else {
|
||||
return maybe_js_object;
|
||||
}
|
||||
HandleScope scope(isolate);
|
||||
Handle<Object> handle(object, isolate);
|
||||
Handle<Object> result =
|
||||
isolate->factory()->NewTypeError("with_expression",
|
||||
HandleVector(&handle, 1));
|
||||
return isolate->Throw(*result);
|
||||
}
|
||||
}
|
||||
|
||||
Object* result;
|
||||
{ MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
|
||||
isolate->context(), JSObject::cast(js_object), is_catch_context);
|
||||
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||
}
|
||||
|
||||
Context* context = Context::cast(result);
|
||||
Context* context;
|
||||
MaybeObject* maybe_context =
|
||||
isolate->heap()->AllocateWithContext(isolate->context(),
|
||||
extension_object);
|
||||
if (!maybe_context->To(&context)) return maybe_context;
|
||||
isolate->set_context(context);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
return PushContextHelper(isolate, args[0], false);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
return PushContextHelper(isolate, args[0], true);
|
||||
JSObject* extension_object = JSObject::cast(args[0]);
|
||||
Context* context;
|
||||
MaybeObject* maybe_context =
|
||||
isolate->heap()->AllocateCatchContext(isolate->context(),
|
||||
extension_object);
|
||||
if (!maybe_context->To(&context)) return maybe_context;
|
||||
isolate->set_context(context);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@ -8607,9 +8607,8 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
|
||||
// Stop search when eval is found or when the global context is
|
||||
// reached.
|
||||
if (attributes != ABSENT || context->IsGlobalContext()) break;
|
||||
if (context->is_function_context()) {
|
||||
context = Handle<Context>(Context::cast(context->closure()->context()),
|
||||
isolate);
|
||||
if (context->IsFunctionContext()) {
|
||||
context = Handle<Context>(context->closure()->context(), isolate);
|
||||
} else {
|
||||
context = Handle<Context>(context->previous(), isolate);
|
||||
}
|
||||
@ -9842,8 +9841,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
|
||||
Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
|
||||
ScopeInfo<> info(*scope_info);
|
||||
|
||||
// Get the context.
|
||||
Handle<Context> context(Context::cast(it.frame()->context()));
|
||||
// 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.
|
||||
//
|
||||
@ -9859,25 +9858,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
|
||||
}
|
||||
|
||||
// Fill in the values of the locals.
|
||||
for (int i = 0; i < info.NumberOfLocals(); i++) {
|
||||
if (is_optimized_frame) {
|
||||
// If we are inspecting an optimized frame use undefined as the
|
||||
// value for all locals.
|
||||
//
|
||||
// TODO(1140): We should be able to get the correct values
|
||||
// for locals in optimized frames.
|
||||
if (is_optimized_frame) {
|
||||
// If we are inspecting an optimized frame use undefined as the
|
||||
// value for all locals.
|
||||
//
|
||||
// TODO(1140): We should be able to get the correct values
|
||||
// for locals in optimized frames.
|
||||
for (int i = 0; i < info.NumberOfLocals(); i++) {
|
||||
locals->set(i * 2 + 1, isolate->heap()->undefined_value());
|
||||
} else if (i < info.number_of_stack_slots()) {
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < info.number_of_stack_slots(); i++) {
|
||||
// Get the value from the stack.
|
||||
locals->set(i * 2 + 1, it.frame()->GetExpression(i));
|
||||
} else {
|
||||
// Traverse the context chain to the function context as all local
|
||||
// variables stored in the context will be on the function context.
|
||||
}
|
||||
for (int i = info.number_of_stack_slots(); i < info.NumberOfLocals(); i++) {
|
||||
Handle<String> name = info.LocalName(i);
|
||||
while (!context->is_function_context()) {
|
||||
context = Handle<Context>(context->previous());
|
||||
}
|
||||
ASSERT(context->is_function_context());
|
||||
locals->set(i * 2 + 1,
|
||||
context->get(scope_info->ContextSlotIndex(*name, NULL)));
|
||||
}
|
||||
@ -10139,7 +10135,7 @@ static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
|
||||
// context.
|
||||
static Handle<JSObject> MaterializeClosure(Isolate* isolate,
|
||||
Handle<Context> context) {
|
||||
ASSERT(context->is_function_context());
|
||||
ASSERT(context->IsFunctionContext());
|
||||
|
||||
Handle<SharedFunctionInfo> shared(context->closure()->shared());
|
||||
Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
|
||||
@ -10238,7 +10234,7 @@ class ScopeIterator {
|
||||
int index = function_->shared()->scope_info()->
|
||||
StackSlotIndex(isolate_->heap()->result_symbol());
|
||||
at_local_ = index < 0;
|
||||
} else if (context_->is_function_context()) {
|
||||
} else if (context_->IsFunctionContext()) {
|
||||
at_local_ = true;
|
||||
} else if (context_->closure() != *function_) {
|
||||
// The context_ is a with block from the outer function.
|
||||
@ -10272,8 +10268,8 @@ class ScopeIterator {
|
||||
}
|
||||
|
||||
// Move to the next context.
|
||||
if (context_->is_function_context()) {
|
||||
context_ = Handle<Context>(Context::cast(context_->closure()->context()));
|
||||
if (context_->IsFunctionContext()) {
|
||||
context_ = Handle<Context>(context_->closure()->context());
|
||||
} else {
|
||||
context_ = Handle<Context>(context_->previous());
|
||||
}
|
||||
@ -10281,7 +10277,7 @@ class ScopeIterator {
|
||||
// If passing the local scope indicate that the current scope is now the
|
||||
// local scope.
|
||||
if (!local_done_ &&
|
||||
(context_->IsGlobalContext() || (context_->is_function_context()))) {
|
||||
(context_->IsGlobalContext() || context_->IsFunctionContext())) {
|
||||
at_local_ = true;
|
||||
}
|
||||
}
|
||||
@ -10295,7 +10291,7 @@ class ScopeIterator {
|
||||
ASSERT(context_->global()->IsGlobalObject());
|
||||
return ScopeTypeGlobal;
|
||||
}
|
||||
if (context_->is_function_context()) {
|
||||
if (context_->IsFunctionContext()) {
|
||||
return ScopeTypeClosure;
|
||||
}
|
||||
ASSERT(context_->has_extension());
|
||||
@ -10863,19 +10859,23 @@ 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(Handle<Context> context_chain,
|
||||
Handle<Context> function_context) {
|
||||
// At the bottom of the chain. Return the function context to link to.
|
||||
if (context_chain->is_function_context()) {
|
||||
return function_context;
|
||||
static Handle<Context> CopyWithContextChain(Isolate* isolate,
|
||||
Handle<Context> current,
|
||||
Handle<Context> base) {
|
||||
// At the end of the chain. Return the base context to link to.
|
||||
if (current->IsFunctionContext() || current->IsGlobalContext()) {
|
||||
return base;
|
||||
}
|
||||
|
||||
// Recursively copy the with contexts.
|
||||
Handle<Context> previous(context_chain->previous());
|
||||
Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
|
||||
Handle<Context> context = CopyWithContextChain(previous, function_context);
|
||||
return context->GetIsolate()->factory()->NewWithContext(
|
||||
context, extension, context_chain->IsCatchContext());
|
||||
// Recursively copy the with and catch contexts.
|
||||
HandleScope scope(isolate);
|
||||
Handle<Context> previous(current->previous());
|
||||
Handle<Context> new_previous = CopyWithContextChain(isolate, previous, base);
|
||||
Handle<JSObject> extension(JSObject::cast(current->extension()));
|
||||
Handle<Context> new_current = current->IsCatchContext()
|
||||
? isolate->factory()->NewCatchContext(new_previous, extension)
|
||||
: isolate->factory()->NewWithContext(new_previous, extension);
|
||||
return scope.CloseAndEscape(new_current);
|
||||
}
|
||||
|
||||
|
||||
@ -11004,11 +11004,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->fcontext());
|
||||
context = CopyWithContextChain(frame_context, context);
|
||||
context = CopyWithContextChain(isolate, frame_context, context);
|
||||
|
||||
if (additional_context->IsJSObject()) {
|
||||
context = isolate->factory()->NewWithContext(context,
|
||||
Handle<JSObject>::cast(additional_context), false);
|
||||
Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
|
||||
context = isolate->factory()->NewWithContext(context, extension);
|
||||
}
|
||||
|
||||
// Wrap the evaluation statement in a new function compiled in the newly
|
||||
|
@ -297,8 +297,8 @@ namespace internal {
|
||||
F(PromoteScheduledException, 0, 1) \
|
||||
\
|
||||
/* Contexts */ \
|
||||
F(NewContext, 1, 1) \
|
||||
F(PushContext, 1, 1) \
|
||||
F(NewFunctionContext, 1, 1) \
|
||||
F(PushWithContext, 1, 1) \
|
||||
F(PushCatchContext, 1, 1) \
|
||||
F(DeleteContextSlot, 2, 1) \
|
||||
F(LoadContextSlot, 2, 2) \
|
||||
|
@ -125,7 +125,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
|
||||
__ movq(rcx, Operand(rsp, 1 * kPointerSize));
|
||||
|
||||
// Setup the object header.
|
||||
__ LoadRoot(kScratchRegister, Heap::kContextMapRootIndex);
|
||||
__ LoadRoot(kScratchRegister, Heap::kFunctionContextMapRootIndex);
|
||||
__ movq(FieldOperand(rax, HeapObject::kMapOffset), kScratchRegister);
|
||||
__ Move(FieldOperand(rax, FixedArray::kLengthOffset), Smi::FromInt(length));
|
||||
|
||||
@ -152,7 +152,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
// Need to collect. Call into runtime system.
|
||||
__ bind(&gc);
|
||||
__ TailCallRuntime(Runtime::kNewContext, 1, 1);
|
||||
__ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -175,7 +175,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
|
||||
FastNewContextStub stub(heap_slots);
|
||||
__ CallStub(&stub);
|
||||
} else {
|
||||
__ CallRuntime(Runtime::kNewContext, 1);
|
||||
__ CallRuntime(Runtime::kNewFunctionContext, 1);
|
||||
}
|
||||
function_in_register = false;
|
||||
// Context is returned in both rax and rsi. It replaces the context
|
||||
|
@ -197,7 +197,7 @@ bool LCodeGen::GeneratePrologue() {
|
||||
FastNewContextStub stub(heap_slots);
|
||||
__ CallStub(&stub);
|
||||
} else {
|
||||
__ CallRuntime(Runtime::kNewContext, 1);
|
||||
__ CallRuntime(Runtime::kNewFunctionContext, 1);
|
||||
}
|
||||
RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
|
||||
// Context is returned in both rax and rsi. It replaces the context
|
||||
|
Loading…
Reference in New Issue
Block a user