Using array index hash code for string-to-number conversion.
Review URL: http://codereview.chromium.org/3141022 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5362 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
7b89a5f2b8
commit
71548e969b
@ -5636,6 +5636,27 @@ void CodeGenerator::GenerateIsRegExpEquivalent(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateHasCachedArrayIndex(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
Load(args->at(0));
|
||||
Register value = frame_->PopToRegister();
|
||||
Register tmp = frame_->scratch0();
|
||||
__ ldr(tmp, FieldMemOperand(value, String::kHashFieldOffset));
|
||||
__ tst(tmp, Operand(String::kContainsCachedArrayIndexMask));
|
||||
cc_reg_ = eq;
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateGetCachedArrayIndex(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
Load(args->at(0));
|
||||
Register value = frame_->PopToRegister();
|
||||
|
||||
__ ldr(value, FieldMemOperand(value, String::kHashFieldOffset));
|
||||
__ IndexFromHash(value, value);
|
||||
frame_->EmitPush(value);
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
|
||||
#ifdef DEBUG
|
||||
|
@ -550,6 +550,9 @@ class CodeGenerator: public AstVisitor {
|
||||
|
||||
void GenerateIsRegExpEquivalent(ZoneList<Expression*>* args);
|
||||
|
||||
void GenerateHasCachedArrayIndex(ZoneList<Expression*>* args);
|
||||
void GenerateGetCachedArrayIndex(ZoneList<Expression*>* args);
|
||||
|
||||
// Simple condition analysis.
|
||||
enum ConditionAnalysis {
|
||||
ALWAYS_TRUE,
|
||||
|
@ -2539,6 +2539,35 @@ void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
|
||||
VisitForValue(args->at(0), kAccumulator);
|
||||
|
||||
Label materialize_true, materialize_false;
|
||||
Label* if_true = NULL;
|
||||
Label* if_false = NULL;
|
||||
Label* fall_through = NULL;
|
||||
PrepareTest(&materialize_true, &materialize_false,
|
||||
&if_true, &if_false, &fall_through);
|
||||
|
||||
__ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
|
||||
__ tst(r0, Operand(String::kContainsCachedArrayIndexMask));
|
||||
|
||||
__ b(eq, if_true);
|
||||
__ b(if_false);
|
||||
|
||||
Apply(context_, if_true, if_false);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
VisitForValue(args->at(0), kAccumulator);
|
||||
__ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
|
||||
__ IndexFromHash(r0, r0);
|
||||
Apply(context_, r0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
||||
Handle<String> name = expr->name();
|
||||
if (name->length() > 0 && name->Get(0) == '_') {
|
||||
|
@ -527,32 +527,6 @@ static void GenerateKeyStringCheck(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Picks out an array index from the hash field.
|
||||
static void GenerateIndexFromHash(MacroAssembler* masm,
|
||||
Register key,
|
||||
Register hash) {
|
||||
// Register use:
|
||||
// key - holds the overwritten key on exit.
|
||||
// hash - holds the key's hash. Clobbered.
|
||||
|
||||
// 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::kArrayIndexValueBits));
|
||||
// We want the smi-tagged index in key. kArrayIndexValueMask has zeros in
|
||||
// the low kHashShift bits.
|
||||
ASSERT(String::kHashShift >= kSmiTagSize);
|
||||
// Here we actually clobber the key which will be used if calling into
|
||||
// runtime later. However as the new key is the numeric value of a string key
|
||||
// there is no difference in using either key.
|
||||
ASSERT(String::kHashShift >= kSmiTagSize);
|
||||
__ Ubfx(hash, hash, String::kHashShift, String::kArrayIndexValueBits);
|
||||
__ mov(key, Operand(hash, LSL, kSmiTagSize));
|
||||
}
|
||||
|
||||
|
||||
// Defined in ic.cc.
|
||||
Object* CallIC_Miss(Arguments args);
|
||||
|
||||
@ -852,7 +826,7 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
GenerateMiss(masm, argc);
|
||||
|
||||
__ bind(&index_string);
|
||||
GenerateIndexFromHash(masm, r2, r3);
|
||||
__ IndexFromHash(r3, r2);
|
||||
// Now jump to the place where smi keys are handled.
|
||||
__ jmp(&index_smi);
|
||||
}
|
||||
@ -1249,7 +1223,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ Ret();
|
||||
|
||||
__ bind(&index_string);
|
||||
GenerateIndexFromHash(masm, key, r3);
|
||||
__ IndexFromHash(r3, key);
|
||||
// Now jump to the place where smi keys are handled.
|
||||
__ jmp(&index_smi);
|
||||
}
|
||||
|
@ -1257,6 +1257,21 @@ void MacroAssembler::IllegalOperation(int num_arguments) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IndexFromHash(Register hash, Register 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::kArrayIndexValueBits));
|
||||
// We want the smi-tagged index in key. kArrayIndexValueMask has zeros in
|
||||
// the low kHashShift bits.
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
Ubfx(hash, hash, String::kHashShift, String::kArrayIndexValueBits);
|
||||
mov(index, Operand(hash, LSL, kSmiTagSize));
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IntegerToDoubleConversionWithVFP3(Register inReg,
|
||||
Register outHighReg,
|
||||
Register outLowReg) {
|
||||
|
@ -469,6 +469,12 @@ class MacroAssembler: public Assembler {
|
||||
// occurred.
|
||||
void IllegalOperation(int num_arguments);
|
||||
|
||||
// Picks out an array index from the hash field.
|
||||
// Register use:
|
||||
// hash - holds the index's hash. Clobbered.
|
||||
// index - holds the overwritten index on exit.
|
||||
void IndexFromHash(Register hash, Register index);
|
||||
|
||||
// Get the number of least significant bits from a register
|
||||
void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
|
||||
|
||||
|
@ -116,7 +116,9 @@ enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION };
|
||||
F(MathSin, 1, 1) \
|
||||
F(MathCos, 1, 1) \
|
||||
F(MathSqrt, 1, 1) \
|
||||
F(IsRegExpEquivalent, 2, 1)
|
||||
F(IsRegExpEquivalent, 2, 1) \
|
||||
F(HasCachedArrayIndex, 1, 1) \
|
||||
F(GetCachedArrayIndex, 1, 1)
|
||||
|
||||
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
|
@ -7918,6 +7918,42 @@ void CodeGenerator::GenerateIsRegExpEquivalent(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateHasCachedArrayIndex(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
Load(args->at(0));
|
||||
Result value = frame_->Pop();
|
||||
value.ToRegister();
|
||||
ASSERT(value.is_valid());
|
||||
if (FLAG_debug_code) {
|
||||
__ AbortIfNotString(value.reg());
|
||||
}
|
||||
|
||||
__ test(FieldOperand(value.reg(), String::kHashFieldOffset),
|
||||
Immediate(String::kContainsCachedArrayIndexMask));
|
||||
|
||||
value.Unuse();
|
||||
destination()->Split(zero);
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateGetCachedArrayIndex(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
Load(args->at(0));
|
||||
Result string = frame_->Pop();
|
||||
string.ToRegister();
|
||||
if (FLAG_debug_code) {
|
||||
__ AbortIfNotString(string.reg());
|
||||
}
|
||||
|
||||
Result number = allocator()->Allocate();
|
||||
ASSERT(number.is_valid());
|
||||
__ mov(number.reg(), FieldOperand(string.reg(), String::kHashFieldOffset));
|
||||
__ IndexFromHash(number.reg(), number.reg());
|
||||
string.Unuse();
|
||||
frame_->Push(&number);
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
|
||||
ASSERT(!in_safe_int32_mode());
|
||||
if (CheckForInlineRuntimeCall(node)) {
|
||||
|
@ -730,6 +730,9 @@ class CodeGenerator: public AstVisitor {
|
||||
// Check whether two RegExps are equivalent
|
||||
void GenerateIsRegExpEquivalent(ZoneList<Expression*>* args);
|
||||
|
||||
void GenerateHasCachedArrayIndex(ZoneList<Expression*>* args);
|
||||
void GenerateGetCachedArrayIndex(ZoneList<Expression*>* args);
|
||||
|
||||
// Simple condition analysis.
|
||||
enum ConditionAnalysis {
|
||||
ALWAYS_TRUE,
|
||||
|
@ -2848,6 +2848,46 @@ void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
|
||||
VisitForValue(args->at(0), kAccumulator);
|
||||
|
||||
if (FLAG_debug_code) {
|
||||
__ AbortIfNotString(eax);
|
||||
}
|
||||
|
||||
Label materialize_true, materialize_false;
|
||||
Label* if_true = NULL;
|
||||
Label* if_false = NULL;
|
||||
Label* fall_through = NULL;
|
||||
PrepareTest(&materialize_true, &materialize_false,
|
||||
&if_true, &if_false, &fall_through);
|
||||
|
||||
__ test(FieldOperand(eax, String::kHashFieldOffset),
|
||||
Immediate(String::kContainsCachedArrayIndexMask));
|
||||
Split(zero, if_true, if_false, fall_through);
|
||||
|
||||
Apply(context_, if_true, if_false);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
|
||||
VisitForValue(args->at(0), kAccumulator);
|
||||
|
||||
if (FLAG_debug_code) {
|
||||
__ AbortIfNotString(eax);
|
||||
}
|
||||
|
||||
__ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
|
||||
__ IndexFromHash(eax, eax);
|
||||
|
||||
Apply(context_, eax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
||||
Handle<String> name = expr->name();
|
||||
if (name->length() > 0 && name->Get(0) == '_') {
|
||||
|
@ -519,31 +519,6 @@ static void GenerateKeyStringCheck(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Picks out an array index from the hash field.
|
||||
static void GenerateIndexFromHash(MacroAssembler* masm,
|
||||
Register key,
|
||||
Register hash) {
|
||||
// Register use:
|
||||
// key - holds the overwritten key on exit.
|
||||
// hash - holds the key's hash. Clobbered.
|
||||
|
||||
// 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::kArrayIndexValueBits));
|
||||
// We want the smi-tagged index in key. kArrayIndexValueMask has zeros in
|
||||
// the low kHashShift bits.
|
||||
ASSERT(String::kHashShift >= kSmiTagSize);
|
||||
__ and_(hash, String::kArrayIndexValueMask);
|
||||
__ shr(hash, String::kHashShift - kSmiTagSize);
|
||||
// Here we actually clobber the key which will be used if calling into
|
||||
// runtime later. However as the new key is the numeric value of a string key
|
||||
// there is no difference in using either key.
|
||||
__ mov(key, hash);
|
||||
}
|
||||
|
||||
|
||||
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : key
|
||||
@ -704,7 +679,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ ret(0);
|
||||
|
||||
__ bind(&index_string);
|
||||
GenerateIndexFromHash(masm, eax, ebx);
|
||||
__ IndexFromHash(ebx, eax);
|
||||
// Now jump to the place where smi keys are handled.
|
||||
__ jmp(&index_smi);
|
||||
}
|
||||
@ -1565,7 +1540,7 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
GenerateMiss(masm, argc);
|
||||
|
||||
__ bind(&index_string);
|
||||
GenerateIndexFromHash(masm, ecx, ebx);
|
||||
__ IndexFromHash(ebx, ecx);
|
||||
// Now jump to the place where smi keys are handled.
|
||||
__ jmp(&index_smi);
|
||||
}
|
||||
|
@ -303,6 +303,17 @@ void MacroAssembler::AbortIfNotSmi(Register object) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::AbortIfNotString(Register object) {
|
||||
test(object, Immediate(kSmiTagMask));
|
||||
Assert(not_equal, "Operand is not a string");
|
||||
push(object);
|
||||
mov(object, FieldOperand(object, HeapObject::kMapOffset));
|
||||
CmpInstanceType(object, FIRST_NONSTRING_TYPE);
|
||||
pop(object);
|
||||
Assert(below, "Operand is not a string");
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::AbortIfSmi(Register object) {
|
||||
test(object, Immediate(kSmiTagMask));
|
||||
Assert(not_equal, "Operand is a smi");
|
||||
@ -940,6 +951,25 @@ void MacroAssembler::IllegalOperation(int num_arguments) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IndexFromHash(Register hash, Register index) {
|
||||
// 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::kArrayIndexValueBits));
|
||||
// We want the smi-tagged index in key. kArrayIndexValueMask has zeros in
|
||||
// the low kHashShift bits.
|
||||
and_(hash, String::kArrayIndexValueMask);
|
||||
STATIC_ASSERT(String::kHashShift >= kSmiTagSize && kSmiTag == 0);
|
||||
if (String::kHashShift > kSmiTagSize) {
|
||||
shr(hash, String::kHashShift - kSmiTagSize);
|
||||
}
|
||||
if (!index.is(hash)) {
|
||||
mov(index, hash);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
|
||||
CallRuntime(Runtime::FunctionForId(id), num_arguments);
|
||||
}
|
||||
|
@ -267,6 +267,9 @@ class MacroAssembler: public Assembler {
|
||||
// Abort execution if argument is a smi. Used in debug code.
|
||||
void AbortIfSmi(Register object);
|
||||
|
||||
// Abort execution if argument is a string. Used in debug code.
|
||||
void AbortIfNotString(Register object);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Exception handling
|
||||
|
||||
@ -396,6 +399,12 @@ class MacroAssembler: public Assembler {
|
||||
// occurred.
|
||||
void IllegalOperation(int num_arguments);
|
||||
|
||||
// Picks out an array index from the hash field.
|
||||
// Register use:
|
||||
// hash - holds the index's hash. Clobbered.
|
||||
// index - holds the overwritten index on exit.
|
||||
void IndexFromHash(Register hash, Register index);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Runtime calls
|
||||
|
||||
|
@ -4854,6 +4854,19 @@ static Object* Runtime_StringToNumber(Arguments args) {
|
||||
if (minus) {
|
||||
if (d == 0) return Heap::minus_zero_value();
|
||||
d = -d;
|
||||
} else if (!subject->HasHashCode() &&
|
||||
len <= String::kMaxArrayIndexSize &&
|
||||
(len == 1 || data[0] != '0')) {
|
||||
// String hash is not calculated yet but all the data are present.
|
||||
// Update the hash field to speed up sequential convertions.
|
||||
uint32_t hash = StringHasher::MakeCachedArrayIndex(d, len);
|
||||
#ifdef DEBUG
|
||||
ASSERT((hash & String::kContainsCachedArrayIndexMask) == 0);
|
||||
subject->Hash(); // Force hash calculation.
|
||||
ASSERT_EQ(static_cast<int>(subject->hash_field()),
|
||||
static_cast<int>(hash));
|
||||
#endif
|
||||
subject->set_hash_field(hash);
|
||||
}
|
||||
return Smi::FromInt(d);
|
||||
}
|
||||
|
@ -502,7 +502,10 @@ function ToBoolean(x) {
|
||||
// ECMA-262, section 9.3, page 31.
|
||||
function ToNumber(x) {
|
||||
if (IS_NUMBER(x)) return x;
|
||||
if (IS_STRING(x)) return %StringToNumber(x);
|
||||
if (IS_STRING(x)) {
|
||||
return %_HasCachedArrayIndex(x) ? %_GetCachedArrayIndex(x)
|
||||
: %StringToNumber(x);
|
||||
}
|
||||
if (IS_BOOLEAN(x)) return x ? 1 : 0;
|
||||
if (IS_UNDEFINED(x)) return $NaN;
|
||||
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
|
||||
|
@ -111,13 +111,20 @@ function GlobalParseInt(string, radix) {
|
||||
if (!(radix == 0 || (2 <= radix && radix <= 36)))
|
||||
return $NaN;
|
||||
}
|
||||
return %StringParseInt(ToString(string), radix);
|
||||
string = TO_STRING_INLINE(string);
|
||||
if (%_HasCachedArrayIndex(string) &&
|
||||
(radix == 0 || radix == 10)) {
|
||||
return %_GetCachedArrayIndex(string);
|
||||
}
|
||||
return %StringParseInt(string, radix);
|
||||
}
|
||||
|
||||
|
||||
// ECMA-262 - 15.1.2.3
|
||||
function GlobalParseFloat(string) {
|
||||
return %StringParseFloat(ToString(string));
|
||||
string = TO_STRING_INLINE(string);
|
||||
if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
|
||||
return %StringParseFloat(string);
|
||||
}
|
||||
|
||||
|
||||
|
@ -7223,6 +7223,34 @@ void CodeGenerator::GenerateIsRegExpEquivalent(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateHasCachedArrayIndex(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
Load(args->at(0));
|
||||
Result value = frame_->Pop();
|
||||
value.ToRegister();
|
||||
ASSERT(value.is_valid());
|
||||
__ testl(FieldOperand(value.reg(), String::kHashFieldOffset),
|
||||
Immediate(String::kContainsCachedArrayIndexMask));
|
||||
value.Unuse();
|
||||
destination()->Split(zero);
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateGetCachedArrayIndex(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
Load(args->at(0));
|
||||
Result string = frame_->Pop();
|
||||
string.ToRegister();
|
||||
|
||||
Result number = allocator()->Allocate();
|
||||
ASSERT(number.is_valid());
|
||||
__ movl(number.reg(), FieldOperand(string.reg(), String::kHashFieldOffset));
|
||||
__ IndexFromHash(number.reg(), number.reg());
|
||||
string.Unuse();
|
||||
frame_->Push(&number);
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
|
||||
if (CheckForInlineRuntimeCall(node)) {
|
||||
return;
|
||||
|
@ -683,6 +683,9 @@ class CodeGenerator: public AstVisitor {
|
||||
|
||||
void GenerateIsRegExpEquivalent(ZoneList<Expression*>* args);
|
||||
|
||||
void GenerateHasCachedArrayIndex(ZoneList<Expression*>* args);
|
||||
void GenerateGetCachedArrayIndex(ZoneList<Expression*>* args);
|
||||
|
||||
// Simple condition analysis.
|
||||
enum ConditionAnalysis {
|
||||
ALWAYS_TRUE,
|
||||
|
@ -2597,6 +2597,40 @@ void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
|
||||
VisitForValue(args->at(0), kAccumulator);
|
||||
|
||||
Label materialize_true, materialize_false;
|
||||
Label* if_true = NULL;
|
||||
Label* if_false = NULL;
|
||||
Label* fall_through = NULL;
|
||||
PrepareTest(&materialize_true, &materialize_false,
|
||||
&if_true, &if_false, &fall_through);
|
||||
|
||||
__ testl(FieldOperand(rax, String::kHashFieldOffset),
|
||||
Immediate(String::kContainsCachedArrayIndexMask));
|
||||
__ j(zero, if_true);
|
||||
__ jmp(if_false);
|
||||
|
||||
Apply(context_, if_true, if_false);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
|
||||
VisitForValue(args->at(0), kAccumulator);
|
||||
|
||||
__ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
|
||||
ASSERT(String::kHashShift >= kSmiTagSize);
|
||||
__ IndexFromHash(rax, rax);
|
||||
|
||||
Apply(context_, rax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
||||
Handle<String> name = expr->name();
|
||||
if (name->length() > 0 && name->Get(0) == '_') {
|
||||
|
@ -572,31 +572,6 @@ static void GenerateKeyStringCheck(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Picks out an array index from the hash field.
|
||||
static void GenerateIndexFromHash(MacroAssembler* masm,
|
||||
Register key,
|
||||
Register hash) {
|
||||
// Register use:
|
||||
// key - holds the overwritten key on exit.
|
||||
// hash - holds the key's hash. Clobbered.
|
||||
|
||||
// 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::kArrayIndexValueBits));
|
||||
// We want the smi-tagged index in key. Even if we subsequently go to
|
||||
// the slow case, converting the key to a smi is always valid.
|
||||
// key: string key
|
||||
// hash: key's hash field, including its array index value.
|
||||
__ and_(hash, Immediate(String::kArrayIndexValueMask));
|
||||
__ shr(hash, Immediate(String::kHashShift));
|
||||
// Here we actually clobber the key which will be used if calling into
|
||||
// runtime later. However as the new key is the numeric value of a string key
|
||||
// there is no difference in using either key.
|
||||
__ Integer32ToSmi(key, hash);
|
||||
}
|
||||
|
||||
|
||||
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
@ -743,7 +718,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ ret(0);
|
||||
|
||||
__ bind(&index_string);
|
||||
GenerateIndexFromHash(masm, rax, rbx);
|
||||
__ IndexFromHash(rbx, rax);
|
||||
__ jmp(&index_smi);
|
||||
}
|
||||
|
||||
@ -1599,7 +1574,7 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
GenerateMiss(masm, argc);
|
||||
|
||||
__ bind(&index_string);
|
||||
GenerateIndexFromHash(masm, rcx, rbx);
|
||||
__ IndexFromHash(rbx, rcx);
|
||||
// Now jump to the place where smi keys are handled.
|
||||
__ jmp(&index_smi);
|
||||
}
|
||||
|
@ -391,6 +391,25 @@ void MacroAssembler::IllegalOperation(int num_arguments) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IndexFromHash(Register hash, Register index) {
|
||||
// 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::kArrayIndexValueBits));
|
||||
// We want the smi-tagged index in key. Even if we subsequently go to
|
||||
// the slow case, converting the key to a smi is always valid.
|
||||
// key: string key
|
||||
// hash: key's hash field, including its array index value.
|
||||
and_(hash, Immediate(String::kArrayIndexValueMask));
|
||||
shr(hash, Immediate(String::kHashShift));
|
||||
// Here we actually clobber the key which will be used if calling into
|
||||
// runtime later. However as the new key is the numeric value of a string key
|
||||
// there is no difference in using either key.
|
||||
Integer32ToSmi(index, hash);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
|
||||
CallRuntime(Runtime::FunctionForId(id), num_arguments);
|
||||
}
|
||||
|
@ -715,6 +715,12 @@ class MacroAssembler: public Assembler {
|
||||
// occurred.
|
||||
void IllegalOperation(int num_arguments);
|
||||
|
||||
// Picks out an array index from the hash field.
|
||||
// Register use:
|
||||
// hash - holds the index's hash. Clobbered.
|
||||
// index - holds the overwritten index on exit.
|
||||
void IndexFromHash(Register hash, Register index);
|
||||
|
||||
// Find the function context up the context chain.
|
||||
void LoadContext(Register dst, int context_chain_length);
|
||||
|
||||
|
@ -176,7 +176,11 @@ var knownProblems = {
|
||||
"_GetFromCache": true,
|
||||
|
||||
// This function expects its first argument to be a non-smi.
|
||||
"_IsStringWrapperSafeForDefaultValueOf" : true
|
||||
"_IsStringWrapperSafeForDefaultValueOf" : true,
|
||||
|
||||
// Only applicable to strings.
|
||||
"_HasCachedArrayIndex": true,
|
||||
"_GetCachedArrayIndex": true
|
||||
};
|
||||
|
||||
var currentlyUncallable = {
|
||||
|
Loading…
Reference in New Issue
Block a user