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/api-arguments-inl.h"
8 #include "src/assembler-inl.h"
9 #include "src/base/bits.h"
10 #include "src/bootstrapper.h"
11 #include "src/code-stubs.h"
12 #include "src/double.h"
13 #include "src/frame-constants.h"
14 #include "src/frames.h"
15 #include "src/ic/ic.h"
16 #include "src/ic/stub-cache.h"
17 #include "src/isolate.h"
18 #include "src/objects/api-callbacks.h"
19 #include "src/regexp/jsregexp.h"
20 #include "src/regexp/regexp-macro-assembler.h"
21 #include "src/runtime/runtime.h"
22 
23 #include "src/ppc/code-stubs-ppc.h"  // Cannot be the first include.
24 
25 namespace v8 {
26 namespace internal {
27 
28 #define __ ACCESS_MASM(masm)
29 
Generate(MacroAssembler * masm)30 void JSEntryStub::Generate(MacroAssembler* masm) {
31   // r3: code entry
32   // r4: function
33   // r5: receiver
34   // r6: argc
35   // [sp+0]: argv
36 
37   Label invoke, handler_entry, exit;
38 
39 // Called from C
40   __ function_descriptor();
41 
42   {
43     NoRootArrayScope no_root_array(masm);
44     ProfileEntryHookStub::MaybeCallEntryHook(masm);
45 
46     // PPC LINUX ABI:
47     // preserve LR in pre-reserved slot in caller's frame
48     __ mflr(r0);
49     __ StoreP(r0, MemOperand(sp, kStackFrameLRSlot * kPointerSize));
50 
51     // Save callee saved registers on the stack.
52     __ MultiPush(kCalleeSaved);
53 
54     // Save callee-saved double registers.
55     __ MultiPushDoubles(kCalleeSavedDoubles);
56     // Set up the reserved register for 0.0.
57     __ LoadDoubleLiteral(kDoubleRegZero, Double(0.0), r0);
58 
59     __ InitializeRootRegister();
60   }
61 
62   // Push a frame with special values setup to mark it as an entry frame.
63   // r3: code entry
64   // r4: function
65   // r5: receiver
66   // r6: argc
67   // r7: argv
68   __ li(r0, Operand(-1));  // Push a bad frame pointer to fail if it is used.
69   __ push(r0);
70   if (FLAG_enable_embedded_constant_pool) {
71     __ li(kConstantPoolRegister, Operand::Zero());
72     __ push(kConstantPoolRegister);
73   }
74   StackFrame::Type marker = type();
75   __ mov(r0, Operand(StackFrame::TypeToMarker(marker)));
76   __ push(r0);
77   __ push(r0);
78   // Save copies of the top frame descriptor on the stack.
79   __ mov(r8, Operand(ExternalReference::Create(
80                  IsolateAddressId::kCEntryFPAddress, isolate())));
81   __ LoadP(r0, MemOperand(r8));
82   __ push(r0);
83 
84   // Set up frame pointer for the frame to be pushed.
85   __ addi(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
86 
87   // If this is the outermost JS call, set js_entry_sp value.
88   Label non_outermost_js;
89   ExternalReference js_entry_sp =
90       ExternalReference::Create(IsolateAddressId::kJSEntrySPAddress, isolate());
91   __ mov(r8, Operand(js_entry_sp));
92   __ LoadP(r9, MemOperand(r8));
93   __ cmpi(r9, Operand::Zero());
94   __ bne(&non_outermost_js);
95   __ StoreP(fp, MemOperand(r8));
96   __ mov(ip, Operand(StackFrame::OUTERMOST_JSENTRY_FRAME));
97   Label cont;
98   __ b(&cont);
99   __ bind(&non_outermost_js);
100   __ mov(ip, Operand(StackFrame::INNER_JSENTRY_FRAME));
101   __ bind(&cont);
102   __ push(ip);  // frame-type
103 
104   // Jump to a faked try block that does the invoke, with a faked catch
105   // block that sets the pending exception.
106   __ b(&invoke);
107 
108   __ bind(&handler_entry);
109   handler_offset_ = handler_entry.pos();
110   // Caught exception: Store result (exception) in the pending exception
111   // field in the JSEnv and return a failure sentinel.  Coming in here the
112   // fp will be invalid because the PushStackHandler below sets it to 0 to
113   // signal the existence of the JSEntry frame.
114   __ mov(ip, Operand(ExternalReference::Create(
115                  IsolateAddressId::kPendingExceptionAddress, isolate())));
116 
117   __ StoreP(r3, MemOperand(ip));
118   __ LoadRoot(r3, Heap::kExceptionRootIndex);
119   __ b(&exit);
120 
121   // Invoke: Link this frame into the handler chain.
122   __ bind(&invoke);
123   // Must preserve r3-r7.
124   __ PushStackHandler();
125   // If an exception not caught by another handler occurs, this handler
126   // returns control to the code after the b(&invoke) above, which
127   // restores all kCalleeSaved registers (including cp and fp) to their
128   // saved values before returning a failure to C.
129 
130   // Invoke the function by calling through JS entry trampoline builtin.
131   // Notice that we cannot store a reference to the trampoline code directly in
132   // this stub, because runtime stubs are not traversed when doing GC.
133 
134   // Expected registers by Builtins::JSEntryTrampoline
135   // r3: code entry
136   // r4: function
137   // r5: receiver
138   // r6: argc
139   // r7: argv
140   __ Call(EntryTrampoline(), RelocInfo::CODE_TARGET);
141 
142   // Unlink this frame from the handler chain.
143   __ PopStackHandler();
144 
145   __ bind(&exit);  // r3 holds result
146   // Check if the current stack frame is marked as the outermost JS frame.
147   Label non_outermost_js_2;
148   __ pop(r8);
149   __ cmpi(r8, Operand(StackFrame::OUTERMOST_JSENTRY_FRAME));
150   __ bne(&non_outermost_js_2);
151   __ mov(r9, Operand::Zero());
152   __ mov(r8, Operand(js_entry_sp));
153   __ StoreP(r9, MemOperand(r8));
154   __ bind(&non_outermost_js_2);
155 
156   // Restore the top frame descriptors from the stack.
157   __ pop(r6);
158   __ mov(ip, Operand(ExternalReference::Create(
159                  IsolateAddressId::kCEntryFPAddress, isolate())));
160   __ StoreP(r6, MemOperand(ip));
161 
162   // Reset the stack to the callee saved registers.
163   __ addi(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
164 
165   // Restore callee-saved double registers.
166   __ MultiPopDoubles(kCalleeSavedDoubles);
167 
168   // Restore callee-saved registers.
169   __ MultiPop(kCalleeSaved);
170 
171   // Return
172   __ LoadP(r0, MemOperand(sp, kStackFrameLRSlot * kPointerSize));
173   __ mtlr(r0);
174   __ blr();
175 }
176 
177 // This stub is paired with DirectCEntryStub::GenerateCall
Generate(MacroAssembler * masm)178 void DirectCEntryStub::Generate(MacroAssembler* masm) {
179   // Place the return address on the stack, making the call
180   // GC safe. The RegExp backend also relies on this.
181   __ mflr(r0);
182   __ StoreP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize));
183   __ Call(ip);  // Call the C++ function.
184   __ LoadP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize));
185   __ mtlr(r0);
186   __ blr();
187 }
188 
189 
GenerateCall(MacroAssembler * masm,Register target)190 void DirectCEntryStub::GenerateCall(MacroAssembler* masm, Register target) {
191   if (FLAG_embedded_builtins) {
192     if (masm->root_array_available() &&
193         isolate()->ShouldLoadConstantsFromRootList()) {
194       // This is basically an inlined version of Call(Handle<Code>) that loads
195       // the code object into lr instead of ip.
196       DCHECK_NE(ip, target);
197       __ IndirectLoadConstant(ip, GetCode());
198       __ addi(r0, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
199       __ Move(ip, target);
200       __ Call(r0);
201       return;
202     }
203   }
204   if (ABI_USES_FUNCTION_DESCRIPTORS) {
205     // AIX/PPC64BE Linux use a function descriptor.
206     __ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(target, kPointerSize));
207     __ LoadP(ip, MemOperand(target, 0));  // Instruction address
208   } else {
209     // ip needs to be set for DirectCEentryStub::Generate, and also
210     // for ABI_CALL_VIA_IP.
211     __ Move(ip, target);
212   }
213 
214   intptr_t code = reinterpret_cast<intptr_t>(GetCode().location());
215   __ mov(r0, Operand(code, RelocInfo::CODE_TARGET));
216   __ Call(r0);  // Call the stub.
217 }
218 
219 
MaybeCallEntryHookDelayed(TurboAssembler * tasm,Zone * zone)220 void ProfileEntryHookStub::MaybeCallEntryHookDelayed(TurboAssembler* tasm,
221                                                      Zone* zone) {
222   if (tasm->isolate()->function_entry_hook() != nullptr) {
223     PredictableCodeSizeScope predictable(tasm,
224 #if V8_TARGET_ARCH_PPC64
225                                          14 * kInstrSize);
226 #else
227                                          11 * kInstrSize);
228 #endif
229     tasm->mflr(r0);
230     tasm->Push(r0, ip);
231     tasm->CallStubDelayed(new (zone) ProfileEntryHookStub(nullptr));
232     tasm->Pop(r0, ip);
233     tasm->mtlr(r0);
234   }
235 }
236 
MaybeCallEntryHook(MacroAssembler * masm)237 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
238   if (masm->isolate()->function_entry_hook() != nullptr) {
239     PredictableCodeSizeScope predictable(masm,
240 #if V8_TARGET_ARCH_PPC64
241                                          14 * kInstrSize);
242 #else
243                                          11 * kInstrSize);
244 #endif
245     ProfileEntryHookStub stub(masm->isolate());
246     __ mflr(r0);
247     __ Push(r0, ip);
248     __ CallStub(&stub);
249     __ Pop(r0, ip);
250     __ mtlr(r0);
251   }
252 }
253 
254 
Generate(MacroAssembler * masm)255 void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
256   // The entry hook is a "push lr, ip" instruction, followed by a call.
257   const int32_t kReturnAddressDistanceFromFunctionStart =
258       Assembler::kCallTargetAddressOffset + 3 * kInstrSize;
259 
260   // This should contain all kJSCallerSaved registers.
261   const RegList kSavedRegs = kJSCallerSaved |  // Caller saved registers.
262                              r15.bit();        // Saved stack pointer.
263 
264   // We also save lr, so the count here is one higher than the mask indicates.
265   const int32_t kNumSavedRegs = kNumJSCallerSaved + 2;
266 
267   // Save all caller-save registers as this may be called from anywhere.
268   __ mflr(ip);
269   __ MultiPush(kSavedRegs | ip.bit());
270 
271   // Compute the function's address for the first argument.
272   __ subi(r3, ip, Operand(kReturnAddressDistanceFromFunctionStart));
273 
274   // The caller's return address is two slots above the saved temporaries.
275   // Grab that for the second argument to the hook.
276   __ addi(r4, sp, Operand((kNumSavedRegs + 1) * kPointerSize));
277 
278   // Align the stack if necessary.
279   int frame_alignment = masm->ActivationFrameAlignment();
280   if (frame_alignment > kPointerSize) {
281     __ mr(r15, sp);
282     DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
283     __ ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
284   }
285 
286 #if !defined(USE_SIMULATOR)
287   uintptr_t entry_hook =
288       reinterpret_cast<uintptr_t>(isolate()->function_entry_hook());
289 #else
290   // Under the simulator we need to indirect the entry hook through a
291   // trampoline function at a known address.
292   ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline));
293   ExternalReference entry_hook =
294       ExternalReference::Create(&dispatcher, ExternalReference::BUILTIN_CALL);
295 
296   // It additionally takes an isolate as a third parameter
297   __ mov(r5, Operand(ExternalReference::isolate_address(isolate())));
298 #endif
299 
300   __ mov(ip, Operand(entry_hook));
301 
302   if (ABI_USES_FUNCTION_DESCRIPTORS) {
303     __ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(ip, kPointerSize));
304     __ LoadP(ip, MemOperand(ip, 0));
305   }
306   // ip set above, so nothing more to do for ABI_CALL_VIA_IP.
307 
308   // PPC LINUX ABI:
309   __ li(r0, Operand::Zero());
310   __ StorePU(r0, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize));
311 
312   __ Call(ip);
313 
314   __ addi(sp, sp, Operand(kNumRequiredStackFrameSlots * kPointerSize));
315 
316   // Restore the stack pointer if needed.
317   if (frame_alignment > kPointerSize) {
318     __ mr(sp, r15);
319   }
320 
321   // Also pop lr to get Ret(0).
322   __ MultiPop(kSavedRegs | ip.bit());
323   __ mtlr(ip);
324   __ Ret();
325 }
326 
AddressOffset(ExternalReference ref0,ExternalReference ref1)327 static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
328   return ref0.address() - ref1.address();
329 }
330 
331 
332 // Calls an API function.  Allocates HandleScope, extracts returned value
333 // from handle and propagates exceptions.  Restores context.  stack_space
334 // - space to be unwound on exit (includes the call JS arguments space and
335 // the additional space allocated for the fast call).
CallApiFunctionAndReturn(MacroAssembler * masm,Register function_address,ExternalReference thunk_ref,int stack_space,MemOperand * stack_space_operand,MemOperand return_value_operand)336 static void CallApiFunctionAndReturn(MacroAssembler* masm,
337                                      Register function_address,
338                                      ExternalReference thunk_ref,
339                                      int stack_space,
340                                      MemOperand* stack_space_operand,
341                                      MemOperand return_value_operand) {
342   Isolate* isolate = masm->isolate();
343   ExternalReference next_address =
344       ExternalReference::handle_scope_next_address(isolate);
345   const int kNextOffset = 0;
346   const int kLimitOffset = AddressOffset(
347       ExternalReference::handle_scope_limit_address(isolate), next_address);
348   const int kLevelOffset = AddressOffset(
349       ExternalReference::handle_scope_level_address(isolate), next_address);
350 
351   // Additional parameter is the address of the actual callback.
352   DCHECK(function_address == r4 || function_address == r5);
353   Register scratch = r6;
354 
355   __ Move(scratch, ExternalReference::is_profiling_address(isolate));
356   __ lbz(scratch, MemOperand(scratch, 0));
357   __ cmpi(scratch, Operand::Zero());
358 
359   if (CpuFeatures::IsSupported(ISELECT)) {
360     __ Move(scratch, thunk_ref);
361     __ isel(eq, scratch, function_address, scratch);
362   } else {
363     Label profiler_disabled;
364     Label end_profiler_check;
365     __ beq(&profiler_disabled);
366     __ Move(scratch, thunk_ref);
367     __ b(&end_profiler_check);
368     __ bind(&profiler_disabled);
369     __ mr(scratch, function_address);
370     __ bind(&end_profiler_check);
371   }
372 
373   // Allocate HandleScope in callee-save registers.
374   // r17 - next_address
375   // r14 - next_address->kNextOffset
376   // r15 - next_address->kLimitOffset
377   // r16 - next_address->kLevelOffset
378   __ Move(r17, next_address);
379   __ LoadP(r14, MemOperand(r17, kNextOffset));
380   __ LoadP(r15, MemOperand(r17, kLimitOffset));
381   __ lwz(r16, MemOperand(r17, kLevelOffset));
382   __ addi(r16, r16, Operand(1));
383   __ stw(r16, MemOperand(r17, kLevelOffset));
384 
385   if (FLAG_log_timer_events) {
386     FrameScope frame(masm, StackFrame::MANUAL);
387     __ PushSafepointRegisters();
388     __ PrepareCallCFunction(1, r3);
389     __ Move(r3, ExternalReference::isolate_address(isolate));
390     __ CallCFunction(ExternalReference::log_enter_external_function(), 1);
391     __ PopSafepointRegisters();
392   }
393 
394   // Native call returns to the DirectCEntry stub which redirects to the
395   // return address pushed on stack (could have moved after GC).
396   // DirectCEntry stub itself is generated early and never moves.
397   DirectCEntryStub stub(isolate);
398   stub.GenerateCall(masm, scratch);
399 
400   if (FLAG_log_timer_events) {
401     FrameScope frame(masm, StackFrame::MANUAL);
402     __ PushSafepointRegisters();
403     __ PrepareCallCFunction(1, r3);
404     __ Move(r3, ExternalReference::isolate_address(isolate));
405     __ CallCFunction(ExternalReference::log_leave_external_function(), 1);
406     __ PopSafepointRegisters();
407   }
408 
409   Label promote_scheduled_exception;
410   Label delete_allocated_handles;
411   Label leave_exit_frame;
412   Label return_value_loaded;
413 
414   // load value from ReturnValue
415   __ LoadP(r3, return_value_operand);
416   __ bind(&return_value_loaded);
417   // No more valid handles (the result handle was the last one). Restore
418   // previous handle scope.
419   __ StoreP(r14, MemOperand(r17, kNextOffset));
420   if (__ emit_debug_code()) {
421     __ lwz(r4, MemOperand(r17, kLevelOffset));
422     __ cmp(r4, r16);
423     __ Check(eq, AbortReason::kUnexpectedLevelAfterReturnFromApiCall);
424   }
425   __ subi(r16, r16, Operand(1));
426   __ stw(r16, MemOperand(r17, kLevelOffset));
427   __ LoadP(r0, MemOperand(r17, kLimitOffset));
428   __ cmp(r15, r0);
429   __ bne(&delete_allocated_handles);
430 
431   // Leave the API exit frame.
432   __ bind(&leave_exit_frame);
433   // LeaveExitFrame expects unwind space to be in a register.
434   if (stack_space_operand != nullptr) {
435     __ lwz(r14, *stack_space_operand);
436   } else {
437     __ mov(r14, Operand(stack_space));
438   }
439   __ LeaveExitFrame(false, r14, stack_space_operand != nullptr);
440 
441   // Check if the function scheduled an exception.
442   __ LoadRoot(r14, Heap::kTheHoleValueRootIndex);
443   __ Move(r15, ExternalReference::scheduled_exception_address(isolate));
444   __ LoadP(r15, MemOperand(r15));
445   __ cmp(r14, r15);
446   __ bne(&promote_scheduled_exception);
447 
448   __ blr();
449 
450   // Re-throw by promoting a scheduled exception.
451   __ bind(&promote_scheduled_exception);
452   __ TailCallRuntime(Runtime::kPromoteScheduledException);
453 
454   // HandleScope limit has changed. Delete allocated extensions.
455   __ bind(&delete_allocated_handles);
456   __ StoreP(r15, MemOperand(r17, kLimitOffset));
457   __ mr(r14, r3);
458   __ PrepareCallCFunction(1, r15);
459   __ Move(r3, ExternalReference::isolate_address(isolate));
460   __ CallCFunction(ExternalReference::delete_handle_scope_extensions(), 1);
461   __ mr(r3, r14);
462   __ b(&leave_exit_frame);
463 }
464 
Generate(MacroAssembler * masm)465 void CallApiCallbackStub::Generate(MacroAssembler* masm) {
466   // ----------- S t a t e -------------
467   //  -- r7                  : call_data
468   //  -- r5                  : holder
469   //  -- r4                  : api_function_address
470   //  -- cp                  : context
471   //  --
472   //  -- sp[0]               : last argument
473   //  -- ...
474   //  -- sp[(argc - 1)* 4]   : first argument
475   //  -- sp[argc * 4]        : receiver
476   // -----------------------------------
477 
478   Register call_data = r7;
479   Register holder = r5;
480   Register api_function_address = r4;
481 
482   typedef FunctionCallbackArguments FCA;
483 
484   STATIC_ASSERT(FCA::kArgsLength == 6);
485   STATIC_ASSERT(FCA::kNewTargetIndex == 5);
486   STATIC_ASSERT(FCA::kDataIndex == 4);
487   STATIC_ASSERT(FCA::kReturnValueOffset == 3);
488   STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
489   STATIC_ASSERT(FCA::kIsolateIndex == 1);
490   STATIC_ASSERT(FCA::kHolderIndex == 0);
491 
492   // new target
493   __ PushRoot(Heap::kUndefinedValueRootIndex);
494 
495   // call data
496   __ push(call_data);
497 
498   Register scratch = call_data;
499   __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
500   // return value
501   __ push(scratch);
502   // return value default
503   __ push(scratch);
504   // isolate
505   __ Move(scratch, ExternalReference::isolate_address(masm->isolate()));
506   __ push(scratch);
507   // holder
508   __ push(holder);
509 
510   // Prepare arguments.
511   __ mr(scratch, sp);
512 
513   // Allocate the v8::Arguments structure in the arguments' space since
514   // it's not controlled by GC.
515   // PPC LINUX ABI:
516   //
517   // Create 4 extra slots on stack:
518   //    [0] space for DirectCEntryStub's LR save
519   //    [1-3] FunctionCallbackInfo
520   const int kApiStackSpace = 4;
521   const int kFunctionCallbackInfoOffset =
522       (kStackFrameExtraParamSlot + 1) * kPointerSize;
523 
524   FrameScope frame_scope(masm, StackFrame::MANUAL);
525   __ EnterExitFrame(false, kApiStackSpace);
526 
527   DCHECK(api_function_address != r3 && scratch != r3);
528   // r3 = FunctionCallbackInfo&
529   // Arguments is after the return address.
530   __ addi(r3, sp, Operand(kFunctionCallbackInfoOffset));
531   // FunctionCallbackInfo::implicit_args_
532   __ StoreP(scratch, MemOperand(r3, 0 * kPointerSize));
533   // FunctionCallbackInfo::values_
534   __ addi(ip, scratch, Operand((FCA::kArgsLength - 1 + argc()) * kPointerSize));
535   __ StoreP(ip, MemOperand(r3, 1 * kPointerSize));
536   // FunctionCallbackInfo::length_ = argc
537   __ li(ip, Operand(argc()));
538   __ stw(ip, MemOperand(r3, 2 * kPointerSize));
539 
540   ExternalReference thunk_ref = ExternalReference::invoke_function_callback();
541 
542   AllowExternalCallThatCantCauseGC scope(masm);
543   // Stores return the first js argument
544   int return_value_offset = 2 + FCA::kReturnValueOffset;
545   MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
546   const int stack_space = argc() + FCA::kArgsLength + 1;
547   MemOperand* stack_space_operand = nullptr;
548   CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, stack_space,
549                            stack_space_operand, return_value_operand);
550 }
551 
552 
Generate(MacroAssembler * masm)553 void CallApiGetterStub::Generate(MacroAssembler* masm) {
554   int arg0Slot = 0;
555   int accessorInfoSlot = 0;
556   int apiStackSpace = 0;
557   // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
558   // name below the exit frame to make GC aware of them.
559   STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
560   STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
561   STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
562   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
563   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
564   STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
565   STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
566   STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
567 
568   Register receiver = ApiGetterDescriptor::ReceiverRegister();
569   Register holder = ApiGetterDescriptor::HolderRegister();
570   Register callback = ApiGetterDescriptor::CallbackRegister();
571   Register scratch = r7;
572   DCHECK(!AreAliased(receiver, holder, callback, scratch));
573 
574   Register api_function_address = r5;
575 
576   __ push(receiver);
577   // Push data from AccessorInfo.
578   __ LoadP(scratch, FieldMemOperand(callback, AccessorInfo::kDataOffset));
579   __ push(scratch);
580   __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
581   __ Push(scratch, scratch);
582   __ Move(scratch, ExternalReference::isolate_address(isolate()));
583   __ Push(scratch, holder);
584   __ Push(Smi::kZero);  // should_throw_on_error -> false
585   __ LoadP(scratch, FieldMemOperand(callback, AccessorInfo::kNameOffset));
586   __ push(scratch);
587 
588   // v8::PropertyCallbackInfo::args_ array and name handle.
589   const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
590 
591   // Load address of v8::PropertyAccessorInfo::args_ array and name handle.
592   __ mr(r3, sp);                               // r3 = Handle<Name>
593   __ addi(r4, r3, Operand(1 * kPointerSize));  // r4 = v8::PCI::args_
594 
595 // If ABI passes Handles (pointer-sized struct) in a register:
596 //
597 // Create 2 extra slots on stack:
598 //    [0] space for DirectCEntryStub's LR save
599 //    [1] AccessorInfo&
600 //
601 // Otherwise:
602 //
603 // Create 3 extra slots on stack:
604 //    [0] space for DirectCEntryStub's LR save
605 //    [1] copy of Handle (first arg)
606 //    [2] AccessorInfo&
607   if (ABI_PASSES_HANDLES_IN_REGS) {
608     accessorInfoSlot = kStackFrameExtraParamSlot + 1;
609     apiStackSpace = 2;
610   } else {
611     arg0Slot = kStackFrameExtraParamSlot + 1;
612     accessorInfoSlot = arg0Slot + 1;
613     apiStackSpace = 3;
614   }
615 
616   FrameScope frame_scope(masm, StackFrame::MANUAL);
617   __ EnterExitFrame(false, apiStackSpace);
618 
619   if (!ABI_PASSES_HANDLES_IN_REGS) {
620     // pass 1st arg by reference
621     __ StoreP(r3, MemOperand(sp, arg0Slot * kPointerSize));
622     __ addi(r3, sp, Operand(arg0Slot * kPointerSize));
623   }
624 
625   // Create v8::PropertyCallbackInfo object on the stack and initialize
626   // it's args_ field.
627   __ StoreP(r4, MemOperand(sp, accessorInfoSlot * kPointerSize));
628   __ addi(r4, sp, Operand(accessorInfoSlot * kPointerSize));
629   // r4 = v8::PropertyCallbackInfo&
630 
631   ExternalReference thunk_ref =
632       ExternalReference::invoke_accessor_getter_callback();
633 
634   __ LoadP(scratch, FieldMemOperand(callback, AccessorInfo::kJsGetterOffset));
635   __ LoadP(api_function_address,
636         FieldMemOperand(scratch, Foreign::kForeignAddressOffset));
637 
638   // +3 is to skip prolog, return address and name handle.
639   MemOperand return_value_operand(
640       fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
641   CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
642                            kStackUnwindSpace, nullptr, return_value_operand);
643 }
644 
645 #undef __
646 }  // namespace internal
647 }  // namespace v8
648 
649 #endif  // V8_TARGET_ARCH_PPC
650