c59549e957
TEST=ci Change-Id: Iaabdbceedbddffd2f980fb0828a8fc211524a3d5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/455180 Commit-Queue: Ryan Macnak <rmacnak@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
1151 lines
37 KiB
C++
1151 lines
37 KiB
C++
// 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::IsAllocatableInNewSpace(instance_size);
|
|
}
|
|
|
|
bool WillAllocateNewOrRememberedContext(intptr_t num_context_variables) {
|
|
if (!dart::Context::IsValidLength(num_context_variables)) return false;
|
|
return dart::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<int32_t>(Thread::Current()->random()->NextUInt32());
|
|
}
|
|
|
|
word TypedDataElementSizeInBytes(classid_t cid) {
|
|
return dart::TypedData::ElementSizeInBytes(cid);
|
|
}
|
|
|
|
word TypedDataMaxNewSpaceElements(classid_t cid) {
|
|
return (dart::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& 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 {
|
|
|
|
const word kPageSize = dart::kPageSize;
|
|
const word kPageSizeInWords = dart::kPageSize / kWordSize;
|
|
const word kPageMask = dart::kPageMask;
|
|
|
|
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::ImmutableBit::encode(
|
|
dart::Object::ShouldHaveImmutabilityBitSet(cid));
|
|
}
|
|
|
|
word Object::tags_offset() {
|
|
return 0;
|
|
}
|
|
|
|
const word UntaggedObject::kCardRememberedBit =
|
|
dart::UntaggedObject::CardRememberedBit::shift();
|
|
|
|
const word UntaggedObject::kCanonicalBit =
|
|
dart::UntaggedObject::CanonicalBit::shift();
|
|
|
|
const word UntaggedObject::kNewOrEvacuationCandidateBit =
|
|
dart::UntaggedObject::NewOrEvacuationCandidateBit::shift();
|
|
|
|
const word UntaggedObject::kOldAndNotRememberedBit =
|
|
dart::UntaggedObject::OldAndNotRememberedBit::shift();
|
|
|
|
const word UntaggedObject::kNotMarkedBit =
|
|
dart::UntaggedObject::NotMarkedBit::shift();
|
|
|
|
const word UntaggedObject::kImmutableBit =
|
|
dart::UntaggedObject::ImmutableBit::shift();
|
|
|
|
const word UntaggedObject::kSizeTagPos =
|
|
dart::UntaggedObject::SizeTagBits::shift();
|
|
|
|
const word UntaggedObject::kSizeTagSize =
|
|
dart::UntaggedObject::SizeTagBits::bitsize();
|
|
|
|
const word UntaggedObject::kClassIdTagPos =
|
|
dart::UntaggedObject::ClassIdTag::shift();
|
|
|
|
const word UntaggedObject::kClassIdTagSize =
|
|
dart::UntaggedObject::kClassIdTagSize;
|
|
|
|
#if defined(HASH_IN_OBJECT_HEADER)
|
|
const word UntaggedObject::kHashTagPos = dart::UntaggedObject::HashTag::shift();
|
|
|
|
const word UntaggedObject::kHashTagSize =
|
|
dart::UntaggedObject::HashTag::bitsize();
|
|
#endif
|
|
|
|
const word UntaggedObject::kSizeTagMaxSizeTag =
|
|
dart::UntaggedObject::SizeTag::kMaxSizeTagInUnitsOfAlignment *
|
|
ObjectAlignment::kObjectAlignment;
|
|
|
|
const word UntaggedObject::kTagBitsSizeTagPos =
|
|
dart::UntaggedObject::SizeTagBits::shift();
|
|
|
|
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();
|
|
|
|
const word UntaggedObject::kBarrierOverlapShift =
|
|
dart::UntaggedObject::kBarrierOverlapShift;
|
|
|
|
const word UntaggedObject::kGenerationalBarrierMask =
|
|
dart::UntaggedObject::kGenerationalBarrierMask;
|
|
|
|
const word UntaggedObject::kIncrementalBarrierMask =
|
|
dart::UntaggedObject::kIncrementalBarrierMask;
|
|
|
|
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 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::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)) {
|
|
// 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 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); \
|
|
}
|
|
|
|
#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;
|
|
}
|
|
|
|
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);
|
|
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<compressed_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());
|
|
}
|
|
|
|
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.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);
|
|
|
|
bool Heap::IsAllocatableInNewSpace(intptr_t instance_size) {
|
|
return dart::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 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 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());
|
|
}
|
|
|
|
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)
|