blob: 3a5a35e281d7e3e15b9d4434d75c01798bfdc442 [file] [log] [blame]
// Copyright (c) 2024, 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.
// Test for @pragma('dyn-module:extendable') and @pragma('dyn-module:can-be-overridden').
import 'package:vm/testing/il_matchers.dart';
@pragma('vm:never-inline')
void myprint(Object message) {
print(message);
}
abstract class A1 {
void foo();
void bar();
void baz();
}
class B1 extends A1 {
void foo() {
myprint('B1.foo');
}
void bar() {
myprint('B1.bar');
}
@pragma('vm:never-inline')
void baz() {
myprint('B1.baz');
}
}
class C1 extends B1 {
@pragma('vm:never-inline')
void baz() {
myprint('C1.baz');
}
}
@pragma('vm:never-inline')
@pragma('vm:testing:print-flow-graph')
void callA1(A1 obj) {
obj.foo();
obj.bar();
obj.baz();
}
@pragma('vm:never-inline')
@pragma('vm:testing:print-flow-graph')
void testIsA1(obj) {
myprint(obj is A1);
myprint(obj is B1);
myprint(obj is C1);
}
abstract class A2 {
void foo();
void bar();
void baz();
}
@pragma('dyn-module:extendable')
class B2 extends A2 {
void foo() {
myprint('B2.foo');
}
@pragma('dyn-module:can-be-overridden')
void bar() {
myprint('B2.bar');
}
@pragma('vm:never-inline')
void baz() {
myprint('B2.baz');
}
}
class C2 extends B2 {
@pragma('vm:never-inline')
void baz() {
myprint('C2.baz');
}
}
class D2 extends B2 {}
@pragma('vm:never-inline')
@pragma('vm:testing:print-flow-graph')
void callA2(A2 obj) {
obj.foo();
obj.bar();
obj.baz();
}
@pragma('vm:never-inline')
@pragma('vm:testing:print-flow-graph')
void testIsA2(obj) {
myprint(obj is A2);
myprint(obj is B2);
myprint(obj is C2);
}
List objs = [Object(), B1(), C1(), B2(), C2()];
main() {
for (final obj in objs) {
testIsA1(obj);
testIsA2(obj);
if (obj is A1) {
callA1(obj);
}
if (obj is A2) {
callA2(obj);
}
}
testCallInTryWithControlFlow(getMyString(), int.parse('1'));
}
void matchIL$callA1(FlowGraph graph) {
graph.dump();
graph.match([
match.block('Graph', []),
match.block('Function', [
'obj' << match.Parameter(index: 0),
match.CheckStackOverflow(),
match.MoveArgument(match.any),
match.StaticCall(match.any),
match.MoveArgument(match.any),
match.StaticCall(match.any),
'cid' << match.LoadClassId('obj'),
match.MoveArgument('obj'),
match.DispatchTableCall('cid'),
match.DartReturn(match.any),
]),
]);
}
void matchIL$callA2(FlowGraph graph) {
graph.dump();
graph.match([
match.block('Graph', []),
match.block('Function', [
'obj' << match.Parameter(index: 0),
match.CheckStackOverflow(),
match.MoveArgument(match.any),
match.StaticCall(match.any),
'cid1' << match.LoadClassId('obj'),
match.Branch(match.TestRange('cid1'), ifTrue: 'B7', ifFalse: 'B8'),
]),
'B7' <<
match.block('Target', [
match.MoveArgument('obj'),
match.DispatchTableCall('cid1'),
match.Goto('B9'),
]),
'B8' <<
match.block('Target', [
match.MoveArgument('obj'),
match.InstanceCall('obj'),
match.Goto('B9'),
]),
'B9' <<
match.block('Join', [
'cid2' << match.LoadClassId('obj'),
match.Branch(match.TestRange('cid2'), ifTrue: 'B10', ifFalse: 'B11'),
]),
'B10' <<
match.block('Target', [
match.MoveArgument('obj'),
match.DispatchTableCall('cid2'),
match.Goto('B12'),
]),
'B11' <<
match.block('Target', [
match.MoveArgument('obj'),
match.InstanceCall('obj'),
match.Goto('B12'),
]),
'B12' <<
match.block('Join', [
match.DartReturn(match.any),
]),
]);
}
void matchIL$testIsA1(FlowGraph graph) {
graph.dump();
graph.match([
match.block('Graph', []),
match.block('Function', [
'obj' << match.Parameter(index: 0),
match.CheckStackOverflow(),
'cid' << match.LoadClassId('obj'),
'test1' << match.TestRange('cid'),
match.MoveArgument('test1'),
match.StaticCall('test1'),
match.MoveArgument('test1'),
match.StaticCall('test1'),
'test2' << match.EqualityCompare('cid', match.any, kind: '=='),
match.MoveArgument('test2'),
match.StaticCall('test2'),
match.DartReturn(match.any),
]),
]);
}
void matchIL$testIsA2(FlowGraph graph) {
graph.dump();
graph.match([
match.block('Graph', []),
match.block('Function', [
'obj' << match.Parameter(index: 0),
match.CheckStackOverflow(),
'test1' << match.InstanceOf('obj', match.any, match.any),
match.MoveArgument('test1'),
match.StaticCall('test1'),
'test2' << match.InstanceOf('obj', match.any, match.any),
match.MoveArgument('test2'),
match.StaticCall('test2'),
'cid' << match.LoadClassId('obj'),
'test3' << match.EqualityCompare('cid', match.any, kind: '=='),
match.MoveArgument('test3'),
match.StaticCall('test3'),
match.DartReturn(match.any),
]),
]);
}
@pragma('dyn-module:extendable')
class MyString {
@pragma('dyn-module:can-be-overridden')
@pragma('vm:never-inline')
int get length => int.parse('2');
@pragma('dyn-module:can-be-overridden')
@pragma('vm:never-inline')
String substring(int start) => 42.toString();
}
MyString getMyString() => [MyString()][int.parse('0')];
@pragma('vm:never-inline')
int intParse(String str) => int.parse(str);
@pragma('vm:never-inline')
@pragma('vm:testing:print-flow-graph')
void testCallInTryWithControlFlow(MyString value, int pos) {
if (pos == value.length) {
} else {
try {
intParse(value.substring(pos));
} catch (e) {}
}
}
void matchIL$testCallInTryWithControlFlow(FlowGraph graph) {
graph.dump();
graph.match([
match.block('Graph', []),
match.block('Function', [
'value' << match.Parameter(index: 0),
'pos' << match.Parameter(index: 1),
match.CheckStackOverflow(),
'cid1' << match.LoadClassId('value'),
match.Branch(match.TestRange('cid1'), ifTrue: 'B9', ifFalse: 'B10'),
]),
'B9' <<
match.block('Target', [
match.MoveArgument('value'),
'value_length1' << match.DispatchTableCall('cid1'),
match.Goto('B11'),
]),
'B10' <<
match.block('Target', [
match.MoveArgument('value'),
'value_length2' << match.InstanceCall('value'),
match.Goto('B11'),
]),
'B11' <<
match.block('Join', [
'value_length' << match.Phi('value_length1', 'value_length2'),
'value_length_unboxed' << match.UnboxInt64('value_length'),
match.Branch(
match.EqualityCompare('pos', 'value_length_unboxed', kind: '=='),
ifTrue: 'B3',
ifFalse: 'B4'),
]),
'B3' <<
match.block('Target', [
match.Goto('B8'),
]),
'B4' <<
match.block('Target', [
match.Goto('B5'),
]),
'B5' <<
match.block('Join', [
'pos_boxed' << match.BoxInt64('pos'),
'cid2' << match.LoadClassId('value'),
match.Branch(match.TestRange('cid2'), ifTrue: 'B12', ifFalse: 'B13'),
]),
'B12' <<
match.block('Target', [
match.MoveArgument('value'),
match.MoveArgument('pos_boxed'),
'value_substring1' << match.DispatchTableCall('cid2'),
match.Goto('B14'),
]),
'B13' <<
match.block('Target', [
match.MoveArgument('value'),
match.MoveArgument('pos_boxed'),
'value_substring2' << match.InstanceCall('value', 'pos_boxed'),
match.Goto('B14'),
]),
'B14' <<
match.block('Join', [
'value_substring' <<
match.Phi('value_substring1', 'value_substring2'),
match.MoveArgument('value_substring'),
match.StaticCall('value_substring'),
match.Goto('B6'),
]),
'B7' <<
match.block('CatchBlock', [
match.Goto('B6'),
]),
'B6' <<
match.block('Join', [
match.Goto('B8'),
]),
'B8' <<
match.block('Join', [
match.DartReturn(match.any),
]),
]);
}