[vm/kernel] Experimental: generate DBC-like bytecode in kernel binaries

To enable bytecode generation, toggle kEnableKernelBytecode flag at
the beginning of pkg/vm/lib/bytecode/gen_bytecode.dart.
This will also enable generation of bytecode in platform dill files.

Also, bytecode generation can be enabled using --gen-bytecode option of
pkg/vm/tool/gen_kernel.

In kernel binaries, the generated bytecode and constant pool are
placed into 'vm.bytecode' metadata attached to members.
pkg/vm/tool/dump_kernel tool can be used to disassemble
bytecode and print constant pool.

Differences between generated bytecode and original DBC are
described in pkg/vm/lib/bytecode/dbc.dart.

Format of constant pool is described in
pkg/vm/lib/bytecode/constant_pool.dart.

Currently, only a small subset of Dart language is supported.
Bytecode generator will not emit vm.bytecode metadata for a
member if its body has an unsupported operation.


Change-Id: I27d9a361dc779ea115e5676508ee757c1754e05d
Reviewed-on: https://dart-review.googlesource.com/49600
Reviewed-by: Samir Jindel <sjindel@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2018-04-23 03:42:52 +00:00 committed by commit-bot@chromium.org
parent db2f3de25d
commit ac7ca17652
20 changed files with 4841 additions and 21 deletions

View file

@ -10,6 +10,9 @@ import 'dart:io' show File, Platform, exitCode;
import 'package:compiler/src/kernel/dart2js_target.dart' show Dart2jsTarget;
import 'package:vm/bytecode/gen_bytecode.dart'
show generateBytecode, kEnableKernelBytecodeForPlatform;
import 'package:vm/target/dart_runner.dart' show DartRunnerTarget;
import 'package:vm/target/flutter_runner.dart' show FlutterRunnerTarget;
@ -85,6 +88,11 @@ Future compilePlatformInternal(
}
new File.fromUri(outlineOutput).writeAsBytesSync(result.summary);
c.options.ticker.logMs("Wrote outline to ${outlineOutput.toFilePath()}");
if (kEnableKernelBytecodeForPlatform) {
generateBytecode(result.component, strongMode: c.options.strongMode);
}
await writeComponentToFile(result.component, fullOutput,
filter: (lib) => !lib.isExternal);

View file

