| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2012 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_INTERPRETER_INTERPRETER_COMMON_H_ | 
 | 18 | #define ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_ | 
 | 19 |  | 
 | 20 | #include "interpreter.h" | 
 | 21 |  | 
 | 22 | #include <math.h> | 
 | 23 |  | 
| Ian Rogers | cf7f191 | 2014-10-22 22:06:39 -0700 | [diff] [blame] | 24 | #include <iostream> | 
| Ian Rogers | c7dd295 | 2014-10-21 23:31:19 -0700 | [diff] [blame] | 25 | #include <sstream> | 
 | 26 |  | 
| Mathieu Chartier | c785344 | 2015-03-27 14:35:38 -0700 | [diff] [blame] | 27 | #include "art_field-inl.h" | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 28 | #include "art_method-inl.h" | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 29 | #include "base/logging.h" | 
| Andreas Gampe | 794ad76 | 2015-02-23 08:12:24 -0800 | [diff] [blame] | 30 | #include "base/macros.h" | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 31 | #include "class_linker-inl.h" | 
 | 32 | #include "common_throws.h" | 
 | 33 | #include "dex_file-inl.h" | 
 | 34 | #include "dex_instruction-inl.h" | 
| Mingyao Yang | 98d1cc8 | 2014-05-15 17:02:16 -0700 | [diff] [blame] | 35 | #include "entrypoints/entrypoint_utils-inl.h" | 
| Mathieu Chartier | 0cd8135 | 2014-05-22 16:48:55 -0700 | [diff] [blame] | 36 | #include "handle_scope-inl.h" | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 37 | #include "lambda/art_lambda_method.h" | 
| Igor Murashkin | e2facc5 | 2015-07-10 13:49:08 -0700 | [diff] [blame] | 38 | #include "lambda/box_table.h" | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 39 | #include "lambda/closure.h" | 
 | 40 | #include "lambda/closure_builder-inl.h" | 
 | 41 | #include "lambda/leaking_allocator.h" | 
 | 42 | #include "lambda/shorty_field_type.h" | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 43 | #include "mirror/class-inl.h" | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 44 | #include "mirror/method.h" | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 45 | #include "mirror/object-inl.h" | 
 | 46 | #include "mirror/object_array-inl.h" | 
| Douglas Leung | 4965c02 | 2014-06-11 11:41:11 -0700 | [diff] [blame] | 47 | #include "mirror/string-inl.h" | 
| Andreas Gampe | 03ec930 | 2015-08-27 17:41:47 -0700 | [diff] [blame] | 48 | #include "stack.h" | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 49 | #include "thread.h" | 
 | 50 | #include "well_known_classes.h" | 
 | 51 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 52 | using ::art::ArtMethod; | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 53 | using ::art::mirror::Array; | 
 | 54 | using ::art::mirror::BooleanArray; | 
 | 55 | using ::art::mirror::ByteArray; | 
 | 56 | using ::art::mirror::CharArray; | 
 | 57 | using ::art::mirror::Class; | 
 | 58 | using ::art::mirror::ClassLoader; | 
 | 59 | using ::art::mirror::IntArray; | 
 | 60 | using ::art::mirror::LongArray; | 
 | 61 | using ::art::mirror::Object; | 
 | 62 | using ::art::mirror::ObjectArray; | 
 | 63 | using ::art::mirror::ShortArray; | 
 | 64 | using ::art::mirror::String; | 
 | 65 | using ::art::mirror::Throwable; | 
 | 66 |  | 
 | 67 | namespace art { | 
 | 68 | namespace interpreter { | 
 | 69 |  | 
| buzbee | 1452bee | 2015-03-06 14:43:04 -0800 | [diff] [blame] | 70 | // External references to all interpreter implementations. | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 71 |  | 
| Sebastien Hertz | d2fe10a | 2014-01-15 10:20:56 +0100 | [diff] [blame] | 72 | template<bool do_access_check, bool transaction_active> | 
| Ian Rogers | e94652f | 2014-12-02 11:13:19 -0800 | [diff] [blame] | 73 | extern JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, | 
| buzbee | 1452bee | 2015-03-06 14:43:04 -0800 | [diff] [blame] | 74 |                                 ShadowFrame& shadow_frame, JValue result_register, | 
 | 75 |                                 bool interpret_one_instruction); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 76 |  | 
| Sebastien Hertz | d2fe10a | 2014-01-15 10:20:56 +0100 | [diff] [blame] | 77 | template<bool do_access_check, bool transaction_active> | 
| Ian Rogers | e94652f | 2014-12-02 11:13:19 -0800 | [diff] [blame] | 78 | extern JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 79 |                               ShadowFrame& shadow_frame, JValue result_register); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 80 |  | 
| buzbee | 1452bee | 2015-03-06 14:43:04 -0800 | [diff] [blame] | 81 | // Mterp does not support transactions or access check, thus no templated versions. | 
 | 82 | extern "C" bool ExecuteMterpImpl(Thread* self, const DexFile::CodeItem* code_item, | 
 | 83 |                                  ShadowFrame* shadow_frame, JValue* result_register); | 
 | 84 |  | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 85 | void ThrowNullPointerExceptionFromInterpreter() | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 86 |     SHARED_REQUIRES(Locks::mutator_lock_); | 
| Sebastien Hertz | da843e1 | 2014-05-28 19:28:31 +0200 | [diff] [blame] | 87 |  | 
| Andreas Gampe | 03ec930 | 2015-08-27 17:41:47 -0700 | [diff] [blame] | 88 | template <bool kMonitorCounting> | 
 | 89 | static inline void DoMonitorEnter(Thread* self, | 
 | 90 |                                   ShadowFrame* frame, | 
| Mathieu Chartier | 2d096c9 | 2015-10-12 16:18:20 -0700 | [diff] [blame] | 91 |                                   Object* ref) | 
 | 92 |     NO_THREAD_SAFETY_ANALYSIS | 
 | 93 |     REQUIRES(!Roles::uninterruptible_) { | 
 | 94 |   StackHandleScope<1> hs(self); | 
 | 95 |   Handle<Object> h_ref(hs.NewHandle(ref)); | 
 | 96 |   h_ref->MonitorEnter(self); | 
 | 97 |   frame->GetLockCountData().AddMonitor<kMonitorCounting>(self, h_ref.Get()); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 98 | } | 
 | 99 |  | 
| Andreas Gampe | 03ec930 | 2015-08-27 17:41:47 -0700 | [diff] [blame] | 100 | template <bool kMonitorCounting> | 
 | 101 | static inline void DoMonitorExit(Thread* self, | 
 | 102 |                                  ShadowFrame* frame, | 
| Mathieu Chartier | 2d096c9 | 2015-10-12 16:18:20 -0700 | [diff] [blame] | 103 |                                  Object* ref) | 
 | 104 |     NO_THREAD_SAFETY_ANALYSIS | 
 | 105 |     REQUIRES(!Roles::uninterruptible_) { | 
 | 106 |   StackHandleScope<1> hs(self); | 
 | 107 |   Handle<Object> h_ref(hs.NewHandle(ref)); | 
 | 108 |   h_ref->MonitorExit(self); | 
 | 109 |   frame->GetLockCountData().RemoveMonitorOrThrow<kMonitorCounting>(self, h_ref.Get()); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 110 | } | 
 | 111 |  | 
| Sebastien Hertz | 45b1597 | 2015-04-03 16:07:05 +0200 | [diff] [blame] | 112 | void AbortTransactionF(Thread* self, const char* fmt, ...) | 
 | 113 |     __attribute__((__format__(__printf__, 2, 3))) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 114 |     SHARED_REQUIRES(Locks::mutator_lock_); | 
| Sebastien Hertz | 45b1597 | 2015-04-03 16:07:05 +0200 | [diff] [blame] | 115 |  | 
 | 116 | void AbortTransactionV(Thread* self, const char* fmt, va_list args) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 117 |     SHARED_REQUIRES(Locks::mutator_lock_); | 
| Mathieu Chartier | b2c7ead | 2014-04-29 11:13:16 -0700 | [diff] [blame] | 118 |  | 
| Sebastien Hertz | d2fe10a | 2014-01-15 10:20:56 +0100 | [diff] [blame] | 119 | void RecordArrayElementsInTransaction(mirror::Array* array, int32_t count) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 120 |     SHARED_REQUIRES(Locks::mutator_lock_); | 
| Sebastien Hertz | d2fe10a | 2014-01-15 10:20:56 +0100 | [diff] [blame] | 121 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 122 | // Invokes the given method. This is part of the invocation support and is used by DoInvoke and | 
 | 123 | // DoInvokeVirtualQuick functions. | 
 | 124 | // Returns true on success, otherwise throws an exception and returns false. | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 125 | template<bool is_range, bool do_assignability_check> | 
| Ian Rogers | e94652f | 2014-12-02 11:13:19 -0800 | [diff] [blame] | 126 | bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame, | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 127 |             const Instruction* inst, uint16_t inst_data, JValue* result); | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 128 |  | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 129 | // Invokes the given lambda closure. This is part of the invocation support and is used by | 
 | 130 | // DoLambdaInvoke functions. | 
 | 131 | // Returns true on success, otherwise throws an exception and returns false. | 
 | 132 | template<bool is_range, bool do_assignability_check> | 
 | 133 | bool DoLambdaCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame, | 
 | 134 |                   const Instruction* inst, uint16_t inst_data, JValue* result); | 
 | 135 |  | 
 | 136 | // Validates that the art method corresponding to a lambda method target | 
 | 137 | // is semantically valid: | 
 | 138 | // | 
 | 139 | // Must be ACC_STATIC and ACC_LAMBDA. Must be a concrete managed implementation | 
 | 140 | // (i.e. not native, not proxy, not abstract, ...). | 
 | 141 | // | 
 | 142 | // If the validation fails, return false and raise an exception. | 
 | 143 | static inline bool IsValidLambdaTargetOrThrow(ArtMethod* called_method) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 144 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 145 |   bool success = false; | 
 | 146 |  | 
 | 147 |   if (UNLIKELY(called_method == nullptr)) { | 
 | 148 |     // The shadow frame should already be pushed, so we don't need to update it. | 
| Alex Light | 9139e00 | 2015-10-09 15:59:48 -0700 | [diff] [blame] | 149 |   } else if (UNLIKELY(!called_method->IsInvokable())) { | 
 | 150 |     called_method->ThrowInvocationTimeError(); | 
 | 151 |     // We got an error. | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 152 |     // TODO(iam): Also handle the case when the method is non-static, what error do we throw? | 
 | 153 |     // TODO(iam): Also make sure that ACC_LAMBDA is set. | 
 | 154 |   } else if (UNLIKELY(called_method->GetCodeItem() == nullptr)) { | 
 | 155 |     // Method could be native, proxy method, etc. Lambda targets have to be concrete impls, | 
 | 156 |     // so don't allow this. | 
 | 157 |   } else { | 
 | 158 |     success = true; | 
 | 159 |   } | 
 | 160 |  | 
 | 161 |   return success; | 
 | 162 | } | 
 | 163 |  | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 164 | // Write out the 'Closure*' into vreg and vreg+1, as if it was a jlong. | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 165 | static inline void WriteLambdaClosureIntoVRegs(ShadowFrame& shadow_frame, | 
| Igor Murashkin | 30c475a | 2015-10-06 13:59:43 -0700 | [diff] [blame] | 166 |                                                const lambda::Closure& lambda_closure, | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 167 |                                                uint32_t vreg) { | 
 | 168 |   // Split the method into a lo and hi 32 bits so we can encode them into 2 virtual registers. | 
| Igor Murashkin | 30c475a | 2015-10-06 13:59:43 -0700 | [diff] [blame] | 169 |   uint32_t closure_lo = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&lambda_closure)); | 
 | 170 |   uint32_t closure_hi = static_cast<uint32_t>(reinterpret_cast<uint64_t>(&lambda_closure) | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 171 |                                                     >> BitSizeOf<uint32_t>()); | 
 | 172 |   // Use uint64_t instead of uintptr_t to allow shifting past the max on 32-bit. | 
 | 173 |   static_assert(sizeof(uint64_t) >= sizeof(uintptr_t), "Impossible"); | 
 | 174 |  | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 175 |   DCHECK_NE(closure_lo | closure_hi, 0u); | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 176 |  | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 177 |   shadow_frame.SetVReg(vreg, closure_lo); | 
 | 178 |   shadow_frame.SetVReg(vreg + 1, closure_hi); | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 179 | } | 
 | 180 |  | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 181 | // Handles create-lambda instructions. | 
 | 182 | // Returns true on success, otherwise throws an exception and returns false. | 
 | 183 | // (Exceptions are thrown by creating a new exception and then being put in the thread TLS) | 
 | 184 | // | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 185 | // The closure must be allocated big enough to hold the data, and should not be | 
 | 186 | // pre-initialized. It is initialized with the actual captured variables as a side-effect, | 
 | 187 | // although this should be unimportant to the caller since this function also handles storing it to | 
 | 188 | // the ShadowFrame. | 
 | 189 | // | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 190 | // As a work-in-progress implementation, this shoves the ArtMethod object corresponding | 
 | 191 | // to the target dex method index into the target register vA and vA + 1. | 
 | 192 | template<bool do_access_check> | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 193 | static inline bool DoCreateLambda(Thread* self, | 
 | 194 |                                   const Instruction* inst, | 
 | 195 |                                   /*inout*/ShadowFrame& shadow_frame, | 
 | 196 |                                   /*inout*/lambda::ClosureBuilder* closure_builder, | 
 | 197 |                                   /*inout*/lambda::Closure* uninitialized_closure) { | 
 | 198 |   DCHECK(closure_builder != nullptr); | 
 | 199 |   DCHECK(uninitialized_closure != nullptr); | 
 | 200 |   DCHECK_ALIGNED(uninitialized_closure, alignof(lambda::Closure)); | 
 | 201 |  | 
| Igor Murashkin | 30c475a | 2015-10-06 13:59:43 -0700 | [diff] [blame] | 202 |   using lambda::ArtLambdaMethod; | 
 | 203 |   using lambda::LeakingAllocator; | 
 | 204 |  | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 205 |   /* | 
 | 206 |    * create-lambda is opcode 0x21c | 
 | 207 |    * - vA is the target register where the closure will be stored into | 
 | 208 |    *   (also stores into vA + 1) | 
 | 209 |    * - vB is the method index which will be the target for a later invoke-lambda | 
 | 210 |    */ | 
 | 211 |   const uint32_t method_idx = inst->VRegB_21c(); | 
 | 212 |   mirror::Object* receiver = nullptr;  // Always static. (see 'kStatic') | 
 | 213 |   ArtMethod* sf_method = shadow_frame.GetMethod(); | 
 | 214 |   ArtMethod* const called_method = FindMethodFromCode<kStatic, do_access_check>( | 
| Andreas Gampe | 3a35714 | 2015-08-07 17:20:11 -0700 | [diff] [blame] | 215 |       method_idx, &receiver, sf_method, self); | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 216 |  | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 217 |   uint32_t vreg_dest_closure = inst->VRegA_21c(); | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 218 |  | 
 | 219 |   if (UNLIKELY(!IsValidLambdaTargetOrThrow(called_method))) { | 
 | 220 |     CHECK(self->IsExceptionPending()); | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 221 |     shadow_frame.SetVReg(vreg_dest_closure, 0u); | 
 | 222 |     shadow_frame.SetVReg(vreg_dest_closure + 1, 0u); | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 223 |     return false; | 
 | 224 |   } | 
 | 225 |  | 
| Igor Murashkin | 30c475a | 2015-10-06 13:59:43 -0700 | [diff] [blame] | 226 |   ArtLambdaMethod* initialized_lambda_method; | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 227 |   // Initialize the ArtLambdaMethod with the right data. | 
 | 228 |   { | 
| Igor Murashkin | 30c475a | 2015-10-06 13:59:43 -0700 | [diff] [blame] | 229 |     // Allocate enough memory to store a well-aligned ArtLambdaMethod. | 
 | 230 |     // This is not the final type yet since the data starts out uninitialized. | 
 | 231 |     LeakingAllocator::AlignedMemoryStorage<ArtLambdaMethod>* uninitialized_lambda_method = | 
 | 232 |             LeakingAllocator::AllocateMemory<ArtLambdaMethod>(self); | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 233 |  | 
 | 234 |     std::string captured_variables_shorty = closure_builder->GetCapturedVariableShortyTypes(); | 
 | 235 |     std::string captured_variables_long_type_desc; | 
 | 236 |  | 
 | 237 |     // Synthesize a long type descriptor from the short one. | 
 | 238 |     for (char shorty : captured_variables_shorty) { | 
 | 239 |       lambda::ShortyFieldType shorty_field_type(shorty); | 
 | 240 |       if (shorty_field_type.IsObject()) { | 
 | 241 |         // Not the true type, but good enough until we implement verifier support. | 
 | 242 |         captured_variables_long_type_desc += "Ljava/lang/Object;"; | 
 | 243 |         UNIMPLEMENTED(FATAL) << "create-lambda with an object captured variable"; | 
 | 244 |       } else if (shorty_field_type.IsLambda()) { | 
 | 245 |         // Not the true type, but good enough until we implement verifier support. | 
 | 246 |         captured_variables_long_type_desc += "Ljava/lang/Runnable;"; | 
 | 247 |         UNIMPLEMENTED(FATAL) << "create-lambda with a lambda captured variable"; | 
 | 248 |       } else { | 
 | 249 |         // The primitive types have the same length shorty or not, so this is always correct. | 
 | 250 |         DCHECK(shorty_field_type.IsPrimitive()); | 
 | 251 |         captured_variables_long_type_desc += shorty_field_type; | 
 | 252 |       } | 
 | 253 |     } | 
 | 254 |  | 
 | 255 |     // Copy strings to dynamically allocated storage. This leaks, but that's ok. Fix it later. | 
 | 256 |     // TODO: Strings need to come from the DexFile, so they won't need their own allocations. | 
| Igor Murashkin | 30c475a | 2015-10-06 13:59:43 -0700 | [diff] [blame] | 257 |     char* captured_variables_type_desc = LeakingAllocator::MakeFlexibleInstance<char>( | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 258 |         self, | 
 | 259 |         captured_variables_long_type_desc.size() + 1); | 
 | 260 |     strcpy(captured_variables_type_desc, captured_variables_long_type_desc.c_str()); | 
| Igor Murashkin | 30c475a | 2015-10-06 13:59:43 -0700 | [diff] [blame] | 261 |     char* captured_variables_shorty_copy = LeakingAllocator::MakeFlexibleInstance<char>( | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 262 |         self, | 
 | 263 |         captured_variables_shorty.size() + 1); | 
 | 264 |     strcpy(captured_variables_shorty_copy, captured_variables_shorty.c_str()); | 
 | 265 |  | 
| Igor Murashkin | 30c475a | 2015-10-06 13:59:43 -0700 | [diff] [blame] | 266 |     // After initialization, the object at the storage is well-typed. Use strong type going forward. | 
 | 267 |     initialized_lambda_method = | 
 | 268 |         new (uninitialized_lambda_method) ArtLambdaMethod(called_method, | 
 | 269 |                                                           captured_variables_type_desc, | 
 | 270 |                                                           captured_variables_shorty_copy, | 
 | 271 |                                                           true);  // innate lambda | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 272 |   } | 
 | 273 |  | 
 | 274 |   // Write all the closure captured variables and the closure header into the closure. | 
| Igor Murashkin | 30c475a | 2015-10-06 13:59:43 -0700 | [diff] [blame] | 275 |   lambda::Closure* initialized_closure = | 
 | 276 |       closure_builder->CreateInPlace(uninitialized_closure, initialized_lambda_method); | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 277 |  | 
| Igor Murashkin | 30c475a | 2015-10-06 13:59:43 -0700 | [diff] [blame] | 278 |   WriteLambdaClosureIntoVRegs(/*inout*/shadow_frame, *initialized_closure, vreg_dest_closure); | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 279 |   return true; | 
 | 280 | } | 
 | 281 |  | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 282 | // Reads out the 'ArtMethod*' stored inside of vreg and vreg+1 | 
 | 283 | // | 
 | 284 | // Validates that the art method points to a valid lambda function, otherwise throws | 
 | 285 | // an exception and returns null. | 
 | 286 | // (Exceptions are thrown by creating a new exception and then being put in the thread TLS) | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 287 | static inline lambda::Closure* ReadLambdaClosureFromVRegsOrThrow(ShadowFrame& shadow_frame, | 
 | 288 |                                                                  uint32_t vreg) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 289 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 290 |   // Lambda closures take up a consecutive pair of 2 virtual registers. | 
 | 291 |   // On 32-bit the high bits are always 0. | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 292 |   uint32_t vc_value_lo = shadow_frame.GetVReg(vreg); | 
 | 293 |   uint32_t vc_value_hi = shadow_frame.GetVReg(vreg + 1); | 
 | 294 |  | 
 | 295 |   uint64_t vc_value_ptr = (static_cast<uint64_t>(vc_value_hi) << BitSizeOf<uint32_t>()) | 
 | 296 |                            | vc_value_lo; | 
 | 297 |  | 
 | 298 |   // Use uint64_t instead of uintptr_t to allow left-shifting past the max on 32-bit. | 
 | 299 |   static_assert(sizeof(uint64_t) >= sizeof(uintptr_t), "Impossible"); | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 300 |   lambda::Closure* const lambda_closure = reinterpret_cast<lambda::Closure*>(vc_value_ptr); | 
 | 301 |   DCHECK_ALIGNED(lambda_closure, alignof(lambda::Closure)); | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 302 |  | 
 | 303 |   // Guard against the user passing a null closure, which is odd but (sadly) semantically valid. | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 304 |   if (UNLIKELY(lambda_closure == nullptr)) { | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 305 |     ThrowNullPointerExceptionFromInterpreter(); | 
 | 306 |     return nullptr; | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 307 |   } else if (UNLIKELY(!IsValidLambdaTargetOrThrow(lambda_closure->GetTargetMethod()))) { | 
 | 308 |     // Sanity check against data corruption. | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 309 |     return nullptr; | 
 | 310 |   } | 
 | 311 |  | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 312 |   return lambda_closure; | 
 | 313 | } | 
 | 314 |  | 
 | 315 | // Forward declaration for lock annotations. See below for documentation. | 
 | 316 | template <bool do_access_check> | 
 | 317 | static inline const char* GetStringDataByDexStringIndexOrThrow(ShadowFrame& shadow_frame, | 
 | 318 |                                                                uint32_t string_idx) | 
 | 319 |     SHARED_REQUIRES(Locks::mutator_lock_); | 
 | 320 |  | 
 | 321 | // Find the c-string data corresponding to a dex file's string index. | 
 | 322 | // Otherwise, returns null if not found and throws a VerifyError. | 
 | 323 | // | 
 | 324 | // Note that with do_access_check=false, we never return null because the verifier | 
 | 325 | // must guard against invalid string indices. | 
 | 326 | // (Exceptions are thrown by creating a new exception and then being put in the thread TLS) | 
 | 327 | template <bool do_access_check> | 
 | 328 | static inline const char* GetStringDataByDexStringIndexOrThrow(ShadowFrame& shadow_frame, | 
 | 329 |                                                                uint32_t string_idx) { | 
 | 330 |   ArtMethod* method = shadow_frame.GetMethod(); | 
 | 331 |   const DexFile* dex_file = method->GetDexFile(); | 
 | 332 |  | 
 | 333 |   mirror::Class* declaring_class = method->GetDeclaringClass(); | 
 | 334 |   if (!do_access_check) { | 
 | 335 |     // MethodVerifier refuses methods with string_idx out of bounds. | 
 | 336 |     DCHECK_LT(string_idx, declaring_class->GetDexCache()->NumStrings()); | 
 | 337 |   } else { | 
 | 338 |     // Access checks enabled: perform string index bounds ourselves. | 
 | 339 |     if (string_idx >= dex_file->GetHeader().string_ids_size_) { | 
 | 340 |       ThrowVerifyError(declaring_class, "String index '%" PRIu32 "' out of bounds", | 
 | 341 |                        string_idx); | 
 | 342 |       return nullptr; | 
 | 343 |     } | 
 | 344 |   } | 
 | 345 |  | 
 | 346 |   const char* type_string = dex_file->StringDataByIdx(string_idx); | 
 | 347 |  | 
 | 348 |   if (UNLIKELY(type_string == nullptr)) { | 
 | 349 |     CHECK_EQ(false, do_access_check) | 
 | 350 |         << " verifier should've caught invalid string index " << string_idx; | 
 | 351 |     CHECK_EQ(true, do_access_check) | 
 | 352 |         << " string idx size check should've caught invalid string index " << string_idx; | 
 | 353 |   } | 
 | 354 |  | 
 | 355 |   return type_string; | 
 | 356 | } | 
 | 357 |  | 
 | 358 | // Handles capture-variable instructions. | 
 | 359 | // Returns true on success, otherwise throws an exception and returns false. | 
 | 360 | // (Exceptions are thrown by creating a new exception and then being put in the thread TLS) | 
 | 361 | template<bool do_access_check> | 
 | 362 | static inline bool DoCaptureVariable(Thread* self, | 
 | 363 |                                      const Instruction* inst, | 
 | 364 |                                      /*inout*/ShadowFrame& shadow_frame, | 
 | 365 |                                      /*inout*/lambda::ClosureBuilder* closure_builder) { | 
 | 366 |   DCHECK(closure_builder != nullptr); | 
 | 367 |   using lambda::ShortyFieldType; | 
 | 368 |   /* | 
 | 369 |    * capture-variable is opcode 0xf6, fmt 0x21c | 
 | 370 |    * - vA is the source register of the variable that will be captured | 
 | 371 |    * - vB is the string ID of the variable's type that will be captured | 
 | 372 |    */ | 
 | 373 |   const uint32_t source_vreg = inst->VRegA_21c(); | 
 | 374 |   const uint32_t string_idx = inst->VRegB_21c(); | 
 | 375 |   // TODO: this should be a proper [type id] instead of a [string ID] pointing to a type. | 
 | 376 |  | 
 | 377 |   const char* type_string = GetStringDataByDexStringIndexOrThrow<do_access_check>(shadow_frame, | 
 | 378 |                                                                                   string_idx); | 
 | 379 |   if (UNLIKELY(type_string == nullptr)) { | 
 | 380 |     CHECK(self->IsExceptionPending()); | 
 | 381 |     return false; | 
 | 382 |   } | 
 | 383 |  | 
 | 384 |   char type_first_letter = type_string[0]; | 
 | 385 |   ShortyFieldType shorty_type; | 
 | 386 |   if (do_access_check && | 
 | 387 |       UNLIKELY(!ShortyFieldType::MaybeCreate(type_first_letter, /*out*/&shorty_type))) {  // NOLINT: [whitespace/comma] [3] | 
 | 388 |     ThrowVerifyError(shadow_frame.GetMethod()->GetDeclaringClass(), | 
 | 389 |                      "capture-variable vB must be a valid type"); | 
 | 390 |     return false; | 
 | 391 |   } else { | 
 | 392 |     // Already verified that the type is valid. | 
 | 393 |     shorty_type = ShortyFieldType(type_first_letter); | 
 | 394 |   } | 
 | 395 |  | 
 | 396 |   const size_t captured_variable_count = closure_builder->GetCaptureCount(); | 
 | 397 |  | 
 | 398 |   // Note: types are specified explicitly so that the closure is packed tightly. | 
 | 399 |   switch (shorty_type) { | 
 | 400 |     case ShortyFieldType::kBoolean: { | 
 | 401 |       uint32_t primitive_narrow_value = shadow_frame.GetVReg(source_vreg); | 
 | 402 |       closure_builder->CaptureVariablePrimitive<bool>(primitive_narrow_value); | 
 | 403 |       break; | 
 | 404 |     } | 
 | 405 |     case ShortyFieldType::kByte: { | 
 | 406 |       uint32_t primitive_narrow_value = shadow_frame.GetVReg(source_vreg); | 
 | 407 |       closure_builder->CaptureVariablePrimitive<int8_t>(primitive_narrow_value); | 
 | 408 |       break; | 
 | 409 |     } | 
 | 410 |     case ShortyFieldType::kChar: { | 
 | 411 |       uint32_t primitive_narrow_value = shadow_frame.GetVReg(source_vreg); | 
 | 412 |       closure_builder->CaptureVariablePrimitive<uint16_t>(primitive_narrow_value); | 
 | 413 |       break; | 
 | 414 |     } | 
 | 415 |     case ShortyFieldType::kShort: { | 
 | 416 |       uint32_t primitive_narrow_value = shadow_frame.GetVReg(source_vreg); | 
 | 417 |       closure_builder->CaptureVariablePrimitive<int16_t>(primitive_narrow_value); | 
 | 418 |       break; | 
 | 419 |     } | 
 | 420 |     case ShortyFieldType::kInt: { | 
 | 421 |       uint32_t primitive_narrow_value = shadow_frame.GetVReg(source_vreg); | 
 | 422 |       closure_builder->CaptureVariablePrimitive<int32_t>(primitive_narrow_value); | 
 | 423 |       break; | 
 | 424 |     } | 
 | 425 |     case ShortyFieldType::kDouble: { | 
 | 426 |       closure_builder->CaptureVariablePrimitive(shadow_frame.GetVRegDouble(source_vreg)); | 
 | 427 |       break; | 
 | 428 |     } | 
 | 429 |     case ShortyFieldType::kFloat: { | 
 | 430 |       closure_builder->CaptureVariablePrimitive(shadow_frame.GetVRegFloat(source_vreg)); | 
 | 431 |       break; | 
 | 432 |     } | 
 | 433 |     case ShortyFieldType::kLambda: { | 
 | 434 |       UNIMPLEMENTED(FATAL) << " capture-variable with type kLambda"; | 
 | 435 |       // TODO: Capturing lambdas recursively will be done at a later time. | 
 | 436 |       UNREACHABLE(); | 
 | 437 |     } | 
 | 438 |     case ShortyFieldType::kLong: { | 
 | 439 |       closure_builder->CaptureVariablePrimitive(shadow_frame.GetVRegLong(source_vreg)); | 
 | 440 |       break; | 
 | 441 |     } | 
 | 442 |     case ShortyFieldType::kObject: { | 
 | 443 |       closure_builder->CaptureVariableObject(shadow_frame.GetVRegReference(source_vreg)); | 
 | 444 |       UNIMPLEMENTED(FATAL) << " capture-variable with type kObject"; | 
 | 445 |       // TODO: finish implementing this. disabled for now since we can't track lambda refs for GC. | 
 | 446 |       UNREACHABLE(); | 
 | 447 |     } | 
 | 448 |  | 
 | 449 |     default: | 
 | 450 |       LOG(FATAL) << "Invalid shorty type value " << shorty_type; | 
 | 451 |       UNREACHABLE(); | 
 | 452 |   } | 
 | 453 |  | 
 | 454 |   DCHECK_EQ(captured_variable_count + 1, closure_builder->GetCaptureCount()); | 
 | 455 |  | 
 | 456 |   return true; | 
 | 457 | } | 
 | 458 |  | 
 | 459 | // Handles capture-variable instructions. | 
 | 460 | // Returns true on success, otherwise throws an exception and returns false. | 
 | 461 | // (Exceptions are thrown by creating a new exception and then being put in the thread TLS) | 
 | 462 | template<bool do_access_check> | 
 | 463 | static inline bool DoLiberateVariable(Thread* self, | 
 | 464 |                                      const Instruction* inst, | 
 | 465 |                                      size_t captured_variable_index, | 
 | 466 |                                      /*inout*/ShadowFrame& shadow_frame) { | 
 | 467 |   using lambda::ShortyFieldType; | 
 | 468 |   /* | 
 | 469 |    * liberate-variable is opcode 0xf7, fmt 0x22c | 
 | 470 |    * - vA is the destination register | 
 | 471 |    * - vB is the register with the lambda closure in it | 
 | 472 |    * - vC is the string ID which needs to be a valid field type descriptor | 
 | 473 |    */ | 
 | 474 |  | 
 | 475 |   const uint32_t dest_vreg = inst->VRegA_22c(); | 
 | 476 |   const uint32_t closure_vreg = inst->VRegB_22c(); | 
 | 477 |   const uint32_t string_idx = inst->VRegC_22c(); | 
 | 478 |   // TODO: this should be a proper [type id] instead of a [string ID] pointing to a type. | 
 | 479 |  | 
 | 480 |  | 
 | 481 |   // Synthesize a long type descriptor from a shorty type descriptor list. | 
 | 482 |   // TODO: Fix the dex encoding to contain the long and short type descriptors. | 
 | 483 |   const char* type_string = GetStringDataByDexStringIndexOrThrow<do_access_check>(shadow_frame, | 
 | 484 |                                                                                   string_idx); | 
 | 485 |   if (UNLIKELY(do_access_check && type_string == nullptr)) { | 
 | 486 |     CHECK(self->IsExceptionPending()); | 
 | 487 |     shadow_frame.SetVReg(dest_vreg, 0); | 
 | 488 |     return false; | 
 | 489 |   } | 
 | 490 |  | 
 | 491 |   char type_first_letter = type_string[0]; | 
 | 492 |   ShortyFieldType shorty_type; | 
 | 493 |   if (do_access_check && | 
 | 494 |       UNLIKELY(!ShortyFieldType::MaybeCreate(type_first_letter, /*out*/&shorty_type))) {  // NOLINT: [whitespace/comma] [3] | 
 | 495 |     ThrowVerifyError(shadow_frame.GetMethod()->GetDeclaringClass(), | 
 | 496 |                      "liberate-variable vC must be a valid type"); | 
 | 497 |     shadow_frame.SetVReg(dest_vreg, 0); | 
 | 498 |     return false; | 
 | 499 |   } else { | 
 | 500 |     // Already verified that the type is valid. | 
 | 501 |     shorty_type = ShortyFieldType(type_first_letter); | 
 | 502 |   } | 
 | 503 |  | 
 | 504 |   // Check for closure being null *after* the type check. | 
 | 505 |   // This way we can access the type info in case we fail later, to know how many vregs to clear. | 
 | 506 |   const lambda::Closure* lambda_closure = | 
 | 507 |       ReadLambdaClosureFromVRegsOrThrow(/*inout*/shadow_frame, closure_vreg); | 
 | 508 |  | 
 | 509 |   // Failed lambda target runtime check, an exception was raised. | 
 | 510 |   if (UNLIKELY(lambda_closure == nullptr)) { | 
 | 511 |     CHECK(self->IsExceptionPending()); | 
 | 512 |  | 
 | 513 |     // Clear the destination vreg(s) to be safe. | 
 | 514 |     shadow_frame.SetVReg(dest_vreg, 0); | 
 | 515 |     if (shorty_type.IsPrimitiveWide() || shorty_type.IsLambda()) { | 
 | 516 |       shadow_frame.SetVReg(dest_vreg + 1, 0); | 
 | 517 |     } | 
 | 518 |     return false; | 
 | 519 |   } | 
 | 520 |  | 
 | 521 |   if (do_access_check && | 
 | 522 |       UNLIKELY(captured_variable_index >= lambda_closure->GetNumberOfCapturedVariables())) { | 
 | 523 |     ThrowVerifyError(shadow_frame.GetMethod()->GetDeclaringClass(), | 
 | 524 |                      "liberate-variable captured variable index %zu out of bounds", | 
 | 525 |                      lambda_closure->GetNumberOfCapturedVariables()); | 
 | 526 |     // Clear the destination vreg(s) to be safe. | 
 | 527 |     shadow_frame.SetVReg(dest_vreg, 0); | 
 | 528 |     if (shorty_type.IsPrimitiveWide() || shorty_type.IsLambda()) { | 
 | 529 |       shadow_frame.SetVReg(dest_vreg + 1, 0); | 
 | 530 |     } | 
 | 531 |     return false; | 
 | 532 |   } | 
 | 533 |  | 
 | 534 |   // Verify that the runtime type of the captured-variable matches the requested dex type. | 
 | 535 |   if (do_access_check) { | 
 | 536 |     ShortyFieldType actual_type = lambda_closure->GetCapturedShortyType(captured_variable_index); | 
 | 537 |     if (actual_type != shorty_type) { | 
 | 538 |       ThrowVerifyError(shadow_frame.GetMethod()->GetDeclaringClass(), | 
 | 539 |                      "cannot liberate-variable of runtime type '%c' to dex type '%c'", | 
 | 540 |                      static_cast<char>(actual_type), | 
 | 541 |                      static_cast<char>(shorty_type)); | 
 | 542 |  | 
 | 543 |       shadow_frame.SetVReg(dest_vreg, 0); | 
 | 544 |       if (shorty_type.IsPrimitiveWide() || shorty_type.IsLambda()) { | 
 | 545 |         shadow_frame.SetVReg(dest_vreg + 1, 0); | 
 | 546 |       } | 
 | 547 |       return false; | 
 | 548 |     } | 
 | 549 |  | 
 | 550 |     if (actual_type.IsLambda() || actual_type.IsObject()) { | 
 | 551 |       UNIMPLEMENTED(FATAL) << "liberate-variable type checks needs to " | 
 | 552 |                            << "parse full type descriptor for objects and lambdas"; | 
 | 553 |     } | 
 | 554 |   } | 
 | 555 |  | 
 | 556 |   // Unpack the captured variable from the closure into the correct type, then save it to the vreg. | 
 | 557 |   if (shorty_type.IsPrimitiveNarrow()) { | 
 | 558 |     uint32_t primitive_narrow_value = | 
 | 559 |         lambda_closure->GetCapturedPrimitiveNarrow(captured_variable_index); | 
 | 560 |     shadow_frame.SetVReg(dest_vreg, primitive_narrow_value); | 
 | 561 |   } else if (shorty_type.IsPrimitiveWide()) { | 
 | 562 |       uint64_t primitive_wide_value = | 
 | 563 |           lambda_closure->GetCapturedPrimitiveWide(captured_variable_index); | 
 | 564 |       shadow_frame.SetVRegLong(dest_vreg, static_cast<int64_t>(primitive_wide_value)); | 
 | 565 |   } else if (shorty_type.IsObject()) { | 
 | 566 |     mirror::Object* unpacked_object = | 
 | 567 |         lambda_closure->GetCapturedObject(captured_variable_index); | 
 | 568 |     shadow_frame.SetVRegReference(dest_vreg, unpacked_object); | 
 | 569 |  | 
 | 570 |     UNIMPLEMENTED(FATAL) << "liberate-variable cannot unpack objects yet"; | 
 | 571 |   } else if (shorty_type.IsLambda()) { | 
 | 572 |     UNIMPLEMENTED(FATAL) << "liberate-variable cannot unpack lambdas yet"; | 
 | 573 |   } else { | 
 | 574 |     LOG(FATAL) << "unreachable"; | 
 | 575 |     UNREACHABLE(); | 
 | 576 |   } | 
 | 577 |  | 
 | 578 |   return true; | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 579 | } | 
 | 580 |  | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 581 | template<bool do_access_check> | 
 | 582 | static inline bool DoInvokeLambda(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, | 
 | 583 |                                   uint16_t inst_data, JValue* result) { | 
 | 584 |   /* | 
 | 585 |    * invoke-lambda is opcode 0x25 | 
 | 586 |    * | 
 | 587 |    * - vC is the closure register (both vC and vC + 1 will be used to store the closure). | 
 | 588 |    * - vB is the number of additional registers up to |{vD,vE,vF,vG}| (4) | 
 | 589 |    * - the rest of the registers are always var-args | 
 | 590 |    * | 
 | 591 |    * - reading var-args for 0x25 gets us vD,vE,vF,vG (but not vB) | 
 | 592 |    */ | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 593 |   uint32_t vreg_closure = inst->VRegC_25x(); | 
 | 594 |   const lambda::Closure* lambda_closure = | 
 | 595 |       ReadLambdaClosureFromVRegsOrThrow(shadow_frame, vreg_closure); | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 596 |  | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 597 |   // Failed lambda target runtime check, an exception was raised. | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 598 |   if (UNLIKELY(lambda_closure == nullptr)) { | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 599 |     CHECK(self->IsExceptionPending()); | 
 | 600 |     result->SetJ(0); | 
 | 601 |     return false; | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 602 |   } | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 603 |  | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 604 |   ArtMethod* const called_method = lambda_closure->GetTargetMethod(); | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 605 |   // Invoke a non-range lambda | 
 | 606 |   return DoLambdaCall<false, do_access_check>(called_method, self, shadow_frame, inst, inst_data, | 
 | 607 |                                               result); | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 608 | } | 
 | 609 |  | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 610 | // Handles invoke-XXX/range instructions (other than invoke-lambda[-range]). | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 611 | // Returns true on success, otherwise throws an exception and returns false. | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 612 | template<InvokeType type, bool is_range, bool do_access_check> | 
 | 613 | static inline bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, | 
 | 614 |                             uint16_t inst_data, JValue* result) { | 
 | 615 |   const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); | 
 | 616 |   const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c(); | 
| Mathieu Chartier | e861ebd | 2013-10-09 15:01:21 -0700 | [diff] [blame] | 617 |   Object* receiver = (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC); | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 618 |   ArtMethod* sf_method = shadow_frame.GetMethod(); | 
| Ian Rogers | e94652f | 2014-12-02 11:13:19 -0800 | [diff] [blame] | 619 |   ArtMethod* const called_method = FindMethodFromCode<type, do_access_check>( | 
| Andreas Gampe | 3a35714 | 2015-08-07 17:20:11 -0700 | [diff] [blame] | 620 |       method_idx, &receiver, sf_method, self); | 
| Mathieu Chartier | 0cd8135 | 2014-05-22 16:48:55 -0700 | [diff] [blame] | 621 |   // The shadow frame should already be pushed, so we don't need to update it. | 
| Ian Rogers | e94652f | 2014-12-02 11:13:19 -0800 | [diff] [blame] | 622 |   if (UNLIKELY(called_method == nullptr)) { | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 623 |     CHECK(self->IsExceptionPending()); | 
 | 624 |     result->SetJ(0); | 
 | 625 |     return false; | 
| Alex Light | 9139e00 | 2015-10-09 15:59:48 -0700 | [diff] [blame] | 626 |   } else if (UNLIKELY(!called_method->IsInvokable())) { | 
 | 627 |     called_method->ThrowInvocationTimeError(); | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 628 |     result->SetJ(0); | 
 | 629 |     return false; | 
 | 630 |   } else { | 
| Nicolas Geoffray | 5550ca8 | 2015-08-21 18:38:30 +0100 | [diff] [blame] | 631 |     if (type == kVirtual || type == kInterface) { | 
 | 632 |       instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); | 
 | 633 |       if (UNLIKELY(instrumentation->HasInvokeVirtualOrInterfaceListeners())) { | 
 | 634 |         instrumentation->InvokeVirtualOrInterface( | 
 | 635 |             self, receiver, sf_method, shadow_frame.GetDexPC(), called_method); | 
 | 636 |       } | 
 | 637 |     } | 
| Ian Rogers | e94652f | 2014-12-02 11:13:19 -0800 | [diff] [blame] | 638 |     return DoCall<is_range, do_access_check>(called_method, self, shadow_frame, inst, inst_data, | 
 | 639 |                                              result); | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 640 |   } | 
 | 641 | } | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 642 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 643 | // Handles invoke-virtual-quick and invoke-virtual-quick-range instructions. | 
 | 644 | // Returns true on success, otherwise throws an exception and returns false. | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 645 | template<bool is_range> | 
 | 646 | static inline bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, | 
 | 647 |                                         const Instruction* inst, uint16_t inst_data, | 
 | 648 |                                         JValue* result) { | 
 | 649 |   const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c(); | 
 | 650 |   Object* const receiver = shadow_frame.GetVRegReference(vregC); | 
| Sebastien Hertz | d4beb6b | 2013-10-02 17:07:20 +0200 | [diff] [blame] | 651 |   if (UNLIKELY(receiver == nullptr)) { | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 652 |     // We lost the reference to the method index so we cannot get a more | 
 | 653 |     // precised exception message. | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 654 |     ThrowNullPointerExceptionFromDexPC(); | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 655 |     return false; | 
 | 656 |   } | 
 | 657 |   const uint32_t vtable_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); | 
| Mingyao Yang | 2cdbad7 | 2014-07-16 10:44:41 -0700 | [diff] [blame] | 658 |   CHECK(receiver->GetClass()->ShouldHaveEmbeddedImtAndVTable()); | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 659 |   ArtMethod* const called_method = receiver->GetClass()->GetEmbeddedVTableEntry( | 
 | 660 |       vtable_idx, sizeof(void*)); | 
| Ian Rogers | e94652f | 2014-12-02 11:13:19 -0800 | [diff] [blame] | 661 |   if (UNLIKELY(called_method == nullptr)) { | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 662 |     CHECK(self->IsExceptionPending()); | 
 | 663 |     result->SetJ(0); | 
 | 664 |     return false; | 
| Alex Light | 9139e00 | 2015-10-09 15:59:48 -0700 | [diff] [blame] | 665 |   } else if (UNLIKELY(!called_method->IsInvokable())) { | 
 | 666 |     called_method->ThrowInvocationTimeError(); | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 667 |     result->SetJ(0); | 
 | 668 |     return false; | 
 | 669 |   } else { | 
| Nicolas Geoffray | 5550ca8 | 2015-08-21 18:38:30 +0100 | [diff] [blame] | 670 |     instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); | 
 | 671 |     if (UNLIKELY(instrumentation->HasInvokeVirtualOrInterfaceListeners())) { | 
 | 672 |       instrumentation->InvokeVirtualOrInterface( | 
 | 673 |           self, receiver, shadow_frame.GetMethod(), shadow_frame.GetDexPC(), called_method); | 
 | 674 |     } | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 675 |     // No need to check since we've been quickened. | 
| Ian Rogers | e94652f | 2014-12-02 11:13:19 -0800 | [diff] [blame] | 676 |     return DoCall<is_range, false>(called_method, self, shadow_frame, inst, inst_data, result); | 
| Sebastien Hertz | c61124b | 2013-09-10 11:44:19 +0200 | [diff] [blame] | 677 |   } | 
 | 678 | } | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 679 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 680 | // Handles iget-XXX and sget-XXX instructions. | 
 | 681 | // Returns true on success, otherwise throws an exception and returns false. | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 682 | template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check> | 
| Ian Rogers | 5487494 | 2014-06-10 16:31:03 -0700 | [diff] [blame] | 683 | bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 684 |                 uint16_t inst_data) SHARED_REQUIRES(Locks::mutator_lock_); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 685 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 686 | // Handles iget-quick, iget-wide-quick and iget-object-quick instructions. | 
 | 687 | // Returns true on success, otherwise throws an exception and returns false. | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 688 | template<Primitive::Type field_type> | 
| Ian Rogers | 5487494 | 2014-06-10 16:31:03 -0700 | [diff] [blame] | 689 | bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 690 |     SHARED_REQUIRES(Locks::mutator_lock_); | 
| Sebastien Hertz | 479fc1e | 2014-04-04 17:51:34 +0200 | [diff] [blame] | 691 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 692 | // Handles iput-XXX and sput-XXX instructions. | 
 | 693 | // Returns true on success, otherwise throws an exception and returns false. | 
| Ian Rogers | 5487494 | 2014-06-10 16:31:03 -0700 | [diff] [blame] | 694 | template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check, | 
 | 695 |          bool transaction_active> | 
 | 696 | bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst, | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 697 |                 uint16_t inst_data) SHARED_REQUIRES(Locks::mutator_lock_); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 698 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 699 | // Handles iput-quick, iput-wide-quick and iput-object-quick instructions. | 
 | 700 | // Returns true on success, otherwise throws an exception and returns false. | 
| Sebastien Hertz | d2fe10a | 2014-01-15 10:20:56 +0100 | [diff] [blame] | 701 | template<Primitive::Type field_type, bool transaction_active> | 
| Ian Rogers | 5487494 | 2014-06-10 16:31:03 -0700 | [diff] [blame] | 702 | bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 703 |     SHARED_REQUIRES(Locks::mutator_lock_); | 
| Ian Rogers | 5487494 | 2014-06-10 16:31:03 -0700 | [diff] [blame] | 704 |  | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 705 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 706 | // Handles string resolution for const-string and const-string-jumbo instructions. Also ensures the | 
 | 707 | // java.lang.String class is initialized. | 
| Ian Rogers | 6786a58 | 2014-10-28 12:49:06 -0700 | [diff] [blame] | 708 | static inline String* ResolveString(Thread* self, ShadowFrame& shadow_frame, uint32_t string_idx) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 709 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 710 |   Class* java_lang_string_class = String::GetJavaLangString(); | 
 | 711 |   if (UNLIKELY(!java_lang_string_class->IsInitialized())) { | 
 | 712 |     ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 713 |     StackHandleScope<1> hs(self); | 
 | 714 |     Handle<mirror::Class> h_class(hs.NewHandle(java_lang_string_class)); | 
| Ian Rogers | 7b078e8 | 2014-09-10 14:44:24 -0700 | [diff] [blame] | 715 |     if (UNLIKELY(!class_linker->EnsureInitialized(self, h_class, true, true))) { | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 716 |       DCHECK(self->IsExceptionPending()); | 
| Mathieu Chartier | c528dba | 2013-11-26 12:00:11 -0800 | [diff] [blame] | 717 |       return nullptr; | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 718 |     } | 
 | 719 |   } | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 720 |   ArtMethod* method = shadow_frame.GetMethod(); | 
| Mathieu Chartier | eace458 | 2014-11-24 18:29:54 -0800 | [diff] [blame] | 721 |   mirror::Class* declaring_class = method->GetDeclaringClass(); | 
| Vladimir Marko | 05792b9 | 2015-08-03 11:56:49 +0100 | [diff] [blame] | 722 |   // MethodVerifier refuses methods with string_idx out of bounds. | 
 | 723 |   DCHECK_LT(string_idx, declaring_class->GetDexCache()->NumStrings()); | 
 | 724 |   mirror::String* s = declaring_class->GetDexCacheStrings()[string_idx].Read(); | 
| Ian Rogers | 6786a58 | 2014-10-28 12:49:06 -0700 | [diff] [blame] | 725 |   if (UNLIKELY(s == nullptr)) { | 
 | 726 |     StackHandleScope<1> hs(self); | 
| Mathieu Chartier | eace458 | 2014-11-24 18:29:54 -0800 | [diff] [blame] | 727 |     Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache())); | 
| Ian Rogers | 6786a58 | 2014-10-28 12:49:06 -0700 | [diff] [blame] | 728 |     s = Runtime::Current()->GetClassLinker()->ResolveString(*method->GetDexFile(), string_idx, | 
 | 729 |                                                             dex_cache); | 
 | 730 |   } | 
 | 731 |   return s; | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 732 | } | 
 | 733 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 734 | // Handles div-int, div-int/2addr, div-int/li16 and div-int/lit8 instructions. | 
 | 735 | // Returns true on success, otherwise throws a java.lang.ArithmeticException and return false. | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 736 | static inline bool DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg, | 
 | 737 |                                int32_t dividend, int32_t divisor) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 738 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Ian Rogers | f72a11d | 2014-10-30 15:41:08 -0700 | [diff] [blame] | 739 |   constexpr int32_t kMinInt = std::numeric_limits<int32_t>::min(); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 740 |   if (UNLIKELY(divisor == 0)) { | 
 | 741 |     ThrowArithmeticExceptionDivideByZero(); | 
 | 742 |     return false; | 
 | 743 |   } | 
 | 744 |   if (UNLIKELY(dividend == kMinInt && divisor == -1)) { | 
 | 745 |     shadow_frame.SetVReg(result_reg, kMinInt); | 
 | 746 |   } else { | 
 | 747 |     shadow_frame.SetVReg(result_reg, dividend / divisor); | 
 | 748 |   } | 
 | 749 |   return true; | 
 | 750 | } | 
 | 751 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 752 | // Handles rem-int, rem-int/2addr, rem-int/li16 and rem-int/lit8 instructions. | 
 | 753 | // Returns true on success, otherwise throws a java.lang.ArithmeticException and return false. | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 754 | static inline bool DoIntRemainder(ShadowFrame& shadow_frame, size_t result_reg, | 
 | 755 |                                   int32_t dividend, int32_t divisor) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 756 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Ian Rogers | f72a11d | 2014-10-30 15:41:08 -0700 | [diff] [blame] | 757 |   constexpr int32_t kMinInt = std::numeric_limits<int32_t>::min(); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 758 |   if (UNLIKELY(divisor == 0)) { | 
 | 759 |     ThrowArithmeticExceptionDivideByZero(); | 
 | 760 |     return false; | 
 | 761 |   } | 
 | 762 |   if (UNLIKELY(dividend == kMinInt && divisor == -1)) { | 
 | 763 |     shadow_frame.SetVReg(result_reg, 0); | 
 | 764 |   } else { | 
 | 765 |     shadow_frame.SetVReg(result_reg, dividend % divisor); | 
 | 766 |   } | 
 | 767 |   return true; | 
 | 768 | } | 
 | 769 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 770 | // Handles div-long and div-long-2addr instructions. | 
 | 771 | // Returns true on success, otherwise throws a java.lang.ArithmeticException and return false. | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 772 | static inline bool DoLongDivide(ShadowFrame& shadow_frame, size_t result_reg, | 
 | 773 |                                 int64_t dividend, int64_t divisor) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 774 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Ian Rogers | 2e2deeb | 2013-09-23 11:58:57 -0700 | [diff] [blame] | 775 |   const int64_t kMinLong = std::numeric_limits<int64_t>::min(); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 776 |   if (UNLIKELY(divisor == 0)) { | 
 | 777 |     ThrowArithmeticExceptionDivideByZero(); | 
 | 778 |     return false; | 
 | 779 |   } | 
 | 780 |   if (UNLIKELY(dividend == kMinLong && divisor == -1)) { | 
 | 781 |     shadow_frame.SetVRegLong(result_reg, kMinLong); | 
 | 782 |   } else { | 
 | 783 |     shadow_frame.SetVRegLong(result_reg, dividend / divisor); | 
 | 784 |   } | 
 | 785 |   return true; | 
 | 786 | } | 
 | 787 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 788 | // Handles rem-long and rem-long-2addr instructions. | 
 | 789 | // Returns true on success, otherwise throws a java.lang.ArithmeticException and return false. | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 790 | static inline bool DoLongRemainder(ShadowFrame& shadow_frame, size_t result_reg, | 
 | 791 |                                    int64_t dividend, int64_t divisor) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 792 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Ian Rogers | 2e2deeb | 2013-09-23 11:58:57 -0700 | [diff] [blame] | 793 |   const int64_t kMinLong = std::numeric_limits<int64_t>::min(); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 794 |   if (UNLIKELY(divisor == 0)) { | 
 | 795 |     ThrowArithmeticExceptionDivideByZero(); | 
 | 796 |     return false; | 
 | 797 |   } | 
 | 798 |   if (UNLIKELY(dividend == kMinLong && divisor == -1)) { | 
 | 799 |     shadow_frame.SetVRegLong(result_reg, 0); | 
 | 800 |   } else { | 
 | 801 |     shadow_frame.SetVRegLong(result_reg, dividend % divisor); | 
 | 802 |   } | 
 | 803 |   return true; | 
 | 804 | } | 
 | 805 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 806 | // Handles filled-new-array and filled-new-array-range instructions. | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 807 | // Returns true on success, otherwise throws an exception and returns false. | 
| Sebastien Hertz | d2fe10a | 2014-01-15 10:20:56 +0100 | [diff] [blame] | 808 | template <bool is_range, bool do_access_check, bool transaction_active> | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 809 | bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame, | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 810 |                       Thread* self, JValue* result); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 811 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 812 | // Handles packed-switch instruction. | 
 | 813 | // Returns the branch offset to the next instruction to execute. | 
| Sebastien Hertz | 3b588e0 | 2013-09-11 14:33:18 +0200 | [diff] [blame] | 814 | static inline int32_t DoPackedSwitch(const Instruction* inst, const ShadowFrame& shadow_frame, | 
 | 815 |                                      uint16_t inst_data) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 816 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 817 |   DCHECK(inst->Opcode() == Instruction::PACKED_SWITCH); | 
 | 818 |   const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t(); | 
| Sebastien Hertz | 3b588e0 | 2013-09-11 14:33:18 +0200 | [diff] [blame] | 819 |   int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data)); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 820 |   DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature)); | 
 | 821 |   uint16_t size = switch_data[1]; | 
| David Brazdil | 2ef645b | 2015-06-17 18:20:52 +0100 | [diff] [blame] | 822 |   if (size == 0) { | 
 | 823 |     // Empty packed switch, move forward by 3 (size of PACKED_SWITCH). | 
 | 824 |     return 3; | 
 | 825 |   } | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 826 |   const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]); | 
| Roland Levillain | 14d9057 | 2015-07-16 10:52:26 +0100 | [diff] [blame] | 827 |   DCHECK_ALIGNED(keys, 4); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 828 |   int32_t first_key = keys[0]; | 
 | 829 |   const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]); | 
| Roland Levillain | 14d9057 | 2015-07-16 10:52:26 +0100 | [diff] [blame] | 830 |   DCHECK_ALIGNED(targets, 4); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 831 |   int32_t index = test_val - first_key; | 
 | 832 |   if (index >= 0 && index < size) { | 
 | 833 |     return targets[index]; | 
 | 834 |   } else { | 
 | 835 |     // No corresponding value: move forward by 3 (size of PACKED_SWITCH). | 
 | 836 |     return 3; | 
 | 837 |   } | 
 | 838 | } | 
 | 839 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 840 | // Handles sparse-switch instruction. | 
 | 841 | // Returns the branch offset to the next instruction to execute. | 
| Sebastien Hertz | 3b588e0 | 2013-09-11 14:33:18 +0200 | [diff] [blame] | 842 | static inline int32_t DoSparseSwitch(const Instruction* inst, const ShadowFrame& shadow_frame, | 
 | 843 |                                      uint16_t inst_data) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 844 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 845 |   DCHECK(inst->Opcode() == Instruction::SPARSE_SWITCH); | 
 | 846 |   const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t(); | 
| Sebastien Hertz | 3b588e0 | 2013-09-11 14:33:18 +0200 | [diff] [blame] | 847 |   int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data)); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 848 |   DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature)); | 
 | 849 |   uint16_t size = switch_data[1]; | 
| Jeff Hao | 935e01a | 2015-03-20 19:44:35 -0700 | [diff] [blame] | 850 |   // Return length of SPARSE_SWITCH if size is 0. | 
 | 851 |   if (size == 0) { | 
 | 852 |     return 3; | 
 | 853 |   } | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 854 |   const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]); | 
| Roland Levillain | 14d9057 | 2015-07-16 10:52:26 +0100 | [diff] [blame] | 855 |   DCHECK_ALIGNED(keys, 4); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 856 |   const int32_t* entries = keys + size; | 
| Roland Levillain | 14d9057 | 2015-07-16 10:52:26 +0100 | [diff] [blame] | 857 |   DCHECK_ALIGNED(entries, 4); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 858 |   int lo = 0; | 
 | 859 |   int hi = size - 1; | 
 | 860 |   while (lo <= hi) { | 
 | 861 |     int mid = (lo + hi) / 2; | 
 | 862 |     int32_t foundVal = keys[mid]; | 
 | 863 |     if (test_val < foundVal) { | 
 | 864 |       hi = mid - 1; | 
 | 865 |     } else if (test_val > foundVal) { | 
 | 866 |       lo = mid + 1; | 
 | 867 |     } else { | 
 | 868 |       return entries[mid]; | 
 | 869 |     } | 
 | 870 |   } | 
 | 871 |   // No corresponding value: move forward by 3 (size of SPARSE_SWITCH). | 
 | 872 |   return 3; | 
 | 873 | } | 
 | 874 |  | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 875 | template <bool _do_check> | 
 | 876 | static inline bool DoBoxLambda(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 877 |                                uint16_t inst_data) SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 878 |   /* | 
 | 879 |    * box-lambda vA, vB /// opcode 0xf8, format 22x | 
 | 880 |    * - vA is the target register where the Object representation of the closure will be stored into | 
 | 881 |    * - vB is a closure (made by create-lambda) | 
 | 882 |    *   (also reads vB + 1) | 
 | 883 |    */ | 
 | 884 |   uint32_t vreg_target_object = inst->VRegA_22x(inst_data); | 
 | 885 |   uint32_t vreg_source_closure = inst->VRegB_22x(); | 
 | 886 |  | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 887 |   lambda::Closure* lambda_closure = ReadLambdaClosureFromVRegsOrThrow(shadow_frame, | 
 | 888 |                                                                       vreg_source_closure); | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 889 |  | 
 | 890 |   // Failed lambda target runtime check, an exception was raised. | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 891 |   if (UNLIKELY(lambda_closure == nullptr)) { | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 892 |     CHECK(self->IsExceptionPending()); | 
 | 893 |     return false; | 
 | 894 |   } | 
 | 895 |  | 
| Igor Murashkin | e2facc5 | 2015-07-10 13:49:08 -0700 | [diff] [blame] | 896 |   mirror::Object* closure_as_object = | 
| Nicolas Geoffray | 3a09092 | 2015-11-24 09:17:30 +0000 | [diff] [blame] | 897 |       Runtime::Current()->GetLambdaBoxTable()->BoxLambda(lambda_closure); | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 898 |  | 
| Igor Murashkin | e2facc5 | 2015-07-10 13:49:08 -0700 | [diff] [blame] | 899 |   // Failed to box the lambda, an exception was raised. | 
 | 900 |   if (UNLIKELY(closure_as_object == nullptr)) { | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 901 |     CHECK(self->IsExceptionPending()); | 
 | 902 |     return false; | 
 | 903 |   } | 
 | 904 |  | 
| Igor Murashkin | e2facc5 | 2015-07-10 13:49:08 -0700 | [diff] [blame] | 905 |   shadow_frame.SetVRegReference(vreg_target_object, closure_as_object); | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 906 |   return true; | 
 | 907 | } | 
 | 908 |  | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 909 | template <bool _do_check> SHARED_REQUIRES(Locks::mutator_lock_) | 
| Igor Murashkin | e2facc5 | 2015-07-10 13:49:08 -0700 | [diff] [blame] | 910 | static inline bool DoUnboxLambda(Thread* self, | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 911 |                                  ShadowFrame& shadow_frame, | 
 | 912 |                                  const Instruction* inst, | 
 | 913 |                                  uint16_t inst_data) { | 
 | 914 |   /* | 
 | 915 |    * unbox-lambda vA, vB, [type id] /// opcode 0xf9, format 22c | 
 | 916 |    * - vA is the target register where the closure will be written into | 
 | 917 |    *   (also writes vA + 1) | 
 | 918 |    * - vB is the Object representation of the closure (made by box-lambda) | 
 | 919 |    */ | 
 | 920 |   uint32_t vreg_target_closure = inst->VRegA_22c(inst_data); | 
 | 921 |   uint32_t vreg_source_object = inst->VRegB_22c(); | 
 | 922 |  | 
 | 923 |   // Raise NullPointerException if object is null | 
 | 924 |   mirror::Object* boxed_closure_object = shadow_frame.GetVRegReference(vreg_source_object); | 
 | 925 |   if (UNLIKELY(boxed_closure_object == nullptr)) { | 
 | 926 |     ThrowNullPointerExceptionFromInterpreter(); | 
 | 927 |     return false; | 
 | 928 |   } | 
 | 929 |  | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 930 |   lambda::Closure* unboxed_closure = nullptr; | 
| Igor Murashkin | e2facc5 | 2015-07-10 13:49:08 -0700 | [diff] [blame] | 931 |   // Raise an exception if unboxing fails. | 
 | 932 |   if (!Runtime::Current()->GetLambdaBoxTable()->UnboxLambda(boxed_closure_object, | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 933 |                                                             /*out*/&unboxed_closure)) { | 
| Igor Murashkin | e2facc5 | 2015-07-10 13:49:08 -0700 | [diff] [blame] | 934 |     CHECK(self->IsExceptionPending()); | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 935 |     return false; | 
 | 936 |   } | 
 | 937 |  | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 938 |   DCHECK(unboxed_closure != nullptr); | 
| Igor Murashkin | 30c475a | 2015-10-06 13:59:43 -0700 | [diff] [blame] | 939 |   WriteLambdaClosureIntoVRegs(/*inout*/shadow_frame, *unboxed_closure, vreg_target_closure); | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 940 |   return true; | 
 | 941 | } | 
 | 942 |  | 
| Ian Rogers | 5487494 | 2014-06-10 16:31:03 -0700 | [diff] [blame] | 943 | uint32_t FindNextInstructionFollowingException(Thread* self, ShadowFrame& shadow_frame, | 
| Sebastien Hertz | 9f10203 | 2014-05-23 08:59:42 +0200 | [diff] [blame] | 944 |     uint32_t dex_pc, const instrumentation::Instrumentation* instrumentation) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 945 |         SHARED_REQUIRES(Locks::mutator_lock_); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 946 |  | 
| Andreas Gampe | 794ad76 | 2015-02-23 08:12:24 -0800 | [diff] [blame] | 947 | NO_RETURN void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame) | 
 | 948 |   __attribute__((cold)) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 949 |   SHARED_REQUIRES(Locks::mutator_lock_); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 950 |  | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 951 | static inline void TraceExecution(const ShadowFrame& shadow_frame, const Instruction* inst, | 
| Ian Rogers | e94652f | 2014-12-02 11:13:19 -0800 | [diff] [blame] | 952 |                                   const uint32_t dex_pc) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 953 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Mathieu Chartier | e861ebd | 2013-10-09 15:01:21 -0700 | [diff] [blame] | 954 |   constexpr bool kTracing = false; | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 955 |   if (kTracing) { | 
 | 956 | #define TRACE_LOG std::cerr | 
| Mathieu Chartier | e861ebd | 2013-10-09 15:01:21 -0700 | [diff] [blame] | 957 |     std::ostringstream oss; | 
 | 958 |     oss << PrettyMethod(shadow_frame.GetMethod()) | 
 | 959 |         << StringPrintf("\n0x%x: ", dex_pc) | 
| Ian Rogers | e94652f | 2014-12-02 11:13:19 -0800 | [diff] [blame] | 960 |         << inst->DumpString(shadow_frame.GetMethod()->GetDexFile()) << "\n"; | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 961 |     for (uint32_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) { | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 962 |       uint32_t raw_value = shadow_frame.GetVReg(i); | 
 | 963 |       Object* ref_value = shadow_frame.GetVRegReference(i); | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 964 |       oss << StringPrintf(" vreg%u=0x%08X", i, raw_value); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 965 |       if (ref_value != nullptr) { | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 966 |         if (ref_value->GetClass()->IsStringClass() && | 
| Jeff Hao | 848f70a | 2014-01-15 13:49:50 -0800 | [diff] [blame] | 967 |             ref_value->AsString()->GetValue() != nullptr) { | 
| Mathieu Chartier | e861ebd | 2013-10-09 15:01:21 -0700 | [diff] [blame] | 968 |           oss << "/java.lang.String \"" << ref_value->AsString()->ToModifiedUtf8() << "\""; | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 969 |         } else { | 
| Mathieu Chartier | e861ebd | 2013-10-09 15:01:21 -0700 | [diff] [blame] | 970 |           oss << "/" << PrettyTypeOf(ref_value); | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 971 |         } | 
 | 972 |       } | 
 | 973 |     } | 
| Mathieu Chartier | e861ebd | 2013-10-09 15:01:21 -0700 | [diff] [blame] | 974 |     TRACE_LOG << oss.str() << "\n"; | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 975 | #undef TRACE_LOG | 
 | 976 |   } | 
 | 977 | } | 
 | 978 |  | 
| Sebastien Hertz | 1eda226 | 2013-09-09 16:53:14 +0200 | [diff] [blame] | 979 | static inline bool IsBackwardBranch(int32_t branch_offset) { | 
 | 980 |   return branch_offset <= 0; | 
 | 981 | } | 
 | 982 |  | 
| Siva Chandra | 05d2415 | 2016-01-05 17:43:17 -0800 | [diff] [blame^] | 983 | void ArtInterpreterToCompiledCodeBridge(Thread* self, const DexFile::CodeItem* code_item, | 
 | 984 |                                         ShadowFrame* shadow_frame, JValue* result); | 
 | 985 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 986 | // Explicitly instantiate all DoInvoke functions. | 
| Bernhard Rosenkränzer | 4605362 | 2013-12-12 02:15:52 +0100 | [diff] [blame] | 987 | #define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range, _do_check)                      \ | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 988 |   template SHARED_REQUIRES(Locks::mutator_lock_)                                     \ | 
| Bernhard Rosenkränzer | 4605362 | 2013-12-12 02:15:52 +0100 | [diff] [blame] | 989 |   bool DoInvoke<_type, _is_range, _do_check>(Thread* self, ShadowFrame& shadow_frame,      \ | 
 | 990 |                                              const Instruction* inst, uint16_t inst_data,  \ | 
 | 991 |                                              JValue* result) | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 992 |  | 
 | 993 | #define EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(_type)       \ | 
 | 994 |   EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, false);  \ | 
 | 995 |   EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, true);   \ | 
 | 996 |   EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, true, false);   \ | 
 | 997 |   EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, true, true); | 
 | 998 |  | 
| Andreas Gampe | c8ccf68 | 2014-09-29 20:07:43 -0700 | [diff] [blame] | 999 | EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kStatic)      // invoke-static/range. | 
 | 1000 | EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kDirect)      // invoke-direct/range. | 
 | 1001 | EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kVirtual)     // invoke-virtual/range. | 
 | 1002 | EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kSuper)       // invoke-super/range. | 
 | 1003 | EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kInterface)   // invoke-interface/range. | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 1004 | #undef EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL | 
 | 1005 | #undef EXPLICIT_DO_INVOKE_TEMPLATE_DECL | 
 | 1006 |  | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 1007 | // Explicitly instantiate all DoInvokeVirtualQuick functions. | 
| Bernhard Rosenkränzer | 4605362 | 2013-12-12 02:15:52 +0100 | [diff] [blame] | 1008 | #define EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(_is_range)                    \ | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 1009 |   template SHARED_REQUIRES(Locks::mutator_lock_)                               \ | 
| Bernhard Rosenkränzer | 4605362 | 2013-12-12 02:15:52 +0100 | [diff] [blame] | 1010 |   bool DoInvokeVirtualQuick<_is_range>(Thread* self, ShadowFrame& shadow_frame,      \ | 
 | 1011 |                                        const Instruction* inst, uint16_t inst_data,  \ | 
 | 1012 |                                        JValue* result) | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 1013 |  | 
 | 1014 | EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(false);  // invoke-virtual-quick. | 
 | 1015 | EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(true);   // invoke-virtual-quick-range. | 
 | 1016 | #undef EXPLICIT_INSTANTIATION_DO_INVOKE_VIRTUAL_QUICK | 
 | 1017 |  | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 1018 | // Explicitly instantiate all DoCreateLambda functions. | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 1019 | #define EXPLICIT_DO_CREATE_LAMBDA_DECL(_do_check)                                                 \ | 
 | 1020 | template SHARED_REQUIRES(Locks::mutator_lock_)                                                    \ | 
 | 1021 | bool DoCreateLambda<_do_check>(Thread* self,                                                      \ | 
 | 1022 |                                const Instruction* inst,                                           \ | 
 | 1023 |                                /*inout*/ShadowFrame& shadow_frame,                                \ | 
 | 1024 |                                /*inout*/lambda::ClosureBuilder* closure_builder,                  \ | 
 | 1025 |                                /*inout*/lambda::Closure* uninitialized_closure); | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 1026 |  | 
 | 1027 | EXPLICIT_DO_CREATE_LAMBDA_DECL(false);  // create-lambda | 
 | 1028 | EXPLICIT_DO_CREATE_LAMBDA_DECL(true);   // create-lambda | 
 | 1029 | #undef EXPLICIT_DO_CREATE_LAMBDA_DECL | 
 | 1030 |  | 
 | 1031 | // Explicitly instantiate all DoInvokeLambda functions. | 
 | 1032 | #define EXPLICIT_DO_INVOKE_LAMBDA_DECL(_do_check)                                    \ | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 1033 | template SHARED_REQUIRES(Locks::mutator_lock_)                                 \ | 
| Igor Murashkin | 158f35c | 2015-06-10 15:55:30 -0700 | [diff] [blame] | 1034 | bool DoInvokeLambda<_do_check>(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, \ | 
 | 1035 |                                uint16_t inst_data, JValue* result); | 
 | 1036 |  | 
 | 1037 | EXPLICIT_DO_INVOKE_LAMBDA_DECL(false);  // invoke-lambda | 
 | 1038 | EXPLICIT_DO_INVOKE_LAMBDA_DECL(true);   // invoke-lambda | 
 | 1039 | #undef EXPLICIT_DO_INVOKE_LAMBDA_DECL | 
 | 1040 |  | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 1041 | // Explicitly instantiate all DoBoxLambda functions. | 
 | 1042 | #define EXPLICIT_DO_BOX_LAMBDA_DECL(_do_check)                                                \ | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 1043 | template SHARED_REQUIRES(Locks::mutator_lock_)                                          \ | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 1044 | bool DoBoxLambda<_do_check>(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, \ | 
 | 1045 |                             uint16_t inst_data); | 
 | 1046 |  | 
 | 1047 | EXPLICIT_DO_BOX_LAMBDA_DECL(false);  // box-lambda | 
 | 1048 | EXPLICIT_DO_BOX_LAMBDA_DECL(true);   // box-lambda | 
 | 1049 | #undef EXPLICIT_DO_BOX_LAMBDA_DECL | 
 | 1050 |  | 
 | 1051 | // Explicitly instantiate all DoUnBoxLambda functions. | 
 | 1052 | #define EXPLICIT_DO_UNBOX_LAMBDA_DECL(_do_check)                                                \ | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 1053 | template SHARED_REQUIRES(Locks::mutator_lock_)                                            \ | 
| Igor Murashkin | 2ee54e2 | 2015-06-18 10:05:11 -0700 | [diff] [blame] | 1054 | bool DoUnboxLambda<_do_check>(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, \ | 
 | 1055 |                               uint16_t inst_data); | 
 | 1056 |  | 
 | 1057 | EXPLICIT_DO_UNBOX_LAMBDA_DECL(false);  // unbox-lambda | 
 | 1058 | EXPLICIT_DO_UNBOX_LAMBDA_DECL(true);   // unbox-lambda | 
 | 1059 | #undef EXPLICIT_DO_BOX_LAMBDA_DECL | 
 | 1060 |  | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 1061 | // Explicitly instantiate all DoCaptureVariable functions. | 
 | 1062 | #define EXPLICIT_DO_CAPTURE_VARIABLE_DECL(_do_check)                                    \ | 
 | 1063 | template SHARED_REQUIRES(Locks::mutator_lock_)                                          \ | 
 | 1064 | bool DoCaptureVariable<_do_check>(Thread* self,                                         \ | 
 | 1065 |                                   const Instruction* inst,                              \ | 
 | 1066 |                                   ShadowFrame& shadow_frame,                            \ | 
 | 1067 |                                   lambda::ClosureBuilder* closure_builder); | 
| Sebastien Hertz | c671485 | 2013-09-30 16:42:32 +0200 | [diff] [blame] | 1068 |  | 
| Igor Murashkin | 6918bf1 | 2015-09-27 19:19:06 -0700 | [diff] [blame] | 1069 | EXPLICIT_DO_CAPTURE_VARIABLE_DECL(false);  // capture-variable | 
 | 1070 | EXPLICIT_DO_CAPTURE_VARIABLE_DECL(true);   // capture-variable | 
 | 1071 | #undef EXPLICIT_DO_CREATE_LAMBDA_DECL | 
 | 1072 |  | 
 | 1073 | // Explicitly instantiate all DoLiberateVariable functions. | 
 | 1074 | #define EXPLICIT_DO_LIBERATE_VARIABLE_DECL(_do_check)                                   \ | 
 | 1075 | template SHARED_REQUIRES(Locks::mutator_lock_)                                          \ | 
 | 1076 | bool DoLiberateVariable<_do_check>(Thread* self,                                        \ | 
 | 1077 |                                    const Instruction* inst,                             \ | 
 | 1078 |                                    size_t captured_variable_index,                      \ | 
 | 1079 |                                    ShadowFrame& shadow_frame);                          \ | 
 | 1080 |  | 
 | 1081 | EXPLICIT_DO_LIBERATE_VARIABLE_DECL(false);  // liberate-variable | 
 | 1082 | EXPLICIT_DO_LIBERATE_VARIABLE_DECL(true);   // liberate-variable | 
 | 1083 | #undef EXPLICIT_DO_LIBERATE_LAMBDA_DECL | 
| Sebastien Hertz | 8ece050 | 2013-08-07 11:26:41 +0200 | [diff] [blame] | 1084 | }  // namespace interpreter | 
 | 1085 | }  // namespace art | 
 | 1086 |  | 
 | 1087 | #endif  // ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_ |