blob: 4016697a6efe78029fc272af8920abbc4f7bfeb4 [file] [log] [blame]
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#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_; }
IsolateGroup* isolate_group() { return isolate_group_; }
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);
bool IsField(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 LookupFieldByKernelField(NameIndex field);
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 SetExpressionEvaluationClass(const Class& cls) {
ASSERT(expression_evaluation_class_ == nullptr);
ASSERT(!cls.IsNull());
expression_evaluation_class_ = &Class::Handle(zone_, cls.ptr());
}
const Class& GetExpressionEvaluationClass() {
if (expression_evaluation_class_ == nullptr) {
return Class::null_class();
}
return *expression_evaluation_class_;
}
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());
}
const Class& GetExpressionEvaluationRealClass() {
if (expression_evaluation_real_class_ == nullptr) {
return Class::null_class();
}
return *expression_evaluation_real_class_;
}
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_;
IsolateGroup* isolate_group_;
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;
// A temporary class needed to contain the function to which an eval
// expression is compiled. This is a fresh class so loading the kernel
// isn't a no-op. It should be unreachable after the eval function is loaded.
Class* expression_evaluation_class_ = nullptr;
// The original class that is the scope in which the eval expression is
// evaluated.
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.
kCanonicalNameField,
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_field_;
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,
kSignatureType,
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.
kRedirectingFactory = 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 IsRedirectingFactory() const {
return (flags_ & kRedirectingFactory) != 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,
kIsMacro = 1 << 6,
};
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,
kUnsupported = 1 << 4,
};
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(), CompileType::kCannotBeSentinel);
} else {
return CompileType(IsNullable(), CompileType::kCannotBeSentinel, cid,
nullptr);
}
}
};
// 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;
intptr_t ReaderSize() 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 SkipListOfCanonicalNameReferences();
void SkipTypeParametersList();
void SkipInitializer();
void SkipExpression();
void SkipStatement();
void SkipFunctionNode();
void SkipName();
void SkipArguments();
void SkipVariableDeclaration();
void SkipLibraryCombinator();
void SkipLibraryDependency();
void SkipLibraryPart();
TokenPosition ReadPosition();
Tag ReadTag(uint8_t* payload = NULL);
uint8_t ReadFlags() { return reader_.ReadFlags(); }
Nullability ReadNullability();
Variance ReadVariance();
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& derived) {
if (derived.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,
Zone* Z);
~ActiveTypeParametersScope();
private:
ActiveClass* active_class_;
ActiveClass saved_;
Zone* zone_;
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);
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_;
bool refers_to_derived_type_param_;
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_