StackTrace should provide access to //@ sourceURL=... value
authoryurys@chromium.org <yurys@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Oct 2010 08:53:51 +0000 (08:53 +0000)
committeryurys@chromium.org <yurys@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Oct 2010 08:53:51 +0000 (08:53 +0000)
Review URL: http://codereview.chromium.org/3602013

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5586 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8.h
src/api.cc
src/top.cc
test/cctest/test-api.cc

index 9ee1687..0c2cf8c 100644 (file)
@@ -758,8 +758,9 @@ class V8EXPORT StackTrace {
     kFunctionName = 1 << 3,
     kIsEval = 1 << 4,
     kIsConstructor = 1 << 5,
+    kScriptNameOrSourceURL = 1 << 6,
     kOverview = kLineNumber | kColumnOffset | kScriptName | kFunctionName,
-    kDetailed = kOverview | kIsEval | kIsConstructor
+    kDetailed = kOverview | kIsEval | kIsConstructor | kScriptNameOrSourceURL
   };
 
   /**
@@ -819,6 +820,13 @@ class V8EXPORT StackFrame {
   Local<String> GetScriptName() const;
 
   /**
+   * Returns the name of the resource that contains the script for the
+   * function for this StackFrame or sourceURL value if the script name
+   * is undefined and its source ends with //@ sourceURL=... string.
+   */
+  Local<String> GetScriptNameOrSourceURL() const;
+
+  /**
    * Returns the name of the function associated with this stack frame.
    */
   Local<String> GetFunctionName() const;
index 7ca9e8f..37c3bfe 100644 (file)
@@ -1679,6 +1679,21 @@ Local<String> StackFrame::GetScriptName() const {
 }
 
 
+Local<String> StackFrame::GetScriptNameOrSourceURL() const {
+  if (IsDeadCheck("v8::StackFrame::GetScriptNameOrSourceURL()")) {
+    return Local<String>();
+  }
+  ENTER_V8;
+  HandleScope scope;
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  i::Handle<i::Object> name = GetProperty(self, "scriptNameOrSourceURL");
+  if (!name->IsString()) {
+    return Local<String>();
+  }
+  return scope.Close(Local<String>::Cast(Utils::ToLocal(name)));
+}
+
+
 Local<String> StackFrame::GetFunctionName() const {
   if (IsDeadCheck("v8::StackFrame::GetFunctionName()")) return Local<String>();
   ENTER_V8;
index e172cb8..0f8c727 100644 (file)
@@ -385,6 +385,25 @@ Handle<JSArray> Top::CaptureCurrentStackTrace(
       SetProperty(stackFrame, script_key, script_name, NONE);
     }
 
+    if (options & StackTrace::kScriptNameOrSourceURL) {
+      Handle<Object> script_name(script->name());
+      Handle<String> method_name =
+          Factory::LookupAsciiSymbol("nameOrSourceURL");
+      Handle<JSValue> script_wrapper = GetScriptWrapper(Handle<Script>(script));
+      Handle<Object> property = GetProperty(script_wrapper, method_name);
+      ASSERT(property->IsJSFunction());
+      Handle<JSFunction> method = Handle<JSFunction>::cast(property); 
+      bool caught_exception;
+      Handle<Object> result = Execution::TryCall(method, script_wrapper, 0,
+                                                 NULL, &caught_exception);
+      if (caught_exception) {
+        result = Factory::undefined_value();
+      }
+      Handle<String> script_name_or_source_url_key =
+          Factory::LookupAsciiSymbol("scriptNameOrSourceURL");
+      SetProperty(stackFrame, script_name_or_source_url_key, result, NONE);
+    }
+
     if (options & StackTrace::kFunctionName) {
       Handle<Object> fun_name(fun->shared()->name());
       if (fun_name->ToBoolean()->IsFalse()) {
index 0631351..e36abf6 100644 (file)
@@ -10555,6 +10555,45 @@ TEST(CaptureStackTraceForUncaughtException) {
 }
 
 
+v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
+  v8::HandleScope scope;
+  v8::Handle<v8::StackTrace> stackTrace =
+      v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
+  CHECK_EQ(5, stackTrace->GetFrameCount());
+  v8::Handle<v8::String> url = v8_str("eval_url");
+  for (int i = 0; i < 3; i++) {
+    v8::Handle<v8::String> name =
+        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
+    CHECK(!name.IsEmpty());
+    CHECK_EQ(url, name); 
+  }
+  return v8::Undefined();
+}
+
+
+TEST(SourceURLInStackTrace) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
+             v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
+  LocalContext context(0, templ);
+
+  const char *source =
+    "function outer() {\n"
+    "function bar() {\n"
+    "  AnalyzeStackOfEvalWithSourceURL();\n"
+    "}\n"
+    "function foo() {\n"
+    "\n"
+    "  bar();\n"
+    "}\n"
+    "foo();\n"
+    "}\n"
+    "eval('(' + outer +')()//@ sourceURL=eval_url');";
+  CHECK(CompileRun(source)->IsUndefined());
+}
+
+
 // Test that idle notification can be handled and eventually returns true.
 THREADED_TEST(IdleNotification) {
   bool rv = false;