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:
Erik Corry
2017-05-18 11:54:36 +02:00
parent 3ba3cc1e0d
commit 5c8e472c82
23 changed files with 245 additions and 167 deletions
-6
View File
@@ -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);
+3 -3
View File
@@ -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);
}
+8 -8
View File
@@ -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));
}
+10 -10
View File
@@ -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
View File
@@ -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
+4
View File
@@ -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.
//
+25 -25
View File
@@ -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);
+24 -25
View File
@@ -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.
+6 -4
View File
@@ -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;
+19 -13
View File
@@ -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);
+7 -4
View File
@@ -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;
+6 -4
View File
@@ -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);
+24 -13
View File
@@ -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, &not_zero_length);
__ addq(RDI, Immediate(1));
__ Bind(&not_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);
+2
View File
@@ -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
View File
@@ -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;
}
+4
View File
@@ -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
View File
@@ -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_
+4 -2
View File
@@ -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)) {
+7 -5
View File
@@ -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));
+8 -6
View File
@@ -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);
+8 -5
View File
@@ -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);
+6 -4
View File
@@ -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);
+10 -7
View File
@@ -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);