// 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 "platform/thread_sanitizer.h" #include "vm/compiler/runtime_api.h" #include "vm/object.h" #if !defined(DART_PRECOMPILED_RUNTIME) #include "vm/compiler/backend/flow_graph_compiler.h" #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(); } #if defined(DEBUG) bool IsNotTemporaryScopedHandle(const Object& obj) { return obj.IsNotTemporaryScopedHandle(); } #endif #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 kNullIdentityHash; } // TypeArguments should be handled before Instance as TypeArguments extends // Instance and TypeArguments::CanonicalizeHash just returns 0. if (obj.IsTypeArguments()) { return TypeArguments::Cast(obj).Hash(); } if (obj.IsInstance()) { return Instance::Cast(obj).CanonicalizeHash(); } if (obj.IsCode()) { return Code::Cast(obj).Hash(); } if (obj.IsFunction()) { return Function::Cast(obj).Hash(); } if (obj.IsField()) { return Field::Cast(obj).Hash(); } if (obj.IsICData()) { return ICData::Cast(obj).Hash(); } // Unlikely. return obj.GetClassId(); } const char* ObjectToCString(const Object& obj) { return obj.ToCString(); } 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& ArgumentsDescriptorBoxed(intptr_t type_args_len, intptr_t num_arguments) { return Array::ZoneHandle( ArgumentsDescriptor::NewBoxed(type_args_len, num_arguments)); } 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).Value(); return true; } return false; } int32_t CreateJitCookie() { return static_cast(Thread::Current()->random()->NextUInt32()); } word TypedDataElementSizeInBytes(classid_t cid) { return dart::TypedData::ElementSizeInBytes(cid); } word TypedDataMaxNewSpaceElements(classid_t cid) { return (target::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(dart::Symbols::PredefinedAddress()); } #endif const Code& StubCodeAllocateArray() { return dart::StubCode::AllocateArray(); } const Code& StubCodeSubtype2TestCache() { return dart::StubCode::Subtype2TestCache(); } const Code& StubCodeSubtype3TestCache() { return dart::StubCode::Subtype3TestCache(); } const Code& StubCodeSubtype4TestCache() { return dart::StubCode::Subtype4TestCache(); } const Code& StubCodeSubtype6TestCache() { return dart::StubCode::Subtype6TestCache(); } 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_); } const char* RuntimeEntry::name() const { return runtime_entry_->name(); } bool RuntimeEntry::is_leaf() const { return runtime_entry_->is_leaf(); } intptr_t RuntimeEntry::argument_count() const { return runtime_entry_->argument_count(); } namespace target { 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::NewOrEvacuationCandidateBit::encode(true) | dart::UntaggedObject::AlwaysSetBit::encode(true) | dart::UntaggedObject::NotMarkedBit::encode(true) | dart::UntaggedObject::ShallowImmutableBit::encode( dart::Object::ShouldHaveShallowImmutabilityBitSet(cid)) | dart::UntaggedObject::DeeplyImmutableBit::encode( dart::Object::ShouldHaveDeeplyImmutabilityBitSet(cid)); } const word UntaggedObject::kSizeTagMaxSizeTag = dart::UntaggedObject::SizeTag::kMaxSizeTagInUnitsOfAlignment * ObjectAlignment::kObjectAlignment; const word UntaggedAbstractType::kTypeStateFinalizedInstantiated = dart::UntaggedAbstractType::kFinalizedInstantiated; const word UntaggedAbstractType::kTypeStateShift = dart::UntaggedAbstractType::TypeStateBits::shift(); const word UntaggedAbstractType::kTypeStateBits = dart::UntaggedAbstractType::TypeStateBits::bitsize(); const word UntaggedAbstractType::kNullabilityMask = dart::UntaggedAbstractType::NullabilityBit::mask(); const word UntaggedType::kTypeClassIdShift = dart::UntaggedType::TypeClassIdBits::shift(); const word UntaggedTypeParameter::kIsFunctionTypeParameterBit = dart::UntaggedTypeParameter::IsFunctionTypeParameter::shift(); 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 kTypedDataBaseCid: return TypedDataBase::InstanceSize(); case kMapCid: return Map::InstanceSize(); case kSetCid: return Set::InstanceSize(); case kUnhandledExceptionCid: return UnhandledException::InstanceSize(); case kWeakPropertyCid: return WeakProperty::InstanceSize(); case kWeakReferenceCid: return WeakReference::InstanceSize(); case kFinalizerCid: return Finalizer::InstanceSize(); case kFinalizerEntryCid: return FinalizerEntry::InstanceSize(); case kNativeFinalizerCid: return NativeFinalizer::InstanceSize(); case kByteBufferCid: case kByteDataViewCid: case kUnmodifiableByteDataViewCid: 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: \ case kUnmodifiableTypedData##clazz##ViewCid: CLASS_LIST_TYPED_DATA(HANDLE_CASE) #undef HANDLE_CASE return handle.target_instance_size(); default: if (handle.id() >= kNumPredefinedCids) { return handle.target_instance_size(); } } FATAL("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::native_fields_array_offset() { return TranslateOffsetInWords(dart::Instance::NativeFieldsOffset()); } word Instance::DataOffsetFor(intptr_t cid) { if (dart::IsExternalTypedDataClassId(cid)) { // Elements start at offset 0 of the external data. return 0; } if (dart::IsTypedDataClassId(cid)) { return TypedData::payload_offset(); } switch (cid) { case kArrayCid: case kImmutableArrayCid: return Array::data_offset(); case kClosureCid: return Closure::element_offset(0); case kTypeArgumentsCid: return TypeArguments::types_offset(); case kOneByteStringCid: return OneByteString::data_offset(); case kTwoByteStringCid: return TwoByteString::data_offset(); case kRecordCid: return Record::field_offset(0); default: UNIMPLEMENTED(); return Array::data_offset(); } } word Instance::ElementSizeFor(intptr_t cid) { if (dart::IsExternalTypedDataClassId(cid) || dart::IsTypedDataClassId(cid) || dart::IsTypedDataViewClassId(cid) || dart::IsUnmodifiableTypedDataViewClassId(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; 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); \ } #define DEFINE_ENUM(Name, Elements) #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(index) - \ static_cast(First)]; \ } JIT_OFFSETS_LIST(DEFINE_FIELD, DEFINE_ARRAY, DEFINE_SIZEOF, DEFINE_ARRAY_SIZEOF, DEFINE_PAYLOAD_SIZEOF, DEFINE_RANGE, DEFINE_CONSTANT, DEFINE_ENUM) COMMON_OFFSETS_LIST(DEFINE_FIELD, DEFINE_ARRAY, DEFINE_SIZEOF, DEFINE_ARRAY_SIZEOF, DEFINE_PAYLOAD_SIZEOF, DEFINE_RANGE, DEFINE_CONSTANT, DEFINE_ENUM) #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(index) - \ static_cast(First)]; \ } JIT_OFFSETS_LIST(DEFINE_JIT_FIELD, DEFINE_JIT_ARRAY, DEFINE_JIT_SIZEOF, DEFINE_ARRAY_SIZEOF, DEFINE_PAYLOAD_SIZEOF, DEFINE_JIT_RANGE, DEFINE_CONSTANT, DEFINE_ENUM) #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(index) - \ static_cast(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, DEFINE_ENUM) #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(index) - \ static_cast(First)]; \ } else { \ return Class##_##Getter[static_cast(index) - \ static_cast(First)]; \ } \ } COMMON_OFFSETS_LIST(DEFINE_FIELD, DEFINE_ARRAY, DEFINE_SIZEOF, DEFINE_ARRAY_SIZEOF, DEFINE_PAYLOAD_SIZEOF, DEFINE_RANGE, DEFINE_CONSTANT, DEFINE_ENUM) #endif #undef DEFINE_FIELD #undef DEFINE_ARRAY #undef DEFINE_SIZEOF #undef DEFINE_RANGE #undef DEFINE_PAYLOAD_SIZEOF #undef DEFINE_CONSTANT #undef DEFINE_ENUM 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; } 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::native_safepoint_state_unacquired() { return dart::Thread::native_safepoint_state_unacquired(); } uword Thread::native_safepoint_state_acquired() { return dart::Thread::native_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); if (runtime_entry->is_leaf()) { return DeoptimizeCopyFrame_entry_point_offset() + TranslateOffsetInWords( host_offset - dart::Thread::DeoptimizeCopyFrame_entry_point_offset()); } else { 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(static_cast(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(dart::Smi::Cast(a).Value()); } bool IsDouble(const dart::Object& a) { return a.IsDouble(); } double DoubleValue(const dart::Object& a) { RELEASE_ASSERT(IsDouble(a)); return dart::Double::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.IsNull() || obj.IsCode(); } 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(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(dart::Nullability::kNullable); const uint8_t Nullability::kNonNullable = static_cast(dart::Nullability::kNonNullable); 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)); } intptr_t Closure::element_index_at_offset(intptr_t offset_in_bytes) { // Note: cannot delegate to dart::Closure::element_index_at_offset as // Closure layout is different between AOT and precompiler. const intptr_t index = (offset_in_bytes - Closure::element_offset(0)) / kCompressedWordSize; ASSERT(index >= 0); return index; } intptr_t Record::field_index_at_offset(intptr_t offset_in_bytes) { return dart::Record::field_index_at_offset( TranslateOffsetInWordsToHost(offset_in_bytes)); } word String::InstanceSize(word payload_size) { return RoundedAllocationSize(String::InstanceSize() + payload_size); } word Integer::NextFieldOffset() { return TranslateOffsetInWords(dart::Integer::NextFieldOffset()); } word Smi::InstanceSize() { return 0; } word Number::NextFieldOffset() { return TranslateOffsetInWords(dart::Number::NextFieldOffset()); } void UnboxFieldIfSupported(const dart::Field& field, const dart::AbstractType& type) { if (field.is_static() || field.is_late()) { return; } if (type.IsNullable()) { return; } classid_t cid = kIllegalCid; if (type.IsDoubleType()) { cid = kDoubleCid; } else if (type.IsFloat32x4Type()) { if (FlowGraphCompiler::SupportsUnboxedSimd128()) { cid = kFloat32x4Cid; } } else if (type.IsFloat64x2Type()) { if (FlowGraphCompiler::SupportsUnboxedSimd128()) { cid = kFloat64x2Cid; } } if (cid != kIllegalCid) { field.set_guarded_cid(cid); field.set_is_nullable(false); field.set_is_unboxed(true); field.set_guarded_list_length(dart::Field::kNoFixedLength); field.set_guarded_list_length_in_object_offset( dart::Field::kUnknownLengthOffset); } } } // 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; const word Record::kMaxElements = Record_kMaxElements; const word RecordShape::kNumFieldsMask = RecordShape_kNumFieldsMask; const word RecordShape::kMaxNumFields = RecordShape_kMaxNumFields; const word RecordShape::kFieldNamesIndexShift = RecordShape_kFieldNamesIndexShift; const word RecordShape::kFieldNamesIndexMask = RecordShape_kFieldNamesIndexMask; const word RecordShape::kMaxFieldNamesIndex = RecordShape_kMaxFieldNamesIndex; } // namespace target } // namespace compiler } // namespace dart #endif // !defined(DART_PRECOMPILED_RUNTIME)