blob: 65dc3806b6fd0fd7a1adeeff17ed41bdc7ac0412 [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
7#include "assembler.h"
8#include "object.h"
9
Carl Shapiro9b9ba282011-08-14 15:30:39 -070010namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -070011namespace arm {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070012
13// Creates a function which invokes a managed method with an array of
14// arguments.
15//
16// At the time of call, the environment looks something like this:
17//
18// R0 = method pointer
19// R1 = receiver pointer or NULL for static methods
20// R2 = (managed) thread pointer
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070021// R3 = argument array or NULL for no argument methods
22// [SP] = JValue* result or NULL for void returns
Carl Shapiro9b9ba282011-08-14 15:30:39 -070023//
24// As the JNI call has already transitioned the thread into the
25// "running" state the remaining responsibilities of this routine are
26// to save the native register value and restore the managed thread
27// register and transfer arguments from the array into register and on
28// the stack, if needed. On return, the thread register must be
29// shuffled and the return value must be store into the result JValue.
Ian Rogers2c8f6532011-09-02 17:16:34 -070030void ArmCreateInvokeStub(Method* method) {
31 UniquePtr<ArmAssembler> assembler(
32 down_cast<ArmAssembler*>(Assembler::Create(kArm)));
33#define __ assembler->
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070034 // Size of frame - spill of R9/LR + Method* + possible receiver + arg array
35 size_t unpadded_frame_size = (3 * kPointerSize) +
36 (method->IsStatic() ? 0 : kPointerSize) +
37 method->NumArgArrayBytes();
38 size_t frame_size = RoundUp(unpadded_frame_size, kStackAlignment);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070039
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070040 // Spill R9 and LR
Carl Shapiro9b9ba282011-08-14 15:30:39 -070041 RegList save = (1 << R9);
42 __ PushList(save | (1 << LR));
43
Carl Shapiro9b9ba282011-08-14 15:30:39 -070044 // Move the managed thread pointer into R9.
45 __ mov(R9, ShifterOperand(R2));
46
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070047 // Move frame down for arguments less 2 pushed values above
48 __ AddConstant(SP, -frame_size + (2 * kPointerSize));
49
50 // Can either get 3 or 2 arguments into registers
51 size_t reg_bytes = (method->IsStatic() ? 3 : 2) * kPointerSize;
52 // Bytes passed by stack
53 size_t stack_bytes;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070054 if (method->NumArgArrayBytes() > reg_bytes) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070055 stack_bytes = method->NumArgArrayBytes() - reg_bytes;
56 } else {
57 stack_bytes = 0;
58 reg_bytes = method->NumArgArrayBytes();
59 }
60
Ian Rogersed8952f2011-08-19 17:11:22 -070061 // Method* at bottom of frame is null thereby terminating managed stack crawls
62 __ LoadImmediate(IP, 0, AL);
63 __ StoreToOffset(kStoreWord, IP, SP, 0);
64
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070065 // Copy values by stack
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070066 for (size_t off = 0; off < stack_bytes; off += kPointerSize) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070067 // we're displaced off of r3 by bytes that'll go in registers
68 int r3_offset = reg_bytes + off;
69 __ LoadFromOffset(kLoadWord, IP, R3, r3_offset);
70
71 // we're displaced off of the arguments by the spill space for the incoming
Shih-wei Liao7d2b1412011-09-05 19:29:47 -070072 // arguments, the Method* and possibly the receiver
73 int sp_offset = reg_bytes + (method->IsStatic() ? 1 : 2) * kPointerSize + off;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070074 __ StoreToOffset(kStoreWord, IP, SP, sp_offset);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070075 }
76
77 // Move all the register arguments into place.
78 if (method->IsStatic()) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070079 if (reg_bytes > 0) {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070080 __ LoadFromOffset(kLoadWord, R1, R3, 0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070081 if (reg_bytes > 4) {
82 __ LoadFromOffset(kLoadWord, R2, R3, 4);
83 if (reg_bytes > 8) {
84 __ LoadFromOffset(kLoadWord, R3, R3, 8);
85 }
86 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -070087 }
88 } else {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070089 if (reg_bytes > 0) {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070090 __ LoadFromOffset(kLoadWord, R2, R3, 0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070091 if (reg_bytes > 4) {
92 __ LoadFromOffset(kLoadWord, R3, R3, 4);
93 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -070094 }
95 }
96
Carl Shapiro9b9ba282011-08-14 15:30:39 -070097 // Load the code pointer we are about to call.
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070098 __ LoadFromOffset(kLoadWord, IP, R0, method->GetCodeOffset().Int32Value());
Carl Shapiro9b9ba282011-08-14 15:30:39 -070099
100 // Do the call.
101 __ blx(IP);
102
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700103 // If the method returns a value, store it to the result pointer.
Brian Carlstrom2ed67392011-09-09 14:53:28 -0700104 char ch = method->GetShorty()->CharAt(0);
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700105 if (ch != 'V') {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700106 // Load the result JValue pointer of the stub caller's out args.
107 __ LoadFromOffset(kLoadWord, IP, SP, frame_size);
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700108 if (ch == 'D' || ch == 'J') {
109 __ StoreToOffset(kStoreWordPair, R0, IP, 0);
110 } else {
111 __ StoreToOffset(kStoreWord, R0, IP, 0);
112 }
113 }
114
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700115 // Remove the frame less the spilled R9 and LR
116 __ AddConstant(SP, frame_size - (2 * kPointerSize));
117
118 // Pop 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
121 ByteArray* code = ByteArray::Alloc(assembler->CodeSize());
122 MemoryRegion region(code->GetData(), code->GetLength());
123 assembler->FinalizeInstructions(region);
124 method->SetInvokeStub(code);
125 CHECK(method->GetInvokeStub() != NULL);
126#undef __
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700127}
128
Ian Rogers2c8f6532011-09-02 17:16:34 -0700129} // namespace arm
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700130} // namespace art