summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
author Treehugger Robot <treehugger-gerrit@google.com> 2016-08-16 21:51:02 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2016-08-16 21:51:03 +0000
commit3cc35c324b748c41be92a51eae68b77846b4c243 (patch)
tree615179a7897249b7e859a1875467bc9c9300f866 /compiler
parent3f410202b177416c785e6172138a265a91c81b0a (diff)
parent9d4b6da934934c322536ee3309b63ce402740f49 (diff)
Merge "jni: Fast path for @FastNative annotated java methods"
Diffstat (limited to 'compiler')
-rw-r--r--compiler/compiler.h8
-rw-r--r--compiler/driver/compiler_driver.cc35
-rw-r--r--compiler/jni/jni_compiler_test.cc43
-rw-r--r--compiler/jni/quick/jni_compiler.cc41
-rw-r--r--compiler/jni/quick/jni_compiler.h8
-rw-r--r--compiler/oat_test.cc2
-rw-r--r--compiler/optimizing/optimizing_compiler.cc9
7 files changed, 131 insertions, 15 deletions
diff --git a/compiler/compiler.h b/compiler/compiler.h
index 487a27fec0..a955f3c481 100644
--- a/compiler/compiler.h
+++ b/compiler/compiler.h
@@ -38,6 +38,11 @@ class Compiler {
kOptimizing
};
+ enum JniOptimizationFlags {
+ kNone,
+ kFastNative,
+ };
+
static Compiler* Create(CompilerDriver* driver, Kind kind);
virtual void Init() = 0;
@@ -57,7 +62,8 @@ class Compiler {
virtual CompiledMethod* JniCompile(uint32_t access_flags,
uint32_t method_idx,
- const DexFile& dex_file) const = 0;
+ const DexFile& dex_file,
+ JniOptimizationFlags optimization_flags) const = 0;
virtual bool JitCompile(Thread* self ATTRIBUTE_UNUSED,
jit::JitCodeCache* code_cache ATTRIBUTE_UNUSED,
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index d0a8335a99..758cd936a2 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -599,7 +599,38 @@ static void CompileMethod(Thread* self,
InstructionSetHasGenericJniStub(driver->GetInstructionSet())) {
// Leaving this empty will trigger the generic JNI version
} else {
- compiled_method = driver->GetCompiler()->JniCompile(access_flags, method_idx, dex_file);
+ // Look-up the ArtMethod associated with this code_item (if any)
+ // -- It is later used to lookup any [optimization] annotations for this method.
+ ScopedObjectAccess soa(self);
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader_handle(hs.NewHandle(
+ soa.Decode<mirror::ClassLoader*>(class_loader)));
+
+ // TODO: Lookup annotation from DexFile directly without resolving method.
+ ArtMethod* method =
+ Runtime::Current()->GetClassLinker()->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
+ dex_file,
+ method_idx,
+ dex_cache,
+ class_loader_handle,
+ /* referrer */ nullptr,
+ invoke_type);
+
+ bool fast_native = false;
+ if (LIKELY(method != nullptr)) {
+ fast_native = method->IsAnnotatedWithFastNative();
+ } else {
+ // Failed method resolutions happen very rarely, e.g. ancestor class cannot be resolved.
+ DCHECK(self->IsExceptionPending());
+ self->ClearException();
+ }
+
+ Compiler::JniOptimizationFlags optimization_flags =
+ fast_native ? Compiler::kFastNative : Compiler::kNone;
+ compiled_method = driver->GetCompiler()->JniCompile(access_flags,
+ method_idx,
+ dex_file,
+ optimization_flags);
CHECK(compiled_method != nullptr);
}
} else if ((access_flags & kAccAbstract) != 0) {
@@ -2874,7 +2905,7 @@ bool CompilerDriver::IsStringTypeIndex(uint16_t type_index, const DexFile* dex_f
bool CompilerDriver::IsStringInit(uint32_t method_index, const DexFile* dex_file, int32_t* offset) {
DexFileMethodInliner* inliner = GetMethodInlinerMap()->GetMethodInliner(dex_file);
- PointerSize pointer_size = InstructionSetPointerSize(GetInstructionSet());
+ const PointerSize pointer_size = InstructionSetPointerSize(GetInstructionSet());
*offset = inliner->GetOffsetForStringInit(method_index, pointer_size);
return inliner->IsStringInitMethodIndex(method_index);
}
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index c4c2399ccd..b83985a771 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -175,6 +175,9 @@ class JniCompilerTest : public CommonCompilerTest {
void StackArgsMixedImpl();
void StackArgsSignExtendedMips64Impl();
+ void NormalNativeImpl();
+ void FastNativeImpl();
+
JNIEnv* env_;
jstring library_search_path_;
jmethodID jmethod_;
@@ -1772,4 +1775,44 @@ void JniCompilerTest::StackArgsSignExtendedMips64Impl() {
JNI_TEST(StackArgsSignExtendedMips64)
+void Java_MyClassNatives_normalNative(JNIEnv*, jclass) {
+ // Intentionally left empty.
+}
+
+// Methods not annotated with anything are not considered "fast native"
+// -- Check that the annotation lookup does not find it.
+void JniCompilerTest::NormalNativeImpl() {
+ SetUpForTest(/* direct */ true,
+ "normalNative",
+ "()V",
+ reinterpret_cast<void*>(&Java_MyClassNatives_normalNative));
+
+ ScopedObjectAccess soa(Thread::Current());
+ ArtMethod* method = soa.DecodeMethod(jmethod_);
+ ASSERT_TRUE(method != nullptr);
+
+ EXPECT_FALSE(method->IsAnnotatedWithFastNative());
+}
+JNI_TEST(NormalNative)
+
+// Methods annotated with @FastNative are considered "fast native"
+// -- Check that the annotation lookup succeeds.
+void Java_MyClassNatives_fastNative(JNIEnv*, jclass) {
+ // Intentionally left empty.
+}
+
+void JniCompilerTest::FastNativeImpl() {
+ SetUpForTest(/* direct */ true,
+ "fastNative",
+ "()V",
+ reinterpret_cast<void*>(&Java_MyClassNatives_fastNative));
+
+ ScopedObjectAccess soa(Thread::Current());
+ ArtMethod* method = soa.DecodeMethod(jmethod_);
+ ASSERT_TRUE(method != nullptr);
+
+ EXPECT_TRUE(method->IsAnnotatedWithFastNative());
+}
+JNI_TEST(FastNative)
+
} // namespace art
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index f99f6a8792..d092c3f1f6 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -17,6 +17,7 @@
#include "jni_compiler.h"
#include <algorithm>
+#include <ios>
#include <memory>
#include <vector>
#include <fstream>
@@ -44,12 +45,15 @@
#include "utils/mips/managed_register_mips.h"
#include "utils/mips64/managed_register_mips64.h"
#include "utils/x86/managed_register_x86.h"
+#include "utils.h"
#include "thread.h"
#define __ jni_asm->
namespace art {
+using JniOptimizationFlags = Compiler::JniOptimizationFlags;
+
template <PointerSize kPointerSize>
static void CopyParameter(JNIMacroAssembler<kPointerSize>* jni_asm,
ManagedRuntimeCallingConvention* mr_conv,
@@ -75,7 +79,8 @@ template <PointerSize kPointerSize>
static CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver,
uint32_t access_flags,
uint32_t method_idx,
- const DexFile& dex_file) {
+ const DexFile& dex_file,
+ JniOptimizationFlags optimization_flags) {
const bool is_native = (access_flags & kAccNative) != 0;
CHECK(is_native);
const bool is_static = (access_flags & kAccStatic) != 0;
@@ -84,6 +89,19 @@ static CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver,
InstructionSet instruction_set = driver->GetInstructionSet();
const InstructionSetFeatures* instruction_set_features = driver->GetInstructionSetFeatures();
+ // i.e. if the method was annotated with @FastNative
+ const bool is_fast_native =
+ (static_cast<uint32_t>(optimization_flags) & Compiler::kFastNative) != 0;
+
+ VLOG(jni) << "JniCompile: Method :: "
+ << art::PrettyMethod(method_idx, dex_file, /* with signature */ true)
+ << " :: access_flags = " << std::hex << access_flags << std::dec;
+
+ if (UNLIKELY(is_fast_native)) {
+ VLOG(jni) << "JniCompile: Fast native method detected :: "
+ << art::PrettyMethod(method_idx, dex_file, /* with signature */ true);
+ }
+
ArenaPool pool;
ArenaAllocator arena(&pool);
@@ -240,7 +258,10 @@ static CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver,
ThreadOffset<kPointerSize> jni_start =
is_synchronized
? QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodStartSynchronized)
- : QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodStart);
+ : (is_fast_native
+ ? QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodFastStart)
+ : QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodStart));
+
main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
FrameOffset locked_object_handle_scope_offset(0);
if (is_synchronized) {
@@ -385,6 +406,7 @@ static CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver,
}
// thread.
end_jni_conv->ResetIterator(FrameOffset(end_out_arg_size));
+
ThreadOffset<kPointerSize> jni_end(-1);
if (reference_return) {
// Pass result.
@@ -396,7 +418,9 @@ static CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver,
} else {
jni_end = is_synchronized
? QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodEndSynchronized)
- : QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodEnd);
+ : (is_fast_native
+ ? QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodFastEnd)
+ : QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodEnd));
}
// Pass saved local reference state.
if (end_jni_conv->IsCurrentParamOnStack()) {
@@ -573,14 +597,17 @@ static void SetNativeParameter(JNIMacroAssembler<kPointerSize>* jni_asm,
}
}
-CompiledMethod* ArtQuickJniCompileMethod(CompilerDriver* compiler, uint32_t access_flags,
- uint32_t method_idx, const DexFile& dex_file) {
+CompiledMethod* ArtQuickJniCompileMethod(CompilerDriver* compiler,
+ uint32_t access_flags,
+ uint32_t method_idx,
+ const DexFile& dex_file,
+ Compiler::JniOptimizationFlags optimization_flags) {
if (Is64BitInstructionSet(compiler->GetInstructionSet())) {
return ArtJniCompileMethodInternal<PointerSize::k64>(
- compiler, access_flags, method_idx, dex_file);
+ compiler, access_flags, method_idx, dex_file, optimization_flags);
} else {
return ArtJniCompileMethodInternal<PointerSize::k32>(
- compiler, access_flags, method_idx, dex_file);
+ compiler, access_flags, method_idx, dex_file, optimization_flags);
}
}
diff --git a/compiler/jni/quick/jni_compiler.h b/compiler/jni/quick/jni_compiler.h
index 46277f105c..26c32a31b8 100644
--- a/compiler/jni/quick/jni_compiler.h
+++ b/compiler/jni/quick/jni_compiler.h
@@ -17,6 +17,7 @@
#ifndef ART_COMPILER_JNI_QUICK_JNI_COMPILER_H_
#define ART_COMPILER_JNI_QUICK_JNI_COMPILER_H_
+#include "compiler.h"
#include "dex_file.h"
namespace art {
@@ -24,8 +25,11 @@ namespace art {
class CompilerDriver;
class CompiledMethod;
-CompiledMethod* ArtQuickJniCompileMethod(CompilerDriver* compiler, uint32_t access_flags,
- uint32_t method_idx, const DexFile& dex_file);
+CompiledMethod* ArtQuickJniCompileMethod(CompilerDriver* compiler,
+ uint32_t access_flags,
+ uint32_t method_idx,
+ const DexFile& dex_file,
+ Compiler::JniOptimizationFlags optimization_flags);
} // namespace art
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index ce044e8e54..bf53bb2d0b 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -445,7 +445,7 @@ TEST_F(OatTest, OatHeaderSizeCheck) {
EXPECT_EQ(72U, sizeof(OatHeader));
EXPECT_EQ(4U, sizeof(OatMethodOffsets));
EXPECT_EQ(20U, sizeof(OatQuickMethodHeader));
- EXPECT_EQ(162 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
+ EXPECT_EQ(164 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
sizeof(QuickEntryPoints));
}
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index f7c82d1987..6aaa15fa02 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -283,8 +283,13 @@ class OptimizingCompiler FINAL : public Compiler {
CompiledMethod* JniCompile(uint32_t access_flags,
uint32_t method_idx,
- const DexFile& dex_file) const OVERRIDE {
- return ArtQuickJniCompileMethod(GetCompilerDriver(), access_flags, method_idx, dex_file);
+ const DexFile& dex_file,
+ JniOptimizationFlags optimization_flags) const OVERRIDE {
+ return ArtQuickJniCompileMethod(GetCompilerDriver(),
+ access_flags,
+ method_idx,
+ dex_file,
+ optimization_flags);
}
uintptr_t GetEntryPointOf(ArtMethod* method) const OVERRIDE