More compact string representation on 64 bit.
This moves the hash code into the header word for strings on 64 bit platforms. With the old layout, 9 character strings became 48-byte objects. With the new layout you have to go to 17 characters before you are bumped from 4 to 6 words (32 to 48 bytes). As a side effect, the class ID field is now 16 bits on all platforms instead of having two different sizes, and the size field is 8 bits on all platforms. This also paves the way for moving the hash code for instance objects into the header, so we won't need the side-lookup in the hash-table-of-hash-codes on 64 bit platforms. R=vegorov@google.com BUG= Review-Url: https://codereview.chromium.org/2893553002 .
This commit is contained in:
@@ -448,13 +448,7 @@ typedef intptr_t word;
|
||||
typedef uintptr_t uword;
|
||||
|
||||
// Size of a class id.
|
||||
#if defined(ARCH_IS_32_BIT)
|
||||
typedef uint16_t classid_t;
|
||||
#elif defined(ARCH_IS_64_BIT)
|
||||
typedef uint32_t classid_t;
|
||||
#else
|
||||
#error Unexpected architecture word size
|
||||
#endif
|
||||
|
||||
// Byte sizes.
|
||||
const int kWordSize = sizeof(word);
|
||||
|
||||
@@ -973,12 +973,12 @@ void Assembler::StoreIntoObjectOffsetNoBarrier(Register object,
|
||||
|
||||
|
||||
void Assembler::LoadClassId(Register result, Register object) {
|
||||
ASSERT(RawObject::kClassIdTagPos == kBitsPerInt32);
|
||||
ASSERT(RawObject::kClassIdTagSize == kBitsPerInt32);
|
||||
ASSERT(RawObject::kClassIdTagPos == 16);
|
||||
ASSERT(RawObject::kClassIdTagSize == 16);
|
||||
const intptr_t class_id_offset =
|
||||
Object::tags_offset() + RawObject::kClassIdTagPos / kBitsPerByte;
|
||||
LoadFromOffset(result, object, class_id_offset - kHeapObjectTag,
|
||||
kUnsignedWord);
|
||||
kUnsignedHalfword);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3624,12 +3624,12 @@ void Assembler::EmitGenericShift(bool wide,
|
||||
|
||||
|
||||
void Assembler::LoadClassId(Register result, Register object) {
|
||||
ASSERT(RawObject::kClassIdTagPos == kBitsPerInt32);
|
||||
ASSERT(RawObject::kClassIdTagSize == kBitsPerInt32);
|
||||
ASSERT(sizeof(classid_t) == sizeof(uint32_t));
|
||||
ASSERT(RawObject::kClassIdTagPos == 16);
|
||||
ASSERT(RawObject::kClassIdTagSize == 16);
|
||||
ASSERT(sizeof(classid_t) == sizeof(uint16_t));
|
||||
const intptr_t class_id_offset =
|
||||
Object::tags_offset() + RawObject::kClassIdTagPos / kBitsPerByte;
|
||||
movl(result, FieldAddress(object, class_id_offset));
|
||||
movzxw(result, FieldAddress(object, class_id_offset));
|
||||
}
|
||||
|
||||
|
||||
@@ -3659,9 +3659,9 @@ void Assembler::SmiUntagOrCheckClass(Register object,
|
||||
intptr_t class_id,
|
||||
Label* is_smi) {
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
ASSERT(RawObject::kClassIdTagPos == kBitsPerInt32);
|
||||
ASSERT(RawObject::kClassIdTagSize == kBitsPerInt32);
|
||||
ASSERT(sizeof(classid_t) == sizeof(uint32_t));
|
||||
ASSERT(RawObject::kClassIdTagPos == 16);
|
||||
ASSERT(RawObject::kClassIdTagSize == 16);
|
||||
ASSERT(sizeof(classid_t) == sizeof(uint16_t));
|
||||
const intptr_t class_id_offset =
|
||||
Object::tags_offset() + RawObject::kClassIdTagPos / kBitsPerByte;
|
||||
|
||||
@@ -3670,7 +3670,7 @@ void Assembler::SmiUntagOrCheckClass(Register object,
|
||||
j(NOT_CARRY, is_smi, kNearJump);
|
||||
// Load cid: can't use LoadClassId, object is untagged. Use TIMES_2 scale
|
||||
// factor in the addressing mode to compensate for this.
|
||||
movl(TMP, Address(object, TIMES_2, class_id_offset));
|
||||
movzxw(TMP, Address(object, TIMES_2, class_id_offset));
|
||||
cmpl(TMP, Immediate(class_id));
|
||||
}
|
||||
|
||||
|
||||
@@ -1911,20 +1911,20 @@ class RODataSerializationCluster : public SerializationCluster {
|
||||
// will be loaded into read-only memory.
|
||||
if (cid_ == kOneByteStringCid) {
|
||||
RawOneByteString* str = static_cast<RawOneByteString*>(object);
|
||||
if (str->ptr()->hash_ == Smi::New(0)) {
|
||||
if (String::GetCachedHash(str) == 0) {
|
||||
intptr_t hash =
|
||||
String::Hash(str->ptr()->data(), Smi::Value(str->ptr()->length_));
|
||||
str->ptr()->hash_ = Smi::New(hash);
|
||||
String::SetCachedHash(str, hash);
|
||||
}
|
||||
ASSERT(str->ptr()->hash_ != Smi::New(0));
|
||||
ASSERT(String::GetCachedHash(str) != 0);
|
||||
} else if (cid_ == kTwoByteStringCid) {
|
||||
RawTwoByteString* str = static_cast<RawTwoByteString*>(object);
|
||||
if (str->ptr()->hash_ == Smi::New(0)) {
|
||||
if (String::GetCachedHash(str) == 0) {
|
||||
intptr_t hash = String::Hash(str->ptr()->data(),
|
||||
Smi::Value(str->ptr()->length_) * 2);
|
||||
str->ptr()->hash_ = Smi::New(hash);
|
||||
String::SetCachedHash(str, hash);
|
||||
}
|
||||
ASSERT(str->ptr()->hash_ != Smi::New(0));
|
||||
ASSERT(String::GetCachedHash(str) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4359,7 +4359,7 @@ class OneByteStringSerializationCluster : public SerializationCluster {
|
||||
intptr_t length = Smi::Value(str->ptr()->length_);
|
||||
s->Write<int32_t>(length);
|
||||
s->Write<bool>(str->IsCanonical());
|
||||
intptr_t hash = Smi::Value(str->ptr()->hash_);
|
||||
intptr_t hash = String::GetCachedHash(str);
|
||||
s->Write<int32_t>(hash);
|
||||
s->WriteBytes(str->ptr()->data(), length);
|
||||
}
|
||||
@@ -4399,7 +4399,7 @@ class OneByteStringDeserializationCluster : public DeserializationCluster {
|
||||
OneByteString::InstanceSize(length),
|
||||
is_vm_object, is_canonical);
|
||||
str->ptr()->length_ = Smi::New(length);
|
||||
str->ptr()->hash_ = Smi::New(d->Read<int32_t>());
|
||||
String::SetCachedHash(str, d->Read<int32_t>());
|
||||
for (intptr_t j = 0; j < length; j++) {
|
||||
str->ptr()->data()[j] = d->Read<uint8_t>();
|
||||
}
|
||||
@@ -4438,7 +4438,7 @@ class TwoByteStringSerializationCluster : public SerializationCluster {
|
||||
intptr_t length = Smi::Value(str->ptr()->length_);
|
||||
s->Write<int32_t>(length);
|
||||
s->Write<bool>(str->IsCanonical());
|
||||
intptr_t hash = Smi::Value(str->ptr()->hash_);
|
||||
intptr_t hash = String::GetCachedHash(str);
|
||||
s->Write<int32_t>(hash);
|
||||
s->WriteBytes(reinterpret_cast<uint8_t*>(str->ptr()->data()), length * 2);
|
||||
}
|
||||
@@ -4478,7 +4478,7 @@ class TwoByteStringDeserializationCluster : public DeserializationCluster {
|
||||
TwoByteString::InstanceSize(length),
|
||||
is_vm_object, is_canonical);
|
||||
str->ptr()->length_ = Smi::New(length);
|
||||
str->ptr()->hash_ = Smi::New(d->Read<int32_t>());
|
||||
String::SetCachedHash(str, d->Read<int32_t>());
|
||||
uint8_t* cdata = reinterpret_cast<uint8_t*>(str->ptr()->data());
|
||||
d->ReadBytes(cdata, length * 2);
|
||||
}
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ static void CheckOffsets() {
|
||||
CHECK_OFFSET(Heap::TopOffset(Heap::kNew), 8);
|
||||
CHECK_OFFSET(Thread::stack_limit_offset(), 8);
|
||||
CHECK_OFFSET(Thread::object_null_offset(), 80);
|
||||
CHECK_OFFSET(SingleTargetCache::upper_limit_offset(), 28);
|
||||
CHECK_OFFSET(SingleTargetCache::upper_limit_offset(), 26);
|
||||
CHECK_OFFSET(Isolate::object_store_offset(), 56);
|
||||
NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 208));
|
||||
#endif
|
||||
|
||||
@@ -44,6 +44,10 @@ const intptr_t kSmiMin32 = -(static_cast<intptr_t>(1) << kSmiBits32);
|
||||
static_cast<intptr_t>(!(sizeof(array) % sizeof(*(array))))) // NOLINT
|
||||
|
||||
|
||||
#if defined(ARCH_IS_64_BIT)
|
||||
#define HASH_IN_OBJECT_HEADER 1
|
||||
#endif
|
||||
|
||||
// The expression OFFSET_OF(type, field) computes the byte-offset of
|
||||
// the specified field relative to the containing type.
|
||||
//
|
||||
|
||||
@@ -1547,7 +1547,7 @@ LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Zone* zone,
|
||||
|
||||
|
||||
void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(sizeof(classid_t) == kInt32Size);
|
||||
ASSERT(sizeof(classid_t) == kInt16Size);
|
||||
const intptr_t value_cid = value()->Type()->ToCid();
|
||||
const intptr_t field_cid = field().guarded_cid();
|
||||
const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
|
||||
@@ -1593,24 +1593,24 @@ void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
__ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
|
||||
|
||||
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset(),
|
||||
kUnsignedWord);
|
||||
kUnsignedHalfword);
|
||||
FieldAddress field_nullability_operand(
|
||||
field_reg, Field::is_nullable_offset(), kUnsignedWord);
|
||||
field_reg, Field::is_nullable_offset(), kUnsignedHalfword);
|
||||
|
||||
if (value_cid == kDynamicCid) {
|
||||
LoadValueCid(compiler, value_cid_reg, value_reg);
|
||||
Label skip_length_check;
|
||||
__ ldr(TMP, field_cid_operand, kUnsignedWord);
|
||||
__ ldr(TMP, field_cid_operand, kUnsignedHalfword);
|
||||
__ CompareRegisters(value_cid_reg, TMP);
|
||||
__ b(&ok, EQ);
|
||||
__ ldr(TMP, field_nullability_operand, kUnsignedWord);
|
||||
__ ldr(TMP, field_nullability_operand, kUnsignedHalfword);
|
||||
__ CompareRegisters(value_cid_reg, TMP);
|
||||
} else if (value_cid == kNullCid) {
|
||||
__ ldr(value_cid_reg, field_nullability_operand, kUnsignedWord);
|
||||
__ ldr(value_cid_reg, field_nullability_operand, kUnsignedHalfword);
|
||||
__ CompareImmediate(value_cid_reg, value_cid);
|
||||
} else {
|
||||
Label skip_length_check;
|
||||
__ ldr(value_cid_reg, field_cid_operand, kUnsignedWord);
|
||||
__ ldr(value_cid_reg, field_cid_operand, kUnsignedHalfword);
|
||||
__ CompareImmediate(value_cid_reg, value_cid);
|
||||
}
|
||||
__ b(&ok, EQ);
|
||||
@@ -1624,17 +1624,17 @@ void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
if (!field().needs_length_check()) {
|
||||
// Uninitialized field can be handled inline. Check if the
|
||||
// field is still unitialized.
|
||||
__ ldr(TMP, field_cid_operand, kUnsignedWord);
|
||||
__ ldr(TMP, field_cid_operand, kUnsignedHalfword);
|
||||
__ CompareImmediate(TMP, kIllegalCid);
|
||||
__ b(fail, NE);
|
||||
|
||||
if (value_cid == kDynamicCid) {
|
||||
__ str(value_cid_reg, field_cid_operand, kUnsignedWord);
|
||||
__ str(value_cid_reg, field_nullability_operand, kUnsignedWord);
|
||||
__ str(value_cid_reg, field_cid_operand, kUnsignedHalfword);
|
||||
__ str(value_cid_reg, field_nullability_operand, kUnsignedHalfword);
|
||||
} else {
|
||||
__ LoadImmediate(TMP, value_cid);
|
||||
__ str(TMP, field_cid_operand, kUnsignedWord);
|
||||
__ str(TMP, field_nullability_operand, kUnsignedWord);
|
||||
__ str(TMP, field_cid_operand, kUnsignedHalfword);
|
||||
__ str(TMP, field_nullability_operand, kUnsignedHalfword);
|
||||
}
|
||||
|
||||
if (deopt == NULL) {
|
||||
@@ -1648,7 +1648,7 @@ void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
__ Bind(fail);
|
||||
|
||||
__ LoadFieldFromOffset(TMP, field_reg, Field::guarded_cid_offset(),
|
||||
kUnsignedWord);
|
||||
kUnsignedHalfword);
|
||||
__ CompareImmediate(TMP, kDynamicCid);
|
||||
__ b(&ok, EQ);
|
||||
|
||||
@@ -1887,7 +1887,7 @@ LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
|
||||
|
||||
void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(sizeof(classid_t) == kInt32Size);
|
||||
ASSERT(sizeof(classid_t) == kInt16Size);
|
||||
Label skip_store;
|
||||
|
||||
const Register instance_reg = locs()->in(0).reg();
|
||||
@@ -1959,7 +1959,7 @@ void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
__ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
|
||||
|
||||
__ LoadFieldFromOffset(temp2, temp, Field::is_nullable_offset(),
|
||||
kUnsignedWord);
|
||||
kUnsignedHalfword);
|
||||
__ CompareImmediate(temp2, kNullCid);
|
||||
__ b(&store_pointer, EQ);
|
||||
|
||||
@@ -1969,17 +1969,17 @@ void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
__ b(&store_pointer, EQ);
|
||||
|
||||
__ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(),
|
||||
kUnsignedWord);
|
||||
kUnsignedHalfword);
|
||||
__ CompareImmediate(temp2, kDoubleCid);
|
||||
__ b(&store_double, EQ);
|
||||
|
||||
__ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(),
|
||||
kUnsignedWord);
|
||||
kUnsignedHalfword);
|
||||
__ CompareImmediate(temp2, kFloat32x4Cid);
|
||||
__ b(&store_float32x4, EQ);
|
||||
|
||||
__ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(),
|
||||
kUnsignedWord);
|
||||
kUnsignedHalfword);
|
||||
__ CompareImmediate(temp2, kFloat64x2Cid);
|
||||
__ b(&store_float64x2, EQ);
|
||||
|
||||
@@ -2243,7 +2243,7 @@ LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
|
||||
|
||||
void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(sizeof(classid_t) == kInt32Size);
|
||||
ASSERT(sizeof(classid_t) == kInt16Size);
|
||||
const Register instance_reg = locs()->in(0).reg();
|
||||
if (IsUnboxedLoad() && compiler->is_optimizing()) {
|
||||
const VRegister result = locs()->out(0).fpu_reg();
|
||||
@@ -2280,23 +2280,23 @@ void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
__ LoadObject(result_reg, Field::ZoneHandle(field()->Original()));
|
||||
|
||||
FieldAddress field_cid_operand(result_reg, Field::guarded_cid_offset(),
|
||||
kUnsignedWord);
|
||||
kUnsignedHalfword);
|
||||
FieldAddress field_nullability_operand(
|
||||
result_reg, Field::is_nullable_offset(), kUnsignedWord);
|
||||
result_reg, Field::is_nullable_offset(), kUnsignedHalfword);
|
||||
|
||||
__ ldr(temp, field_nullability_operand, kUnsignedWord);
|
||||
__ ldr(temp, field_nullability_operand, kUnsignedHalfword);
|
||||
__ CompareImmediate(temp, kNullCid);
|
||||
__ b(&load_pointer, EQ);
|
||||
|
||||
__ ldr(temp, field_cid_operand, kUnsignedWord);
|
||||
__ ldr(temp, field_cid_operand, kUnsignedHalfword);
|
||||
__ CompareImmediate(temp, kDoubleCid);
|
||||
__ b(&load_double, EQ);
|
||||
|
||||
__ ldr(temp, field_cid_operand, kUnsignedWord);
|
||||
__ ldr(temp, field_cid_operand, kUnsignedHalfword);
|
||||
__ CompareImmediate(temp, kFloat32x4Cid);
|
||||
__ b(&load_float32x4, EQ);
|
||||
|
||||
__ ldr(temp, field_cid_operand, kUnsignedWord);
|
||||
__ ldr(temp, field_cid_operand, kUnsignedHalfword);
|
||||
__ CompareImmediate(temp, kFloat64x2Cid);
|
||||
__ b(&load_float64x2, EQ);
|
||||
|
||||
|
||||
@@ -1498,7 +1498,7 @@ LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Zone* zone,
|
||||
|
||||
|
||||
void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(sizeof(classid_t) == kInt32Size);
|
||||
ASSERT(sizeof(classid_t) == kInt16Size);
|
||||
const intptr_t value_cid = value()->Type()->ToCid();
|
||||
const intptr_t field_cid = field().guarded_cid();
|
||||
const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
|
||||
@@ -1550,13 +1550,13 @@ void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
if (value_cid == kDynamicCid) {
|
||||
LoadValueCid(compiler, value_cid_reg, value_reg);
|
||||
|
||||
__ cmpl(value_cid_reg, field_cid_operand);
|
||||
__ cmpw(value_cid_reg, field_cid_operand);
|
||||
__ j(EQUAL, &ok);
|
||||
__ cmpl(value_cid_reg, field_nullability_operand);
|
||||
__ cmpw(value_cid_reg, field_nullability_operand);
|
||||
} else if (value_cid == kNullCid) {
|
||||
__ cmpl(field_nullability_operand, Immediate(value_cid));
|
||||
__ cmpw(field_nullability_operand, Immediate(value_cid));
|
||||
} else {
|
||||
__ cmpl(field_cid_operand, Immediate(value_cid));
|
||||
__ cmpw(field_cid_operand, Immediate(value_cid));
|
||||
}
|
||||
__ j(EQUAL, &ok);
|
||||
|
||||
@@ -1567,16 +1567,16 @@ void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
if (!field().needs_length_check()) {
|
||||
// Uninitialized field can be handled inline. Check if the
|
||||
// field is still unitialized.
|
||||
__ cmpl(field_cid_operand, Immediate(kIllegalCid));
|
||||
__ cmpw(field_cid_operand, Immediate(kIllegalCid));
|
||||
__ j(NOT_EQUAL, fail);
|
||||
|
||||
if (value_cid == kDynamicCid) {
|
||||
__ movl(field_cid_operand, value_cid_reg);
|
||||
__ movl(field_nullability_operand, value_cid_reg);
|
||||
__ movw(field_cid_operand, value_cid_reg);
|
||||
__ movw(field_nullability_operand, value_cid_reg);
|
||||
} else {
|
||||
ASSERT(field_reg != kNoRegister);
|
||||
__ movl(field_cid_operand, Immediate(value_cid));
|
||||
__ movl(field_nullability_operand, Immediate(value_cid));
|
||||
__ movw(field_cid_operand, Immediate(value_cid));
|
||||
__ movw(field_nullability_operand, Immediate(value_cid));
|
||||
}
|
||||
|
||||
if (deopt == NULL) {
|
||||
@@ -1589,7 +1589,7 @@ void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(!compiler->is_optimizing());
|
||||
__ Bind(fail);
|
||||
|
||||
__ cmpl(FieldAddress(field_reg, Field::guarded_cid_offset()),
|
||||
__ cmpw(FieldAddress(field_reg, Field::guarded_cid_offset()),
|
||||
Immediate(kDynamicCid));
|
||||
__ j(EQUAL, &ok);
|
||||
|
||||
@@ -1832,7 +1832,7 @@ static void EnsureMutableBox(FlowGraphCompiler* compiler,
|
||||
|
||||
|
||||
void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(sizeof(classid_t) == kInt32Size);
|
||||
ASSERT(sizeof(classid_t) == kInt16Size);
|
||||
Label skip_store;
|
||||
|
||||
Register instance_reg = locs()->in(0).reg();
|
||||
@@ -1904,7 +1904,7 @@ void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
|
||||
__ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
|
||||
|
||||
__ cmpl(FieldAddress(temp, Field::is_nullable_offset()),
|
||||
__ cmpw(FieldAddress(temp, Field::is_nullable_offset()),
|
||||
Immediate(kNullCid));
|
||||
__ j(EQUAL, &store_pointer);
|
||||
|
||||
@@ -1912,15 +1912,15 @@ void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
__ testq(temp2, Immediate(1 << Field::kUnboxingCandidateBit));
|
||||
__ j(ZERO, &store_pointer);
|
||||
|
||||
__ cmpl(FieldAddress(temp, Field::guarded_cid_offset()),
|
||||
__ cmpw(FieldAddress(temp, Field::guarded_cid_offset()),
|
||||
Immediate(kDoubleCid));
|
||||
__ j(EQUAL, &store_double);
|
||||
|
||||
__ cmpl(FieldAddress(temp, Field::guarded_cid_offset()),
|
||||
__ cmpw(FieldAddress(temp, Field::guarded_cid_offset()),
|
||||
Immediate(kFloat32x4Cid));
|
||||
__ j(EQUAL, &store_float32x4);
|
||||
|
||||
__ cmpl(FieldAddress(temp, Field::guarded_cid_offset()),
|
||||
__ cmpw(FieldAddress(temp, Field::guarded_cid_offset()),
|
||||
Immediate(kFloat64x2Cid));
|
||||
__ j(EQUAL, &store_float64x2);
|
||||
|
||||
@@ -2190,7 +2190,7 @@ LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
|
||||
|
||||
void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(sizeof(classid_t) == kInt32Size);
|
||||
ASSERT(sizeof(classid_t) == kInt16Size);
|
||||
Register instance_reg = locs()->in(0).reg();
|
||||
if (IsUnboxedLoad() && compiler->is_optimizing()) {
|
||||
XmmRegister result = locs()->out(0).fpu_reg();
|
||||
@@ -2229,20 +2229,19 @@ void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
|
||||
__ LoadObject(result, Field::ZoneHandle(field()->Original()));
|
||||
|
||||
__ cmpl(FieldAddress(result, Field::is_nullable_offset()),
|
||||
Immediate(kNullCid));
|
||||
FieldAddress field_cid_operand(result, Field::guarded_cid_offset());
|
||||
FieldAddress field_nullability_operand(result, Field::is_nullable_offset());
|
||||
|
||||
__ cmpw(field_nullability_operand, Immediate(kNullCid));
|
||||
__ j(EQUAL, &load_pointer);
|
||||
|
||||
__ cmpl(FieldAddress(result, Field::guarded_cid_offset()),
|
||||
Immediate(kDoubleCid));
|
||||
__ cmpw(field_cid_operand, Immediate(kDoubleCid));
|
||||
__ j(EQUAL, &load_double);
|
||||
|
||||
__ cmpl(FieldAddress(result, Field::guarded_cid_offset()),
|
||||
Immediate(kFloat32x4Cid));
|
||||
__ cmpw(field_cid_operand, Immediate(kFloat32x4Cid));
|
||||
__ j(EQUAL, &load_float32x4);
|
||||
|
||||
__ cmpl(FieldAddress(result, Field::guarded_cid_offset()),
|
||||
Immediate(kFloat64x2Cid));
|
||||
__ cmpw(field_cid_operand, Immediate(kFloat64x2Cid));
|
||||
__ j(EQUAL, &load_float64x2);
|
||||
|
||||
// Fall through.
|
||||
|
||||
@@ -176,8 +176,9 @@ void Intrinsifier::GrowableArray_add(Assembler* assembler) {
|
||||
__ CompareImmediate(R2, max_len); \
|
||||
__ b(&fall_through, GT); \
|
||||
__ mov(R2, Operand(R2, LSL, scale_shift)); \
|
||||
const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \
|
||||
__ AddImmediate(R2, fixed_size); \
|
||||
const intptr_t fixed_size_plus_alignment_padding = \
|
||||
sizeof(Raw##type_name) + kObjectAlignment - 1; \
|
||||
__ AddImmediate(R2, fixed_size_plus_alignment_padding); \
|
||||
__ bic(R2, R2, Operand(kObjectAlignment - 1)); \
|
||||
Heap::Space space = Heap::kNew; \
|
||||
__ ldr(R3, Address(THR, Thread::heap_offset())); \
|
||||
@@ -1997,8 +1998,9 @@ static void TryAllocateOnebyteString(Assembler* assembler,
|
||||
__ mov(R8, Operand(length_reg)); // Save the length register.
|
||||
// TODO(koda): Protect against negative length and overflow here.
|
||||
__ SmiUntag(length_reg);
|
||||
const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1;
|
||||
__ AddImmediate(length_reg, fixed_size);
|
||||
const intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawString) + kObjectAlignment - 1;
|
||||
__ AddImmediate(length_reg, fixed_size_plus_alignment_padding);
|
||||
__ bic(length_reg, length_reg, Operand(kObjectAlignment - 1));
|
||||
|
||||
const intptr_t cid = kOneByteStringCid;
|
||||
|
||||
@@ -196,8 +196,9 @@ static int GetScaleFactor(intptr_t size) {
|
||||
__ CompareImmediate(R2, max_len); \
|
||||
__ b(&fall_through, GT); \
|
||||
__ LslImmediate(R2, R2, scale_shift); \
|
||||
const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \
|
||||
__ AddImmediate(R2, fixed_size); \
|
||||
const intptr_t fixed_size_plus_alignment_padding = \
|
||||
sizeof(Raw##type_name) + kObjectAlignment - 1; \
|
||||
__ AddImmediate(R2, fixed_size_plus_alignment_padding); \
|
||||
__ andi(R2, R2, Immediate(~(kObjectAlignment - 1))); \
|
||||
Heap::Space space = Heap::kNew; \
|
||||
__ ldr(R3, Address(THR, Thread::heap_offset())); \
|
||||
@@ -1822,8 +1823,8 @@ void Intrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler) {
|
||||
void Intrinsifier::String_getHashCode(Assembler* assembler) {
|
||||
Label fall_through;
|
||||
__ ldr(R0, Address(SP, 0 * kWordSize));
|
||||
__ ldr(R0, FieldAddress(R0, String::hash_offset()));
|
||||
__ CompareRegisters(R0, ZR);
|
||||
__ ldr(R0, FieldAddress(R0, String::hash_offset()), kUnsignedWord);
|
||||
__ adds(R0, R0, Operand(R0)); // Smi tag the hash code, setting Z flag.
|
||||
__ b(&fall_through, EQ);
|
||||
__ ret();
|
||||
// Hash not yet computed.
|
||||
@@ -1995,8 +1996,8 @@ void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) {
|
||||
void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) {
|
||||
Label compute_hash;
|
||||
__ ldr(R1, Address(SP, 0 * kWordSize)); // OneByteString object.
|
||||
__ ldr(R0, FieldAddress(R1, String::hash_offset()));
|
||||
__ CompareRegisters(R0, ZR);
|
||||
__ ldr(R0, FieldAddress(R1, String::hash_offset()), kUnsignedWord);
|
||||
__ adds(R0, R0, Operand(R0)); // Smi tag the hash code, setting Z flag.
|
||||
__ b(&compute_hash, EQ);
|
||||
__ ret(); // Return if already computed.
|
||||
|
||||
@@ -2046,8 +2047,8 @@ void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) {
|
||||
// return hash_ == 0 ? 1 : hash_;
|
||||
__ Bind(&done);
|
||||
__ csinc(R0, R0, ZR, NE); // R0 <- (R0 != 0) ? R0 : (ZR + 1).
|
||||
__ str(R0, FieldAddress(R1, String::hash_offset()), kUnsignedWord);
|
||||
__ SmiTag(R0);
|
||||
__ str(R0, FieldAddress(R1, String::hash_offset()));
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -2064,9 +2065,16 @@ static void TryAllocateOnebyteString(Assembler* assembler,
|
||||
NOT_IN_PRODUCT(__ MaybeTraceAllocation(kOneByteStringCid, R0, failure));
|
||||
__ mov(R6, length_reg); // Save the length register.
|
||||
// TODO(koda): Protect against negative length and overflow here.
|
||||
__ SmiUntag(length_reg);
|
||||
const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1;
|
||||
__ AddImmediate(length_reg, fixed_size);
|
||||
__ adds(length_reg, ZR, Operand(length_reg, ASR, kSmiTagSize)); // Smi untag.
|
||||
// If the length is 0 then we have to make the allocated size a bit bigger,
|
||||
// otherwise the string takes up less space than an ExternalOneByteString,
|
||||
// and cannot be externalized. TODO(erikcorry): We should probably just
|
||||
// return a static zero length string here instead.
|
||||
// length <- (length != 0) ? length : (ZR + 1).
|
||||
__ csinc(length_reg, length_reg, ZR, NE);
|
||||
const intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawString) + kObjectAlignment - 1;
|
||||
__ AddImmediate(length_reg, fixed_size_plus_alignment_padding);
|
||||
__ andi(length_reg, length_reg, Immediate(~(kObjectAlignment - 1)));
|
||||
|
||||
const intptr_t cid = kOneByteStringCid;
|
||||
@@ -2106,6 +2114,7 @@ static void TryAllocateOnebyteString(Assembler* assembler,
|
||||
|
||||
// Get the class index and insert it into the tags.
|
||||
// R2: size and bit tags.
|
||||
// This also clears the hash, which is in the high word of the tags.
|
||||
__ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid));
|
||||
__ orr(R2, R2, Operand(TMP));
|
||||
__ str(R2, FieldAddress(R0, String::tags_offset())); // Store tags.
|
||||
@@ -2114,9 +2123,6 @@ static void TryAllocateOnebyteString(Assembler* assembler,
|
||||
// Set the length field using the saved length (R6).
|
||||
__ StoreIntoObjectNoBarrier(R0, FieldAddress(R0, String::length_offset()),
|
||||
R6);
|
||||
// Clear hash.
|
||||
__ mov(TMP, ZR);
|
||||
__ str(TMP, FieldAddress(R0, String::hash_offset()));
|
||||
__ b(ok);
|
||||
|
||||
__ Bind(&fail);
|
||||
|
||||
@@ -212,8 +212,9 @@ void Intrinsifier::GrowableArray_add(Assembler* assembler) {
|
||||
/* only scale by 8. */ \
|
||||
scale_factor = TIMES_8; \
|
||||
} \
|
||||
const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \
|
||||
__ leal(EDI, Address(EDI, scale_factor, fixed_size)); \
|
||||
const intptr_t fixed_size_plus_alignment_padding = \
|
||||
sizeof(Raw##type_name) + kObjectAlignment - 1; \
|
||||
__ leal(EDI, Address(EDI, scale_factor, fixed_size_plus_alignment_padding)); \
|
||||
__ andl(EDI, Immediate(-kObjectAlignment)); \
|
||||
Heap::Space space = Heap::kNew; \
|
||||
__ movl(ECX, Address(THR, Thread::heap_offset())); \
|
||||
@@ -2027,8 +2028,10 @@ static void TryAllocateOnebyteString(Assembler* assembler,
|
||||
Label pop_and_fail;
|
||||
__ pushl(EDI); // Preserve length.
|
||||
__ SmiUntag(EDI);
|
||||
const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1;
|
||||
__ leal(EDI, Address(EDI, TIMES_1, fixed_size)); // EDI is untagged.
|
||||
const intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawString) + kObjectAlignment - 1;
|
||||
__ leal(EDI, Address(EDI, TIMES_1,
|
||||
fixed_size_plus_alignment_padding)); // EDI is untagged.
|
||||
__ andl(EDI, Immediate(-kObjectAlignment));
|
||||
|
||||
const intptr_t cid = kOneByteStringCid;
|
||||
|
||||
@@ -167,8 +167,9 @@ void Intrinsifier::GrowableArray_add(Assembler* assembler) {
|
||||
/* T2: untagged array length. */ \
|
||||
__ BranchSignedGreater(T2, Immediate(max_len), &fall_through); \
|
||||
__ sll(T2, T2, scale_shift); \
|
||||
const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \
|
||||
__ AddImmediate(T2, fixed_size); \
|
||||
const intptr_t fixed_size_plus_alignment_padding = \
|
||||
sizeof(Raw##type_name) + kObjectAlignment - 1; \
|
||||
__ AddImmediate(T2, fixed_size_plus_alignment_padding); \
|
||||
__ LoadImmediate(TMP, -kObjectAlignment); \
|
||||
__ and_(T2, T2, TMP); \
|
||||
Heap::Space space = Heap::kNew; \
|
||||
@@ -2131,8 +2132,9 @@ static void TryAllocateOnebyteString(Assembler* assembler,
|
||||
__ mov(T6, length_reg); // Save the length register.
|
||||
// TODO(koda): Protect against negative length and overflow here.
|
||||
__ SmiUntag(length_reg);
|
||||
const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1;
|
||||
__ AddImmediate(length_reg, fixed_size);
|
||||
const intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawString) + kObjectAlignment - 1;
|
||||
__ AddImmediate(length_reg, fixed_size_plus_alignment_padding);
|
||||
__ LoadImmediate(TMP, ~(kObjectAlignment - 1));
|
||||
__ and_(length_reg, length_reg, TMP);
|
||||
|
||||
|
||||
@@ -170,8 +170,9 @@ void Intrinsifier::GrowableArray_add(Assembler* assembler) {
|
||||
/* only scale by 8. */ \
|
||||
scale_factor = TIMES_8; \
|
||||
} \
|
||||
const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \
|
||||
__ leaq(RDI, Address(RDI, scale_factor, fixed_size)); \
|
||||
const intptr_t fixed_size_plus_alignment_padding = \
|
||||
sizeof(Raw##type_name) + kObjectAlignment - 1; \
|
||||
__ leaq(RDI, Address(RDI, scale_factor, fixed_size_plus_alignment_padding)); \
|
||||
__ andq(RDI, Immediate(-kObjectAlignment)); \
|
||||
Heap::Space space = Heap::kNew; \
|
||||
__ movq(R13, Address(THR, Thread::heap_offset())); \
|
||||
@@ -1742,9 +1743,11 @@ void Intrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler) {
|
||||
void Intrinsifier::String_getHashCode(Assembler* assembler) {
|
||||
Label fall_through;
|
||||
__ movq(RAX, Address(RSP, +1 * kWordSize)); // String object.
|
||||
__ movq(RAX, FieldAddress(RAX, String::hash_offset()));
|
||||
__ cmpq(RAX, Immediate(0));
|
||||
__ j(EQUAL, &fall_through, Assembler::kNearJump);
|
||||
__ movl(RAX, FieldAddress(RAX, String::hash_offset()));
|
||||
ASSERT(kSmiTag == 0);
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ addq(RAX, RAX); // Smi tag RAX, setting Z flag.
|
||||
__ j(ZERO, &fall_through, Assembler::kNearJump);
|
||||
__ ret();
|
||||
__ Bind(&fall_through);
|
||||
// Hash not yet computed.
|
||||
@@ -1911,9 +1914,10 @@ void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) {
|
||||
void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) {
|
||||
Label compute_hash;
|
||||
__ movq(RBX, Address(RSP, +1 * kWordSize)); // OneByteString object.
|
||||
__ movq(RAX, FieldAddress(RBX, String::hash_offset()));
|
||||
__ movl(RAX, FieldAddress(RBX, String::hash_offset()));
|
||||
__ cmpq(RAX, Immediate(0));
|
||||
__ j(EQUAL, &compute_hash, Assembler::kNearJump);
|
||||
__ SmiTag(RAX);
|
||||
__ ret();
|
||||
|
||||
__ Bind(&compute_hash);
|
||||
@@ -1971,8 +1975,8 @@ void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) {
|
||||
__ j(NOT_EQUAL, &set_hash_code, Assembler::kNearJump);
|
||||
__ incq(RAX);
|
||||
__ Bind(&set_hash_code);
|
||||
__ movl(FieldAddress(RBX, String::hash_offset()), RAX);
|
||||
__ SmiTag(RAX);
|
||||
__ StoreIntoSmiField(FieldAddress(RBX, String::hash_offset()), RAX);
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -1988,11 +1992,19 @@ static void TryAllocateOnebyteString(Assembler* assembler,
|
||||
if (length_reg != RDI) {
|
||||
__ movq(RDI, length_reg);
|
||||
}
|
||||
Label pop_and_fail;
|
||||
Label pop_and_fail, not_zero_length;
|
||||
__ pushq(RDI); // Preserve length.
|
||||
__ SmiUntag(RDI);
|
||||
const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1;
|
||||
__ leaq(RDI, Address(RDI, TIMES_1, fixed_size)); // RDI is a Smi.
|
||||
__ sarq(RDI, Immediate(kSmiTagShift)); // Untag length.
|
||||
// If the length is 0 then we have to make the allocated size a bit bigger,
|
||||
// otherwise the string takes up less space than an ExternalOneByteString,
|
||||
// and cannot be externalized. TODO(erikcorry): We should probably just
|
||||
// return a static zero length string here instead.
|
||||
__ j(NOT_ZERO, ¬_zero_length);
|
||||
__ addq(RDI, Immediate(1));
|
||||
__ Bind(¬_zero_length);
|
||||
const intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawString) + kObjectAlignment - 1;
|
||||
__ addq(RDI, Immediate(fixed_size_plus_alignment_padding));
|
||||
__ andq(RDI, Immediate(-kObjectAlignment));
|
||||
|
||||
const intptr_t cid = kOneByteStringCid;
|
||||
@@ -2034,6 +2046,7 @@ static void TryAllocateOnebyteString(Assembler* assembler,
|
||||
__ Bind(&done);
|
||||
|
||||
// Get the class index and insert it into the tags.
|
||||
// This also clears the hash, which is in the high bits of the tags.
|
||||
__ orq(RDI, Immediate(RawObject::ClassIdTag::encode(cid)));
|
||||
__ movq(FieldAddress(RAX, String::tags_offset()), RDI); // Tags.
|
||||
}
|
||||
@@ -2042,8 +2055,6 @@ static void TryAllocateOnebyteString(Assembler* assembler,
|
||||
__ popq(RDI);
|
||||
__ StoreIntoObjectNoBarrier(RAX, FieldAddress(RAX, String::length_offset()),
|
||||
RDI);
|
||||
// Clear hash.
|
||||
__ ZeroInitSmiField(FieldAddress(RAX, String::hash_offset()));
|
||||
__ jmp(ok, Assembler::kNearJump);
|
||||
|
||||
__ Bind(&pop_and_fail);
|
||||
|
||||
@@ -21337,7 +21337,9 @@ RawOneByteString* OneByteString::New(intptr_t len, Heap::Space space) {
|
||||
NoSafepointScope no_safepoint;
|
||||
RawOneByteString* result = reinterpret_cast<RawOneByteString*>(raw);
|
||||
result->StoreSmi(&(result->ptr()->length_), Smi::New(len));
|
||||
#if !defined(HASH_IN_OBJECT_HEADER)
|
||||
result->StoreSmi(&(result->ptr()->hash_), Smi::New(0));
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+47
-12
@@ -432,6 +432,18 @@ class Object {
|
||||
return *transition_sentinel_;
|
||||
}
|
||||
|
||||
#if defined(HASH_IN_OBJECT_HEADER)
|
||||
static uint32_t GetCachedHash(const RawObject* obj) {
|
||||
uword tags = obj->ptr()->tags_;
|
||||
return tags >> 32;
|
||||
}
|
||||
|
||||
static void SetCachedHash(RawObject* obj, uintptr_t hash) {
|
||||
ASSERT(hash >> 32 == 0);
|
||||
obj->ptr()->tags_ |= hash << 32;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Compiler's constant propagation constants.
|
||||
static const Instance& unknown_constant() {
|
||||
ASSERT(unknown_constant_ != NULL);
|
||||
@@ -6752,8 +6764,11 @@ class String : public Instance {
|
||||
// All strings share the same maximum element count to keep things
|
||||
// simple. We choose a value that will prevent integer overflow for
|
||||
// 2 byte strings, since it is the worst case.
|
||||
static const intptr_t kSizeofRawString =
|
||||
sizeof(RawInstance) + (2 * kWordSize);
|
||||
#if defined(HASH_IN_OBJECT_HEADER)
|
||||
static const intptr_t kSizeofRawString = sizeof(RawInstance) + kWordSize;
|
||||
#else
|
||||
static const intptr_t kSizeofRawString = sizeof(RawInstance) + 2 * kWordSize;
|
||||
#endif
|
||||
static const intptr_t kMaxElements = kSmiMax / kTwoByteChar;
|
||||
|
||||
class CodePointIterator : public ValueObject {
|
||||
@@ -6789,28 +6804,32 @@ class String : public Instance {
|
||||
static intptr_t length_offset() { return OFFSET_OF(RawString, length_); }
|
||||
|
||||
intptr_t Hash() const {
|
||||
intptr_t result = Smi::Value(raw_ptr()->hash_);
|
||||
intptr_t result = GetCachedHash(raw());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = String::Hash(*this, 0, this->Length());
|
||||
this->SetHash(result);
|
||||
SetCachedHash(raw(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool HasHash() const {
|
||||
ASSERT(Smi::New(0) == NULL);
|
||||
return (raw_ptr()->hash_ != NULL);
|
||||
return GetCachedHash(raw()) != 0;
|
||||
}
|
||||
|
||||
#if defined(HASH_IN_OBJECT_HEADER)
|
||||
static intptr_t hash_offset() { return kInt32Size; } // Wrong for big-endian?
|
||||
#else
|
||||
static intptr_t hash_offset() { return OFFSET_OF(RawString, hash_); }
|
||||
#endif
|
||||
static intptr_t Hash(const String& str, intptr_t begin_index, intptr_t len);
|
||||
static intptr_t Hash(const char* characters, intptr_t len);
|
||||
static intptr_t Hash(const uint16_t* characters, intptr_t len);
|
||||
static intptr_t Hash(const int32_t* characters, intptr_t len);
|
||||
static intptr_t HashRawSymbol(const RawString* symbol) {
|
||||
ASSERT(symbol->IsCanonical());
|
||||
intptr_t result = Smi::Value(symbol->ptr()->hash_);
|
||||
intptr_t result = GetCachedHash(symbol);
|
||||
ASSERT(result != 0);
|
||||
return result;
|
||||
}
|
||||
@@ -7029,6 +7048,16 @@ class String : public Instance {
|
||||
intptr_t end,
|
||||
double* result);
|
||||
|
||||
#if !defined(HASH_IN_OBJECT_HEADER)
|
||||
static uint32_t GetCachedHash(const RawString* obj) {
|
||||
return Smi::Value(obj->ptr()->hash_);
|
||||
}
|
||||
|
||||
static void SetCachedHash(RawString* obj, uintptr_t hash) {
|
||||
obj->ptr()->hash_ = Smi::New(hash);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// These two operate on an array of Latin-1 encoded characters.
|
||||
// They are protected to avoid mistaking Latin-1 for UTF-8, but used
|
||||
@@ -7042,11 +7071,7 @@ class String : public Instance {
|
||||
StoreSmi(&raw_ptr()->length_, Smi::New(value));
|
||||
}
|
||||
|
||||
void SetHash(intptr_t value) const {
|
||||
// This is only safe because we create a new Smi, which does not cause
|
||||
// heap allocation.
|
||||
StoreSmi(&raw_ptr()->hash_, Smi::New(value));
|
||||
}
|
||||
void SetHash(intptr_t value) const { SetCachedHash(raw(), value); }
|
||||
|
||||
template <typename HandleType, typename ElementType, typename CallbackType>
|
||||
static void ReadFromImpl(SnapshotReader* reader,
|
||||
@@ -7105,6 +7130,12 @@ class OneByteString : public AllStatic {
|
||||
static intptr_t InstanceSize(intptr_t len) {
|
||||
ASSERT(sizeof(RawOneByteString) == String::kSizeofRawString);
|
||||
ASSERT(0 <= len && len <= kMaxElements);
|
||||
#if defined(HASH_IN_OBJECT_HEADER)
|
||||
// We have to pad zero-length raw strings so that they can be externalized.
|
||||
// If we don't pad, then the external string object does not fit in the
|
||||
// memory allocated for the raw string.
|
||||
if (len == 0) return InstanceSize(1);
|
||||
#endif
|
||||
return String::RoundedAllocationSize(sizeof(RawOneByteString) +
|
||||
(len * kBytesPerElement));
|
||||
}
|
||||
@@ -7238,6 +7269,10 @@ class TwoByteString : public AllStatic {
|
||||
static intptr_t InstanceSize(intptr_t len) {
|
||||
ASSERT(sizeof(RawTwoByteString) == String::kSizeofRawString);
|
||||
ASSERT(0 <= len && len <= kMaxElements);
|
||||
// We have to pad zero-length raw strings so that they can be externalized.
|
||||
// If we don't pad, then the external string object does not fit in the
|
||||
// memory allocated for the raw string.
|
||||
if (len == 0) return InstanceSize(1);
|
||||
return String::RoundedAllocationSize(sizeof(RawTwoByteString) +
|
||||
(len * kBytesPerElement));
|
||||
}
|
||||
@@ -8931,7 +8966,7 @@ bool String::Equals(const String& str) const {
|
||||
|
||||
|
||||
intptr_t Library::UrlHash() const {
|
||||
intptr_t result = Smi::Value(url()->ptr()->hash_);
|
||||
intptr_t result = String::GetCachedHash(url());
|
||||
ASSERT(result != 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -821,7 +821,9 @@ intptr_t RawOneByteString::VisitOneByteStringPointers(
|
||||
RawOneByteString* raw_obj,
|
||||
ObjectPointerVisitor* visitor) {
|
||||
ASSERT(!raw_obj->ptr()->length_->IsHeapObject());
|
||||
#if !defined(HASH_IN_OBJECT_HEADER)
|
||||
ASSERT(!raw_obj->ptr()->hash_->IsHeapObject());
|
||||
#endif
|
||||
intptr_t length = Smi::Value(raw_obj->ptr()->length_);
|
||||
return OneByteString::InstanceSize(length);
|
||||
}
|
||||
@@ -831,7 +833,9 @@ intptr_t RawTwoByteString::VisitTwoByteStringPointers(
|
||||
RawTwoByteString* raw_obj,
|
||||
ObjectPointerVisitor* visitor) {
|
||||
ASSERT(!raw_obj->ptr()->length_->IsHeapObject());
|
||||
#if !defined(HASH_IN_OBJECT_HEADER)
|
||||
ASSERT(!raw_obj->ptr()->hash_->IsHeapObject());
|
||||
#endif
|
||||
intptr_t length = Smi::Value(raw_obj->ptr()->length_);
|
||||
return TwoByteString::InstanceSize(length);
|
||||
}
|
||||
|
||||
+12
-10
@@ -266,21 +266,11 @@ class RawObject {
|
||||
kVMHeapObjectBit = 2,
|
||||
kRememberedBit = 3,
|
||||
kReservedTagPos = 4, // kReservedBit{100K,1M,10M}
|
||||
#if defined(ARCH_IS_32_BIT)
|
||||
kReservedTagSize = 4,
|
||||
kSizeTagPos = kReservedTagPos + kReservedTagSize, // = 8
|
||||
kSizeTagSize = 8,
|
||||
kClassIdTagPos = kSizeTagPos + kSizeTagSize, // = 16
|
||||
kClassIdTagSize = 16,
|
||||
#elif defined(ARCH_IS_64_BIT)
|
||||
kReservedTagSize = 12,
|
||||
kSizeTagPos = kReservedTagPos + kReservedTagSize, // = 16
|
||||
kSizeTagSize = 16,
|
||||
kClassIdTagPos = kSizeTagPos + kSizeTagSize, // = 32
|
||||
kClassIdTagSize = 32,
|
||||
#else
|
||||
#error Unexpected architecture word size
|
||||
#endif
|
||||
};
|
||||
|
||||
COMPILE_ASSERT(kClassIdTagSize == (sizeof(classid_t) * kBitsPerByte));
|
||||
@@ -614,6 +604,7 @@ class RawObject {
|
||||
friend class RawExternalTypedData;
|
||||
friend class RawInstructions;
|
||||
friend class RawInstance;
|
||||
friend class RawString;
|
||||
friend class RawTypedData;
|
||||
friend class Scavenger;
|
||||
friend class ScavengerVisitor;
|
||||
@@ -1863,10 +1854,20 @@ class RawString : public RawInstance {
|
||||
protected:
|
||||
RawObject** from() { return reinterpret_cast<RawObject**>(&ptr()->length_); }
|
||||
RawSmi* length_;
|
||||
#if !defined(HASH_IN_OBJECT_HEADER)
|
||||
RawSmi* hash_;
|
||||
RawObject** to() { return reinterpret_cast<RawObject**>(&ptr()->hash_); }
|
||||
#else
|
||||
RawObject** to() { return reinterpret_cast<RawObject**>(&ptr()->length_); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class Library;
|
||||
friend class OneByteStringSerializationCluster;
|
||||
friend class TwoByteStringSerializationCluster;
|
||||
friend class OneByteStringDeserializationCluster;
|
||||
friend class TwoByteStringDeserializationCluster;
|
||||
friend class RODataSerializationCluster;
|
||||
};
|
||||
|
||||
|
||||
@@ -2453,6 +2454,7 @@ inline intptr_t RawObject::NumberOfTypedDataClasses() {
|
||||
return (kNullCid - kTypedDataInt8ArrayCid);
|
||||
}
|
||||
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_RAW_OBJECT_H_
|
||||
|
||||
@@ -2957,9 +2957,11 @@ RawObject* Simulator::Call(const Code& code,
|
||||
BYTECODE(CreateArrayOpt, A_B_C);
|
||||
const intptr_t length = Smi::Value(RAW_CAST(Smi, FP[rB]));
|
||||
if (LIKELY(static_cast<uintptr_t>(length) <= Array::kMaxElements)) {
|
||||
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
|
||||
const intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawArray) + kObjectAlignment - 1;
|
||||
const intptr_t instance_size =
|
||||
(fixed_size + length * kWordSize) & ~(kObjectAlignment - 1);
|
||||
(fixed_size_plus_alignment_padding + length * kWordSize) &
|
||||
~(kObjectAlignment - 1);
|
||||
const uword start =
|
||||
thread->heap()->new_space()->TryAllocate(instance_size);
|
||||
if (LIKELY(start != 0)) {
|
||||
|
||||
@@ -688,9 +688,10 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
|
||||
const intptr_t cid = kArrayCid;
|
||||
NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, R4, &slow_case));
|
||||
|
||||
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
|
||||
__ LoadImmediate(R9, fixed_size);
|
||||
__ add(R9, R9, Operand(R3, LSL, 1)); // R3 is a Smi.
|
||||
const intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawArray) + kObjectAlignment - 1;
|
||||
__ LoadImmediate(R9, fixed_size_plus_alignment_padding);
|
||||
__ add(R9, R9, Operand(R3, LSL, 1)); // R3 is a Smi.
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ bic(R9, R9, Operand(kObjectAlignment - 1));
|
||||
|
||||
@@ -909,8 +910,9 @@ void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
|
||||
Label slow_case;
|
||||
// First compute the rounded instance size.
|
||||
// R1: number of context variables.
|
||||
intptr_t fixed_size = sizeof(RawContext) + kObjectAlignment - 1;
|
||||
__ LoadImmediate(R2, fixed_size);
|
||||
intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawContext) + kObjectAlignment - 1;
|
||||
__ LoadImmediate(R2, fixed_size_plus_alignment_padding);
|
||||
__ add(R2, R2, Operand(R1, LSL, 2));
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ bic(R2, R2, Operand(kObjectAlignment - 1));
|
||||
|
||||
@@ -723,8 +723,9 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
|
||||
// R2: array length as Smi.
|
||||
// R8: heap.
|
||||
__ LoadFromOffset(R0, R8, Heap::TopOffset(space));
|
||||
intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
|
||||
__ LoadImmediate(R3, fixed_size);
|
||||
intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawArray) + kObjectAlignment - 1;
|
||||
__ LoadImmediate(R3, fixed_size_plus_alignment_padding);
|
||||
__ add(R3, R3, Operand(R2, LSL, 2)); // R2 is Smi.
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ andi(R3, R3, Immediate(~(kObjectAlignment - 1)));
|
||||
@@ -969,8 +970,9 @@ void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
|
||||
Label slow_case;
|
||||
// First compute the rounded instance size.
|
||||
// R1: number of context variables.
|
||||
intptr_t fixed_size = sizeof(RawContext) + kObjectAlignment - 1;
|
||||
__ LoadImmediate(R2, fixed_size);
|
||||
intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawContext) + kObjectAlignment - 1;
|
||||
__ LoadImmediate(R2, fixed_size_plus_alignment_padding);
|
||||
__ add(R2, R2, Operand(R1, LSL, 3));
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ andi(R2, R2, Immediate(~(kObjectAlignment - 1)));
|
||||
@@ -2302,9 +2304,9 @@ void StubCode::GenerateSingleTargetCallStub(Assembler* assembler) {
|
||||
Label miss;
|
||||
__ LoadClassIdMayBeSmi(R1, R0);
|
||||
__ ldr(R2, FieldAddress(R5, SingleTargetCache::lower_limit_offset()),
|
||||
kUnsignedWord);
|
||||
kUnsignedHalfword);
|
||||
__ ldr(R3, FieldAddress(R5, SingleTargetCache::upper_limit_offset()),
|
||||
kUnsignedWord);
|
||||
kUnsignedHalfword);
|
||||
|
||||
__ cmp(R1, Operand(R2));
|
||||
__ b(&miss, LT);
|
||||
|
||||
@@ -599,8 +599,10 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
|
||||
NOT_IN_PRODUCT(
|
||||
__ MaybeTraceAllocation(kArrayCid, EAX, &slow_case, Assembler::kFarJump));
|
||||
|
||||
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
|
||||
__ leal(EBX, Address(EDX, TIMES_2, fixed_size)); // EDX is Smi.
|
||||
const intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawArray) + kObjectAlignment - 1;
|
||||
// EDX is Smi.
|
||||
__ leal(EBX, Address(EDX, TIMES_2, fixed_size_plus_alignment_padding));
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ andl(EBX, Immediate(-kObjectAlignment));
|
||||
|
||||
@@ -824,8 +826,9 @@ void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
|
||||
Label slow_case;
|
||||
// First compute the rounded instance size.
|
||||
// EDX: number of context variables.
|
||||
intptr_t fixed_size = (sizeof(RawContext) + kObjectAlignment - 1);
|
||||
__ leal(EBX, Address(EDX, TIMES_4, fixed_size));
|
||||
intptr_t fixed_size_plus_alignment_padding =
|
||||
(sizeof(RawContext) + kObjectAlignment - 1);
|
||||
__ leal(EBX, Address(EDX, TIMES_4, fixed_size_plus_alignment_padding));
|
||||
__ andl(EBX, Immediate(-kObjectAlignment));
|
||||
|
||||
NOT_IN_PRODUCT(__ MaybeTraceAllocation(kContextCid, EAX, &slow_case,
|
||||
@@ -871,7 +874,7 @@ void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
|
||||
// EDX: number of context variables.
|
||||
{
|
||||
Label size_tag_overflow, done;
|
||||
__ leal(EBX, Address(EDX, TIMES_4, fixed_size));
|
||||
__ leal(EBX, Address(EDX, TIMES_4, fixed_size_plus_alignment_padding));
|
||||
__ andl(EBX, Immediate(-kObjectAlignment));
|
||||
__ cmpl(EBX, Immediate(RawObject::SizeTag::kMaxSizeTag));
|
||||
__ j(ABOVE, &size_tag_overflow, Assembler::kNearJump);
|
||||
|
||||
@@ -711,8 +711,9 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
|
||||
const intptr_t cid = kArrayCid;
|
||||
NOT_IN_PRODUCT(__ MaybeTraceAllocation(kArrayCid, T4, &slow_case));
|
||||
|
||||
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
|
||||
__ LoadImmediate(T2, fixed_size);
|
||||
const intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawArray) + kObjectAlignment - 1;
|
||||
__ LoadImmediate(T2, fixed_size_plus_alignment_padding);
|
||||
__ sll(T3, T3, 1); // T3 is a Smi.
|
||||
__ addu(T2, T2, T3);
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
@@ -973,8 +974,9 @@ void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
|
||||
Label slow_case;
|
||||
// First compute the rounded instance size.
|
||||
// T1: number of context variables.
|
||||
intptr_t fixed_size = sizeof(RawContext) + kObjectAlignment - 1;
|
||||
__ LoadImmediate(T2, fixed_size);
|
||||
intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawContext) + kObjectAlignment - 1;
|
||||
__ LoadImmediate(T2, fixed_size_plus_alignment_padding);
|
||||
__ sll(T0, T1, 2);
|
||||
__ addu(T2, T2, T0);
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
|
||||
@@ -646,8 +646,10 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
|
||||
NOT_IN_PRODUCT(
|
||||
__ MaybeTraceAllocation(kArrayCid, &slow_case, Assembler::kFarJump));
|
||||
|
||||
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
|
||||
__ leaq(RDI, Address(RDI, TIMES_4, fixed_size)); // RDI is a Smi.
|
||||
const intptr_t fixed_size_plus_alignment_padding =
|
||||
sizeof(RawArray) + kObjectAlignment - 1;
|
||||
// RDI is a Smi.
|
||||
__ leaq(RDI, Address(RDI, TIMES_4, fixed_size_plus_alignment_padding));
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ andq(RDI, Immediate(-kObjectAlignment));
|
||||
|
||||
@@ -888,8 +890,9 @@ void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
|
||||
Label slow_case;
|
||||
// First compute the rounded instance size.
|
||||
// R10: number of context variables.
|
||||
intptr_t fixed_size = (sizeof(RawContext) + kObjectAlignment - 1);
|
||||
__ leaq(R13, Address(R10, TIMES_8, fixed_size));
|
||||
intptr_t fixed_size_plus_alignment_padding =
|
||||
(sizeof(RawContext) + kObjectAlignment - 1);
|
||||
__ leaq(R13, Address(R10, TIMES_8, fixed_size_plus_alignment_padding));
|
||||
__ andq(R13, Immediate(-kObjectAlignment));
|
||||
|
||||
// Check for allocation tracing.
|
||||
@@ -933,7 +936,7 @@ void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
|
||||
// R10: number of context variables.
|
||||
{
|
||||
Label size_tag_overflow, done;
|
||||
__ leaq(R13, Address(R10, TIMES_8, fixed_size));
|
||||
__ leaq(R13, Address(R10, TIMES_8, fixed_size_plus_alignment_padding));
|
||||
__ andq(R13, Immediate(-kObjectAlignment));
|
||||
__ cmpq(R13, Immediate(RawObject::SizeTag::kMaxSizeTag));
|
||||
__ j(ABOVE, &size_tag_overflow, Assembler::kNearJump);
|
||||
@@ -2242,8 +2245,8 @@ void StubCode::GenerateUnlinkedCallStub(Assembler* assembler) {
|
||||
void StubCode::GenerateSingleTargetCallStub(Assembler* assembler) {
|
||||
Label miss;
|
||||
__ LoadClassIdMayBeSmi(RAX, RDI);
|
||||
__ movl(R9, FieldAddress(RBX, SingleTargetCache::lower_limit_offset()));
|
||||
__ movl(R10, FieldAddress(RBX, SingleTargetCache::upper_limit_offset()));
|
||||
__ movzxw(R9, FieldAddress(RBX, SingleTargetCache::lower_limit_offset()));
|
||||
__ movzxw(R10, FieldAddress(RBX, SingleTargetCache::upper_limit_offset()));
|
||||
__ cmpq(RAX, R9);
|
||||
__ j(LESS, &miss, Assembler::kNearJump);
|
||||
__ cmpq(RAX, R10);
|
||||
|
||||
Reference in New Issue
Block a user