Commit ae062d5d authored by yurys@chromium.org's avatar yurys@chromium.org

Added new scope type ScopeIterator::ScopeTypeCatch for with generated from catch blocks.

Removed a false assertion in ScopeIterator that assumed context extension to never be a JSContextExtensionObject.

The context extension object in a 'with' context is JSContextExtensionObject iff the 'with' statement is generated from a catch block in order to extend its local scope with a variable holding exception object. This is how we differentiate 'catch' scope from 'with' scope.

Chrome bug:
http://code.google.com/p/chromium/issues/detail?id=17229
Review URL: http://codereview.chromium.org/202005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2843 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 2edebc2c
......@@ -102,7 +102,8 @@ Debug.ScriptCompilationType = { Host: 0,
Debug.ScopeType = { Global: 0,
Local: 1,
With: 2,
Closure: 3 };
Closure: 3,
Catch: 4 };
// Current debug state.
......@@ -900,6 +901,10 @@ function formatScope_(scope) {
result += 'With, ';
result += '#' + scope.object.ref + '#';
break;
case Debug.ScopeType.Catch:
result += 'Catch, ';
result += '#' + scope.object.ref + '#';
break;
case Debug.ScopeType.Closure:
result += 'Closure';
break;
......
......@@ -201,7 +201,8 @@ PropertyAttribute.DontDelete = DONT_DELETE;
ScopeType = { Global: 0,
Local: 1,
With: 2,
Closure: 3 };
Closure: 3,
Catch: 4 };
// Mirror hierarchy:
......
......@@ -6341,7 +6341,12 @@ class ScopeIterator {
ScopeTypeGlobal = 0,
ScopeTypeLocal,
ScopeTypeWith,
ScopeTypeClosure
ScopeTypeClosure,
// Every catch block contains an implicit with block (its parameter is
// a JSContextExtensionObject) that extends current scope with a variable
// holding exception object. Such with blocks are treated as scopes of their
// own type.
ScopeTypeCatch
};
explicit ScopeIterator(JavaScriptFrame* frame)
......@@ -6417,7 +6422,14 @@ class ScopeIterator {
return ScopeTypeClosure;
}
ASSERT(context_->has_extension());
ASSERT(!context_->extension()->IsJSContextExtensionObject());
// Current scope is either an explicit with statement or a with statement
// implicitely generated for a catch block.
// If the extension object here is a JSContextExtensionObject then
// current with statement is one frome a catch block otherwise it's a
// regular with statement.
if (context_->extension()->IsJSContextExtensionObject()) {
return ScopeTypeCatch;
}
return ScopeTypeWith;
}
......@@ -6432,6 +6444,7 @@ class ScopeIterator {
return MaterializeLocalScope(frame_);
break;
case ScopeIterator::ScopeTypeWith:
case ScopeIterator::ScopeTypeCatch:
// Return the with object.
return Handle<JSObject>(CurrentContext()->extension());
break;
......@@ -6488,6 +6501,14 @@ class ScopeIterator {
break;
}
case ScopeIterator::ScopeTypeCatch: {
PrintF("Catch:\n");
Handle<JSObject> extension =
Handle<JSObject>(CurrentContext()->extension());
extension->Print();
break;
}
case ScopeIterator::ScopeTypeClosure: {
PrintF("Closure:\n");
CurrentContext()->Print();
......
......@@ -140,6 +140,11 @@ function CheckScopeContent(content, number, exec_state) {
if (!scope.scopeObject().property('arguments').isUndefined()) {
scope_size--;
}
// Also ignore synthetic variable from catch block.
if (!scope.scopeObject().property('.catch-var').isUndefined()) {
scope_size--;
}
if (count != scope_size) {
print('Names found in scope:');
var names = scope.scopeObject().propertyNames();
......@@ -656,5 +661,101 @@ listener_delegate = function(exec_state) {
debugger;
EndTest();
BeginTest("Catch block 1");
function catch_block_1() {
try {
throw 'Exception';
} catch (e) {
debugger;
}
};
listener_delegate = function(exec_state) {
CheckScopeChain([debug.ScopeType.Catch,
debug.ScopeType.Local,
debug.ScopeType.Global], exec_state);
CheckScopeContent({e:'Exception'}, 0, exec_state);
}
catch_block_1()
EndTest();
BeginTest("Catch block 2");
function catch_block_2() {
try {
throw 'Exception';
} catch (e) {
with({n:10}) {
debugger;
}
}
};
listener_delegate = function(exec_state) {
CheckScopeChain([debug.ScopeType.With,
debug.ScopeType.Catch,
debug.ScopeType.Local,
debug.ScopeType.Global], exec_state);
CheckScopeContent({n:10}, 0, exec_state);
CheckScopeContent({e:'Exception'}, 1, exec_state);
}
catch_block_2()
EndTest();
BeginTest("Catch block 3");
function catch_block_1() {
// Do eval to dynamically declare a local variable so that the context's
// extension slot is initialized with JSContextExtensionObject.
eval("var y = 78;");
try {
throw 'Exception';
} catch (e) {
debugger;
}
};
listener_delegate = function(exec_state) {
CheckScopeChain([debug.ScopeType.Catch,
debug.ScopeType.Local,
debug.ScopeType.Global], exec_state);
CheckScopeContent({e:'Exception'}, 0, exec_state);
CheckScopeContent({y:78}, 1, exec_state);
}
catch_block_1()
EndTest();
BeginTest("Catch block 4");
function catch_block_2() {
// Do eval to dynamically declare a local variable so that the context's
// extension slot is initialized with JSContextExtensionObject.
eval("var y = 98;");
try {
throw 'Exception';
} catch (e) {
with({n:10}) {
debugger;
}
}
};
listener_delegate = function(exec_state) {
CheckScopeChain([debug.ScopeType.With,
debug.ScopeType.Catch,
debug.ScopeType.Local,
debug.ScopeType.Global], exec_state);
CheckScopeContent({n:10}, 0, exec_state);
CheckScopeContent({e:'Exception'}, 1, exec_state);
CheckScopeContent({y:98}, 2, exec_state);
}
catch_block_2()
EndTest();
assertEquals(begin_test_count, break_count, 'one or more tests did not enter the debugger');
assertEquals(begin_test_count, end_test_count, 'one or more tests did not have its result checked');
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment