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

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

Issue 1532413002: Added Dartium changes onto 45.0.2454.104 (Closed) Base URL: http://src.chromium.org/blink/branches/chromium/2454
Patch Set: Created 5 years 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
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include "config.h"
31
32 #include "bindings/core/dart/DartJsInterop.h"
33
34 #include "bindings/core/dart/DartDOMWrapper.h"
35 #include "bindings/core/dart/DartHandleProxy.h"
36 #include "bindings/core/dart/DartJsInteropData.h"
37 #include "bindings/core/dart/DartPersistentValue.h"
38 #include "bindings/core/dart/DartUtilities.h"
39 #include "bindings/core/dart/V8Converter.h"
40 #include "bindings/core/v8/V8Binding.h"
41 #include "bindings/core/v8/V8Element.h"
42 #include "bindings/core/v8/V8RecursionScope.h"
43 #include "bindings/core/v8/V8ScriptRunner.h"
44 #include "core/dom/Element.h"
45
46 #include "wtf/StdLibExtras.h"
47
48 #include <dart_api.h>
49 #include <limits>
50
51 namespace blink {
52
53 const int JsObject::dartClassId = _JsObjectClassId;
54 const int JsFunction::dartClassId = _JsFunctionClassId;
55 const int JsArray::dartClassId = _JsArrayClassId;
56
57 // TODO(jacobr): v8::String::NewFromUtf8 usages should be cached for constant
58 // strings to improve performance.
59 /**
60 * Polyfill script to make Dart List objects look like JavaScript arrays when
61 * passed to JavaScript via JavaScript interop. Handling the edge cases
62 * requires patching the JavaScript Array prototype for a couple methods
63 * and implementing all of the JavaScript Array methods on the JavaScript
64 * proxy object for the Dart List. Some of the JavaScript methods are
65 * implemented in Dart and C++ code, some are implemented in this JavaScript
66 * polyfill script.
67 */
68 const char* dartArrayPolyfill =
69 "(function() {"
70 // If filter has already been defined on the DartList prototype,
71 // another DOM isolate has beaten us to polyfilling.
72 " if ($DartList.prototype.hasOwnProperty('filter')) return;"
73 // This hack is required so that someDartList instanceof Array == true.
74 " $DartList.prototype.__proto__ = Array.prototype;"
75 " $DartList.__proto__ = Array;"
76 // This hack is required for libraries such as jQuery that detect arrays
77 // by looking at the constructor property treat $DartList as Array.
78 " $DartList.prototype.constructor = Array;"
79 " var isArray = Array.isArray;"
80 " var concat = Array.prototype.concat;"
81 " var blob = Blob;"
82 " function makeSafeArg(arg) {"
83 " return (arg instanceof $DartList) ? arg.$toJsArray() : arg;"
84 " };"
85 " function makeSafeArgs(args) {"
86 " var len = args.length;"
87 " for (var i = 0; i < len; ++i) {"
88 " var arg = args[i];"
89 " if (arg instanceof $DartList) {"
90 " args[i] = arg.$toJsArray();"
91 " }"
92 " }"
93 " };"
94
95 // If performance becomes an issue, we could implement these
96 // methods in Dart instead of creating a shallow copy JavaScript
97 // array containing the elements of the Dart List and calling
98 // the JavaScript method.
99
100 // Handle methods that take a callback with value, index, and thisArg
101 // parameters. The trick is we need to make thisArg reference the
102 // underlying Dart List rather than the JavaScript copy we create for
103 // implementation convenience.
104 " ['filter', 'forEach', 'some', 'every', 'map'].forEach(function(name) {"
105 " Object.defineProperty($DartList.prototype, name, {enumerable: false, va lue: function(callback, thisArg) {"
106 " var dartList = this;"
107 " return this.$toJsArray()[name](function(value, index) {"
108 " return callback.call(thisArg, value, index, dartList);"
109 " });"
110 " }});"
111 " });"
112
113 " ['slice', 'indexOf', 'lastIndexOf'].forEach(function(name) {"
114 " Object.defineProperty($DartList.prototype, name, {enumerable: false, va lue: function() {"
115 " var jsArray = this.$toJsArray();"
116 " return jsArray[name].apply(jsArray, arguments);"
117 " }});"
118 " });"
119
120 " ['reduce', 'reduceRight'].forEach(function(name) {"
121 " Object.defineProperty($DartList.prototype, name, {enumerable: false, va lue: function(callback, thisArg) {"
122 " var dartList = this;"
123 " return this.$toJsArray()[name](function(previousValue, currentValue, index) {"
124 " return callback.call(thisArg, previousValue, currentValue, index, dartList);"
125 " });"
126 " }});"
127 " });"
128
129 // Arguments to concat that are Arrays are treated differently.
130 // Warning: this will slow down general JavaScript array concat performance in Dartium.
131 " Array.prototype.concat = function() {"
132 " makeSafeArgs(arguments);"
133 " return concat.apply(this, arguments);"
134 " };"
135
136 // The Blob constructor cannot handle our psuedo Arrays.
137 // Warning: this will slow down general Blob constructor performance in Dart ium.
138 " Blob = function(array, options) {"
139 " if (arguments.length < 2) return new blob(makeSafeArg(array));"
140 " else return new blob(makeSafeArg(array), options);"
141 " };"
142
143 // Need to make sure that Array.isArray returns true for Dart lists.
144 " Array.isArray = function(arr) {"
145 " return isArray(arr) || (arr instanceof $DartList);"
146 " };"
147 "})();";
148
149 static v8::Local<v8::FunctionTemplate> dartFunctionTemplate();
150 static v8::Local<v8::FunctionTemplate> dartObjectTemplate();
151 static v8::Local<v8::FunctionTemplate> dartListTemplate();
152
153 // TODO(jacobr): we should really be using this method everywhere instead of
154 // sticking interop methods in the dart:html _Utils class.
155 static Dart_Handle invokeTopLevelJsInteropMethod(DartDOMData* domData, const cha r* methodName, int argCount, Dart_Handle* args)
156 {
157 Dart_PersistentHandle library = domData->jsLibrary();
158 ASSERT(!Dart_IsError(library));
159 return Dart_Invoke(library, Dart_NewStringFromCString(methodName), argCount, args);
160 }
161
162 template<typename CallbackInfo>
163 void setJsReturnValue(DartDOMData* domData, CallbackInfo info, Dart_Handle resul t)
164 {
165 if (Dart_IsError(result)) {
166 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
167 V8ThrowException::throwException(v8::String::NewFromUtf8(v8Isolate, Dart _GetError(result)), v8Isolate);
168 } else {
169 Dart_Handle exception = 0;
170 v8::Local<v8::Value> ret = JsInterop::fromDart(domData, result, exceptio n);
171 if (exception) {
172 V8ThrowException::throwException(V8Converter::stringToV8(Dart_ToStri ng(exception)), v8::Isolate::GetCurrent());
173 return;
174 }
175 v8SetReturnValue(info, ret);
176 }
177 }
178
179 static void functionInvocationCallback(const v8::FunctionCallbackInfo<v8::Value> & args)
180 {
181 DartScopes scopes(args.Holder());
182 Dart_Handle handle = scopes.handle;
183 DartDOMData* domData = DartDOMData::current();
184 ASSERT(domData);
185 ASSERT(DartUtilities::isFunction(domData, handle));
186
187 Vector<Dart_Handle> dartFunctionArgs;
188 ASSERT(args.Length() == 1 || args.Length() == 2);
189 // If there is 1 argument, we assume it is a v8:Array or arguments, if
190 // there are 2 arguments, the first argument is "this" and the second
191 // argument is an array of arguments.
192 if (args.Length() > 1) {
193 dartFunctionArgs.append(JsInterop::toDart(args[0]));
194 }
195
196 v8::Local<v8::Array> argsList = args[args.Length()-1].As<v8::Array>();
197 uint32_t argsListLength = argsList->Length();
198 for (uint32_t i = 0; i < argsListLength; i++) {
199 dartFunctionArgs.append(JsInterop::toDart(argsList->Get(i)));
200 }
201
202 setJsReturnValue(domData, args, Dart_InvokeClosure(handle, dartFunctionArgs. size(), dartFunctionArgs.data()));
203 }
204
205 static v8::Local<v8::ObjectTemplate> setupInstanceTemplate(v8::Local<v8::Functio nTemplate> proxyTemplate)
206 {
207 v8::Local<v8::ObjectTemplate> instanceTemplate = proxyTemplate->InstanceTemp late();
208 instanceTemplate->SetInternalFieldCount(1);
209 return instanceTemplate;
210 }
211
212 static v8::Local<v8::FunctionTemplate> dartFunctionTemplate()
213 {
214 DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, proxyTemplate, ()) ;
215 v8::Local<v8::FunctionTemplate> proxyTemplateLocal;
216 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
217 if (proxyTemplate.IsEmpty()) {
218 proxyTemplate.Reset(v8::Isolate::GetCurrent(), v8::FunctionTemplate::New (v8Isolate));
219 proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, pro xyTemplate);
220 v8::Local<v8::ObjectTemplate> instanceTemplate = setupInstanceTemplate(p roxyTemplateLocal);
221
222 instanceTemplate->SetCallAsFunctionHandler(&functionInvocationCallback);
223 } else {
224 proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, pro xyTemplate);
225 }
226 return proxyTemplateLocal;
227 }
228
229 static v8::Local<v8::FunctionTemplate> dartObjectTemplate()
230 {
231 DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, proxyTemplate, ()) ;
232 v8::Local<v8::FunctionTemplate> proxyTemplateLocal;
233 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
234 if (proxyTemplate.IsEmpty()) {
235 proxyTemplate.Reset(v8Isolate, v8::FunctionTemplate::New(v8Isolate));
236 proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, pro xyTemplate);
237 proxyTemplateLocal->SetClassName(v8::String::NewFromUtf8(v8Isolate, "Dar tObject"));
238 setupInstanceTemplate(proxyTemplateLocal);
239 } else {
240 proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, pro xyTemplate);
241 }
242 return proxyTemplateLocal;
243 }
244
245 /**
246 * Helper class to manage scopes needed for JSInterop code.
247 */
248 class JsInteropScopes {
249 public:
250 Dart_NativeArguments args;
251 v8::Context::Scope v8Scope;
252 v8::TryCatch tryCatch;
253
254 JsInteropScopes(Dart_NativeArguments args)
255 : args(args)
256 , v8Scope(DartUtilities::currentV8Context())
257 {
258 ASSERT(v8::Isolate::GetCurrent());
259 }
260
261 ~JsInteropScopes()
262 {
263 // The user is expected to call handleJsException before the scope is
264 // closed so that V8 exceptions are properly sent back to Dart.
265 ASSERT(!tryCatch.HasCaught());
266 }
267
268 bool handleJsException(Dart_Handle* exception)
269 {
270 if (!tryCatch.HasCaught())
271 return false;
272 // FIXME: terminate v8 if tryCatch.CanContinue() is false.
273 ASSERT(tryCatch.CanContinue());
274 ASSERT(exception);
275 v8::Handle<v8::Value> ex(tryCatch.Exception()->ToString());
276 if (ex.IsEmpty()) {
277 *exception = Dart_NewStringFromCString("Empty JavaScript exception") ;
278 } else {
279 *exception = V8Converter::stringToDart(ex);
280 }
281 tryCatch.Reset();
282 return true;
283 }
284
285 void setReturnValue(Dart_Handle ret)
286 {
287 ASSERT(!tryCatch.HasCaught());
288 Dart_SetReturnValue(args, ret);
289 }
290
291 void setReturnValue(v8::Local<v8::Value> ret)
292 {
293 ASSERT(!tryCatch.HasCaught());
294 Dart_SetReturnValue(args, JsInterop::toDart(ret));
295 ASSERT(!tryCatch.HasCaught());
296 }
297
298 void setReturnValueInteger(int64_t ret)
299 {
300 ASSERT(!tryCatch.HasCaught());
301 Dart_SetIntegerReturnValue(args, ret);
302 }
303 };
304
305 PassRefPtr<JsObject> JsObject::create(v8::Local<v8::Object> v8Handle)
306 {
307 return adoptRef(new JsObject(v8Handle));
308 }
309
310 v8::Local<v8::Value> JsInterop::fromDart(DartDOMData* domData, Dart_Handle handl e, Dart_Handle& exception)
311 {
312 v8::Handle<v8::Value> value = V8Converter::toV8IfPrimitive(domData, handle, exception);
313 if (!value.IsEmpty() || exception)
314 return value;
315 // TODO(terry): START of uncommented block by Jacob, I've re-enabled for cla mped arrays...
316 value = V8Converter::toV8IfBrowserNative(domData, handle, exception);
317 if (!value.IsEmpty() || exception)
318 return value;
319 // TODO(terry): END of uncommented block by Jacob.
320 if (DartDOMWrapper::subtypeOf(handle, JsObject::dartClassId)) {
321 JsObject* object = DartDOMWrapper::unwrapDartWrapper<JsObject>(domData, handle, exception);
322 if (exception)
323 return v8::Local<v8::Value>();
324 return object->localV8Object();
325 }
326
327 if (DartUtilities::isFunction(domData, handle)) {
328 v8::Local<v8::Object> functionProxy = dartFunctionTemplate()->InstanceTe mplate()->NewInstance();
329 DartHandleProxy::writePointerToProxy(functionProxy, handle);
330 // The raw functionProxy doesn't behave enough like a true JS function
331 // so we wrap it in a true JS function.
332 return domData->jsInteropData()->wrapDartFunction()->Call(functionProxy, 0, 0);
333 }
334
335 v8::Local<v8::Object> proxy;
336 ASSERT(Dart_IsInstance(handle));
337 // Simulate the behavior of the Dart dev compiler where new List() is
338 // equivalent to a JavaScript array. We accomplish this by creating a
339 // JavaScript object that fakes that it is a JavaScript array but is
340 // actually backed by a Dart list. This is not a breaking change as
341 // existing Dart-JS interop passed arrays as opaque Dart handles.
342 // The jsify method can still be called if you wish to create a copy
343 // of a json like Dart data structure.
344 if (Dart_IsList(handle)) {
345 proxy = dartListTemplate()->InstanceTemplate()->NewInstance();
346 } else {
347 proxy = dartObjectTemplate()->InstanceTemplate()->NewInstance();
348 }
349 DartHandleProxy::writePointerToProxy(proxy, handle);
350 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
351 proxy->SetHiddenValue(v8::String::NewFromUtf8(v8Isolate, "dartProxy"), v8::B oolean::New(v8Isolate, true));
352
353 return proxy;
354 }
355
356 // Given a Blink Element instance, make it a V8Object that can then be returned
357 // as a Dart JsObject that holds the Javascript object (V8Object).
358 void JsInterop::returnBlinkElement(Element* value, Dart_NativeArguments args, Da rt_Handle& exception)
359 {
360 JsInteropScopes scopes(args);
361
362 V8ScriptState* state = DartUtilities::v8ScriptStateForCurrentIsolate();
363
364 // This is calling blink::Element::toV8(Element*,...) to return a V8Object f rom
365 // the Blink Element.
366 v8::Handle<v8::Value> v8Value = toV8(value, state->context()->Global(), stat e->isolate());
367 v8::Local<v8::Object> v8Handle = v8Value.As<v8::Object>();
368
369 // Return a Dart JsObject that wraps Element * back to the Dart return value .
370 scopes.setReturnValue(v8Handle);
371 }
372
373 // Given a Blink Element instance, make it a V8Object that can then be returned
374 // as a Dart JsObject that holds the Javascript object (V8Object).
375 v8::Local<v8::Object> JsInterop::blinkElement(Element* value, Dart_Handle& excep tion)
376 {
377 V8ScriptState* state = DartUtilities::v8ScriptStateForCurrentIsolate();
378
379 // This is calling blink::Element::toV8(Element*,...) to return a V8Object f rom
380 // the Blink Element.
381 v8::Handle<v8::Value> v8Value = toV8(value, state->context()->Global(), stat e->isolate());
382 v8::Local<v8::Object> v8Handle = v8Value.As<v8::Object>();
383 return v8Handle;
384 }
385
386 JsObject::JsObject(v8::Local<v8::Object> v8Handle)
387 {
388 v8::Isolate* isolate = v8::Isolate::GetCurrent();
389 v8::Persistent<v8::Object> persistentHandle;
390 v8Object.Reset(isolate, v8Handle);
391 }
392
393 v8::Local<v8::Object> JsObject::localV8Object()
394 {
395 return v8::Local<v8::Object>::New(v8::Isolate::GetCurrent(), v8Object);
396 }
397
398 Dart_Handle JsInterop::toDart(v8::Local<v8::Value> v8Handle)
399 {
400 Dart_Handle handle = V8Converter::toDartIfPrimitive(v8Handle);
401 if (handle)
402 return handle;
403
404 ASSERT(v8Handle->IsObject());
405 v8::Handle<v8::Object> object = v8Handle.As<v8::Object>();
406 // TODO(terry): START of uncommented block by Jacob, I've re-enabled for cla mped arrays...
407 Dart_Handle exception = 0;
408 handle = V8Converter::toDartIfBrowserNative(object, object->CreationContext( )->GetIsolate(), exception);
409 ASSERT(!exception);
410 if (handle)
411 return handle;
412 // TODO(terry): END of uncommented block by Jacob.
413 // Unwrap objects passed from Dart to JS that are being passed back to
414 // Dart. FIXME: we do not yet handle unwrapping JS functions passed
415 // from Dart to JS as we have to wrap them with true JS Function objects.
416 // If this use case is important we can support it at the cost of hanging
417 // an extra expando off the JS function wrapping the Dart function.
418 if (DartHandleProxy::isDartProxy(v8Handle)) {
419 DartPersistentValue* scriptValue = DartHandleProxy::readPointerFromProxy (v8Handle);
420 ASSERT(scriptValue->isIsolateAlive());
421 // If the isolate does not match we fall back to using the existing JS
422 // wrapper for the Dart object so that simple cases that would work in
423 // Dart2Js work. We could alternately throw an exception here.
424 if (scriptValue->isolate() == Dart_CurrentIsolate()) {
425 return scriptValue->value();
426 }
427 }
428
429 return JsObject::toDart(object);
430 }
431
432 Dart_Handle JsObject::toDart(v8::Local<v8::Object> object)
433 {
434 // FIXME: perform caching so that === can be used.
435 if (object->IsFunction()) {
436 RefPtr<JsFunction> jsFunction = JsFunction::create(object.As<v8::Functio n>());
437 return JsFunction::toDart(jsFunction);
438 }
439
440 if (object->IsArray()) {
441 RefPtr<JsArray> jsArray = JsArray::create(object.As<v8::Array>());
442 return JsArray::toDart(jsArray);
443 }
444
445 RefPtr<JsObject> jsObject = JsObject::create(object);
446 return JsObject::toDart(jsObject);
447 }
448
449 static void maybeCreateJsObjectImplClass(DartDOMData* domData)
450 {
451 DartJsInteropData* interopData = domData->jsInteropData();
452 // Skip if the JSObjectImpl class has already been defined.
453 if (interopData->jsObjectImplDefined()) {
454 return;
455 }
456 // Helper method that generates boilerplate source code for
457 // JsObjectImpl, JsFunctionImpl, and JsArrayImpl classes that implement
458 // all Dart types that have been passed to the dart:js registerJsInterfaces
459 // method. The sole purpose of these classes is to ensure that checked mode
460 // allows casting a JsObject to all types implemented by a JsObject.
461 Dart_Handle source = invokeTopLevelJsInteropMethod(domData, "_generateJsObje ctImplPart", 0, 0);
462 ASSERT(Dart_IsString(source));
463
464 Dart_Handle ALLOW_UNUSED ret = Dart_LibraryLoadPatch(domData->jsLibrary(), D art_NewStringFromCString("JsInteropImpl.dart"), source);
465 ASSERT(!Dart_IsError(ret));
466 ret = Dart_FinalizeLoading(false);
467 ASSERT(!Dart_IsError(ret));
468
469 interopData->setJsObjectImplDefined();
470
471 // Start of polyfill work to make Dart List proxies behave like JavaScript
472 // Arrays by monkey patching JavaScript Array and the List JavaScript
473 // proxies as needed.
474 v8::Context::Scope scope(DartUtilities::currentV8Context());
475
476 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
477
478 v8::Local<v8::Function> dartArrayConstructor = dartListTemplate()->GetFuncti on();
479
480 DartUtilities::currentV8Context()->Global()->Set(v8::String::NewFromUtf8(v8I solate, "$DartList"),
481 dartArrayConstructor);
482 V8ScriptRunner::compileAndRunInternalScript(v8::String::NewFromUtf8(v8Isolat e, dartArrayPolyfill), v8Isolate);
483 }
484
485 Dart_Handle JsObject::toDart(PassRefPtr<JsObject> jsObject)
486 {
487 DartDOMData* domData = DartDOMData::current();
488 // We need to ensure JsObjectImpl exists before creating the wrapper.
489 maybeCreateJsObjectImplClass(domData);
490 return DartDOMWrapper::createWrapper<JsObject>(domData, jsObject.get(), JsOb ject::dartClassId);
491 }
492
493 JsObject::~JsObject()
494 {
495 v8Object.Reset();
496 }
497
498 Dart_Handle JsFunction::toDart(PassRefPtr<JsFunction> jsFunction)
499 {
500 DartDOMData* domData = DartDOMData::current();
501 // We need to ensure JsObjectImpl exists before creating the wrapper.
502 maybeCreateJsObjectImplClass(domData);
503 return DartDOMWrapper::createWrapper<JsFunction>(domData, jsFunction.get(), JsFunction::dartClassId);
504 }
505
506 JsFunction::JsFunction(v8::Local<v8::Function> v8Handle) : JsObject(v8Handle) { }
507
508 PassRefPtr<JsFunction> JsFunction::create(v8::Local<v8::Function> v8Handle)
509 {
510 return adoptRef(new JsFunction(v8Handle));
511 }
512
513 v8::Local<v8::Function> JsFunction::localV8Function()
514 {
515 return localV8Object().As<v8::Function>();
516 }
517
518 Dart_Handle JsArray::toDart(PassRefPtr<JsArray> jsArray)
519 {
520 DartDOMData* domData = DartDOMData::current();
521 // We need to ensure JsArrayImpl exists before creating the wrapper.
522 maybeCreateJsObjectImplClass(domData);
523 return DartDOMWrapper::createWrapper<JsArray>(domData, jsArray.get(), JsArra y::dartClassId);
524 }
525
526 JsArray::JsArray(v8::Local<v8::Array> v8Handle) : JsObject(v8Handle) { }
527
528 PassRefPtr<JsArray> JsArray::create(v8::Local<v8::Array> v8Handle)
529 {
530 return adoptRef(new JsArray(v8Handle));
531 }
532
533 v8::Local<v8::Array> JsArray::localV8Array()
534 {
535 return localV8Object().As<v8::Array>();
536 }
537
538 namespace JsInteropInternal {
539
540 typedef HashMap<Dart_Handle, v8::Handle<v8::Value> > DartHandleToV8Map;
541 v8::Handle<v8::Value> jsifyHelper(DartDOMData*, Dart_Handle value, DartHandleToV 8Map&, Dart_Handle& exception);
542
543 void argsListToV8(DartDOMData* domData, Dart_Handle args, Vector<v8::Local<v8::V alue> >* v8Args, Dart_Handle& exception)
544 {
545 if (Dart_IsNull(args))
546 return;
547
548 if (!Dart_IsList(args)) {
549 exception = Dart_NewStringFromCString("args not type list");
550 return;
551 }
552
553 intptr_t argsLength = 0;
554 Dart_ListLength(args, &argsLength);
555 for (intptr_t i = 0; i < argsLength; i++) {
556 v8Args->append(JsInterop::fromDart(domData, Dart_ListGetAt(args, i), exc eption));
557 if (exception)
558 return;
559 }
560 }
561
562 void argsListToV8DebuggerOnly(DartDOMData* domData, Dart_Handle args, Vector<v8: :Local<v8::Value> >* v8Args, Dart_Handle& exception)
563 {
564 if (Dart_IsNull(args))
565 return;
566
567 if (!Dart_IsList(args)) {
568 exception = Dart_NewStringFromCString("args not type list");
569 return;
570 }
571
572 intptr_t argsLength = 0;
573 Dart_ListLength(args, &argsLength);
574 for (intptr_t i = 0; i < argsLength; i++) {
575 v8Args->append(DartHandleProxy::create(Dart_ListGetAt(args, i)));
576 }
577 }
578
579 static void jsObjectConstructorCallback(Dart_NativeArguments args)
580 {
581 Dart_Handle exception = 0;
582 {
583 JsInteropScopes scopes(args);
584 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
585 v8::Local<v8::Value> constructorArg = JsInterop::fromDart(domData, Dart_ GetNativeArgument(args, 0), exception);
586 if (exception)
587 goto fail;
588
589 if (!constructorArg->IsFunction()) {
590 exception = Dart_NewStringFromCString("constructor not a function");
591 goto fail;
592 }
593
594 Vector<v8::Local<v8::Value> > v8Args;
595 argsListToV8(domData, Dart_GetNativeArgument(args, 1), &v8Args, exceptio n);
596
597 v8::Local<v8::Value> ret = constructorArg.As<v8::Function>()->CallAsCons tructor(v8Args.size(), v8Args.data());
598 crashIfV8IsDead();
599
600 if (scopes.handleJsException(&exception))
601 goto fail;
602
603 // Intentionally skip auto-conversion in this case as the user expects
604 // a JSObject. FIXME: evaluate if this is the right solution.
605 // Alternately, we could throw an exception.
606 if (ret->IsObject()) {
607 scopes.setReturnValue(JsObject::toDart(ret.As<v8::Object>()));
608 } else {
609 // This will throw an exception in Dart checked mode.
610 scopes.setReturnValue(ret);
611 }
612 return;
613 }
614
615 fail:
616 Dart_ThrowException(exception);
617 ASSERT_NOT_REACHED();
618 }
619
620 static void identityEqualityCallback(Dart_NativeArguments args)
621 {
622 Dart_Handle exception = 0;
623 {
624 JsInteropScopes scopes(args);
625 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
626 v8::Local<v8::Value> a = JsInterop::fromDart(domData, Dart_GetNativeArgu ment(args, 0), exception);
627 if (exception)
628 goto fail;
629 v8::Local<v8::Value> b = JsInterop::fromDart(domData, Dart_GetNativeArgu ment(args, 1), exception);
630 if (exception)
631 goto fail;
632
633 bool strictEquals = a->StrictEquals(b);
634
635 if (scopes.handleJsException(&exception))
636 goto fail;
637 scopes.setReturnValue(DartUtilities::boolToDart(strictEquals));
638 return;
639 }
640
641 fail:
642 Dart_ThrowException(exception);
643 ASSERT_NOT_REACHED();
644 }
645
646 static void getterCallback(Dart_NativeArguments args)
647 {
648 Dart_Handle exception = 0;
649 {
650 JsInteropScopes scopes(args);
651 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
652 v8::Local<v8::Object> v8Receiver = receiver->localV8Object();
653 Dart_Handle index = Dart_GetNativeArgument(args, 1);
654 uint64_t intIndex = 0;
655 v8::Local<v8::Value> ret;
656
657 if (Dart_IsInteger(index)) {
658 bool isUint64 = false;
659 Dart_IntegerFitsIntoUint64(index, &isUint64);
660 if (isUint64) {
661 Dart_Handle ALLOW_UNUSED result = Dart_IntegerToUint64(index, &i ntIndex);
662 if (intIndex <= std::numeric_limits<uint32_t>::max()) {
663 ASSERT(!Dart_IsError(result));
664 ret = v8Receiver->Get((uint32_t)intIndex);
665 } else {
666 ret = v8Receiver->Get(V8Converter::numberToV8(index));
667 }
668 } else {
669 ret = v8Receiver->Get(V8Converter::numberToV8(index));
670 }
671 } else if (Dart_IsString(index)) {
672 ret = v8Receiver->Get(V8Converter::stringToV8(index));
673 } else if (Dart_IsNumber(index)) {
674 ret = v8Receiver->Get(V8Converter::numberToV8(index));
675 } else {
676 ret = v8Receiver->Get(V8Converter::stringToV8(Dart_ToString(index))) ;
677 }
678
679 if (scopes.handleJsException(&exception))
680 goto fail;
681 scopes.setReturnValue(ret);
682 return;
683 }
684
685 fail:
686 Dart_ThrowException(exception);
687 ASSERT_NOT_REACHED();
688 }
689
690 static void hasPropertyCallback(Dart_NativeArguments args)
691 {
692 Dart_Handle exception = 0;
693 {
694 JsInteropScopes scopes(args);
695 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
696 v8::Local<v8::Object> v8Receiver = receiver->localV8Object();
697 Dart_Handle property = Dart_GetNativeArgument(args, 1);
698
699 if (!Dart_IsString(property))
700 property = Dart_ToString(property);
701
702 bool hasProperty = v8Receiver->Has(V8Converter::stringToV8(property));
703 if (scopes.handleJsException(&exception))
704 goto fail;
705 scopes.setReturnValue(DartUtilities::boolToDart(hasProperty));
706 return;
707 }
708
709 fail:
710 Dart_ThrowException(exception);
711 ASSERT_NOT_REACHED();
712 }
713
714 static void deletePropertyCallback(Dart_NativeArguments args)
715 {
716 Dart_Handle exception = 0;
717 {
718 JsInteropScopes scopes(args);
719 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
720 v8::Local<v8::Object> v8Receiver = receiver->localV8Object();
721 Dart_Handle property = Dart_GetNativeArgument(args, 1);
722 if (!Dart_IsString(property))
723 property = Dart_ToString(property);
724
725 v8Receiver->Delete(V8Converter::stringToV8(property));
726 if (scopes.handleJsException(&exception))
727 goto fail;
728 return;
729 }
730
731 fail:
732 Dart_ThrowException(exception);
733 ASSERT_NOT_REACHED();
734 }
735
736 static void instanceofCallback(Dart_NativeArguments args)
737 {
738 Dart_Handle exception = 0;
739 {
740 JsInteropScopes scopes(args);
741 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
742 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
743 v8::Local<v8::Object> v8Receiver = receiver->localV8Object();
744 v8::Local<v8::Value> type = JsInterop::fromDart(domData, Dart_GetNativeA rgument(args, 1), exception);
745
746 // FIXME: we could optimize the following lines slightly as the return
747 // type is bool.
748 v8::Local<v8::Value> ret = domData->jsInteropData()->instanceofFunction( )->Call(v8Receiver, 1, &type);
749 if (scopes.handleJsException(&exception))
750 goto fail;
751 scopes.setReturnValue(ret);
752 return;
753 }
754
755 fail:
756 Dart_ThrowException(exception);
757 ASSERT_NOT_REACHED();
758 }
759
760 static void setterCallback(Dart_NativeArguments args)
761 {
762 Dart_Handle exception = 0;
763 {
764 JsInteropScopes scopes(args);
765 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
766 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
767 v8::Local<v8::Object> v8Receiver = receiver->localV8Object();
768 Dart_Handle index = Dart_GetNativeArgument(args, 1);
769 v8::Local<v8::Value> value = JsInterop::fromDart(domData, Dart_GetNative Argument(args, 2), exception);
770 if (exception)
771 goto fail;
772 uint64_t intIndex = 0;
773 bool ret = false;
774 if (Dart_IsInteger(index)) {
775 bool isUint64 = false;
776 Dart_IntegerFitsIntoUint64(index, &isUint64);
777 if (isUint64) {
778 Dart_Handle ALLOW_UNUSED result = Dart_IntegerToUint64(index, &i ntIndex);
779 if (intIndex <= std::numeric_limits<uint32_t>::max()) {
780 ASSERT(!Dart_IsError(result));
781 ret = v8Receiver->Set((uint32_t)intIndex, value);
782 } else {
783 ret = v8Receiver->Set(V8Converter::numberToV8(index), value) ;
784 }
785 } else {
786 ret = v8Receiver->Set(V8Converter::numberToV8(index), value);
787 }
788 } else if (Dart_IsString(index)) {
789 ret = v8Receiver->Set(V8Converter::stringToV8(index), value);
790 } else if (Dart_IsNumber(index)) {
791 ret = v8Receiver->Set(V8Converter::numberToV8(index), value);
792 } else {
793 ret = v8Receiver->Set(V8Converter::stringToV8(Dart_ToString(index)), value);
794 }
795
796 if (scopes.handleJsException(&exception))
797 goto fail;
798 scopes.setReturnValue(DartUtilities::boolToDart(ret));
799 return;
800 }
801
802 fail:
803 Dart_ThrowException(exception);
804 ASSERT_NOT_REACHED();
805 }
806
807 static void hashCodeCallback(Dart_NativeArguments args)
808 {
809 Dart_Handle exception = 0;
810 {
811 JsInteropScopes scopes(args);
812 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
813 int hashCode = receiver->localV8Object()->GetIdentityHash();
814 // FIXME: salt the v8 hashcode so we don't leak information about v8
815 // memory allocation.
816 if (scopes.handleJsException(&exception))
817 goto fail;
818 scopes.setReturnValueInteger(hashCode);
819 return;
820 }
821
822 fail:
823 Dart_ThrowException(exception);
824 ASSERT_NOT_REACHED();
825 }
826
827 static void callMethodCallback(Dart_NativeArguments args)
828 {
829 Dart_Handle exception = 0;
830 {
831 JsInteropScopes scopes(args);
832 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
833 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
834 v8::Local<v8::Object> v8Receiver = receiver->localV8Object();
835
836 Dart_Handle name = Dart_GetNativeArgument(args, 1);
837
838 Vector<v8::Local<v8::Value> > v8Args;
839 argsListToV8(domData, Dart_GetNativeArgument(args, 2), &v8Args, exceptio n);
840 if (exception)
841 goto fail;
842 if (!Dart_IsString(name))
843 name = Dart_ToString(name);
844
845 v8::Local<v8::Value> value = v8Receiver->Get(V8Converter::stringToV8(nam e));
846 v8::Local<v8::Value> ret;
847 if (value->IsFunction()) {
848 ret = V8ScriptRunner::callFunction(value.As<v8::Function>(), DartUti lities::scriptExecutionContext(), receiver->localV8Object(), v8Args.size(), v8Ar gs.data(), v8::Isolate::GetCurrent());
849 } else if (value->IsObject()) {
850 ret = V8ScriptRunner::callAsFunction(v8::Isolate::GetCurrent(), valu e.As<v8::Object>(), receiver->localV8Object(), v8Args.size(), v8Args.data());
851 } else {
852 // FIXME: we currently convert this exception to a NoSuchMethod
853 // exception in the Dart code that wraps this native method.
854 // Consider throwing a NoSuchMethod exception directly instead.
855 exception = Dart_NewStringFromCString("property is not a function");
856 goto fail;
857 }
858
859 if (scopes.handleJsException(&exception))
860 goto fail;
861 scopes.setReturnValue(ret);
862 return;
863 }
864
865 fail:
866 Dart_ThrowException(exception);
867 ASSERT_NOT_REACHED();
868 }
869
870 static void newJsArrayCallback(Dart_NativeArguments args)
871 {
872 JsInteropScopes scopes(args);
873 scopes.setReturnValue(JsObject::toDart(v8::Array::New(v8::Isolate::GetCurren t())));
874 return;
875 }
876
877 static void newJsArrayFromSafeListCallback(Dart_NativeArguments args)
878 {
879 Dart_Handle exception = 0;
880 {
881 JsInteropScopes scopes(args);
882 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
883 Dart_Handle list = Dart_GetNativeArgument(args, 0);
884 // Code on the Dart side insures this arg is a native Dart list.
885 ASSERT(Dart_IsList(list));
886
887 intptr_t length = 0;
888 Dart_Handle result = Dart_ListLength(list, &length);
889 ASSERT(!Dart_IsError(result));
890 v8::Local<v8::Array> array = v8::Array::New(v8::Isolate::GetCurrent(), l ength);
891
892 for (intptr_t i = 0; i < length; ++i) {
893 result = Dart_ListGetAt(list, i);
894 ASSERT(!Dart_IsError(result));
895 v8::Handle<v8::Value> v8value = JsInterop::fromDart(domData, result, exception);
896 if (exception)
897 goto fail;
898
899 array->Set(i, v8value);
900 }
901 scopes.setReturnValue(array);
902 return;
903 }
904
905 fail:
906 Dart_ThrowException(exception);
907 ASSERT_NOT_REACHED();
908 }
909
910
911 static void jsArrayLengthCallback(Dart_NativeArguments args)
912 {
913 Dart_Handle exception = 0;
914 {
915 JsInteropScopes scopes(args);
916 JsArray* receiver = DartDOMWrapper::receiver<JsArray>(args);
917 uint32_t length = receiver->localV8Array()->Length();
918 if (scopes.handleJsException(&exception))
919 goto fail;
920 scopes.setReturnValueInteger(length);
921 return;
922 }
923
924 fail:
925 Dart_ThrowException(exception);
926 ASSERT_NOT_REACHED();
927 }
928
929 static void fromBrowserObjectCallback(Dart_NativeArguments args)
930 {
931 Dart_Handle exception = 0;
932 {
933 JsInteropScopes scopes(args);
934 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
935
936 v8::Local<v8::Value> ret = V8Converter::toV8IfBrowserNative(domData, Dar t_GetNativeArgument(args, 0), exception);
937 if (ret.IsEmpty()) {
938 exception = Dart_NewStringFromCString("object must be an Node, Array Buffer, Blob, ImageData, or IDBKeyRange");
939 goto fail;
940 }
941 if (exception)
942 goto fail;
943 ASSERT(ret->IsObject());
944 if (scopes.handleJsException(&exception))
945 goto fail;
946 scopes.setReturnValue(JsObject::toDart(ret.As<v8::Object>()));
947 return;
948 }
949
950 fail:
951 Dart_ThrowException(exception);
952 ASSERT_NOT_REACHED();
953 }
954
955 static void applyCallback(Dart_NativeArguments args)
956 {
957 Dart_Handle exception = 0;
958 {
959 JsInteropScopes scopes(args);
960 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
961 JsFunction* receiver = DartDOMWrapper::receiver<JsFunction>(args);
962
963 Vector<v8::Local<v8::Value> > v8Args;
964 argsListToV8(domData, Dart_GetNativeArgument(args, 1), &v8Args, exceptio n);
965 if (exception)
966 goto fail;
967
968 v8::Local<v8::Value> thisArg;
969 Dart_Handle thisArgDart = Dart_GetNativeArgument(args, 2);
970 if (Dart_IsNull(thisArgDart)) {
971 // Use the global v8 object if no Dart thisArg was passed in.
972 thisArg = DartUtilities::currentV8Context()->Global();
973 } else {
974 Dart_Handle jso = Dart_GetField(thisArgDart, Dart_NewStringFromCStri ng("blink_jsObject"));
975 if (!Dart_IsError(jso) && DartDOMWrapper::subtypeOf(jso, JsObject::d artClassId)) {
976 // Use the blink JS Interop object.
977 JsObject* object = DartDOMWrapper::unwrapDartWrapper<JsObject>(d omData, jso, exception);
978 if (exception)
979 thisArg = v8::Local<v8::Value>();
980 thisArg = object->localV8Object();
981 } else {
982 thisArg = JsInterop::fromDart(domData, thisArgDart, exception);
983 if (exception)
984 goto fail;
985 }
986 if (!thisArg->IsObject()) {
987 exception = Dart_NewStringFromCString("thisArg is not an object" );
988 goto fail;
989 }
990 }
991
992 v8::Local<v8::Value> ret = V8ScriptRunner::callFunction(receiver->localV 8Function(), DartUtilities::scriptExecutionContext(), thisArg.As<v8::Object>(), v8Args.size(), v8Args.data(), v8::Isolate::GetCurrent());
993 if (scopes.handleJsException(&exception))
994 goto fail;
995 scopes.setReturnValue(ret);
996 return;
997 }
998
999 fail:
1000 Dart_ThrowException(exception);
1001 ASSERT_NOT_REACHED();
1002 }
1003
1004 static void applyDebuggerOnlyCallback(Dart_NativeArguments args)
1005 {
1006 Dart_Handle exception = 0;
1007 {
1008 JsInteropScopes scopes(args);
1009 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
1010 JsFunction* receiver = DartDOMWrapper::receiver<JsFunction>(args);
1011
1012 Vector<v8::Local<v8::Value> > v8Args;
1013 argsListToV8DebuggerOnly(domData, Dart_GetNativeArgument(args, 1), &v8Ar gs, exception);
1014 if (exception)
1015 goto fail;
1016
1017 v8::Local<v8::Value> thisArg;
1018 Dart_Handle thisArgDart = Dart_GetNativeArgument(args, 2);
1019 if (Dart_IsNull(thisArgDart)) {
1020 // Use the global v8 object if no Dart thisArg was passed in.
1021 thisArg = DartUtilities::currentV8Context()->Global();
1022 } else {
1023 thisArg = JsInterop::fromDart(domData, thisArgDart, exception);
1024 if (exception)
1025 goto fail;
1026 if (!thisArg->IsObject()) {
1027 exception = Dart_NewStringFromCString("thisArg is not an object" );
1028 goto fail;
1029 }
1030 }
1031
1032 v8::Local<v8::Value> ret = V8ScriptRunner::callFunction(receiver->localV 8Function(), DartUtilities::scriptExecutionContext(), thisArg.As<v8::Object>(), v8Args.size(), v8Args.data(), v8::Isolate::GetCurrent());
1033 if (scopes.handleJsException(&exception))
1034 goto fail;
1035 scopes.setReturnValue(ret);
1036 return;
1037 }
1038
1039 fail:
1040 Dart_ThrowException(exception);
1041 ASSERT_NOT_REACHED();
1042 }
1043
1044 static void toStringCallback(Dart_NativeArguments args)
1045 {
1046 Dart_Handle exception = 0;
1047 {
1048 JsInteropScopes scopes(args);
1049 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
1050 v8::Local<v8::Object> v8Object = receiver->localV8Object();
1051 if (scopes.handleJsException(&exception))
1052 goto fail;
1053 if (v8Object.IsEmpty()) {
1054 exception = Dart_NewStringFromCString("Invalid v8 handle");
1055 goto fail;
1056 }
1057
1058 v8::Local<v8::String> v8String = v8Object->ToString();
1059 if (scopes.handleJsException(&exception))
1060 goto fail;
1061 scopes.setReturnValue(v8String);
1062 return;
1063 }
1064 fail:
1065 Dart_ThrowException(exception);
1066 ASSERT_NOT_REACHED();
1067 }
1068
1069 static void contextCallback(Dart_NativeArguments args)
1070 {
1071 v8::Local<v8::Context> v8Context = DartUtilities::currentV8Context();
1072 v8::Context::Scope scope(v8Context);
1073 Dart_SetReturnValue(args, JsObject::toDart(v8Context->Global()));
1074 }
1075
1076 static void finalizeJsInterfacesCallback(Dart_NativeArguments args)
1077 {
1078 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateData(a rgs));
1079 maybeCreateJsObjectImplClass(domData);
1080 }
1081
1082 static void interfacesFinalizedCallback(Dart_NativeArguments args)
1083 {
1084 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateData(a rgs));
1085 DartJsInteropData* interopData = domData->jsInteropData();
1086 // Skip if the JSObjectImpl class has already been defined.
1087 Dart_SetBooleanReturnValue(args, interopData->jsObjectImplDefined());
1088 }
1089
1090 v8::Handle<v8::Value> mapToV8(DartDOMData* domData, Dart_Handle value, DartHandl eToV8Map& map, Dart_Handle& exception)
1091 {
1092 Dart_Handle asList = DartUtilities::invokeUtilsMethod("convertMapToList", 1, &value);
1093 if (!DartUtilities::checkResult(asList, exception))
1094 return v8::Handle<v8::Value>();
1095 ASSERT(Dart_IsList(asList));
1096
1097 // Now we have a list [key, value, key, value, ....], create a v8 object and set necesary
1098 // properties on it.
1099 v8::Handle<v8::Object> object = v8::Object::New(v8::Isolate::GetCurrent());
1100 map.set(value, object);
1101
1102 // We converted to internal Dart list, methods shouldn't throw exceptions no w.
1103 intptr_t length = 0;
1104 Dart_Handle ALLOW_UNUSED result = Dart_ListLength(asList, &length);
1105 ASSERT(!Dart_IsError(result));
1106 ASSERT(!(length % 2));
1107 for (intptr_t i = 0; i < length; i += 2) {
1108 v8::Handle<v8::Value> key = jsifyHelper(domData, Dart_ListGetAt(asList, i), map, exception);
1109 if (exception)
1110 return v8::Handle<v8::Value>();
1111 v8::Handle<v8::Value> value = jsifyHelper(domData, Dart_ListGetAt(asList , i + 1), map, exception);
1112 if (exception)
1113 return v8::Handle<v8::Value>();
1114
1115 object->Set(key, value);
1116 }
1117
1118 return object;
1119 }
1120
1121 v8::Handle<v8::Value> listToV8(DartDOMData* domData, Dart_Handle value, DartHand leToV8Map& map, Dart_Handle& exception)
1122 {
1123 ASSERT(Dart_IsList(value));
1124
1125 intptr_t length = 0;
1126 Dart_Handle result = Dart_ListLength(value, &length);
1127 if (!DartUtilities::checkResult(result, exception))
1128 return v8::Handle<v8::Value>();
1129
1130 v8::Local<v8::Array> array = v8::Array::New(v8::Isolate::GetCurrent(), lengt h);
1131 map.set(value, array);
1132
1133 for (intptr_t i = 0; i < length; ++i) {
1134 result = Dart_ListGetAt(value, i);
1135 if (!DartUtilities::checkResult(result, exception))
1136 return v8::Handle<v8::Value>();
1137 v8::Handle<v8::Value> v8value = jsifyHelper(domData, result, map, except ion);
1138 if (exception)
1139 return v8::Handle<v8::Value>();
1140 array->Set(i, v8value);
1141 }
1142
1143 return array;
1144 }
1145
1146 v8::Handle<v8::Value> jsifyHelper(DartDOMData* domData, Dart_Handle value, DartH andleToV8Map& map, Dart_Handle& exception)
1147 {
1148 DartHandleToV8Map::iterator iter = map.find(value);
1149 if (iter != map.end())
1150 return iter->value;
1151
1152 if (Dart_IsList(value))
1153 return listToV8(domData, value, map, exception);
1154
1155 bool isMap = DartUtilities::dartToBool(DartUtilities::invokeUtilsMethod("isM ap", 1, &value), exception);
1156 ASSERT(!exception);
1157 if (isMap)
1158 return mapToV8(domData, value, map, exception);
1159
1160 Dart_Handle maybeList = DartUtilities::invokeUtilsMethod("toListIfIterable", 1, &value);
1161 if (Dart_IsList(maybeList))
1162 return listToV8(domData, maybeList, map, exception);
1163
1164 v8::Handle<v8::Value> ret = JsInterop::fromDart(domData, value, exception);
1165 map.set(value, ret);
1166 return ret;
1167 }
1168
1169 static void jsifyCallback(Dart_NativeArguments args)
1170 {
1171 Dart_Handle exception = 0;
1172 {
1173 JsInteropScopes scopes(args);
1174 Dart_Handle value = Dart_GetNativeArgument(args, 0);
1175 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
1176 DartHandleToV8Map map;
1177 v8::Local<v8::Value> ret = jsifyHelper(domData, value, map, exception);
1178 if (exception)
1179 goto fail;
1180
1181 if (scopes.handleJsException(&exception))
1182 goto fail;
1183 // Intentionally skip auto-conversion in this case as the user expects
1184 // a JSObject. FIXME: evaluate if this is the right solution.
1185 // Alternately, we could throw an exception.
1186 if (ret->IsObject()) {
1187 scopes.setReturnValue(JsObject::toDart(ret.As<v8::Object>()));
1188 } else {
1189 // This will throw an exception in Dart checked mode.
1190 scopes.setReturnValue(ret);
1191 }
1192 return;
1193 }
1194 fail:
1195 Dart_ThrowException(exception);
1196 ASSERT_NOT_REACHED();
1197 }
1198
1199 static void withThisCallback(Dart_NativeArguments args)
1200 {
1201 Dart_Handle exception = 0;
1202 {
1203 JsInteropScopes scopes(args);
1204 Dart_Handle function = Dart_GetNativeArgument(args, 0);
1205 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
1206 ASSERT(DartUtilities::isFunction(domData, function));
1207
1208 v8::Local<v8::Object> proxy = dartFunctionTemplate()->InstanceTemplate() ->NewInstance();
1209 DartHandleProxy::writePointerToProxy(proxy, function);
1210
1211 v8::Local<v8::Function> ret = v8::Local<v8::Function>::Cast(domData->jsI nteropData()->captureThisFunction()->Call(proxy, 0, 0));
1212
1213 if (scopes.handleJsException(&exception))
1214 goto fail;
1215 scopes.setReturnValue(ret);
1216 return;
1217 }
1218 fail:
1219 Dart_ThrowException(exception);
1220 ASSERT_NOT_REACHED();
1221 }
1222
1223 }
1224
1225 static DartNativeEntry nativeEntries[] = {
1226 { JsInteropInternal::jsObjectConstructorCallback, 2, "JsObject_constructorCa llback" },
1227 { JsInterop::jsInteropContextCallback, 0, "Js_context_Callback" },
1228 { JsInteropInternal::finalizeJsInterfacesCallback, 0, "Js_finalizeJsInterfac es" },
1229 { JsInteropInternal::interfacesFinalizedCallback, 0, "Js_interfacesFinalized _Callback" },
1230 { JsInteropInternal::jsifyCallback, 1, "JsObject_jsify" },
1231 { JsInteropInternal::withThisCallback, 1, "JsFunction_withThis" },
1232 { JsInterop::jsInteropGetterCallback, 2, "JsObject_[]" },
1233 { JsInteropInternal::setterCallback, 3, "JsObject_[]=" },
1234 { JsInteropInternal::hashCodeCallback, 1, "JsObject_hashCode" },
1235 { JsInterop::jsInteropCallMethodCallback, 3, "JsObject_callMethod" },
1236 { JsInteropInternal::toStringCallback, 1, "JsObject_toString" },
1237 { JsInteropInternal::identityEqualityCallback, 2, "JsObject_identityEquality " },
1238 { JsInteropInternal::hasPropertyCallback, 2, "JsObject_hasProperty" },
1239 { JsInteropInternal::deletePropertyCallback, 2, "JsObject_deleteProperty" },
1240 { JsInteropInternal::instanceofCallback, 2, "JsObject_instanceof" },
1241 { JsInteropInternal::applyCallback, 3, "JsFunction_apply" },
1242 { JsInteropInternal::applyDebuggerOnlyCallback, 3, "JsFunction_applyDebugger Only" },
1243 { JsInteropInternal::newJsArrayCallback, 0, "JsArray_newJsArray" },
1244 { JsInteropInternal::newJsArrayFromSafeListCallback, 1, "JsArray_newJsArrayF romSafeList" },
1245 { JsInteropInternal::jsArrayLengthCallback, 1, "JsArray_length" },
1246 { JsInteropInternal::fromBrowserObjectCallback, 1, "JsObject_fromBrowserObje ct" },
1247 { 0, 0, 0 },
1248 };
1249
1250 Dart_NativeFunction JsInterop::resolver(Dart_Handle nameHandle, int argumentCoun t, bool* autoSetupScope)
1251 {
1252 ASSERT(autoSetupScope);
1253 *autoSetupScope = true;
1254 String name = DartUtilities::toString(nameHandle);
1255
1256 for (intptr_t i = 0; nativeEntries[i].nativeFunction != 0; i++) {
1257 if (argumentCount == nativeEntries[i].argumentCount && name == nativeEnt ries[i].name) {
1258 return nativeEntries[i].nativeFunction;
1259 }
1260 }
1261
1262 return 0;
1263 }
1264
1265 const uint8_t* JsInterop::symbolizer(Dart_NativeFunction nf)
1266 {
1267 for (intptr_t i = 0; nativeEntries[i].nativeFunction != 0; i++) {
1268 if (nf == nativeEntries[i].nativeFunction) {
1269 return reinterpret_cast<const uint8_t*>(nativeEntries[i].name);
1270 }
1271 }
1272 return 0;
1273 }
1274
1275 // Methods enabling a Dart List to emulate a JS Array.
1276 static void indexedGetterArray(uint32_t index, const v8::PropertyCallbackInfo<v8 ::Value>& info)
1277 {
1278 DartScopes scopes(info.Holder());
1279 Dart_Handle handle = scopes.handle;
1280 DartDOMData* domData = DartDOMData::current();
1281 Dart_Handle ret = 0;
1282 ASSERT(Dart_IsList(handle));
1283 ret = Dart_ListGetAt(handle, index);
1284 if (Dart_IsError(ret)) {
1285 // Return undefined if the index is invalid to match JS semantics.
1286 // TODO(jacobr): we should log to the console warning of bad use of a
1287 // Dart List.
1288 return;
1289 }
1290 setJsReturnValue(domData, info, ret);
1291 }
1292
1293 static void indexedSetterArray(uint32_t index, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)
1294 {
1295 DartScopes scopes(info.Holder());
1296 Dart_Handle handle = scopes.handle;
1297 DartDOMData* domData = DartDOMData::current();
1298
1299 Dart_Handle ret = 0;
1300 ASSERT(Dart_IsList(handle));
1301 intptr_t length = 0;
1302 ret = Dart_ListLength(handle, &length);
1303 ASSERT(!Dart_IsError(ret));
1304 if (index >= static_cast<uint32_t>(length)) {
1305 // Approximate JS semantics by filling the list with nulls if we
1306 // attempt to add an element past the end of the list.
1307 // TODO(jacobr): ideally we would match JS semantics exactly and fill
1308 // the list with undefined.
1309 Dart_Handle args[2] = { handle, DartUtilities::unsignedToDart(index + 1) };
1310 ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCString("_arra yExtend"), 2, args);
1311 ASSERT(!Dart_IsError(ret));
1312 }
1313 ret = Dart_ListSetAt(handle, index, DartHandleProxy::unwrapValue(value));
1314 if (Dart_IsError(ret)) {
1315 // Return undefined if the index is invalid to match JS semantics.
1316 // TODO(jacobr): we should log to the console warning of bad use of a
1317 // Dart list or add a JS expando to the object ala JS.
1318 }
1319 setJsReturnValue(domData, info, ret);
1320 }
1321
1322 static void indexedEnumeratorArray(const v8::PropertyCallbackInfo<v8::Array>& in fo)
1323 {
1324 DartScopes scopes(info.Holder());
1325 Dart_Handle handle = scopes.handle;
1326
1327 intptr_t length = 0;
1328 ASSERT(Dart_IsList(handle));
1329 Dart_ListLength(handle, &length);
1330
1331 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1332 v8::Local<v8::Array> indexes = v8::Array::New(v8Isolate, length);
1333 for (int i = 0; i < length; i++)
1334 indexes->Set(i, v8::Integer::New(v8Isolate, i));
1335
1336 v8SetReturnValue(info, indexes);
1337 }
1338
1339 v8::Handle<v8::Array> shallowListToV8(Dart_Handle value, DartDOMData* domData, D art_Handle& exception)
1340 {
1341 ASSERT(Dart_IsList(value));
1342
1343 intptr_t length = 0;
1344 Dart_Handle result = Dart_ListLength(value, &length);
1345 if (!DartUtilities::checkResult(result, exception))
1346 return v8::Handle<v8::Array>();
1347
1348 v8::Local<v8::Array> array = v8::Array::New(v8::Isolate::GetCurrent(), lengt h);
1349
1350 for (intptr_t i = 0; i < length; ++i) {
1351 result = Dart_ListGetAt(value, i);
1352 v8::Handle<v8::Value> v8value = JsInterop::fromDart(domData, result, exc eption);
1353 // TODO(jacobr): is there a better way to handle this error case?
1354 if (exception)
1355 return v8::Handle<v8::Array>();
1356 array->Set(i, v8value);
1357 }
1358 return array;
1359 }
1360
1361 // If one of the methods we added to the Dart List proxy to make it mascarade
1362 // as JavaScript Array happens to get called on a JavaScript object instead of
1363 // a Dart List proxy object we use the corresponding regular JavaScript Array
1364 // method which will do something plausible in most cases even if the
1365 // JavaScript object isn't actually a JavaScript array. The chrome devtools
1366 // appear to go down exactly this code path as I got crashes in the devtools
1367 // due to info.Holder not being a DartHandleProxy. I haven't investigated
1368 // whether devtools would still function properly if we threw an exception
1369 // which would match the behavior of DOM classes when a method is called on the
1370 // wrong object. The current behavior while strange matches the behavior
1371 // observed when an method from Array is called on an arbitrary JS object.
1372 bool handleNonDartProxyThis(const v8::FunctionCallbackInfo<v8::Value>& info, con st char* jsMethodName)
1373 {
1374 if (DartHandleProxy::isDartProxy(info.Holder())) {
1375 return false;
1376 }
1377 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1378 // Get the method on JS array in an inefficient way.
1379 v8::Local<v8::Function> method = v8::Array::New(v8Isolate)->Get(v8::String:: NewFromUtf8(v8Isolate, jsMethodName)).As<v8::Function>();
1380 ASSERT(!method.IsEmpty());
1381 int length = info.Length();
1382 Vector<v8::Local<v8::Value> > v8Args(length);
1383 for (int i = 0; i < length; ++i) {
1384 v8Args[i] = info[i];
1385 }
1386 v8SetReturnValue(info, method->Call(info.Holder(), length, v8Args.data()));
1387 return true;
1388 }
1389
1390 void arrayHelper(const v8::FunctionCallbackInfo<v8::Value>& info, const char* me thodName, const char* jsMethodName)
1391 {
1392 if (handleNonDartProxyThis(info, jsMethodName)) {
1393 return;
1394 }
1395 DartScopes scopes(info.Holder());
1396 DartDOMData* domData = DartDOMData::current();
1397 Dart_Handle handle = scopes.handle;
1398 Dart_Handle ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCStrin g(methodName), 1, &handle);
1399 setJsReturnValue(domData, info, ret);
1400 }
1401
1402 void arrayHelper1Arg(const v8::FunctionCallbackInfo<v8::Value>& info, const char * methodName, const char* jsMethodName)
1403 {
1404 if (handleNonDartProxyThis(info, jsMethodName)) {
1405 return;
1406 }
1407 DartScopes scopes(info.Holder());
1408 DartDOMData* domData = DartDOMData::current();
1409 Dart_Handle handle = scopes.handle;
1410 Dart_Handle e;
1411 if (info.Length() == 0) {
1412 e = Dart_Null();
1413 } else {
1414 e = JsInterop::toDart(info[0]);
1415 }
1416 Dart_Handle args[2] = { handle, e };
1417 Dart_Handle ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCStrin g(methodName), 2, args);
1418 setJsReturnValue(domData, info, ret);
1419 }
1420
1421 void arrayHelperWithArgsAsList(const v8::FunctionCallbackInfo<v8::Value>& info, const char* methodName, const char* jsMethodName)
1422 {
1423 if (handleNonDartProxyThis(info, jsMethodName)) {
1424 return;
1425 }
1426 DartScopes scopes(info.Holder());
1427 DartDOMData* domData = DartDOMData::current();
1428 Dart_Handle handle = scopes.handle;
1429 int length = info.Length();
1430 Dart_Handle argsList = Dart_NewList(length);
1431 for (int i = 0; i < length; ++i) {
1432 Dart_ListSetAt(argsList, i, JsInterop::toDart(info[i]));
1433 }
1434 // Note: this is also just info.Holder().
1435 Dart_Handle args[2] = { handle, argsList };
1436 setJsReturnValue(domData, info, Dart_Invoke(domData->jsLibrary(), Dart_NewSt ringFromCString(methodName), 2, args));
1437 }
1438
1439 static void arrayNamedPropertyGetter(v8::Local<v8::String> name, const v8::Prope rtyCallbackInfo<v8::Value>& info)
1440 {
1441 if (!DartHandleProxy::isDartProxy(info.Holder())) {
1442 // I don't think this case can occur but avoid crashing if there is an
1443 // exotic way to trigger it.
1444 return;
1445 }
1446
1447 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1448 if (!name->Equals(v8::String::NewFromUtf8(v8Isolate, "length")))
1449 return;
1450
1451 DartScopes scopes(info.Holder());
1452 Dart_Handle handle = scopes.handle;
1453
1454 intptr_t length = 0;
1455 Dart_ListLength(handle, &length);
1456 v8SetReturnValueInt(info, length);
1457 }
1458
1459 static void arrayNamedPropertySetter(v8::Local<v8::String> property, v8::Local<v 8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)
1460 {
1461 if (!DartHandleProxy::isDartProxy(info.Holder())) {
1462 // I don't think this case can occur but avoid crashing if there is an
1463 // exotic way to trigger it.
1464 return;
1465 }
1466
1467 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1468 if (!property->Equals(v8::String::NewFromUtf8(v8Isolate, "length"))) {
1469 return;
1470 }
1471
1472 DartScopes scopes(info.Holder());
1473 Dart_Handle handle = scopes.handle;
1474 DartDOMData* domData = DartDOMData::current();
1475 Dart_Handle args[2] = { handle, JsInterop::toDart(value) };
1476 Dart_Handle ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCStrin g("_setListLength"), 2, args);
1477 setJsReturnValue(domData, info, ret);
1478 }
1479
1480 static void arrayQueryProperty(v8::Local<v8::String> name, const v8::PropertyCal lbackInfo<v8::Integer>& info)
1481 {
1482 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1483 if (name->Equals(v8::String::NewFromUtf8(v8Isolate, "length"))) {
1484 v8SetReturnValueInt(info, v8::DontEnum | v8::DontDelete);
1485 }
1486 }
1487
1488 static void arrayDeleteProperty(v8::Local<v8::String> name, const v8::PropertyCa llbackInfo<v8::Boolean>& info)
1489 {
1490 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1491 if (name->Equals(v8::String::NewFromUtf8(v8Isolate, "length"))) {
1492 v8SetReturnValueBool(info, false);
1493 }
1494 }
1495
1496 void arrayToStringCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1497 {
1498 arrayHelper(info, "_arrayToString", "toString");
1499 }
1500
1501
1502 void arrayJoinCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1503 {
1504 arrayHelper1Arg(info, "_arrayJoin", "join");
1505 }
1506
1507 void arrayPushCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1508 {
1509 arrayHelperWithArgsAsList(info, "_arrayPush", "push");
1510 }
1511
1512 void arrayPopCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1513 {
1514 arrayHelper(info, "_arrayPop", "pop");
1515 }
1516
1517 void concatCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1518 {
1519 arrayHelperWithArgsAsList(info, "_arrayConcat", "concat");
1520 }
1521
1522 void arrayReverseCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1523 {
1524 arrayHelper(info, "_arrayReverse", "reverse");
1525 }
1526
1527 void arrayShiftCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1528 {
1529 arrayHelper(info, "_arrayShift", "shift");
1530 }
1531
1532 void arrayUnshiftCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1533 {
1534 arrayHelperWithArgsAsList(info, "_arrayUnshift", "unshift");
1535 }
1536
1537 void arraySpliceCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1538 {
1539 arrayHelperWithArgsAsList(info, "_arraySplice", "splice");
1540 }
1541
1542 void toJsArrayCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1543 {
1544 // This isn't a method on the JavaScript Array class so it is fine to
1545 // just return the existing hopefully Array like JS object if not called on
1546 // a Dart List.
1547 if (!DartHandleProxy::isDartProxy(info.Holder())) {
1548 v8SetReturnValue(info, info.Holder());
1549 }
1550 DartScopes scopes(info.Holder());
1551 DartDOMData* domData = DartDOMData::current();
1552 Dart_Handle handle = scopes.handle;
1553 Dart_Handle exception = 0;
1554 v8::Local<v8::Array> v8Array = shallowListToV8(handle, domData, exception);
1555 ASSERT(!exception);
1556 v8SetReturnValue(info, v8Array);
1557 }
1558
1559 void arraySortCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
1560 {
1561 // TODO(jacobr): consider using the JavaScript sort method instead.
1562 arrayHelper1Arg(info, "_arraySort", "sort");
1563 }
1564
1565 v8::Local<v8::FunctionTemplate> dartListTemplate()
1566 {
1567 DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, proxyTemplate, ()) ;
1568 v8::Local<v8::FunctionTemplate> proxyTemplateLocal;
1569 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
1570 if (proxyTemplate.IsEmpty()) {
1571 proxyTemplate.Reset(v8::Isolate::GetCurrent(), v8::FunctionTemplate::New (v8Isolate));
1572 proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, pro xyTemplate);
1573 // Set to Array because we want these instances to appear to be
1574 // JavaScript arrays as far as user code is concerned.
1575 proxyTemplateLocal->SetClassName(v8::String::NewFromUtf8(v8Isolate, "Arr ay"));
1576 // Hack to set the prototype to be the prototype of an actual JavaScript Array.
1577
1578 v8::Local<v8::ObjectTemplate> protoTemplate = proxyTemplateLocal->Proto typeTemplate();
1579
1580 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "toString"), v8:: FunctionTemplate::New(v8Isolate, arrayToStringCallback), v8::DontEnum);
1581 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "join"), v8::Func tionTemplate::New(v8Isolate, arrayJoinCallback), v8::DontEnum);
1582 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "push"), v8::Func tionTemplate::New(v8Isolate, arrayPushCallback), v8::DontEnum);
1583 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "pop"), v8::Funct ionTemplate::New(v8Isolate, arrayPopCallback), v8::DontEnum);
1584 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "concat"), v8::Fu nctionTemplate::New(v8Isolate, concatCallback), v8::DontEnum);
1585 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "reverse"), v8::F unctionTemplate::New(v8Isolate, arrayReverseCallback), v8::DontEnum);
1586
1587 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "shift"), v8::Fun ctionTemplate::New(v8Isolate, arrayShiftCallback), v8::DontEnum);
1588 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "unshift"), v8::F unctionTemplate::New(v8Isolate, arrayUnshiftCallback), v8::DontEnum);
1589 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "splice"), v8::Fu nctionTemplate::New(v8Isolate, arraySpliceCallback), v8::DontEnum);
1590 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "sort"), v8::Func tionTemplate::New(v8Isolate, arraySortCallback), v8::DontEnum);
1591 protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "$toJsArray"), v8 ::FunctionTemplate::New(v8Isolate, toJsArrayCallback), v8::DontEnum);
1592
1593 // ES6 experimental properties not currently supported that we could sup port if needed.
1594 // These would require building separate live proxy objects.
1595 // "entries",
1596 // "values",
1597 // "keys"
1598
1599 v8::Local<v8::ObjectTemplate> instanceTemplate = setupInstanceTemplate(p roxyTemplateLocal);
1600 instanceTemplate->SetIndexedPropertyHandler(&indexedGetterArray, &indexe dSetterArray, 0, 0, &indexedEnumeratorArray);
1601 instanceTemplate->SetNamedPropertyHandler(&arrayNamedPropertyGetter, &ar rayNamedPropertySetter, &arrayQueryProperty, &arrayDeleteProperty, 0);
1602 } else {
1603 proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, pro xyTemplate);
1604 }
1605 return proxyTemplateLocal;
1606 }
1607
1608 void JsInterop::jsInteropGetterCallback(Dart_NativeArguments args)
1609 {
1610 JsInteropInternal::getterCallback(args);
1611 }
1612
1613 void JsInterop::jsInteropCallMethodCallback(Dart_NativeArguments args)
1614 {
1615 JsInteropInternal::callMethodCallback(args);
1616 }
1617
1618 void JsInterop::jsInteropContextCallback(Dart_NativeArguments args)
1619 {
1620 return JsInteropInternal::contextCallback(args);
1621 }
1622
1623 }
OLDNEW
« no previous file with comments | « Source/bindings/core/dart/DartJsInterop.h ('k') | Source/bindings/core/dart/DartJsInteropData.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698