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

Side by Side Diff: src/x64/stub-cache-x64.cc

Issue 483683005: Move IC code into a subdir and move ic-compilation related code from stub-cache into ic-compiler (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fix BUILD.gn Created 6 years, 4 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/x64/lithium-codegen-x64.cc ('k') | test/cctest/test-debug.cc » ('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 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #if V8_TARGET_ARCH_X64
8
9 #include "src/arguments.h"
10 #include "src/codegen.h"
11 #include "src/ic-inl.h"
12 #include "src/stub-cache.h"
13
14 namespace v8 {
15 namespace internal {
16
17 #define __ ACCESS_MASM(masm)
18
19
20 static void ProbeTable(Isolate* isolate,
21 MacroAssembler* masm,
22 Code::Flags flags,
23 StubCache::Table table,
24 Register receiver,
25 Register name,
26 // The offset is scaled by 4, based on
27 // kCacheIndexShift, which is two bits
28 Register offset) {
29 // We need to scale up the pointer by 2 when the offset is scaled by less
30 // than the pointer size.
31 DCHECK(kPointerSize == kInt64Size
32 ? kPointerSizeLog2 == StubCache::kCacheIndexShift + 1
33 : kPointerSizeLog2 == StubCache::kCacheIndexShift);
34 ScaleFactor scale_factor = kPointerSize == kInt64Size ? times_2 : times_1;
35
36 DCHECK_EQ(3 * kPointerSize, sizeof(StubCache::Entry));
37 // The offset register holds the entry offset times four (due to masking
38 // and shifting optimizations).
39 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
40 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
41 Label miss;
42
43 // Multiply by 3 because there are 3 fields per entry (name, code, map).
44 __ leap(offset, Operand(offset, offset, times_2, 0));
45
46 __ LoadAddress(kScratchRegister, key_offset);
47
48 // Check that the key in the entry matches the name.
49 // Multiply entry offset by 16 to get the entry address. Since the
50 // offset register already holds the entry offset times four, multiply
51 // by a further four.
52 __ cmpl(name, Operand(kScratchRegister, offset, scale_factor, 0));
53 __ j(not_equal, &miss);
54
55 // Get the map entry from the cache.
56 // Use key_offset + kPointerSize * 2, rather than loading map_offset.
57 __ movp(kScratchRegister,
58 Operand(kScratchRegister, offset, scale_factor, kPointerSize * 2));
59 __ cmpp(kScratchRegister, FieldOperand(receiver, HeapObject::kMapOffset));
60 __ j(not_equal, &miss);
61
62 // Get the code entry from the cache.
63 __ LoadAddress(kScratchRegister, value_offset);
64 __ movp(kScratchRegister,
65 Operand(kScratchRegister, offset, scale_factor, 0));
66
67 // Check that the flags match what we're looking for.
68 __ movl(offset, FieldOperand(kScratchRegister, Code::kFlagsOffset));
69 __ andp(offset, Immediate(~Code::kFlagsNotUsedInLookup));
70 __ cmpl(offset, Immediate(flags));
71 __ j(not_equal, &miss);
72
73 #ifdef DEBUG
74 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
75 __ jmp(&miss);
76 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
77 __ jmp(&miss);
78 }
79 #endif
80
81 // Jump to the first instruction in the code stub.
82 __ addp(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
83 __ jmp(kScratchRegister);
84
85 __ bind(&miss);
86 }
87
88
89 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
90 MacroAssembler* masm, Label* miss_label, Register receiver,
91 Handle<Name> name, Register scratch0, Register scratch1) {
92 DCHECK(name->IsUniqueName());
93 DCHECK(!receiver.is(scratch0));
94 Counters* counters = masm->isolate()->counters();
95 __ IncrementCounter(counters->negative_lookups(), 1);
96 __ IncrementCounter(counters->negative_lookups_miss(), 1);
97
98 __ movp(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
99
100 const int kInterceptorOrAccessCheckNeededMask =
101 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
102
103 // Bail out if the receiver has a named interceptor or requires access checks.
104 __ testb(FieldOperand(scratch0, Map::kBitFieldOffset),
105 Immediate(kInterceptorOrAccessCheckNeededMask));
106 __ j(not_zero, miss_label);
107
108 // Check that receiver is a JSObject.
109 __ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE);
110 __ j(below, miss_label);
111
112 // Load properties array.
113 Register properties = scratch0;
114 __ movp(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
115
116 // Check that the properties array is a dictionary.
117 __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset),
118 Heap::kHashTableMapRootIndex);
119 __ j(not_equal, miss_label);
120
121 Label done;
122 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
123 miss_label,
124 &done,
125 properties,
126 name,
127 scratch1);
128 __ bind(&done);
129 __ DecrementCounter(counters->negative_lookups_miss(), 1);
130 }
131
132
133 void StubCache::GenerateProbe(MacroAssembler* masm,
134 Code::Flags flags,
135 Register receiver,
136 Register name,
137 Register scratch,
138 Register extra,
139 Register extra2,
140 Register extra3) {
141 Isolate* isolate = masm->isolate();
142 Label miss;
143 USE(extra); // The register extra is not used on the X64 platform.
144 USE(extra2); // The register extra2 is not used on the X64 platform.
145 USE(extra3); // The register extra2 is not used on the X64 platform.
146 // Make sure that code is valid. The multiplying code relies on the
147 // entry size being 3 * kPointerSize.
148 DCHECK(sizeof(Entry) == 3 * kPointerSize);
149
150 // Make sure the flags do not name a specific type.
151 DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
152
153 // Make sure that there are no register conflicts.
154 DCHECK(!scratch.is(receiver));
155 DCHECK(!scratch.is(name));
156
157 // Check scratch register is valid, extra and extra2 are unused.
158 DCHECK(!scratch.is(no_reg));
159 DCHECK(extra2.is(no_reg));
160 DCHECK(extra3.is(no_reg));
161
162 Counters* counters = masm->isolate()->counters();
163 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
164
165 // Check that the receiver isn't a smi.
166 __ JumpIfSmi(receiver, &miss);
167
168 // Get the map of the receiver and compute the hash.
169 __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
170 // Use only the low 32 bits of the map pointer.
171 __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
172 __ xorp(scratch, Immediate(flags));
173 // We mask out the last two bits because they are not part of the hash and
174 // they are always 01 for maps. Also in the two 'and' instructions below.
175 __ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift));
176
177 // Probe the primary table.
178 ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch);
179
180 // Primary miss: Compute hash for secondary probe.
181 __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
182 __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
183 __ xorp(scratch, Immediate(flags));
184 __ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift));
185 __ subl(scratch, name);
186 __ addl(scratch, Immediate(flags));
187 __ andp(scratch, Immediate((kSecondaryTableSize - 1) << kCacheIndexShift));
188
189 // Probe the secondary table.
190 ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch);
191
192 // Cache miss: Fall-through and let caller handle the miss by
193 // entering the runtime system.
194 __ bind(&miss);
195 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
196 }
197
198
199 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
200 MacroAssembler* masm, int index, Register prototype, Label* miss) {
201 Isolate* isolate = masm->isolate();
202 // Get the global function with the given index.
203 Handle<JSFunction> function(
204 JSFunction::cast(isolate->native_context()->get(index)));
205
206 // Check we're still in the same context.
207 Register scratch = prototype;
208 const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
209 __ movp(scratch, Operand(rsi, offset));
210 __ movp(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
211 __ Cmp(Operand(scratch, Context::SlotOffset(index)), function);
212 __ j(not_equal, miss);
213
214 // Load its initial map. The global functions all have initial maps.
215 __ Move(prototype, Handle<Map>(function->initial_map()));
216 // Load the prototype from the initial map.
217 __ movp(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
218 }
219
220
221 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
222 MacroAssembler* masm, Register receiver, Register result, Register scratch,
223 Label* miss_label) {
224 __ TryGetFunctionPrototype(receiver, result, miss_label);
225 if (!result.is(rax)) __ movp(rax, result);
226 __ ret(0);
227 }
228
229
230 static void PushInterceptorArguments(MacroAssembler* masm,
231 Register receiver,
232 Register holder,
233 Register name,
234 Handle<JSObject> holder_obj) {
235 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
236 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1);
237 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2);
238 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3);
239 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4);
240 __ Push(name);
241 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
242 DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor));
243 __ Move(kScratchRegister, interceptor);
244 __ Push(kScratchRegister);
245 __ Push(receiver);
246 __ Push(holder);
247 }
248
249
250 static void CompileCallLoadPropertyWithInterceptor(
251 MacroAssembler* masm,
252 Register receiver,
253 Register holder,
254 Register name,
255 Handle<JSObject> holder_obj,
256 IC::UtilityId id) {
257 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
258 __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()),
259 NamedLoadHandlerCompiler::kInterceptorArgsLength);
260 }
261
262
263 // Generate call to api function.
264 void PropertyHandlerCompiler::GenerateFastApiCall(
265 MacroAssembler* masm, const CallOptimization& optimization,
266 Handle<Map> receiver_map, Register receiver, Register scratch_in,
267 bool is_store, int argc, Register* values) {
268 DCHECK(optimization.is_simple_api_call());
269
270 __ PopReturnAddressTo(scratch_in);
271 // receiver
272 __ Push(receiver);
273 // Write the arguments to stack frame.
274 for (int i = 0; i < argc; i++) {
275 Register arg = values[argc-1-i];
276 DCHECK(!receiver.is(arg));
277 DCHECK(!scratch_in.is(arg));
278 __ Push(arg);
279 }
280 __ PushReturnAddressFrom(scratch_in);
281 // Stack now matches JSFunction abi.
282
283 // Abi for CallApiFunctionStub.
284 Register callee = rax;
285 Register call_data = rbx;
286 Register holder = rcx;
287 Register api_function_address = rdx;
288 Register scratch = rdi; // scratch_in is no longer valid.
289
290 // Put holder in place.
291 CallOptimization::HolderLookup holder_lookup;
292 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
293 receiver_map,
294 &holder_lookup);
295 switch (holder_lookup) {
296 case CallOptimization::kHolderIsReceiver:
297 __ Move(holder, receiver);
298 break;
299 case CallOptimization::kHolderFound:
300 __ Move(holder, api_holder);
301 break;
302 case CallOptimization::kHolderNotFound:
303 UNREACHABLE();
304 break;
305 }
306
307 Isolate* isolate = masm->isolate();
308 Handle<JSFunction> function = optimization.constant_function();
309 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
310 Handle<Object> call_data_obj(api_call_info->data(), isolate);
311
312 // Put callee in place.
313 __ Move(callee, function);
314
315 bool call_data_undefined = false;
316 // Put call_data in place.
317 if (isolate->heap()->InNewSpace(*call_data_obj)) {
318 __ Move(scratch, api_call_info);
319 __ movp(call_data, FieldOperand(scratch, CallHandlerInfo::kDataOffset));
320 } else if (call_data_obj->IsUndefined()) {
321 call_data_undefined = true;
322 __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex);
323 } else {
324 __ Move(call_data, call_data_obj);
325 }
326
327 // Put api_function_address in place.
328 Address function_address = v8::ToCData<Address>(api_call_info->callback());
329 __ Move(
330 api_function_address, function_address, RelocInfo::EXTERNAL_REFERENCE);
331
332 // Jump to stub.
333 CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
334 __ TailCallStub(&stub);
335 }
336
337
338 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
339 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
340 Register scratch, Label* miss) {
341 Handle<PropertyCell> cell =
342 JSGlobalObject::EnsurePropertyCell(global, name);
343 DCHECK(cell->value()->IsTheHole());
344 __ Move(scratch, cell);
345 __ Cmp(FieldOperand(scratch, Cell::kValueOffset),
346 masm->isolate()->factory()->the_hole_value());
347 __ j(not_equal, miss);
348 }
349
350
351 void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
352 Handle<Code> code) {
353 __ jmp(code, RelocInfo::CODE_TARGET);
354 }
355
356
357 #undef __
358 #define __ ACCESS_MASM((masm()))
359
360
361 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
362 Handle<Name> name) {
363 if (!label->is_unused()) {
364 __ bind(label);
365 __ Move(this->name(), name);
366 }
367 }
368
369
370 // Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
371 // store is successful.
372 void NamedStoreHandlerCompiler::GenerateStoreTransition(
373 Handle<Map> transition, Handle<Name> name, Register receiver_reg,
374 Register storage_reg, Register value_reg, Register scratch1,
375 Register scratch2, Register unused, Label* miss_label, Label* slow) {
376 int descriptor = transition->LastAdded();
377 DescriptorArray* descriptors = transition->instance_descriptors();
378 PropertyDetails details = descriptors->GetDetails(descriptor);
379 Representation representation = details.representation();
380 DCHECK(!representation.IsNone());
381
382 if (details.type() == CONSTANT) {
383 Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
384 __ Cmp(value_reg, constant);
385 __ j(not_equal, miss_label);
386 } else if (representation.IsSmi()) {
387 __ JumpIfNotSmi(value_reg, miss_label);
388 } else if (representation.IsHeapObject()) {
389 __ JumpIfSmi(value_reg, miss_label);
390 HeapType* field_type = descriptors->GetFieldType(descriptor);
391 HeapType::Iterator<Map> it = field_type->Classes();
392 if (!it.Done()) {
393 Label do_store;
394 while (true) {
395 __ CompareMap(value_reg, it.Current());
396 it.Advance();
397 if (it.Done()) {
398 __ j(not_equal, miss_label);
399 break;
400 }
401 __ j(equal, &do_store, Label::kNear);
402 }
403 __ bind(&do_store);
404 }
405 } else if (representation.IsDouble()) {
406 Label do_store, heap_number;
407 __ AllocateHeapNumber(storage_reg, scratch1, slow, MUTABLE);
408
409 __ JumpIfNotSmi(value_reg, &heap_number);
410 __ SmiToInteger32(scratch1, value_reg);
411 __ Cvtlsi2sd(xmm0, scratch1);
412 __ jmp(&do_store);
413
414 __ bind(&heap_number);
415 __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label,
416 DONT_DO_SMI_CHECK);
417 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
418
419 __ bind(&do_store);
420 __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0);
421 }
422
423 // Stub never generated for objects that require access checks.
424 DCHECK(!transition->is_access_check_needed());
425
426 // Perform map transition for the receiver if necessary.
427 if (details.type() == FIELD &&
428 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
429 // The properties must be extended before we can store the value.
430 // We jump to a runtime call that extends the properties array.
431 __ PopReturnAddressTo(scratch1);
432 __ Push(receiver_reg);
433 __ Push(transition);
434 __ Push(value_reg);
435 __ PushReturnAddressFrom(scratch1);
436 __ TailCallExternalReference(
437 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
438 isolate()),
439 3, 1);
440 return;
441 }
442
443 // Update the map of the object.
444 __ Move(scratch1, transition);
445 __ movp(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
446
447 // Update the write barrier for the map field.
448 __ RecordWriteField(receiver_reg,
449 HeapObject::kMapOffset,
450 scratch1,
451 scratch2,
452 kDontSaveFPRegs,
453 OMIT_REMEMBERED_SET,
454 OMIT_SMI_CHECK);
455
456 if (details.type() == CONSTANT) {
457 DCHECK(value_reg.is(rax));
458 __ ret(0);
459 return;
460 }
461
462 int index = transition->instance_descriptors()->GetFieldIndex(
463 transition->LastAdded());
464
465 // Adjust for the number of properties stored in the object. Even in the
466 // face of a transition we can use the old map here because the size of the
467 // object and the number of in-object properties is not going to change.
468 index -= transition->inobject_properties();
469
470 // TODO(verwaest): Share this code as a code stub.
471 SmiCheck smi_check = representation.IsTagged()
472 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
473 if (index < 0) {
474 // Set the property straight into the object.
475 int offset = transition->instance_size() + (index * kPointerSize);
476 if (representation.IsDouble()) {
477 __ movp(FieldOperand(receiver_reg, offset), storage_reg);
478 } else {
479 __ movp(FieldOperand(receiver_reg, offset), value_reg);
480 }
481
482 if (!representation.IsSmi()) {
483 // Update the write barrier for the array address.
484 if (!representation.IsDouble()) {
485 __ movp(storage_reg, value_reg);
486 }
487 __ RecordWriteField(
488 receiver_reg, offset, storage_reg, scratch1, kDontSaveFPRegs,
489 EMIT_REMEMBERED_SET, smi_check);
490 }
491 } else {
492 // Write to the properties array.
493 int offset = index * kPointerSize + FixedArray::kHeaderSize;
494 // Get the properties array (optimistically).
495 __ movp(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
496 if (representation.IsDouble()) {
497 __ movp(FieldOperand(scratch1, offset), storage_reg);
498 } else {
499 __ movp(FieldOperand(scratch1, offset), value_reg);
500 }
501
502 if (!representation.IsSmi()) {
503 // Update the write barrier for the array address.
504 if (!representation.IsDouble()) {
505 __ movp(storage_reg, value_reg);
506 }
507 __ RecordWriteField(
508 scratch1, offset, storage_reg, receiver_reg, kDontSaveFPRegs,
509 EMIT_REMEMBERED_SET, smi_check);
510 }
511 }
512
513 // Return the value (register rax).
514 DCHECK(value_reg.is(rax));
515 __ ret(0);
516 }
517
518
519 void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
520 Register value_reg,
521 Label* miss_label) {
522 DCHECK(lookup->representation().IsHeapObject());
523 __ JumpIfSmi(value_reg, miss_label);
524 HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
525 Label do_store;
526 while (true) {
527 __ CompareMap(value_reg, it.Current());
528 it.Advance();
529 if (it.Done()) {
530 __ j(not_equal, miss_label);
531 break;
532 }
533 __ j(equal, &do_store, Label::kNear);
534 }
535 __ bind(&do_store);
536
537 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
538 lookup->representation());
539 GenerateTailCall(masm(), stub.GetCode());
540 }
541
542
543 Register PropertyHandlerCompiler::CheckPrototypes(
544 Register object_reg, Register holder_reg, Register scratch1,
545 Register scratch2, Handle<Name> name, Label* miss,
546 PrototypeCheckType check) {
547 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
548
549 // Make sure there's no overlap between holder and object registers.
550 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
551 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
552 && !scratch2.is(scratch1));
553
554 // Keep track of the current object in register reg. On the first
555 // iteration, reg is an alias for object_reg, on later iterations,
556 // it is an alias for holder_reg.
557 Register reg = object_reg;
558 int depth = 0;
559
560 Handle<JSObject> current = Handle<JSObject>::null();
561 if (type()->IsConstant()) {
562 current = Handle<JSObject>::cast(type()->AsConstant()->Value());
563 }
564 Handle<JSObject> prototype = Handle<JSObject>::null();
565 Handle<Map> current_map = receiver_map;
566 Handle<Map> holder_map(holder()->map());
567 // Traverse the prototype chain and check the maps in the prototype chain for
568 // fast and global objects or do negative lookup for normal objects.
569 while (!current_map.is_identical_to(holder_map)) {
570 ++depth;
571
572 // Only global objects and objects that do not require access
573 // checks are allowed in stubs.
574 DCHECK(current_map->IsJSGlobalProxyMap() ||
575 !current_map->is_access_check_needed());
576
577 prototype = handle(JSObject::cast(current_map->prototype()));
578 if (current_map->is_dictionary_map() &&
579 !current_map->IsJSGlobalObjectMap()) {
580 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
581 if (!name->IsUniqueName()) {
582 DCHECK(name->IsString());
583 name = factory()->InternalizeString(Handle<String>::cast(name));
584 }
585 DCHECK(current.is_null() ||
586 current->property_dictionary()->FindEntry(name) ==
587 NameDictionary::kNotFound);
588
589 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
590 scratch1, scratch2);
591
592 __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
593 reg = holder_reg; // From now on the object will be in holder_reg.
594 __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
595 } else {
596 bool in_new_space = heap()->InNewSpace(*prototype);
597 // Two possible reasons for loading the prototype from the map:
598 // (1) Can't store references to new space in code.
599 // (2) Handler is shared for all receivers with the same prototype
600 // map (but not necessarily the same prototype instance).
601 bool load_prototype_from_map = in_new_space || depth == 1;
602 if (load_prototype_from_map) {
603 // Save the map in scratch1 for later.
604 __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
605 }
606 if (depth != 1 || check == CHECK_ALL_MAPS) {
607 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
608 }
609
610 // Check access rights to the global object. This has to happen after
611 // the map check so that we know that the object is actually a global
612 // object.
613 // This allows us to install generated handlers for accesses to the
614 // global proxy (as opposed to using slow ICs). See corresponding code
615 // in LookupForRead().
616 if (current_map->IsJSGlobalProxyMap()) {
617 __ CheckAccessGlobalProxy(reg, scratch2, miss);
618 } else if (current_map->IsJSGlobalObjectMap()) {
619 GenerateCheckPropertyCell(
620 masm(), Handle<JSGlobalObject>::cast(current), name,
621 scratch2, miss);
622 }
623 reg = holder_reg; // From now on the object will be in holder_reg.
624
625 if (load_prototype_from_map) {
626 __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
627 } else {
628 __ Move(reg, prototype);
629 }
630 }
631
632 // Go to the next object in the prototype chain.
633 current = prototype;
634 current_map = handle(current->map());
635 }
636
637 // Log the check depth.
638 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
639
640 if (depth != 0 || check == CHECK_ALL_MAPS) {
641 // Check the holder map.
642 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
643 }
644
645 // Perform security check for access to the global object.
646 DCHECK(current_map->IsJSGlobalProxyMap() ||
647 !current_map->is_access_check_needed());
648 if (current_map->IsJSGlobalProxyMap()) {
649 __ CheckAccessGlobalProxy(reg, scratch1, miss);
650 }
651
652 // Return the register containing the holder.
653 return reg;
654 }
655
656
657 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
658 if (!miss->is_unused()) {
659 Label success;
660 __ jmp(&success);
661 __ bind(miss);
662 TailCallBuiltin(masm(), MissBuiltin(kind()));
663 __ bind(&success);
664 }
665 }
666
667
668 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
669 if (!miss->is_unused()) {
670 Label success;
671 __ jmp(&success);
672 GenerateRestoreName(miss, name);
673 TailCallBuiltin(masm(), MissBuiltin(kind()));
674 __ bind(&success);
675 }
676 }
677
678
679 void NamedLoadHandlerCompiler::GenerateLoadCallback(
680 Register reg, Handle<ExecutableAccessorInfo> callback) {
681 // Insert additional parameters into the stack frame above return address.
682 DCHECK(!scratch4().is(reg));
683 __ PopReturnAddressTo(scratch4());
684
685 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
686 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
687 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
688 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
689 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
690 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
691 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
692 __ Push(receiver()); // receiver
693 if (heap()->InNewSpace(callback->data())) {
694 DCHECK(!scratch2().is(reg));
695 __ Move(scratch2(), callback);
696 __ Push(FieldOperand(scratch2(),
697 ExecutableAccessorInfo::kDataOffset)); // data
698 } else {
699 __ Push(Handle<Object>(callback->data(), isolate()));
700 }
701 DCHECK(!kScratchRegister.is(reg));
702 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
703 __ Push(kScratchRegister); // return value
704 __ Push(kScratchRegister); // return value default
705 __ PushAddress(ExternalReference::isolate_address(isolate()));
706 __ Push(reg); // holder
707 __ Push(name()); // name
708 // Save a pointer to where we pushed the arguments pointer. This will be
709 // passed as the const PropertyAccessorInfo& to the C++ callback.
710
711 __ PushReturnAddressFrom(scratch4());
712
713 // Abi for CallApiGetter
714 Register api_function_address = r8;
715 Address getter_address = v8::ToCData<Address>(callback->getter());
716 __ Move(api_function_address, getter_address, RelocInfo::EXTERNAL_REFERENCE);
717
718 CallApiGetterStub stub(isolate());
719 __ TailCallStub(&stub);
720 }
721
722
723 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
724 // Return the constant value.
725 __ Move(rax, value);
726 __ ret(0);
727 }
728
729
730 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
731 LookupIterator* it, Register holder_reg) {
732 DCHECK(holder()->HasNamedInterceptor());
733 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
734
735 // Compile the interceptor call, followed by inline code to load the
736 // property from further up the prototype chain if the call fails.
737 // Check that the maps haven't changed.
738 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
739
740 // Preserve the receiver register explicitly whenever it is different from the
741 // holder and it is needed should the interceptor return without any result.
742 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
743 // case might cause a miss during the prototype check.
744 bool must_perform_prototype_check =
745 !holder().is_identical_to(it->GetHolder<JSObject>());
746 bool must_preserve_receiver_reg =
747 !receiver().is(holder_reg) &&
748 (it->property_kind() == LookupIterator::ACCESSOR ||
749 must_perform_prototype_check);
750
751 // Save necessary data before invoking an interceptor.
752 // Requires a frame to make GC aware of pushed pointers.
753 {
754 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
755
756 if (must_preserve_receiver_reg) {
757 __ Push(receiver());
758 }
759 __ Push(holder_reg);
760 __ Push(this->name());
761
762 // Invoke an interceptor. Note: map checks from receiver to
763 // interceptor's holder has been compiled before (see a caller
764 // of this method.)
765 CompileCallLoadPropertyWithInterceptor(
766 masm(), receiver(), holder_reg, this->name(), holder(),
767 IC::kLoadPropertyWithInterceptorOnly);
768
769 // Check if interceptor provided a value for property. If it's
770 // the case, return immediately.
771 Label interceptor_failed;
772 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
773 __ j(equal, &interceptor_failed);
774 frame_scope.GenerateLeaveFrame();
775 __ ret(0);
776
777 __ bind(&interceptor_failed);
778 __ Pop(this->name());
779 __ Pop(holder_reg);
780 if (must_preserve_receiver_reg) {
781 __ Pop(receiver());
782 }
783
784 // Leave the internal frame.
785 }
786
787 GenerateLoadPostInterceptor(it, holder_reg);
788 }
789
790
791 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
792 // Call the runtime system to load the interceptor.
793 DCHECK(holder()->HasNamedInterceptor());
794 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
795 __ PopReturnAddressTo(scratch2());
796 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
797 holder());
798 __ PushReturnAddressFrom(scratch2());
799
800 ExternalReference ref = ExternalReference(
801 IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
802 __ TailCallExternalReference(
803 ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
804 }
805
806
807 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
808 Handle<JSObject> object, Handle<Name> name,
809 Handle<ExecutableAccessorInfo> callback) {
810 Register holder_reg = Frontend(receiver(), name);
811
812 __ PopReturnAddressTo(scratch1());
813 __ Push(receiver());
814 __ Push(holder_reg);
815 __ Push(callback); // callback info
816 __ Push(name);
817 __ Push(value());
818 __ PushReturnAddressFrom(scratch1());
819
820 // Do tail-call to the runtime system.
821 ExternalReference store_callback_property =
822 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
823 __ TailCallExternalReference(store_callback_property, 5, 1);
824
825 // Return the generated code.
826 return GetCode(kind(), Code::FAST, name);
827 }
828
829
830 #undef __
831 #define __ ACCESS_MASM(masm)
832
833
834 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
835 MacroAssembler* masm, Handle<HeapType> type, Register receiver,
836 Handle<JSFunction> setter) {
837 // ----------- S t a t e -------------
838 // -- rsp[0] : return address
839 // -----------------------------------
840 {
841 FrameScope scope(masm, StackFrame::INTERNAL);
842
843 // Save value register, so we can restore it later.
844 __ Push(value());
845
846 if (!setter.is_null()) {
847 // Call the JavaScript setter with receiver and value on the stack.
848 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
849 // Swap in the global receiver.
850 __ movp(receiver,
851 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
852 }
853 __ Push(receiver);
854 __ Push(value());
855 ParameterCount actual(1);
856 ParameterCount expected(setter);
857 __ InvokeFunction(setter, expected, actual,
858 CALL_FUNCTION, NullCallWrapper());
859 } else {
860 // If we generate a global code snippet for deoptimization only, remember
861 // the place to continue after deoptimization.
862 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
863 }
864
865 // We have to return the passed value, not the return value of the setter.
866 __ Pop(rax);
867
868 // Restore context register.
869 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
870 }
871 __ ret(0);
872 }
873
874
875 #undef __
876 #define __ ACCESS_MASM(masm())
877
878
879 Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
880 Handle<Name> name) {
881 __ PopReturnAddressTo(scratch1());
882 __ Push(receiver());
883 __ Push(this->name());
884 __ Push(value());
885 __ PushReturnAddressFrom(scratch1());
886
887 // Do tail-call to the runtime system.
888 ExternalReference store_ic_property = ExternalReference(
889 IC_Utility(IC::kStorePropertyWithInterceptor), isolate());
890 __ TailCallExternalReference(store_ic_property, 3, 1);
891
892 // Return the generated code.
893 return GetCode(kind(), Code::FAST, name);
894 }
895
896
897 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
898 MapHandleList* receiver_maps, CodeHandleList* handler_stubs,
899 MapHandleList* transitioned_maps) {
900 Label miss;
901 __ JumpIfSmi(receiver(), &miss, Label::kNear);
902
903 __ movp(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
904 int receiver_count = receiver_maps->length();
905 for (int i = 0; i < receiver_count; ++i) {
906 // Check map and tail call if there's a match
907 __ Cmp(scratch1(), receiver_maps->at(i));
908 if (transitioned_maps->at(i).is_null()) {
909 __ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET);
910 } else {
911 Label next_map;
912 __ j(not_equal, &next_map, Label::kNear);
913 __ Move(transition_map(),
914 transitioned_maps->at(i),
915 RelocInfo::EMBEDDED_OBJECT);
916 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
917 __ bind(&next_map);
918 }
919 }
920
921 __ bind(&miss);
922
923 TailCallBuiltin(masm(), MissBuiltin(kind()));
924
925 // Return the generated code.
926 return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
927 }
928
929
930 Register* PropertyAccessCompiler::load_calling_convention() {
931 // receiver, name, scratch1, scratch2, scratch3, scratch4.
932 Register receiver = LoadIC::ReceiverRegister();
933 Register name = LoadIC::NameRegister();
934 static Register registers[] = { receiver, name, rax, rbx, rdi, r8 };
935 return registers;
936 }
937
938
939 Register* PropertyAccessCompiler::store_calling_convention() {
940 // receiver, name, scratch1, scratch2, scratch3.
941 Register receiver = KeyedStoreIC::ReceiverRegister();
942 Register name = KeyedStoreIC::NameRegister();
943 DCHECK(rbx.is(KeyedStoreIC::MapRegister()));
944 static Register registers[] = { receiver, name, rbx, rdi, r8 };
945 return registers;
946 }
947
948
949 Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); }
950
951
952 #undef __
953 #define __ ACCESS_MASM(masm)
954
955
956 void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
957 MacroAssembler* masm, Handle<HeapType> type, Register receiver,
958 Handle<JSFunction> getter) {
959 // ----------- S t a t e -------------
960 // -- rax : receiver
961 // -- rcx : name
962 // -- rsp[0] : return address
963 // -----------------------------------
964 {
965 FrameScope scope(masm, StackFrame::INTERNAL);
966
967 if (!getter.is_null()) {
968 // Call the JavaScript getter with the receiver on the stack.
969 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
970 // Swap in the global receiver.
971 __ movp(receiver,
972 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
973 }
974 __ Push(receiver);
975 ParameterCount actual(0);
976 ParameterCount expected(getter);
977 __ InvokeFunction(getter, expected, actual,
978 CALL_FUNCTION, NullCallWrapper());
979 } else {
980 // If we generate a global code snippet for deoptimization only, remember
981 // the place to continue after deoptimization.
982 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
983 }
984
985 // Restore context register.
986 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
987 }
988 __ ret(0);
989 }
990
991
992 #undef __
993 #define __ ACCESS_MASM(masm())
994
995
996 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
997 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
998 Label miss;
999 FrontendHeader(receiver(), name, &miss);
1000
1001 // Get the value from the cell.
1002 Register result = StoreIC::ValueRegister();
1003 __ Move(result, cell);
1004 __ movp(result, FieldOperand(result, PropertyCell::kValueOffset));
1005
1006 // Check for deleted property if property can actually be deleted.
1007 if (is_configurable) {
1008 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
1009 __ j(equal, &miss);
1010 } else if (FLAG_debug_code) {
1011 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
1012 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
1013 }
1014
1015 Counters* counters = isolate()->counters();
1016 __ IncrementCounter(counters->named_load_global_stub(), 1);
1017 __ ret(0);
1018
1019 FrontendFooter(name, &miss);
1020
1021 // Return the generated code.
1022 return GetCode(kind(), Code::NORMAL, name);
1023 }
1024
1025
1026 Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
1027 CodeHandleList* handlers,
1028 Handle<Name> name,
1029 Code::StubType type,
1030 IcCheckType check) {
1031 Label miss;
1032
1033 if (check == PROPERTY &&
1034 (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) {
1035 // In case we are compiling an IC for dictionary loads and stores, just
1036 // check whether the name is unique.
1037 if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) {
1038 __ JumpIfNotUniqueName(this->name(), &miss);
1039 } else {
1040 __ Cmp(this->name(), name);
1041 __ j(not_equal, &miss);
1042 }
1043 }
1044
1045 Label number_case;
1046 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
1047 __ JumpIfSmi(receiver(), smi_target);
1048
1049 // Polymorphic keyed stores may use the map register
1050 Register map_reg = scratch1();
1051 DCHECK(kind() != Code::KEYED_STORE_IC ||
1052 map_reg.is(KeyedStoreIC::MapRegister()));
1053 __ movp(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
1054 int receiver_count = types->length();
1055 int number_of_handled_maps = 0;
1056 for (int current = 0; current < receiver_count; ++current) {
1057 Handle<HeapType> type = types->at(current);
1058 Handle<Map> map = IC::TypeToMap(*type, isolate());
1059 if (!map->is_deprecated()) {
1060 number_of_handled_maps++;
1061 // Check map and tail call if there's a match
1062 __ Cmp(map_reg, map);
1063 if (type->Is(HeapType::Number())) {
1064 DCHECK(!number_case.is_unused());
1065 __ bind(&number_case);
1066 }
1067 __ j(equal, handlers->at(current), RelocInfo::CODE_TARGET);
1068 }
1069 }
1070 DCHECK(number_of_handled_maps > 0);
1071
1072 __ bind(&miss);
1073 TailCallBuiltin(masm(), MissBuiltin(kind()));
1074
1075 // Return the generated code.
1076 InlineCacheState state =
1077 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
1078 return GetCode(kind(), type, name, state);
1079 }
1080
1081
1082 #undef __
1083 #define __ ACCESS_MASM(masm)
1084
1085
1086 void ElementHandlerCompiler::GenerateLoadDictionaryElement(
1087 MacroAssembler* masm) {
1088 // ----------- S t a t e -------------
1089 // -- rcx : key
1090 // -- rdx : receiver
1091 // -- rsp[0] : return address
1092 // -----------------------------------
1093 DCHECK(rdx.is(LoadIC::ReceiverRegister()));
1094 DCHECK(rcx.is(LoadIC::NameRegister()));
1095 Label slow, miss;
1096
1097 // This stub is meant to be tail-jumped to, the receiver must already
1098 // have been verified by the caller to not be a smi.
1099
1100 __ JumpIfNotSmi(rcx, &miss);
1101 __ SmiToInteger32(rbx, rcx);
1102 __ movp(rax, FieldOperand(rdx, JSObject::kElementsOffset));
1103
1104 // Check whether the elements is a number dictionary.
1105 // rdx: receiver
1106 // rcx: key
1107 // rbx: key as untagged int32
1108 // rax: elements
1109 __ LoadFromNumberDictionary(&slow, rax, rcx, rbx, r9, rdi, rax);
1110 __ ret(0);
1111
1112 __ bind(&slow);
1113 // ----------- S t a t e -------------
1114 // -- rcx : key
1115 // -- rdx : receiver
1116 // -- rsp[0] : return address
1117 // -----------------------------------
1118 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
1119
1120 __ bind(&miss);
1121 // ----------- S t a t e -------------
1122 // -- rcx : key
1123 // -- rdx : receiver
1124 // -- rsp[0] : return address
1125 // -----------------------------------
1126 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss);
1127 }
1128
1129
1130 #undef __
1131
1132 } } // namespace v8::internal
1133
1134 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/lithium-codegen-x64.cc ('k') | test/cctest/test-debug.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698