portable_trampoline_entrypoints.cc revision bd136a29f08486525d6abc7d0a0006ce5b4011c1
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_
18#define ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_
19
20#include "dex_instruction-inl.h"
21#include "entrypoints/entrypoint_utils.h"
22#include "interpreter/interpreter.h"
23#include "mirror/art_method-inl.h"
24#include "mirror/object-inl.h"
25#include "object_utils.h"
26#include "scoped_thread_state_change.h"
27
28namespace art {
29
30// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame.
31class PortableArgumentVisitor {
32 public:
33// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame.
34// Size of Runtime::kRefAndArgs callee save frame.
35// Size of Method* and register parameters in out stack arguments.
36#if defined(__arm__)
37#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8
38#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
39#define PORTABLE_STACK_ARG_SKIP 0
40#elif defined(__mips__)
41#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
42#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64
43#define PORTABLE_STACK_ARG_SKIP 16
44#elif defined(__i386__)
45// For x86 there are no register arguments and the stack pointer will point directly to the called
46// method argument passed by the caller.
47#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0
48#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0
49#define PORTABLE_STACK_ARG_SKIP 4
50#else
51#error "Unsupported architecture"
52#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0
53#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0
54#define PORTABLE_STACK_ARG_SKIP 0
55#endif
56
57  PortableArgumentVisitor(MethodHelper& caller_mh, mirror::ArtMethod** sp)
58    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
59    caller_mh_(caller_mh),
60    args_in_regs_(ComputeArgsInRegs(caller_mh)),
61    num_params_(caller_mh.NumArgs()),
62    reg_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET),
63    stack_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE
64                + PORTABLE_STACK_ARG_SKIP),
65    cur_args_(reg_args_),
66    cur_arg_index_(0),
67    param_index_(0) {
68  }
69
70  virtual ~PortableArgumentVisitor() {}
71
72  virtual void Visit() = 0;
73
74  bool IsParamAReference() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
75    return caller_mh_.IsParamAReference(param_index_);
76  }
77
78  bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
79    return caller_mh_.IsParamALongOrDouble(param_index_);
80  }
81
82  Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
83    return caller_mh_.GetParamPrimitiveType(param_index_);
84  }
85
86  byte* GetParamAddress() const {
87    return cur_args_ + (cur_arg_index_ * kPointerSize);
88  }
89
90  void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
91    for (cur_arg_index_ = 0;  cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) {
92#if (defined(__arm__) || defined(__mips__))
93      if (IsParamALongOrDouble() && cur_arg_index_ == 2) {
94        break;
95      }
96#endif
97      Visit();
98      cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
99      param_index_++;
100    }
101    cur_args_ = stack_args_;
102    cur_arg_index_ = 0;
103    while (param_index_ < num_params_) {
104#if (defined(__arm__) || defined(__mips__))
105      if (IsParamALongOrDouble() && cur_arg_index_ % 2 != 0) {
106        cur_arg_index_++;
107      }
108#endif
109      Visit();
110      cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
111      param_index_++;
112    }
113  }
114
115 private:
116  static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
117#if (defined(__i386__))
118    return 0;
119#else
120    size_t args_in_regs = 0;
121    size_t num_params = mh.NumArgs();
122    for (size_t i = 0; i < num_params; i++) {
123      args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1);
124      if (args_in_regs > 3) {
125        args_in_regs = 3;
126        break;
127      }
128    }
129    return args_in_regs;
130#endif
131  }
132  MethodHelper& caller_mh_;
133  const size_t args_in_regs_;
134  const size_t num_params_;
135  byte* const reg_args_;
136  byte* const stack_args_;
137  byte* cur_args_;
138  size_t cur_arg_index_;
139  size_t param_index_;
140};
141
142// Visits arguments on the stack placing them into the shadow frame.
143class BuildPortableShadowFrameVisitor : public PortableArgumentVisitor {
144 public:
145  BuildPortableShadowFrameVisitor(MethodHelper& caller_mh, mirror::ArtMethod** sp,
146      ShadowFrame& sf, size_t first_arg_reg) :
147    PortableArgumentVisitor(caller_mh, sp), sf_(sf), cur_reg_(first_arg_reg) { }
148  virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
149    Primitive::Type type = GetParamPrimitiveType();
150    switch (type) {
151      case Primitive::kPrimLong:  // Fall-through.
152      case Primitive::kPrimDouble:
153        sf_.SetVRegLong(cur_reg_, *reinterpret_cast<jlong*>(GetParamAddress()));
154        ++cur_reg_;
155        break;
156      case Primitive::kPrimNot:
157        sf_.SetVRegReference(cur_reg_, *reinterpret_cast<mirror::Object**>(GetParamAddress()));
158        break;
159      case Primitive::kPrimBoolean:  // Fall-through.
160      case Primitive::kPrimByte:     // Fall-through.
161      case Primitive::kPrimChar:     // Fall-through.
162      case Primitive::kPrimShort:    // Fall-through.
163      case Primitive::kPrimInt:      // Fall-through.
164      case Primitive::kPrimFloat:
165        sf_.SetVReg(cur_reg_, *reinterpret_cast<jint*>(GetParamAddress()));
166        break;
167      case Primitive::kPrimVoid:
168        LOG(FATAL) << "UNREACHABLE";
169        break;
170    }
171    ++cur_reg_;
172  }
173
174 private:
175  ShadowFrame& sf_;
176  size_t cur_reg_;
177
178  DISALLOW_COPY_AND_ASSIGN(BuildPortableShadowFrameVisitor);
179};
180
181extern "C" uint64_t artPortableToInterpreterBridge(mirror::ArtMethod* method, Thread* self,
182                                                   mirror::ArtMethod** sp)
183    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
184  // Ensure we don't get thread suspension until the object arguments are safely in the shadow
185  // frame.
186  // FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
187
188  if (method->IsAbstract()) {
189    ThrowAbstractMethodError(method);
190    return 0;
191  } else {
192    const char* old_cause = self->StartAssertNoThreadSuspension("Building interpreter shadow frame");
193    MethodHelper mh(method);
194    const DexFile::CodeItem* code_item = mh.GetCodeItem();
195    uint16_t num_regs = code_item->registers_size_;
196    void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
197    ShadowFrame* shadow_frame(ShadowFrame::Create(num_regs, NULL,  // No last shadow coming from quick.
198                                                  method, 0, memory));
199    size_t first_arg_reg = code_item->registers_size_ - code_item->ins_size_;
200    BuildPortableShadowFrameVisitor shadow_frame_builder(mh, sp,
201                                                 *shadow_frame, first_arg_reg);
202    shadow_frame_builder.VisitArguments();
203    // Push a transition back into managed code onto the linked list in thread.
204    ManagedStack fragment;
205    self->PushManagedStackFragment(&fragment);
206    self->PushShadowFrame(shadow_frame);
207    self->EndAssertNoThreadSuspension(old_cause);
208
209    if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) {
210      // Ensure static method's class is initialized.
211      if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(method->GetDeclaringClass(),
212                                                                   true, true)) {
213        DCHECK(Thread::Current()->IsExceptionPending());
214        self->PopManagedStackFragment(fragment);
215        return 0;
216      }
217    }
218
219    JValue result = interpreter::EnterInterpreterFromStub(self, mh, code_item, *shadow_frame);
220    // Pop transition.
221    self->PopManagedStackFragment(fragment);
222    return result.GetJ();
223  }
224}
225
226// Visits arguments on the stack placing them into the args vector, Object* arguments are converted
227// to jobjects.
228class BuildPortableArgumentVisitor : public PortableArgumentVisitor {
229 public:
230  BuildPortableArgumentVisitor(MethodHelper& caller_mh, mirror::ArtMethod** sp,
231                               ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) :
232    PortableArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {}
233
234  virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
235    jvalue val;
236    Primitive::Type type = GetParamPrimitiveType();
237    switch (type) {
238      case Primitive::kPrimNot: {
239        mirror::Object* obj = *reinterpret_cast<mirror::Object**>(GetParamAddress());
240        val.l = soa_.AddLocalReference<jobject>(obj);
241        break;
242      }
243      case Primitive::kPrimLong:  // Fall-through.
244      case Primitive::kPrimDouble:
245        val.j = *reinterpret_cast<jlong*>(GetParamAddress());
246        break;
247      case Primitive::kPrimBoolean:  // Fall-through.
248      case Primitive::kPrimByte:     // Fall-through.
249      case Primitive::kPrimChar:     // Fall-through.
250      case Primitive::kPrimShort:    // Fall-through.
251      case Primitive::kPrimInt:      // Fall-through.
252      case Primitive::kPrimFloat:
253        val.i =  *reinterpret_cast<jint*>(GetParamAddress());
254        break;
255      case Primitive::kPrimVoid:
256        LOG(FATAL) << "UNREACHABLE";
257        val.j = 0;
258        break;
259    }
260    args_.push_back(val);
261  }
262
263 private:
264  ScopedObjectAccessUnchecked& soa_;
265  std::vector<jvalue>& args_;
266
267  DISALLOW_COPY_AND_ASSIGN(BuildPortableArgumentVisitor);
268};
269
270// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
271// which is responsible for recording callee save registers. We explicitly place into jobjects the
272// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a
273// field within the proxy object, which will box the primitive arguments and deal with error cases.
274extern "C" uint64_t artPortableProxyInvokeHandler(mirror::ArtMethod* proxy_method,
275                                                  mirror::Object* receiver,
276                                                  Thread* self, mirror::ArtMethod** sp)
277    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
278  // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
279  const char* old_cause =
280      self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
281  self->VerifyStack();
282  // Start new JNI local reference state.
283  JNIEnvExt* env = self->GetJniEnv();
284  ScopedObjectAccessUnchecked soa(env);
285  ScopedJniEnvLocalRefState env_state(env);
286  // Create local ref. copies of proxy method and the receiver.
287  jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
288
289  // Placing arguments into args vector and remove the receiver.
290  MethodHelper proxy_mh(proxy_method);
291  std::vector<jvalue> args;
292  BuildPortableArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args);
293  local_ref_visitor.VisitArguments();
294  args.erase(args.begin());
295
296  // Convert proxy method into expected interface method.
297  mirror::ArtMethod* interface_method = proxy_method->FindOverriddenMethod();
298  DCHECK(interface_method != NULL);
299  DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
300  jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
301
302  // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
303  // that performs allocations.
304  self->EndAssertNoThreadSuspension(old_cause);
305  JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(),
306                                               rcvr_jobj, interface_method_jobj, args);
307  return result.GetJ();
308}
309
310// Lazily resolve a method for portable. Called by stub code.
311extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called,
312                                                       mirror::Object* receiver,
313                                                       Thread* thread,
314                                                       mirror::ArtMethod** called_addr)
315    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
316  uint32_t dex_pc;
317  mirror::ArtMethod* caller = thread->GetCurrentMethod(&dex_pc);
318
319  ClassLinker* linker = Runtime::Current()->GetClassLinker();
320  InvokeType invoke_type;
321  bool is_range;
322  if (called->IsRuntimeMethod()) {
323    const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
324    CHECK_LT(dex_pc, code->insns_size_in_code_units_);
325    const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
326    Instruction::Code instr_code = instr->Opcode();
327    switch (instr_code) {
328      case Instruction::INVOKE_DIRECT:
329        invoke_type = kDirect;
330        is_range = false;
331        break;
332      case Instruction::INVOKE_DIRECT_RANGE:
333        invoke_type = kDirect;
334        is_range = true;
335        break;
336      case Instruction::INVOKE_STATIC:
337        invoke_type = kStatic;
338        is_range = false;
339        break;
340      case Instruction::INVOKE_STATIC_RANGE:
341        invoke_type = kStatic;
342        is_range = true;
343        break;
344      case Instruction::INVOKE_SUPER:
345        invoke_type = kSuper;
346        is_range = false;
347        break;
348      case Instruction::INVOKE_SUPER_RANGE:
349        invoke_type = kSuper;
350        is_range = true;
351        break;
352      case Instruction::INVOKE_VIRTUAL:
353        invoke_type = kVirtual;
354        is_range = false;
355        break;
356      case Instruction::INVOKE_VIRTUAL_RANGE:
357        invoke_type = kVirtual;
358        is_range = true;
359        break;
360      case Instruction::INVOKE_INTERFACE:
361        invoke_type = kInterface;
362        is_range = false;
363        break;
364      case Instruction::INVOKE_INTERFACE_RANGE:
365        invoke_type = kInterface;
366        is_range = true;
367        break;
368      default:
369        LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
370        // Avoid used uninitialized warnings.
371        invoke_type = kDirect;
372        is_range = true;
373    }
374    uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
375    called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
376    // Incompatible class change should have been handled in resolve method.
377    CHECK(!called->CheckIncompatibleClassChange(invoke_type));
378    // Refine called method based on receiver.
379    if (invoke_type == kVirtual) {
380      called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
381    } else if (invoke_type == kInterface) {
382      called = receiver->GetClass()->FindVirtualMethodForInterface(called);
383    }
384  } else {
385    CHECK(called->IsStatic()) << PrettyMethod(called);
386    invoke_type = kStatic;
387    // Incompatible class change should have been handled in resolve method.
388    CHECK(!called->CheckIncompatibleClassChange(invoke_type));
389  }
390  const void* code = NULL;
391  if (LIKELY(!thread->IsExceptionPending())) {
392    // Ensure that the called method's class is initialized.
393    mirror::Class* called_class = called->GetDeclaringClass();
394    linker->EnsureInitialized(called_class, true, true);
395    if (LIKELY(called_class->IsInitialized())) {
396      code = called->GetEntryPointFromCompiledCode();
397      // TODO: remove this after we solve the link issue.
398      {  // for lazy link.
399        if (code == NULL) {
400          code = linker->GetOatCodeFor(called);
401        }
402      }
403    } else if (called_class->IsInitializing()) {
404      if (invoke_type == kStatic) {
405        // Class is still initializing, go to oat and grab code (trampoline must be left in place
406        // until class is initialized to stop races between threads).
407        code = linker->GetOatCodeFor(called);
408      } else {
409        // No trampoline for non-static methods.
410        code = called->GetEntryPointFromCompiledCode();
411        // TODO: remove this after we solve the link issue.
412        {  // for lazy link.
413          if (code == NULL) {
414            code = linker->GetOatCodeFor(called);
415          }
416        }
417      }
418    } else {
419      DCHECK(called_class->IsErroneous());
420    }
421  }
422  if (LIKELY(code != NULL)) {
423    // Expect class to at least be initializing.
424    DCHECK(called->GetDeclaringClass()->IsInitializing());
425    // Don't want infinite recursion.
426    DCHECK(code != GetResolutionTrampoline(linker));
427    // Set up entry into main method
428    *called_addr = called;
429  }
430  return code;
431}
432
433}  // namespace art
434
435#endif  // ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_
436