summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/Android.bp1
-rw-r--r--compiler/optimizing/code_generator.h2
-rw-r--r--compiler/optimizing/code_generator_riscv64.cc37
-rw-r--r--compiler/optimizing/critical_native_abi_fixup_arm.cc45
-rw-r--r--compiler/optimizing/critical_native_abi_fixup_riscv64.cc71
-rw-r--r--compiler/optimizing/critical_native_abi_fixup_riscv64.h41
-rw-r--r--compiler/optimizing/intrinsics.cc51
-rw-r--r--compiler/optimizing/intrinsics.h5
-rw-r--r--compiler/optimizing/optimization.cc16
-rw-r--r--compiler/optimizing/optimization.h3
-rw-r--r--compiler/optimizing/optimizing_compiler.cc37
-rw-r--r--test/178-app-image-native-method/native_methods.cc28
-rw-r--r--test/178-app-image-native-method/profile1
-rw-r--r--test/178-app-image-native-method/src/Main.java216
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, &parallel_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 {