// Copyright (c) 2011, 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. // dart2jsOptions=--omit-implicit-checks // Test that native methods with unnamed optional arguments are called with the // number of arguments in the call site AND the call site is inlined. import 'native_testing.dart'; typedef int Int2Int(int x); @Native("A") class A { int foo([x, y, z]) native; // Calls can be inlined provided they don't pass an argument. int callFun([Int2Int fn]) native; } class B { @pragma('dart2js:noElision') static var g; @pragma('dart2js:noInline') method1(a) { g = '(Method1Tag)'; // Tag to identify compiled JavaScript method. A x = makeA(); // Call sites that are searched for in compiled JavaScript. x.foo(); x.foo(1); x.foo(2, 10); return x.foo(3, 10, 30); } @pragma('dart2js:noInline') method2() { g = '(Method2Tag)'; A x = makeA(); var r1 = x.callFun(); // Can be inlined. var r2 = x.callFun(); return r1 + r2; } @pragma('dart2js:noInline') method3() { g = '(Method3Tag)'; A x = makeA(); var r1 = x.callFun((x) => x * 2); // Can't be inlined due to conversion. var r2 = x.callFun((x) => x * 0); return r1 + r2; } } A makeA() native; String findMethodTextContaining(instance, string) native; void setup() { JS('', r""" (function(){ function A() {} A.prototype.foo = function () { return arguments.length; }; A.prototype.callFun = function (fn) { return fn ? fn(123) : 1; }; self.makeA = function(){return new A()}; findMethodTextContaining = function (instance, string) { var proto = Object.getPrototypeOf(instance); var keys = Object.keys(proto); for (var i = 0; i < keys.length; i++) { var name = keys[i]; var member = proto[name]; var s = String(member); if (s.indexOf(string)>0) return s; } }; self.nativeConstructor(A); })()"""); applyTestExtensions(['A']); } void match(String s, String pattern1) { var pattern2 = pattern1.replaceAll(' ', ''); Expect.isTrue( s.contains(pattern1) || s.contains(pattern2), "expected $pattern1 or $pattern2 in '$s'", ); } void nomatch(String s, String pattern1) { var pattern2 = pattern1.replaceAll(' ', ''); Expect.isFalse( s.contains(pattern1) || s.contains(pattern2), "should not have $pattern1 or $pattern2 in '$s'", ); } test1() { String method1 = findMethodTextContaining(new B(), '(Method1Tag)'); Expect.isNotNull(method1, 'No method found containing "(Method1Tag)"'); // Direct (inlined) calls don't have $3 or minified names. match(method1, r'.foo()'); match(method1, r'.foo(1)'); match(method1, r'.foo(2, 10)'); match(method1, r'.foo(3, 10, 30)'); // Ensure the methods are compiled by calling them. var a = makeA(); Expect.equals(0, a.foo()); Expect.equals(1, a.foo(10)); Expect.equals(2, a.foo(10, 20)); Expect.equals(3, a.foo(10, 20, 30)); var b = new B(); var r = b.method1(a); Expect.equals(3, r); } test2() { String method2 = findMethodTextContaining(new B(), '(Method2Tag)'); Expect.isNotNull(method2, 'No method found containing "(Method2Tag)"'); // Can always inline the zero-arg call. match(method2, r'.callFun()'); String method3 = findMethodTextContaining(new B(), '(Method3Tag)'); Expect.isNotNull(method3, 'No method found containing "(Method3Tag)"'); // Don't inline native method with a function argument - should call a stub // containing the conversion. nomatch(method3, r'.callFun('); // Ensure the methods are compiled by calling them. var a = makeA(); Expect.equals(369, a.callFun((i) => 3 * i)); var b = new B(); Expect.equals(2, b.method2()); Expect.equals(246, b.method3()); } main() { nativeTesting(); setup(); test1(); test2(); }