fdc765faad
TEST=existing Change-Id: I0a8fdf09f742b55357411f12dc6164d4050bb83c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/196283 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
3664 lines
125 KiB
C++
3664 lines
125 KiB
C++
// 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/kernel_translation_helper.h"
|
|
|
|
#include "vm/class_finalizer.h"
|
|
#include "vm/compiler/aot/precompiler.h"
|
|
#include "vm/compiler/backend/flow_graph_compiler.h"
|
|
#include "vm/compiler/frontend/constant_reader.h"
|
|
#include "vm/flags.h"
|
|
#include "vm/log.h"
|
|
#include "vm/object_store.h"
|
|
#include "vm/parser.h" // for ParsedFunction
|
|
#include "vm/symbols.h"
|
|
|
|
#define Z (zone_)
|
|
#define H (translation_helper_)
|
|
#define T (type_translator_)
|
|
#define I Isolate::Current()
|
|
#define IG IsolateGroup::Current()
|
|
|
|
namespace dart {
|
|
namespace kernel {
|
|
|
|
TranslationHelper::TranslationHelper(Thread* thread)
|
|
: thread_(thread),
|
|
zone_(thread->zone()),
|
|
isolate_(thread->isolate()),
|
|
allocation_space_(Heap::kNew),
|
|
string_offsets_(TypedData::Handle(Z)),
|
|
string_data_(ExternalTypedData::Handle(Z)),
|
|
canonical_names_(TypedData::Handle(Z)),
|
|
metadata_payloads_(ExternalTypedData::Handle(Z)),
|
|
metadata_mappings_(ExternalTypedData::Handle(Z)),
|
|
constants_(Array::Handle(Z)),
|
|
constants_table_(ExternalTypedData::Handle(Z)),
|
|
info_(KernelProgramInfo::Handle(Z)),
|
|
name_index_handle_(Smi::Handle(Z)) {}
|
|
|
|
TranslationHelper::TranslationHelper(Thread* thread, Heap::Space space)
|
|
: thread_(thread),
|
|
zone_(thread->zone()),
|
|
isolate_(thread->isolate()),
|
|
allocation_space_(space),
|
|
string_offsets_(TypedData::Handle(Z)),
|
|
string_data_(ExternalTypedData::Handle(Z)),
|
|
canonical_names_(TypedData::Handle(Z)),
|
|
metadata_payloads_(ExternalTypedData::Handle(Z)),
|
|
metadata_mappings_(ExternalTypedData::Handle(Z)),
|
|
constants_(Array::Handle(Z)),
|
|
constants_table_(ExternalTypedData::Handle(Z)),
|
|
info_(KernelProgramInfo::Handle(Z)),
|
|
name_index_handle_(Smi::Handle(Z)) {}
|
|
|
|
void TranslationHelper::Reset() {
|
|
string_offsets_ = TypedData::null();
|
|
string_data_ = ExternalTypedData::null();
|
|
canonical_names_ = TypedData::null();
|
|
metadata_payloads_ = ExternalTypedData::null();
|
|
metadata_mappings_ = ExternalTypedData::null();
|
|
constants_ = Array::null();
|
|
}
|
|
|
|
void TranslationHelper::InitFromScript(const Script& script) {
|
|
const KernelProgramInfo& info =
|
|
KernelProgramInfo::Handle(Z, script.kernel_program_info());
|
|
if (info.IsNull()) {
|
|
// If there is no kernel data associated with the script, then
|
|
// do not bother initializing!.
|
|
// This can happen with few special functions like
|
|
// NoSuchMethodDispatcher and InvokeFieldDispatcher.
|
|
return;
|
|
}
|
|
InitFromKernelProgramInfo(info);
|
|
}
|
|
|
|
void TranslationHelper::InitFromKernelProgramInfo(
|
|
const KernelProgramInfo& info) {
|
|
SetStringOffsets(TypedData::Handle(Z, info.string_offsets()));
|
|
SetStringData(ExternalTypedData::Handle(Z, info.string_data()));
|
|
SetCanonicalNames(TypedData::Handle(Z, info.canonical_names()));
|
|
SetMetadataPayloads(ExternalTypedData::Handle(Z, info.metadata_payloads()));
|
|
SetMetadataMappings(ExternalTypedData::Handle(Z, info.metadata_mappings()));
|
|
SetConstants(Array::Handle(Z, info.constants()));
|
|
SetConstantsTable(ExternalTypedData::Handle(Z, info.constants_table()));
|
|
SetKernelProgramInfo(info);
|
|
}
|
|
|
|
GrowableObjectArrayPtr TranslationHelper::EnsurePotentialPragmaFunctions() {
|
|
auto& funcs =
|
|
GrowableObjectArray::Handle(Z, info_.potential_pragma_functions());
|
|
if (funcs.IsNull()) {
|
|
funcs = GrowableObjectArray::New(16, Heap::kNew);
|
|
info_.set_potential_pragma_functions(funcs);
|
|
}
|
|
return funcs.ptr();
|
|
}
|
|
|
|
void TranslationHelper::AddPotentialExtensionLibrary(const Library& library) {
|
|
if (potential_extension_libraries_ == nullptr) {
|
|
potential_extension_libraries_ =
|
|
&GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
|
|
}
|
|
potential_extension_libraries_->Add(library);
|
|
}
|
|
|
|
GrowableObjectArrayPtr TranslationHelper::GetPotentialExtensionLibraries() {
|
|
if (potential_extension_libraries_ != nullptr) {
|
|
GrowableObjectArray* result = potential_extension_libraries_;
|
|
potential_extension_libraries_ = nullptr;
|
|
return result->ptr();
|
|
}
|
|
return GrowableObjectArray::null();
|
|
}
|
|
|
|
void TranslationHelper::SetStringOffsets(const TypedData& string_offsets) {
|
|
ASSERT(string_offsets_.IsNull());
|
|
string_offsets_ = string_offsets.ptr();
|
|
}
|
|
|
|
void TranslationHelper::SetStringData(const ExternalTypedData& string_data) {
|
|
ASSERT(string_data_.IsNull());
|
|
string_data_ = string_data.ptr();
|
|
}
|
|
|
|
void TranslationHelper::SetCanonicalNames(const TypedData& canonical_names) {
|
|
ASSERT(canonical_names_.IsNull());
|
|
canonical_names_ = canonical_names.ptr();
|
|
}
|
|
|
|
void TranslationHelper::SetMetadataPayloads(
|
|
const ExternalTypedData& metadata_payloads) {
|
|
ASSERT(metadata_payloads_.IsNull());
|
|
ASSERT(Utils::IsAligned(metadata_payloads.DataAddr(0), kWordSize));
|
|
metadata_payloads_ = metadata_payloads.ptr();
|
|
}
|
|
|
|
void TranslationHelper::SetMetadataMappings(
|
|
const ExternalTypedData& metadata_mappings) {
|
|
ASSERT(metadata_mappings_.IsNull());
|
|
metadata_mappings_ = metadata_mappings.ptr();
|
|
}
|
|
|
|
void TranslationHelper::SetConstants(const Array& constants) {
|
|
ASSERT(constants_.IsNull() ||
|
|
(constants.IsNull() || constants.Length() == 0));
|
|
constants_ = constants.ptr();
|
|
}
|
|
|
|
void TranslationHelper::SetConstantsTable(
|
|
const ExternalTypedData& constants_table) {
|
|
ASSERT(constants_table_.IsNull());
|
|
constants_table_ = constants_table.ptr();
|
|
}
|
|
|
|
void TranslationHelper::SetKernelProgramInfo(const KernelProgramInfo& info) {
|
|
info_ = info.ptr();
|
|
}
|
|
|
|
intptr_t TranslationHelper::StringOffset(StringIndex index) const {
|
|
return string_offsets_.GetUint32(index << 2);
|
|
}
|
|
|
|
intptr_t TranslationHelper::StringSize(StringIndex index) const {
|
|
return StringOffset(StringIndex(index + 1)) - StringOffset(index);
|
|
}
|
|
|
|
uint8_t TranslationHelper::CharacterAt(StringIndex string_index,
|
|
intptr_t index) {
|
|
ASSERT(index < StringSize(string_index));
|
|
return string_data_.GetUint8(StringOffset(string_index) + index);
|
|
}
|
|
|
|
uint8_t* TranslationHelper::StringBuffer(StringIndex string_index) const {
|
|
// Though this implementation appears like it could be replaced by
|
|
// string_data_.DataAddr(StringOffset(string_index)), it can't quite. If the
|
|
// last string in the string table is a zero length string, then the latter
|
|
// expression will try to return the address that is one past the backing
|
|
// store of the string_data_ table. Though this is safe in C++ as long as the
|
|
// address is not dereferenced, it will trigger the assert in
|
|
// ExternalTypedData::DataAddr.
|
|
ASSERT(Thread::Current()->no_safepoint_scope_depth() > 0);
|
|
return reinterpret_cast<uint8_t*>(string_data_.DataAddr(0)) +
|
|
StringOffset(string_index);
|
|
}
|
|
|
|
bool TranslationHelper::StringEquals(StringIndex string_index,
|
|
const char* other) {
|
|
intptr_t length = strlen(other);
|
|
if (length != StringSize(string_index)) return false;
|
|
|
|
NoSafepointScope no_safepoint;
|
|
return memcmp(StringBuffer(string_index), other, length) == 0;
|
|
}
|
|
|
|
NameIndex TranslationHelper::CanonicalNameParent(NameIndex name) {
|
|
// Canonical names are pairs of 4-byte parent and string indexes, so the size
|
|
// of an entry is 8 bytes. The parent is biased: 0 represents the root name
|
|
// and N+1 represents the name with index N.
|
|
return NameIndex(static_cast<intptr_t>(canonical_names_.GetUint32(8 * name)) -
|
|
1);
|
|
}
|
|
|
|
StringIndex TranslationHelper::CanonicalNameString(NameIndex name) {
|
|
return StringIndex(canonical_names_.GetUint32((8 * name) + 4));
|
|
}
|
|
|
|
bool TranslationHelper::IsAdministrative(NameIndex name) {
|
|
// Administrative names start with '@'.
|
|
StringIndex name_string = CanonicalNameString(name);
|
|
return (StringSize(name_string) > 0) && (CharacterAt(name_string, 0) == '@');
|
|
}
|
|
|
|
bool TranslationHelper::IsPrivate(NameIndex name) {
|
|
// Private names start with '_'.
|
|
StringIndex name_string = CanonicalNameString(name);
|
|
return (StringSize(name_string) > 0) && (CharacterAt(name_string, 0) == '_');
|
|
}
|
|
|
|
bool TranslationHelper::IsRoot(NameIndex name) {
|
|
return name == -1;
|
|
}
|
|
|
|
bool TranslationHelper::IsLibrary(NameIndex name) {
|
|
// Libraries are the only canonical names with the root as their parent.
|
|
return !IsRoot(name) && IsRoot(CanonicalNameParent(name));
|
|
}
|
|
|
|
bool TranslationHelper::IsClass(NameIndex name) {
|
|
// Classes have the library as their parent and are not an administrative
|
|
// name starting with @.
|
|
return !IsAdministrative(name) && !IsRoot(name) &&
|
|
IsLibrary(CanonicalNameParent(name));
|
|
}
|
|
|
|
bool TranslationHelper::IsMember(NameIndex name) {
|
|
return IsConstructor(name) || IsProcedure(name);
|
|
}
|
|
|
|
bool TranslationHelper::IsConstructor(NameIndex name) {
|
|
// Constructors with private names have the import URI of the library where
|
|
// they are visible as the parent and the string "@constructors" as the
|
|
// parent's parent. Constructors with non-private names have the string
|
|
// "@constructors" as the parent.
|
|
if (IsRoot(name)) {
|
|
return false;
|
|
}
|
|
NameIndex kind = CanonicalNameParent(name);
|
|
if (IsPrivate(name)) {
|
|
kind = CanonicalNameParent(kind);
|
|
}
|
|
return StringEquals(CanonicalNameString(kind), "@constructors");
|
|
}
|
|
|
|
bool TranslationHelper::IsProcedure(NameIndex name) {
|
|
return IsMethod(name) || IsGetter(name) || IsSetter(name) || IsFactory(name);
|
|
}
|
|
|
|
bool TranslationHelper::IsMethod(NameIndex name) {
|
|
// Methods with private names have the import URI of the library where they
|
|
// are visible as the parent and the string "@methods" as the parent's parent.
|
|
// Methods with non-private names have the string "@methods" as the parent.
|
|
if (IsRoot(name)) {
|
|
return false;
|
|
}
|
|
NameIndex kind = CanonicalNameParent(name);
|
|
if (IsPrivate(name)) {
|
|
kind = CanonicalNameParent(kind);
|
|
}
|
|
return StringEquals(CanonicalNameString(kind), "@methods");
|
|
}
|
|
|
|
bool TranslationHelper::IsGetter(NameIndex name) {
|
|
// Getters with private names have the import URI of the library where they
|
|
// are visible as the parent and the string "@getters" as the parent's parent.
|
|
// Getters with non-private names have the string "@getters" as the parent.
|
|
if (IsRoot(name)) {
|
|
return false;
|
|
}
|
|
NameIndex kind = CanonicalNameParent(name);
|
|
if (IsPrivate(name)) {
|
|
kind = CanonicalNameParent(kind);
|
|
}
|
|
return StringEquals(CanonicalNameString(kind), "@getters");
|
|
}
|
|
|
|
bool TranslationHelper::IsSetter(NameIndex name) {
|
|
// Setters with private names have the import URI of the library where they
|
|
// are visible as the parent and the string "@setters" as the parent's parent.
|
|
// Setters with non-private names have the string "@setters" as the parent.
|
|
if (IsRoot(name)) {
|
|
return false;
|
|
}
|
|
NameIndex kind = CanonicalNameParent(name);
|
|
if (IsPrivate(name)) {
|
|
kind = CanonicalNameParent(kind);
|
|
}
|
|
return StringEquals(CanonicalNameString(kind), "@setters");
|
|
}
|
|
|
|
bool TranslationHelper::IsFactory(NameIndex name) {
|
|
// Factories with private names have the import URI of the library where they
|
|
// are visible as the parent and the string "@factories" as the parent's
|
|
// parent. Factories with non-private names have the string "@factories" as
|
|
// the parent.
|
|
if (IsRoot(name)) {
|
|
return false;
|
|
}
|
|
NameIndex kind = CanonicalNameParent(name);
|
|
if (IsPrivate(name)) {
|
|
kind = CanonicalNameParent(kind);
|
|
}
|
|
return StringEquals(CanonicalNameString(kind), "@factories");
|
|
}
|
|
|
|
NameIndex TranslationHelper::EnclosingName(NameIndex name) {
|
|
ASSERT(IsConstructor(name) || IsProcedure(name));
|
|
NameIndex enclosing = CanonicalNameParent(CanonicalNameParent(name));
|
|
if (IsPrivate(name)) {
|
|
enclosing = CanonicalNameParent(enclosing);
|
|
}
|
|
ASSERT(IsLibrary(enclosing) || IsClass(enclosing));
|
|
return enclosing;
|
|
}
|
|
|
|
InstancePtr TranslationHelper::Canonicalize(const Instance& instance) {
|
|
if (instance.IsNull()) return instance.ptr();
|
|
|
|
return instance.Canonicalize(thread());
|
|
}
|
|
|
|
const String& TranslationHelper::DartString(const char* content,
|
|
Heap::Space space) {
|
|
return String::ZoneHandle(Z, String::New(content, space));
|
|
}
|
|
|
|
String& TranslationHelper::DartString(StringIndex string_index,
|
|
Heap::Space space) {
|
|
intptr_t length = StringSize(string_index);
|
|
uint8_t* buffer = Z->Alloc<uint8_t>(length);
|
|
{
|
|
NoSafepointScope no_safepoint;
|
|
memmove(buffer, StringBuffer(string_index), length);
|
|
}
|
|
return String::ZoneHandle(Z, String::FromUTF8(buffer, length, space));
|
|
}
|
|
|
|
String& TranslationHelper::DartString(const uint8_t* utf8_array,
|
|
intptr_t len,
|
|
Heap::Space space) {
|
|
return String::ZoneHandle(Z, String::FromUTF8(utf8_array, len, space));
|
|
}
|
|
|
|
const String& TranslationHelper::DartString(
|
|
const GrowableHandlePtrArray<const String>& pieces) {
|
|
return String::ZoneHandle(Z, Symbols::FromConcatAll(thread_, pieces));
|
|
}
|
|
|
|
const String& TranslationHelper::DartSymbolPlain(const char* content) const {
|
|
return String::ZoneHandle(Z, Symbols::New(thread_, content));
|
|
}
|
|
|
|
String& TranslationHelper::DartSymbolPlain(StringIndex string_index) const {
|
|
intptr_t length = StringSize(string_index);
|
|
uint8_t* buffer = Z->Alloc<uint8_t>(length);
|
|
{
|
|
NoSafepointScope no_safepoint;
|
|
memmove(buffer, StringBuffer(string_index), length);
|
|
}
|
|
String& result =
|
|
String::ZoneHandle(Z, Symbols::FromUTF8(thread_, buffer, length));
|
|
return result;
|
|
}
|
|
|
|
const String& TranslationHelper::DartSymbolObfuscate(
|
|
const char* content) const {
|
|
String& result = String::ZoneHandle(Z, Symbols::New(thread_, content));
|
|
if (IG->obfuscate()) {
|
|
Obfuscator obfuscator(thread_, String::Handle(Z));
|
|
result = obfuscator.Rename(result, true);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
String& TranslationHelper::DartSymbolObfuscate(StringIndex string_index) const {
|
|
intptr_t length = StringSize(string_index);
|
|
uint8_t* buffer = Z->Alloc<uint8_t>(length);
|
|
{
|
|
NoSafepointScope no_safepoint;
|
|
memmove(buffer, StringBuffer(string_index), length);
|
|
}
|
|
String& result =
|
|
String::ZoneHandle(Z, Symbols::FromUTF8(thread_, buffer, length));
|
|
if (IG->obfuscate()) {
|
|
Obfuscator obfuscator(thread_, String::Handle(Z));
|
|
result = obfuscator.Rename(result, true);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
String& TranslationHelper::DartIdentifier(const Library& lib,
|
|
StringIndex string_index) {
|
|
String& name = DartString(string_index);
|
|
ManglePrivateName(lib, &name);
|
|
return name;
|
|
}
|
|
|
|
const String& TranslationHelper::DartClassName(NameIndex kernel_class) {
|
|
ASSERT(IsClass(kernel_class));
|
|
String& name = DartString(CanonicalNameString(kernel_class));
|
|
return ManglePrivateName(CanonicalNameParent(kernel_class), &name);
|
|
}
|
|
|
|
const String& TranslationHelper::DartConstructorName(NameIndex constructor) {
|
|
ASSERT(IsConstructor(constructor));
|
|
return DartFactoryName(constructor);
|
|
}
|
|
|
|
const String& TranslationHelper::DartProcedureName(NameIndex procedure) {
|
|
ASSERT(IsProcedure(procedure) || IsConstructor(procedure));
|
|
if (IsSetter(procedure)) {
|
|
return DartSetterName(procedure);
|
|
} else if (IsGetter(procedure)) {
|
|
return DartGetterName(procedure);
|
|
} else if (IsFactory(procedure)) {
|
|
return DartFactoryName(procedure);
|
|
} else if (IsMethod(procedure)) {
|
|
return DartMethodName(procedure);
|
|
} else {
|
|
ASSERT(IsConstructor(procedure));
|
|
return DartConstructorName(procedure);
|
|
}
|
|
}
|
|
|
|
const String& TranslationHelper::DartSetterName(NameIndex setter) {
|
|
return DartSetterName(CanonicalNameParent(setter),
|
|
CanonicalNameString(setter));
|
|
}
|
|
|
|
const String& TranslationHelper::DartSetterName(NameIndex parent,
|
|
StringIndex setter) {
|
|
// The names flowing into [setter] are coming from the Kernel file:
|
|
// * user-defined setters: `fieldname=`
|
|
// * property-set expressions: `fieldname`
|
|
//
|
|
// The VM uses `get:fieldname` and `set:fieldname`.
|
|
//
|
|
// => In order to be consistent, we remove the `=` always and adopt the VM
|
|
// conventions.
|
|
intptr_t size = StringSize(setter);
|
|
ASSERT(size > 0);
|
|
if (CharacterAt(setter, size - 1) == '=') {
|
|
--size;
|
|
}
|
|
uint8_t* buffer = Z->Alloc<uint8_t>(size);
|
|
{
|
|
NoSafepointScope no_safepoint;
|
|
memmove(buffer, StringBuffer(setter), size);
|
|
}
|
|
String& name =
|
|
String::ZoneHandle(Z, String::FromUTF8(buffer, size, allocation_space_));
|
|
ManglePrivateName(parent, &name);
|
|
name = Field::SetterSymbol(name);
|
|
return name;
|
|
}
|
|
|
|
const String& TranslationHelper::DartGetterName(NameIndex getter) {
|
|
return DartGetterName(CanonicalNameParent(getter),
|
|
CanonicalNameString(getter));
|
|
}
|
|
|
|
const String& TranslationHelper::DartGetterName(NameIndex parent,
|
|
StringIndex getter) {
|
|
String& name = DartString(getter);
|
|
ManglePrivateName(parent, &name);
|
|
name = Field::GetterSymbol(name);
|
|
return name;
|
|
}
|
|
|
|
const String& TranslationHelper::DartFieldName(NameIndex field) {
|
|
return DartFieldName(CanonicalNameParent(field), CanonicalNameString(field));
|
|
}
|
|
|
|
const String& TranslationHelper::DartFieldName(NameIndex parent,
|
|
StringIndex field) {
|
|
String& name = DartString(field);
|
|
return ManglePrivateName(parent, &name);
|
|
}
|
|
|
|
const String& TranslationHelper::DartMethodName(NameIndex method) {
|
|
return DartMethodName(CanonicalNameParent(method),
|
|
CanonicalNameString(method));
|
|
}
|
|
|
|
const String& TranslationHelper::DartMethodName(NameIndex parent,
|
|
StringIndex method) {
|
|
String& name = DartString(method);
|
|
return ManglePrivateName(parent, &name);
|
|
}
|
|
|
|
const String& TranslationHelper::DartFactoryName(NameIndex factory) {
|
|
ASSERT(IsConstructor(factory) || IsFactory(factory));
|
|
GrowableHandlePtrArray<const String> pieces(Z, 3);
|
|
pieces.Add(DartClassName(EnclosingName(factory)));
|
|
pieces.Add(Symbols::Dot());
|
|
// [DartMethodName] will mangle the name.
|
|
pieces.Add(DartMethodName(factory));
|
|
return String::ZoneHandle(Z, Symbols::FromConcatAll(thread_, pieces));
|
|
}
|
|
|
|
// TODO(https://github.com/dart-lang/sdk/issues/37517): Should emit code to
|
|
// throw a NoSuchMethodError.
|
|
static void CheckStaticLookup(const Object& target) {
|
|
if (target.IsNull()) {
|
|
#ifndef PRODUCT
|
|
ASSERT(IsolateGroup::Current()->HasAttemptedReload());
|
|
Report::LongJump(LanguageError::Handle(LanguageError::New(String::Handle(
|
|
String::New("Unimplemented handling of missing static target")))));
|
|
#else
|
|
UNREACHABLE();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
LibraryPtr TranslationHelper::LookupLibraryByKernelLibrary(
|
|
NameIndex kernel_library) {
|
|
// We only use the string and don't rely on having any particular parent.
|
|
// This ASSERT is just a sanity check.
|
|
ASSERT(IsLibrary(kernel_library) ||
|
|
IsAdministrative(CanonicalNameParent(kernel_library)));
|
|
{
|
|
name_index_handle_ = Smi::New(kernel_library);
|
|
LibraryPtr raw_lib = info_.LookupLibrary(thread_, name_index_handle_);
|
|
NoSafepointScope no_safepoint_scope(thread_);
|
|
if (raw_lib != Library::null()) {
|
|
return raw_lib;
|
|
}
|
|
}
|
|
|
|
const String& library_name =
|
|
DartSymbolPlain(CanonicalNameString(kernel_library));
|
|
ASSERT(!library_name.IsNull());
|
|
const Library& library =
|
|
Library::Handle(Z, Library::LookupLibrary(thread_, library_name));
|
|
CheckStaticLookup(library);
|
|
name_index_handle_ = Smi::New(kernel_library);
|
|
return info_.InsertLibrary(thread_, name_index_handle_, library);
|
|
}
|
|
|
|
ClassPtr TranslationHelper::LookupClassByKernelClass(NameIndex kernel_class) {
|
|
ASSERT(IsClass(kernel_class));
|
|
{
|
|
name_index_handle_ = Smi::New(kernel_class);
|
|
ClassPtr raw_class = info_.LookupClass(thread_, name_index_handle_);
|
|
NoSafepointScope no_safepoint_scope(thread_);
|
|
if (raw_class != Class::null()) {
|
|
return raw_class;
|
|
}
|
|
}
|
|
|
|
const String& class_name = DartClassName(kernel_class);
|
|
NameIndex kernel_library = CanonicalNameParent(kernel_class);
|
|
Library& library =
|
|
Library::Handle(Z, LookupLibraryByKernelLibrary(kernel_library));
|
|
ASSERT(!library.IsNull());
|
|
const Class& klass =
|
|
Class::Handle(Z, library.LookupClassAllowPrivate(class_name));
|
|
CheckStaticLookup(klass);
|
|
ASSERT(!klass.IsNull());
|
|
name_index_handle_ = Smi::New(kernel_class);
|
|
return info_.InsertClass(thread_, name_index_handle_, klass);
|
|
}
|
|
|
|
FieldPtr TranslationHelper::LookupFieldByKernelGetterOrSetter(
|
|
NameIndex kernel_field,
|
|
bool required) {
|
|
ASSERT(IsGetter(kernel_field) || IsSetter(kernel_field));
|
|
NameIndex enclosing = EnclosingName(kernel_field);
|
|
|
|
Class& klass = Class::Handle(Z);
|
|
if (IsLibrary(enclosing)) {
|
|
Library& library =
|
|
Library::Handle(Z, LookupLibraryByKernelLibrary(enclosing));
|
|
klass = library.toplevel_class();
|
|
CheckStaticLookup(klass);
|
|
} else {
|
|
ASSERT(IsClass(enclosing));
|
|
klass = LookupClassByKernelClass(enclosing);
|
|
}
|
|
Field& field = Field::Handle(
|
|
Z, klass.LookupFieldAllowPrivate(
|
|
DartSymbolObfuscate(CanonicalNameString(kernel_field))));
|
|
if (required) {
|
|
CheckStaticLookup(field);
|
|
}
|
|
return field.ptr();
|
|
}
|
|
|
|
FunctionPtr TranslationHelper::LookupStaticMethodByKernelProcedure(
|
|
NameIndex procedure,
|
|
bool required) {
|
|
const String& procedure_name = DartProcedureName(procedure);
|
|
|
|
// The parent is either a library or a class (in which case the procedure is a
|
|
// static method).
|
|
NameIndex enclosing = EnclosingName(procedure);
|
|
if (IsLibrary(enclosing)) {
|
|
Library& library =
|
|
Library::Handle(Z, LookupLibraryByKernelLibrary(enclosing));
|
|
Function& function =
|
|
Function::Handle(Z, library.LookupFunctionAllowPrivate(procedure_name));
|
|
if (required) {
|
|
CheckStaticLookup(function);
|
|
}
|
|
return function.ptr();
|
|
} else {
|
|
ASSERT(IsClass(enclosing));
|
|
Class& klass = Class::Handle(Z, LookupClassByKernelClass(enclosing));
|
|
const auto& error = klass.EnsureIsFinalized(thread_);
|
|
ASSERT(error == Error::null());
|
|
Function& function = Function::ZoneHandle(
|
|
Z, klass.LookupFunctionAllowPrivate(procedure_name));
|
|
if (required) {
|
|
CheckStaticLookup(function);
|
|
}
|
|
return function.ptr();
|
|
}
|
|
}
|
|
|
|
FunctionPtr TranslationHelper::LookupConstructorByKernelConstructor(
|
|
NameIndex constructor) {
|
|
ASSERT(IsConstructor(constructor));
|
|
Class& klass =
|
|
Class::Handle(Z, LookupClassByKernelClass(EnclosingName(constructor)));
|
|
CheckStaticLookup(klass);
|
|
return LookupConstructorByKernelConstructor(klass, constructor);
|
|
}
|
|
|
|
FunctionPtr TranslationHelper::LookupConstructorByKernelConstructor(
|
|
const Class& owner,
|
|
NameIndex constructor) {
|
|
ASSERT(IsConstructor(constructor));
|
|
const auto& error = owner.EnsureIsFinalized(thread_);
|
|
ASSERT(error == Error::null());
|
|
Function& function = Function::Handle(
|
|
Z, owner.LookupConstructorAllowPrivate(DartConstructorName(constructor)));
|
|
CheckStaticLookup(function);
|
|
return function.ptr();
|
|
}
|
|
|
|
FunctionPtr TranslationHelper::LookupConstructorByKernelConstructor(
|
|
const Class& owner,
|
|
StringIndex constructor_name) {
|
|
GrowableHandlePtrArray<const String> pieces(Z, 3);
|
|
pieces.Add(String::Handle(Z, owner.Name()));
|
|
pieces.Add(Symbols::Dot());
|
|
String& name = DartSymbolPlain(constructor_name);
|
|
pieces.Add(ManglePrivateName(Library::Handle(owner.library()), &name));
|
|
|
|
String& new_name =
|
|
String::ZoneHandle(Z, Symbols::FromConcatAll(thread_, pieces));
|
|
const auto& error = owner.EnsureIsFinalized(thread_);
|
|
ASSERT(error == Error::null());
|
|
FunctionPtr function = owner.LookupConstructorAllowPrivate(new_name);
|
|
ASSERT(function != Object::null());
|
|
return function;
|
|
}
|
|
|
|
FunctionPtr TranslationHelper::LookupMethodByMember(NameIndex target,
|
|
const String& method_name) {
|
|
NameIndex kernel_class = EnclosingName(target);
|
|
Class& klass = Class::Handle(Z, LookupClassByKernelClass(kernel_class));
|
|
Function& function = Function::Handle(Z);
|
|
if (klass.EnsureIsFinalized(thread_) == Error::null()) {
|
|
function = klass.LookupFunctionAllowPrivate(method_name);
|
|
}
|
|
#ifdef DEBUG
|
|
if (function.IsNull()) {
|
|
THR_Print("Unable to find \'%s\' in %s\n", method_name.ToCString(),
|
|
klass.ToCString());
|
|
}
|
|
#endif
|
|
CheckStaticLookup(function);
|
|
ASSERT(!function.IsNull());
|
|
return function.ptr();
|
|
}
|
|
|
|
FunctionPtr TranslationHelper::LookupDynamicFunction(const Class& klass,
|
|
const String& name) {
|
|
// Search the superclass chain for the selector.
|
|
Class& iterate_klass = Class::Handle(Z, klass.ptr());
|
|
while (!iterate_klass.IsNull()) {
|
|
FunctionPtr function =
|
|
iterate_klass.LookupDynamicFunctionAllowPrivate(name);
|
|
if (function != Object::null()) {
|
|
return function;
|
|
}
|
|
iterate_klass = iterate_klass.SuperClass();
|
|
}
|
|
return Function::null();
|
|
}
|
|
|
|
Type& TranslationHelper::GetDeclarationType(const Class& klass) {
|
|
ASSERT(!klass.IsNull());
|
|
// Note that if cls is _Closure, the returned type will be _Closure,
|
|
// and not the signature type.
|
|
Type& type = Type::ZoneHandle(Z);
|
|
if (klass.is_type_finalized()) {
|
|
type = klass.DeclarationType();
|
|
} else {
|
|
// Note that the type argument vector is not yet extended.
|
|
type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()));
|
|
}
|
|
return type;
|
|
}
|
|
|
|
void TranslationHelper::SetupFieldAccessorFunction(
|
|
const Class& klass,
|
|
const Function& function,
|
|
const AbstractType& field_type) {
|
|
bool is_setter = function.IsImplicitSetterFunction();
|
|
bool is_method = !function.IsStaticFunction();
|
|
intptr_t parameter_count = (is_method ? 1 : 0) + (is_setter ? 1 : 0);
|
|
|
|
const FunctionType& signature = FunctionType::Handle(Z, function.signature());
|
|
function.SetNumOptionalParameters(0, false);
|
|
function.set_num_fixed_parameters(parameter_count);
|
|
if (parameter_count > 0) {
|
|
signature.set_parameter_types(
|
|
Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
|
|
}
|
|
signature.CreateNameArrayIncludingFlags(Heap::kOld);
|
|
|
|
intptr_t pos = 0;
|
|
if (is_method) {
|
|
signature.SetParameterTypeAt(pos, GetDeclarationType(klass));
|
|
signature.SetParameterNameAt(pos, Symbols::This());
|
|
pos++;
|
|
}
|
|
if (is_setter) {
|
|
signature.SetParameterTypeAt(pos, field_type);
|
|
signature.SetParameterNameAt(pos, Symbols::Value());
|
|
pos++;
|
|
}
|
|
signature.FinalizeNameArrays(function);
|
|
}
|
|
|
|
void TranslationHelper::ReportError(const char* format, ...) {
|
|
const Script& null_script = Script::Handle(Z);
|
|
|
|
va_list args;
|
|
va_start(args, format);
|
|
Report::MessageV(Report::kError, null_script, TokenPosition::kNoSource,
|
|
Report::AtLocation, format, args);
|
|
va_end(args);
|
|
UNREACHABLE();
|
|
}
|
|
|
|
void TranslationHelper::ReportError(const Script& script,
|
|
const TokenPosition position,
|
|
const char* format,
|
|
...) {
|
|
va_list args;
|
|
va_start(args, format);
|
|
Report::MessageV(Report::kError, script, position, Report::AtLocation, format,
|
|
args);
|
|
va_end(args);
|
|
UNREACHABLE();
|
|
}
|
|
|
|
void TranslationHelper::ReportError(const Error& prev_error,
|
|
const char* format,
|
|
...) {
|
|
const Script& null_script = Script::Handle(Z);
|
|
|
|
va_list args;
|
|
va_start(args, format);
|
|
Report::LongJumpV(prev_error, null_script, TokenPosition::kNoSource, format,
|
|
args);
|
|
va_end(args);
|
|
UNREACHABLE();
|
|
}
|
|
|
|
void TranslationHelper::ReportError(const Error& prev_error,
|
|
const Script& script,
|
|
const TokenPosition position,
|
|
const char* format,
|
|
...) {
|
|
va_list args;
|
|
va_start(args, format);
|
|
Report::LongJumpV(prev_error, script, position, format, args);
|
|
va_end(args);
|
|
UNREACHABLE();
|
|
}
|
|
|
|
String& TranslationHelper::ManglePrivateName(NameIndex parent,
|
|
String* name_to_modify,
|
|
bool symbolize,
|
|
bool obfuscate) {
|
|
if (name_to_modify->Length() >= 1 && name_to_modify->CharAt(0) == '_') {
|
|
const Library& library =
|
|
Library::Handle(Z, LookupLibraryByKernelLibrary(parent));
|
|
*name_to_modify = library.PrivateName(*name_to_modify);
|
|
if (obfuscate && IG->obfuscate()) {
|
|
const String& library_key = String::Handle(library.private_key());
|
|
Obfuscator obfuscator(thread_, library_key);
|
|
*name_to_modify = obfuscator.Rename(*name_to_modify);
|
|
}
|
|
} else if (symbolize) {
|
|
*name_to_modify = Symbols::New(thread_, *name_to_modify);
|
|
if (obfuscate && IG->obfuscate()) {
|
|
const String& library_key = String::Handle();
|
|
Obfuscator obfuscator(thread_, library_key);
|
|
*name_to_modify = obfuscator.Rename(*name_to_modify);
|
|
}
|
|
}
|
|
return *name_to_modify;
|
|
}
|
|
|
|
String& TranslationHelper::ManglePrivateName(const Library& library,
|
|
String* name_to_modify,
|
|
bool symbolize,
|
|
bool obfuscate) {
|
|
if (name_to_modify->Length() >= 1 && name_to_modify->CharAt(0) == '_') {
|
|
*name_to_modify = library.PrivateName(*name_to_modify);
|
|
if (obfuscate && IG->obfuscate()) {
|
|
const String& library_key = String::Handle(library.private_key());
|
|
Obfuscator obfuscator(thread_, library_key);
|
|
*name_to_modify = obfuscator.Rename(*name_to_modify);
|
|
}
|
|
} else if (symbolize) {
|
|
*name_to_modify = Symbols::New(thread_, *name_to_modify);
|
|
if (obfuscate && IG->obfuscate()) {
|
|
const String& library_key = String::Handle();
|
|
Obfuscator obfuscator(thread_, library_key);
|
|
*name_to_modify = obfuscator.Rename(*name_to_modify);
|
|
}
|
|
}
|
|
return *name_to_modify;
|
|
}
|
|
|
|
void FunctionNodeHelper::ReadUntilExcluding(Field field) {
|
|
if (field <= next_read_) return;
|
|
|
|
// Ordered with fall-through.
|
|
switch (next_read_) {
|
|
case kStart: {
|
|
Tag tag = helper_->ReadTag(); // read tag.
|
|
ASSERT(tag == kFunctionNode);
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kPosition:
|
|
position_ = helper_->ReadPosition(); // read position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kEndPosition:
|
|
end_position_ = helper_->ReadPosition(); // read end position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kAsyncMarker:
|
|
async_marker_ = static_cast<AsyncMarker>(helper_->ReadByte());
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kDartAsyncMarker:
|
|
dart_async_marker_ = static_cast<AsyncMarker>(
|
|
helper_->ReadByte()); // read dart async marker.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kTypeParameters:
|
|
helper_->SkipTypeParametersList(); // read type parameters.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kTotalParameterCount:
|
|
total_parameter_count_ =
|
|
helper_->ReadUInt(); // read total parameter count.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kRequiredParameterCount:
|
|
required_parameter_count_ =
|
|
helper_->ReadUInt(); // read required parameter count.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kPositionalParameters:
|
|
helper_->SkipListOfVariableDeclarations(); // read positionals.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kNamedParameters:
|
|
helper_->SkipListOfVariableDeclarations(); // read named.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kReturnType:
|
|
helper_->SkipDartType(); // read return type.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kFutureValueType:
|
|
helper_->SkipOptionalDartType(); // read future value type.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kBody:
|
|
if (helper_->ReadTag() == kSomething)
|
|
helper_->SkipStatement(); // read body.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kEnd:
|
|
return;
|
|
}
|
|
}
|
|
|
|
void TypeParameterHelper::ReadUntilExcluding(Field field) {
|
|
for (; next_read_ < field; ++next_read_) {
|
|
switch (next_read_) {
|
|
case kFlags:
|
|
flags_ = helper_->ReadFlags();
|
|
break;
|
|
case kAnnotations:
|
|
helper_->SkipListOfExpressions(); // read annotations.
|
|
break;
|
|
case kVariance:
|
|
helper_->ReadVariance();
|
|
break;
|
|
case kName:
|
|
name_index_ = helper_->ReadStringReference(); // read name index.
|
|
break;
|
|
case kBound:
|
|
helper_->SkipDartType();
|
|
break;
|
|
case kDefaultType:
|
|
helper_->SkipDartType();
|
|
break;
|
|
case kEnd:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void VariableDeclarationHelper::ReadUntilExcluding(Field field) {
|
|
if (field <= next_read_) return;
|
|
|
|
// Ordered with fall-through.
|
|
switch (next_read_) {
|
|
case kPosition:
|
|
position_ = helper_->ReadPosition(); // read position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kEqualPosition:
|
|
equals_position_ = helper_->ReadPosition(); // read equals position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kAnnotations:
|
|
annotation_count_ = helper_->ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < annotation_count_; ++i) {
|
|
helper_->SkipExpression(); // read ith expression.
|
|
}
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kFlags:
|
|
flags_ = helper_->ReadFlags();
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kNameIndex:
|
|
name_index_ = helper_->ReadStringReference(); // read name index.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kType:
|
|
helper_->SkipDartType(); // read type.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kInitializer:
|
|
if (helper_->ReadTag() == kSomething)
|
|
helper_->SkipExpression(); // read initializer.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kEnd:
|
|
return;
|
|
}
|
|
}
|
|
|
|
FieldHelper::FieldHelper(KernelReaderHelper* helper, intptr_t offset)
|
|
: helper_(helper), next_read_(kStart) {
|
|
helper_->SetOffset(offset);
|
|
}
|
|
|
|
void FieldHelper::ReadUntilExcluding(Field field) {
|
|
if (field <= next_read_) return;
|
|
|
|
// Ordered with fall-through.
|
|
switch (next_read_) {
|
|
case kStart: {
|
|
Tag tag = helper_->ReadTag(); // read tag.
|
|
ASSERT(tag == kField);
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kCanonicalNameGetter:
|
|
canonical_name_getter_ =
|
|
helper_->ReadCanonicalNameReference(); // read canonical_name_getter.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kCanonicalNameSetter:
|
|
canonical_name_setter_ =
|
|
helper_->ReadCanonicalNameReference(); // read canonical_name_setter.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kSourceUriIndex:
|
|
source_uri_index_ = helper_->ReadUInt(); // read source_uri_index.
|
|
helper_->set_current_script_id(source_uri_index_);
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kPosition:
|
|
position_ = helper_->ReadPosition(); // read position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kEndPosition:
|
|
end_position_ = helper_->ReadPosition(); // read end position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kFlags:
|
|
flags_ = helper_->ReadUInt();
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kName:
|
|
helper_->SkipName(); // read name.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kAnnotations: {
|
|
annotation_count_ = helper_->ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < annotation_count_; ++i) {
|
|
helper_->SkipExpression(); // read ith expression.
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kType:
|
|
helper_->SkipDartType(); // read type.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kInitializer:
|
|
if (helper_->ReadTag() == kSomething) {
|
|
helper_->SkipExpression(); // read initializer.
|
|
}
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kEnd:
|
|
return;
|
|
}
|
|
}
|
|
|
|
void ProcedureHelper::ReadUntilExcluding(Field field) {
|
|
if (field <= next_read_) return;
|
|
|
|
// Ordered with fall-through.
|
|
switch (next_read_) {
|
|
case kStart: {
|
|
Tag tag = helper_->ReadTag(); // read tag.
|
|
ASSERT(tag == kProcedure);
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kCanonicalName:
|
|
canonical_name_ =
|
|
helper_->ReadCanonicalNameReference(); // read canonical_name.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kSourceUriIndex:
|
|
source_uri_index_ = helper_->ReadUInt(); // read source_uri_index.
|
|
helper_->set_current_script_id(source_uri_index_);
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kStartPosition:
|
|
start_position_ = helper_->ReadPosition(); // read position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kPosition:
|
|
position_ = helper_->ReadPosition(); // read position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kEndPosition:
|
|
end_position_ = helper_->ReadPosition(); // read end position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kKind:
|
|
kind_ = static_cast<Kind>(helper_->ReadByte());
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kStubKind:
|
|
stub_kind_ = static_cast<StubKind>(helper_->ReadByte());
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kFlags:
|
|
flags_ = helper_->ReadUInt();
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kName:
|
|
helper_->SkipName(); // read name.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kAnnotations: {
|
|
annotation_count_ = helper_->ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < annotation_count_; ++i) {
|
|
helper_->SkipExpression(); // read ith expression.
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kStubTarget:
|
|
if (stub_kind_ == kConcreteForwardingStubKind) {
|
|
concrete_forwarding_stub_target_ =
|
|
helper_->ReadCanonicalNameReference();
|
|
} else {
|
|
helper_->ReadCanonicalNameReference();
|
|
}
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kFunction:
|
|
helper_->SkipFunctionNode(); // read function node.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kEnd:
|
|
return;
|
|
}
|
|
}
|
|
|
|
void ConstructorHelper::ReadUntilExcluding(Field field) {
|
|
if (field <= next_read_) return;
|
|
|
|
// Ordered with fall-through.
|
|
switch (next_read_) {
|
|
case kStart: {
|
|
Tag tag = helper_->ReadTag(); // read tag.
|
|
ASSERT(tag == kConstructor);
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kCanonicalName:
|
|
canonical_name_ =
|
|
helper_->ReadCanonicalNameReference(); // read canonical_name.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kSourceUriIndex:
|
|
source_uri_index_ = helper_->ReadUInt(); // read source_uri_index.
|
|
helper_->set_current_script_id(source_uri_index_);
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kStartPosition:
|
|
start_position_ = helper_->ReadPosition(); // read position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kPosition:
|
|
position_ = helper_->ReadPosition(); // read position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kEndPosition:
|
|
end_position_ = helper_->ReadPosition(); // read end position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kFlags:
|
|
flags_ = helper_->ReadFlags();
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kName:
|
|
helper_->SkipName(); // read name.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kAnnotations: {
|
|
annotation_count_ = helper_->ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < annotation_count_; ++i) {
|
|
helper_->SkipExpression(); // read ith expression.
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kFunction:
|
|
helper_->SkipFunctionNode(); // read function.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kInitializers: {
|
|
intptr_t list_length =
|
|
helper_->ReadListLength(); // read initializers list length.
|
|
for (intptr_t i = 0; i < list_length; i++) {
|
|
helper_->SkipInitializer();
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kEnd:
|
|
return;
|
|
}
|
|
}
|
|
|
|
void ClassHelper::ReadUntilExcluding(Field field) {
|
|
if (field <= next_read_) return;
|
|
|
|
// Ordered with fall-through.
|
|
switch (next_read_) {
|
|
case kStart: {
|
|
Tag tag = helper_->ReadTag(); // read tag.
|
|
ASSERT(tag == kClass);
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kCanonicalName:
|
|
canonical_name_ =
|
|
helper_->ReadCanonicalNameReference(); // read canonical_name.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kSourceUriIndex:
|
|
source_uri_index_ = helper_->ReadUInt(); // read source_uri_index.
|
|
helper_->set_current_script_id(source_uri_index_);
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kStartPosition:
|
|
start_position_ = helper_->ReadPosition(); // read position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kPosition:
|
|
position_ = helper_->ReadPosition(); // read position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kEndPosition:
|
|
end_position_ = helper_->ReadPosition(); // read end position.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kFlags:
|
|
flags_ = helper_->ReadFlags(); // read flags.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kNameIndex:
|
|
name_index_ = helper_->ReadStringReference(); // read name index.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kAnnotations: {
|
|
annotation_count_ = helper_->ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < annotation_count_; ++i) {
|
|
helper_->SkipExpression(); // read ith expression.
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kTypeParameters:
|
|
helper_->SkipTypeParametersList(); // read type parameters.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kSuperClass: {
|
|
Tag type_tag = helper_->ReadTag(); // read super class type (part 1).
|
|
if (type_tag == kSomething) {
|
|
helper_->SkipDartType(); // read super class type (part 2).
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kMixinType: {
|
|
Tag type_tag = helper_->ReadTag(); // read mixin type (part 1).
|
|
if (type_tag == kSomething) {
|
|
helper_->SkipDartType(); // read mixin type (part 2).
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kImplementedClasses:
|
|
helper_->SkipListOfDartTypes(); // read implemented_classes.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kFields: {
|
|
intptr_t list_length =
|
|
helper_->ReadListLength(); // read fields list length.
|
|
for (intptr_t i = 0; i < list_length; i++) {
|
|
FieldHelper field_helper(helper_);
|
|
field_helper.ReadUntilExcluding(FieldHelper::kEnd); // read field.
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kConstructors: {
|
|
intptr_t list_length =
|
|
helper_->ReadListLength(); // read constructors list length.
|
|
for (intptr_t i = 0; i < list_length; i++) {
|
|
ConstructorHelper constructor_helper(helper_);
|
|
constructor_helper.ReadUntilExcluding(
|
|
ConstructorHelper::kEnd); // read constructor.
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kProcedures: {
|
|
procedure_count_ = helper_->ReadListLength(); // read procedures #.
|
|
for (intptr_t i = 0; i < procedure_count_; i++) {
|
|
ProcedureHelper procedure_helper(helper_);
|
|
procedure_helper.ReadUntilExcluding(
|
|
ProcedureHelper::kEnd); // read procedure.
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kClassIndex:
|
|
// Read class index.
|
|
for (intptr_t i = 0; i < procedure_count_; ++i) {
|
|
helper_->reader_.ReadUInt32();
|
|
}
|
|
helper_->reader_.ReadUInt32();
|
|
helper_->reader_.ReadUInt32();
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kEnd:
|
|
return;
|
|
}
|
|
}
|
|
|
|
void LibraryHelper::ReadUntilExcluding(Field field) {
|
|
if (field <= next_read_) return;
|
|
|
|
// Ordered with fall-through.
|
|
switch (next_read_) {
|
|
// Note that this (up to canonical name) needs to be kept in sync with
|
|
// "library_canonical_name" (currently in "kernel_loader.h").
|
|
case kFlags: {
|
|
flags_ = helper_->ReadFlags();
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
}
|
|
case kLanguageVersion: {
|
|
helper_->ReadUInt(); // Read major language version.
|
|
helper_->ReadUInt(); // Read minor language version.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
}
|
|
case kCanonicalName:
|
|
canonical_name_ =
|
|
helper_->ReadCanonicalNameReference(); // read canonical_name.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kName:
|
|
name_index_ = helper_->ReadStringReference(); // read name index.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kSourceUriIndex:
|
|
source_uri_index_ = helper_->ReadUInt(); // read source_uri_index.
|
|
helper_->set_current_script_id(source_uri_index_);
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kProblemsAsJson: {
|
|
intptr_t length = helper_->ReadUInt(); // read length of table.
|
|
for (intptr_t i = 0; i < length; ++i) {
|
|
helper_->SkipBytes(helper_->ReadUInt()); // read strings.
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kAnnotations:
|
|
helper_->SkipListOfExpressions(); // read annotations.
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
case kDependencies: {
|
|
intptr_t dependency_count = helper_->ReadUInt(); // read list length.
|
|
for (intptr_t i = 0; i < dependency_count; ++i) {
|
|
helper_->SkipLibraryDependency();
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
void LibraryDependencyHelper::ReadUntilExcluding(Field field) {
|
|
if (field <= next_read_) return;
|
|
|
|
// Ordered with fall-through.
|
|
switch (next_read_) {
|
|
case kFileOffset: {
|
|
helper_->ReadPosition();
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
}
|
|
case kFlags: {
|
|
flags_ = helper_->ReadFlags();
|
|
if (++next_read_ == field) return;
|
|
FALL_THROUGH;
|
|
}
|
|
case kAnnotations: {
|
|
annotation_count_ = helper_->ReadListLength();
|
|
for (intptr_t i = 0; i < annotation_count_; ++i) {
|
|
helper_->SkipExpression(); // read ith expression.
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kTargetLibrary: {
|
|
target_library_canonical_name_ = helper_->ReadCanonicalNameReference();
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kName: {
|
|
name_index_ = helper_->ReadStringReference();
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kCombinators: {
|
|
intptr_t count = helper_->ReadListLength();
|
|
for (intptr_t i = 0; i < count; ++i) {
|
|
// Skip flags
|
|
helper_->SkipBytes(1);
|
|
// Skip list of names.
|
|
helper_->SkipListOfStrings();
|
|
}
|
|
if (++next_read_ == field) return;
|
|
}
|
|
FALL_THROUGH;
|
|
case kEnd:
|
|
return;
|
|
}
|
|
}
|
|
|
|
#if defined(DEBUG)
|
|
|
|
void MetadataHelper::VerifyMetadataMappings(
|
|
const ExternalTypedData& metadata_mappings) {
|
|
const intptr_t kUInt32Size = 4;
|
|
Reader reader(metadata_mappings);
|
|
if (reader.size() == 0) {
|
|
return;
|
|
}
|
|
|
|
// Scan through metadata mappings in reverse direction.
|
|
|
|
// Read metadataMappings length.
|
|
intptr_t offset = reader.size() - kUInt32Size;
|
|
const intptr_t metadata_num = reader.ReadUInt32At(offset);
|
|
|
|
if (metadata_num == 0) {
|
|
ASSERT(metadata_mappings.LengthInBytes() == kUInt32Size);
|
|
return;
|
|
}
|
|
|
|
// Read metadataMappings elements.
|
|
for (intptr_t i = 0; i < metadata_num; ++i) {
|
|
// Read nodeOffsetToMetadataOffset length.
|
|
offset -= kUInt32Size;
|
|
const intptr_t mappings_num = reader.ReadUInt32At(offset);
|
|
|
|
// Skip nodeOffsetToMetadataOffset.
|
|
offset -= mappings_num * 2 * kUInt32Size;
|
|
|
|
// Verify that node offsets are sorted.
|
|
intptr_t prev_node_offset = -1;
|
|
reader.set_offset(offset);
|
|
for (intptr_t j = 0; j < mappings_num; ++j) {
|
|
const intptr_t node_offset = reader.ReadUInt32();
|
|
const intptr_t md_offset = reader.ReadUInt32();
|
|
|
|
ASSERT(node_offset >= 0 && md_offset >= 0);
|
|
ASSERT(node_offset > prev_node_offset);
|
|
prev_node_offset = node_offset;
|
|
}
|
|
|
|
// Skip tag.
|
|
offset -= kUInt32Size;
|
|
}
|
|
}
|
|
|
|
#endif // defined(DEBUG)
|
|
|
|
MetadataHelper::MetadataHelper(KernelReaderHelper* helper,
|
|
const char* tag,
|
|
bool precompiler_only)
|
|
: helper_(helper),
|
|
translation_helper_(helper->translation_helper_),
|
|
tag_(tag),
|
|
mappings_scanned_(false),
|
|
precompiler_only_(precompiler_only),
|
|
mappings_offset_(0),
|
|
mappings_num_(0),
|
|
last_node_offset_(0),
|
|
last_mapping_index_(0) {}
|
|
|
|
void MetadataHelper::SetMetadataMappings(intptr_t mappings_offset,
|
|
intptr_t mappings_num) {
|
|
ASSERT((mappings_offset_ == 0) && (mappings_num_ == 0));
|
|
ASSERT((mappings_offset != 0) && (mappings_num != 0));
|
|
mappings_offset_ = mappings_offset;
|
|
mappings_num_ = mappings_num;
|
|
last_node_offset_ = kIntptrMax;
|
|
last_mapping_index_ = 0;
|
|
}
|
|
|
|
void MetadataHelper::ScanMetadataMappings() {
|
|
const intptr_t kUInt32Size = 4;
|
|
Reader reader(H.metadata_mappings());
|
|
if (reader.size() == 0) {
|
|
return;
|
|
}
|
|
|
|
// Scan through metadata mappings in reverse direction.
|
|
|
|
// Read metadataMappings length.
|
|
intptr_t offset = reader.size() - kUInt32Size;
|
|
uint32_t metadata_num = reader.ReadUInt32At(offset);
|
|
|
|
if (metadata_num == 0) {
|
|
ASSERT(H.metadata_mappings().LengthInBytes() == kUInt32Size);
|
|
return;
|
|
}
|
|
|
|
// Read metadataMappings elements.
|
|
for (uint32_t i = 0; i < metadata_num; ++i) {
|
|
// Read nodeOffsetToMetadataOffset length.
|
|
offset -= kUInt32Size;
|
|
uint32_t mappings_num = reader.ReadUInt32At(offset);
|
|
|
|
// Skip nodeOffsetToMetadataOffset and read tag.
|
|
offset -= mappings_num * 2 * kUInt32Size + kUInt32Size;
|
|
StringIndex tag = StringIndex(reader.ReadUInt32At(offset));
|
|
|
|
if (mappings_num == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (H.StringEquals(tag, tag_)) {
|
|
if ((!FLAG_precompiled_mode) && precompiler_only_) {
|
|
FATAL1("%s metadata is allowed in precompiled mode only", tag_);
|
|
}
|
|
SetMetadataMappings(offset + kUInt32Size, mappings_num);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
intptr_t MetadataHelper::FindMetadataMapping(intptr_t node_offset) {
|
|
const intptr_t kUInt32Size = 4;
|
|
ASSERT(mappings_num_ > 0);
|
|
|
|
Reader reader(H.metadata_mappings());
|
|
|
|
intptr_t left = 0;
|
|
intptr_t right = mappings_num_ - 1;
|
|
while (left < right) {
|
|
intptr_t mid = ((right - left) / 2) + left;
|
|
intptr_t mid_node_offset =
|
|
reader.ReadUInt32At(mappings_offset_ + mid * 2 * kUInt32Size);
|
|
|
|
if (node_offset < mid_node_offset) {
|
|
right = mid - 1;
|
|
} else if (node_offset > mid_node_offset) {
|
|
left = mid + 1;
|
|
} else {
|
|
return mid; // Exact match found.
|
|
}
|
|
}
|
|
ASSERT((0 <= left) && (left <= mappings_num_));
|
|
|
|
// Approximate match is found. Make sure it has an offset greater or equal
|
|
// to the given node offset.
|
|
if (left < mappings_num_) {
|
|
intptr_t found_node_offset =
|
|
reader.ReadUInt32At(mappings_offset_ + left * 2 * kUInt32Size);
|
|
|
|
if (found_node_offset < node_offset) {
|
|
++left;
|
|
}
|
|
}
|
|
ASSERT((left == mappings_num_) ||
|
|
static_cast<intptr_t>(reader.ReadUInt32At(
|
|
mappings_offset_ + left * 2 * kUInt32Size)) >= node_offset);
|
|
|
|
return left;
|
|
}
|
|
|
|
intptr_t MetadataHelper::GetNextMetadataPayloadOffset(intptr_t node_offset) {
|
|
if (!mappings_scanned_) {
|
|
ScanMetadataMappings();
|
|
mappings_scanned_ = true;
|
|
}
|
|
|
|
if (mappings_num_ == 0) {
|
|
return -1; // No metadata.
|
|
}
|
|
|
|
node_offset += helper_->data_program_offset_;
|
|
|
|
// Nodes are parsed in linear order most of the time, so do the search
|
|
// only if looking back.
|
|
if (node_offset < last_node_offset_) {
|
|
last_mapping_index_ = FindMetadataMapping(node_offset);
|
|
}
|
|
|
|
intptr_t index = last_mapping_index_;
|
|
intptr_t mapping_node_offset = 0;
|
|
intptr_t mapping_md_offset = -1;
|
|
|
|
Reader reader(H.metadata_mappings());
|
|
const intptr_t kUInt32Size = 4;
|
|
reader.set_offset(mappings_offset_ + index * 2 * kUInt32Size);
|
|
|
|
for (; index < mappings_num_; ++index) {
|
|
mapping_node_offset = reader.ReadUInt32();
|
|
mapping_md_offset = reader.ReadUInt32();
|
|
|
|
if (mapping_node_offset >= node_offset) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
last_mapping_index_ = index;
|
|
last_node_offset_ = node_offset;
|
|
|
|
if ((index < mappings_num_) && (mapping_node_offset == node_offset)) {
|
|
ASSERT(mapping_md_offset >= 0);
|
|
return mapping_md_offset;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
intptr_t MetadataHelper::GetComponentMetadataPayloadOffset() {
|
|
const intptr_t kComponentNodeOffset = 0;
|
|
return GetNextMetadataPayloadOffset(kComponentNodeOffset -
|
|
helper_->data_program_offset_);
|
|
}
|
|
|
|
DirectCallMetadataHelper::DirectCallMetadataHelper(KernelReaderHelper* helper)
|
|
: MetadataHelper(helper, tag(), /* precompiler_only = */ true) {}
|
|
|
|
bool DirectCallMetadataHelper::ReadMetadata(intptr_t node_offset,
|
|
NameIndex* target_name,
|
|
bool* check_receiver_for_null) {
|
|
intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
|
|
if (md_offset < 0) {
|
|
return false;
|
|
}
|
|
|
|
AlternativeReadingScopeWithNewData 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,
|
|
ConstantReader* constant_reader)
|
|
: MetadataHelper(helper, tag(), /* precompiler_only = */ true),
|
|
constant_reader_(constant_reader) {}
|
|
|
|
InferredTypeMetadata InferredTypeMetadataHelper::GetInferredType(
|
|
intptr_t node_offset,
|
|
bool read_constant) {
|
|
const intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
|
|
if (md_offset < 0) {
|
|
return InferredTypeMetadata(kDynamicCid,
|
|
InferredTypeMetadata::kFlagNullable);
|
|
}
|
|
|
|
AlternativeReadingScopeWithNewData alt(&helper_->reader_,
|
|
&H.metadata_payloads(), md_offset);
|
|
|
|
const NameIndex kernel_name = helper_->ReadCanonicalNameReference();
|
|
const uint8_t flags = helper_->ReadByte();
|
|
|
|
const Object* constant_value = &Object::null_object();
|
|
if ((flags & InferredTypeMetadata::kFlagConstant) != 0) {
|
|
const intptr_t constant_offset = helper_->ReadUInt();
|
|
if (read_constant) {
|
|
constant_value = &Object::ZoneHandle(
|
|
H.zone(), constant_reader_->ReadConstant(constant_offset));
|
|
}
|
|
}
|
|
|
|
if (H.IsRoot(kernel_name)) {
|
|
ASSERT((flags & InferredTypeMetadata::kFlagConstant) == 0);
|
|
return InferredTypeMetadata(kDynamicCid, flags);
|
|
}
|
|
|
|
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, flags, *constant_value);
|
|
}
|
|
|
|
void ProcedureAttributesMetadata::InitializeFromFlags(uint8_t flags) {
|
|
const int kMethodOrSetterCalledDynamicallyBit = 1 << 0;
|
|
const int kNonThisUsesBit = 1 << 1;
|
|
const int kTearOffUsesBit = 1 << 2;
|
|
const int kThisUsesBit = 1 << 3;
|
|
const int kGetterCalledDynamicallyBit = 1 << 4;
|
|
|
|
method_or_setter_called_dynamically =
|
|
(flags & kMethodOrSetterCalledDynamicallyBit) != 0;
|
|
getter_called_dynamically = (flags & kGetterCalledDynamicallyBit) != 0;
|
|
has_this_uses = (flags & kThisUsesBit) != 0;
|
|
has_non_this_uses = (flags & kNonThisUsesBit) != 0;
|
|
has_tearoff_uses = (flags & kTearOffUsesBit) != 0;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
AlternativeReadingScopeWithNewData alt(&helper_->reader_,
|
|
&H.metadata_payloads(), md_offset);
|
|
|
|
const uint8_t flags = helper_->ReadByte();
|
|
metadata->InitializeFromFlags(flags);
|
|
metadata->method_or_setter_selector_id = helper_->ReadUInt();
|
|
metadata->getter_selector_id = helper_->ReadUInt();
|
|
return true;
|
|
}
|
|
|
|
ProcedureAttributesMetadata
|
|
ProcedureAttributesMetadataHelper::GetProcedureAttributes(
|
|
intptr_t node_offset) {
|
|
ProcedureAttributesMetadata metadata;
|
|
ReadMetadata(node_offset, &metadata);
|
|
return metadata;
|
|
}
|
|
|
|
ObfuscationProhibitionsMetadataHelper::ObfuscationProhibitionsMetadataHelper(
|
|
KernelReaderHelper* helper)
|
|
: MetadataHelper(helper, tag(), /* precompiler_only = */ true) {}
|
|
|
|
void ObfuscationProhibitionsMetadataHelper::ReadMetadata(intptr_t node_offset) {
|
|
intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
|
|
if (md_offset < 0) {
|
|
return;
|
|
}
|
|
|
|
AlternativeReadingScopeWithNewData alt(&helper_->reader_,
|
|
&H.metadata_payloads(), md_offset);
|
|
Obfuscator O(Thread::Current(), String::Handle());
|
|
|
|
intptr_t len = helper_->ReadUInt32();
|
|
for (int i = 0; i < len; ++i) {
|
|
StringIndex name = helper_->ReadStringReference();
|
|
O.PreventRenaming(translation_helper_.DartSymbolPlain(name));
|
|
}
|
|
return;
|
|
}
|
|
|
|
LoadingUnitsMetadataHelper::LoadingUnitsMetadataHelper(
|
|
KernelReaderHelper* helper)
|
|
: MetadataHelper(helper, tag(), /* precompiler_only = */ true) {}
|
|
|
|
void LoadingUnitsMetadataHelper::ReadMetadata(intptr_t node_offset) {
|
|
intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
|
|
if (md_offset < 0) {
|
|
return;
|
|
}
|
|
|
|
AlternativeReadingScopeWithNewData alt(&helper_->reader_,
|
|
&H.metadata_payloads(), md_offset);
|
|
|
|
Thread* thread = Thread::Current();
|
|
Zone* zone = thread->zone();
|
|
intptr_t unit_count = helper_->ReadUInt();
|
|
Array& loading_units = Array::Handle(zone, Array::New(unit_count + 1));
|
|
LoadingUnit& unit = LoadingUnit::Handle(zone);
|
|
LoadingUnit& parent = LoadingUnit::Handle(zone);
|
|
Library& lib = Library::Handle(zone);
|
|
|
|
for (int i = 0; i < unit_count; i++) {
|
|
intptr_t id = helper_->ReadUInt();
|
|
unit = LoadingUnit::New();
|
|
unit.set_id(id);
|
|
|
|
intptr_t parent_id = helper_->ReadUInt();
|
|
RELEASE_ASSERT(parent_id < id);
|
|
parent ^= loading_units.At(parent_id);
|
|
RELEASE_ASSERT(parent.IsNull() == (parent_id == 0));
|
|
unit.set_parent(parent);
|
|
|
|
intptr_t library_count = helper_->ReadUInt();
|
|
for (intptr_t j = 0; j < library_count; j++) {
|
|
const String& uri =
|
|
translation_helper_.DartSymbolPlain(helper_->ReadStringReference());
|
|
lib = Library::LookupLibrary(thread, uri);
|
|
if (lib.IsNull()) {
|
|
FATAL1("Missing library: %s\n", uri.ToCString());
|
|
}
|
|
lib.set_loading_unit(unit);
|
|
}
|
|
|
|
loading_units.SetAt(id, unit);
|
|
}
|
|
|
|
ObjectStore* object_store = IG->object_store();
|
|
ASSERT(object_store->loading_units() == Array::null());
|
|
object_store->set_loading_units(loading_units);
|
|
}
|
|
|
|
CallSiteAttributesMetadataHelper::CallSiteAttributesMetadataHelper(
|
|
KernelReaderHelper* helper,
|
|
TypeTranslator* type_translator)
|
|
: MetadataHelper(helper, tag(), /* precompiler_only = */ false),
|
|
type_translator_(*type_translator) {}
|
|
|
|
bool CallSiteAttributesMetadataHelper::ReadMetadata(
|
|
intptr_t node_offset,
|
|
CallSiteAttributesMetadata* metadata) {
|
|
intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
|
|
if (md_offset < 0) {
|
|
return false;
|
|
}
|
|
|
|
AlternativeReadingScopeWithNewData alt(&helper_->reader_,
|
|
&H.metadata_payloads(), md_offset);
|
|
|
|
metadata->receiver_type = &type_translator_.BuildType();
|
|
return true;
|
|
}
|
|
|
|
CallSiteAttributesMetadata
|
|
CallSiteAttributesMetadataHelper::GetCallSiteAttributes(intptr_t node_offset) {
|
|
CallSiteAttributesMetadata metadata;
|
|
ReadMetadata(node_offset, &metadata);
|
|
return metadata;
|
|
}
|
|
|
|
TableSelectorMetadataHelper::TableSelectorMetadataHelper(
|
|
KernelReaderHelper* helper)
|
|
: MetadataHelper(helper, tag(), /* precompiler_only = */ true) {}
|
|
|
|
TableSelectorMetadata* TableSelectorMetadataHelper::GetTableSelectorMetadata(
|
|
Zone* zone) {
|
|
const intptr_t node_offset = GetComponentMetadataPayloadOffset();
|
|
const intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
|
|
if (md_offset < 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
AlternativeReadingScopeWithNewData alt(&helper_->reader_,
|
|
&H.metadata_payloads(), md_offset);
|
|
|
|
const intptr_t num_selectors = helper_->ReadUInt();
|
|
TableSelectorMetadata* metadata =
|
|
new (zone) TableSelectorMetadata(num_selectors);
|
|
for (intptr_t i = 0; i < num_selectors; i++) {
|
|
ReadTableSelectorInfo(&metadata->selectors[i]);
|
|
}
|
|
return metadata;
|
|
}
|
|
|
|
void TableSelectorMetadataHelper::ReadTableSelectorInfo(
|
|
TableSelectorInfo* info) {
|
|
info->call_count = helper_->ReadUInt();
|
|
uint8_t flags = helper_->ReadByte();
|
|
info->called_on_null = (flags & kCalledOnNullBit) != 0;
|
|
info->torn_off = (flags & kTornOffBit) != 0;
|
|
}
|
|
|
|
UnboxingInfoMetadataHelper::UnboxingInfoMetadataHelper(
|
|
KernelReaderHelper* helper)
|
|
: MetadataHelper(helper, tag(), /* precompiler_only = */ true) {}
|
|
|
|
UnboxingInfoMetadata* UnboxingInfoMetadataHelper::GetUnboxingInfoMetadata(
|
|
intptr_t node_offset) {
|
|
const intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
|
|
|
|
if (md_offset < 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
AlternativeReadingScopeWithNewData alt(&helper_->reader_,
|
|
&H.metadata_payloads(), md_offset);
|
|
|
|
const intptr_t num_args = helper_->ReadUInt();
|
|
const auto info = new (helper_->zone_) UnboxingInfoMetadata();
|
|
info->SetArgsCount(num_args);
|
|
for (intptr_t i = 0; i < num_args; i++) {
|
|
const auto arg_info = helper_->ReadByte();
|
|
assert(arg_info >= UnboxingInfoMetadata::kBoxed &&
|
|
arg_info < UnboxingInfoMetadata::kUnboxingCandidate);
|
|
info->unboxed_args_info[i] =
|
|
static_cast<UnboxingInfoMetadata::UnboxingInfoTag>(arg_info);
|
|
}
|
|
const auto return_info = helper_->ReadByte();
|
|
assert(return_info >= UnboxingInfoMetadata::kBoxed &&
|
|
return_info < UnboxingInfoMetadata::kUnboxingCandidate);
|
|
info->return_info =
|
|
static_cast<UnboxingInfoMetadata::UnboxingInfoTag>(return_info);
|
|
return info;
|
|
}
|
|
|
|
intptr_t KernelReaderHelper::ReaderOffset() const {
|
|
return reader_.offset();
|
|
}
|
|
|
|
void KernelReaderHelper::SetOffset(intptr_t offset) {
|
|
reader_.set_offset(offset);
|
|
}
|
|
|
|
void KernelReaderHelper::SkipBytes(intptr_t bytes) {
|
|
reader_.set_offset(ReaderOffset() + bytes);
|
|
}
|
|
|
|
bool KernelReaderHelper::ReadBool() {
|
|
return reader_.ReadBool();
|
|
}
|
|
|
|
uint8_t KernelReaderHelper::ReadByte() {
|
|
return reader_.ReadByte();
|
|
}
|
|
|
|
uint32_t KernelReaderHelper::ReadUInt() {
|
|
return reader_.ReadUInt();
|
|
}
|
|
|
|
uint32_t KernelReaderHelper::ReadUInt32() {
|
|
return reader_.ReadUInt32();
|
|
}
|
|
|
|
uint32_t KernelReaderHelper::PeekUInt() {
|
|
AlternativeReadingScope alt(&reader_);
|
|
return reader_.ReadUInt();
|
|
}
|
|
|
|
double KernelReaderHelper::ReadDouble() {
|
|
return reader_.ReadDouble();
|
|
}
|
|
|
|
uint32_t KernelReaderHelper::PeekListLength() {
|
|
AlternativeReadingScope alt(&reader_);
|
|
return reader_.ReadListLength();
|
|
}
|
|
|
|
intptr_t KernelReaderHelper::ReadListLength() {
|
|
return reader_.ReadListLength();
|
|
}
|
|
|
|
StringIndex KernelReaderHelper::ReadStringReference() {
|
|
return StringIndex(ReadUInt());
|
|
}
|
|
|
|
NameIndex KernelReaderHelper::ReadCanonicalNameReference() {
|
|
return reader_.ReadCanonicalNameReference();
|
|
}
|
|
|
|
NameIndex KernelReaderHelper::ReadInterfaceMemberNameReference() {
|
|
NameIndex name_index = reader_.ReadCanonicalNameReference();
|
|
NameIndex origin_name_index = reader_.ReadCanonicalNameReference();
|
|
if (!FLAG_precompiled_mode && origin_name_index != NameIndex::kInvalidName) {
|
|
// Reference to a skipped member signature target, return the origin target.
|
|
return origin_name_index;
|
|
}
|
|
return name_index;
|
|
}
|
|
|
|
StringIndex KernelReaderHelper::ReadNameAsStringIndex() {
|
|
StringIndex name_index = ReadStringReference(); // read name index.
|
|
if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
|
|
ReadUInt(); // read library index.
|
|
}
|
|
return name_index;
|
|
}
|
|
|
|
const String& KernelReaderHelper::ReadNameAsMethodName() {
|
|
StringIndex name_index = ReadStringReference(); // read name index.
|
|
if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
|
|
NameIndex library_reference =
|
|
ReadCanonicalNameReference(); // read library index.
|
|
return H.DartMethodName(library_reference, name_index);
|
|
} else {
|
|
return H.DartMethodName(NameIndex(), name_index);
|
|
}
|
|
}
|
|
|
|
const String& KernelReaderHelper::ReadNameAsSetterName() {
|
|
StringIndex name_index = ReadStringReference(); // read name index.
|
|
if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
|
|
NameIndex library_reference =
|
|
ReadCanonicalNameReference(); // read library index.
|
|
return H.DartSetterName(library_reference, name_index);
|
|
} else {
|
|
return H.DartSetterName(NameIndex(), name_index);
|
|
}
|
|
}
|
|
|
|
const String& KernelReaderHelper::ReadNameAsGetterName() {
|
|
StringIndex name_index = ReadStringReference(); // read name index.
|
|
if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
|
|
NameIndex library_reference =
|
|
ReadCanonicalNameReference(); // read library index.
|
|
return H.DartGetterName(library_reference, name_index);
|
|
} else {
|
|
return H.DartGetterName(NameIndex(), name_index);
|
|
}
|
|
}
|
|
|
|
const String& KernelReaderHelper::ReadNameAsFieldName() {
|
|
StringIndex name_index = ReadStringReference(); // read name index.
|
|
if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
|
|
NameIndex library_reference =
|
|
ReadCanonicalNameReference(); // read library index.
|
|
return H.DartFieldName(library_reference, name_index);
|
|
} else {
|
|
return H.DartFieldName(NameIndex(), name_index);
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipFlags() {
|
|
ReadFlags();
|
|
}
|
|
|
|
void KernelReaderHelper::SkipStringReference() {
|
|
ReadUInt();
|
|
}
|
|
|
|
void KernelReaderHelper::SkipConstantReference() {
|
|
ReadUInt();
|
|
}
|
|
|
|
void KernelReaderHelper::SkipCanonicalNameReference() {
|
|
ReadUInt();
|
|
}
|
|
|
|
void KernelReaderHelper::SkipInterfaceMemberNameReference() {
|
|
SkipCanonicalNameReference();
|
|
SkipCanonicalNameReference();
|
|
}
|
|
|
|
void KernelReaderHelper::ReportUnexpectedTag(const char* variant, Tag tag) {
|
|
FATAL3("Unexpected tag %d (%s) in ?, expected %s", tag, Reader::TagName(tag),
|
|
variant);
|
|
}
|
|
|
|
void KernelReaderHelper::ReadUntilFunctionNode() {
|
|
const Tag tag = PeekTag();
|
|
if (tag == kProcedure) {
|
|
ProcedureHelper procedure_helper(this);
|
|
procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction);
|
|
// Now at start of FunctionNode.
|
|
} else if (tag == kConstructor) {
|
|
ConstructorHelper constructor_helper(this);
|
|
constructor_helper.ReadUntilExcluding(ConstructorHelper::kFunction);
|
|
// Now at start of FunctionNode.
|
|
// Notice that we also have a list of initializers after that!
|
|
} else if (tag == kFunctionNode) {
|
|
// Already at start of FunctionNode.
|
|
} else {
|
|
ReportUnexpectedTag("a procedure, a constructor or a function node", tag);
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipDartType() {
|
|
Tag tag = ReadTag();
|
|
switch (tag) {
|
|
case kInvalidType:
|
|
case kDynamicType:
|
|
case kVoidType:
|
|
// those contain nothing.
|
|
return;
|
|
case kNeverType:
|
|
ReadNullability();
|
|
return;
|
|
case kInterfaceType:
|
|
SkipInterfaceType(false);
|
|
return;
|
|
case kSimpleInterfaceType:
|
|
SkipInterfaceType(true);
|
|
return;
|
|
case kFunctionType:
|
|
SkipFunctionType(false);
|
|
return;
|
|
case kSimpleFunctionType:
|
|
SkipFunctionType(true);
|
|
return;
|
|
case kTypedefType:
|
|
ReadNullability(); // read nullability.
|
|
ReadUInt(); // read index for canonical name.
|
|
SkipListOfDartTypes(); // read list of types.
|
|
return;
|
|
case kTypeParameterType:
|
|
ReadNullability(); // read nullability.
|
|
ReadUInt(); // read index for parameter.
|
|
SkipOptionalDartType(); // read bound bound.
|
|
return;
|
|
default:
|
|
ReportUnexpectedTag("type", tag);
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipOptionalDartType() {
|
|
Tag tag = ReadTag(); // read tag.
|
|
if (tag == kNothing) {
|
|
return;
|
|
}
|
|
ASSERT(tag == kSomething);
|
|
|
|
SkipDartType(); // read type.
|
|
}
|
|
|
|
void KernelReaderHelper::SkipInterfaceType(bool simple) {
|
|
ReadNullability(); // read nullability.
|
|
ReadUInt(); // read klass_name.
|
|
if (!simple) {
|
|
SkipListOfDartTypes(); // read list of types.
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipFunctionType(bool simple) {
|
|
ReadNullability(); // read nullability.
|
|
|
|
if (!simple) {
|
|
SkipTypeParametersList(); // read type_parameters.
|
|
ReadUInt(); // read required parameter count.
|
|
ReadUInt(); // read total parameter count.
|
|
}
|
|
|
|
SkipListOfDartTypes(); // read positional_parameters types.
|
|
|
|
if (!simple) {
|
|
const intptr_t named_count =
|
|
ReadListLength(); // read named_parameters list length.
|
|
for (intptr_t i = 0; i < named_count; ++i) {
|
|
// read string reference (i.e. named_parameters[i].name).
|
|
SkipStringReference();
|
|
SkipDartType(); // read named_parameters[i].type.
|
|
SkipBytes(1); // read flags
|
|
}
|
|
}
|
|
|
|
if (!simple) {
|
|
SkipOptionalDartType(); // read typedef type.
|
|
}
|
|
|
|
SkipDartType(); // read return type.
|
|
}
|
|
|
|
void KernelReaderHelper::SkipStatementList() {
|
|
intptr_t list_length = ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < list_length; ++i) {
|
|
SkipStatement(); // read ith expression.
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipListOfExpressions() {
|
|
intptr_t list_length = ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < list_length; ++i) {
|
|
SkipExpression(); // read ith expression.
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipListOfDartTypes() {
|
|
intptr_t list_length = ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < list_length; ++i) {
|
|
SkipDartType(); // read ith type.
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipListOfStrings() {
|
|
intptr_t list_length = ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < list_length; ++i) {
|
|
SkipStringReference(); // read ith string index.
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipListOfVariableDeclarations() {
|
|
intptr_t list_length = ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < list_length; ++i) {
|
|
SkipVariableDeclaration(); // read ith variable declaration.
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipTypeParametersList() {
|
|
intptr_t list_length = ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < list_length; ++i) {
|
|
TypeParameterHelper helper(this);
|
|
helper.Finish();
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipInitializer() {
|
|
Tag tag = ReadTag();
|
|
ReadByte(); // read isSynthetic flag.
|
|
switch (tag) {
|
|
case kInvalidInitializer:
|
|
return;
|
|
case kFieldInitializer:
|
|
SkipCanonicalNameReference(); // read field_reference.
|
|
SkipExpression(); // read value.
|
|
return;
|
|
case kSuperInitializer:
|
|
ReadPosition(); // read position.
|
|
SkipCanonicalNameReference(); // read target_reference.
|
|
SkipArguments(); // read arguments.
|
|
return;
|
|
case kRedirectingInitializer:
|
|
ReadPosition(); // read position.
|
|
SkipCanonicalNameReference(); // read target_reference.
|
|
SkipArguments(); // read arguments.
|
|
return;
|
|
case kLocalInitializer:
|
|
SkipVariableDeclaration(); // read variable.
|
|
return;
|
|
case kAssertInitializer:
|
|
SkipStatement();
|
|
return;
|
|
default:
|
|
ReportUnexpectedTag("initializer", tag);
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipExpression() {
|
|
uint8_t payload = 0;
|
|
Tag tag = ReadTag(&payload);
|
|
switch (tag) {
|
|
case kInvalidExpression:
|
|
ReadPosition();
|
|
SkipStringReference();
|
|
return;
|
|
case kVariableGet:
|
|
ReadPosition(); // read position.
|
|
ReadUInt(); // read kernel position.
|
|
ReadUInt(); // read relative variable index.
|
|
SkipOptionalDartType(); // read promoted type.
|
|
return;
|
|
case kSpecializedVariableGet:
|
|
ReadPosition(); // read position.
|
|
ReadUInt(); // read kernel position.
|
|
return;
|
|
case kVariableSet:
|
|
ReadPosition(); // read position.
|
|
ReadUInt(); // read kernel position.
|
|
ReadUInt(); // read relative variable index.
|
|
SkipExpression(); // read expression.
|
|
return;
|
|
case kSpecializedVariableSet:
|
|
ReadPosition(); // read position.
|
|
ReadUInt(); // read kernel position.
|
|
SkipExpression(); // read expression.
|
|
return;
|
|
case kPropertyGet:
|
|
ReadPosition(); // read position.
|
|
SkipExpression(); // read receiver.
|
|
SkipName(); // read name.
|
|
SkipInterfaceMemberNameReference(); // read interface_target_reference.
|
|
return;
|
|
case kPropertySet:
|
|
ReadPosition(); // read position.
|
|
SkipExpression(); // read receiver.
|
|
SkipName(); // read name.
|
|
SkipExpression(); // read value.
|
|
SkipInterfaceMemberNameReference(); // read interface_target_reference.
|
|
return;
|
|
case kSuperPropertyGet:
|
|
ReadPosition(); // read position.
|
|
SkipName(); // read name.
|
|
SkipInterfaceMemberNameReference(); // read interface_target_reference.
|
|
return;
|
|
case kSuperPropertySet:
|
|
ReadPosition(); // read position.
|
|
SkipName(); // read name.
|
|
SkipExpression(); // read value.
|
|
SkipInterfaceMemberNameReference(); // read interface_target_reference.
|
|
return;
|
|
case kStaticGet:
|
|
ReadPosition(); // read position.
|
|
SkipCanonicalNameReference(); // read target_reference.
|
|
return;
|
|
case kStaticSet:
|
|
ReadPosition(); // read position.
|
|
SkipCanonicalNameReference(); // read target_reference.
|
|
SkipExpression(); // read expression.
|
|
return;
|
|
case kMethodInvocation:
|
|
ReadFlags(); // read flags.
|
|
ReadPosition(); // read position.
|
|
SkipExpression(); // read receiver.
|
|
SkipName(); // read name.
|
|
SkipArguments(); // read arguments.
|
|
SkipInterfaceMemberNameReference(); // read interface_target_reference.
|
|
return;
|
|
case kSuperMethodInvocation:
|
|
ReadPosition(); // read position.
|
|
SkipName(); // read name.
|
|
SkipArguments(); // read arguments.
|
|
SkipInterfaceMemberNameReference(); // read interface_target_reference.
|
|
return;
|
|
case kStaticInvocation:
|
|
ReadPosition(); // read position.
|
|
SkipCanonicalNameReference(); // read procedure_reference.
|
|
SkipArguments(); // read arguments.
|
|
return;
|
|
case kConstructorInvocation:
|
|
ReadPosition(); // read position.
|
|
SkipCanonicalNameReference(); // read target_reference.
|
|
SkipArguments(); // read arguments.
|
|
return;
|
|
case kNot:
|
|
SkipExpression(); // read expression.
|
|
return;
|
|
case kNullCheck:
|
|
ReadPosition(); // read position.
|
|
SkipExpression(); // read expression.
|
|
return;
|
|
case kLogicalExpression:
|
|
SkipExpression(); // read left.
|
|
SkipBytes(1); // read operator.
|
|
SkipExpression(); // read right.
|
|
return;
|
|
case kConditionalExpression:
|
|
SkipExpression(); // read condition.
|
|
SkipExpression(); // read then.
|
|
SkipExpression(); // read otherwise.
|
|
SkipOptionalDartType(); // read unused static type.
|
|
return;
|
|
case kStringConcatenation:
|
|
ReadPosition(); // read position.
|
|
SkipListOfExpressions(); // read list of expressions.
|
|
return;
|
|
case kIsExpression:
|
|
ReadPosition(); // read position.
|
|
if (translation_helper_.info().kernel_binary_version() >= 38) {
|
|
SkipFlags(); // read flags.
|
|
}
|
|
SkipExpression(); // read operand.
|
|
SkipDartType(); // read type.
|
|
return;
|
|
case kAsExpression:
|
|
ReadPosition(); // read position.
|
|
SkipFlags(); // read flags.
|
|
SkipExpression(); // read operand.
|
|
SkipDartType(); // read type.
|
|
return;
|
|
case kTypeLiteral:
|
|
SkipDartType(); // read type.
|
|
return;
|
|
case kThisExpression:
|
|
return;
|
|
case kRethrow:
|
|
ReadPosition(); // read position.
|
|
return;
|
|
case kThrow:
|
|
ReadPosition(); // read position.
|
|
SkipExpression(); // read expression.
|
|
return;
|
|
case kListLiteral:
|
|
ReadPosition(); // read position.
|
|
SkipDartType(); // read type.
|
|
SkipListOfExpressions(); // read list of expressions.
|
|
return;
|
|
case kSetLiteral:
|
|
// Set literals are currently desugared in the frontend and will not
|
|
// reach the VM. See http://dartbug.com/35124 for discussion.
|
|
UNREACHABLE();
|
|
return;
|
|
case kMapLiteral: {
|
|
ReadPosition(); // read position.
|
|
SkipDartType(); // read key type.
|
|
SkipDartType(); // read value type.
|
|
intptr_t list_length = ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < list_length; ++i) {
|
|
SkipExpression(); // read ith key.
|
|
SkipExpression(); // read ith value.
|
|
}
|
|
return;
|
|
}
|
|
case kFunctionExpression:
|
|
ReadPosition(); // read position.
|
|
SkipFunctionNode(); // read function node.
|
|
return;
|
|
case kLet:
|
|
ReadPosition(); // read position.
|
|
SkipVariableDeclaration(); // read variable declaration.
|
|
SkipExpression(); // read expression.
|
|
return;
|
|
case kBlockExpression:
|
|
SkipStatementList();
|
|
SkipExpression(); // read expression.
|
|
return;
|
|
case kInstantiation:
|
|
SkipExpression(); // read expression.
|
|
SkipListOfDartTypes(); // read type arguments.
|
|
return;
|
|
case kBigIntLiteral:
|
|
SkipStringReference(); // read string reference.
|
|
return;
|
|
case kStringLiteral:
|
|
SkipStringReference(); // read string reference.
|
|
return;
|
|
case kSpecializedIntLiteral:
|
|
return;
|
|
case kNegativeIntLiteral:
|
|
ReadUInt(); // read value.
|
|
return;
|
|
case kPositiveIntLiteral:
|
|
ReadUInt(); // read value.
|
|
return;
|
|
case kDoubleLiteral:
|
|
ReadDouble(); // read value.
|
|
return;
|
|
case kTrueLiteral:
|
|
return;
|
|
case kFalseLiteral:
|
|
return;
|
|
case kNullLiteral:
|
|
return;
|
|
case kConstantExpression:
|
|
ReadPosition(); // read position.
|
|
SkipDartType(); // read type.
|
|
SkipConstantReference();
|
|
return;
|
|
case kLoadLibrary:
|
|
case kCheckLibraryIsLoaded:
|
|
ReadUInt(); // skip library index
|
|
return;
|
|
case kConstStaticInvocation:
|
|
case kConstConstructorInvocation:
|
|
case kConstListLiteral:
|
|
case kConstSetLiteral:
|
|
case kConstMapLiteral:
|
|
case kSymbolLiteral:
|
|
// Const invocations and const literals are removed by the
|
|
// constant evaluator.
|
|
case kListConcatenation:
|
|
case kSetConcatenation:
|
|
case kMapConcatenation:
|
|
case kInstanceCreation:
|
|
case kFileUriExpression:
|
|
// Collection concatenation, instance creation operations and
|
|
// in-expression URI changes are internal to the front end and
|
|
// removed by the constant evaluator.
|
|
default:
|
|
ReportUnexpectedTag("expression", tag);
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipStatement() {
|
|
Tag tag = ReadTag(); // read tag.
|
|
switch (tag) {
|
|
case kExpressionStatement:
|
|
SkipExpression(); // read expression.
|
|
return;
|
|
case kBlock:
|
|
ReadPosition(); // read file offset.
|
|
ReadPosition(); // read file end offset.
|
|
SkipStatementList();
|
|
return;
|
|
case kEmptyStatement:
|
|
return;
|
|
case kAssertBlock:
|
|
SkipStatementList();
|
|
return;
|
|
case kAssertStatement:
|
|
SkipExpression(); // Read condition.
|
|
ReadPosition(); // read condition start offset.
|
|
ReadPosition(); // read condition end offset.
|
|
if (ReadTag() == kSomething) {
|
|
SkipExpression(); // read (rest of) message.
|
|
}
|
|
return;
|
|
case kLabeledStatement:
|
|
SkipStatement(); // read body.
|
|
return;
|
|
case kBreakStatement:
|
|
ReadPosition(); // read position.
|
|
ReadUInt(); // read target_index.
|
|
return;
|
|
case kWhileStatement:
|
|
ReadPosition(); // read position.
|
|
SkipExpression(); // read condition.
|
|
SkipStatement(); // read body.
|
|
return;
|
|
case kDoStatement:
|
|
ReadPosition(); // read position.
|
|
SkipStatement(); // read body.
|
|
SkipExpression(); // read condition.
|
|
return;
|
|
case kForStatement: {
|
|
ReadPosition(); // read position.
|
|
SkipListOfVariableDeclarations(); // read variables.
|
|
Tag tag = ReadTag(); // Read first part of condition.
|
|
if (tag == kSomething) {
|
|
SkipExpression(); // read rest of condition.
|
|
}
|
|
SkipListOfExpressions(); // read updates.
|
|
SkipStatement(); // read body.
|
|
return;
|
|
}
|
|
case kForInStatement:
|
|
case kAsyncForInStatement:
|
|
ReadPosition(); // read position.
|
|
ReadPosition(); // read body position.
|
|
SkipVariableDeclaration(); // read variable.
|
|
SkipExpression(); // read iterable.
|
|
SkipStatement(); // read body.
|
|
return;
|
|
case kSwitchStatement: {
|
|
ReadPosition(); // read position.
|
|
SkipExpression(); // read condition.
|
|
int case_count = ReadListLength(); // read number of cases.
|
|
for (intptr_t i = 0; i < case_count; ++i) {
|
|
int expression_count = ReadListLength(); // read number of expressions.
|
|
for (intptr_t j = 0; j < expression_count; ++j) {
|
|
ReadPosition(); // read jth position.
|
|
SkipExpression(); // read jth expression.
|
|
}
|
|
ReadBool(); // read is_default.
|
|
SkipStatement(); // read body.
|
|
}
|
|
return;
|
|
}
|
|
case kContinueSwitchStatement:
|
|
ReadPosition(); // read position.
|
|
ReadUInt(); // read target_index.
|
|
return;
|
|
case kIfStatement:
|
|
ReadPosition(); // read position.
|
|
SkipExpression(); // read condition.
|
|
SkipStatement(); // read then.
|
|
SkipStatement(); // read otherwise.
|
|
return;
|
|
case kReturnStatement: {
|
|
ReadPosition(); // read position
|
|
Tag tag = ReadTag(); // read (first part of) expression.
|
|
if (tag == kSomething) {
|
|
SkipExpression(); // read (rest of) expression.
|
|
}
|
|
return;
|
|
}
|
|
case kTryCatch: {
|
|
SkipStatement(); // read body.
|
|
ReadByte(); // read flags
|
|
intptr_t catch_count = ReadListLength(); // read number of catches.
|
|
for (intptr_t i = 0; i < catch_count; ++i) {
|
|
ReadPosition(); // read position.
|
|
SkipDartType(); // read guard.
|
|
tag = ReadTag(); // read first part of exception.
|
|
if (tag == kSomething) {
|
|
SkipVariableDeclaration(); // read exception.
|
|
}
|
|
tag = ReadTag(); // read first part of stack trace.
|
|
if (tag == kSomething) {
|
|
SkipVariableDeclaration(); // read stack trace.
|
|
}
|
|
SkipStatement(); // read body.
|
|
}
|
|
return;
|
|
}
|
|
case kTryFinally:
|
|
SkipStatement(); // read body.
|
|
SkipStatement(); // read finalizer.
|
|
return;
|
|
case kYieldStatement: {
|
|
ReadPosition(); // read position.
|
|
ReadByte(); // read flags.
|
|
SkipExpression(); // read expression.
|
|
return;
|
|
}
|
|
case kVariableDeclaration:
|
|
SkipVariableDeclaration(); // read variable declaration.
|
|
return;
|
|
case kFunctionDeclaration:
|
|
ReadPosition(); // read position.
|
|
SkipVariableDeclaration(); // read variable.
|
|
SkipFunctionNode(); // read function node.
|
|
return;
|
|
default:
|
|
ReportUnexpectedTag("statement", tag);
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipFunctionNode() {
|
|
FunctionNodeHelper function_node_helper(this);
|
|
function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
|
|
}
|
|
|
|
void KernelReaderHelper::SkipName() {
|
|
StringIndex name_index = ReadStringReference(); // read name index.
|
|
if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
|
|
SkipCanonicalNameReference(); // read library index.
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipArguments() {
|
|
ReadUInt(); // read argument count.
|
|
|
|
SkipListOfDartTypes(); // read list of types.
|
|
SkipListOfExpressions(); // read positionals.
|
|
|
|
// List of named.
|
|
intptr_t list_length = ReadListLength(); // read list length.
|
|
for (intptr_t i = 0; i < list_length; ++i) {
|
|
SkipStringReference(); // read ith name index.
|
|
SkipExpression(); // read ith expression.
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipVariableDeclaration() {
|
|
VariableDeclarationHelper helper(this);
|
|
helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd);
|
|
}
|
|
|
|
void KernelReaderHelper::SkipLibraryCombinator() {
|
|
ReadBool(); // read is_show.
|
|
intptr_t name_count = ReadUInt(); // read list length.
|
|
for (intptr_t j = 0; j < name_count; ++j) {
|
|
ReadUInt(); // read ith entry of name_indices.
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipLibraryDependency() {
|
|
ReadPosition(); // read file offset.
|
|
ReadFlags();
|
|
SkipListOfExpressions(); // Annotations.
|
|
ReadCanonicalNameReference();
|
|
ReadStringReference(); // Name.
|
|
intptr_t combinator_count = ReadListLength();
|
|
for (intptr_t i = 0; i < combinator_count; ++i) {
|
|
SkipLibraryCombinator();
|
|
}
|
|
}
|
|
|
|
void KernelReaderHelper::SkipLibraryPart() {
|
|
SkipListOfExpressions(); // Read annotations.
|
|
SkipStringReference(); // Read part URI index.
|
|
}
|
|
|
|
void KernelReaderHelper::SkipLibraryTypedef() {
|
|
SkipCanonicalNameReference(); // read canonical name.
|
|
ReadUInt(); // read source_uri_index.
|
|
ReadPosition(); // read position.
|
|
SkipStringReference(); // read name index.
|
|
SkipListOfExpressions(); // read annotations.
|
|
SkipTypeParametersList(); // read type parameters.
|
|
SkipDartType(); // read type.
|
|
SkipTypeParametersList(); // read type parameters of function type.
|
|
SkipListOfVariableDeclarations(); // read positional parameters.
|
|
SkipListOfVariableDeclarations(); // read named parameters.
|
|
}
|
|
|
|
TokenPosition KernelReaderHelper::ReadPosition() {
|
|
TokenPosition position = reader_.ReadPosition();
|
|
RecordTokenPosition(position);
|
|
return position;
|
|
}
|
|
|
|
intptr_t KernelReaderHelper::SourceTableFieldCountFromFirstLibraryOffset() {
|
|
return SourceTableFieldCountFromFirstLibraryOffset41Plus;
|
|
}
|
|
|
|
intptr_t KernelReaderHelper::SourceTableSize() {
|
|
AlternativeReadingScope alt(&reader_);
|
|
intptr_t library_count = reader_.ReadFromIndexNoReset(
|
|
reader_.size(), LibraryCountFieldCountFromEnd, 1, 0);
|
|
|
|
const intptr_t count_from_first_library_offset =
|
|
SourceTableFieldCountFromFirstLibraryOffset();
|
|
|
|
intptr_t source_table_offset = reader_.ReadFromIndexNoReset(
|
|
reader_.size(),
|
|
LibraryCountFieldCountFromEnd + 1 + library_count + 1 +
|
|
count_from_first_library_offset,
|
|
1, 0);
|
|
SetOffset(source_table_offset); // read source table offset.
|
|
return reader_.ReadUInt32(); // read source table size.
|
|
}
|
|
|
|
intptr_t KernelReaderHelper::GetOffsetForSourceInfo(intptr_t index) {
|
|
AlternativeReadingScope alt(&reader_);
|
|
intptr_t library_count = reader_.ReadFromIndexNoReset(
|
|
reader_.size(), LibraryCountFieldCountFromEnd, 1, 0);
|
|
|
|
const intptr_t count_from_first_library_offset =
|
|
SourceTableFieldCountFromFirstLibraryOffset();
|
|
|
|
intptr_t source_table_offset = reader_.ReadFromIndexNoReset(
|
|
reader_.size(),
|
|
LibraryCountFieldCountFromEnd + 1 + library_count + 1 +
|
|
count_from_first_library_offset,
|
|
1, 0);
|
|
intptr_t next_field_offset = reader_.ReadUInt32();
|
|
SetOffset(source_table_offset);
|
|
intptr_t size = reader_.ReadUInt32(); // read source table size.
|
|
|
|
return reader_.ReadFromIndexNoReset(next_field_offset, 0, size, index);
|
|
}
|
|
|
|
String& KernelReaderHelper::SourceTableUriFor(intptr_t index) {
|
|
AlternativeReadingScope alt(&reader_);
|
|
SetOffset(GetOffsetForSourceInfo(index));
|
|
intptr_t size = ReadUInt(); // read uri List<byte> size.
|
|
return H.DartString(reader_.BufferAt(ReaderOffset()), size, Heap::kOld);
|
|
}
|
|
|
|
const String& KernelReaderHelper::GetSourceFor(intptr_t index) {
|
|
AlternativeReadingScope alt(&reader_);
|
|
SetOffset(GetOffsetForSourceInfo(index));
|
|
SkipBytes(ReadUInt()); // skip uri.
|
|
intptr_t size = ReadUInt(); // read source List<byte> size.
|
|
ASSERT(size >= 0);
|
|
if (size == 0) {
|
|
return Symbols::Empty();
|
|
} else {
|
|
return H.DartString(reader_.BufferAt(ReaderOffset()), size, Heap::kOld);
|
|
}
|
|
}
|
|
|
|
TypedDataPtr KernelReaderHelper::GetLineStartsFor(intptr_t index) {
|
|
// Line starts are delta encoded. So get the max delta first so that we
|
|
// can store them as tighly as possible.
|
|
AlternativeReadingScope alt(&reader_);
|
|
SetOffset(GetOffsetForSourceInfo(index));
|
|
SkipBytes(ReadUInt()); // skip uri.
|
|
SkipBytes(ReadUInt()); // skip source.
|
|
const intptr_t line_start_count = ReadUInt();
|
|
return reader_.ReadLineStartsData(line_start_count);
|
|
}
|
|
|
|
String& KernelReaderHelper::SourceTableImportUriFor(intptr_t index,
|
|
uint32_t binaryVersion) {
|
|
if (binaryVersion < 22) {
|
|
return SourceTableUriFor(index);
|
|
}
|
|
|
|
AlternativeReadingScope alt(&reader_);
|
|
SetOffset(GetOffsetForSourceInfo(index));
|
|
SkipBytes(ReadUInt()); // skip uri.
|
|
SkipBytes(ReadUInt()); // skip source.
|
|
const intptr_t line_start_count = ReadUInt(); // read number of line start
|
|
// entries.
|
|
for (intptr_t i = 0; i < line_start_count; ++i) {
|
|
ReadUInt();
|
|
}
|
|
|
|
intptr_t size = ReadUInt(); // read import uri List<byte> size.
|
|
return H.DartString(reader_.BufferAt(ReaderOffset()), size, Heap::kOld);
|
|
}
|
|
|
|
ExternalTypedDataPtr KernelReaderHelper::GetConstantCoverageFor(
|
|
intptr_t index) {
|
|
AlternativeReadingScope alt(&reader_);
|
|
SetOffset(GetOffsetForSourceInfo(index));
|
|
SkipBytes(ReadUInt()); // skip uri.
|
|
SkipBytes(ReadUInt()); // skip source.
|
|
const intptr_t line_start_count = ReadUInt(); // read number of line start
|
|
// entries.
|
|
for (intptr_t i = 0; i < line_start_count; ++i) {
|
|
ReadUInt();
|
|
}
|
|
|
|
SkipBytes(ReadUInt()); // skip import uri.
|
|
|
|
intptr_t start_offset = ReaderOffset();
|
|
|
|
// Read past "constant coverage constructors".
|
|
const intptr_t constant_coverage_constructors = ReadUInt();
|
|
for (intptr_t i = 0; i < constant_coverage_constructors; ++i) {
|
|
ReadUInt();
|
|
}
|
|
|
|
intptr_t end_offset = ReaderOffset();
|
|
|
|
return reader_.ExternalDataFromTo(start_offset, end_offset);
|
|
}
|
|
|
|
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,
|
|
const FunctionType* innermost_signature,
|
|
Zone* Z)
|
|
: active_class_(active_class), saved_(*active_class) {
|
|
active_class_->enclosing = innermost_signature;
|
|
|
|
intptr_t num_params = 0;
|
|
|
|
Function& f = Function::Handle(Z);
|
|
TypeArguments& f_params = TypeArguments::Handle(Z);
|
|
for (f = innermost.ptr(); 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.ptr(); 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 FunctionType* innermost_signature,
|
|
const TypeArguments& new_params,
|
|
Zone* Z)
|
|
: active_class_(active_class), saved_(*active_class) {
|
|
active_class_->enclosing = innermost_signature;
|
|
|
|
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,
|
|
ConstantReader* constant_reader,
|
|
ActiveClass* active_class,
|
|
bool finalize,
|
|
bool apply_canonical_type_erasure,
|
|
bool in_constant_context)
|
|
: helper_(helper),
|
|
constant_reader_(constant_reader),
|
|
translation_helper_(helper->translation_helper_),
|
|
active_class_(active_class),
|
|
type_parameter_scope_(NULL),
|
|
inferred_type_metadata_helper_(helper_, constant_reader_),
|
|
unboxing_info_metadata_helper_(helper_),
|
|
zone_(translation_helper_.zone()),
|
|
result_(AbstractType::Handle(translation_helper_.zone())),
|
|
finalize_(finalize),
|
|
apply_canonical_type_erasure_(apply_canonical_type_erasure),
|
|
in_constant_context_(in_constant_context) {}
|
|
|
|
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_.ptr());
|
|
}
|
|
|
|
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_.ptr());
|
|
}
|
|
|
|
void TypeTranslator::BuildTypeInternal() {
|
|
Tag tag = helper_->ReadTag();
|
|
switch (tag) {
|
|
case kInvalidType:
|
|
case kDynamicType:
|
|
result_ = Object::dynamic_type().ptr();
|
|
break;
|
|
case kVoidType:
|
|
result_ = Object::void_type().ptr();
|
|
break;
|
|
case kNeverType: {
|
|
Nullability nullability = helper_->ReadNullability();
|
|
if (apply_canonical_type_erasure_ &&
|
|
nullability != Nullability::kNullable) {
|
|
nullability = Nullability::kLegacy;
|
|
}
|
|
result_ = Type::Handle(Z, IG->object_store()->never_type())
|
|
.ToNullability(nullability, Heap::kOld);
|
|
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`.
|
|
|
|
Nullability nullability = helper_->ReadNullability();
|
|
if (apply_canonical_type_erasure_ && nullability != Nullability::kNullable) {
|
|
nullability = Nullability::kLegacy;
|
|
}
|
|
|
|
NameIndex klass_name =
|
|
helper_->ReadCanonicalNameReference(); // read klass_name.
|
|
|
|
const Class& klass = Class::Handle(Z, H.LookupClassByKernelClass(klass_name));
|
|
ASSERT(!klass.IsNull());
|
|
if (simple) {
|
|
if (finalize_ || klass.is_type_finalized()) {
|
|
// Fast path for non-generic types: retrieve or populate the class's only
|
|
// canonical type (as long as only one nullability variant is used), which
|
|
// is its declaration type.
|
|
result_ = klass.DeclarationType();
|
|
result_ = Type::Cast(result_).ToNullability(nullability, Heap::kOld);
|
|
} else {
|
|
// Note that the type argument vector is not yet extended.
|
|
result_ = Type::New(klass, Object::null_type_arguments(), nullability);
|
|
}
|
|
return;
|
|
}
|
|
|
|
intptr_t length =
|
|
helper_->ReadListLength(); // read type_arguments list length.
|
|
const TypeArguments& type_arguments =
|
|
BuildTypeArguments(length); // read type arguments.
|
|
result_ = Type::New(klass, type_arguments, nullability);
|
|
result_ = result_.NormalizeFutureOrType(Heap::kOld);
|
|
if (finalize_) {
|
|
ASSERT(active_class_->klass != NULL);
|
|
result_ = ClassFinalizer::FinalizeType(result_);
|
|
}
|
|
}
|
|
|
|
void TypeTranslator::BuildFunctionType(bool simple) {
|
|
const intptr_t num_enclosing_type_arguments =
|
|
active_class_->enclosing != NULL
|
|
? active_class_->enclosing->NumTypeArguments()
|
|
: 0;
|
|
Nullability nullability = helper_->ReadNullability();
|
|
if (apply_canonical_type_erasure_ && nullability != Nullability::kNullable) {
|
|
nullability = Nullability::kLegacy;
|
|
}
|
|
FunctionType& signature = FunctionType::ZoneHandle(
|
|
Z, FunctionType::New(num_enclosing_type_arguments, nullability));
|
|
|
|
// Suspend finalization of types inside this one. They will be finalized after
|
|
// the whole function type is constructed.
|
|
bool finalize = finalize_;
|
|
finalize_ = false;
|
|
intptr_t type_parameter_count = 0;
|
|
|
|
if (!simple) {
|
|
type_parameter_count = helper_->ReadListLength();
|
|
LoadAndSetupTypeParameters(
|
|
active_class_, Object::null_function(), Object::null_class(), signature,
|
|
type_parameter_count, active_class_->klass->nnbd_mode());
|
|
}
|
|
|
|
ActiveTypeParametersScope scope(
|
|
active_class_, &signature,
|
|
TypeArguments::Handle(Z, signature.type_parameters()), Z);
|
|
|
|
if (!simple) {
|
|
LoadAndSetupBounds(active_class_, Object::null_function(),
|
|
Object::null_class(), signature, type_parameter_count);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// The additional first parameter is the receiver (type set to dynamic).
|
|
const intptr_t kImplicitClosureParam = 1;
|
|
signature.set_num_implicit_parameters(kImplicitClosureParam);
|
|
signature.set_num_fixed_parameters(kImplicitClosureParam + required_count);
|
|
signature.SetNumOptionalParameters(all_count - required_count,
|
|
positional_count > required_count);
|
|
|
|
signature.set_parameter_types(Array::Handle(
|
|
Z, Array::New(kImplicitClosureParam + all_count, Heap::kOld)));
|
|
signature.CreateNameArrayIncludingFlags(Heap::kOld);
|
|
|
|
intptr_t pos = 0;
|
|
signature.SetParameterTypeAt(pos, AbstractType::dynamic_type());
|
|
signature.SetParameterNameAt(pos, H.DartSymbolPlain("_receiver_"));
|
|
++pos;
|
|
for (intptr_t i = 0; i < positional_count; ++i, ++pos) {
|
|
BuildTypeInternal(); // read ith positional parameter.
|
|
signature.SetParameterTypeAt(pos, result_);
|
|
signature.SetParameterNameAt(pos, H.DartSymbolPlain("noname"));
|
|
}
|
|
|
|
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.
|
|
const uint8_t flags = helper_->ReadFlags(); // read flags
|
|
signature.SetParameterTypeAt(pos, result_);
|
|
signature.SetParameterNameAt(pos, name);
|
|
if ((flags & static_cast<uint8_t>(NamedTypeFlags::kIsRequired)) != 0) {
|
|
signature.SetIsRequiredAt(pos);
|
|
}
|
|
}
|
|
}
|
|
signature.TruncateUnusedParameterFlags();
|
|
|
|
if (!simple) {
|
|
helper_->SkipOptionalDartType(); // read typedef type.
|
|
}
|
|
|
|
BuildTypeInternal(); // read return type.
|
|
signature.set_result_type(result_);
|
|
|
|
finalize_ = finalize;
|
|
|
|
if (finalize_) {
|
|
signature ^= ClassFinalizer::FinalizeType(signature);
|
|
}
|
|
|
|
result_ = signature.ptr();
|
|
}
|
|
|
|
void TypeTranslator::BuildTypeParameterType() {
|
|
Nullability nullability = helper_->ReadNullability();
|
|
if (apply_canonical_type_erasure_ && nullability != Nullability::kNullable) {
|
|
nullability = Nullability::kLegacy;
|
|
}
|
|
|
|
intptr_t parameter_index = helper_->ReadUInt(); // read parameter index.
|
|
helper_->SkipOptionalDartType(); // read bound.
|
|
|
|
// If the type is from a constant, the parameter index isn't offset by the
|
|
// enclosing context.
|
|
if (!in_constant_context_) {
|
|
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.
|
|
const auto& type_param =
|
|
TypeParameter::CheckedHandle(Z, class_types.TypeAt(parameter_index));
|
|
result_ = type_param.ToNullability(nullability, Heap::kOld);
|
|
active_class_->RecordDerivedTypeParameter(Z, type_param,
|
|
TypeParameter::Cast(result_));
|
|
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) {
|
|
const auto& type_param = TypeParameter::CheckedHandle(
|
|
Z, class_types.TypeAt(parameter_index));
|
|
result_ = type_param.ToNullability(nullability, Heap::kOld);
|
|
active_class_->RecordDerivedTypeParameter(
|
|
Z, type_param, TypeParameter::Cast(result_));
|
|
return;
|
|
}
|
|
parameter_index -= class_types.Length();
|
|
}
|
|
// Factory function should not be considered as procedure.
|
|
intptr_t procedure_type_parameter_count =
|
|
(active_class_->MemberIsProcedure() &&
|
|
!active_class_->MemberIsFactoryProcedure())
|
|
? active_class_->MemberTypeParameterCount(Z)
|
|
: 0;
|
|
if (procedure_type_parameter_count > 0) {
|
|
if (procedure_type_parameter_count > parameter_index) {
|
|
const auto& type_param = TypeParameter::CheckedHandle(
|
|
Z,
|
|
TypeArguments::Handle(Z, active_class_->member->type_parameters())
|
|
.TypeAt(parameter_index));
|
|
result_ = type_param.ToNullability(nullability, Heap::kOld);
|
|
active_class_->RecordDerivedTypeParameter(
|
|
Z, type_param, TypeParameter::Cast(result_));
|
|
if (finalize_) {
|
|
result_ = ClassFinalizer::FinalizeType(result_);
|
|
}
|
|
return;
|
|
}
|
|
parameter_index -= procedure_type_parameter_count;
|
|
}
|
|
}
|
|
}
|
|
if (active_class_->local_type_parameters != NULL) {
|
|
if (parameter_index < active_class_->local_type_parameters->Length()) {
|
|
const auto& type_param = TypeParameter::CheckedHandle(
|
|
Z, active_class_->local_type_parameters->TypeAt(parameter_index));
|
|
result_ = type_param.ToNullability(nullability, Heap::kOld);
|
|
active_class_->RecordDerivedTypeParameter(Z, type_param,
|
|
TypeParameter::Cast(result_));
|
|
if (finalize_) {
|
|
result_ = ClassFinalizer::FinalizeType(result_);
|
|
}
|
|
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(); // read ith type.
|
|
type_arguments.SetTypeAt(i, result_);
|
|
}
|
|
|
|
if (finalize_) {
|
|
type_arguments = type_arguments.Canonicalize(Thread::Current(), nullptr);
|
|
}
|
|
}
|
|
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));
|
|
if (finalize_) {
|
|
type ^= ClassFinalizer::FinalizeType(type);
|
|
}
|
|
|
|
const TypeArguments& instantiated_type_arguments =
|
|
TypeArguments::ZoneHandle(Z, type.arguments());
|
|
return instantiated_type_arguments;
|
|
}
|
|
|
|
void TypeTranslator::LoadAndSetupTypeParameters(
|
|
ActiveClass* active_class,
|
|
const Function& function,
|
|
const Class& parameterized_class,
|
|
const FunctionType& parameterized_signature,
|
|
intptr_t type_parameter_count,
|
|
const NNBDMode nnbd_mode) {
|
|
ASSERT(parameterized_class.IsNull() != parameterized_signature.IsNull());
|
|
ASSERT(type_parameter_count >= 0);
|
|
if (type_parameter_count == 0) {
|
|
return;
|
|
}
|
|
|
|
// The finalized index of a type parameter can only be determined if the
|
|
// length of the flattened type argument vector is known, which in turn can
|
|
// only be determined after the super type and its class have been loaded.
|
|
// Due to the added complexity of loading classes out of order from the kernel
|
|
// file, class type parameter indices are not finalized during class loading.
|
|
// However, function type parameter indices can be immediately finalized.
|
|
|
|
// 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);
|
|
|
|
const Nullability nullability = (nnbd_mode == NNBDMode::kOptedInLib)
|
|
? Nullability::kNonNullable
|
|
: Nullability::kLegacy;
|
|
|
|
// - Create array of [TypeParameter] objects (without bound).
|
|
// - Create array of [String] objects.
|
|
type_parameters = TypeArguments::New(type_parameter_count);
|
|
intptr_t offset = 0;
|
|
if (!parameterized_class.IsNull()) {
|
|
ASSERT(parameterized_class.type_parameters() == TypeArguments::null());
|
|
parameterized_class.set_type_parameters(type_parameters);
|
|
} else {
|
|
ASSERT(parameterized_signature.type_parameters() == TypeArguments::null());
|
|
parameterized_signature.set_type_parameters(type_parameters);
|
|
offset = parameterized_signature.NumParentTypeArguments();
|
|
if (!function.IsNull()) {
|
|
function.SetNumTypeParameters(type_parameter_count);
|
|
}
|
|
}
|
|
|
|
const Library& lib = Library::Handle(Z, active_class->klass->library());
|
|
{
|
|
AlternativeReadingScope alt(&helper_->reader_);
|
|
String& name = String::Handle(Z);
|
|
for (intptr_t i = 0; i < type_parameter_count; i++) {
|
|
TypeParameterHelper helper(helper_);
|
|
helper.Finish();
|
|
if (parameterized_class.IsNull() && function.IsNull()) {
|
|
// Erase provided name and use a canonical one instead.
|
|
name = Symbols::NewFormatted(H.thread(), "X%" Pd, offset + i);
|
|
} else {
|
|
name = H.DartIdentifier(lib, helper.name_index_).ptr();
|
|
}
|
|
// Bounds are filled later in LoadAndSetupBounds as bound types may
|
|
// reference type parameters which are not created yet.
|
|
parameter = TypeParameter::New(
|
|
parameterized_class, offset, offset + i, name, null_bound,
|
|
helper.IsGenericCovariantImpl(), nullability);
|
|
type_parameters.SetTypeAt(i, parameter);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TypeTranslator::LoadAndSetupBounds(
|
|
ActiveClass* active_class,
|
|
const Function& function,
|
|
const Class& parameterized_class,
|
|
const FunctionType& parameterized_signature,
|
|
intptr_t type_parameter_count) {
|
|
ASSERT(parameterized_class.IsNull() != parameterized_signature.IsNull());
|
|
ASSERT(type_parameter_count >= 0);
|
|
if (type_parameter_count == 0) {
|
|
return;
|
|
}
|
|
|
|
const TypeArguments& type_parameters =
|
|
TypeArguments::Handle(Z, !parameterized_class.IsNull()
|
|
? parameterized_class.type_parameters()
|
|
: parameterized_signature.type_parameters());
|
|
TypeParameter& parameter = TypeParameter::Handle(Z);
|
|
|
|
// Fill in the bounds and default arguments of all [TypeParameter]s.
|
|
for (intptr_t i = 0; i < type_parameter_count; i++) {
|
|
TypeParameterHelper helper(helper_);
|
|
helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
|
|
|
|
parameter ^= type_parameters.TypeAt(i);
|
|
AbstractType& bound = BuildTypeWithoutFinalization(); // read ith bound.
|
|
parameter.set_bound(bound);
|
|
helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kDefaultType);
|
|
AbstractType& default_arg = BuildTypeWithoutFinalization();
|
|
parameter.set_default_argument(default_arg);
|
|
helper.Finish();
|
|
}
|
|
|
|
// Note that function.UpdateCachedDefaultTypeArguments() is called in
|
|
// function.set_signature() and is not required here.
|
|
|
|
// Fix bounds and default arguments in all derived type parameters (with
|
|
// different nullabilities).
|
|
const intptr_t offset = !parameterized_signature.IsNull()
|
|
? parameterized_signature.NumParentTypeArguments()
|
|
: 0;
|
|
if (active_class->derived_type_parameters != nullptr) {
|
|
auto& derived = TypeParameter::Handle(Z);
|
|
auto& type = AbstractType::Handle(Z);
|
|
for (intptr_t i = 0, n = active_class->derived_type_parameters->Length();
|
|
i < n; ++i) {
|
|
derived ^= active_class->derived_type_parameters->At(i);
|
|
if (derived.bound() == AbstractType::null() &&
|
|
((!parameterized_class.IsNull() &&
|
|
derived.parameterized_class() == parameterized_class.ptr()) ||
|
|
(!parameterized_signature.IsNull() &&
|
|
derived.parameterized_class() == Class::null() &&
|
|
derived.index() >= offset &&
|
|
derived.index() < offset + type_parameter_count))) {
|
|
parameter ^= type_parameters.TypeAt(derived.index() - offset);
|
|
type = parameter.bound();
|
|
derived.set_bound(type);
|
|
type = parameter.default_argument();
|
|
derived.set_default_argument(type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const Type& TypeTranslator::ReceiverType(const Class& klass) {
|
|
ASSERT(!klass.IsNull());
|
|
// Note that if klass is _Closure, the returned type will be _Closure,
|
|
// and not the signature type.
|
|
Type& type = Type::ZoneHandle(Z);
|
|
if (finalize_ || klass.is_type_finalized()) {
|
|
type = klass.DeclarationType();
|
|
} else {
|
|
type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()),
|
|
Nullability::kNonNullable);
|
|
}
|
|
return type;
|
|
}
|
|
|
|
static void SetupUnboxingInfoOfParameter(const Function& function,
|
|
intptr_t param_index,
|
|
const UnboxingInfoMetadata* metadata) {
|
|
const intptr_t param_pos =
|
|
param_index + (function.HasThisParameter() ? 1 : 0);
|
|
|
|
if (param_pos < function.maximum_unboxed_parameter_count()) {
|
|
switch (metadata->unboxed_args_info[param_index]) {
|
|
case UnboxingInfoMetadata::kUnboxedIntCandidate:
|
|
function.set_unboxed_integer_parameter_at(param_pos);
|
|
break;
|
|
case UnboxingInfoMetadata::kUnboxedDoubleCandidate:
|
|
if (FlowGraphCompiler::SupportsUnboxedDoubles()) {
|
|
function.set_unboxed_double_parameter_at(param_pos);
|
|
}
|
|
break;
|
|
case UnboxingInfoMetadata::kUnboxingCandidate:
|
|
UNREACHABLE();
|
|
break;
|
|
case UnboxingInfoMetadata::kBoxed:
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SetupUnboxingInfoOfReturnValue(
|
|
const Function& function,
|
|
const UnboxingInfoMetadata* metadata) {
|
|
switch (metadata->return_info) {
|
|
case UnboxingInfoMetadata::kUnboxedIntCandidate:
|
|
function.set_unboxed_integer_return();
|
|
break;
|
|
case UnboxingInfoMetadata::kUnboxedDoubleCandidate:
|
|
if (FlowGraphCompiler::SupportsUnboxedDoubles()) {
|
|
function.set_unboxed_double_return();
|
|
}
|
|
break;
|
|
case UnboxingInfoMetadata::kUnboxingCandidate:
|
|
UNREACHABLE();
|
|
break;
|
|
case UnboxingInfoMetadata::kBoxed:
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void TypeTranslator::SetupUnboxingInfoMetadata(const Function& function,
|
|
intptr_t library_kernel_offset) {
|
|
const intptr_t kernel_offset =
|
|
function.kernel_offset() + library_kernel_offset;
|
|
const auto unboxing_info =
|
|
unboxing_info_metadata_helper_.GetUnboxingInfoMetadata(kernel_offset);
|
|
|
|
// TODO(dartbug.com/32292): accept unboxed parameters and return value
|
|
// when FLAG_use_table_dispatch == false.
|
|
if (FLAG_precompiled_mode && unboxing_info != nullptr &&
|
|
FLAG_use_table_dispatch && FLAG_use_bare_instructions) {
|
|
for (intptr_t i = 0; i < unboxing_info->unboxed_args_info.length(); i++) {
|
|
SetupUnboxingInfoOfParameter(function, i, unboxing_info);
|
|
}
|
|
SetupUnboxingInfoOfReturnValue(function, unboxing_info);
|
|
}
|
|
}
|
|
|
|
void TypeTranslator::SetupUnboxingInfoMetadataForFieldAccessors(
|
|
const Function& field_accessor,
|
|
intptr_t library_kernel_offset) {
|
|
const intptr_t kernel_offset =
|
|
field_accessor.kernel_offset() + library_kernel_offset;
|
|
const auto unboxing_info =
|
|
unboxing_info_metadata_helper_.GetUnboxingInfoMetadata(kernel_offset);
|
|
|
|
// TODO(dartbug.com/32292): accept unboxed parameters and return value
|
|
// when FLAG_use_table_dispatch == false.
|
|
if (FLAG_precompiled_mode && unboxing_info != nullptr &&
|
|
FLAG_use_table_dispatch && FLAG_use_bare_instructions) {
|
|
if (field_accessor.IsImplicitSetterFunction()) {
|
|
for (intptr_t i = 0; i < unboxing_info->unboxed_args_info.length(); i++) {
|
|
SetupUnboxingInfoOfParameter(field_accessor, i, unboxing_info);
|
|
}
|
|
} else {
|
|
ASSERT(field_accessor.IsImplicitGetterFunction() ||
|
|
field_accessor.IsImplicitStaticGetterFunction());
|
|
SetupUnboxingInfoOfReturnValue(field_accessor, unboxing_info);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TypeTranslator::SetupFunctionParameters(
|
|
const Class& klass,
|
|
const Function& function,
|
|
bool is_method,
|
|
bool is_closure,
|
|
FunctionNodeHelper* function_node_helper) {
|
|
ASSERT(!(is_method && is_closure));
|
|
bool is_factory = function.IsFactory();
|
|
intptr_t extra_parameters = (is_method || is_closure || is_factory) ? 1 : 0;
|
|
|
|
const FunctionType& signature = FunctionType::Handle(Z, function.signature());
|
|
ASSERT(!signature.IsNull());
|
|
intptr_t type_parameter_count = 0;
|
|
if (!is_factory) {
|
|
type_parameter_count = helper_->ReadListLength();
|
|
LoadAndSetupTypeParameters(active_class_, function, Class::Handle(Z),
|
|
signature, type_parameter_count,
|
|
function.nnbd_mode());
|
|
}
|
|
|
|
ActiveTypeParametersScope scope(active_class_, function, &signature, Z);
|
|
|
|
if (!is_factory) {
|
|
LoadAndSetupBounds(active_class_, function, Class::Handle(Z), signature,
|
|
type_parameter_count);
|
|
function_node_helper->SetJustRead(FunctionNodeHelper::kTypeParameters);
|
|
}
|
|
|
|
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(); // read list length.
|
|
|
|
intptr_t named_parameter_count =
|
|
total_parameter_count - positional_parameter_count;
|
|
|
|
function.set_num_fixed_parameters(extra_parameters +
|
|
required_parameter_count);
|
|
if (named_parameter_count > 0) {
|
|
function.SetNumOptionalParameters(named_parameter_count, false);
|
|
} else {
|
|
function.SetNumOptionalParameters(
|
|
positional_parameter_count - required_parameter_count, true);
|
|
}
|
|
intptr_t parameter_count = extra_parameters + total_parameter_count;
|
|
|
|
intptr_t pos = 0;
|
|
if (parameter_count > 0) {
|
|
signature.set_parameter_types(
|
|
Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
|
|
signature.CreateNameArrayIncludingFlags(Heap::kOld);
|
|
if (is_method) {
|
|
ASSERT(!klass.IsNull());
|
|
signature.SetParameterTypeAt(pos, H.GetDeclarationType(klass));
|
|
signature.SetParameterNameAt(pos, Symbols::This());
|
|
pos++;
|
|
} else if (is_closure) {
|
|
signature.SetParameterTypeAt(pos, AbstractType::dynamic_type());
|
|
signature.SetParameterNameAt(pos, Symbols::ClosureParameter());
|
|
pos++;
|
|
} else if (is_factory) {
|
|
signature.SetParameterTypeAt(pos, AbstractType::dynamic_type());
|
|
signature.SetParameterNameAt(pos, Symbols::TypeArgumentsParameter());
|
|
pos++;
|
|
}
|
|
} else {
|
|
ASSERT(!is_method && !is_closure && !is_factory);
|
|
}
|
|
|
|
const Library& lib = Library::Handle(Z, active_class_->klass->library());
|
|
for (intptr_t i = 0; i < positional_parameter_count; ++i, ++pos) {
|
|
// Read ith variable declaration.
|
|
VariableDeclarationHelper helper(helper_);
|
|
helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
|
|
// The required flag should only be set on named parameters.
|
|
ASSERT(!helper.IsRequired());
|
|
const AbstractType& type = BuildTypeWithoutFinalization(); // read type.
|
|
Tag tag = helper_->ReadTag(); // read (first part of) initializer.
|
|
if (tag == kSomething) {
|
|
helper_->SkipExpression(); // read (actual) initializer.
|
|
}
|
|
|
|
signature.SetParameterTypeAt(pos, type);
|
|
signature.SetParameterNameAt(pos,
|
|
H.DartIdentifier(lib, helper.name_index_));
|
|
}
|
|
|
|
intptr_t named_parameter_count_check =
|
|
helper_->ReadListLength(); // read list length.
|
|
ASSERT(named_parameter_count_check == named_parameter_count);
|
|
for (intptr_t i = 0; i < named_parameter_count; ++i, ++pos) {
|
|
// Read ith variable declaration.
|
|
VariableDeclarationHelper helper(helper_);
|
|
helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
|
|
const AbstractType& type = BuildTypeWithoutFinalization(); // read type.
|
|
Tag tag = helper_->ReadTag(); // read (first part of) initializer.
|
|
if (tag == kSomething) {
|
|
helper_->SkipExpression(); // read (actual) initializer.
|
|
}
|
|
|
|
signature.SetParameterTypeAt(pos, type);
|
|
signature.SetParameterNameAt(pos,
|
|
H.DartIdentifier(lib, helper.name_index_));
|
|
if (helper.IsRequired()) {
|
|
signature.SetIsRequiredAt(pos);
|
|
}
|
|
}
|
|
signature.FinalizeNameArrays(function);
|
|
|
|
function_node_helper->SetJustRead(FunctionNodeHelper::kNamedParameters);
|
|
|
|
// The result type for generative constructors has already been set.
|
|
if (!function.IsGenerativeConstructor()) {
|
|
const AbstractType& return_type =
|
|
BuildTypeWithoutFinalization(); // read return type.
|
|
signature.set_result_type(return_type);
|
|
function_node_helper->SetJustRead(FunctionNodeHelper::kReturnType);
|
|
}
|
|
}
|
|
|
|
} // namespace kernel
|
|
} // namespace dart
|