| Index: Source/bindings/core/dart/DartJsInterop.cpp
|
| diff --git a/Source/bindings/core/dart/DartJsInterop.cpp b/Source/bindings/core/dart/DartJsInterop.cpp
|
| index 76ba5ddfe7e7a02b887455b211cd392565c1e14b..4afe555d642e06a1da77065ccd5bf18c0dba5f38 100644
|
| --- a/Source/bindings/core/dart/DartJsInterop.cpp
|
| +++ b/Source/bindings/core/dart/DartJsInterop.cpp
|
| @@ -147,6 +147,7 @@ const char* dartArrayPolyfill =
|
| "})();";
|
|
|
| static v8::Local<v8::FunctionTemplate> dartFunctionTemplate();
|
| +static v8::Local<v8::FunctionTemplate> dartFunctionTemplateNoWrap();
|
| static v8::Local<v8::FunctionTemplate> dartObjectTemplate();
|
| static v8::Local<v8::FunctionTemplate> dartListTemplate();
|
|
|
| @@ -190,18 +191,43 @@ static void functionInvocationCallback(const v8::FunctionCallbackInfo<v8::Value>
|
| // there are 2 arguments, the first argument is "this" and the second
|
| // argument is an array of arguments.
|
| if (args.Length() > 1) {
|
| - dartFunctionArgs.append(JsInterop::toDart(args[0]));
|
| + dartFunctionArgs.append(JsInterop::toDart(args[0], true));
|
| }
|
|
|
| v8::Local<v8::Array> argsList = args[args.Length()-1].As<v8::Array>();
|
| uint32_t argsListLength = argsList->Length();
|
| for (uint32_t i = 0; i < argsListLength; i++) {
|
| - dartFunctionArgs.append(JsInterop::toDart(argsList->Get(i)));
|
| + dartFunctionArgs.append(JsInterop::toDart(argsList->Get(i), true));
|
| }
|
|
|
| setJsReturnValue(domData, args, Dart_InvokeClosure(handle, dartFunctionArgs.size(), dartFunctionArgs.data()));
|
| }
|
|
|
| +static void functionInvocationCallbackNoWrap(const v8::FunctionCallbackInfo<v8::Value>& args)
|
| +{
|
| + DartScopes scopes(args.Holder());
|
| + Dart_Handle handle = scopes.handle;
|
| + DartDOMData* domData = DartDOMData::current();
|
| + ASSERT(domData);
|
| + ASSERT(DartUtilities::isFunction(domData, handle));
|
| +
|
| + Vector<Dart_Handle> dartFunctionArgs;
|
| + ASSERT(args.Length() == 1 || args.Length() == 2);
|
| + // If there is 1 argument, we assume it is a v8:Array or arguments, if
|
| + // there are 2 arguments, the first argument is "this" and the second
|
| + // argument is an array of arguments.
|
| + if (args.Length() > 1) {
|
| + dartFunctionArgs.append(JsInterop::toDart(args[0], false));
|
| + }
|
| +
|
| + v8::Local<v8::Array> argsList = args[args.Length()-1].As<v8::Array>();
|
| + uint32_t argsListLength = argsList->Length();
|
| + for (uint32_t i = 0; i < argsListLength; i++) {
|
| + dartFunctionArgs.append(JsInterop::toDart(argsList->Get(i), false));
|
| + }
|
| +
|
| + setJsReturnValue(domData, args, Dart_InvokeClosure(handle, dartFunctionArgs.size(), dartFunctionArgs.data()));
|
| +}
|
| static v8::Local<v8::ObjectTemplate> setupInstanceTemplate(v8::Local<v8::FunctionTemplate> proxyTemplate)
|
| {
|
| v8::Local<v8::ObjectTemplate> instanceTemplate = proxyTemplate->InstanceTemplate();
|
| @@ -209,6 +235,7 @@ static v8::Local<v8::ObjectTemplate> setupInstanceTemplate(v8::Local<v8::Functio
|
| return instanceTemplate;
|
| }
|
|
|
| +
|
| static v8::Local<v8::FunctionTemplate> dartFunctionTemplate()
|
| {
|
| DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, proxyTemplate, ());
|
| @@ -226,16 +253,17 @@ static v8::Local<v8::FunctionTemplate> dartFunctionTemplate()
|
| return proxyTemplateLocal;
|
| }
|
|
|
| -static v8::Local<v8::FunctionTemplate> dartObjectTemplate()
|
| +static v8::Local<v8::FunctionTemplate> dartFunctionTemplateNoWrap()
|
| {
|
| DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, proxyTemplate, ());
|
| v8::Local<v8::FunctionTemplate> proxyTemplateLocal;
|
| v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| if (proxyTemplate.IsEmpty()) {
|
| - proxyTemplate.Reset(v8Isolate, v8::FunctionTemplate::New(v8Isolate));
|
| + proxyTemplate.Reset(v8::Isolate::GetCurrent(), v8::FunctionTemplate::New(v8Isolate));
|
| proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, proxyTemplate);
|
| - proxyTemplateLocal->SetClassName(v8::String::NewFromUtf8(v8Isolate, "DartObject"));
|
| - setupInstanceTemplate(proxyTemplateLocal);
|
| + v8::Local<v8::ObjectTemplate> instanceTemplate = setupInstanceTemplate(proxyTemplateLocal);
|
| +
|
| + instanceTemplate->SetCallAsFunctionHandler(&functionInvocationCallbackNoWrap);
|
| } else {
|
| proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, proxyTemplate);
|
| }
|
| @@ -291,7 +319,7 @@ public:
|
| void setReturnValue(v8::Local<v8::Value> ret)
|
| {
|
| ASSERT(!tryCatch.HasCaught());
|
| - Dart_SetReturnValue(args, JsInterop::toDart(ret));
|
| + Dart_SetReturnValue(args, JsInterop::toDart(ret, false));
|
| ASSERT(!tryCatch.HasCaught());
|
| }
|
|
|
| @@ -312,17 +340,19 @@ v8::Local<v8::Value> JsInterop::fromDart(DartDOMData* domData, Dart_Handle handl
|
| v8::Handle<v8::Value> value = V8Converter::toV8IfPrimitive(domData, handle, exception);
|
| if (!value.IsEmpty() || exception)
|
| return value;
|
| - // TODO(terry): START of uncommented block by Jacob, I've re-enabled for clamped arrays...
|
| - value = V8Converter::toV8IfBrowserNative(domData, handle, exception);
|
| - if (!value.IsEmpty() || exception)
|
| - return value;
|
| - // TODO(terry): END of uncommented block by Jacob.
|
| - if (DartDOMWrapper::subtypeOf(handle, JsObject::dartClassId)) {
|
| - JsObject* object = DartDOMWrapper::unwrapDartWrapper<JsObject>(domData, handle, exception);
|
| +
|
| + Dart_Handle jso = invokeTopLevelJsInteropMethod(domData, "unwrap_jso", 1, &handle);
|
| + ASSERT(!Dart_IsError(jso));
|
| + if (DartDOMWrapper::subtypeOf(jso, JsObject::dartClassId)) {
|
| + JsObject* object = DartDOMWrapper::unwrapDartWrapper<JsObject>(domData, jso, exception);
|
| if (exception)
|
| return v8::Local<v8::Value>();
|
| return object->localV8Object();
|
| }
|
| + // TODO(terry): START of uncommented block by Jacob, I've re-enabled for clamped arrays...
|
| + value = V8Converter::toV8IfBrowserNative(domData, handle, exception);
|
| + if (!value.IsEmpty() || exception)
|
| + return value;
|
|
|
| if (DartUtilities::isFunction(domData, handle)) {
|
| v8::Local<v8::Object> functionProxy = dartFunctionTemplate()->InstanceTemplate()->NewInstance();
|
| @@ -395,7 +425,7 @@ v8::Local<v8::Object> JsObject::localV8Object()
|
| return v8::Local<v8::Object>::New(v8::Isolate::GetCurrent(), v8Object);
|
| }
|
|
|
| -Dart_Handle JsInterop::toDart(v8::Local<v8::Value> v8Handle)
|
| +Dart_Handle JsInterop::toDart(v8::Local<v8::Value> v8Handle, bool sometimesUseHtml)
|
| {
|
| Dart_Handle handle = V8Converter::toDartIfPrimitive(v8Handle);
|
| if (handle)
|
| @@ -426,27 +456,117 @@ Dart_Handle JsInterop::toDart(v8::Local<v8::Value> v8Handle)
|
| }
|
| }
|
|
|
| - return JsObject::toDart(object);
|
| + return JsObject::toDart(object, sometimesUseHtml);
|
| }
|
|
|
| -Dart_Handle JsObject::toDart(v8::Local<v8::Object> object)
|
| +Dart_Handle JsObject::toDart(v8::Local<v8::Object> object, bool sometimesUseHtml)
|
| {
|
| - // FIXME: perform caching so that === can be used.
|
| + Dart_Handle wrapper;
|
| + v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| + DartDOMData* domData = DartDOMData::current();
|
| + DartJsInteropData* interopData = domData->jsInteropData();
|
| + v8::Local<v8::String> existingDartWrapperKey = interopData->existingDartWrapperHiddenField(v8Isolate);
|
| +
|
| + // TODO(alanknight): This will fail for multiple isolates referencing the same JS object.
|
| + // We probably need to use a different property name for different isolates.
|
| + v8::Local<v8::Value> hiddenValue = object->GetHiddenValue(existingDartWrapperKey);
|
| +
|
| + if (*hiddenValue && hiddenValue->IsObject()) {
|
| + DartPersistentValue* scriptValue = DartHandleProxy::readPointerFromProxy(hiddenValue.As<v8::Object>());
|
| + ASSERT(scriptValue->isIsolateAlive());
|
| + // If the isolate does not match we fall back to using the existing JS
|
| + // wrapper for the Dart object so that simple cases that would work in
|
| + // Dart2Js work. We could alternately throw an exception here.
|
| + if (scriptValue->isolate() == Dart_CurrentIsolate()) {
|
| + Dart_Handle wrapper = scriptValue->value();
|
| + if (sometimesUseHtml) {
|
| + wrapper = invokeTopLevelJsInteropMethod(domData, "_maybeWrap", 1, &wrapper);
|
| + }
|
| + return wrapper;
|
| + }
|
| + }
|
| +
|
| + Dart_Handle ret = 0;
|
| if (object->IsFunction()) {
|
| RefPtr<JsFunction> jsFunction = JsFunction::create(object.As<v8::Function>());
|
| - return JsFunction::toDart(jsFunction);
|
| + wrapper = JsFunction::toDart(jsFunction);
|
| + } else if (object->IsArray()
|
| + // Check for Dart List objects from different Dart isolates.
|
| + // In dart2js the List from a different isolate would just be a regular
|
| + // JS Array so it can be treated as a JS Array.
|
| + || dartListTemplate()->HasInstance(object)) {
|
| + RefPtr<JsArray> jsArray = JsArray::create(object);
|
| + wrapper = JsArray::toDart(jsArray);
|
| + } else {
|
| + RefPtr<JsObject> jsObject = JsObject::create(object);
|
| + wrapper = JsObject::toDart(jsObject);
|
| + if (sometimesUseHtml) {
|
| + ret = invokeTopLevelJsInteropMethod(DartDOMData::current(), "_maybeWrap", 1, &wrapper);
|
| + }
|
| }
|
|
|
| - if (object->IsArray()) {
|
| - RefPtr<JsArray> jsArray = JsArray::create(object.As<v8::Array>());
|
| - return JsArray::toDart(jsArray);
|
| + v8::Local<v8::Object> proxy;
|
| +
|
| + // Prevent creation of cross frame dart:html objects for classes other than Window.
|
| + // Verify that the object is from the same context using the same check
|
| + // we used to use in V8Converter.
|
| + if (!object->CreationContext()->Global()->StrictEquals(DartUtilities::currentV8Context()->Global())) {
|
| + // Short circuit creating dart:html wrappers for cross frame objects
|
| + // other than window.
|
| + // TODO(jacobr): handle cross frame Window objects differently to more
|
| + // exactly match existing dart:html semantics.
|
| + if (!object->CreationContext()->Global()->StrictEquals(object)) {
|
| + Dart_SetField(wrapper, Dart_NewStringFromCString("_dartHtmlWrapper"), wrapper);
|
| + }
|
| }
|
| + ASSERT(Dart_IsInstance(wrapper));
|
| + // Simulate the behavior of the Dart dev compiler where new List() is
|
| + // equivalent to a JavaScript array. We accomplish this by creating a
|
| + // JavaScript object that fakes that it is a JavaScript array but is
|
| + // actually backed by a Dart list. This is not a breaking change as
|
| + // existing Dart-JS interop passed arrays as opaque Dart handles.
|
| + // The jsify method can still be called if you wish to create a copy
|
| + // of a json like Dart data structure.
|
| + proxy = dartObjectTemplate()->InstanceTemplate()->NewInstance();
|
| + DartHandleProxy::writePointerToProxy(proxy, wrapper);
|
| + object->SetHiddenValue(existingDartWrapperKey, proxy);
|
| + return ret != 0 ? ret : wrapper;
|
| +}
|
|
|
| - RefPtr<JsObject> jsObject = JsObject::create(object);
|
| - return JsObject::toDart(jsObject);
|
| +void JsInterop::buildInteropPatchFiles(DartDOMData* domData, Vector<InteropPatchFile>* patches, Dart_Handle& exception)
|
| +{
|
| + // Build patch files implementing all external methods specified with new
|
| + // style JS interop and JsObjectImpl, JsFunctionImpl, and JsArrayImpl
|
| + // classes that implement all Dart types annoted with @Js.
|
| + // The sole purpose of these classes is to ensure that checked mode
|
| + // allows casting a JsObject to all types implemented by a JsObject.
|
| + Dart_Handle externals = invokeTopLevelJsInteropMethod(domData, "_generateInteropPatchFiles", 0, 0);
|
| + if (Dart_IsError(externals)) {
|
| + exception = externals;
|
| + return;
|
| + }
|
| + ASSERT(Dart_IsList(externals));
|
| + intptr_t externalsLength = 0;
|
| + Dart_ListLength(externals, &externalsLength);
|
| + ASSERT(externalsLength % 3 == 0);
|
| +
|
| + for (intptr_t i = 0; i < externalsLength; i += 3) {
|
| + InteropPatchFile patch;
|
| +
|
| + Dart_Handle libraryUri = Dart_ListGetAt(externals, i);
|
| + Dart_Handle patchFileUri = Dart_ListGetAt(externals, i + 1);
|
| + Dart_Handle source = Dart_ListGetAt(externals, i + 2);
|
| + ASSERT(Dart_IsString(libraryUri));
|
| + ASSERT(Dart_IsString(patchFileUri));
|
| + ASSERT(Dart_IsString(source));
|
| + patch.libraryUri = DartUtilities::toString(libraryUri);
|
| + patch.patchFileUri = DartUtilities::toString(patchFileUri);
|
| + patch.source = DartUtilities::toString(source);
|
| + patches->append(patch);
|
| + }
|
| }
|
|
|
| -static void maybeCreateJsObjectImplClass(DartDOMData* domData)
|
| +void JsInterop::initializeJsInterop(DartDOMData* domData, const Vector<InteropPatchFile>& patches, Dart_Handle& exception)
|
| {
|
| DartJsInteropData* interopData = domData->jsInteropData();
|
| // Skip if the JSObjectImpl class has already been defined.
|
| @@ -458,36 +578,54 @@ static void maybeCreateJsObjectImplClass(DartDOMData* domData)
|
| // all Dart types that have been passed to the dart:js registerJsInterfaces
|
| // method. The sole purpose of these classes is to ensure that checked mode
|
| // allows casting a JsObject to all types implemented by a JsObject.
|
| - Dart_Handle source = invokeTopLevelJsInteropMethod(domData, "_generateJsObjectImplPart", 0, 0);
|
| - ASSERT(Dart_IsString(source));
|
|
|
| - Dart_Handle ret = Dart_LibraryLoadPatch(domData->jsLibrary(), Dart_NewStringFromCString("JsInteropImpl.dart"), source);
|
| - ALLOW_UNUSED_LOCAL(ret);
|
| - ASSERT(!Dart_IsError(ret));
|
| + Dart_Handle ret;
|
| + for (size_t i = 0; i < patches.size(); ++i) {
|
| + const InteropPatchFile& patch = patches[i];
|
| + Dart_Handle library = Dart_LookupLibrary(DartUtilities::safeStringToDartString(patch.libraryUri));
|
| + ASSERT(Dart_IsLibrary(library));
|
| + Dart_Handle patchFileUri = DartUtilities::safeStringToDartString(patch.patchFileUri);
|
| + Dart_Handle source = DartUtilities::safeStringToDartString(patch.source);
|
| + ret = Dart_LibraryLoadPatch(library, patchFileUri, source);
|
| + if (Dart_IsError(ret)) {
|
| + exception = ret;
|
| + return;
|
| + }
|
| + }
|
| ret = Dart_FinalizeLoading(false);
|
| - ASSERT(!Dart_IsError(ret));
|
| + if (Dart_IsError(ret)) {
|
| + exception = ret;
|
| + return;
|
| + }
|
|
|
| interopData->setJsObjectImplDefined();
|
|
|
| - // Start of polyfill work to make Dart List proxies behave like JavaScript
|
| - // Arrays by monkey patching JavaScript Array and the List JavaScript
|
| - // proxies as needed.
|
| - v8::Context::Scope scope(DartUtilities::currentV8Context());
|
| + if (domData->isDOMEnabled()) {
|
| + // Start of polyfill work to make Dart List proxies behave like JavaScript
|
| + // Arrays by monkey patching JavaScript Array and the List JavaScript
|
| + // proxies as needed.
|
| + v8::Context::Scope scope(DartUtilities::currentV8Context());
|
|
|
| - v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| + v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| +
|
| + v8::Local<v8::Function> dartArrayConstructor = dartListTemplate()->GetFunction();
|
|
|
| - v8::Local<v8::Function> dartArrayConstructor = dartListTemplate()->GetFunction();
|
| + DartUtilities::currentV8Context()->Global()->Set(v8::String::NewFromUtf8(v8Isolate, "$DartList"),
|
| + dartArrayConstructor);
|
| + V8ScriptRunner::compileAndRunInternalScript(v8::String::NewFromUtf8(v8Isolate, dartArrayPolyfill), v8Isolate);
|
|
|
| - DartUtilities::currentV8Context()->Global()->Set(v8::String::NewFromUtf8(v8Isolate, "$DartList"),
|
| - dartArrayConstructor);
|
| - V8ScriptRunner::compileAndRunInternalScript(v8::String::NewFromUtf8(v8Isolate, dartArrayPolyfill), v8Isolate);
|
| + ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCString("_registerAllJsInterfaces"), 0, 0);
|
| + if (Dart_IsError(ret)) {
|
| + exception = ret;
|
| + return;
|
| + }
|
| + }
|
| }
|
|
|
| Dart_Handle JsObject::toDart(PassRefPtr<JsObject> jsObject)
|
| {
|
| DartDOMData* domData = DartDOMData::current();
|
| // We need to ensure JsObjectImpl exists before creating the wrapper.
|
| - maybeCreateJsObjectImplClass(domData);
|
| return DartDOMWrapper::createWrapper<JsObject>(domData, jsObject.get(), JsObject::dartClassId);
|
| }
|
|
|
| @@ -500,7 +638,6 @@ Dart_Handle JsFunction::toDart(PassRefPtr<JsFunction> jsFunction)
|
| {
|
| DartDOMData* domData = DartDOMData::current();
|
| // We need to ensure JsObjectImpl exists before creating the wrapper.
|
| - maybeCreateJsObjectImplClass(domData);
|
| return DartDOMWrapper::createWrapper<JsFunction>(domData, jsFunction.get(), JsFunction::dartClassId);
|
| }
|
|
|
| @@ -520,22 +657,16 @@ Dart_Handle JsArray::toDart(PassRefPtr<JsArray> jsArray)
|
| {
|
| DartDOMData* domData = DartDOMData::current();
|
| // We need to ensure JsArrayImpl exists before creating the wrapper.
|
| - maybeCreateJsObjectImplClass(domData);
|
| return DartDOMWrapper::createWrapper<JsArray>(domData, jsArray.get(), JsArray::dartClassId);
|
| }
|
|
|
| -JsArray::JsArray(v8::Local<v8::Array> v8Handle) : JsObject(v8Handle) { }
|
| +JsArray::JsArray(v8::Local<v8::Object> v8Handle) : JsObject(v8Handle) { }
|
|
|
| -PassRefPtr<JsArray> JsArray::create(v8::Local<v8::Array> v8Handle)
|
| +PassRefPtr<JsArray> JsArray::create(v8::Local<v8::Object> v8Handle)
|
| {
|
| return adoptRef(new JsArray(v8Handle));
|
| }
|
|
|
| -v8::Local<v8::Array> JsArray::localV8Array()
|
| -{
|
| - return localV8Object().As<v8::Array>();
|
| -}
|
| -
|
| namespace JsInteropInternal {
|
|
|
| typedef HashMap<Dart_Handle, v8::Handle<v8::Value> > DartHandleToV8Map;
|
| @@ -605,7 +736,7 @@ static void jsObjectConstructorCallback(Dart_NativeArguments args)
|
| // a JSObject. FIXME: evaluate if this is the right solution.
|
| // Alternately, we could throw an exception.
|
| if (ret->IsObject()) {
|
| - scopes.setReturnValue(JsObject::toDart(ret.As<v8::Object>()));
|
| + scopes.setReturnValue(JsObject::toDart(ret.As<v8::Object>(), false));
|
| } else {
|
| // This will throw an exception in Dart checked mode.
|
| scopes.setReturnValue(ret);
|
| @@ -872,7 +1003,7 @@ fail:
|
| static void newJsArrayCallback(Dart_NativeArguments args)
|
| {
|
| JsInteropScopes scopes(args);
|
| - scopes.setReturnValue(JsObject::toDart(v8::Array::New(v8::Isolate::GetCurrent())));
|
| + scopes.setReturnValue(JsObject::toDart(v8::Array::New(v8::Isolate::GetCurrent()), false));
|
| return;
|
| }
|
|
|
| @@ -916,10 +1047,10 @@ static void jsArrayLengthCallback(Dart_NativeArguments args)
|
| {
|
| JsInteropScopes scopes(args);
|
| JsArray* receiver = DartDOMWrapper::receiver<JsArray>(args);
|
| - uint32_t length = receiver->localV8Array()->Length();
|
| + v8::Local<v8::Value> length = receiver->localV8Object()->Get(v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), "length"));
|
| if (scopes.handleJsException(&exception))
|
| goto fail;
|
| - scopes.setReturnValueInteger(length);
|
| + scopes.setReturnValue(length);
|
| return;
|
| }
|
|
|
| @@ -945,7 +1076,7 @@ static void fromBrowserObjectCallback(Dart_NativeArguments args)
|
| ASSERT(ret->IsObject());
|
| if (scopes.handleJsException(&exception))
|
| goto fail;
|
| - scopes.setReturnValue(JsObject::toDart(ret.As<v8::Object>()));
|
| + scopes.setReturnValue(JsObject::toDart(ret.As<v8::Object>(), false));
|
| return;
|
| }
|
|
|
| @@ -973,18 +1104,9 @@ static void applyCallback(Dart_NativeArguments args)
|
| // Use the global v8 object if no Dart thisArg was passed in.
|
| thisArg = DartUtilities::currentV8Context()->Global();
|
| } else {
|
| - Dart_Handle jso = Dart_GetField(thisArgDart, Dart_NewStringFromCString("blink_jsObject"));
|
| - if (!Dart_IsError(jso) && DartDOMWrapper::subtypeOf(jso, JsObject::dartClassId)) {
|
| - // Use the blink JS Interop object.
|
| - JsObject* object = DartDOMWrapper::unwrapDartWrapper<JsObject>(domData, jso, exception);
|
| - if (exception)
|
| - thisArg = v8::Local<v8::Value>();
|
| - thisArg = object->localV8Object();
|
| - } else {
|
| - thisArg = JsInterop::fromDart(domData, thisArgDart, exception);
|
| - if (exception)
|
| - goto fail;
|
| - }
|
| + thisArg = JsInterop::fromDart(domData, thisArgDart, exception);
|
| + if (exception)
|
| + goto fail;
|
| if (!thisArg->IsObject()) {
|
| exception = Dart_NewStringFromCString("thisArg is not an object");
|
| goto fail;
|
| @@ -1082,13 +1204,12 @@ static void contextCallback(Dart_NativeArguments args)
|
| {
|
| v8::Local<v8::Context> v8Context = DartUtilities::currentV8Context();
|
| v8::Context::Scope scope(v8Context);
|
| - Dart_SetReturnValue(args, JsObject::toDart(v8Context->Global()));
|
| + Dart_SetReturnValue(args, JsObject::toDart(v8Context->Global(), false));
|
| }
|
|
|
| static void finalizeJsInterfacesCallback(Dart_NativeArguments args)
|
| {
|
| - DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateData(args));
|
| - maybeCreateJsObjectImplClass(domData);
|
| + // Obsolete.
|
| }
|
|
|
| static void interfacesFinalizedCallback(Dart_NativeArguments args)
|
| @@ -1197,7 +1318,7 @@ static void jsifyCallback(Dart_NativeArguments args)
|
| // a JSObject. FIXME: evaluate if this is the right solution.
|
| // Alternately, we could throw an exception.
|
| if (ret->IsObject()) {
|
| - scopes.setReturnValue(JsObject::toDart(ret.As<v8::Object>()));
|
| + scopes.setReturnValue(JsObject::toDart(ret.As<v8::Object>(), false));
|
| } else {
|
| // This will throw an exception in Dart checked mode.
|
| scopes.setReturnValue(ret);
|
| @@ -1233,6 +1354,31 @@ fail:
|
| ASSERT_NOT_REACHED();
|
| }
|
|
|
| +
|
| +static void withThisCallbackNoWrap(Dart_NativeArguments args)
|
| +{
|
| + Dart_Handle exception = 0;
|
| + {
|
| + JsInteropScopes scopes(args);
|
| + Dart_Handle function = Dart_GetNativeArgument(args, 0);
|
| + DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateData(args));
|
| + ASSERT(DartUtilities::isFunction(domData, function));
|
| +
|
| + v8::Local<v8::Object> proxy = dartFunctionTemplateNoWrap()->InstanceTemplate()->NewInstance();
|
| + DartHandleProxy::writePointerToProxy(proxy, function);
|
| +
|
| + v8::Local<v8::Function> ret = v8::Local<v8::Function>::Cast(domData->jsInteropData()->captureThisFunction()->Call(proxy, 0, 0));
|
| +
|
| + if (scopes.handleJsException(&exception))
|
| + goto fail;
|
| + scopes.setReturnValue(ret);
|
| + return;
|
| + }
|
| +fail:
|
| + Dart_ThrowException(exception);
|
| + ASSERT_NOT_REACHED();
|
| +}
|
| +
|
| }
|
|
|
| static DartNativeEntry nativeEntries[] = {
|
| @@ -1242,6 +1388,7 @@ static DartNativeEntry nativeEntries[] = {
|
| { JsInteropInternal::interfacesFinalizedCallback, 0, "Js_interfacesFinalized_Callback" },
|
| { JsInteropInternal::jsifyCallback, 1, "JsObject_jsify" },
|
| { JsInteropInternal::withThisCallback, 1, "JsFunction_withThis" },
|
| + { JsInteropInternal::withThisCallbackNoWrap, 1, "JsFunction_withThisNoWrap" },
|
| { JsInterop::jsInteropGetterCallback, 2, "JsObject_[]" },
|
| { JsInteropInternal::setterCallback, 3, "JsObject_[]=" },
|
| { JsInteropInternal::hashCodeCallback, 1, "JsObject_hashCode" },
|
| @@ -1424,7 +1571,7 @@ void arrayHelper1Arg(const v8::FunctionCallbackInfo<v8::Value>& info, const char
|
| if (info.Length() == 0) {
|
| e = Dart_Null();
|
| } else {
|
| - e = JsInterop::toDart(info[0]);
|
| + e = JsInterop::toDart(info[0], false);
|
| }
|
| Dart_Handle args[2] = { handle, e };
|
| Dart_Handle ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCString(methodName), 2, args);
|
| @@ -1442,7 +1589,7 @@ void arrayHelperWithArgsAsList(const v8::FunctionCallbackInfo<v8::Value>& info,
|
| int length = info.Length();
|
| Dart_Handle argsList = Dart_NewList(length);
|
| for (int i = 0; i < length; ++i) {
|
| - Dart_ListSetAt(argsList, i, JsInterop::toDart(info[i]));
|
| + Dart_ListSetAt(argsList, i, JsInterop::toDart(info[i], false));
|
| }
|
| // Note: this is also just info.Holder().
|
| Dart_Handle args[2] = { handle, argsList };
|
| @@ -1485,7 +1632,7 @@ static void arrayNamedPropertySetter(v8::Local<v8::String> property, v8::Local<v
|
| DartScopes scopes(info.Holder());
|
| Dart_Handle handle = scopes.handle;
|
| DartDOMData* domData = DartDOMData::current();
|
| - Dart_Handle args[2] = { handle, JsInterop::toDart(value) };
|
| + Dart_Handle args[2] = { handle, JsInterop::toDart(value, true) };
|
| Dart_Handle ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCString("_setListLength"), 2, args);
|
| setJsReturnValue(domData, info, ret);
|
| }
|
| @@ -1618,6 +1765,36 @@ v8::Local<v8::FunctionTemplate> dartListTemplate()
|
| return proxyTemplateLocal;
|
| }
|
|
|
| +void dartObjectToStringCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
|
| +{
|
| + if (handleNonDartProxyThis(info, "toString")) {
|
| + return;
|
| + }
|
| + DartScopes scopes(info.Holder());
|
| + DartDOMData* domData = DartDOMData::current();
|
| + Dart_Handle handle = scopes.handle;
|
| + setJsReturnValue(domData, info, Dart_ToString(handle));
|
| +}
|
| +
|
| +static v8::Local<v8::FunctionTemplate> dartObjectTemplate()
|
| +{
|
| + DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, proxyTemplate, ());
|
| + v8::Local<v8::FunctionTemplate> proxyTemplateLocal;
|
| + v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| + if (proxyTemplate.IsEmpty()) {
|
| + proxyTemplate.Reset(v8Isolate, v8::FunctionTemplate::New(v8Isolate));
|
| + proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, proxyTemplate);
|
| + v8::Local<v8::ObjectTemplate> protoTemplate = proxyTemplateLocal->PrototypeTemplate();
|
| + protoTemplate->Set(v8::String::NewFromUtf8(v8Isolate, "toString"), v8::FunctionTemplate::New(v8Isolate, dartObjectToStringCallback));
|
| +
|
| + proxyTemplateLocal->SetClassName(v8::String::NewFromUtf8(v8Isolate, "DartObject"));
|
| + setupInstanceTemplate(proxyTemplateLocal);
|
| + } else {
|
| + proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, proxyTemplate);
|
| + }
|
| + return proxyTemplateLocal;
|
| +}
|
| +
|
| void JsInterop::jsInteropGetterCallback(Dart_NativeArguments args)
|
| {
|
| JsInteropInternal::getterCallback(args);
|
|
|