diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart index bb580634fd9..8038b81dd9f 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart @@ -268,9 +268,18 @@ getStaticSetters(value) => _getMembers(value, _staticSetterSig); getGenericTypeCtor(value) => JS('', '#[#]', value, _genericTypeCtor); -/// Get the type of a method from an object using the stored signature -getType(obj) => - JS('', '# == null ? # : #.__proto__.constructor', obj, Object, obj); +/// Get the type of an object. +getType(obj) { + if (obj == null) return JS('!', '#', Object); + + if (JS('!', '#.__proto__ == null', obj)) { + // Object.create(null) produces a js object without a prototype. + // In that case use the version from a js object literal. + return JS('!', '#.Object.prototype.constructor', global_); + } + + return JS('!', '#.__proto__.constructor', obj); +} getLibraryUri(value) => JS('', '#[#]', value, _libraryUri); setLibraryUri(f, uri) => JS('', '#[#] = #', f, _libraryUri, uri); diff --git a/tests/lib/js/method_call_on_object_test.dart b/tests/lib/js/method_call_on_object_test.dart new file mode 100644 index 00000000000..b8eba44192b --- /dev/null +++ b/tests/lib/js/method_call_on_object_test.dart @@ -0,0 +1,65 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Tests method calls (typed and dynamic) on various forms of JS objects. + +@JS() +library js_parameters_test; + +import 'package:js/js.dart'; +import 'package:expect/expect.dart'; + +@JS() +external void eval(String code); + +@JS() +class Foo { + external Foo(); + external dynamic method(int x); +} + +@JS() +external Foo makeFooLiteral(); + +@JS() +external Foo makeFooObjectCreate(); + +main() { + // These examples from based on benchmarks-internal/js + eval(r''' +self.Foo = function Foo() {} +self.Foo.prototype.method = function(x) { return x + 1; } + +self.makeFooLiteral = function() { + return { + method: function(x) { return x + 1; } + } +} + +// Objects created in this way have no prototype. +self.makeFooObjectCreate = function() { + var o = Object.create(null); + o.method = function(x) { return x + 1; } + return o; +} +'''); + + var foo = Foo(); + Expect.equals(2, foo.method(1)); + + foo = makeFooLiteral(); + Expect.equals(2, foo.method(1)); + + foo = makeFooObjectCreate(); + Expect.equals(2, foo.method(1)); + + dynamic dynamicFoo = Foo(); + Expect.equals(2, dynamicFoo.method(1)); + + dynamicFoo = makeFooLiteral(); + Expect.equals(2, dynamicFoo.method(1)); + + dynamicFoo = makeFooObjectCreate(); + Expect.equals(2, dynamicFoo.method(1)); +} diff --git a/tests/lib_2/js/method_call_on_object_test.dart b/tests/lib_2/js/method_call_on_object_test.dart new file mode 100644 index 00000000000..b8eba44192b --- /dev/null +++ b/tests/lib_2/js/method_call_on_object_test.dart @@ -0,0 +1,65 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Tests method calls (typed and dynamic) on various forms of JS objects. + +@JS() +library js_parameters_test; + +import 'package:js/js.dart'; +import 'package:expect/expect.dart'; + +@JS() +external void eval(String code); + +@JS() +class Foo { + external Foo(); + external dynamic method(int x); +} + +@JS() +external Foo makeFooLiteral(); + +@JS() +external Foo makeFooObjectCreate(); + +main() { + // These examples from based on benchmarks-internal/js + eval(r''' +self.Foo = function Foo() {} +self.Foo.prototype.method = function(x) { return x + 1; } + +self.makeFooLiteral = function() { + return { + method: function(x) { return x + 1; } + } +} + +// Objects created in this way have no prototype. +self.makeFooObjectCreate = function() { + var o = Object.create(null); + o.method = function(x) { return x + 1; } + return o; +} +'''); + + var foo = Foo(); + Expect.equals(2, foo.method(1)); + + foo = makeFooLiteral(); + Expect.equals(2, foo.method(1)); + + foo = makeFooObjectCreate(); + Expect.equals(2, foo.method(1)); + + dynamic dynamicFoo = Foo(); + Expect.equals(2, dynamicFoo.method(1)); + + dynamicFoo = makeFooLiteral(); + Expect.equals(2, dynamicFoo.method(1)); + + dynamicFoo = makeFooObjectCreate(); + Expect.equals(2, dynamicFoo.method(1)); +}