Remove the different length string types
The different length string types was used to encode the string length and the hash in one field. This is now split into two fields one for length and one for hash. The hash field still encodes the array index of the string if it has one. If an array index is encoded in the hash field the string length is added to the top bits of the hash field to avoid a hash value of zero. On 32-bit this causes an additional 4 bytes to be used for all string objects. On 64-bit this will be half on average dur to pointer alignment. Review URL: http://codereview.chromium.org/436001 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3350 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
56074f783a
commit
eb4d261e24
16
include/v8.h
16
include/v8.h
@ -2819,6 +2819,18 @@ template <> struct SmiConstants<8> {
|
||||
const int kSmiShiftSize = SmiConstants<sizeof(void*)>::kSmiShiftSize;
|
||||
const int kSmiValueSize = SmiConstants<sizeof(void*)>::kSmiValueSize;
|
||||
|
||||
template <size_t ptr_size> struct InternalConstants;
|
||||
|
||||
// Internal constants for 32-bit systems.
|
||||
template <> struct InternalConstants<4> {
|
||||
static const int kStringResourceOffset = 3 * sizeof(void*);
|
||||
};
|
||||
|
||||
// Internal constants for 64-bit systems.
|
||||
template <> struct InternalConstants<8> {
|
||||
static const int kStringResourceOffset = 2 * sizeof(void*);
|
||||
};
|
||||
|
||||
/**
|
||||
* This class exports constants and functionality from within v8 that
|
||||
* is necessary to implement inline functions in the v8 api. Don't
|
||||
@ -2831,7 +2843,9 @@ class Internals {
|
||||
// the implementation of v8.
|
||||
static const int kHeapObjectMapOffset = 0;
|
||||
static const int kMapInstanceTypeOffset = sizeof(void*) + sizeof(int);
|
||||
static const int kStringResourceOffset = 2 * sizeof(void*);
|
||||
static const int kStringResourceOffset =
|
||||
InternalConstants<sizeof(void*)>::kStringResourceOffset;
|
||||
|
||||
static const int kProxyProxyOffset = sizeof(void*);
|
||||
static const int kJSObjectHeaderSize = 3 * sizeof(void*);
|
||||
static const int kFullStringRepresentationMask = 0x07;
|
||||
|
@ -3308,9 +3308,6 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
|
||||
|
||||
// Now r2 has the string type.
|
||||
__ ldr(r3, FieldMemOperand(r1, String::kLengthOffset));
|
||||
__ and_(r4, r2, Operand(kStringSizeMask));
|
||||
__ add(r4, r4, Operand(String::kLongLengthShift));
|
||||
__ mov(r3, Operand(r3, LSR, r4));
|
||||
// Now r3 has the length of the string. Compare with the index.
|
||||
__ cmp(r3, Operand(r0, LSR, kSmiTagSize));
|
||||
__ b(le, &slow);
|
||||
|
@ -107,12 +107,15 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
|
||||
static const int kProbes = 4;
|
||||
for (int i = 0; i < kProbes; i++) {
|
||||
// Compute the masked index: (hash + i + i * i) & mask.
|
||||
__ ldr(t1, FieldMemOperand(r2, String::kLengthOffset));
|
||||
__ mov(t1, Operand(t1, LSR, String::kHashShift));
|
||||
__ ldr(t1, FieldMemOperand(r2, String::kHashFieldOffset));
|
||||
if (i > 0) {
|
||||
__ add(t1, t1, Operand(StringDictionary::GetProbeOffset(i)));
|
||||
// Add the probe offset (i + i * i) left shifted to avoid right shifting
|
||||
// the hash in a separate instruction. The value hash + i + i * i is right
|
||||
// shifted in the following and instruction.
|
||||
__ add(t1, t1, Operand(
|
||||
StringDictionary::GetProbeOffset(i) << String::kHashFieldOffset));
|
||||
}
|
||||
__ and_(t1, t1, Operand(r3));
|
||||
__ and_(t1, r3, Operand(t1, LSR, String::kHashShift));
|
||||
|
||||
// Scale the index by multiplying by the element size.
|
||||
ASSERT(StringDictionary::kEntrySize == 3);
|
||||
|
@ -229,10 +229,7 @@ void StubCompiler::GenerateLoadStringLength2(MacroAssembler* masm,
|
||||
miss, &check_wrapper);
|
||||
|
||||
// Load length directly from the string.
|
||||
__ and_(scratch1, scratch1, Operand(kStringSizeMask));
|
||||
__ add(scratch1, scratch1, Operand(String::kHashShift));
|
||||
__ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
|
||||
__ mov(r0, Operand(r0, LSR, scratch1));
|
||||
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
|
||||
__ Ret();
|
||||
|
||||
|
@ -41,10 +41,10 @@ int Heap::MaxObjectSizeInPagedSpace() {
|
||||
|
||||
Object* Heap::AllocateSymbol(Vector<const char> str,
|
||||
int chars,
|
||||
uint32_t length_field) {
|
||||
uint32_t hash_field) {
|
||||
unibrow::Utf8InputBuffer<> buffer(str.start(),
|
||||
static_cast<unsigned>(str.length()));
|
||||
return AllocateInternalSymbol(&buffer, chars, length_field);
|
||||
return AllocateInternalSymbol(&buffer, chars, hash_field);
|
||||
}
|
||||
|
||||
|
||||
|
155
src/heap.cc
155
src/heap.cc
@ -1187,34 +1187,14 @@ bool Heap::CreateInitialMaps() {
|
||||
roots_[entry.index] = Map::cast(obj);
|
||||
}
|
||||
|
||||
obj = AllocateMap(SHORT_STRING_TYPE, SeqTwoByteString::kAlignedSize);
|
||||
obj = AllocateMap(STRING_TYPE, SeqTwoByteString::kAlignedSize);
|
||||
if (obj->IsFailure()) return false;
|
||||
set_undetectable_short_string_map(Map::cast(obj));
|
||||
set_undetectable_string_map(Map::cast(obj));
|
||||
Map::cast(obj)->set_is_undetectable();
|
||||
|
||||
obj = AllocateMap(MEDIUM_STRING_TYPE, SeqTwoByteString::kAlignedSize);
|
||||
obj = AllocateMap(ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
|
||||
if (obj->IsFailure()) return false;
|
||||
set_undetectable_medium_string_map(Map::cast(obj));
|
||||
Map::cast(obj)->set_is_undetectable();
|
||||
|
||||
obj = AllocateMap(LONG_STRING_TYPE, SeqTwoByteString::kAlignedSize);
|
||||
if (obj->IsFailure()) return false;
|
||||
set_undetectable_long_string_map(Map::cast(obj));
|
||||
Map::cast(obj)->set_is_undetectable();
|
||||
|
||||
obj = AllocateMap(SHORT_ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
|
||||
if (obj->IsFailure()) return false;
|
||||
set_undetectable_short_ascii_string_map(Map::cast(obj));
|
||||
Map::cast(obj)->set_is_undetectable();
|
||||
|
||||
obj = AllocateMap(MEDIUM_ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
|
||||
if (obj->IsFailure()) return false;
|
||||
set_undetectable_medium_ascii_string_map(Map::cast(obj));
|
||||
Map::cast(obj)->set_is_undetectable();
|
||||
|
||||
obj = AllocateMap(LONG_ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
|
||||
if (obj->IsFailure()) return false;
|
||||
set_undetectable_long_ascii_string_map(Map::cast(obj));
|
||||
set_undetectable_ascii_string_map(Map::cast(obj));
|
||||
Map::cast(obj)->set_is_undetectable();
|
||||
|
||||
obj = AllocateMap(BYTE_ARRAY_TYPE, ByteArray::kAlignedSize);
|
||||
@ -1856,26 +1836,17 @@ Object* Heap::AllocateConsString(String* first, String* second) {
|
||||
}
|
||||
}
|
||||
|
||||
Map* map;
|
||||
if (length <= String::kMaxShortSize) {
|
||||
map = is_ascii ? short_cons_ascii_string_map()
|
||||
: short_cons_string_map();
|
||||
} else if (length <= String::kMaxMediumSize) {
|
||||
map = is_ascii ? medium_cons_ascii_string_map()
|
||||
: medium_cons_string_map();
|
||||
} else {
|
||||
map = is_ascii ? long_cons_ascii_string_map()
|
||||
: long_cons_string_map();
|
||||
}
|
||||
Map* map = is_ascii ? cons_ascii_string_map() : cons_string_map();
|
||||
|
||||
Object* result = Allocate(map,
|
||||
always_allocate() ? OLD_POINTER_SPACE : NEW_SPACE);
|
||||
if (result->IsFailure()) return result;
|
||||
ConsString* cons_string = ConsString::cast(result);
|
||||
WriteBarrierMode mode = cons_string->GetWriteBarrierMode();
|
||||
cons_string->set_length(length);
|
||||
cons_string->set_hash_field(String::kEmptyHashField);
|
||||
cons_string->set_first(first, mode);
|
||||
cons_string->set_second(second, mode);
|
||||
cons_string->set_length(length);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1925,25 +1896,20 @@ Object* Heap::AllocateSubString(String* buffer,
|
||||
|
||||
Object* Heap::AllocateExternalStringFromAscii(
|
||||
ExternalAsciiString::Resource* resource) {
|
||||
Map* map;
|
||||
size_t length = resource->length();
|
||||
if (length <= static_cast<size_t>(String::kMaxShortSize)) {
|
||||
map = short_external_ascii_string_map();
|
||||
} else if (length <= static_cast<size_t>(String::kMaxMediumSize)) {
|
||||
map = medium_external_ascii_string_map();
|
||||
} else if (length <= static_cast<size_t>(String::kMaxLength)) {
|
||||
map = long_external_ascii_string_map();
|
||||
} else {
|
||||
if (length > static_cast<size_t>(String::kMaxLength)) {
|
||||
Top::context()->mark_out_of_memory();
|
||||
return Failure::OutOfMemoryException();
|
||||
}
|
||||
|
||||
Map* map = external_ascii_string_map();
|
||||
Object* result = Allocate(map,
|
||||
always_allocate() ? OLD_DATA_SPACE : NEW_SPACE);
|
||||
if (result->IsFailure()) return result;
|
||||
|
||||
ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
|
||||
external_string->set_length(static_cast<int>(length));
|
||||
external_string->set_hash_field(String::kEmptyHashField);
|
||||
external_string->set_resource(resource);
|
||||
|
||||
return result;
|
||||
@ -1957,13 +1923,15 @@ Object* Heap::AllocateExternalStringFromTwoByte(
|
||||
Top::context()->mark_out_of_memory();
|
||||
return Failure::OutOfMemoryException();
|
||||
}
|
||||
Map* map = ExternalTwoByteString::StringMap(static_cast<int>(length));
|
||||
|
||||
Map* map = Heap::external_string_map();
|
||||
Object* result = Allocate(map,
|
||||
always_allocate() ? OLD_DATA_SPACE : NEW_SPACE);
|
||||
if (result->IsFailure()) return result;
|
||||
|
||||
ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
|
||||
external_string->set_length(static_cast<int>(length));
|
||||
external_string->set_hash_field(String::kEmptyHashField);
|
||||
external_string->set_resource(resource);
|
||||
|
||||
return result;
|
||||
@ -2604,48 +2572,12 @@ Map* Heap::SymbolMapForString(String* string) {
|
||||
|
||||
// Find the corresponding symbol map for strings.
|
||||
Map* map = string->map();
|
||||
|
||||
if (map == short_ascii_string_map()) return short_ascii_symbol_map();
|
||||
if (map == medium_ascii_string_map()) return medium_ascii_symbol_map();
|
||||
if (map == long_ascii_string_map()) return long_ascii_symbol_map();
|
||||
|
||||
if (map == short_string_map()) return short_symbol_map();
|
||||
if (map == medium_string_map()) return medium_symbol_map();
|
||||
if (map == long_string_map()) return long_symbol_map();
|
||||
|
||||
if (map == short_cons_string_map()) return short_cons_symbol_map();
|
||||
if (map == medium_cons_string_map()) return medium_cons_symbol_map();
|
||||
if (map == long_cons_string_map()) return long_cons_symbol_map();
|
||||
|
||||
if (map == short_cons_ascii_string_map()) {
|
||||
return short_cons_ascii_symbol_map();
|
||||
}
|
||||
if (map == medium_cons_ascii_string_map()) {
|
||||
return medium_cons_ascii_symbol_map();
|
||||
}
|
||||
if (map == long_cons_ascii_string_map()) {
|
||||
return long_cons_ascii_symbol_map();
|
||||
}
|
||||
|
||||
if (map == short_external_string_map()) {
|
||||
return short_external_symbol_map();
|
||||
}
|
||||
if (map == medium_external_string_map()) {
|
||||
return medium_external_symbol_map();
|
||||
}
|
||||
if (map == long_external_string_map()) {
|
||||
return long_external_symbol_map();
|
||||
}
|
||||
|
||||
if (map == short_external_ascii_string_map()) {
|
||||
return short_external_ascii_symbol_map();
|
||||
}
|
||||
if (map == medium_external_ascii_string_map()) {
|
||||
return medium_external_ascii_symbol_map();
|
||||
}
|
||||
if (map == long_external_ascii_string_map()) {
|
||||
return long_external_ascii_symbol_map();
|
||||
}
|
||||
if (map == ascii_string_map()) return ascii_symbol_map();
|
||||
if (map == string_map()) return symbol_map();
|
||||
if (map == cons_string_map()) return cons_symbol_map();
|
||||
if (map == cons_ascii_string_map()) return cons_ascii_symbol_map();
|
||||
if (map == external_string_map()) return external_symbol_map();
|
||||
if (map == external_ascii_string_map()) return external_ascii_symbol_map();
|
||||
|
||||
// No match found.
|
||||
return NULL;
|
||||
@ -2654,7 +2586,7 @@ Map* Heap::SymbolMapForString(String* string) {
|
||||
|
||||
Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
|
||||
int chars,
|
||||
uint32_t length_field) {
|
||||
uint32_t hash_field) {
|
||||
// Ensure the chars matches the number of characters in the buffer.
|
||||
ASSERT(static_cast<unsigned>(chars) == buffer->Length());
|
||||
// Determine whether the string is ascii.
|
||||
@ -2669,22 +2601,10 @@ Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
|
||||
Map* map;
|
||||
|
||||
if (is_ascii) {
|
||||
if (chars <= String::kMaxShortSize) {
|
||||
map = short_ascii_symbol_map();
|
||||
} else if (chars <= String::kMaxMediumSize) {
|
||||
map = medium_ascii_symbol_map();
|
||||
} else {
|
||||
map = long_ascii_symbol_map();
|
||||
}
|
||||
map = ascii_symbol_map();
|
||||
size = SeqAsciiString::SizeFor(chars);
|
||||
} else {
|
||||
if (chars <= String::kMaxShortSize) {
|
||||
map = short_symbol_map();
|
||||
} else if (chars <= String::kMaxMediumSize) {
|
||||
map = medium_symbol_map();
|
||||
} else {
|
||||
map = long_symbol_map();
|
||||
}
|
||||
map = symbol_map();
|
||||
size = SeqTwoByteString::SizeFor(chars);
|
||||
}
|
||||
|
||||
@ -2695,9 +2615,10 @@ Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
|
||||
if (result->IsFailure()) return result;
|
||||
|
||||
reinterpret_cast<HeapObject*>(result)->set_map(map);
|
||||
// The hash value contains the length of the string.
|
||||
// Set length and hash fields of the allocated string.
|
||||
String* answer = String::cast(result);
|
||||
answer->set_length_field(length_field);
|
||||
answer->set_length(chars);
|
||||
answer->set_hash_field(hash_field);
|
||||
|
||||
ASSERT_EQ(size, answer->Size());
|
||||
|
||||
@ -2728,19 +2649,10 @@ Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
|
||||
}
|
||||
if (result->IsFailure()) return result;
|
||||
|
||||
// Determine the map based on the string's length.
|
||||
Map* map;
|
||||
if (length <= String::kMaxShortSize) {
|
||||
map = short_ascii_string_map();
|
||||
} else if (length <= String::kMaxMediumSize) {
|
||||
map = medium_ascii_string_map();
|
||||
} else {
|
||||
map = long_ascii_string_map();
|
||||
}
|
||||
|
||||
// Partially initialize the object.
|
||||
HeapObject::cast(result)->set_map(map);
|
||||
HeapObject::cast(result)->set_map(ascii_string_map());
|
||||
String::cast(result)->set_length(length);
|
||||
String::cast(result)->set_hash_field(String::kEmptyHashField);
|
||||
ASSERT_EQ(size, HeapObject::cast(result)->Size());
|
||||
return result;
|
||||
}
|
||||
@ -2765,19 +2677,10 @@ Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) {
|
||||
}
|
||||
if (result->IsFailure()) return result;
|
||||
|
||||
// Determine the map based on the string's length.
|
||||
Map* map;
|
||||
if (length <= String::kMaxShortSize) {
|
||||
map = short_string_map();
|
||||
} else if (length <= String::kMaxMediumSize) {
|
||||
map = medium_string_map();
|
||||
} else {
|
||||
map = long_string_map();
|
||||
}
|
||||
|
||||
// Partially initialize the object.
|
||||
HeapObject::cast(result)->set_map(map);
|
||||
HeapObject::cast(result)->set_map(string_map());
|
||||
String::cast(result)->set_length(length);
|
||||
String::cast(result)->set_hash_field(String::kEmptyHashField);
|
||||
ASSERT_EQ(size, HeapObject::cast(result)->Size());
|
||||
return result;
|
||||
}
|
||||
|
62
src/heap.h
62
src/heap.h
@ -59,50 +59,20 @@ namespace internal {
|
||||
V(Object, termination_exception, TerminationException) \
|
||||
V(Map, hash_table_map, HashTableMap) \
|
||||
V(FixedArray, empty_fixed_array, EmptyFixedArray) \
|
||||
V(Map, short_string_map, ShortStringMap) \
|
||||
V(Map, medium_string_map, MediumStringMap) \
|
||||
V(Map, long_string_map, LongStringMap) \
|
||||
V(Map, short_ascii_string_map, ShortAsciiStringMap) \
|
||||
V(Map, medium_ascii_string_map, MediumAsciiStringMap) \
|
||||
V(Map, long_ascii_string_map, LongAsciiStringMap) \
|
||||
V(Map, short_symbol_map, ShortSymbolMap) \
|
||||
V(Map, medium_symbol_map, MediumSymbolMap) \
|
||||
V(Map, long_symbol_map, LongSymbolMap) \
|
||||
V(Map, short_ascii_symbol_map, ShortAsciiSymbolMap) \
|
||||
V(Map, medium_ascii_symbol_map, MediumAsciiSymbolMap) \
|
||||
V(Map, long_ascii_symbol_map, LongAsciiSymbolMap) \
|
||||
V(Map, short_cons_symbol_map, ShortConsSymbolMap) \
|
||||
V(Map, medium_cons_symbol_map, MediumConsSymbolMap) \
|
||||
V(Map, long_cons_symbol_map, LongConsSymbolMap) \
|
||||
V(Map, short_cons_ascii_symbol_map, ShortConsAsciiSymbolMap) \
|
||||
V(Map, medium_cons_ascii_symbol_map, MediumConsAsciiSymbolMap) \
|
||||
V(Map, long_cons_ascii_symbol_map, LongConsAsciiSymbolMap) \
|
||||
V(Map, short_external_symbol_map, ShortExternalSymbolMap) \
|
||||
V(Map, medium_external_symbol_map, MediumExternalSymbolMap) \
|
||||
V(Map, long_external_symbol_map, LongExternalSymbolMap) \
|
||||
V(Map, short_external_ascii_symbol_map, ShortExternalAsciiSymbolMap) \
|
||||
V(Map, medium_external_ascii_symbol_map, MediumExternalAsciiSymbolMap) \
|
||||
V(Map, long_external_ascii_symbol_map, LongExternalAsciiSymbolMap) \
|
||||
V(Map, short_cons_string_map, ShortConsStringMap) \
|
||||
V(Map, medium_cons_string_map, MediumConsStringMap) \
|
||||
V(Map, long_cons_string_map, LongConsStringMap) \
|
||||
V(Map, short_cons_ascii_string_map, ShortConsAsciiStringMap) \
|
||||
V(Map, medium_cons_ascii_string_map, MediumConsAsciiStringMap) \
|
||||
V(Map, long_cons_ascii_string_map, LongConsAsciiStringMap) \
|
||||
V(Map, short_external_string_map, ShortExternalStringMap) \
|
||||
V(Map, medium_external_string_map, MediumExternalStringMap) \
|
||||
V(Map, long_external_string_map, LongExternalStringMap) \
|
||||
V(Map, short_external_ascii_string_map, ShortExternalAsciiStringMap) \
|
||||
V(Map, medium_external_ascii_string_map, MediumExternalAsciiStringMap) \
|
||||
V(Map, long_external_ascii_string_map, LongExternalAsciiStringMap) \
|
||||
V(Map, undetectable_short_string_map, UndetectableShortStringMap) \
|
||||
V(Map, undetectable_medium_string_map, UndetectableMediumStringMap) \
|
||||
V(Map, undetectable_long_string_map, UndetectableLongStringMap) \
|
||||
V(Map, undetectable_short_ascii_string_map, UndetectableShortAsciiStringMap) \
|
||||
V(Map, \
|
||||
undetectable_medium_ascii_string_map, \
|
||||
UndetectableMediumAsciiStringMap) \
|
||||
V(Map, undetectable_long_ascii_string_map, UndetectableLongAsciiStringMap) \
|
||||
V(Map, string_map, StringMap) \
|
||||
V(Map, ascii_string_map, AsciiStringMap) \
|
||||
V(Map, symbol_map, SymbolMap) \
|
||||
V(Map, ascii_symbol_map, AsciiSymbolMap) \
|
||||
V(Map, cons_symbol_map, ConsSymbolMap) \
|
||||
V(Map, cons_ascii_symbol_map, ConsAsciiSymbolMap) \
|
||||
V(Map, external_symbol_map, ExternalSymbolMap) \
|
||||
V(Map, external_ascii_symbol_map, ExternalAsciiSymbolMap) \
|
||||
V(Map, cons_string_map, ConsStringMap) \
|
||||
V(Map, cons_ascii_string_map, ConsAsciiStringMap) \
|
||||
V(Map, external_string_map, ExternalStringMap) \
|
||||
V(Map, external_ascii_string_map, ExternalAsciiStringMap) \
|
||||
V(Map, undetectable_string_map, UndetectableStringMap) \
|
||||
V(Map, undetectable_ascii_string_map, UndetectableAsciiStringMap) \
|
||||
V(Map, pixel_array_map, PixelArrayMap) \
|
||||
V(Map, external_byte_array_map, ExternalByteArrayMap) \
|
||||
V(Map, external_unsigned_byte_array_map, ExternalUnsignedByteArrayMap) \
|
||||
@ -409,11 +379,11 @@ class Heap : public AllStatic {
|
||||
// Please note this function does not perform a garbage collection.
|
||||
static inline Object* AllocateSymbol(Vector<const char> str,
|
||||
int chars,
|
||||
uint32_t length_field);
|
||||
uint32_t hash_field);
|
||||
|
||||
static Object* AllocateInternalSymbol(unibrow::CharacterStream* buffer,
|
||||
int chars,
|
||||
uint32_t length_field);
|
||||
uint32_t hash_field);
|
||||
|
||||
static Object* AllocateExternalSymbol(Vector<const char> str,
|
||||
int chars);
|
||||
|
@ -4777,18 +4777,8 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
|
||||
__ test(ecx, Immediate(kIsNotStringMask));
|
||||
__ j(not_zero, &slow_case);
|
||||
|
||||
// Here we make assumptions about the tag values and the shifts needed.
|
||||
// See the comment in objects.h.
|
||||
ASSERT(kLongStringTag == 0);
|
||||
ASSERT(kMediumStringTag + String::kLongLengthShift ==
|
||||
String::kMediumLengthShift);
|
||||
ASSERT(kShortStringTag + String::kLongLengthShift ==
|
||||
String::kShortLengthShift);
|
||||
__ and_(ecx, kStringSizeMask);
|
||||
__ add(Operand(ecx), Immediate(String::kLongLengthShift));
|
||||
// Fetch the length field into the temporary register.
|
||||
__ mov(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset));
|
||||
__ shr_cl(temp.reg());
|
||||
// Check for index out of range.
|
||||
__ cmp(index.reg(), Operand(temp.reg()));
|
||||
__ j(greater_equal, &slow_case);
|
||||
@ -6502,11 +6492,8 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
|
||||
// String value => false iff empty.
|
||||
__ cmp(ecx, FIRST_NONSTRING_TYPE);
|
||||
__ j(above_equal, ¬_string);
|
||||
__ and_(ecx, kStringSizeMask);
|
||||
__ cmp(ecx, kShortStringTag);
|
||||
__ j(not_equal, &true_result); // Empty string is always short.
|
||||
__ mov(edx, FieldOperand(eax, String::kLengthOffset));
|
||||
__ shr(edx, String::kShortLengthShift);
|
||||
__ test(edx, Operand(edx));
|
||||
__ j(zero, &false_result);
|
||||
__ jmp(&true_result);
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "ic-inl.h"
|
||||
#include "runtime.h"
|
||||
#include "stub-cache.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -108,7 +109,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
for (int i = 0; i < kProbes; i++) {
|
||||
// Compute the masked index: (hash + i + i * i) & mask.
|
||||
__ mov(r1, FieldOperand(name, String::kLengthOffset));
|
||||
__ mov(r1, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ shr(r1, String::kHashShift);
|
||||
if (i > 0) {
|
||||
__ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i)));
|
||||
@ -216,18 +217,6 @@ void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
// For use in assert below.
|
||||
static int TenToThe(int exponent) {
|
||||
ASSERT(exponent <= 9);
|
||||
ASSERT(exponent >= 1);
|
||||
int answer = 10;
|
||||
for (int i = 1; i < exponent; i++) answer *= 10;
|
||||
return answer;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- esp[0] : return address
|
||||
@ -309,7 +298,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
|
||||
__ j(above_equal, &slow);
|
||||
// Is the string an array index, with cached numeric value?
|
||||
__ mov(ebx, FieldOperand(eax, String::kLengthOffset));
|
||||
__ mov(ebx, FieldOperand(eax, String::kHashFieldOffset));
|
||||
__ test(ebx, Immediate(String::kIsArrayIndexMask));
|
||||
__ j(not_zero, &index_string, not_taken);
|
||||
|
||||
@ -324,20 +313,16 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ mov(eax, Operand(ecx));
|
||||
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
|
||||
__ ret(0);
|
||||
// Array index string: If short enough use cache in length/hash field (ebx).
|
||||
// We assert that there are enough bits in an int32_t after the hash shift
|
||||
// bits have been subtracted to allow space for the length and the cached
|
||||
// array index.
|
||||
// If the hash field contains an array index pick it out. The assert checks
|
||||
// that the constants for the maximum number of digits for an array index
|
||||
// cached in the hash field and the number of bits reserved for it does not
|
||||
// conflict.
|
||||
ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
|
||||
(1 << (String::kShortLengthShift - String::kHashShift)));
|
||||
(1 << String::kArrayIndexValueBits));
|
||||
__ bind(&index_string);
|
||||
const int kLengthFieldLimit =
|
||||
(String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
|
||||
__ cmp(ebx, kLengthFieldLimit);
|
||||
__ j(above_equal, &slow);
|
||||
__ mov(eax, Operand(ebx));
|
||||
__ and_(eax, (1 << String::kShortLengthShift) - 1);
|
||||
__ shr(eax, String::kLongLengthShift);
|
||||
__ and_(eax, String::kArrayIndexHashMask);
|
||||
__ shr(eax, String::kHashShift);
|
||||
__ jmp(&index_int);
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
__ j(zero, &miss, not_taken);
|
||||
|
||||
// Get the map of the receiver and compute the hash.
|
||||
__ mov(scratch, FieldOperand(name, String::kLengthOffset));
|
||||
__ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ xor_(scratch, flags);
|
||||
__ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
|
||||
@ -135,7 +135,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
ProbeTable(masm, flags, kPrimary, name, scratch, extra);
|
||||
|
||||
// Primary miss: Compute hash for secondary probe.
|
||||
__ mov(scratch, FieldOperand(name, String::kLengthOffset));
|
||||
__ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ xor_(scratch, flags);
|
||||
__ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
|
||||
@ -234,13 +234,9 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
|
||||
// scratch register.
|
||||
GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper);
|
||||
|
||||
// Load length directly from the string.
|
||||
// Load length from the string and convert to a smi.
|
||||
__ bind(&load_length);
|
||||
__ and_(scratch, kStringSizeMask);
|
||||
__ mov(eax, FieldOperand(receiver, String::kLengthOffset));
|
||||
// ecx is also the receiver.
|
||||
__ lea(ecx, Operand(scratch, String::kLongLengthShift));
|
||||
__ shr_cl(eax);
|
||||
__ shl(eax, kSmiTagSize);
|
||||
__ ret(0);
|
||||
|
||||
|
@ -547,42 +547,18 @@ static const char* TypeToString(InstanceType type) {
|
||||
case INVALID_TYPE: return "INVALID";
|
||||
case MAP_TYPE: return "MAP";
|
||||
case HEAP_NUMBER_TYPE: return "HEAP_NUMBER";
|
||||
case SHORT_SYMBOL_TYPE:
|
||||
case MEDIUM_SYMBOL_TYPE:
|
||||
case LONG_SYMBOL_TYPE: return "SYMBOL";
|
||||
case SHORT_ASCII_SYMBOL_TYPE:
|
||||
case MEDIUM_ASCII_SYMBOL_TYPE:
|
||||
case LONG_ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL";
|
||||
case SHORT_CONS_SYMBOL_TYPE:
|
||||
case MEDIUM_CONS_SYMBOL_TYPE:
|
||||
case LONG_CONS_SYMBOL_TYPE: return "CONS_SYMBOL";
|
||||
case SHORT_CONS_ASCII_SYMBOL_TYPE:
|
||||
case MEDIUM_CONS_ASCII_SYMBOL_TYPE:
|
||||
case LONG_CONS_ASCII_SYMBOL_TYPE: return "CONS_ASCII_SYMBOL";
|
||||
case SHORT_EXTERNAL_ASCII_SYMBOL_TYPE:
|
||||
case MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE:
|
||||
case LONG_EXTERNAL_ASCII_SYMBOL_TYPE:
|
||||
case SHORT_EXTERNAL_SYMBOL_TYPE:
|
||||
case MEDIUM_EXTERNAL_SYMBOL_TYPE:
|
||||
case LONG_EXTERNAL_SYMBOL_TYPE: return "EXTERNAL_SYMBOL";
|
||||
case SHORT_ASCII_STRING_TYPE:
|
||||
case MEDIUM_ASCII_STRING_TYPE:
|
||||
case LONG_ASCII_STRING_TYPE: return "ASCII_STRING";
|
||||
case SHORT_STRING_TYPE:
|
||||
case MEDIUM_STRING_TYPE:
|
||||
case LONG_STRING_TYPE: return "TWO_BYTE_STRING";
|
||||
case SHORT_CONS_STRING_TYPE:
|
||||
case MEDIUM_CONS_STRING_TYPE:
|
||||
case LONG_CONS_STRING_TYPE:
|
||||
case SHORT_CONS_ASCII_STRING_TYPE:
|
||||
case MEDIUM_CONS_ASCII_STRING_TYPE:
|
||||
case LONG_CONS_ASCII_STRING_TYPE: return "CONS_STRING";
|
||||
case SHORT_EXTERNAL_ASCII_STRING_TYPE:
|
||||
case MEDIUM_EXTERNAL_ASCII_STRING_TYPE:
|
||||
case LONG_EXTERNAL_ASCII_STRING_TYPE:
|
||||
case SHORT_EXTERNAL_STRING_TYPE:
|
||||
case MEDIUM_EXTERNAL_STRING_TYPE:
|
||||
case LONG_EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING";
|
||||
case SYMBOL_TYPE: return "SYMBOL";
|
||||
case ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL";
|
||||
case CONS_SYMBOL_TYPE: return "CONS_SYMBOL";
|
||||
case CONS_ASCII_SYMBOL_TYPE: return "CONS_ASCII_SYMBOL";
|
||||
case EXTERNAL_ASCII_SYMBOL_TYPE:
|
||||
case EXTERNAL_SYMBOL_TYPE: return "EXTERNAL_SYMBOL";
|
||||
case ASCII_STRING_TYPE: return "ASCII_STRING";
|
||||
case STRING_TYPE: return "TWO_BYTE_STRING";
|
||||
case CONS_STRING_TYPE:
|
||||
case CONS_ASCII_STRING_TYPE: return "CONS_STRING";
|
||||
case EXTERNAL_ASCII_STRING_TYPE:
|
||||
case EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING";
|
||||
case FIXED_ARRAY_TYPE: return "FIXED_ARRAY";
|
||||
case BYTE_ARRAY_TYPE: return "BYTE_ARRAY";
|
||||
case PIXEL_ARRAY_TYPE: return "PIXEL_ARRAY";
|
||||
|
@ -280,11 +280,6 @@ STATIC_CHECK((kStringRepresentationMask | kStringEncodingMask) ==
|
||||
Internals::kFullStringRepresentationMask);
|
||||
|
||||
|
||||
uint32_t StringShape::size_tag() {
|
||||
return (type_ & kStringSizeMask);
|
||||
}
|
||||
|
||||
|
||||
bool StringShape::IsSequentialAscii() {
|
||||
return full_representation_tag() == (kSeqStringTag | kAsciiStringTag);
|
||||
}
|
||||
@ -1635,6 +1630,19 @@ HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) {
|
||||
INT_ACCESSORS(Array, length, kLengthOffset)
|
||||
|
||||
|
||||
INT_ACCESSORS(String, length, kLengthOffset)
|
||||
|
||||
|
||||
uint32_t String::hash_field() {
|
||||
return READ_UINT32_FIELD(this, kHashFieldOffset);
|
||||
}
|
||||
|
||||
|
||||
void String::set_hash_field(uint32_t value) {
|
||||
WRITE_UINT32_FIELD(this, kHashFieldOffset, value);
|
||||
}
|
||||
|
||||
|
||||
bool String::Equals(String* other) {
|
||||
if (other == this) return true;
|
||||
if (StringShape(this).IsSymbol() && StringShape(other).IsSymbol()) {
|
||||
@ -1644,38 +1652,6 @@ bool String::Equals(String* other) {
|
||||
}
|
||||
|
||||
|
||||
int String::length() {
|
||||
uint32_t len = READ_INT_FIELD(this, kLengthOffset);
|
||||
|
||||
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
|
||||
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
|
||||
ASSERT(kLongStringTag == 0);
|
||||
|
||||
return len >> (StringShape(this).size_tag() + kLongLengthShift);
|
||||
}
|
||||
|
||||
|
||||
void String::set_length(int value) {
|
||||
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
|
||||
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
|
||||
ASSERT(kLongStringTag == 0);
|
||||
|
||||
WRITE_INT_FIELD(this,
|
||||
kLengthOffset,
|
||||
value << (StringShape(this).size_tag() + kLongLengthShift));
|
||||
}
|
||||
|
||||
|
||||
uint32_t String::length_field() {
|
||||
return READ_UINT32_FIELD(this, kLengthOffset);
|
||||
}
|
||||
|
||||
|
||||
void String::set_length_field(uint32_t value) {
|
||||
WRITE_UINT32_FIELD(this, kLengthOffset, value);
|
||||
}
|
||||
|
||||
|
||||
Object* String::TryFlattenIfNotFlat() {
|
||||
// We don't need to flatten strings that are already flat. Since this code
|
||||
// is inlined, it can be helpful in the flat case to not call out to Flatten.
|
||||
@ -1779,30 +1755,12 @@ void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) {
|
||||
|
||||
int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) {
|
||||
uint32_t length = READ_INT_FIELD(this, kLengthOffset);
|
||||
|
||||
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
|
||||
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
|
||||
ASSERT(kLongStringTag == 0);
|
||||
|
||||
// Use the map (and not 'this') to compute the size tag, since
|
||||
// TwoByteStringSize is called during GC when maps are encoded.
|
||||
length >>= StringShape(instance_type).size_tag() + kLongLengthShift;
|
||||
|
||||
return SizeFor(length);
|
||||
}
|
||||
|
||||
|
||||
int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) {
|
||||
uint32_t length = READ_INT_FIELD(this, kLengthOffset);
|
||||
|
||||
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
|
||||
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
|
||||
ASSERT(kLongStringTag == 0);
|
||||
|
||||
// Use the map (and not 'this') to compute the size tag, since
|
||||
// AsciiStringSize is called during GC when maps are encoded.
|
||||
length >>= StringShape(instance_type).size_tag() + kLongLengthShift;
|
||||
|
||||
return SizeFor(length);
|
||||
}
|
||||
|
||||
@ -1850,34 +1808,6 @@ void ExternalAsciiString::set_resource(
|
||||
}
|
||||
|
||||
|
||||
Map* ExternalAsciiString::StringMap(int length) {
|
||||
Map* map;
|
||||
// Number of characters: determines the map.
|
||||
if (length <= String::kMaxShortSize) {
|
||||
map = Heap::short_external_ascii_string_map();
|
||||
} else if (length <= String::kMaxMediumSize) {
|
||||
map = Heap::medium_external_ascii_string_map();
|
||||
} else {
|
||||
map = Heap::long_external_ascii_string_map();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
Map* ExternalAsciiString::SymbolMap(int length) {
|
||||
Map* map;
|
||||
// Number of characters: determines the map.
|
||||
if (length <= String::kMaxShortSize) {
|
||||
map = Heap::short_external_ascii_symbol_map();
|
||||
} else if (length <= String::kMaxMediumSize) {
|
||||
map = Heap::medium_external_ascii_symbol_map();
|
||||
} else {
|
||||
map = Heap::long_external_ascii_symbol_map();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
ExternalTwoByteString::Resource* ExternalTwoByteString::resource() {
|
||||
return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset));
|
||||
}
|
||||
@ -1889,34 +1819,6 @@ void ExternalTwoByteString::set_resource(
|
||||
}
|
||||
|
||||
|
||||
Map* ExternalTwoByteString::StringMap(int length) {
|
||||
Map* map;
|
||||
// Number of characters: determines the map.
|
||||
if (length <= String::kMaxShortSize) {
|
||||
map = Heap::short_external_string_map();
|
||||
} else if (length <= String::kMaxMediumSize) {
|
||||
map = Heap::medium_external_string_map();
|
||||
} else {
|
||||
map = Heap::long_external_string_map();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
Map* ExternalTwoByteString::SymbolMap(int length) {
|
||||
Map* map;
|
||||
// Number of characters: determines the map.
|
||||
if (length <= String::kMaxShortSize) {
|
||||
map = Heap::short_external_symbol_map();
|
||||
} else if (length <= String::kMaxMediumSize) {
|
||||
map = Heap::medium_external_symbol_map();
|
||||
} else {
|
||||
map = Heap::long_external_symbol_map();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
byte ByteArray::get(int index) {
|
||||
ASSERT(index >= 0 && index < this->length());
|
||||
return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
|
||||
@ -2900,13 +2802,13 @@ NumberDictionary* JSObject::element_dictionary() {
|
||||
|
||||
|
||||
bool String::HasHashCode() {
|
||||
return (length_field() & kHashComputedMask) != 0;
|
||||
return (hash_field() & kHashComputedMask) != 0;
|
||||
}
|
||||
|
||||
|
||||
uint32_t String::Hash() {
|
||||
// Fast case: has hash code already been computed?
|
||||
uint32_t field = length_field();
|
||||
uint32_t field = hash_field();
|
||||
if (field & kHashComputedMask) return field >> kHashShift;
|
||||
// Slow case: compute hash code and set it.
|
||||
return ComputeAndSetHash();
|
||||
@ -2923,7 +2825,7 @@ StringHasher::StringHasher(int length)
|
||||
|
||||
|
||||
bool StringHasher::has_trivial_hash() {
|
||||
return length_ > String::kMaxMediumSize;
|
||||
return length_ > String::kMaxHashCalcLength;
|
||||
}
|
||||
|
||||
|
||||
@ -2979,7 +2881,7 @@ uint32_t StringHasher::GetHash() {
|
||||
|
||||
|
||||
bool String::AsArrayIndex(uint32_t* index) {
|
||||
uint32_t field = length_field();
|
||||
uint32_t field = hash_field();
|
||||
if ((field & kHashComputedMask) && !(field & kIsArrayIndexMask)) return false;
|
||||
return SlowAsArrayIndex(index);
|
||||
}
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "scanner.h"
|
||||
#include "scopeinfo.h"
|
||||
#include "string-stream.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
#include "disassembler.h"
|
||||
@ -754,19 +755,21 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
|
||||
ASSERT(size >= ExternalString::kSize);
|
||||
bool is_symbol = this->IsSymbol();
|
||||
int length = this->length();
|
||||
int hash_field = this->hash_field();
|
||||
|
||||
// Morph the object to an external string by adjusting the map and
|
||||
// reinitializing the fields.
|
||||
this->set_map(ExternalTwoByteString::StringMap(length));
|
||||
this->set_map(Heap::external_string_map());
|
||||
ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
|
||||
self->set_length(length);
|
||||
self->set_hash_field(hash_field);
|
||||
self->set_resource(resource);
|
||||
// Additionally make the object into an external symbol if the original string
|
||||
// was a symbol to start with.
|
||||
if (is_symbol) {
|
||||
self->Hash(); // Force regeneration of the hash value.
|
||||
// Now morph this external string into a external symbol.
|
||||
self->set_map(ExternalTwoByteString::SymbolMap(length));
|
||||
this->set_map(Heap::external_symbol_map());
|
||||
}
|
||||
|
||||
// Fill the remainder of the string with dead wood.
|
||||
@ -798,19 +801,21 @@ bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
|
||||
ASSERT(size >= ExternalString::kSize);
|
||||
bool is_symbol = this->IsSymbol();
|
||||
int length = this->length();
|
||||
int hash_field = this->hash_field();
|
||||
|
||||
// Morph the object to an external string by adjusting the map and
|
||||
// reinitializing the fields.
|
||||
this->set_map(ExternalAsciiString::StringMap(length));
|
||||
this->set_map(Heap::external_ascii_string_map());
|
||||
ExternalAsciiString* self = ExternalAsciiString::cast(this);
|
||||
self->set_length(length);
|
||||
self->set_hash_field(hash_field);
|
||||
self->set_resource(resource);
|
||||
// Additionally make the object into an external symbol if the original string
|
||||
// was a symbol to start with.
|
||||
if (is_symbol) {
|
||||
self->Hash(); // Force regeneration of the hash value.
|
||||
// Now morph this external string into a external symbol.
|
||||
self->set_map(ExternalAsciiString::SymbolMap(length));
|
||||
this->set_map(Heap::external_ascii_symbol_map());
|
||||
}
|
||||
|
||||
// Fill the remainder of the string with dead wood.
|
||||
@ -822,7 +827,7 @@ bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
|
||||
|
||||
void String::StringShortPrint(StringStream* accumulator) {
|
||||
int len = length();
|
||||
if (len > kMaxMediumSize) {
|
||||
if (len > kMaxShortPrintLength) {
|
||||
accumulator->Add("<Very long string[%u]>", len);
|
||||
return;
|
||||
}
|
||||
@ -4484,23 +4489,11 @@ bool String::MarkAsUndetectable() {
|
||||
if (StringShape(this).IsSymbol()) return false;
|
||||
|
||||
Map* map = this->map();
|
||||
if (map == Heap::short_string_map()) {
|
||||
this->set_map(Heap::undetectable_short_string_map());
|
||||
if (map == Heap::string_map()) {
|
||||
this->set_map(Heap::undetectable_string_map());
|
||||
return true;
|
||||
} else if (map == Heap::medium_string_map()) {
|
||||
this->set_map(Heap::undetectable_medium_string_map());
|
||||
return true;
|
||||
} else if (map == Heap::long_string_map()) {
|
||||
this->set_map(Heap::undetectable_long_string_map());
|
||||
return true;
|
||||
} else if (map == Heap::short_ascii_string_map()) {
|
||||
this->set_map(Heap::undetectable_short_ascii_string_map());
|
||||
return true;
|
||||
} else if (map == Heap::medium_ascii_string_map()) {
|
||||
this->set_map(Heap::undetectable_medium_ascii_string_map());
|
||||
return true;
|
||||
} else if (map == Heap::long_ascii_string_map()) {
|
||||
this->set_map(Heap::undetectable_long_ascii_string_map());
|
||||
} else if (map == Heap::ascii_string_map()) {
|
||||
this->set_map(Heap::undetectable_ascii_string_map());
|
||||
return true;
|
||||
}
|
||||
// Rest cannot be marked as undetectable
|
||||
@ -4523,17 +4516,17 @@ bool String::IsEqualTo(Vector<const char> str) {
|
||||
|
||||
uint32_t String::ComputeAndSetHash() {
|
||||
// Should only be called if hash code has not yet been computed.
|
||||
ASSERT(!(length_field() & kHashComputedMask));
|
||||
ASSERT(!(hash_field() & kHashComputedMask));
|
||||
|
||||
// Compute the hash code.
|
||||
StringInputBuffer buffer(this);
|
||||
uint32_t field = ComputeLengthAndHashField(&buffer, length());
|
||||
uint32_t field = ComputeHashField(&buffer, length());
|
||||
|
||||
// Store the hash code in the object.
|
||||
set_length_field(field);
|
||||
set_hash_field(field);
|
||||
|
||||
// Check the hash code is there.
|
||||
ASSERT(length_field() & kHashComputedMask);
|
||||
ASSERT(hash_field() & kHashComputedMask);
|
||||
uint32_t result = field >> kHashShift;
|
||||
ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
|
||||
return result;
|
||||
@ -4573,9 +4566,10 @@ bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
|
||||
bool String::SlowAsArrayIndex(uint32_t* index) {
|
||||
if (length() <= kMaxCachedArrayIndexLength) {
|
||||
Hash(); // force computation of hash code
|
||||
uint32_t field = length_field();
|
||||
uint32_t field = hash_field();
|
||||
if ((field & kIsArrayIndexMask) == 0) return false;
|
||||
*index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift;
|
||||
// Isolate the array index form the full hash field.
|
||||
*index = (kArrayIndexHashMask & field) >> kHashShift;
|
||||
return true;
|
||||
} else {
|
||||
StringInputBuffer buffer(this);
|
||||
@ -4584,37 +4578,42 @@ bool String::SlowAsArrayIndex(uint32_t* index) {
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t HashField(uint32_t hash, bool is_array_index) {
|
||||
static inline uint32_t HashField(uint32_t hash,
|
||||
bool is_array_index,
|
||||
int length = -1) {
|
||||
uint32_t result =
|
||||
(hash << String::kLongLengthShift) | String::kHashComputedMask;
|
||||
if (is_array_index) result |= String::kIsArrayIndexMask;
|
||||
(hash << String::kHashShift) | String::kHashComputedMask;
|
||||
if (is_array_index) {
|
||||
// For array indexes mix the length into the hash as an array index could
|
||||
// be zero.
|
||||
ASSERT(length > 0);
|
||||
ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
|
||||
(1 << String::kArrayIndexValueBits));
|
||||
result |= String::kIsArrayIndexMask;
|
||||
result |= length << String::kArrayIndexHashLengthShift;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
uint32_t StringHasher::GetHashField() {
|
||||
ASSERT(is_valid());
|
||||
if (length_ <= String::kMaxShortSize) {
|
||||
uint32_t payload;
|
||||
if (length_ <= String::kMaxHashCalcLength) {
|
||||
if (is_array_index()) {
|
||||
payload = v8::internal::HashField(array_index(), true);
|
||||
return v8::internal::HashField(array_index(), true, length_);
|
||||
} else {
|
||||
payload = v8::internal::HashField(GetHash(), false);
|
||||
return v8::internal::HashField(GetHash(), false);
|
||||
}
|
||||
return (payload & ((1 << String::kShortLengthShift) - 1)) |
|
||||
(length_ << String::kShortLengthShift);
|
||||
} else if (length_ <= String::kMaxMediumSize) {
|
||||
uint32_t payload = v8::internal::HashField(GetHash(), false);
|
||||
return (payload & ((1 << String::kMediumLengthShift) - 1)) |
|
||||
(length_ << String::kMediumLengthShift);
|
||||
return payload;
|
||||
} else {
|
||||
return v8::internal::HashField(length_, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t String::ComputeLengthAndHashField(unibrow::CharacterStream* buffer,
|
||||
int length) {
|
||||
uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
|
||||
int length) {
|
||||
StringHasher hasher(length);
|
||||
|
||||
// Very long strings have a trivial hash that doesn't inspect the
|
||||
@ -6177,6 +6176,7 @@ Object* JSObject::GetPropertyPostInterceptor(JSObject* receiver,
|
||||
return pt->GetPropertyWithReceiver(receiver, name, attributes);
|
||||
}
|
||||
|
||||
|
||||
Object* JSObject::GetLocalPropertyPostInterceptor(
|
||||
JSObject* receiver,
|
||||
String* name,
|
||||
@ -6737,19 +6737,19 @@ class RegExpKey : public HashTableKey {
|
||||
class Utf8SymbolKey : public HashTableKey {
|
||||
public:
|
||||
explicit Utf8SymbolKey(Vector<const char> string)
|
||||
: string_(string), length_field_(0) { }
|
||||
: string_(string), hash_field_(0) { }
|
||||
|
||||
bool IsMatch(Object* string) {
|
||||
return String::cast(string)->IsEqualTo(string_);
|
||||
}
|
||||
|
||||
uint32_t Hash() {
|
||||
if (length_field_ != 0) return length_field_ >> String::kHashShift;
|
||||
if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
|
||||
unibrow::Utf8InputBuffer<> buffer(string_.start(),
|
||||
static_cast<unsigned>(string_.length()));
|
||||
chars_ = buffer.Length();
|
||||
length_field_ = String::ComputeLengthAndHashField(&buffer, chars_);
|
||||
uint32_t result = length_field_ >> String::kHashShift;
|
||||
hash_field_ = String::ComputeHashField(&buffer, chars_);
|
||||
uint32_t result = hash_field_ >> String::kHashShift;
|
||||
ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
|
||||
return result;
|
||||
}
|
||||
@ -6759,12 +6759,12 @@ class Utf8SymbolKey : public HashTableKey {
|
||||
}
|
||||
|
||||
Object* AsObject() {
|
||||
if (length_field_ == 0) Hash();
|
||||
return Heap::AllocateSymbol(string_, chars_, length_field_);
|
||||
if (hash_field_ == 0) Hash();
|
||||
return Heap::AllocateSymbol(string_, chars_, hash_field_);
|
||||
}
|
||||
|
||||
Vector<const char> string_;
|
||||
uint32_t length_field_;
|
||||
uint32_t hash_field_;
|
||||
int chars_; // Caches the number of characters when computing the hash code.
|
||||
};
|
||||
|
||||
@ -6805,7 +6805,7 @@ class SymbolKey : public HashTableKey {
|
||||
StringInputBuffer buffer(string_);
|
||||
return Heap::AllocateInternalSymbol(&buffer,
|
||||
string_->length(),
|
||||
string_->length_field());
|
||||
string_->hash_field());
|
||||
}
|
||||
|
||||
static uint32_t StringHash(Object* obj) {
|
||||
|
479
src/objects.h
479
src/objects.h
@ -221,248 +221,128 @@ enum PropertyNormalizationMode {
|
||||
// NOTE: Everything following JS_VALUE_TYPE is considered a
|
||||
// JSObject for GC purposes. The first four entries here have typeof
|
||||
// 'object', whereas JS_FUNCTION_TYPE has typeof 'function'.
|
||||
#define INSTANCE_TYPE_LIST_ALL(V) \
|
||||
V(SHORT_SYMBOL_TYPE) \
|
||||
V(MEDIUM_SYMBOL_TYPE) \
|
||||
V(LONG_SYMBOL_TYPE) \
|
||||
V(SHORT_ASCII_SYMBOL_TYPE) \
|
||||
V(MEDIUM_ASCII_SYMBOL_TYPE) \
|
||||
V(LONG_ASCII_SYMBOL_TYPE) \
|
||||
V(SHORT_CONS_SYMBOL_TYPE) \
|
||||
V(MEDIUM_CONS_SYMBOL_TYPE) \
|
||||
V(LONG_CONS_SYMBOL_TYPE) \
|
||||
V(SHORT_CONS_ASCII_SYMBOL_TYPE) \
|
||||
V(MEDIUM_CONS_ASCII_SYMBOL_TYPE) \
|
||||
V(LONG_CONS_ASCII_SYMBOL_TYPE) \
|
||||
V(SHORT_EXTERNAL_SYMBOL_TYPE) \
|
||||
V(MEDIUM_EXTERNAL_SYMBOL_TYPE) \
|
||||
V(LONG_EXTERNAL_SYMBOL_TYPE) \
|
||||
V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE) \
|
||||
V(MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE) \
|
||||
V(LONG_EXTERNAL_ASCII_SYMBOL_TYPE) \
|
||||
V(SHORT_STRING_TYPE) \
|
||||
V(MEDIUM_STRING_TYPE) \
|
||||
V(LONG_STRING_TYPE) \
|
||||
V(SHORT_ASCII_STRING_TYPE) \
|
||||
V(MEDIUM_ASCII_STRING_TYPE) \
|
||||
V(LONG_ASCII_STRING_TYPE) \
|
||||
V(SHORT_CONS_STRING_TYPE) \
|
||||
V(MEDIUM_CONS_STRING_TYPE) \
|
||||
V(LONG_CONS_STRING_TYPE) \
|
||||
V(SHORT_CONS_ASCII_STRING_TYPE) \
|
||||
V(MEDIUM_CONS_ASCII_STRING_TYPE) \
|
||||
V(LONG_CONS_ASCII_STRING_TYPE) \
|
||||
V(SHORT_EXTERNAL_STRING_TYPE) \
|
||||
V(MEDIUM_EXTERNAL_STRING_TYPE) \
|
||||
V(LONG_EXTERNAL_STRING_TYPE) \
|
||||
V(SHORT_EXTERNAL_ASCII_STRING_TYPE) \
|
||||
V(MEDIUM_EXTERNAL_ASCII_STRING_TYPE) \
|
||||
V(LONG_EXTERNAL_ASCII_STRING_TYPE) \
|
||||
V(LONG_PRIVATE_EXTERNAL_ASCII_STRING_TYPE) \
|
||||
\
|
||||
V(MAP_TYPE) \
|
||||
V(HEAP_NUMBER_TYPE) \
|
||||
V(FIXED_ARRAY_TYPE) \
|
||||
V(CODE_TYPE) \
|
||||
V(JS_GLOBAL_PROPERTY_CELL_TYPE) \
|
||||
V(ODDBALL_TYPE) \
|
||||
V(PROXY_TYPE) \
|
||||
V(BYTE_ARRAY_TYPE) \
|
||||
V(PIXEL_ARRAY_TYPE) \
|
||||
/* Note: the order of these external array */ \
|
||||
/* types is relied upon in */ \
|
||||
/* Object::IsExternalArray(). */ \
|
||||
V(EXTERNAL_BYTE_ARRAY_TYPE) \
|
||||
V(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE) \
|
||||
V(EXTERNAL_SHORT_ARRAY_TYPE) \
|
||||
V(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE) \
|
||||
V(EXTERNAL_INT_ARRAY_TYPE) \
|
||||
V(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE) \
|
||||
V(EXTERNAL_FLOAT_ARRAY_TYPE) \
|
||||
V(FILLER_TYPE) \
|
||||
\
|
||||
V(ACCESSOR_INFO_TYPE) \
|
||||
V(ACCESS_CHECK_INFO_TYPE) \
|
||||
V(INTERCEPTOR_INFO_TYPE) \
|
||||
V(SHARED_FUNCTION_INFO_TYPE) \
|
||||
V(CALL_HANDLER_INFO_TYPE) \
|
||||
V(FUNCTION_TEMPLATE_INFO_TYPE) \
|
||||
V(OBJECT_TEMPLATE_INFO_TYPE) \
|
||||
V(SIGNATURE_INFO_TYPE) \
|
||||
V(TYPE_SWITCH_INFO_TYPE) \
|
||||
V(SCRIPT_TYPE) \
|
||||
\
|
||||
V(JS_VALUE_TYPE) \
|
||||
V(JS_OBJECT_TYPE) \
|
||||
V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \
|
||||
V(JS_GLOBAL_OBJECT_TYPE) \
|
||||
V(JS_BUILTINS_OBJECT_TYPE) \
|
||||
V(JS_GLOBAL_PROXY_TYPE) \
|
||||
V(JS_ARRAY_TYPE) \
|
||||
V(JS_REGEXP_TYPE) \
|
||||
\
|
||||
V(JS_FUNCTION_TYPE) \
|
||||
#define INSTANCE_TYPE_LIST_ALL(V) \
|
||||
V(SYMBOL_TYPE) \
|
||||
V(ASCII_SYMBOL_TYPE) \
|
||||
V(CONS_SYMBOL_TYPE) \
|
||||
V(CONS_ASCII_SYMBOL_TYPE) \
|
||||
V(EXTERNAL_SYMBOL_TYPE) \
|
||||
V(EXTERNAL_ASCII_SYMBOL_TYPE) \
|
||||
V(STRING_TYPE) \
|
||||
V(ASCII_STRING_TYPE) \
|
||||
V(CONS_STRING_TYPE) \
|
||||
V(CONS_ASCII_STRING_TYPE) \
|
||||
V(EXTERNAL_STRING_TYPE) \
|
||||
V(EXTERNAL_ASCII_STRING_TYPE) \
|
||||
V(PRIVATE_EXTERNAL_ASCII_STRING_TYPE) \
|
||||
\
|
||||
V(MAP_TYPE) \
|
||||
V(HEAP_NUMBER_TYPE) \
|
||||
V(FIXED_ARRAY_TYPE) \
|
||||
V(CODE_TYPE) \
|
||||
V(JS_GLOBAL_PROPERTY_CELL_TYPE) \
|
||||
V(ODDBALL_TYPE) \
|
||||
V(PROXY_TYPE) \
|
||||
V(BYTE_ARRAY_TYPE) \
|
||||
V(PIXEL_ARRAY_TYPE) \
|
||||
/* Note: the order of these external array */ \
|
||||
/* types is relied upon in */ \
|
||||
/* Object::IsExternalArray(). */ \
|
||||
V(EXTERNAL_BYTE_ARRAY_TYPE) \
|
||||
V(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE) \
|
||||
V(EXTERNAL_SHORT_ARRAY_TYPE) \
|
||||
V(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE) \
|
||||
V(EXTERNAL_INT_ARRAY_TYPE) \
|
||||
V(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE) \
|
||||
V(EXTERNAL_FLOAT_ARRAY_TYPE) \
|
||||
V(FILLER_TYPE) \
|
||||
\
|
||||
V(ACCESSOR_INFO_TYPE) \
|
||||
V(ACCESS_CHECK_INFO_TYPE) \
|
||||
V(INTERCEPTOR_INFO_TYPE) \
|
||||
V(SHARED_FUNCTION_INFO_TYPE) \
|
||||
V(CALL_HANDLER_INFO_TYPE) \
|
||||
V(FUNCTION_TEMPLATE_INFO_TYPE) \
|
||||
V(OBJECT_TEMPLATE_INFO_TYPE) \
|
||||
V(SIGNATURE_INFO_TYPE) \
|
||||
V(TYPE_SWITCH_INFO_TYPE) \
|
||||
V(SCRIPT_TYPE) \
|
||||
\
|
||||
V(JS_VALUE_TYPE) \
|
||||
V(JS_OBJECT_TYPE) \
|
||||
V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \
|
||||
V(JS_GLOBAL_OBJECT_TYPE) \
|
||||
V(JS_BUILTINS_OBJECT_TYPE) \
|
||||
V(JS_GLOBAL_PROXY_TYPE) \
|
||||
V(JS_ARRAY_TYPE) \
|
||||
V(JS_REGEXP_TYPE) \
|
||||
\
|
||||
V(JS_FUNCTION_TYPE) \
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
#define INSTANCE_TYPE_LIST_DEBUGGER(V) \
|
||||
V(DEBUG_INFO_TYPE) \
|
||||
#define INSTANCE_TYPE_LIST_DEBUGGER(V) \
|
||||
V(DEBUG_INFO_TYPE) \
|
||||
V(BREAK_POINT_INFO_TYPE)
|
||||
#else
|
||||
#define INSTANCE_TYPE_LIST_DEBUGGER(V)
|
||||
#endif
|
||||
|
||||
#define INSTANCE_TYPE_LIST(V) \
|
||||
INSTANCE_TYPE_LIST_ALL(V) \
|
||||
#define INSTANCE_TYPE_LIST(V) \
|
||||
INSTANCE_TYPE_LIST_ALL(V) \
|
||||
INSTANCE_TYPE_LIST_DEBUGGER(V)
|
||||
|
||||
|
||||
// Since string types are not consecutive, this macro is used to
|
||||
// iterate over them.
|
||||
#define STRING_TYPE_LIST(V) \
|
||||
V(SHORT_SYMBOL_TYPE, \
|
||||
V(SYMBOL_TYPE, \
|
||||
SeqTwoByteString::kAlignedSize, \
|
||||
short_symbol, \
|
||||
ShortSymbol) \
|
||||
V(MEDIUM_SYMBOL_TYPE, \
|
||||
symbol, \
|
||||
Symbol) \
|
||||
V(ASCII_SYMBOL_TYPE, \
|
||||
SeqAsciiString::kAlignedSize, \
|
||||
ascii_symbol, \
|
||||
AsciiSymbol) \
|
||||
V(CONS_SYMBOL_TYPE, \
|
||||
ConsString::kSize, \
|
||||
cons_symbol, \
|
||||
ConsSymbol) \
|
||||
V(CONS_ASCII_SYMBOL_TYPE, \
|
||||
ConsString::kSize, \
|
||||
cons_ascii_symbol, \
|
||||
ConsAsciiSymbol) \
|
||||
V(EXTERNAL_SYMBOL_TYPE, \
|
||||
ExternalTwoByteString::kSize, \
|
||||
external_symbol, \
|
||||
ExternalSymbol) \
|
||||
V(EXTERNAL_ASCII_SYMBOL_TYPE, \
|
||||
ExternalAsciiString::kSize, \
|
||||
external_ascii_symbol, \
|
||||
ExternalAsciiSymbol) \
|
||||
V(STRING_TYPE, \
|
||||
SeqTwoByteString::kAlignedSize, \
|
||||
medium_symbol, \
|
||||
MediumSymbol) \
|
||||
V(LONG_SYMBOL_TYPE, \
|
||||
SeqTwoByteString::kAlignedSize, \
|
||||
long_symbol, \
|
||||
LongSymbol) \
|
||||
V(SHORT_ASCII_SYMBOL_TYPE, \
|
||||
string, \
|
||||
String) \
|
||||
V(ASCII_STRING_TYPE, \
|
||||
SeqAsciiString::kAlignedSize, \
|
||||
short_ascii_symbol, \
|
||||
ShortAsciiSymbol) \
|
||||
V(MEDIUM_ASCII_SYMBOL_TYPE, \
|
||||
SeqAsciiString::kAlignedSize, \
|
||||
medium_ascii_symbol, \
|
||||
MediumAsciiSymbol) \
|
||||
V(LONG_ASCII_SYMBOL_TYPE, \
|
||||
SeqAsciiString::kAlignedSize, \
|
||||
long_ascii_symbol, \
|
||||
LongAsciiSymbol) \
|
||||
V(SHORT_CONS_SYMBOL_TYPE, \
|
||||
ascii_string, \
|
||||
AsciiString) \
|
||||
V(CONS_STRING_TYPE, \
|
||||
ConsString::kSize, \
|
||||
short_cons_symbol, \
|
||||
ShortConsSymbol) \
|
||||
V(MEDIUM_CONS_SYMBOL_TYPE, \
|
||||
cons_string, \
|
||||
ConsString) \
|
||||
V(CONS_ASCII_STRING_TYPE, \
|
||||
ConsString::kSize, \
|
||||
medium_cons_symbol, \
|
||||
MediumConsSymbol) \
|
||||
V(LONG_CONS_SYMBOL_TYPE, \
|
||||
ConsString::kSize, \
|
||||
long_cons_symbol, \
|
||||
LongConsSymbol) \
|
||||
V(SHORT_CONS_ASCII_SYMBOL_TYPE, \
|
||||
ConsString::kSize, \
|
||||
short_cons_ascii_symbol, \
|
||||
ShortConsAsciiSymbol) \
|
||||
V(MEDIUM_CONS_ASCII_SYMBOL_TYPE, \
|
||||
ConsString::kSize, \
|
||||
medium_cons_ascii_symbol, \
|
||||
MediumConsAsciiSymbol) \
|
||||
V(LONG_CONS_ASCII_SYMBOL_TYPE, \
|
||||
ConsString::kSize, \
|
||||
long_cons_ascii_symbol, \
|
||||
LongConsAsciiSymbol) \
|
||||
V(SHORT_EXTERNAL_SYMBOL_TYPE, \
|
||||
cons_ascii_string, \
|
||||
ConsAsciiString) \
|
||||
V(EXTERNAL_STRING_TYPE, \
|
||||
ExternalTwoByteString::kSize, \
|
||||
short_external_symbol, \
|
||||
ShortExternalSymbol) \
|
||||
V(MEDIUM_EXTERNAL_SYMBOL_TYPE, \
|
||||
ExternalTwoByteString::kSize, \
|
||||
medium_external_symbol, \
|
||||
MediumExternalSymbol) \
|
||||
V(LONG_EXTERNAL_SYMBOL_TYPE, \
|
||||
ExternalTwoByteString::kSize, \
|
||||
long_external_symbol, \
|
||||
LongExternalSymbol) \
|
||||
V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE, \
|
||||
external_string, \
|
||||
ExternalString) \
|
||||
V(EXTERNAL_ASCII_STRING_TYPE, \
|
||||
ExternalAsciiString::kSize, \
|
||||
short_external_ascii_symbol, \
|
||||
ShortExternalAsciiSymbol) \
|
||||
V(MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE, \
|
||||
ExternalAsciiString::kSize, \
|
||||
medium_external_ascii_symbol, \
|
||||
MediumExternalAsciiSymbol) \
|
||||
V(LONG_EXTERNAL_ASCII_SYMBOL_TYPE, \
|
||||
ExternalAsciiString::kSize, \
|
||||
long_external_ascii_symbol, \
|
||||
LongExternalAsciiSymbol) \
|
||||
V(SHORT_STRING_TYPE, \
|
||||
SeqTwoByteString::kAlignedSize, \
|
||||
short_string, \
|
||||
ShortString) \
|
||||
V(MEDIUM_STRING_TYPE, \
|
||||
SeqTwoByteString::kAlignedSize, \
|
||||
medium_string, \
|
||||
MediumString) \
|
||||
V(LONG_STRING_TYPE, \
|
||||
SeqTwoByteString::kAlignedSize, \
|
||||
long_string, \
|
||||
LongString) \
|
||||
V(SHORT_ASCII_STRING_TYPE, \
|
||||
SeqAsciiString::kAlignedSize, \
|
||||
short_ascii_string, \
|
||||
ShortAsciiString) \
|
||||
V(MEDIUM_ASCII_STRING_TYPE, \
|
||||
SeqAsciiString::kAlignedSize, \
|
||||
medium_ascii_string, \
|
||||
MediumAsciiString) \
|
||||
V(LONG_ASCII_STRING_TYPE, \
|
||||
SeqAsciiString::kAlignedSize, \
|
||||
long_ascii_string, \
|
||||
LongAsciiString) \
|
||||
V(SHORT_CONS_STRING_TYPE, \
|
||||
ConsString::kSize, \
|
||||
short_cons_string, \
|
||||
ShortConsString) \
|
||||
V(MEDIUM_CONS_STRING_TYPE, \
|
||||
ConsString::kSize, \
|
||||
medium_cons_string, \
|
||||
MediumConsString) \
|
||||
V(LONG_CONS_STRING_TYPE, \
|
||||
ConsString::kSize, \
|
||||
long_cons_string, \
|
||||
LongConsString) \
|
||||
V(SHORT_CONS_ASCII_STRING_TYPE, \
|
||||
ConsString::kSize, \
|
||||
short_cons_ascii_string, \
|
||||
ShortConsAsciiString) \
|
||||
V(MEDIUM_CONS_ASCII_STRING_TYPE, \
|
||||
ConsString::kSize, \
|
||||
medium_cons_ascii_string, \
|
||||
MediumConsAsciiString) \
|
||||
V(LONG_CONS_ASCII_STRING_TYPE, \
|
||||
ConsString::kSize, \
|
||||
long_cons_ascii_string, \
|
||||
LongConsAsciiString) \
|
||||
V(SHORT_EXTERNAL_STRING_TYPE, \
|
||||
ExternalTwoByteString::kSize, \
|
||||
short_external_string, \
|
||||
ShortExternalString) \
|
||||
V(MEDIUM_EXTERNAL_STRING_TYPE, \
|
||||
ExternalTwoByteString::kSize, \
|
||||
medium_external_string, \
|
||||
MediumExternalString) \
|
||||
V(LONG_EXTERNAL_STRING_TYPE, \
|
||||
ExternalTwoByteString::kSize, \
|
||||
long_external_string, \
|
||||
LongExternalString) \
|
||||
V(SHORT_EXTERNAL_ASCII_STRING_TYPE, \
|
||||
ExternalAsciiString::kSize, \
|
||||
short_external_ascii_string, \
|
||||
ShortExternalAsciiString) \
|
||||
V(MEDIUM_EXTERNAL_ASCII_STRING_TYPE, \
|
||||
ExternalAsciiString::kSize, \
|
||||
medium_external_ascii_string, \
|
||||
MediumExternalAsciiString) \
|
||||
V(LONG_EXTERNAL_ASCII_STRING_TYPE, \
|
||||
ExternalAsciiString::kSize, \
|
||||
long_external_ascii_string, \
|
||||
LongExternalAsciiString)
|
||||
external_ascii_string, \
|
||||
ExternalAsciiString) \
|
||||
|
||||
// A struct is a simple object a set of object-valued fields. Including an
|
||||
// object type in this causes the compiler to generate most of the boilerplate
|
||||
@ -473,27 +353,27 @@ enum PropertyNormalizationMode {
|
||||
// Note that for subtle reasons related to the ordering or numerical values of
|
||||
// type tags, elements in this list have to be added to the INSTANCE_TYPE_LIST
|
||||
// manually.
|
||||
#define STRUCT_LIST_ALL(V) \
|
||||
V(ACCESSOR_INFO, AccessorInfo, accessor_info) \
|
||||
V(ACCESS_CHECK_INFO, AccessCheckInfo, access_check_info) \
|
||||
V(INTERCEPTOR_INFO, InterceptorInfo, interceptor_info) \
|
||||
V(CALL_HANDLER_INFO, CallHandlerInfo, call_handler_info) \
|
||||
V(FUNCTION_TEMPLATE_INFO, FunctionTemplateInfo, function_template_info) \
|
||||
V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info) \
|
||||
V(SIGNATURE_INFO, SignatureInfo, signature_info) \
|
||||
V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info) \
|
||||
#define STRUCT_LIST_ALL(V) \
|
||||
V(ACCESSOR_INFO, AccessorInfo, accessor_info) \
|
||||
V(ACCESS_CHECK_INFO, AccessCheckInfo, access_check_info) \
|
||||
V(INTERCEPTOR_INFO, InterceptorInfo, interceptor_info) \
|
||||
V(CALL_HANDLER_INFO, CallHandlerInfo, call_handler_info) \
|
||||
V(FUNCTION_TEMPLATE_INFO, FunctionTemplateInfo, function_template_info) \
|
||||
V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info) \
|
||||
V(SIGNATURE_INFO, SignatureInfo, signature_info) \
|
||||
V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info) \
|
||||
V(SCRIPT, Script, script)
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
#define STRUCT_LIST_DEBUGGER(V) \
|
||||
V(DEBUG_INFO, DebugInfo, debug_info) \
|
||||
#define STRUCT_LIST_DEBUGGER(V) \
|
||||
V(DEBUG_INFO, DebugInfo, debug_info) \
|
||||
V(BREAK_POINT_INFO, BreakPointInfo, break_point_info)
|
||||
#else
|
||||
#define STRUCT_LIST_DEBUGGER(V)
|
||||
#endif
|
||||
|
||||
#define STRUCT_LIST(V) \
|
||||
STRUCT_LIST_ALL(V) \
|
||||
#define STRUCT_LIST(V) \
|
||||
STRUCT_LIST_ALL(V) \
|
||||
STRUCT_LIST_DEBUGGER(V)
|
||||
|
||||
// We use the full 8 bits of the instance_type field to encode heap object
|
||||
@ -509,15 +389,6 @@ const uint32_t kIsSymbolMask = 0x20;
|
||||
const uint32_t kNotSymbolTag = 0x0;
|
||||
const uint32_t kSymbolTag = 0x20;
|
||||
|
||||
// If bit 7 is clear, bits 3 and 4 are the string's size (short, medium or
|
||||
// long). These values are very special in that they are also used to shift
|
||||
// the length field to get the length, removing the hash value. This avoids
|
||||
// using if or switch when getting the length of a string.
|
||||
const uint32_t kStringSizeMask = 0x18;
|
||||
const uint32_t kShortStringTag = 0x18;
|
||||
const uint32_t kMediumStringTag = 0x10;
|
||||
const uint32_t kLongStringTag = 0x00;
|
||||
|
||||
// If bit 7 is clear then bit 2 indicates whether the string consists of
|
||||
// two-byte characters or one-byte characters.
|
||||
const uint32_t kStringEncodingMask = 0x4;
|
||||
@ -547,60 +418,20 @@ const uint32_t kShortcutTypeTag = kConsStringTag;
|
||||
|
||||
|
||||
enum InstanceType {
|
||||
SHORT_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSeqStringTag,
|
||||
MEDIUM_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSeqStringTag,
|
||||
LONG_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kSeqStringTag,
|
||||
SHORT_ASCII_SYMBOL_TYPE =
|
||||
kShortStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
|
||||
MEDIUM_ASCII_SYMBOL_TYPE =
|
||||
kMediumStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
|
||||
LONG_ASCII_SYMBOL_TYPE =
|
||||
kLongStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
|
||||
SHORT_CONS_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kConsStringTag,
|
||||
MEDIUM_CONS_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kConsStringTag,
|
||||
LONG_CONS_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kConsStringTag,
|
||||
SHORT_CONS_ASCII_SYMBOL_TYPE =
|
||||
kShortStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
|
||||
MEDIUM_CONS_ASCII_SYMBOL_TYPE =
|
||||
kMediumStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
|
||||
LONG_CONS_ASCII_SYMBOL_TYPE =
|
||||
kLongStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
|
||||
SHORT_EXTERNAL_SYMBOL_TYPE =
|
||||
kShortStringTag | kSymbolTag | kExternalStringTag,
|
||||
MEDIUM_EXTERNAL_SYMBOL_TYPE =
|
||||
kMediumStringTag | kSymbolTag | kExternalStringTag,
|
||||
LONG_EXTERNAL_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kExternalStringTag,
|
||||
SHORT_EXTERNAL_ASCII_SYMBOL_TYPE =
|
||||
kShortStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
|
||||
MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE =
|
||||
kMediumStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
|
||||
LONG_EXTERNAL_ASCII_SYMBOL_TYPE =
|
||||
kLongStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
|
||||
SHORT_STRING_TYPE = kShortStringTag | kSeqStringTag,
|
||||
MEDIUM_STRING_TYPE = kMediumStringTag | kSeqStringTag,
|
||||
LONG_STRING_TYPE = kLongStringTag | kSeqStringTag,
|
||||
SHORT_ASCII_STRING_TYPE = kShortStringTag | kAsciiStringTag | kSeqStringTag,
|
||||
MEDIUM_ASCII_STRING_TYPE = kMediumStringTag | kAsciiStringTag | kSeqStringTag,
|
||||
LONG_ASCII_STRING_TYPE = kLongStringTag | kAsciiStringTag | kSeqStringTag,
|
||||
SHORT_CONS_STRING_TYPE = kShortStringTag | kConsStringTag,
|
||||
MEDIUM_CONS_STRING_TYPE = kMediumStringTag | kConsStringTag,
|
||||
LONG_CONS_STRING_TYPE = kLongStringTag | kConsStringTag,
|
||||
SHORT_CONS_ASCII_STRING_TYPE =
|
||||
kShortStringTag | kAsciiStringTag | kConsStringTag,
|
||||
MEDIUM_CONS_ASCII_STRING_TYPE =
|
||||
kMediumStringTag | kAsciiStringTag | kConsStringTag,
|
||||
LONG_CONS_ASCII_STRING_TYPE =
|
||||
kLongStringTag | kAsciiStringTag | kConsStringTag,
|
||||
SHORT_EXTERNAL_STRING_TYPE = kShortStringTag | kExternalStringTag,
|
||||
MEDIUM_EXTERNAL_STRING_TYPE = kMediumStringTag | kExternalStringTag,
|
||||
LONG_EXTERNAL_STRING_TYPE = kLongStringTag | kExternalStringTag,
|
||||
SHORT_EXTERNAL_ASCII_STRING_TYPE =
|
||||
kShortStringTag | kAsciiStringTag | kExternalStringTag,
|
||||
MEDIUM_EXTERNAL_ASCII_STRING_TYPE =
|
||||
kMediumStringTag | kAsciiStringTag | kExternalStringTag,
|
||||
LONG_EXTERNAL_ASCII_STRING_TYPE =
|
||||
kLongStringTag | kAsciiStringTag | kExternalStringTag,
|
||||
LONG_PRIVATE_EXTERNAL_ASCII_STRING_TYPE = LONG_EXTERNAL_ASCII_STRING_TYPE,
|
||||
SYMBOL_TYPE = kSymbolTag | kSeqStringTag,
|
||||
ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kSeqStringTag,
|
||||
CONS_SYMBOL_TYPE = kSymbolTag | kConsStringTag,
|
||||
CONS_ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kConsStringTag,
|
||||
EXTERNAL_SYMBOL_TYPE = kSymbolTag | kExternalStringTag,
|
||||
EXTERNAL_ASCII_SYMBOL_TYPE =
|
||||
kAsciiStringTag | kSymbolTag | kExternalStringTag,
|
||||
STRING_TYPE = kSeqStringTag,
|
||||
ASCII_STRING_TYPE = kAsciiStringTag | kSeqStringTag,
|
||||
CONS_STRING_TYPE = kConsStringTag,
|
||||
CONS_ASCII_STRING_TYPE = kAsciiStringTag | kConsStringTag,
|
||||
EXTERNAL_STRING_TYPE = kExternalStringTag,
|
||||
EXTERNAL_ASCII_STRING_TYPE = kAsciiStringTag | kExternalStringTag,
|
||||
PRIVATE_EXTERNAL_ASCII_STRING_TYPE = EXTERNAL_ASCII_STRING_TYPE,
|
||||
|
||||
MAP_TYPE = kNotStringTag,
|
||||
HEAP_NUMBER_TYPE,
|
||||
@ -3910,12 +3741,9 @@ class String: public HeapObject {
|
||||
inline int length();
|
||||
inline void set_length(int value);
|
||||
|
||||
// Get and set the uninterpreted length field of the string. Notice
|
||||
// that the length field is also used to cache the hash value of
|
||||
// strings. In order to get or set the actual length of the string
|
||||
// use the length() and set_length methods.
|
||||
inline uint32_t length_field();
|
||||
inline void set_length_field(uint32_t value);
|
||||
// Get and set the hash field of the string.
|
||||
inline uint32_t hash_field();
|
||||
inline void set_hash_field(uint32_t value);
|
||||
|
||||
inline bool IsAsciiRepresentation();
|
||||
inline bool IsTwoByteRepresentation();
|
||||
@ -3986,8 +3814,8 @@ class String: public HeapObject {
|
||||
// Returns a hash value used for the property table
|
||||
inline uint32_t Hash();
|
||||
|
||||
static uint32_t ComputeLengthAndHashField(unibrow::CharacterStream* buffer,
|
||||
int length);
|
||||
static uint32_t ComputeHashField(unibrow::CharacterStream* buffer,
|
||||
int length);
|
||||
|
||||
static bool ComputeArrayIndex(unibrow::CharacterStream* buffer,
|
||||
uint32_t* index,
|
||||
@ -4018,7 +3846,8 @@ class String: public HeapObject {
|
||||
|
||||
// Layout description.
|
||||
static const int kLengthOffset = HeapObject::kHeaderSize;
|
||||
static const int kSize = kLengthOffset + kIntSize;
|
||||
static const int kHashFieldOffset = kLengthOffset + kIntSize;
|
||||
static const int kSize = kHashFieldOffset + kIntSize;
|
||||
// Notice: kSize is not pointer-size aligned if pointers are 64-bit.
|
||||
|
||||
// Maximum number of characters to consider when trying to convert a string
|
||||
@ -4042,22 +3871,30 @@ class String: public HeapObject {
|
||||
static const int kIsArrayIndexMask = 1 << 1;
|
||||
static const int kNofLengthBitFields = 2;
|
||||
|
||||
// Shift constant retrieving hash code from hash field.
|
||||
static const int kHashShift = kNofLengthBitFields;
|
||||
|
||||
// Array index strings this short can keep their index in the hash
|
||||
// field.
|
||||
static const int kMaxCachedArrayIndexLength = 7;
|
||||
|
||||
// Shift constants for retrieving length and hash code from
|
||||
// length/hash field.
|
||||
static const int kHashShift = kNofLengthBitFields;
|
||||
static const int kShortLengthShift = kHashShift + kShortStringTag;
|
||||
static const int kMediumLengthShift = kHashShift + kMediumStringTag;
|
||||
static const int kLongLengthShift = kHashShift + kLongStringTag;
|
||||
// For strings which are array indexes the hash value has the string length
|
||||
// mixed into the hash, mainly to avoid a hash value of zero which would be
|
||||
// the case for the string '0'. 24 bits are used for the array index value.
|
||||
static const int kArrayIndexHashLengthShift = 24 + kNofLengthBitFields;
|
||||
static const int kArrayIndexHashMask = (1 << kArrayIndexHashLengthShift) - 1;
|
||||
static const int kArrayIndexValueBits =
|
||||
kArrayIndexHashLengthShift - kHashShift;
|
||||
|
||||
// Maximal string length that can be stored in the hash/length field for
|
||||
// different types of strings.
|
||||
static const int kMaxShortSize = (1 << (32 - kShortLengthShift)) - 1;
|
||||
static const int kMaxMediumSize = (1 << (32 - kMediumLengthShift)) - 1;
|
||||
static const int kMaxLength = (1 << (32 - kLongLengthShift)) - 1;
|
||||
// Value of empty hash field indicating that the hash is not computed.
|
||||
static const int kEmptyHashField = 0;
|
||||
|
||||
// Maximal string length.
|
||||
static const int kMaxLength = (1 << (32 - 2)) - 1;
|
||||
|
||||
// Max length for computing hash. For strings longer than this limit the
|
||||
// string length is used as the hash value.
|
||||
static const int kMaxHashCalcLength = 16383;
|
||||
|
||||
// Limit for truncation in short printing.
|
||||
static const int kMaxShortPrintLength = 1024;
|
||||
@ -4339,9 +4176,6 @@ class ExternalAsciiString: public ExternalString {
|
||||
unsigned* offset,
|
||||
unsigned chars);
|
||||
|
||||
// Identify the map for the external string/symbol with a particular length.
|
||||
static inline Map* StringMap(int length);
|
||||
static inline Map* SymbolMap(int length);
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalAsciiString);
|
||||
};
|
||||
@ -4374,9 +4208,6 @@ class ExternalTwoByteString: public ExternalString {
|
||||
unsigned* offset_ptr,
|
||||
unsigned chars);
|
||||
|
||||
// Identify the map for the external string/symbol with a particular length.
|
||||
static inline Map* StringMap(int length);
|
||||
static inline Map* SymbolMap(int length);
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalTwoByteString);
|
||||
};
|
||||
|
@ -3762,6 +3762,7 @@ static Object* Runtime_StringAdd(Arguments args) {
|
||||
ASSERT(args.length() == 2);
|
||||
CONVERT_CHECKED(String, str1, args[0]);
|
||||
CONVERT_CHECKED(String, str2, args[1]);
|
||||
Counters::cons_strings_runtime.Increment();
|
||||
return Heap::AllocateConsString(str1, str2);
|
||||
}
|
||||
|
||||
@ -4987,6 +4988,9 @@ static Object* Runtime_DebugPrint(Arguments args) {
|
||||
PrintF("DebugPrint: ");
|
||||
}
|
||||
args[0]->Print();
|
||||
if (args[0]->IsHeapObject()) {
|
||||
HeapObject::cast(args[0])->map()->Print();
|
||||
}
|
||||
#else
|
||||
// ShortPrint is available in release mode. Print is not.
|
||||
args[0]->ShortPrint();
|
||||
|
@ -188,7 +188,7 @@ void StringStream::Add(Vector<const char> format, Vector<FmtElm> elms) {
|
||||
void StringStream::PrintObject(Object* o) {
|
||||
o->ShortPrint(this);
|
||||
if (o->IsString()) {
|
||||
if (String::cast(o)->length() <= String::kMaxMediumSize) {
|
||||
if (String::cast(o)->length() <= String::kMaxShortPrintLength) {
|
||||
return;
|
||||
}
|
||||
} else if (o->IsNumber() || o->IsOddball()) {
|
||||
|
@ -226,9 +226,9 @@ class StubCache : public AllStatic {
|
||||
// hash code would effectively throw away two bits of the hash
|
||||
// code.
|
||||
ASSERT(kHeapObjectTagSize == String::kHashShift);
|
||||
// Compute the hash of the name (use entire length field).
|
||||
// Compute the hash of the name (use entire hash field).
|
||||
ASSERT(name->HasHashCode());
|
||||
uint32_t field = name->length_field();
|
||||
uint32_t field = name->hash_field();
|
||||
// Using only the low bits in 64-bit mode is unlikely to increase the
|
||||
// risk of collision even if the heap is spread over an area larger than
|
||||
// 4Gb (and not at all if it isn't).
|
||||
|
@ -309,4 +309,13 @@ char* StringBuilder::Finalize() {
|
||||
return buffer_.start();
|
||||
}
|
||||
|
||||
|
||||
int TenToThe(int exponent) {
|
||||
ASSERT(exponent <= 9);
|
||||
ASSERT(exponent >= 1);
|
||||
int answer = 10;
|
||||
for (int i = 1; i < exponent; i++) answer *= 10;
|
||||
return answer;
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -584,6 +584,9 @@ static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
|
||||
}
|
||||
|
||||
|
||||
// Calculate 10^exponent.
|
||||
int TenToThe(int exponent);
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_UTILS_H_
|
||||
|
@ -3767,20 +3767,8 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
|
||||
__ testb(rcx, Immediate(kIsNotStringMask));
|
||||
__ j(not_zero, &slow_case);
|
||||
|
||||
// Here we make assumptions about the tag values and the shifts needed.
|
||||
// See the comment in objects.h.
|
||||
ASSERT(kLongStringTag == 0);
|
||||
ASSERT(kMediumStringTag + String::kLongLengthShift ==
|
||||
String::kMediumLengthShift);
|
||||
ASSERT(kShortStringTag + String::kLongLengthShift ==
|
||||
String::kShortLengthShift);
|
||||
__ and_(rcx, Immediate(kStringSizeMask));
|
||||
__ addq(rcx, Immediate(String::kLongLengthShift));
|
||||
// Fetch the length field into the temporary register.
|
||||
__ movl(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset));
|
||||
__ shrl_cl(temp.reg());
|
||||
// Check for index out of range.
|
||||
__ cmpl(index.reg(), temp.reg());
|
||||
__ cmpl(index.reg(), FieldOperand(object.reg(), String::kLengthOffset));
|
||||
__ j(greater_equal, &slow_case);
|
||||
// Reload the instance type (into the temp register this time)..
|
||||
__ movq(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset));
|
||||
@ -6175,11 +6163,8 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
|
||||
// String value => false iff empty.
|
||||
__ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE));
|
||||
__ j(above_equal, ¬_string);
|
||||
__ and_(rcx, Immediate(kStringSizeMask));
|
||||
__ cmpq(rcx, Immediate(kShortStringTag));
|
||||
__ j(not_equal, &true_result); // Empty string is always short.
|
||||
__ movl(rdx, FieldOperand(rax, String::kLengthOffset));
|
||||
__ shr(rdx, Immediate(String::kShortLengthShift));
|
||||
__ testl(rdx, rdx);
|
||||
__ j(zero, &false_result);
|
||||
__ jmp(&true_result);
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "ic-inl.h"
|
||||
#include "runtime.h"
|
||||
#include "stub-cache.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -107,7 +108,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
for (int i = 0; i < kProbes; i++) {
|
||||
// Compute the masked index: (hash + i + i * i) & mask.
|
||||
__ movl(r1, FieldOperand(name, String::kLengthOffset));
|
||||
__ movl(r1, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ shrl(r1, Immediate(String::kHashShift));
|
||||
if (i > 0) {
|
||||
__ addl(r1, Immediate(StringDictionary::GetProbeOffset(i)));
|
||||
@ -239,18 +240,6 @@ void KeyedLoadIC::Generate(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
// For use in assert below.
|
||||
static int TenToThe(int exponent) {
|
||||
ASSERT(exponent <= 9);
|
||||
ASSERT(exponent >= 1);
|
||||
int answer = 10;
|
||||
for (int i = 1; i < exponent; i++) answer *= 10;
|
||||
return answer;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rsp[0] : return address
|
||||
@ -327,7 +316,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
|
||||
__ j(above_equal, &slow);
|
||||
// Is the string an array index, with cached numeric value?
|
||||
__ movl(rbx, FieldOperand(rax, String::kLengthOffset));
|
||||
__ movl(rbx, FieldOperand(rax, String::kHashFieldOffset));
|
||||
__ testl(rbx, Immediate(String::kIsArrayIndexMask));
|
||||
|
||||
// If the string is a symbol, do a quick inline probe of the receiver's
|
||||
@ -342,20 +331,16 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ movq(rax, rcx);
|
||||
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
|
||||
__ ret(0);
|
||||
// Array index string: If short enough use cache in length/hash field (rbx).
|
||||
// We assert that there are enough bits in an int32_t after the hash shift
|
||||
// bits have been subtracted to allow space for the length and the cached
|
||||
// array index.
|
||||
// If the hash field contains an array index pick it out. The assert checks
|
||||
// that the constants for the maximum number of digits for an array index
|
||||
// cached in the hash field and the number of bits reserved for it does not
|
||||
// conflict.
|
||||
ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
|
||||
(1 << (String::kShortLengthShift - String::kHashShift)));
|
||||
(1 << String::kArrayIndexValueBits));
|
||||
__ bind(&index_string);
|
||||
const int kLengthFieldLimit =
|
||||
(String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
|
||||
__ cmpl(rbx, Immediate(kLengthFieldLimit));
|
||||
__ j(above_equal, &slow);
|
||||
__ movl(rax, rbx);
|
||||
__ and_(rax, Immediate((1 << String::kShortLengthShift) - 1));
|
||||
__ shrl(rax, Immediate(String::kLongLengthShift));
|
||||
__ and_(rax, Immediate(String::kArrayIndexHashMask));
|
||||
__ shrl(rax, Immediate(String::kHashShift));
|
||||
__ jmp(&index_int);
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
__ JumpIfSmi(receiver, &miss);
|
||||
|
||||
// Get the map of the receiver and compute the hash.
|
||||
__ movl(scratch, FieldOperand(name, String::kLengthOffset));
|
||||
__ movl(scratch, FieldOperand(name, String::kHashFieldOffset));
|
||||
// Use only the low 32 bits of the map pointer.
|
||||
__ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ xor_(scratch, Immediate(flags));
|
||||
@ -183,7 +183,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
ProbeTable(masm, flags, kPrimary, name, scratch);
|
||||
|
||||
// Primary miss: Compute hash for secondary probe.
|
||||
__ movl(scratch, FieldOperand(name, String::kLengthOffset));
|
||||
__ movl(scratch, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ xor_(scratch, Immediate(flags));
|
||||
__ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
|
||||
@ -323,11 +323,7 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
|
||||
|
||||
// Load length directly from the string.
|
||||
__ bind(&load_length);
|
||||
__ and_(scratch, Immediate(kStringSizeMask));
|
||||
__ movl(rax, FieldOperand(receiver, String::kLengthOffset));
|
||||
// rcx is also the receiver.
|
||||
__ lea(rcx, Operand(scratch, String::kLongLengthShift));
|
||||
__ shr_cl(rax);
|
||||
__ Integer32ToSmi(rax, rax);
|
||||
__ ret(0);
|
||||
|
||||
|
@ -65,9 +65,9 @@ static Object* AllocateAfterFailures() {
|
||||
|
||||
// Old data space.
|
||||
OldSpace* old_data_space = Heap::old_data_space();
|
||||
static const int kOldDataSpaceFillerSize = SeqAsciiString::SizeFor(0);
|
||||
static const int kOldDataSpaceFillerSize = ByteArray::SizeFor(0);
|
||||
while (old_data_space->Available() > kOldDataSpaceFillerSize) {
|
||||
CHECK(!Heap::AllocateRawAsciiString(0, TENURED)->IsFailure());
|
||||
CHECK(!Heap::Heap::AllocateByteArray(0, TENURED)->IsFailure());
|
||||
}
|
||||
CHECK(!Heap::AllocateRawAsciiString(100, TENURED)->IsFailure());
|
||||
|
||||
|
@ -7029,27 +7029,17 @@ static void MorphAString(i::String* string,
|
||||
CHECK(i::StringShape(string).IsExternal());
|
||||
if (string->IsAsciiRepresentation()) {
|
||||
// Check old map is not symbol or long.
|
||||
CHECK(string->map() == i::Heap::short_external_ascii_string_map() ||
|
||||
string->map() == i::Heap::medium_external_ascii_string_map());
|
||||
CHECK(string->map() == i::Heap::external_ascii_string_map());
|
||||
// Morph external string to be TwoByte string.
|
||||
if (string->length() <= i::String::kMaxShortSize) {
|
||||
string->set_map(i::Heap::short_external_string_map());
|
||||
} else {
|
||||
string->set_map(i::Heap::medium_external_string_map());
|
||||
}
|
||||
string->set_map(i::Heap::external_string_map());
|
||||
i::ExternalTwoByteString* morphed =
|
||||
i::ExternalTwoByteString::cast(string);
|
||||
morphed->set_resource(uc16_resource);
|
||||
} else {
|
||||
// Check old map is not symbol or long.
|
||||
CHECK(string->map() == i::Heap::short_external_string_map() ||
|
||||
string->map() == i::Heap::medium_external_string_map());
|
||||
CHECK(string->map() == i::Heap::external_string_map());
|
||||
// Morph external string to be ASCII string.
|
||||
if (string->length() <= i::String::kMaxShortSize) {
|
||||
string->set_map(i::Heap::short_external_ascii_string_map());
|
||||
} else {
|
||||
string->set_map(i::Heap::medium_external_ascii_string_map());
|
||||
}
|
||||
string->set_map(i::Heap::external_ascii_string_map());
|
||||
i::ExternalAsciiString* morphed =
|
||||
i::ExternalAsciiString::cast(string);
|
||||
morphed->set_resource(ascii_resource);
|
||||
|
@ -37,8 +37,7 @@ TEST(HeapMaps) {
|
||||
CheckMap(Heap::meta_map(), MAP_TYPE, Map::kSize);
|
||||
CheckMap(Heap::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
|
||||
CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, FixedArray::kHeaderSize);
|
||||
CheckMap(Heap::long_string_map(), LONG_STRING_TYPE,
|
||||
SeqTwoByteString::kAlignedSize);
|
||||
CheckMap(Heap::string_map(), STRING_TYPE, SeqTwoByteString::kAlignedSize);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user