Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index 82733a7c1d35ea4d65646f3e33fc31fca3f5e3bb..e3dba22bf66e21e182445f758c1280a161f11843 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -8314,6 +8314,30 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) { |
} |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) { |
+ NoHandleAllocation ha; |
+ ASSERT(args.length() == 2); |
+ SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]); |
+ 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()->AllocateBlockContext(function, |
+ isolate->context(), |
+ scope_info); |
+ if (!maybe_context->To(&context)) return maybe_context; |
+ isolate->set_context(context); |
+ return context; |
+} |
+ |
+ |
RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { |
HandleScope scope(isolate); |
ASSERT(args.length() == 2); |
@@ -10639,6 +10663,34 @@ static Handle<JSObject> MaterializeCatchScope(Isolate* isolate, |
} |
+// Create a plain JSObject which materializes the block scope for the specified |
+// block context. |
+static Handle<JSObject> MaterializeBlockScope( |
+ Isolate* isolate, |
+ Handle<Context> context) { |
+ ASSERT(context->IsBlockContext()); |
+ Handle<SerializedScopeInfo> serialized_scope_info( |
+ SerializedScopeInfo::cast(context->extension())); |
+ ScopeInfo<> scope_info(*serialized_scope_info); |
+ |
+ // Allocate and initialize a JSObject with all the arguments, stack locals |
+ // heap locals and extension properties of the debugged function. |
+ Handle<JSObject> block_scope = |
+ isolate->factory()->NewJSObject(isolate->object_function()); |
+ |
+ // Fill all context locals. |
+ if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) { |
+ if (!CopyContextLocalsToScopeObject(isolate, |
+ serialized_scope_info, scope_info, |
+ context, block_scope)) { |
+ return Handle<JSObject>(); |
+ } |
+ } |
+ |
+ return block_scope; |
+} |
+ |
+ |
// Iterate over the actual scopes visible from a stack frame. All scopes are |
// backed by an actual context except the local scope, which is inserted |
// "artifically" in the context chain. |
@@ -10649,7 +10701,8 @@ class ScopeIterator { |
ScopeTypeLocal, |
ScopeTypeWith, |
ScopeTypeClosure, |
- ScopeTypeCatch |
+ ScopeTypeCatch, |
+ ScopeTypeBlock |
}; |
ScopeIterator(Isolate* isolate, |
@@ -10675,8 +10728,10 @@ class ScopeIterator { |
} else if (context_->IsFunctionContext()) { |
at_local_ = true; |
} else if (context_->closure() != *function_) { |
- // The context_ is a with or catch block from the outer function. |
- ASSERT(context_->IsWithContext() || context_->IsCatchContext()); |
+ // The context_ is a block or with or catch block from the outer function. |
+ ASSERT(context_->IsWithContext() || |
+ context_->IsCatchContext() || |
+ context_->IsBlockContext()); |
at_local_ = true; |
} |
} |
@@ -10731,6 +10786,9 @@ class ScopeIterator { |
if (context_->IsCatchContext()) { |
return ScopeTypeCatch; |
} |
+ if (context_->IsBlockContext()) { |
+ return ScopeTypeBlock; |
+ } |
ASSERT(context_->IsWithContext()); |
return ScopeTypeWith; |
} |
@@ -10751,6 +10809,8 @@ class ScopeIterator { |
case ScopeIterator::ScopeTypeClosure: |
// Materialize the content of the closure scope into a JSObject. |
return MaterializeClosure(isolate_, CurrentContext()); |
+ case ScopeIterator::ScopeTypeBlock: |
+ return MaterializeBlockScope(isolate_, CurrentContext()); |
} |
UNREACHABLE(); |
return Handle<JSObject>(); |
@@ -11307,7 +11367,13 @@ static Handle<Context> CopyWithContextChain(Isolate* isolate, |
new_previous, |
name, |
thrown_object); |
+ } else if (current->IsBlockContext()) { |
+ Handle<SerializedScopeInfo> scope_info( |
+ SerializedScopeInfo::cast(current->extension())); |
+ new_current = |
+ isolate->factory()->NewBlockContext(function, new_previous, scope_info); |
} else { |
+ ASSERT(current->IsWithContext()); |
Handle<JSObject> extension(JSObject::cast(current->extension())); |
new_current = |
isolate->factory()->NewWithContext(function, new_previous, extension); |