| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2011-2012 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 |
| 11 // with the distribution. | 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
| 15 // | 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #if defined(V8_TARGET_ARCH_ARM) | 30 #if defined(V8_TARGET_ARCH_SH4) |
| 31 | 31 |
| 32 #include "assembler-arm.h" | 32 #include "assembler-sh4.h" |
| 33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
| 34 #include "codegen.h" | 34 #include "codegen.h" |
| 35 #include "disasm.h" | 35 #include "disasm.h" |
| 36 #include "ic-inl.h" | 36 #include "ic-inl.h" |
| 37 #include "runtime.h" | 37 #include "runtime.h" |
| 38 #include "stub-cache.h" | 38 #include "stub-cache.h" |
| 39 | 39 |
| 40 namespace v8 { | 40 namespace v8 { |
| 41 namespace internal { | 41 namespace internal { |
| 42 | 42 |
| 43 | 43 |
| 44 // ---------------------------------------------------------------------------- | 44 // ---------------------------------------------------------------------------- |
| 45 // Static IC stub generators. | 45 // Static IC stub generators. |
| 46 // | 46 // |
| 47 | 47 |
| 48 #define __ ACCESS_MASM(masm) | 48 #define __ ACCESS_MASM(masm) |
| 49 | 49 |
| 50 // ARM to SH4 mapping |
| 51 #include "map-sh4.h" |
| 50 | 52 |
| 51 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, | 53 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, |
| 52 Register type, | 54 Register type, |
| 53 Label* global_object) { | 55 Label* global_object) { |
| 54 // Register usage: | 56 // Register usage: |
| 55 // type: holds the receiver instance type on entry. | 57 // type: holds the receiver instance type on entry. |
| 56 __ cmp(type, Operand(JS_GLOBAL_OBJECT_TYPE)); | 58 __ cmpeq(type, Operand(JS_GLOBAL_OBJECT_TYPE)); |
| 57 __ b(eq, global_object); | 59 __ bt(global_object); |
| 58 __ cmp(type, Operand(JS_BUILTINS_OBJECT_TYPE)); | 60 __ cmpeq(type, Operand(JS_BUILTINS_OBJECT_TYPE)); |
| 59 __ b(eq, global_object); | 61 __ bt(global_object); |
| 60 __ cmp(type, Operand(JS_GLOBAL_PROXY_TYPE)); | 62 __ cmpeq(type, Operand(JS_GLOBAL_PROXY_TYPE)); |
| 61 __ b(eq, global_object); | 63 __ bt(global_object); |
| 62 } | 64 } |
| 63 | 65 |
| 64 | 66 |
| 65 // Generated code falls through if the receiver is a regular non-global | 67 // Generated code falls through if the receiver is a regular non-global |
| 66 // JS object with slow properties and no interceptors. | 68 // JS object with slow properties and no interceptors. |
| 67 static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm, | 69 static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm, |
| 68 Register receiver, | 70 Register receiver, |
| 69 Register elements, | 71 Register elements, |
| 70 Register t0, | 72 Register t0, |
| 71 Register t1, | 73 Register t1, |
| 72 Label* miss) { | 74 Label* miss) { |
| 73 // Register usage: | 75 // Register usage: |
| 74 // receiver: holds the receiver on entry and is unchanged. | 76 // receiver: holds the receiver on entry and is unchanged. |
| 75 // elements: holds the property dictionary on fall through. | 77 // elements: holds the property dictionary on fall through. |
| 76 // Scratch registers: | 78 // Scratch registers: |
| 77 // t0: used to holds the receiver map. | 79 // t0: used to holds the receiver map. |
| 78 // t1: used to holds the receiver instance type, receiver bit mask and | 80 // t1: used to holds the receiver instance type, receiver bit mask and |
| 79 // elements map. | 81 // elements map. |
| 80 | 82 |
| 81 // Check that the receiver isn't a smi. | 83 // Check that the receiver isn't a smi. |
| 82 __ JumpIfSmi(receiver, miss); | 84 __ JumpIfSmi(receiver, miss); |
| 83 | 85 |
| 84 // Check that the receiver is a valid JS object. | 86 // Check that the receiver is a valid JS object. |
| 85 __ CompareObjectType(receiver, t0, t1, FIRST_SPEC_OBJECT_TYPE); | 87 __ CompareObjectType(receiver, t0, t1, FIRST_SPEC_OBJECT_TYPE, ge); |
| 86 __ b(lt, miss); | 88 __ bf(miss); |
| 87 | 89 |
| 88 // If this assert fails, we have to check upper bound too. | 90 // If this assert fails, we have to check upper bound too. |
| 89 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); | 91 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); |
| 90 | 92 |
| 91 GenerateGlobalInstanceTypeCheck(masm, t1, miss); | 93 GenerateGlobalInstanceTypeCheck(masm, t1, miss); |
| 92 | 94 |
| 93 // Check that the global object does not require access checks. | 95 // Check that the global object does not require access checks. |
| 94 __ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset)); | 96 __ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset)); |
| 95 __ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) | | 97 __ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) | |
| 96 (1 << Map::kHasNamedInterceptor))); | 98 (1 << Map::kHasNamedInterceptor))); |
| 97 __ b(ne, miss); | 99 __ bf(miss); |
| 98 | 100 |
| 99 __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 101 __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| 100 __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset)); | 102 __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset)); |
| 101 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 103 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
| 102 __ cmp(t1, ip); | 104 __ cmpeq(t1, ip); |
| 103 __ b(ne, miss); | 105 __ bf(miss); |
| 104 } | 106 } |
| 105 | 107 |
| 106 | 108 |
| 107 // Helper function used from LoadIC/CallIC GenerateNormal. | 109 // Helper function used from LoadIC/CallIC GenerateNormal. |
| 108 // | 110 // |
| 109 // elements: Property dictionary. It is not clobbered if a jump to the miss | 111 // elements: Property dictionary. It is not clobbered if a jump to the miss |
| 110 // label is done. | 112 // label is done. |
| 111 // name: Property name. It is not clobbered if a jump to the miss label is | 113 // name: Property name. It is not clobbered if a jump to the miss label is |
| 112 // done | 114 // done |
| 113 // result: Register for the result. It is only updated if a jump to the miss | 115 // result: Register for the result. It is only updated if a jump to the miss |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 // is a normal property that is not read only. | 194 // is a normal property that is not read only. |
| 193 __ bind(&done); // scratch2 == elements + 4 * index | 195 __ bind(&done); // scratch2 == elements + 4 * index |
| 194 const int kElementsStartOffset = StringDictionary::kHeaderSize + | 196 const int kElementsStartOffset = StringDictionary::kHeaderSize + |
| 195 StringDictionary::kElementsStartIndex * kPointerSize; | 197 StringDictionary::kElementsStartIndex * kPointerSize; |
| 196 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 198 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
| 197 const int kTypeAndReadOnlyMask = | 199 const int kTypeAndReadOnlyMask = |
| 198 (PropertyDetails::TypeField::kMask | | 200 (PropertyDetails::TypeField::kMask | |
| 199 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; | 201 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; |
| 200 __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset)); | 202 __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset)); |
| 201 __ tst(scratch1, Operand(kTypeAndReadOnlyMask)); | 203 __ tst(scratch1, Operand(kTypeAndReadOnlyMask)); |
| 202 __ b(ne, miss); | 204 __ bf(miss); |
| 203 | 205 |
| 204 // Store the value at the masked, scaled index and return. | 206 // Store the value at the masked, scaled index and return. |
| 205 const int kValueOffset = kElementsStartOffset + kPointerSize; | 207 const int kValueOffset = kElementsStartOffset + kPointerSize; |
| 206 __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag)); | 208 __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag)); |
| 207 __ str(value, MemOperand(scratch2)); | 209 __ str(value, MemOperand(scratch2)); |
| 208 | 210 |
| 209 // Update the write barrier. Make sure not to clobber the value. | 211 // Update the write barrier. Make sure not to clobber the value. |
| 210 __ mov(scratch1, value); | 212 __ mov(scratch1, value); |
| 211 __ RecordWrite( | 213 __ RecordWrite( |
| 212 elements, scratch2, scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs); | 214 elements, scratch2, scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset)); | 278 __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset)); |
| 277 __ tst(scratch, | 279 __ tst(scratch, |
| 278 Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit))); | 280 Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit))); |
| 279 __ b(ne, slow); | 281 __ b(ne, slow); |
| 280 // Check that the object is some kind of JS object EXCEPT JS Value type. | 282 // Check that the object is some kind of JS object EXCEPT JS Value type. |
| 281 // In the case that the object is a value-wrapper object, | 283 // In the case that the object is a value-wrapper object, |
| 282 // we enter the runtime system to make sure that indexing into string | 284 // we enter the runtime system to make sure that indexing into string |
| 283 // objects work as intended. | 285 // objects work as intended. |
| 284 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 286 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
| 285 __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 287 __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
| 286 __ cmp(scratch, Operand(JS_OBJECT_TYPE)); | 288 __ cmpge(scratch, Operand(JS_OBJECT_TYPE)); |
| 287 __ b(lt, slow); | 289 __ bf(slow); |
| 288 } | 290 } |
| 289 | 291 |
| 290 | 292 |
| 291 // Loads an indexed element from a fast case array. | 293 // Loads an indexed element from a fast case array. |
| 292 // If not_fast_array is NULL, doesn't perform the elements map check. | 294 // If not_fast_array is NULL, doesn't perform the elements map check. |
| 293 static void GenerateFastArrayLoad(MacroAssembler* masm, | 295 static void GenerateFastArrayLoad(MacroAssembler* masm, |
| 294 Register receiver, | 296 Register receiver, |
| 295 Register key, | 297 Register key, |
| 296 Register elements, | 298 Register elements, |
| 297 Register scratch1, | 299 Register scratch1, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 326 // Check that the object is in fast mode and writable. | 328 // Check that the object is in fast mode and writable. |
| 327 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset)); | 329 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset)); |
| 328 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 330 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
| 329 __ cmp(scratch1, ip); | 331 __ cmp(scratch1, ip); |
| 330 __ b(ne, not_fast_array); | 332 __ b(ne, not_fast_array); |
| 331 } else { | 333 } else { |
| 332 __ AssertFastElements(elements); | 334 __ AssertFastElements(elements); |
| 333 } | 335 } |
| 334 // Check that the key (index) is within bounds. | 336 // Check that the key (index) is within bounds. |
| 335 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset)); | 337 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
| 336 __ cmp(key, Operand(scratch1)); | 338 __ cmphs(key, scratch1); |
| 337 __ b(hs, out_of_range); | 339 __ bt(out_of_range); |
| 338 // Fast case: Do the load. | 340 // Fast case: Do the load. |
| 339 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 341 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 340 // The key is a smi. | 342 // The key is a smi. |
| 341 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); | 343 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
| 342 __ ldr(scratch2, | 344 __ lsl(scratch2, key, Operand(kPointerSizeLog2 - kSmiTagSize)); |
| 343 MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize)); | 345 __ ldr(scratch2, MemOperand(scratch1, scratch2)); |
| 344 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 346 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 345 __ cmp(scratch2, ip); | 347 __ cmp(scratch2, ip); |
| 346 // In case the loaded value is the_hole we have to consult GetProperty | 348 // In case the loaded value is the_hole we have to consult GetProperty |
| 347 // to ensure the prototype chain is searched. | 349 // to ensure the prototype chain is searched. |
| 348 __ b(eq, out_of_range); | 350 __ b(eq, out_of_range); |
| 349 __ mov(result, scratch2); | 351 __ mov(result, scratch2); |
| 350 } | 352 } |
| 351 | 353 |
| 352 | 354 |
| 353 // Checks whether a key is an array index string or a symbol string. | 355 // Checks whether a key is an array index string or a symbol string. |
| 354 // Falls through if a key is a symbol. | 356 // Falls through if a key is a symbol. |
| 355 static void GenerateKeyStringCheck(MacroAssembler* masm, | 357 static void GenerateKeyStringCheck(MacroAssembler* masm, |
| 356 Register key, | 358 Register key, |
| 357 Register map, | 359 Register map, |
| 358 Register hash, | 360 Register hash, |
| 359 Label* index_string, | 361 Label* index_string, |
| 360 Label* not_symbol) { | 362 Label* not_symbol) { |
| 361 // The key is not a smi. | 363 // The key is not a smi. |
| 362 // Is it a string? | 364 // Is it a string? |
| 363 __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE); | 365 __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE, ge); |
| 364 __ b(ge, not_symbol); | 366 __ bt(not_symbol); |
| 365 | 367 |
| 366 // Is the string an array index, with cached numeric value? | 368 // Is the string an array index, with cached numeric value? |
| 367 __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset)); | 369 __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset)); |
| 368 __ tst(hash, Operand(String::kContainsCachedArrayIndexMask)); | 370 __ tst(hash, Operand(String::kContainsCachedArrayIndexMask)); |
| 369 __ b(eq, index_string); | 371 __ b(eq, index_string); |
| 370 | 372 |
| 371 // Is the string a symbol? | 373 // Is the string a symbol? |
| 372 // map: key map | 374 // map: key map |
| 373 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 375 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
| 374 STATIC_ASSERT(kSymbolTag != 0); | 376 STATIC_ASSERT(kSymbolTag != 0); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 400 argc); | 402 argc); |
| 401 Isolate::Current()->stub_cache()->GenerateProbe( | 403 Isolate::Current()->stub_cache()->GenerateProbe( |
| 402 masm, flags, r1, r2, r3, r4, r5, r6); | 404 masm, flags, r1, r2, r3, r4, r5, r6); |
| 403 | 405 |
| 404 // If the stub cache probing failed, the receiver might be a value. | 406 // If the stub cache probing failed, the receiver might be a value. |
| 405 // For value objects, we use the map of the prototype objects for | 407 // For value objects, we use the map of the prototype objects for |
| 406 // the corresponding JSValue for the cache and that is what we need | 408 // the corresponding JSValue for the cache and that is what we need |
| 407 // to probe. | 409 // to probe. |
| 408 // | 410 // |
| 409 // Check for number. | 411 // Check for number. |
| 410 __ JumpIfSmi(r1, &number); | 412 __ JumpIfSmi(r1, &number, Label::kNear); |
| 411 __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE); | 413 __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE, eq); |
| 412 __ b(ne, &non_number); | 414 __ bf_near(&non_number); |
| 413 __ bind(&number); | 415 __ bind(&number); |
| 414 StubCompiler::GenerateLoadGlobalFunctionPrototype( | 416 StubCompiler::GenerateLoadGlobalFunctionPrototype( |
| 415 masm, Context::NUMBER_FUNCTION_INDEX, r1); | 417 masm, Context::NUMBER_FUNCTION_INDEX, r1); |
| 416 __ b(&probe); | 418 __ b(&probe); |
| 417 | 419 |
| 418 // Check for string. | 420 // Check for string. |
| 419 __ bind(&non_number); | 421 __ bind(&non_number); |
| 420 __ cmp(r3, Operand(FIRST_NONSTRING_TYPE)); | 422 __ cmphs(r3, Operand(FIRST_NONSTRING_TYPE)); |
| 421 __ b(hs, &non_string); | 423 __ bt_near(&non_string); |
| 422 StubCompiler::GenerateLoadGlobalFunctionPrototype( | 424 StubCompiler::GenerateLoadGlobalFunctionPrototype( |
| 423 masm, Context::STRING_FUNCTION_INDEX, r1); | 425 masm, Context::STRING_FUNCTION_INDEX, r1); |
| 424 __ b(&probe); | 426 __ b(&probe); |
| 425 | 427 |
| 426 // Check for boolean. | 428 // Check for boolean. |
| 427 __ bind(&non_string); | 429 __ bind(&non_string); |
| 428 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 430 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 429 __ cmp(r1, ip); | 431 __ cmp(r1, ip); |
| 430 __ b(eq, &boolean); | 432 __ b(eq, &boolean); |
| 431 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 433 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 447 static void GenerateFunctionTailCall(MacroAssembler* masm, | 449 static void GenerateFunctionTailCall(MacroAssembler* masm, |
| 448 int argc, | 450 int argc, |
| 449 Label* miss, | 451 Label* miss, |
| 450 Register scratch) { | 452 Register scratch) { |
| 451 // r1: function | 453 // r1: function |
| 452 | 454 |
| 453 // Check that the value isn't a smi. | 455 // Check that the value isn't a smi. |
| 454 __ JumpIfSmi(r1, miss); | 456 __ JumpIfSmi(r1, miss); |
| 455 | 457 |
| 456 // Check that the value is a JSFunction. | 458 // Check that the value is a JSFunction. |
| 457 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE); | 459 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE, eq); |
| 458 __ b(ne, miss); | 460 __ bf(miss); |
| 459 | 461 |
| 460 // Invoke the function. | 462 // Invoke the function. |
| 461 ParameterCount actual(argc); | 463 ParameterCount actual(argc); |
| 462 __ InvokeFunction(r1, actual, JUMP_FUNCTION, | 464 __ InvokeFunction(r1, actual, JUMP_FUNCTION, |
| 463 NullCallWrapper(), CALL_AS_METHOD); | 465 NullCallWrapper(), CALL_AS_METHOD); |
| 464 } | 466 } |
| 465 | 467 |
| 466 | 468 |
| 467 void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) { | 469 void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) { |
| 468 // ----------- S t a t e ------------- | 470 // ----------- S t a t e ------------- |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 __ Push(r3, r2); | 514 __ Push(r3, r2); |
| 513 | 515 |
| 514 // Call the entry. | 516 // Call the entry. |
| 515 __ mov(r0, Operand(2)); | 517 __ mov(r0, Operand(2)); |
| 516 __ mov(r1, Operand(ExternalReference(IC_Utility(id), isolate))); | 518 __ mov(r1, Operand(ExternalReference(IC_Utility(id), isolate))); |
| 517 | 519 |
| 518 CEntryStub stub(1); | 520 CEntryStub stub(1); |
| 519 __ CallStub(&stub); | 521 __ CallStub(&stub); |
| 520 | 522 |
| 521 // Move result to r1 and leave the internal frame. | 523 // Move result to r1 and leave the internal frame. |
| 522 __ mov(r1, Operand(r0)); | 524 __ mov(r1, r0); |
| 523 } | 525 } |
| 524 | 526 |
| 525 // Check if the receiver is a global object of some sort. | 527 // Check if the receiver is a global object of some sort. |
| 526 // This can happen only for regular CallIC but not KeyedCallIC. | 528 // This can happen only for regular CallIC but not KeyedCallIC. |
| 527 if (id == IC::kCallIC_Miss) { | 529 if (id == IC::kCallIC_Miss) { |
| 528 Label invoke, global; | 530 Label invoke, global; |
| 529 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver | 531 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver |
| 530 __ JumpIfSmi(r2, &invoke); | 532 __ JumpIfSmi(r2, &invoke, Label::kNear); |
| 531 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE); | 533 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE, eq); |
| 532 __ b(eq, &global); | 534 __ bt_near(&global); |
| 533 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE)); | 535 __ cmpeq(r3, Operand(JS_BUILTINS_OBJECT_TYPE)); |
| 534 __ b(ne, &invoke); | 536 __ bf_near(&invoke); |
| 535 | 537 |
| 536 // Patch the receiver on the stack. | 538 // Patch the receiver on the stack. |
| 537 __ bind(&global); | 539 __ bind(&global); |
| 538 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); | 540 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); |
| 539 __ str(r2, MemOperand(sp, argc * kPointerSize)); | 541 __ str(r2, MemOperand(sp, argc * kPointerSize)); |
| 540 __ bind(&invoke); | 542 __ bind(&invoke); |
| 541 } | 543 } |
| 542 | 544 |
| 543 // Invoke the function. | 545 // Invoke the function. |
| 544 CallKind call_kind = CallICBase::Contextual::decode(extra_state) | 546 CallKind call_kind = CallICBase::Contextual::decode(extra_state) |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 602 GenerateFunctionTailCall(masm, argc, &slow_call, r0); | 604 GenerateFunctionTailCall(masm, argc, &slow_call, r0); |
| 603 | 605 |
| 604 __ bind(&check_number_dictionary); | 606 __ bind(&check_number_dictionary); |
| 605 // r2: key | 607 // r2: key |
| 606 // r3: elements map | 608 // r3: elements map |
| 607 // r4: elements | 609 // r4: elements |
| 608 // Check whether the elements is a number dictionary. | 610 // Check whether the elements is a number dictionary. |
| 609 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 611 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
| 610 __ cmp(r3, ip); | 612 __ cmp(r3, ip); |
| 611 __ b(ne, &slow_load); | 613 __ b(ne, &slow_load); |
| 612 __ mov(r0, Operand(r2, ASR, kSmiTagSize)); | 614 __ asr(r0, r2, Operand(kSmiTagSize)); |
| 613 // r0: untagged index | 615 // r0: untagged index |
| 614 __ LoadFromNumberDictionary(&slow_load, r4, r2, r1, r0, r3, r5); | 616 __ LoadFromNumberDictionary(&slow_load, r4, r2, r1, r0, r3, r5); |
| 615 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, r0, r3); | 617 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, r0, r3); |
| 616 __ jmp(&do_call); | 618 __ jmp(&do_call); |
| 617 | 619 |
| 618 __ bind(&slow_load); | 620 __ bind(&slow_load); |
| 619 // This branch is taken when calling KeyedCallIC_Miss is neither required | 621 // This branch is taken when calling KeyedCallIC_Miss is neither required |
| 620 // nor beneficial. | 622 // nor beneficial. |
| 621 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, r0, r3); | 623 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, r0, r3); |
| 622 { | 624 { |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 763 Register scratch3, | 765 Register scratch3, |
| 764 Label* unmapped_case, | 766 Label* unmapped_case, |
| 765 Label* slow_case) { | 767 Label* slow_case) { |
| 766 Heap* heap = masm->isolate()->heap(); | 768 Heap* heap = masm->isolate()->heap(); |
| 767 | 769 |
| 768 // Check that the receiver is a JSObject. Because of the map check | 770 // Check that the receiver is a JSObject. Because of the map check |
| 769 // later, we do not need to check for interceptors or whether it | 771 // later, we do not need to check for interceptors or whether it |
| 770 // requires access checks. | 772 // requires access checks. |
| 771 __ JumpIfSmi(object, slow_case); | 773 __ JumpIfSmi(object, slow_case); |
| 772 // Check that the object is some kind of JSObject. | 774 // Check that the object is some kind of JSObject. |
| 773 __ CompareObjectType(object, scratch1, scratch2, FIRST_JS_RECEIVER_TYPE); | 775 __ CompareObjectType(object, scratch1, scratch2, FIRST_JS_RECEIVER_TYPE, ge); |
| 774 __ b(lt, slow_case); | 776 __ bf(slow_case); |
| 775 | 777 |
| 776 // Check that the key is a positive smi. | 778 // Check that the key is a positive smi. |
| 777 __ tst(key, Operand(0x80000001)); | 779 __ tst(key, Operand(0x80000001)); |
| 778 __ b(ne, slow_case); | 780 __ b(ne, slow_case); |
| 779 | 781 |
| 780 // Load the elements into scratch1 and check its map. | 782 // Load the elements into scratch1 and check its map. |
| 781 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map()); | 783 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map()); |
| 782 __ ldr(scratch1, FieldMemOperand(object, JSObject::kElementsOffset)); | 784 __ ldr(scratch1, FieldMemOperand(object, JSObject::kElementsOffset)); |
| 783 __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK); | 785 __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK); |
| 784 | 786 |
| 785 // Check if element is in the range of mapped arguments. If not, jump | 787 // Check if element is in the range of mapped arguments. If not, jump |
| 786 // to the unmapped lookup with the parameter map in scratch1. | 788 // to the unmapped lookup with the parameter map in scratch1. |
| 787 __ ldr(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset)); | 789 __ ldr(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset)); |
| 788 __ sub(scratch2, scratch2, Operand(Smi::FromInt(2))); | 790 __ sub(scratch2, scratch2, Operand(Smi::FromInt(2))); |
| 789 __ cmp(key, Operand(scratch2)); | 791 __ cmphs(key, scratch2); |
| 790 __ b(cs, unmapped_case); | 792 __ b(t, unmapped_case); |
| 791 | 793 |
| 792 // Load element index and check whether it is the hole. | 794 // Load element index and check whether it is the hole. |
| 793 const int kOffset = | 795 const int kOffset = |
| 794 FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag; | 796 FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag; |
| 795 | 797 |
| 796 __ mov(scratch3, Operand(kPointerSize >> 1)); | 798 __ mov(scratch3, Operand(kPointerSize >> 1)); |
| 797 __ mul(scratch3, key, scratch3); | 799 __ mul(scratch3, key, scratch3); |
| 798 __ add(scratch3, scratch3, Operand(kOffset)); | 800 __ add(scratch3, scratch3, Operand(kOffset)); |
| 799 | 801 |
| 800 __ ldr(scratch2, MemOperand(scratch1, scratch3)); | 802 __ ldr(scratch2, MemOperand(scratch1, scratch3)); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 822 // second element of the parameter_map. The parameter_map register | 824 // second element of the parameter_map. The parameter_map register |
| 823 // must be loaded with the parameter map of the arguments object and is | 825 // must be loaded with the parameter map of the arguments object and is |
| 824 // overwritten. | 826 // overwritten. |
| 825 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; | 827 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; |
| 826 Register backing_store = parameter_map; | 828 Register backing_store = parameter_map; |
| 827 __ ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset)); | 829 __ ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset)); |
| 828 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map()); | 830 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map()); |
| 829 __ CheckMap(backing_store, scratch, fixed_array_map, slow_case, | 831 __ CheckMap(backing_store, scratch, fixed_array_map, slow_case, |
| 830 DONT_DO_SMI_CHECK); | 832 DONT_DO_SMI_CHECK); |
| 831 __ ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset)); | 833 __ ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset)); |
| 832 __ cmp(key, Operand(scratch)); | 834 __ cmphs(key, scratch); |
| 833 __ b(cs, slow_case); | 835 __ b(t, slow_case); |
| 834 __ mov(scratch, Operand(kPointerSize >> 1)); | 836 __ mov(scratch, Operand(kPointerSize >> 1)); |
| 835 __ mul(scratch, key, scratch); | 837 __ mul(scratch, key, scratch); |
| 836 __ add(scratch, | 838 __ add(scratch, |
| 837 scratch, | 839 scratch, |
| 838 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 840 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 839 return MemOperand(backing_store, scratch); | 841 return MemOperand(backing_store, scratch); |
| 840 } | 842 } |
| 841 | 843 |
| 842 | 844 |
| 843 void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) { | 845 void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) { |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 992 | 994 |
| 993 __ bind(&check_number_dictionary); | 995 __ bind(&check_number_dictionary); |
| 994 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 996 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 995 __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset)); | 997 __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset)); |
| 996 | 998 |
| 997 // Check whether the elements is a number dictionary. | 999 // Check whether the elements is a number dictionary. |
| 998 // r0: key | 1000 // r0: key |
| 999 // r3: elements map | 1001 // r3: elements map |
| 1000 // r4: elements | 1002 // r4: elements |
| 1001 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 1003 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
| 1002 __ cmp(r3, ip); | 1004 __ cmpeq(r3, ip); |
| 1003 __ b(ne, &slow); | 1005 __ bf(&slow); |
| 1004 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); | 1006 __ asr(r2, r0, Operand(kSmiTagSize)); |
| 1005 __ LoadFromNumberDictionary(&slow, r4, r0, r0, r2, r3, r5); | 1007 __ LoadFromNumberDictionary(&slow, r4, r0, r0, r2, r3, r5); |
| 1006 __ Ret(); | 1008 __ Ret(); |
| 1007 | 1009 |
| 1008 // Slow case, key and receiver still in r0 and r1. | 1010 // Slow case, key and receiver still in r0 and r1. |
| 1009 __ bind(&slow); | 1011 __ bind(&slow); |
| 1010 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), | 1012 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), |
| 1011 1, r2, r3); | 1013 1, r2, r3); |
| 1012 GenerateRuntimeGetProperty(masm); | 1014 GenerateRuntimeGetProperty(masm); |
| 1013 | 1015 |
| 1014 __ bind(&check_string); | 1016 __ bind(&check_string); |
| 1015 GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow); | 1017 GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow); |
| 1016 | 1018 |
| 1017 GenerateKeyedLoadReceiverCheck( | 1019 GenerateKeyedLoadReceiverCheck( |
| 1018 masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow); | 1020 masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow); |
| 1019 | 1021 |
| 1020 // If the receiver is a fast-case object, check the keyed lookup | 1022 // If the receiver is a fast-case object, check the keyed lookup |
| 1021 // cache. Otherwise probe the dictionary. | 1023 // cache. Otherwise probe the dictionary. |
| 1022 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset)); | 1024 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset)); |
| 1023 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset)); | 1025 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset)); |
| 1024 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 1026 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
| 1025 __ cmp(r4, ip); | 1027 __ cmp(r4, ip); |
| 1026 __ b(eq, &probe_dictionary); | 1028 __ bt(&probe_dictionary); |
| 1027 | 1029 |
| 1028 // Load the map of the receiver, compute the keyed lookup cache hash | 1030 // Load the map of the receiver, compute the keyed lookup cache hash |
| 1029 // based on 32 bits of the map pointer and the string hash. | 1031 // based on 32 bits of the map pointer and the string hash. |
| 1030 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 1032 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 1031 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift)); | 1033 __ asr(r3, r2, Operand(KeyedLookupCache::kMapHashShift)); |
| 1032 __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset)); | 1034 __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset)); |
| 1033 __ eor(r3, r3, Operand(r4, ASR, String::kHashShift)); | 1035 __ asr(r4, r4, Operand(String::kHashShift)); |
| 1036 __ eor(r3, r3, r4); |
| 1034 int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask; | 1037 int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask; |
| 1035 __ And(r3, r3, Operand(mask)); | 1038 __ land(r3, r3, Operand(mask)); |
| 1036 | 1039 |
| 1037 // Load the key (consisting of map and symbol) from the cache and | 1040 // Load the key (consisting of map and symbol) from the cache and |
| 1038 // check for match. | 1041 // check for match. |
| 1039 Label load_in_object_property; | 1042 Label load_in_object_property; |
| 1040 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket; | 1043 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket; |
| 1041 Label hit_on_nth_entry[kEntriesPerBucket]; | 1044 Label hit_on_nth_entry[kEntriesPerBucket]; |
| 1042 ExternalReference cache_keys = | 1045 ExternalReference cache_keys = |
| 1043 ExternalReference::keyed_lookup_cache_keys(isolate); | 1046 ExternalReference::keyed_lookup_cache_keys(isolate); |
| 1044 | 1047 |
| 1045 __ mov(r4, Operand(cache_keys)); | 1048 __ mov(r4, Operand(cache_keys)); |
| 1046 __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1)); | 1049 __ lsl(r5, r3, Operand(kPointerSizeLog2 + 1)); |
| 1050 __ add(r4, r4, r5); |
| 1047 | 1051 |
| 1048 for (int i = 0; i < kEntriesPerBucket - 1; i++) { | 1052 for (int i = 0; i < kEntriesPerBucket - 1; i++) { |
| 1049 Label try_next_entry; | 1053 Label try_next_entry; |
| 1050 // Load map and move r4 to next entry. | 1054 // Load map and move r4 to next entry. |
| 1051 __ ldr(r5, MemOperand(r4, kPointerSize * 2, PostIndex)); | 1055 __ ldr(r5, MemOperand(r4, kPointerSize * 2, PostIndex)); |
| 1052 __ cmp(r2, r5); | 1056 __ cmp(r2, r5); |
| 1053 __ b(ne, &try_next_entry); | 1057 __ b(ne, &try_next_entry); |
| 1054 __ ldr(r5, MemOperand(r4, -kPointerSize)); // Load symbol | 1058 __ ldr(r5, MemOperand(r4, -kPointerSize)); // Load symbol |
| 1055 __ cmp(r0, r5); | 1059 __ cmp(r0, r5); |
| 1056 __ b(eq, &hit_on_nth_entry[i]); | 1060 __ b(eq, &hit_on_nth_entry[i]); |
| 1057 __ bind(&try_next_entry); | 1061 __ bind(&try_next_entry); |
| 1058 } | 1062 } |
| 1059 | 1063 |
| 1060 // Last entry: Load map and move r4 to symbol. | 1064 // Last entry: Load map and move r4 to symbol. |
| 1061 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); | 1065 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); |
| 1062 __ cmp(r2, r5); | 1066 __ cmp(r2, r5); |
| 1063 __ b(ne, &slow); | 1067 __ b(ne, &slow); |
| 1064 __ ldr(r5, MemOperand(r4)); | 1068 __ ldr(r5, MemOperand(r4)); |
| 1065 __ cmp(r0, r5); | 1069 __ cmpeq(r0, r5); |
| 1066 __ b(ne, &slow); | 1070 __ bf(&slow); |
| 1067 | 1071 |
| 1068 // Get field offset. | 1072 // Get field offset. |
| 1069 // r0 : key | 1073 // r0 : key |
| 1070 // r1 : receiver | 1074 // r1 : receiver |
| 1071 // r2 : receiver's map | 1075 // r2 : receiver's map |
| 1072 // r3 : lookup cache index | 1076 // r3 : lookup cache index |
| 1073 ExternalReference cache_field_offsets = | 1077 ExternalReference cache_field_offsets = |
| 1074 ExternalReference::keyed_lookup_cache_field_offsets(isolate); | 1078 ExternalReference::keyed_lookup_cache_field_offsets(isolate); |
| 1075 | 1079 |
| 1076 // Hit on nth entry. | 1080 // Hit on nth entry. |
| 1077 for (int i = kEntriesPerBucket - 1; i >= 0; i--) { | 1081 for (int i = kEntriesPerBucket - 1; i >= 0; i--) { |
| 1078 __ bind(&hit_on_nth_entry[i]); | 1082 __ bind(&hit_on_nth_entry[i]); |
| 1079 __ mov(r4, Operand(cache_field_offsets)); | 1083 __ mov(r4, Operand(cache_field_offsets)); |
| 1080 if (i != 0) { | 1084 if (i != 0) { |
| 1081 __ add(r3, r3, Operand(i)); | 1085 __ add(r3, r3, Operand(i)); |
| 1082 } | 1086 } |
| 1083 __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2)); | 1087 __ lsl(r6, r3, Operand(kPointerSizeLog2)); |
| 1088 __ ldr(r5, MemOperand(r4, r6)); |
| 1084 __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset)); | 1089 __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset)); |
| 1085 __ sub(r5, r5, r6, SetCC); | 1090 __ sub(r5, r5, r6); |
| 1086 __ b(ge, &property_array_property); | 1091 __ cmpge(r5, Operand(0)); |
| 1092 __ bt(&property_array_property); |
| 1087 if (i != 0) { | 1093 if (i != 0) { |
| 1088 __ jmp(&load_in_object_property); | 1094 __ jmp(&load_in_object_property); |
| 1089 } | 1095 } |
| 1090 } | 1096 } |
| 1091 | 1097 |
| 1092 // Load in-object property. | 1098 // Load in-object property. |
| 1093 __ bind(&load_in_object_property); | 1099 __ bind(&load_in_object_property); |
| 1094 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset)); | 1100 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset)); |
| 1095 __ add(r6, r6, r5); // Index from start of object. | 1101 __ add(r6, r6, r5); // Index from start of object. |
| 1096 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag. | 1102 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag. |
| 1097 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2)); | 1103 __ lsl(r0, r6, Operand(kPointerSizeLog2)); |
| 1104 __ ldr(r0, MemOperand(r1, r0)); |
| 1098 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), | 1105 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), |
| 1099 1, r2, r3); | 1106 1, r2, r3); |
| 1100 __ Ret(); | 1107 __ Ret(); |
| 1101 | 1108 |
| 1102 // Load property array property. | 1109 // Load property array property. |
| 1103 __ bind(&property_array_property); | 1110 __ bind(&property_array_property); |
| 1104 __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset)); | 1111 __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset)); |
| 1105 __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 1112 __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 1106 __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2)); | 1113 __ lsl(r0, r5, Operand(kPointerSizeLog2)); |
| 1114 __ ldr(r0, MemOperand(r1, r0)); |
| 1107 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), | 1115 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), |
| 1108 1, r2, r3); | 1116 1, r2, r3); |
| 1109 __ Ret(); | 1117 __ Ret(); |
| 1110 | 1118 |
| 1111 // Do a quick inline probe of the receiver's dictionary, if it | 1119 // Do a quick inline probe of the receiver's dictionary, if it |
| 1112 // exists. | 1120 // exists. |
| 1113 __ bind(&probe_dictionary); | 1121 __ bind(&probe_dictionary); |
| 1114 // r1: receiver | 1122 // r1: receiver |
| 1115 // r0: key | 1123 // r0: key |
| 1116 // r3: elements | 1124 // r3: elements |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1164 | 1172 |
| 1165 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { | 1173 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { |
| 1166 // ---------- S t a t e -------------- | 1174 // ---------- S t a t e -------------- |
| 1167 // -- lr : return address | 1175 // -- lr : return address |
| 1168 // -- r0 : key | 1176 // -- r0 : key |
| 1169 // -- r1 : receiver | 1177 // -- r1 : receiver |
| 1170 // ----------------------------------- | 1178 // ----------------------------------- |
| 1171 Label slow; | 1179 Label slow; |
| 1172 | 1180 |
| 1173 // Check that the receiver isn't a smi. | 1181 // Check that the receiver isn't a smi. |
| 1174 __ JumpIfSmi(r1, &slow); | 1182 __ JumpIfSmi(r1, &slow, Label::kNear); |
| 1175 | 1183 |
| 1176 // Check that the key is an array index, that is Uint32. | 1184 // Check that the key is an array index, that is Uint32. |
| 1177 __ tst(r0, Operand(kSmiTagMask | kSmiSignMask)); | 1185 __ tst(r0, Operand(kSmiTagMask | kSmiSignMask)); |
| 1178 __ b(ne, &slow); | 1186 __ bf_near(&slow); |
| 1179 | 1187 |
| 1180 // Get the map of the receiver. | 1188 // Get the map of the receiver. |
| 1181 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 1189 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 1182 | 1190 |
| 1183 // Check that it has indexed interceptor and access checks | 1191 // Check that it has indexed interceptor and access checks |
| 1184 // are not enabled for this object. | 1192 // are not enabled for this object. |
| 1185 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset)); | 1193 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset)); |
| 1186 __ and_(r3, r3, Operand(kSlowCaseBitFieldMask)); | 1194 __ land(r3, r3, Operand(kSlowCaseBitFieldMask)); |
| 1187 __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor)); | 1195 __ cmpeq(r3, Operand(1 << Map::kHasIndexedInterceptor)); |
| 1188 __ b(ne, &slow); | 1196 __ bf_near(&slow); |
| 1189 | 1197 |
| 1190 // Everything is fine, call runtime. | 1198 // Everything is fine, call runtime. |
| 1191 __ Push(r1, r0); // Receiver, key. | 1199 __ Push(r1, r0); // Receiver, key. |
| 1192 | 1200 |
| 1193 // Perform tail call to the entry. | 1201 // Perform tail call to the entry. |
| 1194 __ TailCallExternalReference( | 1202 __ TailCallExternalReference( |
| 1195 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor), | 1203 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor), |
| 1196 masm->isolate()), | 1204 masm->isolate()), |
| 1197 2, | 1205 2, |
| 1198 1); | 1206 1); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1332 Label non_smi_value; | 1340 Label non_smi_value; |
| 1333 __ JumpIfNotSmi(value, &non_smi_value); | 1341 __ JumpIfNotSmi(value, &non_smi_value); |
| 1334 | 1342 |
| 1335 if (increment_length == kIncrementLength) { | 1343 if (increment_length == kIncrementLength) { |
| 1336 // Add 1 to receiver->length. | 1344 // Add 1 to receiver->length. |
| 1337 __ add(scratch_value, key, Operand(Smi::FromInt(1))); | 1345 __ add(scratch_value, key, Operand(Smi::FromInt(1))); |
| 1338 __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); | 1346 __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 1339 } | 1347 } |
| 1340 // It's irrelevant whether array is smi-only or not when writing a smi. | 1348 // It's irrelevant whether array is smi-only or not when writing a smi. |
| 1341 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 1349 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 1342 __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize)); | 1350 __ lsl(scratch_value, address, Operand(kPointerSizeLog2 - kSmiTagSize)); |
| 1351 __ add(address, address, scratch_value); |
| 1343 __ str(value, MemOperand(address)); | 1352 __ str(value, MemOperand(address)); |
| 1344 __ Ret(); | 1353 __ Ret(); |
| 1345 | 1354 |
| 1346 __ bind(&non_smi_value); | 1355 __ bind(&non_smi_value); |
| 1347 // Escape to elements kind transition case. | 1356 // Escape to elements kind transition case. |
| 1348 __ CheckFastObjectElements(receiver_map, scratch_value, | 1357 __ CheckFastObjectElements(receiver_map, scratch_value, |
| 1349 &transition_smi_elements); | 1358 &transition_smi_elements); |
| 1350 | 1359 |
| 1351 // Fast elements array, store the value to the elements backing store. | 1360 // Fast elements array, store the value to the elements backing store. |
| 1352 __ bind(&finish_object_store); | 1361 __ bind(&finish_object_store); |
| 1353 if (increment_length == kIncrementLength) { | 1362 if (increment_length == kIncrementLength) { |
| 1354 // Add 1 to receiver->length. | 1363 // Add 1 to receiver->length. |
| 1355 __ add(scratch_value, key, Operand(Smi::FromInt(1))); | 1364 __ add(scratch_value, key, Operand(Smi::FromInt(1))); |
| 1356 __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); | 1365 __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 1357 } | 1366 } |
| 1358 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 1367 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 1359 __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize)); | 1368 __ lsl(scratch_value, key, Operand(kPointerSizeLog2 - kSmiTagSize)); |
| 1369 __ add(address, address, scratch_value); |
| 1360 __ str(value, MemOperand(address)); | 1370 __ str(value, MemOperand(address)); |
| 1361 // Update write barrier for the elements array address. | 1371 // Update write barrier for the elements array address. |
| 1362 __ mov(scratch_value, value); // Preserve the value which is returned. | 1372 __ mov(scratch_value, value); // Preserve the value which is returned. |
| 1363 __ RecordWrite(elements, | 1373 __ RecordWrite(elements, |
| 1364 address, | 1374 address, |
| 1365 scratch_value, | 1375 scratch_value, |
| 1366 kLRHasNotBeenSaved, | 1376 kLRHasNotBeenSaved, |
| 1367 kDontSaveFPRegs, | 1377 kDontSaveFPRegs, |
| 1368 EMIT_REMEMBERED_SET, | 1378 EMIT_REMEMBERED_SET, |
| 1369 OMIT_SMI_CHECK); | 1379 OMIT_SMI_CHECK); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1454 // Register usage. | 1464 // Register usage. |
| 1455 Register value = r0; | 1465 Register value = r0; |
| 1456 Register key = r1; | 1466 Register key = r1; |
| 1457 Register receiver = r2; | 1467 Register receiver = r2; |
| 1458 Register receiver_map = r3; | 1468 Register receiver_map = r3; |
| 1459 Register elements_map = r6; | 1469 Register elements_map = r6; |
| 1460 Register elements = r7; // Elements array of the receiver. | 1470 Register elements = r7; // Elements array of the receiver. |
| 1461 // r4 and r5 are used as general scratch registers. | 1471 // r4 and r5 are used as general scratch registers. |
| 1462 | 1472 |
| 1463 // Check that the key is a smi. | 1473 // Check that the key is a smi. |
| 1464 __ JumpIfNotSmi(key, &slow); | 1474 __ JumpIfNotSmi(key, &slow, Label::kNear); |
| 1465 // Check that the object isn't a smi. | 1475 // Check that the object isn't a smi. |
| 1466 __ JumpIfSmi(receiver, &slow); | 1476 __ JumpIfSmi(receiver, &slow, Label::kNear); |
| 1467 // Get the map of the object. | 1477 // Get the map of the object. |
| 1468 __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 1478 __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 1469 // Check that the receiver does not require access checks. We need | 1479 // Check that the receiver does not require access checks. We need |
| 1470 // to do this because this generic stub does not perform map checks. | 1480 // to do this because this generic stub does not perform map checks. |
| 1471 __ ldrb(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset)); | 1481 __ ldrb(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset)); |
| 1472 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded)); | 1482 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded)); |
| 1473 __ b(ne, &slow); | 1483 __ bf_near(&slow); |
| 1474 // Check if the object is a JS array or not. | 1484 // Check if the object is a JS array or not. |
| 1475 __ ldrb(r4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset)); | 1485 __ ldrb(r4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset)); |
| 1476 __ cmp(r4, Operand(JS_ARRAY_TYPE)); | 1486 __ cmp(r4, Operand(JS_ARRAY_TYPE)); |
| 1477 __ b(eq, &array); | 1487 __ b(eq, &array); |
| 1478 // Check that the object is some kind of JSObject. | 1488 // Check that the object is some kind of JSObject. |
| 1479 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE)); | 1489 __ cmpge(r4, Operand(FIRST_JS_OBJECT_TYPE)); |
| 1480 __ b(lt, &slow); | 1490 __ bf_near(&slow); |
| 1481 | 1491 |
| 1482 // Object case: Check key against length in the elements array. | 1492 // Object case: Check key against length in the elements array. |
| 1483 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 1493 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 1484 // Check array bounds. Both the key and the length of FixedArray are smis. | 1494 // Check array bounds. Both the key and the length of FixedArray are smis. |
| 1485 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset)); | 1495 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
| 1486 __ cmp(key, Operand(ip)); | 1496 __ cmphs(key, ip); |
| 1487 __ b(lo, &fast_object); | 1497 __ bf(&fast_object); |
| 1488 | 1498 |
| 1489 // Slow case, handle jump to runtime. | 1499 // Slow case, handle jump to runtime. |
| 1490 __ bind(&slow); | 1500 __ bind(&slow); |
| 1491 // Entry registers are intact. | 1501 // Entry registers are intact. |
| 1492 // r0: value. | 1502 // r0: value. |
| 1493 // r1: key. | 1503 // r1: key. |
| 1494 // r2: receiver. | 1504 // r2: receiver. |
| 1495 GenerateRuntimeSetProperty(masm, strict_mode); | 1505 GenerateRuntimeSetProperty(masm, strict_mode); |
| 1496 | 1506 |
| 1497 // Extra capacity case: Check if there is extra capacity to | 1507 // Extra capacity case: Check if there is extra capacity to |
| 1498 // perform the store and update the length. Used for adding one | 1508 // perform the store and update the length. Used for adding one |
| 1499 // element to the array by writing to array[array.length]. | 1509 // element to the array by writing to array[array.length]. |
| 1500 __ bind(&extra); | 1510 __ bind(&extra); |
| 1501 // Condition code from comparing key and array length is still available. | 1511 // Condition code from comparing key and array length is still available. |
| 1502 __ b(ne, &slow); // Only support writing to writing to array[array.length]. | 1512 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
| 1513 __ cmpeq(key, ip); |
| 1514 __ bf(&slow); // Only support writing to writing to array[array.length]. |
| 1503 // Check for room in the elements backing store. | 1515 // Check for room in the elements backing store. |
| 1504 // Both the key and the length of FixedArray are smis. | 1516 // Both the key and the length of FixedArray are smis. |
| 1505 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset)); | 1517 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
| 1506 __ cmp(key, Operand(ip)); | 1518 __ cmphs(key, ip); |
| 1507 __ b(hs, &slow); | 1519 __ bt(&slow); |
| 1508 __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); | 1520 __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); |
| 1509 __ cmp(elements_map, | 1521 __ cmp(elements_map, |
| 1510 Operand(masm->isolate()->factory()->fixed_array_map())); | 1522 Operand(masm->isolate()->factory()->fixed_array_map())); |
| 1511 __ b(ne, &check_if_double_array); | 1523 __ b(ne, &check_if_double_array); |
| 1512 __ jmp(&fast_object_grow); | 1524 __ jmp(&fast_object_grow); |
| 1513 | 1525 |
| 1514 __ bind(&check_if_double_array); | 1526 __ bind(&check_if_double_array); |
| 1515 __ cmp(elements_map, | 1527 __ cmp(elements_map, |
| 1516 Operand(masm->isolate()->factory()->fixed_double_array_map())); | 1528 Operand(masm->isolate()->factory()->fixed_double_array_map())); |
| 1517 __ b(ne, &slow); | 1529 __ b(ne, &slow); |
| 1518 __ jmp(&fast_double_grow); | 1530 __ jmp(&fast_double_grow); |
| 1519 | 1531 |
| 1520 // Array case: Get the length and the elements array from the JS | 1532 // Array case: Get the length and the elements array from the JS |
| 1521 // array. Check that the array is in fast mode (and writable); if it | 1533 // array. Check that the array is in fast mode (and writable); if it |
| 1522 // is the length is always a smi. | 1534 // is the length is always a smi. |
| 1523 __ bind(&array); | 1535 __ bind(&array); |
| 1524 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 1536 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 1525 | 1537 |
| 1526 // Check the key against the length in the array. | 1538 // Check the key against the length in the array. |
| 1527 __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset)); | 1539 __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 1528 __ cmp(key, Operand(ip)); | 1540 __ cmphs(key, ip); |
| 1529 __ b(hs, &extra); | 1541 __ bt(&extra); |
| 1542 // Fall through to fast case. |
| 1530 | 1543 |
| 1531 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, | 1544 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, |
| 1532 &slow, kCheckMap, kDontIncrementLength, | 1545 &slow, kCheckMap, kDontIncrementLength, |
| 1533 value, key, receiver, receiver_map, | 1546 value, key, receiver, receiver_map, |
| 1534 elements_map, elements); | 1547 elements_map, elements); |
| 1535 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, | 1548 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, |
| 1536 &slow, kDontCheckMap, kIncrementLength, | 1549 &slow, kDontCheckMap, kIncrementLength, |
| 1537 value, key, receiver, receiver_map, | 1550 value, key, receiver, receiver_map, |
| 1538 elements_map, elements); | 1551 elements_map, elements); |
| 1539 } | 1552 } |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1593 Label miss; | 1606 Label miss; |
| 1594 | 1607 |
| 1595 Register receiver = r1; | 1608 Register receiver = r1; |
| 1596 Register value = r0; | 1609 Register value = r0; |
| 1597 Register scratch = r3; | 1610 Register scratch = r3; |
| 1598 | 1611 |
| 1599 // Check that the receiver isn't a smi. | 1612 // Check that the receiver isn't a smi. |
| 1600 __ JumpIfSmi(receiver, &miss); | 1613 __ JumpIfSmi(receiver, &miss); |
| 1601 | 1614 |
| 1602 // Check that the object is a JS array. | 1615 // Check that the object is a JS array. |
| 1603 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE); | 1616 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE, eq); |
| 1604 __ b(ne, &miss); | 1617 __ bf(&miss); |
| 1605 | 1618 |
| 1606 // Check that elements are FixedArray. | 1619 // Check that elements are FixedArray. |
| 1607 // We rely on StoreIC_ArrayLength below to deal with all types of | 1620 // We rely on StoreIC_ArrayLength below to deal with all types of |
| 1608 // fast elements (including COW). | 1621 // fast elements (including COW). |
| 1609 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset)); | 1622 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset)); |
| 1610 __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE); | 1623 __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE, eq); |
| 1611 __ b(ne, &miss); | 1624 __ b(ne, &miss); |
| 1612 | 1625 |
| 1613 // Check that the array has fast properties, otherwise the length | 1626 // Check that the array has fast properties, otherwise the length |
| 1614 // property might have been redefined. | 1627 // property might have been redefined. |
| 1615 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kPropertiesOffset)); | 1628 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kPropertiesOffset)); |
| 1616 __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kMapOffset)); | 1629 __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kMapOffset)); |
| 1617 __ CompareRoot(scratch, Heap::kHashTableMapRootIndex); | 1630 __ CompareRoot(scratch, Heap::kHashTableMapRootIndex); |
| 1618 __ b(eq, &miss); | 1631 __ b(eq, &miss); |
| 1619 | 1632 |
| 1620 // Check that value is a smi. | 1633 // Check that value is a smi. |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1727 | 1740 |
| 1728 // Activate inlined smi code. | 1741 // Activate inlined smi code. |
| 1729 if (previous_state == UNINITIALIZED) { | 1742 if (previous_state == UNINITIALIZED) { |
| 1730 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); | 1743 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 1731 } | 1744 } |
| 1732 } | 1745 } |
| 1733 | 1746 |
| 1734 | 1747 |
| 1735 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { | 1748 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { |
| 1736 Address cmp_instruction_address = | 1749 Address cmp_instruction_address = |
| 1737 Assembler::return_address_from_call_start(address); | 1750 address + Assembler::kCallTargetAddressOffset; |
| 1738 | 1751 |
| 1739 // If the instruction following the call is not a cmp rx, #yyy, nothing | 1752 // If the instruction following the call is not a cmp #ii, rx, nothing |
| 1740 // was inlined. | 1753 // was inlined. |
| 1741 Instr instr = Assembler::instr_at(cmp_instruction_address); | 1754 Instr instr = Assembler::instr_at(cmp_instruction_address); |
| 1742 if (!Assembler::IsCmpImmediate(instr)) { | 1755 if (!Assembler::IsCmpImmediate(instr)) { |
| 1743 return; | 1756 return; |
| 1744 } | 1757 } |
| 1745 | 1758 |
| 1746 // The delta to the start of the map check instruction and the | 1759 // The delta to the start of the map check instruction and the |
| 1747 // condition code uses at the patched jump. | 1760 // condition code uses at the patched jump. |
| 1748 int delta = Assembler::GetCmpImmediateRawImmediate(instr); | 1761 int delta = Assembler::GetCmpImmediateAsUnsigned(instr); |
| 1749 delta += | 1762 // TODO(stm): is this needed for ST40 ? |
| 1750 Assembler::GetCmpImmediateRegister(instr).code() * kOff12Mask; | 1763 // delta += Assembler::GetCmpImmediateRegister(instr).code() * kOff12Mask |
| 1751 // If the delta is 0 the instruction is cmp r0, #0 which also signals that | 1764 |
| 1765 // If the delta is 0 the instruction is cmp #0, r0 which also signals that |
| 1752 // nothing was inlined. | 1766 // nothing was inlined. |
| 1753 if (delta == 0) { | 1767 if (delta == 0) { |
| 1754 return; | 1768 return; |
| 1755 } | 1769 } |
| 1756 | 1770 |
| 1757 #ifdef DEBUG | 1771 #ifdef DEBUG |
| 1758 if (FLAG_trace_ic) { | 1772 if (FLAG_trace_ic) { |
| 1759 PrintF("[ patching ic at %p, cmp=%p, delta=%d\n", | 1773 PrintF("[ patching ic at %p, cmp=%p, delta=%d\n", |
| 1760 address, cmp_instruction_address, delta); | 1774 address, cmp_instruction_address, delta); |
| 1761 } | 1775 } |
| 1762 #endif | 1776 #endif |
| 1763 | 1777 |
| 1764 Address patch_address = | 1778 Address patch_address = |
| 1765 cmp_instruction_address - delta * Instruction::kInstrSize; | 1779 cmp_instruction_address - delta * Assembler::kInstrSize; |
| 1766 Instr instr_at_patch = Assembler::instr_at(patch_address); | 1780 Instr instr_at_patch = Assembler::instr_at(patch_address); |
| 1781 #ifdef DEBUG |
| 1782 Instr instr_before_patch = |
| 1783 Assembler::instr_at(patch_address - Assembler::kInstrSize); |
| 1784 #endif |
| 1767 Instr branch_instr = | 1785 Instr branch_instr = |
| 1768 Assembler::instr_at(patch_address + Instruction::kInstrSize); | 1786 Assembler::instr_at(patch_address + Assembler::kInstrSize); |
| 1769 // This is patching a conditional "jump if not smi/jump if smi" site. | 1787 ASSERT(Assembler::IsCmpRegister(instr_at_patch)); |
| 1770 // Enabling by changing from | 1788 ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(), |
| 1771 // cmp rx, rx | 1789 Assembler::GetRm(instr_at_patch).code()); |
| 1772 // b eq/ne, <target> | 1790 ASSERT(Assembler::IsMovImmediate(instr_before_patch)); |
| 1773 // to | 1791 ASSERT_EQ(Assembler::GetRn(instr_before_patch).code(), sh4_ip.code()); |
| 1774 // tst rx, #kSmiTagMask | 1792 ASSERT(Assembler::IsBranch(branch_instr)); |
| 1775 // b ne/eq, <target> | 1793 if (Assembler::GetCondition(branch_instr) == f) { |
| 1776 // and vice-versa to be disabled again. | 1794 // This is patching a "jump if not smi" site to be active. |
| 1777 CodePatcher patcher(patch_address, 2); | 1795 // Changing |
| 1778 Register reg = Assembler::GetRn(instr_at_patch); | 1796 // mov #kSmiTagMask, sh4_ip |
| 1779 if (check == ENABLE_INLINED_SMI_CHECK) { | 1797 // cmp rx, rx |
| 1780 ASSERT(Assembler::IsCmpRegister(instr_at_patch)); | 1798 // bf <skip> // actually a bt <target> |
| 1781 ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(), | 1799 // ... |
| 1782 Assembler::GetRm(instr_at_patch).code()); | 1800 // bra <target> |
| 1783 patcher.masm()->tst(reg, Operand(kSmiTagMask)); | 1801 // skip: |
| 1802 // to |
| 1803 // mov #kSmiTagMask, sh4_ip |
| 1804 // tst rx, sh4_ip |
| 1805 // bt <skip> // actually implements a bf <target> |
| 1806 // ... |
| 1807 CodePatcher patcher(patch_address, 2); |
| 1808 Register reg = Assembler::GetRn(instr_at_patch); |
| 1809 patcher.masm()->tst(reg, sh4_ip); |
| 1810 patcher.EmitCondition(t); |
| 1784 } else { | 1811 } else { |
| 1785 ASSERT(check == DISABLE_INLINED_SMI_CHECK); | 1812 ASSERT(Assembler::GetCondition(branch_instr) == t); |
| 1786 ASSERT(Assembler::IsTstImmediate(instr_at_patch)); | 1813 // This is patching a "jump if smi" site to be active. |
| 1787 patcher.masm()->cmp(reg, reg); | 1814 // Changing |
| 1788 } | 1815 // mov #kSmiTagMask, sh4_ip |
| 1789 ASSERT(Assembler::IsBranch(branch_instr)); | 1816 // cmp rx, rx |
| 1790 if (Assembler::GetCondition(branch_instr) == eq) { | 1817 // bt <skip> // actually a bf <target> |
| 1791 patcher.EmitCondition(ne); | 1818 // ... |
| 1792 } else { | 1819 // bra <target> |
| 1793 ASSERT(Assembler::GetCondition(branch_instr) == ne); | 1820 // skip: |
| 1794 patcher.EmitCondition(eq); | 1821 // to |
| 1822 // mov #kSmiTagMask, sh4_ip |
| 1823 // tst rx, sh4_ip |
| 1824 // bf <target> |
| 1825 // ... |
| 1826 CodePatcher patcher(patch_address, 2); |
| 1827 Register reg = Assembler::GetRn(instr_at_patch); |
| 1828 patcher.masm()->tst(reg, sh4_ip); |
| 1829 patcher.EmitCondition(f); |
| 1795 } | 1830 } |
| 1796 } | 1831 } |
| 1797 | 1832 |
| 1798 | 1833 |
| 1799 } } // namespace v8::internal | 1834 } } // namespace v8::internal |
| 1800 | 1835 |
| 1801 #endif // V8_TARGET_ARCH_ARM | 1836 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |