[vm] Refactoring: move out classes independent of StreamingFlowGraphBuilder

This change continues refactoring to split kernel_binary_flowgraph and
kernel_to_il and move out parts which have no dependencies on flow graph
construction.

Bytecode reading is moved to a separate file bytecode_reader{.h, .cc}.

Metadata helpers, TypeTranslator, ActiveClass and other Active* are moved
to kernel_translation_helper.

Removed dependency of ICData tags on IL Instruction tags, so ICData objects
can be created by bytecode reader without depending on IL.

Unused AlternativeScriptScope is removed.

Change-Id: Ic9f98af82697b48013fb89802076b56833acf55d
Reviewed-on: https://dart-review.googlesource.com/63262
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2018-07-03 19:02:54 +00:00 committed by commit-bot@chromium.org
parent aa009339b3
commit 8c63d578a6
16 changed files with 1622 additions and 1586 deletions

View file

@ -2444,7 +2444,7 @@ class ICDataSerializationCluster : public SerializationCluster {
}
s->Write<uint32_t>(ic->ptr()->state_bits_);
#if defined(TAG_IC_DATA)
s->Write<int32_t>(ic->ptr()->tag_);
s->Write<int32_t>(static_cast<int32_t>(ic->ptr()->tag_));
#endif
}
}
@ -2489,7 +2489,7 @@ class ICDataDeserializationCluster : public DeserializationCluster {
NOT_IN_PRECOMPILED(ic->ptr()->deopt_id_ = d->Read<int32_t>());
ic->ptr()->state_bits_ = d->Read<int32_t>();
#if defined(TAG_IC_DATA)
ic->ptr()->tag_ = d->Read<int32_t>();
ic->ptr()->tag_ = static_cast<ICData::Tag>(d->Read<int32_t>());
#endif
}
}

View file

