mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:59:47 +00:00
[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:
parent
db2f3de25d
commit
ac7ca17652
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
917
pkg/vm/lib/bytecode/assembler.dart
Normal file
917
pkg/vm/lib/bytecode/assembler.dart
Normal 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));
|
||||
}
|
||||
}
|
803
pkg/vm/lib/bytecode/constant_pool.dart
Normal file
803
pkg/vm/lib/bytecode/constant_pool.dart
Normal 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();
|
||||
}
|
||||
}
|
644
pkg/vm/lib/bytecode/dbc.dart
Normal file
644
pkg/vm/lib/bytecode/dbc.dart
Normal 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:';
|
165
pkg/vm/lib/bytecode/disassembler.dart
Normal file
165
pkg/vm/lib/bytecode/disassembler.dart
Normal 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';
|
||||
}
|
||||
}
|
1069
pkg/vm/lib/bytecode/gen_bytecode.dart
Normal file
1069
pkg/vm/lib/bytecode/gen_bytecode.dart
Normal file
File diff suppressed because it is too large
Load diff
204
pkg/vm/lib/bytecode/local_vars.dart
Normal file
204
pkg/vm/lib/bytecode/local_vars.dart
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
44
pkg/vm/lib/metadata/bytecode.dart
Normal file
44
pkg/vm/lib/metadata/bytecode.dart
Normal 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);
|
||||
}
|
||||
}
|
36
pkg/vm/test/bytecode/gen_bytecode_test.dart
Normal file
36
pkg/vm/test/bytecode/gen_bytecode_test.dart
Normal 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));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
|
@ -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) {
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
142
pkg/vm/testcases/bytecode/boostrapping.dart
Normal file
142
pkg/vm/testcases/bytecode/boostrapping.dart
Normal 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() {}
|
739
pkg/vm/testcases/bytecode/boostrapping.dart.expect
Normal file
739
pkg/vm/testcases/bytecode/boostrapping.dart.expect
Normal 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 {}
|
7
pkg/vm/testcases/bytecode/hello.dart
Normal file
7
pkg/vm/testcases/bytecode/hello.dart
Normal 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!');
|
||||
}
|
24
pkg/vm/testcases/bytecode/hello.dart.expect
Normal file
24
pkg/vm/testcases/bytecode/hello.dart.expect
Normal 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!");
|
||||
}
|
|
@ -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, ___, ___, ___) \
|
||||
|
|
Loading…
Reference in a new issue