blob: 3210c351af0a365ff6900417e16306f65abd9a21 [file] [log] [blame]
// Copyright (c) 2019, 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/runtime_api.h"
#include "vm/object.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/compiler/runtime_offsets_list.h"
#include "vm/dart_api_state.h"
#include "vm/dart_entry.h"
#include "vm/longjump.h"
#include "vm/native_arguments.h"
#include "vm/native_entry.h"
#include "vm/object_store.h"
#include "vm/runtime_entry.h"
#include "vm/symbols.h"
#include "vm/timeline.h"
#endif // !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
namespace compiler {
namespace target {
#include "vm/compiler/runtime_offsets_extracted.h"
bool IsSmi(int64_t v) {
return Utils::IsInt(kSmiBits + 1, v);
}
bool WillAllocateNewOrRememberedObject(intptr_t instance_size) {
ASSERT(Utils::IsAligned(instance_size, ObjectAlignment::kObjectAlignment));
return dart::Heap::IsAllocatableInNewSpace(instance_size);
}
bool WillAllocateNewOrRememberedContext(intptr_t num_context_variables) {
if (!dart::Context::IsValidLength(num_context_variables)) return false;
return dart::Heap::IsAllocatableInNewSpace(
dart::Context::InstanceSize(num_context_variables));
}
bool WillAllocateNewOrRememberedArray(intptr_t length) {
if (!dart::Array::IsValidLength(length)) return false;
return !dart::Array::UseCardMarkingForAllocation(length);
}
} // namespace target
} // namespace compiler
} // namespace dart
#if !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
namespace compiler {
bool IsSameObject(const Object& a, const Object& b) {
if (a.IsInstance() && b.IsInstance()) {
return Instance::Cast(a).IsIdenticalTo(Instance::Cast(b));
}
return a.ptr() == b.ptr();
}
bool IsEqualType(const AbstractType& a, const AbstractType& b) {
return a.Equals(b);
}
bool IsDoubleType(const AbstractType& type) {
return type.IsDoubleType();
}
bool IsBoolType(const AbstractType& type) {
return type.IsBoolType();
}
bool IsSubtypeOfInt(const AbstractType& type) {
return type.IsIntType() || type.IsIntegerImplementationType() ||
type.IsSmiType() || type.IsMintType();
}
bool IsSmiType(const AbstractType& type) {
return type.IsSmiType();
}
bool IsNotTemporaryScopedHandle(const Object& obj) {
return obj.IsNotTemporaryScopedHandle();
}
#define DO(clazz) \
bool Is##clazz##Handle(const Object& obj) { return obj.Is##clazz(); }
CLASS_LIST_FOR_HANDLES(DO)
#undef DO
bool IsInOldSpace(const Object& obj) {
return obj.IsSmi() || obj.IsOld();
}
intptr_t ObjectHash(const Object& obj) {
if (obj.IsNull()) {
return 2011;
}
if (obj.IsInstance()) {
return Instance::Cast(obj).CanonicalizeHash();
}
if (obj.IsCode()) {
// Instructions don't move during compaction.
return Code::Cast(obj).PayloadStart();
}
if (obj.IsFunction()) {
return Function::Cast(obj).Hash();
}
if (obj.IsField()) {
return dart::String::HashRawSymbol(Field::Cast(obj).name());
}
if (obj.IsICData()) {
return ICData::Cast(obj).Hash();
}
// Unlikely.
return obj.GetClassId();
}
void SetToNull(Object* obj) {
*obj = Object::null();
}
Object& NewZoneHandle(Zone* zone) {
return Object::ZoneHandle(zone, Object::null());
}
Object& NewZoneHandle(Zone* zone, const Object& obj) {
return Object::ZoneHandle(zone, obj.ptr());
}
const Object& NullObject() {
return Object::null_object();
}
const Object& SentinelObject() {
return Object::sentinel();
}
const Bool& TrueObject() {
return dart::Bool::True();
}
const Bool& FalseObject() {
return dart::Bool::False();
}
const Object& EmptyTypeArguments() {
return Object::empty_type_arguments();
}
const Type& DynamicType() {
return dart::Type::dynamic_type();
}
const Type& ObjectType() {
return Type::Handle(dart::Type::ObjectType());
}
const Type& VoidType() {
return dart::Type::void_type();
}
const Type& IntType() {
return Type::Handle(dart::Type::IntType());
}
const Class& GrowableObjectArrayClass() {
auto object_store = IsolateGroup::Current()->object_store();
return Class::Handle(object_store->growable_object_array_class());
}
const Class& MintClass() {
auto object_store = IsolateGroup::Current()->object_store();
return Class::Handle(object_store->mint_class());
}
const Class& DoubleClass() {
auto object_store = IsolateGroup::Current()->object_store();
return Class::Handle(object_store->double_class());
}
const Class& Float32x4Class() {
auto object_store = IsolateGroup::Current()->object_store();
return Class::Handle(object_store->float32x4_class());
}
const Class& Float64x2Class() {
auto object_store = IsolateGroup::Current()->object_store();
return Class::Handle(object_store->float64x2_class());
}
const Class& Int32x4Class() {
auto object_store = IsolateGroup::Current()->object_store();
return Class::Handle(object_store->int32x4_class());
}
const Class& ClosureClass() {
auto object_store = IsolateGroup::Current()->object_store();
return Class::Handle(object_store->closure_class());
}
const Array& OneArgArgumentsDescriptor() {
return Array::ZoneHandle(
ArgumentsDescriptor::NewBoxed(/*type_args_len=*/0, /*num_arguments=*/1));
}
bool IsOriginalObject(const Object& object) {
if (object.IsICData()) {
return ICData::Cast(object).IsOriginal();
} else if (object.IsField()) {
return Field::Cast(object).IsOriginal();
}
return true;
}
const String& AllocateString(const char* buffer) {
return String::ZoneHandle(String::New(buffer, dart::Heap::kOld));
}
bool HasIntegerValue(const dart::Object& object, int64_t* value) {
if (object.IsInteger()) {
*value = Integer::Cast(object).AsInt64Value();
return true;
}
return false;
}
int32_t CreateJitCookie() {
return static_cast<int32_t>(IsolateGroup::Current()->random()->NextUInt32());
}
word TypedDataElementSizeInBytes(classid_t cid) {
return dart::TypedData::ElementSizeInBytes(cid);
}
word TypedDataMaxNewSpaceElements(classid_t cid) {
return (dart::Heap::kNewAllocatableSize - target::TypedData::HeaderSize()) /
TypedDataElementSizeInBytes(cid);
}
const Field& LookupMathRandomStateFieldOffset() {
const auto& math_lib = dart::Library::Handle(dart::Library::MathLibrary());
ASSERT(!math_lib.IsNull());
const auto& random_class = dart::Class::Handle(
math_lib.LookupClassAllowPrivate(dart::Symbols::_Random()));
ASSERT(!random_class.IsNull());
const auto& state_field = dart::Field::ZoneHandle(
random_class.LookupInstanceFieldAllowPrivate(dart::Symbols::_state()));
return state_field;
}
const Field& LookupConvertUtf8DecoderScanFlagsField() {
const auto& convert_lib =
dart::Library::Handle(dart::Library::ConvertLibrary());
ASSERT(!convert_lib.IsNull());
const auto& _utf8decoder_class = dart::Class::Handle(
convert_lib.LookupClassAllowPrivate(dart::Symbols::_Utf8Decoder()));
ASSERT(!_utf8decoder_class.IsNull());
const auto& scan_flags_field = dart::Field::ZoneHandle(
_utf8decoder_class.LookupInstanceFieldAllowPrivate(
dart::Symbols::_scanFlags()));
return scan_flags_field;
}
word LookupFieldOffsetInBytes(const Field& field) {
return field.TargetOffset();
}
#if defined(TARGET_ARCH_IA32)
uword SymbolsPredefinedAddress() {
return reinterpret_cast<uword>(dart::Symbols::PredefinedAddress());
}
#endif
const Code& StubCodeAllocateArray() {
return dart::StubCode::AllocateArray();
}
const Code& StubCodeSubtype3TestCache() {
return dart::StubCode::Subtype3TestCache();
}
const Code& StubCodeSubtype7TestCache() {
return dart::StubCode::Subtype7TestCache();
}
#define DEFINE_ALIAS(name) \
const RuntimeEntry& k##name##RuntimeEntry(dart::k##name##RuntimeEntry);
RUNTIME_ENTRY_LIST(DEFINE_ALIAS)
#undef DEFINE_ALIAS
#define DEFINE_ALIAS(type, name, ...) \
const RuntimeEntry& k##name##RuntimeEntry(dart::k##name##RuntimeEntry);
LEAF_RUNTIME_ENTRY_LIST(DEFINE_ALIAS)
#undef DEFINE_ALIAS
void BailoutWithBranchOffsetError() {
Thread::Current()->long_jump_base()->Jump(1, Object::branch_offset_error());
}
word RuntimeEntry::OffsetFromThread() const {
return target::Thread::OffsetFromThread(runtime_entry_);
}
bool RuntimeEntry::is_leaf() const {
return runtime_entry_->is_leaf();
}
namespace target {
const word kOldPageSize = dart::kOldPageSize;
const word kOldPageSizeInWords = dart::kOldPageSize / kWordSize;
const word kOldPageMask = dart::kOldPageMask;
static word TranslateOffsetInWordsToHost(word offset) {
RELEASE_ASSERT((offset % kCompressedWordSize) == 0);
return (offset / kCompressedWordSize) * dart::kCompressedWordSize;
}
bool SizeFitsInSizeTag(uword instance_size) {
return dart::UntaggedObject::SizeTag::SizeFits(
TranslateOffsetInWordsToHost(instance_size));
}
uword MakeTagWordForNewSpaceObject(classid_t cid, uword instance_size) {
return dart::UntaggedObject::SizeTag::encode(
TranslateOffsetInWordsToHost(instance_size)) |
dart::UntaggedObject::ClassIdTag::encode(cid) |
dart::UntaggedObject::NewBit::encode(true);
}
word Object::tags_offset() {
return 0;
}
const word UntaggedObject::kCardRememberedBit =
dart::UntaggedObject::kCardRememberedBit;
const word UntaggedObject::kOldAndNotRememberedBit =
dart::UntaggedObject::kOldAndNotRememberedBit;
const word UntaggedObject::kOldAndNotMarkedBit =
dart::UntaggedObject::kOldAndNotMarkedBit;
const word UntaggedObject::kSizeTagPos = dart::UntaggedObject::kSizeTagPos;
const word UntaggedObject::kSizeTagSize = dart::UntaggedObject::kSizeTagSize;
const word UntaggedObject::kClassIdTagPos =
dart::UntaggedObject::kClassIdTagPos;
const word UntaggedObject::kClassIdTagSize =
dart::UntaggedObject::kClassIdTagSize;
const word UntaggedObject::kHashTagPos = dart::UntaggedObject::kHashTagPos;
const word UntaggedObject::kHashTagSize = dart::UntaggedObject::kHashTagSize;
const word UntaggedObject::kSizeTagMaxSizeTag =
dart::UntaggedObject::SizeTag::kMaxSizeTagInUnitsOfAlignment *
ObjectAlignment::kObjectAlignment;
const word UntaggedObject::kTagBitsSizeTagPos =
dart::UntaggedObject::TagBits::kSizeTagPos;
const word UntaggedAbstractType::kTypeStateFinalizedInstantiated =
dart::UntaggedAbstractType::kFinalizedInstantiated;
const bool UntaggedType::kTypeClassIdIsSigned =
std::is_signed<decltype(dart::UntaggedType::type_class_id_)>::value;
const word UntaggedType::kTypeClassIdBitSize =
sizeof(dart::UntaggedType::type_class_id_) * kBitsPerByte;
const word UntaggedObject::kBarrierOverlapShift =
dart::UntaggedObject::kBarrierOverlapShift;
bool IsTypedDataClassId(intptr_t cid) {
return dart::IsTypedDataClassId(cid);
}
const word Class::kNoTypeArguments = dart::Class::kNoTypeArguments;
classid_t Class::GetId(const dart::Class& handle) {
return handle.id();
}
static word TranslateOffsetInWords(word offset) {
RELEASE_ASSERT((offset % dart::kWordSize) == 0);
return (offset / dart::kWordSize) * kWordSize;
}
static uword GetInstanceSizeImpl(const dart::Class& handle) {
switch (handle.id()) {
case kMintCid:
return Mint::InstanceSize();
case kDoubleCid:
return Double::InstanceSize();
case kInt32x4Cid:
return Int32x4::InstanceSize();
case kFloat32x4Cid:
return Float32x4::InstanceSize();
case kFloat64x2Cid:
return Float64x2::InstanceSize();
case kObjectCid:
return Object::InstanceSize();
case kInstanceCid:
return Instance::InstanceSize();
case kGrowableObjectArrayCid:
return GrowableObjectArray::InstanceSize();
case kClosureCid:
return Closure::InstanceSize();
case kTypedDataBaseCid:
return TypedDataBase::InstanceSize();
case kLinkedHashMapCid:
return LinkedHashMap::InstanceSize();
case kLinkedHashSetCid:
return LinkedHashSet::InstanceSize();
case kUnhandledExceptionCid:
return UnhandledException::InstanceSize();
case kWeakPropertyCid:
return WeakProperty::InstanceSize();
case kByteBufferCid:
case kByteDataViewCid:
case kPointerCid:
case kDynamicLibraryCid:
#define HANDLE_CASE(clazz) case kFfi##clazz##Cid:
CLASS_LIST_FFI_TYPE_MARKER(HANDLE_CASE)
#undef HANDLE_CASE
#define HANDLE_CASE(clazz) \
case kTypedData##clazz##Cid: \
case kTypedData##clazz##ViewCid: \
case kExternalTypedData##clazz##Cid:
CLASS_LIST_TYPED_DATA(HANDLE_CASE)
#undef HANDLE_CASE
return handle.target_instance_size();
default:
if (handle.id() >= kNumPredefinedCids) {
return handle.target_instance_size();
}
}
FATAL3("Unsupported class for size translation: %s (id=%" Pd
", kNumPredefinedCids=%" Pd ")\n",
handle.ToCString(), handle.id(), kNumPredefinedCids);
return -1;
}
uword Class::GetInstanceSize(const dart::Class& handle) {
return Utils::RoundUp(GetInstanceSizeImpl(handle),
ObjectAlignment::kObjectAlignment);
}
// Currently, we only have compressed pointers on the target if we also have
// compressed pointers on the host, since only 64-bit architectures can have
// compressed pointers and there is no 32-bit host/64-bit target combination.
// Thus, we cheat a little here and use the host information about compressed
// pointers for the target, instead of storing this information in the extracted
// offsets information.
bool Class::HasCompressedPointers(const dart::Class& handle) {
return handle.HasCompressedPointers();
}
intptr_t Class::NumTypeArguments(const dart::Class& klass) {
return klass.NumTypeArguments();
}
bool Class::HasTypeArgumentsField(const dart::Class& klass) {
return klass.host_type_arguments_field_offset() !=
dart::Class::kNoTypeArguments;
}
intptr_t Class::TypeArgumentsFieldOffset(const dart::Class& klass) {
return klass.target_type_arguments_field_offset();
}
bool Class::TraceAllocation(const dart::Class& klass) {
return klass.TraceAllocation(dart::IsolateGroup::Current());
}
word Instance::first_field_offset() {
return TranslateOffsetInWords(dart::Instance::NextFieldOffset());
}
word Instance::native_fields_array_offset() {
return TranslateOffsetInWords(dart::Instance::NativeFieldsOffset());
}
word Instance::DataOffsetFor(intptr_t cid) {
if (dart::IsExternalTypedDataClassId(cid) ||
dart::IsExternalStringClassId(cid)) {
// Elements start at offset 0 of the external data.
return 0;
}
if (dart::IsTypedDataClassId(cid)) {
return TypedData::data_offset();
}
switch (cid) {
case kArrayCid:
case kImmutableArrayCid:
return Array::data_offset();
case kTypeArgumentsCid:
return TypeArguments::types_offset();
case kOneByteStringCid:
return OneByteString::data_offset();
case kTwoByteStringCid:
return TwoByteString::data_offset();
default:
UNIMPLEMENTED();
return Array::data_offset();
}
}
word Instance::ElementSizeFor(intptr_t cid) {
if (dart::IsExternalTypedDataClassId(cid) || dart::IsTypedDataClassId(cid) ||
dart::IsTypedDataViewClassId(cid)) {
return dart::TypedDataBase::ElementSizeInBytes(cid);
}
switch (cid) {
case kArrayCid:
case kImmutableArrayCid:
return kCompressedWordSize;
case kTypeArgumentsCid:
return kCompressedWordSize;
case kOneByteStringCid:
return dart::OneByteString::kBytesPerElement;
case kTwoByteStringCid:
return dart::TwoByteString::kBytesPerElement;
case kExternalOneByteStringCid:
return dart::ExternalOneByteString::kBytesPerElement;
case kExternalTwoByteStringCid:
return dart::ExternalTwoByteString::kBytesPerElement;
default:
UNIMPLEMENTED();
return 0;
}
}
word ICData::CodeIndexFor(word num_args) {
return dart::ICData::CodeIndexFor(num_args);
}
word ICData::CountIndexFor(word num_args) {
return dart::ICData::CountIndexFor(num_args);
}
word ICData::TargetIndexFor(word num_args) {
return dart::ICData::TargetIndexFor(num_args);
}
word ICData::ExactnessIndexFor(word num_args) {
return dart::ICData::ExactnessIndexFor(num_args);
}
word ICData::TestEntryLengthFor(word num_args, bool exactness_check) {
return dart::ICData::TestEntryLengthFor(num_args, exactness_check);
}
word ICData::EntryPointIndexFor(word num_args) {
return dart::ICData::EntryPointIndexFor(num_args);
}
const word MegamorphicCache::kSpreadFactor =
dart::MegamorphicCache::kSpreadFactor;
// Currently we have two different axes for offset generation:
//
// * Target architecture
// * DART_PRECOMPILED_RUNTIME (i.e, AOT vs. JIT)
//
// TODO(dartbug.com/43646): Add DART_PRECOMPILER as another axis.
#define DEFINE_CONSTANT(Class, Name) const word Class::Name = Class##_##Name;
#define DEFINE_ARRAY_SIZEOF(clazz, name, ElementOffset) \
word clazz::name() { return 0; } \
word clazz::name(intptr_t length) { \
return RoundedAllocationSize(clazz::ElementOffset(length)); \
}
#define DEFINE_PAYLOAD_SIZEOF(clazz, name, header) \
word clazz::name() { return 0; } \
word clazz::name(word payload_size) { \
return RoundedAllocationSize(clazz::header() + payload_size); \
}
#if defined(TARGET_ARCH_IA32)
#define DEFINE_FIELD(clazz, name) \
word clazz::name() { return clazz##_##name; }
#define DEFINE_ARRAY(clazz, name) \
word clazz::name(intptr_t index) { \
return clazz##_elements_start_offset + index * clazz##_element_size; \
}
#define DEFINE_SIZEOF(clazz, name, what) \
word clazz::name() { return clazz##_##name; }
#define DEFINE_RANGE(Class, Getter, Type, First, Last, Filter) \
word Class::Getter(Type index) { \
return Class##_##Getter[static_cast<intptr_t>(index) - \
static_cast<intptr_t>(First)]; \
}
JIT_OFFSETS_LIST(DEFINE_FIELD,
DEFINE_ARRAY,
DEFINE_SIZEOF,
DEFINE_ARRAY_SIZEOF,
DEFINE_PAYLOAD_SIZEOF,
DEFINE_RANGE,
DEFINE_CONSTANT)
COMMON_OFFSETS_LIST(DEFINE_FIELD,
DEFINE_ARRAY,
DEFINE_SIZEOF,
DEFINE_ARRAY_SIZEOF,
DEFINE_PAYLOAD_SIZEOF,
DEFINE_RANGE,
DEFINE_CONSTANT)
#else
#define DEFINE_JIT_FIELD(clazz, name) \
word clazz::name() { \
if (FLAG_precompiled_mode) { \
FATAL("Use of JIT-only field %s in precompiled mode", \
#clazz "::" #name); \
} \
return clazz##_##name; \
}
#define DEFINE_JIT_ARRAY(clazz, name) \
word clazz::name(intptr_t index) { \
if (FLAG_precompiled_mode) { \
FATAL("Use of JIT-only array %s in precompiled mode", \
#clazz "::" #name); \
} \
return clazz##_elements_start_offset + index * clazz##_element_size; \
}
#define DEFINE_JIT_SIZEOF(clazz, name, what) \
word clazz::name() { \
if (FLAG_precompiled_mode) { \
FATAL("Use of JIT-only sizeof %s in precompiled mode", \
#clazz "::" #name); \
} \
return clazz##_##name; \
}
#define DEFINE_JIT_RANGE(Class, Getter, Type, First, Last, Filter) \
word Class::Getter(Type index) { \
if (FLAG_precompiled_mode) { \
FATAL("Use of JIT-only range %s in precompiled mode", \
#Class "::" #Getter); \
} \
return Class##_##Getter[static_cast<intptr_t>(index) - \
static_cast<intptr_t>(First)]; \
}
JIT_OFFSETS_LIST(DEFINE_JIT_FIELD,
DEFINE_JIT_ARRAY,
DEFINE_JIT_SIZEOF,
DEFINE_ARRAY_SIZEOF,
DEFINE_PAYLOAD_SIZEOF,
DEFINE_JIT_RANGE,
DEFINE_CONSTANT)
#undef DEFINE_JIT_FIELD
#undef DEFINE_JIT_ARRAY
#undef DEFINE_JIT_SIZEOF
#undef DEFINE_JIT_RANGE
#if defined(DART_PRECOMPILER)
// The following could check FLAG_precompiled_mode for more safety, but that
// causes problems for defining things like native Slots, where the definition
// cannot be based on a runtime flag. Instead, we limit the visibility of these
// definitions using DART_PRECOMPILER.
#define DEFINE_AOT_FIELD(clazz, name) \
word clazz::name() { return AOT_##clazz##_##name; }
#define DEFINE_AOT_ARRAY(clazz, name) \
word clazz::name(intptr_t index) { \
return AOT_##clazz##_elements_start_offset + \
index * AOT_##clazz##_element_size; \
}
#define DEFINE_AOT_SIZEOF(clazz, name, what) \
word clazz::name() { return AOT_##clazz##_##name; }
#define DEFINE_AOT_RANGE(Class, Getter, Type, First, Last, Filter) \
word Class::Getter(Type index) { \
return AOT_##Class##_##Getter[static_cast<intptr_t>(index) - \
static_cast<intptr_t>(First)]; \
}
#else
#define DEFINE_AOT_FIELD(clazz, name) \
word clazz::name() { \
FATAL("Use of AOT-only field %s outside of the precompiler", \
#clazz "::" #name); \
}
#define DEFINE_AOT_ARRAY(clazz, name) \
word clazz::name(intptr_t index) { \
FATAL("Use of AOT-only array %s outside of the precompiler", \
#clazz "::" #name); \
}
#define DEFINE_AOT_SIZEOF(clazz, name, what) \
word clazz::name() { \
FATAL("Use of AOT-only sizeof %s outside of the precompiler", \
#clazz "::" #name); \
}
#define DEFINE_AOT_RANGE(Class, Getter, Type, First, Last, Filter) \
word Class::Getter(Type index) { \
FATAL("Use of AOT-only range %s outside of the precompiler", \
#Class "::" #Getter); \
}
#endif // defined(DART_PRECOMPILER)
AOT_OFFSETS_LIST(DEFINE_AOT_FIELD,
DEFINE_AOT_ARRAY,
DEFINE_AOT_SIZEOF,
DEFINE_ARRAY_SIZEOF,
DEFINE_PAYLOAD_SIZEOF,
DEFINE_AOT_RANGE,
DEFINE_CONSTANT)
#undef DEFINE_AOT_FIELD
#undef DEFINE_AOT_ARRAY
#undef DEFINE_AOT_SIZEOF
#undef DEFINE_AOT_RANGE
#define DEFINE_FIELD(clazz, name) \
word clazz::name() { \
return FLAG_precompiled_mode ? AOT_##clazz##_##name : clazz##_##name; \
}
#define DEFINE_ARRAY(clazz, name) \
word clazz::name(intptr_t index) { \
if (FLAG_precompiled_mode) { \
return AOT_##clazz##_elements_start_offset + \
index * AOT_##clazz##_element_size; \
} else { \
return clazz##_elements_start_offset + index * clazz##_element_size; \
} \
}
#define DEFINE_SIZEOF(clazz, name, what) \
word clazz::name() { \
return FLAG_precompiled_mode ? AOT_##clazz##_##name : clazz##_##name; \
}
#define DEFINE_RANGE(Class, Getter, Type, First, Last, Filter) \
word Class::Getter(Type index) { \
if (FLAG_precompiled_mode) { \
return AOT_##Class##_##Getter[static_cast<intptr_t>(index) - \
static_cast<intptr_t>(First)]; \
} else { \
return Class##_##Getter[static_cast<intptr_t>(index) - \
static_cast<intptr_t>(First)]; \
} \
}
COMMON_OFFSETS_LIST(DEFINE_FIELD,
DEFINE_ARRAY,
DEFINE_SIZEOF,
DEFINE_ARRAY_SIZEOF,
DEFINE_PAYLOAD_SIZEOF,
DEFINE_RANGE,
DEFINE_CONSTANT)
#endif
#undef DEFINE_FIELD
#undef DEFINE_ARRAY
#undef DEFINE_SIZEOF
#undef DEFINE_RANGE
#undef DEFINE_PAYLOAD_SIZEOF
#undef DEFINE_CONSTANT
const word StoreBufferBlock::kSize = dart::StoreBufferBlock::kSize;
const word MarkingStackBlock::kSize = dart::MarkingStackBlock::kSize;
// For InstructionsSections and Instructions, we define these by hand, because
// they depend on flags or #defines.
// Used for InstructionsSection and Instructions methods, since we don't
// serialize Instructions objects in bare instructions mode, just payloads.
DART_FORCE_INLINE static bool BareInstructionsPayloads() {
return FLAG_precompiled_mode && FLAG_use_bare_instructions;
}
word InstructionsSection::HeaderSize() {
// We only create InstructionsSections in precompiled mode.
ASSERT(FLAG_precompiled_mode);
return Utils::RoundUp(InstructionsSection::UnalignedHeaderSize(),
Instructions::kBarePayloadAlignment);
}
word Instructions::HeaderSize() {
return BareInstructionsPayloads()
? 0
: Utils::RoundUp(UnalignedHeaderSize(), kNonBarePayloadAlignment);
}
word Instructions::InstanceSize() {
return 0;
}
word Instructions::InstanceSize(word payload_size) {
const intptr_t alignment = BareInstructionsPayloads()
? kBarePayloadAlignment
: ObjectAlignment::kObjectAlignment;
return Utils::RoundUp(Instructions::HeaderSize() + payload_size, alignment);
}
word Thread::stack_overflow_shared_stub_entry_point_offset(bool fpu_regs) {
return fpu_regs ? stack_overflow_shared_with_fpu_regs_entry_point_offset()
: stack_overflow_shared_without_fpu_regs_entry_point_offset();
}
uword Thread::full_safepoint_state_unacquired() {
return dart::Thread::full_safepoint_state_unacquired();
}
uword Thread::full_safepoint_state_acquired() {
return dart::Thread::full_safepoint_state_acquired();
}
uword Thread::generated_execution_state() {
return dart::Thread::ExecutionState::kThreadInGenerated;
}
uword Thread::native_execution_state() {
return dart::Thread::ExecutionState::kThreadInNative;
}
uword Thread::vm_execution_state() {
return dart::Thread::ExecutionState::kThreadInVM;
}
uword Thread::vm_tag_dart_id() {
return dart::VMTag::kDartTagId;
}
uword Thread::exit_through_runtime_call() {
return dart::Thread::kExitThroughRuntimeCall;
}
uword Thread::exit_through_ffi() {
return dart::Thread::kExitThroughFfi;
}
word Thread::OffsetFromThread(const dart::Object& object) {
auto host_offset = dart::Thread::OffsetFromThread(object);
return object_null_offset() +
TranslateOffsetInWords(host_offset -
dart::Thread::object_null_offset());
}
intptr_t Thread::OffsetFromThread(const dart::RuntimeEntry* runtime_entry) {
auto host_offset = dart::Thread::OffsetFromThread(runtime_entry);
return AllocateArray_entry_point_offset() +
TranslateOffsetInWords(
host_offset - dart::Thread::AllocateArray_entry_point_offset());
}
bool CanLoadFromThread(const dart::Object& object,
intptr_t* offset /* = nullptr */) {
if (dart::Thread::CanLoadFromThread(object)) {
if (offset != nullptr) {
*offset = Thread::OffsetFromThread(object);
}
return true;
}
return false;
}
static_assert(
kSmiBits <= dart::kSmiBits,
"Expected that size of Smi on HOST is at least as large as on target.");
bool IsSmi(const dart::Object& a) {
return a.IsSmi() && IsSmi(dart::Smi::Cast(a).Value());
}
word ToRawSmi(const dart::Object& a) {
RELEASE_ASSERT(IsSmi(a));
return static_cast<word>(static_cast<intptr_t>(a.ptr()));
}
word ToRawSmi(intptr_t value) {
return dart::Smi::RawValue(value);
}
word SmiValue(const dart::Object& a) {
RELEASE_ASSERT(IsSmi(a));
return static_cast<word>(dart::Smi::Cast(a).Value());
}
#if defined(TARGET_ARCH_IA32)
uword Code::EntryPointOf(const dart::Code& code) {
static_assert(kHostWordSize == kWordSize,
"Can't embed raw pointers to runtime objects when host and "
"target word sizes are different");
return code.EntryPoint();
}
bool CanEmbedAsRawPointerInGeneratedCode(const dart::Object& obj) {
return obj.IsSmi() || obj.InVMIsolateHeap();
}
word ToRawPointer(const dart::Object& a) {
static_assert(kHostWordSize == kWordSize,
"Can't embed raw pointers to runtime objects when host and "
"target word sizes are different");
return static_cast<word>(a.ptr());
}
#endif // defined(TARGET_ARCH_IA32)
word RegExp::function_offset(classid_t cid, bool sticky) {
#if !defined(DART_COMPRESSED_POINTERS)
return TranslateOffsetInWords(dart::RegExp::function_offset(cid, sticky));
#else
// TODO(rmacnak): TranslateOffsetInWords doesn't account for, say, header
// being 1 word and slots being half words.
return dart::RegExp::function_offset(cid, sticky);
#endif
}
const word Symbols::kNumberOfOneCharCodeSymbols =
dart::Symbols::kNumberOfOneCharCodeSymbols;
const word Symbols::kNullCharCodeSymbolOffset =
dart::Symbols::kNullCharCodeSymbolOffset;
const word String::kHashBits = dart::String::kHashBits;
const uint8_t Nullability::kNullable =
static_cast<uint8_t>(dart::Nullability::kNullable);
const uint8_t Nullability::kNonNullable =
static_cast<uint8_t>(dart::Nullability::kNonNullable);
const uint8_t Nullability::kLegacy =
static_cast<uint8_t>(dart::Nullability::kLegacy);
bool Heap::IsAllocatableInNewSpace(intptr_t instance_size) {
return dart::Heap::IsAllocatableInNewSpace(instance_size);
}
word Field::OffsetOf(const dart::Field& field) {
return field.TargetOffset();
}
word FieldTable::OffsetOf(const dart::Field& field) {
return TranslateOffsetInWords(
dart::FieldTable::FieldOffsetFor(field.field_id()));
}
word FreeListElement::FakeInstance::InstanceSize() {
return 0;
}
word ForwardingCorpse::FakeInstance::InstanceSize() {
return 0;
}
word Instance::NextFieldOffset() {
return TranslateOffsetInWords(dart::Instance::NextFieldOffset());
}
intptr_t Array::index_at_offset(intptr_t offset_in_bytes) {
return dart::Array::index_at_offset(
TranslateOffsetInWordsToHost(offset_in_bytes));
}
word String::InstanceSize(word payload_size) {
return RoundedAllocationSize(String::InstanceSize() + payload_size);
}
word LocalVarDescriptors::InstanceSize() {
return 0;
}
word Integer::NextFieldOffset() {
return TranslateOffsetInWords(dart::Integer::NextFieldOffset());
}
word Smi::InstanceSize() {
return 0;
}
word Number::NextFieldOffset() {
return TranslateOffsetInWords(dart::Number::NextFieldOffset());
}
} // namespace target
} // namespace compiler
} // namespace dart
#else
namespace dart {
namespace compiler {
namespace target {
const word Array::kMaxElements = Array_kMaxElements;
const word Context::kMaxElements = Context_kMaxElements;
} // namespace target
} // namespace compiler
} // namespace dart
#endif // !defined(DART_PRECOMPILED_RUNTIME)