diff options
-rw-r--r-- | runtime/arch/arm/quick_entrypoints_arm.S | 68 | ||||
-rw-r--r-- | runtime/arch/arm64/quick_entrypoints_arm64.S | 43 | ||||
-rw-r--r-- | runtime/arch/x86/quick_entrypoints_x86.S | 58 | ||||
-rw-r--r-- | runtime/arch/x86_64/quick_entrypoints_x86_64.S | 59 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc | 6 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 21 | ||||
-rw-r--r-- | runtime/instrumentation.cc | 104 | ||||
-rw-r--r-- | runtime/instrumentation.h | 16 | ||||
-rw-r--r-- | runtime/instrumentation_test.cc | 18 | ||||
-rw-r--r-- | runtime/interpreter/interpreter.cc | 81 | ||||
-rw-r--r-- | runtime/interpreter/interpreter.h | 8 | ||||
-rw-r--r-- | runtime/thread.cc | 33 | ||||
-rw-r--r-- | runtime/thread.h | 15 | ||||
-rw-r--r-- | test/597-deopt-runtime-method/deopt.cc | 60 | ||||
-rw-r--r-- | test/597-deopt-runtime-method/expected.txt | 2 | ||||
-rw-r--r-- | test/597-deopt-runtime-method/info.txt | 1 | ||||
-rw-r--r-- | test/597-deopt-runtime-method/run | 18 | ||||
-rw-r--r-- | test/597-deopt-runtime-method/src/Main.java | 70 | ||||
-rw-r--r-- | test/knownfailures.json | 3 |
19 files changed, 202 insertions, 482 deletions
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S index ea8d501939..cf2bfeeeef 100644 --- a/runtime/arch/arm/quick_entrypoints_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -1832,45 +1832,47 @@ ENTRY art_quick_instrumentation_entry mov r12, r0 @ r12 holds reference to code ldr r0, [sp, #4] @ restore r0 RESTORE_SAVE_REFS_AND_ARGS_FRAME - adr lr, art_quick_instrumentation_exit + /* thumb mode */ 1 - @ load art_quick_instrumentation_exit into lr in thumb mode REFRESH_MARKING_REGISTER - bx r12 @ call method with lr set to art_quick_instrumentation_exit -.Ldeliver_instrumentation_entry_exception: - @ Deliver exception for art_quick_instrumentation_entry placed after - @ art_quick_instrumentation_exit so that the fallthrough works. - RESTORE_SAVE_REFS_AND_ARGS_FRAME - DELIVER_PENDING_EXCEPTION -END art_quick_instrumentation_entry - -ENTRY art_quick_instrumentation_exit + blx r12 @ call method with lr set to art_quick_instrumentation_exit +@ Deliberate fall-through into art_quick_instrumentation_exit. + .type art_quick_instrumentation_exit, #function + .global art_quick_instrumentation_exit +art_quick_instrumentation_exit: mov lr, #0 @ link register is to here, so clobber with 0 for later checks - SETUP_SAVE_EVERYTHING_FRAME r2 - - add r3, sp, #8 @ store fpr_res pointer, in kSaveEverything frame - add r2, sp, #136 @ store gpr_res pointer, in kSaveEverything frame - mov r1, sp @ pass SP + SETUP_SAVE_REFS_ONLY_FRAME r2 @ set up frame knowing r2 and r3 must be dead on exit + mov r12, sp @ remember bottom of caller's frame + push {r0-r1} @ save return value + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset r1, 4 + mov r2, sp @ store gpr_res pointer. + vpush {d0} @ save fp return value + .cfi_adjust_cfa_offset 8 + mov r3, sp @ store fpr_res pointer + mov r1, r12 @ pass SP mov r0, r9 @ pass Thread::Current blx artInstrumentationMethodExitFromCode @ (Thread*, SP, gpr_res*, fpr_res*) - cbz r0, .Ldo_deliver_instrumentation_exception - @ Deliver exception if we got nullptr as function. - cbnz r1, .Ldeoptimize - // Normal return. - str r0, [sp, #FRAME_SIZE_SAVE_EVERYTHING - 4] - @ Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME + mov r2, r0 @ link register saved by instrumentation + mov lr, r1 @ r1 is holding link register if we're to bounce to deoptimize + vpop {d0} @ restore fp return value + .cfi_adjust_cfa_offset -8 + pop {r0, r1} @ restore return value + .cfi_adjust_cfa_offset -8 + .cfi_restore r0 + .cfi_restore r1 + RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER - bx lr + cbz r2, .Ldo_deliver_instrumentation_exception + @ Deliver exception if we got nullptr as function. + bx r2 @ Otherwise, return +.Ldeliver_instrumentation_entry_exception: + @ Deliver exception for art_quick_instrumentation_entry placed after + @ art_quick_instrumentation_exit so that the fallthrough works. + RESTORE_SAVE_REFS_AND_ARGS_FRAME .Ldo_deliver_instrumentation_exception: - DELIVER_PENDING_EXCEPTION_FRAME_READY -.Ldeoptimize: - str r1, [sp, #FRAME_SIZE_SAVE_EVERYTHING - 4] - @ Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - // Jump to art_quick_deoptimize. - b art_quick_deoptimize -END art_quick_instrumentation_exit + DELIVER_PENDING_EXCEPTION +END art_quick_instrumentation_entry /* * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization @@ -1878,7 +1880,7 @@ END art_quick_instrumentation_exit */ .extern artDeoptimize ENTRY art_quick_deoptimize - SETUP_SAVE_EVERYTHING_FRAME r0 + SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r0 mov r0, r9 @ pass Thread::Current blx artDeoptimize @ (Thread*) END art_quick_deoptimize diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S index 6c9ce93d2e..3d8ca402cf 100644 --- a/runtime/arch/arm64/quick_entrypoints_arm64.S +++ b/runtime/arch/arm64/quick_entrypoints_arm64.S @@ -2355,31 +2355,32 @@ END art_quick_instrumentation_entry .extern artInstrumentationMethodExitFromCode ENTRY art_quick_instrumentation_exit mov xLR, #0 // Clobber LR for later checks. - SETUP_SAVE_EVERYTHING_FRAME - add x3, sp, #8 // Pass floating-point result pointer, in kSaveEverything frame. - add x2, sp, #264 // Pass integer result pointer, in kSaveEverything frame. - mov x1, sp // Pass SP. + SETUP_SAVE_REFS_ONLY_FRAME + + str x0, [sp, #-16]! // Save integer result. + .cfi_adjust_cfa_offset 16 + str d0, [sp, #8] // Save floating-point result. + + add x3, sp, #8 // Pass floating-point result pointer. + mov x2, sp // Pass integer result pointer. + add x1, sp, #16 // Pass SP. mov x0, xSELF // Pass Thread. bl artInstrumentationMethodExitFromCode // (Thread*, SP, gpr_res*, fpr_res*) - cbz x0, .Ldo_deliver_instrumentation_exception - // Handle error - cbnz x1, .Ldeoptimize - // Normal return. - str x0, [sp, #FRAME_SIZE_SAVE_EVERYTHING - 8] - // Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME + mov xIP0, x0 // Return address from instrumentation call. + mov xLR, x1 // r1 is holding link register if we're to bounce to deoptimize + + ldr d0, [sp, #8] // Restore floating-point result. + ldr x0, [sp], #16 // Restore integer result, and drop stack area. + .cfi_adjust_cfa_offset -16 + + RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER - br lr -.Ldo_deliver_instrumentation_exception: - DELIVER_PENDING_EXCEPTION_FRAME_READY -.Ldeoptimize: - str x1, [sp, #FRAME_SIZE_SAVE_EVERYTHING - 8] - // Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - // Jump to art_quick_deoptimize. - b art_quick_deoptimize + cbz xIP0, 1f // Handle error + br xIP0 // Tail-call out. +1: + DELIVER_PENDING_EXCEPTION END art_quick_instrumentation_exit /* @@ -2388,7 +2389,7 @@ END art_quick_instrumentation_exit */ .extern artDeoptimize ENTRY art_quick_deoptimize - SETUP_SAVE_EVERYTHING_FRAME + SETUP_SAVE_ALL_CALLEE_SAVES_FRAME mov x0, xSELF // Pass thread. bl artDeoptimize // (Thread*) brk 0 diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index af82e08698..4e5e93ac5a 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -2056,43 +2056,42 @@ END_FUNCTION art_quick_instrumentation_entry DEFINE_FUNCTION_CUSTOM_CFA art_quick_instrumentation_exit, 0 pushl LITERAL(0) // Push a fake return PC as there will be none on the stack. CFI_ADJUST_CFA_OFFSET(4) - SETUP_SAVE_EVERYTHING_FRAME ebx, ebx - - movl %esp, %ecx // Remember SP - subl LITERAL(8), %esp // Align stack. + SETUP_SAVE_REFS_ONLY_FRAME ebx, ebx + mov %esp, %ecx // Remember SP + subl LITERAL(8), %esp // Save float return value. CFI_ADJUST_CFA_OFFSET(8) - PUSH edx // Save gpr return value. edx and eax need to be together, - // which isn't the case in kSaveEverything frame. + movq %xmm0, (%esp) + PUSH edx // Save gpr return value. PUSH eax - leal 32(%esp), %eax // Get pointer to fpr_result, in kSaveEverything frame + leal 8(%esp), %eax // Get pointer to fpr_result movl %esp, %edx // Get pointer to gpr_result PUSH eax // Pass fpr_result PUSH edx // Pass gpr_result - PUSH ecx // Pass SP + PUSH ecx // Pass SP. pushl %fs:THREAD_SELF_OFFSET // Pass Thread::Current. CFI_ADJUST_CFA_OFFSET(4) - call SYMBOL(artInstrumentationMethodExitFromCode) // (Thread*, SP, gpr_result*, fpr_result*) - // Return result could have been changed if it's a reference. - movl 16(%esp), %ecx - movl %ecx, (80+32)(%esp) - addl LITERAL(32), %esp // Pop arguments and grp_result. - CFI_ADJUST_CFA_OFFSET(-32) - testl %eax, %eax // Check if we returned error. - jz .Ldo_deliver_instrumentation_exception - testl %edx, %edx - jnz .Ldeoptimize - // Normal return. - movl %eax, FRAME_SIZE_SAVE_EVERYTHING-4(%esp) // Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - ret -.Ldeoptimize: - mov %edx, (FRAME_SIZE_SAVE_EVERYTHING-4)(%esp) // Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - jmp SYMBOL(art_quick_deoptimize) -.Ldo_deliver_instrumentation_exception: - DELIVER_PENDING_EXCEPTION_FRAME_READY + jz 1f + mov %eax, %ecx // Move returned link register. + addl LITERAL(16), %esp // Pop arguments. + CFI_ADJUST_CFA_OFFSET(-16) + movl %edx, %ebx // Move returned link register for deopt + // (ebx is pretending to be our LR). + POP eax // Restore gpr return value. + POP edx + movq (%esp), %xmm0 // Restore fpr return value. + addl LITERAL(8), %esp + CFI_ADJUST_CFA_OFFSET(-8) + RESTORE_SAVE_REFS_ONLY_FRAME + addl LITERAL(4), %esp // Remove fake return pc. + CFI_ADJUST_CFA_OFFSET(-4) + jmp *%ecx // Return. +1: + addl LITERAL(32), %esp + CFI_ADJUST_CFA_OFFSET(-32) + RESTORE_SAVE_REFS_ONLY_FRAME + DELIVER_PENDING_EXCEPTION END_FUNCTION art_quick_instrumentation_exit /* @@ -2100,7 +2099,8 @@ END_FUNCTION art_quick_instrumentation_exit * will long jump to the upcall with a special exception of -1. */ DEFINE_FUNCTION art_quick_deoptimize - SETUP_SAVE_EVERYTHING_FRAME ebx, ebx + PUSH ebx // Entry point for a jump. Fake that we were called. + SETUP_SAVE_ALL_CALLEE_SAVES_FRAME ebx, ebx subl LITERAL(12), %esp // Align stack. CFI_ADJUST_CFA_OFFSET(12) pushl %fs:THREAD_SELF_OFFSET // Pass Thread::Current(). diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S index 6bf08289ee..73e86100f6 100644 --- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S +++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S @@ -2019,31 +2019,45 @@ DEFINE_FUNCTION_CUSTOM_CFA art_quick_instrumentation_exit, 0 pushq LITERAL(0) // Push a fake return PC as there will be none on the stack. CFI_ADJUST_CFA_OFFSET(8) - SETUP_SAVE_EVERYTHING_FRAME + SETUP_SAVE_REFS_ONLY_FRAME - leaq 16(%rsp), %rcx // Pass floating-point result pointer, in kSaveEverything frame. - leaq 144(%rsp), %rdx // Pass integer result pointer, in kSaveEverything frame. - movq %rsp, %rsi // Pass SP. - movq %gs:THREAD_SELF_OFFSET, %rdi // Pass Thread. + // We need to save rax and xmm0. We could use a callee-save from SETUP_REF_ONLY, but then + // we would need to fully restore it. As there are a good number of callee-save registers, it + // seems easier to have an extra small stack area. But this should be revisited. + + movq %rsp, %rsi // Pass SP. + + PUSH rax // Save integer result. + movq %rsp, %rdx // Pass integer result pointer. + + subq LITERAL(8), %rsp // Save floating-point result. + CFI_ADJUST_CFA_OFFSET(8) + movq %xmm0, (%rsp) + movq %rsp, %rcx // Pass floating-point result pointer. + + movq %gs:THREAD_SELF_OFFSET, %rdi // Pass Thread. call SYMBOL(artInstrumentationMethodExitFromCode) // (Thread*, SP, gpr_res*, fpr_res*) - testq %rax, %rax // Check if we have a return-pc to go to. If we don't then there was + movq %rax, %rdi // Store return PC + movq %rdx, %rsi // Store second return PC in hidden arg. + + movq (%rsp), %xmm0 // Restore floating-point result. + addq LITERAL(8), %rsp + CFI_ADJUST_CFA_OFFSET(-8) + POP rax // Restore integer result. + + RESTORE_SAVE_REFS_ONLY_FRAME + + testq %rdi, %rdi // Check if we have a return-pc to go to. If we don't then there was // an exception - jz .Ldo_deliver_instrumentation_exception - testq %rdx, %rdx - jnz .Ldeoptimize - // Normal return. - movq %rax, FRAME_SIZE_SAVE_EVERYTHING-8(%rsp) // Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - ret -.Ldeoptimize: - movq %rdx, FRAME_SIZE_SAVE_EVERYTHING-8(%rsp) // Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - // Jump to art_quick_deoptimize. - jmp SYMBOL(art_quick_deoptimize) -.Ldo_deliver_instrumentation_exception: - DELIVER_PENDING_EXCEPTION_FRAME_READY + jz 1f + + addq LITERAL(8), %rsp // Drop fake return pc. + + jmp *%rdi // Return. +1: + DELIVER_PENDING_EXCEPTION END_FUNCTION art_quick_instrumentation_exit /* @@ -2051,7 +2065,10 @@ END_FUNCTION art_quick_instrumentation_exit * will long jump to the upcall with a special exception of -1. */ DEFINE_FUNCTION art_quick_deoptimize - SETUP_SAVE_EVERYTHING_FRAME // Stack should be aligned now. + pushq %rsi // Entry point for a jump. Fake that we were called. + // Use hidden arg. + SETUP_SAVE_ALL_CALLEE_SAVES_FRAME + // Stack should be aligned now. movq %gs:THREAD_SELF_OFFSET, %rdi // Pass Thread. call SYMBOL(artDeoptimize) // (Thread*) UNREACHABLE diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc index 5f40711753..53f0727a5f 100644 --- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc @@ -73,11 +73,7 @@ extern "C" NO_RETURN void artDeoptimizeFromCompiledCode(DeoptimizationKind kind, // Before deoptimizing to interpreter, we must push the deoptimization context. JValue return_value; return_value.SetJ(0); // we never deoptimize from compiled code with an invoke result. - self->PushDeoptimizationContext(return_value, - false /* is_reference */, - self->GetException(), - true /* from_code */, - DeoptimizationMethodType::kDefault); + self->PushDeoptimizationContext(return_value, false, /* from_code */ true, self->GetException()); artDeoptimizeImpl(self, kind, true); } diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 5f713265df..e08319d509 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -744,11 +744,7 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, ObjPtr<mirror::Throwable> pending_exception; bool from_code = false; - DeoptimizationMethodType method_type; - self->PopDeoptimizationContext(/* out */ &result, - /* out */ &pending_exception, - /* out */ &from_code, - /* out */ &method_type); + self->PopDeoptimizationContext(&result, &pending_exception, /* out */ &from_code); // Push a transition back into managed code onto the linked list in thread. self->PushManagedStackFragment(&fragment); @@ -775,11 +771,7 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, if (pending_exception != nullptr) { self->SetException(pending_exception); } - interpreter::EnterInterpreterFromDeoptimize(self, - deopt_frame, - &result, - from_code, - DeoptimizationMethodType::kDefault); + interpreter::EnterInterpreterFromDeoptimize(self, deopt_frame, from_code, &result); } else { const char* old_cause = self->StartAssertNoThreadSuspension( "Building interpreter shadow frame"); @@ -831,11 +823,7 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, // Push the context of the deoptimization stack so we can restore the return value and the // exception before executing the deoptimized frames. self->PushDeoptimizationContext( - result, - shorty[0] == 'L' || shorty[0] == '[', /* class or array */ - self->GetException(), - false /* from_code */, - DeoptimizationMethodType::kDefault); + result, shorty[0] == 'L', /* from_code */ false, self->GetException()); // Set special exception to cause deoptimization. self->SetException(Thread::GetDeoptimizationException()); @@ -1053,8 +1041,7 @@ extern "C" TwoWordReturn artInstrumentationMethodExitFromCode(Thread* self, CHECK(!self->IsExceptionPending()) << "Enter instrumentation exit stub with pending exception " << self->GetException()->Dump(); // Compute address of return PC and sanity check that it currently holds 0. - size_t return_pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, - CalleeSaveType::kSaveEverything); + size_t return_pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, CalleeSaveType::kSaveRefsOnly); uintptr_t* return_pc = reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(sp) + return_pc_offset); CHECK_EQ(*return_pc, 0U); diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 916928d39b..a8cf59b326 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -227,32 +227,39 @@ static void InstrumentationInstallStack(Thread* thread, void* arg) return true; // Continue. } uintptr_t return_pc = GetReturnPc(); - if (kVerboseInstrumentation) { - LOG(INFO) << " Installing exit stub in " << DescribeLocation(); - } - if (return_pc == instrumentation_exit_pc_) { - CHECK_LT(instrumentation_stack_depth_, instrumentation_stack_->size()); - - if (m->IsRuntimeMethod()) { + if (m->IsRuntimeMethod()) { + if (return_pc == instrumentation_exit_pc_) { + if (kVerboseInstrumentation) { + LOG(INFO) << " Handling quick to interpreter transition. Frame " << GetFrameId(); + } + CHECK_LT(instrumentation_stack_depth_, instrumentation_stack_->size()); const InstrumentationStackFrame& frame = instrumentation_stack_->at(instrumentation_stack_depth_); - if (frame.interpreter_entry_) { - // This instrumentation frame is for an interpreter bridge and is - // pushed when executing the instrumented interpreter bridge. So method - // enter event must have been reported. However we need to push a DEX pc - // into the dex_pcs_ list to match size of instrumentation stack. - uint32_t dex_pc = DexFile::kDexNoIndex; - dex_pcs_.push_back(dex_pc); - last_return_pc_ = frame.return_pc_; - ++instrumentation_stack_depth_; - return true; + CHECK(frame.interpreter_entry_); + // This is an interpreter frame so method enter event must have been reported. However we + // need to push a DEX pc into the dex_pcs_ list to match size of instrumentation stack. + // Since we won't report method entry here, we can safely push any DEX pc. + dex_pcs_.push_back(0); + last_return_pc_ = frame.return_pc_; + ++instrumentation_stack_depth_; + return true; + } else { + if (kVerboseInstrumentation) { + LOG(INFO) << " Skipping runtime method. Frame " << GetFrameId(); } + last_return_pc_ = GetReturnPc(); + return true; // Ignore unresolved methods since they will be instrumented after resolution. } - + } + if (kVerboseInstrumentation) { + LOG(INFO) << " Installing exit stub in " << DescribeLocation(); + } + if (return_pc == instrumentation_exit_pc_) { // We've reached a frame which has already been installed with instrumentation exit stub. // We should have already installed instrumentation on previous frames. reached_existing_instrumentation_frames_ = true; + CHECK_LT(instrumentation_stack_depth_, instrumentation_stack_->size()); const InstrumentationStackFrame& frame = instrumentation_stack_->at(instrumentation_stack_depth_); CHECK_EQ(m, frame.method_) << "Expected " << ArtMethod::PrettyMethod(m) @@ -264,12 +271,8 @@ static void InstrumentationInstallStack(Thread* thread, void* arg) } else { CHECK_NE(return_pc, 0U); CHECK(!reached_existing_instrumentation_frames_); - InstrumentationStackFrame instrumentation_frame( - m->IsRuntimeMethod() ? nullptr : GetThisObject(), - m, - return_pc, - GetFrameId(), // A runtime method still gets a frame id. - false); + InstrumentationStackFrame instrumentation_frame(GetThisObject(), m, return_pc, GetFrameId(), + false); if (kVerboseInstrumentation) { LOG(INFO) << "Pushing frame " << instrumentation_frame.Dump(); } @@ -286,12 +289,9 @@ static void InstrumentationInstallStack(Thread* thread, void* arg) instrumentation_stack_->insert(it, instrumentation_frame); SetReturnPc(instrumentation_exit_pc_); } - uint32_t dex_pc = DexFile::kDexNoIndex; - if (last_return_pc_ != 0 && - GetCurrentOatQuickMethodHeader() != nullptr) { - dex_pc = GetCurrentOatQuickMethodHeader()->ToDexPc(m, last_return_pc_); - } - dex_pcs_.push_back(dex_pc); + dex_pcs_.push_back((GetCurrentOatQuickMethodHeader() == nullptr) + ? DexFile::kDexNoIndex + : GetCurrentOatQuickMethodHeader()->ToDexPc(m, last_return_pc_)); last_return_pc_ = return_pc; ++instrumentation_stack_depth_; return true; // Continue. @@ -389,8 +389,7 @@ static void InstrumentationRestoreStack(Thread* thread, void* arg) CHECK(m == instrumentation_frame.method_) << ArtMethod::PrettyMethod(m); } SetReturnPc(instrumentation_frame.return_pc_); - if (instrumentation_->ShouldNotifyMethodEnterExitEvents() && - !m->IsRuntimeMethod()) { + if (instrumentation_->ShouldNotifyMethodEnterExitEvents()) { // Create the method exit events. As the methods didn't really exit the result is 0. // We only do this if no debugger is attached to prevent from posting events twice. instrumentation_->MethodExitEvent(thread_, instrumentation_frame.this_object_, m, @@ -948,7 +947,6 @@ void Instrumentation::MethodEnterEventImpl(Thread* thread, ObjPtr<mirror::Object> this_object, ArtMethod* method, uint32_t dex_pc) const { - DCHECK(!method->IsRuntimeMethod()); if (HasMethodEntryListeners()) { Thread* self = Thread::Current(); StackHandleScope<1> hs(self); @@ -1153,22 +1151,6 @@ void Instrumentation::PushInstrumentationStackFrame(Thread* self, mirror::Object stack->push_front(instrumentation_frame); } -DeoptimizationMethodType Instrumentation::GetDeoptimizationMethodType(ArtMethod* method) { - if (method->IsRuntimeMethod()) { - // Certain methods have strict requirement on whether the dex instruction - // should be re-executed upon deoptimization. - if (method == Runtime::Current()->GetCalleeSaveMethod( - CalleeSaveType::kSaveEverythingForClinit)) { - return DeoptimizationMethodType::kKeepDexPc; - } - if (method == Runtime::Current()->GetCalleeSaveMethod( - CalleeSaveType::kSaveEverythingForSuspendCheck)) { - return DeoptimizationMethodType::kKeepDexPc; - } - } - return DeoptimizationMethodType::kDefault; -} - TwoWordReturn Instrumentation::PopInstrumentationStackFrame(Thread* self, uintptr_t* return_pc, uint64_t* gpr_result, @@ -1189,21 +1171,7 @@ TwoWordReturn Instrumentation::PopInstrumentationStackFrame(Thread* self, ArtMethod* method = instrumentation_frame.method_; uint32_t length; const PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); - char return_shorty; - - // Runtime method does not call into MethodExitEvent() so there should not be - // suspension point below. - ScopedAssertNoThreadSuspension ants(__FUNCTION__, method->IsRuntimeMethod()); - if (method->IsRuntimeMethod()) { - // Some runtime methods such as allocations, unresolved field getters, etc. - // return references. We don't keep track of whether a runtime method returns - // a reference or not. But since there is no suspension point below, we don't - // need to reassign return value. - return_shorty = 'V'; - } else { - return_shorty = method->GetInterfaceMethodIfProxy(pointer_size)->GetShorty(&length)[0]; - } - + char return_shorty = method->GetInterfaceMethodIfProxy(pointer_size)->GetShorty(&length)[0]; bool is_ref = return_shorty == '[' || return_shorty == 'L'; StackHandleScope<1> hs(self); MutableHandle<mirror::Object> res(hs.NewHandle<mirror::Object>(nullptr)); @@ -1223,7 +1191,7 @@ TwoWordReturn Instrumentation::PopInstrumentationStackFrame(Thread* self, // return_pc. uint32_t dex_pc = DexFile::kDexNoIndex; mirror::Object* this_object = instrumentation_frame.this_object_; - if (!method->IsRuntimeMethod() && !instrumentation_frame.interpreter_entry_) { + if (!instrumentation_frame.interpreter_entry_) { MethodExitEvent(self, this_object, instrumentation_frame.method_, dex_pc, return_value); } @@ -1249,12 +1217,10 @@ TwoWordReturn Instrumentation::PopInstrumentationStackFrame(Thread* self, << " in " << *self; } - DeoptimizationMethodType deopt_method_type = GetDeoptimizationMethodType(method); self->PushDeoptimizationContext(return_value, - return_shorty == 'L' || return_shorty == '[', - nullptr /* no pending exception */, + return_shorty == 'L', false /* from_code */, - deopt_method_type); + nullptr /* no pending exception */); return GetTwoWordSuccessValue(*return_pc, reinterpret_cast<uintptr_t>(GetQuickDeoptimizationEntryPoint())); } else { diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h index 577bbf99f1..9969489648 100644 --- a/runtime/instrumentation.h +++ b/runtime/instrumentation.h @@ -39,7 +39,6 @@ class ArtMethod; template <typename T> class Handle; union JValue; class Thread; -enum class DeoptimizationMethodType; namespace instrumentation { @@ -436,9 +435,6 @@ class Instrumentation { bool interpreter_entry) REQUIRES_SHARED(Locks::mutator_lock_); - DeoptimizationMethodType GetDeoptimizationMethodType(ArtMethod* method) - REQUIRES_SHARED(Locks::mutator_lock_); - // Called when an instrumented method is exited. Removes the pushed instrumentation frame // returning the intended link register. Generates method exit events. The gpr_result and // fpr_result pointers are pointers to the locations where the integer/pointer and floating point @@ -665,15 +661,9 @@ std::ostream& operator<<(std::ostream& os, const Instrumentation::Instrumentatio // An element in the instrumentation side stack maintained in art::Thread. struct InstrumentationStackFrame { - InstrumentationStackFrame(mirror::Object* this_object, - ArtMethod* method, - uintptr_t return_pc, - size_t frame_id, - bool interpreter_entry) - : this_object_(this_object), - method_(method), - return_pc_(return_pc), - frame_id_(frame_id), + InstrumentationStackFrame(mirror::Object* this_object, ArtMethod* method, + uintptr_t return_pc, size_t frame_id, bool interpreter_entry) + : this_object_(this_object), method_(method), return_pc_(return_pc), frame_id_(frame_id), interpreter_entry_(interpreter_entry) { } diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc index bfd36cc11c..d25655f15a 100644 --- a/runtime/instrumentation_test.cc +++ b/runtime/instrumentation_test.cc @@ -473,23 +473,7 @@ TEST_F(InstrumentationTest, NoInstrumentation) { // Test instrumentation listeners for each event. TEST_F(InstrumentationTest, MethodEntryEvent) { - ScopedObjectAccess soa(Thread::Current()); - jobject class_loader = LoadDex("Instrumentation"); - Runtime* const runtime = Runtime::Current(); - ClassLinker* class_linker = runtime->GetClassLinker(); - StackHandleScope<1> hs(soa.Self()); - Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); - mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); - ASSERT_TRUE(klass != nullptr); - ArtMethod* method = - klass->FindClassMethod("returnReference", "()Ljava/lang/Object;", kRuntimePointerSize); - ASSERT_TRUE(method != nullptr); - ASSERT_TRUE(method->IsDirect()); - ASSERT_TRUE(method->GetDeclaringClass() == klass); - TestEvent(instrumentation::Instrumentation::kMethodEntered, - /*event_method*/ method, - /*event_field*/ nullptr, - /*with_object*/ true); + TestEvent(instrumentation::Instrumentation::kMethodEntered); } TEST_F(InstrumentationTest, MethodExitObjectEvent) { diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index 25d4dd6985..9cb74f7c36 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -499,9 +499,8 @@ static int16_t GetReceiverRegisterForStringInit(const Instruction* instr) { void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* shadow_frame, - JValue* ret_val, bool from_code, - DeoptimizationMethodType deopt_method_type) + JValue* ret_val) REQUIRES_SHARED(Locks::mutator_lock_) { JValue value; // Set value to last known result in case the shadow frame chain is empty. @@ -528,27 +527,11 @@ void EnterInterpreterFromDeoptimize(Thread* self, new_dex_pc = found_dex_pc; // the dex pc of a matching catch handler // or DexFile::kDexNoIndex if there is none. } else if (!from_code) { - // Deoptimization is not called from code directly. + // For the debugger and full deoptimization stack, we must go past the invoke + // instruction, as it already executed. + // TODO: should be tested more once b/17586779 is fixed. const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]); - if (deopt_method_type == DeoptimizationMethodType::kKeepDexPc) { - DCHECK(first); - // Need to re-execute the dex instruction. - // (1) An invocation might be split into class initialization and invoke. - // In this case, the invoke should not be skipped. - // (2) A suspend check should also execute the dex instruction at the - // corresponding dex pc. - new_dex_pc = dex_pc; - } else if (instr->Opcode() == Instruction::MONITOR_ENTER || - instr->Opcode() == Instruction::MONITOR_EXIT) { - DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault); - DCHECK(first); - // Non-idempotent dex instruction should not be re-executed. - // On the other hand, if a MONITOR_ENTER is at the dex_pc of a suspend - // check, that MONITOR_ENTER should be executed. That case is handled - // above. - new_dex_pc = dex_pc + instr->SizeInCodeUnits(); - } else if (instr->IsInvoke()) { - DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault); + if (instr->IsInvoke()) { if (IsStringInit(instr, shadow_frame->GetMethod())) { uint16_t this_obj_vreg = GetReceiverRegisterForStringInit(instr); // Move the StringFactory.newStringFromChars() result into the register representing @@ -561,44 +544,30 @@ void EnterInterpreterFromDeoptimize(Thread* self, } new_dex_pc = dex_pc + instr->SizeInCodeUnits(); } else if (instr->Opcode() == Instruction::NEW_INSTANCE) { - DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault); - if (!first && value.GetL()->IsString()) { - // It's possible to deoptimize at a NEW_INSTANCE dex instruction that's for a - // java string, which is turned into a call into StringFactory.newEmptyString(); - // Move the StringFactory.newEmptyString() result into the destination register. - shadow_frame->SetVRegReference(instr->VRegA_21c(), value.GetL()); - // new-instance doesn't generate a result value. - value.SetJ(0); - // Skip the dex instruction since we essentially come back from an invocation. - new_dex_pc = dex_pc + instr->SizeInCodeUnits(); - if (kIsDebugBuild) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - // This is a suspend point. But it's ok since value has been set into shadow_frame. - ObjPtr<mirror::Class> klass = class_linker->ResolveType( - dex::TypeIndex(instr->VRegB_21c()), shadow_frame->GetMethod()); - DCHECK(klass->IsStringClass()); - } - } else { - DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault); - DCHECK(first); - // A regular NEW_INSTANCE is simply re-executed. - new_dex_pc = dex_pc; + // It's possible to deoptimize at a NEW_INSTANCE dex instruciton that's for a + // java string, which is turned into a call into StringFactory.newEmptyString(); + // Move the StringFactory.newEmptyString() result into the destination register. + DCHECK(value.GetL()->IsString()); + shadow_frame->SetVRegReference(instr->VRegA_21c(), value.GetL()); + // new-instance doesn't generate a result value. + value.SetJ(0); + // Skip the dex instruction since we essentially come back from an invocation. + new_dex_pc = dex_pc + instr->SizeInCodeUnits(); + if (kIsDebugBuild) { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + // This is a suspend point. But it's ok since value has been set into shadow_frame. + ObjPtr<mirror::Class> klass = class_linker->ResolveType( + dex::TypeIndex(instr->VRegB_21c()), shadow_frame->GetMethod()); + DCHECK(klass->IsStringClass()); } } else { - DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault); - DCHECK(first); - // By default, we re-execute the dex instruction since if they are not - // an invoke, so that we don't have to decode the dex instruction to move - // result into the right vreg. All slow paths have been audited to be - // idempotent except monitor-enter/exit and invocation stubs. - // TODO: move result and advance dex pc. That also requires that we can - // tell the return type of a runtime method, which we don't do currently. - new_dex_pc = dex_pc; + CHECK(false) << "Unexpected instruction opcode " << instr->Opcode() + << " at dex_pc " << dex_pc + << " of method: " << ArtMethod::PrettyMethod(shadow_frame->GetMethod(), false); } } else { // Nothing to do, the dex_pc is the one at which the code requested // the deoptimization. - DCHECK(first); } if (new_dex_pc != DexFile::kDexNoIndex) { shadow_frame->SetDexPC(new_dex_pc); @@ -607,10 +576,8 @@ void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* old_frame = shadow_frame; shadow_frame = shadow_frame->GetLink(); ShadowFrame::DeleteDeoptimizedFrame(old_frame); - // Following deoptimizations of shadow frames must be at invocation point - // and should advance dex pc past the invoke instruction. + // Following deoptimizations of shadow frames must pass the invoke instruction. from_code = false; - deopt_method_type = DeoptimizationMethodType::kDefault; first = false; } ret_val->SetJ(value.GetJ()); diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h index df8568edcd..65cfade09a 100644 --- a/runtime/interpreter/interpreter.h +++ b/runtime/interpreter/interpreter.h @@ -30,7 +30,6 @@ class ArtMethod; union JValue; class ShadowFrame; class Thread; -enum class DeoptimizationMethodType; namespace interpreter { @@ -45,11 +44,8 @@ extern void EnterInterpreterFromInvoke(Thread* self, ArtMethod* method, REQUIRES_SHARED(Locks::mutator_lock_); // 'from_code' denotes whether the deoptimization was explicitly triggered by compiled code. -extern void EnterInterpreterFromDeoptimize(Thread* self, - ShadowFrame* shadow_frame, - JValue* ret_val, - bool from_code, - DeoptimizationMethodType method_type) +extern void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* shadow_frame, bool from_code, + JValue* ret_val) REQUIRES_SHARED(Locks::mutator_lock_); extern JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* code_item, diff --git a/runtime/thread.cc b/runtime/thread.cc index 01560f8a9a..cdbb90888a 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -166,13 +166,11 @@ class DeoptimizationContextRecord { bool is_reference, bool from_code, ObjPtr<mirror::Throwable> pending_exception, - DeoptimizationMethodType method_type, DeoptimizationContextRecord* link) : ret_val_(ret_val), is_reference_(is_reference), from_code_(from_code), pending_exception_(pending_exception.Ptr()), - deopt_method_type_(method_type), link_(link) {} JValue GetReturnValue() const { return ret_val_; } @@ -187,9 +185,6 @@ class DeoptimizationContextRecord { mirror::Object** GetPendingExceptionAsGCRoot() { return reinterpret_cast<mirror::Object**>(&pending_exception_); } - DeoptimizationMethodType GetDeoptimizationMethodType() const { - return deopt_method_type_; - } private: // The value returned by the method at the top of the stack before deoptimization. @@ -205,9 +200,6 @@ class DeoptimizationContextRecord { // exception). mirror::Throwable* pending_exception_; - // Whether the context was created for an (idempotent) runtime method. - const DeoptimizationMethodType deopt_method_type_; - // A link to the previous DeoptimizationContextRecord. DeoptimizationContextRecord* const link_; @@ -237,30 +229,26 @@ class StackedShadowFrameRecord { void Thread::PushDeoptimizationContext(const JValue& return_value, bool is_reference, - ObjPtr<mirror::Throwable> exception, bool from_code, - DeoptimizationMethodType method_type) { + ObjPtr<mirror::Throwable> exception) { DeoptimizationContextRecord* record = new DeoptimizationContextRecord( return_value, is_reference, from_code, exception, - method_type, tlsPtr_.deoptimization_context_stack); tlsPtr_.deoptimization_context_stack = record; } void Thread::PopDeoptimizationContext(JValue* result, ObjPtr<mirror::Throwable>* exception, - bool* from_code, - DeoptimizationMethodType* method_type) { + bool* from_code) { AssertHasDeoptimizationContext(); DeoptimizationContextRecord* record = tlsPtr_.deoptimization_context_stack; tlsPtr_.deoptimization_context_stack = record->GetLink(); result->SetJ(record->GetReturnValue().GetJ()); *exception = record->GetPendingException(); *from_code = record->GetFromCode(); - *method_type = record->GetDeoptimizationMethodType(); delete record; } @@ -3096,16 +3084,10 @@ void Thread::QuickDeliverException() { NthCallerVisitor visitor(this, 0, false); visitor.WalkStack(); if (Runtime::Current()->IsAsyncDeoptimizeable(visitor.caller_pc)) { - // method_type shouldn't matter due to exception handling. - const DeoptimizationMethodType method_type = DeoptimizationMethodType::kDefault; // Save the exception into the deoptimization context so it can be restored // before entering the interpreter. PushDeoptimizationContext( - JValue(), - false /* is_reference */, - exception, - false /* from_code */, - method_type); + JValue(), /*is_reference */ false, /* from_code */ false, exception); artDeoptimize(this); UNREACHABLE(); } else { @@ -3665,8 +3647,7 @@ void Thread::DeoptimizeWithDeoptimizationException(JValue* result) { PopStackedShadowFrame(StackedShadowFrameType::kDeoptimizationShadowFrame); ObjPtr<mirror::Throwable> pending_exception; bool from_code = false; - DeoptimizationMethodType method_type; - PopDeoptimizationContext(result, &pending_exception, &from_code, &method_type); + PopDeoptimizationContext(result, &pending_exception, &from_code); SetTopOfStack(nullptr); SetTopOfShadowStack(shadow_frame); @@ -3675,11 +3656,7 @@ void Thread::DeoptimizeWithDeoptimizationException(JValue* result) { if (pending_exception != nullptr) { SetException(pending_exception); } - interpreter::EnterInterpreterFromDeoptimize(this, - shadow_frame, - result, - from_code, - method_type); + interpreter::EnterInterpreterFromDeoptimize(this, shadow_frame, from_code, result); } void Thread::SetException(ObjPtr<mirror::Throwable> new_exception) { diff --git a/runtime/thread.h b/runtime/thread.h index ad4506e309..7540fd2563 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -117,13 +117,6 @@ enum class StackedShadowFrameType { kDeoptimizationShadowFrame, }; -// The type of method that triggers deoptimization. It contains info on whether -// the deoptimized method should advance dex_pc. -enum class DeoptimizationMethodType { - kKeepDexPc, // dex pc is required to be kept upon deoptimization. - kDefault // dex pc may or may not advance depending on other conditions. -}; - // This should match RosAlloc::kNumThreadLocalSizeBrackets. static constexpr size_t kNumRosAllocThreadLocalSizeBracketsInThread = 16; @@ -967,18 +960,14 @@ class Thread { // values on stacks. // 'from_code' denotes whether the deoptimization was explicitly made from // compiled code. - // 'method_type' contains info on whether deoptimization should advance - // dex_pc. void PushDeoptimizationContext(const JValue& return_value, bool is_reference, - ObjPtr<mirror::Throwable> exception, bool from_code, - DeoptimizationMethodType method_type) + ObjPtr<mirror::Throwable> exception) REQUIRES_SHARED(Locks::mutator_lock_); void PopDeoptimizationContext(JValue* result, ObjPtr<mirror::Throwable>* exception, - bool* from_code, - DeoptimizationMethodType* method_type) + bool* from_code) REQUIRES_SHARED(Locks::mutator_lock_); void AssertHasDeoptimizationContext() REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/test/597-deopt-runtime-method/deopt.cc b/test/597-deopt-runtime-method/deopt.cc deleted file mode 100644 index 07d367fa40..0000000000 --- a/test/597-deopt-runtime-method/deopt.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "jni.h" -#include "mirror/class-inl.h" -#include "runtime.h" -#include "thread_list.h" -#include "thread_state.h" -#include "gc/gc_cause.h" -#include "gc/scoped_gc_critical_section.h" -#include "scoped_thread_state_change-inl.h" - -namespace art { - -extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeAll( - JNIEnv* env, - jclass cls ATTRIBUTE_UNUSED) { - ScopedObjectAccess soa(env); - ScopedThreadSuspension sts(Thread::Current(), kWaitingForDeoptimization); - gc::ScopedGCCriticalSection gcs(Thread::Current(), - gc::kGcCauseInstrumentation, - gc::kCollectorTypeInstrumentation); - // We need to suspend mutator threads first. - ScopedSuspendAll ssa(__FUNCTION__); - static bool first = true; - if (first) { - // We need to enable deoptimization once in order to call DeoptimizeEverything(). - Runtime::Current()->GetInstrumentation()->EnableDeoptimization(); - first = false; - } - Runtime::Current()->GetInstrumentation()->DeoptimizeEverything("test"); -} - -extern "C" JNIEXPORT void JNICALL Java_Main_undeoptimizeAll( - JNIEnv* env, - jclass cls ATTRIBUTE_UNUSED) { - ScopedObjectAccess soa(env); - ScopedThreadSuspension sts(Thread::Current(), kWaitingForDeoptimization); - gc::ScopedGCCriticalSection gcs(Thread::Current(), - gc::kGcCauseInstrumentation, - gc::kCollectorTypeInstrumentation); - // We need to suspend mutator threads first. - ScopedSuspendAll ssa(__FUNCTION__); - Runtime::Current()->GetInstrumentation()->UndeoptimizeEverything("test"); -} - -} // namespace art diff --git a/test/597-deopt-runtime-method/expected.txt b/test/597-deopt-runtime-method/expected.txt deleted file mode 100644 index f993efcdad..0000000000 --- a/test/597-deopt-runtime-method/expected.txt +++ /dev/null @@ -1,2 +0,0 @@ -JNI_OnLoad called -Finishing diff --git a/test/597-deopt-runtime-method/info.txt b/test/597-deopt-runtime-method/info.txt deleted file mode 100644 index 46ad4913d6..0000000000 --- a/test/597-deopt-runtime-method/info.txt +++ /dev/null @@ -1 +0,0 @@ -Test deoptimizing when returning from runtime method. diff --git a/test/597-deopt-runtime-method/run b/test/597-deopt-runtime-method/run deleted file mode 100644 index bc04498bfe..0000000000 --- a/test/597-deopt-runtime-method/run +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# We want to run in debuggable mode and compiled. -exec ${RUN} --jit -Xcompiler-option --debuggable "${@}" diff --git a/test/597-deopt-runtime-method/src/Main.java b/test/597-deopt-runtime-method/src/Main.java deleted file mode 100644 index c3a9694b5f..0000000000 --- a/test/597-deopt-runtime-method/src/Main.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -public class Main implements Runnable { - static final int numberOfThreads = 2; - volatile static boolean sExitFlag = false; - volatile static boolean sEntered = false; - int threadIndex; - - private static native void deoptimizeAll(); - private static native void undeoptimizeAll(); - private static native void assertIsInterpreted(); - private static native void assertIsManaged(); - private static native void ensureJitCompiled(Class<?> cls, String methodName); - - Main(int index) { - threadIndex = index; - } - - public static void main(String[] args) throws Exception { - System.loadLibrary(args[0]); - - final Thread[] threads = new Thread[numberOfThreads]; - for (int t = 0; t < threads.length; t++) { - threads[t] = new Thread(new Main(t)); - threads[t].start(); - } - for (Thread t : threads) { - t.join(); - } - System.out.println("Finishing"); - } - - public void $noinline$busyLoop() { - assertIsManaged(); - sEntered = true; - for (;;) { - if (sExitFlag) { - break; - } - } - assertIsInterpreted(); - } - - public void run() { - if (threadIndex == 0) { - while (!sEntered) { - Thread.yield(); - } - deoptimizeAll(); - sExitFlag = true; - } else { - ensureJitCompiled(Main.class, "$noinline$busyLoop"); - $noinline$busyLoop(); - } - } -} diff --git a/test/knownfailures.json b/test/knownfailures.json index 4166454044..20cfc34e43 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -207,8 +207,7 @@ "variant": "trace | stream" }, { - "tests": ["597-deopt-runtime-method", - "604-hot-static-interface", + "tests": ["604-hot-static-interface", "612-jit-dex-cache", "613-inlining-dex-cache", "626-set-resolved-string"], |