[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>
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index de660dd..c688a31 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -2444,7 +2444,7 @@
}
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 @@
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
}
}
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 5b941df..d180a24 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -1649,7 +1649,7 @@
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 @@
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;
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index b1ed153..0dd7ed5 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -320,9 +320,20 @@
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");
}
}
diff --git a/runtime/vm/compiler/compiler_sources.gni b/runtime/vm/compiler/compiler_sources.gni
index 09118db..5f6b3f9 100644
--- a/runtime/vm/compiler/compiler_sources.gni
+++ b/runtime/vm/compiler/compiler_sources.gni
@@ -75,6 +75,8 @@
"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",
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
new file mode 100644
index 0000000..b3ed8a3
--- /dev/null
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -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)
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.h b/runtime/vm/compiler/frontend/bytecode_reader.h
new file mode 100644
index 0000000..e32cf14
--- /dev/null
+++ b/runtime/vm/compiler/frontend/bytecode_reader.h
@@ -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_
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 3a8f5cb..037f497 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -4,10 +4,8 @@
#include "vm/compiler/frontend/kernel_binary_flowgraph.h"
-#include "vm/bootstrap.h"
-#include "vm/code_descriptors.h"
#include "vm/compiler/aot/precompiler.h"
-#include "vm/compiler/assembler/disassembler_kbc.h"
+#include "vm/compiler/frontend/bytecode_reader.h"
#include "vm/compiler/frontend/prologue_builder.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/dart_entry.h"
@@ -19,11 +17,6 @@
#if !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
-
-#if defined(DART_USE_INTERPRETER)
-DEFINE_FLAG(bool, dump_kernel_bytecode, false, "Dump kernel bytecode");
-#endif // defined(DART_USE_INTERPRETER)
-
namespace kernel {
#define Z (zone_)
@@ -63,738 +56,6 @@
return !FLAG_precompiled_mode || !attrs.has_dynamic_invocations;
}
-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);
-}
-
-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;
-}
-
-ProcedureAttributesMetadataHelper::ProcedureAttributesMetadataHelper(
- KernelReaderHelper* helper)
- : MetadataHelper(helper, tag(), /* precompiler_only = */ true) {}
-
-ProcedureAttributesMetadata
-ProcedureAttributesMetadataHelper::GetProcedureAttributes(
- intptr_t node_offset) {
- ProcedureAttributesMetadata metadata;
- ReadMetadata(node_offset, &metadata);
- return metadata;
-}
-
-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);
-}
-
-#if defined(DART_USE_INTERPRETER)
-
-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(Instruction::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(Instruction::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();
-}
-#endif // defined(DART_USE_INTERPRETER)
-
StreamingScopeBuilder::StreamingScopeBuilder(ParsedFunction* parsed_function)
: result_(NULL),
parsed_function_(parsed_function),
@@ -2428,456 +1689,6 @@
}
}
-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 = ¶meterized_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;
-}
-
StreamingConstantEvaluator::StreamingConstantEvaluator(
StreamingFlowGraphBuilder* builder)
: builder_(builder),
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index 35f905c..82600d0 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -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 @@
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:
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 38bfda8..83d8666 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -28,67 +28,6 @@
#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 = ¶ms;
-}
-
-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 @@
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,
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index a305b30..26defcf 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -201,110 +201,6 @@
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;
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 2c963ac..59b1acc 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -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 @@
}
}
+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 @@
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 = ¶ms;
+}
+
+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 = ¶meterized_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
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 75d4566..6964154 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -778,6 +778,77 @@
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 @@
#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
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 2440091..65fd953 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -13540,7 +13540,7 @@
}
#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 @@
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 @@
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();
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index ba4f605..17cc0f4 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2004,8 +2004,9 @@
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;
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 5d7a7f0..88bd409 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1663,8 +1663,10 @@
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
};
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 435e697..2609707 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1639,7 +1639,7 @@
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 @@
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.