diff options
-rw-r--r-- | compiler/Android.bp | 1 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_riscv64.cc | 37 | ||||
-rw-r--r-- | compiler/optimizing/critical_native_abi_fixup_arm.cc | 45 | ||||
-rw-r--r-- | compiler/optimizing/critical_native_abi_fixup_riscv64.cc | 71 | ||||
-rw-r--r-- | compiler/optimizing/critical_native_abi_fixup_riscv64.h | 41 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics.cc | 51 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics.h | 5 | ||||
-rw-r--r-- | compiler/optimizing/optimization.cc | 16 | ||||
-rw-r--r-- | compiler/optimizing/optimization.h | 3 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 37 | ||||
-rw-r--r-- | test/178-app-image-native-method/native_methods.cc | 28 | ||||
-rw-r--r-- | test/178-app-image-native-method/profile | 1 | ||||
-rw-r--r-- | test/178-app-image-native-method/src/Main.java | 216 |
14 files changed, 484 insertions, 70 deletions
diff --git a/compiler/Android.bp b/compiler/Android.bp index e49f57074f..57cda8fc69 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -235,6 +235,7 @@ art_cc_defaults { srcs: [ "jni/quick/riscv64/calling_convention_riscv64.cc", "optimizing/code_generator_riscv64.cc", + "optimizing/critical_native_abi_fixup_riscv64.cc", "optimizing/intrinsics_riscv64.cc", "utils/riscv64/assembler_riscv64.cc", "utils/riscv64/jni_macro_assembler_riscv64.cc", diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index cd44fb3fa7..7e46966247 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -598,7 +598,7 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> { if (kIsDebugBuild) { uint32_t shorty_len; const char* shorty = GetCriticalNativeShorty(invoke, &shorty_len); - DCHECK_EQ(GetCriticalNativeDirectCallFrameSize(shorty, shorty_len), out_frame_size); + CHECK_EQ(GetCriticalNativeDirectCallFrameSize(shorty, shorty_len), out_frame_size); } if (out_frame_size != 0u) { FinishCriticalNativeFrameSetup(out_frame_size, ¶llel_move); diff --git a/compiler/optimizing/code_generator_riscv64.cc b/compiler/optimizing/code_generator_riscv64.cc index b9d589b576..f0a9e51b0a 100644 --- a/compiler/optimizing/code_generator_riscv64.cc +++ b/compiler/optimizing/code_generator_riscv64.cc @@ -207,11 +207,13 @@ Location CriticalNativeCallingConventionVisitorRiscv64::GetNextLocation(DataType if (fpr_index_ < kParameterFpuRegistersLength) { location = Location::FpuRegisterLocation(kParameterFpuRegisters[fpr_index_]); ++fpr_index_; + } else { + // Native ABI allows passing excessive FP args in GPRs. This is facilitated by + // inserting fake conversion intrinsic calls (`Double.doubleToRawLongBits()` + // or `Float.floatToRawIntBits()`) by `CriticalNativeAbiFixupRiscv64`. + // Remaining FP args shall be passed on the stack. + CHECK_EQ(gpr_index_, kRuntimeParameterCoreRegistersLength); } - // Native ABI allows passing excessive FP args in GPRs. This is facilitated by - // inserting fake conversion intrinsic calls (`Double.doubleToRawLongBits()` - // or `Float.floatToRawIntBits()`) by `CriticalNativeAbiFixupRiscv64`. - // TODO(riscv64): Implement these intrinsics and `CriticalNativeAbiFixupRiscv64`. } else { // Native ABI uses the same core registers as a runtime call. if (gpr_index_ < kRuntimeParameterCoreRegistersLength) { @@ -220,10 +222,11 @@ Location CriticalNativeCallingConventionVisitorRiscv64::GetNextLocation(DataType } } if (location.IsInvalid()) { - if (DataType::Is64BitType(type)) { - location = Location::DoubleStackSlot(stack_offset_); - } else { + // Only a `float` gets a single slot. Integral args need to be sign-extended to 64 bits. + if (type == DataType::Type::kFloat32) { location = Location::StackSlot(stack_offset_); + } else { + location = Location::DoubleStackSlot(stack_offset_); } stack_offset_ += kFramePointerSize; @@ -5840,10 +5843,13 @@ void CodeGeneratorRISCV64::MoveLocation(Location destination, destination.IsStackSlot() ? DataType::Type::kFloat32 : DataType::Type::kFloat64; } } - DCHECK((destination.IsDoubleStackSlot() == DataType::Is64BitType(dst_type)) && - (source.IsFpuRegister() == DataType::IsFloatingPointType(dst_type))); + DCHECK_EQ(source.IsFpuRegister(), DataType::IsFloatingPointType(dst_type)); + // For direct @CriticalNative calls, we need to sign-extend narrow integral args + // to 64 bits, so widening integral values is allowed. Narrowing is forbidden. + DCHECK_IMPLIES(DataType::IsFloatingPointType(dst_type) || destination.IsStackSlot(), + destination.IsDoubleStackSlot() == DataType::Is64BitType(dst_type)); // Move to stack from GPR/FPR - if (DataType::Is64BitType(dst_type)) { + if (destination.IsDoubleStackSlot()) { if (source.IsRegister()) { __ Stored(source.AsRegister<XRegister>(), SP, destination.GetStackIndex()); } else { @@ -5872,15 +5878,20 @@ void CodeGeneratorRISCV64::MoveLocation(Location destination, } } else { DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot()); - DCHECK_EQ(source.IsDoubleStackSlot(), destination.IsDoubleStackSlot()); + // For direct @CriticalNative calls, we need to sign-extend narrow integral args + // to 64 bits, so widening move is allowed. Narrowing move is forbidden. + DCHECK_IMPLIES(destination.IsStackSlot(), source.IsStackSlot()); // Move to stack from stack ScratchRegisterScope srs(GetAssembler()); XRegister tmp = srs.AllocateXRegister(); - if (destination.IsStackSlot()) { + if (source.IsStackSlot()) { __ Loadw(tmp, SP, source.GetStackIndex()); - __ Storew(tmp, SP, destination.GetStackIndex()); } else { __ Loadd(tmp, SP, source.GetStackIndex()); + } + if (destination.IsStackSlot()) { + __ Storew(tmp, SP, destination.GetStackIndex()); + } else { __ Stored(tmp, SP, destination.GetStackIndex()); } } diff --git a/compiler/optimizing/critical_native_abi_fixup_arm.cc b/compiler/optimizing/critical_native_abi_fixup_arm.cc index 77e156608b..4b1dec05b5 100644 --- a/compiler/optimizing/critical_native_abi_fixup_arm.cc +++ b/compiler/optimizing/critical_native_abi_fixup_arm.cc @@ -16,12 +16,8 @@ #include "critical_native_abi_fixup_arm.h" -#include "art_method-inl.h" #include "intrinsics.h" -#include "jni/jni_internal.h" #include "nodes.h" -#include "scoped_thread_state_change-inl.h" -#include "well_known_classes.h" namespace art HIDDEN { namespace arm { @@ -43,46 +39,7 @@ static void FixUpArguments(HInvokeStaticOrDirect* invoke) { break; // Remaining arguments are passed on stack. } if (DataType::IsFloatingPointType(input_type)) { - bool is_double = (input_type == DataType::Type::kFloat64); - DataType::Type converted_type = is_double ? DataType::Type::kInt64 : DataType::Type::kInt32; - ArtMethod* resolved_method = is_double - ? WellKnownClasses::java_lang_Double_doubleToRawLongBits - : WellKnownClasses::java_lang_Float_floatToRawIntBits; - DCHECK(resolved_method != nullptr); - DCHECK(resolved_method->IsIntrinsic()); - MethodReference target_method(nullptr, 0); - { - ScopedObjectAccess soa(Thread::Current()); - target_method = - MethodReference(resolved_method->GetDexFile(), resolved_method->GetDexMethodIndex()); - } - // Use arbitrary dispatch info that does not require the method argument. - HInvokeStaticOrDirect::DispatchInfo dispatch_info = { - MethodLoadKind::kBssEntry, - CodePtrLocation::kCallArtMethod, - /*method_load_data=*/ 0u - }; - HBasicBlock* block = invoke->GetBlock(); - ArenaAllocator* allocator = block->GetGraph()->GetAllocator(); - HInvokeStaticOrDirect* new_input = new (allocator) HInvokeStaticOrDirect( - allocator, - /*number_of_arguments=*/ 1u, - converted_type, - invoke->GetDexPc(), - /*method_reference=*/ MethodReference(nullptr, dex::kDexNoIndex), - resolved_method, - dispatch_info, - kStatic, - target_method, - HInvokeStaticOrDirect::ClinitCheckRequirement::kNone, - !block->GetGraph()->IsDebuggable()); - // The intrinsic has no side effects and does not need environment or dex cache on ARM. - new_input->SetSideEffects(SideEffects::None()); - IntrinsicOptimizations opt(new_input); - opt.SetDoesNotNeedEnvironment(); - new_input->SetRawInputAt(0u, input); - block->InsertInstructionBefore(new_input, invoke); - invoke->ReplaceInput(new_input, i); + InsertFpToIntegralIntrinsic(invoke, i); } reg = next_reg; } diff --git a/compiler/optimizing/critical_native_abi_fixup_riscv64.cc b/compiler/optimizing/critical_native_abi_fixup_riscv64.cc new file mode 100644 index 0000000000..c2c98d1df9 --- /dev/null +++ b/compiler/optimizing/critical_native_abi_fixup_riscv64.cc @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2023 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 "critical_native_abi_fixup_riscv64.h" + +#include "arch/riscv64/jni_frame_riscv64.h" +#include "intrinsics.h" +#include "nodes.h" + +namespace art HIDDEN { +namespace riscv64 { + +// Fix up FP arguments passed in core registers for call to @CriticalNative by inserting fake calls +// to Float.floatToRawIntBits() or Double.doubleToRawLongBits() to satisfy type consistency checks. +static void FixUpArguments(HInvokeStaticOrDirect* invoke) { + DCHECK_EQ(invoke->GetCodePtrLocation(), CodePtrLocation::kCallCriticalNative); + size_t core_reg = 0u; + size_t fp_reg = 0u; + for (size_t i = 0, num_args = invoke->GetNumberOfArguments(); i != num_args; ++i) { + if (core_reg == kMaxIntLikeArgumentRegisters) { + break; // Remaining arguments are passed in FP regs or on the stack. + } + HInstruction* input = invoke->InputAt(i); + DataType::Type input_type = input->GetType(); + if (DataType::IsFloatingPointType(input_type)) { + if (fp_reg < kMaxFloatOrDoubleArgumentRegisters) { + ++fp_reg; + } else { + DCHECK_LT(core_reg, kMaxIntLikeArgumentRegisters); + InsertFpToIntegralIntrinsic(invoke, i); + ++core_reg; + } + } else { + ++core_reg; + } + } +} + +bool CriticalNativeAbiFixupRiscv64::Run() { + if (!graph_->HasDirectCriticalNativeCall()) { + return false; + } + + for (HBasicBlock* block : graph_->GetReversePostOrder()) { + for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { + HInstruction* instruction = it.Current(); + if (instruction->IsInvokeStaticOrDirect() && + instruction->AsInvokeStaticOrDirect()->GetCodePtrLocation() == + CodePtrLocation::kCallCriticalNative) { + FixUpArguments(instruction->AsInvokeStaticOrDirect()); + } + } + } + return true; +} + +} // namespace riscv64 +} // namespace art diff --git a/compiler/optimizing/critical_native_abi_fixup_riscv64.h b/compiler/optimizing/critical_native_abi_fixup_riscv64.h new file mode 100644 index 0000000000..dc76cff2b8 --- /dev/null +++ b/compiler/optimizing/critical_native_abi_fixup_riscv64.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 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. + */ + +#ifndef ART_COMPILER_OPTIMIZING_CRITICAL_NATIVE_ABI_FIXUP_RISCV64_H_ +#define ART_COMPILER_OPTIMIZING_CRITICAL_NATIVE_ABI_FIXUP_RISCV64_H_ + +#include "base/macros.h" +#include "nodes.h" +#include "optimization.h" + +namespace art HIDDEN { +namespace riscv64 { + +class CriticalNativeAbiFixupRiscv64 : public HOptimization { + public: + CriticalNativeAbiFixupRiscv64(HGraph* graph, OptimizingCompilerStats* stats) + : HOptimization(graph, kCriticalNativeAbiFixupRiscv64PassName, stats) {} + + static constexpr const char* kCriticalNativeAbiFixupRiscv64PassName = + "critical_native_abi_fixup_riscv64"; + + bool Run() override; +}; + +} // namespace riscv64 +} // namespace art + +#endif // ART_COMPILER_OPTIMIZING_CRITICAL_NATIVE_ABI_FIXUP_RISCV64_H_ diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 8357e57c1f..d84e1cbc97 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -32,6 +32,7 @@ #include "obj_ptr-inl.h" #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" +#include "well_known_classes.h" namespace art HIDDEN { @@ -412,4 +413,54 @@ void IntrinsicVisitor::AssertNonMovableStringClass() { } } +void InsertFpToIntegralIntrinsic(HInvokeStaticOrDirect* invoke, size_t input_index) { + DCHECK_EQ(invoke->GetCodePtrLocation(), CodePtrLocation::kCallCriticalNative); + DCHECK(!invoke->GetBlock()->GetGraph()->IsDebuggable()) + << "Unexpected direct @CriticalNative call in a debuggable graph!"; + DCHECK_LT(input_index, invoke->GetNumberOfArguments()); + HInstruction* input = invoke->InputAt(input_index); + DataType::Type input_type = input->GetType(); + DCHECK(DataType::IsFloatingPointType(input_type)); + bool is_double = (input_type == DataType::Type::kFloat64); + DataType::Type converted_type = is_double ? DataType::Type::kInt64 : DataType::Type::kInt32; + ArtMethod* resolved_method = is_double + ? WellKnownClasses::java_lang_Double_doubleToRawLongBits + : WellKnownClasses::java_lang_Float_floatToRawIntBits; + DCHECK(resolved_method != nullptr); + DCHECK(resolved_method->IsIntrinsic()); + MethodReference target_method(nullptr, 0); + { + ScopedObjectAccess soa(Thread::Current()); + target_method = + MethodReference(resolved_method->GetDexFile(), resolved_method->GetDexMethodIndex()); + } + // Use arbitrary dispatch info that does not require the method argument. + HInvokeStaticOrDirect::DispatchInfo dispatch_info = { + MethodLoadKind::kBssEntry, + CodePtrLocation::kCallArtMethod, + /*method_load_data=*/ 0u + }; + HBasicBlock* block = invoke->GetBlock(); + ArenaAllocator* allocator = block->GetGraph()->GetAllocator(); + HInvokeStaticOrDirect* new_input = new (allocator) HInvokeStaticOrDirect( + allocator, + /*number_of_arguments=*/ 1u, + converted_type, + invoke->GetDexPc(), + /*method_reference=*/ MethodReference(nullptr, dex::kDexNoIndex), + resolved_method, + dispatch_info, + kStatic, + target_method, + HInvokeStaticOrDirect::ClinitCheckRequirement::kNone, + /*enable_intrinsic_opt=*/ true); + // The intrinsic has no side effects and does not need the environment. + new_input->SetSideEffects(SideEffects::None()); + IntrinsicOptimizations opt(new_input); + opt.SetDoesNotNeedEnvironment(); + new_input->SetRawInputAt(0u, input); + block->InsertInstructionBefore(new_input, invoke); + invoke->ReplaceInput(new_input, input_index); +} + } // namespace art diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h index b6c7e1b997..a16b93dfc6 100644 --- a/compiler/optimizing/intrinsics.h +++ b/compiler/optimizing/intrinsics.h @@ -328,6 +328,11 @@ bool IsCallFreeIntrinsic(HInvoke* invoke, Codegenerator* codegen) { return false; } +// Insert a `Float.floatToRawIntBits()` or `Double.doubleToRawLongBits()` intrinsic for a +// given input. These fake calls are needed on arm and riscv64 to satisfy type consistency +// checks while passing certain FP args in core registers for direct @CriticalNative calls. +void InsertFpToIntegralIntrinsic(HInvokeStaticOrDirect* invoke, size_t input_index); + } // namespace art #endif // ART_COMPILER_OPTIMIZING_INTRINSICS_H_ diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc index 4f20b55c7e..21b3c8558e 100644 --- a/compiler/optimizing/optimization.cc +++ b/compiler/optimizing/optimization.cc @@ -23,6 +23,9 @@ #ifdef ART_ENABLE_CODEGEN_arm64 #include "instruction_simplifier_arm64.h" #endif +#ifdef ART_ENABLE_CODEGEN_riscv64 +#include "critical_native_abi_fixup_riscv64.h" +#endif #ifdef ART_ENABLE_CODEGEN_x86 #include "pc_relative_fixups_x86.h" #include "instruction_simplifier_x86.h" @@ -109,6 +112,10 @@ const char* OptimizationPassName(OptimizationPass pass) { case OptimizationPass::kInstructionSimplifierArm64: return arm64::InstructionSimplifierArm64::kInstructionSimplifierArm64PassName; #endif +#ifdef ART_ENABLE_CODEGEN_riscv64 + case OptimizationPass::kCriticalNativeAbiFixupRiscv64: + return riscv64::CriticalNativeAbiFixupRiscv64::kCriticalNativeAbiFixupRiscv64PassName; +#endif #ifdef ART_ENABLE_CODEGEN_x86 case OptimizationPass::kPcRelativeFixupsX86: return x86::PcRelativeFixups::kPcRelativeFixupsX86PassName; @@ -155,6 +162,9 @@ OptimizationPass OptimizationPassByName(const std::string& pass_name) { #ifdef ART_ENABLE_CODEGEN_arm64 X(OptimizationPass::kInstructionSimplifierArm64); #endif +#ifdef ART_ENABLE_CODEGEN_riscv64 + X(OptimizationPass::kCriticalNativeAbiFixupRiscv64); +#endif #ifdef ART_ENABLE_CODEGEN_x86 X(OptimizationPass::kPcRelativeFixupsX86); X(OptimizationPass::kX86MemoryOperandGeneration); @@ -303,6 +313,12 @@ ArenaVector<HOptimization*> ConstructOptimizations( opt = new (allocator) arm64::InstructionSimplifierArm64(graph, stats); break; #endif +#ifdef ART_ENABLE_CODEGEN_riscv64 + case OptimizationPass::kCriticalNativeAbiFixupRiscv64: + DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; + opt = new (allocator) riscv64::CriticalNativeAbiFixupRiscv64(graph, stats); + break; +#endif #ifdef ART_ENABLE_CODEGEN_x86 case OptimizationPass::kPcRelativeFixupsX86: DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h index 134e3cdc7a..57c5f4639c 100644 --- a/compiler/optimizing/optimization.h +++ b/compiler/optimizing/optimization.h @@ -93,6 +93,9 @@ enum class OptimizationPass { #ifdef ART_ENABLE_CODEGEN_arm64 kInstructionSimplifierArm64, #endif +#ifdef ART_ENABLE_CODEGEN_riscv64 + kCriticalNativeAbiFixupRiscv64, +#endif #ifdef ART_ENABLE_CODEGEN_x86 kPcRelativeFixupsX86, kInstructionSimplifierX86, diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 682c2418f8..0fea53c247 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -461,6 +461,18 @@ bool OptimizingCompiler::RunBaselineOptimizations(HGraph* graph, arm_optimizations); } #endif +#if defined(ART_ENABLE_CODEGEN_riscv64) + case InstructionSet::kRiscv64: { + OptimizationDef riscv64_optimizations[] = { + OptDef(OptimizationPass::kCriticalNativeAbiFixupRiscv64), + }; + return RunOptimizations(graph, + codegen, + dex_compilation_unit, + pass_observer, + riscv64_optimizations); + } +#endif #ifdef ART_ENABLE_CODEGEN_x86 case InstructionSet::kX86: { OptimizationDef x86_optimizations[] = { @@ -519,6 +531,18 @@ bool OptimizingCompiler::RunArchOptimizations(HGraph* graph, arm64_optimizations); } #endif +#if defined(ART_ENABLE_CODEGEN_riscv64) + case InstructionSet::kRiscv64: { + OptimizationDef riscv64_optimizations[] = { + OptDef(OptimizationPass::kCriticalNativeAbiFixupRiscv64) + }; + return RunOptimizations(graph, + codegen, + dex_compilation_unit, + pass_observer, + riscv64_optimizations); + } +#endif #ifdef ART_ENABLE_CODEGEN_x86 case InstructionSet::kX86: { OptimizationDef x86_optimizations[] = { @@ -759,6 +783,7 @@ static bool CanAssembleGraphForRiscv64(HGraph* graph) { case HInstruction::kLongConstant: case HInstruction::kNullConstant: case HInstruction::kLoadClass: + case HInstruction::kClinitCheck: case HInstruction::kLoadString: case HInstruction::kLoadMethodHandle: case HInstruction::kLoadMethodType: @@ -800,22 +825,12 @@ static bool CanAssembleGraphForRiscv64(HGraph* graph) { case HInstruction::kNot: case HInstruction::kMin: case HInstruction::kMax: + case HInstruction::kInvokeStaticOrDirect: case HInstruction::kInvokeVirtual: case HInstruction::kInvokeInterface: case HInstruction::kCurrentMethod: case HInstruction::kNullCheck: break; - case HInstruction::kInvokeStaticOrDirect: - if (it.Current()->AsInvokeStaticOrDirect()->GetCodePtrLocation() == - CodePtrLocation::kCallCriticalNative && - it.Current()->AsInvokeStaticOrDirect()->GetNumberOfArguments() >= 8u) { - // TODO(riscv64): If there are more than 8 FP args, some may be passed in GPRs - // and this requires a `CriticalNativeAbiFixupRiscv64` pass similar to the one - // we have for ARM. This is not yet implemented. For simplicity, we reject all - // direct @CriticalNative calls with more than 8 args. - return false; - } - break; default: // Unimplemented instruction. return false; diff --git a/test/178-app-image-native-method/native_methods.cc b/test/178-app-image-native-method/native_methods.cc index 654073e30e..51fcbf2378 100644 --- a/test/178-app-image-native-method/native_methods.cc +++ b/test/178-app-image-native-method/native_methods.cc @@ -638,6 +638,34 @@ extern "C" JNIEXPORT jint JNICALL Java_CriticalSignatures_nativeFullArgs( return 42; } +extern "C" JNIEXPORT jint JNICALL Java_CriticalSignatures_nativeDFDFDFDFDFIJ( + jdouble d1, + jfloat f1, + jdouble d2, + jfloat f2, + jdouble d3, + jfloat f3, + jdouble d4, + jfloat f4, + jdouble d5, + jfloat f5, + jint i, + jlong j) { + if (d1 != 1.0) return -1; + if (f1 != 2.0f) return -2; + if (d2 != 3.0) return -3; + if (f2 != 4.0f) return -4; + if (d3 != 5.0) return -5; + if (f3 != 6.0f) return -6; + if (d4 != 7.0) return -7; + if (f4 != 8.0f) return -8; + if (d5 != 9.0) return -9; + if (f5 != 10.0f) return -10; + if (i != 11) return -11; + if (j != 12) return -12; + return 42; +} + extern "C" JNIEXPORT jint JNICALL Java_CriticalClinitCheck_nativeMethodVoid() { return 42; } diff --git a/test/178-app-image-native-method/profile b/test/178-app-image-native-method/profile index 1c25dee0a6..5f3d95bbb4 100644 --- a/test/178-app-image-native-method/profile +++ b/test/178-app-image-native-method/profile @@ -14,4 +14,5 @@ HSPLMain;->$noinline$opt$testMissing()V HSPLMain;->$noinline$opt$testMissingFast()V HSPLMain;->$noinline$opt$testMissingCritical()V HSPLMain;->$noinline$opt$testCriticalSignatures()V +HSPLMain;->$noinline$opt$testCriticalSignaturesStackMoves()V HSPLMain;->$noinline$opt$testCriticalClinitCheck()V diff --git a/test/178-app-image-native-method/src/Main.java b/test/178-app-image-native-method/src/Main.java index 877efa4be4..760f066caa 100644 --- a/test/178-app-image-native-method/src/Main.java +++ b/test/178-app-image-native-method/src/Main.java @@ -201,7 +201,7 @@ public class Main { // for i in {0..84}; \ // do echo " 0xf00000000L + $((i*3))L,"; \ // echo " $((i*3+2)),"; \ - // done + // done 0xf00000000L + 0L, 2, 0xf00000000L + 3L, @@ -372,8 +372,206 @@ public class Main { 251, 0xf00000000L + 252L, 254)); + assertEquals(42, CriticalSignatures.nativeDFDFDFDFDFIJ( + 1.0, 2.0f, 3.0, 4.0f, 5.0, 6.0f, 7.0, 8.0f, 9.0, 10.0f, 11, 12L)); + // Exercise spilling args from registers on riscv64. + double double9_0 = $noinline$returnDoubleArg(9.0); + float float10_0 = $noinline$returnFloatArg(10.0f); + int int11 = $noinline$returnIntArg(11); + long long12 = $noinline$returnLongArg(12); + assertEquals(42, CriticalSignatures.nativeDFDFDFDFDFIJ( + 1.0, 2.0f, 3.0, 4.0f, 5.0, 6.0f, 7.0, 8.0f, double9_0, float10_0, int11, long12)); + // Split out the last test to keep this method under the large method threshold. + $noinline$opt$testCriticalSignaturesStackMoves(); } + public static void $noinline$opt$testCriticalSignaturesStackMoves() { + // Exercise moving non-const args to stack by having more non-const args than registers. + // At least on riscv64, where we need to properly sign-extend narrow (int) arguments + // passed on stack, this covers both register and stack source locations. + assertEquals(42, CriticalSignatures.nativeFullArgs( + // Generated by script (then modified to close argument list): + // for i in {0..84}; \ + // do echo " \$noinline\$returnLongArg(0xf00000000L + $((i*3))L),"; \ + // echo " \$noinline\$returnIntArg($((i*3+2))),"; \ + // done + $noinline$returnLongArg(0xf00000000L + 0L), + $noinline$returnIntArg(2), + $noinline$returnLongArg(0xf00000000L + 3L), + $noinline$returnIntArg(5), + $noinline$returnLongArg(0xf00000000L + 6L), + $noinline$returnIntArg(8), + $noinline$returnLongArg(0xf00000000L + 9L), + $noinline$returnIntArg(11), + $noinline$returnLongArg(0xf00000000L + 12L), + $noinline$returnIntArg(14), + $noinline$returnLongArg(0xf00000000L + 15L), + $noinline$returnIntArg(17), + $noinline$returnLongArg(0xf00000000L + 18L), + $noinline$returnIntArg(20), + $noinline$returnLongArg(0xf00000000L + 21L), + $noinline$returnIntArg(23), + $noinline$returnLongArg(0xf00000000L + 24L), + $noinline$returnIntArg(26), + $noinline$returnLongArg(0xf00000000L + 27L), + $noinline$returnIntArg(29), + $noinline$returnLongArg(0xf00000000L + 30L), + $noinline$returnIntArg(32), + $noinline$returnLongArg(0xf00000000L + 33L), + $noinline$returnIntArg(35), + $noinline$returnLongArg(0xf00000000L + 36L), + $noinline$returnIntArg(38), + $noinline$returnLongArg(0xf00000000L + 39L), + $noinline$returnIntArg(41), + $noinline$returnLongArg(0xf00000000L + 42L), + $noinline$returnIntArg(44), + $noinline$returnLongArg(0xf00000000L + 45L), + $noinline$returnIntArg(47), + $noinline$returnLongArg(0xf00000000L + 48L), + $noinline$returnIntArg(50), + $noinline$returnLongArg(0xf00000000L + 51L), + $noinline$returnIntArg(53), + $noinline$returnLongArg(0xf00000000L + 54L), + $noinline$returnIntArg(56), + $noinline$returnLongArg(0xf00000000L + 57L), + $noinline$returnIntArg(59), + $noinline$returnLongArg(0xf00000000L + 60L), + $noinline$returnIntArg(62), + $noinline$returnLongArg(0xf00000000L + 63L), + $noinline$returnIntArg(65), + $noinline$returnLongArg(0xf00000000L + 66L), + $noinline$returnIntArg(68), + $noinline$returnLongArg(0xf00000000L + 69L), + $noinline$returnIntArg(71), + $noinline$returnLongArg(0xf00000000L + 72L), + $noinline$returnIntArg(74), + $noinline$returnLongArg(0xf00000000L + 75L), + $noinline$returnIntArg(77), + $noinline$returnLongArg(0xf00000000L + 78L), + $noinline$returnIntArg(80), + $noinline$returnLongArg(0xf00000000L + 81L), + $noinline$returnIntArg(83), + $noinline$returnLongArg(0xf00000000L + 84L), + $noinline$returnIntArg(86), + $noinline$returnLongArg(0xf00000000L + 87L), + $noinline$returnIntArg(89), + $noinline$returnLongArg(0xf00000000L + 90L), + $noinline$returnIntArg(92), + $noinline$returnLongArg(0xf00000000L + 93L), + $noinline$returnIntArg(95), + $noinline$returnLongArg(0xf00000000L + 96L), + $noinline$returnIntArg(98), + $noinline$returnLongArg(0xf00000000L + 99L), + $noinline$returnIntArg(101), + $noinline$returnLongArg(0xf00000000L + 102L), + $noinline$returnIntArg(104), + $noinline$returnLongArg(0xf00000000L + 105L), + $noinline$returnIntArg(107), + $noinline$returnLongArg(0xf00000000L + 108L), + $noinline$returnIntArg(110), + $noinline$returnLongArg(0xf00000000L + 111L), + $noinline$returnIntArg(113), + $noinline$returnLongArg(0xf00000000L + 114L), + $noinline$returnIntArg(116), + $noinline$returnLongArg(0xf00000000L + 117L), + $noinline$returnIntArg(119), + $noinline$returnLongArg(0xf00000000L + 120L), + $noinline$returnIntArg(122), + $noinline$returnLongArg(0xf00000000L + 123L), + $noinline$returnIntArg(125), + $noinline$returnLongArg(0xf00000000L + 126L), + $noinline$returnIntArg(128), + $noinline$returnLongArg(0xf00000000L + 129L), + $noinline$returnIntArg(131), + $noinline$returnLongArg(0xf00000000L + 132L), + $noinline$returnIntArg(134), + $noinline$returnLongArg(0xf00000000L + 135L), + $noinline$returnIntArg(137), + $noinline$returnLongArg(0xf00000000L + 138L), + $noinline$returnIntArg(140), + $noinline$returnLongArg(0xf00000000L + 141L), + $noinline$returnIntArg(143), + $noinline$returnLongArg(0xf00000000L + 144L), + $noinline$returnIntArg(146), + $noinline$returnLongArg(0xf00000000L + 147L), + $noinline$returnIntArg(149), + $noinline$returnLongArg(0xf00000000L + 150L), + $noinline$returnIntArg(152), + $noinline$returnLongArg(0xf00000000L + 153L), + $noinline$returnIntArg(155), + $noinline$returnLongArg(0xf00000000L + 156L), + $noinline$returnIntArg(158), + $noinline$returnLongArg(0xf00000000L + 159L), + $noinline$returnIntArg(161), + $noinline$returnLongArg(0xf00000000L + 162L), + $noinline$returnIntArg(164), + $noinline$returnLongArg(0xf00000000L + 165L), + $noinline$returnIntArg(167), + $noinline$returnLongArg(0xf00000000L + 168L), + $noinline$returnIntArg(170), + $noinline$returnLongArg(0xf00000000L + 171L), + $noinline$returnIntArg(173), + $noinline$returnLongArg(0xf00000000L + 174L), + $noinline$returnIntArg(176), + $noinline$returnLongArg(0xf00000000L + 177L), + $noinline$returnIntArg(179), + $noinline$returnLongArg(0xf00000000L + 180L), + $noinline$returnIntArg(182), + $noinline$returnLongArg(0xf00000000L + 183L), + $noinline$returnIntArg(185), + $noinline$returnLongArg(0xf00000000L + 186L), + $noinline$returnIntArg(188), + $noinline$returnLongArg(0xf00000000L + 189L), + $noinline$returnIntArg(191), + $noinline$returnLongArg(0xf00000000L + 192L), + $noinline$returnIntArg(194), + $noinline$returnLongArg(0xf00000000L + 195L), + $noinline$returnIntArg(197), + $noinline$returnLongArg(0xf00000000L + 198L), + $noinline$returnIntArg(200), + $noinline$returnLongArg(0xf00000000L + 201L), + $noinline$returnIntArg(203), + $noinline$returnLongArg(0xf00000000L + 204L), + $noinline$returnIntArg(206), + $noinline$returnLongArg(0xf00000000L + 207L), + $noinline$returnIntArg(209), + $noinline$returnLongArg(0xf00000000L + 210L), + $noinline$returnIntArg(212), + $noinline$returnLongArg(0xf00000000L + 213L), + $noinline$returnIntArg(215), + $noinline$returnLongArg(0xf00000000L + 216L), + $noinline$returnIntArg(218), + $noinline$returnLongArg(0xf00000000L + 219L), + $noinline$returnIntArg(221), + $noinline$returnLongArg(0xf00000000L + 222L), + $noinline$returnIntArg(224), + $noinline$returnLongArg(0xf00000000L + 225L), + $noinline$returnIntArg(227), + $noinline$returnLongArg(0xf00000000L + 228L), + $noinline$returnIntArg(230), + $noinline$returnLongArg(0xf00000000L + 231L), + $noinline$returnIntArg(233), + $noinline$returnLongArg(0xf00000000L + 234L), + $noinline$returnIntArg(236), + $noinline$returnLongArg(0xf00000000L + 237L), + $noinline$returnIntArg(239), + $noinline$returnLongArg(0xf00000000L + 240L), + $noinline$returnIntArg(242), + $noinline$returnLongArg(0xf00000000L + 243L), + $noinline$returnIntArg(245), + $noinline$returnLongArg(0xf00000000L + 246L), + $noinline$returnIntArg(248), + $noinline$returnLongArg(0xf00000000L + 249L), + $noinline$returnIntArg(251), + $noinline$returnLongArg(0xf00000000L + 252L), + $noinline$returnIntArg(254))); + } + + static double $noinline$returnDoubleArg(double d) { return d; } + static float $noinline$returnFloatArg(float f) { return f; } + static int $noinline$returnIntArg(int i) { return i; } + static long $noinline$returnLongArg(long l) { return l; } + static void $noinline$regressionTestB181736463() { // Regression test for bug 181736463 (GenericJNI crashing when class initializer throws). try { @@ -820,6 +1018,22 @@ class CriticalSignatures { int i251, long l252, int i254); + + // This signature exercises passing FP args in core registers on riscv64. + @CriticalNative + public static native int nativeDFDFDFDFDFIJ( + double d1, + float f1, + double d2, + float f2, + double d3, + float f3, + double d4, + float f4, + double d5, + float f5, + int i, + long j); } class CriticalClinitCheck { |