Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(170)

Side by Side Diff: src/arm/ic-arm.cc

Issue 2801007: Remove redundant checks in and around GenerateDictionaryLoad.... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | src/ia32/ic-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 29 matching lines...) Expand all
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
51 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
52 Register type,
53 Label* global_object) {
54 // Register usage:
55 // type: holds the receiver instance type on entry.
56 __ cmp(type, Operand(JS_GLOBAL_OBJECT_TYPE));
57 __ b(eq, global_object);
58 __ cmp(type, Operand(JS_BUILTINS_OBJECT_TYPE));
59 __ b(eq, global_object);
60 __ cmp(type, Operand(JS_GLOBAL_PROXY_TYPE));
61 __ b(eq, global_object);
62 }
63
64
65 // Generated code falls through if the receiver is a regular non-global
66 // JS object with slow properties and no interceptors.
67 static void GenerateDictionaryLoadReceiverCheck(MacroAssembler* masm,
68 Register receiver,
69 Register elements,
70 Register t0,
71 Register t1,
72 Label* miss) {
73 // Register usage:
74 // receiver: holds the receiver on entry and is unchanged.
75 // elements: holds the property dictionary on fall through.
76 // Scratch registers:
77 // t0: used to holds the receiver map.
78 // t1: used to holds the receiver instance type, receiver bit mask and
79 // elements map.
80
81 // Check that the receiver isn't a smi.
82 __ tst(receiver, Operand(kSmiTagMask));
83 __ b(eq, miss);
84
85 // Check that the receiver is a valid JS object.
86 __ CompareObjectType(receiver, t0, t1, FIRST_JS_OBJECT_TYPE);
87 __ b(lt, miss);
88
89 // If this assert fails, we have to check upper bound too.
90 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
91
92 GenerateGlobalInstanceTypeCheck(masm, t1, miss);
93
94 // Check that the global object does not require access checks.
95 __ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset));
96 __ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) |
97 (1 << Map::kHasNamedInterceptor)));
98 __ b(nz, miss);
99
100 __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
101 __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
102 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
103 __ cmp(t1, ip);
104 __ b(nz, miss);
105 }
106
107
50 // Helper function used from LoadIC/CallIC GenerateNormal. 108 // Helper function used from LoadIC/CallIC GenerateNormal.
51 // receiver: Receiver. It is not clobbered if a jump to the miss label is 109 //
52 // done 110 // elements: Property dictionary. It is not clobbered if a jump to the miss
111 // label is done.
53 // name: Property name. It is not clobbered if a jump to the miss label is 112 // name: Property name. It is not clobbered if a jump to the miss label is
54 // done 113 // done
55 // result: Register for the result. It is only updated if a jump to the miss 114 // result: Register for the result. It is only updated if a jump to the miss
56 // label is not done. Can be the same as receiver or name clobbering 115 // label is not done. Can be the same as elements or name clobbering
57 // one of these in the case of not jumping to the miss label. 116 // one of these in the case of not jumping to the miss label.
58 // The three scratch registers need to be different from the receiver, name and 117 // The two scratch registers need to be different from elements, name and
59 // result. 118 // result.
119 // The generated code assumes that the receiver has slow properties,
120 // is not a global object and does not have interceptors.
60 static void GenerateDictionaryLoad(MacroAssembler* masm, 121 static void GenerateDictionaryLoad(MacroAssembler* masm,
61 Label* miss, 122 Label* miss,
62 Register receiver, 123 Register elements,
63 Register name, 124 Register name,
64 Register result, 125 Register result,
65 Register scratch1, 126 Register scratch1,
66 Register scratch2, 127 Register scratch2) {
67 Register scratch3,
68 DictionaryCheck check_dictionary) {
69 // Main use of the scratch registers. 128 // Main use of the scratch registers.
70 // scratch1: Used to hold the property dictionary. 129 // scratch1: Used as temporary and to hold the capacity of the property
71 // scratch2: Used as temporary and to hold the capacity of the property
72 // dictionary. 130 // dictionary.
73 // scratch3: Used as temporary. 131 // scratch2: Used as temporary.
74 132
75 Label done; 133 Label done;
76 134
77 // Check for the absence of an interceptor.
78 // Load the map into scratch1.
79 __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kMapOffset));
80
81 // Bail out if the receiver has a named interceptor.
82 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
83 __ tst(scratch2, Operand(1 << Map::kHasNamedInterceptor));
84 __ b(nz, miss);
85
86 // Bail out if we have a JS global proxy object.
87 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
88 __ cmp(scratch2, Operand(JS_GLOBAL_PROXY_TYPE));
89 __ b(eq, miss);
90
91 // Possible work-around for http://crbug.com/16276.
92 // See also: http://codereview.chromium.org/155418.
93 __ cmp(scratch2, Operand(JS_GLOBAL_OBJECT_TYPE));
94 __ b(eq, miss);
95 __ cmp(scratch2, Operand(JS_BUILTINS_OBJECT_TYPE));
96 __ b(eq, miss);
97
98 // Load the properties array.
99 __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
100
101 // Check that the properties array is a dictionary.
102 if (check_dictionary == CHECK_DICTIONARY) {
103 __ ldr(scratch2, FieldMemOperand(scratch1, HeapObject::kMapOffset));
104 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
105 __ cmp(scratch2, ip);
106 __ b(ne, miss);
107 }
108
109 // Compute the capacity mask. 135 // Compute the capacity mask.
110 const int kCapacityOffset = StringDictionary::kHeaderSize + 136 const int kCapacityOffset = StringDictionary::kHeaderSize +
111 StringDictionary::kCapacityIndex * kPointerSize; 137 StringDictionary::kCapacityIndex * kPointerSize;
112 __ ldr(scratch2, FieldMemOperand(scratch1, kCapacityOffset)); 138 __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
113 __ mov(scratch2, Operand(scratch2, ASR, kSmiTagSize)); // convert smi to int 139 __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize)); // convert smi to int
114 __ sub(scratch2, scratch2, Operand(1)); 140 __ sub(scratch1, scratch1, Operand(1));
115 141
116 const int kElementsStartOffset = StringDictionary::kHeaderSize + 142 const int kElementsStartOffset = StringDictionary::kHeaderSize +
117 StringDictionary::kElementsStartIndex * kPointerSize; 143 StringDictionary::kElementsStartIndex * kPointerSize;
118 144
119 // Generate an unrolled loop that performs a few probes before 145 // Generate an unrolled loop that performs a few probes before
120 // giving up. Measurements done on Gmail indicate that 2 probes 146 // giving up. Measurements done on Gmail indicate that 2 probes
121 // cover ~93% of loads from dictionaries. 147 // cover ~93% of loads from dictionaries.
122 static const int kProbes = 4; 148 static const int kProbes = 4;
123 for (int i = 0; i < kProbes; i++) { 149 for (int i = 0; i < kProbes; i++) {
124 // Compute the masked index: (hash + i + i * i) & mask. 150 // Compute the masked index: (hash + i + i * i) & mask.
125 __ ldr(scratch3, FieldMemOperand(name, String::kHashFieldOffset)); 151 __ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
126 if (i > 0) { 152 if (i > 0) {
127 // Add the probe offset (i + i * i) left shifted to avoid right shifting 153 // Add the probe offset (i + i * i) left shifted to avoid right shifting
128 // the hash in a separate instruction. The value hash + i + i * i is right 154 // the hash in a separate instruction. The value hash + i + i * i is right
129 // shifted in the following and instruction. 155 // shifted in the following and instruction.
130 ASSERT(StringDictionary::GetProbeOffset(i) < 156 ASSERT(StringDictionary::GetProbeOffset(i) <
131 1 << (32 - String::kHashFieldOffset)); 157 1 << (32 - String::kHashFieldOffset));
132 __ add(scratch3, scratch3, Operand( 158 __ add(scratch2, scratch2, Operand(
133 StringDictionary::GetProbeOffset(i) << String::kHashShift)); 159 StringDictionary::GetProbeOffset(i) << String::kHashShift));
134 } 160 }
135 __ and_(scratch3, scratch2, Operand(scratch3, LSR, String::kHashShift)); 161 __ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift));
136 162
137 // Scale the index by multiplying by the element size. 163 // Scale the index by multiplying by the element size.
138 ASSERT(StringDictionary::kEntrySize == 3); 164 ASSERT(StringDictionary::kEntrySize == 3);
139 // scratch3 = scratch3 * 3. 165 // scratch2 = scratch2 * 3.
140 __ add(scratch3, scratch3, Operand(scratch3, LSL, 1)); 166 __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
141 167
142 // Check if the key is identical to the name. 168 // Check if the key is identical to the name.
143 __ add(scratch3, scratch1, Operand(scratch3, LSL, 2)); 169 __ add(scratch2, elements, Operand(scratch2, LSL, 2));
144 __ ldr(ip, FieldMemOperand(scratch3, kElementsStartOffset)); 170 __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
145 __ cmp(name, Operand(ip)); 171 __ cmp(name, Operand(ip));
146 if (i != kProbes - 1) { 172 if (i != kProbes - 1) {
147 __ b(eq, &done); 173 __ b(eq, &done);
148 } else { 174 } else {
149 __ b(ne, miss); 175 __ b(ne, miss);
150 } 176 }
151 } 177 }
152 178
153 // Check that the value is a normal property. 179 // Check that the value is a normal property.
154 __ bind(&done); // scratch3 == scratch1 + 4 * index 180 __ bind(&done); // scratch2 == elements + 4 * index
155 __ ldr(scratch2, 181 __ ldr(scratch1,
156 FieldMemOperand(scratch3, kElementsStartOffset + 2 * kPointerSize)); 182 FieldMemOperand(scratch2, kElementsStartOffset + 2 * kPointerSize));
157 __ tst(scratch2, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize)); 183 __ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
158 __ b(ne, miss); 184 __ b(ne, miss);
159 185
160 // Get the value at the masked, scaled index and return. 186 // Get the value at the masked, scaled index and return.
161 __ ldr(result, 187 __ ldr(result,
162 FieldMemOperand(scratch3, kElementsStartOffset + 1 * kPointerSize)); 188 FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
163 } 189 }
164 190
165 191
166 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, 192 static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
167 Label* miss, 193 Label* miss,
168 Register elements, 194 Register elements,
169 Register key, 195 Register key,
170 Register result, 196 Register result,
171 Register t0, 197 Register t0,
172 Register t1, 198 Register t1,
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); 329 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
304 } 330 }
305 331
306 332
307 // Checks the receiver for special cases (value type, slow case bits). 333 // Checks the receiver for special cases (value type, slow case bits).
308 // Falls through for regular JS object. 334 // Falls through for regular JS object.
309 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, 335 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
310 Register receiver, 336 Register receiver,
311 Register scratch1, 337 Register scratch1,
312 Register scratch2, 338 Register scratch2,
339 int interceptor_bit,
313 Label* slow) { 340 Label* slow) {
314 // Check that the object isn't a smi. 341 // Check that the object isn't a smi.
315 __ BranchOnSmi(receiver, slow); 342 __ BranchOnSmi(receiver, slow);
316 // Get the map of the receiver. 343 // Get the map of the receiver.
317 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset)); 344 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
318 // Check bit field. 345 // Check bit field.
319 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset)); 346 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
320 __ tst(scratch2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask)); 347 __ tst(scratch2,
321 __ b(ne, slow); 348 Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
349 __ b(nz, slow);
322 // Check that the object is some kind of JS object EXCEPT JS Value type. 350 // Check that the object is some kind of JS object EXCEPT JS Value type.
323 // In the case that the object is a value-wrapper object, 351 // In the case that the object is a value-wrapper object,
324 // we enter the runtime system to make sure that indexing into string 352 // we enter the runtime system to make sure that indexing into string
325 // objects work as intended. 353 // objects work as intended.
326 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); 354 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
327 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); 355 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
328 __ cmp(scratch1, Operand(JS_OBJECT_TYPE)); 356 __ cmp(scratch1, Operand(JS_OBJECT_TYPE));
329 __ b(lt, slow); 357 __ b(lt, slow);
330 } 358 }
331 359
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
495 masm, Context::BOOLEAN_FUNCTION_INDEX, r1); 523 masm, Context::BOOLEAN_FUNCTION_INDEX, r1);
496 524
497 // Probe the stub cache for the value object. 525 // Probe the stub cache for the value object.
498 __ bind(&probe); 526 __ bind(&probe);
499 StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg); 527 StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
500 528
501 __ bind(&miss); 529 __ bind(&miss);
502 } 530 }
503 531
504 532
505 static void GenerateNormalHelper(MacroAssembler* masm, 533 static void GenerateFunctionTailCall(MacroAssembler* masm,
506 int argc, 534 int argc,
507 bool is_global_object, 535 Label* miss,
508 Label* miss, 536 Register scratch) {
509 Register scratch) { 537 // r1: function
510 // Search dictionary - put result in register r1.
511 GenerateDictionaryLoad(masm, miss, r1, r2, r1, r0, r3, r4, CHECK_DICTIONARY);
512 538
513 // Check that the value isn't a smi. 539 // Check that the value isn't a smi.
514 __ tst(r1, Operand(kSmiTagMask)); 540 __ tst(r1, Operand(kSmiTagMask));
515 __ b(eq, miss); 541 __ b(eq, miss);
516 542
517 // Check that the value is a JSFunction. 543 // Check that the value is a JSFunction.
518 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE); 544 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
519 __ b(ne, miss); 545 __ b(ne, miss);
520 546
521 // Patch the receiver with the global proxy if necessary.
522 if (is_global_object) {
523 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
524 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
525 __ str(r0, MemOperand(sp, argc * kPointerSize));
526 }
527
528 // Invoke the function. 547 // Invoke the function.
529 ParameterCount actual(argc); 548 ParameterCount actual(argc);
530 __ InvokeFunction(r1, actual, JUMP_FUNCTION); 549 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
531 } 550 }
532 551
533 552
534 static void GenerateCallNormal(MacroAssembler* masm, int argc) { 553 static void GenerateCallNormal(MacroAssembler* masm, int argc) {
535 // ----------- S t a t e ------------- 554 // ----------- S t a t e -------------
536 // -- r2 : name 555 // -- r2 : name
537 // -- lr : return address 556 // -- lr : return address
538 // ----------------------------------- 557 // -----------------------------------
539 Label miss, global_object, non_global_object; 558 Label miss;
540 559
541 // Get the receiver of the function from the stack into r1. 560 // Get the receiver of the function from the stack into r1.
542 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); 561 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
543 562
544 // Check that the receiver isn't a smi. 563 GenerateDictionaryLoadReceiverCheck(masm, r1, r0, r3, r4, &miss);
545 __ tst(r1, Operand(kSmiTagMask));
546 __ b(eq, &miss);
547 564
548 // Check that the receiver is a valid JS object. Put the map in r3. 565 // r0: elements
549 __ CompareObjectType(r1, r3, r0, FIRST_JS_OBJECT_TYPE); 566 // Search the dictionary - put result in register r1.
550 __ b(lt, &miss); 567 GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
551 568
552 // If this assert fails, we have to check upper bound too. 569 GenerateFunctionTailCall(masm, argc, &miss, r4);
553 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
554
555 // Check for access to global object.
556 __ cmp(r0, Operand(JS_GLOBAL_OBJECT_TYPE));
557 __ b(eq, &global_object);
558 __ cmp(r0, Operand(JS_BUILTINS_OBJECT_TYPE));
559 __ b(ne, &non_global_object);
560
561 // Accessing global object: Load and invoke.
562 __ bind(&global_object);
563 // Check that the global object does not require access checks.
564 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
565 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
566 __ b(ne, &miss);
567 GenerateNormalHelper(masm, argc, true, &miss, r4);
568
569 // Accessing non-global object: Check for access to global proxy.
570 Label global_proxy, invoke;
571 __ bind(&non_global_object);
572 __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE));
573 __ b(eq, &global_proxy);
574 // Check that the non-global, non-global-proxy object does not
575 // require access checks.
576 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
577 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
578 __ b(ne, &miss);
579 __ bind(&invoke);
580 GenerateNormalHelper(masm, argc, false, &miss, r4);
581
582 // Global object access: Check access rights.
583 __ bind(&global_proxy);
584 __ CheckAccessGlobalProxy(r1, r0, &miss);
585 __ b(&invoke);
586 570
587 __ bind(&miss); 571 __ bind(&miss);
588 } 572 }
589 573
590 574
591 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { 575 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
592 // ----------- S t a t e ------------- 576 // ----------- S t a t e -------------
593 // -- r2 : name 577 // -- r2 : name
594 // -- lr : return address 578 // -- lr : return address
595 // ----------------------------------- 579 // -----------------------------------
596 580
581 if (id == IC::kCallIC_Miss) {
582 __ IncrementCounter(&Counters::call_miss, 1, r3, r4);
583 } else {
584 __ IncrementCounter(&Counters::keyed_call_miss, 1, r3, r4);
585 }
586
597 // Get the receiver of the function from the stack. 587 // Get the receiver of the function from the stack.
598 __ ldr(r3, MemOperand(sp, argc * kPointerSize)); 588 __ ldr(r3, MemOperand(sp, argc * kPointerSize));
599 589
600 __ EnterInternalFrame(); 590 __ EnterInternalFrame();
601 591
602 // Push the receiver and the name of the function. 592 // Push the receiver and the name of the function.
603 __ Push(r3, r2); 593 __ Push(r3, r2);
604 594
605 // Call the entry. 595 // Call the entry.
606 __ mov(r0, Operand(2)); 596 __ mov(r0, Operand(2));
607 __ mov(r1, Operand(ExternalReference(IC_Utility(id)))); 597 __ mov(r1, Operand(ExternalReference(IC_Utility(id))));
608 598
609 CEntryStub stub(1); 599 CEntryStub stub(1);
610 __ CallStub(&stub); 600 __ CallStub(&stub);
611 601
612 // Move result to r1 and leave the internal frame. 602 // Move result to r1 and leave the internal frame.
613 __ mov(r1, Operand(r0)); 603 __ mov(r1, Operand(r0));
614 __ LeaveInternalFrame(); 604 __ LeaveInternalFrame();
615 605
616 // Check if the receiver is a global object of some sort. 606 // Check if the receiver is a global object of some sort.
617 Label invoke, global; 607 // This can happen only for regular CallIC but not KeyedCallIC.
618 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver 608 if (id == IC::kCallIC_Miss) {
619 __ tst(r2, Operand(kSmiTagMask)); 609 Label invoke, global;
620 __ b(eq, &invoke); 610 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
621 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE); 611 __ tst(r2, Operand(kSmiTagMask));
622 __ b(eq, &global); 612 __ b(eq, &invoke);
623 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE)); 613 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
624 __ b(ne, &invoke); 614 __ b(eq, &global);
615 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
616 __ b(ne, &invoke);
625 617
626 // Patch the receiver on the stack. 618 // Patch the receiver on the stack.
627 __ bind(&global); 619 __ bind(&global);
628 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); 620 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
629 __ str(r2, MemOperand(sp, argc * kPointerSize)); 621 __ str(r2, MemOperand(sp, argc * kPointerSize));
622 __ bind(&invoke);
623 }
630 624
631 // Invoke the function. 625 // Invoke the function.
632 ParameterCount actual(argc); 626 ParameterCount actual(argc);
633 __ bind(&invoke);
634 __ InvokeFunction(r1, actual, JUMP_FUNCTION); 627 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
635 } 628 }
636 629
637 630
638 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { 631 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
639 // ----------- S t a t e ------------- 632 // ----------- S t a t e -------------
640 // -- r2 : name 633 // -- r2 : name
641 // -- lr : return address 634 // -- lr : return address
642 // ----------------------------------- 635 // -----------------------------------
643 636
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 Label do_call, slow_call, slow_load, slow_reload_receiver; 684 Label do_call, slow_call, slow_load, slow_reload_receiver;
692 Label check_number_dictionary, check_string, lookup_monomorphic_cache; 685 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
693 Label index_smi, index_string; 686 Label index_smi, index_string;
694 687
695 // Check that the key is a smi. 688 // Check that the key is a smi.
696 __ BranchOnNotSmi(r2, &check_string); 689 __ BranchOnNotSmi(r2, &check_string);
697 __ bind(&index_smi); 690 __ bind(&index_smi);
698 // Now the key is known to be a smi. This place is also jumped to from below 691 // Now the key is known to be a smi. This place is also jumped to from below
699 // where a numeric string is converted to a smi. 692 // where a numeric string is converted to a smi.
700 693
701 GenerateKeyedLoadReceiverCheck(masm, r1, r0, r3, &slow_call); 694 GenerateKeyedLoadReceiverCheck(
695 masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
702 696
703 GenerateFastArrayLoad( 697 GenerateFastArrayLoad(
704 masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load); 698 masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
705 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1, r0, r3); 699 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1, r0, r3);
706 700
707 __ bind(&do_call); 701 __ bind(&do_call);
708 // receiver in r1 is not used after this point. 702 // receiver in r1 is not used after this point.
709 // r2: key 703 // r2: key
710 // r1: function 704 // r1: function
711 705 GenerateFunctionTailCall(masm, argc, &slow_call, r0);
712 // Check that the value in r1 is a JSFunction.
713 __ BranchOnSmi(r1, &slow_call);
714 __ CompareObjectType(r1, r0, r0, JS_FUNCTION_TYPE);
715 __ b(ne, &slow_call);
716 // Invoke the function.
717 ParameterCount actual(argc);
718 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
719 706
720 __ bind(&check_number_dictionary); 707 __ bind(&check_number_dictionary);
721 // r2: key 708 // r2: key
722 // r3: elements map 709 // r3: elements map
723 // r4: elements 710 // r4: elements
724 // Check whether the elements is a number dictionary. 711 // Check whether the elements is a number dictionary.
725 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); 712 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
726 __ cmp(r3, ip); 713 __ cmp(r3, ip);
727 __ b(ne, &slow_load); 714 __ b(ne, &slow_load);
728 __ mov(r0, Operand(r2, ASR, kSmiTagSize)); 715 __ mov(r0, Operand(r2, ASR, kSmiTagSize));
(...skipping 15 matching lines...) Expand all
744 __ mov(r1, r0); 731 __ mov(r1, r0);
745 __ jmp(&do_call); 732 __ jmp(&do_call);
746 733
747 __ bind(&check_string); 734 __ bind(&check_string);
748 GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call); 735 GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
749 736
750 // The key is known to be a symbol. 737 // The key is known to be a symbol.
751 // If the receiver is a regular JS object with slow properties then do 738 // If the receiver is a regular JS object with slow properties then do
752 // a quick inline probe of the receiver's dictionary. 739 // a quick inline probe of the receiver's dictionary.
753 // Otherwise do the monomorphic cache probe. 740 // Otherwise do the monomorphic cache probe.
754 GenerateKeyedLoadReceiverCheck(masm, r1, r0, r3, &lookup_monomorphic_cache); 741 GenerateKeyedLoadReceiverCheck(
742 masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
755 743
756 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset)); 744 __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
757 __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); 745 __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
758 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); 746 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
759 __ cmp(r3, ip); 747 __ cmp(r3, ip);
760 __ b(ne, &lookup_monomorphic_cache); 748 __ b(ne, &lookup_monomorphic_cache);
761 749
762 GenerateDictionaryLoad( 750 GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
763 masm, &slow_load, r1, r2, r1, r0, r3, r4, DICTIONARY_CHECK_DONE);
764 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1, r0, r3); 751 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1, r0, r3);
765 __ jmp(&do_call); 752 __ jmp(&do_call);
766 753
767 __ bind(&lookup_monomorphic_cache); 754 __ bind(&lookup_monomorphic_cache);
768 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1, r0, r3); 755 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1, r0, r3);
769 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); 756 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
770 // Fall through on miss. 757 // Fall through on miss.
771 758
772 __ bind(&slow_call); 759 __ bind(&slow_call);
773 // This branch is taken if: 760 // This branch is taken if:
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
819 } 806 }
820 807
821 808
822 void LoadIC::GenerateNormal(MacroAssembler* masm) { 809 void LoadIC::GenerateNormal(MacroAssembler* masm) {
823 // ----------- S t a t e ------------- 810 // ----------- S t a t e -------------
824 // -- r2 : name 811 // -- r2 : name
825 // -- lr : return address 812 // -- lr : return address
826 // -- r0 : receiver 813 // -- r0 : receiver
827 // -- sp[0] : receiver 814 // -- sp[0] : receiver
828 // ----------------------------------- 815 // -----------------------------------
829 Label miss, probe, global; 816 Label miss;
830 817
831 // Check that the receiver isn't a smi. 818 GenerateDictionaryLoadReceiverCheck(masm, r0, r1, r3, r4, &miss);
832 __ tst(r0, Operand(kSmiTagMask));
833 __ b(eq, &miss);
834 819
835 // Check that the receiver is a valid JS object. Put the map in r3. 820 // r1: elements
836 __ CompareObjectType(r0, r3, r1, FIRST_JS_OBJECT_TYPE); 821 GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
837 __ b(lt, &miss);
838 // If this assert fails, we have to check upper bound too.
839 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
840
841 // Check for access to global object (unlikely).
842 __ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE));
843 __ b(eq, &global);
844
845 // Check for non-global object that requires access check.
846 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
847 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
848 __ b(ne, &miss);
849
850 __ bind(&probe);
851 GenerateDictionaryLoad(masm, &miss, r0, r2, r0, r1, r3, r4, CHECK_DICTIONARY);
852 __ Ret(); 822 __ Ret();
853 823
854 // Global object access: Check access rights.
855 __ bind(&global);
856 __ CheckAccessGlobalProxy(r0, r1, &miss);
857 __ b(&probe);
858
859 // Cache miss: Jump to runtime. 824 // Cache miss: Jump to runtime.
860 __ bind(&miss); 825 __ bind(&miss);
861 GenerateMiss(masm); 826 GenerateMiss(masm);
862 } 827 }
863 828
864 829
865 void LoadIC::GenerateMiss(MacroAssembler* masm) { 830 void LoadIC::GenerateMiss(MacroAssembler* masm) {
866 // ----------- S t a t e ------------- 831 // ----------- S t a t e -------------
867 // -- r2 : name 832 // -- r2 : name
868 // -- lr : return address 833 // -- lr : return address
869 // -- r0 : receiver 834 // -- r0 : receiver
870 // -- sp[0] : receiver 835 // -- sp[0] : receiver
871 // ----------------------------------- 836 // -----------------------------------
872 837
838 __ IncrementCounter(&Counters::load_miss, 1, r3, r4);
839
873 __ mov(r3, r0); 840 __ mov(r3, r0);
874 __ Push(r3, r2); 841 __ Push(r3, r2);
875 842
876 // Perform tail call to the entry. 843 // Perform tail call to the entry.
877 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); 844 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
878 __ TailCallExternalReference(ref, 2, 1); 845 __ TailCallExternalReference(ref, 2, 1);
879 } 846 }
880 847
881 848
882 static inline bool IsInlinedICSite(Address address, 849 static inline bool IsInlinedICSite(Address address,
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
1006 Object* KeyedLoadIC_Miss(Arguments args); 973 Object* KeyedLoadIC_Miss(Arguments args);
1007 974
1008 975
1009 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { 976 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
1010 // ---------- S t a t e -------------- 977 // ---------- S t a t e --------------
1011 // -- lr : return address 978 // -- lr : return address
1012 // -- r0 : key 979 // -- r0 : key
1013 // -- r1 : receiver 980 // -- r1 : receiver
1014 // ----------------------------------- 981 // -----------------------------------
1015 982
983 __ IncrementCounter(&Counters::keyed_load_miss, 1, r3, r4);
984
1016 __ Push(r1, r0); 985 __ Push(r1, r0);
1017 986
1018 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss)); 987 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
1019 __ TailCallExternalReference(ref, 2, 1); 988 __ TailCallExternalReference(ref, 2, 1);
1020 } 989 }
1021 990
1022 991
1023 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { 992 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1024 // ---------- S t a t e -------------- 993 // ---------- S t a t e --------------
1025 // -- lr : return address 994 // -- lr : return address
(...skipping 12 matching lines...) Expand all
1038 // -- lr : return address 1007 // -- lr : return address
1039 // -- r0 : key 1008 // -- r0 : key
1040 // -- r1 : receiver 1009 // -- r1 : receiver
1041 // ----------------------------------- 1010 // -----------------------------------
1042 Label slow, check_string, index_smi, index_string; 1011 Label slow, check_string, index_smi, index_string;
1043 Label check_pixel_array, probe_dictionary, check_number_dictionary; 1012 Label check_pixel_array, probe_dictionary, check_number_dictionary;
1044 1013
1045 Register key = r0; 1014 Register key = r0;
1046 Register receiver = r1; 1015 Register receiver = r1;
1047 1016
1048 GenerateKeyedLoadReceiverCheck(masm, receiver, r2, r3, &slow);
1049
1050 // Check that the key is a smi. 1017 // Check that the key is a smi.
1051 __ BranchOnNotSmi(key, &check_string); 1018 __ BranchOnNotSmi(key, &check_string);
1052 __ bind(&index_smi); 1019 __ bind(&index_smi);
1053 // Now the key is known to be a smi. This place is also jumped to from below 1020 // Now the key is known to be a smi. This place is also jumped to from below
1054 // where a numeric string is converted to a smi. 1021 // where a numeric string is converted to a smi.
1055 1022
1023 GenerateKeyedLoadReceiverCheck(
1024 masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
1025
1056 GenerateFastArrayLoad( 1026 GenerateFastArrayLoad(
1057 masm, receiver, key, r4, r3, r2, r0, &check_pixel_array, &slow); 1027 masm, receiver, key, r4, r3, r2, r0, &check_pixel_array, &slow);
1058 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3); 1028 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3);
1059 __ Ret(); 1029 __ Ret();
1060 1030
1061 // Check whether the elements is a pixel array. 1031 // Check whether the elements is a pixel array.
1062 // r0: key 1032 // r0: key
1063 // r3: elements map 1033 // r3: elements map
1064 // r4: elements 1034 // r4: elements
1065 __ bind(&check_pixel_array); 1035 __ bind(&check_pixel_array);
(...skipping 22 matching lines...) Expand all
1088 __ Ret(); 1058 __ Ret();
1089 1059
1090 // Slow case, key and receiver still in r0 and r1. 1060 // Slow case, key and receiver still in r0 and r1.
1091 __ bind(&slow); 1061 __ bind(&slow);
1092 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3); 1062 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3);
1093 GenerateRuntimeGetProperty(masm); 1063 GenerateRuntimeGetProperty(masm);
1094 1064
1095 __ bind(&check_string); 1065 __ bind(&check_string);
1096 GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow); 1066 GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
1097 1067
1068 GenerateKeyedLoadReceiverCheck(
1069 masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
1070
1098 // If the receiver is a fast-case object, check the keyed lookup 1071 // If the receiver is a fast-case object, check the keyed lookup
1099 // cache. Otherwise probe the dictionary. 1072 // cache. Otherwise probe the dictionary.
1100 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset)); 1073 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
1101 __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); 1074 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
1102 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); 1075 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
1103 __ cmp(r3, ip); 1076 __ cmp(r4, ip);
1104 __ b(eq, &probe_dictionary); 1077 __ b(eq, &probe_dictionary);
1105 1078
1106 // Load the map of the receiver, compute the keyed lookup cache hash 1079 // Load the map of the receiver, compute the keyed lookup cache hash
1107 // based on 32 bits of the map pointer and the string hash. 1080 // based on 32 bits of the map pointer and the string hash.
1108 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); 1081 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1109 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift)); 1082 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
1110 __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset)); 1083 __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
1111 __ eor(r3, r3, Operand(r4, ASR, String::kHashShift)); 1084 __ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
1112 __ And(r3, r3, Operand(KeyedLookupCache::kCapacityMask)); 1085 __ And(r3, r3, Operand(KeyedLookupCache::kCapacityMask));
1113 1086
(...skipping 27 matching lines...) Expand all
1141 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset)); 1114 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
1142 __ add(r6, r6, r5); // Index from start of object. 1115 __ add(r6, r6, r5); // Index from start of object.
1143 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag. 1116 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag.
1144 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2)); 1117 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
1145 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3); 1118 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
1146 __ Ret(); 1119 __ Ret();
1147 1120
1148 // Do a quick inline probe of the receiver's dictionary, if it 1121 // Do a quick inline probe of the receiver's dictionary, if it
1149 // exists. 1122 // exists.
1150 __ bind(&probe_dictionary); 1123 __ bind(&probe_dictionary);
1124 // r1: receiver
1125 // r0: key
1126 // r3: elements
1127 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1128 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
1129 GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
1151 // Load the property to r0. 1130 // Load the property to r0.
1152 GenerateDictionaryLoad( 1131 GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
1153 masm, &slow, r1, r0, r0, r2, r3, r4, DICTIONARY_CHECK_DONE);
1154 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3); 1132 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3);
1155 __ Ret(); 1133 __ Ret();
1156 1134
1157 __ bind(&index_string); 1135 __ bind(&index_string);
1158 GenerateIndexFromHash(masm, key, r3); 1136 GenerateIndexFromHash(masm, key, r3);
1159 // Now jump to the place where smi keys are handled. 1137 // Now jump to the place where smi keys are handled.
1160 __ jmp(&index_smi); 1138 __ jmp(&index_smi);
1161 } 1139 }
1162 1140
1163 1141
(...skipping 995 matching lines...) Expand 10 before | Expand all | Expand 10 after
2159 GenerateMiss(masm); 2137 GenerateMiss(masm);
2160 } 2138 }
2161 2139
2162 2140
2163 #undef __ 2141 #undef __
2164 2142
2165 2143
2166 } } // namespace v8::internal 2144 } } // namespace v8::internal
2167 2145
2168 #endif // V8_TARGET_ARCH_ARM 2146 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « no previous file | src/ia32/ic-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698