OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 1550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1561 EmitCheckForSymbolsOrObjects(masm, lhs_, rhs_, &flat_string_check, &slow); | 1561 EmitCheckForSymbolsOrObjects(masm, lhs_, rhs_, &flat_string_check, &slow); |
1562 } | 1562 } |
1563 | 1563 |
1564 // Check for both being sequential ASCII strings, and inline if that is the | 1564 // Check for both being sequential ASCII strings, and inline if that is the |
1565 // case. | 1565 // case. |
1566 __ bind(&flat_string_check); | 1566 __ bind(&flat_string_check); |
1567 | 1567 |
1568 __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs_, rhs_, r2, r3, &slow); | 1568 __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs_, rhs_, r2, r3, &slow); |
1569 | 1569 |
1570 __ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2, r3); | 1570 __ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2, r3); |
1571 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, | 1571 if (cc_ == eq) { |
| 1572 StringCompareStub::GenerateFlatAsciiStringEquals(masm, |
1572 lhs_, | 1573 lhs_, |
1573 rhs_, | 1574 rhs_, |
1574 r2, | 1575 r2, |
1575 r3, | 1576 r3, |
1576 r4, | 1577 r4); |
1577 r5); | 1578 } else { |
| 1579 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, |
| 1580 lhs_, |
| 1581 rhs_, |
| 1582 r2, |
| 1583 r3, |
| 1584 r4, |
| 1585 r5); |
| 1586 } |
1578 // Never falls through to here. | 1587 // Never falls through to here. |
1579 | 1588 |
1580 __ bind(&slow); | 1589 __ bind(&slow); |
1581 | 1590 |
1582 __ Push(lhs_, rhs_); | 1591 __ Push(lhs_, rhs_); |
1583 // Figure out which native to call and setup the arguments. | 1592 // Figure out which native to call and setup the arguments. |
1584 Builtins::JavaScript native; | 1593 Builtins::JavaScript native; |
1585 if (cc_ == eq) { | 1594 if (cc_ == eq) { |
1586 native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; | 1595 native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
1587 } else { | 1596 } else { |
(...skipping 3797 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5385 __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); | 5394 __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); |
5386 __ add(sp, sp, Operand(3 * kPointerSize)); | 5395 __ add(sp, sp, Operand(3 * kPointerSize)); |
5387 __ Ret(); | 5396 __ Ret(); |
5388 | 5397 |
5389 // Just jump to runtime to create the sub string. | 5398 // Just jump to runtime to create the sub string. |
5390 __ bind(&runtime); | 5399 __ bind(&runtime); |
5391 __ TailCallRuntime(Runtime::kSubString, 3, 1); | 5400 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
5392 } | 5401 } |
5393 | 5402 |
5394 | 5403 |
| 5404 void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, |
| 5405 Register left, |
| 5406 Register right, |
| 5407 Register scratch1, |
| 5408 Register scratch2, |
| 5409 Register scratch3) { |
| 5410 Register length = scratch1; |
| 5411 |
| 5412 // Compare lengths. |
| 5413 Label strings_not_equal, check_zero_length; |
| 5414 __ ldr(length, FieldMemOperand(left, String::kLengthOffset)); |
| 5415 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); |
| 5416 __ cmp(length, scratch2); |
| 5417 __ b(eq, &check_zero_length); |
| 5418 __ bind(&strings_not_equal); |
| 5419 __ mov(r0, Operand(Smi::FromInt(NOT_EQUAL))); |
| 5420 __ Ret(); |
| 5421 |
| 5422 // Check if the length is zero. |
| 5423 Label compare_chars; |
| 5424 __ bind(&check_zero_length); |
| 5425 STATIC_ASSERT(kSmiTag == 0); |
| 5426 __ tst(length, Operand(length)); |
| 5427 __ b(ne, &compare_chars); |
| 5428 __ mov(r0, Operand(Smi::FromInt(EQUAL))); |
| 5429 __ Ret(); |
| 5430 |
| 5431 // Compare characters. |
| 5432 __ bind(&compare_chars); |
| 5433 GenerateAsciiCharsCompareLoop(masm, |
| 5434 left, right, length, scratch2, scratch3, |
| 5435 &strings_not_equal); |
| 5436 |
| 5437 // Characters are equal. |
| 5438 __ mov(r0, Operand(Smi::FromInt(EQUAL))); |
| 5439 __ Ret(); |
| 5440 } |
| 5441 |
| 5442 |
5395 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 5443 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
5396 Register left, | 5444 Register left, |
5397 Register right, | 5445 Register right, |
5398 Register scratch1, | 5446 Register scratch1, |
5399 Register scratch2, | 5447 Register scratch2, |
5400 Register scratch3, | 5448 Register scratch3, |
5401 Register scratch4) { | 5449 Register scratch4) { |
5402 Label compare_lengths; | 5450 Label result_not_equal, compare_lengths; |
5403 // Find minimum length and length difference. | 5451 // Find minimum length and length difference. |
5404 __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset)); | 5452 __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset)); |
5405 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); | 5453 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); |
5406 __ sub(scratch3, scratch1, Operand(scratch2), SetCC); | 5454 __ sub(scratch3, scratch1, Operand(scratch2), SetCC); |
5407 Register length_delta = scratch3; | 5455 Register length_delta = scratch3; |
5408 __ mov(scratch1, scratch2, LeaveCC, gt); | 5456 __ mov(scratch1, scratch2, LeaveCC, gt); |
5409 Register min_length = scratch1; | 5457 Register min_length = scratch1; |
5410 STATIC_ASSERT(kSmiTag == 0); | 5458 STATIC_ASSERT(kSmiTag == 0); |
5411 __ tst(min_length, Operand(min_length)); | 5459 __ tst(min_length, Operand(min_length)); |
5412 __ b(eq, &compare_lengths); | 5460 __ b(eq, &compare_lengths); |
5413 | 5461 |
5414 // Untag smi. | 5462 // Compare loop. |
5415 __ mov(min_length, Operand(min_length, ASR, kSmiTagSize)); | 5463 GenerateAsciiCharsCompareLoop(masm, |
| 5464 left, right, min_length, scratch2, scratch4, |
| 5465 &result_not_equal); |
5416 | 5466 |
5417 // Setup registers so that we only need to increment one register | 5467 // Compare lengths - strings up to min-length are equal. |
5418 // in the loop. | |
5419 __ add(scratch2, min_length, | |
5420 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
5421 __ add(left, left, Operand(scratch2)); | |
5422 __ add(right, right, Operand(scratch2)); | |
5423 // Registers left and right points to the min_length character of strings. | |
5424 __ rsb(min_length, min_length, Operand(-1)); | |
5425 Register index = min_length; | |
5426 // Index starts at -min_length. | |
5427 | |
5428 { | |
5429 // Compare loop. | |
5430 Label loop; | |
5431 __ bind(&loop); | |
5432 // Compare characters. | |
5433 __ add(index, index, Operand(1), SetCC); | |
5434 __ ldrb(scratch2, MemOperand(left, index), ne); | |
5435 __ ldrb(scratch4, MemOperand(right, index), ne); | |
5436 // Skip to compare lengths with eq condition true. | |
5437 __ b(eq, &compare_lengths); | |
5438 __ cmp(scratch2, scratch4); | |
5439 __ b(eq, &loop); | |
5440 // Fallthrough with eq condition false. | |
5441 } | |
5442 // Compare lengths - strings up to min-length are equal. | |
5443 __ bind(&compare_lengths); | 5468 __ bind(&compare_lengths); |
5444 ASSERT(Smi::FromInt(EQUAL) == static_cast<Smi*>(0)); | 5469 ASSERT(Smi::FromInt(EQUAL) == static_cast<Smi*>(0)); |
5445 // Use zero length_delta as result. | 5470 // Use length_delta as result if it's zero. |
5446 __ mov(r0, Operand(length_delta), SetCC, eq); | 5471 __ mov(r0, Operand(length_delta), SetCC); |
5447 // Fall through to here if characters compare not-equal. | 5472 __ bind(&result_not_equal); |
| 5473 // Conditionally update the result based either on length_delta or |
| 5474 // the last comparion performed in the loop above. |
5448 __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt); | 5475 __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt); |
5449 __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt); | 5476 __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt); |
5450 __ Ret(); | 5477 __ Ret(); |
5451 } | 5478 } |
5452 | 5479 |
5453 | 5480 |
| 5481 void StringCompareStub::GenerateAsciiCharsCompareLoop( |
| 5482 MacroAssembler* masm, |
| 5483 Register left, |
| 5484 Register right, |
| 5485 Register length, |
| 5486 Register scratch1, |
| 5487 Register scratch2, |
| 5488 Label* chars_not_equal) { |
| 5489 // Change index to run from -length to -1 by adding length to string |
| 5490 // start. This means that loop ends when index reaches zero, which |
| 5491 // doesn't need an additional compare. |
| 5492 __ SmiUntag(length); |
| 5493 __ add(scratch1, length, |
| 5494 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 5495 __ add(left, left, Operand(scratch1)); |
| 5496 __ add(right, right, Operand(scratch1)); |
| 5497 __ rsb(length, length, Operand(0)); |
| 5498 Register index = length; // index = -length; |
| 5499 |
| 5500 // Compare loop. |
| 5501 Label loop; |
| 5502 __ bind(&loop); |
| 5503 __ ldrb(scratch1, MemOperand(left, index)); |
| 5504 __ ldrb(scratch2, MemOperand(right, index)); |
| 5505 __ cmp(scratch1, scratch2); |
| 5506 __ b(ne, chars_not_equal); |
| 5507 __ add(index, index, Operand(1), SetCC); |
| 5508 __ b(ne, &loop); |
| 5509 } |
| 5510 |
| 5511 |
5454 void StringCompareStub::Generate(MacroAssembler* masm) { | 5512 void StringCompareStub::Generate(MacroAssembler* masm) { |
5455 Label runtime; | 5513 Label runtime; |
5456 | 5514 |
5457 Counters* counters = masm->isolate()->counters(); | 5515 Counters* counters = masm->isolate()->counters(); |
5458 | 5516 |
5459 // Stack frame on entry. | 5517 // Stack frame on entry. |
5460 // sp[0]: right string | 5518 // sp[0]: right string |
5461 // sp[4]: left string | 5519 // sp[4]: left string |
5462 __ Ldrd(r0 , r1, MemOperand(sp)); // Load right in r0, left in r1. | 5520 __ Ldrd(r0 , r1, MemOperand(sp)); // Load right in r0, left in r1. |
5463 | 5521 |
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5896 | 5954 |
5897 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0); | 5955 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0); |
5898 __ bind(&generic_stub); | 5956 __ bind(&generic_stub); |
5899 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); | 5957 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); |
5900 | 5958 |
5901 __ bind(&miss); | 5959 __ bind(&miss); |
5902 GenerateMiss(masm); | 5960 GenerateMiss(masm); |
5903 } | 5961 } |
5904 | 5962 |
5905 | 5963 |
| 5964 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { |
| 5965 ASSERT(state_ == CompareIC::STRINGS); |
| 5966 Label miss; |
| 5967 |
| 5968 // Registers containing left and right operands respectively. |
| 5969 Register left = r1; |
| 5970 Register right = r0; |
| 5971 Register tmp1 = r2; |
| 5972 Register tmp2 = r3; |
| 5973 Register tmp3 = r4; |
| 5974 Register tmp4 = r5; |
| 5975 |
| 5976 // Check that both operands are heap objects. |
| 5977 __ JumpIfEitherSmi(left, right, &miss); |
| 5978 |
| 5979 // Check that both operands are strings. This leaves the instance |
| 5980 // types loaded in tmp1 and tmp2. |
| 5981 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); |
| 5982 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); |
| 5983 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); |
| 5984 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); |
| 5985 STATIC_ASSERT(kNotStringTag != 0); |
| 5986 __ orr(tmp3, tmp1, tmp2); |
| 5987 __ tst(tmp3, Operand(kIsNotStringMask)); |
| 5988 __ b(ne, &miss); |
| 5989 |
| 5990 // Fast check for identical strings. |
| 5991 __ cmp(left, right); |
| 5992 STATIC_ASSERT(EQUAL == 0); |
| 5993 STATIC_ASSERT(kSmiTag == 0); |
| 5994 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); |
| 5995 __ Ret(eq); |
| 5996 |
| 5997 // Handle not identical strings. |
| 5998 |
| 5999 // Check that both strings are symbols. If they are, we're done |
| 6000 // because we already know they are not identical. |
| 6001 ASSERT(GetCondition() == eq); |
| 6002 STATIC_ASSERT(kSymbolTag != 0); |
| 6003 __ and_(tmp3, tmp1, Operand(tmp2)); |
| 6004 __ tst(tmp3, Operand(kIsSymbolMask)); |
| 6005 // Make sure r0 is non-zero. At this point input operands are |
| 6006 // guaranteed to be non-zero. |
| 6007 ASSERT(right.is(r0)); |
| 6008 __ Ret(ne); |
| 6009 |
| 6010 // Check that both strings are sequential ASCII. |
| 6011 Label runtime; |
| 6012 __ JumpIfBothInstanceTypesAreNotSequentialAscii(tmp1, tmp2, tmp3, tmp4, |
| 6013 &runtime); |
| 6014 |
| 6015 // Compare flat ASCII strings. Returns when done. |
| 6016 StringCompareStub::GenerateFlatAsciiStringEquals( |
| 6017 masm, left, right, tmp1, tmp2, tmp3); |
| 6018 |
| 6019 // Handle more complex cases in runtime. |
| 6020 __ bind(&runtime); |
| 6021 __ Push(left, right); |
| 6022 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); |
| 6023 |
| 6024 __ bind(&miss); |
| 6025 GenerateMiss(masm); |
| 6026 } |
| 6027 |
| 6028 |
5906 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { | 6029 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { |
5907 ASSERT(state_ == CompareIC::OBJECTS); | 6030 ASSERT(state_ == CompareIC::OBJECTS); |
5908 Label miss; | 6031 Label miss; |
5909 __ and_(r2, r1, Operand(r0)); | 6032 __ and_(r2, r1, Operand(r0)); |
5910 __ tst(r2, Operand(kSmiTagMask)); | 6033 __ tst(r2, Operand(kSmiTagMask)); |
5911 __ b(eq, &miss); | 6034 __ b(eq, &miss); |
5912 | 6035 |
5913 __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE); | 6036 __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE); |
5914 __ b(ne, &miss); | 6037 __ b(ne, &miss); |
5915 __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE); | 6038 __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5966 void DirectCEntryStub::GenerateCall(MacroAssembler* masm, | 6089 void DirectCEntryStub::GenerateCall(MacroAssembler* masm, |
5967 Register target) { | 6090 Register target) { |
5968 __ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()), | 6091 __ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()), |
5969 RelocInfo::CODE_TARGET)); | 6092 RelocInfo::CODE_TARGET)); |
5970 // Push return address (accessible to GC through exit frame pc). | 6093 // Push return address (accessible to GC through exit frame pc). |
5971 __ str(pc, MemOperand(sp, 0)); | 6094 __ str(pc, MemOperand(sp, 0)); |
5972 __ Jump(target); // Call the C++ function. | 6095 __ Jump(target); // Call the C++ function. |
5973 } | 6096 } |
5974 | 6097 |
5975 | 6098 |
| 6099 void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, |
| 6100 Label* miss, |
| 6101 Label* done, |
| 6102 Register receiver, |
| 6103 Register properties, |
| 6104 String* name, |
| 6105 Register scratch0) { |
| 6106 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
| 6107 // not equal to the name and kProbes-th slot is not used (its name is the |
| 6108 // undefined value), it guarantees the hash table doesn't contain the |
| 6109 // property. It's true even if some slots represent deleted properties |
| 6110 // (their names are the null value). |
| 6111 for (int i = 0; i < kInlinedProbes; i++) { |
| 6112 // scratch0 points to properties hash. |
| 6113 // Compute the masked index: (hash + i + i * i) & mask. |
| 6114 Register index = scratch0; |
| 6115 // Capacity is smi 2^n. |
| 6116 __ ldr(index, FieldMemOperand(properties, kCapacityOffset)); |
| 6117 __ sub(index, index, Operand(1)); |
| 6118 __ and_(index, index, Operand( |
| 6119 Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i)))); |
| 6120 |
| 6121 // Scale the index by multiplying by the entry size. |
| 6122 ASSERT(StringDictionary::kEntrySize == 3); |
| 6123 __ add(index, index, Operand(index, LSL, 1)); // index *= 3. |
| 6124 |
| 6125 Register entity_name = scratch0; |
| 6126 // Having undefined at this place means the name is not contained. |
| 6127 ASSERT_EQ(kSmiTagSize, 1); |
| 6128 Register tmp = properties; |
| 6129 __ add(tmp, properties, Operand(index, LSL, 1)); |
| 6130 __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset)); |
| 6131 |
| 6132 ASSERT(!tmp.is(entity_name)); |
| 6133 __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex); |
| 6134 __ cmp(entity_name, tmp); |
| 6135 __ b(eq, done); |
| 6136 |
| 6137 if (i != kInlinedProbes - 1) { |
| 6138 // Stop if found the property. |
| 6139 __ cmp(entity_name, Operand(Handle<String>(name))); |
| 6140 __ b(eq, miss); |
| 6141 |
| 6142 // Check if the entry name is not a symbol. |
| 6143 __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); |
| 6144 __ ldrb(entity_name, |
| 6145 FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); |
| 6146 __ tst(entity_name, Operand(kIsSymbolMask)); |
| 6147 __ b(eq, miss); |
| 6148 |
| 6149 // Restore the properties. |
| 6150 __ ldr(properties, |
| 6151 FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| 6152 } |
| 6153 } |
| 6154 |
| 6155 const int spill_mask = |
| 6156 (lr.bit() | r6.bit() | r5.bit() | r4.bit() | r3.bit() | |
| 6157 r2.bit() | r1.bit() | r0.bit()); |
| 6158 |
| 6159 __ stm(db_w, sp, spill_mask); |
| 6160 __ ldr(r0, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| 6161 __ mov(r1, Operand(Handle<String>(name))); |
| 6162 StringDictionaryLookupStub stub(NEGATIVE_LOOKUP); |
| 6163 __ CallStub(&stub); |
| 6164 __ tst(r0, Operand(r0)); |
| 6165 __ ldm(ia_w, sp, spill_mask); |
| 6166 |
| 6167 __ b(eq, done); |
| 6168 __ b(ne, miss); |
| 6169 } |
| 6170 |
| 6171 |
| 6172 // Probe the string dictionary in the |elements| register. Jump to the |
| 6173 // |done| label if a property with the given name is found. Jump to |
| 6174 // the |miss| label otherwise. |
| 6175 // If lookup was successful |scratch2| will be equal to elements + 4 * index. |
| 6176 void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, |
| 6177 Label* miss, |
| 6178 Label* done, |
| 6179 Register elements, |
| 6180 Register name, |
| 6181 Register scratch1, |
| 6182 Register scratch2) { |
| 6183 // Assert that name contains a string. |
| 6184 if (FLAG_debug_code) __ AbortIfNotString(name); |
| 6185 |
| 6186 // Compute the capacity mask. |
| 6187 __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset)); |
| 6188 __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize)); // convert smi to int |
| 6189 __ sub(scratch1, scratch1, Operand(1)); |
| 6190 |
| 6191 // Generate an unrolled loop that performs a few probes before |
| 6192 // giving up. Measurements done on Gmail indicate that 2 probes |
| 6193 // cover ~93% of loads from dictionaries. |
| 6194 for (int i = 0; i < kInlinedProbes; i++) { |
| 6195 // Compute the masked index: (hash + i + i * i) & mask. |
| 6196 __ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset)); |
| 6197 if (i > 0) { |
| 6198 // Add the probe offset (i + i * i) left shifted to avoid right shifting |
| 6199 // the hash in a separate instruction. The value hash + i + i * i is right |
| 6200 // shifted in the following and instruction. |
| 6201 ASSERT(StringDictionary::GetProbeOffset(i) < |
| 6202 1 << (32 - String::kHashFieldOffset)); |
| 6203 __ add(scratch2, scratch2, Operand( |
| 6204 StringDictionary::GetProbeOffset(i) << String::kHashShift)); |
| 6205 } |
| 6206 __ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift)); |
| 6207 |
| 6208 // Scale the index by multiplying by the element size. |
| 6209 ASSERT(StringDictionary::kEntrySize == 3); |
| 6210 // scratch2 = scratch2 * 3. |
| 6211 __ add(scratch2, scratch2, Operand(scratch2, LSL, 1)); |
| 6212 |
| 6213 // Check if the key is identical to the name. |
| 6214 __ add(scratch2, elements, Operand(scratch2, LSL, 2)); |
| 6215 __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset)); |
| 6216 __ cmp(name, Operand(ip)); |
| 6217 __ b(eq, done); |
| 6218 } |
| 6219 |
| 6220 const int spill_mask = |
| 6221 (lr.bit() | r6.bit() | r5.bit() | r4.bit() | |
| 6222 r3.bit() | r2.bit() | r1.bit() | r0.bit()) & |
| 6223 ~(scratch1.bit() | scratch2.bit()); |
| 6224 |
| 6225 __ stm(db_w, sp, spill_mask); |
| 6226 __ Move(r0, elements); |
| 6227 __ Move(r1, name); |
| 6228 StringDictionaryLookupStub stub(POSITIVE_LOOKUP); |
| 6229 __ CallStub(&stub); |
| 6230 __ tst(r0, Operand(r0)); |
| 6231 __ mov(scratch2, Operand(r2)); |
| 6232 __ ldm(ia_w, sp, spill_mask); |
| 6233 |
| 6234 __ b(ne, done); |
| 6235 __ b(eq, miss); |
| 6236 } |
| 6237 |
| 6238 |
| 6239 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { |
| 6240 // Registers: |
| 6241 // result: StringDictionary to probe |
| 6242 // r1: key |
| 6243 // : StringDictionary to probe. |
| 6244 // index_: will hold an index of entry if lookup is successful. |
| 6245 // might alias with result_. |
| 6246 // Returns: |
| 6247 // result_ is zero if lookup failed, non zero otherwise. |
| 6248 |
| 6249 Register result = r0; |
| 6250 Register dictionary = r0; |
| 6251 Register key = r1; |
| 6252 Register index = r2; |
| 6253 Register mask = r3; |
| 6254 Register hash = r4; |
| 6255 Register undefined = r5; |
| 6256 Register entry_key = r6; |
| 6257 |
| 6258 Label in_dictionary, maybe_in_dictionary, not_in_dictionary; |
| 6259 |
| 6260 __ ldr(mask, FieldMemOperand(dictionary, kCapacityOffset)); |
| 6261 __ mov(mask, Operand(mask, ASR, kSmiTagSize)); |
| 6262 __ sub(mask, mask, Operand(1)); |
| 6263 |
| 6264 __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset)); |
| 6265 |
| 6266 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); |
| 6267 |
| 6268 for (int i = kInlinedProbes; i < kTotalProbes; i++) { |
| 6269 // Compute the masked index: (hash + i + i * i) & mask. |
| 6270 // Capacity is smi 2^n. |
| 6271 if (i > 0) { |
| 6272 // Add the probe offset (i + i * i) left shifted to avoid right shifting |
| 6273 // the hash in a separate instruction. The value hash + i + i * i is right |
| 6274 // shifted in the following and instruction. |
| 6275 ASSERT(StringDictionary::GetProbeOffset(i) < |
| 6276 1 << (32 - String::kHashFieldOffset)); |
| 6277 __ add(index, hash, Operand( |
| 6278 StringDictionary::GetProbeOffset(i) << String::kHashShift)); |
| 6279 } else { |
| 6280 __ mov(index, Operand(hash)); |
| 6281 } |
| 6282 __ and_(index, mask, Operand(index, LSR, String::kHashShift)); |
| 6283 |
| 6284 // Scale the index by multiplying by the entry size. |
| 6285 ASSERT(StringDictionary::kEntrySize == 3); |
| 6286 __ add(index, index, Operand(index, LSL, 1)); // index *= 3. |
| 6287 |
| 6288 ASSERT_EQ(kSmiTagSize, 1); |
| 6289 __ add(index, dictionary, Operand(index, LSL, 2)); |
| 6290 __ ldr(entry_key, FieldMemOperand(index, kElementsStartOffset)); |
| 6291 |
| 6292 // Having undefined at this place means the name is not contained. |
| 6293 __ cmp(entry_key, Operand(undefined)); |
| 6294 __ b(eq, ¬_in_dictionary); |
| 6295 |
| 6296 // Stop if found the property. |
| 6297 __ cmp(entry_key, Operand(key)); |
| 6298 __ b(eq, &in_dictionary); |
| 6299 |
| 6300 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { |
| 6301 // Check if the entry name is not a symbol. |
| 6302 __ ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset)); |
| 6303 __ ldrb(entry_key, |
| 6304 FieldMemOperand(entry_key, Map::kInstanceTypeOffset)); |
| 6305 __ tst(entry_key, Operand(kIsSymbolMask)); |
| 6306 __ b(eq, &maybe_in_dictionary); |
| 6307 } |
| 6308 } |
| 6309 |
| 6310 __ bind(&maybe_in_dictionary); |
| 6311 // If we are doing negative lookup then probing failure should be |
| 6312 // treated as a lookup success. For positive lookup probing failure |
| 6313 // should be treated as lookup failure. |
| 6314 if (mode_ == POSITIVE_LOOKUP) { |
| 6315 __ mov(result, Operand(0)); |
| 6316 __ Ret(); |
| 6317 } |
| 6318 |
| 6319 __ bind(&in_dictionary); |
| 6320 __ mov(result, Operand(1)); |
| 6321 __ Ret(); |
| 6322 |
| 6323 __ bind(¬_in_dictionary); |
| 6324 __ mov(result, Operand(0)); |
| 6325 __ Ret(); |
| 6326 } |
| 6327 |
| 6328 |
5976 #undef __ | 6329 #undef __ |
5977 | 6330 |
5978 } } // namespace v8::internal | 6331 } } // namespace v8::internal |
5979 | 6332 |
5980 #endif // V8_TARGET_ARCH_ARM | 6333 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |