| 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);
|
| }
|
|
|
|
|