// Now that we have the types we might as well check for
// internalized-internalized.
- // Ensure that no non-strings have the internalized bit set.
- STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsInternalizedMask);
+ Label not_internalized;
STATIC_ASSERT(kInternalizedTag != 0);
- __ and_(r2, r2, Operand(r3));
- __ tst(r2, Operand(kIsInternalizedMask));
- __ b(ne, &return_not_equal);
+ __ and_(r2, r2, Operand(kIsNotStringMask | kIsInternalizedMask));
+ __ cmp(r2, Operand(kInternalizedTag | kStringTag));
+ __ b(ne, ¬_internalized); // r2 (rhs) is not an internalized string
+
+ __ and_(r3, r3, Operand(kIsNotStringMask | kIsInternalizedMask));
+ __ cmp(r3, Operand(kInternalizedTag | kStringTag));
+ __ b(eq, &return_not_equal); // both rhs and lhs are internalized strings
+
+ __ bind(¬_internalized);
}
(lhs.is(r1) && rhs.is(r0)));
// r2 is object type of rhs.
- // Ensure that no non-strings have the internalized bit set.
Label object_test;
STATIC_ASSERT(kInternalizedTag != 0);
__ tst(r2, Operand(kIsNotStringMask));
__ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
__ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
STATIC_ASSERT(kInternalizedTag != 0);
- __ and_(tmp1, tmp1, Operand(tmp2));
- __ tst(tmp1, Operand(kIsInternalizedMask));
- __ b(eq, &miss);
+
+ __ and_(tmp1, tmp1, Operand(kIsNotStringMask | kIsInternalizedMask));
+ __ cmp(tmp1, Operand(kInternalizedTag | kStringTag));
+ __ b(ne, &miss);
+
+ __ and_(tmp2, tmp2, Operand(kIsNotStringMask | kIsInternalizedMask));
+ __ cmp(tmp2, Operand(kInternalizedTag | kStringTag));
+ __ b(ne, &miss);
// Internalized strings are compared by identity.
__ cmp(left, right);
__ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
__ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
- Label succeed1;
- __ tst(tmp1, Operand(kIsInternalizedMask));
- __ b(ne, &succeed1);
- __ cmp(tmp1, Operand(SYMBOL_TYPE));
- __ b(ne, &miss);
- __ bind(&succeed1);
-
- Label succeed2;
- __ tst(tmp2, Operand(kIsInternalizedMask));
- __ b(ne, &succeed2);
- __ cmp(tmp2, Operand(SYMBOL_TYPE));
- __ b(ne, &miss);
- __ bind(&succeed2);
+ __ JumpIfNotUniqueName(tmp1, &miss);
+ __ JumpIfNotUniqueName(tmp2, &miss);
// Unique names are compared by identity.
__ cmp(left, right);
// Handle not identical strings.
// Check that both strings are internalized strings. If they are, we're done
- // because we already know they are not identical.
+ // because we already know they are not identical. We know they are both
+ // strings.
if (equality) {
ASSERT(GetCondition() == eq);
STATIC_ASSERT(kInternalizedTag != 0);
__ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
__ ldrb(entity_name,
FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
- __ tst(entity_name, Operand(kIsInternalizedMask));
- __ b(ne, &good);
- __ cmp(entity_name, Operand(SYMBOL_TYPE));
- __ b(ne, miss);
-
+ __ JumpIfNotUniqueName(entity_name, miss);
__ bind(&good);
// Restore the properties.
if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
// Check if the entry name is not a unique name.
- Label cont;
__ ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
__ ldrb(entry_key,
FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
- __ tst(entry_key, Operand(kIsInternalizedMask));
- __ b(ne, &cont);
- __ cmp(entry_key, Operand(SYMBOL_TYPE));
- __ b(ne, &maybe_in_dictionary);
- __ bind(&cont);
+ __ JumpIfNotUniqueName(entry_key, &maybe_in_dictionary);
}
}
__ tst(hash, Operand(Name::kContainsCachedArrayIndexMask));
__ b(eq, index_string);
- // Is the string internalized?
+ // Is the string internalized? We know it's a string, so a single
+ // bit test is enough.
// map: key map
__ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
STATIC_ASSERT(kInternalizedTag != 0);
}
+void MacroAssembler::JumpIfNotUniqueName(Register reg,
+ Label* not_unique_name) {
+ STATIC_ASSERT(((SYMBOL_TYPE - 1) & kIsInternalizedMask) == kInternalizedTag);
+ cmp(reg, Operand(kInternalizedTag));
+ b(lt, not_unique_name);
+ cmp(reg, Operand(SYMBOL_TYPE));
+ b(gt, not_unique_name);
+}
+
+
// Allocates a heap number or jumps to the need_gc label if the young space
// is full and a scavenge is needed.
void MacroAssembler::AllocateHeapNumber(Register result,
Register scratch,
Label* failure);
+ void JumpIfNotUniqueName(Register reg, Label* not_unique_name);
// ---------------------------------------------------------------------------
// Patching helpers.
__ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
__ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
STATIC_ASSERT(kInternalizedTag != 0);
- __ and_(tmp1, tmp2);
- __ test(tmp1, Immediate(kIsInternalizedMask));
- __ j(zero, &miss, Label::kNear);
+ __ and_(tmp1, Immediate(kIsNotStringMask | kIsInternalizedMask));
+ __ cmpb(tmp1, kInternalizedTag | kStringTag);
+ __ j(not_equal, &miss, Label::kNear);
+
+ __ and_(tmp2, Immediate(kIsNotStringMask | kIsInternalizedMask));
+ __ cmpb(tmp2, kInternalizedTag | kStringTag);
+ __ j(not_equal, &miss, Label::kNear);
// Internalized strings are compared by identity.
Label done;
__ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
__ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
- Label succeed1;
- __ test(tmp1, Immediate(kIsInternalizedMask));
- __ j(not_zero, &succeed1);
- __ cmpb(tmp1, static_cast<uint8_t>(SYMBOL_TYPE));
- __ j(not_equal, &miss);
- __ bind(&succeed1);
-
- Label succeed2;
- __ test(tmp2, Immediate(kIsInternalizedMask));
- __ j(not_zero, &succeed2);
- __ cmpb(tmp2, static_cast<uint8_t>(SYMBOL_TYPE));
- __ j(not_equal, &miss);
- __ bind(&succeed2);
+ __ JumpIfNotUniqueName(tmp1, &miss, Label::kNear);
+ __ JumpIfNotUniqueName(tmp2, &miss, Label::kNear);
// Unique names are compared by identity.
Label done;
// Check that both strings are internalized. If they are, we're done
// because we already know they are not identical. But in the case of
- // non-equality compare, we still need to determine the order.
+ // non-equality compare, we still need to determine the order. We
+ // also know they are both strings.
if (equality) {
Label do_compare;
STATIC_ASSERT(kInternalizedTag != 0);
// Check if the entry name is not a unique name.
__ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
- __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
- kIsInternalizedMask);
- __ j(not_zero, &good);
- __ cmpb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
- static_cast<uint8_t>(SYMBOL_TYPE));
- __ j(not_equal, miss);
+ __ JumpIfNotUniqueName(FieldOperand(entity_name, Map::kInstanceTypeOffset),
+ miss);
__ bind(&good);
}
// key we are looking for.
// Check if the entry name is not a unique name.
- Label cont;
__ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
- __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset),
- kIsInternalizedMask);
- __ j(not_zero, &cont);
- __ cmpb(FieldOperand(scratch, Map::kInstanceTypeOffset),
- static_cast<uint8_t>(SYMBOL_TYPE));
- __ j(not_equal, &maybe_in_dictionary);
- __ bind(&cont);
+ __ JumpIfNotUniqueName(FieldOperand(scratch, Map::kInstanceTypeOffset),
+ &maybe_in_dictionary);
}
}
__ test(hash, Immediate(Name::kContainsCachedArrayIndexMask));
__ j(zero, index_string);
- // Is the string internalized?
+ // Is the string internalized? We already know it's a string so a single
+ // bit test is enough.
STATIC_ASSERT(kInternalizedTag != 0);
__ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsInternalizedMask);
__ j(zero, not_unique);
}
+void MacroAssembler::JumpIfNotUniqueName(Operand operand,
+ Label* not_unique_name,
+ Label::Distance distance) {
+ STATIC_ASSERT(((SYMBOL_TYPE - 1) & kIsInternalizedMask) == kInternalizedTag);
+ cmp(operand, Immediate(kInternalizedTag));
+ j(less, not_unique_name, distance);
+ cmp(operand, Immediate(SYMBOL_TYPE));
+ j(greater, not_unique_name, distance);
+}
+
+
void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
int frame_alignment = OS::ActivationFrameAlignment();
if (frame_alignment != 0) {
Register scratch2,
Label* on_not_flat_ascii_strings);
+ // Checks if the given register or operand is a unique name
+ void JumpIfNotUniqueName(Register reg, Label* not_unique_name,
+ Label::Distance distance = Label::kFar) {
+ JumpIfNotUniqueName(Operand(reg), not_unique_name, distance);
+ }
+
+ void JumpIfNotUniqueName(Operand operand, Label* not_unique_name,
+ Label::Distance distance = Label::kFar);
+
static int SafepointRegisterStackIndex(Register reg) {
return SafepointRegisterStackIndex(reg.code());
}
bool Object::IsInternalizedString() {
if (!this->IsHeapObject()) return false;
uint32_t type = HeapObject::cast(this)->map()->instance_type();
- // Because the internalized tag is non-zero and no non-string types have the
- // internalized bit set we can test for internalized strings with a very
- // simple test operation.
STATIC_ASSERT(kInternalizedTag != 0);
- ASSERT(kNotStringTag + kIsInternalizedMask > LAST_TYPE);
- return (type & kIsInternalizedMask) != 0;
+ return (type & (kIsNotStringMask | kIsInternalizedMask)) ==
+ (kInternalizedTag | kStringTag);
}
bool StringShape::IsInternalized() {
ASSERT(valid());
STATIC_ASSERT(kInternalizedTag != 0);
- return (type_ & kIsInternalizedMask) != 0;
+ return (type_ & (kIsNotStringMask | kIsInternalizedMask)) ==
+ (kInternalizedTag | kStringTag);
}
int HeapObject::SizeFromMap(Map* map) {
int instance_size = map->instance_size();
if (instance_size != kVariableSizeSentinel) return instance_size;
- // We can ignore the "internalized" bit because it is only set for strings
- // and thus implies a string type.
- int instance_type =
- static_cast<int>(map->instance_type()) & ~kIsInternalizedMask;
// Only inline the most frequent cases.
+ int instance_type = static_cast<int>(map->instance_type());
if (instance_type == FIXED_ARRAY_TYPE) {
return FixedArray::BodyDescriptor::SizeOf(map, this);
}
- if (instance_type == ASCII_STRING_TYPE) {
+ if (instance_type == ASCII_STRING_TYPE ||
+ instance_type == ASCII_INTERNALIZED_STRING_TYPE) {
return SeqOneByteString::SizeFor(
reinterpret_cast<SeqOneByteString*>(this)->length());
}
if (instance_type == FREE_SPACE_TYPE) {
return reinterpret_cast<FreeSpace*>(this)->size();
}
- if (instance_type == STRING_TYPE) {
+ if (instance_type == STRING_TYPE ||
+ instance_type == INTERNALIZED_STRING_TYPE) {
return SeqTwoByteString::SizeFor(
reinterpret_cast<SeqTwoByteString*>(this)->length());
}
const uint32_t kNotStringTag = 0x80;
// Bit 6 indicates that the object is an internalized string (if set) or not.
-// There are not enough types that the non-string types (with bit 7 set) can
-// have bit 6 set too.
+// Bit 7 has to be clear as well.
const uint32_t kIsInternalizedMask = 0x40;
const uint32_t kNotInternalizedTag = 0x0;
const uint32_t kInternalizedTag = 0x40;
__ movq(scratch, FieldOperand(object, HeapObject::kMapOffset));
__ movzxbq(scratch,
FieldOperand(scratch, Map::kInstanceTypeOffset));
- // Ensure that no non-strings have the internalized bit set.
- STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsInternalizedMask);
STATIC_ASSERT(kInternalizedTag != 0);
- __ testb(scratch, Immediate(kIsInternalizedMask));
- __ j(zero, label);
+ __ and_(scratch, Immediate(kIsNotStringMask | kIsInternalizedMask));
+ __ cmpb(scratch, Immediate(kInternalizedTag | kStringTag));
+ __ j(not_equal, label);
}
__ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
__ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
STATIC_ASSERT(kInternalizedTag != 0);
- __ and_(tmp1, tmp2);
- __ testb(tmp1, Immediate(kIsInternalizedMask));
- __ j(zero, &miss, Label::kNear);
+ __ and_(tmp1, Immediate(kIsNotStringMask | kIsInternalizedMask));
+ __ cmpb(tmp1, Immediate(kInternalizedTag | kStringTag));
+ __ j(not_equal, &miss, Label::kNear);
+
+ __ and_(tmp2, Immediate(kIsNotStringMask | kIsInternalizedMask));
+ __ cmpb(tmp2, Immediate(kInternalizedTag | kStringTag));
+ __ j(not_equal, &miss, Label::kNear);
// Internalized strings are compared by identity.
Label done;
__ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
__ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
- Label succeed1;
- __ testb(tmp1, Immediate(kIsInternalizedMask));
- __ j(not_zero, &succeed1, Label::kNear);
- __ cmpb(tmp1, Immediate(static_cast<uint8_t>(SYMBOL_TYPE)));
- __ j(not_equal, &miss, Label::kNear);
- __ bind(&succeed1);
-
- Label succeed2;
- __ testb(tmp2, Immediate(kIsInternalizedMask));
- __ j(not_zero, &succeed2, Label::kNear);
- __ cmpb(tmp2, Immediate(static_cast<uint8_t>(SYMBOL_TYPE)));
- __ j(not_equal, &miss, Label::kNear);
- __ bind(&succeed2);
+ __ JumpIfNotUniqueName(tmp1, &miss, Label::kNear);
+ __ JumpIfNotUniqueName(tmp2, &miss, Label::kNear);
// Unique names are compared by identity.
Label done;
__ bind(¬_same);
// Check that both strings are internalized strings. If they are, we're done
- // because we already know they are not identical.
+ // because we already know they are not identical. We also know they are both
+ // strings.
if (equality) {
Label do_compare;
STATIC_ASSERT(kInternalizedTag != 0);
// Check if the entry name is not a unique name.
__ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
- __ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
- Immediate(kIsInternalizedMask));
- __ j(not_zero, &good, Label::kNear);
- __ cmpb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
- Immediate(static_cast<uint8_t>(SYMBOL_TYPE)));
- __ j(not_equal, miss);
-
+ __ JumpIfNotUniqueName(FieldOperand(entity_name, Map::kInstanceTypeOffset),
+ miss);
__ bind(&good);
}
// key we are looking for.
// Check if the entry name is not a unique name.
- Label cont;
__ movq(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
- __ testb(FieldOperand(scratch, Map::kInstanceTypeOffset),
- Immediate(kIsInternalizedMask));
- __ j(not_zero, &cont);
- __ cmpb(FieldOperand(scratch, Map::kInstanceTypeOffset),
- Immediate(static_cast<uint8_t>(SYMBOL_TYPE)));
- __ j(not_equal, &maybe_in_dictionary);
- __ bind(&cont);
+ __ JumpIfNotUniqueName(FieldOperand(scratch, Map::kInstanceTypeOffset),
+ &maybe_in_dictionary);
}
}
__ testl(hash, Immediate(Name::kContainsCachedArrayIndexMask));
__ j(zero, index_string); // The value in hash is used at jump target.
- // Is the string internalized?
+ // Is the string internalized? We already know it's a string so a single
+ // bit test is enough.
STATIC_ASSERT(kInternalizedTag != 0);
__ testb(FieldOperand(map, Map::kInstanceTypeOffset),
Immediate(kIsInternalizedMask));
}
+template<class T>
+static void JumpIfNotUniqueNameHelper(MacroAssembler* masm,
+ T operand_or_register,
+ Label* not_unique_name,
+ Label::Distance distance) {
+ STATIC_ASSERT(((SYMBOL_TYPE - 1) & kIsInternalizedMask) == kInternalizedTag);
+ masm->cmpb(operand_or_register, Immediate(kInternalizedTag));
+ masm->j(less, not_unique_name, distance);
+ masm->cmpb(operand_or_register, Immediate(SYMBOL_TYPE));
+ masm->j(greater, not_unique_name, distance);
+}
+
+
+void MacroAssembler::JumpIfNotUniqueName(Operand operand,
+ Label* not_unique_name,
+ Label::Distance distance) {
+ JumpIfNotUniqueNameHelper<Operand>(this, operand, not_unique_name, distance);
+}
+
+
+void MacroAssembler::JumpIfNotUniqueName(Register reg,
+ Label* not_unique_name,
+ Label::Distance distance) {
+ JumpIfNotUniqueNameHelper<Register>(this, reg, not_unique_name, distance);
+}
+
void MacroAssembler::Move(Register dst, Register src) {
if (!dst.is(src)) {
Label* on_fail,
Label::Distance near_jump = Label::kFar);
+ // Checks if the given register or operand is a unique name
+ void JumpIfNotUniqueName(Register reg, Label* not_unique_name,
+ Label::Distance distance = Label::kFar);
+ void JumpIfNotUniqueName(Operand operand, Label* not_unique_name,
+ Label::Distance distance = Label::kFar);
+
// ---------------------------------------------------------------------------
// Macro instructions.