OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 // t0 - used to hold the property dictionary. | 54 // t0 - used to hold the property dictionary. |
55 // | 55 // |
56 // t1 - initially the receiver | 56 // t1 - initially the receiver |
57 // - used for the index into the property dictionary | 57 // - used for the index into the property dictionary |
58 // - holds the result on exit. | 58 // - holds the result on exit. |
59 // | 59 // |
60 // r3 - used as temporary and to hold the capacity of the property | 60 // r3 - used as temporary and to hold the capacity of the property |
61 // dictionary. | 61 // dictionary. |
62 // | 62 // |
63 // r2 - holds the name of the property and is unchanged. | 63 // r2 - holds the name of the property and is unchanged. |
| 64 // r4 - used as temporary. |
64 | 65 |
65 Label done; | 66 Label done; |
66 | 67 |
67 // Check for the absence of an interceptor. | 68 // Check for the absence of an interceptor. |
68 // Load the map into t0. | 69 // Load the map into t0. |
69 __ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset)); | 70 __ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset)); |
70 | 71 |
71 // Bail out if the receiver has a named interceptor. | 72 // Bail out if the receiver has a named interceptor. |
72 __ ldrb(r3, FieldMemOperand(t0, Map::kBitFieldOffset)); | 73 __ ldrb(r3, FieldMemOperand(t0, Map::kBitFieldOffset)); |
73 __ tst(r3, Operand(1 << Map::kHasNamedInterceptor)); | 74 __ tst(r3, Operand(1 << Map::kHasNamedInterceptor)); |
(...skipping 27 matching lines...) Expand all Loading... |
101 | 102 |
102 const int kElementsStartOffset = StringDictionary::kHeaderSize + | 103 const int kElementsStartOffset = StringDictionary::kHeaderSize + |
103 StringDictionary::kElementsStartIndex * kPointerSize; | 104 StringDictionary::kElementsStartIndex * kPointerSize; |
104 | 105 |
105 // Generate an unrolled loop that performs a few probes before | 106 // Generate an unrolled loop that performs a few probes before |
106 // giving up. Measurements done on Gmail indicate that 2 probes | 107 // giving up. Measurements done on Gmail indicate that 2 probes |
107 // cover ~93% of loads from dictionaries. | 108 // cover ~93% of loads from dictionaries. |
108 static const int kProbes = 4; | 109 static const int kProbes = 4; |
109 for (int i = 0; i < kProbes; i++) { | 110 for (int i = 0; i < kProbes; i++) { |
110 // Compute the masked index: (hash + i + i * i) & mask. | 111 // Compute the masked index: (hash + i + i * i) & mask. |
111 __ ldr(t1, FieldMemOperand(r2, String::kHashFieldOffset)); | 112 __ ldr(r4, FieldMemOperand(r2, String::kHashFieldOffset)); |
112 if (i > 0) { | 113 if (i > 0) { |
113 // Add the probe offset (i + i * i) left shifted to avoid right shifting | 114 // Add the probe offset (i + i * i) left shifted to avoid right shifting |
114 // the hash in a separate instruction. The value hash + i + i * i is right | 115 // the hash in a separate instruction. The value hash + i + i * i is right |
115 // shifted in the following and instruction. | 116 // shifted in the following and instruction. |
116 ASSERT(StringDictionary::GetProbeOffset(i) < | 117 ASSERT(StringDictionary::GetProbeOffset(i) < |
117 1 << (32 - String::kHashFieldOffset)); | 118 1 << (32 - String::kHashFieldOffset)); |
118 __ add(t1, t1, Operand( | 119 __ add(r4, r4, Operand( |
119 StringDictionary::GetProbeOffset(i) << String::kHashShift)); | 120 StringDictionary::GetProbeOffset(i) << String::kHashShift)); |
120 } | 121 } |
121 __ and_(t1, r3, Operand(t1, LSR, String::kHashShift)); | 122 __ and_(r4, r3, Operand(r4, LSR, String::kHashShift)); |
122 | 123 |
123 // Scale the index by multiplying by the element size. | 124 // Scale the index by multiplying by the element size. |
124 ASSERT(StringDictionary::kEntrySize == 3); | 125 ASSERT(StringDictionary::kEntrySize == 3); |
125 __ add(t1, t1, Operand(t1, LSL, 1)); // t1 = t1 * 3 | 126 __ add(r4, r4, Operand(r4, LSL, 1)); // r4 = r4 * 3 |
126 | 127 |
127 // Check if the key is identical to the name. | 128 // Check if the key is identical to the name. |
128 __ add(t1, t0, Operand(t1, LSL, 2)); | 129 __ add(r4, t0, Operand(r4, LSL, 2)); |
129 __ ldr(ip, FieldMemOperand(t1, kElementsStartOffset)); | 130 __ ldr(ip, FieldMemOperand(r4, kElementsStartOffset)); |
130 __ cmp(r2, Operand(ip)); | 131 __ cmp(r2, Operand(ip)); |
131 if (i != kProbes - 1) { | 132 if (i != kProbes - 1) { |
132 __ b(eq, &done); | 133 __ b(eq, &done); |
133 } else { | 134 } else { |
134 __ b(ne, miss); | 135 __ b(ne, miss); |
135 } | 136 } |
136 } | 137 } |
137 | 138 |
138 // Check that the value is a normal property. | 139 // Check that the value is a normal property. |
139 __ bind(&done); // t1 == t0 + 4*index | 140 __ bind(&done); // r4 == t0 + 4*index |
140 __ ldr(r3, FieldMemOperand(t1, kElementsStartOffset + 2 * kPointerSize)); | 141 __ ldr(r3, FieldMemOperand(r4, kElementsStartOffset + 2 * kPointerSize)); |
141 __ tst(r3, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 142 __ tst(r3, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
142 __ b(ne, miss); | 143 __ b(ne, miss); |
143 | 144 |
144 // Get the value at the masked, scaled index and return. | 145 // Get the value at the masked, scaled index and return. |
145 __ ldr(t1, FieldMemOperand(t1, kElementsStartOffset + 1 * kPointerSize)); | 146 __ ldr(t1, FieldMemOperand(r4, kElementsStartOffset + 1 * kPointerSize)); |
146 } | 147 } |
147 | 148 |
148 | 149 |
149 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | 150 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, |
150 Label* miss, | 151 Label* miss, |
151 Register elements, | 152 Register elements, |
152 Register key, | 153 Register key, |
153 Register t0, | 154 Register t0, |
154 Register t1, | 155 Register t1, |
155 Register t2) { | 156 Register t2) { |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 const int kValueOffset = | 233 const int kValueOffset = |
233 NumberDictionary::kElementsStartOffset + kPointerSize; | 234 NumberDictionary::kElementsStartOffset + kPointerSize; |
234 __ ldr(t0, FieldMemOperand(t2, kValueOffset)); | 235 __ ldr(t0, FieldMemOperand(t2, kValueOffset)); |
235 } | 236 } |
236 | 237 |
237 | 238 |
238 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { | 239 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { |
239 // ----------- S t a t e ------------- | 240 // ----------- S t a t e ------------- |
240 // -- r2 : name | 241 // -- r2 : name |
241 // -- lr : return address | 242 // -- lr : return address |
242 // -- [sp] : receiver | 243 // -- r0 : receiver |
| 244 // -- sp[0] : receiver |
243 // ----------------------------------- | 245 // ----------------------------------- |
244 Label miss; | 246 Label miss; |
245 | 247 |
246 __ ldr(r0, MemOperand(sp, 0)); | |
247 | |
248 StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss); | 248 StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss); |
249 __ bind(&miss); | 249 __ bind(&miss); |
250 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 250 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
251 } | 251 } |
252 | 252 |
253 | 253 |
254 void LoadIC::GenerateStringLength(MacroAssembler* masm) { | 254 void LoadIC::GenerateStringLength(MacroAssembler* masm) { |
255 // ----------- S t a t e ------------- | 255 // ----------- S t a t e ------------- |
256 // -- r2 : name | 256 // -- r2 : name |
257 // -- lr : return address | 257 // -- lr : return address |
258 // -- [sp] : receiver | 258 // -- r0 : receiver |
| 259 // -- sp[0] : receiver |
259 // ----------------------------------- | 260 // ----------------------------------- |
260 Label miss; | 261 Label miss; |
261 | 262 |
262 __ ldr(r0, MemOperand(sp, 0)); | |
263 | |
264 StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss); | 263 StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss); |
265 // Cache miss: Jump to runtime. | 264 // Cache miss: Jump to runtime. |
266 __ bind(&miss); | 265 __ bind(&miss); |
267 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 266 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
268 } | 267 } |
269 | 268 |
270 | 269 |
271 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { | 270 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { |
272 // ----------- S t a t e ------------- | 271 // ----------- S t a t e ------------- |
273 // -- r2 : name | 272 // -- r2 : name |
274 // -- lr : return address | 273 // -- lr : return address |
275 // -- [sp] : receiver | 274 // -- r0 : receiver |
| 275 // -- sp[0] : receiver |
276 // ----------------------------------- | 276 // ----------------------------------- |
277 Label miss; | 277 Label miss; |
278 | 278 |
279 // Load receiver. | |
280 __ ldr(r0, MemOperand(sp, 0)); | |
281 | |
282 StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss); | 279 StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss); |
283 __ bind(&miss); | 280 __ bind(&miss); |
284 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 281 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
285 } | 282 } |
286 | 283 |
287 | 284 |
288 // Defined in ic.cc. | 285 // Defined in ic.cc. |
289 Object* CallIC_Miss(Arguments args); | 286 Object* CallIC_Miss(Arguments args); |
290 | 287 |
291 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { | 288 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 | 341 |
345 // Cache miss: Jump to runtime. | 342 // Cache miss: Jump to runtime. |
346 __ bind(&miss); | 343 __ bind(&miss); |
347 GenerateMiss(masm, argc); | 344 GenerateMiss(masm, argc); |
348 } | 345 } |
349 | 346 |
350 | 347 |
351 static void GenerateNormalHelper(MacroAssembler* masm, | 348 static void GenerateNormalHelper(MacroAssembler* masm, |
352 int argc, | 349 int argc, |
353 bool is_global_object, | 350 bool is_global_object, |
354 Label* miss) { | 351 Label* miss, |
| 352 Register scratch) { |
355 // Search dictionary - put result in register r1. | 353 // Search dictionary - put result in register r1. |
356 GenerateDictionaryLoad(masm, miss, r0, r1); | 354 GenerateDictionaryLoad(masm, miss, r0, r1); |
357 | 355 |
358 // Check that the value isn't a smi. | 356 // Check that the value isn't a smi. |
359 __ tst(r1, Operand(kSmiTagMask)); | 357 __ tst(r1, Operand(kSmiTagMask)); |
360 __ b(eq, miss); | 358 __ b(eq, miss); |
361 | 359 |
362 // Check that the value is a JSFunction. | 360 // Check that the value is a JSFunction. |
363 __ CompareObjectType(r1, r0, r0, JS_FUNCTION_TYPE); | 361 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE); |
364 __ b(ne, miss); | 362 __ b(ne, miss); |
365 | 363 |
366 // Patch the receiver with the global proxy if necessary. | 364 // Patch the receiver with the global proxy if necessary. |
367 if (is_global_object) { | 365 if (is_global_object) { |
368 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); | 366 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); |
369 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); | 367 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); |
370 __ str(r0, MemOperand(sp, argc * kPointerSize)); | 368 __ str(r0, MemOperand(sp, argc * kPointerSize)); |
371 } | 369 } |
372 | 370 |
373 // Invoke the function. | 371 // Invoke the function. |
(...skipping 28 matching lines...) Expand all Loading... |
402 __ b(eq, &global_object); | 400 __ b(eq, &global_object); |
403 __ cmp(r0, Operand(JS_BUILTINS_OBJECT_TYPE)); | 401 __ cmp(r0, Operand(JS_BUILTINS_OBJECT_TYPE)); |
404 __ b(ne, &non_global_object); | 402 __ b(ne, &non_global_object); |
405 | 403 |
406 // Accessing global object: Load and invoke. | 404 // Accessing global object: Load and invoke. |
407 __ bind(&global_object); | 405 __ bind(&global_object); |
408 // Check that the global object does not require access checks. | 406 // Check that the global object does not require access checks. |
409 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset)); | 407 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset)); |
410 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded)); | 408 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded)); |
411 __ b(ne, &miss); | 409 __ b(ne, &miss); |
412 GenerateNormalHelper(masm, argc, true, &miss); | 410 GenerateNormalHelper(masm, argc, true, &miss, r4); |
413 | 411 |
414 // Accessing non-global object: Check for access to global proxy. | 412 // Accessing non-global object: Check for access to global proxy. |
415 Label global_proxy, invoke; | 413 Label global_proxy, invoke; |
416 __ bind(&non_global_object); | 414 __ bind(&non_global_object); |
417 __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE)); | 415 __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE)); |
418 __ b(eq, &global_proxy); | 416 __ b(eq, &global_proxy); |
419 // Check that the non-global, non-global-proxy object does not | 417 // Check that the non-global, non-global-proxy object does not |
420 // require access checks. | 418 // require access checks. |
421 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset)); | 419 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset)); |
422 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded)); | 420 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded)); |
423 __ b(ne, &miss); | 421 __ b(ne, &miss); |
424 __ bind(&invoke); | 422 __ bind(&invoke); |
425 GenerateNormalHelper(masm, argc, false, &miss); | 423 GenerateNormalHelper(masm, argc, false, &miss, r4); |
426 | 424 |
427 // Global object access: Check access rights. | 425 // Global object access: Check access rights. |
428 __ bind(&global_proxy); | 426 __ bind(&global_proxy); |
429 __ CheckAccessGlobalProxy(r1, r0, &miss); | 427 __ CheckAccessGlobalProxy(r1, r0, &miss); |
430 __ b(&invoke); | 428 __ b(&invoke); |
431 | 429 |
432 // Cache miss: Jump to runtime. | 430 // Cache miss: Jump to runtime. |
433 __ bind(&miss); | 431 __ bind(&miss); |
434 GenerateMiss(masm, argc); | 432 GenerateMiss(masm, argc); |
435 } | 433 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 } | 480 } |
483 | 481 |
484 | 482 |
485 // Defined in ic.cc. | 483 // Defined in ic.cc. |
486 Object* LoadIC_Miss(Arguments args); | 484 Object* LoadIC_Miss(Arguments args); |
487 | 485 |
488 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { | 486 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { |
489 // ----------- S t a t e ------------- | 487 // ----------- S t a t e ------------- |
490 // -- r2 : name | 488 // -- r2 : name |
491 // -- lr : return address | 489 // -- lr : return address |
492 // -- [sp] : receiver | 490 // -- r0 : receiver |
| 491 // -- sp[0] : receiver |
493 // ----------------------------------- | 492 // ----------------------------------- |
494 | 493 |
495 __ ldr(r0, MemOperand(sp, 0)); | |
496 // Probe the stub cache. | 494 // Probe the stub cache. |
497 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, | 495 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, |
498 NOT_IN_LOOP, | 496 NOT_IN_LOOP, |
499 MONOMORPHIC); | 497 MONOMORPHIC); |
500 StubCache::GenerateProbe(masm, flags, r0, r2, r3, no_reg); | 498 StubCache::GenerateProbe(masm, flags, r0, r2, r3, no_reg); |
501 | 499 |
502 // Cache miss: Jump to runtime. | 500 // Cache miss: Jump to runtime. |
503 GenerateMiss(masm); | 501 GenerateMiss(masm); |
504 } | 502 } |
505 | 503 |
506 | 504 |
507 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 505 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
508 // ----------- S t a t e ------------- | 506 // ----------- S t a t e ------------- |
509 // -- r2 : name | 507 // -- r2 : name |
510 // -- lr : return address | 508 // -- lr : return address |
511 // -- [sp] : receiver | 509 // -- r0 : receiver |
| 510 // -- sp[0] : receiver |
512 // ----------------------------------- | 511 // ----------------------------------- |
513 Label miss, probe, global; | 512 Label miss, probe, global; |
514 | 513 |
515 __ ldr(r0, MemOperand(sp, 0)); | |
516 // Check that the receiver isn't a smi. | 514 // Check that the receiver isn't a smi. |
517 __ tst(r0, Operand(kSmiTagMask)); | 515 __ tst(r0, Operand(kSmiTagMask)); |
518 __ b(eq, &miss); | 516 __ b(eq, &miss); |
519 | 517 |
520 // Check that the receiver is a valid JS object. Put the map in r3. | 518 // Check that the receiver is a valid JS object. Put the map in r3. |
521 __ CompareObjectType(r0, r3, r1, FIRST_JS_OBJECT_TYPE); | 519 __ CompareObjectType(r0, r3, r1, FIRST_JS_OBJECT_TYPE); |
522 __ b(lt, &miss); | 520 __ b(lt, &miss); |
523 // If this assert fails, we have to check upper bound too. | 521 // If this assert fails, we have to check upper bound too. |
524 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 522 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
525 | 523 |
(...skipping 18 matching lines...) Expand all Loading... |
544 // Cache miss: Restore receiver from stack and jump to runtime. | 542 // Cache miss: Restore receiver from stack and jump to runtime. |
545 __ bind(&miss); | 543 __ bind(&miss); |
546 GenerateMiss(masm); | 544 GenerateMiss(masm); |
547 } | 545 } |
548 | 546 |
549 | 547 |
550 void LoadIC::GenerateMiss(MacroAssembler* masm) { | 548 void LoadIC::GenerateMiss(MacroAssembler* masm) { |
551 // ----------- S t a t e ------------- | 549 // ----------- S t a t e ------------- |
552 // -- r2 : name | 550 // -- r2 : name |
553 // -- lr : return address | 551 // -- lr : return address |
554 // -- [sp] : receiver | 552 // -- r0 : receiver |
| 553 // -- sp[0] : receiver |
555 // ----------------------------------- | 554 // ----------------------------------- |
556 | 555 |
557 __ ldr(r3, MemOperand(sp, 0)); | 556 __ mov(r3, r0); |
558 __ stm(db_w, sp, r2.bit() | r3.bit()); | 557 __ Push(r3, r2); |
559 | 558 |
560 // Perform tail call to the entry. | 559 // Perform tail call to the entry. |
561 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); | 560 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); |
562 __ TailCallExternalReference(ref, 2, 1); | 561 __ TailCallExternalReference(ref, 2, 1); |
563 } | 562 } |
564 | 563 |
565 | 564 |
566 void LoadIC::ClearInlinedVersion(Address address) { | 565 void LoadIC::ClearInlinedVersion(Address address) { |
567 // Reset the map check of the inlined inobject property load (if present) to | 566 // Reset the map check of the inlined inobject property load (if present) to |
568 // guarantee failure by holding an invalid map (the null value). The offset | 567 // guarantee failure by holding an invalid map (the null value). The offset |
(...skipping 1166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1735 __ bind(&miss); | 1734 __ bind(&miss); |
1736 | 1735 |
1737 GenerateMiss(masm); | 1736 GenerateMiss(masm); |
1738 } | 1737 } |
1739 | 1738 |
1740 | 1739 |
1741 #undef __ | 1740 #undef __ |
1742 | 1741 |
1743 | 1742 |
1744 } } // namespace v8::internal | 1743 } } // namespace v8::internal |
OLD | NEW |