blob: a8661bb528810b515f833fd7ce284948c996d17f [file] [log] [blame]
// 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;
import 'package:kernel/text/ast_to_text.dart' show Printer;
/*
In kernel binary, constant pool is encoded in the following way
(using notation from pkg/kernel/binary.md):
type ConstantPool {
List<ConstantPoolEntry>
}
type ConstantIndex = UInt;
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;
}
enum InvocationKind {
method, // x.foo(...) or foo(...)
getter, // x.foo
setter // x.foo = ...
}
type ConstantICData extends ConstantPoolEntry {
Byte tag = 7;
Byte invocationKind; // Index in InvocationKind enum.
Name targetName;
ConstantIndex argDesc;
}
type ConstantStaticICData extends ConstantPoolEntry {
Byte tag = 8;
Byte invocationKind; // Index in InvocationKind enum.
CanonicalNameReference target;
ConstantIndex argDesc;
}
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;
DartType type;
}
type ConstantTypeArguments extends ConstantPoolEntry {
Byte tag = 15;
List<DartType> types;
}
type ConstantList extends ConstantPoolEntry {
Byte tag = 16;
DartType typeArg;
List<ConstantIndex> entries;
}
type ConstantInstance extends ConstantPoolEntry {
Byte tag = 17;
CanonicalNameReference class;
ConstantIndex typeArguments;
List<Pair<CanonicalNameReference, ConstantIndex>> fieldValues;
}
type ConstantSymbol extends ConstantPoolEntry {
Byte tag = 18;
StringReference value;
}
type ConstantTypeArgumentsForInstanceAllocation extends ConstantPoolEntry {
Byte tag = 19;
CanonicalNameReference instantiatingClass;
List<DartType> types;
}
type ConstantContextOffset extends ConstantPoolEntry {
Byte tag = 20;
// 0 = Offset of 'parent' field in Context object.
// 1 + i = Offset of i-th variable in Context object.
UInt index;
}
type ConstantClosureFunction extends ConstantPoolEntry {
Byte tag = 21;
StringReference name;
FunctionNode function; // Doesn't have a body.
}
type ConstantEndClosureFunctionScope extends ConstantPoolEntry {
Byte tag = 22;
}
type ConstantNativeEntry extends ConstantPoolEntry {
Byte tag = 23;
StringReference nativeName;
}
type ConstantSubtypeTestCache extends ConstantPoolEntry {
Byte tag = 24;
}
type ConstantPartialTearOffInstantiation extends ConstantPoolEntry {
Byte tag = 25;
ConstantIndex tearOffConstant;
ConstantIndex typeArguments;
}
*/
enum ConstantTag {
kInvalid,
kNull,
kString,
kInt,
kDouble,
kBool,
kArgDesc,
kICData,
kStaticICData,
kField,
kFieldOffset,
kClass,
kTypeArgumentsFieldOffset,
kTearOff,
kType,
kTypeArguments,
kList,
kInstance,
kSymbol,
kTypeArgumentsForInstanceAllocation,
kContextOffset,
kClosureFunction,
kEndClosureFunctionScope,
kNativeEntry,
kSubtypeTestCache,
kPartialTearOffInstantiation
}
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);
case ConstantTag.kSymbol:
return new ConstantSymbol.readFromBinary(source);
case ConstantTag.kTypeArgumentsForInstanceAllocation:
return new ConstantTypeArgumentsForInstanceAllocation.readFromBinary(
source);
case ConstantTag.kContextOffset:
return new ConstantContextOffset.readFromBinary(source);
case ConstantTag.kClosureFunction:
return new ConstantClosureFunction.readFromBinary(source);
case ConstantTag.kEndClosureFunctionScope:
return new ConstantEndClosureFunctionScope.readFromBinary(source);
case ConstantTag.kNativeEntry:
return new ConstantNativeEntry.readFromBinary(source);
case ConstantTag.kSubtypeTestCache:
return new ConstantSubtypeTestCache.readFromBinary(source);
case ConstantTag.kPartialTearOffInstantiation:
return new ConstantPartialTearOffInstantiation.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, bool isFactory: false})
: this(
args.positional.length +
args.named.length +
(hasReceiver ? 1 : 0) +
// VM expects that type arguments vector passed to a factory
// constructor is counted in numArguments, and not counted in
// numTypeArgs.
// TODO(alexmarkov): Clean this up.
(isFactory ? 1 : 0),
numTypeArgs: isFactory ? 0 : 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 => _combineHashes(
_combineHashes(numArguments, numTypeArgs), listHashCode(argNames));
@override
bool operator ==(other) =>
other is ConstantArgDesc &&
this.numArguments == other.numArguments &&
this.numTypeArgs == other.numTypeArgs &&
listEquals(this.argNames, other.argNames);
}
enum InvocationKind { method, getter, setter }
String _invocationKindToString(InvocationKind kind) {
switch (kind) {
case InvocationKind.method:
return '';
case InvocationKind.getter:
return 'get ';
case InvocationKind.setter:
return 'set ';
}
throw 'Unexpected InvocationKind $kind';
}
class ConstantICData extends ConstantPoolEntry {
final InvocationKind invocationKind;
final Name targetName;
final int argDescConstantIndex;
ConstantICData(
this.invocationKind, this.targetName, this.argDescConstantIndex);
@override
ConstantTag get tag => ConstantTag.kICData;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeByte(invocationKind.index);
sink.writeName(targetName);
sink.writeUInt30(argDescConstantIndex);
}
ConstantICData.readFromBinary(BinarySource source)
: invocationKind = InvocationKind.values[source.readByte()],
targetName = source.readName(),
argDescConstantIndex = source.readUInt();
@override
String toString() => 'ICData ${_invocationKindToString(invocationKind)}'
'target-name \'$targetName\', arg-desc CP#$argDescConstantIndex';
// ConstantICData entries are created per call site and should not be merged,
// so ConstantICData class uses identity [hashCode] and [operator ==].
@override
int get hashCode => identityHashCode(this);
@override
bool operator ==(other) => identical(this, other);
}
class ConstantStaticICData extends ConstantPoolEntry {
final InvocationKind invocationKind;
final Reference _reference;
final int argDescConstantIndex;
ConstantStaticICData(
InvocationKind invocationKind, Member member, int argDescConstantIndex)
: this.byReference(
invocationKind, member.reference, argDescConstantIndex);
ConstantStaticICData.byReference(
this.invocationKind, this._reference, this.argDescConstantIndex);
Member get target => _reference.asMember;
@override
ConstantTag get tag => ConstantTag.kStaticICData;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeByte(invocationKind.index);
sink.writeCanonicalNameReference(getCanonicalNameOfMember(target));
sink.writeUInt30(argDescConstantIndex);
}
ConstantStaticICData.readFromBinary(BinarySource source)
: invocationKind = InvocationKind.values[source.readByte()],
_reference = source.readCanonicalNameReference().getReference(),
argDescConstantIndex = source.readUInt();
@override
String toString() => 'StaticICData ${_invocationKindToString(invocationKind)}'
'target \'$target\', arg-desc CP#$argDescConstantIndex';
// ConstantStaticICData entries are created per call site and should not be
// merged, so ConstantStaticICData class uses identity [hashCode] and
// [operator ==].
@override
int get hashCode => identityHashCode(this);
@override
bool operator ==(other) => identical(this, other);
}
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.writeDartType(type);
}
ConstantType.readFromBinary(BinarySource source)
: type = source.readDartType();
@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.writeDartType);
}
ConstantTypeArguments.readFromBinary(BinarySource source)
: typeArgs = new List<DartType>.generate(
source.readUInt(), (_) => source.readDartType());
@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.writeDartType(typeArg);
sink.writeUInt30(entries.length);
entries.forEach(sink.writeUInt30);
}
ConstantList.readFromBinary(BinarySource source)
: typeArg = source.readDartType(),
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() {
final values = _fieldValues.map<String, String>(
(Reference fieldRef, int valueIndex) =>
new MapEntry(fieldRef.asField.name.name, 'CP#$valueIndex'));
return 'Instance $classNode type-args CP#$_typeArgumentsConstantIndex $values';
}
@override
int get hashCode => _combineHashes(
_combineHashes(classNode.hashCode, _typeArgumentsConstantIndex),
mapHashCode(_fieldValues));
@override
bool operator ==(other) =>
other is ConstantInstance &&
this.classNode == other.classNode &&
this._typeArgumentsConstantIndex == other._typeArgumentsConstantIndex &&
mapEquals(this._fieldValues, other._fieldValues);
}
class ConstantSymbol extends ConstantPoolEntry {
final String value;
ConstantSymbol(this.value);
ConstantSymbol.fromLiteral(SymbolLiteral literal) : this(literal.value);
@override
ConstantTag get tag => ConstantTag.kSymbol;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeStringReference(value);
}
ConstantSymbol.readFromBinary(BinarySource source)
: value = source.readStringReference();
@override
String toString() => 'Symbol \'$value\'';
@override
int get hashCode => value.hashCode;
@override
bool operator ==(other) =>
other is ConstantSymbol && this.value == other.value;
}
class ConstantTypeArgumentsForInstanceAllocation extends ConstantPoolEntry {
final Reference _instantiatingClassRef;
final List<DartType> typeArgs;
Class get instantiatingClass => _instantiatingClassRef.asClass;
ConstantTypeArgumentsForInstanceAllocation(
Class instantiatingClass, List<DartType> typeArgs)
: this.byReference(instantiatingClass.reference, typeArgs);
ConstantTypeArgumentsForInstanceAllocation.byReference(
this._instantiatingClassRef, this.typeArgs);
@override
ConstantTag get tag => ConstantTag.kTypeArgumentsForInstanceAllocation;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeCanonicalNameReference(
getCanonicalNameOfClass(instantiatingClass));
sink.writeUInt30(typeArgs.length);
typeArgs.forEach(sink.writeDartType);
}
ConstantTypeArgumentsForInstanceAllocation.readFromBinary(BinarySource source)
: _instantiatingClassRef =
source.readCanonicalNameReference().getReference(),
typeArgs = new List<DartType>.generate(
source.readUInt(), (_) => source.readDartType());
@override
String toString() =>
'TypeArgumentsForInstanceAllocation $instantiatingClass $typeArgs';
@override
int get hashCode =>
_combineHashes(instantiatingClass.hashCode, listHashCode(typeArgs));
@override
bool operator ==(other) =>
other is ConstantTypeArgumentsForInstanceAllocation &&
this.instantiatingClass == other.instantiatingClass &&
listEquals(this.typeArgs, other.typeArgs);
}
class ConstantContextOffset extends ConstantPoolEntry {
static const int kParent = 0;
static const int kVariableBase = 1;
final int _index;
ConstantContextOffset._(this._index);
ConstantContextOffset.parent() : this._(kParent);
ConstantContextOffset.variable(int index) : this._(index + kVariableBase);
@override
ConstantTag get tag => ConstantTag.kContextOffset;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeUInt30(_index);
}
ConstantContextOffset.readFromBinary(BinarySource source)
: _index = source.readUInt();
@override
String toString() =>
'ContextOffset ${_index == kParent ? 'parent' : 'var [${_index - kVariableBase}]'}';
@override
int get hashCode => _index;
@override
bool operator ==(other) =>
other is ConstantContextOffset && this._index == other._index;
}
class ConstantClosureFunction extends ConstantPoolEntry {
final String name;
final FunctionNode function;
ConstantClosureFunction(this.name, this.function);
@override
ConstantTag get tag => ConstantTag.kClosureFunction;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeStringReference(name);
_withoutFunctionBody(() {
sink.writeNode(function);
});
}
ConstantClosureFunction.readFromBinary(BinarySource source)
: name = source.readStringReference(),
function = source.readFunctionNode() {
assert(function.body == null);
}
@override
String toString() {
StringBuffer buffer = new StringBuffer();
_withoutFunctionBody(() {
new Printer(buffer).writeFunction(function);
});
return 'ClosureFunction $name ${buffer.toString().trim()}';
}
_withoutFunctionBody(action()) {
final savedBody = function.body;
function.body = null;
action();
function.body = savedBody;
}
// ConstantClosureFunction entries are created per closure and should not
// be merged, so ConstantClosureFunction class uses identity [hashCode] and
// [operator ==].
}
class ConstantEndClosureFunctionScope extends ConstantPoolEntry {
ConstantEndClosureFunctionScope();
@override
ConstantTag get tag => ConstantTag.kEndClosureFunctionScope;
@override
void writeValueToBinary(BinarySink sink) {}
ConstantEndClosureFunctionScope.readFromBinary(BinarySource source) {}
@override
String toString() => 'EndClosureFunctionScope';
// ConstantEndClosureFunctionScope entries are created per closure and should
// not be merged, so ConstantEndClosureFunctionScope class uses identity
// [hashCode] and [operator ==].
}
class ConstantNativeEntry extends ConstantPoolEntry {
final String nativeName;
ConstantNativeEntry(this.nativeName);
@override
ConstantTag get tag => ConstantTag.kNativeEntry;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeStringReference(nativeName);
}
ConstantNativeEntry.readFromBinary(BinarySource source)
: nativeName = source.readStringReference();
@override
String toString() => 'NativeEntry $nativeName';
@override
int get hashCode => nativeName.hashCode;
@override
bool operator ==(other) =>
other is ConstantNativeEntry && this.nativeName == other.nativeName;
}
class ConstantSubtypeTestCache extends ConstantPoolEntry {
ConstantSubtypeTestCache();
@override
ConstantTag get tag => ConstantTag.kSubtypeTestCache;
@override
void writeValueToBinary(BinarySink sink) {}
ConstantSubtypeTestCache.readFromBinary(BinarySource source);
@override
String toString() => 'SubtypeTestCache';
// ConstantSubtypeTestCache entries are created per subtype test site and
// should not be merged, so ConstantSubtypeTestCache class uses identity
// [hashCode] and [operator ==].
@override
int get hashCode => identityHashCode(this);
@override
bool operator ==(other) => identical(this, other);
}
class ConstantPartialTearOffInstantiation extends ConstantPoolEntry {
final int tearOffConstantIndex;
final int typeArgumentsConstantIndex;
ConstantPartialTearOffInstantiation(
this.tearOffConstantIndex, this.typeArgumentsConstantIndex);
@override
ConstantTag get tag => ConstantTag.kPartialTearOffInstantiation;
@override
void writeValueToBinary(BinarySink sink) {
sink.writeUInt30(tearOffConstantIndex);
sink.writeUInt30(typeArgumentsConstantIndex);
}
ConstantPartialTearOffInstantiation.readFromBinary(BinarySource source)
: tearOffConstantIndex = source.readUInt(),
typeArgumentsConstantIndex = source.readUInt();
@override
String toString() {
return 'PartialTearOffInstantiation tear-off CP#$tearOffConstantIndex type-args CP#$typeArgumentsConstantIndex';
}
@override
int get hashCode =>
_combineHashes(tearOffConstantIndex, typeArgumentsConstantIndex);
@override
bool operator ==(other) =>
other is ConstantPartialTearOffInstantiation &&
this.tearOffConstantIndex == other.tearOffConstantIndex &&
this.typeArgumentsConstantIndex == other.typeArgumentsConstantIndex;
}
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(Node node, BinarySink sink) {
final function = (node as Member).function;
sink.enterScope(
typeParameters: function?.typeParameters, memberScope: true);
final closureStack = <ConstantClosureFunction>[];
sink.writeUInt30(entries.length);
entries.forEach((e) {
e.writeToBinary(sink);
if (e is ConstantClosureFunction) {
sink.enterScope(typeParameters: e.function.typeParameters);
closureStack.add(e);
} else if (e is ConstantEndClosureFunctionScope) {
sink.leaveScope(
typeParameters: closureStack.removeLast().function.typeParameters);
}
});
assert(closureStack.isEmpty);
sink.leaveScope(
typeParameters: function?.typeParameters, memberScope: true);
}
ConstantPool.readFromBinary(Node node, BinarySource source) {
final function = (node as Member).function;
if (function != null) {
source.enterScope(typeParameters: function.typeParameters);
}
final closureStack = <ConstantClosureFunction>[];
int len = source.readUInt();
for (int i = 0; i < len; i++) {
final e = new ConstantPoolEntry.readFromBinary(source);
entries.add(e);
if (e is ConstantClosureFunction) {
source.enterScope(typeParameters: e.function.typeParameters);
closureStack.add(e);
} else if (e is ConstantEndClosureFunctionScope) {
source.leaveScope(
typeParameters: closureStack.removeLast().function.typeParameters);
}
}
assert(closureStack.isEmpty);
if (function != null) {
source.leaveScope(typeParameters: function.typeParameters);
}
}
@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();
}
}
int _combineHashes(int hash1, int hash2) =>
(((hash1 * 31) & 0x3fffffff) + hash2) & 0x3fffffff;