Debugger: correctly find closure to recompile eval for debugging.
authoryangguo <yangguo@chromium.org>
Tue, 11 Aug 2015 08:20:29 +0000 (01:20 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 11 Aug 2015 08:20:40 +0000 (08:20 +0000)
R=mstarzinger@chromium.org
BUG=chromium:517592
LOG=N

Review URL: https://codereview.chromium.org/1285793002

Cr-Commit-Position: refs/heads/master@{#30104}

src/compiler.cc
src/debug/debug.cc
test/mjsunit/regress/regress-crbug-517592.js [new file with mode: 0644]

index f4787cd1537107218cdeb9f54be3d61e54abfb6d..8a0ea19b62caf3a70e1d929fa1b698cd2d07fd49 100644 (file)
@@ -1017,11 +1017,16 @@ bool CompileForDebugging(CompilationInfo* info) {
 }
 
 
+static inline bool IsEvalToplevel(Handle<SharedFunctionInfo> shared) {
+  return shared->is_toplevel() && shared->script()->IsScript() &&
+         Script::cast(shared->script())->compilation_type() ==
+             Script::COMPILATION_TYPE_EVAL;
+}
+
+
 bool Compiler::CompileDebugCode(Handle<JSFunction> function) {
   Handle<SharedFunctionInfo> shared(function->shared());
-  if (shared->is_toplevel() && shared->script()->IsScript() &&
-      Script::cast(shared->script())->compilation_type() ==
-          Script::COMPILATION_TYPE_EVAL) {
+  if (IsEvalToplevel(shared)) {
     return CompileEvalForDebugging(function, shared);
   } else {
     CompilationInfoWithZone info(function);
@@ -1032,6 +1037,7 @@ bool Compiler::CompileDebugCode(Handle<JSFunction> function) {
 
 bool Compiler::CompileDebugCode(Handle<SharedFunctionInfo> shared) {
   DCHECK(shared->allows_lazy_compilation_without_context());
+  DCHECK(!IsEvalToplevel(shared));
   Zone zone;
   ParseInfo parse_info(&zone, shared);
   CompilationInfo info(&parse_info);
@@ -1142,6 +1148,10 @@ static Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
     SharedFunctionInfo::InitFromFunctionLiteral(result, lit);
     SharedFunctionInfo::SetScript(result, script);
     result->set_is_toplevel(true);
+    if (info->is_eval()) {
+      // Eval scripts cannot be (re-)compiled without context.
+      result->set_allows_lazy_compilation_without_context(false);
+    }
 
     Handle<String> script_name = script->name()->IsString()
         ? Handle<String>(String::cast(script->name()))
index 891c92e59e30a28492d0ea6d2554db9aa367f4b0..55837342eb9e9547ea300f6d331fbe519ddfc1b9 100644 (file)
@@ -1528,10 +1528,12 @@ class SharedFunctionInfoFinder {
     if (current_candidate_ != NULL) {
       if (current_start_position_ == start_position &&
           shared->end_position() == current_candidate_->end_position()) {
+        // If we already have a matching closure, do not throw it away.
+        if (current_candidate_closure_ != NULL && closure == NULL) return;
         // If a top-level function contains only one function
         // declaration the source for the top-level and the function
         // is the same. In that case prefer the non top-level function.
-        if (shared->is_toplevel()) return;
+        if (!current_candidate_->is_toplevel() && shared->is_toplevel()) return;
       } else if (start_position < current_start_position_ ||
                  current_candidate_->end_position() < shared->end_position()) {
         return;
diff --git a/test/mjsunit/regress/regress-crbug-517592.js b/test/mjsunit/regress/regress-crbug-517592.js
new file mode 100644 (file)
index 0000000..760d892
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug --min-preparse-length=10
+
+var source =
+  "var foo = function foo() {\n" +
+  "  return 1;\n" +
+  "}\n" +
+  "//@ sourceURL=test";
+
+Debug = debug.Debug;
+Debug.setListener(listener);
+var exception = null;
+var break_count = 0;
+
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.Break) break_count++;
+  if (event != Debug.DebugEvent.AfterCompile) return;
+  try {
+    var name = event_data.script().name();
+    var id = event_data.script().id();
+    assertEquals("test", name);
+    Debug.setScriptBreakPointById(id, 2);
+  } catch (e) {
+    exception = e;
+  }
+}
+
+eval(source);
+
+assertEquals(0, break_count);
+foo();
+assertEquals(1, break_count);
+assertNull(exception);