1 /* 2 * Copyright (C) 2024 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_UNSTARTED_RUNTIME_TEST_H_ 18 #define ART_RUNTIME_INTERPRETER_UNSTARTED_RUNTIME_TEST_H_ 19 20 #include "unstarted_runtime.h" 21 22 #include <memory> 23 24 #include "class_linker-inl.h" 25 #include "common_runtime_test.h" 26 #include "handle.h" 27 #include "handle_scope-inl.h" 28 #include "interpreter_common.h" 29 #include "mirror/object_array-alloc-inl.h" 30 #include "mirror/object_array-inl.h" 31 #include "shadow_frame-inl.h" 32 33 namespace art HIDDEN { 34 namespace interpreter { 35 36 // Deleter to be used with ShadowFrame::CreateDeoptimizedFrame objects. 37 struct DeoptShadowFrameDelete { 38 // NOTE: Deleting a const object is valid but free() takes a non-const pointer. operatorDeoptShadowFrameDelete39 void operator()(ShadowFrame* ptr) const { 40 ShadowFrame::DeleteDeoptimizedFrame(ptr); 41 } 42 }; 43 // Alias for std::unique_ptr<> that uses the above deleter. 44 using UniqueDeoptShadowFramePtr = std::unique_ptr<ShadowFrame, DeoptShadowFrameDelete>; 45 46 class UnstartedRuntimeTestBase : public CommonRuntimeTest { 47 protected: 48 // Re-expose all UnstartedRuntime implementations so we don't need to declare a million 49 // test friends. 50 51 // Methods that intercept available libcore implementations. 52 #define UNSTARTED_DIRECT(Name, DescriptorIgnored, NameIgnored, SignatureIgnored) \ 53 static void Unstarted ## Name(Thread* self, \ 54 ShadowFrame* shadow_frame, \ 55 JValue* result, \ 56 size_t arg_offset) \ 57 REQUIRES_SHARED(Locks::mutator_lock_) { \ 58 interpreter::UnstartedRuntime::Unstarted ## Name(self, shadow_frame, result, arg_offset); \ 59 } UNSTARTED_RUNTIME_DIRECT_LIST(UNSTARTED_DIRECT)60 UNSTARTED_RUNTIME_DIRECT_LIST(UNSTARTED_DIRECT) 61 #undef UNSTARTED_DIRECT 62 63 // Methods that are native. 64 #define UNSTARTED_JNI(Name, DescriptorIgnored, NameIgnored, SignatureIgnored) \ 65 static void UnstartedJNI ## Name(Thread* self, \ 66 ArtMethod* method, \ 67 mirror::Object* receiver, \ 68 uint32_t* args, \ 69 JValue* result) \ 70 REQUIRES_SHARED(Locks::mutator_lock_) { \ 71 interpreter::UnstartedRuntime::UnstartedJNI ## Name(self, method, receiver, args, result); \ 72 } 73 UNSTARTED_RUNTIME_JNI_LIST(UNSTARTED_JNI) 74 #undef UNSTARTED_JNI 75 76 UniqueDeoptShadowFramePtr CreateShadowFrame(uint32_t num_vregs, 77 ArtMethod* method, 78 uint32_t dex_pc) { 79 return UniqueDeoptShadowFramePtr( 80 ShadowFrame::CreateDeoptimizedFrame(num_vregs, method, dex_pc)); 81 } 82 GetBootClassLoader()83 mirror::ClassLoader* GetBootClassLoader() REQUIRES_SHARED(Locks::mutator_lock_) { 84 Thread* self = Thread::Current(); 85 StackHandleScope<2> hs(self); 86 87 // Create the fake boot classloader. Any instance is fine, they are technically interchangeable. 88 Handle<mirror::Class> boot_cp_class = hs.NewHandle(class_linker_->FindClass( 89 self, "Ljava/lang/BootClassLoader;", ScopedNullHandle<mirror::ClassLoader>())); 90 CHECK(boot_cp_class != nullptr); 91 CHECK(class_linker_->EnsureInitialized( 92 self, boot_cp_class, /*can_init_fields=*/ true, /*can_init_parents=*/ true)); 93 94 Handle<mirror::ClassLoader> boot_cp = 95 hs.NewHandle(boot_cp_class->AllocObject(self)->AsClassLoader()); 96 CHECK(boot_cp != nullptr); 97 98 ArtMethod* boot_cp_init = 99 boot_cp_class->FindConstructor("()V", class_linker_->GetImagePointerSize()); 100 CHECK(boot_cp_init != nullptr); 101 102 JValue result; 103 UniqueDeoptShadowFramePtr shadow_frame = CreateShadowFrame(10, boot_cp_init, 0); 104 shadow_frame->SetVRegReference(0, boot_cp.Get()); 105 106 // create instruction data for invoke-direct {v0} of method with fake index 107 uint16_t inst_data[3] = { 0x1070, 0x0000, 0x0010 }; 108 109 interpreter::DoCall<false>(boot_cp_init, 110 self, 111 *shadow_frame, 112 Instruction::At(inst_data), 113 inst_data[0], 114 /* string_init= */ false, 115 &result); 116 CHECK(!self->IsExceptionPending()); 117 118 return boot_cp.Get(); 119 } 120 }; 121 122 } // namespace interpreter 123 } // namespace art 124 125 #endif // ART_RUNTIME_INTERPRETER_UNSTARTED_RUNTIME_TEST_H_ 126