blob: dadf7b42200b0e4cc7490650a9de01d2ff0b4e0a [file] [log] [blame]
Carl Shapiro9b9ba282011-08-14 15:30:39 -07001// Copyright 2011 Google Inc. All Rights Reserved.
Carl Shapiro9b9ba282011-08-14 15:30:39 -07002
3#include "jni_internal.h"
4
5#include <algorithm>
6
Ian Rogers4a510d82011-10-09 14:30:24 -07007#include "asm_support.h"
Carl Shapiro9b9ba282011-08-14 15:30:39 -07008#include "assembler.h"
Brian Carlstrom3320cf42011-10-04 14:58:28 -07009#include "compiled_method.h"
Carl Shapiro9b9ba282011-08-14 15:30:39 -070010#include "object.h"
11
Carl Shapiro9b9ba282011-08-14 15:30:39 -070012namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -070013namespace arm {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070014
15// Creates a function which invokes a managed method with an array of
16// arguments.
17//
18// At the time of call, the environment looks something like this:
19//
20// R0 = method pointer
21// R1 = receiver pointer or NULL for static methods
22// R2 = (managed) thread pointer
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070023// R3 = argument array or NULL for no argument methods
24// [SP] = JValue* result or NULL for void returns
Carl Shapiro9b9ba282011-08-14 15:30:39 -070025//
26// As the JNI call has already transitioned the thread into the
27// "running" state the remaining responsibilities of this routine are
28// to save the native register value and restore the managed thread
29// register and transfer arguments from the array into register and on
30// the stack, if needed. On return, the thread register must be
31// shuffled and the return value must be store into the result JValue.
Ian Rogers0571d352011-11-03 19:51:38 -070032CompiledInvokeStub* ArmCreateInvokeStub(bool is_static, const char* shorty) {
Ian Rogers2c8f6532011-09-02 17:16:34 -070033 UniquePtr<ArmAssembler> assembler(
34 down_cast<ArmAssembler*>(Assembler::Create(kArm)));
35#define __ assembler->
Ian Rogers0571d352011-11-03 19:51:38 -070036 size_t num_arg_array_bytes = NumArgArrayBytes(shorty);
buzbeec1f45042011-09-21 16:03:19 -070037 // Size of frame - spill of R4,R9/LR + Method* + possible receiver + arg array
38 size_t unpadded_frame_size = (4 * kPointerSize) +
Ian Rogers0571d352011-11-03 19:51:38 -070039 (is_static ? 0 : kPointerSize) +
40 num_arg_array_bytes;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070041 size_t frame_size = RoundUp(unpadded_frame_size, kStackAlignment);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070042
buzbeec1f45042011-09-21 16:03:19 -070043 // Spill R4,R9 and LR
44 RegList save = (1 << R9) | (1 << R4);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070045 __ PushList(save | (1 << LR));
46
Carl Shapiro9b9ba282011-08-14 15:30:39 -070047 // Move the managed thread pointer into R9.
48 __ mov(R9, ShifterOperand(R2));
49
Ian Rogersae675992011-10-09 17:10:22 -070050 // Reset R4 to suspend check interval
Ian Rogers4a510d82011-10-09 14:30:24 -070051 __ LoadImmediate(R4, SUSPEND_CHECK_INTERVAL);
52
buzbeec1f45042011-09-21 16:03:19 -070053 // Move frame down for arguments less 3 pushed values above
54 __ AddConstant(SP, -frame_size + (3 * kPointerSize));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070055
56 // Can either get 3 or 2 arguments into registers
Ian Rogers0571d352011-11-03 19:51:38 -070057 size_t reg_bytes = (is_static ? 3 : 2) * kPointerSize;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070058 // Bytes passed by stack
59 size_t stack_bytes;
Ian Rogers0571d352011-11-03 19:51:38 -070060 if (num_arg_array_bytes > reg_bytes) {
61 stack_bytes = num_arg_array_bytes - reg_bytes;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070062 } else {
63 stack_bytes = 0;
Ian Rogers0571d352011-11-03 19:51:38 -070064 reg_bytes = num_arg_array_bytes;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070065 }
66
Ian Rogersed8952f2011-08-19 17:11:22 -070067 // Method* at bottom of frame is null thereby terminating managed stack crawls
68 __ LoadImmediate(IP, 0, AL);
69 __ StoreToOffset(kStoreWord, IP, SP, 0);
70
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070071 // Copy values by stack
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070072 for (size_t off = 0; off < stack_bytes; off += kPointerSize) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070073 // we're displaced off of r3 by bytes that'll go in registers
74 int r3_offset = reg_bytes + off;
75 __ LoadFromOffset(kLoadWord, IP, R3, r3_offset);
76
77 // we're displaced off of the arguments by the spill space for the incoming
Shih-wei Liao7d2b1412011-09-05 19:29:47 -070078 // arguments, the Method* and possibly the receiver
Ian Rogers0571d352011-11-03 19:51:38 -070079 int sp_offset = reg_bytes + (is_static ? 1 : 2) * kPointerSize + off;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070080 __ StoreToOffset(kStoreWord, IP, SP, sp_offset);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070081 }
82
83 // Move all the register arguments into place.
Ian Rogers0571d352011-11-03 19:51:38 -070084 if (is_static) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070085 if (reg_bytes > 0) {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070086 __ LoadFromOffset(kLoadWord, R1, R3, 0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070087 if (reg_bytes > 4) {
88 __ LoadFromOffset(kLoadWord, R2, R3, 4);
89 if (reg_bytes > 8) {
90 __ LoadFromOffset(kLoadWord, R3, R3, 8);
91 }
92 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -070093 }
94 } else {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070095 if (reg_bytes > 0) {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070096 __ LoadFromOffset(kLoadWord, R2, R3, 0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070097 if (reg_bytes > 4) {
98 __ LoadFromOffset(kLoadWord, R3, R3, 4);
99 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700100 }
101 }
102
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700103 // Load the code pointer we are about to call.
Ian Rogers0571d352011-11-03 19:51:38 -0700104 __ LoadFromOffset(kLoadWord, IP, R0, Method::GetCodeOffset().Int32Value());
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700105
106 // Do the call.
107 __ blx(IP);
108
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700109 // If the method returns a value, store it to the result pointer.
Ian Rogers0571d352011-11-03 19:51:38 -0700110 if (shorty[0] != 'V') {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700111 // Load the result JValue pointer of the stub caller's out args.
112 __ LoadFromOffset(kLoadWord, IP, SP, frame_size);
Ian Rogers0571d352011-11-03 19:51:38 -0700113 StoreOperandType type = (shorty[0] == 'J' || shorty[0] == 'D') ? kStoreWordPair : kStoreWord;
114 __ StoreToOffset(type, R0, IP, 0);
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700115 }
116
buzbeec1f45042011-09-21 16:03:19 -0700117 // Remove the frame less the spilled R4, R9 and LR
118 __ AddConstant(SP, frame_size - (3 * kPointerSize));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700119
buzbeec1f45042011-09-21 16:03:19 -0700120 // Pop R4, R9 and the LR into PC
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700121 __ PopList(save | (1 << PC));
Ian Rogers2c8f6532011-09-02 17:16:34 -0700122 // TODO: store native_entry in the stub table
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700123 std::vector<uint8_t> code(assembler->CodeSize());
124 MemoryRegion region(&code[0], code.size());
Ian Rogers2c8f6532011-09-02 17:16:34 -0700125 assembler->FinalizeInstructions(region);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700126 return new CompiledInvokeStub(code);
Ian Rogers2c8f6532011-09-02 17:16:34 -0700127#undef __
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700128}
129
Ian Rogers2c8f6532011-09-02 17:16:34 -0700130} // namespace arm
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700131} // namespace art