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