blob: f1ed092d1bbb0822f38e85fa2388278ddf5563dc [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.
Brian Carlstrom3320cf42011-10-04 14:58:28 -070032CompiledInvokeStub* ArmCreateInvokeStub(const Method* method) {
Ian Rogers2c8f6532011-09-02 17:16:34 -070033 UniquePtr<ArmAssembler> assembler(
34 down_cast<ArmAssembler*>(Assembler::Create(kArm)));
35#define __ assembler->
buzbeec1f45042011-09-21 16:03:19 -070036 // Size of frame - spill of R4,R9/LR + Method* + possible receiver + arg array
37 size_t unpadded_frame_size = (4 * kPointerSize) +
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070038 (method->IsStatic() ? 0 : kPointerSize) +
39 method->NumArgArrayBytes();
40 size_t frame_size = RoundUp(unpadded_frame_size, kStackAlignment);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070041
buzbeec1f45042011-09-21 16:03:19 -070042 // Spill R4,R9 and LR
43 RegList save = (1 << R9) | (1 << R4);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070044 __ PushList(save | (1 << LR));
45
Carl Shapiro9b9ba282011-08-14 15:30:39 -070046 // Move the managed thread pointer into R9.
47 __ mov(R9, ShifterOperand(R2));
48
Ian Rogersae675992011-10-09 17:10:22 -070049 // Reset R4 to suspend check interval
Ian Rogers4a510d82011-10-09 14:30:24 -070050 __ LoadImmediate(R4, SUSPEND_CHECK_INTERVAL);
51
buzbeec1f45042011-09-21 16:03:19 -070052 // Move frame down for arguments less 3 pushed values above
53 __ AddConstant(SP, -frame_size + (3 * kPointerSize));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070054
55 // Can either get 3 or 2 arguments into registers
56 size_t reg_bytes = (method->IsStatic() ? 3 : 2) * kPointerSize;
57 // Bytes passed by stack
58 size_t stack_bytes;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070059 if (method->NumArgArrayBytes() > reg_bytes) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070060 stack_bytes = method->NumArgArrayBytes() - reg_bytes;
61 } else {
62 stack_bytes = 0;
63 reg_bytes = method->NumArgArrayBytes();
64 }
65
Ian Rogersed8952f2011-08-19 17:11:22 -070066 // Method* at bottom of frame is null thereby terminating managed stack crawls
67 __ LoadImmediate(IP, 0, AL);
68 __ StoreToOffset(kStoreWord, IP, SP, 0);
69
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070070 // Copy values by stack
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070071 for (size_t off = 0; off < stack_bytes; off += kPointerSize) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070072 // we're displaced off of r3 by bytes that'll go in registers
73 int r3_offset = reg_bytes + off;
74 __ LoadFromOffset(kLoadWord, IP, R3, r3_offset);
75
76 // we're displaced off of the arguments by the spill space for the incoming
Shih-wei Liao7d2b1412011-09-05 19:29:47 -070077 // arguments, the Method* and possibly the receiver
78 int sp_offset = reg_bytes + (method->IsStatic() ? 1 : 2) * kPointerSize + off;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070079 __ StoreToOffset(kStoreWord, IP, SP, sp_offset);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070080 }
81
82 // Move all the register arguments into place.
83 if (method->IsStatic()) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070084 if (reg_bytes > 0) {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070085 __ LoadFromOffset(kLoadWord, R1, R3, 0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070086 if (reg_bytes > 4) {
87 __ LoadFromOffset(kLoadWord, R2, R3, 4);
88 if (reg_bytes > 8) {
89 __ LoadFromOffset(kLoadWord, R3, R3, 8);
90 }
91 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -070092 }
93 } else {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070094 if (reg_bytes > 0) {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070095 __ LoadFromOffset(kLoadWord, R2, R3, 0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070096 if (reg_bytes > 4) {
97 __ LoadFromOffset(kLoadWord, R3, R3, 4);
98 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -070099 }
100 }
101
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700102 // Load the code pointer we are about to call.
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700103 __ LoadFromOffset(kLoadWord, IP, R0, method->GetCodeOffset().Int32Value());
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700104
105 // Do the call.
106 __ blx(IP);
107
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700108 // If the method returns a value, store it to the result pointer.
Ian Rogersae675992011-10-09 17:10:22 -0700109 if (!method->IsReturnVoid()) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700110 // Load the result JValue pointer of the stub caller's out args.
111 __ LoadFromOffset(kLoadWord, IP, SP, frame_size);
Ian Rogersae675992011-10-09 17:10:22 -0700112 __ StoreToOffset(method->IsReturnALongOrDouble() ? kStoreWordPair : kStoreWord, R0, IP, 0);
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700113 }
114
buzbeec1f45042011-09-21 16:03:19 -0700115 // Remove the frame less the spilled R4, R9 and LR
116 __ AddConstant(SP, frame_size - (3 * kPointerSize));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700117
buzbeec1f45042011-09-21 16:03:19 -0700118 // Pop R4, R9 and the LR into PC
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700119 __ PopList(save | (1 << PC));
Ian Rogers2c8f6532011-09-02 17:16:34 -0700120 // TODO: store native_entry in the stub table
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700121 std::vector<uint8_t> code(assembler->CodeSize());
122 MemoryRegion region(&code[0], code.size());
Ian Rogers2c8f6532011-09-02 17:16:34 -0700123 assembler->FinalizeInstructions(region);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700124 return new CompiledInvokeStub(code);
Ian Rogers2c8f6532011-09-02 17:16:34 -0700125#undef __
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700126}
127
Ian Rogers2c8f6532011-09-02 17:16:34 -0700128} // namespace arm
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700129} // namespace art