[vm/kernel/bytecode] Generate bytecode for assertions, bool checks
In addition:
* Use InstanceCall1 instead of InstanceCall2 for now as InstanceCall2
requires ICData objects with 2 checked arguments.
* Remove try-catch around bytecode generation as all operations are
supported and silent fallback is no longer needed.
Change-Id: Iead5a4997450cc47ef3bb3221647e733b7a72b62
Reviewed-on: https://dart-review.googlesource.com/62443
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/lib/bytecode/assembler.dart b/pkg/vm/lib/bytecode/assembler.dart
index d5fa43b..3ccf658 100644
--- a/pkg/vm/lib/bytecode/assembler.dart
+++ b/pkg/vm/lib/bytecode/assembler.dart
@@ -67,6 +67,10 @@
bytecode.addAll(_encodeBufferOut);
}
+ int _getOpcodeAt(int pos) {
+ return bytecode[pos]; // TODO(alexmarkov): Take endianness into account.
+ }
+
void _setWord(int pos, int word) {
_encodeBufferIn[0] = word; // TODO(alexmarkov): Which endianness to use?
bytecode.setRange(pos, pos + _encodeBufferOut.length, _encodeBufferOut);
@@ -166,8 +170,14 @@
emitWord(_encodeT(Opcode.kJump, label.jumpOperand(offset)));
}
+ void emitJumpIfNoAsserts(Label label) {
+ emitWord(_encodeT(Opcode.kJumpIfNoAsserts, label.jumpOperand(offset)));
+ }
+
void patchJump(int pos, int rt) {
- _setWord(pos, _encodeT(Opcode.kJump, rt));
+ final Opcode opcode = Opcode.values[_getOpcodeAt(pos)];
+ assert(isJump(opcode));
+ _setWord(pos, _encodeT(opcode, rt));
}
void emitReturn(int ra) {
diff --git a/pkg/vm/lib/bytecode/dbc.dart b/pkg/vm/lib/bytecode/dbc.dart
index c2e6216..a3b002b 100644
--- a/pkg/vm/lib/bytecode/dbc.dart
+++ b/pkg/vm/lib/bytecode/dbc.dart
@@ -18,6 +18,10 @@
// 3. NativeCall instruction is modified to have 'D' format and take 1 argument:
// D = index of NativeEntry constant pool entry
//
+// 4. JumpIfNoAsserts instruction is added. This instruction jumps to the given
+// target if assertions are not enabled. It has the same format as Jump
+// instruction.
+//
enum Opcode {
kTrap,
@@ -29,6 +33,7 @@
kDropR,
kDrop,
kJump,
+ kJumpIfNoAsserts,
kReturn,
kReturnTOS,
kMove,
@@ -266,6 +271,8 @@
Encoding.kA, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kJump: const Format(
Encoding.kT, const [Operand.tgt, Operand.none, Operand.none]),
+ Opcode.kJumpIfNoAsserts: const Format(
+ Encoding.kT, const [Operand.tgt, Operand.none, Operand.none]),
Opcode.kReturn: const Format(
Encoding.kA, const [Operand.reg, Operand.none, Operand.none]),
Opcode.kReturnTOS: const Format(
@@ -651,3 +658,5 @@
exception,
stackTrace,
}
+
+bool isJump(Opcode opcode) => BytecodeFormats[opcode].encoding == Encoding.kT;
diff --git a/pkg/vm/lib/bytecode/disassembler.dart b/pkg/vm/lib/bytecode/disassembler.dart
index 279d492..be1e109 100644
--- a/pkg/vm/lib/bytecode/disassembler.dart
+++ b/pkg/vm/lib/bytecode/disassembler.dart
@@ -95,7 +95,7 @@
void _scanForJumpTargets() {
for (int i = 0; i < _instructions.length; i++) {
final instr = _instructions[i];
- if (instr.opcode == Opcode.kJump) {
+ if (isJump(instr.opcode)) {
final target = i + instr.operands[0];
assert(0 <= target && target < _instructions.length);
if (!_labels.containsKey(target)) {
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 986874d..c3c76cf 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -30,8 +30,6 @@
/// Flag to toggle generation of bytecode in platform kernel files.
const bool isKernelBytecodeEnabledForPlatform = isKernelBytecodeEnabled;
-const bool isTraceEnabled = false;
-
void generateBytecode(Component component,
{bool strongMode: true, bool dropAST: false}) {
final coreTypes = new CoreTypes(component);
@@ -107,42 +105,36 @@
if (node.isAbstract) {
return;
}
- try {
- if (node is Field) {
- if (node.isStatic && node.initializer != null) {
- start(node);
- if (node.isConst) {
- _genPushConstExpr(node.initializer);
- } else {
- node.initializer.accept(this);
- }
- _genReturnTOS();
- end(node);
- }
- } else if ((node is Procedure && !node.isRedirectingFactoryConstructor) ||
- (node is Constructor)) {
+ if (node is Field) {
+ if (node.isStatic && node.initializer != null) {
start(node);
- if (node is Constructor) {
- _genConstructorInitializers(node);
- }
- if (node.isExternal) {
- final String nativeName = getExternalName(node);
- if (nativeName == null) {
- return;
- }
- _genNativeCall(nativeName);
+ if (node.isConst) {
+ _genPushConstExpr(node.initializer);
} else {
- node.function?.body?.accept(this);
- // TODO(alexmarkov): figure out when 'return null' should be generated.
- _genPushNull();
+ node.initializer.accept(this);
}
_genReturnTOS();
end(node);
}
- } on UnsupportedOperationError catch (e) {
- if (isTraceEnabled) {
- print('Unable to generate bytecode for $node: $e');
+ } else if ((node is Procedure && !node.isRedirectingFactoryConstructor) ||
+ (node is Constructor)) {
+ start(node);
+ if (node is Constructor) {
+ _genConstructorInitializers(node);
}
+ if (node.isExternal) {
+ final String nativeName = getExternalName(node);
+ if (nativeName == null) {
+ return;
+ }
+ _genNativeCall(nativeName);
+ } else {
+ node.function?.body?.accept(this);
+ // TODO(alexmarkov): figure out when 'return null' should be generated.
+ _genPushNull();
+ }
+ _genReturnTOS();
+ end(node);
}
}
@@ -230,6 +222,10 @@
Procedure get futureValue =>
_futureValue ??= libraryIndex.getMember('dart:async', 'Future', 'value');
+ Procedure _throwNewAssertionError;
+ Procedure get throwNewAssertionError => _throwNewAssertionError ??=
+ libraryIndex.getMember('dart:core', '_AssertionError', '_throwNew');
+
void _genConstructorInitializers(Constructor node) {
bool isRedirecting =
node.initializers.any((init) => init is RedirectingInitializer);
@@ -491,14 +487,14 @@
}
/// Generates bool condition. Returns `true` if condition is negated.
- bool _genCondition(Node condition) {
+ bool _genCondition(Expression condition) {
bool negated = false;
if (condition is Not) {
condition = (condition as Not).operand;
negated = true;
}
condition.accept(this);
- // TODO(alexmarkov): bool check
+ asm.emitAssertBoolean(0);
return negated;
}
@@ -628,10 +624,6 @@
metadata.mapping[node] =
new BytecodeMetadata(cp, asm.bytecode, asm.exceptionsTable, closures);
- if (isTraceEnabled) {
- print('Generated bytecode for $node');
- }
-
enclosingClass = null;
enclosingMember = null;
classTypeParameters = null;
@@ -1611,7 +1603,24 @@
@override
visitAssertStatement(AssertStatement node) {
- // TODO(alexmarkov): support asserts
+ final Label done = new Label();
+ asm.emitJumpIfNoAsserts(done);
+
+ final bool negated = _genCondition(node.condition);
+ _genJumpIfTrue(negated, done);
+
+ _genPushInt(node.conditionStartOffset);
+ _genPushInt(node.conditionEndOffset);
+
+ if (node.message != null) {
+ node.message.accept(this);
+ } else {
+ _genPushNull();
+ }
+
+ _genStaticCall(throwNewAssertionError, new ConstantArgDesc(3), 3);
+
+ asm.bind(done);
}
@override
@@ -1623,7 +1632,14 @@
@override
visitAssertBlock(AssertBlock node) {
- // TODO(alexmarkov): support asserts
+ final Label done = new Label();
+ asm.emitJumpIfNoAsserts(done);
+
+ _enterScope(node);
+ visitList(node.statements, this);
+ _leaveScope();
+
+ asm.bind(done);
}
@override
@@ -1852,7 +1868,9 @@
for (var expr in switchCase.expressions) {
asm.emitPush(temp);
_genPushConstExpr(expr);
- asm.emitInstanceCall2(
+ // TODO(alexmarkov): generate InstanceCall2 once we have a way to
+ // mark ICData as having 2 checked arguments.
+ asm.emitInstanceCall1(
2,
cp.add(new ConstantICData(
InvocationKind.method, new Name('=='), equalsArgDesc)));
diff --git a/pkg/vm/testcases/bytecode/asserts.dart b/pkg/vm/testcases/bytecode/asserts.dart
new file mode 100644
index 0000000..2778c8d
--- /dev/null
+++ b/pkg/vm/testcases/bytecode/asserts.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2018, 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.
+
+void test1(bool condition) {
+ assert(condition);
+}
+
+void test2(bool condition(), String message()) {
+ assert(condition(), message());
+}
+
+main() {}
diff --git a/pkg/vm/testcases/bytecode/asserts.dart.expect b/pkg/vm/testcases/bytecode/asserts.dart.expect
new file mode 100644
index 0000000..6d2946c
--- /dev/null
+++ b/pkg/vm/testcases/bytecode/asserts.dart.expect
@@ -0,0 +1,80 @@
+library #lib;
+import self as self;
+import "dart:core" as core;
+
+[@vm.bytecode=
+Bytecode {
+ Entry 0
+ CheckStack
+ JumpIfNoAsserts L1
+ Push FP[-5]
+ AssertBoolean 0
+ PushConstant CP#0
+ IfEqStrictTOS
+ Jump L1
+ PushConstant CP#1
+ PushConstant CP#2
+ PushConstant CP#3
+ PushConstant CP#5
+ IndirectStaticCall 3, CP#4
+L1:
+ PushConstant CP#3
+ ReturnTOS
+}
+ConstantPool {
+ [0] = Bool true
+ [1] = Int 255
+ [2] = Int 264
+ [3] = Null
+ [4] = ArgDesc num-args 3, num-type-args 0, names []
+ [5] = StaticICData target 'dart.core::_AssertionError::_throwNew', arg-desc CP#4
+}
+]static method test1(core::bool condition) → void {
+ assert(condition);
+}
+[@vm.bytecode=
+Bytecode {
+ Entry 0
+ CheckStack
+ JumpIfNoAsserts L1
+ Push FP[-6]
+ InstanceCall1 1, CP#1
+ AssertBoolean 0
+ PushConstant CP#2
+ IfEqStrictTOS
+ Jump L1
+ PushConstant CP#3
+ PushConstant CP#4
+ Push FP[-5]
+ InstanceCall1 1, CP#5
+ PushConstant CP#7
+ IndirectStaticCall 3, CP#6
+L1:
+ PushConstant CP#8
+ ReturnTOS
+}
+ConstantPool {
+ [0] = ArgDesc num-args 1, num-type-args 0, names []
+ [1] = ICData target-name 'call', arg-desc CP#0
+ [2] = Bool true
+ [3] = Int 328
+ [4] = Int 339
+ [5] = ICData target-name 'call', arg-desc CP#0
+ [6] = ArgDesc num-args 3, num-type-args 0, names []
+ [7] = StaticICData target 'dart.core::_AssertionError::_throwNew', arg-desc CP#6
+ [8] = Null
+}
+]static method test2(() → core::bool condition, () → core::String message) → void {
+ assert(condition.call(), message.call());
+}
+[@vm.bytecode=
+Bytecode {
+ Entry 0
+ CheckStack
+ PushConstant CP#0
+ ReturnTOS
+}
+ConstantPool {
+ [0] = Null
+}
+]static method main() → dynamic {}
diff --git a/pkg/vm/testcases/bytecode/async.dart b/pkg/vm/testcases/bytecode/async.dart
index e3900c7..cf1d164 100644
--- a/pkg/vm/testcases/bytecode/async.dart
+++ b/pkg/vm/testcases/bytecode/async.dart
@@ -56,4 +56,9 @@
return nested;
}
+Future<int> testAssert(Future<int> a) async {
+ assert((await a) == 42);
+ return 7;
+}
+
main() {}
diff --git a/pkg/vm/testcases/bytecode/async.dart.expect b/pkg/vm/testcases/bytecode/async.dart.expect
index 60a3f58..981b101 100644
--- a/pkg/vm/testcases/bytecode/async.dart.expect
+++ b/pkg/vm/testcases/bytecode/async.dart.expect
@@ -714,6 +714,7 @@
LoadFieldTOS CP#1
PushConstant CP#17
InstanceCall1 2, CP#19
+ AssertBoolean 0
PushConstant CP#20
IfNeStrictTOS
Jump L2
@@ -884,6 +885,7 @@
Push r8
PushConstant CP#17
InstanceCall1 2, CP#34
+ AssertBoolean 0
PushConstant CP#20
IfNeStrictTOS
Jump L7
@@ -1309,6 +1311,7 @@
PushConstant CP#8
PushConstant CP#27
InstanceCall1 4, CP#28
+ AssertBoolean 0
PushConstant CP#29
IfNeStrictTOS
Jump L4
@@ -2172,6 +2175,292 @@
}
[@vm.bytecode=
Bytecode {
+ Entry 4
+ CheckStack
+ AllocateContext 1
+ StoreLocal r1
+ Push r1
+ Push r0
+ StoreFieldTOS CP#0
+ PopLocal r0
+ Push r0
+ Push FP[-5]
+ StoreFieldTOS CP#1
+ AllocateContext 8
+ StoreLocal r1
+ Push r1
+ Push r0
+ StoreFieldTOS CP#0
+ PopLocal r0
+ Push r0
+ PushConstant CP#2
+ PushConstant CP#4
+ IndirectStaticCall 1, CP#3
+ StoreFieldTOS CP#5
+ Push r0
+ PushConstant CP#6
+ StoreFieldTOS CP#7
+ PushConstant CP#6
+ PopLocal r2
+ Push r0
+ PushConstant CP#6
+ StoreFieldTOS CP#8
+ Push r0
+ PushConstant CP#6
+ StoreFieldTOS CP#9
+ Push r0
+ PushConstant CP#10
+ StoreFieldTOS CP#1
+ Push r0
+ PushConstant CP#6
+ StoreFieldTOS CP#11
+ Push r0
+ PushConstant CP#6
+ StoreFieldTOS CP#12
+ Push r0
+ Allocate CP#32
+ StoreLocal r3
+ Push r3
+ PushConstant CP#6
+ StoreFieldTOS CP#33
+ Push r3
+ PushConstant CP#6
+ StoreFieldTOS CP#34
+ Push r3
+ PushConstant CP#13
+ StoreFieldTOS CP#35
+ Push r3
+ Push r0
+ StoreFieldTOS CP#14
+ StoreFieldTOS CP#16
+ Push r0
+ LoadFieldTOS CP#16
+ PushConstant CP#36
+ IndirectStaticCall 1, CP#3
+ StoreLocal r2
+ Drop1
+ Push r0
+ Push r0
+ LoadFieldTOS CP#16
+ PushConstant CP#37
+ IndirectStaticCall 1, CP#3
+ StoreLocal r3
+ StoreFieldTOS CP#8
+ Push r3
+ Drop1
+ Push r0
+ Push r0
+ LoadFieldTOS CP#16
+ PushConstant CP#38
+ IndirectStaticCall 1, CP#3
+ StoreLocal r3
+ StoreFieldTOS CP#9
+ Push r3
+ Drop1
+ PushConstant CP#39
+ Push r0
+ LoadFieldTOS CP#16
+ PushConstant CP#40
+ IndirectStaticCall 2, CP#20
+ Drop1
+ Push r0
+ LoadFieldTOS CP#5
+ InstanceCall1 1, CP#41
+ ReturnTOS
+ Push r0
+ LoadFieldTOS CP#0
+ PopLocal r0
+ PushConstant CP#6
+ ReturnTOS
+}
+ConstantPool {
+ [0] = ContextOffset parent
+ [1] = ContextOffset var [0]
+ [2] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
+ [3] = ArgDesc num-args 1, num-type-args 0, names []
+ [4] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#3
+ [5] = ContextOffset var [7]
+ [6] = Null
+ [7] = ContextOffset var [6]
+ [8] = ContextOffset var [3]
+ [9] = ContextOffset var [4]
+ [10] = Int 0
+ [11] = ContextOffset var [1]
+ [12] = ContextOffset var [2]
+ [13] = ClosureFunction :async_op ([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding ;
+ [14] = FieldOffset dart.core::_Closure::_context
+ [15] = Int 1
+ [16] = ContextOffset var [5]
+ [17] = ArgDesc num-args 4, num-type-args 0, names []
+ [18] = StaticICData target 'dart.async::_awaitHelper', arg-desc CP#17
+ [19] = Int 42
+ [20] = ArgDesc num-args 2, num-type-args 0, names []
+ [21] = ICData target-name '==', arg-desc CP#20
+ [22] = Bool true
+ [23] = Int 1161
+ [24] = Int 1176
+ [25] = ArgDesc num-args 3, num-type-args 0, names []
+ [26] = StaticICData target 'dart.core::_AssertionError::_throwNew', arg-desc CP#25
+ [27] = Int 7
+ [28] = ICData target-name 'complete', arg-desc CP#20
+ [29] = Type dynamic
+ [30] = ICData target-name 'completeError', arg-desc CP#25
+ [31] = EndClosureFunctionScope
+ [32] = Class dart.core::_Closure
+ [33] = FieldOffset dart.core::_Closure::_instantiator_type_arguments
+ [34] = FieldOffset dart.core::_Closure::_function_type_arguments
+ [35] = FieldOffset dart.core::_Closure::_function
+ [36] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#3
+ [37] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#3
+ [38] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#3
+ [39] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
+ [40] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#20
+ [41] = ICData get target-name 'future', arg-desc CP#3
+}
+Closure CP#13 {
+ EntryOptional 1, 3, 0
+ LoadConstant r1, CP#6
+ LoadConstant r2, CP#6
+ LoadConstant r3, CP#6
+ Frame 6
+ CheckStack
+ Push r0
+ LoadFieldTOS CP#14
+ PopLocal r4
+ Push r4
+ LoadFieldTOS CP#1
+ StoreLocal r5
+ PushConstant CP#10
+ IfNeStrictNumTOS
+ Jump L1
+ Push r4
+ Push r4
+ StoreFieldTOS CP#12
+Try #0 start:
+ JumpIfNoAsserts L2
+ Push r4
+ PushConstant CP#15
+ StoreFieldTOS CP#1
+ Push r4
+ Push r4
+ StoreFieldTOS CP#11
+ Push r4
+ LoadFieldTOS CP#0
+ LoadFieldTOS CP#1
+ Push r4
+ LoadFieldTOS CP#8
+ Push r4
+ LoadFieldTOS CP#9
+ Push r4
+ LoadFieldTOS CP#16
+ PushConstant CP#18
+ IndirectStaticCall 4, CP#17
+ PopLocal r8
+ PushConstant CP#6
+ ReturnTOS
+L6:
+ IfEqNull r2
+ Jump L3
+ Push r2
+ Push r3
+ Throw 1
+L3:
+ JumpIfNoAsserts L2
+ Push r1
+ PushConstant CP#19
+ InstanceCall1 2, CP#21
+ AssertBoolean 0
+ PushConstant CP#22
+ IfEqStrictTOS
+ Jump L2
+ PushConstant CP#23
+ PushConstant CP#24
+ PushConstant CP#6
+ PushConstant CP#26
+ IndirectStaticCall 3, CP#25
+L2:
+ Push r4
+ PushConstant CP#27
+ StoreLocal r8
+ StoreFieldTOS CP#7
+ Push r8
+ Drop1
+ Jump L4
+L4:
+ Push r4
+ LoadFieldTOS CP#5
+ Push r4
+ LoadFieldTOS CP#7
+ InstanceCall1 2, CP#28
+ Drop1
+ PushConstant CP#6
+ ReturnTOS
+ Jump L5
+Try #0 end:
+Try #0 handler:
+ Push r0
+ LoadFieldTOS CP#14
+ PopLocal r4
+ Push r4
+ LoadFieldTOS CP#12
+ PopLocal r4
+ MoveSpecial r6, exception
+ MoveSpecial r7, stackTrace
+ Push r6
+ PopLocal r8
+ Push r7
+ PopLocal r9
+ Push r4
+ LoadFieldTOS CP#5
+ Push r8
+ Push r9
+ InstanceCall1 3, CP#30
+ Drop1
+ Jump L5
+L5:
+ PushConstant CP#6
+ ReturnTOS
+L1:
+ Push r4
+ LoadFieldTOS CP#11
+ PopLocal r4
+ Jump L6
+
+}
+]static method testAssert(asy::Future<core::int> a) → asy::Future<core::int> /* originally async */ {
+ final asy::Completer<core::int> :async_completer = asy::Completer::sync<core::int>();
+ asy::FutureOr<core::int> :return_value;
+ dynamic :async_stack_trace;
+ dynamic :async_op_then;
+ dynamic :async_op_error;
+ dynamic :await_jump_var = 0;
+ dynamic :await_ctx_var;
+ dynamic :saved_try_context_var0;
+ function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
+ try {
+ #L6:
+ {
+ assert {
+ [yield] let dynamic #t8 = asy::_awaitHelper(a, :async_op_then, :async_op_error, :async_op) in null;
+ assert(:result.{core::num::==}(42));
+ }
+ :return_value = 7;
+ break #L6;
+ }
+ :async_completer.{asy::Completer::complete}(:return_value);
+ return;
+ }
+ on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+ :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+ }
+ :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+ :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+ :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+ asy::Future::microtask<dynamic>(:async_op);
+ return :async_completer.{asy::Completer::future};
+}
+[@vm.bytecode=
+Bytecode {
Entry 0
CheckStack
PushConstant CP#0
diff --git a/pkg/vm/testcases/bytecode/bootstrapping.dart.expect b/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
index 8df59b8..d135ff4 100644
--- a/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
+++ b/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
@@ -146,6 +146,7 @@
PushStatic CP#0
PushConstant CP#1
InstanceCall1 2, CP#3
+ AssertBoolean 0
PushConstant CP#4
IfNeStrictTOS
Jump L1
@@ -460,6 +461,7 @@
PushStatic CP#0
PushConstant CP#1
InstanceCall1 2, CP#3
+ AssertBoolean 0
PushConstant CP#4
IfNeStrictTOS
Jump L1
@@ -467,6 +469,7 @@
PushStatic CP#5
PushConstant CP#1
InstanceCall1 2, CP#6
+ AssertBoolean 0
BooleanNegateTOS
PopLocal r0
Jump L2
@@ -475,6 +478,7 @@
PopLocal r0
L2:
Push r0
+ AssertBoolean 0
PushConstant CP#4
IfNeStrictTOS
Jump L3
@@ -654,6 +658,7 @@
PushStatic CP#0
PushConstant CP#1
InstanceCall1 2, CP#3
+ AssertBoolean 0
PushConstant CP#4
IfEqStrictTOS
Jump L1
@@ -661,6 +666,7 @@
PushStatic CP#0
PushConstant CP#5
InstanceCall1 2, CP#6
+ AssertBoolean 0
PopLocal r1
Jump L2
L1:
@@ -668,6 +674,7 @@
PopLocal r1
L2:
Push r1
+ AssertBoolean 0
PushConstant CP#4
IfEqStrictTOS
Jump L3
@@ -675,6 +682,7 @@
PushStatic CP#0
PushConstant CP#7
InstanceCall1 2, CP#8
+ AssertBoolean 0
PopLocal r0
Jump L4
L3:
@@ -682,6 +690,7 @@
PopLocal r0
L4:
Push r0
+ AssertBoolean 0
PushConstant CP#4
IfNeStrictTOS
Jump L5
diff --git a/pkg/vm/testcases/bytecode/closures.dart.expect b/pkg/vm/testcases/bytecode/closures.dart.expect
index 2bece87..af1ed56 100644
--- a/pkg/vm/testcases/bytecode/closures.dart.expect
+++ b/pkg/vm/testcases/bytecode/closures.dart.expect
@@ -730,6 +730,7 @@
LoadFieldTOS CP#1
PushConstant CP#13
InstanceCall1 2, CP#14
+ AssertBoolean 0
PushConstant CP#15
IfNeStrictTOS
Jump L1
@@ -894,6 +895,7 @@
LoadFieldTOS CP#2
PushConstant CP#7
InstanceCall1 2, CP#9
+ AssertBoolean 0
PushConstant CP#10
IfNeStrictTOS
Jump L1
diff --git a/pkg/vm/testcases/bytecode/loops.dart.expect b/pkg/vm/testcases/bytecode/loops.dart.expect
index f2bf88a..fe91f5f 100644
--- a/pkg/vm/testcases/bytecode/loops.dart.expect
+++ b/pkg/vm/testcases/bytecode/loops.dart.expect
@@ -16,6 +16,7 @@
Push FP[-5]
InstanceCall1 1, CP#2
InstanceCall1 2, CP#4
+ AssertBoolean 0
PushConstant CP#5
IfNeStrictTOS
Jump L1
@@ -71,6 +72,7 @@
Push r1
PushConstant CP#0
InstanceCall1 2, CP#2
+ AssertBoolean 0
PushConstant CP#3
IfNeStrictTOS
Jump L1
@@ -78,6 +80,7 @@
Push FP[-5]
InstanceCall1 1, CP#5
InstanceCall1 2, CP#6
+ AssertBoolean 0
PushConstant CP#3
IfNeStrictTOS
Jump L2
@@ -142,12 +145,14 @@
Push FP[-5]
InstanceCall1 1, CP#4
InstanceCall1 2, CP#6
+ AssertBoolean 0
PushConstant CP#7
IfNeStrictTOS
Jump L1
Push r1
PushConstant CP#0
InstanceCall1 2, CP#8
+ AssertBoolean 0
PushConstant CP#7
IfNeStrictTOS
Jump L2
@@ -215,6 +220,7 @@
Push FP[-5]
InstanceCall1 1, CP#2
InstanceCall1 2, CP#4
+ AssertBoolean 0
PushConstant CP#5
IfNeStrictTOS
Jump L1
@@ -286,6 +292,7 @@
Push FP[-5]
InstanceCall1 1, CP#7
InstanceCall1 2, CP#8
+ AssertBoolean 0
PushConstant CP#9
IfEqStrictTOS
Jump L1
diff --git a/pkg/vm/testcases/bytecode/switch.dart.expect b/pkg/vm/testcases/bytecode/switch.dart.expect
index cf87dfd..c82563b 100644
--- a/pkg/vm/testcases/bytecode/switch.dart.expect
+++ b/pkg/vm/testcases/bytecode/switch.dart.expect
@@ -12,19 +12,19 @@
PopLocal r1
Push r1
PushConstant CP#2
- InstanceCall2 2, CP#3
+ InstanceCall1 2, CP#3
PushConstant CP#4
IfEqStrictTOS
Jump L1
Push r1
PushConstant CP#5
- InstanceCall2 2, CP#6
+ InstanceCall1 2, CP#6
PushConstant CP#4
IfEqStrictTOS
Jump L2
Push r1
PushConstant CP#7
- InstanceCall2 2, CP#8
+ InstanceCall1 2, CP#8
PushConstant CP#4
IfEqStrictTOS
Jump L3
@@ -99,37 +99,37 @@
PopLocal r1
Push r1
PushConstant CP#2
- InstanceCall2 2, CP#3
+ InstanceCall1 2, CP#3
PushConstant CP#4
IfEqStrictTOS
Jump L1
Push r1
PushConstant CP#5
- InstanceCall2 2, CP#6
+ InstanceCall1 2, CP#6
PushConstant CP#4
IfEqStrictTOS
Jump L1
Push r1
PushConstant CP#7
- InstanceCall2 2, CP#8
+ InstanceCall1 2, CP#8
PushConstant CP#4
IfEqStrictTOS
Jump L1
Push r1
PushConstant CP#9
- InstanceCall2 2, CP#10
+ InstanceCall1 2, CP#10
PushConstant CP#4
IfEqStrictTOS
Jump L2
Push r1
PushConstant CP#11
- InstanceCall2 2, CP#12
+ InstanceCall1 2, CP#12
PushConstant CP#4
IfEqStrictTOS
Jump L2
Push r1
PushConstant CP#13
- InstanceCall2 2, CP#14
+ InstanceCall1 2, CP#14
PushConstant CP#4
IfEqStrictTOS
Jump L2
@@ -212,37 +212,37 @@
PopLocal r1
Push r1
PushConstant CP#2
- InstanceCall2 2, CP#3
+ InstanceCall1 2, CP#3
PushConstant CP#4
IfEqStrictTOS
Jump L1
Push r1
PushConstant CP#5
- InstanceCall2 2, CP#6
+ InstanceCall1 2, CP#6
PushConstant CP#4
IfEqStrictTOS
Jump L1
Push r1
PushConstant CP#7
- InstanceCall2 2, CP#8
+ InstanceCall1 2, CP#8
PushConstant CP#4
IfEqStrictTOS
Jump L1
Push r1
PushConstant CP#9
- InstanceCall2 2, CP#10
+ InstanceCall1 2, CP#10
PushConstant CP#4
IfEqStrictTOS
Jump L2
Push r1
PushConstant CP#11
- InstanceCall2 2, CP#12
+ InstanceCall1 2, CP#12
PushConstant CP#4
IfEqStrictTOS
Jump L2
Push r1
PushConstant CP#13
- InstanceCall2 2, CP#14
+ InstanceCall1 2, CP#14
PushConstant CP#4
IfEqStrictTOS
Jump L2
diff --git a/pkg/vm/testcases/bytecode/try_blocks.dart.expect b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
index f3ac1e4..bf677f1 100644
--- a/pkg/vm/testcases/bytecode/try_blocks.dart.expect
+++ b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
@@ -571,6 +571,7 @@
IndirectStaticCall 1, CP#1
Drop1
Push FP[-5]
+ AssertBoolean 0
PushConstant CP#6
IfNeStrictTOS
Jump L2
@@ -617,9 +618,9 @@
ReturnTOS
}
ExceptionsTable {
- try-index 0, outer -1, start 2, end 35, handler 35, needs-stack-trace, types [CP#3]
+ try-index 0, outer -1, start 2, end 36, handler 36, needs-stack-trace, types [CP#3]
try-index 1, outer 0, start 2, end 7, handler 7, needs-stack-trace, types [CP#3]
- try-index 2, outer 0, start 11, end 24, handler 24, types [CP#3]
+ try-index 2, outer 0, start 11, end 25, handler 25, types [CP#3]
}
ConstantPool {
[0] = String 'try 1 > try 2'
@@ -669,6 +670,7 @@
Push r0
PushConstant CP#1
InstanceCall1 2, CP#3
+ AssertBoolean 0
PushConstant CP#4
IfNeStrictTOS
Jump L1
@@ -676,6 +678,7 @@
Push r0
PushConstant CP#5
InstanceCall1 2, CP#6
+ AssertBoolean 0
PushConstant CP#4
IfNeStrictTOS
Jump L2
@@ -715,7 +718,7 @@
ReturnTOS
}
ExceptionsTable {
- try-index 0, outer -1, start 11, end 19, handler 19, needs-stack-trace, types [CP#7]
+ try-index 0, outer -1, start 12, end 21, handler 21, needs-stack-trace, types [CP#7]
}
ConstantPool {
[0] = Int 0
@@ -765,13 +768,13 @@
PopLocal r2
Push r2
PushConstant CP#3
- InstanceCall2 2, CP#4
+ InstanceCall1 2, CP#4
PushConstant CP#5
IfEqStrictTOS
Jump L1
Push r2
PushConstant CP#6
- InstanceCall2 2, CP#7
+ InstanceCall1 2, CP#7
PushConstant CP#5
IfEqStrictTOS
Jump L2
diff --git a/pkg/vm/testcases/bytecode/type_ops.dart.expect b/pkg/vm/testcases/bytecode/type_ops.dart.expect
index cf66e57..9a60881 100644
--- a/pkg/vm/testcases/bytecode/type_ops.dart.expect
+++ b/pkg/vm/testcases/bytecode/type_ops.dart.expect
@@ -110,6 +110,7 @@
PushConstant CP#1
PushConstant CP#2
InstanceCall1 4, CP#4
+ AssertBoolean 0
PushConstant CP#5
IfNeStrictTOS
Jump L1
@@ -124,6 +125,7 @@
PushConstant CP#1
PushConstant CP#9
InstanceCall1 4, CP#10
+ AssertBoolean 0
PushConstant CP#5
IfNeStrictTOS
Jump L2
@@ -186,6 +188,7 @@
Push FP[-7]
PushConstant CP#1
InstanceCall1 4, CP#3
+ AssertBoolean 0
PushConstant CP#4
IfNeStrictTOS
Jump L1
@@ -200,6 +203,7 @@
Push FP[-7]
PushConstant CP#9
InstanceCall1 4, CP#10
+ AssertBoolean 0
PushConstant CP#4
IfNeStrictTOS
Jump L2
@@ -368,6 +372,7 @@
PushConstant CP#0
PushConstant CP#1
InstanceCall1 4, CP#3
+ AssertBoolean 0
PushConstant CP#4
IfNeStrictTOS
Jump L1
@@ -381,6 +386,7 @@
PushConstant CP#0
PushConstant CP#8
InstanceCall1 4, CP#9
+ AssertBoolean 0
PushConstant CP#4
IfNeStrictTOS
Jump L2
diff --git a/runtime/vm/constants_kbc.h b/runtime/vm/constants_kbc.h
index 312ca7f..4b8e028 100644
--- a/runtime/vm/constants_kbc.h
+++ b/runtime/vm/constants_kbc.h
@@ -113,6 +113,11 @@
// Jump to the given target. Target is specified as offset from the PC of the
// jump instruction.
//
+// - JumpIfNoAsserts target
+//
+// Jump to the given target if assertions are not enabled.
+// Target is specified as offset from the PC of the jump instruction.
+//
// - Return R; ReturnTOS
//
// Return to the caller using either a value from the given register or a
@@ -772,6 +777,7 @@
V(DropR, A, num, ___, ___) \
V(Drop, A, num, ___, ___) \
V(Jump, T, tgt, ___, ___) \
+ V(JumpIfNoAsserts, T, tgt, ___, ___) \
V(Return, A, reg, ___, ___) \
V(ReturnTOS, 0, ___, ___, ___) \
V(Move, A_X, reg, xeg, ___) \
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index 1e31f0f..f320a65 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -4164,6 +4164,15 @@
}
{
+ BYTECODE(JumpIfNoAsserts, 0);
+ if (!thread->isolate()->asserts()) {
+ const int32_t target = static_cast<int32_t>(op) >> 8;
+ pc += (target - 1);
+ }
+ DISPATCH();
+ }
+
+ {
BYTECODE(LoadClassId, A_D);
const uint16_t object_reg = rD;
RawObject* obj = static_cast<RawObject*>(FP[object_reg]);