@ -1649,7 +1649,7 @@ const ICData* FlowGraphCompiler::GetOrAddInstanceCallICData(
arguments_descriptor, deopt_id, num_args_tested,
ICData::kInstance));
#if defined(TAG_IC_DATA)
ic_data.set_tag(Instruction::kInstanceCall);
ic_data.set_tag(ICData::Tag::kInstanceCall);
#endif
if (deopt_id_to_ic_data_ != NULL) {
(*deopt_id_to_ic_data_)[deopt_id] = &ic_data;
@ -1683,7 +1683,7 @@ const ICData* FlowGraphCompiler::GetOrAddStaticCallICData(
deopt_id, num_args_tested, rebind_rule));
ic_data.AddTarget(target);
#if defined(TAG_IC_DATA)
ic_data.set_tag(Instruction::kStaticCall);
ic_data.set_tag(ICData::Tag::kStaticCall);
#endif
if (deopt_id_to_ic_data_ != NULL) {
(*deopt_id_to_ic_data_)[deopt_id] = &ic_data;

View file

@ -320,9 +320,20 @@ const ICData* Instruction::GetICData(
const ICData* result = ic_data_array[deopt_id_];
#if defined(TAG_IC_DATA)
if (result != NULL) {
if (result->tag() == -1) {
result->set_tag(tag());
} else if (result->tag() != tag()) {
ICData::Tag ic_data_tag = ICData::Tag::kUnknown;
switch (tag()) {
case kInstanceCall:
ic_data_tag = ICData::Tag::kInstanceCall;
break;
case kStaticCall:
ic_data_tag = ICData::Tag::kStaticCall;
break;
default:
UNREACHABLE();
}
if (result->tag() == ICData::Tag::kUnknown) {
result->set_tag(ic_data_tag);
} else if (result->tag() != ic_data_tag) {
FATAL("ICData tag mismatch");
}
}

View file

@ -75,6 +75,8 @@ compiler_sources = [
"cha.h",
"compiler_pass.cc",
"compiler_pass.h",
"frontend/bytecode_reader.cc",
"frontend/bytecode_reader.h",
"frontend/flow_graph_builder.cc",
"frontend/flow_graph_builder.h",
"frontend/kernel_binary_flowgraph.cc",

View file

@ -0,0 +1,612 @@
// 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.
#include "vm/compiler/frontend/bytecode_reader.h"
#include "vm/bootstrap.h"
#include "vm/code_descriptors.h"
#include "vm/compiler/assembler/disassembler_kbc.h"
#include "vm/dart_entry.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#if defined(DART_USE_INTERPRETER)
#define Z (zone_)
#define H (translation_helper_)
#define T (type_translator_)
#define I Isolate::Current()
namespace dart {
DEFINE_FLAG(bool, dump_kernel_bytecode, false, "Dump kernel bytecode");
namespace kernel {
BytecodeMetadataHelper::BytecodeMetadataHelper(KernelReaderHelper* helper,
TypeTranslator* type_translator,
ActiveClass* active_class)
: MetadataHelper(helper, tag(), /* precompiler_only = */ false),
type_translator_(*type_translator),
active_class_(active_class) {}
void BytecodeMetadataHelper::ReadMetadata(const Function& function) {
const intptr_t node_offset = function.kernel_offset();
const intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
if (md_offset < 0) {
return;
}
AlternativeReadingScope alt(&helper_->reader_, &H.metadata_payloads(),
md_offset);
// Create object pool and read pool entries.
const intptr_t obj_count = helper_->reader_.ReadListLength();
const ObjectPool& pool =
ObjectPool::Handle(helper_->zone_, ObjectPool::New(obj_count));
ReadPoolEntries(function, function, pool, 0);
// Read bytecode and attach to function.
const Code& bytecode = Code::Handle(helper_->zone_, ReadBytecode(pool));
function.AttachBytecode(bytecode);
// Read exceptions table.
ReadExceptionsTable(bytecode);
if (FLAG_dump_kernel_bytecode) {
KernelBytecodeDisassembler::Disassemble(function);
}
// Read closures.
Function& closure = Function::Handle(helper_->zone_);
Code& closure_bytecode = Code::Handle(helper_->zone_);
intptr_t num_closures = helper_->ReadListLength();
for (intptr_t i = 0; i < num_closures; i++) {
intptr_t closure_index = helper_->ReadUInt();
ASSERT(closure_index < obj_count);
closure ^= pool.ObjectAt(closure_index);
// Read closure bytecode and attach to closure function.
closure_bytecode = ReadBytecode(pool);
closure.AttachBytecode(closure_bytecode);
// Read closure exceptions table.
ReadExceptionsTable(closure_bytecode);
if (FLAG_dump_kernel_bytecode) {
KernelBytecodeDisassembler::Disassemble(closure);
}
}
}
intptr_t BytecodeMetadataHelper::ReadPoolEntries(const Function& function,
const Function& inner_function,
const ObjectPool& pool,
intptr_t from_index) {
// These enums and the code below reading the constant pool from kernel must
// be kept in sync with pkg/vm/lib/bytecode/constant_pool.dart.
enum ConstantPoolTag {
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,
};
enum InvocationKind {
method, // x.foo(...) or foo(...)
getter, // x.foo
setter // x.foo = ...
};
Object& obj = Object::Handle(helper_->zone_);
Object& elem = Object::Handle(helper_->zone_);
Array& array = Array::Handle(helper_->zone_);
Field& field = Field::Handle(helper_->zone_);
Class& cls = Class::Handle(helper_->zone_);
String& name = String::Handle(helper_->zone_);
TypeArguments& type_args = TypeArguments::Handle(helper_->zone_);
const intptr_t obj_count = pool.Length();
for (intptr_t i = from_index; i < obj_count; ++i) {
const intptr_t tag = helper_->ReadTag();
switch (tag) {
case ConstantPoolTag::kInvalid:
UNREACHABLE();
case ConstantPoolTag::kNull:
obj = Object::null();
break;
case ConstantPoolTag::kString:
obj = H.DartString(helper_->ReadStringReference()).raw();
ASSERT(obj.IsString());
obj = H.Canonicalize(String::Cast(obj));
break;
case ConstantPoolTag::kInt: {
uint32_t low_bits = helper_->ReadUInt32();
int64_t value = helper_->ReadUInt32();
value = (value << 32) | low_bits;
obj = Integer::New(value);
} break;
case ConstantPoolTag::kDouble: {
uint32_t low_bits = helper_->ReadUInt32();
uint64_t bits = helper_->ReadUInt32();
bits = (bits << 32) | low_bits;
double value = bit_cast<double, uint64_t>(bits);
obj = Double::New(value);
} break;
case ConstantPoolTag::kBool:
if (helper_->ReadUInt() == 1) {
obj = Bool::True().raw();
} else {
obj = Bool::False().raw();
}
break;
case ConstantPoolTag::kArgDesc: {
intptr_t num_arguments = helper_->ReadUInt();
intptr_t num_type_args = helper_->ReadUInt();
intptr_t num_arg_names = helper_->ReadListLength();
if (num_arg_names == 0) {
obj = ArgumentsDescriptor::New(num_type_args, num_arguments);
} else {
array = Array::New(num_arg_names);
for (intptr_t j = 0; j < num_arg_names; j++) {
array.SetAt(j, H.DartSymbolPlain(helper_->ReadStringReference()));
}
obj = ArgumentsDescriptor::New(num_type_args, num_arguments, array);
}
} break;
case ConstantPoolTag::kICData: {
InvocationKind kind = static_cast<InvocationKind>(helper_->ReadByte());
if (kind == InvocationKind::getter) {
name = helper_->ReadNameAsGetterName().raw();
} else if (kind == InvocationKind::setter) {
name = helper_->ReadNameAsSetterName().raw();
} else {
ASSERT(kind == InvocationKind::method);
name = helper_->ReadNameAsMethodName().raw();
}
intptr_t arg_desc_index = helper_->ReadUInt();
ASSERT(arg_desc_index < i);
array ^= pool.ObjectAt(arg_desc_index);
// TODO(regis): Should num_args_tested be explicitly provided?
obj = ICData::New(function, name,
array, // Arguments descriptor.
Thread::kNoDeoptId, 1 /* num_args_tested */,
ICData::RebindRule::kInstance);
#if defined(TAG_IC_DATA)
ICData::Cast(obj).set_tag(ICData::Tag::kInstanceCall);
#endif
} break;
case ConstantPoolTag::kStaticICData: {
InvocationKind kind = static_cast<InvocationKind>(helper_->ReadByte());
NameIndex target = helper_->ReadCanonicalNameReference();
if (H.IsConstructor(target)) {
name = H.DartConstructorName(target).raw();
elem = H.LookupConstructorByKernelConstructor(target);
} else if (H.IsField(target)) {
if (kind == InvocationKind::getter) {
name = H.DartGetterName(target).raw();
} else if (kind == InvocationKind::setter) {
name = H.DartSetterName(target).raw();
} else {
ASSERT(kind == InvocationKind::method);
UNIMPLEMENTED(); // TODO(regis): Revisit.
}
field = H.LookupFieldByKernelField(target);
cls = field.Owner();
elem = cls.LookupFunctionAllowPrivate(name);
} else {
if ((kind == InvocationKind::method) && H.IsGetter(target)) {
UNIMPLEMENTED(); // TODO(regis): Revisit.
}
name = H.DartProcedureName(target).raw();
elem = H.LookupStaticMethodByKernelProcedure(target);
}
ASSERT(elem.IsFunction());
intptr_t arg_desc_index = helper_->ReadUInt();
ASSERT(arg_desc_index < i);
array ^= pool.ObjectAt(arg_desc_index);
obj = ICData::New(function, name,
array, // Arguments descriptor.
Thread::kNoDeoptId, 0 /* num_args_tested */,
ICData::RebindRule::kStatic);
ICData::Cast(obj).AddTarget(Function::Cast(elem));
#if defined(TAG_IC_DATA)
ICData::Cast(obj).set_tag(ICData::Tag::kStaticCall);
#endif
} break;
case ConstantPoolTag::kField:
obj = H.LookupFieldByKernelField(helper_->ReadCanonicalNameReference());
ASSERT(obj.IsField());
break;
case ConstantPoolTag::kFieldOffset:
obj = H.LookupFieldByKernelField(helper_->ReadCanonicalNameReference());
ASSERT(obj.IsField());
obj = Smi::New(Field::Cast(obj).Offset() / kWordSize);
break;
case ConstantPoolTag::kClass:
obj = H.LookupClassByKernelClass(helper_->ReadCanonicalNameReference());
ASSERT(obj.IsClass());
break;
case ConstantPoolTag::kTypeArgumentsFieldOffset:
cls = H.LookupClassByKernelClass(helper_->ReadCanonicalNameReference());
obj = Smi::New(cls.type_arguments_field_offset() / kWordSize);
break;
case ConstantPoolTag::kTearOff:
obj = H.LookupStaticMethodByKernelProcedure(
helper_->ReadCanonicalNameReference());
ASSERT(obj.IsFunction());
obj = Function::Cast(obj).ImplicitClosureFunction();
ASSERT(obj.IsFunction());
obj = Function::Cast(obj).ImplicitStaticClosure();
ASSERT(obj.IsInstance());
obj = H.Canonicalize(Instance::Cast(obj));
break;
case ConstantPoolTag::kType:
obj = type_translator_.BuildType().raw();
ASSERT(obj.IsAbstractType());
break;
case ConstantPoolTag::kTypeArguments:
obj = type_translator_.BuildTypeArguments(helper_->ReadListLength())
.raw();
ASSERT(obj.IsNull() || obj.IsTypeArguments());
break;
case ConstantPoolTag::kList: {
obj = type_translator_.BuildType().raw();
ASSERT(obj.IsAbstractType());
const intptr_t length = helper_->ReadListLength();
array = Array::New(length, AbstractType::Cast(obj));
for (intptr_t j = 0; j < length; j++) {
intptr_t elem_index = helper_->ReadUInt();
ASSERT(elem_index < i);
elem = pool.ObjectAt(elem_index);
array.SetAt(j, elem);
}
obj = H.Canonicalize(Array::Cast(array));
ASSERT(!obj.IsNull());
} break;
case ConstantPoolTag::kInstance: {
cls = H.LookupClassByKernelClass(helper_->ReadCanonicalNameReference());
obj = Instance::New(cls, Heap::kOld);
intptr_t type_args_index = helper_->ReadUInt();
ASSERT(type_args_index < i);
type_args ^= pool.ObjectAt(type_args_index);
if (!type_args.IsNull()) {
Instance::Cast(obj).SetTypeArguments(type_args);
}
intptr_t num_fields = helper_->ReadUInt();
for (intptr_t j = 0; j < num_fields; j++) {
NameIndex field_name = helper_->ReadCanonicalNameReference();
ASSERT(H.IsField(field_name));
field = H.LookupFieldByKernelField(field_name);
intptr_t elem_index = helper_->ReadUInt();
ASSERT(elem_index < i);
elem = pool.ObjectAt(elem_index);
Instance::Cast(obj).SetField(field, elem);
}
obj = H.Canonicalize(Instance::Cast(obj));
} break;
case ConstantPoolTag::kSymbol:
obj = H.DartSymbolPlain(helper_->ReadStringReference()).raw();
ASSERT(String::Cast(obj).IsSymbol());
break;
case ConstantPoolTag::kTypeArgumentsForInstanceAllocation: {
cls = H.LookupClassByKernelClass(helper_->ReadCanonicalNameReference());
obj =
type_translator_
.BuildInstantiatedTypeArguments(cls, helper_->ReadListLength())
.raw();
ASSERT(obj.IsNull() || obj.IsTypeArguments());
} break;
case ConstantPoolTag::kContextOffset: {
intptr_t index = helper_->ReadUInt();
if (index == 0) {
obj = Smi::New(Context::parent_offset() / kWordSize);
} else {
obj = Smi::New(Context::variable_offset(index - 1) / kWordSize);
}
} break;
case ConstantPoolTag::kClosureFunction: {
name = H.DartSymbolPlain(helper_->ReadStringReference()).raw();
const Function& closure = Function::Handle(
helper_->zone_,
Function::NewClosureFunction(name, inner_function,
TokenPosition::kNoSource));
FunctionNodeHelper function_node_helper(helper_);
function_node_helper.ReadUntilExcluding(
FunctionNodeHelper::kTypeParameters);
type_translator_.LoadAndSetupTypeParameters(
active_class_, closure, helper_->ReadListLength(), closure);
function_node_helper.SetJustRead(FunctionNodeHelper::kTypeParameters);
// Scope remains opened until ConstantPoolTag::kEndClosureFunctionScope.
ActiveTypeParametersScope scope(
active_class_, &closure,
TypeArguments::Handle(helper_->zone_, closure.type_parameters()),
helper_->zone_);
function_node_helper.ReadUntilExcluding(
FunctionNodeHelper::kPositionalParameters);
intptr_t required_parameter_count =
function_node_helper.required_parameter_count_;
intptr_t total_parameter_count =
function_node_helper.total_parameter_count_;
intptr_t positional_parameter_count = helper_->ReadListLength();
intptr_t named_parameter_count =
total_parameter_count - positional_parameter_count;
const intptr_t extra_parameters = 1;
closure.set_num_fixed_parameters(extra_parameters +
required_parameter_count);
if (named_parameter_count > 0) {
closure.SetNumOptionalParameters(named_parameter_count, false);
} else {
closure.SetNumOptionalParameters(
positional_parameter_count - required_parameter_count, true);
}
intptr_t parameter_count = extra_parameters + total_parameter_count;
closure.set_parameter_types(Array::Handle(
helper_->zone_, Array::New(parameter_count, Heap::kOld)));
closure.set_parameter_names(Array::Handle(
helper_->zone_, Array::New(parameter_count, Heap::kOld)));
intptr_t pos = 0;
closure.SetParameterTypeAt(pos, AbstractType::dynamic_type());
closure.SetParameterNameAt(pos, Symbols::ClosureParameter());
pos++;
const Library& lib =
Library::Handle(helper_->zone_, active_class_->klass->library());
for (intptr_t j = 0; j < positional_parameter_count; ++j, ++pos) {
VariableDeclarationHelper helper(helper_);
helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
const AbstractType& type = type_translator_.BuildVariableType();
Tag tag = helper_->ReadTag(); // read (first part of) initializer.
if (tag == kSomething) {
helper_->SkipExpression(); // read (actual) initializer.
}
closure.SetParameterTypeAt(pos, type);
closure.SetParameterNameAt(pos,
H.DartIdentifier(lib, helper.name_index_));
}
intptr_t named_parameter_count_check = helper_->ReadListLength();
ASSERT(named_parameter_count_check == named_parameter_count);
for (intptr_t j = 0; j < named_parameter_count; ++j, ++pos) {
VariableDeclarationHelper helper(helper_);
helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
const AbstractType& type = type_translator_.BuildVariableType();
Tag tag = helper_->ReadTag(); // read (first part of) initializer.
if (tag == kSomething) {
helper_->SkipExpression(); // read (actual) initializer.
}
closure.SetParameterTypeAt(pos, type);
closure.SetParameterNameAt(pos,
H.DartIdentifier(lib, helper.name_index_));
}
function_node_helper.SetJustRead(FunctionNodeHelper::kNamedParameters);
const AbstractType& return_type = type_translator_.BuildVariableType();
closure.set_result_type(return_type);
function_node_helper.SetJustRead(FunctionNodeHelper::kReturnType);
// The closure has no body.
function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
pool.SetTypeAt(i, ObjectPool::kTaggedObject);
pool.SetObjectAt(i, closure);
// Continue reading the constant pool entries inside the opened
// ActiveTypeParametersScope until the scope gets closed by a
// kEndClosureFunctionScope tag, in which case control returns here.
i = ReadPoolEntries(function, closure, pool, i + 1);
// Pool entry at index i has been set to null, because it was a
// kEndClosureFunctionScope.
ASSERT(pool.ObjectAt(i) == Object::null());
continue;
}
case ConstantPoolTag::kEndClosureFunctionScope: {
// Entry is not used and set to null.
obj = Object::null();
pool.SetTypeAt(i, ObjectPool::kTaggedObject);
pool.SetObjectAt(i, obj);
return i; // The caller will close the scope.
} break;
case ConstantPoolTag::kNativeEntry: {
name = H.DartString(helper_->ReadStringReference()).raw();
obj = NativeEntry(function, name);
} break;
case ConstantPoolTag::kSubtypeTestCache: {
obj = SubtypeTestCache::New();
} break;
default:
UNREACHABLE();
}
pool.SetTypeAt(i, ObjectPool::kTaggedObject);
pool.SetObjectAt(i, obj);
}
// Return the index of the last read pool entry.
return obj_count - 1;
}
RawCode* BytecodeMetadataHelper::ReadBytecode(const ObjectPool& pool) {
intptr_t size = helper_->reader_.ReadUInt();
intptr_t offset = helper_->reader_.offset();
const uint8_t* data = helper_->reader_.BufferAt(offset);
helper_->reader_.set_offset(offset + size);
// Create and return code object.
return Code::FinalizeBytecode(reinterpret_cast<const void*>(data), size,
pool);
}
void BytecodeMetadataHelper::ReadExceptionsTable(const Code& bytecode) {
const intptr_t try_block_count = helper_->reader_.ReadListLength();
if (try_block_count > 0) {
const ObjectPool& pool =
ObjectPool::Handle(helper_->zone_, bytecode.object_pool());
AbstractType& handler_type = AbstractType::Handle(helper_->zone_);
Array& handler_types = Array::ZoneHandle(helper_->zone_);
DescriptorList* pc_descriptors_list =
new (helper_->zone_) DescriptorList(64);
ExceptionHandlerList* exception_handlers_list =
new (helper_->zone_) ExceptionHandlerList();
// Encoding of ExceptionsTable is described in
// pkg/vm/lib/bytecode/exceptions.dart.
for (intptr_t try_index = 0; try_index < try_block_count; try_index++) {
intptr_t outer_try_index_plus1 = helper_->reader_.ReadUInt();
intptr_t outer_try_index = outer_try_index_plus1 - 1;
intptr_t start_pc = helper_->reader_.ReadUInt();
intptr_t end_pc = helper_->reader_.ReadUInt();
intptr_t handler_pc = helper_->reader_.ReadUInt();
uint8_t flags = helper_->reader_.ReadByte();
const uint8_t kFlagNeedsStackTrace = 1 << 0;
const uint8_t kFlagIsSynthetic = 1 << 1;
const bool needs_stacktrace = (flags & kFlagNeedsStackTrace) != 0;
const bool is_generated = (flags & kFlagIsSynthetic) != 0;
intptr_t type_count = helper_->reader_.ReadListLength();
ASSERT(type_count > 0);
handler_types = Array::New(type_count, Heap::kOld);
for (intptr_t i = 0; i < type_count; i++) {
intptr_t type_index = helper_->reader_.ReadUInt();
ASSERT(type_index < pool.Length());
handler_type ^= pool.ObjectAt(type_index);
handler_types.SetAt(i, handler_type);
}
pc_descriptors_list->AddDescriptor(RawPcDescriptors::kOther, start_pc,
Thread::kNoDeoptId,
TokenPosition::kNoSource, try_index);
pc_descriptors_list->AddDescriptor(RawPcDescriptors::kOther, end_pc,
Thread::kNoDeoptId,
TokenPosition::kNoSource, -1);
exception_handlers_list->AddHandler(
try_index, outer_try_index, handler_pc, TokenPosition::kNoSource,
is_generated, handler_types, needs_stacktrace);
}
const PcDescriptors& descriptors = PcDescriptors::Handle(
helper_->zone_,
pc_descriptors_list->FinalizePcDescriptors(bytecode.PayloadStart()));
bytecode.set_pc_descriptors(descriptors);
const ExceptionHandlers& handlers = ExceptionHandlers::Handle(
helper_->zone_, exception_handlers_list->FinalizeExceptionHandlers(
bytecode.PayloadStart()));
bytecode.set_exception_handlers(handlers);
} else {
bytecode.set_pc_descriptors(Object::empty_descriptors());
bytecode.set_exception_handlers(Object::empty_exception_handlers());
}
}
RawTypedData* BytecodeMetadataHelper::NativeEntry(const Function& function,
const String& external_name) {
Zone* zone = helper_->zone_;
MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
// This list of recognized methods must be kept in sync with the list of
// methods handled specially by the NativeCall bytecode in the interpreter.
switch (kind) {
case MethodRecognizer::kObjectEquals:
case MethodRecognizer::kStringBaseLength:
case MethodRecognizer::kStringBaseIsEmpty:
case MethodRecognizer::kGrowableArrayLength:
case MethodRecognizer::kObjectArrayLength:
case MethodRecognizer::kImmutableArrayLength:
case MethodRecognizer::kTypedDataLength:
case MethodRecognizer::kClassIDgetID:
case MethodRecognizer::kGrowableArrayCapacity:
case MethodRecognizer::kListFactory:
case MethodRecognizer::kObjectArrayAllocate:
case MethodRecognizer::kLinkedHashMap_getIndex:
case MethodRecognizer::kLinkedHashMap_setIndex:
case MethodRecognizer::kLinkedHashMap_getData:
case MethodRecognizer::kLinkedHashMap_setData:
case MethodRecognizer::kLinkedHashMap_getHashMask:
case MethodRecognizer::kLinkedHashMap_setHashMask:
case MethodRecognizer::kLinkedHashMap_getUsedData:
case MethodRecognizer::kLinkedHashMap_setUsedData:
case MethodRecognizer::kLinkedHashMap_getDeletedKeys:
case MethodRecognizer::kLinkedHashMap_setDeletedKeys:
break;
default:
kind = MethodRecognizer::kUnknown;
}
NativeFunctionWrapper trampoline = NULL;
NativeFunction native_function = NULL;
intptr_t argc_tag = 0;
if (kind == MethodRecognizer::kUnknown) {
if (FLAG_link_natives_lazily) {
trampoline = &NativeEntry::BootstrapNativeCallWrapper;
native_function =
reinterpret_cast<NativeFunction>(&NativeEntry::LinkNativeCall);
} else {
const Class& cls = Class::Handle(zone, function.Owner());
const Library& library = Library::Handle(zone, cls.library());
Dart_NativeEntryResolver resolver = library.native_entry_resolver();
const bool is_bootstrap_native = Bootstrap::IsBootstrapResolver(resolver);
const int num_params =
NativeArguments::ParameterCountForResolution(function);
bool is_auto_scope = true;
native_function = NativeEntry::ResolveNative(library, external_name,
num_params, &is_auto_scope);
ASSERT(native_function != NULL); // TODO(regis): Should we throw instead?
if (is_bootstrap_native) {
trampoline = &NativeEntry::BootstrapNativeCallWrapper;
} else if (is_auto_scope) {
trampoline = &NativeEntry::AutoScopeNativeCallWrapper;
} else {
trampoline = &NativeEntry::NoScopeNativeCallWrapper;
}
}
argc_tag = NativeArguments::ComputeArgcTag(function);
}
// TODO(regis): Introduce a new VM class subclassing Object and containing
// these four untagged values.
#ifdef ARCH_IS_32_BIT
const TypedData& native_entry = TypedData::Handle(
zone, TypedData::New(kTypedDataUint32ArrayCid, 4, Heap::kOld));
native_entry.SetUint32(0 << 2, static_cast<uint32_t>(kind));
native_entry.SetUint32(1 << 2, reinterpret_cast<uint32_t>(trampoline));
native_entry.SetUint32(2 << 2, reinterpret_cast<uint32_t>(native_function));
native_entry.SetUint32(3 << 2, static_cast<uint32_t>(argc_tag));
#else
const TypedData& native_entry = TypedData::Handle(
zone, TypedData::New(kTypedDataUint64ArrayCid, 4, Heap::kOld));
native_entry.SetUint64(0 << 3, static_cast<uint64_t>(kind));
native_entry.SetUint64(1 << 3, reinterpret_cast<uint64_t>(trampoline));
native_entry.SetUint64(2 << 3, reinterpret_cast<uint64_t>(native_function));
native_entry.SetUint64(3 << 3, static_cast<uint64_t>(argc_tag));
#endif
return native_entry.raw();
}
} // namespace kernel
} // namespace dart
#endif // defined(DART_USE_INTERPRETER)
#endif // !defined(DART_PRECOMPILED_RUNTIME)

View file

@ -0,0 +1,48 @@
// 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.
#ifndef RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_READER_H_
#define RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_READER_H_
#include "vm/compiler/frontend/kernel_translation_helper.h"
#include "vm/object.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#if defined(DART_USE_INTERPRETER)
namespace dart {
namespace kernel {
// Helper class which provides access to bytecode metadata.
class BytecodeMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.bytecode"; }
explicit BytecodeMetadataHelper(KernelReaderHelper* helper,
TypeTranslator* type_translator,
ActiveClass* active_class);
void ReadMetadata(const Function& function);
private:
// Returns the index of the last read pool entry.
intptr_t ReadPoolEntries(const Function& function,
const Function& inner_function,
const ObjectPool& pool,
intptr_t from_index);
RawCode* ReadBytecode(const ObjectPool& pool);
void ReadExceptionsTable(const Code& bytecode);
RawTypedData* NativeEntry(const Function& function,
const String& external_name);
TypeTranslator& type_translator_;
ActiveClass* const active_class_;
};
} // namespace kernel
} // namespace dart
#endif // defined(DART_USE_INTERPRETER)
#endif // !defined(DART_PRECOMPILED_RUNTIME)
#endif // RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_READER_H_

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,7 @@
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/compiler/frontend/bytecode_reader.h"
#include "vm/compiler/frontend/kernel_to_il.h"
#include "vm/compiler/frontend/kernel_translation_helper.h"
#include "vm/kernel.h"
@ -16,184 +17,6 @@
namespace dart {
namespace kernel {
class TypeTranslator;
struct DirectCallMetadata {
DirectCallMetadata(const Function& target, bool check_receiver_for_null)
: target_(target), check_receiver_for_null_(check_receiver_for_null) {}
const Function& target_;
const bool check_receiver_for_null_;
};
// Helper class which provides access to direct call metadata.
class DirectCallMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.direct-call.metadata"; }
explicit DirectCallMetadataHelper(KernelReaderHelper* helper);
DirectCallMetadata GetDirectTargetForPropertyGet(intptr_t node_offset);
DirectCallMetadata GetDirectTargetForPropertySet(intptr_t node_offset);
DirectCallMetadata GetDirectTargetForMethodInvocation(intptr_t node_offset);
private:
bool ReadMetadata(intptr_t node_offset,
NameIndex* target_name,
bool* check_receiver_for_null);
};
struct InferredTypeMetadata {
InferredTypeMetadata(intptr_t cid_, bool nullable_)
: cid(cid_), nullable(nullable_) {}
const intptr_t cid;
const bool nullable;
bool IsTrivial() const { return (cid == kDynamicCid) && nullable; }
};
// Helper class which provides access to inferred type metadata.
class InferredTypeMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.inferred-type.metadata"; }
explicit InferredTypeMetadataHelper(KernelReaderHelper* helper);
InferredTypeMetadata GetInferredType(intptr_t node_offset);
};
struct ProcedureAttributesMetadata {
ProcedureAttributesMetadata(bool has_dynamic_invocations = true,
bool has_non_this_uses = true,
bool has_tearoff_uses = true)
: has_dynamic_invocations(has_dynamic_invocations),
has_non_this_uses(has_non_this_uses),
has_tearoff_uses(has_tearoff_uses) {}
bool has_dynamic_invocations;
bool has_non_this_uses;
bool has_tearoff_uses;
};
// Helper class which provides access to direct call metadata.
class ProcedureAttributesMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.procedure-attributes.metadata"; }
explicit ProcedureAttributesMetadataHelper(KernelReaderHelper* helper);
ProcedureAttributesMetadata GetProcedureAttributes(intptr_t node_offset);
private:
bool ReadMetadata(intptr_t node_offset,
ProcedureAttributesMetadata* metadata);
};
#if defined(DART_USE_INTERPRETER)
// Helper class which provides access to bytecode metadata.
class BytecodeMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.bytecode"; }
explicit BytecodeMetadataHelper(KernelReaderHelper* helper,
TypeTranslator* type_translator,
ActiveClass* active_class);
void ReadMetadata(const Function& function);
private:
// Returns the index of the last read pool entry.
intptr_t ReadPoolEntries(const Function& function,
const Function& inner_function,
const ObjectPool& pool,
intptr_t from_index);
RawCode* ReadBytecode(const ObjectPool& pool);
void ReadExceptionsTable(const Code& bytecode);
RawTypedData* NativeEntry(const Function& function,
const String& external_name);
TypeTranslator& type_translator_;
ActiveClass* const active_class_;
};
#endif // defined(DART_USE_INTERPRETER)
class TypeTranslator {
public:
TypeTranslator(KernelReaderHelper* helper,
ActiveClass* active_class,
bool finalize = false);
// Can return a malformed type.
AbstractType& BuildType();
// Can return a malformed type.
AbstractType& BuildTypeWithoutFinalization();
// Is guaranteed to be not malformed.
AbstractType& BuildVariableType();
// Will return `TypeArguments::null()` in case any of the arguments are
// malformed.
const TypeArguments& BuildTypeArguments(intptr_t length);
// Will return `TypeArguments::null()` in case any of the arguments are
// malformed.
const TypeArguments& BuildInstantiatedTypeArguments(
const Class& receiver_class,
intptr_t length);
void LoadAndSetupTypeParameters(ActiveClass* active_class,
const Object& set_on,
intptr_t type_parameter_count,
const Function& parameterized_function);
const Type& ReceiverType(const Class& klass);
private:
// Can build a malformed type.
void BuildTypeInternal(bool invalid_as_dynamic = false);
void BuildInterfaceType(bool simple);
void BuildFunctionType(bool simple);
void BuildTypeParameterType();
class TypeParameterScope {
public:
TypeParameterScope(TypeTranslator* translator, intptr_t parameter_count)
: parameter_count_(parameter_count),
outer_(translator->type_parameter_scope_),
translator_(translator) {
outer_parameter_count_ = 0;
if (outer_ != NULL) {
outer_parameter_count_ =
outer_->outer_parameter_count_ + outer_->parameter_count_;
}
translator_->type_parameter_scope_ = this;
}
~TypeParameterScope() { translator_->type_parameter_scope_ = outer_; }
TypeParameterScope* outer() const { return outer_; }
intptr_t parameter_count() const { return parameter_count_; }
intptr_t outer_parameter_count() const { return outer_parameter_count_; }
private:
intptr_t parameter_count_;
intptr_t outer_parameter_count_;
TypeParameterScope* outer_;
TypeTranslator* translator_;
};
KernelReaderHelper* helper_;
TranslationHelper& translation_helper_;
ActiveClass* const active_class_;
TypeParameterScope* type_parameter_scope_;
Zone* zone_;
AbstractType& result_;
bool finalize_;
friend class StreamingScopeBuilder;
friend class KernelLoader;
};
class StreamingScopeBuilder {
public:
explicit StreamingScopeBuilder(ParsedFunction* parsed_function);
@ -919,24 +742,6 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
friend class StreamingScopeBuilder;
};
class AlternativeScriptScope {
public:
AlternativeScriptScope(TranslationHelper* helper,
const Script& new_script,
const Script& old_script)
: helper_(helper), old_script_(old_script) {
helper_->Reset();
helper_->InitFromScript(new_script);
}
~AlternativeScriptScope() {
helper_->Reset();
helper_->InitFromScript(old_script_);
}
TranslationHelper* helper_;
const Script& old_script_;
};
// Helper class that reads a kernel Constant from binary.
class ConstantHelper {
public:

View file

@ -28,67 +28,6 @@ namespace kernel {
#define T (type_translator_)
#define I Isolate::Current()
ActiveTypeParametersScope::ActiveTypeParametersScope(ActiveClass* active_class,
const Function& innermost,
Zone* Z)
: active_class_(active_class), saved_(*active_class) {
active_class_->enclosing = &innermost;
intptr_t num_params = 0;
Function& f = Function::Handle(Z);
TypeArguments& f_params = TypeArguments::Handle(Z);
for (f = innermost.raw(); f.parent_function() != Object::null();
f = f.parent_function()) {
f_params = f.type_parameters();
num_params += f_params.Length();
}
if (num_params == 0) return;
TypeArguments& params =
TypeArguments::Handle(Z, TypeArguments::New(num_params));
intptr_t index = num_params;
for (f = innermost.raw(); f.parent_function() != Object::null();
f = f.parent_function()) {
f_params = f.type_parameters();
for (intptr_t j = f_params.Length() - 1; j >= 0; --j) {
params.SetTypeAt(--index, AbstractType::Handle(Z, f_params.TypeAt(j)));
}
}
active_class_->local_type_parameters = &params;
}
ActiveTypeParametersScope::ActiveTypeParametersScope(
ActiveClass* active_class,
const Function* function,
const TypeArguments& new_params,
Zone* Z)
: active_class_(active_class), saved_(*active_class) {
active_class_->enclosing = function;
if (new_params.IsNull()) return;
const TypeArguments* old_params = active_class->local_type_parameters;
const intptr_t old_param_count =
old_params == NULL ? 0 : old_params->Length();
const TypeArguments& extended_params = TypeArguments::Handle(
Z, TypeArguments::New(old_param_count + new_params.Length()));
intptr_t index = 0;
for (intptr_t i = 0; i < old_param_count; ++i) {
extended_params.SetTypeAt(
index++, AbstractType::ZoneHandle(Z, old_params->TypeAt(i)));
}
for (intptr_t i = 0; i < new_params.Length(); ++i) {
extended_params.SetTypeAt(
index++, AbstractType::ZoneHandle(Z, new_params.TypeAt(i)));
}
active_class_->local_type_parameters = &extended_params;
}
Fragment& Fragment::operator+=(const Fragment& other) {
if (entry == NULL) {
entry = other.entry;
@ -136,25 +75,6 @@ Fragment operator<<(const Fragment& fragment, Instruction* next) {
return result;
}
intptr_t ActiveClass::MemberTypeParameterCount(Zone* zone) {
ASSERT(member != NULL);
if (member->IsFactory()) {
TypeArguments& class_types =
TypeArguments::Handle(zone, klass->type_parameters());
return class_types.Length();
} else if (member->IsMethodExtractor()) {
Function& extracted =
Function::Handle(zone, member->extracted_method_closure());
TypeArguments& function_types =
TypeArguments::Handle(zone, extracted.type_parameters());
return function_types.Length();
} else {
TypeArguments& function_types =
TypeArguments::Handle(zone, member->type_parameters());
return function_types.Length();
}
}
FlowGraphBuilder::FlowGraphBuilder(
intptr_t kernel_offset,
ParsedFunction* parsed_function,

View file

@ -201,110 +201,6 @@ Fragment operator<<(const Fragment& fragment, Instruction* next);
typedef ZoneGrowableArray<PushArgumentInstr*>* ArgumentArray;
class ActiveClass {
public:
ActiveClass()
: klass(NULL),
member(NULL),
enclosing(NULL),
local_type_parameters(NULL) {}
bool HasMember() { return member != NULL; }
bool MemberIsProcedure() {
ASSERT(member != NULL);
RawFunction::Kind function_kind = member->kind();
return function_kind == RawFunction::kRegularFunction ||
function_kind == RawFunction::kGetterFunction ||
function_kind == RawFunction::kSetterFunction ||
function_kind == RawFunction::kMethodExtractor ||
function_kind == RawFunction::kDynamicInvocationForwarder ||
member->IsFactory();
}
bool MemberIsFactoryProcedure() {
ASSERT(member != NULL);
return member->IsFactory();
}
intptr_t MemberTypeParameterCount(Zone* zone);
intptr_t ClassNumTypeArguments() {
ASSERT(klass != NULL);
return klass->NumTypeArguments();
}
const char* ToCString() {
return member != NULL ? member->ToCString() : klass->ToCString();
}
// The current enclosing class (or the library top-level class).
const Class* klass;
const Function* member;
// The innermost enclosing function. This is used for building types, as a
// parent for function types.
const Function* enclosing;
const TypeArguments* local_type_parameters;
};
class ActiveClassScope {
public:
ActiveClassScope(ActiveClass* active_class, const Class* klass)
: active_class_(active_class), saved_(*active_class) {
active_class_->klass = klass;
}
~ActiveClassScope() { *active_class_ = saved_; }
private:
ActiveClass* active_class_;
ActiveClass saved_;
};
class ActiveMemberScope {
public:
ActiveMemberScope(ActiveClass* active_class, const Function* member)
: active_class_(active_class), saved_(*active_class) {
// The class is inherited.
active_class_->member = member;
}
~ActiveMemberScope() { *active_class_ = saved_; }
private:
ActiveClass* active_class_;
ActiveClass saved_;
};
class ActiveTypeParametersScope {
public:
// Set the local type parameters of the ActiveClass to be exactly all type
// parameters defined by 'innermost' and any enclosing *closures* (but not
// enclosing methods/top-level functions/classes).
//
// Also, the enclosing function is set to 'innermost'.
ActiveTypeParametersScope(ActiveClass* active_class,
const Function& innermost,
Zone* Z);
// Append the list of the local type parameters to the list in ActiveClass.
//
// Also, the enclosing function is set to 'function'.
ActiveTypeParametersScope(ActiveClass* active_class,
const Function* function,
const TypeArguments& new_params,
Zone* Z);
~ActiveTypeParametersScope() { *active_class_ = saved_; }
private:
ActiveClass* active_class_;
ActiveClass saved_;
};
struct FunctionScope {
intptr_t kernel_offset;
LocalScope* scope;

View file

@ -7,6 +7,7 @@
#include "vm/class_finalizer.h"
#include "vm/compiler/aot/precompiler.h"
#include "vm/log.h"
#include "vm/object_store.h"
#include "vm/symbols.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
@ -1499,6 +1500,153 @@ intptr_t MetadataHelper::GetNextMetadataPayloadOffset(intptr_t node_offset) {
}
}
DirectCallMetadataHelper::DirectCallMetadataHelper(KernelReaderHelper* helper)
: MetadataHelper(helper, tag(), /* precompiler_only = */ true) {}
bool DirectCallMetadataHelper::ReadMetadata(intptr_t node_offset,
NameIndex* target_name,
bool* check_receiver_for_null) {
intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
if (md_offset < 0) {
return false;
}
AlternativeReadingScope alt(&helper_->reader_, &H.metadata_payloads(),
md_offset);
*target_name = helper_->ReadCanonicalNameReference();
*check_receiver_for_null = helper_->ReadBool();
return true;
}
DirectCallMetadata DirectCallMetadataHelper::GetDirectTargetForPropertyGet(
intptr_t node_offset) {
NameIndex kernel_name;
bool check_receiver_for_null = false;
if (!ReadMetadata(node_offset, &kernel_name, &check_receiver_for_null)) {
return DirectCallMetadata(Function::null_function(), false);
}
if (H.IsProcedure(kernel_name) && !H.IsGetter(kernel_name)) {
// Tear-off. Use method extractor as direct call target.
const String& method_name = H.DartMethodName(kernel_name);
const Function& target_method = Function::ZoneHandle(
helper_->zone_, H.LookupMethodByMember(kernel_name, method_name));
const String& getter_name = H.DartGetterName(kernel_name);
return DirectCallMetadata(
Function::ZoneHandle(helper_->zone_,
target_method.GetMethodExtractor(getter_name)),
check_receiver_for_null);
} else {
const String& getter_name = H.DartGetterName(kernel_name);
const Function& target = Function::ZoneHandle(
helper_->zone_, H.LookupMethodByMember(kernel_name, getter_name));
ASSERT(target.IsGetterFunction() || target.IsImplicitGetterFunction());
return DirectCallMetadata(target, check_receiver_for_null);
}
}
DirectCallMetadata DirectCallMetadataHelper::GetDirectTargetForPropertySet(
intptr_t node_offset) {
NameIndex kernel_name;
bool check_receiver_for_null = false;
if (!ReadMetadata(node_offset, &kernel_name, &check_receiver_for_null)) {
return DirectCallMetadata(Function::null_function(), false);
}
const String& method_name = H.DartSetterName(kernel_name);
const Function& target = Function::ZoneHandle(
helper_->zone_, H.LookupMethodByMember(kernel_name, method_name));
ASSERT(target.IsSetterFunction() || target.IsImplicitSetterFunction());
return DirectCallMetadata(target, check_receiver_for_null);
}
DirectCallMetadata DirectCallMetadataHelper::GetDirectTargetForMethodInvocation(
intptr_t node_offset) {
NameIndex kernel_name;
bool check_receiver_for_null = false;
if (!ReadMetadata(node_offset, &kernel_name, &check_receiver_for_null)) {
return DirectCallMetadata(Function::null_function(), false);
}
const String& method_name = H.DartProcedureName(kernel_name);
const Function& target = Function::ZoneHandle(
helper_->zone_, H.LookupMethodByMember(kernel_name, method_name));
return DirectCallMetadata(target, check_receiver_for_null);
}
InferredTypeMetadataHelper::InferredTypeMetadataHelper(
KernelReaderHelper* helper)
: MetadataHelper(helper, tag(), /* precompiler_only = */ true) {}
InferredTypeMetadata InferredTypeMetadataHelper::GetInferredType(
intptr_t node_offset) {
const intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
if (md_offset < 0) {
return InferredTypeMetadata(kDynamicCid, true);
}
AlternativeReadingScope alt(&helper_->reader_, &H.metadata_payloads(),
md_offset);
const NameIndex kernel_name = helper_->ReadCanonicalNameReference();
const bool nullable = helper_->ReadBool();
if (H.IsRoot(kernel_name)) {
return InferredTypeMetadata(kDynamicCid, nullable);
}
const Class& klass =
Class::Handle(helper_->zone_, H.LookupClassByKernelClass(kernel_name));
ASSERT(!klass.IsNull());
intptr_t cid = klass.id();
if (cid == kClosureCid) {
// VM uses more specific function types and doesn't expect instances of
// _Closure class, so inferred _Closure class doesn't make sense for the VM.
cid = kDynamicCid;
}
return InferredTypeMetadata(cid, nullable);
}
ProcedureAttributesMetadataHelper::ProcedureAttributesMetadataHelper(
KernelReaderHelper* helper)
: MetadataHelper(helper, tag(), /* precompiler_only = */ true) {}
bool ProcedureAttributesMetadataHelper::ReadMetadata(
intptr_t node_offset,
ProcedureAttributesMetadata* metadata) {
intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
if (md_offset < 0) {
return false;
}
AlternativeReadingScope alt(&helper_->reader_, &H.metadata_payloads(),
md_offset);
const int kDynamicUsesBit = 1 << 0;
const int kNonThisUsesBit = 1 << 1;
const int kTearOffUsesBit = 1 << 2;
const uint8_t flags = helper_->ReadByte();
metadata->has_dynamic_invocations =
(flags & kDynamicUsesBit) == kDynamicUsesBit;
metadata->has_non_this_uses = (flags & kNonThisUsesBit) == kNonThisUsesBit;
metadata->has_tearoff_uses = (flags & kTearOffUsesBit) == kTearOffUsesBit;
return true;
}
ProcedureAttributesMetadata
ProcedureAttributesMetadataHelper::GetProcedureAttributes(
intptr_t node_offset) {
ProcedureAttributesMetadata metadata;
ReadMetadata(node_offset, &metadata);
return metadata;
}
intptr_t KernelReaderHelper::ReaderOffset() const {
return reader_.offset();
}
@ -2199,6 +2347,536 @@ TokenPosition KernelReaderHelper::ReadPosition(bool record) {
return position;
}
intptr_t ActiveClass::MemberTypeParameterCount(Zone* zone) {
ASSERT(member != NULL);
if (member->IsFactory()) {
TypeArguments& class_types =
TypeArguments::Handle(zone, klass->type_parameters());
return class_types.Length();
} else if (member->IsMethodExtractor()) {
Function& extracted =
Function::Handle(zone, member->extracted_method_closure());
TypeArguments& function_types =
TypeArguments::Handle(zone, extracted.type_parameters());
return function_types.Length();
} else {
TypeArguments& function_types =
TypeArguments::Handle(zone, member->type_parameters());
return function_types.Length();
}
}
ActiveTypeParametersScope::ActiveTypeParametersScope(ActiveClass* active_class,
const Function& innermost,
Zone* Z)
: active_class_(active_class), saved_(*active_class) {
active_class_->enclosing = &innermost;
intptr_t num_params = 0;
Function& f = Function::Handle(Z);
TypeArguments& f_params = TypeArguments::Handle(Z);
for (f = innermost.raw(); f.parent_function() != Object::null();
f = f.parent_function()) {
f_params = f.type_parameters();
num_params += f_params.Length();
}
if (num_params == 0) return;
TypeArguments& params =
TypeArguments::Handle(Z, TypeArguments::New(num_params));
intptr_t index = num_params;
for (f = innermost.raw(); f.parent_function() != Object::null();
f = f.parent_function()) {
f_params = f.type_parameters();
for (intptr_t j = f_params.Length() - 1; j >= 0; --j) {
params.SetTypeAt(--index, AbstractType::Handle(Z, f_params.TypeAt(j)));
}
}
active_class_->local_type_parameters = &params;
}
ActiveTypeParametersScope::ActiveTypeParametersScope(
ActiveClass* active_class,
const Function* function,
const TypeArguments& new_params,
Zone* Z)
: active_class_(active_class), saved_(*active_class) {
active_class_->enclosing = function;
if (new_params.IsNull()) return;
const TypeArguments* old_params = active_class->local_type_parameters;
const intptr_t old_param_count =
old_params == NULL ? 0 : old_params->Length();
const TypeArguments& extended_params = TypeArguments::Handle(
Z, TypeArguments::New(old_param_count + new_params.Length()));
intptr_t index = 0;
for (intptr_t i = 0; i < old_param_count; ++i) {
extended_params.SetTypeAt(
index++, AbstractType::ZoneHandle(Z, old_params->TypeAt(i)));
}
for (intptr_t i = 0; i < new_params.Length(); ++i) {
extended_params.SetTypeAt(
index++, AbstractType::ZoneHandle(Z, new_params.TypeAt(i)));
}
active_class_->local_type_parameters = &extended_params;
}
TypeTranslator::TypeTranslator(KernelReaderHelper* helper,
ActiveClass* active_class,
bool finalize)
: helper_(helper),
translation_helper_(helper->translation_helper_),
active_class_(active_class),
type_parameter_scope_(NULL),
zone_(translation_helper_.zone()),
result_(AbstractType::Handle(translation_helper_.zone())),
finalize_(finalize) {}
AbstractType& TypeTranslator::BuildType() {
BuildTypeInternal();
// We return a new `ZoneHandle` here on purpose: The intermediate language
// instructions do not make a copy of the handle, so we do it.
return AbstractType::ZoneHandle(Z, result_.raw());
}
AbstractType& TypeTranslator::BuildTypeWithoutFinalization() {
bool saved_finalize = finalize_;
finalize_ = false;
BuildTypeInternal();
finalize_ = saved_finalize;
// We return a new `ZoneHandle` here on purpose: The intermediate language
// instructions do not make a copy of the handle, so we do it.
return AbstractType::ZoneHandle(Z, result_.raw());
}
AbstractType& TypeTranslator::BuildVariableType() {
AbstractType& abstract_type = BuildType();
// We return a new `ZoneHandle` here on purpose: The intermediate language
// instructions do not make a copy of the handle, so we do it.
AbstractType& type = Type::ZoneHandle(Z);
if (abstract_type.IsMalformed()) {
type = AbstractType::dynamic_type().raw();
} else {
type = result_.raw();
}
return type;
}
void TypeTranslator::BuildTypeInternal(bool invalid_as_dynamic) {
Tag tag = helper_->ReadTag();
switch (tag) {
case kInvalidType:
if (invalid_as_dynamic) {
result_ = Object::dynamic_type().raw();
} else {
result_ = ClassFinalizer::NewFinalizedMalformedType(
Error::Handle(Z), // No previous error.
Script::Handle(Z, Script::null()), TokenPosition::kNoSource,
"[InvalidType] in Kernel IR.");
}
break;
case kDynamicType:
result_ = Object::dynamic_type().raw();
break;
case kVoidType:
result_ = Object::void_type().raw();
break;
case kBottomType:
result_ =
Class::Handle(Z, I->object_store()->null_class()).CanonicalType();
break;
case kInterfaceType:
BuildInterfaceType(false);
break;
case kSimpleInterfaceType:
BuildInterfaceType(true);
break;
case kFunctionType:
BuildFunctionType(false);
break;
case kSimpleFunctionType:
BuildFunctionType(true);
break;
case kTypeParameterType:
BuildTypeParameterType();
break;
default:
helper_->ReportUnexpectedTag("type", tag);
UNREACHABLE();
}
}
void TypeTranslator::BuildInterfaceType(bool simple) {
// NOTE: That an interface type like `T<A, B>` is considered to be
// malformed iff `T` is malformed.
// => We therefore ignore errors in `A` or `B`.
NameIndex klass_name =
helper_->ReadCanonicalNameReference(); // read klass_name.
intptr_t length;
if (simple) {
length = 0;
} else {
length = helper_->ReadListLength(); // read type_arguments list length.
}
const TypeArguments& type_arguments =
BuildTypeArguments(length); // read type arguments.
Object& klass = Object::Handle(Z, H.LookupClassByKernelClass(klass_name));
result_ = Type::New(klass, type_arguments, TokenPosition::kNoSource);
if (finalize_) {
ASSERT(active_class_->klass != NULL);
result_ = ClassFinalizer::FinalizeType(*active_class_->klass, result_);
}
}
void TypeTranslator::BuildFunctionType(bool simple) {
Function& signature_function = Function::ZoneHandle(
Z, Function::NewSignatureFunction(*active_class_->klass,
active_class_->enclosing != NULL
? *active_class_->enclosing
: Function::Handle(Z),
TokenPosition::kNoSource));
// Suspend finalization of types inside this one. They will be finalized after
// the whole function type is constructed.
//
// TODO(31213): Test further when nested generic function types
// are supported by fasta.
bool finalize = finalize_;
finalize_ = false;
if (!simple) {
LoadAndSetupTypeParameters(active_class_, signature_function,
helper_->ReadListLength(), signature_function);
}
ActiveTypeParametersScope scope(
active_class_, &signature_function,
TypeArguments::Handle(Z, signature_function.type_parameters()), Z);
intptr_t required_count;
intptr_t all_count;
intptr_t positional_count;
if (!simple) {
required_count = helper_->ReadUInt(); // read required parameter count.
all_count = helper_->ReadUInt(); // read total parameter count.
positional_count =
helper_->ReadListLength(); // read positional_parameters list length.
} else {
positional_count =
helper_->ReadListLength(); // read positional_parameters list length.
required_count = positional_count;
all_count = positional_count;
}
const Array& parameter_types =
Array::Handle(Z, Array::New(1 + all_count, Heap::kOld));
signature_function.set_parameter_types(parameter_types);
const Array& parameter_names =
Array::Handle(Z, Array::New(1 + all_count, Heap::kOld));
signature_function.set_parameter_names(parameter_names);
intptr_t pos = 0;
parameter_types.SetAt(pos, AbstractType::dynamic_type());
parameter_names.SetAt(pos, H.DartSymbolPlain("_receiver_"));
++pos;
for (intptr_t i = 0; i < positional_count; ++i, ++pos) {
BuildTypeInternal(); // read ith positional parameter.
if (result_.IsMalformed()) {
result_ = AbstractType::dynamic_type().raw();
}
parameter_types.SetAt(pos, result_);
parameter_names.SetAt(pos, H.DartSymbolPlain("noname"));
}
// The additional first parameter is the receiver type (set to dynamic).
signature_function.set_num_fixed_parameters(1 + required_count);
signature_function.SetNumOptionalParameters(
all_count - required_count, positional_count > required_count);
if (!simple) {
const intptr_t named_count =
helper_->ReadListLength(); // read named_parameters list length.
for (intptr_t i = 0; i < named_count; ++i, ++pos) {
// read string reference (i.e. named_parameters[i].name).
String& name = H.DartSymbolObfuscate(helper_->ReadStringReference());
BuildTypeInternal(); // read named_parameters[i].type.
if (result_.IsMalformed()) {
result_ = AbstractType::dynamic_type().raw();
}
parameter_types.SetAt(pos, result_);
parameter_names.SetAt(pos, name);
}
}
helper_->SkipListOfStrings(); // read positional parameter names.
if (!simple) {
helper_->SkipCanonicalNameReference(); // read typedef reference.
}
BuildTypeInternal(); // read return type.
if (result_.IsMalformed()) {
result_ = AbstractType::dynamic_type().raw();
}
signature_function.set_result_type(result_);
finalize_ = finalize;
Type& signature_type =
Type::ZoneHandle(Z, signature_function.SignatureType());
if (finalize_) {
signature_type ^=
ClassFinalizer::FinalizeType(*active_class_->klass, signature_type);
// Do not refer to signature_function anymore, since it may have been
// replaced during canonicalization.
signature_function = Function::null();
}
result_ = signature_type.raw();
}
void TypeTranslator::BuildTypeParameterType() {
intptr_t parameter_index = helper_->ReadUInt(); // read parameter index.
helper_->SkipOptionalDartType(); // read bound.
const TypeArguments& class_types =
TypeArguments::Handle(Z, active_class_->klass->type_parameters());
if (parameter_index < class_types.Length()) {
// The index of the type parameter in [parameters] is
// the same index into the `klass->type_parameters()` array.
result_ ^= class_types.TypeAt(parameter_index);
return;
}
parameter_index -= class_types.Length();
if (active_class_->HasMember()) {
if (active_class_->MemberIsFactoryProcedure()) {
//
// WARNING: This is a little hackish:
//
// We have a static factory constructor. The kernel IR gives the factory
// constructor function its own type parameters (which are equal in name
// and number to the ones of the enclosing class). I.e.,
//
// class A<T> {
// factory A.x() { return new B<T>(); }
// }
//
// is basically translated to this:
//
// class A<T> {
// static A.x<T'>() { return new B<T'>(); }
// }
//
if (class_types.Length() > parameter_index) {
result_ ^= class_types.TypeAt(parameter_index);
return;
}
parameter_index -= class_types.Length();
}
intptr_t procedure_type_parameter_count =
active_class_->MemberIsProcedure()
? active_class_->MemberTypeParameterCount(Z)
: 0;
if (procedure_type_parameter_count > 0) {
if (procedure_type_parameter_count > parameter_index) {
if (I->reify_generic_functions()) {
result_ ^=
TypeArguments::Handle(Z, active_class_->member->type_parameters())
.TypeAt(parameter_index);
} else {
result_ ^= Type::DynamicType();
}
return;
}
parameter_index -= procedure_type_parameter_count;
}
}
if (active_class_->local_type_parameters != NULL) {
if (parameter_index < active_class_->local_type_parameters->Length()) {
if (I->reify_generic_functions()) {
result_ ^=
active_class_->local_type_parameters->TypeAt(parameter_index);
} else {
result_ ^= Type::DynamicType();
}
return;
}
parameter_index -= active_class_->local_type_parameters->Length();
}
if (type_parameter_scope_ != NULL &&
parameter_index < type_parameter_scope_->outer_parameter_count() +
type_parameter_scope_->parameter_count()) {
result_ ^= Type::DynamicType();
return;
}
H.ReportError(
helper_->script(), TokenPosition::kNoSource,
"Unbound type parameter found in %s. Please report this at dartbug.com.",
active_class_->ToCString());
}
const TypeArguments& TypeTranslator::BuildTypeArguments(intptr_t length) {
bool only_dynamic = true;
intptr_t offset = helper_->ReaderOffset();
for (intptr_t i = 0; i < length; ++i) {
if (helper_->ReadTag() != kDynamicType) { // Read the ith types tag.
only_dynamic = false;
helper_->SetOffset(offset);
break;
}
}
TypeArguments& type_arguments = TypeArguments::ZoneHandle(Z);
if (!only_dynamic) {
type_arguments = TypeArguments::New(length);
for (intptr_t i = 0; i < length; ++i) {
BuildTypeInternal(true); // read ith type.
type_arguments.SetTypeAt(i, result_);
}
if (finalize_) {
type_arguments = type_arguments.Canonicalize();
}
}
return type_arguments;
}
const TypeArguments& TypeTranslator::BuildInstantiatedTypeArguments(
const Class& receiver_class,
intptr_t length) {
const TypeArguments& type_arguments = BuildTypeArguments(length);
// If type_arguments is null all arguments are dynamic.
// If, however, this class doesn't specify all the type arguments directly we
// still need to finalize the type below in order to get any non-dynamic types
// from any super. See http://www.dartbug.com/29537.
if (type_arguments.IsNull() && receiver_class.NumTypeArguments() == length) {
return type_arguments;
}
// We make a temporary [Type] object and use `ClassFinalizer::FinalizeType` to
// finalize the argument types.
// (This can for example make the [type_arguments] vector larger)
Type& type = Type::Handle(
Z, Type::New(receiver_class, type_arguments, TokenPosition::kNoSource));
if (finalize_) {
type ^= ClassFinalizer::FinalizeType(*active_class_->klass, type);
}
const TypeArguments& instantiated_type_arguments =
TypeArguments::ZoneHandle(Z, type.arguments());
return instantiated_type_arguments;
}
void TypeTranslator::LoadAndSetupTypeParameters(
ActiveClass* active_class,
const Object& set_on,
intptr_t type_parameter_count,
const Function& parameterized_function) {
ASSERT(type_parameter_count >= 0);
if (type_parameter_count == 0) {
return;
}
ASSERT(set_on.IsClass() || set_on.IsFunction());
bool set_on_class = set_on.IsClass();
ASSERT(set_on_class == parameterized_function.IsNull());
// First setup the type parameters, so if any of the following code uses it
// (in a recursive way) we're fine.
TypeArguments& type_parameters = TypeArguments::Handle(Z);
TypeParameter& parameter = TypeParameter::Handle(Z);
const Type& null_bound = Type::Handle(Z);
// Step a) Create array of [TypeParameter] objects (without bound).
type_parameters = TypeArguments::New(type_parameter_count);
const Library& lib = Library::Handle(Z, active_class->klass->library());
{
AlternativeReadingScope alt(&helper_->reader_);
for (intptr_t i = 0; i < type_parameter_count; i++) {
TypeParameterHelper helper(helper_);
helper.Finish();
parameter = TypeParameter::New(
set_on_class ? *active_class->klass : Class::Handle(Z),
parameterized_function, i,
H.DartIdentifier(lib, helper.name_index_), // read ith name index.
null_bound, TokenPosition::kNoSource);
type_parameters.SetTypeAt(i, parameter);
}
}
if (set_on.IsClass()) {
Class::Cast(set_on).set_type_parameters(type_parameters);
} else {
Function::Cast(set_on).set_type_parameters(type_parameters);
}
const Function* enclosing = NULL;
if (!parameterized_function.IsNull()) {
enclosing = &parameterized_function;
}
ActiveTypeParametersScope scope(active_class, enclosing, type_parameters, Z);
// Step b) Fill in the bounds of all [TypeParameter]s.
for (intptr_t i = 0; i < type_parameter_count; i++) {
TypeParameterHelper helper(helper_);
helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
// TODO(github.com/dart-lang/kernel/issues/42): This should be handled
// by the frontend.
parameter ^= type_parameters.TypeAt(i);
const Tag tag = helper_->PeekTag(); // peek ith bound type.
if (tag == kDynamicType) {
helper_->SkipDartType(); // read ith bound.
parameter.set_bound(Type::Handle(Z, I->object_store()->object_type()));
} else {
AbstractType& bound = BuildTypeWithoutFinalization(); // read ith bound.
if (bound.IsMalformedOrMalbounded()) {
bound = I->object_store()->object_type();
}
parameter.set_bound(bound);
}
helper.Finish();
}
}
const Type& TypeTranslator::ReceiverType(const Class& klass) {
ASSERT(!klass.IsNull());
ASSERT(!klass.IsTypedefClass());
// Note that if klass is _Closure, the returned type will be _Closure,
// and not the signature type.
Type& type = Type::ZoneHandle(Z, klass.CanonicalType());
if (!type.IsNull()) {
return type;
}
type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()),
klass.token_pos());
if (klass.is_type_finalized()) {
type ^= ClassFinalizer::FinalizeType(klass, type);
klass.SetCanonicalType(type);
}
return type;
}
} // namespace kernel
} // namespace dart

View file

@ -778,6 +778,77 @@ class MetadataHelper {
intptr_t last_mapping_index_;
};
struct DirectCallMetadata {
DirectCallMetadata(const Function& target, bool check_receiver_for_null)
: target_(target), check_receiver_for_null_(check_receiver_for_null) {}
const Function& target_;
const bool check_receiver_for_null_;
};
// Helper class which provides access to direct call metadata.
class DirectCallMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.direct-call.metadata"; }
explicit DirectCallMetadataHelper(KernelReaderHelper* helper);
DirectCallMetadata GetDirectTargetForPropertyGet(intptr_t node_offset);
DirectCallMetadata GetDirectTargetForPropertySet(intptr_t node_offset);
DirectCallMetadata GetDirectTargetForMethodInvocation(intptr_t node_offset);
private:
bool ReadMetadata(intptr_t node_offset,
NameIndex* target_name,
bool* check_receiver_for_null);
};
struct InferredTypeMetadata {
InferredTypeMetadata(intptr_t cid_, bool nullable_)
: cid(cid_), nullable(nullable_) {}
const intptr_t cid;
const bool nullable;
bool IsTrivial() const { return (cid == kDynamicCid) && nullable; }
};
// Helper class which provides access to inferred type metadata.
class InferredTypeMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.inferred-type.metadata"; }
explicit InferredTypeMetadataHelper(KernelReaderHelper* helper);
InferredTypeMetadata GetInferredType(intptr_t node_offset);
};
struct ProcedureAttributesMetadata {
ProcedureAttributesMetadata(bool has_dynamic_invocations = true,
bool has_non_this_uses = true,
bool has_tearoff_uses = true)
: has_dynamic_invocations(has_dynamic_invocations),
has_non_this_uses(has_non_this_uses),
has_tearoff_uses(has_tearoff_uses) {}
bool has_dynamic_invocations;
bool has_non_this_uses;
bool has_tearoff_uses;
};
// Helper class which provides access to direct call metadata.
class ProcedureAttributesMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.procedure-attributes.metadata"; }
explicit ProcedureAttributesMetadataHelper(KernelReaderHelper* helper);
ProcedureAttributesMetadata GetProcedureAttributes(intptr_t node_offset);
private:
bool ReadMetadata(intptr_t node_offset,
ProcedureAttributesMetadata* metadata);
};
class KernelReaderHelper {
public:
KernelReaderHelper(Zone* zone,
@ -910,6 +981,185 @@ class KernelReaderHelper {
#endif // defined(DART_USE_INTERPRETER)
};
class ActiveClass {
public:
ActiveClass()
: klass(NULL),
member(NULL),
enclosing(NULL),
local_type_parameters(NULL) {}
bool HasMember() { return member != NULL; }
bool MemberIsProcedure() {
ASSERT(member != NULL);
RawFunction::Kind function_kind = member->kind();
return function_kind == RawFunction::kRegularFunction ||
function_kind == RawFunction::kGetterFunction ||
function_kind == RawFunction::kSetterFunction ||
function_kind == RawFunction::kMethodExtractor ||
function_kind == RawFunction::kDynamicInvocationForwarder ||
member->IsFactory();
}
bool MemberIsFactoryProcedure() {
ASSERT(member != NULL);
return member->IsFactory();
}
intptr_t MemberTypeParameterCount(Zone* zone);
intptr_t ClassNumTypeArguments() {
ASSERT(klass != NULL);
return klass->NumTypeArguments();
}
const char* ToCString() {
return member != NULL ? member->ToCString() : klass->ToCString();
}
// The current enclosing class (or the library top-level class).
const Class* klass;
const Function* member;
// The innermost enclosing function. This is used for building types, as a
// parent for function types.
const Function* enclosing;
const TypeArguments* local_type_parameters;
};
class ActiveClassScope {
public:
ActiveClassScope(ActiveClass* active_class, const Class* klass)
: active_class_(active_class), saved_(*active_class) {
active_class_->klass = klass;
}
~ActiveClassScope() { *active_class_ = saved_; }
private:
ActiveClass* active_class_;
ActiveClass saved_;
};
class ActiveMemberScope {
public:
ActiveMemberScope(ActiveClass* active_class, const Function* member)
: active_class_(active_class), saved_(*active_class) {
// The class is inherited.
active_class_->member = member;
}
~ActiveMemberScope() { *active_class_ = saved_; }
private:
ActiveClass* active_class_;
ActiveClass saved_;
};
class ActiveTypeParametersScope {
public:
// Set the local type parameters of the ActiveClass to be exactly all type
// parameters defined by 'innermost' and any enclosing *closures* (but not
// enclosing methods/top-level functions/classes).
//
// Also, the enclosing function is set to 'innermost'.
ActiveTypeParametersScope(ActiveClass* active_class,
const Function& innermost,
Zone* Z);
// Append the list of the local type parameters to the list in ActiveClass.
//
// Also, the enclosing function is set to 'function'.
ActiveTypeParametersScope(ActiveClass* active_class,
const Function* function,
const TypeArguments& new_params,
Zone* Z);
~ActiveTypeParametersScope() { *active_class_ = saved_; }
private:
ActiveClass* active_class_;
ActiveClass saved_;
};
class TypeTranslator {
public:
TypeTranslator(KernelReaderHelper* helper,
ActiveClass* active_class,
bool finalize = false);
// Can return a malformed type.
AbstractType& BuildType();
// Can return a malformed type.
AbstractType& BuildTypeWithoutFinalization();
// Is guaranteed to be not malformed.
AbstractType& BuildVariableType();
// Will return `TypeArguments::null()` in case any of the arguments are
// malformed.
const TypeArguments& BuildTypeArguments(intptr_t length);
// Will return `TypeArguments::null()` in case any of the arguments are
// malformed.
const TypeArguments& BuildInstantiatedTypeArguments(
const Class& receiver_class,
intptr_t length);
void LoadAndSetupTypeParameters(ActiveClass* active_class,
const Object& set_on,
intptr_t type_parameter_count,
const Function& parameterized_function);
const Type& ReceiverType(const Class& klass);
private:
// Can build a malformed type.
void BuildTypeInternal(bool invalid_as_dynamic = false);
void BuildInterfaceType(bool simple);
void BuildFunctionType(bool simple);
void BuildTypeParameterType();
class TypeParameterScope {
public:
TypeParameterScope(TypeTranslator* translator, intptr_t parameter_count)
: parameter_count_(parameter_count),
outer_(translator->type_parameter_scope_),
translator_(translator) {
outer_parameter_count_ = 0;
if (outer_ != NULL) {
outer_parameter_count_ =
outer_->outer_parameter_count_ + outer_->parameter_count_;
}
translator_->type_parameter_scope_ = this;
}
~TypeParameterScope() { translator_->type_parameter_scope_ = outer_; }
TypeParameterScope* outer() const { return outer_; }
intptr_t parameter_count() const { return parameter_count_; }
intptr_t outer_parameter_count() const { return outer_parameter_count_; }
private:
intptr_t parameter_count_;
intptr_t outer_parameter_count_;
TypeParameterScope* outer_;
TypeTranslator* translator_;
};
KernelReaderHelper* helper_;
TranslationHelper& translation_helper_;
ActiveClass* const active_class_;
TypeParameterScope* type_parameter_scope_;
Zone* zone_;
AbstractType& result_;
bool finalize_;
friend class StreamingScopeBuilder;
friend class KernelLoader;
};
} // namespace kernel
} // namespace dart

