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
3 // found in the LICENSE file.
4
5 #if V8_TARGET_ARCH_ARM64
6
7 #include "src/ic/handler-compiler.h"
8
9 #include "src/api-arguments.h"
10 #include "src/field-type.h"
11 #include "src/ic/call-optimization.h"
12 #include "src/ic/ic.h"
13 #include "src/isolate-inl.h"
14
15 namespace v8 {
16 namespace internal {
17
18 #define __ ACCESS_MASM(masm)
19
PushVectorAndSlot(Register vector,Register slot)20 void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
21 Register slot) {
22 MacroAssembler* masm = this->masm();
23 STATIC_ASSERT(LoadWithVectorDescriptor::kSlot <
24 LoadWithVectorDescriptor::kVector);
25 STATIC_ASSERT(StoreWithVectorDescriptor::kSlot <
26 StoreWithVectorDescriptor::kVector);
27 STATIC_ASSERT(StoreTransitionDescriptor::kSlot <
28 StoreTransitionDescriptor::kVector);
29 __ Push(slot);
30 __ Push(vector);
31 }
32
33
PopVectorAndSlot(Register vector,Register slot)34 void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
35 MacroAssembler* masm = this->masm();
36 __ Pop(vector);
37 __ Pop(slot);
38 }
39
40
DiscardVectorAndSlot()41 void PropertyHandlerCompiler::DiscardVectorAndSlot() {
42 MacroAssembler* masm = this->masm();
43 // Remove vector and slot.
44 __ Drop(2);
45 }
46
PushReturnAddress(Register tmp)47 void PropertyHandlerCompiler::PushReturnAddress(Register tmp) {
48 // No-op. Return address is in lr register.
49 }
50
PopReturnAddress(Register tmp)51 void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
52 // No-op. Return address is in lr register.
53 }
54
GenerateDictionaryNegativeLookup(MacroAssembler * masm,Label * miss_label,Register receiver,Handle<Name> name,Register scratch0,Register scratch1)55 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
56 MacroAssembler* masm, Label* miss_label, Register receiver,
57 Handle<Name> name, Register scratch0, Register scratch1) {
58 DCHECK(!AreAliased(receiver, scratch0, scratch1));
59 DCHECK(name->IsUniqueName());
60 Counters* counters = masm->isolate()->counters();
61 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
62 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
63
64 Label done;
65
66 const int kInterceptorOrAccessCheckNeededMask =
67 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
68
69 // Bail out if the receiver has a named interceptor or requires access checks.
70 Register map = scratch1;
71 __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
72 __ Ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
73 __ Tst(scratch0, kInterceptorOrAccessCheckNeededMask);
74 __ B(ne, miss_label);
75
76 // Check that receiver is a JSObject.
77 __ Ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
78 __ Cmp(scratch0, FIRST_JS_RECEIVER_TYPE);
79 __ B(lt, miss_label);
80
81 // Load properties array.
82 Register properties = scratch0;
83 __ Ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
84 // Check that the properties array is a dictionary.
85 __ Ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
86 __ JumpIfNotRoot(map, Heap::kHashTableMapRootIndex, miss_label);
87
88 NameDictionaryLookupStub::GenerateNegativeLookup(
89 masm, miss_label, &done, receiver, properties, name, scratch1);
90 __ Bind(&done);
91 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
92 }
93
94
GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler * masm,int index,Register result,Label * miss)95 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
96 MacroAssembler* masm, int index, Register result, Label* miss) {
97 __ LoadNativeContextSlot(index, result);
98 // Load its initial map. The global functions all have initial maps.
99 __ Ldr(result,
100 FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
101 // Load the prototype from the initial map.
102 __ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
103 }
104
105
GenerateLoadFunctionPrototype(MacroAssembler * masm,Register receiver,Register scratch1,Register scratch2,Label * miss_label)106 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
107 MacroAssembler* masm, Register receiver, Register scratch1,
108 Register scratch2, Label* miss_label) {
109 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
110 // TryGetFunctionPrototype can't put the result directly in x0 because the
111 // 3 inputs registers can't alias and we call this function from
112 // LoadIC::GenerateFunctionPrototype, where receiver is x0. So we explicitly
113 // move the result in x0.
114 __ Mov(x0, scratch1);
115 __ Ret();
116 }
117
118
119 // Generate code to check that a global property cell is empty. Create
120 // the property cell at compilation time if no cell exists for the
121 // property.
GenerateCheckPropertyCell(MacroAssembler * masm,Handle<JSGlobalObject> global,Handle<Name> name,Register scratch,Label * miss)122 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
123 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
124 Register scratch, Label* miss) {
125 Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
126 global, name, PropertyCellType::kInvalidated);
127 Isolate* isolate = masm->isolate();
128 DCHECK(cell->value()->IsTheHole(isolate));
129 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
130 __ LoadWeakValue(scratch, weak_cell, miss);
131 __ Ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
132 __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss);
133 }
134
135
PushInterceptorArguments(MacroAssembler * masm,Register receiver,Register holder,Register name,Handle<JSObject> holder_obj)136 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
137 Register holder, Register name,
138 Handle<JSObject> holder_obj) {
139 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
140 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
141 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
142 STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
143
144 __ Push(name, receiver, holder);
145 }
146
147
CompileCallLoadPropertyWithInterceptor(MacroAssembler * masm,Register receiver,Register holder,Register name,Handle<JSObject> holder_obj,Runtime::FunctionId id)148 static void CompileCallLoadPropertyWithInterceptor(
149 MacroAssembler* masm, Register receiver, Register holder, Register name,
150 Handle<JSObject> holder_obj, Runtime::FunctionId id) {
151 DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
152 Runtime::FunctionForId(id)->nargs);
153 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
154 __ CallRuntime(id);
155 }
156
157
158 // Generate call to api function.
GenerateApiAccessorCall(MacroAssembler * masm,const CallOptimization & optimization,Handle<Map> receiver_map,Register receiver,Register scratch,bool is_store,Register store_parameter,Register accessor_holder,int accessor_index)159 void PropertyHandlerCompiler::GenerateApiAccessorCall(
160 MacroAssembler* masm, const CallOptimization& optimization,
161 Handle<Map> receiver_map, Register receiver, Register scratch,
162 bool is_store, Register store_parameter, Register accessor_holder,
163 int accessor_index) {
164 DCHECK(!AreAliased(accessor_holder, scratch));
165 DCHECK(!AreAliased(receiver, scratch));
166
167 MacroAssembler::PushPopQueue queue(masm);
168 queue.Queue(receiver);
169 // Write the arguments to the stack frame.
170 if (is_store) {
171 DCHECK(!receiver.is(store_parameter));
172 DCHECK(!scratch.is(store_parameter));
173 queue.Queue(store_parameter);
174 }
175 queue.PushQueued();
176
177 DCHECK(optimization.is_simple_api_call());
178
179 // Abi for CallApiCallbackStub.
180 Register callee = x0;
181 Register data = x4;
182 Register holder = x2;
183 Register api_function_address = x1;
184
185 // Put callee in place.
186 __ LoadAccessor(callee, accessor_holder, accessor_index,
187 is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
188
189 // Put holder in place.
190 CallOptimization::HolderLookup holder_lookup;
191 int holder_depth = 0;
192 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
193 &holder_depth);
194 switch (holder_lookup) {
195 case CallOptimization::kHolderIsReceiver:
196 __ Mov(holder, receiver);
197 break;
198 case CallOptimization::kHolderFound:
199 __ Ldr(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
200 __ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
201 for (int i = 1; i < holder_depth; i++) {
202 __ Ldr(holder, FieldMemOperand(holder, HeapObject::kMapOffset));
203 __ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
204 }
205 break;
206 case CallOptimization::kHolderNotFound:
207 UNREACHABLE();
208 break;
209 }
210
211 Isolate* isolate = masm->isolate();
212 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
213 bool call_data_undefined = false;
214 // Put call data in place.
215 if (api_call_info->data()->IsUndefined(isolate)) {
216 call_data_undefined = true;
217 __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
218 } else {
219 if (optimization.is_constant_call()) {
220 __ Ldr(data,
221 FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
222 __ Ldr(data,
223 FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
224 __ Ldr(data,
225 FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
226 } else {
227 __ Ldr(data,
228 FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
229 }
230 __ Ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
231 }
232
233 if (api_call_info->fast_handler()->IsCode()) {
234 // Just tail call into the fast handler if present.
235 __ Jump(handle(Code::cast(api_call_info->fast_handler())),
236 RelocInfo::CODE_TARGET);
237 return;
238 }
239
240 // Put api_function_address in place.
241 Address function_address = v8::ToCData<Address>(api_call_info->callback());
242 ApiFunction fun(function_address);
243 ExternalReference ref = ExternalReference(
244 &fun, ExternalReference::DIRECT_API_CALL, masm->isolate());
245 __ Mov(api_function_address, ref);
246
247 // Jump to stub.
248 CallApiCallbackStub stub(isolate, is_store, call_data_undefined,
249 !optimization.is_constant_call());
250 __ TailCallStub(&stub);
251 }
252
253
GenerateStoreViaSetter(MacroAssembler * masm,Handle<Map> map,Register receiver,Register holder,int accessor_index,int expected_arguments,Register scratch)254 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
255 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
256 int accessor_index, int expected_arguments, Register scratch) {
257 // ----------- S t a t e -------------
258 // -- lr : return address
259 // -----------------------------------
260 Label miss;
261 {
262 FrameScope scope(masm, StackFrame::INTERNAL);
263
264 // Save context register
265 __ Push(cp);
266 // Save value register, so we can restore it later.
267 __ Push(value());
268
269 if (accessor_index >= 0) {
270 DCHECK(!AreAliased(holder, scratch));
271 DCHECK(!AreAliased(receiver, scratch));
272 DCHECK(!AreAliased(value(), scratch));
273 // Call the JavaScript setter with receiver and value on the stack.
274 if (map->IsJSGlobalObjectMap()) {
275 // Swap in the global receiver.
276 __ Ldr(scratch,
277 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
278 receiver = scratch;
279 }
280 __ Push(receiver, value());
281 __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_SETTER);
282 __ Mov(x0, 1);
283 __ Call(masm->isolate()->builtins()->CallFunction(
284 ConvertReceiverMode::kNotNullOrUndefined),
285 RelocInfo::CODE_TARGET);
286 } else {
287 // If we generate a global code snippet for deoptimization only, remember
288 // the place to continue after deoptimization.
289 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
290 }
291
292 // We have to return the passed value, not the return value of the setter.
293 __ Pop(x0);
294
295 // Restore context register.
296 __ Pop(cp);
297 }
298 __ Ret();
299 }
300
301
GenerateLoadViaGetter(MacroAssembler * masm,Handle<Map> map,Register receiver,Register holder,int accessor_index,int expected_arguments,Register scratch)302 void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
303 MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
304 int accessor_index, int expected_arguments, Register scratch) {
305 {
306 FrameScope scope(masm, StackFrame::INTERNAL);
307
308 // Save context register
309 __ Push(cp);
310
311 if (accessor_index >= 0) {
312 DCHECK(!AreAliased(holder, scratch));
313 DCHECK(!AreAliased(receiver, scratch));
314 // Call the JavaScript getter with the receiver on the stack.
315 if (map->IsJSGlobalObjectMap()) {
316 // Swap in the global receiver.
317 __ Ldr(scratch,
318 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
319 receiver = scratch;
320 }
321 __ Push(receiver);
322 __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_GETTER);
323 __ Mov(x0, 0);
324 __ Call(masm->isolate()->builtins()->CallFunction(
325 ConvertReceiverMode::kNotNullOrUndefined),
326 RelocInfo::CODE_TARGET);
327 } else {
328 // If we generate a global code snippet for deoptimization only, remember
329 // the place to continue after deoptimization.
330 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
331 }
332
333 // Restore context register.
334 __ Pop(cp);
335 }
336 __ Ret();
337 }
338
339 #undef __
340 #define __ ACCESS_MASM(masm())
341
342
CompileLoadGlobal(Handle<PropertyCell> cell,Handle<Name> name,bool is_configurable)343 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
344 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
345 Label miss;
346 if (IC::ICUseVector(kind())) {
347 PushVectorAndSlot();
348 }
349 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
350
351 // Get the value from the cell.
352 Register result = StoreDescriptor::ValueRegister();
353 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
354 __ LoadWeakValue(result, weak_cell, &miss);
355 __ Ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset));
356
357 // Check for deleted property if property can actually be deleted.
358 if (is_configurable) {
359 __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss);
360 }
361
362 Counters* counters = isolate()->counters();
363 __ IncrementCounter(counters->ic_named_load_global_stub(), 1, x1, x3);
364 if (IC::ICUseVector(kind())) {
365 DiscardVectorAndSlot();
366 }
367 __ Ret();
368
369 FrontendFooter(name, &miss);
370
371 // Return the generated code.
372 return GetCode(kind(), name);
373 }
374
375
value()376 Register NamedStoreHandlerCompiler::value() {
377 return StoreDescriptor::ValueRegister();
378 }
379
380
GenerateRestoreName(Label * label,Handle<Name> name)381 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
382 Handle<Name> name) {
383 if (!label->is_unused()) {
384 __ Bind(label);
385 __ Mov(this->name(), Operand(name));
386 }
387 }
388
389
GenerateRestoreName(Handle<Name> name)390 void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
391 __ Mov(this->name(), Operand(name));
392 }
393
394
GenerateRestoreMap(Handle<Map> transition,Register map_reg,Register scratch,Label * miss)395 void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
396 Register map_reg,
397 Register scratch,
398 Label* miss) {
399 Handle<WeakCell> cell = Map::WeakCellForMap(transition);
400 DCHECK(!map_reg.is(scratch));
401 __ LoadWeakValue(map_reg, cell, miss);
402 if (transition->CanBeDeprecated()) {
403 __ Ldrsw(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
404 __ TestAndBranchIfAnySet(scratch, Map::Deprecated::kMask, miss);
405 }
406 }
407
408
GenerateConstantCheck(Register map_reg,int descriptor,Register value_reg,Register scratch,Label * miss_label)409 void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
410 int descriptor,
411 Register value_reg,
412 Register scratch,
413 Label* miss_label) {
414 DCHECK(!map_reg.is(scratch));
415 DCHECK(!map_reg.is(value_reg));
416 DCHECK(!value_reg.is(scratch));
417 __ LoadInstanceDescriptors(map_reg, scratch);
418 __ Ldr(scratch,
419 FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
420 __ Cmp(value_reg, scratch);
421 __ B(ne, miss_label);
422 }
423
GenerateFieldTypeChecks(FieldType * field_type,Register value_reg,Label * miss_label)424 void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
425 Register value_reg,
426 Label* miss_label) {
427 Register map_reg = scratch1();
428 Register scratch = scratch2();
429 DCHECK(!value_reg.is(map_reg));
430 DCHECK(!value_reg.is(scratch));
431 __ JumpIfSmi(value_reg, miss_label);
432 if (field_type->IsClass()) {
433 __ Ldr(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
434 __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
435 scratch);
436 __ B(ne, miss_label);
437 }
438 }
439
GenerateAccessCheck(Handle<WeakCell> native_context_cell,Register scratch1,Register scratch2,Label * miss,bool compare_native_contexts_only)440 void PropertyHandlerCompiler::GenerateAccessCheck(
441 Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
442 Label* miss, bool compare_native_contexts_only) {
443 Label done;
444 // Load current native context.
445 __ Ldr(scratch1, NativeContextMemOperand());
446 // Load expected native context.
447 __ LoadWeakValue(scratch2, native_context_cell, miss);
448 __ Cmp(scratch1, scratch2);
449
450 if (!compare_native_contexts_only) {
451 __ B(eq, &done);
452
453 // Compare security tokens of current and expected native contexts.
454 __ Ldr(scratch1,
455 ContextMemOperand(scratch1, Context::SECURITY_TOKEN_INDEX));
456 __ Ldr(scratch2,
457 ContextMemOperand(scratch2, Context::SECURITY_TOKEN_INDEX));
458 __ Cmp(scratch1, scratch2);
459 }
460 __ B(ne, miss);
461
462 __ bind(&done);
463 }
464
CheckPrototypes(Register object_reg,Register holder_reg,Register scratch1,Register scratch2,Handle<Name> name,Label * miss,ReturnHolder return_what)465 Register PropertyHandlerCompiler::CheckPrototypes(
466 Register object_reg, Register holder_reg, Register scratch1,
467 Register scratch2, Handle<Name> name, Label* miss,
468 ReturnHolder return_what) {
469 Handle<Map> receiver_map = map();
470
471 // object_reg and holder_reg registers can alias.
472 DCHECK(!AreAliased(object_reg, scratch1, scratch2));
473 DCHECK(!AreAliased(holder_reg, scratch1, scratch2));
474
475 Handle<Cell> validity_cell =
476 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
477 if (!validity_cell.is_null()) {
478 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value());
479 __ Mov(scratch1, Operand(validity_cell));
480 __ Ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset));
481 // Compare scratch1 against Map::kPrototypeChainValid.
482 static_assert(Map::kPrototypeChainValid == 0,
483 "Map::kPrototypeChainValid has unexpected value");
484 __ Cbnz(scratch1, miss);
485 }
486
487 // Keep track of the current object in register reg.
488 Register reg = object_reg;
489 int depth = 0;
490
491 Handle<JSObject> current = Handle<JSObject>::null();
492 if (receiver_map->IsJSGlobalObjectMap()) {
493 current = isolate()->global_object();
494 }
495
496 Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
497 isolate());
498 Handle<Map> holder_map(holder()->map());
499 // Traverse the prototype chain and check the maps in the prototype chain for
500 // fast and global objects or do negative lookup for normal objects.
501 while (!current_map.is_identical_to(holder_map)) {
502 ++depth;
503
504 if (current_map->IsJSGlobalObjectMap()) {
505 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
506 name, scratch2, miss);
507 } else if (current_map->is_dictionary_map()) {
508 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
509 DCHECK(name->IsUniqueName());
510 DCHECK(current.is_null() || (current->property_dictionary()->FindEntry(
511 name) == NameDictionary::kNotFound));
512
513 if (depth > 1) {
514 Handle<WeakCell> weak_cell =
515 Map::GetOrCreatePrototypeWeakCell(current, isolate());
516 __ LoadWeakValue(reg, weak_cell, miss);
517 }
518 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
519 scratch2);
520 }
521
522 reg = holder_reg; // From now on the object will be in holder_reg.
523 // Go to the next object in the prototype chain.
524 current = handle(JSObject::cast(current_map->prototype()));
525 current_map = handle(current->map());
526 }
527
528 DCHECK(!current_map->IsJSGlobalProxyMap());
529
530 // Log the check depth.
531 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
532
533 bool return_holder = return_what == RETURN_HOLDER;
534 if (return_holder && depth != 0) {
535 Handle<WeakCell> weak_cell =
536 Map::GetOrCreatePrototypeWeakCell(current, isolate());
537 __ LoadWeakValue(reg, weak_cell, miss);
538 }
539
540 // Return the register containing the holder.
541 return return_holder ? reg : no_reg;
542 }
543
544
FrontendFooter(Handle<Name> name,Label * miss)545 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
546 if (!miss->is_unused()) {
547 Label success;
548 __ B(&success);
549
550 __ Bind(miss);
551 if (IC::ICUseVector(kind())) {
552 DCHECK(kind() == Code::LOAD_IC);
553 PopVectorAndSlot();
554 }
555 TailCallBuiltin(masm(), MissBuiltin(kind()));
556
557 __ Bind(&success);
558 }
559 }
560
561
FrontendFooter(Handle<Name> name,Label * miss)562 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
563 if (!miss->is_unused()) {
564 Label success;
565 __ B(&success);
566
567 GenerateRestoreName(miss, name);
568 if (IC::ICUseVector(kind())) PopVectorAndSlot();
569 TailCallBuiltin(masm(), MissBuiltin(kind()));
570
571 __ Bind(&success);
572 }
573 }
574
575
GenerateLoadConstant(Handle<Object> value)576 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
577 // Return the constant value.
578 __ LoadObject(x0, value);
579 __ Ret();
580 }
581
GenerateLoadInterceptorWithFollowup(LookupIterator * it,Register holder_reg)582 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
583 LookupIterator* it, Register holder_reg) {
584 DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(),
585 scratch3()));
586 DCHECK(holder()->HasNamedInterceptor());
587 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
588
589 // Compile the interceptor call, followed by inline code to load the
590 // property from further up the prototype chain if the call fails.
591 // Check that the maps haven't changed.
592 DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
593
594 // Preserve the receiver register explicitly whenever it is different from the
595 // holder and it is needed should the interceptor return without any result.
596 // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
597 // case might cause a miss during the prototype check.
598 bool must_perform_prototype_check =
599 !holder().is_identical_to(it->GetHolder<JSObject>());
600 bool must_preserve_receiver_reg =
601 !receiver().is(holder_reg) &&
602 (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
603
604 // Save necessary data before invoking an interceptor.
605 // Requires a frame to make GC aware of pushed pointers.
606 {
607 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
608 if (must_preserve_receiver_reg) {
609 __ Push(receiver(), holder_reg, this->name());
610 } else {
611 __ Push(holder_reg, this->name());
612 }
613 InterceptorVectorSlotPush(holder_reg);
614 // Invoke an interceptor. Note: map checks from receiver to
615 // interceptor's holder has been compiled before (see a caller
616 // of this method.)
617 CompileCallLoadPropertyWithInterceptor(
618 masm(), receiver(), holder_reg, this->name(), holder(),
619 Runtime::kLoadPropertyWithInterceptorOnly);
620
621 // Check if interceptor provided a value for property. If it's
622 // the case, return immediately.
623 Label interceptor_failed;
624 __ JumpIfRoot(x0, Heap::kNoInterceptorResultSentinelRootIndex,
625 &interceptor_failed);
626 frame_scope.GenerateLeaveFrame();
627 __ Ret();
628
629 __ Bind(&interceptor_failed);
630 InterceptorVectorSlotPop(holder_reg);
631 if (must_preserve_receiver_reg) {
632 __ Pop(this->name(), holder_reg, receiver());
633 } else {
634 __ Pop(this->name(), holder_reg);
635 }
636 // Leave the internal frame.
637 }
638
639 GenerateLoadPostInterceptor(it, holder_reg);
640 }
641
642
GenerateLoadInterceptor(Register holder_reg)643 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
644 // Call the runtime system to load the interceptor.
645 DCHECK(holder()->HasNamedInterceptor());
646 DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
647 PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
648 holder());
649
650 __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
651 }
652
ZapStackArgumentsRegisterAliases()653 void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
654 STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
655 }
656
CompileStoreCallback(Handle<JSObject> object,Handle<Name> name,Handle<AccessorInfo> callback,LanguageMode language_mode)657 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
658 Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
659 LanguageMode language_mode) {
660 ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreCallback");
661 Register holder_reg = Frontend(name);
662
663 // Stub never generated for non-global objects that require access checks.
664 DCHECK(holder()->IsJSGlobalProxy() || !holder()->IsAccessCheckNeeded());
665
666 // receiver() and holder_reg can alias.
667 DCHECK(!AreAliased(receiver(), scratch1(), scratch2(), value()));
668 DCHECK(!AreAliased(holder_reg, scratch1(), scratch2(), value()));
669 // If the callback cannot leak, then push the callback directly,
670 // otherwise wrap it in a weak cell.
671 if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
672 __ Mov(scratch1(), Operand(callback));
673 } else {
674 Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
675 __ Mov(scratch1(), Operand(cell));
676 }
677 __ Mov(scratch2(), Operand(name));
678 __ Push(receiver(), holder_reg, scratch1(), scratch2(), value());
679 __ Push(Smi::FromInt(language_mode));
680
681 // Do tail-call to the runtime system.
682 __ TailCallRuntime(Runtime::kStoreCallbackProperty);
683
684 // Return the generated code.
685 return GetCode(kind(), name);
686 }
687
688
689 #undef __
690 } // namespace internal
691 } // namespace v8
692
693 #endif // V8_TARGET_ARCH_IA32
694