| 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 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 // Miss: fall through. | 88 // Miss: fall through. |
| 89 __ bind(&miss); | 89 __ bind(&miss); |
| 90 } | 90 } |
| 91 | 91 |
| 92 | 92 |
| 93 // Helper function used to check that the dictionary doesn't contain | 93 // Helper function used to check that the dictionary doesn't contain |
| 94 // the property. This function may return false negatives, so miss_label | 94 // the property. This function may return false negatives, so miss_label |
| 95 // must always call a backup property check that is complete. | 95 // must always call a backup property check that is complete. |
| 96 // This function is safe to call if the receiver has fast properties. | 96 // This function is safe to call if the receiver has fast properties. |
| 97 // Name must be a symbol and receiver must be a heap object. | 97 // Name must be a symbol and receiver must be a heap object. |
| 98 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, | 98 MUST_USE_RESULT static MaybeObject* GenerateDictionaryNegativeLookup( |
| 99 Label* miss_label, | 99 MacroAssembler* masm, |
| 100 Register receiver, | 100 Label* miss_label, |
| 101 String* name, | 101 Register receiver, |
| 102 Register scratch0, | 102 String* name, |
| 103 Register scratch1) { | 103 Register scratch0, |
| 104 Register scratch1) { |
| 104 ASSERT(name->IsSymbol()); | 105 ASSERT(name->IsSymbol()); |
| 105 Counters* counters = masm->isolate()->counters(); | 106 Counters* counters = masm->isolate()->counters(); |
| 106 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); | 107 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); |
| 107 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); | 108 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); |
| 108 | 109 |
| 109 Label done; | 110 Label done; |
| 110 | 111 |
| 111 const int kInterceptorOrAccessCheckNeededMask = | 112 const int kInterceptorOrAccessCheckNeededMask = |
| 112 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); | 113 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); |
| 113 | 114 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 129 // Check that the properties array is a dictionary. | 130 // Check that the properties array is a dictionary. |
| 130 __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset)); | 131 __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset)); |
| 131 Register tmp = properties; | 132 Register tmp = properties; |
| 132 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex); | 133 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex); |
| 133 __ cmp(map, tmp); | 134 __ cmp(map, tmp); |
| 134 __ b(ne, miss_label); | 135 __ b(ne, miss_label); |
| 135 | 136 |
| 136 // Restore the temporarily used register. | 137 // Restore the temporarily used register. |
| 137 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 138 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| 138 | 139 |
| 139 // Compute the capacity mask. | |
| 140 const int kCapacityOffset = | |
| 141 StringDictionary::kHeaderSize + | |
| 142 StringDictionary::kCapacityIndex * kPointerSize; | |
| 143 | 140 |
| 144 // Generate an unrolled loop that performs a few probes before | 141 MaybeObject* result = StringDictionaryLookupStub::GenerateNegativeLookup( |
| 145 // giving up. | 142 masm, |
| 146 static const int kProbes = 4; | 143 miss_label, |
| 147 const int kElementsStartOffset = | 144 &done, |
| 148 StringDictionary::kHeaderSize + | 145 receiver, |
| 149 StringDictionary::kElementsStartIndex * kPointerSize; | 146 properties, |
| 147 name, |
| 148 scratch1); |
| 149 if (result->IsFailure()) return result; |
| 150 | 150 |
| 151 // If names of slots in range from 1 to kProbes - 1 for the hash value are | |
| 152 // not equal to the name and kProbes-th slot is not used (its name is the | |
| 153 // undefined value), it guarantees the hash table doesn't contain the | |
| 154 // property. It's true even if some slots represent deleted properties | |
| 155 // (their names are the null value). | |
| 156 for (int i = 0; i < kProbes; i++) { | |
| 157 // scratch0 points to properties hash. | |
| 158 // Compute the masked index: (hash + i + i * i) & mask. | |
| 159 Register index = scratch1; | |
| 160 // Capacity is smi 2^n. | |
| 161 __ ldr(index, FieldMemOperand(properties, kCapacityOffset)); | |
| 162 __ sub(index, index, Operand(1)); | |
| 163 __ and_(index, index, Operand( | |
| 164 Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i)))); | |
| 165 | |
| 166 // Scale the index by multiplying by the entry size. | |
| 167 ASSERT(StringDictionary::kEntrySize == 3); | |
| 168 __ add(index, index, Operand(index, LSL, 1)); // index *= 3. | |
| 169 | |
| 170 Register entity_name = scratch1; | |
| 171 // Having undefined at this place means the name is not contained. | |
| 172 ASSERT_EQ(kSmiTagSize, 1); | |
| 173 Register tmp = properties; | |
| 174 __ add(tmp, properties, Operand(index, LSL, 1)); | |
| 175 __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset)); | |
| 176 | |
| 177 ASSERT(!tmp.is(entity_name)); | |
| 178 __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex); | |
| 179 __ cmp(entity_name, tmp); | |
| 180 if (i != kProbes - 1) { | |
| 181 __ b(eq, &done); | |
| 182 | |
| 183 // Stop if found the property. | |
| 184 __ cmp(entity_name, Operand(Handle<String>(name))); | |
| 185 __ b(eq, miss_label); | |
| 186 | |
| 187 // Check if the entry name is not a symbol. | |
| 188 __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); | |
| 189 __ ldrb(entity_name, | |
| 190 FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); | |
| 191 __ tst(entity_name, Operand(kIsSymbolMask)); | |
| 192 __ b(eq, miss_label); | |
| 193 | |
| 194 // Restore the properties. | |
| 195 __ ldr(properties, | |
| 196 FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | |
| 197 } else { | |
| 198 // Give up probing if still not found the undefined value. | |
| 199 __ b(ne, miss_label); | |
| 200 } | |
| 201 } | |
| 202 __ bind(&done); | 151 __ bind(&done); |
| 203 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); | 152 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); |
| 153 |
| 154 return result; |
| 204 } | 155 } |
| 205 | 156 |
| 206 | 157 |
| 207 void StubCache::GenerateProbe(MacroAssembler* masm, | 158 void StubCache::GenerateProbe(MacroAssembler* masm, |
| 208 Code::Flags flags, | 159 Code::Flags flags, |
| 209 Register receiver, | 160 Register receiver, |
| 210 Register name, | 161 Register name, |
| 211 Register scratch, | 162 Register scratch, |
| 212 Register extra, | 163 Register extra, |
| 213 Register extra2) { | 164 Register extra2) { |
| (...skipping 885 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1099 Object* lookup_result = NULL; // Initialization to please compiler. | 1050 Object* lookup_result = NULL; // Initialization to please compiler. |
| 1100 if (!maybe_lookup_result->ToObject(&lookup_result)) { | 1051 if (!maybe_lookup_result->ToObject(&lookup_result)) { |
| 1101 set_failure(Failure::cast(maybe_lookup_result)); | 1052 set_failure(Failure::cast(maybe_lookup_result)); |
| 1102 return reg; | 1053 return reg; |
| 1103 } | 1054 } |
| 1104 name = String::cast(lookup_result); | 1055 name = String::cast(lookup_result); |
| 1105 } | 1056 } |
| 1106 ASSERT(current->property_dictionary()->FindEntry(name) == | 1057 ASSERT(current->property_dictionary()->FindEntry(name) == |
| 1107 StringDictionary::kNotFound); | 1058 StringDictionary::kNotFound); |
| 1108 | 1059 |
| 1109 GenerateDictionaryNegativeLookup(masm(), | 1060 MaybeObject* negative_lookup = GenerateDictionaryNegativeLookup(masm(), |
| 1110 miss, | 1061 miss, |
| 1111 reg, | 1062 reg, |
| 1112 name, | 1063 name, |
| 1113 scratch1, | 1064 scratch1, |
| 1114 scratch2); | 1065 scratch2); |
| 1066 if (negative_lookup->IsFailure()) { |
| 1067 set_failure(Failure::cast(negative_lookup)); |
| 1068 return reg; |
| 1069 } |
| 1070 |
| 1115 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); | 1071 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 1116 reg = holder_reg; // from now the object is in holder_reg | 1072 reg = holder_reg; // from now the object is in holder_reg |
| 1117 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); | 1073 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); |
| 1118 } else if (heap()->InNewSpace(prototype)) { | 1074 } else if (heap()->InNewSpace(prototype)) { |
| 1119 // Get the map of the current object. | 1075 // Get the map of the current object. |
| 1120 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); | 1076 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 1121 __ cmp(scratch1, Operand(Handle<Map>(current->map()))); | 1077 __ cmp(scratch1, Operand(Handle<Map>(current->map()))); |
| 1122 | 1078 |
| 1123 // Branch on the result of the map check. | 1079 // Branch on the result of the map check. |
| 1124 __ b(ne, miss); | 1080 __ b(ne, miss); |
| (...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1591 } else { | 1547 } else { |
| 1592 Label call_builtin; | 1548 Label call_builtin; |
| 1593 | 1549 |
| 1594 Register elements = r3; | 1550 Register elements = r3; |
| 1595 Register end_elements = r5; | 1551 Register end_elements = r5; |
| 1596 | 1552 |
| 1597 // Get the elements array of the object. | 1553 // Get the elements array of the object. |
| 1598 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); | 1554 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); |
| 1599 | 1555 |
| 1600 // Check that the elements are in fast mode and writable. | 1556 // Check that the elements are in fast mode and writable. |
| 1601 __ CheckMap(elements, r0, | 1557 __ CheckMap(elements, |
| 1602 Heap::kFixedArrayMapRootIndex, &call_builtin, true); | 1558 r0, |
| 1559 Heap::kFixedArrayMapRootIndex, |
| 1560 &call_builtin, |
| 1561 DONT_DO_SMI_CHECK); |
| 1603 | 1562 |
| 1604 if (argc == 1) { // Otherwise fall through to call the builtin. | 1563 if (argc == 1) { // Otherwise fall through to call the builtin. |
| 1605 Label exit, attempt_to_grow_elements; | 1564 Label exit, attempt_to_grow_elements; |
| 1606 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER | 1565 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER |
| 1607 Label with_write_barrier; | 1566 Label with_write_barrier; |
| 1608 #endif | 1567 #endif |
| 1609 | 1568 |
| 1610 // Get the array's length into r0 and calculate new length. | 1569 // Get the array's length into r0 and calculate new length. |
| 1611 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); | 1570 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 1612 STATIC_ASSERT(kSmiTagSize == 1); | 1571 STATIC_ASSERT(kSmiTagSize == 1); |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1748 __ JumpIfSmi(receiver, &miss); | 1707 __ JumpIfSmi(receiver, &miss); |
| 1749 | 1708 |
| 1750 // Check that the maps haven't changed. | 1709 // Check that the maps haven't changed. |
| 1751 CheckPrototypes(JSObject::cast(object), | 1710 CheckPrototypes(JSObject::cast(object), |
| 1752 receiver, holder, elements, r4, r0, name, &miss); | 1711 receiver, holder, elements, r4, r0, name, &miss); |
| 1753 | 1712 |
| 1754 // Get the elements array of the object. | 1713 // Get the elements array of the object. |
| 1755 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); | 1714 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); |
| 1756 | 1715 |
| 1757 // Check that the elements are in fast mode and writable. | 1716 // Check that the elements are in fast mode and writable. |
| 1758 __ CheckMap(elements, r0, Heap::kFixedArrayMapRootIndex, &call_builtin, true); | 1717 __ CheckMap(elements, |
| 1718 r0, |
| 1719 Heap::kFixedArrayMapRootIndex, |
| 1720 &call_builtin, |
| 1721 DONT_DO_SMI_CHECK); |
| 1759 | 1722 |
| 1760 // Get the array's length into r4 and calculate new length. | 1723 // Get the array's length into r4 and calculate new length. |
| 1761 __ ldr(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); | 1724 __ ldr(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 1762 __ sub(r4, r4, Operand(Smi::FromInt(1)), SetCC); | 1725 __ sub(r4, r4, Operand(Smi::FromInt(1)), SetCC); |
| 1763 __ b(lt, &return_undefined); | 1726 __ b(lt, &return_undefined); |
| 1764 | 1727 |
| 1765 // Get the last element. | 1728 // Get the last element. |
| 1766 __ LoadRoot(r6, Heap::kTheHoleValueRootIndex); | 1729 __ LoadRoot(r6, Heap::kTheHoleValueRootIndex); |
| 1767 STATIC_ASSERT(kSmiTagSize == 1); | 1730 STATIC_ASSERT(kSmiTagSize == 1); |
| 1768 STATIC_ASSERT(kSmiTag == 0); | 1731 STATIC_ASSERT(kSmiTag == 0); |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2090 | 2053 |
| 2091 // Load the (only) argument into r0. | 2054 // Load the (only) argument into r0. |
| 2092 __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); | 2055 __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); |
| 2093 | 2056 |
| 2094 // If the argument is a smi, just return. | 2057 // If the argument is a smi, just return. |
| 2095 STATIC_ASSERT(kSmiTag == 0); | 2058 STATIC_ASSERT(kSmiTag == 0); |
| 2096 __ tst(r0, Operand(kSmiTagMask)); | 2059 __ tst(r0, Operand(kSmiTagMask)); |
| 2097 __ Drop(argc + 1, eq); | 2060 __ Drop(argc + 1, eq); |
| 2098 __ Ret(eq); | 2061 __ Ret(eq); |
| 2099 | 2062 |
| 2100 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, true); | 2063 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK); |
| 2101 | 2064 |
| 2102 Label wont_fit_smi, no_vfp_exception, restore_fpscr_and_return; | 2065 Label wont_fit_smi, no_vfp_exception, restore_fpscr_and_return; |
| 2103 | 2066 |
| 2104 // If vfp3 is enabled, we use the fpu rounding with the RM (round towards | 2067 // If vfp3 is enabled, we use the fpu rounding with the RM (round towards |
| 2105 // minus infinity) mode. | 2068 // minus infinity) mode. |
| 2106 | 2069 |
| 2107 // Load the HeapNumber value. | 2070 // Load the HeapNumber value. |
| 2108 // We will need access to the value in the core registers, so we load it | 2071 // We will need access to the value in the core registers, so we load it |
| 2109 // with ldrd and move it to the fpu. It also spares a sub instruction for | 2072 // with ldrd and move it to the fpu. It also spares a sub instruction for |
| 2110 // updating the HeapNumber value address, as vldr expects a multiple | 2073 // updating the HeapNumber value address, as vldr expects a multiple |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2251 Label slow; | 2214 Label slow; |
| 2252 __ b(mi, &slow); | 2215 __ b(mi, &slow); |
| 2253 | 2216 |
| 2254 // Smi case done. | 2217 // Smi case done. |
| 2255 __ Drop(argc + 1); | 2218 __ Drop(argc + 1); |
| 2256 __ Ret(); | 2219 __ Ret(); |
| 2257 | 2220 |
| 2258 // Check if the argument is a heap number and load its exponent and | 2221 // Check if the argument is a heap number and load its exponent and |
| 2259 // sign. | 2222 // sign. |
| 2260 __ bind(¬_smi); | 2223 __ bind(¬_smi); |
| 2261 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, true); | 2224 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK); |
| 2262 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | 2225 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
| 2263 | 2226 |
| 2264 // Check the sign of the argument. If the argument is positive, | 2227 // Check the sign of the argument. If the argument is positive, |
| 2265 // just return it. | 2228 // just return it. |
| 2266 Label negative_sign; | 2229 Label negative_sign; |
| 2267 __ tst(r1, Operand(HeapNumber::kSignMask)); | 2230 __ tst(r1, Operand(HeapNumber::kSignMask)); |
| 2268 __ b(ne, &negative_sign); | 2231 __ b(ne, &negative_sign); |
| 2269 __ Drop(argc + 1); | 2232 __ Drop(argc + 1); |
| 2270 __ Ret(); | 2233 __ Ret(); |
| 2271 | 2234 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2303 JSGlobalPropertyCell* cell, | 2266 JSGlobalPropertyCell* cell, |
| 2304 JSFunction* function, | 2267 JSFunction* function, |
| 2305 String* name) { | 2268 String* name) { |
| 2306 Counters* counters = isolate()->counters(); | 2269 Counters* counters = isolate()->counters(); |
| 2307 | 2270 |
| 2308 ASSERT(optimization.is_simple_api_call()); | 2271 ASSERT(optimization.is_simple_api_call()); |
| 2309 // Bail out if object is a global object as we don't want to | 2272 // Bail out if object is a global object as we don't want to |
| 2310 // repatch it to global receiver. | 2273 // repatch it to global receiver. |
| 2311 if (object->IsGlobalObject()) return heap()->undefined_value(); | 2274 if (object->IsGlobalObject()) return heap()->undefined_value(); |
| 2312 if (cell != NULL) return heap()->undefined_value(); | 2275 if (cell != NULL) return heap()->undefined_value(); |
| 2276 if (!object->IsJSObject()) return heap()->undefined_value(); |
| 2313 int depth = optimization.GetPrototypeDepthOfExpectedType( | 2277 int depth = optimization.GetPrototypeDepthOfExpectedType( |
| 2314 JSObject::cast(object), holder); | 2278 JSObject::cast(object), holder); |
| 2315 if (depth == kInvalidProtoDepth) return heap()->undefined_value(); | 2279 if (depth == kInvalidProtoDepth) return heap()->undefined_value(); |
| 2316 | 2280 |
| 2317 Label miss, miss_before_stack_reserved; | 2281 Label miss, miss_before_stack_reserved; |
| 2318 | 2282 |
| 2319 GenerateNameCheck(name, &miss_before_stack_reserved); | 2283 GenerateNameCheck(name, &miss_before_stack_reserved); |
| 2320 | 2284 |
| 2321 // Get the receiver from the stack. | 2285 // Get the receiver from the stack. |
| 2322 const int argc = arguments().immediate(); | 2286 const int argc = arguments().immediate(); |
| (...skipping 809 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3132 | 3096 |
| 3133 GenerateLoadFunctionPrototype(masm(), r1, r2, r3, &miss); | 3097 GenerateLoadFunctionPrototype(masm(), r1, r2, r3, &miss); |
| 3134 __ bind(&miss); | 3098 __ bind(&miss); |
| 3135 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, r2, r3); | 3099 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, r2, r3); |
| 3136 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3100 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3137 | 3101 |
| 3138 return GetCode(CALLBACKS, name); | 3102 return GetCode(CALLBACKS, name); |
| 3139 } | 3103 } |
| 3140 | 3104 |
| 3141 | 3105 |
| 3142 MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) { | 3106 MaybeObject* KeyedLoadStubCompiler::CompileLoadFastElement(Map* receiver_map) { |
| 3107 // ----------- S t a t e ------------- |
| 3108 // -- lr : return address |
| 3109 // -- r0 : key |
| 3110 // -- r1 : receiver |
| 3111 // ----------------------------------- |
| 3112 MaybeObject* maybe_stub = KeyedLoadFastElementStub().TryGetCode(); |
| 3113 Code* stub; |
| 3114 if (!maybe_stub->To(&stub)) return maybe_stub; |
| 3115 __ DispatchMap(r1, |
| 3116 r2, |
| 3117 Handle<Map>(receiver_map), |
| 3118 Handle<Code>(stub), |
| 3119 DO_SMI_CHECK); |
| 3120 |
| 3121 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss(); |
| 3122 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 3123 |
| 3124 // Return the generated code. |
| 3125 return GetCode(NORMAL, NULL); |
| 3126 } |
| 3127 |
| 3128 |
| 3129 MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic( |
| 3130 MapList* receiver_maps, |
| 3131 CodeList* handler_ics) { |
| 3143 // ----------- S t a t e ------------- | 3132 // ----------- S t a t e ------------- |
| 3144 // -- lr : return address | 3133 // -- lr : return address |
| 3145 // -- r0 : key | 3134 // -- r0 : key |
| 3146 // -- r1 : receiver | 3135 // -- r1 : receiver |
| 3147 // ----------------------------------- | 3136 // ----------------------------------- |
| 3148 Label miss; | 3137 Label miss; |
| 3138 __ JumpIfSmi(r1, &miss); |
| 3149 | 3139 |
| 3150 // Check that the receiver isn't a smi. | 3140 int receiver_count = receiver_maps->length(); |
| 3151 __ tst(r1, Operand(kSmiTagMask)); | |
| 3152 __ b(eq, &miss); | |
| 3153 | |
| 3154 // Check that the map matches. | |
| 3155 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3141 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3156 __ cmp(r2, Operand(Handle<Map>(receiver->map()))); | 3142 for (int current = 0; current < receiver_count; ++current) { |
| 3157 __ b(ne, &miss); | 3143 Handle<Map> map(receiver_maps->at(current)); |
| 3158 | 3144 Handle<Code> code(handler_ics->at(current)); |
| 3159 // Check that the key is a smi. | 3145 __ mov(ip, Operand(map)); |
| 3160 __ tst(r0, Operand(kSmiTagMask)); | 3146 __ cmp(r2, ip); |
| 3161 __ b(ne, &miss); | 3147 __ Jump(code, RelocInfo::CODE_TARGET, eq); |
| 3162 | 3148 } |
| 3163 // Get the elements array. | |
| 3164 __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset)); | |
| 3165 __ AssertFastElements(r2); | |
| 3166 | |
| 3167 // Check that the key is within bounds. | |
| 3168 __ ldr(r3, FieldMemOperand(r2, FixedArray::kLengthOffset)); | |
| 3169 __ cmp(r0, Operand(r3)); | |
| 3170 __ b(hs, &miss); | |
| 3171 | |
| 3172 // Load the result and make sure it's not the hole. | |
| 3173 __ add(r3, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
| 3174 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); | |
| 3175 __ ldr(r4, | |
| 3176 MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); | |
| 3177 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | |
| 3178 __ cmp(r4, ip); | |
| 3179 __ b(eq, &miss); | |
| 3180 __ mov(r0, r4); | |
| 3181 __ Ret(); | |
| 3182 | 3149 |
| 3183 __ bind(&miss); | 3150 __ bind(&miss); |
| 3184 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3151 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss(); |
| 3152 __ Jump(miss_ic, RelocInfo::CODE_TARGET, al); |
| 3185 | 3153 |
| 3186 // Return the generated code. | 3154 // Return the generated code. |
| 3187 return GetCode(NORMAL, NULL); | 3155 return GetCode(NORMAL, NULL, MEGAMORPHIC); |
| 3188 } | 3156 } |
| 3189 | 3157 |
| 3190 | 3158 |
| 3191 MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, | 3159 MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, |
| 3192 int index, | 3160 int index, |
| 3193 Map* transition, | 3161 Map* transition, |
| 3194 String* name) { | 3162 String* name) { |
| 3195 // ----------- S t a t e ------------- | 3163 // ----------- S t a t e ------------- |
| 3196 // -- r0 : value | 3164 // -- r0 : value |
| 3197 // -- r1 : name | 3165 // -- r1 : name |
| (...skipping 21 matching lines...) Expand all Loading... |
| 3219 | 3187 |
| 3220 __ DecrementCounter(counters->keyed_store_field(), 1, r3, r4); | 3188 __ DecrementCounter(counters->keyed_store_field(), 1, r3, r4); |
| 3221 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss(); | 3189 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss(); |
| 3222 __ Jump(ic, RelocInfo::CODE_TARGET); | 3190 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 3223 | 3191 |
| 3224 // Return the generated code. | 3192 // Return the generated code. |
| 3225 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); | 3193 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); |
| 3226 } | 3194 } |
| 3227 | 3195 |
| 3228 | 3196 |
| 3229 MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized( | 3197 MaybeObject* KeyedStoreStubCompiler::CompileStoreFastElement( |
| 3230 JSObject* receiver) { | 3198 Map* receiver_map) { |
| 3231 // ----------- S t a t e ------------- | 3199 // ----------- S t a t e ------------- |
| 3232 // -- r0 : value | 3200 // -- r0 : value |
| 3233 // -- r1 : key | 3201 // -- r1 : key |
| 3234 // -- r2 : receiver | 3202 // -- r2 : receiver |
| 3235 // -- lr : return address | 3203 // -- lr : return address |
| 3236 // -- r3 : scratch | 3204 // -- r3 : scratch |
| 3237 // -- r4 : scratch (elements) | |
| 3238 // ----------------------------------- | 3205 // ----------------------------------- |
| 3239 Label miss; | 3206 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; |
| 3207 MaybeObject* maybe_stub = |
| 3208 KeyedStoreFastElementStub(is_js_array).TryGetCode(); |
| 3209 Code* stub; |
| 3210 if (!maybe_stub->To(&stub)) return maybe_stub; |
| 3211 __ DispatchMap(r2, |
| 3212 r3, |
| 3213 Handle<Map>(receiver_map), |
| 3214 Handle<Code>(stub), |
| 3215 DO_SMI_CHECK); |
| 3240 | 3216 |
| 3241 Register value_reg = r0; | 3217 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
| 3242 Register key_reg = r1; | |
| 3243 Register receiver_reg = r2; | |
| 3244 Register scratch = r3; | |
| 3245 Register elements_reg = r4; | |
| 3246 | |
| 3247 // Check that the receiver isn't a smi. | |
| 3248 __ tst(receiver_reg, Operand(kSmiTagMask)); | |
| 3249 __ b(eq, &miss); | |
| 3250 | |
| 3251 // Check that the map matches. | |
| 3252 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); | |
| 3253 __ cmp(scratch, Operand(Handle<Map>(receiver->map()))); | |
| 3254 __ b(ne, &miss); | |
| 3255 | |
| 3256 // Check that the key is a smi. | |
| 3257 __ tst(key_reg, Operand(kSmiTagMask)); | |
| 3258 __ b(ne, &miss); | |
| 3259 | |
| 3260 // Get the elements array and make sure it is a fast element array, not 'cow'. | |
| 3261 __ ldr(elements_reg, | |
| 3262 FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); | |
| 3263 __ ldr(scratch, FieldMemOperand(elements_reg, HeapObject::kMapOffset)); | |
| 3264 __ cmp(scratch, Operand(Handle<Map>(factory()->fixed_array_map()))); | |
| 3265 __ b(ne, &miss); | |
| 3266 | |
| 3267 // Check that the key is within bounds. | |
| 3268 if (receiver->IsJSArray()) { | |
| 3269 __ ldr(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); | |
| 3270 } else { | |
| 3271 __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); | |
| 3272 } | |
| 3273 // Compare smis. | |
| 3274 __ cmp(key_reg, scratch); | |
| 3275 __ b(hs, &miss); | |
| 3276 | |
| 3277 __ add(scratch, | |
| 3278 elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
| 3279 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); | |
| 3280 __ str(value_reg, | |
| 3281 MemOperand(scratch, key_reg, LSL, kPointerSizeLog2 - kSmiTagSize)); | |
| 3282 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER | |
| 3283 __ RecordWrite(scratch, | |
| 3284 Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize), | |
| 3285 receiver_reg , elements_reg); | |
| 3286 #endif | |
| 3287 | |
| 3288 // value_reg (r0) is preserved. | |
| 3289 // Done. | |
| 3290 __ Ret(); | |
| 3291 | |
| 3292 __ bind(&miss); | |
| 3293 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss(); | |
| 3294 __ Jump(ic, RelocInfo::CODE_TARGET); | 3218 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 3295 | 3219 |
| 3296 // Return the generated code. | 3220 // Return the generated code. |
| 3297 return GetCode(NORMAL, NULL); | 3221 return GetCode(NORMAL, NULL); |
| 3298 } | 3222 } |
| 3299 | 3223 |
| 3300 | 3224 |
| 3225 MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic( |
| 3226 MapList* receiver_maps, |
| 3227 CodeList* handler_ics) { |
| 3228 // ----------- S t a t e ------------- |
| 3229 // -- r0 : value |
| 3230 // -- r1 : key |
| 3231 // -- r2 : receiver |
| 3232 // -- lr : return address |
| 3233 // -- r3 : scratch |
| 3234 // ----------------------------------- |
| 3235 Label miss; |
| 3236 __ JumpIfSmi(r2, &miss); |
| 3237 |
| 3238 int receiver_count = receiver_maps->length(); |
| 3239 __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset)); |
| 3240 for (int current = 0; current < receiver_count; ++current) { |
| 3241 Handle<Map> map(receiver_maps->at(current)); |
| 3242 Handle<Code> code(handler_ics->at(current)); |
| 3243 __ mov(ip, Operand(map)); |
| 3244 __ cmp(r3, ip); |
| 3245 __ Jump(code, RelocInfo::CODE_TARGET, eq); |
| 3246 } |
| 3247 |
| 3248 __ bind(&miss); |
| 3249 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
| 3250 __ Jump(miss_ic, RelocInfo::CODE_TARGET, al); |
| 3251 |
| 3252 // Return the generated code. |
| 3253 return GetCode(NORMAL, NULL, MEGAMORPHIC); |
| 3254 } |
| 3255 |
| 3256 |
| 3301 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { | 3257 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { |
| 3302 // ----------- S t a t e ------------- | 3258 // ----------- S t a t e ------------- |
| 3303 // -- r0 : argc | 3259 // -- r0 : argc |
| 3304 // -- r1 : constructor | 3260 // -- r1 : constructor |
| 3305 // -- lr : return address | 3261 // -- lr : return address |
| 3306 // -- [sp] : last argument | 3262 // -- [sp] : last argument |
| 3307 // ----------------------------------- | 3263 // ----------------------------------- |
| 3308 Label generic_stub_call; | 3264 Label generic_stub_call; |
| 3309 | 3265 |
| 3310 // Use r7 for holding undefined which is used in several places below. | 3266 // Use r7 for holding undefined which is used in several places below. |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3435 // construction. | 3391 // construction. |
| 3436 __ bind(&generic_stub_call); | 3392 __ bind(&generic_stub_call); |
| 3437 Handle<Code> code = masm()->isolate()->builtins()->JSConstructStubGeneric(); | 3393 Handle<Code> code = masm()->isolate()->builtins()->JSConstructStubGeneric(); |
| 3438 __ Jump(code, RelocInfo::CODE_TARGET); | 3394 __ Jump(code, RelocInfo::CODE_TARGET); |
| 3439 | 3395 |
| 3440 // Return the generated code. | 3396 // Return the generated code. |
| 3441 return GetCode(); | 3397 return GetCode(); |
| 3442 } | 3398 } |
| 3443 | 3399 |
| 3444 | 3400 |
| 3401 MaybeObject* ExternalArrayLoadStubCompiler::CompileLoad( |
| 3402 JSObject*receiver, ExternalArrayType array_type) { |
| 3403 // ----------- S t a t e ------------- |
| 3404 // -- lr : return address |
| 3405 // -- r0 : key |
| 3406 // -- r1 : receiver |
| 3407 // ----------------------------------- |
| 3408 MaybeObject* maybe_stub = |
| 3409 KeyedLoadExternalArrayStub(array_type).TryGetCode(); |
| 3410 Code* stub; |
| 3411 if (!maybe_stub->To(&stub)) return maybe_stub; |
| 3412 __ DispatchMap(r1, |
| 3413 r2, |
| 3414 Handle<Map>(receiver->map()), |
| 3415 Handle<Code>(stub), |
| 3416 DO_SMI_CHECK); |
| 3417 |
| 3418 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss(); |
| 3419 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 3420 |
| 3421 // Return the generated code. |
| 3422 return GetCode(); |
| 3423 } |
| 3424 |
| 3425 |
| 3426 MaybeObject* ExternalArrayStoreStubCompiler::CompileStore( |
| 3427 JSObject* receiver, ExternalArrayType array_type) { |
| 3428 // ----------- S t a t e ------------- |
| 3429 // -- r0 : value |
| 3430 // -- r1 : name |
| 3431 // -- r2 : receiver |
| 3432 // -- lr : return address |
| 3433 // ----------------------------------- |
| 3434 MaybeObject* maybe_stub = |
| 3435 KeyedStoreExternalArrayStub(array_type).TryGetCode(); |
| 3436 Code* stub; |
| 3437 if (!maybe_stub->To(&stub)) return maybe_stub; |
| 3438 __ DispatchMap(r2, |
| 3439 r3, |
| 3440 Handle<Map>(receiver->map()), |
| 3441 Handle<Code>(stub), |
| 3442 DONT_DO_SMI_CHECK); |
| 3443 |
| 3444 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
| 3445 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 3446 |
| 3447 return GetCode(); |
| 3448 } |
| 3449 |
| 3450 |
| 3451 #undef __ |
| 3452 #define __ ACCESS_MASM(masm) |
| 3453 |
| 3454 |
| 3445 static bool IsElementTypeSigned(ExternalArrayType array_type) { | 3455 static bool IsElementTypeSigned(ExternalArrayType array_type) { |
| 3446 switch (array_type) { | 3456 switch (array_type) { |
| 3447 case kExternalByteArray: | 3457 case kExternalByteArray: |
| 3448 case kExternalShortArray: | 3458 case kExternalShortArray: |
| 3449 case kExternalIntArray: | 3459 case kExternalIntArray: |
| 3450 return true; | 3460 return true; |
| 3451 | 3461 |
| 3452 case kExternalUnsignedByteArray: | 3462 case kExternalUnsignedByteArray: |
| 3453 case kExternalUnsignedShortArray: | 3463 case kExternalUnsignedShortArray: |
| 3454 case kExternalUnsignedIntArray: | 3464 case kExternalUnsignedIntArray: |
| 3455 return false; | 3465 return false; |
| 3456 | 3466 |
| 3457 default: | 3467 default: |
| 3458 UNREACHABLE(); | 3468 UNREACHABLE(); |
| 3459 return false; | 3469 return false; |
| 3460 } | 3470 } |
| 3461 } | 3471 } |
| 3462 | 3472 |
| 3463 | 3473 |
| 3464 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( | 3474 void KeyedLoadStubCompiler::GenerateLoadExternalArray( |
| 3465 JSObject* receiver_object, | 3475 MacroAssembler* masm, |
| 3466 ExternalArrayType array_type, | 3476 ExternalArrayType array_type) { |
| 3467 Code::Flags flags) { | |
| 3468 // ---------- S t a t e -------------- | 3477 // ---------- S t a t e -------------- |
| 3469 // -- lr : return address | 3478 // -- lr : return address |
| 3470 // -- r0 : key | 3479 // -- r0 : key |
| 3471 // -- r1 : receiver | 3480 // -- r1 : receiver |
| 3472 // ----------------------------------- | 3481 // ----------------------------------- |
| 3473 Label slow, failed_allocation; | 3482 Label miss_force_generic, slow, failed_allocation; |
| 3474 | 3483 |
| 3475 Register key = r0; | 3484 Register key = r0; |
| 3476 Register receiver = r1; | 3485 Register receiver = r1; |
| 3477 | 3486 |
| 3478 // Check that the object isn't a smi | 3487 // This stub is meant to be tail-jumped to, the receiver must already |
| 3479 __ JumpIfSmi(receiver, &slow); | 3488 // have been verified by the caller to not be a smi. |
| 3480 | 3489 |
| 3481 // Check that the key is a smi. | 3490 // Check that the key is a smi. |
| 3482 __ JumpIfNotSmi(key, &slow); | 3491 __ JumpIfNotSmi(key, &miss_force_generic); |
| 3483 | |
| 3484 // Make sure that we've got the right map. | |
| 3485 __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 3486 __ cmp(r2, Operand(Handle<Map>(receiver_object->map()))); | |
| 3487 __ b(ne, &slow); | |
| 3488 | 3492 |
| 3489 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 3493 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 3490 // r3: elements array | 3494 // r3: elements array |
| 3491 | 3495 |
| 3492 // Check that the index is in range. | 3496 // Check that the index is in range. |
| 3493 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); | 3497 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); |
| 3494 __ cmp(ip, Operand(key, ASR, kSmiTagSize)); | 3498 __ cmp(ip, Operand(key, ASR, kSmiTagSize)); |
| 3495 // Unsigned comparison catches both negative and too-large values. | 3499 // Unsigned comparison catches both negative and too-large values. |
| 3496 __ b(lo, &slow); | 3500 __ b(lo, &miss_force_generic); |
| 3497 | 3501 |
| 3498 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); | 3502 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); |
| 3499 // r3: base pointer of external storage | 3503 // r3: base pointer of external storage |
| 3500 | 3504 |
| 3501 // We are not untagging smi key and instead work with it | 3505 // We are not untagging smi key and instead work with it |
| 3502 // as if it was premultiplied by 2. | 3506 // as if it was premultiplied by 2. |
| 3503 ASSERT((kSmiTag == 0) && (kSmiTagSize == 1)); | 3507 ASSERT((kSmiTag == 0) && (kSmiTagSize == 1)); |
| 3504 | 3508 |
| 3505 Register value = r2; | 3509 Register value = r2; |
| 3506 switch (array_type) { | 3510 switch (array_type) { |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3623 __ b(ne, &box_int_1); | 3627 __ b(ne, &box_int_1); |
| 3624 // Tag integer as smi and return it. | 3628 // Tag integer as smi and return it. |
| 3625 __ mov(r0, Operand(value, LSL, kSmiTagSize)); | 3629 __ mov(r0, Operand(value, LSL, kSmiTagSize)); |
| 3626 __ Ret(); | 3630 __ Ret(); |
| 3627 | 3631 |
| 3628 Register hiword = value; // r2. | 3632 Register hiword = value; // r2. |
| 3629 Register loword = r3; | 3633 Register loword = r3; |
| 3630 | 3634 |
| 3631 __ bind(&box_int_0); | 3635 __ bind(&box_int_0); |
| 3632 // Integer does not have leading zeros. | 3636 // Integer does not have leading zeros. |
| 3633 GenerateUInt2Double(masm(), hiword, loword, r4, 0); | 3637 GenerateUInt2Double(masm, hiword, loword, r4, 0); |
| 3634 __ b(&done); | 3638 __ b(&done); |
| 3635 | 3639 |
| 3636 __ bind(&box_int_1); | 3640 __ bind(&box_int_1); |
| 3637 // Integer has one leading zero. | 3641 // Integer has one leading zero. |
| 3638 GenerateUInt2Double(masm(), hiword, loword, r4, 1); | 3642 GenerateUInt2Double(masm, hiword, loword, r4, 1); |
| 3639 | 3643 |
| 3640 | 3644 |
| 3641 __ bind(&done); | 3645 __ bind(&done); |
| 3642 // Integer was converted to double in registers hiword:loword. | 3646 // Integer was converted to double in registers hiword:loword. |
| 3643 // Wrap it into a HeapNumber. Don't use r0 and r1 as AllocateHeapNumber | 3647 // Wrap it into a HeapNumber. Don't use r0 and r1 as AllocateHeapNumber |
| 3644 // clobbers all registers - also when jumping due to exhausted young | 3648 // clobbers all registers - also when jumping due to exhausted young |
| 3645 // space. | 3649 // space. |
| 3646 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); | 3650 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); |
| 3647 __ AllocateHeapNumber(r4, r5, r7, r6, &slow); | 3651 __ AllocateHeapNumber(r4, r5, r7, r6, &slow); |
| 3648 | 3652 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3750 | 3754 |
| 3751 } else { | 3755 } else { |
| 3752 // Tag integer as smi and return it. | 3756 // Tag integer as smi and return it. |
| 3753 __ mov(r0, Operand(value, LSL, kSmiTagSize)); | 3757 __ mov(r0, Operand(value, LSL, kSmiTagSize)); |
| 3754 __ Ret(); | 3758 __ Ret(); |
| 3755 } | 3759 } |
| 3756 | 3760 |
| 3757 // Slow case, key and receiver still in r0 and r1. | 3761 // Slow case, key and receiver still in r0 and r1. |
| 3758 __ bind(&slow); | 3762 __ bind(&slow); |
| 3759 __ IncrementCounter( | 3763 __ IncrementCounter( |
| 3760 masm()->isolate()->counters()->keyed_load_external_array_slow(), | 3764 masm->isolate()->counters()->keyed_load_external_array_slow(), |
| 3761 1, r2, r3); | 3765 1, r2, r3); |
| 3762 | 3766 |
| 3763 // ---------- S t a t e -------------- | 3767 // ---------- S t a t e -------------- |
| 3764 // -- lr : return address | 3768 // -- lr : return address |
| 3765 // -- r0 : key | 3769 // -- r0 : key |
| 3766 // -- r1 : receiver | 3770 // -- r1 : receiver |
| 3767 // ----------------------------------- | 3771 // ----------------------------------- |
| 3768 | 3772 |
| 3769 __ Push(r1, r0); | 3773 __ Push(r1, r0); |
| 3770 | 3774 |
| 3771 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 3775 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
| 3772 | 3776 |
| 3773 return GetCode(flags); | 3777 __ bind(&miss_force_generic); |
| 3778 Code* stub = masm->isolate()->builtins()->builtin( |
| 3779 Builtins::kKeyedLoadIC_MissForceGeneric); |
| 3780 __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET); |
| 3774 } | 3781 } |
| 3775 | 3782 |
| 3776 | 3783 |
| 3777 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( | 3784 void KeyedStoreStubCompiler::GenerateStoreExternalArray( |
| 3778 JSObject* receiver_object, | 3785 MacroAssembler* masm, |
| 3779 ExternalArrayType array_type, | 3786 ExternalArrayType array_type) { |
| 3780 Code::Flags flags) { | |
| 3781 // ---------- S t a t e -------------- | 3787 // ---------- S t a t e -------------- |
| 3782 // -- r0 : value | 3788 // -- r0 : value |
| 3783 // -- r1 : key | 3789 // -- r1 : key |
| 3784 // -- r2 : receiver | 3790 // -- r2 : receiver |
| 3785 // -- lr : return address | 3791 // -- lr : return address |
| 3786 // ----------------------------------- | 3792 // ----------------------------------- |
| 3787 Label slow, check_heap_number; | 3793 Label slow, check_heap_number, miss_force_generic; |
| 3788 | 3794 |
| 3789 // Register usage. | 3795 // Register usage. |
| 3790 Register value = r0; | 3796 Register value = r0; |
| 3791 Register key = r1; | 3797 Register key = r1; |
| 3792 Register receiver = r2; | 3798 Register receiver = r2; |
| 3793 // r3 mostly holds the elements array or the destination external array. | 3799 // r3 mostly holds the elements array or the destination external array. |
| 3794 | 3800 |
| 3795 // Check that the object isn't a smi. | 3801 // This stub is meant to be tail-jumped to, the receiver must already |
| 3796 __ JumpIfSmi(receiver, &slow); | 3802 // have been verified by the caller to not be a smi. |
| 3797 | |
| 3798 // Make sure that we've got the right map. | |
| 3799 __ ldr(r3, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 3800 __ cmp(r3, Operand(Handle<Map>(receiver_object->map()))); | |
| 3801 __ b(ne, &slow); | |
| 3802 | 3803 |
| 3803 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 3804 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 3804 | 3805 |
| 3805 // Check that the key is a smi. | 3806 // Check that the key is a smi. |
| 3806 __ JumpIfNotSmi(key, &slow); | 3807 __ JumpIfNotSmi(key, &miss_force_generic); |
| 3807 | 3808 |
| 3808 // Check that the index is in range | 3809 // Check that the index is in range |
| 3809 __ SmiUntag(r4, key); | 3810 __ SmiUntag(r4, key); |
| 3810 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); | 3811 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); |
| 3811 __ cmp(r4, ip); | 3812 __ cmp(r4, ip); |
| 3812 // Unsigned comparison catches both negative and too-large values. | 3813 // Unsigned comparison catches both negative and too-large values. |
| 3813 __ b(hs, &slow); | 3814 __ b(hs, &miss_force_generic); |
| 3814 | 3815 |
| 3815 // Handle both smis and HeapNumbers in the fast path. Go to the | 3816 // Handle both smis and HeapNumbers in the fast path. Go to the |
| 3816 // runtime for all other kinds of values. | 3817 // runtime for all other kinds of values. |
| 3817 // r3: external array. | 3818 // r3: external array. |
| 3818 // r4: key (integer). | 3819 // r4: key (integer). |
| 3819 if (array_type == kExternalPixelArray) { | 3820 if (array_type == kExternalPixelArray) { |
| 3820 // Double to pixel conversion is only implemented in the runtime for now. | 3821 // Double to pixel conversion is only implemented in the runtime for now. |
| 3821 __ JumpIfNotSmi(value, &slow); | 3822 __ JumpIfNotSmi(value, &slow); |
| 3822 } else { | 3823 } else { |
| 3823 __ JumpIfNotSmi(value, &check_heap_number); | 3824 __ JumpIfNotSmi(value, &check_heap_number); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3841 case kExternalShortArray: | 3842 case kExternalShortArray: |
| 3842 case kExternalUnsignedShortArray: | 3843 case kExternalUnsignedShortArray: |
| 3843 __ strh(r5, MemOperand(r3, r4, LSL, 1)); | 3844 __ strh(r5, MemOperand(r3, r4, LSL, 1)); |
| 3844 break; | 3845 break; |
| 3845 case kExternalIntArray: | 3846 case kExternalIntArray: |
| 3846 case kExternalUnsignedIntArray: | 3847 case kExternalUnsignedIntArray: |
| 3847 __ str(r5, MemOperand(r3, r4, LSL, 2)); | 3848 __ str(r5, MemOperand(r3, r4, LSL, 2)); |
| 3848 break; | 3849 break; |
| 3849 case kExternalFloatArray: | 3850 case kExternalFloatArray: |
| 3850 // Perform int-to-float conversion and store to memory. | 3851 // Perform int-to-float conversion and store to memory. |
| 3851 StoreIntAsFloat(masm(), r3, r4, r5, r6, r7, r9); | 3852 StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9); |
| 3852 break; | 3853 break; |
| 3853 case kExternalDoubleArray: | 3854 case kExternalDoubleArray: |
| 3854 __ add(r3, r3, Operand(r4, LSL, 3)); | 3855 __ add(r3, r3, Operand(r4, LSL, 3)); |
| 3855 // r3: effective address of the double element | 3856 // r3: effective address of the double element |
| 3856 FloatingPointHelper::Destination destination; | 3857 FloatingPointHelper::Destination destination; |
| 3857 if (CpuFeatures::IsSupported(VFP3)) { | 3858 if (CpuFeatures::IsSupported(VFP3)) { |
| 3858 destination = FloatingPointHelper::kVFPRegisters; | 3859 destination = FloatingPointHelper::kVFPRegisters; |
| 3859 } else { | 3860 } else { |
| 3860 destination = FloatingPointHelper::kCoreRegisters; | 3861 destination = FloatingPointHelper::kCoreRegisters; |
| 3861 } | 3862 } |
| 3862 FloatingPointHelper::ConvertIntToDouble( | 3863 FloatingPointHelper::ConvertIntToDouble( |
| 3863 masm(), r5, destination, | 3864 masm, r5, destination, |
| 3864 d0, r6, r7, // These are: double_dst, dst1, dst2. | 3865 d0, r6, r7, // These are: double_dst, dst1, dst2. |
| 3865 r4, s2); // These are: scratch2, single_scratch. | 3866 r4, s2); // These are: scratch2, single_scratch. |
| 3866 if (destination == FloatingPointHelper::kVFPRegisters) { | 3867 if (destination == FloatingPointHelper::kVFPRegisters) { |
| 3867 CpuFeatures::Scope scope(VFP3); | 3868 CpuFeatures::Scope scope(VFP3); |
| 3868 __ vstr(d0, r3, 0); | 3869 __ vstr(d0, r3, 0); |
| 3869 } else { | 3870 } else { |
| 3870 __ str(r6, MemOperand(r3, 0)); | 3871 __ str(r6, MemOperand(r3, 0)); |
| 3871 __ str(r7, MemOperand(r3, Register::kSizeInBytes)); | 3872 __ str(r7, MemOperand(r3, Register::kSizeInBytes)); |
| 3872 } | 3873 } |
| 3873 break; | 3874 break; |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4080 __ str(r5, MemOperand(r3, r4, LSL, 2)); | 4081 __ str(r5, MemOperand(r3, r4, LSL, 2)); |
| 4081 break; | 4082 break; |
| 4082 default: | 4083 default: |
| 4083 UNREACHABLE(); | 4084 UNREACHABLE(); |
| 4084 break; | 4085 break; |
| 4085 } | 4086 } |
| 4086 } | 4087 } |
| 4087 } | 4088 } |
| 4088 } | 4089 } |
| 4089 | 4090 |
| 4090 // Slow case: call runtime. | 4091 // Slow case, key and receiver still in r0 and r1. |
| 4091 __ bind(&slow); | 4092 __ bind(&slow); |
| 4093 __ IncrementCounter( |
| 4094 masm->isolate()->counters()->keyed_load_external_array_slow(), |
| 4095 1, r2, r3); |
| 4092 | 4096 |
| 4093 // Entry registers are intact. | |
| 4094 // ---------- S t a t e -------------- | 4097 // ---------- S t a t e -------------- |
| 4095 // -- r0 : value | |
| 4096 // -- r1 : key | |
| 4097 // -- r2 : receiver | |
| 4098 // -- lr : return address | 4098 // -- lr : return address |
| 4099 // -- r0 : key |
| 4100 // -- r1 : receiver |
| 4101 // ----------------------------------- |
| 4102 Handle<Code> slow_ic = |
| 4103 masm->isolate()->builtins()->KeyedStoreIC_Slow(); |
| 4104 __ Jump(slow_ic, RelocInfo::CODE_TARGET); |
| 4105 |
| 4106 // Miss case, call the runtime. |
| 4107 __ bind(&miss_force_generic); |
| 4108 |
| 4109 // ---------- S t a t e -------------- |
| 4110 // -- lr : return address |
| 4111 // -- r0 : key |
| 4112 // -- r1 : receiver |
| 4099 // ----------------------------------- | 4113 // ----------------------------------- |
| 4100 | 4114 |
| 4101 // Push receiver, key and value for runtime call. | 4115 Handle<Code> miss_ic = |
| 4102 __ Push(r2, r1, r0); | 4116 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
| 4117 __ Jump(miss_ic, RelocInfo::CODE_TARGET); |
| 4118 } |
| 4103 | 4119 |
| 4104 __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes | |
| 4105 __ mov(r0, Operand(Smi::FromInt( | |
| 4106 Code::ExtractExtraICStateFromFlags(flags) & kStrictMode))); | |
| 4107 __ Push(r1, r0); | |
| 4108 | 4120 |
| 4109 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); | 4121 void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { |
| 4122 // ----------- S t a t e ------------- |
| 4123 // -- lr : return address |
| 4124 // -- r0 : key |
| 4125 // -- r1 : receiver |
| 4126 // ----------------------------------- |
| 4127 Label miss_force_generic; |
| 4110 | 4128 |
| 4111 return GetCode(flags); | 4129 // This stub is meant to be tail-jumped to, the receiver must already |
| 4130 // have been verified by the caller to not be a smi. |
| 4131 |
| 4132 // Check that the key is a smi. |
| 4133 __ JumpIfNotSmi(r0, &miss_force_generic); |
| 4134 |
| 4135 // Get the elements array. |
| 4136 __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset)); |
| 4137 __ AssertFastElements(r2); |
| 4138 |
| 4139 // Check that the key is within bounds. |
| 4140 __ ldr(r3, FieldMemOperand(r2, FixedArray::kLengthOffset)); |
| 4141 __ cmp(r0, Operand(r3)); |
| 4142 __ b(hs, &miss_force_generic); |
| 4143 |
| 4144 // Load the result and make sure it's not the hole. |
| 4145 __ add(r3, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 4146 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
| 4147 __ ldr(r4, |
| 4148 MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 4149 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 4150 __ cmp(r4, ip); |
| 4151 __ b(eq, &miss_force_generic); |
| 4152 __ mov(r0, r4); |
| 4153 __ Ret(); |
| 4154 |
| 4155 __ bind(&miss_force_generic); |
| 4156 Code* stub = masm->isolate()->builtins()->builtin( |
| 4157 Builtins::kKeyedLoadIC_MissForceGeneric); |
| 4158 __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET); |
| 4159 } |
| 4160 |
| 4161 |
| 4162 void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, |
| 4163 bool is_js_array) { |
| 4164 // ----------- S t a t e ------------- |
| 4165 // -- r0 : value |
| 4166 // -- r1 : key |
| 4167 // -- r2 : receiver |
| 4168 // -- lr : return address |
| 4169 // -- r3 : scratch |
| 4170 // -- r4 : scratch (elements) |
| 4171 // ----------------------------------- |
| 4172 Label miss_force_generic; |
| 4173 |
| 4174 Register value_reg = r0; |
| 4175 Register key_reg = r1; |
| 4176 Register receiver_reg = r2; |
| 4177 Register scratch = r3; |
| 4178 Register elements_reg = r4; |
| 4179 |
| 4180 // This stub is meant to be tail-jumped to, the receiver must already |
| 4181 // have been verified by the caller to not be a smi. |
| 4182 |
| 4183 // Check that the key is a smi. |
| 4184 __ JumpIfNotSmi(r0, &miss_force_generic); |
| 4185 |
| 4186 // Get the elements array and make sure it is a fast element array, not 'cow'. |
| 4187 __ ldr(elements_reg, |
| 4188 FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); |
| 4189 __ CheckMap(elements_reg, |
| 4190 scratch, |
| 4191 Heap::kFixedArrayMapRootIndex, |
| 4192 &miss_force_generic, |
| 4193 DONT_DO_SMI_CHECK); |
| 4194 |
| 4195 // Check that the key is within bounds. |
| 4196 if (is_js_array) { |
| 4197 __ ldr(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); |
| 4198 } else { |
| 4199 __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); |
| 4200 } |
| 4201 // Compare smis. |
| 4202 __ cmp(key_reg, scratch); |
| 4203 __ b(hs, &miss_force_generic); |
| 4204 |
| 4205 __ add(scratch, |
| 4206 elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 4207 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
| 4208 __ str(value_reg, |
| 4209 MemOperand(scratch, key_reg, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 4210 __ RecordWrite(scratch, |
| 4211 Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize), |
| 4212 receiver_reg , elements_reg); |
| 4213 |
| 4214 // value_reg (r0) is preserved. |
| 4215 // Done. |
| 4216 __ Ret(); |
| 4217 |
| 4218 __ bind(&miss_force_generic); |
| 4219 Handle<Code> ic = |
| 4220 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
| 4221 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 4112 } | 4222 } |
| 4113 | 4223 |
| 4114 | 4224 |
| 4115 #undef __ | 4225 #undef __ |
| 4116 | 4226 |
| 4117 } } // namespace v8::internal | 4227 } } // namespace v8::internal |
| 4118 | 4228 |
| 4119 #endif // V8_TARGET_ARCH_ARM | 4229 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |