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