Files
sdk/runtime/vm/compiler/frontend/kernel_translation_helper.h
T
Johnni Winther 9ca19cac6f [kernel] Change encoding of types in constants to not be offset by the context
Function type parameters in occurring in constants were using an offset
based on the context in which the constant first occurred. This meant
that function type parameters occurring in a generic context would have
a different offset that those occurring in a non-generic context.

The loading of .dill in ast_from_binary would read all constants outside
the context and would therefore get the indices wrong on generic
function types.

This CL changes the encoding of these type parameters to always use
a fresh context.

Closes #45415

TEST=pkg/front_end/testcases/generic_metadata/from_dill/main.dart

Change-Id: Ifdaedb4581f1e022c908fc58a58ceac3d7b0900e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193481
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2021-03-31 12:31:43 +00:00

1557 lines
48 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.
#ifndef RUNTIME_VM_COMPILER_FRONTEND_KERNEL_TRANSLATION_HELPER_H_
#define RUNTIME_VM_COMPILER_FRONTEND_KERNEL_TRANSLATION_HELPER_H_
#if defined(DART_PRECOMPILED_RUNTIME)
#error "AOT runtime should not use compiler sources (including header files)"
#endif // defined(DART_PRECOMPILED_RUNTIME)
#include "vm/compiler/backend/il.h" // For CompileType.
#include "vm/kernel.h"
#include "vm/kernel_binary.h"
#include "vm/object.h"
namespace dart {
namespace kernel {
class ConstantReader;
class KernelReaderHelper;
class TypeTranslator;
class TranslationHelper {
public:
explicit TranslationHelper(Thread* thread);
TranslationHelper(Thread* thread, Heap::Space space);
virtual ~TranslationHelper() {}
void Reset();
void InitFromScript(const Script& script);
void InitFromKernelProgramInfo(const KernelProgramInfo& info);
Thread* thread() { return thread_; }
Zone* zone() { return zone_; }
Isolate* isolate() { return isolate_; }
Heap::Space allocation_space() { return allocation_space_; }
// Access to strings.
const TypedData& string_offsets() const { return string_offsets_; }
void SetStringOffsets(const TypedData& string_offsets);
const ExternalTypedData& string_data() const { return string_data_; }
void SetStringData(const ExternalTypedData& string_data);
const TypedData& canonical_names() const { return canonical_names_; }
void SetCanonicalNames(const TypedData& canonical_names);
const ExternalTypedData& metadata_payloads() const {
return metadata_payloads_;
}
void SetMetadataPayloads(const ExternalTypedData& metadata_payloads);
const ExternalTypedData& metadata_mappings() const {
return metadata_mappings_;
}
void SetMetadataMappings(const ExternalTypedData& metadata_mappings);
// Access to previously evaluated constants from the constants table.
const Array& constants() { return constants_; }
void SetConstants(const Array& constants);
// Access to the raw bytes of the constants table.
const ExternalTypedData& constants_table() const { return constants_table_; }
void SetConstantsTable(const ExternalTypedData& constants_table);
KernelProgramInfo& info() { return info_; }
GrowableObjectArrayPtr EnsurePotentialPragmaFunctions();
void AddPotentialExtensionLibrary(const Library& library);
GrowableObjectArrayPtr GetPotentialExtensionLibraries();
void SetKernelProgramInfo(const KernelProgramInfo& info);
const KernelProgramInfo& GetKernelProgramInfo() const { return info_; }
intptr_t StringOffset(StringIndex index) const;
intptr_t StringSize(StringIndex index) const;
// The address of the backing store of the string with a given index. If the
// backing store is in the VM's heap this address is not safe for GC (call the
// function and use the result within a NoSafepointScope).
uint8_t* StringBuffer(StringIndex index) const;
uint8_t CharacterAt(StringIndex string_index, intptr_t index);
bool StringEquals(StringIndex string_index, const char* other);
// Accessors and predicates for canonical names.
NameIndex CanonicalNameParent(NameIndex name);
StringIndex CanonicalNameString(NameIndex name);
bool IsAdministrative(NameIndex name);
bool IsPrivate(NameIndex name);
bool IsRoot(NameIndex name);
bool IsLibrary(NameIndex name);
bool IsClass(NameIndex name);
bool IsMember(NameIndex name);
bool IsConstructor(NameIndex name);
bool IsProcedure(NameIndex name);
bool IsMethod(NameIndex name);
bool IsGetter(NameIndex name);
bool IsSetter(NameIndex name);
bool IsFactory(NameIndex name);
// For a member (field, constructor, or procedure) return the canonical name
// of the enclosing class or library.
NameIndex EnclosingName(NameIndex name);
InstancePtr Canonicalize(const Instance& instance);
const String& DartString(const char* content) {
return DartString(content, allocation_space_);
}
const String& DartString(const char* content, Heap::Space space);
String& DartString(StringIndex index) {
return DartString(index, allocation_space_);
}
String& DartString(StringIndex string_index, Heap::Space space);
String& DartString(const uint8_t* utf8_array,
intptr_t len,
Heap::Space space);
const String& DartString(const GrowableHandlePtrArray<const String>& pieces);
const String& DartSymbolPlain(const char* content) const;
String& DartSymbolPlain(StringIndex string_index) const;
const String& DartSymbolObfuscate(const char* content) const;
String& DartSymbolObfuscate(StringIndex string_index) const;
String& DartIdentifier(const Library& lib, StringIndex string_index);
const String& DartClassName(NameIndex kernel_class);
const String& DartConstructorName(NameIndex constructor);
const String& DartProcedureName(NameIndex procedure);
const String& DartSetterName(NameIndex setter);
const String& DartSetterName(NameIndex parent, StringIndex setter);
const String& DartGetterName(NameIndex getter);
const String& DartGetterName(NameIndex parent, StringIndex getter);
const String& DartFieldName(NameIndex field);
const String& DartFieldName(NameIndex parent, StringIndex field);
const String& DartMethodName(NameIndex method);
const String& DartMethodName(NameIndex parent, StringIndex method);
const String& DartFactoryName(NameIndex factory);
// A subclass overrides these when reading in the Kernel program in order to
// support recursive type expressions (e.g. for "implements X" ...
// annotations).
virtual LibraryPtr LookupLibraryByKernelLibrary(NameIndex library);
virtual ClassPtr LookupClassByKernelClass(NameIndex klass);
FieldPtr LookupFieldByKernelGetterOrSetter(NameIndex field,
bool required = true);
FunctionPtr LookupStaticMethodByKernelProcedure(NameIndex procedure,
bool required = true);
FunctionPtr LookupConstructorByKernelConstructor(NameIndex constructor);
FunctionPtr LookupConstructorByKernelConstructor(const Class& owner,
NameIndex constructor);
FunctionPtr LookupConstructorByKernelConstructor(
const Class& owner,
StringIndex constructor_name);
FunctionPtr LookupMethodByMember(NameIndex target, const String& method_name);
FunctionPtr LookupDynamicFunction(const Class& klass, const String& name);
Type& GetDeclarationType(const Class& klass);
void SetupFieldAccessorFunction(const Class& klass,
const Function& function,
const AbstractType& field_type);
void ReportError(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
void ReportError(const Script& script,
const TokenPosition position,
const char* format,
...) PRINTF_ATTRIBUTE(4, 5);
void ReportError(const Error& prev_error, const char* format, ...)
PRINTF_ATTRIBUTE(3, 4);
void ReportError(const Error& prev_error,
const Script& script,
const TokenPosition position,
const char* format,
...) PRINTF_ATTRIBUTE(5, 6);
void SetExpressionEvaluationFunction(const Function& function) {
ASSERT(expression_evaluation_function_ == nullptr);
expression_evaluation_function_ = &Function::Handle(zone_, function.ptr());
}
const Function& GetExpressionEvaluationFunction() {
if (expression_evaluation_function_ == nullptr) {
return Function::null_function();
}
return *expression_evaluation_function_;
}
void SetExpressionEvaluationRealClass(const Class& real_class) {
ASSERT(expression_evaluation_real_class_ == nullptr);
ASSERT(!real_class.IsNull());
expression_evaluation_real_class_ = &Class::Handle(zone_, real_class.ptr());
}
ClassPtr GetExpressionEvaluationRealClass() {
ASSERT(expression_evaluation_real_class_ != nullptr);
return expression_evaluation_real_class_->ptr();
}
private:
// This will mangle [name_to_modify] if necessary and make the result a symbol
// if asked. The result will be available in [name_to_modify] and it is also
// returned. If the name is private, the canonical name [parent] will be used
// to get the import URI of the library where the name is visible.
String& ManglePrivateName(NameIndex parent,
String* name_to_modify,
bool symbolize = true,
bool obfuscate = true);
String& ManglePrivateName(const Library& library,
String* name_to_modify,
bool symbolize = true,
bool obfuscate = true);
Thread* thread_;
Zone* zone_;
Isolate* isolate_;
Heap::Space allocation_space_;
TypedData& string_offsets_;
ExternalTypedData& string_data_;
TypedData& canonical_names_;
ExternalTypedData& metadata_payloads_;
ExternalTypedData& metadata_mappings_;
Array& constants_;
ExternalTypedData& constants_table_;
KernelProgramInfo& info_;
Smi& name_index_handle_;
GrowableObjectArray* potential_extension_libraries_ = nullptr;
Function* expression_evaluation_function_ = nullptr;
Class* expression_evaluation_real_class_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(TranslationHelper);
};
// Helper class that reads a kernel FunctionNode from binary.
//
// Use ReadUntilExcluding to read up to but not including a field.
// One can then for instance read the field from the call-site (and remember to
// call SetAt to inform this helper class), and then use this to read more.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class FunctionNodeHelper {
public:
enum Field {
kStart, // tag.
kPosition,
kEndPosition,
kAsyncMarker,
kDartAsyncMarker,
kTypeParameters,
kTotalParameterCount,
kRequiredParameterCount,
kPositionalParameters,
kNamedParameters,
kReturnType,
kFutureValueType,
kBody,
kEnd,
};
enum AsyncMarker : intptr_t {
kSync = 0,
kSyncStar = 1,
kAsync = 2,
kAsyncStar = 3,
kSyncYielding = 4,
};
explicit FunctionNodeHelper(KernelReaderHelper* helper) {
helper_ = helper;
next_read_ = kStart;
}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
TokenPosition position_ = TokenPosition::kNoSource;
TokenPosition end_position_ = TokenPosition::kNoSource;
AsyncMarker async_marker_;
AsyncMarker dart_async_marker_;
intptr_t total_parameter_count_ = 0;
intptr_t required_parameter_count_ = 0;
private:
KernelReaderHelper* helper_;
intptr_t next_read_;
DISALLOW_COPY_AND_ASSIGN(FunctionNodeHelper);
};
class TypeParameterHelper {
public:
enum Field {
kStart, // tag.
kFlags,
kAnnotations,
kVariance,
kName,
kBound,
kDefaultType,
kEnd,
};
enum Flag {
kIsGenericCovariantImpl = 1 << 0,
};
explicit TypeParameterHelper(KernelReaderHelper* helper) {
helper_ = helper;
next_read_ = kStart;
}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
void ReadUntilExcludingAndSetJustRead(Field field) {
ReadUntilExcluding(field);
SetJustRead(field);
}
void Finish() { ReadUntilExcluding(kEnd); }
bool IsGenericCovariantImpl() {
return (flags_ & kIsGenericCovariantImpl) != 0;
}
TokenPosition position_ = TokenPosition::kNoSource;
uint8_t flags_ = 0;
StringIndex name_index_;
private:
KernelReaderHelper* helper_;
intptr_t next_read_;
DISALLOW_COPY_AND_ASSIGN(TypeParameterHelper);
};
// Helper class that reads a kernel VariableDeclaration from binary.
//
// Use ReadUntilExcluding to read up to but not including a field.
// One can then for instance read the field from the call-site (and remember to
// call SetAt to inform this helper class), and then use this to read more.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class VariableDeclarationHelper {
public:
enum Field {
kPosition,
kEqualPosition,
kAnnotations,
kFlags,
kNameIndex,
kType,
kInitializer,
kEnd,
};
enum Flag {
kFinal = 1 << 0,
kConst = 1 << 1,
kCovariant = 1 << 3,
kIsGenericCovariantImpl = 1 << 4,
kLate = 1 << 5,
kRequired = 1 << 6,
kLowered = 1 << 7,
};
explicit VariableDeclarationHelper(KernelReaderHelper* helper)
: annotation_count_(0), helper_(helper), next_read_(kPosition) {}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
bool IsConst() const { return (flags_ & kConst) != 0; }
bool IsFinal() const { return (flags_ & kFinal) != 0; }
bool IsCovariant() const { return (flags_ & kCovariant) != 0; }
bool IsLate() const { return (flags_ & kLate) != 0; }
bool IsRequired() const { return (flags_ & kRequired) != 0; }
bool IsGenericCovariantImpl() const {
return (flags_ & kIsGenericCovariantImpl) != 0;
}
TokenPosition position_ = TokenPosition::kNoSource;
TokenPosition equals_position_ = TokenPosition::kNoSource;
uint8_t flags_ = 0;
StringIndex name_index_;
intptr_t annotation_count_ = 0;
private:
KernelReaderHelper* helper_;
intptr_t next_read_;
DISALLOW_COPY_AND_ASSIGN(VariableDeclarationHelper);
};
// Helper class that reads a kernel Field from binary.
//
// Use ReadUntilExcluding to read up to but not including a field.
// One can then for instance read the field from the call-site (and remember to
// call SetAt to inform this helper class), and then use this to read more.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class FieldHelper {
public:
enum Field {
kStart, // tag.
kCanonicalNameGetter,
kCanonicalNameSetter,
kSourceUriIndex,
kPosition,
kEndPosition,
kFlags,
kName,
kAnnotations,
kType,
kInitializer,
kEnd,
};
enum Flag {
kFinal = 1 << 0,
kConst = 1 << 1,
kStatic = 1 << 2,
kIsCovariant = 1 << 3,
kIsGenericCovariantImpl = 1 << 4,
kIsLate = 1 << 5,
kExtensionMember = 1 << 6,
};
explicit FieldHelper(KernelReaderHelper* helper)
: helper_(helper), next_read_(kStart) {}
FieldHelper(KernelReaderHelper* helper, intptr_t offset);
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
bool IsConst() { return (flags_ & kConst) != 0; }
bool IsFinal() { return (flags_ & kFinal) != 0; }
bool IsStatic() { return (flags_ & kStatic) != 0; }
bool IsCovariant() const { return (flags_ & kIsCovariant) != 0; }
bool IsGenericCovariantImpl() {
return (flags_ & kIsGenericCovariantImpl) != 0;
}
bool IsLate() const { return (flags_ & kIsLate) != 0; }
bool IsExtensionMember() const { return (flags_ & kExtensionMember) != 0; }
NameIndex canonical_name_getter_;
NameIndex canonical_name_setter_;
TokenPosition position_ = TokenPosition::kNoSource;
TokenPosition end_position_ = TokenPosition::kNoSource;
uint32_t flags_ = 0;
intptr_t source_uri_index_ = 0;
intptr_t annotation_count_ = 0;
private:
KernelReaderHelper* helper_;
intptr_t next_read_;
DISALLOW_COPY_AND_ASSIGN(FieldHelper);
};
// Helper class that reads a kernel Procedure from binary.
//
// Use ReadUntilExcluding to read up to but not including a field.
// One can then for instance read the field from the call-site (and remember to
// call SetAt to inform this helper class), and then use this to read more.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class ProcedureHelper {
public:
enum Field {
kStart, // tag.
kCanonicalName,
kSourceUriIndex,
kStartPosition,
kPosition,
kEndPosition,
kKind,
kStubKind,
kFlags,
kName,
kAnnotations,
kStubTarget,
kFunction,
kEnd,
};
enum Kind {
kMethod,
kGetter,
kSetter,
kOperator,
kFactory,
};
enum StubKind {
kRegularStubKind,
kAbstractForwardingStubKind,
kConcreteForwardingStubKind,
kNoSuchMethodForwarderStubKind,
kMemberSignatureStubKind,
kAbstractMixinStubKind,
kConcreteMixinStubKind,
};
enum Flag {
kStatic = 1 << 0,
kAbstract = 1 << 1,
kExternal = 1 << 2,
kConst = 1 << 3, // Only for external const factories.
// TODO(29841): Remove this line after the issue is resolved.
kRedirectingFactoryConstructor = 1 << 4,
kExtensionMember = 1 << 5,
kSyntheticProcedure = 1 << 7,
};
explicit ProcedureHelper(KernelReaderHelper* helper)
: helper_(helper), next_read_(kStart) {}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
bool IsStatic() const { return (flags_ & kStatic) != 0; }
bool IsAbstract() const { return (flags_ & kAbstract) != 0; }
bool IsExternal() const { return (flags_ & kExternal) != 0; }
bool IsConst() const { return (flags_ & kConst) != 0; }
bool IsForwardingStub() const {
return stub_kind_ == kAbstractForwardingStubKind ||
stub_kind_ == kConcreteForwardingStubKind;
}
bool IsRedirectingFactoryConstructor() const {
return (flags_ & kRedirectingFactoryConstructor) != 0;
}
bool IsNoSuchMethodForwarder() const {
return stub_kind_ == kNoSuchMethodForwarderStubKind;
}
bool IsExtensionMember() const { return (flags_ & kExtensionMember) != 0; }
bool IsMemberSignature() const {
return stub_kind_ == kMemberSignatureStubKind;
}
NameIndex canonical_name_;
TokenPosition start_position_ = TokenPosition::kNoSource;
TokenPosition position_ = TokenPosition::kNoSource;
TokenPosition end_position_ = TokenPosition::kNoSource;
Kind kind_;
uint32_t flags_ = 0;
intptr_t source_uri_index_ = 0;
intptr_t annotation_count_ = 0;
StubKind stub_kind_;
// Only valid if the 'isForwardingStub' flag is set.
NameIndex concrete_forwarding_stub_target_;
private:
KernelReaderHelper* helper_;
intptr_t next_read_;
DISALLOW_COPY_AND_ASSIGN(ProcedureHelper);
};
// Helper class that reads a kernel Constructor from binary.
//
// Use ReadUntilExcluding to read up to but not including a field.
// One can then for instance read the field from the call-site (and remember to
// call SetAt to inform this helper class), and then use this to read more.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class ConstructorHelper {
public:
enum Field {
kStart, // tag.
kCanonicalName,
kSourceUriIndex,
kStartPosition,
kPosition,
kEndPosition,
kFlags,
kName,
kAnnotations,
kFunction,
kInitializers,
kEnd,
};
enum Flag {
kConst = 1 << 0,
kExternal = 1 << 1,
kSynthetic = 1 << 2,
};
explicit ConstructorHelper(KernelReaderHelper* helper)
: helper_(helper), next_read_(kStart) {}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
bool IsExternal() { return (flags_ & kExternal) != 0; }
bool IsConst() { return (flags_ & kConst) != 0; }
bool IsSynthetic() { return (flags_ & kSynthetic) != 0; }
NameIndex canonical_name_;
TokenPosition start_position_ = TokenPosition::kNoSource;
TokenPosition position_ = TokenPosition::kNoSource;
TokenPosition end_position_ = TokenPosition::kNoSource;
uint8_t flags_ = 0;
intptr_t source_uri_index_ = 0;
intptr_t annotation_count_ = 0;
private:
KernelReaderHelper* helper_;
intptr_t next_read_;
DISALLOW_COPY_AND_ASSIGN(ConstructorHelper);
};
// Helper class that reads a kernel Class from binary.
//
// Use ReadUntilExcluding to read up to but not including a field.
// One can then for instance read the field from the call-site (and remember to
// call SetAt to inform this helper class), and then use this to read more.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class ClassHelper {
public:
enum Field {
kStart, // tag.
kCanonicalName,
kSourceUriIndex,
kStartPosition,
kPosition,
kEndPosition,
kFlags,
kNameIndex,
kAnnotations,
kTypeParameters,
kSuperClass,
kMixinType,
kImplementedClasses,
kFields,
kConstructors,
kProcedures,
kClassIndex,
kEnd,
};
enum Flag {
kIsAbstract = 1 << 0,
kIsEnumClass = 1 << 1,
kIsAnonymousMixin = 1 << 2,
kIsEliminatedMixin = 1 << 3,
kFlagMixinDeclaration = 1 << 4,
kHasConstConstructor = 1 << 5,
};
explicit ClassHelper(KernelReaderHelper* helper)
: helper_(helper), next_read_(kStart) {}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
bool is_abstract() const { return (flags_ & Flag::kIsAbstract) != 0; }
bool is_enum_class() const { return (flags_ & Flag::kIsEnumClass) != 0; }
bool is_transformed_mixin_application() const {
return (flags_ & Flag::kIsEliminatedMixin) != 0;
}
bool has_const_constructor() const {
return (flags_ & Flag::kHasConstConstructor) != 0;
}
NameIndex canonical_name_;
TokenPosition start_position_ = TokenPosition::kNoSource;
TokenPosition position_ = TokenPosition::kNoSource;
TokenPosition end_position_ = TokenPosition::kNoSource;
StringIndex name_index_;
intptr_t source_uri_index_ = 0;
intptr_t annotation_count_ = 0;
intptr_t procedure_count_ = 0;
uint8_t flags_ = 0;
private:
KernelReaderHelper* helper_;
intptr_t next_read_;
DISALLOW_COPY_AND_ASSIGN(ClassHelper);
};
// Helper class that reads a kernel Library from binary.
//
// Use ReadUntilExcluding to read up to but not including a field.
// One can then for instance read the field from the call-site (and remember to
// call SetAt to inform this helper class), and then use this to read more.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class LibraryHelper {
public:
enum Field {
kFlags,
kLanguageVersion /* from binary version 27 */,
kCanonicalName,
kName,
kSourceUriIndex,
kProblemsAsJson,
kAnnotations,
kDependencies,
// There are other fields in a library:
// * kAdditionalExports
// * kParts
// * kTypedefs
// * kClasses
// * kToplevelField
// * kToplevelProcedures
// * kSourceReferences
// * kLibraryIndex
// but we never read them via this helper and it makes extending the format
// harder to keep the code around.
};
enum Flag {
kSynthetic = 1 << 0,
kIsNonNullableByDefault = 1 << 1,
kNonNullableByDefaultCompiledModeBit1 = 1 << 2,
kNonNullableByDefaultCompiledModeBit2 = 1 << 3,
};
explicit LibraryHelper(KernelReaderHelper* helper, uint32_t binary_version)
: helper_(helper), binary_version_(binary_version), next_read_(kFlags) {}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
bool IsSynthetic() const { return (flags_ & kSynthetic) != 0; }
bool IsNonNullableByDefault() const {
return (flags_ & kIsNonNullableByDefault) != 0;
}
NNBDCompiledMode GetNonNullableByDefaultCompiledMode() const {
bool bit1 = (flags_ & kNonNullableByDefaultCompiledModeBit1) != 0;
bool bit2 = (flags_ & kNonNullableByDefaultCompiledModeBit2) != 0;
if (!bit1 && !bit2) return NNBDCompiledMode::kWeak;
if (bit1 && !bit2) return NNBDCompiledMode::kStrong;
if (bit1 && bit2) return NNBDCompiledMode::kAgnostic;
if (!bit1 && bit2) return NNBDCompiledMode::kInvalid;
UNREACHABLE();
}
uint8_t flags_ = 0;
NameIndex canonical_name_;
StringIndex name_index_;
intptr_t source_uri_index_ = 0;
private:
KernelReaderHelper* helper_;
uint32_t binary_version_;
intptr_t next_read_;
DISALLOW_COPY_AND_ASSIGN(LibraryHelper);
};
class LibraryDependencyHelper {
public:
enum Field {
kFileOffset,
kFlags,
kAnnotations,
kTargetLibrary,
kName,
kCombinators,
kEnd,
};
enum Flag {
Export = 1 << 0,
Deferred = 1 << 1,
};
enum CombinatorFlag {
Show = 1 << 0,
};
explicit LibraryDependencyHelper(KernelReaderHelper* helper)
: helper_(helper), next_read_(kFileOffset) {}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
uint8_t flags_ = 0;
StringIndex name_index_;
NameIndex target_library_canonical_name_;
intptr_t annotation_count_ = 0;
private:
KernelReaderHelper* helper_;
intptr_t next_read_;
DISALLOW_COPY_AND_ASSIGN(LibraryDependencyHelper);
};
// Base class for helpers accessing metadata of a certain kind.
// Assumes that metadata is accessed in linear order.
class MetadataHelper {
public:
MetadataHelper(KernelReaderHelper* helper,
const char* tag,
bool precompiler_only);
#if defined(DEBUG)
static void VerifyMetadataMappings(
const ExternalTypedData& metadata_mappings);
#endif
protected:
// Look for metadata mapping with node offset greater or equal than the given.
intptr_t FindMetadataMapping(intptr_t node_offset);
// Return offset of the metadata payload corresponding to the given node,
// or -1 if there is no metadata.
// Assumes metadata is accesses for nodes in linear order most of the time.
intptr_t GetNextMetadataPayloadOffset(intptr_t node_offset);
// Returns metadata associated with component.
intptr_t GetComponentMetadataPayloadOffset();
KernelReaderHelper* helper_;
TranslationHelper& translation_helper_;
private:
MetadataHelper();
void SetMetadataMappings(intptr_t mappings_offset, intptr_t mappings_num);
void ScanMetadataMappings();
const char* tag_;
bool mappings_scanned_;
bool precompiler_only_;
intptr_t mappings_offset_;
intptr_t mappings_num_;
intptr_t last_node_offset_;
intptr_t last_mapping_index_;
DISALLOW_COPY_AND_ASSIGN(MetadataHelper);
};
struct DirectCallMetadata {
DirectCallMetadata(const Function& target, bool check_receiver_for_null)
: target_(target), check_receiver_for_null_(check_receiver_for_null) {}
const Function& target_;
const bool check_receiver_for_null_;
};
// Helper class which provides access to direct call metadata.
class DirectCallMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.direct-call.metadata"; }
explicit DirectCallMetadataHelper(KernelReaderHelper* helper);
DirectCallMetadata GetDirectTargetForPropertyGet(intptr_t node_offset);
DirectCallMetadata GetDirectTargetForPropertySet(intptr_t node_offset);
DirectCallMetadata GetDirectTargetForMethodInvocation(intptr_t node_offset);
private:
bool ReadMetadata(intptr_t node_offset,
NameIndex* target_name,
bool* check_receiver_for_null);
DISALLOW_COPY_AND_ASSIGN(DirectCallMetadataHelper);
};
struct InferredTypeMetadata {
enum Flag {
kFlagNullable = 1 << 0,
kFlagInt = 1 << 1,
kFlagSkipCheck = 1 << 2,
kFlagConstant = 1 << 3,
kFlagReceiverNotInt = 1 << 4,
};
InferredTypeMetadata(intptr_t cid_,
uint8_t flags_,
const Object& constant_value_ = Object::null_object())
: cid(cid_), flags(flags_), constant_value(constant_value_) {}
const intptr_t cid;
const uint8_t flags;
const Object& constant_value;
bool IsTrivial() const {
return (cid == kDynamicCid) && (flags == kFlagNullable);
}
bool IsNullable() const { return (flags & kFlagNullable) != 0; }
bool IsInt() const {
return (flags & kFlagInt) != 0 || cid == kMintCid || cid == kSmiCid;
}
bool IsSkipCheck() const { return (flags & kFlagSkipCheck) != 0; }
bool IsConstant() const { return (flags & kFlagConstant) != 0; }
bool ReceiverNotInt() const { return (flags & kFlagReceiverNotInt) != 0; }
CompileType ToCompileType(Zone* zone) const {
if (IsInt() && cid == kDynamicCid) {
return CompileType::FromAbstractType(
Type::ZoneHandle(
zone, (IsNullable() ? Type::NullableIntType() : Type::IntType())),
IsNullable());
} else {
return CompileType::CreateNullable(IsNullable(), cid);
}
}
};
// Helper class which provides access to inferred type metadata.
class InferredTypeMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.inferred-type.metadata"; }
explicit InferredTypeMetadataHelper(KernelReaderHelper* helper,
ConstantReader* constant_reader);
InferredTypeMetadata GetInferredType(intptr_t node_offset,
bool read_constant = true);
private:
ConstantReader* constant_reader_;
DISALLOW_COPY_AND_ASSIGN(InferredTypeMetadataHelper);
};
struct ProcedureAttributesMetadata {
static const int32_t kInvalidSelectorId = 0;
bool method_or_setter_called_dynamically = true;
bool getter_called_dynamically = true;
bool has_this_uses = true;
bool has_non_this_uses = true;
bool has_tearoff_uses = true;
int32_t method_or_setter_selector_id = kInvalidSelectorId;
int32_t getter_selector_id = kInvalidSelectorId;
void InitializeFromFlags(uint8_t flags);
};
// Helper class which provides access to direct call metadata.
class ProcedureAttributesMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.procedure-attributes.metadata"; }
explicit ProcedureAttributesMetadataHelper(KernelReaderHelper* helper);
ProcedureAttributesMetadata GetProcedureAttributes(intptr_t node_offset);
private:
bool ReadMetadata(intptr_t node_offset,
ProcedureAttributesMetadata* metadata);
DISALLOW_COPY_AND_ASSIGN(ProcedureAttributesMetadataHelper);
};
class ObfuscationProhibitionsMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.obfuscation-prohibitions.metadata"; }
explicit ObfuscationProhibitionsMetadataHelper(KernelReaderHelper* helper);
void ReadProhibitions() { ReadMetadata(0); }
private:
void ReadMetadata(intptr_t node_offset);
DISALLOW_COPY_AND_ASSIGN(ObfuscationProhibitionsMetadataHelper);
};
class LoadingUnitsMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.loading-units.metadata"; }
explicit LoadingUnitsMetadataHelper(KernelReaderHelper* helper);
void ReadLoadingUnits() { ReadMetadata(0); }
private:
void ReadMetadata(intptr_t node_offset);
DISALLOW_COPY_AND_ASSIGN(LoadingUnitsMetadataHelper);
};
struct CallSiteAttributesMetadata {
const AbstractType* receiver_type = nullptr;
};
// Helper class which provides access to direct call metadata.
class CallSiteAttributesMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.call-site-attributes.metadata"; }
CallSiteAttributesMetadataHelper(KernelReaderHelper* helper,
TypeTranslator* type_translator);
CallSiteAttributesMetadata GetCallSiteAttributes(intptr_t node_offset);
private:
bool ReadMetadata(intptr_t node_offset, CallSiteAttributesMetadata* metadata);
TypeTranslator& type_translator_;
DISALLOW_COPY_AND_ASSIGN(CallSiteAttributesMetadataHelper);
};
// Information about a table selector computed by the TFA.
struct TableSelectorInfo {
int call_count = 0;
bool called_on_null = true;
bool torn_off = true;
};
// Collection of table selector information for all selectors in the program.
class TableSelectorMetadata : public ZoneAllocated {
public:
explicit TableSelectorMetadata(intptr_t num_selectors)
: selectors(num_selectors) {
selectors.FillWith(TableSelectorInfo(), 0, num_selectors);
}
GrowableArray<TableSelectorInfo> selectors;
DISALLOW_COPY_AND_ASSIGN(TableSelectorMetadata);
};
// Helper class which provides access to table selector metadata.
class TableSelectorMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.table-selector.metadata"; }
explicit TableSelectorMetadataHelper(KernelReaderHelper* helper);
TableSelectorMetadata* GetTableSelectorMetadata(Zone* zone);
private:
static const uint8_t kCalledOnNullBit = 1 << 0;
static const uint8_t kTornOffBit = 1 << 1;
void ReadTableSelectorInfo(TableSelectorInfo* info);
DISALLOW_COPY_AND_ASSIGN(TableSelectorMetadataHelper);
};
// Information about a function regarding unboxed parameters and return value.
class UnboxingInfoMetadata : public ZoneAllocated {
public:
enum UnboxingInfoTag {
kBoxed = 0,
kUnboxedIntCandidate = 1 << 0,
kUnboxedDoubleCandidate = 1 << 1,
kUnboxingCandidate = kUnboxedIntCandidate | kUnboxedDoubleCandidate,
};
UnboxingInfoMetadata() : unboxed_args_info(0) { return_info = kBoxed; }
void SetArgsCount(intptr_t num_args) {
ASSERT(unboxed_args_info.is_empty());
unboxed_args_info.SetLength(num_args);
unboxed_args_info.FillWith(kBoxed, 0, num_args);
}
GrowableArray<UnboxingInfoTag> unboxed_args_info;
UnboxingInfoTag return_info;
DISALLOW_COPY_AND_ASSIGN(UnboxingInfoMetadata);
};
// Helper class which provides access to unboxing information metadata.
class UnboxingInfoMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.unboxing-info.metadata"; }
explicit UnboxingInfoMetadataHelper(KernelReaderHelper* helper);
UnboxingInfoMetadata* GetUnboxingInfoMetadata(intptr_t node_offset);
DISALLOW_COPY_AND_ASSIGN(UnboxingInfoMetadataHelper);
};
class KernelReaderHelper {
public:
KernelReaderHelper(Zone* zone,
TranslationHelper* translation_helper,
const Script& script,
const ExternalTypedData& data,
intptr_t data_program_offset)
: zone_(zone),
translation_helper_(*translation_helper),
reader_(data),
script_(script),
data_program_offset_(data_program_offset) {}
KernelReaderHelper(Zone* zone,
TranslationHelper* translation_helper,
const ProgramBinary& binary,
intptr_t data_program_offset)
: zone_(zone),
translation_helper_(*translation_helper),
reader_(binary),
script_(Script::Handle(zone_)),
data_program_offset_(data_program_offset) {}
virtual ~KernelReaderHelper() = default;
void SetOffset(intptr_t offset);
intptr_t ReadListLength();
virtual void ReportUnexpectedTag(const char* variant, Tag tag);
void ReadUntilFunctionNode();
Tag PeekTag(uint8_t* payload = NULL);
protected:
const Script& script() const { return script_; }
virtual void set_current_script_id(intptr_t id) {
// Do nothing by default.
// This is overridden in KernelTokenPositionCollector.
USE(id);
}
virtual void RecordTokenPosition(TokenPosition position) {
// Do nothing by default.
// This is overridden in KernelTokenPositionCollector.
USE(position);
}
intptr_t ReaderOffset() const;
void SkipBytes(intptr_t skip);
bool ReadBool();
uint8_t ReadByte();
uint32_t ReadUInt();
uint32_t ReadUInt32();
uint32_t PeekUInt();
double ReadDouble();
uint32_t PeekListLength();
StringIndex ReadStringReference();
NameIndex ReadCanonicalNameReference();
NameIndex ReadInterfaceMemberNameReference();
StringIndex ReadNameAsStringIndex();
const String& ReadNameAsMethodName();
const String& ReadNameAsGetterName();
const String& ReadNameAsSetterName();
const String& ReadNameAsFieldName();
void SkipFlags();
void SkipStringReference();
void SkipConstantReference();
void SkipCanonicalNameReference();
void SkipInterfaceMemberNameReference();
void SkipDartType();
void SkipOptionalDartType();
void SkipInterfaceType(bool simple);
void SkipFunctionType(bool simple);
void SkipStatementList();
void SkipListOfExpressions();
void SkipListOfDartTypes();
void SkipListOfStrings();
void SkipListOfVariableDeclarations();
void SkipTypeParametersList();
void SkipInitializer();
void SkipExpression();
void SkipStatement();
void SkipFunctionNode();
void SkipName();
void SkipArguments();
void SkipVariableDeclaration();
void SkipLibraryCombinator();
void SkipLibraryDependency();
void SkipLibraryPart();
void SkipLibraryTypedef();
TokenPosition ReadPosition();
Tag ReadTag(uint8_t* payload = NULL);
uint8_t ReadFlags() { return reader_.ReadFlags(); }
Nullability ReadNullability();
Variance ReadVariance();
intptr_t SourceTableFieldCountFromFirstLibraryOffset();
intptr_t SourceTableSize();
intptr_t GetOffsetForSourceInfo(intptr_t index);
String& SourceTableUriFor(intptr_t index);
const String& GetSourceFor(intptr_t index);
TypedDataPtr GetLineStartsFor(intptr_t index);
String& SourceTableImportUriFor(intptr_t index, uint32_t binaryVersion);
ExternalTypedDataPtr GetConstantCoverageFor(intptr_t index);
Zone* zone_;
TranslationHelper& translation_helper_;
Reader reader_;
const Script& script_;
// Some items like variables are specified in the kernel binary as
// absolute offsets (as in, offsets within the whole kernel program)
// of their declaration nodes. Hence, to cache and/or access them
// uniquely from within a function's kernel data, we need to
// add/subtract the offset of the kernel data in the over all
// kernel program.
intptr_t data_program_offset_;
friend class ClassHelper;
friend class CallSiteAttributesMetadataHelper;
friend class ConstantReader;
friend class ConstantHelper;
friend class ConstructorHelper;
friend class DirectCallMetadataHelper;
friend class FieldHelper;
friend class FunctionNodeHelper;
friend class InferredTypeMetadataHelper;
friend class KernelLoader;
friend class LibraryDependencyHelper;
friend class LibraryHelper;
friend class MetadataHelper;
friend class ProcedureAttributesMetadataHelper;
friend class ProcedureHelper;
friend class SimpleExpressionConverter;
friend class ScopeBuilder;
friend class TableSelectorMetadataHelper;
friend class TypeParameterHelper;
friend class TypeTranslator;
friend class UnboxingInfoMetadataHelper;
friend class VariableDeclarationHelper;
friend class ObfuscationProhibitionsMetadataHelper;
friend class LoadingUnitsMetadataHelper;
friend bool NeedsDynamicInvocationForwarder(const Function& function);
friend ArrayPtr CollectConstConstructorCoverageFrom(
const Script& interesting_script);
private:
DISALLOW_COPY_AND_ASSIGN(KernelReaderHelper);
};
class ActiveClass {
public:
ActiveClass()
: klass(NULL),
member(NULL),
enclosing(NULL),
local_type_parameters(NULL) {}
bool HasMember() { return member != NULL; }
bool MemberIsProcedure() {
ASSERT(member != NULL);
UntaggedFunction::Kind function_kind = member->kind();
return function_kind == UntaggedFunction::kRegularFunction ||
function_kind == UntaggedFunction::kGetterFunction ||
function_kind == UntaggedFunction::kSetterFunction ||
function_kind == UntaggedFunction::kMethodExtractor ||
function_kind == UntaggedFunction::kDynamicInvocationForwarder ||
member->IsFactory();
}
bool MemberIsFactoryProcedure() {
ASSERT(member != NULL);
return member->IsFactory();
}
bool RequireConstCanonicalTypeErasure(bool null_safety) const {
return klass != nullptr && !null_safety &&
Library::Handle(klass->library()).nnbd_compiled_mode() ==
NNBDCompiledMode::kAgnostic;
}
intptr_t MemberTypeParameterCount(Zone* zone);
intptr_t ClassNumTypeArguments() {
ASSERT(klass != NULL);
return klass->NumTypeArguments();
}
void RecordDerivedTypeParameter(Zone* zone,
const TypeParameter& original,
const TypeParameter& derived) {
if (original.ptr() != derived.ptr() &&
original.bound() == AbstractType::null()) {
if (derived_type_parameters == nullptr) {
derived_type_parameters = &GrowableObjectArray::Handle(
zone, GrowableObjectArray::New(Heap::kOld));
}
derived_type_parameters->Add(derived);
}
}
const char* ToCString() {
return member != NULL ? member->ToCString() : klass->ToCString();
}
// The current enclosing class (or the library top-level class).
const Class* klass;
const Function* member;
// The innermost enclosing signature. This is used for building types, as a
// parent for function types.
const FunctionType* enclosing;
const TypeArguments* local_type_parameters;
GrowableObjectArray* derived_type_parameters = nullptr;
};
class ActiveClassScope {
public:
ActiveClassScope(ActiveClass* active_class, const Class* klass)
: active_class_(active_class), saved_(*active_class) {
active_class_->klass = klass;
}
~ActiveClassScope() { *active_class_ = saved_; }
private:
ActiveClass* active_class_;
ActiveClass saved_;
DISALLOW_COPY_AND_ASSIGN(ActiveClassScope);
};
class ActiveMemberScope {
public:
ActiveMemberScope(ActiveClass* active_class, const Function* member)
: active_class_(active_class), saved_(*active_class) {
// The class is inherited.
active_class_->member = member;
}
~ActiveMemberScope() { *active_class_ = saved_; }
private:
ActiveClass* active_class_;
ActiveClass saved_;
DISALLOW_COPY_AND_ASSIGN(ActiveMemberScope);
};
class ActiveEnclosingFunctionScope {
public:
ActiveEnclosingFunctionScope(ActiveClass* active_class,
const FunctionType* enclosing_signature)
: active_class_(active_class), saved_(*active_class) {
active_class_->enclosing = enclosing_signature;
}
~ActiveEnclosingFunctionScope() { *active_class_ = saved_; }
private:
ActiveClass* active_class_;
ActiveClass saved_;
DISALLOW_COPY_AND_ASSIGN(ActiveEnclosingFunctionScope);
};
class ActiveTypeParametersScope {
public:
// Set the local type parameters of the ActiveClass to be exactly all type
// parameters defined by 'innermost' and any enclosing *closures* (but not
// enclosing methods/top-level functions/classes).
//
// Also, the enclosing signature is set to innermost's signature.
ActiveTypeParametersScope(ActiveClass* active_class,
const Function& innermost,
const FunctionType* innermost_signature,
Zone* Z);
// Append the list of the local type parameters to the list in ActiveClass.
//
// Also, the enclosing signature is set to 'signature'.
ActiveTypeParametersScope(ActiveClass* active_class,
const FunctionType* innermost_signature,
const TypeArguments& new_params,
Zone* Z);
~ActiveTypeParametersScope() { *active_class_ = saved_; }
private:
ActiveClass* active_class_;
ActiveClass saved_;
DISALLOW_COPY_AND_ASSIGN(ActiveTypeParametersScope);
};
class TypeTranslator {
public:
TypeTranslator(KernelReaderHelper* helper,
ConstantReader* constant_reader,
ActiveClass* active_class,
bool finalize = false,
bool apply_canonical_type_erasure = false,
bool in_constant_context = false);
AbstractType& BuildType();
AbstractType& BuildTypeWithoutFinalization();
const TypeArguments& BuildTypeArguments(intptr_t length);
const TypeArguments& BuildInstantiatedTypeArguments(
const Class& receiver_class,
intptr_t length);
void LoadAndSetupTypeParameters(ActiveClass* active_class,
const Function& function,
const Class& parameterized_class,
const FunctionType& parameterized_signature,
intptr_t type_parameter_count,
const NNBDMode nnbd_mode);
void LoadAndSetupBounds(ActiveClass* active_class,
const Function& function,
const Class& parameterized_class,
const FunctionType& parameterized_signature,
intptr_t type_parameter_count);
const Type& ReceiverType(const Class& klass);
void SetupFunctionParameters(const Class& klass,
const Function& function,
bool is_method,
bool is_closure,
FunctionNodeHelper* function_node_helper);
private:
void SetupUnboxingInfoMetadata(const Function& function,
intptr_t library_kernel_offset);
void SetupUnboxingInfoMetadataForFieldAccessors(
const Function& field_accessor,
intptr_t library_kernel_offset);
void BuildTypeInternal();
void BuildInterfaceType(bool simple);
void BuildFunctionType(bool simple);
void BuildTypeParameterType();
class TypeParameterScope {
public:
TypeParameterScope(TypeTranslator* translator, intptr_t parameter_count)
: parameter_count_(parameter_count),
outer_(translator->type_parameter_scope_),
translator_(translator) {
outer_parameter_count_ = 0;
if (outer_ != NULL) {
outer_parameter_count_ =
outer_->outer_parameter_count_ + outer_->parameter_count_;
}
translator_->type_parameter_scope_ = this;
}
~TypeParameterScope() { translator_->type_parameter_scope_ = outer_; }
TypeParameterScope* outer() const { return outer_; }
intptr_t parameter_count() const { return parameter_count_; }
intptr_t outer_parameter_count() const { return outer_parameter_count_; }
private:
intptr_t parameter_count_;
intptr_t outer_parameter_count_;
TypeParameterScope* outer_;
TypeTranslator* translator_;
};
KernelReaderHelper* helper_;
ConstantReader* constant_reader_;
TranslationHelper& translation_helper_;
ActiveClass* const active_class_;
TypeParameterScope* type_parameter_scope_;
InferredTypeMetadataHelper inferred_type_metadata_helper_;
UnboxingInfoMetadataHelper unboxing_info_metadata_helper_;
Zone* zone_;
AbstractType& result_;
bool finalize_;
const bool apply_canonical_type_erasure_;
const bool in_constant_context_;
friend class ScopeBuilder;
friend class KernelLoader;
DISALLOW_COPY_AND_ASSIGN(TypeTranslator);
};
} // namespace kernel
} // namespace dart
#endif // RUNTIME_VM_COMPILER_FRONTEND_KERNEL_TRANSLATION_HELPER_H_