View file

@ -13540,7 +13540,7 @@ void ICData::set_ic_data_array(const Array& value) const {
}
#if defined(TAG_IC_DATA)
void ICData::set_tag(intptr_t value) const {
void ICData::set_tag(Tag value) const {
StoreNonPointer(&raw_ptr()->tag_, value);
}
#endif
@ -14427,7 +14427,7 @@ RawICData* ICData::NewDescriptor(Zone* zone,
NOT_IN_PRECOMPILED(result.set_deopt_id(deopt_id));
result.set_state_bits(0);
#if defined(TAG_IC_DATA)
result.set_tag(-1);
result.set_tag(ICData::Tag::kUnknown);
#endif
result.set_rebind_rule(rebind_rule);
result.SetNumArgsTested(num_args_tested);
@ -14451,7 +14451,7 @@ RawICData* ICData::New() {
result.set_deopt_id(Thread::kNoDeoptId);
result.set_state_bits(0);
#if defined(TAG_IC_DATA)
result.set_tag(-1);
result.set_tag(ICData::Tag::kUnknown);
#endif
return result.raw();
}

View file

@ -2004,8 +2004,9 @@ class ICData : public Object {
enum { kCachedICDataArrayCount = 4 };
#if defined(TAG_IC_DATA)
void set_tag(intptr_t value) const;
intptr_t tag() const { return raw_ptr()->tag_; }
using Tag = RawICData::Tag;
void set_tag(Tag value) const;
Tag tag() const { return raw_ptr()->tag_; }
#endif
bool is_static_call() const;

View file

@ -1663,8 +1663,10 @@ class RawICData : public RawObject {
NOT_IN_PRECOMPILED(int32_t deopt_id_);
uint32_t state_bits_; // Number of arguments tested in IC, deopt reasons.
#if defined(TAG_IC_DATA)
intptr_t tag_; // Debugging, verifying that the icdata is assigned to the
// same instruction again. Store -1 or Instruction::Tag.
enum class Tag : intptr_t{kUnknown, kInstanceCall, kStaticCall};
Tag tag_; // Debugging, verifying that the icdata is assigned to the
// same instruction again.
#endif
};

View file

@ -1639,7 +1639,7 @@ RawICData* ICData::ReadFrom(SnapshotReader* reader,
NOT_IN_PRECOMPILED(result.set_deopt_id(reader->Read<int32_t>()));
result.set_state_bits(reader->Read<uint32_t>());
#if defined(TAG_IC_DATA)
result.set_tag(reader->Read<int16_t>());
result.set_tag(static_cast<ICData::Tag>(reader->Read<int16_t>()));
#endif
// Set all the object fields.
@ -1666,7 +1666,7 @@ void RawICData::WriteTo(SnapshotWriter* writer,
NOT_IN_PRECOMPILED(writer->Write<int32_t>(ptr()->deopt_id_));
writer->Write<uint32_t>(ptr()->state_bits_);
#if defined(TAG_IC_DATA)
writer->Write<int16_t>(ptr()->tag_);
writer->Write<int16_t>(static_cast<int64_t>(ptr()->tag_));
#endif
// Write out all the object pointer fields.