@ -8,6 +8,7 @@ import 'package:kernel/kernel.dart' show Component, writeComponentToText;
import 'package:kernel/binary/ast_from_binary.dart'
show BinaryBuilderWithMetadata;
import 'package:vm/metadata/bytecode.dart' show BytecodeMetadataRepository;
import 'package:vm/metadata/direct_call.dart' show DirectCallMetadataRepository;
import 'package:vm/metadata/inferred_type.dart'
show InferredTypeMetadataRepository;
@ -37,6 +38,7 @@ main(List<String> arguments) async {
component.addMetadataRepository(new InferredTypeMetadataRepository());
component.addMetadataRepository(new ProcedureAttributesMetadataRepository());
component.addMetadataRepository(new UnreachableNodeMetadataRepository());
component.addMetadataRepository(new BytecodeMetadataRepository());
final List<int> bytes = new File(input).readAsBytesSync();
new BinaryBuilderWithMetadata(bytes).readComponent(component);

View file

@ -14,6 +14,7 @@ import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:kernel/target/vm.dart' show VmTarget;
import 'package:kernel/text/ast_to_text.dart'
show globalDebuggingNames, NameSystem;
import 'package:vm/bytecode/gen_bytecode.dart' show kEnableKernelBytecode;
import 'package:vm/kernel_front_end.dart' show compileToKernel, ErrorDetector;
final ArgParser _argParser = new ArgParser(allowTrailingOptions: true)
@ -36,7 +37,9 @@ final ArgParser _argParser = new ArgParser(allowTrailingOptions: true)
'Enable global type flow analysis and related transformations in AOT mode.',
defaultsTo: true)
..addMultiOption('entry-points',
help: 'Path to JSON file with the list of entry points');
help: 'Path to JSON file with the list of entry points')
..addFlag('gen-bytecode',
help: 'Generate bytecode', defaultsTo: kEnableKernelBytecode);
final String _usage = '''
Usage: dart pkg/vm/bin/gen_kernel.dart --platform vm_platform_strong.dill [options] input.dart
@ -73,6 +76,7 @@ Future<int> compile(List<String> arguments) async {
final bool aot = options['aot'];
final bool syncAsync = options['sync-async'];
final bool tfa = options['tfa'];
final bool genBytecode = options['gen-bytecode'];
final List<String> entryPoints = options['entry-points'] ?? <String>[];
if (entryPoints.isEmpty) {
@ -100,7 +104,10 @@ Future<int> compile(List<String> arguments) async {
Component component = await compileToKernel(
Uri.base.resolveUri(new Uri.file(filename)), compilerOptions,
aot: aot, useGlobalTypeFlowAnalysis: tfa, entryPoints: entryPoints);
aot: aot,
useGlobalTypeFlowAnalysis: tfa,
entryPoints: entryPoints,
genBytecode: genBytecode);
if (errorDetector.hasCompilationErrors || (component == null)) {
return _compileTimeErrorExitCode;

View file

@ -0,0 +1,917 @@
// 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.
library vm.bytecode.assembler;
import 'dart:typed_data';
import 'package:vm/bytecode/dbc.dart';
class Label {
List<int> _jumps = <int>[];
int offset = -1;
Label();
bool get isBound => offset >= 0;
int jumpOperand(int jumpOffset) {
if (isBound) {
// Jump instruction takes an offset in DBC words.
return (offset - jumpOffset) >> BytecodeAssembler.kLog2BytesPerBytecode;
}
_jumps.add(jumpOffset);
return 0;
}
List<int> bind(int offset) {
assert(!isBound);
this.offset = offset;
final jumps = _jumps;
_jumps = null;
return jumps;
}
}
class BytecodeAssembler {
static const int kBitsPerInt = 64;
static const int kLog2BytesPerBytecode = 2;
// TODO(alexmarkov): figure out more efficient storage for generated bytecode.
final List<int> bytecode = new List<int>();
final Uint32List _encodeBufferIn;
final Uint8List _encodeBufferOut;
BytecodeAssembler._(this._encodeBufferIn, this._encodeBufferOut);
factory BytecodeAssembler() {
final buf = new Uint32List(1);
return new BytecodeAssembler._(buf, new Uint8List.view(buf.buffer));
}
int get offset => bytecode.length;
void bind(Label label) {
final List<int> jumps = label.bind(offset);
for (int jumpOffset in jumps) {
patchJump(jumpOffset, label.jumpOperand(jumpOffset));
}
}
void emitWord(int word) {
_encodeBufferIn[0] = word; // TODO(alexmarkov): Which endianness to use?
bytecode.addAll(_encodeBufferOut);
}
void _setWord(int pos, int word) {
_encodeBufferIn[0] = word; // TODO(alexmarkov): Which endianness to use?
bytecode.setRange(pos, pos + _encodeBufferOut.length, _encodeBufferOut);
}
int _unsigned(int v, int bits) {
assert(bits < kBitsPerInt);
final int mask = (1 << bits) - 1;
if ((v & mask) != v) {
throw 'Value $v is out of unsigned $bits-bit range';
}
return v;
}
int _signed(int v, int bits) {
assert(bits < kBitsPerInt);
final int shift = kBitsPerInt - bits;
if (((v << shift) >> shift) != v) {
throw 'Value $v is out of signed $bits-bit range';
}
final int mask = (1 << bits) - 1;
return v & mask;
}
int _uint8(int v) => _unsigned(v, 8);
int _uint16(int v) => _unsigned(v, 16);
int _int8(int v) => _signed(v, 8);
int _int16(int v) => _signed(v, 16);
int _int24(int v) => _signed(v, 24);
int _encode0(Opcode opcode) => _uint8(opcode.index);
int _encodeA(Opcode opcode, int ra) =>
_uint8(opcode.index) | (_uint8(ra) << 8);
int _encodeAD(Opcode opcode, int ra, int rd) =>
_uint8(opcode.index) | (_uint8(ra) << 8) | (_uint16(rd) << 16);
int _encodeAX(Opcode opcode, int ra, int rx) =>
_uint8(opcode.index) | (_uint8(ra) << 8) | (_int16(rx) << 16);
int _encodeD(Opcode opcode, int rd) =>
_uint8(opcode.index) | (_uint16(rd) << 16);
int _encodeX(Opcode opcode, int rx) =>
_uint8(opcode.index) | (_int16(rx) << 16);
int _encodeABC(Opcode opcode, int ra, int rb, int rc) =>
_uint8(opcode.index) |
(_uint8(ra) << 8) |
(_uint8(rb) << 16) |
(_uint8(rc) << 24);
int _encodeABY(Opcode opcode, int ra, int rb, int ry) =>
_uint8(opcode.index) |
(_uint8(ra) << 8) |
(_uint8(rb) << 16) |
(_int8(ry) << 24);
int _encodeT(Opcode opcode, int rt) =>
_uint8(opcode.index) | (_int24(rt) << 8);
void emitTrap() {
emitWord(_encode0(Opcode.kTrap));
}
void emitNop(int ra, int rd) {
emitWord(_encodeAD(Opcode.kNop, ra, rd));
}
void emitCompile() {
emitWord(_encode0(Opcode.kCompile));
}
void emitHotCheck(int ra, int rd) {
emitWord(_encodeAD(Opcode.kHotCheck, ra, rd));
}
void emitIntrinsic(int ra) {
emitWord(_encodeA(Opcode.kIntrinsic, ra));
}
void emitDrop1() {
emitWord(_encode0(Opcode.kDrop1));
}
void emitDropR(int ra) {
emitWord(_encodeA(Opcode.kDropR, ra));
}
void emitDrop(int ra) {
emitWord(_encodeA(Opcode.kDrop, ra));
}
void emitJump(Label label) {
emitWord(_encodeT(Opcode.kJump, label.jumpOperand(offset)));
}
void patchJump(int pos, int rt) {
_setWord(pos, _encodeT(Opcode.kJump, rt));
}
void emitReturn(int ra) {
emitWord(_encodeA(Opcode.kReturn, ra));
}
void emitReturnTOS() {
emitWord(_encode0(Opcode.kReturnTOS));
}
void emitMove(int ra, int rx) {
emitWord(_encodeAX(Opcode.kMove, ra, rx));
}
void emitSwap(int ra, int rx) {
emitWord(_encodeAX(Opcode.kSwap, ra, rx));
}
void emitPush(int rx) {
emitWord(_encodeX(Opcode.kPush, rx));
}
void emitLoadConstant(int ra, int rd) {
emitWord(_encodeAD(Opcode.kLoadConstant, ra, rd));
}
void emitLoadClassId(int ra, int rd) {
emitWord(_encodeAD(Opcode.kLoadClassId, ra, rd));
}
void emitLoadClassIdTOS() {
emitWord(_encode0(Opcode.kLoadClassIdTOS));
}
void emitPushConstant(int rd) {
emitWord(_encodeD(Opcode.kPushConstant, rd));
}
void emitStoreLocal(int rx) {
emitWord(_encodeX(Opcode.kStoreLocal, rx));
}
void emitPopLocal(int rx) {
emitWord(_encodeX(Opcode.kPopLocal, rx));
}
void emitIndirectStaticCall(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIndirectStaticCall, ra, rd));
}
void emitStaticCall(int ra, int rd) {
emitWord(_encodeAD(Opcode.kStaticCall, ra, rd));
}
void emitInstanceCall1(int ra, int rd) {
emitWord(_encodeAD(Opcode.kInstanceCall1, ra, rd));
}
void emitInstanceCall2(int ra, int rd) {
emitWord(_encodeAD(Opcode.kInstanceCall2, ra, rd));
}
void emitInstanceCall1Opt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kInstanceCall1Opt, ra, rd));
}
void emitInstanceCall2Opt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kInstanceCall2Opt, ra, rd));
}
void emitPushPolymorphicInstanceCall(int ra, int rd) {
emitWord(_encodeAD(Opcode.kPushPolymorphicInstanceCall, ra, rd));
}
void emitPushPolymorphicInstanceCallByRange(int ra, int rd) {
emitWord(_encodeAD(Opcode.kPushPolymorphicInstanceCallByRange, ra, rd));
}
void emitNativeCall(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kNativeCall, ra, rb, rc));
}
void emitOneByteStringFromCharCode(int ra, int rx) {
emitWord(_encodeAX(Opcode.kOneByteStringFromCharCode, ra, rx));
}
void emitStringToCharCode(int ra, int rx) {
emitWord(_encodeAX(Opcode.kStringToCharCode, ra, rx));
}
void emitAddTOS() {
emitWord(_encode0(Opcode.kAddTOS));
}
void emitSubTOS() {
emitWord(_encode0(Opcode.kSubTOS));
}
void emitMulTOS() {
emitWord(_encode0(Opcode.kMulTOS));
}
void emitBitOrTOS() {
emitWord(_encode0(Opcode.kBitOrTOS));
}
void emitBitAndTOS() {
emitWord(_encode0(Opcode.kBitAndTOS));
}
void emitEqualTOS() {
emitWord(_encode0(Opcode.kEqualTOS));
}
void emitLessThanTOS() {
emitWord(_encode0(Opcode.kLessThanTOS));
}
void emitGreaterThanTOS() {
emitWord(_encode0(Opcode.kGreaterThanTOS));
}
void emitSmiAddTOS() {
emitWord(_encode0(Opcode.kSmiAddTOS));
}
void emitSmiSubTOS() {
emitWord(_encode0(Opcode.kSmiSubTOS));
}
void emitSmiMulTOS() {
emitWord(_encode0(Opcode.kSmiMulTOS));
}
void emitSmiBitAndTOS() {
emitWord(_encode0(Opcode.kSmiBitAndTOS));
}
void emitAdd(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kAdd, ra, rb, rc));
}
void emitSub(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kSub, ra, rb, rc));
}
void emitMul(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kMul, ra, rb, rc));
}
void emitDiv(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kDiv, ra, rb, rc));
}
void emitMod(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kMod, ra, rb, rc));
}
void emitShl(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kShl, ra, rb, rc));
}
void emitShr(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kShr, ra, rb, rc));
}
void emitShlImm(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kShlImm, ra, rb, rc));
}
void emitNeg(int ra, int rd) {
emitWord(_encodeAD(Opcode.kNeg, ra, rd));
}
void emitBitOr(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kBitOr, ra, rb, rc));
}
void emitBitAnd(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kBitAnd, ra, rb, rc));
}
void emitBitXor(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kBitXor, ra, rb, rc));
}
void emitBitNot(int ra, int rd) {
emitWord(_encodeAD(Opcode.kBitNot, ra, rd));
}
void emitMin(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kMin, ra, rb, rc));
}
void emitMax(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kMax, ra, rb, rc));
}
void emitWriteIntoDouble(int ra, int rd) {
emitWord(_encodeAD(Opcode.kWriteIntoDouble, ra, rd));
}
void emitUnboxDouble(int ra, int rd) {
emitWord(_encodeAD(Opcode.kUnboxDouble, ra, rd));
}
void emitCheckedUnboxDouble(int ra, int rd) {
emitWord(_encodeAD(Opcode.kCheckedUnboxDouble, ra, rd));
}
void emitUnboxInt32(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kUnboxInt32, ra, rb, rc));
}
void emitBoxInt32(int ra, int rd) {
emitWord(_encodeAD(Opcode.kBoxInt32, ra, rd));
}
void emitBoxUint32(int ra, int rd) {
emitWord(_encodeAD(Opcode.kBoxUint32, ra, rd));
}
void emitSmiToDouble(int ra, int rd) {
emitWord(_encodeAD(Opcode.kSmiToDouble, ra, rd));
}
void emitDoubleToSmi(int ra, int rd) {
emitWord(_encodeAD(Opcode.kDoubleToSmi, ra, rd));
}
void emitDAdd(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kDAdd, ra, rb, rc));
}
void emitDSub(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kDSub, ra, rb, rc));
}
void emitDMul(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kDMul, ra, rb, rc));
}
void emitDDiv(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kDDiv, ra, rb, rc));
}
void emitDNeg(int ra, int rd) {
emitWord(_encodeAD(Opcode.kDNeg, ra, rd));
}
void emitDSqrt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kDSqrt, ra, rd));
}
void emitDMin(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kDMin, ra, rb, rc));
}
void emitDMax(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kDMax, ra, rb, rc));
}
void emitDCos(int ra, int rd) {
emitWord(_encodeAD(Opcode.kDCos, ra, rd));
}
void emitDSin(int ra, int rd) {
emitWord(_encodeAD(Opcode.kDSin, ra, rd));
}
void emitDPow(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kDPow, ra, rb, rc));
}
void emitDMod(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kDMod, ra, rb, rc));
}
void emitDTruncate(int ra, int rd) {
emitWord(_encodeAD(Opcode.kDTruncate, ra, rd));
}
void emitDFloor(int ra, int rd) {
emitWord(_encodeAD(Opcode.kDFloor, ra, rd));
}
void emitDCeil(int ra, int rd) {
emitWord(_encodeAD(Opcode.kDCeil, ra, rd));
}
void emitDoubleToFloat(int ra, int rd) {
emitWord(_encodeAD(Opcode.kDoubleToFloat, ra, rd));
}
void emitFloatToDouble(int ra, int rd) {
emitWord(_encodeAD(Opcode.kFloatToDouble, ra, rd));
}
void emitDoubleIsNaN(int ra) {
emitWord(_encodeA(Opcode.kDoubleIsNaN, ra));
}
void emitDoubleIsInfinite(int ra) {
emitWord(_encodeA(Opcode.kDoubleIsInfinite, ra));
}
void emitStoreStaticTOS(int rd) {
emitWord(_encodeD(Opcode.kStoreStaticTOS, rd));
}
void emitPushStatic(int rd) {
emitWord(_encodeD(Opcode.kPushStatic, rd));
}
void emitInitStaticTOS() {
emitWord(_encode0(Opcode.kInitStaticTOS));
}
void emitIfNeStrictTOS() {
emitWord(_encode0(Opcode.kIfNeStrictTOS));
}
void emitIfEqStrictTOS() {
emitWord(_encode0(Opcode.kIfEqStrictTOS));
}
void emitIfNeStrictNumTOS() {
emitWord(_encode0(Opcode.kIfNeStrictNumTOS));
}
void emitIfEqStrictNumTOS() {
emitWord(_encode0(Opcode.kIfEqStrictNumTOS));
}
void emitIfSmiLtTOS() {
emitWord(_encode0(Opcode.kIfSmiLtTOS));
}
void emitIfSmiLeTOS() {
emitWord(_encode0(Opcode.kIfSmiLeTOS));
}
void emitIfSmiGeTOS() {
emitWord(_encode0(Opcode.kIfSmiGeTOS));
}
void emitIfSmiGtTOS() {
emitWord(_encode0(Opcode.kIfSmiGtTOS));
}
void emitIfNeStrict(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfNeStrict, ra, rd));
}
void emitIfEqStrict(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfEqStrict, ra, rd));
}
void emitIfLe(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfLe, ra, rd));
}
void emitIfLt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfLt, ra, rd));
}
void emitIfGe(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfGe, ra, rd));
}
void emitIfGt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfGt, ra, rd));
}
void emitIfULe(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfULe, ra, rd));
}
void emitIfULt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfULt, ra, rd));
}
void emitIfUGe(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfUGe, ra, rd));
}
void emitIfUGt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfUGt, ra, rd));
}
void emitIfDNe(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfDNe, ra, rd));
}
void emitIfDEq(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfDEq, ra, rd));
}
void emitIfDLe(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfDLe, ra, rd));
}
void emitIfDLt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfDLt, ra, rd));
}
void emitIfDGe(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfDGe, ra, rd));
}
void emitIfDGt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfDGt, ra, rd));
}
void emitIfNeStrictNum(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfNeStrictNum, ra, rd));
}
void emitIfEqStrictNum(int ra, int rd) {
emitWord(_encodeAD(Opcode.kIfEqStrictNum, ra, rd));
}
void emitIfEqNull(int ra) {
emitWord(_encodeA(Opcode.kIfEqNull, ra));
}
void emitIfNeNull(int ra) {
emitWord(_encodeA(Opcode.kIfNeNull, ra));
}
void emitCreateArrayTOS() {
emitWord(_encode0(Opcode.kCreateArrayTOS));
}
void emitCreateArrayOpt(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kCreateArrayOpt, ra, rb, rc));
}
void emitAllocate(int rd) {
emitWord(_encodeD(Opcode.kAllocate, rd));
}
void emitAllocateT() {
emitWord(_encode0(Opcode.kAllocateT));
}
void emitAllocateOpt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kAllocateOpt, ra, rd));
}
void emitAllocateTOpt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kAllocateTOpt, ra, rd));
}
void emitStoreIndexedTOS() {
emitWord(_encode0(Opcode.kStoreIndexedTOS));
}
void emitStoreIndexed(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kStoreIndexed, ra, rb, rc));
}
void emitStoreIndexedUint8(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kStoreIndexedUint8, ra, rb, rc));
}
void emitStoreIndexedExternalUint8(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kStoreIndexedExternalUint8, ra, rb, rc));
}
void emitStoreIndexedOneByteString(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kStoreIndexedOneByteString, ra, rb, rc));
}
void emitStoreIndexedUint32(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kStoreIndexedUint32, ra, rb, rc));
}
void emitStoreIndexedFloat32(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kStoreIndexedFloat32, ra, rb, rc));
}
void emitStoreIndexed4Float32(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kStoreIndexed4Float32, ra, rb, rc));
}
void emitStoreIndexedFloat64(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kStoreIndexedFloat64, ra, rb, rc));
}
void emitStoreIndexed8Float64(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kStoreIndexed8Float64, ra, rb, rc));
}
void emitNoSuchMethod() {
emitWord(_encode0(Opcode.kNoSuchMethod));
}
void emitTailCall() {
emitWord(_encode0(Opcode.kTailCall));
}
void emitTailCallOpt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kTailCallOpt, ra, rd));
}
void emitLoadArgDescriptor() {
emitWord(_encode0(Opcode.kLoadArgDescriptor));
}
void emitLoadArgDescriptorOpt(int ra) {
emitWord(_encodeA(Opcode.kLoadArgDescriptorOpt, ra));
}
void emitLoadFpRelativeSlot(int rx) {
emitWord(_encodeX(Opcode.kLoadFpRelativeSlot, rx));
}
void emitLoadFpRelativeSlotOpt(int ra, int rb, int ry) {
emitWord(_encodeABY(Opcode.kLoadFpRelativeSlotOpt, ra, rb, ry));
}
void emitStoreFpRelativeSlot(int rx) {
emitWord(_encodeX(Opcode.kStoreFpRelativeSlot, rx));
}
void emitStoreFpRelativeSlotOpt(int ra, int rb, int ry) {
emitWord(_encodeABY(Opcode.kStoreFpRelativeSlotOpt, ra, rb, ry));
}
void emitLoadIndexedTOS() {
emitWord(_encode0(Opcode.kLoadIndexedTOS));
}
void emitLoadIndexed(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexed, ra, rb, rc));
}
void emitLoadIndexedUint8(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexedUint8, ra, rb, rc));
}
void emitLoadIndexedInt8(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexedInt8, ra, rb, rc));
}
void emitLoadIndexedInt32(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexedInt32, ra, rb, rc));
}
void emitLoadIndexedUint32(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexedUint32, ra, rb, rc));
}
void emitLoadIndexedExternalUint8(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexedExternalUint8, ra, rb, rc));
}
void emitLoadIndexedExternalInt8(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexedExternalInt8, ra, rb, rc));
}
void emitLoadIndexedFloat32(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexedFloat32, ra, rb, rc));
}
void emitLoadIndexed4Float32(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexed4Float32, ra, rb, rc));
}
void emitLoadIndexedFloat64(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexedFloat64, ra, rb, rc));
}
void emitLoadIndexed8Float64(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexed8Float64, ra, rb, rc));
}
void emitLoadIndexedOneByteString(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexedOneByteString, ra, rb, rc));
}
void emitLoadIndexedTwoByteString(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadIndexedTwoByteString, ra, rb, rc));
}
void emitStoreField(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kStoreField, ra, rb, rc));
}
void emitStoreFieldExt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kStoreFieldExt, ra, rd));
}
void emitStoreFieldTOS(int rd) {
emitWord(_encodeD(Opcode.kStoreFieldTOS, rd));
}
void emitLoadField(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadField, ra, rb, rc));
}
void emitLoadFieldExt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kLoadFieldExt, ra, rd));
}
void emitLoadUntagged(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kLoadUntagged, ra, rb, rc));
}
void emitLoadFieldTOS(int rd) {
emitWord(_encodeD(Opcode.kLoadFieldTOS, rd));
}
void emitBooleanNegateTOS() {
emitWord(_encode0(Opcode.kBooleanNegateTOS));
}
void emitBooleanNegate(int ra, int rd) {
emitWord(_encodeAD(Opcode.kBooleanNegate, ra, rd));
}
void emitThrow(int ra) {
emitWord(_encodeA(Opcode.kThrow, ra));
}
void emitEntry(int rd) {
emitWord(_encodeD(Opcode.kEntry, rd));
}
void emitEntryOptimized(int ra, int rd) {
emitWord(_encodeAD(Opcode.kEntryOptimized, ra, rd));
}
void emitFrame(int rd) {
emitWord(_encodeD(Opcode.kFrame, rd));
}
void emitSetFrame(int ra) {
emitWord(_encodeA(Opcode.kSetFrame, ra));
}
void emitAllocateContext(int rd) {
emitWord(_encodeD(Opcode.kAllocateContext, rd));
}
void emitAllocateUninitializedContext(int ra, int rd) {
emitWord(_encodeAD(Opcode.kAllocateUninitializedContext, ra, rd));
}
void emitCloneContext() {
emitWord(_encode0(Opcode.kCloneContext));
}
void emitMoveSpecial(int ra, int rd) {
emitWord(_encodeAD(Opcode.kMoveSpecial, ra, rd));
}
void emitInstantiateType(int rd) {
emitWord(_encodeD(Opcode.kInstantiateType, rd));
}
void emitInstantiateTypeArgumentsTOS(int ra, int rd) {
emitWord(_encodeAD(Opcode.kInstantiateTypeArgumentsTOS, ra, rd));
}
void emitInstanceOf() {
emitWord(_encode0(Opcode.kInstanceOf));
}
void emitBadTypeError() {
emitWord(_encode0(Opcode.kBadTypeError));
}
void emitAssertAssignable(int ra, int rd) {
emitWord(_encodeAD(Opcode.kAssertAssignable, ra, rd));
}
void emitAssertSubtype() {
emitWord(_encode0(Opcode.kAssertSubtype));
}
void emitAssertBoolean(int ra) {
emitWord(_encodeA(Opcode.kAssertBoolean, ra));
}
void emitTestSmi(int ra, int rd) {
emitWord(_encodeAD(Opcode.kTestSmi, ra, rd));
}
void emitTestCids(int ra, int rd) {
emitWord(_encodeAD(Opcode.kTestCids, ra, rd));
}
void emitCheckSmi(int ra) {
emitWord(_encodeA(Opcode.kCheckSmi, ra));
}
void emitCheckEitherNonSmi(int ra, int rd) {
emitWord(_encodeAD(Opcode.kCheckEitherNonSmi, ra, rd));
}
void emitCheckClassId(int ra, int rd) {
emitWord(_encodeAD(Opcode.kCheckClassId, ra, rd));
}
void emitCheckClassIdRange(int ra, int rd) {
emitWord(_encodeAD(Opcode.kCheckClassIdRange, ra, rd));
}
void emitCheckBitTest(int ra, int rd) {
emitWord(_encodeAD(Opcode.kCheckBitTest, ra, rd));
}
void emitCheckCids(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kCheckCids, ra, rb, rc));
}
void emitCheckCidsByRange(int ra, int rb, int rc) {
emitWord(_encodeABC(Opcode.kCheckCidsByRange, ra, rb, rc));
}
void emitCheckStack() {
emitWord(_encode0(Opcode.kCheckStack));
}
void emitCheckStackAlwaysExit() {
emitWord(_encode0(Opcode.kCheckStackAlwaysExit));
}
void emitCheckFunctionTypeArgs(int ra, int rd) {
emitWord(_encodeAD(Opcode.kCheckFunctionTypeArgs, ra, rd));
}
void emitDebugStep() {
emitWord(_encode0(Opcode.kDebugStep));
}
void emitDebugBreak(int ra) {
emitWord(_encodeA(Opcode.kDebugBreak, ra));
}
void emitDeopt(int ra, int rd) {
emitWord(_encodeAD(Opcode.kDeopt, ra, rd));
}
void emitDeoptRewind() {
emitWord(_encode0(Opcode.kDeoptRewind));
}
}

View file

@ -0,0 +1,803 @@
// 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.
library vm.bytecode.constant_pool;
import 'dart:typed_data';
import 'package:kernel/ast.dart' hide MapEntry;
/*
In kernel binary, constant pool is encoded in the following way
(using notation from pkg/kernel/binary.md):
type ConstantPool {
List<ConstantPoolEntry>
}
abstract type ConstantPoolEntry {
Byte tag;
}
type ConstantNull extends ConstantPoolEntry {
Byte tag = 1;
}
type ConstantString extends ConstantPoolEntry {
Byte tag = 2;
StringReference value;
}
type ConstantInt extends ConstantPoolEntry {
Byte tag = 3;
UInt32 low;
UInt32 high;
}
type ConstantDouble extends ConstantPoolEntry {
Byte tag = 4;
UInt32 low;
UInt32 high;
}
type ConstantBool extends ConstantPoolEntry {
Byte tag = 5;
UInt flag;
}
type ConstantArgDesc extends ConstantPoolEntry {
Byte tag = 6;
UInt numArguments;
UInt numTypeArgs;
List<StringReference> names;
}
type ConstantICData extends ConstantPoolEntry {
Byte tag = 7;
StringReference targetName;
UInt argDescConstantIndex;
}
type ConstantStaticICData extends ConstantPoolEntry {
Byte tag = 8;
CanonicalNameReference target;
UInt argDescConstantIndex;
}
type ConstantField extends ConstantPoolEntry {
Byte tag = 9;
CanonicalNameReference field;
}
type ConstantFieldOffset extends ConstantPoolEntry {
Byte tag = 10;
CanonicalNameReference field;
}
type ConstantClass extends ConstantPoolEntry {
Byte tag = 11;
CanonicalNameReference class;
}
type ConstantTypeArgumentsFieldOffset extends ConstantPoolEntry {
Byte tag = 12;
CanonicalNameReference class;
}
type ConstantTearOff extends ConstantPoolEntry {
Byte tag = 13;
CanonicalNameReference target;
}
type ConstantType extends ConstantPoolEntry {
Byte tag = 14;
NodeReference type;
}
type ConstantTypeArguments extends ConstantPoolEntry {
Byte tag = 15;
List<NodeReference> types;
}
type ConstantList extends ConstantPoolEntry {
Byte tag = 16;
NodeReference typeArg;
List<UInt> entries;
}
type ConstantInstance extends ConstantPoolEntry {
Byte tag = 17;
CanonicalNameReference class;
UInt typeArgumentsConstantIndex;
List<Pair<CanonicalNameReference, UInt>> fieldValues;
}
*/
enum ConstantTag {
kInvalid,
kNull,
kString,
kInt,
kDouble,
kBool,
kArgDesc,
kICData,
kStaticICData,
kField,
kFieldOffset,
kClass,
kTypeArgumentsFieldOffset,
kTearOff,
kType,
kTypeArguments,
kList,
kInstance,
}
abstract class ConstantPoolEntry {
const ConstantPoolEntry();
ConstantTag get tag;
void writeToBinary(BinarySink sink) {
sink.writeUInt30(tag.index);
writeValueToBinary(sink);
}
void writeValueToBinary(BinarySink sink);
factory ConstantPoolEntry.readFromBinary(BinarySource source) {
ConstantTag tag = ConstantTag.values[source.readUInt()];
switch (tag) {
case ConstantTag.kInvalid:
break;
case ConstantTag.kNull:
return new ConstantNull.readFromBinary(source);
case ConstantTag.kString:
return new ConstantString.readFromBinary(source);
case ConstantTag.kInt:
return new ConstantInt.readFromBinary(source);
case ConstantTag.kDouble:
return new ConstantDouble.readFromBinary(source);
case ConstantTag.kBool:
return new ConstantBool.readFromBinary(source);
case ConstantTag.kICData:
return new ConstantICData.readFromBinary(source);
case ConstantTag.kStaticICData:
return new ConstantStaticICData.readFromBinary(source);
case ConstantTag.kArgDesc:
return new ConstantArgDesc.readFromBinary(source);
case ConstantTag.kField:
return new ConstantField.readFromBinary(source);
case ConstantTag.kFieldOffset:
return new ConstantFieldOffset.readFromBinary(source);
case ConstantTag.kClass:
return new ConstantClass.readFromBinary(source);
case ConstantTag.kTypeArgumentsFieldOffset:
return new ConstantTypeArgumentsFieldOffset.readFromBinary(source);
case ConstantTag.kTearOff:
return new ConstantTearOff.readFromBinary(source);
case ConstantTag.kType:
return new ConstantType.readFromBinary(source);
case ConstantTag.kTypeArguments:
return new ConstantTypeArguments.readFromBinary(source);
case ConstantTag.kList:
return new ConstantList.readFromBinary(source);
case ConstantTag.kInstance:
return new ConstantInstance.readFromBinary(source);
}
throw 'Unexpected constant tag $tag';
}
}
class ConstantNull extends ConstantPoolEntry {
const ConstantNull();
@override
ConstantTag get tag => ConstantTag.kNull;
@override
void writeValueToBinary(BinarySink sink) {}
ConstantNull.readFromBinary(BinarySource source);
@override
String toString() => 'Null';
@override
int get hashCode => 1961;
@override
bool operator ==(other) => other is ConstantNull;
}
class ConstantString extends ConstantPoolEntry {
final String value;
ConstantString(this.value);
ConstantString.fromLiteral(StringLiteral literal) : this(literal.value);
@override
ConstantTag get tag => ConstantTag.kString;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeStringReference(value);
}
ConstantString.readFromBinary(BinarySource source)
: value = source.readStringReference();
@override
String toString() => 'String \'$value\'';
@override
int get hashCode => value.hashCode;
@override
bool operator ==(other) =>
other is ConstantString && this.value == other.value;
}
class ConstantInt extends ConstantPoolEntry {
final int value;
ConstantInt(this.value);
ConstantInt.fromLiteral(IntLiteral literal) : this(literal.value);
@override
ConstantTag get tag => ConstantTag.kInt;
@override
void writeValueToBinary(BinarySink sink) {
// TODO(alexmarkov): more efficient encoding
sink.writeUInt32(value & 0xffffffff);
sink.writeUInt32((value >> 32) & 0xffffffff);
}
ConstantInt.readFromBinary(BinarySource source)
: value = source.readUint32() | (source.readUint32() << 32);
@override
String toString() => 'Int $value';
@override
int get hashCode => value;
@override
bool operator ==(other) => other is ConstantInt && this.value == other.value;
}
class ConstantDouble extends ConstantPoolEntry {
final double value;
ConstantDouble(this.value);
ConstantDouble.fromLiteral(DoubleLiteral literal) : this(literal.value);
@override
ConstantTag get tag => ConstantTag.kDouble;
static int doubleToIntBits(double value) {
final buf = new ByteData(8);
buf.setFloat64(0, value, Endian.host);
return buf.getInt64(0, Endian.host);
}
static double intBitsToDouble(int bits) {
final buf = new ByteData(8);
buf.setInt64(0, bits, Endian.host);
return buf.getFloat64(0, Endian.host);
}
@override
void writeValueToBinary(BinarySink sink) {
// TODO(alexmarkov): more efficient encoding
int bits = doubleToIntBits(value);
sink.writeUInt32(bits & 0xffffffff);
sink.writeUInt32((bits >> 32) & 0xffffffff);
}
ConstantDouble.readFromBinary(BinarySource source)
: value =
intBitsToDouble(source.readUint32() | (source.readUint32() << 32));
@override
String toString() => 'Double $value';
@override
int get hashCode => value.hashCode;
@override
bool operator ==(other) =>
other is ConstantDouble && value.compareTo(other.value) == 0;
}
class ConstantBool extends ConstantPoolEntry {
final bool value;
ConstantBool(this.value);
ConstantBool.fromLiteral(BoolLiteral literal) : this(literal.value);
@override
ConstantTag get tag => ConstantTag.kBool;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeUInt30(value ? 1 : 0);
}
ConstantBool.readFromBinary(BinarySource source)
: value = source.readUInt() != 0;
@override
String toString() => 'Bool $value';
@override
int get hashCode => value.hashCode;
@override
bool operator ==(other) => other is ConstantBool && this.value == other.value;
}
class ConstantArgDesc extends ConstantPoolEntry {
final int numArguments;
final int numTypeArgs;
final List<String> argNames;
ConstantArgDesc(this.numArguments,
{this.numTypeArgs = 0, this.argNames = const <String>[]});
ConstantArgDesc.fromArguments(Arguments args, {bool hasReceiver: false})
: this(args.positional.length + args.named.length + (hasReceiver ? 1 : 0),
numTypeArgs: args.types.length,
argNames: new List<String>.from(args.named.map((ne) => ne.name)));
@override
ConstantTag get tag => ConstantTag.kArgDesc;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeUInt30(numArguments);
sink.writeUInt30(numTypeArgs);
sink.writeUInt30(argNames.length);
argNames.forEach(sink.writeStringReference);
}
ConstantArgDesc.readFromBinary(BinarySource source)
: numArguments = source.readUInt(),
numTypeArgs = source.readUInt(),
argNames = new List<String>.generate(
source.readUInt(), (_) => source.readStringReference());
@override
String toString() =>
'ArgDesc num-args $numArguments, num-type-args $numTypeArgs, names $argNames';
@override
int get hashCode =>
(numArguments * 31 + numTypeArgs) * 31 + listHashCode(argNames);
@override
bool operator ==(other) =>
other is ConstantArgDesc &&
this.numArguments == other.numArguments &&
this.numTypeArgs == other.numTypeArgs &&
listEquals(this.argNames, other.argNames);
}
class ConstantICData extends ConstantPoolEntry {
final String targetName;
final int argDescConstantIndex;
ConstantICData(this.targetName, this.argDescConstantIndex);
@override
ConstantTag get tag => ConstantTag.kICData;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeStringReference(targetName);
sink.writeUInt30(argDescConstantIndex);
}
ConstantICData.readFromBinary(BinarySource source)
: targetName = source.readStringReference(),
argDescConstantIndex = source.readUInt();
@override
String toString() =>
'ICData target-name \'$targetName\', arg-desc CP#$argDescConstantIndex';
@override
int get hashCode => targetName.hashCode * 31 + argDescConstantIndex;
@override
bool operator ==(other) =>
other is ConstantICData &&
this.targetName == other.targetName &&
this.argDescConstantIndex == other.argDescConstantIndex;
}
class ConstantStaticICData extends ConstantPoolEntry {
final Reference _reference;
final int argDescConstantIndex;
ConstantStaticICData(Member member, int argDescConstantIndex)
: this.byReference(member.reference, argDescConstantIndex);
ConstantStaticICData.byReference(this._reference, this.argDescConstantIndex);
Member get target => _reference.asMember;
@override
ConstantTag get tag => ConstantTag.kStaticICData;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeCanonicalNameReference(getCanonicalNameOfMember(target));
sink.writeUInt30(argDescConstantIndex);
}
ConstantStaticICData.readFromBinary(BinarySource source)
: _reference = source.readCanonicalNameReference().getReference(),
argDescConstantIndex = source.readUInt();
@override
String toString() =>
'StaticICData target \'$target\', arg-desc CP#$argDescConstantIndex';
@override
int get hashCode => target.hashCode * 31 + argDescConstantIndex;
@override
bool operator ==(other) =>
other is ConstantStaticICData &&
this.target == other.target &&
this.argDescConstantIndex == other.argDescConstantIndex;
}
class ConstantField extends ConstantPoolEntry {
final Reference _reference;
Field get field => _reference.asField;
ConstantField(Field field) : this.byReference(field.reference);
ConstantField.byReference(this._reference);
@override
ConstantTag get tag => ConstantTag.kField;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeCanonicalNameReference(getCanonicalNameOfMember(field));
}
ConstantField.readFromBinary(BinarySource source)
: _reference = source.readCanonicalNameReference().getReference();
@override
String toString() => 'Field $field';
@override
int get hashCode => field.hashCode;
@override
bool operator ==(other) =>
other is ConstantField && this.field == other.field;
}
class ConstantFieldOffset extends ConstantPoolEntry {
final Reference _reference;
Field get field => _reference.asField;
ConstantFieldOffset(Field field) : this.byReference(field.reference);
ConstantFieldOffset.byReference(this._reference);
@override
ConstantTag get tag => ConstantTag.kFieldOffset;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeCanonicalNameReference(getCanonicalNameOfMember(field));
}
ConstantFieldOffset.readFromBinary(BinarySource source)
: _reference = source.readCanonicalNameReference().getReference();
@override
String toString() => 'FieldOffset $field';
@override
int get hashCode => field.hashCode;
@override
bool operator ==(other) =>
other is ConstantFieldOffset && this.field == other.field;
}
class ConstantClass extends ConstantPoolEntry {
final Reference _reference;
Class get classNode => _reference.asClass;
ConstantClass(Class class_) : this.byReference(class_.reference);
ConstantClass.byReference(this._reference);
@override
ConstantTag get tag => ConstantTag.kClass;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeCanonicalNameReference(getCanonicalNameOfClass(classNode));
}
ConstantClass.readFromBinary(BinarySource source)
: _reference = source.readCanonicalNameReference().getReference();
@override
String toString() => 'Class $classNode';
@override
int get hashCode => classNode.hashCode;
@override
bool operator ==(other) =>
other is ConstantClass && this.classNode == other.classNode;
}
class ConstantTypeArgumentsFieldOffset extends ConstantPoolEntry {
final Reference _reference;
Class get classNode => _reference.asClass;
ConstantTypeArgumentsFieldOffset(Class class_)
: this.byReference(class_.reference);
ConstantTypeArgumentsFieldOffset.byReference(this._reference);
@override
ConstantTag get tag => ConstantTag.kTypeArgumentsFieldOffset;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeCanonicalNameReference(getCanonicalNameOfClass(classNode));
}
ConstantTypeArgumentsFieldOffset.readFromBinary(BinarySource source)
: _reference = source.readCanonicalNameReference().getReference();
@override
String toString() => 'TypeArgumentsFieldOffset $classNode';
@override
int get hashCode => classNode.hashCode;
@override
bool operator ==(other) =>
other is ConstantTypeArgumentsFieldOffset &&
this.classNode == other.classNode;
}
class ConstantTearOff extends ConstantPoolEntry {
final Reference _reference;
Procedure get procedure => _reference.asProcedure;
ConstantTearOff(Procedure procedure) : this.byReference(procedure.reference);
ConstantTearOff.byReference(this._reference);
@override
ConstantTag get tag => ConstantTag.kTearOff;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeCanonicalNameReference(getCanonicalNameOfMember(procedure));
}
ConstantTearOff.readFromBinary(BinarySource source)
: _reference = source.readCanonicalNameReference().getReference();
@override
String toString() => 'TearOff $procedure';
@override
int get hashCode => procedure.hashCode;
@override
bool operator ==(other) =>
other is ConstantTearOff && this.procedure == other.procedure;
}
class ConstantType extends ConstantPoolEntry {
final DartType type;
ConstantType(this.type);
@override
ConstantTag get tag => ConstantTag.kType;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeNodeReference(type);
}
ConstantType.readFromBinary(BinarySource source)
: type = source.readNodeReference() as DartType;
@override
String toString() => 'Type $type';
@override
int get hashCode => type.hashCode;
@override
bool operator ==(other) => other is ConstantType && this.type == other.type;
}
class ConstantTypeArguments extends ConstantPoolEntry {
final List<DartType> typeArgs;
ConstantTypeArguments(this.typeArgs);
@override
ConstantTag get tag => ConstantTag.kTypeArguments;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeUInt30(typeArgs.length);
typeArgs.forEach(sink.writeNodeReference);
}
ConstantTypeArguments.readFromBinary(BinarySource source)
: typeArgs = new List<DartType>.generate(
source.readUInt(), (_) => source.readNodeReference() as DartType);
@override
String toString() => 'TypeArgs $typeArgs';
@override
int get hashCode => listHashCode(typeArgs);
@override
bool operator ==(other) =>
other is ConstantTypeArguments &&
listEquals(this.typeArgs, other.typeArgs);
}
class ConstantList extends ConstantPoolEntry {
final DartType typeArg;
final List<int> entries;
ConstantList(this.typeArg, this.entries);
@override
ConstantTag get tag => ConstantTag.kList;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeNodeReference(typeArg);
sink.writeUInt30(entries.length);
entries.forEach(sink.writeUInt30);
}
ConstantList.readFromBinary(BinarySource source)
: typeArg = source.readNodeReference() as DartType,
entries =
new List<int>.generate(source.readUInt(), (_) => source.readUInt());
@override
String toString() => 'List type-arg $typeArg, entries CP# $entries';
@override
int get hashCode => typeArg.hashCode ^ listHashCode(entries);
@override
bool operator ==(other) =>
other is ConstantList &&
this.typeArg == other.typeArg &&
listEquals(this.entries, other.entries);
}
class ConstantInstance extends ConstantPoolEntry {
final Reference _classReference;
final int _typeArgumentsConstantIndex;
final Map<Reference, int> _fieldValues;
ConstantInstance(Class class_, int typeArgumentsConstantIndex,
Map<Reference, int> fieldValues)
: this.byReference(
class_.reference, typeArgumentsConstantIndex, fieldValues);
ConstantInstance.byReference(this._classReference,
this._typeArgumentsConstantIndex, this._fieldValues);
@override
ConstantTag get tag => ConstantTag.kInstance;
Class get classNode => _classReference.asClass;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeCanonicalNameReference(getCanonicalNameOfClass(classNode));
sink.writeUInt30(_typeArgumentsConstantIndex);
sink.writeUInt30(_fieldValues.length);
_fieldValues.forEach((Reference fieldRef, int valueIndex) {
sink.writeCanonicalNameReference(
getCanonicalNameOfMember(fieldRef.asField));
sink.writeUInt30(valueIndex);
});
}
ConstantInstance.readFromBinary(BinarySource source)
: _classReference = source.readCanonicalNameReference().getReference(),
_typeArgumentsConstantIndex = source.readUInt(),
_fieldValues = new Map<Reference, int>() {
final fieldValuesLen = source.readUInt();
for (int i = 0; i < fieldValuesLen; i++) {
final fieldRef = source.readCanonicalNameReference().getReference();
final valueIndex = source.readUInt();
_fieldValues[fieldRef] = valueIndex;
}
}
@override
String toString() =>
'Instance $classNode type-args CP#$_typeArgumentsConstantIndex'
' ${_fieldValues.map<String, int>((Reference fieldRef, int valueIndex) =>
new MapEntry(fieldRef.asField.name.name, valueIndex))}';
@override
int get hashCode =>
(classNode.hashCode * 31 + _typeArgumentsConstantIndex) * 31 +
mapHashCode(_fieldValues);
@override
bool operator ==(other) =>
other is ConstantInstance &&
this.classNode == other.classNode &&
this._typeArgumentsConstantIndex == other._typeArgumentsConstantIndex &&
mapEquals(this._fieldValues, other._fieldValues);
}
class ConstantPool {
final List<ConstantPoolEntry> entries = <ConstantPoolEntry>[];
final Map<ConstantPoolEntry, int> _canonicalizationCache =
<ConstantPoolEntry, int>{};
ConstantPool();
int add(ConstantPoolEntry entry) {
return _canonicalizationCache.putIfAbsent(entry, () {
int index = entries.length;
entries.add(entry);
return index;
});
}
void writeToBinary(BinarySink sink) {
sink.writeUInt30(entries.length);
entries.forEach((e) {
e.writeToBinary(sink);
});
}
ConstantPool.readFromBinary(BinarySource source) {
int len = source.readUInt();
for (int i = 0; i < len; i++) {
entries.add(new ConstantPoolEntry.readFromBinary(source));
}
}
@override
String toString() {
StringBuffer sb = new StringBuffer();
sb.writeln('ConstantPool {');
for (int i = 0; i < entries.length; i++) {
sb.writeln(' [$i] = ${entries[i]}');
}
sb.writeln('}');
return sb.toString();
}
}

View file

@ -0,0 +1,644 @@
// 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.
library vm.bytecode.dbc;
// List of changes from original DBC:
//
// 1. StoreFieldTOS, LoadFieldTOS instructions:
// D = index of constant pool entry with FieldOffset or
// TypeArgumentsFieldOffset tags (instead of field offset in words).
//
enum Opcode {
kTrap,
kNop,
kCompile,
kHotCheck,
kIntrinsic,
kDrop1,
kDropR,
kDrop,
kJump,
kReturn,
kReturnTOS,
kMove,
kSwap,
kPush,
kLoadConstant,
kLoadClassId,
kLoadClassIdTOS,
kPushConstant,
kStoreLocal,
kPopLocal,
kIndirectStaticCall,
kStaticCall,
kInstanceCall1,
kInstanceCall2,
kInstanceCall1Opt,
kInstanceCall2Opt,
kPushPolymorphicInstanceCall,
kPushPolymorphicInstanceCallByRange,
kNativeCall,
kOneByteStringFromCharCode,
kStringToCharCode,
kAddTOS,
kSubTOS,
kMulTOS,
kBitOrTOS,
kBitAndTOS,
kEqualTOS,
kLessThanTOS,
kGreaterThanTOS,
kSmiAddTOS,
kSmiSubTOS,
kSmiMulTOS,
kSmiBitAndTOS,
kAdd,
kSub,
kMul,
kDiv,
kMod,
kShl,
kShr,
kShlImm,
kNeg,
kBitOr,
kBitAnd,
kBitXor,
kBitNot,
kMin,
kMax,
kWriteIntoDouble,
kUnboxDouble,
kCheckedUnboxDouble,
kUnboxInt32,
kBoxInt32,
kBoxUint32,
kSmiToDouble,
kDoubleToSmi,
kDAdd,
kDSub,
kDMul,
kDDiv,
kDNeg,
kDSqrt,
kDMin,
kDMax,
kDCos,
kDSin,
kDPow,
kDMod,
kDTruncate,
kDFloor,
kDCeil,
kDoubleToFloat,
kFloatToDouble,
kDoubleIsNaN,
kDoubleIsInfinite,
kStoreStaticTOS,
kPushStatic,
kInitStaticTOS,
kIfNeStrictTOS,
kIfEqStrictTOS,
kIfNeStrictNumTOS,
kIfEqStrictNumTOS,
kIfSmiLtTOS,
kIfSmiLeTOS,
kIfSmiGeTOS,
kIfSmiGtTOS,
kIfNeStrict,
kIfEqStrict,
kIfLe,
kIfLt,
kIfGe,
kIfGt,
kIfULe,
kIfULt,
kIfUGe,
kIfUGt,
kIfDNe,
kIfDEq,
kIfDLe,
kIfDLt,
kIfDGe,
kIfDGt,
kIfNeStrictNum,
kIfEqStrictNum,
kIfEqNull,
kIfNeNull,
kCreateArrayTOS,
kCreateArrayOpt,
kAllocate,
kAllocateT,
kAllocateOpt,
kAllocateTOpt,
kStoreIndexedTOS,
kStoreIndexed,
kStoreIndexedUint8,
kStoreIndexedExternalUint8,
kStoreIndexedOneByteString,
kStoreIndexedUint32,
kStoreIndexedFloat32,
kStoreIndexed4Float32,
kStoreIndexedFloat64,
kStoreIndexed8Float64,
kNoSuchMethod,
kTailCall,
kTailCallOpt,
kLoadArgDescriptor,
kLoadArgDescriptorOpt,
kLoadFpRelativeSlot,
kLoadFpRelativeSlotOpt,
kStoreFpRelativeSlot,
kStoreFpRelativeSlotOpt,
kLoadIndexedTOS,
kLoadIndexed,
kLoadIndexedUint8,
kLoadIndexedInt8,
kLoadIndexedInt32,
kLoadIndexedUint32,
kLoadIndexedExternalUint8,
kLoadIndexedExternalInt8,
kLoadIndexedFloat32,
kLoadIndexed4Float32,
kLoadIndexedFloat64,
kLoadIndexed8Float64,
kLoadIndexedOneByteString,
kLoadIndexedTwoByteString,
kStoreField,
kStoreFieldExt,
kStoreFieldTOS,
kLoadField,
kLoadFieldExt,
kLoadUntagged,
kLoadFieldTOS,
kBooleanNegateTOS,
kBooleanNegate,
kThrow,
kEntry,
kEntryOptimized,
kFrame,
kSetFrame,
kAllocateContext,
kAllocateUninitializedContext,
kCloneContext,
kMoveSpecial,
kInstantiateType,
kInstantiateTypeArgumentsTOS,
kInstanceOf,
kBadTypeError,
kAssertAssignable,
kAssertSubtype,
kAssertBoolean,
kTestSmi,
kTestCids,
kCheckSmi,
kCheckEitherNonSmi,
kCheckClassId,
kCheckClassIdRange,
kCheckBitTest,
kCheckCids,
kCheckCidsByRange,
kCheckStack,
kCheckStackAlwaysExit,
kCheckFunctionTypeArgs,
kDebugStep,
kDebugBreak,
kDeopt,
kDeoptRewind,
}
enum Encoding {
k0,
kA,
kAD,
kAX,
kD,
kX,
kABC,
kABY,
kT,
}
enum Operand {
none, // ignored / non-existent operand
imm, // immediate operand
lit, // constant literal from object pool
reg, // register (unsigned FP relative local)
xeg, // x-register (signed FP relative local)
tgt, // jump target relative to the PC of the current instruction
}
class Format {
final Encoding encoding;
final List<Operand> operands;
const Format(this.encoding, this.operands);
}
const Map<Opcode, Format> BytecodeFormats = const {
Opcode.kTrap: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kNop: const Format(
Encoding.kAD, const [Operand.imm, Operand.lit, Operand.none]),
Opcode.kCompile: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kHotCheck: const Format(
Encoding.kAD, const [Operand.imm, Operand.imm, Operand.none]),
Opcode.kIntrinsic: const Format(
Encoding.kA, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kDrop1: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kDropR: const Format(
Encoding.kA, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kDrop: const Format(
Encoding.kA, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kJump: 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(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kMove: const Format(
Encoding.kAX, const [Operand.reg, Operand.xeg, Operand.none]),
Opcode.kSwap: const Format(
Encoding.kAX, const [Operand.reg, Operand.xeg, Operand.none]),
Opcode.kPush: const Format(
Encoding.kX, const [Operand.xeg, Operand.none, Operand.none]),
Opcode.kLoadConstant: const Format(
Encoding.kAD, const [Operand.reg, Operand.lit, Operand.none]),
Opcode.kLoadClassId: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kLoadClassIdTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kPushConstant: const Format(
Encoding.kD, const [Operand.lit, Operand.none, Operand.none]),
Opcode.kStoreLocal: const Format(
Encoding.kX, const [Operand.xeg, Operand.none, Operand.none]),
Opcode.kPopLocal: const Format(
Encoding.kX, const [Operand.xeg, Operand.none, Operand.none]),
Opcode.kIndirectStaticCall: const Format(
Encoding.kAD, const [Operand.imm, Operand.lit, Operand.none]),
Opcode.kStaticCall: const Format(
Encoding.kAD, const [Operand.imm, Operand.imm, Operand.none]),
Opcode.kInstanceCall1: const Format(
Encoding.kAD, const [Operand.imm, Operand.lit, Operand.none]),
Opcode.kInstanceCall2: const Format(
Encoding.kAD, const [Operand.imm, Operand.lit, Operand.none]),
Opcode.kInstanceCall1Opt: const Format(
Encoding.kAD, const [Operand.imm, Operand.lit, Operand.none]),
Opcode.kInstanceCall2Opt: const Format(
Encoding.kAD, const [Operand.imm, Operand.lit, Operand.none]),
Opcode.kPushPolymorphicInstanceCall: const Format(
Encoding.kAD, const [Operand.imm, Operand.imm, Operand.none]),
Opcode.kPushPolymorphicInstanceCallByRange: const Format(
Encoding.kAD, const [Operand.imm, Operand.imm, Operand.none]),
Opcode.kNativeCall: const Format(
Encoding.kABC, const [Operand.imm, Operand.imm, Operand.imm]),
Opcode.kOneByteStringFromCharCode: const Format(
Encoding.kAX, const [Operand.reg, Operand.xeg, Operand.none]),
Opcode.kStringToCharCode: const Format(
Encoding.kAX, const [Operand.reg, Operand.xeg, Operand.none]),
Opcode.kAddTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kSubTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kMulTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kBitOrTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kBitAndTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kEqualTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kLessThanTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kGreaterThanTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kSmiAddTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kSmiSubTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kSmiMulTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kSmiBitAndTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kAdd: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kSub: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kMul: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kDiv: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kMod: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kShl: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kShr: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kShlImm: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.imm]),
Opcode.kNeg: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kBitOr: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kBitAnd: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kBitXor: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kBitNot: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kMin: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kMax: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kWriteIntoDouble: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kUnboxDouble: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kCheckedUnboxDouble: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kUnboxInt32: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.imm]),
Opcode.kBoxInt32: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kBoxUint32: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kSmiToDouble: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kDoubleToSmi: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kDAdd: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kDSub: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kDMul: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kDDiv: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kDNeg: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kDSqrt: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kDMin: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kDMax: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kDCos: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kDSin: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kDPow: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kDMod: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kDTruncate: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kDFloor: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kDCeil: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kDoubleToFloat: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kFloatToDouble: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kDoubleIsNaN: const Format(
Encoding.kA, const [Operand.reg, Operand.none, Operand.none]),
Opcode.kDoubleIsInfinite: const Format(
Encoding.kA, const [Operand.reg, Operand.none, Operand.none]),
Opcode.kStoreStaticTOS: const Format(
Encoding.kD, const [Operand.lit, Operand.none, Operand.none]),
Opcode.kPushStatic: const Format(
Encoding.kD, const [Operand.lit, Operand.none, Operand.none]),
Opcode.kInitStaticTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kIfNeStrictTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kIfEqStrictTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kIfNeStrictNumTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kIfEqStrictNumTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kIfSmiLtTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kIfSmiLeTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kIfSmiGeTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kIfSmiGtTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kIfNeStrict: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfEqStrict: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfLe: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfLt: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfGe: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfGt: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfULe: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfULt: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfUGe: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfUGt: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfDNe: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfDEq: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfDLe: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfDLt: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfDGe: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfDGt: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfNeStrictNum: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfEqStrictNum: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kIfEqNull: const Format(
Encoding.kA, const [Operand.reg, Operand.none, Operand.none]),
Opcode.kIfNeNull: const Format(
Encoding.kA, const [Operand.reg, Operand.none, Operand.none]),
Opcode.kCreateArrayTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kCreateArrayOpt: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kAllocate: const Format(
Encoding.kD, const [Operand.lit, Operand.none, Operand.none]),
Opcode.kAllocateT: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kAllocateOpt: const Format(
Encoding.kAD, const [Operand.reg, Operand.lit, Operand.none]),
Opcode.kAllocateTOpt: const Format(
Encoding.kAD, const [Operand.reg, Operand.lit, Operand.none]),
Opcode.kStoreIndexedTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kStoreIndexed: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kStoreIndexedUint8: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kStoreIndexedExternalUint8: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kStoreIndexedOneByteString: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kStoreIndexedUint32: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kStoreIndexedFloat32: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kStoreIndexed4Float32: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kStoreIndexedFloat64: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kStoreIndexed8Float64: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kNoSuchMethod: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kTailCall: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kTailCallOpt: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kLoadArgDescriptor: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kLoadArgDescriptorOpt: const Format(
Encoding.kA, const [Operand.reg, Operand.none, Operand.none]),
Opcode.kLoadFpRelativeSlot: const Format(
Encoding.kX, const [Operand.reg, Operand.none, Operand.none]),
Opcode.kLoadFpRelativeSlotOpt: const Format(
Encoding.kABY, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kStoreFpRelativeSlot: const Format(
Encoding.kX, const [Operand.reg, Operand.none, Operand.none]),
Opcode.kStoreFpRelativeSlotOpt: const Format(
Encoding.kABY, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexedTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kLoadIndexed: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexedUint8: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexedInt8: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexedInt32: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexedUint32: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexedExternalUint8: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexedExternalInt8: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexedFloat32: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexed4Float32: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexedFloat64: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexed8Float64: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexedOneByteString: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kLoadIndexedTwoByteString: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.reg]),
Opcode.kStoreField: const Format(
Encoding.kABC, const [Operand.reg, Operand.imm, Operand.reg]),
Opcode.kStoreFieldExt: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kStoreFieldTOS: const Format(
Encoding.kD, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kLoadField: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.imm]),
Opcode.kLoadFieldExt: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kLoadUntagged: const Format(
Encoding.kABC, const [Operand.reg, Operand.reg, Operand.imm]),
Opcode.kLoadFieldTOS: const Format(
Encoding.kD, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kBooleanNegateTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kBooleanNegate: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kThrow: const Format(
Encoding.kA, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kEntry: const Format(
Encoding.kD, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kEntryOptimized: const Format(
Encoding.kAD, const [Operand.imm, Operand.imm, Operand.none]),
Opcode.kFrame: const Format(
Encoding.kD, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kSetFrame: const Format(
Encoding.kA, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kAllocateContext: const Format(
Encoding.kD, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kAllocateUninitializedContext: const Format(
Encoding.kAD, const [Operand.reg, Operand.imm, Operand.none]),
Opcode.kCloneContext: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kMoveSpecial: const Format(
Encoding.kAD, const [Operand.reg, Operand.imm, Operand.none]),
Opcode.kInstantiateType: const Format(
Encoding.kD, const [Operand.lit, Operand.none, Operand.none]),
Opcode.kInstantiateTypeArgumentsTOS: const Format(
Encoding.kAD, const [Operand.imm, Operand.lit, Operand.none]),
Opcode.kInstanceOf: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kBadTypeError: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kAssertAssignable: const Format(
Encoding.kAD, const [Operand.imm, Operand.lit, Operand.none]),
Opcode.kAssertSubtype: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kAssertBoolean: const Format(
Encoding.kA, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kTestSmi: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kTestCids: const Format(
Encoding.kAD, const [Operand.reg, Operand.imm, Operand.none]),
Opcode.kCheckSmi: const Format(
Encoding.kA, const [Operand.reg, Operand.none, Operand.none]),
Opcode.kCheckEitherNonSmi: const Format(
Encoding.kAD, const [Operand.reg, Operand.reg, Operand.none]),
Opcode.kCheckClassId: const Format(
Encoding.kAD, const [Operand.reg, Operand.imm, Operand.none]),
Opcode.kCheckClassIdRange: const Format(
Encoding.kAD, const [Operand.reg, Operand.imm, Operand.none]),
Opcode.kCheckBitTest: const Format(
Encoding.kAD, const [Operand.reg, Operand.imm, Operand.none]),
Opcode.kCheckCids: const Format(
Encoding.kABC, const [Operand.reg, Operand.imm, Operand.imm]),
Opcode.kCheckCidsByRange: const Format(
Encoding.kABC, const [Operand.reg, Operand.imm, Operand.imm]),
Opcode.kCheckStack: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kCheckStackAlwaysExit: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kCheckFunctionTypeArgs: const Format(
Encoding.kAD, const [Operand.imm, Operand.imm, Operand.none]),
Opcode.kDebugStep: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kDebugBreak: const Format(
Encoding.kA, const [Operand.imm, Operand.none, Operand.none]),
Opcode.kDeopt: const Format(
Encoding.kAD, const [Operand.imm, Operand.imm, Operand.none]),
Opcode.kDeoptRewind: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
};
// Should match constant in runtime/vm/stack_frame_dbc.h.
const int kParamEndSlotFromFp = 4;
// Prefix used to distinguish getters in ICData target names.
// Should match constant in runtime/vm/object.cc.
const String kGetterPrefix = 'get:';
// Prefix used to distinguish setters in ICData target names.
// Should match constant in runtime/vm/object.cc.
const String kSetterPrefix = 'set:';

View file

@ -0,0 +1,165 @@
// 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.
library vm.bytecode.disassembler;
import 'dart:typed_data';
import 'package:vm/bytecode/dbc.dart';
class _Instruction {
final Opcode opcode;
final List<int> operands;
_Instruction(this.opcode, this.operands);
}
class BytecodeDisassembler {
static const int kOpcodeMask = 0xFF;
static const int kBitsPerInt = 64;
List<_Instruction> _instructions;
int _labelCount;
Map<int, int> _labels;
String disassemble(List<int> bytecode) {
_init(bytecode);
_scanForJumpTargets();
return _disasm();
}
void _init(List<int> bytecode) {
final uint8list = new Uint8List.fromList(bytecode);
// TODO(alexmarkov): endianness?
Uint32List words = uint8list.buffer.asUint32List();
_instructions = new List<_Instruction>(words.length);
for (int i = 0; i < words.length; i++) {
_instructions[i] = _decodeInstruction(words[i]);
}
_labelCount = 0;
_labels = <int, int>{};
}
_Instruction _decodeInstruction(int word) {
final opcode = Opcode.values[word & kOpcodeMask];
final format = BytecodeFormats[opcode];
return new _Instruction(opcode, _decodeOperands(format, word));
}
List<int> _decodeOperands(Format format, int word) {
switch (format.encoding) {
case Encoding.k0:
return const [];
case Encoding.kA:
return [_unsigned(word, 8, 8)];
case Encoding.kAD:
return [_unsigned(word, 8, 8), _unsigned(word, 16, 16)];
case Encoding.kAX:
return [_unsigned(word, 8, 8), _signed(word, 16, 16)];
case Encoding.kD:
return [_unsigned(word, 16, 16)];
case Encoding.kX:
return [_signed(word, 16, 16)];
case Encoding.kABC:
return [
_unsigned(word, 8, 8),
_unsigned(word, 16, 8),
_unsigned(word, 24, 8)
];
case Encoding.kABY:
return [
_unsigned(word, 8, 8),
_unsigned(word, 16, 8),
_signed(word, 24, 8)
];
case Encoding.kT:
return [_signed(word, 8, 24)];
}
throw 'Unexpected format $format';
}
int _unsigned(int word, int pos, int bits) =>
(word >> pos) & ((1 << bits) - 1);
int _signed(int word, int pos, int bits) =>
_unsigned(word, pos, bits) <<
(kBitsPerInt - bits) >>
(kBitsPerInt - bits);
void _scanForJumpTargets() {
for (int i = 0; i < _instructions.length; i++) {
final instr = _instructions[i];
if (instr.opcode == Opcode.kJump) {
final target = i + instr.operands[0];
assert(0 <= target && target < _instructions.length);
_labels[target] ??= (++_labelCount);
}
}
}
String _disasm() {
StringBuffer out = new StringBuffer();
for (int i = 0; i < _instructions.length; i++) {
int label = _labels[i];
if (label != null) {
out.writeln('L$label:');
}
_writeInstruction(out, i, _instructions[i]);
}
return out.toString();
}
void _writeInstruction(StringBuffer out, int bci, _Instruction instr) {
final format = BytecodeFormats[instr.opcode];
assert(format != null);
out.write(' ');
const int kOpcodeWidth = 20;
const String kOpcodePrefix = 'Opcode.k';
String opcode = instr.opcode.toString();
assert(opcode.startsWith(kOpcodePrefix));
opcode = opcode.substring(kOpcodePrefix.length);
if (instr.operands.isEmpty) {
out.writeln(opcode);
return;
}
out.write(opcode.padRight(kOpcodeWidth));
for (int i = 0; i < instr.operands.length; i++) {
if (i == 0) {
out.write(' ');
} else {
out.write(', ');
}
final operand =
_formatOperand(bci, format.operands[i], instr.operands[i]);
out.write(operand);
}
out.writeln();
}
String _formatOperand(int bci, Operand fmt, int value) {
switch (fmt) {
case Operand.none:
break;
case Operand.imm:
return '$value';
case Operand.lit:
return 'CP#$value';
case Operand.reg:
return 'r$value';
case Operand.xeg:
return (value < 0) ? 'FP[$value]' : 'r$value';
case Operand.tgt:
return 'L${_labels[bci + value] ?? (throw 'Label not found')}';
}
throw 'Unexpected operand format $fmt';
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,204 @@
// 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.
library vm.bytecode.local_vars;
import 'dart:math' show max;
import 'package:kernel/ast.dart';
import 'package:vm/bytecode/dbc.dart';
class LocalVariables extends RecursiveVisitor<Null> {
final Map<VariableDeclaration, int> _vars = <VariableDeclaration, int>{};
final Map<TreeNode, int> _temps = <TreeNode, int>{};
final List<int> _scopes = <int>[];
int _localVars = 0;
int _frameSize = 0;
int _thisVarIndex;
int _functionTypeArgsVarIndex;
int get thisVarIndex =>
_thisVarIndex ?? (throw '\'this\' variable is not allocated');
int get functionTypeArgsVarIndex =>
_functionTypeArgsVarIndex ??
(throw '\'functionTypeArgs\' variable is not allocated');
int get frameSize => _frameSize;
int varIndex(VariableDeclaration variable) =>
_vars[variable] ?? (throw '\'$variable\' variable is not allocated');
int tempIndex(TreeNode node) =>
_temps[node] ??
(throw 'Temp is not allocated for node ${node.runtimeType} $node');
int _allocateVar(VariableDeclaration node, {int index}) {
if (index == null) {
index = _localVars++;
} else {
assert(index < 0); // Should be a parameter.
}
_frameSize = max(_frameSize, _localVars);
if (node != null) {
assert(_vars[node] == null);
_vars[node] = index;
}
return index;
}
// TODO(alexmarkov): allocate temporaries more efficiently.
void _allocateTemp(TreeNode node) {
_temps[node] = _allocateVar(null);
}
int _allocateParameter(VariableDeclaration node, int i, int paramNum) {
assert(0 <= i && i < paramNum);
int paramSlotIndex = -kParamEndSlotFromFp - paramNum + i;
return _allocateVar(node, index: paramSlotIndex);
}
void _enterScope() {
_scopes.add(_localVars);
}
void _leaveScope() {
final int enclosingScopeLocalVars = _scopes.removeLast();
assert(_localVars >= enclosingScopeLocalVars);
_localVars = enclosingScopeLocalVars;
}
@override
visitField(Field node) {
if (node.initializer != null) {
assert(_vars.isEmpty);
assert(_localVars == 0);
_enterScope();
node.initializer.accept(this);
_leaveScope();
assert(_scopes.isEmpty);
}
}
@override
defaultMember(Member node) {
assert(_vars.isEmpty);
assert(_localVars == 0);
final function = node.function;
final bool hasTypeArgs = function.typeParameters.isNotEmpty;
final bool hasReceiver =
node is Constructor || ((node is Procedure) && !node.isStatic);
final int numParams = function.positionalParameters.length +
function.namedParameters.length +
(hasTypeArgs ? 1 : 0) +
(hasReceiver ? 1 : 0);
int count = 0;
if (hasTypeArgs) {
_functionTypeArgsVarIndex = _allocateParameter(null, count++, numParams);
}
if (hasReceiver) {
_thisVarIndex = _allocateParameter(null, count++, numParams);
}
for (var param in function.positionalParameters) {
_allocateParameter(param, count++, numParams);
}
List<VariableDeclaration> namedParams = function.namedParameters;
namedParams.sort((VariableDeclaration a, VariableDeclaration b) =>
a.name.compareTo(b.name));
for (var param in namedParams) {
_allocateParameter(param, count++, numParams);
}
_enterScope();
if (node is Constructor) {
_enterScope();
visitList(node.initializers, this);
_leaveScope();
}
function.body?.accept(this);
_leaveScope();
assert(_scopes.isEmpty);
}
@override
visitBlock(Block node) {
_enterScope();
node.visitChildren(this);
_leaveScope();
}
@override
visitVariableDeclaration(VariableDeclaration node) {
_allocateVar(node);
node.visitChildren(this);
}
@override
visitLet(Let node) {
_enterScope();
node.variable.accept(this);
node.body.accept(this);
_leaveScope();
}
// -------------- Allocation of temporaries --------------
@override
visitConstructorInvocation(ConstructorInvocation node) {
if (node.isConst) {
return;
}
_allocateTemp(node);
super.visitConstructorInvocation(node);
}
@override
visitListLiteral(ListLiteral node) {
if (node.isConst) {
return;
}
_allocateTemp(node);
super.visitListLiteral(node);
}
@override
visitMapLiteral(MapLiteral node) {
if (node.isConst) {
return;
}
super.visitMapLiteral(node);
}
@override
visitStringConcatenation(StringConcatenation node) {
_allocateTemp(node);
super.visitStringConcatenation(node);
}
@override
visitConditionalExpression(ConditionalExpression node) {
_allocateTemp(node);
super.visitConditionalExpression(node);
}
@override
visitLogicalExpression(LogicalExpression node) {
_allocateTemp(node);
super.visitLogicalExpression(node);
}
@override
visitPropertySet(PropertySet node) {
_allocateTemp(node);
super.visitPropertySet(node);
}
}

View file

@ -16,6 +16,7 @@ import 'package:front_end/src/api_prototype/compilation_message.dart'
import 'package:front_end/src/fasta/severity.dart' show Severity;
import 'package:kernel/ast.dart' show Component, StaticGet, Field;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:vm/bytecode/gen_bytecode.dart' show generateBytecode;
import 'transformations/devirtualization.dart' as devirtualization
show transformComponent;
@ -34,7 +35,8 @@ import 'transformations/type_flow/transformer.dart' as globalTypeFlow
Future<Component> compileToKernel(Uri source, CompilerOptions options,
{bool aot: false,
bool useGlobalTypeFlowAnalysis: false,
List<String> entryPoints}) async {
List<String> entryPoints,
bool genBytecode: false}) async {
// Replace error handler to detect if there are compilation errors.
final errorDetector =
new ErrorDetector(previousErrorHandler: options.onError);
@ -51,6 +53,10 @@ Future<Component> compileToKernel(Uri source, CompilerOptions options,
component, options.strongMode, useGlobalTypeFlowAnalysis, entryPoints);
}
if (genBytecode && component != null) {
generateBytecode(component, strongMode: options.strongMode);
}
return component;
}

View file

@ -0,0 +1,44 @@
// 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.
library vm.metadata.bytecode;
import 'package:kernel/ast.dart';
import 'package:vm/bytecode/constant_pool.dart' show ConstantPool;
import 'package:vm/bytecode/disassembler.dart' show BytecodeDisassembler;
/// Metadata containing bytecode.
class BytecodeMetadata {
final List<int> bytecodes;
final ConstantPool constantPool;
BytecodeMetadata(this.bytecodes, this.constantPool);
@override
String toString() =>
"\nBytecode {\n${new BytecodeDisassembler().disassemble(bytecodes)}}\n$constantPool";
}
/// Repository for [BytecodeMetadata].
class BytecodeMetadataRepository extends MetadataRepository<BytecodeMetadata> {
@override
final String tag = 'vm.bytecode';
@override
final Map<TreeNode, BytecodeMetadata> mapping =
<TreeNode, BytecodeMetadata>{};
@override
void writeToBinary(BytecodeMetadata metadata, BinarySink sink) {
sink.writeByteList(metadata.bytecodes);
metadata.constantPool.writeToBinary(sink);
}
@override
BytecodeMetadata readFromBinary(BinarySource source) {
final List<int> bytecodes = source.readByteList();
final ConstantPool constantPool = new ConstantPool.readFromBinary(source);
return new BytecodeMetadata(bytecodes, constantPool);
}
}

View file

@ -0,0 +1,36 @@
// 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.
import 'dart:io';
import 'package:kernel/ast.dart';
import 'package:kernel/kernel.dart';
import 'package:test/test.dart';
import 'package:vm/bytecode/gen_bytecode.dart' show generateBytecode;
import '../common_test_utils.dart';
final String pkgVmDir = Platform.script.resolve('../..').toFilePath();
runTestCase(Uri source) async {
Component component = await compileTestCaseToKernelProgram(source);
generateBytecode(component, strongMode: true);
final actual = kernelLibraryToString(component.mainMethod.enclosingLibrary);
compareResultWithExpectationsFile(source, actual);
}
main() {
group('gen-bytecode', () {
final testCasesDir = new Directory(pkgVmDir + '/testcases/bytecode');
for (var entry
in testCasesDir.listSync(recursive: true, followLinks: false)) {
if (entry.path.endsWith(".dart")) {
test(entry.path, () => runTestCase(entry.uri));
}
}
});
}

View file

@ -9,6 +9,7 @@ import 'package:front_end/src/api_prototype/front_end.dart';
import 'package:front_end/src/compute_platform_binaries_location.dart'
show computePlatformBinariesLocation;
import 'package:kernel/ast.dart';
import 'package:kernel/text/ast_to_text.dart' show Printer;
import 'package:kernel/target/targets.dart';
import 'package:kernel/target/vm.dart';
import 'package:test/test.dart';
@ -26,7 +27,21 @@ Future<Component> compileTestCaseToKernelProgram(Uri sourceUri) async {
..onError = (CompilationMessage error) {
fail("Compilation error: ${error}");
};
return kernelForProgram(sourceUri, options);
final Component component = await kernelForProgram(sourceUri, options);
// Make sure the library name is the same and does not depend on the order
// of test cases.
component.mainMethod.enclosingLibrary.name = '#lib';
return component;
}
String kernelLibraryToString(Library library) {
final StringBuffer buffer = new StringBuffer();
new Printer(buffer, showExternal: false, showMetadata: true)
.writeLibraryFile(library);
return buffer.toString();
}
void compareResultWithExpectationsFile(Uri source, String actual) {

View file

@ -12,7 +12,7 @@ import 'package:test/test.dart';
import 'package:vm/transformations/type_flow/native_code.dart';
import 'package:vm/transformations/type_flow/summary_collector.dart';
import 'common_test_utils.dart';
import '../../common_test_utils.dart';
final String pkgVmDir = Platform.script.resolve('../../..').toFilePath();
@ -43,10 +43,6 @@ runTestCase(Uri source) async {
final Component component = await compileTestCaseToKernelProgram(source);
final Library library = component.mainMethod.enclosingLibrary;
// Make sure the library name is the same and does not depend on the order
// of test cases.
library.name = '#lib';
final typeEnvironment = new TypeEnvironment(
new CoreTypes(component), new ClassHierarchy(component));

View file

@ -7,22 +7,17 @@ import 'dart:io';
import 'package:kernel/ast.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/kernel.dart';
import 'package:kernel/text/ast_to_text.dart';
import 'package:test/test.dart';
import 'package:vm/transformations/type_flow/transformer.dart'
show transformComponent;
import 'common_test_utils.dart';
import '../../common_test_utils.dart';
final String pkgVmDir = Platform.script.resolve('../../..').toFilePath();
runTestCase(Uri source) async {
Component component = await compileTestCaseToKernelProgram(source);
// Make sure the library name is the same and does not depend on the order
// of test cases.
component.mainMethod.enclosingLibrary.name = '#lib';
final coreTypes = new CoreTypes(component);
final entryPoints = [
@ -32,10 +27,7 @@ runTestCase(Uri source) async {
component = transformComponent(coreTypes, component, entryPoints);
final StringBuffer buffer = new StringBuffer();
new Printer(buffer, showExternal: false, showMetadata: true)
.writeLibraryFile(component.mainMethod.enclosingLibrary);
final actual = buffer.toString();
final actual = kernelLibraryToString(component.mainMethod.enclosingLibrary);
compareResultWithExpectationsFile(source, actual);
}

View file

@ -0,0 +1,142 @@
// 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.
// Selection of methods used during bootstrapping.
// ignore_for_file: native_function_body_in_non_sdk_code
// ignore_for_file: unused_element, unused_field
// -----------------------------------------------------------------
void _printString(String s) native "Builtin_PrintString";
void _print(arg) {
_printString(arg.toString());
}
_getPrintClosure() => _print;
// -----------------------------------------------------------------
typedef void _ScheduleImmediateClosure(void callback());
class _ScheduleImmediate {
static _ScheduleImmediateClosure _closure;
}
void _setScheduleImmediateClosure(_ScheduleImmediateClosure closure) {
_ScheduleImmediate._closure = closure;
}
// -----------------------------------------------------------------
class _NamespaceImpl implements _Namespace {
_NamespaceImpl._();
static _NamespaceImpl _create(_NamespaceImpl namespace, var n)
native "Namespace_Create";
static int _getPointer(_NamespaceImpl namespace)
native "Namespace_GetPointer";
static int _getDefault() native "Namespace_GetDefault";
// If the platform supports "namespaces", this method is called by the
// embedder with the platform-specific namespace information.
static _NamespaceImpl _cachedNamespace = null;
static void _setupNamespace(var namespace) {
_cachedNamespace = _create(new _NamespaceImpl._(), namespace);
}
static _NamespaceImpl get _namespace {
if (_cachedNamespace == null) {
// The embedder has not supplied a namespace before one is needed, so
// instead use a safe-ish default value.
_cachedNamespace = _create(new _NamespaceImpl._(), _getDefault());
}
return _cachedNamespace;
}
static int get _namespacePointer => _getPointer(_namespace);
}
class _Namespace {
static void _setupNamespace(var namespace) {
_NamespaceImpl._setupNamespace(namespace);
}
static _Namespace get _namespace => _NamespaceImpl._namespace;
static int get _namespacePointer => _NamespaceImpl._namespacePointer;
}
// -----------------------------------------------------------------
// These may be set to different values by the embedder by calling
// _setStdioFDs when initializing dart:io.
int _stdinFD = 0;
int _stdoutFD = 1;
int _stderrFD = 2;
// This is an embedder entrypoint.
void _setStdioFDs(int stdin, int stdout, int stderr) {
_stdinFD = stdin;
_stdoutFD = stdout;
_stderrFD = stderr;
}
// -----------------------------------------------------------------
class VMLibraryHooks {
// Example: "dart:isolate _Timer._factory"
static var timerFactory;
// Example: "dart:io _EventHandler._sendData"
static var eventHandlerSendData;
// A nullary closure that answers the current clock value in milliseconds.
// Example: "dart:io _EventHandler._timerMillisecondClock"
static var timerMillisecondClock;
// Implementation of Resource.readAsBytes.
static var resourceReadAsBytes;
// Implementation of package root/map provision.
static var packageRootString;
static var packageConfigString;
static var packageRootUriFuture;
static var packageConfigUriFuture;
static var resolvePackageUriFuture;
static var _computeScriptUri;
static var _cachedScript;
static set platformScript(var f) {
_computeScriptUri = f;
_cachedScript = null;
}
static get platformScript {
if (_cachedScript == null && _computeScriptUri != null) {
_cachedScript = _computeScriptUri();
}
return _cachedScript;
}
}
String _rawScript;
Uri _scriptUri() {
if (_rawScript.startsWith('http:') ||
_rawScript.startsWith('https:') ||
_rawScript.startsWith('file:')) {
return Uri.parse(_rawScript);
} else {
return Uri.base.resolveUri(new Uri.file(_rawScript));
}
}
_setupHooks() {
VMLibraryHooks.platformScript = _scriptUri;
}
// -----------------------------------------------------------------
main() {}

View file

@ -0,0 +1,739 @@
library #lib;
import self as self;
import "dart:core" as core;
import "dart:_internal" as _in;
typedef _ScheduleImmediateClosure = (() → void) → void;
class _ScheduleImmediate extends core::Object {
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field (() → void) → void _closure = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
Push FP[-5]
PushConstant CP#1
IndirectStaticCall 1, CP#0
Drop1
PushConstant CP#2
ReturnTOS
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
[2] = Null
}
] synthetic constructor •() → void
: super core::Object::•()
;
}
class _NamespaceImpl extends core::Object implements self::_Namespace {
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field self::_NamespaceImpl _cachedNamespace = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
Push FP[-5]
PushConstant CP#1
IndirectStaticCall 1, CP#0
Drop1
PushConstant CP#2
ReturnTOS
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
[2] = Null
}
] constructor _() → void
: super core::Object::•()
;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] @_in::ExternalName::•("Namespace_Create")
external static method _create(self::_NamespaceImpl namespace, dynamic n) → self::_NamespaceImpl;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] @_in::ExternalName::•("Namespace_GetPointer")
external static method _getPointer(self::_NamespaceImpl namespace) → core::int;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] @_in::ExternalName::•("Namespace_GetDefault")
external static method _getDefault() → core::int;
[@vm.bytecode=
Bytecode {
Entry 1
CheckStack
Allocate CP#0
StoreLocal r0
Push r0
PushConstant CP#2
IndirectStaticCall 1, CP#1
Drop1
Push FP[-5]
PushConstant CP#4
IndirectStaticCall 2, CP#3
StoreStaticTOS CP#5
Drop1
PushConstant CP#6
ReturnTOS
}
ConstantPool {
[0] = Class #lib::_NamespaceImpl
[1] = ArgDesc num-args 1, num-type-args 0, names []
[2] = StaticICData target '#lib::_NamespaceImpl::_', arg-desc CP#1
[3] = ArgDesc num-args 2, num-type-args 0, names []
[4] = StaticICData target '#lib::_NamespaceImpl::_create', arg-desc CP#3
[5] = Field #lib::_NamespaceImpl::_cachedNamespace
[6] = Null
}
] static method _setupNamespace(dynamic namespace) → void {
self::_NamespaceImpl::_cachedNamespace = self::_NamespaceImpl::_create(new self::_NamespaceImpl::_(), namespace);
}
[@vm.bytecode=
Bytecode {
Entry 1
CheckStack
PushConstant CP#0
PushStatic CP#0
PushConstant CP#1
InstanceCall1 2, CP#3
PushConstant CP#4
IfNeStrictTOS
Jump L1
Allocate CP#5
StoreLocal r0
Push r0
PushConstant CP#7
IndirectStaticCall 1, CP#6
Drop1
PushConstant CP#9
IndirectStaticCall 0, CP#8
PushConstant CP#10
IndirectStaticCall 2, CP#2
StoreStaticTOS CP#0
Drop1
L1:
PushConstant CP#0
PushStatic CP#0
ReturnTOS
PushConstant CP#1
ReturnTOS
}
ConstantPool {
[0] = Field #lib::_NamespaceImpl::_cachedNamespace
[1] = Null
[2] = ArgDesc num-args 2, num-type-args 0, names []
[3] = ICData target-name '==', arg-desc CP#2
[4] = Bool true
[5] = Class #lib::_NamespaceImpl
[6] = ArgDesc num-args 1, num-type-args 0, names []
[7] = StaticICData target '#lib::_NamespaceImpl::_', arg-desc CP#6
[8] = ArgDesc num-args 0, num-type-args 0, names []
[9] = StaticICData target '#lib::_NamespaceImpl::_getDefault', arg-desc CP#8
[10] = StaticICData target '#lib::_NamespaceImpl::_create', arg-desc CP#2
}
] static get _namespace() → self::_NamespaceImpl {
if(self::_NamespaceImpl::_cachedNamespace.{core::Object::==}(null)) {
self::_NamespaceImpl::_cachedNamespace = self::_NamespaceImpl::_create(new self::_NamespaceImpl::_(), self::_NamespaceImpl::_getDefault());
}
return self::_NamespaceImpl::_cachedNamespace;
}
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#1
IndirectStaticCall 0, CP#0
PushConstant CP#3
IndirectStaticCall 1, CP#2
ReturnTOS
PushConstant CP#4
ReturnTOS
}
ConstantPool {
[0] = ArgDesc num-args 0, num-type-args 0, names []
[1] = StaticICData target '#lib::_NamespaceImpl::_namespace', arg-desc CP#0
[2] = ArgDesc num-args 1, num-type-args 0, names []
[3] = StaticICData target '#lib::_NamespaceImpl::_getPointer', arg-desc CP#2
[4] = Null
}
] static get _namespacePointer() → core::int
return self::_NamespaceImpl::_getPointer(self::_NamespaceImpl::_namespace);
}
class _Namespace extends core::Object {
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
Push FP[-5]
PushConstant CP#1
IndirectStaticCall 1, CP#0
Drop1
PushConstant CP#2
ReturnTOS
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
[2] = Null
}
] synthetic constructor •() → void
: super core::Object::•()
;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
Push FP[-5]
PushConstant CP#1
IndirectStaticCall 1, CP#0
Drop1
PushConstant CP#2
ReturnTOS
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = StaticICData target '#lib::_NamespaceImpl::_setupNamespace', arg-desc CP#0
[2] = Null
}
] static method _setupNamespace(dynamic namespace) → void {
self::_NamespaceImpl::_setupNamespace(namespace);
}
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#1
IndirectStaticCall 0, CP#0
ReturnTOS
PushConstant CP#2
ReturnTOS
}
ConstantPool {
[0] = ArgDesc num-args 0, num-type-args 0, names []
[1] = StaticICData target '#lib::_NamespaceImpl::_namespace', arg-desc CP#0
[2] = Null
}
] static get _namespace() → self::_Namespace
return self::_NamespaceImpl::_namespace;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#1
IndirectStaticCall 0, CP#0
ReturnTOS
PushConstant CP#2
ReturnTOS
}
ConstantPool {
[0] = ArgDesc num-args 0, num-type-args 0, names []
[1] = StaticICData target '#lib::_NamespaceImpl::_namespacePointer', arg-desc CP#0
[2] = Null
}
] static get _namespacePointer() → core::int
return self::_NamespaceImpl::_namespacePointer;
}
class VMLibraryHooks extends core::Object {
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field dynamic timerFactory = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field dynamic eventHandlerSendData = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field dynamic timerMillisecondClock = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field dynamic resourceReadAsBytes = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field dynamic packageRootString = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field dynamic packageConfigString = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field dynamic packageRootUriFuture = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field dynamic packageConfigUriFuture = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field dynamic resolvePackageUriFuture = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field dynamic _computeScriptUri = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
] static field dynamic _cachedScript = null;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
Push FP[-5]
PushConstant CP#1
IndirectStaticCall 1, CP#0
Drop1
PushConstant CP#2
ReturnTOS
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
[2] = Null
}
] synthetic constructor •() → void
: super core::Object::•()
;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
Push FP[-5]
StoreStaticTOS CP#0
Drop1
PushConstant CP#1
StoreStaticTOS CP#2
Drop1
PushConstant CP#1
ReturnTOS
}
ConstantPool {
[0] = Field #lib::VMLibraryHooks::_computeScriptUri
[1] = Null
[2] = Field #lib::VMLibraryHooks::_cachedScript
}
] static set platformScript(dynamic f) → void {
self::VMLibraryHooks::_computeScriptUri = f;
self::VMLibraryHooks::_cachedScript = null;
}
[@vm.bytecode=
Bytecode {
Entry 1
CheckStack
PushConstant CP#0
PushStatic CP#0
PushConstant CP#1
InstanceCall1 2, CP#3
PushConstant CP#4
IfNeStrictTOS
Jump L1
PushConstant CP#5
PushStatic CP#5
PushConstant CP#1
InstanceCall1 2, CP#3
BooleanNegateTOS
PopLocal r0
Jump L2
L1:
PushConstant CP#6
PopLocal r0
L2:
Push r0
PushConstant CP#4
IfNeStrictTOS
Jump L3
PushConstant CP#5
PushStatic CP#5
InstanceCall1 1, CP#8
StoreStaticTOS CP#0
Drop1
L3:
PushConstant CP#0
PushStatic CP#0
ReturnTOS
PushConstant CP#1
ReturnTOS
}
ConstantPool {
[0] = Field #lib::VMLibraryHooks::_cachedScript
[1] = Null
[2] = ArgDesc num-args 2, num-type-args 0, names []
[3] = ICData target-name '==', arg-desc CP#2
[4] = Bool true
[5] = Field #lib::VMLibraryHooks::_computeScriptUri
[6] = Bool false
[7] = ArgDesc num-args 1, num-type-args 0, names []
[8] = ICData target-name 'call', arg-desc CP#7
}
] static get platformScript() → dynamic {
if(self::VMLibraryHooks::_cachedScript.==(null) && !self::VMLibraryHooks::_computeScriptUri.==(null)) {
self::VMLibraryHooks::_cachedScript = self::VMLibraryHooks::_computeScriptUri.call();
}
return self::VMLibraryHooks::_cachedScript;
}
}
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Int 0
}
]static field core::int _stdinFD = 0;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Int 1
}
]static field core::int _stdoutFD = 1;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Int 2
}
]static field core::int _stderrFD = 2;
static field core::String _rawScript;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
]@_in::ExternalName::•("Builtin_PrintString")
external static method _printString(core::String s) → void;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
Push FP[-5]
InstanceCall1 1, CP#1
PushConstant CP#2
IndirectStaticCall 1, CP#0
Drop1
PushConstant CP#3
ReturnTOS
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = ICData target-name 'toString', arg-desc CP#0
[2] = StaticICData target '#lib::_printString', arg-desc CP#0
[3] = Null
}
]static method _print(dynamic arg) → void {
self::_printString(arg.toString() as{TypeError} core::String);
}
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
PushConstant CP#1
ReturnTOS
}
ConstantPool {
[0] = TearOff #lib::_print
[1] = Null
}
]static method _getPrintClosure() → dynamic
return self::_print;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
Push FP[-5]
StoreStaticTOS CP#0
Drop1
PushConstant CP#1
ReturnTOS
}
ConstantPool {
[0] = Field #lib::_ScheduleImmediate::_closure
[1] = Null
}
]static method _setScheduleImmediateClosure((() → void) → void closure) → void {
self::_ScheduleImmediate::_closure = closure;
}
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
Push FP[-7]
StoreStaticTOS CP#0
Drop1
Push FP[-6]
StoreStaticTOS CP#1
Drop1
Push FP[-5]
StoreStaticTOS CP#2
Drop1
PushConstant CP#3
ReturnTOS
}
ConstantPool {
[0] = Field #lib::_stdinFD
[1] = Field #lib::_stdoutFD
[2] = Field #lib::_stderrFD
[3] = Null
}
]static method _setStdioFDs(core::int stdin, core::int stdout, core::int stderr) → void {
self::_stdinFD = stdin;
self::_stdoutFD = stdout;
self::_stderrFD = stderr;
}
[@vm.bytecode=
Bytecode {
Entry 2
CheckStack
PushConstant CP#0
PushStatic CP#0
PushConstant CP#1
InstanceCall1 2, CP#3
PushConstant CP#4
IfEqStrictTOS
Jump L1
PushConstant CP#0
PushStatic CP#0
PushConstant CP#5
InstanceCall1 2, CP#3
PopLocal r1
Jump L2
L1:
PushConstant CP#4
PopLocal r1
L2:
Push r1
PushConstant CP#4
IfEqStrictTOS
Jump L3
PushConstant CP#0
PushStatic CP#0
PushConstant CP#6
InstanceCall1 2, CP#3
PopLocal r0
Jump L4
L3:
PushConstant CP#4
PopLocal r0
L4:
Push r0
PushConstant CP#4
IfNeStrictTOS
Jump L5
PushConstant CP#0
PushStatic CP#0
PushConstant CP#8
IndirectStaticCall 1, CP#7
ReturnTOS
Jump L6
L5:
PushConstant CP#10
IndirectStaticCall 0, CP#9
PushConstant CP#11
PushConstant CP#0
PushStatic CP#0
PushConstant CP#12
IndirectStaticCall 2, CP#7
InstanceCall1 2, CP#13
ReturnTOS
L6:
PushConstant CP#11
ReturnTOS
}
ConstantPool {
[0] = Field #lib::_rawScript
[1] = String 'http:'
[2] = ArgDesc num-args 2, num-type-args 0, names []
[3] = ICData target-name 'startsWith', arg-desc CP#2
[4] = Bool true
[5] = String 'https:'
[6] = String 'file:'
[7] = ArgDesc num-args 1, num-type-args 0, names []
[8] = StaticICData target 'dart.core::Uri::parse', arg-desc CP#7
[9] = ArgDesc num-args 0, num-type-args 0, names []
[10] = StaticICData target 'dart.core::Uri::base', arg-desc CP#9
[11] = Null
[12] = StaticICData target 'dart.core::_Uri::file', arg-desc CP#7
[13] = ICData target-name 'resolveUri', arg-desc CP#2
}
]static method _scriptUri() → core::Uri {
if(self::_rawScript.{core::String::startsWith}("http:") || self::_rawScript.{core::String::startsWith}("https:") || self::_rawScript.{core::String::startsWith}("file:")) {
return core::Uri::parse(self::_rawScript);
}
else {
return core::Uri::base.{core::Uri::resolveUri}(core::_Uri::file(self::_rawScript));
}
}
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
PushConstant CP#2
IndirectStaticCall 1, CP#1
Drop1
PushConstant CP#3
ReturnTOS
}
ConstantPool {
[0] = TearOff #lib::_scriptUri
[1] = ArgDesc num-args 1, num-type-args 0, names []
[2] = StaticICData target '#lib::VMLibraryHooks::platformScript', arg-desc CP#1
[3] = Null
}
]static method _setupHooks() → dynamic {
self::VMLibraryHooks::platformScript = self::_scriptUri;
}
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
ReturnTOS
}
ConstantPool {
[0] = Null
}
]static method main() → dynamic {}

View file

@ -0,0 +1,7 @@
// 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.
main() {
print('Hello, Dart Bytecode!');
}

View file

@ -0,0 +1,24 @@
library #lib;
import self as self;
import "dart:core" as core;
[@vm.bytecode=
Bytecode {
Entry 0
CheckStack
PushConstant CP#0
PushConstant CP#2
IndirectStaticCall 1, CP#1
Drop1
PushConstant CP#3
ReturnTOS
}
ConstantPool {
[0] = String 'Hello, Dart Bytecode!'
[1] = ArgDesc num-args 1, num-type-args 0, names []
[2] = StaticICData target 'dart.core::print', arg-desc CP#1
[3] = Null
}
]static method main() → dynamic {
core::print("Hello, Dart Bytecode!");
}

View file

@ -310,7 +310,7 @@ namespace dart {
// this instruction does so, and skips the following instruction. Otherwise,
// the following instruction is not skipped.
//
// - StoreStaticT`OS D
// - StoreStaticTOS D
//
// Stores TOS into the static field PP[D].
//
@ -908,7 +908,7 @@ namespace dart {
V(Entry, D, num, ___, ___) \
V(EntryOptimized, A_D, num, num, ___) \
V(Frame, D, num, ___, ___) \
V(SetFrame, A, num, ___, num) \
V(SetFrame, A, num, ___, ___) \
V(AllocateContext, D, num, ___, ___) \
V(AllocateUninitializedContext, A_D, reg, num, ___) \
V(CloneContext, 0, ___, ___, ___) \