Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(264)

Side by Side Diff: Source/bindings/core/dart/DartJsInterop.cpp

Issue 1177953010: Support new style JS interop (Closed) Base URL: svn://svn.chromium.org/blink/branches/dart/dartium
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 45
46 #include <dart_api.h> 46 #include <dart_api.h>
47 #include <limits> 47 #include <limits>
48 48
49 namespace blink { 49 namespace blink {
50 50
51 const int JsObject::dartClassId = _JsObjectClassId; 51 const int JsObject::dartClassId = _JsObjectClassId;
52 const int JsFunction::dartClassId = _JsFunctionClassId; 52 const int JsFunction::dartClassId = _JsFunctionClassId;
53 const int JsArray::dartClassId = _JsArrayClassId; 53 const int JsArray::dartClassId = _JsArrayClassId;
54 54
55 const char* dartArrayPolyfill =
56 "(function() {"
57 // If filter has already been defined on the DartList prototype,
58 // another DOM isolate has beaten us to polyfilling.
59 " if ($DartList.prototype.hasOwnProperty('filter')) return;"
60 " var isArray = Array.isArray;"
61 " var concat = Array.prototype.concat;"
62 " function makeSafeArgs(args) {"
63 " var len = args.length;"
64 " for (var i = 0; i < len; ++i) {"
65 " var arg = args[i];"
66 " if (arg instanceof $DartList) {"
67 " args[i] = arg.$toJsArray();"
68 " }"
69 " }"
70 " };"
71
72 // If performance becomes an issue, we could implement these
73 // methods in Dart instead of creating a shallow copy JavaScript
74 // array containing the elements of the Dart List and calling
75 // the JavaScript method.
76
77 // Handle methods that take a callback with value, index, and thisArg
78 // parameters. The trick is we need to make thisArg reference the
79 // underlying Dart List rather than the JavaScript copy we create for
80 // implementation convenience.
81 " ['filter', 'forEach', 'some', 'every', 'map'].forEach(function(name) {"
82 " Object.defineProperty($DartList.prototype, name, {enumerable: false, va lue: function(callback, thisArg) {"
83 " var dartList = this;"
84 " return this.$toJsArray()[name](function(value, index) {"
85 " return callback.call(thisArg, value, index, dartList);"
86 " });"
87 " }});"
88 " });"
89
90 " ['slice', 'indexOf', 'lastIndexOf'].forEach(function(name) {"
91 " Object.defineProperty($DartList.prototype, name, {enumerable: false, va lue: function() {"
92 " var jsArray = this.$toJsArray();"
93 " return jsArray[name].apply(jsArray, arguments);"
94 " }});"
95 " });"
96
97 " ['reduce', 'reduceRight'].forEach(function(name) {"
98 " Object.defineProperty($DartList.prototype, name, {enumerable: false, va lue: function(callback, thisArg) {"
99 " var dartList = this;"
100 " return this.$toJsArray()[name](function(previousValue, currentValue, index) {"
101 " return callback.call(thisArg, previousValue, currentValue, index, dartList);"
102 " });"
103 " }});"
104 " });"
105
106 // Arguments to concat that are Arrays are treated differently.
107 // Warning: this will slow down general JavaScript array concat performance in Dartium.
108 " Array.prototype.concat = function() {"
109 " makeSafeArgs(arguments);"
110 " return concat.apply(this, arguments);"
111 " };"
112
113 // Need to make sure that Array.isArray returns true for Dart lists.
114 " Array.isArray = function(arr) {"
115 " return isArray(arr) || (arr instanceof $DartList);"
116 " };"
117 "})();";
118
55 static v8::Local<v8::FunctionTemplate> dartFunctionTemplate(); 119 static v8::Local<v8::FunctionTemplate> dartFunctionTemplate();
56 static v8::Local<v8::FunctionTemplate> dartObjectTemplate(); 120 static v8::Local<v8::FunctionTemplate> dartObjectTemplate();
121 static v8::Local<v8::FunctionTemplate> dartListTemplate();
122
123 // TODO(jacobr): we should really be using this method everywhere instead of
124 // sticking interop methods in the dart:html _Utils class.
125 static Dart_Handle invokeTopLevelJsInteropMethod(DartDOMData* domData, const cha r* methodName, int argCount, Dart_Handle* args)
126 {
127 Dart_PersistentHandle library = domData->jsLibrary();
128 ASSERT(!Dart_IsError(library));
129 return Dart_Invoke(library, Dart_NewStringFromCString(methodName), argCount, args);
130 }
57 131
58 template<typename CallbackInfo> 132 template<typename CallbackInfo>
59 void setJsReturnValue(DartDOMData* domData, CallbackInfo info, Dart_Handle resul t) 133 void setJsReturnValue(DartDOMData* domData, CallbackInfo info, Dart_Handle resul t)
60 { 134 {
61 if (Dart_IsError(result)) { 135 if (Dart_IsError(result)) {
62 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent(); 136 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
63 V8ThrowException::throwException(v8::String::NewFromUtf8(v8Isolate, Dart _GetError(result)), v8Isolate); 137 V8ThrowException::throwException(v8::String::NewFromUtf8(v8Isolate, Dart _GetError(result)), v8Isolate);
64 } else { 138 } else {
65 Dart_Handle exception = 0; 139 Dart_Handle exception = 0;
66 v8::Local<v8::Value> ret = JsInterop::fromDart(domData, result, exceptio n); 140 v8::Local<v8::Value> ret = JsInterop::fromDart(domData, result, exceptio n);
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 if (DartUtilities::isFunction(domData, handle)) { 297 if (DartUtilities::isFunction(domData, handle)) {
224 v8::Local<v8::Object> functionProxy = dartFunctionTemplate()->InstanceTe mplate()->NewInstance(); 298 v8::Local<v8::Object> functionProxy = dartFunctionTemplate()->InstanceTe mplate()->NewInstance();
225 DartHandleProxy::writePointerToProxy(functionProxy, handle); 299 DartHandleProxy::writePointerToProxy(functionProxy, handle);
226 // The raw functionProxy doesn't behave enough like a true JS function 300 // The raw functionProxy doesn't behave enough like a true JS function
227 // so we wrap it in a true JS function. 301 // so we wrap it in a true JS function.
228 return domData->jsInteropData()->wrapDartFunction()->Call(functionProxy, 0, 0); 302 return domData->jsInteropData()->wrapDartFunction()->Call(functionProxy, 0, 0);
229 } 303 }
230 304
231 v8::Local<v8::Object> proxy; 305 v8::Local<v8::Object> proxy;
232 ASSERT(Dart_IsInstance(handle)); 306 ASSERT(Dart_IsInstance(handle));
233 proxy = dartObjectTemplate()->InstanceTemplate()->NewInstance(); 307 // Simulate the behavior of the Dart dev compiler where new List() is
308 // equivalent to a JavaScript array. We accomplish this by creating a
309 // JavaScript object that fakes that it is a JavaScript array but is
310 // actually backed by a Dart list. This is not a breaking change as
311 // existing Dart-JS interop passed arrays as opaque Dart handles.
312 // The jsify method can still be called if you wish to create a copy
313 // of a json like Dart data structure.
314 if (Dart_IsList(handle)) {
315 proxy = dartListTemplate()->InstanceTemplate()->NewInstance();
316 } else {
317 proxy = dartObjectTemplate()->InstanceTemplate()->NewInstance();
318 }
234 DartHandleProxy::writePointerToProxy(proxy, handle); 319 DartHandleProxy::writePointerToProxy(proxy, handle);
235 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent(); 320 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
236 proxy->SetHiddenValue(v8::String::NewFromUtf8(v8Isolate, "dartProxy"), v8::B oolean::New(v8Isolate, true)); 321 proxy->SetHiddenValue(v8::String::NewFromUtf8(v8Isolate, "dartProxy"), v8::B oolean::New(v8Isolate, true));
237 322
238 return proxy; 323 return proxy;
239 } 324 }
240 325
241 JsObject::JsObject(v8::Local<v8::Object> v8Handle) 326 JsObject::JsObject(v8::Local<v8::Object> v8Handle)
242 { 327 {
243 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 328 v8::Isolate* isolate = v8::Isolate::GetCurrent();
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 378
294 if (object->IsArray()) { 379 if (object->IsArray()) {
295 RefPtr<JsArray> jsArray = JsArray::create(object.As<v8::Array>()); 380 RefPtr<JsArray> jsArray = JsArray::create(object.As<v8::Array>());
296 return JsArray::toDart(jsArray); 381 return JsArray::toDart(jsArray);
297 } 382 }
298 383
299 RefPtr<JsObject> jsObject = JsObject::create(object); 384 RefPtr<JsObject> jsObject = JsObject::create(object);
300 return JsObject::toDart(jsObject); 385 return JsObject::toDart(jsObject);
301 } 386 }
302 387
388 static void maybeCreateJsObjectImplClass(DartDOMData* domData)
389 {
390 DartJsInteropData* interopData = domData->jsInteropData();
391 // Skip if the JSObjectImpl class has already been defined.
392 if (interopData->jsObjectImplDefined()) {
393 return;
394 }
395 // Helper method that generates boilerplate source code for
396 // JsObjectImpl, JsFunctionImpl, and JsArrayImpl classes that implement
397 // all Dart types that have been passed to the dart:js registerJsInterfaces
398 // method. The sole purpose of these classes is to ensure that checked mode
399 // allows casting a JsObject to all types implemented by a JsObject.
400 Dart_Handle source = invokeTopLevelJsInteropMethod(domData, "_generateJsObje ctImplPart", 0, 0);
401 ASSERT(Dart_IsString(source));
402
403 Dart_Handle ALLOW_UNUSED ret = Dart_LibraryLoadPatch(domData->jsLibrary(), D art_NewStringFromCString("JsInteropImpl.dart"), source);
404 ASSERT(!Dart_IsError(ret));
405 ret = Dart_FinalizeLoading(false);
406 ASSERT(!Dart_IsError(ret));
407
408 interopData->setJsObjectImplDefined();
409
410 // Start of polyfill work to make Dart List proxies behave like JavaScript
411 // Arrays by monkey patching JavaScript Array and the List JavaScript
412 // proxies as needed.
413 v8::Context::Scope scope(DartUtilities::currentV8Context());
414
415 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
416
417 v8::Local<v8::Function> dartArrayConstructor = dartListTemplate()->GetFuncti on();
418
419 DartUtilities::currentV8Context()->Global()->Set(v8::String::NewFromUtf8(v8I solate, "$DartList"),
420 dartArrayConstructor);
421 V8ScriptRunner::compileAndRunInternalScript(v8::String::NewFromUtf8(v8Isolat e, dartArrayPolyfill), v8Isolate);
422 }
423
303 Dart_Handle JsObject::toDart(PassRefPtr<JsObject> jsObject) 424 Dart_Handle JsObject::toDart(PassRefPtr<JsObject> jsObject)
304 { 425 {
305 return DartDOMWrapper::createWrapper<JsObject>(DartDOMData::current(), jsObj ect.get(), JsObject::dartClassId); 426 DartDOMData* domData = DartDOMData::current();
427 // We need to ensure JsObjectImpl exists before creating the wrapper.
428 maybeCreateJsObjectImplClass(domData);
429 return DartDOMWrapper::createWrapper<JsObject>(domData, jsObject.get(), JsOb ject::dartClassId);
306 } 430 }
307 431
308 JsObject::~JsObject() 432 JsObject::~JsObject()
309 { 433 {
310 v8Object.Reset(); 434 v8Object.Reset();
311 } 435 }
312 436
313 Dart_Handle JsFunction::toDart(PassRefPtr<JsFunction> jsFunction) 437 Dart_Handle JsFunction::toDart(PassRefPtr<JsFunction> jsFunction)
314 { 438 {
315 return DartDOMWrapper::createWrapper<JsFunction>(DartDOMData::current(), jsF unction.get(), JsFunction::dartClassId); 439 DartDOMData* domData = DartDOMData::current();
440 // We need to ensure JsObjectImpl exists before creating the wrapper.
441 maybeCreateJsObjectImplClass(domData);
442 return DartDOMWrapper::createWrapper<JsFunction>(domData, jsFunction.get(), JsFunction::dartClassId);
316 } 443 }
317 444
318 JsFunction::JsFunction(v8::Local<v8::Function> v8Handle) : JsObject(v8Handle) { } 445 JsFunction::JsFunction(v8::Local<v8::Function> v8Handle) : JsObject(v8Handle) { }
319 446
320 PassRefPtr<JsFunction> JsFunction::create(v8::Local<v8::Function> v8Handle) 447 PassRefPtr<JsFunction> JsFunction::create(v8::Local<v8::Function> v8Handle)
321 { 448 {
322 return adoptRef(new JsFunction(v8Handle)); 449 return adoptRef(new JsFunction(v8Handle));
323 } 450 }
324 451
325 v8::Local<v8::Function> JsFunction::localV8Function() 452 v8::Local<v8::Function> JsFunction::localV8Function()
326 { 453 {
327 return localV8Object().As<v8::Function>(); 454 return localV8Object().As<v8::Function>();
328 } 455 }
329 456
330 Dart_Handle JsArray::toDart(PassRefPtr<JsArray> jsArray) 457 Dart_Handle JsArray::toDart(PassRefPtr<JsArray> jsArray)
331 { 458 {
332 return DartDOMWrapper::createWrapper<JsArray>(DartDOMData::current(), jsArra y.get(), JsArray::dartClassId); 459 DartDOMData* domData = DartDOMData::current();
460 // We need to ensure JsArrayImpl exists before creating the wrapper.
461 maybeCreateJsObjectImplClass(domData);
462 return DartDOMWrapper::createWrapper<JsArray>(domData, jsArray.get(), JsArra y::dartClassId);
333 } 463 }
334 464
335 JsArray::JsArray(v8::Local<v8::Array> v8Handle) : JsObject(v8Handle) { } 465 JsArray::JsArray(v8::Local<v8::Array> v8Handle) : JsObject(v8Handle) { }
336 466
337 PassRefPtr<JsArray> JsArray::create(v8::Local<v8::Array> v8Handle) 467 PassRefPtr<JsArray> JsArray::create(v8::Local<v8::Array> v8Handle)
338 { 468 {
339 return adoptRef(new JsArray(v8Handle)); 469 return adoptRef(new JsArray(v8Handle));
340 } 470 }
341 471
342 v8::Local<v8::Array> JsArray::localV8Array() 472 v8::Local<v8::Array> JsArray::localV8Array()
(...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after
865 ASSERT_NOT_REACHED(); 995 ASSERT_NOT_REACHED();
866 } 996 }
867 997
868 static void contextCallback(Dart_NativeArguments args) 998 static void contextCallback(Dart_NativeArguments args)
869 { 999 {
870 v8::Local<v8::Context> v8Context = DartUtilities::currentV8Context(); 1000 v8::Local<v8::Context> v8Context = DartUtilities::currentV8Context();
871 v8::Context::Scope scope(v8Context); 1001 v8::Context::Scope scope(v8Context);
872 Dart_SetReturnValue(args, JsObject::toDart(v8Context->Global())); 1002 Dart_SetReturnValue(args, JsObject::toDart(v8Context->Global()));
873 } 1003 }
874 1004
1005 static void finalizeJsInterfacesCallback(Dart_NativeArguments args)
1006 {
1007 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateData(a rgs));
1008 maybeCreateJsObjectImplClass(domData);
1009 }
1010
875 v8::Handle<v8::Value> mapToV8(DartDOMData* domData, Dart_Handle value, DartHandl eToV8Map& map, Dart_Handle& exception) 1011 v8::Handle<v8::Value> mapToV8(DartDOMData* domData, Dart_Handle value, DartHandl eToV8Map& map, Dart_Handle& exception)
876 { 1012 {
877 Dart_Handle asList = DartUtilities::invokeUtilsMethod("convertMapToList", 1, &value); 1013 Dart_Handle asList = DartUtilities::invokeUtilsMethod("convertMapToList", 1, &value);
878 if (!DartUtilities::checkResult(asList, exception)) 1014 if (!DartUtilities::checkResult(asList, exception))
879 return v8::Handle<v8::Value>(); 1015 return v8::Handle<v8::Value>();
880 ASSERT(Dart_IsList(asList)); 1016 ASSERT(Dart_IsList(asList));
881 1017
882 // Now we have a list [key, value, key, value, ....], create a v8 object and set necesary 1018 // Now we have a list [key, value, key, value, ....], create a v8 object and set necesary
883 // properties on it. 1019 // properties on it.
884 v8::Handle<v8::Object> object = v8::Object::New(v8::Isolate::GetCurrent()); 1020 v8::Handle<v8::Object> object = v8::Object::New(v8::Isolate::GetCurrent());
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
1003 fail: 1139 fail:
1004 Dart_ThrowException(exception); 1140 Dart_ThrowException(exception);
1005 ASSERT_NOT_REACHED(); 1141 ASSERT_NOT_REACHED();
1006 } 1142 }
1007 1143
1008 } 1144 }
1009 1145
1010 static DartNativeEntry nativeEntries[] = { 1146 static DartNativeEntry nativeEntries[] = {
1011 { JsInteropInternal::jsObjectConstructorCallback, 2, "JsObject_constructorCa llback" }, 1147 { JsInteropInternal::jsObjectConstructorCallback, 2, "JsObject_constructorCa llback" },
1012 { JsInteropInternal::contextCallback, 0, "Js_context_Callback" }, 1148 { JsInteropInternal::contextCallback, 0, "Js_context_Callback" },
1149 { JsInteropInternal::finalizeJsInterfacesCallback, 0, "Js_finalizeJsInterfac es" },
1013 { JsInteropInternal::jsifyCallback, 1, "JsObject_jsify" }, 1150 { JsInteropInternal::jsifyCallback, 1, "JsObject_jsify" },
1014 { JsInteropInternal::withThisCallback, 1, "JsFunction_withThis" }, 1151 { JsInteropInternal::withThisCallback, 1, "JsFunction_withThis" },
1015 { JsInteropInternal::getterCallback, 2, "JsObject_[]" }, 1152 { JsInteropInternal::getterCallback, 2, "JsObject_[]" },
1016 { JsInteropInternal::setterCallback, 3, "JsObject_[]=" }, 1153 { JsInteropInternal::setterCallback, 3, "JsObject_[]=" },
1017 { JsInteropInternal::hashCodeCallback, 1, "JsObject_hashCode" }, 1154 { JsInteropInternal::hashCodeCallback, 1, "JsObject_hashCode" },
1018 { JsInteropInternal::callMethodCallback, 3, "JsObject_callMethod" }, 1155 { JsInteropInternal::callMethodCallback, 3, "JsObject_callMethod" },
1019 { JsInteropInternal::toStringCallback, 1, "JsObject_toString" }, 1156 { JsInteropInternal::toStringCallback, 1, "JsObject_toString" },
1020 { JsInteropInternal::identityEqualityCallback, 2, "JsObject_identityEquality " }, 1157 { JsInteropInternal::identityEqualityCallback, 2, "JsObject_identityEquality " },
1021 { JsInteropInternal::hasPropertyCallback, 2, "JsObject_hasProperty" }, 1158 { JsInteropInternal::hasPropertyCallback, 2, "JsObject_hasProperty" },
1022 { JsInteropInternal::deletePropertyCallback, 2, "JsObject_deleteProperty" }, 1159 { JsInteropInternal::deletePropertyCallback, 2, "JsObject_deleteProperty" },
(...skipping 25 matching lines...) Expand all
1048 const uint8_t* JsInterop::symbolizer(Dart_NativeFunction nf) 1185 const uint8_t* JsInterop::symbolizer(Dart_NativeFunction nf)
1049 { 1186 {
1050 for (intptr_t i = 0; nativeEntries[i].nativeFunction != 0; i++) { 1187 for (intptr_t i = 0; nativeEntries[i].nativeFunction != 0; i++) {
1051 if (nf == nativeEntries[i].nativeFunction) { 1188 if (nf == nativeEntries[i].nativeFunction) {
1052 return reinterpret_cast<const uint8_t*>(nativeEntries[i].name); 1189 return reinterpret_cast<const uint8_t*>(nativeEntries[i].name);
1053 } 1190 }
1054 } 1191 }
1055 return 0; 1192 return 0;
1056 } 1193 }
1057 1194
1058 } 1195 // Methods enabling a Dart List to emulate a JS Array.
1196 static void indexedGetterArray(uint32_t index, const v8::PropertyCallbackInfo<v8 ::Value>& info)
1197 {
1198 DartScopes scopes(info.Holder());
1199 Dart_Handle handle = scopes.handle;
1200 DartDOMData* domData = DartDOMData::current();
1201 Dart_Handle ret = 0;
1202 ASSERT(Dart_IsList(handle));
1203 ret = Dart_ListGetAt(handle, index);
1204 if (Dart_IsError(ret)) {
1205 // Return undefined if the index is invalid to match JS semantics.
1206 // TODO(jacobr): we should log to the console warning of bad use of a
1207 // Dart List.
1208 return;
1209 }
1210 setJsReturnValue(domData, info, ret);
1211 }
1212
1213 static void indexedSetterArray(uint32_t index, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)
1214 {
1215 DartScopes scopes(info.Holder());
1216 Dart_Handle handle = scopes.handle;
1217 DartDOMData* domData = DartDOMData::current();
1218
1219 Dart_Handle ret = 0;
1220 ASSERT(Dart_IsList(handle));
1221 intptr_t length = 0;
1222 ret = Dart_ListLength(handle, &length);
1223 ASSERT(!Dart_IsError(ret));
1224 if (index >= length) {
1225 // Approximate JS semantics by filling the list with nulls if we
1226 // attempt to add an element past the end of the list.
1227 // TODO(jacobr): ideally we would match JS semantics exactly and fill
1228 // the list with undefined.
1229 Dart_Handle args[2] = { handle, DartUtilities::unsignedToDart(index + 1) };
1230 ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCString("_arra yExtend"), 2, args);
1231 ASSERT(!Dart_IsError(ret));
1232 }
1233 ret = Dart_ListSetAt(handle, index, DartHandleProxy::unwrapValue(value));
1234 if (Dart_IsError(ret)) {
1235 // Return undefined if the index is invalid to match JS semantics.
1236 // TODO(jacobr): we should log to the console warning of bad use of a
1237 // Dart list or add a JS expando to the object ala JS.
1238 }
1239 setJsReturnValue(domData, info, ret);
1240 }
1241
1242 static void indexedEnumeratorArray(const v8::PropertyCallbackInfo<v8::Array>& in fo)
1243 {
1244 DartScopes scopes(info.Holder());
1245 Dart_Handle handle = scopes.handle;
1246
1247 intptr_t length = 0;
1248 ASSERT(Dart_IsList(handle));
1249 Dart_ListLength(handle, &length);
1250
1251 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1252 v8::Local<v8::Array> indexes = v8::Array::New(v8Isolate, length);
1253 for (int i = 0; i < length; i++)
1254 indexes->Set(i, v8::Integer::New(v8Isolate, i));
1255
1256 v8SetReturnValue(info, indexes);
1257 }
1258
1259 v8::Handle<v8::Array> shallowListToV8(Dart_Handle value, DartDOMData* domData, D art_Handle& exception)
1260 {
1261 ASSERT(Dart_IsList(value));
1262
1263 intptr_t length = 0;
1264 Dart_Handle result = Dart_ListLength(value, &length);
1265 if (!DartUtilities::checkResult(result, exception))
1266 return v8::Handle<v8::Array>();
1267
1268 v8::Local<v8::Array> array = v8::Array::New(v8::Isolate::GetCurrent(), lengt h);
1269
1270 for (intptr_t i = 0; i < length; ++i) {
1271 result = Dart_ListGetAt(value, i);
1272 v8::Handle<v8::Value> v8value = JsInterop::fromDart(domData, result, exc eption);
1273 // TODO(jacobr): is there a better way to handle this error case?
1274 if (exception)
1275 return v8::Handle<v8::Array>();
1276 array->Set(i, v8value);
1277 }
1278 return array;
1279 }
1280
1281 void arrayHelper(const v8::FunctionCallbackInfo<v8::Value>& info, const char* me thodName)
1282 {
1283 // We need to bail out if "this" is not a Dart proxy or we will crash the VM .
1284 // TODO(jacob): we could generate a user readable error message instead of
1285 // just returning.
1286 if (!DartHandleProxy::isDartProxy(info.Holder())) {
1287 return;
1288 }
1289 DartScopes scopes(info.Holder());
1290 DartDOMData* domData = DartDOMData::current();
1291 Dart_Handle handle = scopes.handle;
1292 Dart_Handle ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCStrin g(methodName), 1, &handle);
1293 setJsReturnValue(domData, info, ret);
1294 }
1295
1296 void arrayHelper1Arg(const v8::FunctionCallbackInfo<v8::Value>& info, const char * methodName)
1297 {
1298 // We need to bail out if "this" is not a Dart proxy or we will crash the VM .
1299 // TODO(jacob): we could generate a user readable error message instead of
1300 // just returning.
1301 if (!DartHandleProxy::isDartProxy(info.Holder())) {
1302 return;
1303 }
1304 DartScopes scopes(info.Holder());
1305 DartDOMData* domData = DartDOMData::current();
1306 Dart_Handle handle = scopes.handle;
1307 Dart_Handle e;
1308 if (info.Length() == 0) {
1309 e = Dart_Null();
1310 } else {
1311 e = JsInterop::toDart(info[0]);
1312 }
1313 Dart_Handle args[2] = { handle, e };
1314 Dart_Handle ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCStrin g(methodName), 2, args);
1315 setJsReturnValue(domData, info, ret);
1316 }
1317
1318 static void arrayNamedPropertyGetter(v8::Local<v8::String> name, const v8::Prope rtyCallbackInfo<v8::Value>& info)
1319 {
1320 if (!DartHandleProxy::isDartProxy(info.Holder())) {
1321 return;
1322 }
1323
1324 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1325 if (!name->Equals(v8::String::NewFromUtf8(v8Isolate, "length")))
1326 return;
1327
1328 DartScopes scopes(info.Holder());
1329 Dart_Handle handle = scopes.handle;
1330
1331 intptr_t length = 0;
1332 Dart_ListLength(handle, &length);
1333 v8SetReturnValueInt(info, length);
1334 }
1335
1336 static void arrayNamedPropertySetter(v8::Local<v8::String> property, v8::Local<v 8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)
1337 {
1338 if (!DartHandleProxy::isDartProxy(info.Holder())) {
1339 return;
1340 }
1341
1342 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1343 if (!property->Equals(v8::String::NewFromUtf8(v8Isolate, "length"))) {
1344 return;
1345 }
1346
1347 DartScopes scopes(info.Holder());
1348 Dart_Handle handle = scopes.handle;
1349 DartDOMData* domData = DartDOMData::current();
1350 Dart_Handle args[2] = { handle, JsInterop::toDart(value) };
1351 Dart_Handle ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCStrin g("_setListLength"), 2, args);
1352 setJsReturnValue(domData, info, ret);
1353 }
1354
1355 static void arrayQueryProperty(v8::Local<v8::String> name, const v8::PropertyCal lbackInfo<v8::Integer>& info)
1356 {
1357 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1358 if (name->Equals(v8::String::NewFromUtf8(v8Isolate, "length"))) {
1359 v8SetReturnValueInt(info, v8::DontEnum | v8::DontDelete);
1360 }
1361 }
1362
1363 static void arrayDeleteProperty(v8::Local<v8::String> name, const v8::PropertyCa llbackInfo<v8::Boolean>& info)
1364 {
1365 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1366 if (name->Equals(v8::String::NewFromUtf8(v8Isolate, "length"))) {
1367 v8SetReturnValueBool(info, false);
1368 }
1369 }
1370
1371 void arrayToStringCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1372 {
1373 arrayHelper(info, "_arrayToString");
1374 }
1375
1376
1377 void arrayJoinCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1378 {
1379 arrayHelper1Arg(info, "_arrayJoin");
1380 }
1381
1382 void arrayPushCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1383 {
1384 arrayHelper1Arg(info, "_arrayPush");
1385 }
1386
1387 void arrayPopCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1388 {
1389 arrayHelper(info, "_arrayPop");
1390 }
1391
1392 void arrayHelperWithArgsAsList(const v8::FunctionCallbackInfo<v8::Value>& info, const char* methodName)
1393 {
1394 // We need to bail out if "this" is not a Dart proxy or we will crash the VM .
1395 // TODO(jacob): we could generate a user readable error message instead of
1396 // just returning.
1397 if (!DartHandleProxy::isDartProxy(info.Holder())) {
1398 return;
1399 }
1400 DartScopes scopes(info.Holder());
1401 DartDOMData* domData = DartDOMData::current();
1402 Dart_Handle handle = scopes.handle;
1403 int length = info.Length();
1404 Dart_Handle argsList = Dart_NewList(length);
1405 for (int i = 0; i < length; ++i) {
1406 Dart_ListSetAt(argsList, i, JsInterop::toDart(info[i]));
1407 }
1408 // Note: this is also just info.Holder().
1409 Dart_Handle args[2] = { handle, argsList };
1410 setJsReturnValue(domData, info, Dart_Invoke(domData->jsLibrary(), Dart_NewSt ringFromCString(methodName), 2, args));
1411 }
1412
1413 void concatCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1414 {
1415 arrayHelperWithArgsAsList(info, "_arrayConcat");
1416 }
1417
1418 void arrayReverseCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1419 {
1420 arrayHelper(info, "_arrayReverse");
1421 }
1422
1423 void arrayShiftCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1424 {
1425 arrayHelper(info, "_arrayShift");
1426 }
1427
1428 void arrayUnshiftCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1429 {
1430 arrayHelperWithArgsAsList(info, "_arrayUnshift");
1431 }
1432
1433 void arraySpliceCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1434 {
1435 arrayHelperWithArgsAsList(info, "_arraySplice");
1436 }
1437
1438 void toJsArrayCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1439 {
1440 if (!DartHandleProxy::isDartProxy(info.Holder())) {
1441 return;
1442 }
1443 DartScopes scopes(info.Holder());
1444 DartDOMData* domData = DartDOMData::current();
1445 Dart_Handle handle = scopes.handle;
1446 Dart_Handle exception = 0;
1447 v8::Local<v8::Array> v8Array = shallowListToV8(handle, domData, exception);
1448 ASSERT(!exception);
1449 v8SetReturnValue(info, v8Array);
1450 }
1451
1452 void arraySortCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1453 {
1454 // TODO(jacobr): consider using the JavaScript sort method instead.
1455 arrayHelper1Arg(info, "_arraySort");
1456 }
1457
1458 v8::Local<v8::FunctionTemplate> dartListTemplate()
1459 {
1460 DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, proxyTemplate, ()) ;
1461 v8::Local<v8::FunctionTemplate> proxyTemplateLocal;
1462 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1463 if (proxyTemplate.IsEmpty()) {
1464 proxyTemplate.Reset(v8::Isolate::GetCurrent(), v8::FunctionTemplate::New (v8Isolate));
1465 proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, pro xyTemplate);
1466 // Set to Array because we want these instances to appear to be
1467 // JavaScript arrays as far as user code is concerned.
1468 proxyTemplateLocal->SetClassName(v8::String::NewFromUtf8(v8Isolate, "Arr ay"));
1469 // Hack to set the prototype to be the prototype of an actual JavaScript Array.
1470
1471 v8::Local<v8::ObjectTemplate> protoTemplate = proxyTemplateLocal->Proto typeTemplate();
1472
1473 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "toString"), v8:: FunctionTemplate::New(v8Isolate, arrayToStringCallback), v8::DontEnum);
1474 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "join"), v8::Func tionTemplate::New(v8Isolate, arrayJoinCallback), v8::DontEnum);
1475 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "push"), v8::Func tionTemplate::New(v8Isolate, arrayPushCallback), v8::DontEnum);
1476 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "pop"), v8::Funct ionTemplate::New(v8Isolate, arrayPopCallback), v8::DontEnum);
1477 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "concat"), v8::Fu nctionTemplate::New(v8Isolate, concatCallback), v8::DontEnum);
1478 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "reverse"), v8::F unctionTemplate::New(v8Isolate, arrayReverseCallback), v8::DontEnum);
1479
1480 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "shift"), v8::Fun ctionTemplate::New(v8Isolate, arrayShiftCallback), v8::DontEnum);
1481 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "unshift"), v8::F unctionTemplate::New(v8Isolate, arrayUnshiftCallback), v8::DontEnum);
1482 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "splice"), v8::Fu nctionTemplate::New(v8Isolate, arraySpliceCallback), v8::DontEnum);
1483 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "sort"), v8::Func tionTemplate::New(v8Isolate, arraySortCallback), v8::DontEnum);
1484 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "$toJsArray"), v8 ::FunctionTemplate::New(v8Isolate, toJsArrayCallback), v8::DontEnum);
1485
1486 // ES6 experimental properties not currently supported that we could sup port if needed.
1487 // These would require building separate live proxy objects.
1488 // "entries",
1489 // "values",
1490 // "keys"
1491
1492 v8::Local<v8::ObjectTemplate> instanceTemplate = setupInstanceTemplate(p roxyTemplateLocal);
1493 instanceTemplate->SetIndexedPropertyHandler(&indexedGetterArray, &indexe dSetterArray, 0, 0, &indexedEnumeratorArray);
1494 instanceTemplate->SetNamedPropertyHandler(&arrayNamedPropertyGetter, &ar rayNamedPropertySetter, &arrayQueryProperty, &arrayDeleteProperty, 0);
1495 } else {
1496 proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, pro xyTemplate);
1497 }
1498 return proxyTemplateLocal;
1499 }
1500
1501 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698