OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_ARM64 | 7 #if V8_TARGET_ARCH_ARM64 |
8 | 8 |
9 #include "src/codegen.h" | 9 #include "src/ic/ic-compiler.h" |
10 #include "src/ic-inl.h" | |
11 #include "src/stub-cache.h" | |
12 | 10 |
13 namespace v8 { | 11 namespace v8 { |
14 namespace internal { | 12 namespace internal { |
15 | 13 |
16 | |
17 #define __ ACCESS_MASM(masm) | 14 #define __ ACCESS_MASM(masm) |
18 | 15 |
19 | 16 |
20 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( | 17 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( |
21 MacroAssembler* masm, Label* miss_label, Register receiver, | 18 MacroAssembler* masm, Label* miss_label, Register receiver, |
22 Handle<Name> name, Register scratch0, Register scratch1) { | 19 Handle<Name> name, Register scratch0, Register scratch1) { |
23 DCHECK(!AreAliased(receiver, scratch0, scratch1)); | 20 DCHECK(!AreAliased(receiver, scratch0, scratch1)); |
24 DCHECK(name->IsUniqueName()); | 21 DCHECK(name->IsUniqueName()); |
25 Counters* counters = masm->isolate()->counters(); | 22 Counters* counters = masm->isolate()->counters(); |
26 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); | 23 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); |
(...skipping 16 matching lines...) Expand all Loading... |
43 __ Cmp(scratch0, FIRST_SPEC_OBJECT_TYPE); | 40 __ Cmp(scratch0, FIRST_SPEC_OBJECT_TYPE); |
44 __ B(lt, miss_label); | 41 __ B(lt, miss_label); |
45 | 42 |
46 // Load properties array. | 43 // Load properties array. |
47 Register properties = scratch0; | 44 Register properties = scratch0; |
48 __ Ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 45 __ Ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
49 // Check that the properties array is a dictionary. | 46 // Check that the properties array is a dictionary. |
50 __ Ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset)); | 47 __ Ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset)); |
51 __ JumpIfNotRoot(map, Heap::kHashTableMapRootIndex, miss_label); | 48 __ JumpIfNotRoot(map, Heap::kHashTableMapRootIndex, miss_label); |
52 | 49 |
53 NameDictionaryLookupStub::GenerateNegativeLookup(masm, | 50 NameDictionaryLookupStub::GenerateNegativeLookup( |
54 miss_label, | 51 masm, miss_label, &done, receiver, properties, name, scratch1); |
55 &done, | |
56 receiver, | |
57 properties, | |
58 name, | |
59 scratch1); | |
60 __ Bind(&done); | 52 __ Bind(&done); |
61 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); | 53 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); |
62 } | 54 } |
63 | 55 |
64 | 56 |
65 // Probe primary or secondary table. | |
66 // If the entry is found in the cache, the generated code jump to the first | |
67 // instruction of the stub in the cache. | |
68 // If there is a miss the code fall trough. | |
69 // | |
70 // 'receiver', 'name' and 'offset' registers are preserved on miss. | |
71 static void ProbeTable(Isolate* isolate, | |
72 MacroAssembler* masm, | |
73 Code::Flags flags, | |
74 StubCache::Table table, | |
75 Register receiver, | |
76 Register name, | |
77 Register offset, | |
78 Register scratch, | |
79 Register scratch2, | |
80 Register scratch3) { | |
81 // Some code below relies on the fact that the Entry struct contains | |
82 // 3 pointers (name, code, map). | |
83 STATIC_ASSERT(sizeof(StubCache::Entry) == (3 * kPointerSize)); | |
84 | |
85 ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); | |
86 ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); | |
87 ExternalReference map_offset(isolate->stub_cache()->map_reference(table)); | |
88 | |
89 uintptr_t key_off_addr = reinterpret_cast<uintptr_t>(key_offset.address()); | |
90 uintptr_t value_off_addr = | |
91 reinterpret_cast<uintptr_t>(value_offset.address()); | |
92 uintptr_t map_off_addr = reinterpret_cast<uintptr_t>(map_offset.address()); | |
93 | |
94 Label miss; | |
95 | |
96 DCHECK(!AreAliased(name, offset, scratch, scratch2, scratch3)); | |
97 | |
98 // Multiply by 3 because there are 3 fields per entry. | |
99 __ Add(scratch3, offset, Operand(offset, LSL, 1)); | |
100 | |
101 // Calculate the base address of the entry. | |
102 __ Mov(scratch, key_offset); | |
103 __ Add(scratch, scratch, Operand(scratch3, LSL, kPointerSizeLog2)); | |
104 | |
105 // Check that the key in the entry matches the name. | |
106 __ Ldr(scratch2, MemOperand(scratch)); | |
107 __ Cmp(name, scratch2); | |
108 __ B(ne, &miss); | |
109 | |
110 // Check the map matches. | |
111 __ Ldr(scratch2, MemOperand(scratch, map_off_addr - key_off_addr)); | |
112 __ Ldr(scratch3, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
113 __ Cmp(scratch2, scratch3); | |
114 __ B(ne, &miss); | |
115 | |
116 // Get the code entry from the cache. | |
117 __ Ldr(scratch, MemOperand(scratch, value_off_addr - key_off_addr)); | |
118 | |
119 // Check that the flags match what we're looking for. | |
120 __ Ldr(scratch2.W(), FieldMemOperand(scratch, Code::kFlagsOffset)); | |
121 __ Bic(scratch2.W(), scratch2.W(), Code::kFlagsNotUsedInLookup); | |
122 __ Cmp(scratch2.W(), flags); | |
123 __ B(ne, &miss); | |
124 | |
125 #ifdef DEBUG | |
126 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { | |
127 __ B(&miss); | |
128 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { | |
129 __ B(&miss); | |
130 } | |
131 #endif | |
132 | |
133 // Jump to the first instruction in the code stub. | |
134 __ Add(scratch, scratch, Code::kHeaderSize - kHeapObjectTag); | |
135 __ Br(scratch); | |
136 | |
137 // Miss: fall through. | |
138 __ Bind(&miss); | |
139 } | |
140 | |
141 | |
142 void StubCache::GenerateProbe(MacroAssembler* masm, | |
143 Code::Flags flags, | |
144 Register receiver, | |
145 Register name, | |
146 Register scratch, | |
147 Register extra, | |
148 Register extra2, | |
149 Register extra3) { | |
150 Isolate* isolate = masm->isolate(); | |
151 Label miss; | |
152 | |
153 // Make sure the flags does not name a specific type. | |
154 DCHECK(Code::ExtractTypeFromFlags(flags) == 0); | |
155 | |
156 // Make sure that there are no register conflicts. | |
157 DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3)); | |
158 | |
159 // Make sure extra and extra2 registers are valid. | |
160 DCHECK(!extra.is(no_reg)); | |
161 DCHECK(!extra2.is(no_reg)); | |
162 DCHECK(!extra3.is(no_reg)); | |
163 | |
164 Counters* counters = masm->isolate()->counters(); | |
165 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, | |
166 extra2, extra3); | |
167 | |
168 // Check that the receiver isn't a smi. | |
169 __ JumpIfSmi(receiver, &miss); | |
170 | |
171 // Compute the hash for primary table. | |
172 __ Ldr(scratch, FieldMemOperand(name, Name::kHashFieldOffset)); | |
173 __ Ldr(extra, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
174 __ Add(scratch, scratch, extra); | |
175 __ Eor(scratch, scratch, flags); | |
176 // We shift out the last two bits because they are not part of the hash. | |
177 __ Ubfx(scratch, scratch, kCacheIndexShift, | |
178 CountTrailingZeros(kPrimaryTableSize, 64)); | |
179 | |
180 // Probe the primary table. | |
181 ProbeTable(isolate, masm, flags, kPrimary, receiver, name, | |
182 scratch, extra, extra2, extra3); | |
183 | |
184 // Primary miss: Compute hash for secondary table. | |
185 __ Sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift)); | |
186 __ Add(scratch, scratch, flags >> kCacheIndexShift); | |
187 __ And(scratch, scratch, kSecondaryTableSize - 1); | |
188 | |
189 // Probe the secondary table. | |
190 ProbeTable(isolate, masm, flags, kSecondary, receiver, name, | |
191 scratch, extra, extra2, extra3); | |
192 | |
193 // Cache miss: Fall-through and let caller handle the miss by | |
194 // entering the runtime system. | |
195 __ Bind(&miss); | |
196 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, | |
197 extra2, extra3); | |
198 } | |
199 | |
200 | |
201 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( | 57 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( |
202 MacroAssembler* masm, int index, Register prototype, Label* miss) { | 58 MacroAssembler* masm, int index, Register prototype, Label* miss) { |
203 Isolate* isolate = masm->isolate(); | 59 Isolate* isolate = masm->isolate(); |
204 // Get the global function with the given index. | 60 // Get the global function with the given index. |
205 Handle<JSFunction> function( | 61 Handle<JSFunction> function( |
206 JSFunction::cast(isolate->native_context()->get(index))); | 62 JSFunction::cast(isolate->native_context()->get(index))); |
207 | 63 |
208 // Check we're still in the same context. | 64 // Check we're still in the same context. |
209 Register scratch = prototype; | 65 Register scratch = prototype; |
210 __ Ldr(scratch, GlobalObjectMemOperand()); | 66 __ Ldr(scratch, GlobalObjectMemOperand()); |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 // Generate StoreTransition code, value is passed in x0 register. | 227 // Generate StoreTransition code, value is passed in x0 register. |
372 // When leaving generated code after success, the receiver_reg and storage_reg | 228 // When leaving generated code after success, the receiver_reg and storage_reg |
373 // may be clobbered. Upon branch to miss_label, the receiver and name registers | 229 // may be clobbered. Upon branch to miss_label, the receiver and name registers |
374 // have their original values. | 230 // have their original values. |
375 void NamedStoreHandlerCompiler::GenerateStoreTransition( | 231 void NamedStoreHandlerCompiler::GenerateStoreTransition( |
376 Handle<Map> transition, Handle<Name> name, Register receiver_reg, | 232 Handle<Map> transition, Handle<Name> name, Register receiver_reg, |
377 Register storage_reg, Register value_reg, Register scratch1, | 233 Register storage_reg, Register value_reg, Register scratch1, |
378 Register scratch2, Register scratch3, Label* miss_label, Label* slow) { | 234 Register scratch2, Register scratch3, Label* miss_label, Label* slow) { |
379 Label exit; | 235 Label exit; |
380 | 236 |
381 DCHECK(!AreAliased(receiver_reg, storage_reg, value_reg, | 237 DCHECK(!AreAliased(receiver_reg, storage_reg, value_reg, scratch1, scratch2, |
382 scratch1, scratch2, scratch3)); | 238 scratch3)); |
383 | 239 |
384 // We don't need scratch3. | 240 // We don't need scratch3. |
385 scratch3 = NoReg; | 241 scratch3 = NoReg; |
386 | 242 |
387 int descriptor = transition->LastAdded(); | 243 int descriptor = transition->LastAdded(); |
388 DescriptorArray* descriptors = transition->instance_descriptors(); | 244 DescriptorArray* descriptors = transition->instance_descriptors(); |
389 PropertyDetails details = descriptors->GetDetails(descriptor); | 245 PropertyDetails details = descriptors->GetDetails(descriptor); |
390 Representation representation = details.representation(); | 246 Representation representation = details.representation(); |
391 DCHECK(!representation.IsNone()); | 247 DCHECK(!representation.IsNone()); |
392 | 248 |
(...skipping 23 matching lines...) Expand all Loading... |
416 __ Bind(&do_store); | 272 __ Bind(&do_store); |
417 } | 273 } |
418 } else if (representation.IsDouble()) { | 274 } else if (representation.IsDouble()) { |
419 UseScratchRegisterScope temps(masm()); | 275 UseScratchRegisterScope temps(masm()); |
420 DoubleRegister temp_double = temps.AcquireD(); | 276 DoubleRegister temp_double = temps.AcquireD(); |
421 __ SmiUntagToDouble(temp_double, value_reg, kSpeculativeUntag); | 277 __ SmiUntagToDouble(temp_double, value_reg, kSpeculativeUntag); |
422 | 278 |
423 Label do_store; | 279 Label do_store; |
424 __ JumpIfSmi(value_reg, &do_store); | 280 __ JumpIfSmi(value_reg, &do_store); |
425 | 281 |
426 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, | 282 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label, |
427 miss_label, DONT_DO_SMI_CHECK); | 283 DONT_DO_SMI_CHECK); |
428 __ Ldr(temp_double, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); | 284 __ Ldr(temp_double, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); |
429 | 285 |
430 __ Bind(&do_store); | 286 __ Bind(&do_store); |
431 __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2, temp_double, | 287 __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2, temp_double, |
432 NoReg, MUTABLE); | 288 NoReg, MUTABLE); |
433 } | 289 } |
434 | 290 |
435 // Stub never generated for objects that require access checks. | 291 // Stub never generated for objects that require access checks. |
436 DCHECK(!transition->is_access_check_needed()); | 292 DCHECK(!transition->is_access_check_needed()); |
437 | 293 |
438 // Perform map transition for the receiver if necessary. | 294 // Perform map transition for the receiver if necessary. |
439 if (details.type() == FIELD && | 295 if (details.type() == FIELD && |
440 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { | 296 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { |
441 // The properties must be extended before we can store the value. | 297 // The properties must be extended before we can store the value. |
442 // We jump to a runtime call that extends the properties array. | 298 // We jump to a runtime call that extends the properties array. |
443 __ Mov(scratch1, Operand(transition)); | 299 __ Mov(scratch1, Operand(transition)); |
444 __ Push(receiver_reg, scratch1, value_reg); | 300 __ Push(receiver_reg, scratch1, value_reg); |
445 __ TailCallExternalReference( | 301 __ TailCallExternalReference( |
446 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 302 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
447 isolate()), | 303 isolate()), |
448 3, 1); | 304 3, 1); |
449 return; | 305 return; |
450 } | 306 } |
451 | 307 |
452 // Update the map of the object. | 308 // Update the map of the object. |
453 __ Mov(scratch1, Operand(transition)); | 309 __ Mov(scratch1, Operand(transition)); |
454 __ Str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); | 310 __ Str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); |
455 | 311 |
456 // Update the write barrier for the map field. | 312 // Update the write barrier for the map field. |
457 __ RecordWriteField(receiver_reg, | 313 __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, |
458 HeapObject::kMapOffset, | 314 kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, |
459 scratch1, | |
460 scratch2, | |
461 kLRHasNotBeenSaved, | |
462 kDontSaveFPRegs, | |
463 OMIT_REMEMBERED_SET, | |
464 OMIT_SMI_CHECK); | 315 OMIT_SMI_CHECK); |
465 | 316 |
466 if (details.type() == CONSTANT) { | 317 if (details.type() == CONSTANT) { |
467 DCHECK(value_reg.is(x0)); | 318 DCHECK(value_reg.is(x0)); |
468 __ Ret(); | 319 __ Ret(); |
469 return; | 320 return; |
470 } | 321 } |
471 | 322 |
472 int index = transition->instance_descriptors()->GetFieldIndex( | 323 int index = transition->instance_descriptors()->GetFieldIndex( |
473 transition->LastAdded()); | 324 transition->LastAdded()); |
474 | 325 |
475 // Adjust for the number of properties stored in the object. Even in the | 326 // Adjust for the number of properties stored in the object. Even in the |
476 // face of a transition we can use the old map here because the size of the | 327 // face of a transition we can use the old map here because the size of the |
477 // object and the number of in-object properties is not going to change. | 328 // object and the number of in-object properties is not going to change. |
478 index -= transition->inobject_properties(); | 329 index -= transition->inobject_properties(); |
479 | 330 |
480 // TODO(verwaest): Share this code as a code stub. | 331 // TODO(verwaest): Share this code as a code stub. |
481 SmiCheck smi_check = representation.IsTagged() | 332 SmiCheck smi_check = |
482 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; | 333 representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; |
483 Register prop_reg = representation.IsDouble() ? storage_reg : value_reg; | 334 Register prop_reg = representation.IsDouble() ? storage_reg : value_reg; |
484 if (index < 0) { | 335 if (index < 0) { |
485 // Set the property straight into the object. | 336 // Set the property straight into the object. |
486 int offset = transition->instance_size() + (index * kPointerSize); | 337 int offset = transition->instance_size() + (index * kPointerSize); |
487 __ Str(prop_reg, FieldMemOperand(receiver_reg, offset)); | 338 __ Str(prop_reg, FieldMemOperand(receiver_reg, offset)); |
488 | 339 |
489 if (!representation.IsSmi()) { | 340 if (!representation.IsSmi()) { |
490 // Update the write barrier for the array address. | 341 // Update the write barrier for the array address. |
491 if (!representation.IsDouble()) { | 342 if (!representation.IsDouble()) { |
492 __ Mov(storage_reg, value_reg); | 343 __ Mov(storage_reg, value_reg); |
493 } | 344 } |
494 __ RecordWriteField(receiver_reg, | 345 __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, |
495 offset, | 346 kLRHasNotBeenSaved, kDontSaveFPRegs, |
496 storage_reg, | 347 EMIT_REMEMBERED_SET, smi_check); |
497 scratch1, | |
498 kLRHasNotBeenSaved, | |
499 kDontSaveFPRegs, | |
500 EMIT_REMEMBERED_SET, | |
501 smi_check); | |
502 } | 348 } |
503 } else { | 349 } else { |
504 // Write to the properties array. | 350 // Write to the properties array. |
505 int offset = index * kPointerSize + FixedArray::kHeaderSize; | 351 int offset = index * kPointerSize + FixedArray::kHeaderSize; |
506 // Get the properties array | 352 // Get the properties array |
507 __ Ldr(scratch1, | 353 __ Ldr(scratch1, |
508 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); | 354 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); |
509 __ Str(prop_reg, FieldMemOperand(scratch1, offset)); | 355 __ Str(prop_reg, FieldMemOperand(scratch1, offset)); |
510 | 356 |
511 if (!representation.IsSmi()) { | 357 if (!representation.IsSmi()) { |
512 // Update the write barrier for the array address. | 358 // Update the write barrier for the array address. |
513 if (!representation.IsDouble()) { | 359 if (!representation.IsDouble()) { |
514 __ Mov(storage_reg, value_reg); | 360 __ Mov(storage_reg, value_reg); |
515 } | 361 } |
516 __ RecordWriteField(scratch1, | 362 __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, |
517 offset, | 363 kLRHasNotBeenSaved, kDontSaveFPRegs, |
518 storage_reg, | 364 EMIT_REMEMBERED_SET, smi_check); |
519 receiver_reg, | |
520 kLRHasNotBeenSaved, | |
521 kDontSaveFPRegs, | |
522 EMIT_REMEMBERED_SET, | |
523 smi_check); | |
524 } | 365 } |
525 } | 366 } |
526 | 367 |
527 __ Bind(&exit); | 368 __ Bind(&exit); |
528 // Return the value (register x0). | 369 // Return the value (register x0). |
529 DCHECK(value_reg.is(x0)); | 370 DCHECK(value_reg.is(x0)); |
530 __ Ret(); | 371 __ Ret(); |
531 } | 372 } |
532 | 373 |
533 | 374 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
588 !current_map->is_access_check_needed()); | 429 !current_map->is_access_check_needed()); |
589 | 430 |
590 prototype = handle(JSObject::cast(current_map->prototype())); | 431 prototype = handle(JSObject::cast(current_map->prototype())); |
591 if (current_map->is_dictionary_map() && | 432 if (current_map->is_dictionary_map() && |
592 !current_map->IsJSGlobalObjectMap()) { | 433 !current_map->IsJSGlobalObjectMap()) { |
593 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. | 434 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. |
594 if (!name->IsUniqueName()) { | 435 if (!name->IsUniqueName()) { |
595 DCHECK(name->IsString()); | 436 DCHECK(name->IsString()); |
596 name = factory()->InternalizeString(Handle<String>::cast(name)); | 437 name = factory()->InternalizeString(Handle<String>::cast(name)); |
597 } | 438 } |
598 DCHECK(current.is_null() || | 439 DCHECK(current.is_null() || (current->property_dictionary()->FindEntry( |
599 (current->property_dictionary()->FindEntry(name) == | 440 name) == NameDictionary::kNotFound)); |
600 NameDictionary::kNotFound)); | |
601 | 441 |
602 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, | 442 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, |
603 scratch1, scratch2); | 443 scratch2); |
604 | 444 |
605 __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); | 445 __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); |
606 reg = holder_reg; // From now on the object will be in holder_reg. | 446 reg = holder_reg; // From now on the object will be in holder_reg. |
607 __ Ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); | 447 __ Ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); |
608 } else { | 448 } else { |
609 // Two possible reasons for loading the prototype from the map: | 449 // Two possible reasons for loading the prototype from the map: |
610 // (1) Can't store references to new space in code. | 450 // (1) Can't store references to new space in code. |
611 // (2) Handler is shared for all receivers with the same prototype | 451 // (2) Handler is shared for all receivers with the same prototype |
612 // map (but not necessarily the same prototype instance). | 452 // map (but not necessarily the same prototype instance). |
613 bool load_prototype_from_map = | 453 bool load_prototype_from_map = |
614 heap()->InNewSpace(*prototype) || depth == 1; | 454 heap()->InNewSpace(*prototype) || depth == 1; |
615 Register map_reg = scratch1; | 455 Register map_reg = scratch1; |
616 __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); | 456 __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); |
617 | 457 |
618 if (depth != 1 || check == CHECK_ALL_MAPS) { | 458 if (depth != 1 || check == CHECK_ALL_MAPS) { |
619 __ CheckMap(map_reg, current_map, miss, DONT_DO_SMI_CHECK); | 459 __ CheckMap(map_reg, current_map, miss, DONT_DO_SMI_CHECK); |
620 } | 460 } |
621 | 461 |
622 // Check access rights to the global object. This has to happen after | 462 // Check access rights to the global object. This has to happen after |
623 // the map check so that we know that the object is actually a global | 463 // the map check so that we know that the object is actually a global |
624 // object. | 464 // object. |
625 // This allows us to install generated handlers for accesses to the | 465 // This allows us to install generated handlers for accesses to the |
626 // global proxy (as opposed to using slow ICs). See corresponding code | 466 // global proxy (as opposed to using slow ICs). See corresponding code |
627 // in LookupForRead(). | 467 // in LookupForRead(). |
628 if (current_map->IsJSGlobalProxyMap()) { | 468 if (current_map->IsJSGlobalProxyMap()) { |
629 UseScratchRegisterScope temps(masm()); | 469 UseScratchRegisterScope temps(masm()); |
630 __ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), miss); | 470 __ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), miss); |
631 } else if (current_map->IsJSGlobalObjectMap()) { | 471 } else if (current_map->IsJSGlobalObjectMap()) { |
632 GenerateCheckPropertyCell( | 472 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), |
633 masm(), Handle<JSGlobalObject>::cast(current), name, | 473 name, scratch2, miss); |
634 scratch2, miss); | |
635 } | 474 } |
636 | 475 |
637 reg = holder_reg; // From now on the object will be in holder_reg. | 476 reg = holder_reg; // From now on the object will be in holder_reg. |
638 | 477 |
639 if (load_prototype_from_map) { | 478 if (load_prototype_from_map) { |
640 __ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); | 479 __ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); |
641 } else { | 480 } else { |
642 __ Mov(reg, Operand(prototype)); | 481 __ Mov(reg, Operand(prototype)); |
643 } | 482 } |
644 } | 483 } |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
714 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); | 553 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); |
715 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); | 554 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); |
716 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); | 555 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); |
717 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); | 556 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); |
718 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); | 557 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); |
719 | 558 |
720 __ Push(receiver()); | 559 __ Push(receiver()); |
721 | 560 |
722 if (heap()->InNewSpace(callback->data())) { | 561 if (heap()->InNewSpace(callback->data())) { |
723 __ Mov(scratch3(), Operand(callback)); | 562 __ Mov(scratch3(), Operand(callback)); |
724 __ Ldr(scratch3(), FieldMemOperand(scratch3(), | 563 __ Ldr(scratch3(), |
725 ExecutableAccessorInfo::kDataOffset)); | 564 FieldMemOperand(scratch3(), ExecutableAccessorInfo::kDataOffset)); |
726 } else { | 565 } else { |
727 __ Mov(scratch3(), Operand(Handle<Object>(callback->data(), isolate()))); | 566 __ Mov(scratch3(), Operand(Handle<Object>(callback->data(), isolate()))); |
728 } | 567 } |
729 __ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex); | 568 __ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex); |
730 __ Mov(scratch2(), Operand(ExternalReference::isolate_address(isolate()))); | 569 __ Mov(scratch2(), Operand(ExternalReference::isolate_address(isolate()))); |
731 __ Push(scratch3(), scratch4(), scratch4(), scratch2(), reg, name()); | 570 __ Push(scratch3(), scratch4(), scratch4(), scratch2(), reg, name()); |
732 | 571 |
733 Register args_addr = scratch2(); | 572 Register args_addr = scratch2(); |
734 __ Add(args_addr, __ StackPointer(), kPointerSize); | 573 __ Add(args_addr, __ StackPointer(), kPointerSize); |
735 | 574 |
(...skipping 15 matching lines...) Expand all Loading... |
751 ExternalReference ref = ExternalReference(&fun, type, isolate()); | 590 ExternalReference ref = ExternalReference(&fun, type, isolate()); |
752 __ Mov(getter_address_reg, ref); | 591 __ Mov(getter_address_reg, ref); |
753 | 592 |
754 CallApiGetterStub stub(isolate()); | 593 CallApiGetterStub stub(isolate()); |
755 __ TailCallStub(&stub); | 594 __ TailCallStub(&stub); |
756 } | 595 } |
757 | 596 |
758 | 597 |
759 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( | 598 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( |
760 LookupIterator* it, Register holder_reg) { | 599 LookupIterator* it, Register holder_reg) { |
761 DCHECK(!AreAliased(receiver(), this->name(), | 600 DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(), |
762 scratch1(), scratch2(), scratch3())); | 601 scratch3())); |
763 DCHECK(holder()->HasNamedInterceptor()); | 602 DCHECK(holder()->HasNamedInterceptor()); |
764 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); | 603 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); |
765 | 604 |
766 // Compile the interceptor call, followed by inline code to load the | 605 // Compile the interceptor call, followed by inline code to load the |
767 // property from further up the prototype chain if the call fails. | 606 // property from further up the prototype chain if the call fails. |
768 // Check that the maps haven't changed. | 607 // Check that the maps haven't changed. |
769 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); | 608 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); |
770 | 609 |
771 // Preserve the receiver register explicitly whenever it is different from the | 610 // Preserve the receiver register explicitly whenever it is different from the |
772 // holder and it is needed should the interceptor return without any result. | 611 // holder and it is needed should the interceptor return without any result. |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 if (!setter.is_null()) { | 716 if (!setter.is_null()) { |
878 // Call the JavaScript setter with receiver and value on the stack. | 717 // Call the JavaScript setter with receiver and value on the stack. |
879 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { | 718 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { |
880 // Swap in the global receiver. | 719 // Swap in the global receiver. |
881 __ Ldr(receiver, | 720 __ Ldr(receiver, |
882 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); | 721 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); |
883 } | 722 } |
884 __ Push(receiver, value()); | 723 __ Push(receiver, value()); |
885 ParameterCount actual(1); | 724 ParameterCount actual(1); |
886 ParameterCount expected(setter); | 725 ParameterCount expected(setter); |
887 __ InvokeFunction(setter, expected, actual, | 726 __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, |
888 CALL_FUNCTION, NullCallWrapper()); | 727 NullCallWrapper()); |
889 } else { | 728 } else { |
890 // If we generate a global code snippet for deoptimization only, remember | 729 // If we generate a global code snippet for deoptimization only, remember |
891 // the place to continue after deoptimization. | 730 // the place to continue after deoptimization. |
892 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); | 731 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); |
893 } | 732 } |
894 | 733 |
895 // We have to return the passed value, not the return value of the setter. | 734 // We have to return the passed value, not the return value of the setter. |
896 __ Pop(x0); | 735 __ Pop(x0); |
897 | 736 |
898 // Restore context register. | 737 // Restore context register. |
(...skipping 29 matching lines...) Expand all Loading... |
928 // example, PropertyAccessCompiler::keyed_store_calling_convention()[3] (x3) is | 767 // example, PropertyAccessCompiler::keyed_store_calling_convention()[3] (x3) is |
929 // actually | 768 // actually |
930 // used for KeyedStoreCompiler::transition_map(). We should verify which | 769 // used for KeyedStoreCompiler::transition_map(). We should verify which |
931 // registers are actually scratch registers, and which are important. For now, | 770 // registers are actually scratch registers, and which are important. For now, |
932 // we use the same assignments as ARM to remain on the safe side. | 771 // we use the same assignments as ARM to remain on the safe side. |
933 | 772 |
934 Register* PropertyAccessCompiler::load_calling_convention() { | 773 Register* PropertyAccessCompiler::load_calling_convention() { |
935 // receiver, name, scratch1, scratch2, scratch3, scratch4. | 774 // receiver, name, scratch1, scratch2, scratch3, scratch4. |
936 Register receiver = LoadIC::ReceiverRegister(); | 775 Register receiver = LoadIC::ReceiverRegister(); |
937 Register name = LoadIC::NameRegister(); | 776 Register name = LoadIC::NameRegister(); |
938 static Register registers[] = { receiver, name, x3, x0, x4, x5 }; | 777 static Register registers[] = {receiver, name, x3, x0, x4, x5}; |
939 return registers; | 778 return registers; |
940 } | 779 } |
941 | 780 |
942 | 781 |
943 Register* PropertyAccessCompiler::store_calling_convention() { | 782 Register* PropertyAccessCompiler::store_calling_convention() { |
944 // receiver, value, scratch1, scratch2, scratch3. | 783 // receiver, value, scratch1, scratch2, scratch3. |
945 Register receiver = StoreIC::ReceiverRegister(); | 784 Register receiver = StoreIC::ReceiverRegister(); |
946 Register name = StoreIC::NameRegister(); | 785 Register name = StoreIC::NameRegister(); |
947 DCHECK(x3.is(KeyedStoreIC::MapRegister())); | 786 DCHECK(x3.is(KeyedStoreIC::MapRegister())); |
948 static Register registers[] = { receiver, name, x3, x4, x5 }; | 787 static Register registers[] = {receiver, name, x3, x4, x5}; |
949 return registers; | 788 return registers; |
950 } | 789 } |
951 | 790 |
952 | 791 |
953 Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } | 792 Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } |
954 | 793 |
955 | 794 |
956 #undef __ | 795 #undef __ |
957 #define __ ACCESS_MASM(masm) | 796 #define __ ACCESS_MASM(masm) |
958 | 797 |
959 void NamedLoadHandlerCompiler::GenerateLoadViaGetter( | 798 void NamedLoadHandlerCompiler::GenerateLoadViaGetter( |
960 MacroAssembler* masm, Handle<HeapType> type, Register receiver, | 799 MacroAssembler* masm, Handle<HeapType> type, Register receiver, |
961 Handle<JSFunction> getter) { | 800 Handle<JSFunction> getter) { |
962 { | 801 { |
963 FrameScope scope(masm, StackFrame::INTERNAL); | 802 FrameScope scope(masm, StackFrame::INTERNAL); |
964 | 803 |
965 if (!getter.is_null()) { | 804 if (!getter.is_null()) { |
966 // Call the JavaScript getter with the receiver on the stack. | 805 // Call the JavaScript getter with the receiver on the stack. |
967 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { | 806 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { |
968 // Swap in the global receiver. | 807 // Swap in the global receiver. |
969 __ Ldr(receiver, | 808 __ Ldr(receiver, |
970 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); | 809 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); |
971 } | 810 } |
972 __ Push(receiver); | 811 __ Push(receiver); |
973 ParameterCount actual(0); | 812 ParameterCount actual(0); |
974 ParameterCount expected(getter); | 813 ParameterCount expected(getter); |
975 __ InvokeFunction(getter, expected, actual, | 814 __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, |
976 CALL_FUNCTION, NullCallWrapper()); | 815 NullCallWrapper()); |
977 } else { | 816 } else { |
978 // If we generate a global code snippet for deoptimization only, remember | 817 // If we generate a global code snippet for deoptimization only, remember |
979 // the place to continue after deoptimization. | 818 // the place to continue after deoptimization. |
980 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); | 819 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); |
981 } | 820 } |
982 | 821 |
983 // Restore context register. | 822 // Restore context register. |
984 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 823 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
985 } | 824 } |
986 __ Ret(); | 825 __ Ret(); |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1128 __ Bind(&slow); | 967 __ Bind(&slow); |
1129 __ IncrementCounter( | 968 __ IncrementCounter( |
1130 masm->isolate()->counters()->keyed_load_external_array_slow(), 1, x4, x3); | 969 masm->isolate()->counters()->keyed_load_external_array_slow(), 1, x4, x3); |
1131 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); | 970 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); |
1132 | 971 |
1133 // Miss case, call the runtime. | 972 // Miss case, call the runtime. |
1134 __ Bind(&miss); | 973 __ Bind(&miss); |
1135 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 974 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
1136 } | 975 } |
1137 | 976 |
1138 | 977 #undef __ |
1139 } } // namespace v8::internal | 978 } |
| 979 } // namespace v8::internal |
1140 | 980 |
1141 #endif // V8_TARGET_ARCH_ARM64 | 981 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |