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

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

Issue 144963003: A64: add missing files. (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/a64
Patch Set: Created 6 years, 11 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 | « src/a64/full-codegen-a64.cc ('k') | src/a64/instructions-a64.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
27
28 #include "v8.h"
29
30 #if defined(V8_TARGET_ARCH_A64)
31
32 #include "a64/assembler-a64.h"
33 #include "code-stubs.h"
34 #include "codegen.h"
35 #include "disasm.h"
36 #include "ic-inl.h"
37 #include "runtime.h"
38 #include "stub-cache.h"
39
40 namespace v8 {
41 namespace internal {
42
43
44 #define __ ACCESS_MASM(masm)
45
46
47 // "type" holds an instance type on entry and is not clobbered.
48 // Generated code branch on "global_object" if type is any kind of global
49 // JS object.
50 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
51 Register type,
52 Label* global_object) {
53 __ Cmp(type, JS_GLOBAL_OBJECT_TYPE);
54 __ Ccmp(type, JS_BUILTINS_OBJECT_TYPE, ZFlag, ne);
55 __ Ccmp(type, JS_GLOBAL_PROXY_TYPE, ZFlag, ne);
56 __ B(eq, global_object);
57 }
58
59
60 // Generated code falls through if the receiver is a regular non-global
61 // JS object with slow properties and no interceptors.
62 //
63 // "receiver" holds the receiver on entry and is unchanged.
64 // "elements" holds the property dictionary on fall through.
65 static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
66 Register receiver,
67 Register elements,
68 Register scratch0,
69 Register scratch1,
70 Label* miss) {
71 ASSERT(!AreAliased(receiver, elements, scratch0, scratch1));
72
73 // Check that the receiver isn't a smi.
74 __ JumpIfSmi(receiver, miss);
75
76 // Check that the receiver is a valid JS object.
77 // Let t be the object instance type, we want:
78 // FIRST_SPEC_OBJECT_TYPE <= t <= LAST_SPEC_OBJECT_TYPE.
79 // Since LAST_SPEC_OBJECT_TYPE is the last possible instance type we only
80 // check the lower bound.
81 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
82
83 __ JumpIfObjectType(receiver, scratch0, scratch1, FIRST_SPEC_OBJECT_TYPE,
84 miss, lt);
85
86 // scratch0 now contains the map of the receiver and scratch1 the object type.
87 Register map = scratch0;
88 Register type = scratch1;
89
90 // Check if the receiver is a global JS object.
91 GenerateGlobalInstanceTypeCheck(masm, type, miss);
92
93 // Check that the object does not require access checks.
94 __ Ldrb(scratch1, FieldMemOperand(map, Map::kBitFieldOffset));
95 __ Tbnz(scratch1, Map::kIsAccessCheckNeeded, miss);
96 __ Tbnz(scratch1, Map::kHasNamedInterceptor, miss);
97
98 // Check that the properties dictionary is valid.
99 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
100 __ Ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
101 __ JumpIfNotRoot(scratch1, Heap::kHashTableMapRootIndex, miss);
102 }
103
104
105 // Helper function used from LoadIC/CallIC GenerateNormal.
106 //
107 // elements: Property dictionary. It is not clobbered if a jump to the miss
108 // label is done.
109 // name: Property name. It is not clobbered if a jump to the miss label is
110 // done
111 // result: Register for the result. It is only updated if a jump to the miss
112 // label is not done.
113 // The scratch registers need to be different from elements, name and result.
114 // The generated code assumes that the receiver has slow properties,
115 // is not a global object and does not have interceptors.
116 static void GenerateDictionaryLoad(MacroAssembler* masm,
117 Label* miss,
118 Register elements,
119 Register name,
120 Register result,
121 Register scratch1,
122 Register scratch2) {
123 ASSERT(!AreAliased(elements, name, scratch1, scratch2));
124 ASSERT(!AreAliased(result, scratch1, scratch2));
125
126 Label done;
127
128 // Probe the dictionary.
129 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
130 miss,
131 &done,
132 elements,
133 name,
134 scratch1,
135 scratch2);
136
137 // If probing finds an entry check that the value is a normal property.
138 __ Bind(&done);
139
140 static const int kElementsStartOffset = NameDictionary::kHeaderSize +
141 NameDictionary::kElementsStartIndex * kPointerSize;
142 static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
143 __ Ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
144 __ Tst(scratch1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
145 __ B(ne, miss);
146
147 // Get the value at the masked, scaled index and return.
148 __ Ldr(result,
149 FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
150 }
151
152
153 // Helper function used from StoreIC::GenerateNormal.
154 //
155 // elements: Property dictionary. It is not clobbered if a jump to the miss
156 // label is done.
157 // name: Property name. It is not clobbered if a jump to the miss label is
158 // done
159 // value: The value to store (never clobbered).
160 //
161 // The generated code assumes that the receiver has slow properties,
162 // is not a global object and does not have interceptors.
163 static void GenerateDictionaryStore(MacroAssembler* masm,
164 Label* miss,
165 Register elements,
166 Register name,
167 Register value,
168 Register scratch1,
169 Register scratch2) {
170 ASSERT(!AreAliased(elements, name, value, scratch1, scratch2));
171
172 Label done;
173
174 // Probe the dictionary.
175 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
176 miss,
177 &done,
178 elements,
179 name,
180 scratch1,
181 scratch2);
182
183 // If probing finds an entry in the dictionary check that the value
184 // is a normal property that is not read only.
185 __ Bind(&done);
186
187 static const int kElementsStartOffset = NameDictionary::kHeaderSize +
188 NameDictionary::kElementsStartIndex * kPointerSize;
189 static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
190 static const int kTypeAndReadOnlyMask =
191 PropertyDetails::TypeField::kMask |
192 PropertyDetails::AttributesField::encode(READ_ONLY);
193 __ Ldrsw(scratch1, UntagSmiFieldMemOperand(scratch2, kDetailsOffset));
194 __ Tst(scratch1, kTypeAndReadOnlyMask);
195 __ B(ne, miss);
196
197 // Store the value at the masked, scaled index and return.
198 static const int kValueOffset = kElementsStartOffset + kPointerSize;
199 __ Add(scratch2, scratch2, kValueOffset - kHeapObjectTag);
200 __ Str(value, MemOperand(scratch2));
201
202 // Update the write barrier. Make sure not to clobber the value.
203 __ Mov(scratch1, value);
204 __ RecordWrite(
205 elements, scratch2, scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs);
206 }
207
208
209 // Checks the receiver for special cases (value type, slow case bits).
210 // Falls through for regular JS object and return the map of the
211 // receiver in 'map_scratch' if the receiver is not a SMI.
212 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
213 Register receiver,
214 Register map_scratch,
215 Register scratch,
216 int interceptor_bit,
217 Label* slow) {
218 ASSERT(!AreAliased(map_scratch, scratch));
219
220 // Check that the object isn't a smi.
221 __ JumpIfSmi(receiver, slow);
222 // Get the map of the receiver.
223 __ Ldr(map_scratch, FieldMemOperand(receiver, HeapObject::kMapOffset));
224 // Check bit field.
225 __ Ldrb(scratch, FieldMemOperand(map_scratch, Map::kBitFieldOffset));
226 __ Tbnz(scratch, Map::kIsAccessCheckNeeded, slow);
227 __ Tbnz(scratch, interceptor_bit, slow);
228
229 // Check that the object is some kind of JS object EXCEPT JS Value type.
230 // In the case that the object is a value-wrapper object, we enter the
231 // runtime system to make sure that indexing into string objects work
232 // as intended.
233 STATIC_ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
234 __ Ldrb(scratch, FieldMemOperand(map_scratch, Map::kInstanceTypeOffset));
235 __ Cmp(scratch, JS_OBJECT_TYPE);
236 __ B(lt, slow);
237 }
238
239
240 // Loads an indexed element from a fast case array.
241 // If not_fast_array is NULL, doesn't perform the elements map check.
242 //
243 // receiver - holds the receiver on entry.
244 // Unchanged unless 'result' is the same register.
245 //
246 // key - holds the smi key on entry.
247 // Unchanged unless 'result' is the same register.
248 //
249 // elements - holds the elements of the receiver on exit.
250 //
251 // elements_map - holds the elements map on exit if the not_fast_array branch is
252 // taken. Otherwise, this is used as a scratch register.
253 //
254 // result - holds the result on exit if the load succeeded.
255 // Allowed to be the the same as 'receiver' or 'key'.
256 // Unchanged on bailout so 'receiver' and 'key' can be safely
257 // used by further computation.
258 static void GenerateFastArrayLoad(MacroAssembler* masm,
259 Register receiver,
260 Register key,
261 Register elements,
262 Register elements_map,
263 Register scratch2,
264 Register result,
265 Label* not_fast_array,
266 Label* slow) {
267 ASSERT(!AreAliased(receiver, key, elements, elements_map, scratch2));
268
269 // Check for fast array.
270 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
271 if (not_fast_array != NULL) {
272 // Check that the object is in fast mode and writable.
273 __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
274 __ JumpIfNotRoot(elements_map, Heap::kFixedArrayMapRootIndex,
275 not_fast_array);
276 } else {
277 __ AssertFastElements(elements);
278 }
279
280 // The elements_map register is only used for the not_fast_array path, which
281 // was handled above. From this point onward it is a scratch register.
282 Register scratch1 = elements_map;
283
284 // Check that the key (index) is within bounds.
285 __ Ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
286 __ Cmp(key, scratch1);
287 __ B(hs, slow);
288
289 // Fast case: Do the load.
290 __ Add(scratch1, elements, FixedArray::kHeaderSize - kHeapObjectTag);
291 __ SmiUntag(scratch2, key);
292 __ Ldr(scratch2, MemOperand(scratch1, scratch2, LSL, kPointerSizeLog2));
293
294 // In case the loaded value is the_hole we have to consult GetProperty
295 // to ensure the prototype chain is searched.
296 __ JumpIfRoot(scratch2, Heap::kTheHoleValueRootIndex, slow);
297
298 // Move the value to the result register.
299 // 'result' can alias with 'receiver' or 'key' but these two must be
300 // preserved if we jump to 'slow'.
301 __ Mov(result, scratch2);
302 }
303
304
305 // Checks whether a key is an array index string or a unique name.
306 // Falls through if a key is a unique name.
307 // The map of the key is returned in 'map_scratch'.
308 // If the jump to 'index_string' is done the hash of the key is left
309 // in 'hash_scratch'.
310 static void GenerateKeyNameCheck(MacroAssembler* masm,
311 Register key,
312 Register map_scratch,
313 Register hash_scratch,
314 Label* index_string,
315 Label* not_unique) {
316 ASSERT(!AreAliased(key, map_scratch, hash_scratch));
317
318 // Is the key a name?
319 Label unique;
320 __ JumpIfObjectType(key, map_scratch, hash_scratch, LAST_UNIQUE_NAME_TYPE,
321 not_unique, hi);
322 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
323 __ B(eq, &unique);
324
325 // Is the string an array index with cached numeric value?
326 __ Ldr(hash_scratch.W(), FieldMemOperand(key, Name::kHashFieldOffset));
327 __ TestAndBranchIfAllClear(hash_scratch,
328 Name::kContainsCachedArrayIndexMask,
329 index_string);
330
331 // Is the string internalized?
332 __ Ldrb(hash_scratch, FieldMemOperand(map_scratch, Map::kInstanceTypeOffset));
333 STATIC_ASSERT(kInternalizedTag != 0);
334 __ TestAndBranchIfAllClear(hash_scratch, kIsInternalizedMask,
335 not_unique);
336
337 __ Bind(&unique);
338 // Fall through if the key is a unique name.
339 }
340
341
342 // Neither 'object' nor 'key' are modified by this function.
343 //
344 // If the 'unmapped_case' or 'slow_case' exit is taken, the 'map' register is
345 // left with the object's elements map. Otherwise, it is used as a scratch
346 // register.
347 static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
348 Register object,
349 Register key,
350 Register map,
351 Register scratch1,
352 Register scratch2,
353 Label* unmapped_case,
354 Label* slow_case) {
355 ASSERT(!AreAliased(object, key, map, scratch1, scratch2));
356
357 Heap* heap = masm->isolate()->heap();
358
359 // Check that the receiver is a JSObject. Because of the elements
360 // map check later, we do not need to check for interceptors or
361 // whether it requires access checks.
362 __ JumpIfSmi(object, slow_case);
363 // Check that the object is some kind of JSObject.
364 __ JumpIfObjectType(object, map, scratch1, FIRST_JS_RECEIVER_TYPE,
365 slow_case, lt);
366
367 // Check that the key is a positive smi.
368 __ JumpIfNotSmi(key, slow_case);
369 __ Tbnz(key, kXSignBit, slow_case);
370
371 // Load the elements object and check its map.
372 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
373 __ Ldr(map, FieldMemOperand(object, JSObject::kElementsOffset));
374 __ CheckMap(map, scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
375
376 // Check if element is in the range of mapped arguments. If not, jump
377 // to the unmapped lookup.
378 __ Ldr(scratch1, FieldMemOperand(map, FixedArray::kLengthOffset));
379 __ Sub(scratch1, scratch1, Operand(Smi::FromInt(2)));
380 __ Cmp(key, scratch1);
381 __ B(hs, unmapped_case);
382
383 // Load element index and check whether it is the hole.
384 static const int offset =
385 FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
386
387 __ Add(scratch1, map, offset);
388 __ SmiUntag(scratch2, key);
389 __ Ldr(scratch1, MemOperand(scratch1, scratch2, LSL, kPointerSizeLog2));
390 __ JumpIfRoot(scratch1, Heap::kTheHoleValueRootIndex, unmapped_case);
391
392 // Load value from context and return it.
393 __ Ldr(scratch2, FieldMemOperand(map, FixedArray::kHeaderSize));
394 __ SmiUntag(scratch1);
395 __ Add(scratch2, scratch2, Context::kHeaderSize - kHeapObjectTag);
396 return MemOperand(scratch2, scratch1, LSL, kPointerSizeLog2);
397 }
398
399
400 // The 'parameter_map' register must be loaded with the parameter map of the
401 // arguments object and is overwritten.
402 static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
403 Register key,
404 Register parameter_map,
405 Register scratch,
406 Label* slow_case) {
407 ASSERT(!AreAliased(key, parameter_map, scratch));
408
409 // Element is in arguments backing store, which is referenced by the
410 // second element of the parameter_map.
411 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
412 Register backing_store = parameter_map;
413 __ Ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
414 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
415 __ CheckMap(
416 backing_store, scratch, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
417 __ Ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
418 __ Cmp(key, scratch);
419 __ B(hs, slow_case);
420
421 __ Add(backing_store,
422 backing_store,
423 FixedArray::kHeaderSize - kHeapObjectTag);
424 __ SmiUntag(scratch, key);
425 return MemOperand(backing_store, scratch, LSL, kPointerSizeLog2);
426 }
427
428
429 Object* CallIC_Miss(Arguments args);
430
431 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
432 int argc,
433 Code::Kind kind,
434 Code::ExtraICState extra_state) {
435 // ----------- S t a t e -------------
436 // -- x1 : receiver
437 // -- x2 : name
438 // -----------------------------------
439 Register receiver = x1;
440 Register name = x2;
441
442 Label number, non_number, non_string, boolean, probe, miss;
443
444 // Probe the stub cache.
445 Code::Flags flags = Code::ComputeFlags(kind,
446 MONOMORPHIC,
447 extra_state,
448 Code::NORMAL,
449 argc);
450 Isolate::Current()->stub_cache()->GenerateProbe(
451 masm, flags, receiver, name, x3, x4, x5, x6);
452
453 // If the stub cache probing failed, the receiver might be a value.
454 // For value objects, we use the map of the prototype objects for
455 // the corresponding JSValue for the cache and that is what we need
456 // to probe.
457
458 // Check for number.
459 __ JumpIfSmi(receiver, &number);
460 Register receiver_type = x3;
461 __ JumpIfNotObjectType(receiver, x4, receiver_type, HEAP_NUMBER_TYPE,
462 &non_number);
463
464 __ Bind(&number);
465 StubCompiler::GenerateLoadGlobalFunctionPrototype(
466 masm, Context::NUMBER_FUNCTION_INDEX, receiver);
467 __ B(&probe);
468
469 // Check for string.
470 __ Bind(&non_number);
471 __ Cmp(receiver_type, FIRST_NONSTRING_TYPE);
472 __ B(hs, &non_string);
473 StubCompiler::GenerateLoadGlobalFunctionPrototype(
474 masm, Context::STRING_FUNCTION_INDEX, receiver);
475 __ B(&probe);
476
477 // Check for boolean.
478 __ Bind(&non_string);
479 __ JumpIfRoot(receiver, Heap::kTrueValueRootIndex, &boolean);
480 __ JumpIfNotRoot(receiver, Heap::kFalseValueRootIndex, &miss);
481
482 __ Bind(&boolean);
483 StubCompiler::GenerateLoadGlobalFunctionPrototype(
484 masm, Context::BOOLEAN_FUNCTION_INDEX, receiver);
485
486 // Probe the stub cache for the value object.
487 __ Bind(&probe);
488 Isolate::Current()->stub_cache()->GenerateProbe(
489 masm, flags, receiver, name, x3, x4, x5, x6);
490
491 __ Bind(&miss);
492 // Fall-through on miss.
493 }
494
495
496 static void GenerateFunctionTailCall(MacroAssembler* masm,
497 int argc,
498 Label* miss,
499 Register function,
500 Register scratch) {
501 ASSERT(!AreAliased(function, scratch));
502
503 // Check that the value is a JSFunction.
504 __ JumpIfSmi(function, miss);
505 __ JumpIfNotObjectType(function, scratch, scratch, JS_FUNCTION_TYPE, miss);
506
507 // Invoke the function.
508 ParameterCount actual(argc);
509 __ InvokeFunction(
510 function, actual, JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
511 }
512
513
514 void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
515 // ----------- S t a t e -------------
516 // -- x2 : name
517 // -- lr : return address
518 // -----------------------------------
519 Label miss;
520 Register name = x2;
521
522 // Get the receiver of the function from the stack.
523 Register receiver = x1;
524 __ Peek(receiver, argc * kXRegSizeInBytes);
525
526 Register elements = x0;
527 GenerateNameDictionaryReceiverCheck(masm, receiver, elements, x3, x4, &miss);
528
529 // Search the dictionary.
530 Register function = x1;
531 GenerateDictionaryLoad(masm, &miss, elements, name, function, x3, x4);
532
533 GenerateFunctionTailCall(masm, argc, &miss, function, x4);
534
535 __ Bind(&miss);
536 // Fall-through on miss.
537 }
538
539
540 void CallICBase::GenerateMiss(MacroAssembler* masm,
541 int argc,
542 IC::UtilityId id,
543 Code::ExtraICState extra_state) {
544 // ----------- S t a t e -------------
545 // -- x2 : name
546 // -- lr : return address
547 // -----------------------------------
548 Isolate* isolate = masm->isolate();
549
550 if (id == IC::kCallIC_Miss) {
551 __ IncrementCounter(isolate->counters()->call_miss(), 1, x3, x4);
552 } else {
553 __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, x3, x4);
554 }
555
556 // Get the receiver of the function from the stack.
557 __ Peek(x3, argc * kXRegSizeInBytes);
558
559 {
560 FrameScope scope(masm, StackFrame::INTERNAL);
561
562 // Push the receiver and the name of the function.
563 __ Push(x3, x2);
564
565 // Call the entry.
566 __ Mov(x0, 2);
567 __ Mov(x1, Operand(ExternalReference(IC_Utility(id), isolate)));
568
569 CEntryStub stub(1);
570 __ CallStub(&stub);
571
572 // Move result to x1 and leave the internal frame.
573 __ Mov(x1, x0);
574 }
575
576 // Check if the receiver is a global object of some sort.
577 // This can happen only for regular CallIC but not KeyedCallIC.
578 if (id == IC::kCallIC_Miss) {
579 Label invoke, global;
580 __ Peek(x2, argc * kPointerSize); // receiver
581 __ JumpIfSmi(x2, &invoke);
582 __ JumpIfObjectType(x2, x3, x3, JS_GLOBAL_OBJECT_TYPE, &global);
583 __ Cmp(x3, JS_BUILTINS_OBJECT_TYPE);
584 __ B(ne, &invoke);
585
586 // Patch the receiver on the stack.
587 __ Bind(&global);
588 __ Ldr(x2, FieldMemOperand(x2, GlobalObject::kGlobalReceiverOffset));
589 __ Poke(x2, argc * kXRegSizeInBytes);
590 __ Bind(&invoke);
591 }
592
593 // Invoke the function.
594 CallKind call_kind = CallICBase::Contextual::decode(extra_state)
595 ? CALL_AS_FUNCTION
596 : CALL_AS_METHOD;
597 ParameterCount actual(argc);
598 __ InvokeFunction(x1,
599 actual,
600 JUMP_FUNCTION,
601 NullCallWrapper(),
602 call_kind);
603 }
604
605
606 void CallIC::GenerateMegamorphic(MacroAssembler* masm,
607 int argc,
608 Code::ExtraICState extra_ic_state) {
609 // ----------- S t a t e -------------
610 // -- x2 : name
611 // -- lr : return address
612 // -----------------------------------
613
614 // Get the receiver of the function from the stack.
615 // GenerateMonomorphicCacheProbe expects the receiver to be in x1.
616 Register receiver = x1;
617 __ Peek(receiver, argc * kXRegSizeInBytes);
618
619 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
620 GenerateMiss(masm, argc, extra_ic_state);
621 }
622
623
624 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
625 // ----------- S t a t e -------------
626 // -- x2 : name / key
627 // -- lr : return address
628 // -----------------------------------
629 Register key = x2;
630
631 // Get the receiver of the function from the stack.
632 Register receiver = x1;
633 __ Peek(receiver, argc * kXRegSizeInBytes);
634
635 Label key_is_not_smi;
636 Label key_is_smi;
637 Label slow_call;
638 Label not_fast_array;
639 Label slow_load;
640 Label do_call;
641 Label key_is_index_name;
642 Label lookup_monomorphic_cache;
643
644 __ JumpIfNotSmi(key, &key_is_not_smi);
645 __ Bind(&key_is_smi);
646 // Now the key is known to be a smi. This place is also jumped to from below
647 // where a numeric string is converted to a smi.
648 // Live values:
649 // x1: receiver
650 // x2: key
651 GenerateKeyedLoadReceiverCheck(masm, receiver, x10, x11,
652 Map::kHasIndexedInterceptor, &slow_call);
653
654 // Due to the requirements of some helpers, both 'function' and 'receiver' are
655 // mapped to x1. However, they are never live at the same time.
656 Register function = x1;
657 Register elements_map = x3;
658 Register elements = x4;
659 GenerateFastArrayLoad(masm, receiver, key, elements, elements_map, x10,
660 function, &not_fast_array, &slow_load);
661 Counters* counters = masm->isolate()->counters();
662 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, x10, x11);
663
664 __ Bind(&do_call);
665 // Live values:
666 // x1: function
667 // x2: key
668 // GenerateFunctionTailCall requires that function is x1. This is enforced by
669 // MacroAssembler::InvokeFunction.
670 GenerateFunctionTailCall(masm, argc, &slow_call, function, x10);
671
672 // It should not be possible for execution to fall through a tail call.
673 if (__ emit_debug_code()) {
674 __ Abort("Unreachable code.");
675 }
676
677 __ Bind(&not_fast_array);
678 // Check whether the elements is a number dictionary.
679 // Live values:
680 // x1: receiver
681 // x2: key
682 // x3: elements map
683 // x4: elements
684 __ JumpIfNotRoot(elements_map, Heap::kHashTableMapRootIndex, &slow_load);
685 __ LoadFromNumberDictionary(&slow_load, elements, key, function,
686 x10, x11, x12, x13);
687 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, x10, x11);
688 __ B(&do_call);
689
690 __ Bind(&slow_load);
691 // This branch is taken when calling KeyedCallIC_Miss (via GenerateMiss) is
692 // neither required nor beneficial.
693 // Live values:
694 // x1: receiver
695 // x2: key
696 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, x10, x11);
697 {
698 FrameScope scope(masm, StackFrame::INTERNAL);
699 // The key needs to be preserved across the runtime call.
700 __ Push(key);
701 // Pass the receiver and the key as argument to KeyedGetProperty.
702 __ Push(receiver, key);
703 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
704 __ Pop(key);
705 }
706 // The return value is in x0 (as per AAPCS64).
707 __ Mov(function, x0);
708 __ B(&do_call);
709
710 __ Bind(&key_is_not_smi);
711 // The key isn't a SMI. Check to see if it's a name.
712 // Live values:
713 // x1: receiver
714 // x2: key
715 Register map = x6;
716 Register hash = x7;
717 GenerateKeyNameCheck(masm, key, map, hash, &key_is_index_name, &slow_call);
718
719 // If the check fell through, the key is known to be a unique name.
720 //
721 // If the receiver is a regular JS object with slow properties then do
722 // a quick inline probe of the receiver's dictionary.
723 // Otherwise do the monomorphic cache probe.
724 GenerateKeyedLoadReceiverCheck(masm, receiver, map, x10,
725 Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
726
727 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
728 __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
729 __ JumpIfNotRoot(elements_map, Heap::kHashTableMapRootIndex,
730 &lookup_monomorphic_cache);
731
732 GenerateDictionaryLoad(masm, &slow_load, elements, key, function, x10, x11);
733 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, x10, x11);
734 __ B(&do_call);
735
736 __ Bind(&lookup_monomorphic_cache);
737 // Live values:
738 // x1: receiver
739 // x2: key
740 // These assignments are expected by GenerateMonomorphicCacheProbe.
741 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, x10, x11);
742 ASSERT(receiver.Is(x1));
743 ASSERT(key.Is(x2));
744 GenerateMonomorphicCacheProbe(masm,
745 argc,
746 Code::KEYED_CALL_IC,
747 Code::kNoExtraICState);
748 // Fall through on miss.
749
750 __ Bind(&slow_call);
751 // This branch is taken if:
752 // - the receiver requires boxing or access check,
753 // - the key is neither smi nor a unique name,
754 // - the value loaded is not a function,
755 // - there is hope that the runtime will create a monomorphic call stub
756 // that will get fetched next time.
757 __ IncrementCounter(counters->keyed_call_generic_slow(), 1, x10, x11);
758 GenerateMiss(masm, argc);
759
760 __ Bind(&key_is_index_name);
761 // Live values:
762 // x1: receiver
763 // x2: key
764 // x7: hash
765 // The key is an array index string, so calculate its hash and derive the
766 // numerical index from it.
767 __ IndexFromHash(hash, key);
768 __ B(&key_is_smi);
769 }
770
771
772 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
773 // ----------- S t a t e -------------
774 // -- x2 : name
775 // -- lr : return address
776 // -----------------------------------
777 Register name = x2;
778
779 // Check if the name is really a name.
780 Label miss;
781 __ JumpIfSmi(name, &miss);
782 __ IsObjectNameType(name, x0, &miss);
783 CallICBase::GenerateNormal(masm, argc);
784
785 __ Bind(&miss);
786 GenerateMiss(masm, argc);
787 }
788
789
790 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
791 // ----------- S t a t e -------------
792 // -- x2 : name
793 // -- lr : return address
794 // -- x0 : receiver
795 // -----------------------------------
796
797 // Probe the stub cache.
798 Code::Flags flags = Code::ComputeFlags(
799 Code::STUB, MONOMORPHIC, Code::kNoExtraICState,
800 Code::NORMAL, Code::LOAD_IC);
801 Isolate::Current()->stub_cache()->GenerateProbe(
802 masm, flags, x0, x2, x3, x4, x5, x6);
803
804 // Cache miss: Jump to runtime.
805 GenerateMiss(masm);
806 }
807
808
809 void LoadIC::GenerateNormal(MacroAssembler* masm) {
810 // ----------- S t a t e -------------
811 // -- x2 : name
812 // -- lr : return address
813 // -- x0 : receiver
814 // -----------------------------------
815 Label miss;
816
817 GenerateNameDictionaryReceiverCheck(masm, x0, x1, x3, x4, &miss);
818
819 // x1 now holds the property dictionary.
820 GenerateDictionaryLoad(masm, &miss, x1, x2, x0, x3, x4);
821 __ Ret();
822
823 // Cache miss: Jump to runtime.
824 __ Bind(&miss);
825 GenerateMiss(masm);
826 }
827
828
829 void LoadIC::GenerateMiss(MacroAssembler* masm) {
830 // ----------- S t a t e -------------
831 // -- x2 : name
832 // -- lr : return address
833 // -- x0 : receiver
834 // -----------------------------------
835 Isolate* isolate = masm->isolate();
836 ASM_LOCATION("LoadIC::GenerateMiss");
837
838 __ IncrementCounter(isolate->counters()->load_miss(), 1, x3, x4);
839
840 // TODO(jbramley): Does the target actually expect an argument in x3, or is
841 // this inherited from ARM's push semantics?
842 __ Mov(x3, x0);
843 __ Push(x3, x2);
844
845 // Perform tail call to the entry.
846 ExternalReference ref =
847 ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
848 __ TailCallExternalReference(ref, 2, 1);
849 }
850
851
852 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
853 // ---------- S t a t e --------------
854 // -- x2 : name
855 // -- lr : return address
856 // -- x0 : receiver
857 // -----------------------------------
858
859 // TODO(jbramley): Does the target actually expect an argument in x3, or is
860 // this inherited from ARM's push semantics?
861 __ Mov(x3, x0);
862 __ Push(x3, x2);
863
864 __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
865 }
866
867
868 void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
869 // ---------- S t a t e --------------
870 // -- lr : return address
871 // -- x0 : key
872 // -- x1 : receiver
873 // -----------------------------------
874 Register result = x0;
875 Register key = x0;
876 Register receiver = x1;
877 Label miss, unmapped;
878
879 Register map_scratch = x2;
880 MemOperand mapped_location = GenerateMappedArgumentsLookup(
881 masm, receiver, key, map_scratch, x3, x4, &unmapped, &miss);
882 __ Ldr(result, mapped_location);
883 __ Ret();
884
885 __ Bind(&unmapped);
886 // Parameter map is left in map_scratch when a jump on unmapped is done.
887 MemOperand unmapped_location =
888 GenerateUnmappedArgumentsLookup(masm, key, map_scratch, x3, &miss);
889 __ Ldr(x2, unmapped_location);
890 __ JumpIfRoot(x2, Heap::kTheHoleValueRootIndex, &miss);
891 // Move the result in x0. x0 must be preserved on miss.
892 __ Mov(result, x2);
893 __ Ret();
894
895 __ Bind(&miss);
896 GenerateMiss(masm, MISS);
897 }
898
899
900 void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
901 ASM_LOCATION("KeyedStoreIC::GenerateNonStrictArguments");
902 // ---------- S t a t e --------------
903 // -- lr : return address
904 // -- x0 : value
905 // -- x1 : key
906 // -- x2 : receiver
907 // -----------------------------------
908
909 Label slow, notin;
910
911 Register value = x0;
912 Register key = x1;
913 Register receiver = x2;
914 Register map = x3;
915
916 // These registers are used by GenerateMappedArgumentsLookup to build a
917 // MemOperand. They are live for as long as the MemOperand is live.
918 Register mapped1 = x4;
919 Register mapped2 = x5;
920
921 MemOperand mapped =
922 GenerateMappedArgumentsLookup(masm, receiver, key, map,
923 mapped1, mapped2,
924 &notin, &slow);
925 Operand mapped_offset = mapped.OffsetAsOperand();
926 __ Str(value, mapped);
927 __ Add(x10, mapped.base(), mapped_offset);
928 __ Mov(x11, value);
929 __ RecordWrite(mapped.base(), x10, x11, kLRHasNotBeenSaved, kDontSaveFPRegs);
930 __ Ret();
931
932 __ Bind(&notin);
933
934 // These registers are used by GenerateMappedArgumentsLookup to build a
935 // MemOperand. They are live for as long as the MemOperand is live.
936 Register unmapped1 = map; // This is assumed to alias 'map'.
937 Register unmapped2 = x4;
938 MemOperand unmapped =
939 GenerateUnmappedArgumentsLookup(masm, key, unmapped1, unmapped2, &slow);
940 Operand unmapped_offset = unmapped.OffsetAsOperand();
941 __ Str(value, unmapped);
942 __ Add(x10, unmapped.base(), unmapped_offset);
943 __ Mov(x11, value);
944 __ RecordWrite(unmapped.base(), x10, x11,
945 kLRHasNotBeenSaved, kDontSaveFPRegs);
946 __ Ret();
947 __ Bind(&slow);
948 GenerateMiss(masm, MISS);
949 }
950
951
952 void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
953 int argc) {
954 // ----------- S t a t e -------------
955 // -- x2 : key / name
956 // -- lr : return address
957 // -----------------------------------
958 Register key = x2;
959
960 Label slow, not_mapped, do_call;
961
962 // Get the receiver of the function from the stack.
963 Register map = x0;
964 Register function = x1;
965 Register receiver = x3;
966 __ Peek(receiver, argc * kXRegSizeInBytes);
967
968 MemOperand mapped_location =
969 GenerateMappedArgumentsLookup(masm, receiver, key, map, x10, x11,
970 &not_mapped, &slow);
971 // If we fell through, mapped_location will load the function.
972 __ Ldr(function, mapped_location);
973
974 __ Bind(&do_call);
975 // Live values:
976 // x1: function
977 // GenerateFunctionTailCall requires that function is x1. This is enforced by
978 // MacroAssembler::InvokeFunction.
979 GenerateFunctionTailCall(masm, argc, &slow, function, x10);
980
981 __ Bind(&not_mapped);
982 // The argument is not mapped, but 'map' has been populated.
983 MemOperand unmapped_location =
984 GenerateUnmappedArgumentsLookup(masm, key, map, x10, &slow);
985 // If we fell through, unmapped_location will load the function.
986 __ Ldr(function, unmapped_location);
987 // Check for the hole value before calling the function. For the mapped case,
988 // GenerateMappedArgumentsLookup does this check automatically. If we're not
989 // going to the slow case, we re-use the tail call code at do_call.
990 __ JumpIfNotRoot(function, Heap::kTheHoleValueRootIndex, &do_call);
991
992 __ Bind(&slow);
993 GenerateMiss(masm, argc);
994 }
995
996
997 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
998 // ---------- S t a t e --------------
999 // -- lr : return address
1000 // -- x0 : key
1001 // -- x1 : receiver
1002 // -----------------------------------
1003 Isolate* isolate = masm->isolate();
1004
1005 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, x10, x11);
1006
1007 __ Push(x1, x0);
1008
1009 // Perform tail call to the entry.
1010 ExternalReference ref = (miss_mode == MISS_FORCE_GENERIC)
1011 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
1012 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
1013
1014 __ TailCallExternalReference(ref, 2, 1);
1015 }
1016
1017
1018 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1019 // ---------- S t a t e --------------
1020 // -- lr : return address
1021 // -- x0 : key
1022 // -- x1 : receiver
1023 // -----------------------------------
1024 Register key = x0;
1025 Register receiver = x1;
1026
1027 __ Push(receiver, key);
1028 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
1029 }
1030
1031
1032 static void GenerateKeyedLoadWithSmiKey(MacroAssembler* masm,
1033 Register key,
1034 Register receiver,
1035 Register scratch1,
1036 Register scratch2,
1037 Register scratch3,
1038 Register scratch4,
1039 Register scratch5,
1040 Label *slow) {
1041 ASSERT(!AreAliased(
1042 key, receiver, scratch1, scratch2, scratch3, scratch4, scratch5));
1043
1044 Isolate* isolate = masm->isolate();
1045 Label check_number_dictionary;
1046 // If we can load the value, it should be returned in x0.
1047 Register result = x0;
1048
1049 GenerateKeyedLoadReceiverCheck(
1050 masm, receiver, scratch1, scratch2, Map::kHasIndexedInterceptor, slow);
1051
1052 // Check the receiver's map to see if it has fast elements.
1053 __ CheckFastElements(scratch1, scratch2, &check_number_dictionary);
1054
1055 GenerateFastArrayLoad(
1056 masm, receiver, key, scratch3, scratch2, scratch1, result, NULL, slow);
1057 __ IncrementCounter(
1058 isolate->counters()->keyed_load_generic_smi(), 1, scratch1, scratch2);
1059 __ Ret();
1060
1061 __ Bind(&check_number_dictionary);
1062 __ Ldr(scratch3, FieldMemOperand(receiver, JSObject::kElementsOffset));
1063 __ Ldr(scratch2, FieldMemOperand(scratch3, JSObject::kMapOffset));
1064
1065 // Check whether we have a number dictionary.
1066 __ JumpIfNotRoot(scratch2, Heap::kHashTableMapRootIndex, slow);
1067
1068 __ LoadFromNumberDictionary(
1069 slow, scratch3, key, result, scratch1, scratch2, scratch4, scratch5);
1070 __ Ret();
1071 }
1072
1073 static void GenerateKeyedLoadWithNameKey(MacroAssembler* masm,
1074 Register key,
1075 Register receiver,
1076 Register scratch1,
1077 Register scratch2,
1078 Register scratch3,
1079 Register scratch4,
1080 Register scratch5,
1081 Label *slow) {
1082 ASSERT(!AreAliased(
1083 key, receiver, scratch1, scratch2, scratch3, scratch4, scratch5));
1084
1085 Isolate* isolate = masm->isolate();
1086 Label probe_dictionary, property_array_property;
1087 // If we can load the value, it should be returned in x0.
1088 Register result = x0;
1089
1090 GenerateKeyedLoadReceiverCheck(
1091 masm, receiver, scratch1, scratch2, Map::kHasNamedInterceptor, slow);
1092
1093 // If the receiver is a fast-case object, check the keyed lookup cache.
1094 // Otherwise probe the dictionary.
1095 __ Ldr(scratch2, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
1096 __ Ldr(scratch3, FieldMemOperand(scratch2, HeapObject::kMapOffset));
1097 __ JumpIfRoot(scratch3, Heap::kHashTableMapRootIndex, &probe_dictionary);
1098
1099 // We keep the map of the receiver in scratch1.
1100 Register receiver_map = scratch1;
1101
1102 // Load the map of the receiver, compute the keyed lookup cache hash
1103 // based on 32 bits of the map pointer and the name hash.
1104 __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
1105 __ Mov(scratch2, Operand(receiver_map, ASR, KeyedLookupCache::kMapHashShift));
1106 __ Ldr(scratch3.W(), FieldMemOperand(key, Name::kHashFieldOffset));
1107 __ Eor(scratch2, scratch2, Operand(scratch3, ASR, Name::kHashShift));
1108 int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
1109 __ And(scratch2, scratch2, mask);
1110
1111 // Load the key (consisting of map and unique name) from the cache and
1112 // check for match.
1113 Label load_in_object_property;
1114 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
1115 Label hit_on_nth_entry[kEntriesPerBucket];
1116 ExternalReference cache_keys =
1117 ExternalReference::keyed_lookup_cache_keys(isolate);
1118
1119 __ Mov(scratch3, Operand(cache_keys));
1120 __ Add(scratch3, scratch3, Operand(scratch2, LSL, kPointerSizeLog2 + 1));
1121
1122 for (int i = 0; i < kEntriesPerBucket - 1; i++) {
1123 Label try_next_entry;
1124 // Load map and make scratch3 pointing to the next entry.
1125 __ Ldr(scratch4, MemOperand(scratch3, kPointerSize * 2, PostIndex));
1126 __ Cmp(receiver_map, scratch4);
1127 __ B(ne, &try_next_entry);
1128 __ Ldr(scratch4, MemOperand(scratch3, -kPointerSize)); // Load name
1129 __ Cmp(key, scratch4);
1130 __ B(eq, &hit_on_nth_entry[i]);
1131 __ Bind(&try_next_entry);
1132 }
1133
1134 // Last entry.
1135 __ Ldr(scratch4, MemOperand(scratch3, kPointerSize, PostIndex));
1136 __ Cmp(receiver_map, scratch4);
1137 __ B(ne, slow);
1138 __ Ldr(scratch4, MemOperand(scratch3));
1139 __ Cmp(key, scratch4);
1140 __ B(ne, slow);
1141
1142 // Get field offset.
1143 ExternalReference cache_field_offsets =
1144 ExternalReference::keyed_lookup_cache_field_offsets(isolate);
1145
1146 // Hit on nth entry.
1147 for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
1148 __ Bind(&hit_on_nth_entry[i]);
1149 __ Mov(scratch3, Operand(cache_field_offsets));
1150 if (i != 0) {
1151 __ Add(scratch2, scratch2, i);
1152 }
1153 __ Ldr(scratch4.W(), MemOperand(scratch3, scratch2, LSL, 2));
1154 __ Ldrb(scratch5,
1155 FieldMemOperand(receiver_map, Map::kInObjectPropertiesOffset));
1156 __ Subs(scratch4, scratch4, scratch5);
1157 __ B(ge, &property_array_property);
1158 if (i != 0) {
1159 __ B(&load_in_object_property);
1160 }
1161 }
1162
1163 // Load in-object property.
1164 __ Bind(&load_in_object_property);
1165 __ Ldrb(scratch5, FieldMemOperand(receiver_map, Map::kInstanceSizeOffset));
1166 __ Add(scratch5, scratch5, scratch4); // Index from start of object.
1167 __ Sub(receiver, receiver, kHeapObjectTag); // Remove the heap tag.
1168 __ Ldr(result, MemOperand(receiver, scratch5, LSL, kPointerSizeLog2));
1169 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1170 1, scratch1, scratch2);
1171 __ Ret();
1172
1173 // Load property array property.
1174 __ Bind(&property_array_property);
1175 __ Ldr(scratch1, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
1176 __ Add(scratch1, scratch1, FixedArray::kHeaderSize - kHeapObjectTag);
1177 __ Ldr(result, MemOperand(scratch1, scratch4, LSL, kPointerSizeLog2));
1178 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1179 1, scratch1, scratch2);
1180 __ Ret();
1181
1182 // Do a quick inline probe of the receiver's dictionary, if it exists.
1183 __ Bind(&probe_dictionary);
1184 __ Ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
1185 __ Ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
1186 GenerateGlobalInstanceTypeCheck(masm, scratch1, slow);
1187 // Load the property.
1188 GenerateDictionaryLoad(masm, slow, scratch2, key, result, scratch1, scratch3);
1189 __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
1190 1, scratch1, scratch2);
1191 __ Ret();
1192 }
1193
1194
1195 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
1196 // ---------- S t a t e --------------
1197 // -- lr : return address
1198 // -- x0 : key
1199 // -- x1 : receiver
1200 // -----------------------------------
1201 Label slow, check_name, index_smi, index_name;
1202
1203 Register key = x0;
1204 Register receiver = x1;
1205
1206 __ JumpIfNotSmi(key, &check_name);
1207 __ Bind(&index_smi);
1208 // Now the key is known to be a smi. This place is also jumped to from below
1209 // where a numeric string is converted to a smi.
1210 GenerateKeyedLoadWithSmiKey(masm, key, receiver, x2, x3, x4, x5, x6, &slow);
1211
1212 // Slow case, key and receiver still in x0 and x1.
1213 __ Bind(&slow);
1214 __ IncrementCounter(
1215 masm->isolate()->counters()->keyed_load_generic_slow(), 1, x2, x3);
1216 GenerateRuntimeGetProperty(masm);
1217
1218 __ Bind(&check_name);
1219 GenerateKeyNameCheck(masm, key, x2, x3, &index_name, &slow);
1220
1221 GenerateKeyedLoadWithNameKey(masm, key, receiver, x2, x3, x4, x5, x6, &slow);
1222
1223 __ Bind(&index_name);
1224 __ IndexFromHash(x3, key);
1225 // Now jump to the place where smi keys are handled.
1226 __ B(&index_smi);
1227 }
1228
1229
1230 void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
1231 // ---------- S t a t e --------------
1232 // -- lr : return address
1233 // -- x0 : key (index)
1234 // -- x1 : receiver
1235 // -----------------------------------
1236 Label miss;
1237
1238 Register index = x0;
1239 Register receiver = x1;
1240 Register result = x0;
1241 Register scratch = x3;
1242
1243 StringCharAtGenerator char_at_generator(receiver,
1244 index,
1245 scratch,
1246 result,
1247 &miss, // When not a string.
1248 &miss, // When not a number.
1249 &miss, // When index out of range.
1250 STRING_INDEX_IS_ARRAY_INDEX);
1251 char_at_generator.GenerateFast(masm);
1252 __ Ret();
1253
1254 StubRuntimeCallHelper call_helper;
1255 char_at_generator.GenerateSlow(masm, call_helper);
1256
1257 __ Bind(&miss);
1258 GenerateMiss(masm, MISS);
1259 }
1260
1261
1262 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1263 // ---------- S t a t e --------------
1264 // -- lr : return address
1265 // -- x0 : key
1266 // -- x1 : receiver
1267 // -----------------------------------
1268 Label slow;
1269 Register key = x0;
1270 Register receiver = x1;
1271
1272 // Check that the receiver isn't a smi.
1273 __ JumpIfSmi(receiver, &slow);
1274
1275 // Check that the key is an array index, that is Uint32.
1276 __ TestAndBranchIfAnySet(key, kSmiTagMask | kSmiSignMask, &slow);
1277
1278 // Get the map of the receiver.
1279 Register map = x2;
1280 __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
1281
1282 // Check that it has indexed interceptor and access checks
1283 // are not enabled for this object.
1284 __ Ldrb(x3, FieldMemOperand(map, Map::kBitFieldOffset));
1285 ASSERT(kSlowCaseBitFieldMask ==
1286 ((1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor)));
1287 __ Tbnz(x3, Map::kIsAccessCheckNeeded, &slow);
1288 __ Tbz(x3, Map::kHasIndexedInterceptor, &slow);
1289
1290 // Everything is fine, call runtime.
1291 __ Push(receiver, key);
1292 __ TailCallExternalReference(
1293 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
1294 masm->isolate()),
1295 2,
1296 1);
1297
1298 __ Bind(&slow);
1299 GenerateMiss(masm, MISS);
1300 }
1301
1302
1303 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
1304 ASM_LOCATION("KeyedStoreIC::GenerateMiss");
1305 // ---------- S t a t e --------------
1306 // -- x0 : value
1307 // -- x1 : key
1308 // -- x2 : receiver
1309 // -- lr : return address
1310 // -----------------------------------
1311
1312 // Push receiver, key and value for runtime call.
1313 __ Push(x2, x1, x0);
1314
1315 ExternalReference ref = (miss_mode == MISS_FORCE_GENERIC)
1316 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1317 masm->isolate())
1318 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1319 __ TailCallExternalReference(ref, 3, 1);
1320 }
1321
1322
1323 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1324 ASM_LOCATION("KeyedStoreIC::GenerateSlow");
1325 // ---------- S t a t e --------------
1326 // -- lr : return address
1327 // -- x0 : value
1328 // -- x1 : key
1329 // -- x2 : receiver
1330 // -----------------------------------
1331
1332 // Push receiver, key and value for runtime call.
1333 __ Push(x2, x1, x0);
1334
1335 // The slow case calls into the runtime to complete the store without causing
1336 // an IC miss that would otherwise cause a transition to the generic stub.
1337 ExternalReference ref =
1338 ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
1339 __ TailCallExternalReference(ref, 3, 1);
1340 }
1341
1342
1343 void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
1344 ASM_LOCATION("KeyedStoreIC::GenerateTransitionElementsSmiToDouble");
1345 // ---------- S t a t e --------------
1346 // -- lr : return address
1347 // -- x0 : value
1348 // -- x1 : key
1349 // -- x2 : receiver
1350 // -- x3 : target map
1351 // -----------------------------------
1352 // Must return the modified receiver in x0.
1353 Register receiver = x2;
1354
1355 if (!FLAG_trace_elements_transitions) {
1356 Label fail;
1357 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
1358 FAST_DOUBLE_ELEMENTS);
1359 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
1360 __ Mov(x0, receiver);
1361 __ Ret();
1362 __ Bind(&fail);
1363 }
1364
1365 __ Push(receiver);
1366 __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
1367 }
1368
1369
1370 void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
1371 MacroAssembler* masm) {
1372 ASM_LOCATION("KeyedStoreIC::GenerateTransitionElementsDoubleToObject");
1373 // ---------- S t a t e --------------
1374 // -- x2 : receiver
1375 // -- x3 : target map
1376 // -- lr : return address
1377 // -----------------------------------
1378 // Must return the modified receiver in r0.
1379 Register receiver = x2;
1380
1381 if (!FLAG_trace_elements_transitions) {
1382 Label fail;
1383 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS,
1384 FAST_ELEMENTS);
1385 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
1386 __ Mov(x0, receiver);
1387 __ Ret();
1388 __ Bind(&fail);
1389 }
1390
1391 __ Push(receiver);
1392 __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
1393 }
1394
1395
1396 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1397 StrictModeFlag strict_mode) {
1398 ASM_LOCATION("KeyedStoreIC::GenerateRuntimeSetProperty");
1399 // ---------- S t a t e --------------
1400 // -- x0 : value
1401 // -- x1 : key
1402 // -- x2 : receiver
1403 // -- lr : return address
1404 // -----------------------------------
1405
1406 // Push receiver, key and value for runtime call.
1407 __ Push(x2, x1, x0);
1408
1409 // Push PropertyAttributes(NONE) and strict_mode for runtime call.
1410 STATIC_ASSERT(NONE == 0);
1411 __ Mov(x10, Operand(Smi::FromInt(strict_mode)));
1412 __ Push(xzr, x10);
1413
1414 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1415 }
1416
1417
1418 static void KeyedStoreGenerateGenericHelper(
1419 MacroAssembler* masm,
1420 Label* fast_object,
1421 Label* fast_double,
1422 Label* slow,
1423 KeyedStoreCheckMap check_map,
1424 KeyedStoreIncrementLength increment_length,
1425 Register value,
1426 Register key,
1427 Register receiver,
1428 Register receiver_map,
1429 Register elements_map,
1430 Register elements) {
1431 ASSERT(!AreAliased(
1432 value, key, receiver, receiver_map, elements_map, elements, x10, x11));
1433
1434 Label transition_smi_elements;
1435 Label transition_double_elements;
1436 Label fast_double_without_map_check;
1437 Label non_double_value;
1438 Label finish_store;
1439
1440 __ Bind(fast_object);
1441 if (check_map == kCheckMap) {
1442 __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
1443 __ Cmp(elements_map,
1444 Operand(masm->isolate()->factory()->fixed_array_map()));
1445 __ B(ne, fast_double);
1446 }
1447
1448 // Smi stores don't require further checks.
1449 __ JumpIfSmi(value, &finish_store);
1450
1451 // Escape to elements kind transition case.
1452 __ CheckFastObjectElements(receiver_map, x10, &transition_smi_elements);
1453
1454 __ Bind(&finish_store);
1455 if (increment_length == kIncrementLength) {
1456 // Add 1 to receiver->length.
1457 __ Add(x10, key, Operand(Smi::FromInt(1)));
1458 __ Str(x10, FieldMemOperand(receiver, JSArray::kLengthOffset));
1459 }
1460
1461 Register address = x11;
1462 __ Add(address, elements, FixedArray::kHeaderSize - kHeapObjectTag);
1463 __ Add(address, address, Operand::UntagSmiAndScale(key, kPointerSizeLog2));
1464 __ Str(value, MemOperand(address));
1465
1466 Label dont_record_write;
1467 __ JumpIfSmi(value, &dont_record_write);
1468
1469 // Update write barrier for the elements array address.
1470 __ Mov(x10, value); // Preserve the value which is returned.
1471 __ RecordWrite(elements,
1472 address,
1473 x10,
1474 kLRHasNotBeenSaved,
1475 kDontSaveFPRegs,
1476 EMIT_REMEMBERED_SET,
1477 OMIT_SMI_CHECK,
1478 EXPECT_PREGENERATED);
1479
1480 __ Bind(&dont_record_write);
1481 __ Ret();
1482
1483
1484 __ Bind(fast_double);
1485 if (check_map == kCheckMap) {
1486 // Check for fast double array case. If this fails, call through to the
1487 // runtime.
1488 __ JumpIfNotRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex, slow);
1489 }
1490
1491 __ Bind(&fast_double_without_map_check);
1492 __ StoreNumberToDoubleElements(value,
1493 key,
1494 elements,
1495 x10,
1496 d0,
1497 d1,
1498 &transition_double_elements);
1499 if (increment_length == kIncrementLength) {
1500 // Add 1 to receiver->length.
1501 __ Add(x10, key, Operand(Smi::FromInt(1)));
1502 __ Str(x10, FieldMemOperand(receiver, JSArray::kLengthOffset));
1503 }
1504 __ Ret();
1505
1506
1507 __ Bind(&transition_smi_elements);
1508 // Transition the array appropriately depending on the value type.
1509 __ Ldr(x10, FieldMemOperand(value, HeapObject::kMapOffset));
1510 __ JumpIfNotRoot(x10, Heap::kHeapNumberMapRootIndex, &non_double_value);
1511
1512 // Value is a double. Transition FAST_SMI_ELEMENTS ->
1513 // FAST_DOUBLE_ELEMENTS and complete the store.
1514 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
1515 FAST_DOUBLE_ELEMENTS,
1516 receiver_map,
1517 x10,
1518 slow);
1519 ASSERT(receiver_map.Is(x3)); // Transition code expects map in x3.
1520 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
1521 FAST_DOUBLE_ELEMENTS);
1522 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
1523 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1524 __ B(&fast_double_without_map_check);
1525
1526 __ Bind(&non_double_value);
1527 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS.
1528 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
1529 FAST_ELEMENTS,
1530 receiver_map,
1531 x10,
1532 slow);
1533 ASSERT(receiver_map.Is(x3)); // Transition code expects map in x3.
1534 mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
1535 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
1536 slow);
1537 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1538 __ B(&finish_store);
1539
1540 __ Bind(&transition_double_elements);
1541 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
1542 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
1543 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
1544 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
1545 FAST_ELEMENTS,
1546 receiver_map,
1547 x10,
1548 slow);
1549 ASSERT(receiver_map.Is(x3)); // Transition code expects map in x3.
1550 mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
1551 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
1552 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1553 __ B(&finish_store);
1554 }
1555
1556
1557 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
1558 StrictModeFlag strict_mode) {
1559 ASM_LOCATION("KeyedStoreIC::GenerateGeneric");
1560 // ---------- S t a t e --------------
1561 // -- x0 : value
1562 // -- x1 : key
1563 // -- x2 : receiver
1564 // -- lr : return address
1565 // -----------------------------------
1566 Label slow;
1567 Label array;
1568 Label fast_object;
1569 Label extra;
1570 Label fast_object_grow;
1571 Label fast_double_grow;
1572 Label fast_double;
1573
1574 Register value = x0;
1575 Register key = x1;
1576 Register receiver = x2;
1577 Register receiver_map = x3;
1578 Register elements = x4;
1579 Register elements_map = x5;
1580
1581 __ JumpIfNotSmi(key, &slow);
1582 __ JumpIfSmi(receiver, &slow);
1583 __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
1584
1585 // Check that the receiver does not require access checks. We need to do this
1586 // because this generic stub does not perform map checks.
1587 __ Ldrb(x10, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
1588 __ Tbnz(x10, Map::kIsAccessCheckNeeded, &slow);
1589
1590 // Check if the object is a JS array or not.
1591 Register instance_type = x10;
1592 __ CompareInstanceType(receiver_map, instance_type, JS_ARRAY_TYPE);
1593 __ B(eq, &array);
1594 // Check that the object is some kind of JSObject.
1595 __ Cmp(instance_type, FIRST_JS_OBJECT_TYPE);
1596 __ B(lt, &slow);
1597
1598 // Object case: Check key against length in the elements array.
1599 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1600 // Check array bounds. Both the key and the length of FixedArray are smis.
1601 __ Ldrsw(x10, UntagSmiFieldMemOperand(elements, FixedArray::kLengthOffset));
1602 __ Cmp(x10, Operand::UntagSmi(key));
1603 __ B(hi, &fast_object);
1604
1605
1606 __ Bind(&slow);
1607 // Slow case, handle jump to runtime.
1608 // Live values:
1609 // x0: value
1610 // x1: key
1611 // x2: receiver
1612 GenerateRuntimeSetProperty(masm, strict_mode);
1613
1614
1615 __ Bind(&extra);
1616 // Extra capacity case: Check if there is extra capacity to
1617 // perform the store and update the length. Used for adding one
1618 // element to the array by writing to array[array.length].
1619
1620 // Check for room in the elements backing store.
1621 // Both the key and the length of FixedArray are smis.
1622 __ Ldrsw(x10, UntagSmiFieldMemOperand(elements, FixedArray::kLengthOffset));
1623 __ Cmp(x10, Operand::UntagSmi(key));
1624 __ B(ls, &slow);
1625
1626 __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
1627 __ Cmp(elements_map, Operand(masm->isolate()->factory()->fixed_array_map()));
1628 __ B(eq, &fast_object_grow);
1629 __ Cmp(elements_map,
1630 Operand(masm->isolate()->factory()->fixed_double_array_map()));
1631 __ B(eq, &fast_double_grow);
1632 __ B(&slow);
1633
1634
1635 __ Bind(&array);
1636 // Array case: Get the length and the elements array from the JS
1637 // array. Check that the array is in fast mode (and writable); if it
1638 // is the length is always a smi.
1639
1640 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1641
1642 // Check the key against the length in the array.
1643 __ Ldrsw(x10, UntagSmiFieldMemOperand(receiver, JSArray::kLengthOffset));
1644 __ Cmp(x10, Operand::UntagSmi(key));
1645 __ B(eq, &extra); // We can handle the case where we are appending 1 element.
1646 __ B(lo, &slow);
1647
1648 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
1649 &slow, kCheckMap, kDontIncrementLength,
1650 value, key, receiver, receiver_map,
1651 elements_map, elements);
1652 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
1653 &slow, kDontCheckMap, kIncrementLength,
1654 value, key, receiver, receiver_map,
1655 elements_map, elements);
1656 }
1657
1658
1659 void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
1660 StrictModeFlag strict_mode) {
1661 // ----------- S t a t e -------------
1662 // -- x0 : value
1663 // -- x1 : receiver
1664 // -- x2 : name
1665 // -- lr : return address
1666 // -----------------------------------
1667
1668 // Probe the stub cache.
1669 Code::Flags flags =
1670 Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
1671
1672 Isolate::Current()->stub_cache()->GenerateProbe(
1673 masm, flags, x1, x2, x3, x4, x5, x6);
1674
1675 // Cache miss: Jump to runtime.
1676 GenerateMiss(masm);
1677 }
1678
1679
1680 void StoreIC::GenerateMiss(MacroAssembler* masm) {
1681 // ----------- S t a t e -------------
1682 // -- x0 : value
1683 // -- x1 : receiver
1684 // -- x2 : name
1685 // -- lr : return address
1686 // -----------------------------------
1687
1688 __ Push(x1, x2, x0);
1689
1690 // Tail call to the entry.
1691 ExternalReference ref =
1692 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
1693 __ TailCallExternalReference(ref, 3, 1);
1694 }
1695
1696
1697 void StoreIC::GenerateNormal(MacroAssembler* masm) {
1698 // ----------- S t a t e -------------
1699 // -- x0 : value
1700 // -- x1 : receiver
1701 // -- x2 : name
1702 // -- lr : return address
1703 // -----------------------------------
1704 Label miss;
1705 Register value = x0;
1706 Register receiver = x1;
1707 Register name = x2;
1708 Register dictionary = x3;
1709
1710 GenerateNameDictionaryReceiverCheck(
1711 masm, receiver, dictionary, x4, x5, &miss);
1712
1713 GenerateDictionaryStore(masm, &miss, dictionary, name, value, x4, x5);
1714 Counters* counters = masm->isolate()->counters();
1715 __ IncrementCounter(counters->store_normal_hit(), 1, x4, x5);
1716 __ Ret();
1717
1718 // Cache miss: Jump to runtime.
1719 __ Bind(&miss);
1720 __ IncrementCounter(counters->store_normal_miss(), 1, x4, x5);
1721 GenerateMiss(masm);
1722 }
1723
1724
1725 void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1726 StrictModeFlag strict_mode) {
1727 ASM_LOCATION("StoreIC::GenerateGlobalProxy");
1728 // ----------- S t a t e -------------
1729 // -- x0 : value
1730 // -- x1 : receiver
1731 // -- x2 : name
1732 // -- lr : return address
1733 // -----------------------------------
1734
1735 __ Push(x1, x2, x0);
1736
1737 __ Mov(x11, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1738 __ Mov(x10, Operand(Smi::FromInt(strict_mode)));
1739 __ Push(x11, x10);
1740
1741 // Do tail-call to runtime routine.
1742 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1743 }
1744
1745
1746 void StoreIC::GenerateSlow(MacroAssembler* masm) {
1747 // ---------- S t a t e --------------
1748 // -- x0 : value
1749 // -- x1 : receiver
1750 // -- x2 : name
1751 // -- lr : return address
1752 // -----------------------------------
1753
1754 // Push receiver, name and value for runtime call.
1755 __ Push(x1, x2, x0);
1756
1757 // The slow case calls into the runtime to complete the store without causing
1758 // an IC miss that would otherwise cause a transition to the generic stub.
1759 ExternalReference ref =
1760 ExternalReference(IC_Utility(kStoreIC_Slow), masm->isolate());
1761 __ TailCallExternalReference(ref, 3, 1);
1762 }
1763
1764
1765 Condition CompareIC::ComputeCondition(Token::Value op) {
1766 switch (op) {
1767 case Token::EQ_STRICT:
1768 case Token::EQ:
1769 return eq;
1770 case Token::LT:
1771 return lt;
1772 case Token::GT:
1773 return gt;
1774 case Token::LTE:
1775 return le;
1776 case Token::GTE:
1777 return ge;
1778 default:
1779 UNREACHABLE();
1780 return al;
1781 }
1782 }
1783
1784
1785 bool CompareIC::HasInlinedSmiCode(Address address) {
1786 // The address of the instruction following the call.
1787 Address info_address =
1788 Assembler::return_address_from_call_start(address);
1789
1790 InstructionSequence* patch_info = InstructionSequence::At(info_address);
1791 return patch_info->IsInlineData();
1792 }
1793
1794
1795 // Activate a SMI fast-path by patching the instructions generated by
1796 // JumpPatchSite::EmitJumpIf(Not)Smi(), using the information encoded by
1797 // JumpPatchSite::EmitPatchInfo().
1798 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
1799 // The patch information is encoded in the instruction stream using
1800 // instructions which have no side effects, so we can safely execute them.
1801 // The patch information is encoded directly after the call to the helper
1802 // function which is requesting this patch operation.
1803 Address info_address =
1804 Assembler::return_address_from_call_start(address);
1805 InlineSmiCheckInfo info(info_address);
1806
1807 // Check and decode the patch information instruction.
1808 if (!info.HasSmiCheck()) {
1809 return;
1810 }
1811
1812 #ifdef DEBUG
1813 if (FLAG_trace_ic) {
1814 PrintF("[ Patching ic at %p, marker=%p, SMI check=%p\n",
1815 address, info_address, reinterpret_cast<void*>(info.SmiCheck()));
1816 }
1817 #endif
1818
1819 // Patch and activate code generated by JumpPatchSite::EmitJumpIfNotSmi()
1820 // and JumpPatchSite::EmitJumpIfSmi().
1821 // Changing
1822 // tb(n)z xzr, #0, <target>
1823 // to
1824 // tb(!n)z test_reg, #0, <target>
1825 Instruction* to_patch = info.SmiCheck();
1826 PatchingAssembler patcher(to_patch, 1);
1827 ASSERT(to_patch->IsTestBranch());
1828 ASSERT(to_patch->ImmTestBranchBit5() == 0);
1829 ASSERT(to_patch->ImmTestBranchBit40() == 0);
1830
1831 STATIC_ASSERT(kSmiTag == 0);
1832 STATIC_ASSERT(kSmiTagMask == 1);
1833
1834 int branch_imm = to_patch->ImmTestBranch();
1835 Register smi_reg;
1836 if (check == ENABLE_INLINED_SMI_CHECK) {
1837 ASSERT(to_patch->Rt() == xzr.code());
1838 smi_reg = info.SmiRegister();
1839 } else {
1840 ASSERT(check == DISABLE_INLINED_SMI_CHECK);
1841 ASSERT(to_patch->Rt() != xzr.code());
1842 smi_reg = xzr;
1843 }
1844
1845 if (to_patch->Mask(TestBranchMask) == TBZ) {
1846 // This is JumpIfNotSmi(smi_reg, branch_imm).
1847 patcher.tbnz(smi_reg, 0, branch_imm);
1848 } else {
1849 ASSERT(to_patch->Mask(TestBranchMask) == TBNZ);
1850 // This is JumpIfSmi(smi_reg, branch_imm).
1851 patcher.tbz(smi_reg, 0, branch_imm);
1852 }
1853 }
1854
1855
1856 } } // namespace v8::internal
1857
1858 #endif // V8_TARGET_ARCH_A64
OLDNEW
« no previous file with comments | « src/a64/full-codegen-a64.cc ('k') | src/a64/instructions-a64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698