blob: cef4a56c4e6ef2f4aba5d91e3bf34617a6a5d14c [file] [log] [blame]
// Copyright (c) 2013, 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.
import "native_testing.dart";
// Test for dartNativeDispatchHooksTransformer
// - uncached, instance, leaf and interior caching modes.
// - composition of getTag.
@Native("T1A")
class T1A {
foo() native;
}
@Native("T1B")
class T1B {
foo() native;
}
@Native("T1C")
class T1C {
foo() native;
}
@Native("T1D")
class T1D {
foo() native;
}
makeT1A() native;
makeT1B() native;
makeT1C() native;
makeT1D() native;
int getTagCallCount() native;
void clearTagCallCount() native;
void setup() {
JS('', r'''
(function(){
function T1A() { this.v = "a"; }
function T1B() { this.v = "b"; }
function T1C() { this.v = "c"; }
function T1D() { this.v = "d"; }
// T1B, T1C and T1D extend T1A in the implementation but not the declared types.
// T1A must not be leaf-cached otherwise we will pick up the interceptor for T1A
// when looking for the dispatch record for an uncached or not-yet-cached T1B,
// T1C or T1D.
T1B.prototype.__proto__ = T1A.prototype;
T1C.prototype.__proto__ = T1A.prototype;
T1D.prototype.__proto__ = T1A.prototype;
// All classes share one implementation of native method 'foo'.
T1A.prototype.foo = function() { return this.v + this.name(); };
T1A.prototype.name = function() { return "A"; };
T1B.prototype.name = function() { return "B"; };
T1C.prototype.name = function() { return "C"; };
T1D.prototype.name = function() { return "D"; };
self.makeT1A = function(){return new T1A()};
self.makeT1B = function(){return new T1B()};
self.makeT1C = function(){return new T1C()};
self.makeT1D = function(){return new T1D()};
self.nativeConstructor(T1A, undefined, true);
self.nativeConstructor(T1B, undefined, true);
self.nativeConstructor(T1C, undefined, true);
self.nativeConstructor(T1D, undefined, true);
var getTagCount = 0;
self.getTagCallCount = function() { return getTagCount; };
self.clearTagCallCount = function() { getTagCount = 0; };
function transformer1(hooks) {
var getTag = hooks.getTag;
function getTagNew(obj) {
var tag = getTag(obj);
// Dependency to test composition, rename T1D -> Dep -> -T1D.
if (tag == "T1D") return "Dep";
return tag;
}
hooks.getTag = getTagNew;
}
function transformer2(hooks) {
var getTag = hooks.getTag;
function getTagNew(obj) {
++getTagCount;
var tag = getTag(obj);
if (tag == "T1A") return "+T1A"; // Interior cached on prototype
if (tag == "T1B") return "~T1B"; // Uncached
if (tag == "T1C") return "!T1C"; // Instance cached
if (tag == "Dep") return "-T1D"; // Leaf cached on prototype
return tag;
}
hooks.getTag = getTagNew;
}
self.dartNativeDispatchHooksTransformer = [transformer1, transformer2];
})()''');
applyTestExtensions(['T1A', 'T1B', 'T1C', 'T1D']);
}
main() {
nativeTesting();
setup();
var t1a = makeT1A();
var t1b = makeT1B();
var t1c = makeT1C();
var t1d = makeT1D();
clearTagCallCount();
Expect.equals("aA", confuse(t1a).foo(), 't1a is T1A');
Expect.equals("bB", confuse(t1b).foo(), 't1b is T1B');
Expect.equals("cC", confuse(t1c).foo(), 't1c is T1C');
Expect.equals("dD", confuse(t1d).foo(), 't1d is T1D');
Expect.equals(4, getTagCallCount(), '4 fresh instances / types');
clearTagCallCount();
Expect.equals("aA", confuse(t1a).foo(), 't1a is T1A');
Expect.equals("bB", confuse(t1b).foo(), 't1b is T1B');
Expect.equals("cC", confuse(t1c).foo(), 't1c is T1C');
Expect.equals("dD", confuse(t1d).foo(), 't1d is T1D');
Expect.equals(1, getTagCallCount(), '1 = 1 uncached + (3 cached)');
t1a = makeT1A();
t1b = makeT1B();
t1c = makeT1C();
t1d = makeT1D();
clearTagCallCount();
Expect.equals("aA", confuse(t1a).foo(), 't1a is T1A');
Expect.equals("bB", confuse(t1b).foo(), 't1b is T1B');
Expect.equals("cC", confuse(t1c).foo(), 't1c is T1C');
Expect.equals("dD", confuse(t1d).foo(), 't1d is T1D');
Expect.equals(2, getTagCallCount(),
'2 = 1 fresh instance + 1 uncached (+ 2 proto cached)');
clearTagCallCount();
Expect.equals("aA", confuse(t1a).foo(), 't1a is T1A');
Expect.equals("bB", confuse(t1b).foo(), 't1b is T1B');
Expect.equals("cC", confuse(t1c).foo(), 't1c is T1C');
Expect.equals("dD", confuse(t1d).foo(), 't1d is T1D');
Expect.equals(1, getTagCallCount(),
'1 = 2 proto cached + 1 instance cached + 1 uncached');
}