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