Index: Source/bindings/dart/DartDebugServer.cpp |
diff --git a/Source/bindings/dart/DartDebugServer.cpp b/Source/bindings/dart/DartDebugServer.cpp |
index 3a44ed13b4c6ef6de5eb2a9b8cdf0a8d2a2e9393..8136fe259d4865bd382c649504bdede38a9e6350 100644 |
--- a/Source/bindings/dart/DartDebugServer.cpp |
+++ b/Source/bindings/dart/DartDebugServer.cpp |
@@ -199,6 +199,45 @@ void DartDebugServer::disable() |
disable->Call(dartDebugObject(), 0, 0); |
} |
+bool lookupTokenLineNumber(const Dart_CodeLocation& location, int* lineNumber, int* columnNumber) |
+{ |
+ Dart_Handle info = Dart_ScriptGetTokenInfo(location.library_id, location.script_url); |
+ ASSERT(Dart_IsList(info)); |
+ intptr_t infoLength = 0; |
+ Dart_Handle res = Dart_ListLength(info, &infoLength); |
+ ASSERT(!Dart_IsError(res)); |
+ Dart_Handle elem; |
+ bool lineStart = true; |
+ int currentLineNumber = 0; |
+ for (intptr_t i = 0; i < infoLength; i++) { |
+ elem = Dart_ListGetAt(info, i); |
+ if (Dart_IsNull(elem)) { |
+ lineStart = true; |
+ } else { |
+ ASSERT(Dart_IsInteger(elem)); |
+ Dart_Handle exception = 0; |
+ int64_t value = DartUtilities::toInteger(elem, exception); |
+ ASSERT(!exception); |
+ if (lineStart) { |
+ // Line number. |
+ currentLineNumber = value; |
+ lineStart = false; |
+ } else { |
+ // Token offset. |
+ if (value == location.token_pos) { |
+ *lineNumber = currentLineNumber; |
+ ASSERT(i + 1 < infoLength); |
+ *columnNumber = DartUtilities::toInteger(Dart_ListGetAt(info, i + 1), exception); |
+ ASSERT(!exception); |
+ return true; |
+ } |
+ i++; // skip columnNumber. |
+ } |
+ } |
+ } |
+ return false; |
+} |
+ |
v8::Handle<v8::Object> DartDebugServer::createExecutionState(Dart_StackTrace trace) |
{ |
intptr_t length = 0; |
@@ -210,28 +249,34 @@ v8::Handle<v8::Object> DartDebugServer::createExecutionState(Dart_StackTrace tra |
int isolateHandle = isolateMap().getByValue(Dart_CurrentIsolate()); |
v8::Local<v8::Array> callFrames = v8::Array::New(length); |
- for (int i = length - 1; i >=0; --i) { |
+ for (int i = length - 1; i >= 0; --i) { |
Dart_ActivationFrame frame = 0; |
result = Dart_GetActivationFrame(trace, i, &frame); |
ASSERT(!Dart_IsError(result)); |
Dart_Handle functionName = 0; |
- Dart_Handle scriptURL = 0; |
- intptr_t lineNumber = 0; |
- intptr_t libraryId = 0; |
+ Dart_Handle function = 0; |
- result = Dart_ActivationFrameInfo(frame, &functionName, &scriptURL, &lineNumber, &libraryId); |
+ Dart_CodeLocation location; |
+ result = Dart_ActivationFrameGetLocation(frame, &functionName, &function, &location); |
+ int lineNumber = 0; |
+ int columnNumber = 0; |
+ lookupTokenLineNumber(location, &lineNumber, &columnNumber); |
ASSERT(!Dart_IsError(result)); |
- Dart_Handle libraryURL = Dart_GetLibraryURL(libraryId); |
+ Dart_Handle libraryURL = Dart_GetLibraryURL(location.library_id); |
ASSERT(!Dart_IsError(libraryURL)); |
Dart_Handle library = Dart_LookupLibrary(libraryURL); |
+ Dart_Handle localVariablesHandle = Dart_GetLocalVariables(frame); |
v8::Local<v8::Object> callFrame = v8::Object::New(); |
callFrame->Set(v8::String::New("functionName"), V8Converter::stringToV8(functionName)); |
- callFrame->Set(v8::String::New("scriptURL"), V8Converter::stringToV8(scriptURL)); |
+ callFrame->Set(v8::String::New("functionProxy"), DartHandleProxy::create(function)); |
+ callFrame->Set(v8::String::New("scriptURL"), V8Converter::stringToV8(location.script_url)); |
callFrame->Set(v8::String::New("lineNumber"), v8::Number::New(lineNumber - 1)); |
- callFrame->Set(v8::String::New("libraryProxy"), DartHandleProxy::createLibraryProxy(library, libraryId, Dart_Null())); |
+ callFrame->Set(v8::String::New("columnNumber"), v8::Number::New(columnNumber - 1)); |
+ callFrame->Set(v8::String::New("libraryProxy"), DartHandleProxy::createLibraryProxy(library, location.library_id, Dart_Null())); |
callFrame->Set(v8::String::New("localScopeProxy"), DartHandleProxy::createLocalScopeProxy( |
- Dart_GetLocalVariables(frame))); |
+ localVariablesHandle)); |
+ callFrame->Set(v8::String::New("localVariables"), DartHandleProxy::create(localVariablesHandle)); |
callFrame->Set(v8::String::New("isolateHandle"), v8::Number::New(isolateHandle)); |
callFrames->Set(i, callFrame); |
} |
@@ -406,51 +451,57 @@ static void stepOut(const v8::FunctionCallbackInfo<v8::Value>& args) |
static void evaluateInScope(const v8::FunctionCallbackInfo<v8::Value>& args) |
{ |
v8::Handle<v8::String> expression = args[0]->ToString(); |
- v8::Handle<v8::Object> receiver = args[1].As<v8::Object>(); |
- v8::Handle<v8::Value> scopeObjectGlobal = args[2]; |
- v8::Handle<v8::Value> scopeObjectLocal = args[3]; |
- v8::Handle<v8::Value> scopes[] = { scopeObjectGlobal, scopeObjectLocal }; |
+ v8::Handle<v8::Value> receiver = args[1]; |
+ v8::Handle<v8::Object> functionProxy = args[2].As<v8::Object>(); |
+ v8::Handle<v8::Value> localVariablesProxy = args[3]; |
+ DartScopes scopes(functionProxy); |
+ Dart_Handle target = 0; |
if (receiver->IsNull() || receiver->IsUndefined()) { |
- // There is no receiver which indicates we are in a static method |
- // scope in Dart. We should ignore the receiver for this case. |
- // Using null or undefined as the receiver for a function triggers |
- // asserts in V8 while running in Debug mode if an exception occurs. |
- receiver = v8::Object::New(); |
- expression = v8::String::Concat(v8::String::New( |
- "(function($$scopeObjectGlobal, $$scopeObjectLocal) { " |
- "with ($$scopeObjectGlobal) with($$scopeObjectLocal) { " |
- "return "), |
- expression); |
- expression = v8::String::Concat(expression, v8::String::New("} })")); |
+ Dart_Handle functionHandle = scopes.handle; |
+ ASSERT(Dart_IsFunction(functionHandle)); |
+ target = Dart_FunctionOwner(functionHandle); |
} else { |
- expression = v8::String::Concat(v8::String::New( |
- "(function($$scopeObjectGlobal, $$scopeObjectLocal) { " |
- "with ($$scopeObjectGlobal) with (this) with($$scopeObjectLocal) { " |
- "return "), |
- expression); |
- expression = v8::String::Concat(expression, v8::String::New("} })")); |
+ target = DartHandleProxy::unwrapValue(receiver); |
} |
+ ASSERT(!Dart_IsError(target)); |
+ Dart_Handle localVariables = DartHandleProxy::unwrapValue(localVariablesProxy); |
+ ASSERT(Dart_IsList(localVariables)); |
+ intptr_t localVariablesLength = 0; |
+ Dart_ListLength(localVariables, &localVariablesLength); |
+ |
+ Dart_Handle wrapExpressionArgs[2] = { V8Converter::stringToDart(expression), localVariables }; |
+ |
+ Dart_Handle wrappedExpressionTuple = |
+ DartUtilities::invokeUtilsMethod("wrapExpressionAsClosure", 2, wrapExpressionArgs); |
+ ASSERT(Dart_IsList(wrappedExpressionTuple)); |
+ Dart_Handle wrappedExpression = Dart_ListGetAt(wrappedExpressionTuple, 0); |
+ Dart_Handle wrappedExpressionArgs = Dart_ListGetAt(wrappedExpressionTuple, 1); |
+ |
+ ASSERT(Dart_IsString(wrappedExpression)); |
+ Dart_Handle closure = Dart_EvaluateExpr(target, wrappedExpression); |
+ if (Dart_IsError(closure)) { |
+ // There was a parse error. FIXME: consider cleaning up the line |
+ // numbers in the error message. |
+ V8ThrowException::throwError(v8::String::New(Dart_GetError(closure))); |
+ } else { |
+ // Invoke the closure passing in the expression arguments specified by |
+ // wrappedExpressionTuple. |
+ ASSERT(Dart_IsClosure(closure)); |
+ intptr_t length = 0; |
+ Dart_ListLength(wrappedExpressionArgs, &length); |
+ Vector<Dart_Handle> dartFunctionArgs; |
+ for (uint32_t i = 0; i < length; i ++) { |
+ dartFunctionArgs.append(Dart_ListGetAt(wrappedExpressionArgs, i)); |
+ } |
- v8::TryCatch tryCatch; |
- v8::Handle<v8::Function> function = V8ScriptRunner::compileAndRunInternalScript(expression, args.GetIsolate()).As<v8::Function>(); |
- |
- if (tryCatch.HasCaught()) { |
- v8SetReturnValue(args, tryCatch.ReThrow()); |
- return; |
- } |
- |
- v8::Local<v8::Value> result = V8ScriptRunner::callFunction( |
- function, getScriptExecutionContext(), |
- receiver, |
- 2, scopes); |
- |
- if (tryCatch.HasCaught()) { |
- v8SetReturnValue(args, tryCatch.ReThrow()); |
- return; |
+ Dart_Handle result = Dart_InvokeClosure(closure, dartFunctionArgs.size(), dartFunctionArgs.data()); |
+ if (Dart_IsError(result)) { |
+ V8ThrowException::throwError(v8::String::New(Dart_GetError(result))); |
+ } else { |
+ v8SetReturnValue(args, DartHandleProxy::create(result)); |
+ } |
} |
- crashIfV8IsDead(); |
- v8SetReturnValue(args, result); |
} |
void DartDebugServer::ensureHooksInstalled() |
@@ -487,6 +538,15 @@ void DartDebugServer::ensureHooksInstalled() |
nativeCallbacks->Set(v8::String::New("stepOver"), v8::FunctionTemplate::New(&stepOver)->GetFunction()); |
nativeCallbacks->Set(v8::String::New("stepOut"), v8::FunctionTemplate::New(&stepOut)->GetFunction()); |
nativeCallbacks->Set(v8::String::New("evaluateInScope"), evaluateInScopeFunction); |
+ { |
+ // Trampoline script is required to properly set calling context before |
+ // invoking Dart code because of security checks in console.log |
+ // implementation (see InjectedScriptManager::canAccessInspectedWindow). |
+ V8Scope v8scope; |
+ v8::Handle<v8::String> trampolineScript = v8::String::New("(function (func, args) { return func.apply(this, args); })"); |
+ v8::Local<v8::Function> trampoline = v8::Local<v8::Function>::Cast(v8::Script::Compile(trampolineScript)->Run()); |
+ nativeCallbacks->Set(v8::String::New("invocationTrampoline"), trampoline); |
+ } |
dartDebugObject()->Set(v8::String::New("nativeCallbacks"), nativeCallbacks); |
} |