summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/Android.mk53
-rw-r--r--runtime/arch/arm/asm_support_arm.S25
-rw-r--r--runtime/arch/arm/entrypoints_init_arm.cc10
-rw-r--r--runtime/arch/arm/instruction_set_features_arm.S (renamed from runtime/arch/arm/arm_sdiv.S)28
-rw-r--r--runtime/arch/arm/portable_entrypoints_arm.S4
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S4
-rw-r--r--runtime/arch/arm64/asm_support_arm64.S15
-rw-r--r--runtime/arch/arm64/entrypoints_init_arm64.cc10
-rw-r--r--runtime/arch/arm64/portable_entrypoints_arm64.S4
-rw-r--r--runtime/arch/arm64/quick_entrypoints_arm64.S4
-rw-r--r--runtime/arch/mips/entrypoints_init_mips.cc12
-rw-r--r--runtime/arch/mips/portable_entrypoints_mips.S1
-rw-r--r--runtime/arch/stub_test.cc4
-rw-r--r--runtime/arch/x86/asm_support_x86.S10
-rw-r--r--runtime/arch/x86/entrypoints_init_x86.cc11
-rw-r--r--runtime/arch/x86/portable_entrypoints_x86.S4
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S4
-rw-r--r--runtime/arch/x86_64/asm_support_x86_64.S22
-rw-r--r--runtime/arch/x86_64/entrypoints_init_x86_64.cc11
-rw-r--r--runtime/arch/x86_64/portable_entrypoints_x86_64.S4
-rw-r--r--runtime/arch/x86_64/quick_entrypoints_x86_64.S4
-rw-r--r--runtime/base/logging.cc2
-rw-r--r--runtime/base/macros.h5
-rw-r--r--runtime/base/mutex.cc9
-rw-r--r--runtime/class_linker.cc219
-rw-r--r--runtime/class_linker.h148
-rw-r--r--runtime/debugger.cc2
-rw-r--r--runtime/entrypoints/entrypoint_utils.h53
-rw-r--r--runtime/entrypoints/interpreter/interpreter_entrypoints.cc4
-rw-r--r--runtime/entrypoints/interpreter/interpreter_entrypoints.h4
-rw-r--r--runtime/entrypoints/jni/jni_entrypoints.cc2
-rw-r--r--runtime/entrypoints/portable/portable_trampoline_entrypoints.cc17
-rw-r--r--runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc4
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc3
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc7
-rw-r--r--runtime/entrypoints/runtime_asm_entrypoints.h117
-rw-r--r--runtime/exception_test.cc4
-rw-r--r--runtime/gc/heap.h1
-rw-r--r--runtime/gc/reference_queue.h18
-rw-r--r--runtime/gc/space/image_space.cc2
-rw-r--r--runtime/instruction_set.cc388
-rw-r--r--runtime/instruction_set.h159
-rw-r--r--runtime/instruction_set_test.cc211
-rw-r--r--runtime/instrumentation.cc51
-rw-r--r--runtime/interpreter/interpreter.cc25
-rw-r--r--runtime/interpreter/interpreter.h15
-rw-r--r--runtime/interpreter/interpreter_common.cc8
-rw-r--r--runtime/jdwp/jdwp_handler.cc4
-rw-r--r--runtime/jni_internal.cc6
-rw-r--r--runtime/mirror/art_method-inl.h102
-rw-r--r--runtime/mirror/art_method.cc112
-rw-r--r--runtime/mirror/art_method.h46
-rw-r--r--runtime/mirror/string.h5
-rw-r--r--runtime/oat.cc12
-rw-r--r--runtime/oat.h8
-rw-r--r--runtime/parsed_options.cc6
-rw-r--r--runtime/profiler.cc18
-rw-r--r--runtime/quick_exception_handler.cc5
-rw-r--r--runtime/reflection.cc7
-rw-r--r--runtime/reflection.h2
-rw-r--r--runtime/runtime.cc23
-rw-r--r--runtime/runtime.h6
-rw-r--r--runtime/stack.cc15
-rw-r--r--runtime/thread.cc4
-rw-r--r--runtime/thread.h3
-rw-r--r--runtime/utils.cc25
-rw-r--r--runtime/utils.h6
-rw-r--r--runtime/utils_test.cc26
68 files changed, 1499 insertions, 664 deletions
diff --git a/runtime/Android.mk b/runtime/Android.mk
index e9544761bd..dbafb83c9f 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -218,11 +218,11 @@ LIBART_TARGET_SRC_FILES := \
LIBART_TARGET_SRC_FILES_arm := \
arch/arm/context_arm.cc.arm \
arch/arm/entrypoints_init_arm.cc \
+ arch/arm/instruction_set_features_arm.S \
arch/arm/jni_entrypoints_arm.S \
arch/arm/memcmp16_arm.S \
arch/arm/portable_entrypoints_arm.S \
arch/arm/quick_entrypoints_arm.S \
- arch/arm/arm_sdiv.S \
arch/arm/thread_arm.cc \
arch/arm/fault_handler_arm.cc
@@ -317,7 +317,7 @@ LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \
thread_state.h \
verifier/method_verifier.h
-LIBART_CFLAGS :=
+LIBART_CFLAGS := -DBUILDING_LIBART=1
ifeq ($(ART_USE_PORTABLE_COMPILER),true)
LIBART_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
endif
@@ -328,6 +328,29 @@ else
LIBART_CFLAGS += -DUSE_JEMALLOC
endif
+# Default dex2oat instruction set features.
+LIBART_HOST_DEFAULT_INSTRUCTION_SET_FEATURES := default
+LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := default
+2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := default
+ifeq ($(DEX2OAT_TARGET_ARCH),arm)
+ ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a15 krait denver))
+ LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := lpae,div
+ else
+ ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a7))
+ LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := div
+ endif
+ endif
+endif
+ifeq ($(2ND_DEX2OAT_TARGET_ARCH),arm)
+ ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a15 krait denver))
+ 2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := lpae,div
+ else
+ ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a7))
+ 2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := div
+ endif
+ endif
+endif
+
# $(1): target or host
# $(2): ndebug or debug
define build-libart
@@ -393,6 +416,9 @@ $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PAT
ifeq ($$(art_target_or_host),target)
$$(eval $$(call set-target-local-clang-vars))
$$(eval $$(call set-target-local-cflags-vars,$(2)))
+ LOCAL_CFLAGS_$(DEX2OAT_TARGET_ARCH) += -DART_DEFAULT_INSTRUCTION_SET_FEATURES="$(LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES)"
+ LOCAL_CFLAGS_$(2ND_DEX2OAT_TARGET_ARCH) += -DART_DEFAULT_INSTRUCTION_SET_FEATURES="$(2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES)"
+
# TODO: Loop with ifeq, ART_TARGET_CLANG
ifneq ($$(ART_TARGET_CLANG_$$(TARGET_ARCH)),true)
LOCAL_SRC_FILES_$$(TARGET_ARCH) += $$(LIBART_GCC_ONLY_SRC_FILES)
@@ -401,18 +427,25 @@ $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PAT
LOCAL_SRC_FILES_$$(TARGET_2ND_ARCH) += $$(LIBART_GCC_ONLY_SRC_FILES)
endif
else # host
- LOCAL_CLANG := $$(ART_HOST_CLANG)
- ifeq ($$(ART_HOST_CLANG),false)
+ ifneq ($$(ART_HOST_CLANG),true)
+ # Add files only built with GCC on the host.
LOCAL_SRC_FILES += $$(LIBART_GCC_ONLY_SRC_FILES)
endif
+ LOCAL_CLANG := $$(ART_HOST_CLANG)
+ LOCAL_LDLIBS := $$(ART_HOST_LDLIBS)
+ LOCAL_LDLIBS += -ldl -lpthread
+ ifeq ($$(HOST_OS),linux)
+ LOCAL_LDLIBS += -lrt
+ endif
LOCAL_CFLAGS += $$(ART_HOST_CFLAGS)
+ LOCAL_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES="$(LIBART_HOST_DEFAULT_INSTRUCTION_SET_FEATURES)"
+
ifeq ($$(art_ndebug_or_debug),debug)
LOCAL_CFLAGS += $$(ART_HOST_DEBUG_CFLAGS)
- LOCAL_LDLIBS += $$(ART_HOST_DEBUG_LDLIBS)
- LOCAL_STATIC_LIBRARIES := libgtest_host
else
LOCAL_CFLAGS += $$(ART_HOST_NON_DEBUG_CFLAGS)
endif
+ LOCAL_MULTILIB := both
endif
LOCAL_C_INCLUDES += $$(ART_C_INCLUDES)
@@ -427,11 +460,6 @@ $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PAT
else # host
LOCAL_STATIC_LIBRARIES += libcutils libziparchive-host libz libutils
LOCAL_SHARED_LIBRARIES += libsigchain
- LOCAL_LDLIBS += -ldl -lpthread
- ifeq ($$(HOST_OS),linux)
- LOCAL_LDLIBS += -lrt
- endif
- LOCAL_MULTILIB := both
endif
ifeq ($$(ART_USE_PORTABLE_COMPILER),true)
include $$(LLVM_GEN_INTRINSICS_MK)
@@ -488,6 +516,9 @@ endif
LOCAL_PATH :=
LIBART_COMMON_SRC_FILES :=
LIBART_GCC_ONLY_SRC_FILES :=
+LIBART_HOST_DEFAULT_INSTRUCTION_SET_FEATURES :=
+LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES :=
+2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES :=
LIBART_TARGET_LDFLAGS :=
LIBART_HOST_LDFLAGS :=
LIBART_TARGET_SRC_FILES :=
diff --git a/runtime/arch/arm/asm_support_arm.S b/runtime/arch/arm/asm_support_arm.S
index a3e3b21c7e..fb6458c9d4 100644
--- a/runtime/arch/arm/asm_support_arm.S
+++ b/runtime/arch/arm/asm_support_arm.S
@@ -42,18 +42,6 @@
.fnstart
.endm
-.macro ENTRY_NO_HIDE name
- .thumb_func
- .type \name, #function
- .global \name
- /* Cache alignment for function entry */
- .balign 16
-\name:
- .cfi_startproc
- .fnstart
-.endm
-
-
.macro ARM_ENTRY name
.arm
.type \name, #function
@@ -68,19 +56,6 @@
.fnstart
.endm
-.macro ARM_ENTRY_NO_HIDE name
- .arm
- .type \name, #function
- .global \name
- /* Cache alignment for function entry */
- .balign 16
-\name:
- .cfi_startproc
- /* Ensure we get a sane starting CFA. */
- .cfi_def_cfa sp,0
- .fnstart
-.endm
-
.macro END name
.fnend
.cfi_endproc
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index 2780d1b5c9..ff0eb4ae45 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -21,17 +21,11 @@
#include "entrypoints/quick/quick_entrypoints.h"
#include "entrypoints/entrypoint_utils.h"
#include "entrypoints/math_entrypoints.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
+#include "interpreter/interpreter.h"
namespace art {
-// Interpreter entrypoints.
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result);
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result);
-
// Portable entrypoints.
extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
diff --git a/runtime/arch/arm/arm_sdiv.S b/runtime/arch/arm/instruction_set_features_arm.S
index babdbf5526..c26f2cd003 100644
--- a/runtime/arch/arm/arm_sdiv.S
+++ b/runtime/arch/arm/instruction_set_features_arm.S
@@ -1,15 +1,29 @@
+/*
+ * Copyright (C) 2014 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 "asm_support_arm.S"
+
+.section .text
// This function is used to check for the CPU's support for the sdiv
// instruction at runtime. It will either return the value 1 or
// will cause an invalid instruction trap (SIGILL signal). The
// caller must arrange for the signal handler to set the r0
// register to 0 and move the pc forward by 4 bytes (to skip
// the invalid instruction).
-
-
-#include "asm_support_arm.S"
-
-.section .text
-ENTRY_NO_HIDE CheckForARMSDIVInstruction
+ENTRY artCheckForARMSDIVInstruction
mov r1,#1
// depending on the architecture, the assembler will not allow an
// sdiv instruction, so we will have to output the bytes directly.
@@ -21,4 +35,4 @@ ENTRY_NO_HIDE CheckForARMSDIVInstruction
// It will have 0 otherwise (set by the signal handler)
// the value is just returned from this function.
bx lr
- END CheckForARMSDIVInstruction
+END artCheckForARMSDIVInstruction
diff --git a/runtime/arch/arm/portable_entrypoints_arm.S b/runtime/arch/arm/portable_entrypoints_arm.S
index 3491c18c37..a34db6c6c7 100644
--- a/runtime/arch/arm/portable_entrypoints_arm.S
+++ b/runtime/arch/arm/portable_entrypoints_arm.S
@@ -138,7 +138,7 @@ ENTRY art_portable_resolution_trampoline
END art_portable_resolution_trampoline
.extern artPortableToInterpreterBridge
-ENTRY_NO_HIDE art_portable_to_interpreter_bridge
+ENTRY art_portable_to_interpreter_bridge
@ Fake callee save ref and args frame set up, note portable doesn't use callee save frames.
@ TODO: just save the registers that are needed in artPortableToInterpreterBridge.
push {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves
@@ -165,3 +165,5 @@ ENTRY_NO_HIDE art_portable_to_interpreter_bridge
.cfi_adjust_cfa_offset -48
bx lr @ return
END art_portable_to_interpreter_bridge
+
+UNIMPLEMENTED art_portable_imt_conflict_trampoline
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 466e9eb098..3d619be0cd 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -919,7 +919,7 @@ END art_quick_resolution_trampoline
/*
* Called to do a generic JNI down-call
*/
-ENTRY_NO_HIDE art_quick_generic_jni_trampoline
+ENTRY art_quick_generic_jni_trampoline
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
str r0, [sp, #0] // Store native ArtMethod* to bottom of stack.
@@ -1014,7 +1014,7 @@ ENTRY_NO_HIDE art_quick_generic_jni_trampoline
END art_quick_generic_jni_trampoline
.extern artQuickToInterpreterBridge
-ENTRY_NO_HIDE art_quick_to_interpreter_bridge
+ENTRY art_quick_to_interpreter_bridge
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
mov r1, r9 @ pass Thread::Current
mov r2, sp @ pass SP
diff --git a/runtime/arch/arm64/asm_support_arm64.S b/runtime/arch/arm64/asm_support_arm64.S
index fb49460364..b3e9242c5c 100644
--- a/runtime/arch/arm64/asm_support_arm64.S
+++ b/runtime/arch/arm64/asm_support_arm64.S
@@ -52,15 +52,6 @@
.cfi_startproc
.endm
-.macro ENTRY_NO_HIDE name
- .type \name, #function
- .global \name
- /* Cache alignment for function entry */
- .balign 16
-\name:
- .cfi_startproc
-.endm
-
.macro END name
.cfi_endproc
.size \name, .-\name
@@ -72,10 +63,4 @@
END \name
.endm
-.macro UNIMPLEMENTED_NO_HIDE name
- ENTRY_NO_HIDE \name
- brk 0
- END \name
-.endm
-
#endif // ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_S_
diff --git a/runtime/arch/arm64/entrypoints_init_arm64.cc b/runtime/arch/arm64/entrypoints_init_arm64.cc
index 70e93b3051..871e1d1b04 100644
--- a/runtime/arch/arm64/entrypoints_init_arm64.cc
+++ b/runtime/arch/arm64/entrypoints_init_arm64.cc
@@ -20,17 +20,11 @@
#include "entrypoints/quick/quick_entrypoints.h"
#include "entrypoints/entrypoint_utils.h"
#include "entrypoints/math_entrypoints.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
+#include "interpreter/interpreter.h"
namespace art {
-// Interpreter entrypoints.
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result);
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result);
-
// Portable entrypoints.
extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
diff --git a/runtime/arch/arm64/portable_entrypoints_arm64.S b/runtime/arch/arm64/portable_entrypoints_arm64.S
index 41711b5c66..9e2c030d71 100644
--- a/runtime/arch/arm64/portable_entrypoints_arm64.S
+++ b/runtime/arch/arm64/portable_entrypoints_arm64.S
@@ -25,4 +25,6 @@ UNIMPLEMENTED art_portable_proxy_invoke_handler
UNIMPLEMENTED art_portable_resolution_trampoline
-UNIMPLEMENTED_NO_HIDE art_portable_to_interpreter_bridge
+UNIMPLEMENTED art_portable_to_interpreter_bridge
+
+UNIMPLEMENTED art_portable_imt_conflict_trampoline
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 52a2a881f2..ab9bf2d34e 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1438,7 +1438,7 @@ END art_quick_resolution_trampoline
/*
* Called to do a generic JNI down-call
*/
-ENTRY_NO_HIDE art_quick_generic_jni_trampoline
+ENTRY art_quick_generic_jni_trampoline
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
str x0, [sp, #0] // Store native ArtMethod* to bottom of stack.
@@ -1534,7 +1534,7 @@ END art_quick_generic_jni_trampoline
* x0 = method being called/to bridge to.
* x1..x7, d0..d7 = arguments to that method.
*/
-ENTRY_NO_HIDE art_quick_to_interpreter_bridge
+ENTRY art_quick_to_interpreter_bridge
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME // Set up frame and save arguments.
// x0 will contain mirror::ArtMethod* method.
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index 25e911d765..db0f71fa37 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "atomic.h"
#include "entrypoints/interpreter/interpreter_entrypoints.h"
#include "entrypoints/jni/jni_entrypoints.h"
#include "entrypoints/portable/portable_entrypoints.h"
@@ -21,18 +22,11 @@
#include "entrypoints/quick/quick_entrypoints.h"
#include "entrypoints/entrypoint_utils.h"
#include "entrypoints/math_entrypoints.h"
-#include "atomic.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
+#include "interpreter/interpreter.h"
namespace art {
-// Interpreter entrypoints.
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result);
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result);
-
// Portable entrypoints.
extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
diff --git a/runtime/arch/mips/portable_entrypoints_mips.S b/runtime/arch/mips/portable_entrypoints_mips.S
index 7545ce0d6c..a171a1d6cc 100644
--- a/runtime/arch/mips/portable_entrypoints_mips.S
+++ b/runtime/arch/mips/portable_entrypoints_mips.S
@@ -131,3 +131,4 @@ END art_portable_invoke_stub
UNIMPLEMENTED art_portable_resolution_trampoline
UNIMPLEMENTED art_portable_to_interpreter_bridge
+UNIMPLEMENTED art_portable_imt_conflict_trampoline
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 6b74a1b1d2..c9b9f04d69 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -260,7 +260,7 @@ class StubTest : public CommonRuntimeTest {
"d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
"d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
"memory"); // clobber.
-#elif defined(__x86_64__) && !defined(__APPLE__)
+#elif defined(__x86_64__) && !defined(__APPLE__) && defined(__clang__)
// Note: Uses the native convention
// TODO: Set the thread?
__asm__ __volatile__(
@@ -485,7 +485,7 @@ class StubTest : public CommonRuntimeTest {
"d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
"d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
"memory"); // clobber.
-#elif defined(__x86_64__) && !defined(__APPLE__)
+#elif defined(__x86_64__) && !defined(__APPLE__) && defined(__clang__)
// Note: Uses the native convention
// TODO: Set the thread?
__asm__ __volatile__(
diff --git a/runtime/arch/x86/asm_support_x86.S b/runtime/arch/x86/asm_support_x86.S
index efbbfb3f10..78b97e5cbe 100644
--- a/runtime/arch/x86/asm_support_x86.S
+++ b/runtime/arch/x86/asm_support_x86.S
@@ -135,16 +135,6 @@ VAR(c_name, 0):
CFI_DEF_CFA(esp, 4)
END_MACRO
-MACRO1(DEFINE_FUNCTION_NO_HIDE, c_name)
- FUNCTION_TYPE(\c_name, 0)
- .globl VAR(c_name, 0)
- ALIGN_FUNCTION_ENTRY
-VAR(c_name, 0):
- CFI_STARTPROC
- // Ensure we get a sane starting CFA.
- CFI_DEF_CFA(esp, 4)
-END_MACRO
-
MACRO1(END_FUNCTION, c_name)
CFI_ENDPROC
SIZE(\c_name, 0)
diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc
index 682c5021ce..f2b91cd81b 100644
--- a/runtime/arch/x86/entrypoints_init_x86.cc
+++ b/runtime/arch/x86/entrypoints_init_x86.cc
@@ -19,18 +19,11 @@
#include "entrypoints/portable/portable_entrypoints.h"
#include "entrypoints/quick/quick_alloc_entrypoints.h"
#include "entrypoints/quick/quick_entrypoints.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
+#include "interpreter/interpreter.h"
namespace art {
-// Interpreter entrypoints.
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result);
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result);
-
// Portable entrypoints.
extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
diff --git a/runtime/arch/x86/portable_entrypoints_x86.S b/runtime/arch/x86/portable_entrypoints_x86.S
index f5fe869593..70c0ae2d94 100644
--- a/runtime/arch/x86/portable_entrypoints_x86.S
+++ b/runtime/arch/x86/portable_entrypoints_x86.S
@@ -111,7 +111,7 @@ DEFINE_FUNCTION art_portable_resolution_trampoline
ret
END_FUNCTION art_portable_resolution_trampoline
-DEFINE_FUNCTION_NO_HIDE art_portable_to_interpreter_bridge
+DEFINE_FUNCTION art_portable_to_interpreter_bridge
PUSH ebp // Set up frame.
movl %esp, %ebp
CFI_DEF_CFA_REGISTER(%ebp)
@@ -127,3 +127,5 @@ DEFINE_FUNCTION_NO_HIDE art_portable_to_interpreter_bridge
CFI_DEF_CFA(%esp, 4)
ret
END_FUNCTION art_portable_to_interpreter_bridge
+
+UNIMPLEMENTED art_portable_imt_conflict_trampoline
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 411d273bca..a158e6db1f 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1140,7 +1140,7 @@ DEFINE_FUNCTION art_quick_resolution_trampoline
DELIVER_PENDING_EXCEPTION
END_FUNCTION art_quick_resolution_trampoline
-DEFINE_FUNCTION_NO_HIDE art_quick_generic_jni_trampoline
+DEFINE_FUNCTION art_quick_generic_jni_trampoline
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
// This also stores the native ArtMethod reference at the bottom of the stack.
@@ -1220,7 +1220,7 @@ DEFINE_FUNCTION_NO_HIDE art_quick_generic_jni_trampoline
DELIVER_PENDING_EXCEPTION
END_FUNCTION art_quick_generic_jni_trampoline
-DEFINE_FUNCTION_NO_HIDE art_quick_to_interpreter_bridge
+DEFINE_FUNCTION art_quick_to_interpreter_bridge
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME // save frame
mov %esp, %edx // remember SP
PUSH eax // alignment padding
diff --git a/runtime/arch/x86_64/asm_support_x86_64.S b/runtime/arch/x86_64/asm_support_x86_64.S
index 4ae61a2a65..5964314914 100644
--- a/runtime/arch/x86_64/asm_support_x86_64.S
+++ b/runtime/arch/x86_64/asm_support_x86_64.S
@@ -132,16 +132,6 @@ VAR(c_name, 0):
CFI_DEF_CFA(rsp, 8)
END_MACRO
-MACRO1(DEFINE_FUNCTION_NO_HIDE, c_name)
- FUNCTION_TYPE(\c_name, 0)
- .globl VAR(c_name, 0)
- ALIGN_FUNCTION_ENTRY
-VAR(c_name, 0):
- CFI_STARTPROC
- // Ensure we get a sane starting CFA.
- CFI_DEF_CFA(rsp, 8)
-END_MACRO
-
MACRO1(END_FUNCTION, c_name)
CFI_ENDPROC
SIZE(\c_name, 0)
@@ -172,18 +162,6 @@ VAR(name, 0):
SIZE(\name, 0)
END_MACRO
-MACRO1(UNIMPLEMENTED_NO_HIDE,name)
- FUNCTION_TYPE(\name, 0)
- .globl VAR(name, 0)
- ALIGN_FUNCTION_ENTRY
-VAR(name, 0):
- CFI_STARTPROC
- int3
- int3
- CFI_ENDPROC
- SIZE(\name, 0)
-END_MACRO
-
MACRO0(UNREACHABLE)
int3
END_MACRO
diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
index c9028e1355..be7359403a 100644
--- a/runtime/arch/x86_64/entrypoints_init_x86_64.cc
+++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
@@ -19,19 +19,12 @@
#include "entrypoints/portable/portable_entrypoints.h"
#include "entrypoints/quick/quick_alloc_entrypoints.h"
#include "entrypoints/quick/quick_entrypoints.h"
-#include "entrypoints/entrypoint_utils.h"
#include "entrypoints/math_entrypoints.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
+#include "interpreter/interpreter.h"
namespace art {
-// Interpreter entrypoints.
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result);
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result);
-
// Portable entrypoints.
extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
diff --git a/runtime/arch/x86_64/portable_entrypoints_x86_64.S b/runtime/arch/x86_64/portable_entrypoints_x86_64.S
index 7b84d178db..3a54005aee 100644
--- a/runtime/arch/x86_64/portable_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/portable_entrypoints_x86_64.S
@@ -25,4 +25,6 @@ UNIMPLEMENTED art_portable_proxy_invoke_handler
UNIMPLEMENTED art_portable_resolution_trampoline
-UNIMPLEMENTED_NO_HIDE art_portable_to_interpreter_bridge
+UNIMPLEMENTED art_portable_to_interpreter_bridge
+
+UNIMPLEMENTED art_portable_imt_conflict_trampoline
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index ca9c0bf0fa..648a99a0ec 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1266,7 +1266,7 @@ END_FUNCTION art_quick_resolution_trampoline
/*
* Called to do a generic JNI down-call
*/
-DEFINE_FUNCTION_NO_HIDE art_quick_generic_jni_trampoline
+DEFINE_FUNCTION art_quick_generic_jni_trampoline
// Save callee and GPR args, mixed together to agree with core spills bitmap.
PUSH r15 // Callee save.
PUSH r14 // Callee save.
@@ -1453,7 +1453,7 @@ END_FUNCTION art_quick_generic_jni_trampoline
* RDI = method being called / to bridge to.
* RSI, RDX, RCX, R8, R9 are arguments to that method.
*/
-DEFINE_FUNCTION_NO_HIDE art_quick_to_interpreter_bridge
+DEFINE_FUNCTION art_quick_to_interpreter_bridge
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME // Set up frame and save arguments.
movq %gs:THREAD_SELF_OFFSET, %rsi // RSI := Thread::Current()
movq %rsp, %rdx // RDX := sp
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index b2ad1d06d6..5af597b89b 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -85,7 +85,7 @@ void InitLogging(char* argv[]) {
}
std::vector<std::string> specs;
- Split(tags, ' ', specs);
+ Split(tags, ' ', &specs);
for (size_t i = 0; i < specs.size(); ++i) {
// "tag-pattern:[vdiwefs]"
std::string spec(specs[i]);
diff --git a/runtime/base/macros.h b/runtime/base/macros.h
index f5a38bbf35..c80d35e42b 100644
--- a/runtime/base/macros.h
+++ b/runtime/base/macros.h
@@ -63,6 +63,11 @@ struct CompileAssert {
#define COMPILE_ASSERT(expr, msg) \
typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] // NOLINT
+// Declare a friend relationship in a class with a test. Used rather that FRIEND_TEST to avoid
+// globally importing gtest/gtest.h into the main ART header files.
+#define ART_FRIEND_TEST(test_set_name, individual_test)\
+friend class test_set_name##_##individual_test##_Test
+
// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions.
// It goes in the private: declarations in a class.
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index cbcd408b6d..70b6f7e295 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -83,18 +83,25 @@ static bool ComputeRelativeTimeSpec(timespec* result_ts, const timespec& lhs, co
}
#endif
-class ScopedAllMutexesLock {
+class ScopedAllMutexesLock FINAL {
public:
explicit ScopedAllMutexesLock(const BaseMutex* mutex) : mutex_(mutex) {
while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakAcquire(0, mutex)) {
NanoSleep(100);
}
}
+
~ScopedAllMutexesLock() {
+#if !defined(__clang__)
+ // TODO: remove this workaround target GCC/libc++/bionic bug "invalid failure memory model".
+ while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakSequentiallyConsistent(mutex_, 0)) {
+#else
while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakRelease(mutex_, 0)) {
+#endif
NanoSleep(100);
}
}
+
private:
const BaseMutex* const mutex_;
};
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5718e44f9c..bbbb9e0b81 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -32,6 +32,7 @@
#include "compiler_callbacks.h"
#include "debugger.h"
#include "dex_file-inl.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc_root-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/accounting/heap_bitmap.h"
@@ -236,44 +237,6 @@ static void ShuffleForward(const size_t num_fields, size_t* current_field_idx,
}
}
-const char* ClassLinker::class_roots_descriptors_[] = {
- "Ljava/lang/Class;",
- "Ljava/lang/Object;",
- "[Ljava/lang/Class;",
- "[Ljava/lang/Object;",
- "Ljava/lang/String;",
- "Ljava/lang/DexCache;",
- "Ljava/lang/ref/Reference;",
- "Ljava/lang/reflect/ArtField;",
- "Ljava/lang/reflect/ArtMethod;",
- "Ljava/lang/reflect/Proxy;",
- "[Ljava/lang/String;",
- "[Ljava/lang/reflect/ArtField;",
- "[Ljava/lang/reflect/ArtMethod;",
- "Ljava/lang/ClassLoader;",
- "Ljava/lang/Throwable;",
- "Ljava/lang/ClassNotFoundException;",
- "Ljava/lang/StackTraceElement;",
- "Z",
- "B",
- "C",
- "D",
- "F",
- "I",
- "J",
- "S",
- "V",
- "[Z",
- "[B",
- "[C",
- "[D",
- "[F",
- "[I",
- "[J",
- "[S",
- "[Ljava/lang/StackTraceElement;",
-};
-
ClassLinker::ClassLinker(InternTable* intern_table)
// dex_lock_ is recursive as it may be used in stack dumping.
: dex_lock_("ClassLinker dex lock", kDefaultMutexLevel),
@@ -292,16 +255,9 @@ ClassLinker::ClassLinker(InternTable* intern_table)
quick_imt_conflict_trampoline_(nullptr),
quick_generic_jni_trampoline_(nullptr),
quick_to_interpreter_bridge_trampoline_(nullptr) {
- CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax));
memset(find_array_class_cache_, 0, kFindArrayCacheSize * sizeof(mirror::Class*));
}
-// To set a value for generic JNI. May be necessary in compiler tests.
-extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
-
void ClassLinker::InitWithoutImage(const std::vector<const DexFile*>& boot_class_path) {
VLOG(startup) << "ClassLinker::Init";
CHECK(!Runtime::Current()->GetHeap()->HasImageSpace()) << "Runtime has image. We should use it.";
@@ -482,12 +438,12 @@ void ClassLinker::InitWithoutImage(const std::vector<const DexFile*>& boot_class
// Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that
// we do not need friend classes or a publicly exposed setter.
- quick_generic_jni_trampoline_ = reinterpret_cast<void*>(art_quick_generic_jni_trampoline);
+ quick_generic_jni_trampoline_ = GetQuickGenericJniStub();
if (!runtime->IsCompiler()) {
// We need to set up the generic trampolines since we don't have an image.
- quick_resolution_trampoline_ = reinterpret_cast<void*>(art_quick_resolution_trampoline);
- quick_imt_conflict_trampoline_ = reinterpret_cast<void*>(art_quick_imt_conflict_trampoline);
- quick_to_interpreter_bridge_trampoline_ = reinterpret_cast<void*>(art_quick_to_interpreter_bridge);
+ quick_resolution_trampoline_ = GetQuickResolutionStub();
+ quick_imt_conflict_trampoline_ = GetQuickImtConflictStub();
+ quick_to_interpreter_bridge_trampoline_ = GetQuickToInterpreterBridge();
}
// Object, String and DexCache need to be rerun through FindSystemClass to finish init
@@ -571,15 +527,15 @@ void ClassLinker::InitWithoutImage(const std::vector<const DexFile*>& boot_class
CHECK_EQ(java_lang_reflect_ArtField.Get(), Art_field_class);
mirror::Class* String_array_class =
- FindSystemClass(self, class_roots_descriptors_[kJavaLangStringArrayClass]);
+ FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass));
CHECK_EQ(object_array_string.Get(), String_array_class);
mirror::Class* Art_method_array_class =
- FindSystemClass(self, class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]);
+ FindSystemClass(self, GetClassRootDescriptor(kJavaLangReflectArtMethodArrayClass));
CHECK_EQ(object_array_art_method.Get(), Art_method_array_class);
mirror::Class* Art_field_array_class =
- FindSystemClass(self, class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]);
+ FindSystemClass(self, GetClassRootDescriptor(kJavaLangReflectArtFieldArrayClass));
CHECK_EQ(object_array_art_field.Get(), Art_field_array_class);
// End of special init trickery, subsequent classes may be loaded via FindSystemClass.
@@ -1666,7 +1622,7 @@ static void InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg)
if (obj->IsArtMethod()) {
mirror::ArtMethod* method = obj->AsArtMethod();
if (!method->IsNative()) {
- method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
+ method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
if (method != Runtime::Current()->GetResolutionMethod()) {
method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
@@ -2535,7 +2491,7 @@ const void* ClassLinker::GetQuickOatCodeFor(mirror::ArtMethod* method) {
if (result == nullptr) {
if (method->IsNative()) {
// No code and native? Use generic trampoline.
- result = GetQuickGenericJniTrampoline();
+ result = GetQuickGenericJniStub();
} else if (method->IsPortableCompiled()) {
// No code? Do we expect portable code?
result = GetQuickToPortableBridge();
@@ -2689,7 +2645,7 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) {
// Use interpreter entry point.
// Check whether the method is native, in which case it's generic JNI.
if (quick_code == nullptr && portable_code == nullptr && method->IsNative()) {
- quick_code = GetQuickGenericJniTrampoline();
+ quick_code = GetQuickGenericJniStub();
portable_code = GetPortableToQuickBridge();
} else {
portable_code = GetPortableToInterpreterBridge();
@@ -2715,7 +2671,8 @@ void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method,
const OatFile::OatClass* oat_class,
const DexFile& dex_file, uint32_t dex_method_index,
uint32_t method_index) {
- if (Runtime::Current()->IsCompiler()) {
+ Runtime* runtime = Runtime::Current();
+ if (runtime->IsCompiler()) {
// The following code only applies to a non-compiler runtime.
return;
}
@@ -2734,7 +2691,7 @@ void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method,
method->GetEntryPointFromQuickCompiledCode(),
method->GetEntryPointFromPortableCompiledCode());
if (enter_interpreter && !method->IsNative()) {
- method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
+ method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
} else {
method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
}
@@ -2750,15 +2707,15 @@ void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method,
// For static methods excluding the class initializer, install the trampoline.
// It will be replaced by the proper entry point by ClassLinker::FixupStaticTrampolines
// after initializing class (see ClassLinker::InitializeClass method).
- method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionTrampoline());
- method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionTrampoline());
+ method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
+ method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionStub());
} else if (enter_interpreter) {
if (!method->IsNative()) {
// Set entry point from compiled code if there's no code or in interpreter only mode.
method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
} else {
- method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniTrampoline());
+ method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
}
} else if (method->GetEntryPointFromPortableCompiledCode() != nullptr) {
@@ -2772,18 +2729,18 @@ void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method,
if (method->IsNative()) {
// Unregistering restores the dlsym lookup stub.
- method->UnregisterNative(Thread::Current());
+ method->UnregisterNative();
if (enter_interpreter) {
- // We have a native method here without code. Then it should have either the GenericJni
- // trampoline as entrypoint (non-static), or the Resolution trampoline (static).
- DCHECK(method->GetEntryPointFromQuickCompiledCode() == GetQuickResolutionTrampoline()
- || method->GetEntryPointFromQuickCompiledCode() == GetQuickGenericJniTrampoline());
+ // We have a native method here without code. Then it should have either the generic JNI
+ // trampoline as entrypoint (non-static), or the resolution trampoline (static).
+ // TODO: this doesn't handle all the cases where trampolines may be installed.
+ const void* entry_point = method->GetEntryPointFromQuickCompiledCode();
+ DCHECK(IsQuickGenericJniStub(entry_point) || IsQuickResolutionStub(entry_point));
}
}
// Allow instrumentation its chance to hijack code.
- Runtime* runtime = Runtime::Current();
runtime->GetInstrumentation()->UpdateMethodsCode(method.Get(),
method->GetEntryPointFromQuickCompiledCode(),
method->GetEntryPointFromPortableCompiledCode(),
@@ -3224,13 +3181,13 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto
new_class.Assign(GetClassRoot(kClassArrayClass));
} else if (strcmp(descriptor, "[Ljava/lang/Object;") == 0) {
new_class.Assign(GetClassRoot(kObjectArrayClass));
- } else if (strcmp(descriptor, class_roots_descriptors_[kJavaLangStringArrayClass]) == 0) {
+ } else if (strcmp(descriptor, GetClassRootDescriptor(kJavaLangStringArrayClass)) == 0) {
new_class.Assign(GetClassRoot(kJavaLangStringArrayClass));
} else if (strcmp(descriptor,
- class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]) == 0) {
+ GetClassRootDescriptor(kJavaLangReflectArtMethodArrayClass)) == 0) {
new_class.Assign(GetClassRoot(kJavaLangReflectArtMethodArrayClass));
} else if (strcmp(descriptor,
- class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]) == 0) {
+ GetClassRootDescriptor(kJavaLangReflectArtFieldArrayClass)) == 0) {
new_class.Assign(GetClassRoot(kJavaLangReflectArtFieldArrayClass));
} else if (strcmp(descriptor, "[C") == 0) {
new_class.Assign(GetClassRoot(kCharArrayClass));
@@ -5546,6 +5503,84 @@ void ClassLinker::DumpAllClasses(int flags) {
}
}
+static OatFile::OatMethod CreateOatMethod(const void* code, const uint8_t* gc_map,
+ bool is_portable) {
+ CHECK_EQ(kUsePortableCompiler, is_portable);
+ CHECK(code != nullptr);
+ const uint8_t* base;
+ uint32_t code_offset, gc_map_offset;
+ if (gc_map == nullptr) {
+ base = reinterpret_cast<const uint8_t*>(code); // Base of data points at code.
+ base -= sizeof(void*); // Move backward so that code_offset != 0.
+ code_offset = sizeof(void*);
+ gc_map_offset = 0;
+ } else {
+ // TODO: 64bit support.
+ base = nullptr; // Base of data in oat file, ie 0.
+ code_offset = PointerToLowMemUInt32(code);
+ gc_map_offset = PointerToLowMemUInt32(gc_map);
+ }
+ return OatFile::OatMethod(base, code_offset, gc_map_offset);
+}
+
+bool ClassLinker::IsPortableResolutionStub(const void* entry_point) const {
+ return (entry_point == GetPortableResolutionStub()) ||
+ (portable_resolution_trampoline_ == entry_point);
+}
+
+bool ClassLinker::IsQuickResolutionStub(const void* entry_point) const {
+ return (entry_point == GetQuickResolutionStub()) ||
+ (quick_resolution_trampoline_ == entry_point);
+}
+
+bool ClassLinker::IsPortableToInterpreterBridge(const void* entry_point) const {
+ return (entry_point == GetPortableToInterpreterBridge());
+ // TODO: portable_to_interpreter_bridge_trampoline_ == entry_point;
+}
+
+bool ClassLinker::IsQuickToInterpreterBridge(const void* entry_point) const {
+ return (entry_point == GetQuickToInterpreterBridge()) ||
+ (quick_to_interpreter_bridge_trampoline_ == entry_point);
+}
+
+bool ClassLinker::IsQuickGenericJniStub(const void* entry_point) const {
+ return (entry_point == GetQuickGenericJniStub()) ||
+ (quick_generic_jni_trampoline_ == entry_point);
+}
+
+const void* ClassLinker::GetRuntimeQuickGenericJniStub() const {
+ return GetQuickGenericJniStub();
+}
+
+void ClassLinker::SetEntryPointsToCompiledCode(mirror::ArtMethod* method, const void* method_code,
+ bool is_portable) const {
+ OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr, is_portable);
+ oat_method.LinkMethod(method);
+ method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+ // Create bridges to transition between different kinds of compiled bridge.
+ if (method->GetEntryPointFromPortableCompiledCode() == nullptr) {
+ method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
+ } else {
+ CHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
+ method->SetEntryPointFromQuickCompiledCode(GetQuickToPortableBridge());
+ method->SetIsPortableCompiled();
+ }
+}
+
+void ClassLinker::SetEntryPointsToInterpreter(mirror::ArtMethod* method) const {
+ if (!method->IsNative()) {
+ method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
+ method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
+ method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
+ } else {
+ const void* quick_method_code = GetQuickGenericJniStub();
+ OatFile::OatMethod oat_method = CreateOatMethod(quick_method_code, nullptr, false);
+ oat_method.LinkMethod(method);
+ method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+ method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
+ }
+}
+
void ClassLinker::DumpForSigQuit(std::ostream& os) {
Thread* self = Thread::Current();
if (dex_cache_image_class_lookup_required_) {
@@ -5584,4 +5619,50 @@ void ClassLinker::SetClassRoot(ClassRoot class_root, mirror::Class* klass) {
class_roots->Set<false>(class_root, klass);
}
+const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) {
+ static const char* class_roots_descriptors[] = {
+ "Ljava/lang/Class;",
+ "Ljava/lang/Object;",
+ "[Ljava/lang/Class;",
+ "[Ljava/lang/Object;",
+ "Ljava/lang/String;",
+ "Ljava/lang/DexCache;",
+ "Ljava/lang/ref/Reference;",
+ "Ljava/lang/reflect/ArtField;",
+ "Ljava/lang/reflect/ArtMethod;",
+ "Ljava/lang/reflect/Proxy;",
+ "[Ljava/lang/String;",
+ "[Ljava/lang/reflect/ArtField;",
+ "[Ljava/lang/reflect/ArtMethod;",
+ "Ljava/lang/ClassLoader;",
+ "Ljava/lang/Throwable;",
+ "Ljava/lang/ClassNotFoundException;",
+ "Ljava/lang/StackTraceElement;",
+ "Z",
+ "B",
+ "C",
+ "D",
+ "F",
+ "I",
+ "J",
+ "S",
+ "V",
+ "[Z",
+ "[B",
+ "[C",
+ "[D",
+ "[F",
+ "[I",
+ "[J",
+ "[S",
+ "[Ljava/lang/StackTraceElement;",
+ };
+ COMPILE_ASSERT(arraysize(class_roots_descriptors) == size_t(kClassRootsMax),
+ mismatch_between_class_descriptors_and_class_root_enum);
+
+ const char* descriptor = class_roots_descriptors[class_root];
+ CHECK(descriptor != nullptr);
+ return descriptor;
+}
+
} // namespace art
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 373fa893ea..18479268ed 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -27,7 +27,6 @@
#include "base/mutex.h"
#include "dex_file.h"
#include "gc_root.h"
-#include "gtest/gtest.h"
#include "jni.h"
#include "oat_file.h"
#include "object_callbacks.h"
@@ -60,6 +59,46 @@ enum VisitRootFlags : uint8_t;
class ClassLinker {
public:
+ // Well known mirror::Class roots accessed via GetClassRoot.
+ enum ClassRoot {
+ kJavaLangClass,
+ kJavaLangObject,
+ kClassArrayClass,
+ kObjectArrayClass,
+ kJavaLangString,
+ kJavaLangDexCache,
+ kJavaLangRefReference,
+ kJavaLangReflectArtField,
+ kJavaLangReflectArtMethod,
+ kJavaLangReflectProxy,
+ kJavaLangStringArrayClass,
+ kJavaLangReflectArtFieldArrayClass,
+ kJavaLangReflectArtMethodArrayClass,
+ kJavaLangClassLoader,
+ kJavaLangThrowable,
+ kJavaLangClassNotFoundException,
+ kJavaLangStackTraceElement,
+ kPrimitiveBoolean,
+ kPrimitiveByte,
+ kPrimitiveChar,
+ kPrimitiveDouble,
+ kPrimitiveFloat,
+ kPrimitiveInt,
+ kPrimitiveLong,
+ kPrimitiveShort,
+ kPrimitiveVoid,
+ kBooleanArrayClass,
+ kByteArrayClass,
+ kCharArrayClass,
+ kDoubleArrayClass,
+ kFloatArrayClass,
+ kIntArrayClass,
+ kLongArrayClass,
+ kShortArrayClass,
+ kJavaLangStackTraceElementArrayClass,
+ kClassRootsMax,
+ };
+
explicit ClassLinker(InternTable* intern_table);
~ClassLinker();
@@ -371,34 +410,38 @@ class ClassLinker {
pid_t GetClassesLockOwner(); // For SignalCatcher.
pid_t GetDexLockOwner(); // For SignalCatcher.
- const void* GetPortableResolutionTrampoline() const {
- return portable_resolution_trampoline_;
- }
+ mirror::Class* GetClassRoot(ClassRoot class_root) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- const void* GetQuickGenericJniTrampoline() const {
- return quick_generic_jni_trampoline_;
- }
+ static const char* GetClassRootDescriptor(ClassRoot class_root);
- const void* GetQuickResolutionTrampoline() const {
- return quick_resolution_trampoline_;
- }
+ // Is the given entry point portable code to run the resolution stub?
+ bool IsPortableResolutionStub(const void* entry_point) const;
- const void* GetPortableImtConflictTrampoline() const {
- return portable_imt_conflict_trampoline_;
- }
+ // Is the given entry point quick code to run the resolution stub?
+ bool IsQuickResolutionStub(const void* entry_point) const;
- const void* GetQuickImtConflictTrampoline() const {
- return quick_imt_conflict_trampoline_;
- }
+ // Is the given entry point portable code to bridge into the interpreter?
+ bool IsPortableToInterpreterBridge(const void* entry_point) const;
- const void* GetQuickToInterpreterBridgeTrampoline() const {
- return quick_to_interpreter_bridge_trampoline_;
- }
+ // Is the given entry point quick code to bridge into the interpreter?
+ bool IsQuickToInterpreterBridge(const void* entry_point) const;
+
+ // Is the given entry point quick code to run the generic JNI stub?
+ bool IsQuickGenericJniStub(const void* entry_point) const;
InternTable* GetInternTable() const {
return intern_table_;
}
+ // Set the entrypoints up for method to the given code.
+ void SetEntryPointsToCompiledCode(mirror::ArtMethod* method, const void* method_code,
+ bool is_portable) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Set the entrypoints up for method to the enter the interpreter.
+ void SetEntryPointsToInterpreter(mirror::ArtMethod* method) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Attempts to insert a class into a class table. Returns NULL if
// the class was inserted, otherwise returns an existing class with
// the same descriptor and ClassLoader.
@@ -668,6 +711,12 @@ class ClassLinker {
void FixupTemporaryDeclaringClass(mirror::Class* temp_class, mirror::Class* new_class)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void SetClassRoot(ClassRoot class_root, mirror::Class* klass)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Return the quick generic JNI stub for testing.
+ const void* GetRuntimeQuickGenericJniStub() const;
+
std::vector<const DexFile*> boot_class_path_;
mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
@@ -691,61 +740,9 @@ class ClassLinker {
// the classes into the class_table_ to avoid dex cache based searches.
Atomic<uint32_t> failed_dex_cache_class_lookups_;
- // indexes into class_roots_.
- // needs to be kept in sync with class_roots_descriptors_.
- enum ClassRoot {
- kJavaLangClass,
- kJavaLangObject,
- kClassArrayClass,
- kObjectArrayClass,
- kJavaLangString,
- kJavaLangDexCache,
- kJavaLangRefReference,
- kJavaLangReflectArtField,
- kJavaLangReflectArtMethod,
- kJavaLangReflectProxy,
- kJavaLangStringArrayClass,
- kJavaLangReflectArtFieldArrayClass,
- kJavaLangReflectArtMethodArrayClass,
- kJavaLangClassLoader,
- kJavaLangThrowable,
- kJavaLangClassNotFoundException,
- kJavaLangStackTraceElement,
- kPrimitiveBoolean,
- kPrimitiveByte,
- kPrimitiveChar,
- kPrimitiveDouble,
- kPrimitiveFloat,
- kPrimitiveInt,
- kPrimitiveLong,
- kPrimitiveShort,
- kPrimitiveVoid,
- kBooleanArrayClass,
- kByteArrayClass,
- kCharArrayClass,
- kDoubleArrayClass,
- kFloatArrayClass,
- kIntArrayClass,
- kLongArrayClass,
- kShortArrayClass,
- kJavaLangStackTraceElementArrayClass,
- kClassRootsMax,
- };
+ // Well known mirror::Class roots.
GcRoot<mirror::ObjectArray<mirror::Class>> class_roots_;
- mirror::Class* GetClassRoot(ClassRoot class_root) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- void SetClassRoot(ClassRoot class_root, mirror::Class* klass)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- static const char* class_roots_descriptors_[];
-
- const char* GetClassRootDescriptor(ClassRoot class_root) {
- const char* descriptor = class_roots_descriptors_[class_root];
- CHECK(descriptor != NULL);
- return descriptor;
- }
-
// The interface table used by all arrays.
GcRoot<mirror::IfTable> array_iftable_;
@@ -773,12 +770,11 @@ class ClassLinker {
friend class ImageWriter; // for GetClassRoots
friend class ImageDumper; // for FindOpenedOatFileFromOatLocation
friend class ElfPatcher; // for FindOpenedOatFileForDexFile & FindOpenedOatFileFromOatLocation
+ friend class JniCompilerTest; // for GetRuntimeQuickGenericJniStub
friend class NoDex2OatTest; // for FindOpenedOatFileForDexFile
friend class NoPatchoatTest; // for FindOpenedOatFileForDexFile
- FRIEND_TEST(ClassLinkerTest, ClassRootDescriptors);
- FRIEND_TEST(mirror::DexCacheTest, Open);
- FRIEND_TEST(ExceptionTest, FindExceptionHandler);
- FRIEND_TEST(ObjectTest, AllocObjectArray);
+ ART_FRIEND_TEST(mirror::DexCacheTest, Open); // for AllocDexCache
+
DISALLOW_COPY_AND_ASSIGN(ClassLinker);
};
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 971ff89036..b676c62ee1 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -617,7 +617,7 @@ bool Dbg::ParseJdwpOptions(const std::string& options) {
VLOG(jdwp) << "ParseJdwpOptions: " << options;
std::vector<std::string> pairs;
- Split(options, ',', pairs);
+ Split(options, ',', &pairs);
for (size_t i = 0; i < pairs.size(); ++i) {
std::string::size_type equals = pairs[i].find('=');
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index ce34993950..c46d8871d5 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -183,59 +183,6 @@ JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, cons
bool FillArrayData(mirror::Object* obj, const Instruction::ArrayDataPayload* payload)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-// Entry point for deoptimization.
-extern "C" void art_quick_deoptimize();
-static inline uintptr_t GetQuickDeoptimizationEntryPoint() {
- return reinterpret_cast<uintptr_t>(art_quick_deoptimize);
-}
-
-// Return address of instrumentation stub.
-extern "C" void art_quick_instrumentation_entry(void*);
-static inline void* GetQuickInstrumentationEntryPoint() {
- return reinterpret_cast<void*>(art_quick_instrumentation_entry);
-}
-
-// The return_pc of instrumentation exit stub.
-extern "C" void art_quick_instrumentation_exit();
-static inline uintptr_t GetQuickInstrumentationExitPc() {
- return reinterpret_cast<uintptr_t>(art_quick_instrumentation_exit);
-}
-
-extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
-static inline const void* GetPortableToInterpreterBridge() {
- return reinterpret_cast<void*>(art_portable_to_interpreter_bridge);
-}
-
-static inline const void* GetPortableToQuickBridge() {
- // TODO: portable to quick bridge. Bug: 8196384
- return GetPortableToInterpreterBridge();
-}
-
-extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
-static inline const void* GetQuickToInterpreterBridge() {
- return reinterpret_cast<void*>(art_quick_to_interpreter_bridge);
-}
-
-static inline const void* GetQuickToPortableBridge() {
- // TODO: quick to portable bridge. Bug: 8196384
- return GetQuickToInterpreterBridge();
-}
-
-extern "C" void art_portable_proxy_invoke_handler();
-static inline const void* GetPortableProxyInvokeHandler() {
- return reinterpret_cast<void*>(art_portable_proxy_invoke_handler);
-}
-
-extern "C" void art_quick_proxy_invoke_handler();
-static inline const void* GetQuickProxyInvokeHandler() {
- return reinterpret_cast<void*>(art_quick_proxy_invoke_handler);
-}
-
-extern "C" void* art_jni_dlsym_lookup_stub(JNIEnv*, jobject);
-static inline void* GetJniDlsymLookupStub() {
- return reinterpret_cast<void*>(art_jni_dlsym_lookup_stub);
-}
-
template <typename INT_TYPE, typename FLOAT_TYPE>
static inline INT_TYPE art_float_to_integral(FLOAT_TYPE f);
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
index b617636d13..908d3cd43c 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -25,7 +25,7 @@
namespace art {
// TODO: Make the MethodHelper here be compaction safe.
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
+extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper* mh,
const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result) {
mirror::ArtMethod* method = shadow_frame->GetMethod();
@@ -54,7 +54,7 @@ extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& m
} else {
method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
(shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
- result, mh.GetShorty());
+ result, mh->GetShorty());
}
}
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.h b/runtime/entrypoints/interpreter/interpreter_entrypoints.h
index d8b22046de..5d646e905f 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.h
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.h
@@ -33,10 +33,10 @@ class Thread;
// Pointers to functions that are called by interpreter trampolines via thread-local storage.
struct PACKED(4) InterpreterEntryPoints {
- void (*pInterpreterToInterpreterBridge)(Thread* self, MethodHelper& mh,
+ void (*pInterpreterToInterpreterBridge)(Thread* self, MethodHelper* mh,
const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result);
- void (*pInterpreterToCompiledCodeBridge)(Thread* self, MethodHelper& mh,
+ void (*pInterpreterToCompiledCodeBridge)(Thread* self, MethodHelper* mh,
const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result);
};
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index edb3b723ef..2752407750 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -45,7 +45,7 @@ extern "C" void* artFindNativeMethod(Thread* self) {
return NULL;
} else {
// Register so that future calls don't come here
- method->RegisterNative(self, native_code, false);
+ method->RegisterNative(native_code, false);
return native_code;
}
}
diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
index 642c94a01e..c3664bfac6 100644
--- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
@@ -19,6 +19,7 @@
#include "dex_instruction-inl.h"
#include "entrypoints/entrypoint_utils-inl.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
#include "interpreter/interpreter.h"
#include "mirror/art_method-inl.h"
#include "mirror/object-inl.h"
@@ -222,7 +223,7 @@ extern "C" uint64_t artPortableToInterpreterBridge(mirror::ArtMethod* method, Th
}
}
- JValue result = interpreter::EnterInterpreterFromStub(self, mh, code_item, *shadow_frame);
+ JValue result = interpreter::EnterInterpreterFromEntryPoint(self, &mh, code_item, shadow_frame);
// Pop transition.
self->PopManagedStackFragment(fragment);
return result.GetJ();
@@ -323,7 +324,7 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called
uint32_t dex_pc;
mirror::ArtMethod* caller = self->GetCurrentMethod(&dex_pc);
- ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
InvokeType invoke_type;
bool is_range;
if (called->IsRuntimeMethod()) {
@@ -379,7 +380,7 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called
is_range = true;
}
uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
- called = linker->ResolveMethod(Thread::Current(), dex_method_idx, &caller, invoke_type);
+ called = class_linker->ResolveMethod(Thread::Current(), dex_method_idx, &caller, invoke_type);
// Incompatible class change should have been handled in resolve method.
CHECK(!called->CheckIncompatibleClassChange(invoke_type));
// Refine called method based on receiver.
@@ -399,27 +400,27 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called
// Ensure that the called method's class is initialized.
StackHandleScope<1> hs(self);
Handle<mirror::Class> called_class(hs.NewHandle(called->GetDeclaringClass()));
- linker->EnsureInitialized(self, called_class, true, true);
+ class_linker->EnsureInitialized(self, called_class, true, true);
if (LIKELY(called_class->IsInitialized())) {
code = called->GetEntryPointFromPortableCompiledCode();
// TODO: remove this after we solve the link issue.
if (code == nullptr) {
bool have_portable_code;
- code = linker->GetPortableOatCodeFor(called, &have_portable_code);
+ code = class_linker->GetPortableOatCodeFor(called, &have_portable_code);
}
} else if (called_class->IsInitializing()) {
if (invoke_type == kStatic) {
// Class is still initializing, go to oat and grab code (trampoline must be left in place
// until class is initialized to stop races between threads).
bool have_portable_code;
- code = linker->GetPortableOatCodeFor(called, &have_portable_code);
+ code = class_linker->GetPortableOatCodeFor(called, &have_portable_code);
} else {
// No trampoline for non-static methods.
code = called->GetEntryPointFromPortableCompiledCode();
// TODO: remove this after we solve the link issue.
if (code == nullptr) {
bool have_portable_code;
- code = linker->GetPortableOatCodeFor(called, &have_portable_code);
+ code = class_linker->GetPortableOatCodeFor(called, &have_portable_code);
}
}
} else {
@@ -430,7 +431,7 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called
// Expect class to at least be initializing.
DCHECK(called->GetDeclaringClass()->IsInitializing());
// Don't want infinite recursion.
- DCHECK(code != linker->GetPortableResolutionTrampoline());
+ DCHECK(!class_linker->IsPortableResolutionStub(code));
// Set up entry into main method
*called_addr = called;
}
diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
index 42ace40637..bb0e5e31c8 100644
--- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
@@ -15,6 +15,7 @@
*/
#include "callee_save_frame.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
#include "instruction_set.h"
#include "instrumentation.h"
#include "mirror/art_method-inl.h"
@@ -38,8 +39,7 @@ extern "C" const void* artInstrumentationMethodEntryFromCode(mirror::ArtMethod*
} else {
result = instrumentation->GetQuickCodeFor(method);
}
- DCHECK((result != Runtime::Current()->GetClassLinker()->GetQuickToInterpreterBridgeTrampoline())
- || !Runtime::Current()->GetHeap()->HasImageSpace());
+ DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(result));
bool interpreter_entry = (result == GetQuickToInterpreterBridge());
instrumentation->PushInstrumentationStackFrame(self, method->IsStatic() ? nullptr : this_object,
method, lr, interpreter_entry);
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 96903db414..224756bbc2 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -19,6 +19,7 @@
#include "dex_file-inl.h"
#include "dex_instruction-inl.h"
#include "entrypoints/entrypoint_utils-inl.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
#include "instruction_set.h"
#include "interpreter/interpreter.h"
@@ -504,7 +505,7 @@ extern "C" uint64_t artQuickToInterpreterBridge(mirror::ArtMethod* method, Threa
return 0;
}
}
- JValue result = interpreter::EnterInterpreterFromStub(self, mh, code_item, *shadow_frame);
+ JValue result = interpreter::EnterInterpreterFromEntryPoint(self, &mh, code_item, shadow_frame);
// Pop transition.
self->PopManagedStackFragment(fragment);
// No need to restore the args since the method has already been run by the interpreter.
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
index 02b8a5b605..41af88e638 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
@@ -55,9 +55,10 @@ class QuickTrampolineEntrypointsTest : public CommonRuntimeTest {
NO_THREAD_SAFETY_ANALYSIS {
mirror::ArtMethod* save_method = CreateCalleeSaveMethod(isa, type);
QuickMethodFrameInfo frame_info = save_method->GetQuickFrameInfo();
- EXPECT_EQ(save_method->GetReturnPcOffsetInBytes(), pc_offset) << "Expected and real pc offset"
- " differs for " << type << " core spills=" << std::hex << frame_info.CoreSpillMask() <<
- " fp spills=" << frame_info.FpSpillMask() << std::dec << " ISA " << isa;
+ EXPECT_EQ(save_method->GetReturnPcOffset().SizeValue(), pc_offset)
+ << "Expected and real pc offset differs for " << type
+ << " core spills=" << std::hex << frame_info.CoreSpillMask()
+ << " fp spills=" << frame_info.FpSpillMask() << std::dec << " ISA " << isa;
}
};
diff --git a/runtime/entrypoints/runtime_asm_entrypoints.h b/runtime/entrypoints/runtime_asm_entrypoints.h
new file mode 100644
index 0000000000..db36a73956
--- /dev/null
+++ b/runtime/entrypoints/runtime_asm_entrypoints.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2012 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_RUNTIME_ENTRYPOINTS_RUNTIME_ASM_ENTRYPOINTS_H_
+#define ART_RUNTIME_ENTRYPOINTS_RUNTIME_ASM_ENTRYPOINTS_H_
+
+namespace art {
+
+#ifndef BUILDING_LIBART
+#error "File and symbols only for use within libart."
+#endif
+
+extern "C" void* art_jni_dlsym_lookup_stub(JNIEnv*, jobject);
+static inline const void* GetJniDlsymLookupStub() {
+ return reinterpret_cast<const void*>(art_jni_dlsym_lookup_stub);
+}
+
+// Return the address of portable stub code for handling IMT conflicts.
+extern "C" void art_portable_imt_conflict_trampoline(mirror::ArtMethod*);
+static inline const void* GetPortableImtConflictStub() {
+ return reinterpret_cast<const void*>(art_portable_imt_conflict_trampoline);
+}
+
+// Return the address of quick stub code for handling IMT conflicts.
+extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
+static inline const void* GetQuickImtConflictStub() {
+ return reinterpret_cast<const void*>(art_quick_imt_conflict_trampoline);
+}
+
+// Return the address of portable stub code for bridging from portable code to the interpreter.
+extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
+static inline const void* GetPortableToInterpreterBridge() {
+ return reinterpret_cast<const void*>(art_portable_to_interpreter_bridge);
+}
+
+// Return the address of quick stub code for bridging from quick code to the interpreter.
+extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
+static inline const void* GetQuickToInterpreterBridge() {
+ return reinterpret_cast<const void*>(art_quick_to_interpreter_bridge);
+}
+
+// Return the address of portable stub code for bridging from portable code to quick.
+static inline const void* GetPortableToQuickBridge() {
+ // TODO: portable to quick bridge. Bug: 8196384
+ return GetPortableToInterpreterBridge();
+}
+
+// Return the address of quick stub code for bridging from quick code to portable.
+static inline const void* GetQuickToPortableBridge() {
+ // TODO: quick to portable bridge. Bug: 8196384
+ return GetQuickToInterpreterBridge();
+}
+
+// Return the address of quick stub code for handling JNI calls.
+extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
+static inline const void* GetQuickGenericJniStub() {
+ return reinterpret_cast<const void*>(art_quick_generic_jni_trampoline);
+}
+
+// Return the address of portable stub code for handling transitions into the proxy invoke handler.
+extern "C" void art_portable_proxy_invoke_handler();
+static inline const void* GetPortableProxyInvokeHandler() {
+ return reinterpret_cast<const void*>(art_portable_proxy_invoke_handler);
+}
+
+// Return the address of quick stub code for handling transitions into the proxy invoke handler.
+extern "C" void art_quick_proxy_invoke_handler();
+static inline const void* GetQuickProxyInvokeHandler() {
+ return reinterpret_cast<const void*>(art_quick_proxy_invoke_handler);
+}
+
+// Return the address of portable stub code for resolving a method at first call.
+extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
+static inline const void* GetPortableResolutionStub() {
+ return reinterpret_cast<const void*>(art_portable_resolution_trampoline);
+}
+
+// Return the address of quick stub code for resolving a method at first call.
+extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
+static inline const void* GetQuickResolutionStub() {
+ return reinterpret_cast<const void*>(art_quick_resolution_trampoline);
+}
+
+// Entry point for quick code that performs deoptimization.
+extern "C" void art_quick_deoptimize();
+static inline const void* GetQuickDeoptimizationEntryPoint() {
+ return reinterpret_cast<const void*>(art_quick_deoptimize);
+}
+
+// Return address of instrumentation entry point used by non-interpreter based tracing.
+extern "C" void art_quick_instrumentation_entry(void*);
+static inline const void* GetQuickInstrumentationEntryPoint() {
+ return reinterpret_cast<const void*>(art_quick_instrumentation_entry);
+}
+
+// The return_pc of instrumentation exit stub.
+extern "C" void art_quick_instrumentation_exit();
+static inline const void* GetQuickInstrumentationExitPc() {
+ return reinterpret_cast<const void*>(art_quick_instrumentation_exit);
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_ENTRYPOINTS_RUNTIME_ASM_ENTRYPOINTS_H_
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index 3a17ecaa57..1714134d25 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -175,7 +175,7 @@ TEST_F(ExceptionTest, StackTraceElement) {
fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_));
fake_stack.push_back(0);
fake_stack.push_back(0);
- fake_stack.push_back(method_f_->ToNativePc(dex_pc)); // return pc
+ fake_stack.push_back(method_f_->ToNativeQuickPc(dex_pc)); // return pc
// Create/push fake 16byte stack frame for method f
fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_));
@@ -194,7 +194,7 @@ TEST_F(ExceptionTest, StackTraceElement) {
// Set up thread to appear as if we called out of method_g_ at pc dex 3
thread->SetTopOfStack(
reinterpret_cast<StackReference<mirror::ArtMethod>*>(&fake_stack[0]),
- method_g_->ToNativePc(dex_pc)); // return pc
+ method_g_->ToNativeQuickPc(dex_pc)); // return pc
} else {
// Create/push fake 20-byte shadow frame for method g
fake_stack.push_back(0);
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index c09dca8c4d..ba85c55c96 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -32,7 +32,6 @@
#include "gc/collector_type.h"
#include "gc/space/large_object_space.h"
#include "globals.h"
-#include "gtest/gtest.h"
#include "instruction_set.h"
#include "jni.h"
#include "object_callbacks.h"
diff --git a/runtime/gc/reference_queue.h b/runtime/gc/reference_queue.h
index dbf4abc238..4ef8478752 100644
--- a/runtime/gc/reference_queue.h
+++ b/runtime/gc/reference_queue.h
@@ -24,7 +24,6 @@
#include "atomic.h"
#include "base/timing_logger.h"
#include "globals.h"
-#include "gtest/gtest.h"
#include "jni.h"
#include "object_callbacks.h"
#include "offsets.h"
@@ -45,44 +44,56 @@ class Heap;
class ReferenceQueue {
public:
explicit ReferenceQueue(Mutex* lock);
+
// Enqueue a reference if is not already enqueued. Thread safe to call from multiple threads
// since it uses a lock to avoid a race between checking for the references presence and adding
// it.
void AtomicEnqueueIfNotEnqueued(Thread* self, mirror::Reference* ref)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+
// Enqueue a reference, unlike EnqueuePendingReference, enqueue reference checks that the
// reference IsEnqueueable. Not thread safe, used when mutators are paused to minimize lock
// overhead.
void EnqueueReference(mirror::Reference* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
void EnqueuePendingReference(mirror::Reference* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
mirror::Reference* DequeuePendingReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Enqueues finalizer references with white referents. White referents are blackened, moved to the
// zombie field, and the referent field is cleared.
void EnqueueFinalizerReferences(ReferenceQueue* cleared_references,
IsHeapReferenceMarkedCallback* is_marked_callback,
MarkObjectCallback* mark_object_callback, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Walks the reference list marking any references subject to the reference clearing policy.
// References with a black referent are removed from the list. References with white referents
// biased toward saving are blackened and also removed from the list.
void ForwardSoftReferences(IsHeapReferenceMarkedCallback* preserve_callback, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Unlink the reference list clearing references objects with white referents. Cleared references
// registered to a reference queue are scheduled for appending by the heap worker thread.
void ClearWhiteReferences(ReferenceQueue* cleared_references,
IsHeapReferenceMarkedCallback* is_marked_callback, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
void Dump(std::ostream& os) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
bool IsEmpty() const {
return list_ == nullptr;
}
+
void Clear() {
list_ = nullptr;
}
+
mirror::Reference* GetList() {
return list_;
}
+
// Visits list_, currently only used for the mark compact GC.
void UpdateRoots(IsMarkedCallback* callback, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -90,10 +101,13 @@ class ReferenceQueue {
private:
// Lock, used for parallel GC reference enqueuing. It allows for multiple threads simultaneously
// calling AtomicEnqueueIfNotEnqueued.
- Mutex* lock_;
+ Mutex* const lock_;
+
// The actual reference list. Only a root for the mark compact GC since it will be null for other
// GC types.
mirror::Reference* list_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReferenceQueue);
};
} // namespace gc
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 452af90750..39d82cc8a3 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -118,7 +118,7 @@ static bool GenerateImage(const std::string& image_filename, InstructionSet imag
std::string* error_msg) {
const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
std::vector<std::string> boot_class_path;
- Split(boot_class_path_string, ':', boot_class_path);
+ Split(boot_class_path_string, ':', &boot_class_path);
if (boot_class_path.empty()) {
*error_msg = "Failed to generate image because no boot class path specified";
return false;
diff --git a/runtime/instruction_set.cc b/runtime/instruction_set.cc
index 644e0556b1..b5f85719a0 100644
--- a/runtime/instruction_set.cc
+++ b/runtime/instruction_set.cc
@@ -16,6 +16,12 @@
#include "instruction_set.h"
+#include <fstream>
+
+#include "base/casts.h"
+#include "base/stringprintf.h"
+#include "utils.h"
+
namespace art {
const char* GetInstructionSetString(const InstructionSet isa) {
@@ -35,7 +41,7 @@ const char* GetInstructionSetString(const InstructionSet isa) {
return "none";
default:
LOG(FATAL) << "Unknown ISA " << isa;
- return nullptr;
+ UNREACHABLE();
}
}
@@ -117,15 +123,385 @@ size_t GetStackOverflowReservedBytes(InstructionSet isa) {
}
}
-std::string InstructionSetFeatures::GetFeatureString() const {
+const InstructionSetFeatures* InstructionSetFeatures::FromVariant(InstructionSet isa,
+ const std::string& variant,
+ std::string* error_msg) {
+ const InstructionSetFeatures* result;
+ switch (isa) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromVariant(variant, error_msg);
+ break;
+ default:
+ result = UnknownInstructionSetFeatures::Unknown(isa);
+ break;
+ }
+ CHECK_EQ(result == nullptr, error_msg->size() != 0);
+ return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromFeatureString(InstructionSet isa,
+ const std::string& feature_list,
+ std::string* error_msg) {
+ const InstructionSetFeatures* result;
+ switch (isa) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromFeatureString(feature_list, error_msg);
+ break;
+ default:
+ result = UnknownInstructionSetFeatures::Unknown(isa);
+ break;
+ }
+ // TODO: warn if feature_list doesn't agree with result's GetFeatureList().
+ CHECK_EQ(result == nullptr, error_msg->size() != 0);
+ return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromBitmap(InstructionSet isa,
+ uint32_t bitmap) {
+ const InstructionSetFeatures* result;
+ switch (isa) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromBitmap(bitmap);
+ break;
+ default:
+ result = UnknownInstructionSetFeatures::Unknown(isa);
+ break;
+ }
+ CHECK_EQ(bitmap, result->AsBitmap());
+ return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromCppDefines() {
+ const InstructionSetFeatures* result;
+ switch (kRuntimeISA) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromCppDefines();
+ break;
+ default:
+ result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
+ break;
+ }
+ return result;
+}
+
+
+const InstructionSetFeatures* InstructionSetFeatures::FromCpuInfo() {
+ const InstructionSetFeatures* result;
+ switch (kRuntimeISA) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromCpuInfo();
+ break;
+ default:
+ result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
+ break;
+ }
+ return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromHwcap() {
+ const InstructionSetFeatures* result;
+ switch (kRuntimeISA) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromHwcap();
+ break;
+ default:
+ result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
+ break;
+ }
+ return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromAssembly() {
+ const InstructionSetFeatures* result;
+ switch (kRuntimeISA) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromAssembly();
+ break;
+ default:
+ result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
+ break;
+ }
+ return result;
+}
+
+const ArmInstructionSetFeatures* InstructionSetFeatures::AsArmInstructionSetFeatures() const {
+ DCHECK_EQ(kArm, GetInstructionSet());
+ return down_cast<const ArmInstructionSetFeatures*>(this);
+}
+
+std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs) {
+ os << "ISA: " << rhs.GetInstructionSet() << " Feature string: " << rhs.GetFeatureString();
+ return os;
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromFeatureString(
+ const std::string& feature_list, std::string* error_msg) {
+ std::vector<std::string> features;
+ Split(feature_list, ',', &features);
+ bool has_lpae = false;
+ bool has_div = false;
+ for (auto i = features.begin(); i != features.end(); i++) {
+ std::string feature = Trim(*i);
+ if (feature == "default" || feature == "none") {
+ // Nothing to do.
+ } else if (feature == "div") {
+ has_div = true;
+ } else if (feature == "nodiv") {
+ has_div = false;
+ } else if (feature == "lpae") {
+ has_lpae = true;
+ } else if (feature == "nolpae") {
+ has_lpae = false;
+ } else {
+ *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+ return nullptr;
+ }
+ }
+ return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromVariant(
+ const std::string& variant, std::string* error_msg) {
+ // Look for variants that have divide support.
+ bool has_div = false;
+ {
+ static const char* arm_variants_with_div[] = {
+ "cortex-a7", "cortex-a12", "cortex-a15", "cortex-a17", "cortex-a53", "cortex-a57",
+ "cortex-m3", "cortex-m4", "cortex-r4", "cortex-r5",
+ "cyclone", "denver", "krait", "swift"
+ };
+ for (const char* div_variant : arm_variants_with_div) {
+ if (variant == div_variant) {
+ has_div = true;
+ break;
+ }
+ }
+ }
+ // Look for variants that have LPAE support.
+ bool has_lpae = false;
+ {
+ static const char* arm_variants_with_lpae[] = {
+ "cortex-a7", "cortex-a15", "krait", "denver"
+ };
+ for (const char* lpae_variant : arm_variants_with_lpae) {
+ if (variant == lpae_variant) {
+ has_lpae = true;
+ break;
+ }
+ }
+ }
+ if (has_div == false && has_lpae == false) {
+ // Avoid unsupported variants.
+ static const char* unsupported_arm_variants[] = {
+ // ARM processors that aren't ARMv7 compatible aren't supported.
+ "arm2", "arm250", "arm3", "arm6", "arm60", "arm600", "arm610", "arm620",
+ "cortex-m0", "cortex-m0plus", "cortex-m1",
+ "fa526", "fa626", "fa606te", "fa626te", "fmp626", "fa726te",
+ "iwmmxt", "iwmmxt2",
+ "strongarm", "strongarm110", "strongarm1100", "strongarm1110",
+ "xscale"
+ };
+ for (const char* us_variant : unsupported_arm_variants) {
+ if (variant == us_variant) {
+ *error_msg = StringPrintf("Attempt to use unsupported ARM variant: %s", us_variant);
+ return nullptr;
+ }
+ }
+ // Warn if the variant is unknown.
+ // TODO: some of the variants below may have feature support, but that support is currently
+ // unknown so we'll choose conservative (sub-optimal) defaults without warning.
+ // TODO: some of the architectures may not support all features required by ART and should be
+ // moved to unsupported_arm_variants[] above.
+ static const char* arm_variants_without_known_features[] = {
+ "arm7", "arm7m", "arm7d", "arm7dm", "arm7di", "arm7dmi", "arm70", "arm700", "arm700i",
+ "arm710", "arm710c", "arm7100", "arm720", "arm7500", "arm7500fe", "arm7tdmi", "arm7tdmi-s",
+ "arm710t", "arm720t", "arm740t",
+ "arm8", "arm810",
+ "arm9", "arm9e", "arm920", "arm920t", "arm922t", "arm946e-s", "arm966e-s", "arm968e-s",
+ "arm926ej-s", "arm940t", "arm9tdmi",
+ "arm10tdmi", "arm1020t", "arm1026ej-s", "arm10e", "arm1020e", "arm1022e",
+ "arm1136j-s", "arm1136jf-s",
+ "arm1156t2-s", "arm1156t2f-s", "arm1176jz-s", "arm1176jzf-s",
+ "cortex-a5", "cortex-a8", "cortex-a9", "cortex-a9-mp", "cortex-r4f",
+ "marvell-pj4", "mpcore", "mpcorenovfp"
+ };
+ bool found = false;
+ for (const char* ff_variant : arm_variants_without_known_features) {
+ if (variant == ff_variant) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ LOG(WARNING) << "Unknown instruction set features for ARM CPU variant (" << variant
+ << ") using conservative defaults";
+ }
+ }
+ return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+ bool has_lpae = (bitmap & kLpaeBitfield) != 0;
+ bool has_div = (bitmap & kDivBitfield) != 0;
+ return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCppDefines() {
+#if defined(__ARM_ARCH_EXT_IDIV__)
+ bool has_div = true;
+#else
+ bool has_div = false;
+#endif
+#if defined(__ARM_FEATURE_LPAE)
+ bool has_lpae = true;
+#else
+ bool has_lpae = false;
+#endif
+ return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCpuInfo() {
+ // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that
+ // the kernel puts the appropriate feature flags in here. Sometimes it doesn't.
+ bool has_lpae = false;
+ bool has_div = false;
+
+ std::ifstream in("/proc/cpuinfo");
+ if (!in.fail()) {
+ while (!in.eof()) {
+ std::string line;
+ std::getline(in, line);
+ if (!in.eof()) {
+ LOG(INFO) << "cpuinfo line: " << line;
+ if (line.find("Features") != std::string::npos) {
+ LOG(INFO) << "found features";
+ if (line.find("idivt") != std::string::npos) {
+ // We always expect both ARM and Thumb divide instructions to be available or not
+ // available.
+ CHECK_NE(line.find("idiva"), std::string::npos);
+ has_div = true;
+ }
+ if (line.find("lpae") != std::string::npos) {
+ has_lpae = true;
+ }
+ }
+ }
+ }
+ in.close();
+ } else {
+ LOG(INFO) << "Failed to open /proc/cpuinfo";
+ }
+ return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+#if defined(HAVE_ANDROID_OS) && defined(__arm__)
+#include <sys/auxv.h>
+#include <asm/hwcap.h>
+#endif
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromHwcap() {
+ bool has_lpae = false;
+ bool has_div = false;
+
+#if defined(HAVE_ANDROID_OS) && defined(__arm__)
+ uint64_t hwcaps = getauxval(AT_HWCAP);
+ LOG(INFO) << "hwcaps=" << hwcaps;
+ if ((hwcaps & HWCAP_IDIVT) != 0) {
+ // We always expect both ARM and Thumb divide instructions to be available or not
+ // available.
+ CHECK_NE(hwcaps & HWCAP_IDIVA, 0U);
+ has_div = true;
+ }
+ if ((hwcaps & HWCAP_LPAE) != 0) {
+ has_lpae = true;
+ }
+#endif
+
+ return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+// A signal handler called by a fault for an illegal instruction. We record the fact in r0
+// and then increment the PC in the signal context to return to the next instruction. We know the
+// instruction is an sdiv (4 bytes long).
+static void bad_divide_inst_handle(int signo, siginfo *si, void *data) {
+ UNUSED(signo);
+ UNUSED(si);
+#if defined(__arm__)
+ struct ucontext *uc = (struct ucontext *)data;
+ struct sigcontext *sc = &uc->uc_mcontext;
+ sc->arm_r0 = 0; // Set R0 to #0 to signal error.
+ sc->arm_pc += 4; // Skip offending instruction.
+#else
+ UNUSED(data);
+#endif
+}
+
+#if defined(__arm__)
+extern "C" bool artCheckForARMSDIVInstruction();
+#endif
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromAssembly() {
+ // See if have a sdiv instruction. Register a signal handler and try to execute an sdiv
+ // instruction. If we get a SIGILL then it's not supported.
+ struct sigaction sa, osa;
+ sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
+ sa.sa_sigaction = bad_divide_inst_handle;
+ sigaction(SIGILL, &sa, &osa);
+
+ bool has_div = false;
+#if defined(__arm__)
+ if (artCheckForARMSDIVInstruction()) {
+ has_div = true;
+ }
+#endif
+
+ // Restore the signal handler.
+ sigaction(SIGILL, &osa, nullptr);
+
+ // Use compile time features to "detect" LPAE support.
+ // TODO: write an assembly LPAE support test.
+#if defined(__ARM_FEATURE_LPAE)
+ bool has_lpae = true;
+#else
+ bool has_lpae = false;
+#endif
+ return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+
+bool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+ if (kArm != other->GetInstructionSet()) {
+ return false;
+ }
+ const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures();
+ return has_lpae_ == other_as_arm->has_lpae_ && has_div_ == other_as_arm->has_div_;
+}
+
+uint32_t ArmInstructionSetFeatures::AsBitmap() const {
+ return (has_lpae_ ? kLpaeBitfield : 0) | (has_div_ ? kDivBitfield : 0);
+}
+
+std::string ArmInstructionSetFeatures::GetFeatureString() const {
std::string result;
- if ((mask_ & kHwDiv) != 0) {
- result += "div";
+ if (has_div_) {
+ result += ",div";
+ }
+ if (has_lpae_) {
+ result += ",lpae";
}
if (result.size() == 0) {
- result = "none";
+ return "none";
+ } else {
+ // Strip leading comma.
+ return result.substr(1, result.size());
}
- return result;
}
} // namespace art
diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h
index de6d0f47d9..529fa0c05f 100644
--- a/runtime/instruction_set.h
+++ b/runtime/instruction_set.h
@@ -22,6 +22,7 @@
#include "base/logging.h" // Logging is required for FATAL in the helper functions.
#include "base/macros.h"
+#include "base/value_object.h"
#include "globals.h" // For KB.
namespace art {
@@ -177,53 +178,163 @@ static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
size_t GetStackOverflowReservedBytes(InstructionSet isa);
-enum InstructionFeatures {
- kHwDiv = 0x1, // Supports hardware divide.
- kHwLpae = 0x2, // Supports Large Physical Address Extension.
+class ArmInstructionSetFeatures;
+
+// Abstraction used to describe features of a different instruction sets.
+class InstructionSetFeatures {
+ public:
+ // Process a CPU variant string for the given ISA and create an InstructionSetFeatures.
+ static const InstructionSetFeatures* FromVariant(InstructionSet isa,
+ const std::string& variant,
+ std::string* error_msg);
+
+ // Parse a string of the form "div,lpae" and create an InstructionSetFeatures.
+ static const InstructionSetFeatures* FromFeatureString(InstructionSet isa,
+ const std::string& feature_list,
+ std::string* error_msg);
+
+ // Parse a bitmap for the given isa and create an InstructionSetFeatures.
+ static const InstructionSetFeatures* FromBitmap(InstructionSet isa, uint32_t bitmap);
+
+ // Turn C pre-processor #defines into the equivalent instruction set features for kRuntimeISA.
+ static const InstructionSetFeatures* FromCppDefines();
+
+ // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+ static const InstructionSetFeatures* FromCpuInfo();
+
+ // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+ // InstructionSetFeatures.
+ static const InstructionSetFeatures* FromHwcap();
+
+ // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+ // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+ static const InstructionSetFeatures* FromAssembly();
+
+ // Are these features the same as the other given features?
+ virtual bool Equals(const InstructionSetFeatures* other) const = 0;
+
+ // Return the ISA these features relate to.
+ virtual InstructionSet GetInstructionSet() const = 0;
+
+ // Return a bitmap that represents the features. ISA specific.
+ virtual uint32_t AsBitmap() const = 0;
+
+ // Return a string of the form "div,lpae" or "none".
+ virtual std::string GetFeatureString() const = 0;
+
+ // Down cast this ArmInstructionFeatures.
+ const ArmInstructionSetFeatures* AsArmInstructionSetFeatures() const;
+
+ virtual ~InstructionSetFeatures() {}
+
+ protected:
+ InstructionSetFeatures() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InstructionSetFeatures);
};
+std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs);
-// This is a bitmask of supported features per architecture.
-class PACKED(4) InstructionSetFeatures {
+// Instruction set features relevant to the ARM architecture.
+class ArmInstructionSetFeatures FINAL : public InstructionSetFeatures {
public:
- InstructionSetFeatures() : mask_(0) {}
- explicit InstructionSetFeatures(uint32_t mask) : mask_(mask) {}
+ // Process a CPU variant string like "krait" or "cortex-a15" and create InstructionSetFeatures.
+ static const ArmInstructionSetFeatures* FromVariant(const std::string& variant,
+ std::string* error_msg);
- static InstructionSetFeatures GuessInstructionSetFeatures();
+ // Parse a string of the form "div,lpae" and create an InstructionSetFeatures.
+ static const ArmInstructionSetFeatures* FromFeatureString(const std::string& feature_list,
+ std::string* error_msg);
- bool HasDivideInstruction() const {
- return (mask_ & kHwDiv) != 0;
+ // Parse a bitmap and create an InstructionSetFeatures.
+ static const ArmInstructionSetFeatures* FromBitmap(uint32_t bitmap);
+
+ // Turn C pre-processor #defines into the equivalent instruction set features.
+ static const ArmInstructionSetFeatures* FromCppDefines();
+
+ // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+ static const ArmInstructionSetFeatures* FromCpuInfo();
+
+ // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+ // InstructionSetFeatures.
+ static const ArmInstructionSetFeatures* FromHwcap();
+
+ // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+ // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+ static const ArmInstructionSetFeatures* FromAssembly();
+
+ bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+ InstructionSet GetInstructionSet() const OVERRIDE {
+ return kArm;
}
- void SetHasDivideInstruction(bool v) {
- mask_ = (mask_ & ~kHwDiv) | (v ? kHwDiv : 0);
+ uint32_t AsBitmap() const OVERRIDE;
+
+ // Return a string of the form "div,lpae" or "none".
+ std::string GetFeatureString() const OVERRIDE;
+
+ // Is the divide instruction feature enabled?
+ bool HasDivideInstruction() const {
+ return has_div_;
}
+ // Is the Large Physical Address Extension (LPAE) instruction feature enabled? When true code can
+ // be used that assumes double register loads and stores (ldrd, strd) don't tear.
bool HasLpae() const {
- return (mask_ & kHwLpae) != 0;
+ return has_lpae_;
}
- void SetHasLpae(bool v) {
- mask_ = (mask_ & ~kHwLpae) | (v ? kHwLpae : 0);
+ virtual ~ArmInstructionSetFeatures() {}
+
+ private:
+ ArmInstructionSetFeatures(bool has_lpae, bool has_div)
+ : has_lpae_(has_lpae), has_div_(has_div) {
}
- std::string GetFeatureString() const;
+ // Bitmap positions for encoding features as a bitmap.
+ enum {
+ kDivBitfield = 1,
+ kLpaeBitfield = 2,
+ };
- // Other features in here.
+ const bool has_lpae_;
+ const bool has_div_;
- bool operator==(const InstructionSetFeatures &peer) const {
- return mask_ == peer.mask_;
+ DISALLOW_COPY_AND_ASSIGN(ArmInstructionSetFeatures);
+};
+
+// A class used for instruction set features on ISAs that don't yet have any features defined.
+class UnknownInstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+ static const UnknownInstructionSetFeatures* Unknown(InstructionSet isa) {
+ return new UnknownInstructionSetFeatures(isa);
}
- bool operator!=(const InstructionSetFeatures &peer) const {
- return mask_ != peer.mask_;
+ bool Equals(const InstructionSetFeatures* other) const OVERRIDE {
+ return isa_ == other->GetInstructionSet();
}
- bool operator<=(const InstructionSetFeatures &peer) const {
- return (mask_ & peer.mask_) == mask_;
+ InstructionSet GetInstructionSet() const OVERRIDE {
+ return isa_;
}
+ uint32_t AsBitmap() const OVERRIDE {
+ return 0;
+ }
+
+ std::string GetFeatureString() const OVERRIDE {
+ return "none";
+ }
+
+ virtual ~UnknownInstructionSetFeatures() {}
+
private:
- uint32_t mask_;
+ explicit UnknownInstructionSetFeatures(InstructionSet isa) : isa_(isa) {}
+
+ const InstructionSet isa_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnknownInstructionSetFeatures);
};
// The following definitions create return types for two word-sized entities that will be passed
diff --git a/runtime/instruction_set_test.cc b/runtime/instruction_set_test.cc
index 80191b1387..948063d452 100644
--- a/runtime/instruction_set_test.cc
+++ b/runtime/instruction_set_test.cc
@@ -16,6 +16,7 @@
#include "instruction_set.h"
+#include "base/stringprintf.h"
#include "common_runtime_test.h"
namespace art {
@@ -50,4 +51,214 @@ TEST_F(InstructionSetTest, PointerSize) {
EXPECT_EQ(sizeof(void*), GetInstructionSetPointerSize(kRuntimeISA));
}
+TEST_F(InstructionSetTest, X86Features) {
+ // Build features for a 32-bit x86 atom processor.
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> x86_features(
+ InstructionSetFeatures::FromVariant(kX86, "atom", &error_msg));
+ ASSERT_TRUE(x86_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(x86_features->GetInstructionSet(), kX86);
+ EXPECT_TRUE(x86_features->Equals(x86_features.get()));
+ EXPECT_STREQ("none", x86_features->GetFeatureString().c_str());
+ EXPECT_EQ(x86_features->AsBitmap(), 0U);
+
+ // Build features for a 32-bit x86 default processor.
+ std::unique_ptr<const InstructionSetFeatures> x86_default_features(
+ InstructionSetFeatures::FromFeatureString(kX86, "default", &error_msg));
+ ASSERT_TRUE(x86_default_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(x86_default_features->GetInstructionSet(), kX86);
+ EXPECT_TRUE(x86_default_features->Equals(x86_default_features.get()));
+ EXPECT_STREQ("none", x86_default_features->GetFeatureString().c_str());
+ EXPECT_EQ(x86_default_features->AsBitmap(), 0U);
+
+ // Build features for a 64-bit x86-64 atom processor.
+ std::unique_ptr<const InstructionSetFeatures> x86_64_features(
+ InstructionSetFeatures::FromVariant(kX86_64, "atom", &error_msg));
+ ASSERT_TRUE(x86_64_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(x86_64_features->GetInstructionSet(), kX86_64);
+ EXPECT_TRUE(x86_64_features->Equals(x86_64_features.get()));
+ EXPECT_STREQ("none", x86_64_features->GetFeatureString().c_str());
+ EXPECT_EQ(x86_64_features->AsBitmap(), 0U);
+
+ EXPECT_FALSE(x86_64_features->Equals(x86_features.get()));
+ EXPECT_FALSE(x86_64_features->Equals(x86_default_features.get()));
+ EXPECT_TRUE(x86_features->Equals(x86_default_features.get()));
+}
+
+TEST_F(InstructionSetTest, ArmFeaturesFromVariant) {
+ // Build features for a 32-bit ARM krait processor.
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> krait_features(
+ InstructionSetFeatures::FromVariant(kArm, "krait", &error_msg));
+ ASSERT_TRUE(krait_features.get() != nullptr) << error_msg;
+
+ ASSERT_EQ(krait_features->GetInstructionSet(), kArm);
+ EXPECT_TRUE(krait_features->Equals(krait_features.get()));
+ EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasLpae());
+ EXPECT_STREQ("div,lpae", krait_features->GetFeatureString().c_str());
+ EXPECT_EQ(krait_features->AsBitmap(), 3U);
+
+ // Build features for a 32-bit ARM denver processor.
+ std::unique_ptr<const InstructionSetFeatures> denver_features(
+ InstructionSetFeatures::FromVariant(kArm, "denver", &error_msg));
+ ASSERT_TRUE(denver_features.get() != nullptr) << error_msg;
+
+ EXPECT_TRUE(denver_features->Equals(denver_features.get()));
+ EXPECT_TRUE(denver_features->Equals(krait_features.get()));
+ EXPECT_TRUE(krait_features->Equals(denver_features.get()));
+ EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasLpae());
+ EXPECT_STREQ("div,lpae", denver_features->GetFeatureString().c_str());
+ EXPECT_EQ(denver_features->AsBitmap(), 3U);
+
+ // Build features for a 32-bit ARMv7 processor.
+ std::unique_ptr<const InstructionSetFeatures> arm7_features(
+ InstructionSetFeatures::FromVariant(kArm, "arm7", &error_msg));
+ ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
+
+ EXPECT_TRUE(arm7_features->Equals(arm7_features.get()));
+ EXPECT_FALSE(arm7_features->Equals(krait_features.get()));
+ EXPECT_FALSE(krait_features->Equals(arm7_features.get()));
+ EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasLpae());
+ EXPECT_STREQ("none", arm7_features->GetFeatureString().c_str());
+ EXPECT_EQ(arm7_features->AsBitmap(), 0U);
+
+ // ARM6 is not a supported architecture variant.
+ std::unique_ptr<const InstructionSetFeatures> arm6_features(
+ InstructionSetFeatures::FromVariant(kArm, "arm6", &error_msg));
+ EXPECT_TRUE(arm6_features.get() == nullptr);
+ EXPECT_NE(error_msg.size(), 0U);
+}
+
+TEST_F(InstructionSetTest, ArmFeaturesFromString) {
+ // Build features for a 32-bit ARM with LPAE and div processor.
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> krait_features(
+ InstructionSetFeatures::FromFeatureString(kArm, "lpae,div", &error_msg));
+ ASSERT_TRUE(krait_features.get() != nullptr) << error_msg;
+
+ ASSERT_EQ(krait_features->GetInstructionSet(), kArm);
+ EXPECT_TRUE(krait_features->Equals(krait_features.get()));
+ EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasLpae());
+ EXPECT_STREQ("div,lpae", krait_features->GetFeatureString().c_str());
+ EXPECT_EQ(krait_features->AsBitmap(), 3U);
+
+ // Build features for a 32-bit ARM processor with LPAE and div flipped.
+ std::unique_ptr<const InstructionSetFeatures> denver_features(
+ InstructionSetFeatures::FromFeatureString(kArm, "div,lpae", &error_msg));
+ ASSERT_TRUE(denver_features.get() != nullptr) << error_msg;
+
+ EXPECT_TRUE(denver_features->Equals(denver_features.get()));
+ EXPECT_TRUE(denver_features->Equals(krait_features.get()));
+ EXPECT_TRUE(krait_features->Equals(denver_features.get()));
+ EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasLpae());
+ EXPECT_STREQ("div,lpae", denver_features->GetFeatureString().c_str());
+ EXPECT_EQ(denver_features->AsBitmap(), 3U);
+
+ // Build features for a 32-bit default ARM processor.
+ std::unique_ptr<const InstructionSetFeatures> arm7_features(
+ InstructionSetFeatures::FromFeatureString(kArm, "default", &error_msg));
+ ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
+
+ EXPECT_TRUE(arm7_features->Equals(arm7_features.get()));
+ EXPECT_FALSE(arm7_features->Equals(krait_features.get()));
+ EXPECT_FALSE(krait_features->Equals(arm7_features.get()));
+ EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasLpae());
+ EXPECT_STREQ("none", arm7_features->GetFeatureString().c_str());
+ EXPECT_EQ(arm7_features->AsBitmap(), 0U);
+}
+
+#ifdef HAVE_ANDROID_OS
+#include "cutils/properties.h"
+
+TEST_F(InstructionSetTest, FeaturesFromSystemPropertyVariant) {
+ // Take the default set of instruction features from the build.
+ std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+ InstructionSetFeatures::FromCppDefines());
+
+ // Read the features property.
+ std::string key = StringPrintf("dalvik.vm.isa.%s.variant", GetInstructionSetString(kRuntimeISA));
+ char dex2oat_isa_variant[PROPERTY_VALUE_MAX];
+ if (property_get(key.c_str(), dex2oat_isa_variant, nullptr) > 0) {
+ // Use features from property to build InstructionSetFeatures and check against build's
+ // features.
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> property_features(
+ InstructionSetFeatures::FromVariant(kRuntimeISA, dex2oat_isa_variant, &error_msg));
+ ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
+
+ EXPECT_TRUE(property_features->Equals(instruction_set_features.get()))
+ << "System property features: " << *property_features.get()
+ << "\nFeatures from build: " << *instruction_set_features.get();
+ }
+}
+
+TEST_F(InstructionSetTest, FeaturesFromSystemPropertyString) {
+ // Take the default set of instruction features from the build.
+ std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+ InstructionSetFeatures::FromCppDefines());
+
+ // Read the features property.
+ std::string key = StringPrintf("dalvik.vm.isa.%s.features", GetInstructionSetString(kRuntimeISA));
+ char dex2oat_isa_features[PROPERTY_VALUE_MAX];
+ if (property_get(key.c_str(), dex2oat_isa_features, nullptr) > 0) {
+ // Use features from property to build InstructionSetFeatures and check against build's
+ // features.
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> property_features(
+ InstructionSetFeatures::FromFeatureString(kRuntimeISA, dex2oat_isa_features, &error_msg));
+ ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
+
+ EXPECT_TRUE(property_features->Equals(instruction_set_features.get()))
+ << "System property features: " << *property_features.get()
+ << "\nFeatures from build: " << *instruction_set_features.get();
+ }
+}
+#endif
+
+TEST_F(InstructionSetTest, FeaturesFromCpuInfo) {
+ // Take the default set of instruction features from the build.
+ std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+ InstructionSetFeatures::FromCppDefines());
+
+ // Check we get the same instruction set features using /proc/cpuinfo.
+ std::unique_ptr<const InstructionSetFeatures> cpuinfo_features(
+ InstructionSetFeatures::FromCpuInfo());
+ EXPECT_TRUE(cpuinfo_features->Equals(instruction_set_features.get()))
+ << "CPU Info features: " << *cpuinfo_features.get()
+ << "\nFeatures from build: " << *instruction_set_features.get();
+}
+
+TEST_F(InstructionSetTest, FeaturesFromHwcap) {
+ // Take the default set of instruction features from the build.
+ std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+ InstructionSetFeatures::FromCppDefines());
+
+ // Check we get the same instruction set features using AT_HWCAP.
+ std::unique_ptr<const InstructionSetFeatures> hwcap_features(
+ InstructionSetFeatures::FromHwcap());
+ EXPECT_TRUE(hwcap_features->Equals(instruction_set_features.get()))
+ << "Hwcap features: " << *hwcap_features.get()
+ << "\nFeatures from build: " << *instruction_set_features.get();
+}
+
+
+TEST_F(InstructionSetTest, FeaturesFromAssembly) {
+ // Take the default set of instruction features from the build.
+ std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+ InstructionSetFeatures::FromCppDefines());
+
+ // Check we get the same instruction set features using assembly tests.
+ std::unique_ptr<const InstructionSetFeatures> assembly_features(
+ InstructionSetFeatures::FromAssembly());
+ EXPECT_TRUE(assembly_features->Equals(instruction_set_features.get()))
+ << "Assembly features: " << *assembly_features.get()
+ << "\nFeatures from build: " << *instruction_set_features.get();
+}
+
} // namespace art
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 15be6b752b..6c6058f81e 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -25,6 +25,7 @@
#include "debugger.h"
#include "dex_file-inl.h"
#include "entrypoints/quick/quick_alloc_entrypoints.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc_root-inl.h"
#include "interpreter/interpreter.h"
#include "mirror/art_method-inl.h"
@@ -95,21 +96,20 @@ static void UpdateEntrypoints(mirror::ArtMethod* method, const void* quick_code,
}
if (!method->IsResolutionMethod()) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- if (quick_code == GetQuickToInterpreterBridge() ||
- quick_code == class_linker->GetQuickToInterpreterBridgeTrampoline() ||
- (quick_code == class_linker->GetQuickResolutionTrampoline() &&
- Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly()
- && !method->IsNative() && !method->IsProxyMethod())) {
+ if (class_linker->IsQuickToInterpreterBridge(quick_code) ||
+ (class_linker->IsQuickResolutionStub(quick_code) &&
+ Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly() &&
+ !method->IsNative() && !method->IsProxyMethod())) {
if (kIsDebugBuild) {
if (quick_code == GetQuickToInterpreterBridge()) {
DCHECK(portable_code == GetPortableToInterpreterBridge());
- } else if (quick_code == class_linker->GetQuickResolutionTrampoline()) {
- DCHECK(portable_code == class_linker->GetPortableResolutionTrampoline());
+ } else if (class_linker->IsQuickResolutionStub(quick_code)) {
+ DCHECK(class_linker->IsPortableResolutionStub(portable_code));
}
}
DCHECK(!method->IsNative()) << PrettyMethod(method);
DCHECK(!method->IsProxyMethod()) << PrettyMethod(method);
- method->SetEntryPointFromInterpreter(art::interpreter::artInterpreterToInterpreterBridge);
+ method->SetEntryPointFromInterpreter(art::artInterpreterToInterpreterBridge);
} else {
method->SetEntryPointFromInterpreter(art::artInterpreterToCompiledCodeBridge);
}
@@ -140,8 +140,8 @@ void Instrumentation::InstallStubsForMethod(mirror::ArtMethod* method) {
new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
new_quick_code = class_linker->GetQuickOatCodeFor(method);
} else {
- new_portable_code = class_linker->GetPortableResolutionTrampoline();
- new_quick_code = class_linker->GetQuickResolutionTrampoline();
+ new_portable_code = GetPortableResolutionStub();
+ new_quick_code = GetQuickResolutionStub();
}
} else { // !uninstall
if ((interpreter_stubs_installed_ || forced_interpret_only_ || IsDeoptimized(method)) &&
@@ -159,11 +159,11 @@ void Instrumentation::InstallStubsForMethod(mirror::ArtMethod* method) {
} else {
new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
new_quick_code = class_linker->GetQuickOatCodeFor(method);
- DCHECK(new_quick_code != class_linker->GetQuickToInterpreterBridgeTrampoline());
+ DCHECK(!class_linker->IsQuickToInterpreterBridge(new_quick_code));
}
} else {
- new_portable_code = class_linker->GetPortableResolutionTrampoline();
- new_quick_code = class_linker->GetQuickResolutionTrampoline();
+ new_portable_code = GetPortableResolutionStub();
+ new_quick_code = GetQuickResolutionStub();
}
}
}
@@ -287,7 +287,7 @@ static void InstrumentationInstallStack(Thread* thread, void* arg)
Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
std::unique_ptr<Context> context(Context::Create());
- uintptr_t instrumentation_exit_pc = GetQuickInstrumentationExitPc();
+ uintptr_t instrumentation_exit_pc = reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc());
InstallStackVisitor visitor(thread, context.get(), instrumentation_exit_pc);
visitor.WalkStack(true);
CHECK_EQ(visitor.dex_pcs_.size(), thread->GetInstrumentationStack()->size());
@@ -388,7 +388,8 @@ static void InstrumentationRestoreStack(Thread* thread, void* arg)
std::deque<instrumentation::InstrumentationStackFrame>* stack = thread->GetInstrumentationStack();
if (stack->size() > 0) {
Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
- uintptr_t instrumentation_exit_pc = GetQuickInstrumentationExitPc();
+ uintptr_t instrumentation_exit_pc =
+ reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc());
RestoreStackVisitor visitor(thread, instrumentation_exit_pc, instrumentation);
visitor.WalkStack(true);
CHECK_EQ(visitor.frames_removed_, stack->size());
@@ -669,11 +670,10 @@ void Instrumentation::UpdateMethodsCode(mirror::ArtMethod* method, const void* q
new_have_portable_code = false;
} else {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- if (quick_code == class_linker->GetQuickResolutionTrampoline() ||
- quick_code == class_linker->GetQuickToInterpreterBridgeTrampoline() ||
- quick_code == GetQuickToInterpreterBridge()) {
- DCHECK((portable_code == class_linker->GetPortableResolutionTrampoline()) ||
- (portable_code == GetPortableToInterpreterBridge()));
+ if (class_linker->IsQuickResolutionStub(quick_code) ||
+ class_linker->IsQuickToInterpreterBridge(quick_code)) {
+ DCHECK(class_linker->IsPortableResolutionStub(portable_code) ||
+ class_linker->IsPortableToInterpreterBridge(portable_code));
new_portable_code = portable_code;
new_quick_code = quick_code;
new_have_portable_code = have_portable_code;
@@ -793,9 +793,7 @@ void Instrumentation::Undeoptimize(mirror::ArtMethod* method) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
if (method->IsStatic() && !method->IsConstructor() &&
!method->GetDeclaringClass()->IsInitialized()) {
- // TODO: we're updating to entrypoints in the image here, we can avoid the trampoline.
- UpdateEntrypoints(method, class_linker->GetQuickResolutionTrampoline(),
- class_linker->GetPortableResolutionTrampoline(), false);
+ UpdateEntrypoints(method, GetQuickResolutionStub(), GetPortableResolutionStub(), false);
} else {
bool have_portable_code = false;
const void* quick_code = class_linker->GetQuickOatCodeFor(method);
@@ -877,9 +875,10 @@ const void* Instrumentation::GetQuickCodeFor(mirror::ArtMethod* method) const {
const void* code = method->GetEntryPointFromQuickCompiledCode();
DCHECK(code != nullptr);
ClassLinker* class_linker = runtime->GetClassLinker();
- if (LIKELY(code != class_linker->GetQuickResolutionTrampoline()) &&
- LIKELY(code != class_linker->GetQuickToInterpreterBridgeTrampoline()) &&
- LIKELY(code != GetQuickToInterpreterBridge())) {
+ if (LIKELY(!class_linker->IsQuickResolutionStub(code) &&
+ !class_linker->IsQuickToInterpreterBridge(code)) &&
+ !class_linker->IsQuickResolutionStub(code) &&
+ !class_linker->IsQuickToInterpreterBridge(code)) {
return code;
}
}
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 8fb1712eb9..dfb03cdeb8 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -507,8 +507,9 @@ void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* shadow_frame, JVa
ret_val->SetJ(value.GetJ());
}
-JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame) {
+JValue EnterInterpreterFromEntryPoint(Thread* self, MethodHelper* mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame) {
DCHECK_EQ(self, Thread::Current());
bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) {
@@ -516,10 +517,10 @@ JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh, const DexFile::C
return JValue();
}
- return Execute(self, mh, code_item, shadow_frame, JValue());
+ return Execute(self, *mh, code_item, *shadow_frame, JValue());
}
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
+extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper* mh,
const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result) {
bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
@@ -529,10 +530,10 @@ extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh
}
self->PushShadowFrame(shadow_frame);
- DCHECK_EQ(shadow_frame->GetMethod(), mh.Get());
+ DCHECK_EQ(shadow_frame->GetMethod(), mh->Get());
// Ensure static methods are initialized.
- if (mh.Get()->IsStatic()) {
- mirror::Class* declaring_class = mh.Get()->GetDeclaringClass();
+ if (mh->Get()->IsStatic()) {
+ mirror::Class* declaring_class = mh->Get()->GetDeclaringClass();
if (UNLIKELY(!declaring_class->IsInitialized())) {
StackHandleScope<1> hs(self);
HandleWrapper<Class> h_declaring_class(hs.NewHandleWrapper(&declaring_class));
@@ -546,15 +547,15 @@ extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh
}
}
- if (LIKELY(!mh.Get()->IsNative())) {
- result->SetJ(Execute(self, mh, code_item, *shadow_frame, JValue()).GetJ());
+ if (LIKELY(!mh->Get()->IsNative())) {
+ result->SetJ(Execute(self, *mh, code_item, *shadow_frame, JValue()).GetJ());
} else {
// We don't expect to be asked to interpret native code (which is entered via a JNI compiler
// generated stub) except during testing and image writing.
CHECK(!Runtime::Current()->IsStarted());
- Object* receiver = mh.Get()->IsStatic() ? nullptr : shadow_frame->GetVRegReference(0);
- uint32_t* args = shadow_frame->GetVRegArgs(mh.Get()->IsStatic() ? 0 : 1);
- UnstartedRuntimeJni(self, mh.Get(), receiver, args, result);
+ Object* receiver = mh->Get()->IsStatic() ? nullptr : shadow_frame->GetVRegReference(0);
+ uint32_t* args = shadow_frame->GetVRegArgs(mh->Get()->IsStatic() ? 0 : 1);
+ UnstartedRuntimeJni(self, mh->Get(), receiver, args, result);
}
self->PopShadowFrame();
diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h
index 0750eb5c49..d327a71a4f 100644
--- a/runtime/interpreter/interpreter.h
+++ b/runtime/interpreter/interpreter.h
@@ -42,19 +42,20 @@ extern void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* shadow_fra
JValue* ret_val)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-extern JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame)
+extern JValue EnterInterpreterFromEntryPoint(Thread* self, MethodHelper* mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
+
+} // namespace interpreter
+
+extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper* mh,
const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-} // namespace interpreter
-
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
+extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper* mh,
const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 52583ae2b8..3ccdd03136 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -506,7 +506,7 @@ void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh) {
exit(0); // Unreachable, keep GCC happy.
}
-static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
+static void UnstartedRuntimeInvoke(Thread* self, MethodHelper* mh,
const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -666,9 +666,9 @@ bool DoCall(ArtMethod* method, Thread* self, ShadowFrame& shadow_frame,
mh.Get()->GetEntryPointFromInterpreter() == artInterpreterToCompiledCodeBridge) {
LOG(FATAL) << "Attempt to call compiled code when -Xint: " << PrettyMethod(mh.Get());
}
- (mh.Get()->GetEntryPointFromInterpreter())(self, mh, code_item, new_shadow_frame, result);
+ (mh.Get()->GetEntryPointFromInterpreter())(self, &mh, code_item, new_shadow_frame, result);
} else {
- UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, first_dest_reg);
+ UnstartedRuntimeInvoke(self, &mh, code_item, new_shadow_frame, result, first_dest_reg);
}
return !self->IsExceptionPending();
}
@@ -809,7 +809,7 @@ static void UnstartedRuntimeFindClass(Thread* self, Handle<mirror::String> class
result->SetL(found);
}
-static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
+static void UnstartedRuntimeInvoke(Thread* self, MethodHelper* mh,
const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
JValue* result, size_t arg_offset) {
// In a runtime that's not started we intercept certain methods to avoid complicated dependency
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index 16a774fdf0..7fdc18e8a0 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -329,14 +329,14 @@ static JdwpError VM_ClassPaths(JdwpState*, Request*, ExpandBuf* pReply)
expandBufAddUtf8String(pReply, "/");
std::vector<std::string> class_path;
- Split(Runtime::Current()->GetClassPathString(), ':', class_path);
+ Split(Runtime::Current()->GetClassPathString(), ':', &class_path);
expandBufAdd4BE(pReply, class_path.size());
for (size_t i = 0; i < class_path.size(); ++i) {
expandBufAddUtf8String(pReply, class_path[i]);
}
std::vector<std::string> boot_class_path;
- Split(Runtime::Current()->GetBootClassPathString(), ':', boot_class_path);
+ Split(Runtime::Current()->GetBootClassPathString(), ':', &boot_class_path);
expandBufAdd4BE(pReply, boot_class_path.size());
for (size_t i = 0; i < boot_class_path.size(); ++i) {
expandBufAddUtf8String(pReply, boot_class_path[i]);
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index dea30145eb..e098e11e51 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -2144,7 +2144,7 @@ class JNI {
VLOG(jni) << "[Registering JNI native method " << PrettyMethod(m) << "]";
- m->RegisterNative(soa.Self(), fnPtr, is_fast);
+ m->RegisterNative(fnPtr, is_fast);
}
return JNI_OK;
}
@@ -2160,14 +2160,14 @@ class JNI {
for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
mirror::ArtMethod* m = c->GetDirectMethod(i);
if (m->IsNative()) {
- m->UnregisterNative(soa.Self());
+ m->UnregisterNative();
unregistered_count++;
}
}
for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
mirror::ArtMethod* m = c->GetVirtualMethod(i);
if (m->IsNative()) {
- m->UnregisterNative(soa.Self());
+ m->UnregisterNative();
unregistered_count++;
}
}
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 1a65d99023..664a412292 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -24,7 +24,6 @@
#include "class_linker.h"
#include "dex_cache.h"
#include "dex_file.h"
-#include "entrypoints/entrypoint_utils.h"
#include "method_helper.h"
#include "object-inl.h"
#include "object_array.h"
@@ -176,32 +175,6 @@ inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) {
}
}
-inline void ArtMethod::AssertPcIsWithinQuickCode(uintptr_t pc) {
- if (!kIsDebugBuild) {
- return;
- }
- if (IsNative() || IsRuntimeMethod() || IsProxyMethod()) {
- return;
- }
- if (pc == GetQuickInstrumentationExitPc()) {
- return;
- }
- const void* code = GetEntryPointFromQuickCompiledCode();
- if (code == GetQuickToInterpreterBridge() || code == GetQuickInstrumentationEntryPoint()) {
- return;
- }
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- if (code == class_linker->GetQuickResolutionTrampoline() ||
- code == class_linker->GetQuickToInterpreterBridgeTrampoline()) {
- return;
- }
- DCHECK(IsWithinQuickCode(pc))
- << PrettyMethod(this)
- << " pc=" << std::hex << pc
- << " code=" << code
- << " size=" << GetCodeSize();
-}
-
inline uint32_t ArtMethod::GetQuickOatCodeOffset() {
DCHECK(!Runtime::Current()->IsStarted());
return PointerToLowMemUInt32(GetEntryPointFromQuickCompiledCode());
@@ -222,27 +195,6 @@ inline void ArtMethod::SetPortableOatCodeOffset(uint32_t code_offset) {
SetEntryPointFromPortableCompiledCode(reinterpret_cast<void*>(code_offset));
}
-inline const void* ArtMethod::GetQuickOatEntryPoint() {
- if (IsPortableCompiled() || IsAbstract() || IsRuntimeMethod() || IsProxyMethod()) {
- return nullptr;
- }
- Runtime* runtime = Runtime::Current();
- const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(this);
- // On failure, instead of nullptr we get the quick-generic-jni-trampoline for native method
- // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
- // for non-native methods.
- DCHECK(entry_point != runtime->GetClassLinker()->GetQuickToInterpreterBridgeTrampoline());
- if (UNLIKELY(entry_point == GetQuickToInterpreterBridge()) ||
- UNLIKELY(entry_point == runtime->GetClassLinker()->GetQuickGenericJniTrampoline())) {
- return nullptr;
- }
- return entry_point;
-}
-
-inline const void* ArtMethod::GetQuickOatCodePointer() {
- return EntryPointToCodePointer(GetQuickOatEntryPoint());
-}
-
inline const uint8_t* ArtMethod::GetMappingTable() {
const void* code_pointer = GetQuickOatCodePointer();
if (code_pointer == nullptr) {
@@ -341,69 +293,17 @@ inline bool ArtMethod::IsImtConflictMethod() {
return result;
}
-inline uintptr_t ArtMethod::NativePcOffset(const uintptr_t pc) {
+inline uintptr_t ArtMethod::NativeQuickPcOffset(const uintptr_t pc) {
const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this);
return pc - reinterpret_cast<uintptr_t>(code);
}
-inline uintptr_t ArtMethod::NativePcOffset(const uintptr_t pc, const void* quick_entry_point) {
- DCHECK(quick_entry_point != GetQuickToInterpreterBridge());
- DCHECK(quick_entry_point == Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this));
- return pc - reinterpret_cast<uintptr_t>(quick_entry_point);
-}
-
template<VerifyObjectFlags kVerifyFlags>
inline void ArtMethod::SetNativeMethod(const void* native_method) {
SetFieldPtr<false, true, kVerifyFlags>(
OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_), native_method);
}
-inline QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo() {
- if (UNLIKELY(IsPortableCompiled())) {
- // Portable compiled dex bytecode or jni stub.
- return QuickMethodFrameInfo(kStackAlignment, 0u, 0u);
- }
- Runtime* runtime = Runtime::Current();
- // For Proxy method we exclude direct method (there is only one direct method - constructor).
- // Direct method is cloned from original java.lang.reflect.Proxy class together with code
- // and as a result it is executed as usual quick compiled method without any stubs.
- // So the frame info should be returned as it is a quick method not a stub.
- if (UNLIKELY(IsAbstract()) || UNLIKELY(IsProxyMethod() && !IsDirect())) {
- return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
- }
- if (UNLIKELY(IsRuntimeMethod())) {
- return runtime->GetRuntimeMethodFrameInfo(this);
- }
-
- const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(this);
- // On failure, instead of nullptr we get the quick-generic-jni-trampoline for native method
- // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
- // for non-native methods. And we really shouldn't see a failure for non-native methods here.
- DCHECK(entry_point != runtime->GetClassLinker()->GetQuickToInterpreterBridgeTrampoline());
- CHECK(entry_point != GetQuickToInterpreterBridge());
-
- if (UNLIKELY(entry_point == runtime->GetClassLinker()->GetQuickGenericJniTrampoline())) {
- // Generic JNI frame.
- DCHECK(IsNative());
- StackHandleScope<1> hs(Thread::Current());
- uint32_t handle_refs =
- MethodHelper(hs.NewHandle(this)).GetNumberOfReferenceArgsWithoutReceiver() + 1;
- size_t scope_size = HandleScope::SizeOf(handle_refs);
- QuickMethodFrameInfo callee_info = runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
-
- // Callee saves + handle scope + method ref + alignment
- size_t frame_size = RoundUp(callee_info.FrameSizeInBytes() + scope_size
- - sizeof(void*) // callee-save frame stores a whole method pointer
- + sizeof(StackReference<mirror::ArtMethod>),
- kStackAlignment);
-
- return QuickMethodFrameInfo(frame_size, callee_info.CoreSpillMask(), callee_info.FpSpillMask());
- }
-
- const void* code_pointer = EntryPointToCodePointer(entry_point);
- return GetQuickFrameInfo(code_pointer);
-}
-
inline QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo(const void* code_pointer) {
DCHECK(code_pointer != nullptr);
DCHECK_EQ(code_pointer, GetQuickOatCodePointer());
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 787c76715a..5c72e5567d 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -23,6 +23,8 @@
#include "class-inl.h"
#include "dex_file-inl.h"
#include "dex_instruction.h"
+#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
#include "interpreter/interpreter.h"
#include "jni_internal.h"
@@ -203,7 +205,7 @@ uint32_t ArtMethod::ToDexPc(const uintptr_t pc, bool abort_on_failure) {
return DexFile::kDexNoIndex;
}
-uintptr_t ArtMethod::ToNativePc(const uint32_t dex_pc) {
+uintptr_t ArtMethod::ToNativeQuickPc(const uint32_t dex_pc) {
const void* entry_point = GetQuickOatEntryPoint();
MappingTable table(
entry_point != nullptr ? GetMappingTable(EntryPointToCodePointer(entry_point)) : nullptr);
@@ -281,6 +283,36 @@ uint32_t ArtMethod::FindCatchBlock(Handle<ArtMethod> h_this, Handle<Class> excep
return found_dex_pc;
}
+void ArtMethod::AssertPcIsWithinQuickCode(uintptr_t pc) {
+ if (IsNative() || IsRuntimeMethod() || IsProxyMethod()) {
+ return;
+ }
+ if (pc == reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc())) {
+ return;
+ }
+ const void* code = GetEntryPointFromQuickCompiledCode();
+ if (code == GetQuickInstrumentationEntryPoint()) {
+ return;
+ }
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ if (class_linker->IsQuickToInterpreterBridge(code) ||
+ class_linker->IsQuickResolutionStub(code)) {
+ return;
+ }
+ /*
+ * During a stack walk, a return PC may point past-the-end of the code
+ * in the case that the last instruction is a call that isn't expected to
+ * return. Thus, we check <= code + GetCodeSize().
+ *
+ * NOTE: For Thumb both pc and code are offset by 1 indicating the Thumb state.
+ */
+ CHECK(PcIsWithinQuickCode(pc))
+ << PrettyMethod(this)
+ << " pc=" << std::hex << pc
+ << " code=" << code
+ << " size=" << GetCodeSize();
+}
+
bool ArtMethod::IsEntrypointInterpreter() {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
const void* oat_quick_code = class_linker->GetOatMethodQuickCodeFor(this);
@@ -294,6 +326,31 @@ bool ArtMethod::IsEntrypointInterpreter() {
}
}
+const void* ArtMethod::GetQuickOatEntryPoint() {
+ if (IsPortableCompiled() || IsAbstract() || IsRuntimeMethod() || IsProxyMethod()) {
+ return nullptr;
+ }
+ Runtime* runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ const void* code = runtime->GetInstrumentation()->GetQuickCodeFor(this);
+ // On failure, instead of nullptr we get the quick-generic-jni-trampoline for native method
+ // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
+ // for non-native methods.
+ if (class_linker->IsQuickToInterpreterBridge(code) ||
+ class_linker->IsQuickGenericJniStub(code)) {
+ return nullptr;
+ }
+ return code;
+}
+
+#ifndef NDEBUG
+uintptr_t ArtMethod::NativeQuickPcOffset(const uintptr_t pc, const void* quick_entry_point) {
+ CHECK_NE(quick_entry_point, GetQuickToInterpreterBridge());
+ CHECK_EQ(quick_entry_point, Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this));
+ return pc - reinterpret_cast<uintptr_t>(quick_entry_point);
+}
+#endif
+
void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
const char* shorty) {
if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
@@ -379,8 +436,53 @@ void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue*
self->PopManagedStackFragment(fragment);
}
-void ArtMethod::RegisterNative(Thread* self, const void* native_method, bool is_fast) {
- DCHECK(Thread::Current() == self);
+QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo() {
+ if (UNLIKELY(IsPortableCompiled())) {
+ // Portable compiled dex bytecode or jni stub.
+ return QuickMethodFrameInfo(kStackAlignment, 0u, 0u);
+ }
+ Runtime* runtime = Runtime::Current();
+ // For Proxy method we exclude direct method (there is only one direct method - constructor).
+ // Direct method is cloned from original java.lang.reflect.Proxy class together with code
+ // and as a result it is executed as usual quick compiled method without any stubs.
+ // So the frame info should be returned as it is a quick method not a stub.
+ if (UNLIKELY(IsAbstract()) || UNLIKELY(IsProxyMethod() && !IsDirect())) {
+ return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+ }
+ if (UNLIKELY(IsRuntimeMethod())) {
+ return runtime->GetRuntimeMethodFrameInfo(this);
+ }
+
+ const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(this);
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ // On failure, instead of nullptr we get the quick-generic-jni-trampoline for native method
+ // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
+ // for non-native methods. And we really shouldn't see a failure for non-native methods here.
+ DCHECK(!class_linker->IsQuickToInterpreterBridge(entry_point));
+
+ if (class_linker->IsQuickGenericJniStub(entry_point)) {
+ // Generic JNI frame.
+ DCHECK(IsNative());
+ StackHandleScope<1> hs(Thread::Current());
+ uint32_t handle_refs =
+ MethodHelper(hs.NewHandle(this)).GetNumberOfReferenceArgsWithoutReceiver() + 1;
+ size_t scope_size = HandleScope::SizeOf(handle_refs);
+ QuickMethodFrameInfo callee_info = runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+
+ // Callee saves + handle scope + method ref + alignment
+ size_t frame_size = RoundUp(callee_info.FrameSizeInBytes() + scope_size
+ - sizeof(void*) // callee-save frame stores a whole method pointer
+ + sizeof(StackReference<mirror::ArtMethod>),
+ kStackAlignment);
+
+ return QuickMethodFrameInfo(frame_size, callee_info.CoreSpillMask(), callee_info.FpSpillMask());
+ }
+
+ const void* code_pointer = EntryPointToCodePointer(entry_point);
+ return GetQuickFrameInfo(code_pointer);
+}
+
+void ArtMethod::RegisterNative(const void* native_method, bool is_fast) {
CHECK(IsNative()) << PrettyMethod(this);
CHECK(!IsFastNative()) << PrettyMethod(this);
CHECK(native_method != NULL) << PrettyMethod(this);
@@ -390,10 +492,10 @@ void ArtMethod::RegisterNative(Thread* self, const void* native_method, bool is_
SetNativeMethod(native_method);
}
-void ArtMethod::UnregisterNative(Thread* self) {
+void ArtMethod::UnregisterNative() {
CHECK(IsNative() && !IsFastNative()) << PrettyMethod(this);
// restore stub to lookup native pointer via dlsym
- RegisterNative(self, GetJniDlsymLookupStub(), false);
+ RegisterNative(GetJniDlsymLookupStub(), false);
}
} // namespace mirror
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 939d856eb7..1dbfe5de8b 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -39,7 +39,7 @@ class ShadowFrame;
namespace mirror {
-typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper& mh,
+typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper* mh,
const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result);
// C++ mirror of java.lang.reflect.ArtMethod.
@@ -302,7 +302,10 @@ class MANAGED ArtMethod FINAL : public Object {
uint32_t GetCodeSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool IsWithinQuickCode(uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Check whether the given PC is within the quick compiled code associated with this method's
+ // quick entrypoint. This code isn't robust for instrumentation, etc. and is only used for
+ // debug purposes.
+ bool PcIsWithinQuickCode(uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
uintptr_t code = reinterpret_cast<uintptr_t>(GetEntryPointFromQuickCompiledCode());
if (code == 0) {
return pc == 0;
@@ -329,16 +332,19 @@ class MANAGED ArtMethod FINAL : public Object {
void SetQuickOatCodeOffset(uint32_t code_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void SetPortableOatCodeOffset(uint32_t code_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static const void* EntryPointToCodePointer(const void* entry_point) ALWAYS_INLINE {
+ ALWAYS_INLINE static const void* EntryPointToCodePointer(const void* entry_point) {
uintptr_t code = reinterpret_cast<uintptr_t>(entry_point);
code &= ~0x1; // TODO: Make this Thumb2 specific.
return reinterpret_cast<const void*>(code);
}
- // Actual entry point pointer to compiled oat code or nullptr.
+ // Actual entry point pointer to compiled oat code or nullptr if method has no compiled code.
const void* GetQuickOatEntryPoint() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Actual pointer to compiled oat code or nullptr.
- const void* GetQuickOatCodePointer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ const void* GetQuickOatCodePointer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return EntryPointToCodePointer(GetQuickOatEntryPoint());
+ }
// Callers should wrap the uint8_t* in a MappingTable instance for convenient access.
const uint8_t* GetMappingTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -378,24 +384,25 @@ class MANAGED ArtMethod FINAL : public Object {
QuickMethodFrameInfo GetQuickFrameInfo(const void* code_pointer)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- size_t GetReturnPcOffsetInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return GetReturnPcOffsetInBytes(GetFrameSizeInBytes());
+ FrameOffset GetReturnPcOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return GetReturnPcOffset(GetFrameSizeInBytes());
}
- size_t GetReturnPcOffsetInBytes(uint32_t frame_size_in_bytes)
+ FrameOffset GetReturnPcOffset(uint32_t frame_size_in_bytes)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK_EQ(frame_size_in_bytes, GetFrameSizeInBytes());
- return frame_size_in_bytes - sizeof(void*);
+ return FrameOffset(frame_size_in_bytes - sizeof(void*));
}
- size_t GetHandleScopeOffsetInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return sizeof(void*);
+ FrameOffset GetHandleScopeOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK_LT(sizeof(void*), GetFrameSizeInBytes());
+ return FrameOffset(sizeof(void*));
}
- void RegisterNative(Thread* self, const void* native_method, bool is_fast)
+ void RegisterNative(const void* native_method, bool is_fast)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void UnregisterNative(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void UnregisterNative() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static MemberOffset NativeMethodOffset() {
return OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_);
@@ -423,16 +430,23 @@ class MANAGED ArtMethod FINAL : public Object {
bool IsImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- uintptr_t NativePcOffset(const uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- uintptr_t NativePcOffset(const uintptr_t pc, const void* quick_entry_point)
+ uintptr_t NativeQuickPcOffset(const uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+#ifdef NDEBUG
+ uintptr_t NativeQuickPcOffset(const uintptr_t pc, const void* quick_entry_point)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return pc - reinterpret_cast<uintptr_t>(quick_entry_point);
+ }
+#else
+ uintptr_t NativeQuickPcOffset(const uintptr_t pc, const void* quick_entry_point)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+#endif
// Converts a native PC to a dex PC.
uint32_t ToDexPc(const uintptr_t pc, bool abort_on_failure = true)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Converts a dex PC to a native PC.
- uintptr_t ToNativePc(const uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ uintptr_t ToNativeQuickPc(const uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Find the catch block for the given exception type and dex_pc. When a catch block is found,
// indicates whether the found catch block is responsible for clearing the exception or whether
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 1320ab71a3..64408a6604 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -17,8 +17,6 @@
#ifndef ART_RUNTIME_MIRROR_STRING_H_
#define ART_RUNTIME_MIRROR_STRING_H_
-#include <gtest/gtest.h>
-
#include "gc_root.h"
#include "object.h"
#include "object_callbacks.h"
@@ -163,7 +161,8 @@ class MANAGED String FINAL : public Object {
static GcRoot<Class> java_lang_String_;
friend struct art::StringOffsets; // for verifying offset information
- FRIEND_TEST(ObjectTest, StringLength); // for SetOffset and SetCount
+ ART_FRIEND_TEST(ObjectTest, StringLength); // for SetOffset and SetCount
+
DISALLOW_IMPLICIT_CONSTRUCTORS(String);
};
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 6810d73cbb..a237bf6a7e 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -39,7 +39,7 @@ static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* vari
}
OatHeader* OatHeader::Create(InstructionSet instruction_set,
- const InstructionSetFeatures& instruction_set_features,
+ const InstructionSetFeatures* instruction_set_features,
const std::vector<const DexFile*>* dex_files,
uint32_t image_file_location_oat_checksum,
uint32_t image_file_location_oat_data_begin,
@@ -60,7 +60,7 @@ OatHeader* OatHeader::Create(InstructionSet instruction_set,
}
OatHeader::OatHeader(InstructionSet instruction_set,
- const InstructionSetFeatures& instruction_set_features,
+ const InstructionSetFeatures* instruction_set_features,
const std::vector<const DexFile*>* dex_files,
uint32_t image_file_location_oat_checksum,
uint32_t image_file_location_oat_data_begin,
@@ -76,8 +76,8 @@ OatHeader::OatHeader(InstructionSet instruction_set,
instruction_set_ = instruction_set;
UpdateChecksum(&instruction_set_, sizeof(instruction_set_));
- instruction_set_features_ = instruction_set_features;
- UpdateChecksum(&instruction_set_features_, sizeof(instruction_set_features_));
+ instruction_set_features_bitmap_ = instruction_set_features->AsBitmap();
+ UpdateChecksum(&instruction_set_features_bitmap_, sizeof(instruction_set_features_bitmap_));
dex_file_count_ = dex_files->size();
UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_));
@@ -149,9 +149,9 @@ InstructionSet OatHeader::GetInstructionSet() const {
return instruction_set_;
}
-const InstructionSetFeatures& OatHeader::GetInstructionSetFeatures() const {
+uint32_t OatHeader::GetInstructionSetFeaturesBitmap() const {
CHECK(IsValid());
- return instruction_set_features_;
+ return instruction_set_features_bitmap_;
}
uint32_t OatHeader::GetExecutableOffset() const {
diff --git a/runtime/oat.h b/runtime/oat.h
index 6a32e3e56e..92b98b1be5 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -37,7 +37,7 @@ class PACKED(4) OatHeader {
static constexpr const char* kDex2OatHostKey = "dex2oat-host";
static OatHeader* Create(InstructionSet instruction_set,
- const InstructionSetFeatures& instruction_set_features,
+ const InstructionSetFeatures* instruction_set_features,
const std::vector<const DexFile*>* dex_files,
uint32_t image_file_location_oat_checksum,
uint32_t image_file_location_oat_data_begin,
@@ -93,7 +93,7 @@ class PACKED(4) OatHeader {
void SetImagePatchDelta(int32_t off);
InstructionSet GetInstructionSet() const;
- const InstructionSetFeatures& GetInstructionSetFeatures() const;
+ uint32_t GetInstructionSetFeaturesBitmap() const;
uint32_t GetImageFileLocationOatChecksum() const;
uint32_t GetImageFileLocationOatDataBegin() const;
@@ -106,7 +106,7 @@ class PACKED(4) OatHeader {
private:
OatHeader(InstructionSet instruction_set,
- const InstructionSetFeatures& instruction_set_features,
+ const InstructionSetFeatures* instruction_set_features,
const std::vector<const DexFile*>* dex_files,
uint32_t image_file_location_oat_checksum,
uint32_t image_file_location_oat_data_begin,
@@ -119,7 +119,7 @@ class PACKED(4) OatHeader {
uint32_t adler32_checksum_;
InstructionSet instruction_set_;
- InstructionSetFeatures instruction_set_features_;
+ uint32_t instruction_set_features_bitmap_;
uint32_t dex_file_count_;
uint32_t executable_offset_;
uint32_t interpreter_to_interpreter_bridge_offset_;
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index d82002683a..dcca9d3164 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -205,7 +205,7 @@ static gc::CollectorType ParseCollectorType(const std::string& option) {
bool ParsedOptions::ParseXGcOption(const std::string& option) {
std::vector<std::string> gc_options;
- Split(option.substr(strlen("-Xgc:")), ',', gc_options);
+ Split(option.substr(strlen("-Xgc:")), ',', &gc_options);
for (const std::string& gc_option : gc_options) {
gc::CollectorType collector_type = ParseCollectorType(gc_option);
if (collector_type != gc::kCollectorTypeNone) {
@@ -501,7 +501,7 @@ bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognize
is_explicit_gc_disabled_ = true;
} else if (StartsWith(option, "-verbose:")) {
std::vector<std::string> verbose_options;
- Split(option.substr(strlen("-verbose:")), ',', verbose_options);
+ Split(option.substr(strlen("-verbose:")), ',', &verbose_options);
for (size_t i = 0; i < verbose_options.size(); ++i) {
if (verbose_options[i] == "class") {
gLogVerbosity.class_linker = true;
@@ -536,7 +536,7 @@ bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognize
}
} else if (StartsWith(option, "-verbose-methods:")) {
gLogVerbosity.compiler = false;
- Split(option.substr(strlen("-verbose-methods:")), ',', gVerboseMethods);
+ Split(option.substr(strlen("-verbose-methods:")), ',', &gVerboseMethods);
} else if (StartsWith(option, "-Xlockprofthreshold:")) {
if (!ParseUnsignedInteger(option, ':', &lock_profiling_threshold_)) {
return false;
diff --git a/runtime/profiler.cc b/runtime/profiler.cc
index cde4177d6d..1d06d352a9 100644
--- a/runtime/profiler.cc
+++ b/runtime/profiler.cc
@@ -16,9 +16,11 @@
#include "profiler.h"
-#include <fstream>
-#include <sys/uio.h>
#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <fstream>
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
@@ -742,7 +744,7 @@ void ProfileSampleResults::ReadPrevious(int fd, ProfileDataType type) {
return;
}
std::vector<std::string> summary_info;
- Split(line, '/', summary_info);
+ Split(line, '/', &summary_info);
if (summary_info.size() != 3) {
// Bad summary info. It should be count/nullcount/bootcount
return;
@@ -757,7 +759,7 @@ void ProfileSampleResults::ReadPrevious(int fd, ProfileDataType type) {
break;
}
std::vector<std::string> info;
- Split(line, '/', info);
+ Split(line, '/', &info);
if (info.size() != 3 && info.size() != 4) {
// Malformed.
break;
@@ -770,10 +772,10 @@ void ProfileSampleResults::ReadPrevious(int fd, ProfileDataType type) {
context_map = new PreviousContextMap();
std::string context_counts_str = info[3].substr(1, info[3].size() - 2);
std::vector<std::string> context_count_pairs;
- Split(context_counts_str, '#', context_count_pairs);
+ Split(context_counts_str, '#', &context_count_pairs);
for (uint32_t i = 0; i < context_count_pairs.size(); ++i) {
std::vector<std::string> context_count;
- Split(context_count_pairs[i], ':', context_count);
+ Split(context_count_pairs[i], ':', &context_count);
if (context_count.size() == 2) {
// Handles the situtation when the profile file doesn't contain context information.
uint32_t dexpc = strtoul(context_count[0].c_str(), nullptr, 10);
@@ -819,7 +821,7 @@ bool ProfileFile::LoadFile(const std::string& fileName) {
return false;
}
std::vector<std::string> summary_info;
- Split(line, '/', summary_info);
+ Split(line, '/', &summary_info);
if (summary_info.size() != 3) {
// Bad summary info. It should be total/null/boot.
return false;
@@ -837,7 +839,7 @@ bool ProfileFile::LoadFile(const std::string& fileName) {
break;
}
std::vector<std::string> info;
- Split(line, '/', info);
+ Split(line, '/', &info);
if (info.size() != 3 && info.size() != 4) {
// Malformed.
return false;
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 2c158ba963..8e578374c0 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -19,6 +19,7 @@
#include "arch/context.h"
#include "dex_instruction.h"
#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
#include "handle_scope-inl.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
@@ -96,7 +97,7 @@ class CatchBlockStackVisitor FINAL : public StackVisitor {
if (found_dex_pc != DexFile::kDexNoIndex) {
exception_handler_->SetHandlerMethod(method.Get());
exception_handler_->SetHandlerDexPc(found_dex_pc);
- exception_handler_->SetHandlerQuickFramePc(method->ToNativePc(found_dex_pc));
+ exception_handler_->SetHandlerQuickFramePc(method->ToNativeQuickPc(found_dex_pc));
exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
return false; // End stack walk.
}
@@ -308,7 +309,7 @@ class InstrumentationStackVisitor : public StackVisitor {
size_t current_frame_depth = GetFrameDepth();
if (current_frame_depth < frame_depth_) {
CHECK(GetMethod() != nullptr);
- if (UNLIKELY(GetQuickInstrumentationExitPc() == GetReturnPc())) {
+ if (UNLIKELY(reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) == GetReturnPc())) {
++instrumentation_frames_to_pop_;
}
return true;
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 23f8076e0f..b57e48fdd5 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -19,6 +19,7 @@
#include "class_linker.h"
#include "common_throws.h"
#include "dex_file-inl.h"
+#include "entrypoints/entrypoint_utils.h"
#include "jni_internal.h"
#include "method_helper-inl.h"
#include "mirror/art_field-inl.h"
@@ -528,7 +529,7 @@ JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnab
}
void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg_offset,
- MethodHelper& mh, JValue* result) {
+ MethodHelper* mh, JValue* result) {
// We want to make sure that the stack is not within a small distance from the
// protected region in case we are calling into a leaf function whose stack
// check has been elided.
@@ -537,10 +538,10 @@ void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg
return;
}
- ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+ ArgArray arg_array(mh->GetShorty(), mh->GetShortyLength());
arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset);
shadow_frame->GetMethod()->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result,
- mh.GetShorty());
+ mh->GetShorty());
}
jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaMethod,
diff --git a/runtime/reflection.h b/runtime/reflection.h
index 23d8e05452..f9a795194d 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -65,7 +65,7 @@ JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnab
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg_offset,
- MethodHelper& mh, JValue* result)
+ MethodHelper* mh, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject method, jobject receiver,
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 3bd825b640..e366084e4b 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -47,6 +47,7 @@
#include "class_linker.h"
#include "debugger.h"
#include "elf_file.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
#include "fault_handler.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/heap.h"
@@ -92,10 +93,9 @@
namespace art {
+// If a signal isn't handled properly, enable a handler that attempts to dump the Java stack.
static constexpr bool kEnableJavaStackTraceHandler = false;
-const char* Runtime::kDefaultInstructionSetFeatures =
- STRINGIFY(ART_DEFAULT_INSTRUCTION_SET_FEATURES);
-Runtime* Runtime::instance_ = NULL;
+Runtime* Runtime::instance_ = nullptr;
Runtime::Runtime()
: instruction_set_(kNone),
@@ -803,7 +803,7 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized)
}
} else if (!IsCompiler() || !image_dex2oat_enabled_) {
std::vector<std::string> dex_filenames;
- Split(boot_class_path_string_, ':', dex_filenames);
+ Split(boot_class_path_string_, ':', &dex_filenames);
std::vector<const DexFile*> boot_class_path;
OpenDexFiles(dex_filenames, options->image_, boot_class_path);
class_linker_->InitWithoutImage(boot_class_path);
@@ -1216,8 +1216,8 @@ mirror::ArtMethod* Runtime::CreateImtConflictMethod() {
method->SetEntryPointFromPortableCompiledCode(nullptr);
method->SetEntryPointFromQuickCompiledCode(nullptr);
} else {
- method->SetEntryPointFromPortableCompiledCode(class_linker->GetPortableImtConflictTrampoline());
- method->SetEntryPointFromQuickCompiledCode(class_linker->GetQuickImtConflictTrampoline());
+ method->SetEntryPointFromPortableCompiledCode(GetPortableImtConflictStub());
+ method->SetEntryPointFromQuickCompiledCode(GetQuickImtConflictStub());
}
return method.Get();
}
@@ -1236,8 +1236,8 @@ mirror::ArtMethod* Runtime::CreateResolutionMethod() {
method->SetEntryPointFromPortableCompiledCode(nullptr);
method->SetEntryPointFromQuickCompiledCode(nullptr);
} else {
- method->SetEntryPointFromPortableCompiledCode(class_linker->GetPortableResolutionTrampoline());
- method->SetEntryPointFromQuickCompiledCode(class_linker->GetQuickResolutionTrampoline());
+ method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionStub());
+ method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
}
return method.Get();
}
@@ -1454,9 +1454,10 @@ void Runtime::AddCurrentRuntimeFeaturesAsDex2OatArguments(std::vector<std::strin
instruction_set += GetInstructionSetString(kRuntimeISA);
argv->push_back(instruction_set);
- std::string features("--instruction-set-features=");
- features += GetDefaultInstructionSetFeatures();
- argv->push_back(features);
+ std::unique_ptr<const InstructionSetFeatures> features(InstructionSetFeatures::FromCppDefines());
+ std::string feature_string("--instruction-set-features=");
+ feature_string += features->GetFeatureString();
+ argv->push_back(feature_string);
}
void Runtime::UpdateProfilerState(int state) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 7bffc335ef..f3bea17d6d 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -483,10 +483,6 @@ class Runtime {
return target_sdk_version_;
}
- static const char* GetDefaultInstructionSetFeatures() {
- return kDefaultInstructionSetFeatures;
- }
-
private:
static void InitPlatformSignalHandlers();
@@ -506,8 +502,6 @@ class Runtime {
// A pointer to the active runtime or NULL.
static Runtime* instance_;
- static const char* kDefaultInstructionSetFeatures;
-
// NOTE: these must match the gc::ProcessState values as they come directly from the framework.
static constexpr int kProfileForground = 0;
static constexpr int kProfileBackgrouud = 1;
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 008941fcee..b4e85e2c23 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -18,6 +18,7 @@
#include "arch/context.h"
#include "base/hex_dump.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object.h"
@@ -119,7 +120,7 @@ mirror::Object* StackVisitor::GetThisObject() const {
} else if (m->IsNative()) {
if (cur_quick_frame_ != nullptr) {
HandleScope* hs = reinterpret_cast<HandleScope*>(
- reinterpret_cast<char*>(cur_quick_frame_) + m->GetHandleScopeOffsetInBytes());
+ reinterpret_cast<char*>(cur_quick_frame_) + m->GetHandleScopeOffset().SizeValue());
return hs->GetReference(0);
} else {
return cur_shadow_frame_->GetVRegReference(0);
@@ -143,7 +144,7 @@ mirror::Object* StackVisitor::GetThisObject() const {
size_t StackVisitor::GetNativePcOffset() const {
DCHECK(!IsShadowFrame());
- return GetMethod()->NativePcOffset(cur_quick_frame_pc_);
+ return GetMethod()->NativeQuickPcOffset(cur_quick_frame_pc_);
}
bool StackVisitor::GetVReg(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
@@ -394,14 +395,14 @@ bool StackVisitor::SetFPR(uint32_t reg, uintptr_t value) {
uintptr_t StackVisitor::GetReturnPc() const {
uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame());
DCHECK(sp != NULL);
- uint8_t* pc_addr = sp + GetMethod()->GetReturnPcOffsetInBytes();
+ uint8_t* pc_addr = sp + GetMethod()->GetReturnPcOffset().SizeValue();
return *reinterpret_cast<uintptr_t*>(pc_addr);
}
void StackVisitor::SetReturnPc(uintptr_t new_ret_pc) {
uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame());
CHECK(sp != NULL);
- uint8_t* pc_addr = sp + GetMethod()->GetReturnPcOffsetInBytes();
+ uint8_t* pc_addr = sp + GetMethod()->GetReturnPcOffset().SizeValue();
*reinterpret_cast<uintptr_t*>(pc_addr) = new_ret_pc;
}
@@ -509,7 +510,7 @@ void StackVisitor::SanityCheckFrame() const {
// const size_t kMaxExpectedFrameSize = (256 + 2 + 3 + 3) * sizeof(word);
const size_t kMaxExpectedFrameSize = 2 * KB;
CHECK_LE(frame_size, kMaxExpectedFrameSize);
- size_t return_pc_offset = method->GetReturnPcOffsetInBytes();
+ size_t return_pc_offset = method->GetReturnPcOffset().SizeValue();
CHECK_LT(return_pc_offset, frame_size);
}
}
@@ -543,13 +544,13 @@ void StackVisitor::WalkStack(bool include_transitions) {
}
size_t frame_size = method->GetFrameSizeInBytes();
// Compute PC for next stack frame from return PC.
- size_t return_pc_offset = method->GetReturnPcOffsetInBytes(frame_size);
+ size_t return_pc_offset = method->GetReturnPcOffset(frame_size).SizeValue();
uint8_t* return_pc_addr = reinterpret_cast<uint8_t*>(cur_quick_frame_) + return_pc_offset;
uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr);
if (UNLIKELY(exit_stubs_installed)) {
// While profiling, the return pc is restored from the side stack, except when walking
// the stack for an exception where the side stack will be unwound in VisitFrame.
- if (GetQuickInstrumentationExitPc() == return_pc) {
+ if (reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) == return_pc) {
const instrumentation::InstrumentationStackFrame& instrumentation_frame =
GetInstrumentationStackFrame(thread_, instrumentation_stack_depth);
instrumentation_stack_depth++;
diff --git a/runtime/thread.cc b/runtime/thread.cc
index fd37703949..efe27eefde 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2108,7 +2108,7 @@ class ReferenceMapVisitor : public StackVisitor {
if (m->IsOptimized()) {
Runtime* runtime = Runtime::Current();
const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(m);
- uintptr_t native_pc_offset = m->NativePcOffset(GetCurrentQuickFramePc(), entry_point);
+ uintptr_t native_pc_offset = m->NativeQuickPcOffset(GetCurrentQuickFramePc(), entry_point);
StackMap map = m->GetStackMap(native_pc_offset);
MemoryRegion mask = map.GetStackMask();
for (size_t i = 0; i < mask.size_in_bits(); ++i) {
@@ -2137,7 +2137,7 @@ class ReferenceMapVisitor : public StackVisitor {
if (num_regs > 0) {
Runtime* runtime = Runtime::Current();
const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(m);
- uintptr_t native_pc_offset = m->NativePcOffset(GetCurrentQuickFramePc(), entry_point);
+ uintptr_t native_pc_offset = m->NativeQuickPcOffset(GetCurrentQuickFramePc(), entry_point);
const uint8_t* reg_bitmap = map.FindBitMap(native_pc_offset);
DCHECK(reg_bitmap != nullptr);
const void* code_pointer = mirror::ArtMethod::EntryPointToCodePointer(entry_point);
diff --git a/runtime/thread.h b/runtime/thread.h
index b0be841730..32ed758ef7 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -144,6 +144,9 @@ class Thread {
// Reset internal state of child thread after fork.
void InitAfterFork();
+ // Get the currently executing thread, frequently referred to as 'self'. This call has reasonably
+ // high cost and so we favor passing self around when possible.
+ // TODO: mark as PURE so the compiler may coalesce and remove?
static Thread* Current();
// On a runnable thread, check for pending thread suspension request and handle if pending.
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 0688c1a784..9c94f6cb01 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -963,7 +963,7 @@ bool IsValidDescriptor(const char* s) {
return IsValidClassName<kDescriptor, '/'>(s);
}
-void Split(const std::string& s, char separator, std::vector<std::string>& result) {
+void Split(const std::string& s, char separator, std::vector<std::string>* result) {
const char* p = s.data();
const char* end = p + s.size();
while (p != end) {
@@ -974,12 +974,12 @@ void Split(const std::string& s, char separator, std::vector<std::string>& resul
while (++p != end && *p != separator) {
// Skip to the next occurrence of the separator.
}
- result.push_back(std::string(start, p - start));
+ result->push_back(std::string(start, p - start));
}
}
}
-std::string Trim(std::string s) {
+std::string Trim(const std::string& s) {
std::string result;
unsigned int start_index = 0;
unsigned int end_index = s.size() - 1;
@@ -1009,7 +1009,7 @@ std::string Trim(std::string s) {
}
template <typename StringT>
-std::string Join(std::vector<StringT>& strings, char separator) {
+std::string Join(const std::vector<StringT>& strings, char separator) {
if (strings.empty()) {
return "";
}
@@ -1023,9 +1023,8 @@ std::string Join(std::vector<StringT>& strings, char separator) {
}
// Explicit instantiations.
-template std::string Join<std::string>(std::vector<std::string>& strings, char separator);
-template std::string Join<const char*>(std::vector<const char*>& strings, char separator);
-template std::string Join<char*>(std::vector<char*>& strings, char separator);
+template std::string Join<std::string>(const std::vector<std::string>& strings, char separator);
+template std::string Join<const char*>(const std::vector<const char*>& strings, char separator);
bool StartsWith(const std::string& s, const char* prefix) {
return s.compare(0, strlen(prefix), prefix) == 0;
@@ -1087,7 +1086,7 @@ void GetTaskStats(pid_t tid, char* state, int* utime, int* stime, int* task_cpu)
stats = stats.substr(stats.find(')') + 2);
// Extract the three fields we care about.
std::vector<std::string> fields;
- Split(stats, ' ', fields);
+ Split(stats, ' ', &fields);
*state = fields[0][0];
*utime = strtoull(fields[11].c_str(), NULL, 10);
*stime = strtoull(fields[12].c_str(), NULL, 10);
@@ -1104,12 +1103,12 @@ std::string GetSchedulerGroupName(pid_t tid) {
return "";
}
std::vector<std::string> cgroup_lines;
- Split(cgroup_file, '\n', cgroup_lines);
+ Split(cgroup_file, '\n', &cgroup_lines);
for (size_t i = 0; i < cgroup_lines.size(); ++i) {
std::vector<std::string> cgroup_fields;
- Split(cgroup_lines[i], ':', cgroup_fields);
+ Split(cgroup_lines[i], ':', &cgroup_fields);
std::vector<std::string> cgroups;
- Split(cgroup_fields[1], ',', cgroups);
+ Split(cgroup_fields[1], ',', &cgroups);
for (size_t i = 0; i < cgroups.size(); ++i) {
if (cgroups[i] == "cpu") {
return cgroup_fields[2].substr(1); // Skip the leading slash.
@@ -1154,7 +1153,7 @@ void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix,
}
} else if (current_method != nullptr &&
Locks::mutator_lock_->IsSharedHeld(Thread::Current()) &&
- current_method->IsWithinQuickCode(it->pc)) {
+ current_method->PcIsWithinQuickCode(it->pc)) {
const void* start_of_code = current_method->GetEntryPointFromQuickCompiledCode();
os << JniLongName(current_method) << "+"
<< (it->pc - reinterpret_cast<uintptr_t>(start_of_code));
@@ -1189,7 +1188,7 @@ void DumpKernelStack(std::ostream& os, pid_t tid, const char* prefix, bool inclu
}
std::vector<std::string> kernel_stack_frames;
- Split(kernel_stack, '\n', kernel_stack_frames);
+ Split(kernel_stack, '\n', &kernel_stack_frames);
// We skip the last stack frame because it's always equivalent to "[<ffffffff>] 0xffffffff",
// which looking at the source appears to be the kernel's way of saying "that's all, folks!".
kernel_stack_frames.pop_back();
diff --git a/runtime/utils.h b/runtime/utils.h
index 53b49c8fd4..b7daa64d90 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -380,13 +380,13 @@ void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts
// Splits a string using the given separator character into a vector of
// strings. Empty strings will be omitted.
-void Split(const std::string& s, char separator, std::vector<std::string>& result);
+void Split(const std::string& s, char separator, std::vector<std::string>* result);
// Trims whitespace off both ends of the given string.
-std::string Trim(std::string s);
+std::string Trim(const std::string& s);
// Joins a vector of strings into a single string, using the given separator.
-template <typename StringT> std::string Join(std::vector<StringT>& strings, char separator);
+template <typename StringT> std::string Join(const std::vector<StringT>& strings, char separator);
// Returns the calling thread's tid. (The C libraries don't expose this.)
pid_t GetTid();
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index 1b2c3eec05..92323da554 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -241,62 +241,62 @@ TEST_F(UtilsTest, Split) {
expected.clear();
actual.clear();
- Split("", ':', actual);
+ Split("", ':', &actual);
EXPECT_EQ(expected, actual);
actual.clear();
- Split(":", ':', actual);
+ Split(":", ':', &actual);
EXPECT_EQ(expected, actual);
expected.clear();
expected.push_back("foo");
actual.clear();
- Split(":foo", ':', actual);
+ Split(":foo", ':', &actual);
EXPECT_EQ(expected, actual);
actual.clear();
- Split("foo:", ':', actual);
+ Split("foo:", ':', &actual);
EXPECT_EQ(expected, actual);
actual.clear();
- Split(":foo:", ':', actual);
+ Split(":foo:", ':', &actual);
EXPECT_EQ(expected, actual);
expected.push_back("bar");
actual.clear();
- Split("foo:bar", ':', actual);
+ Split("foo:bar", ':', &actual);
EXPECT_EQ(expected, actual);
actual.clear();
- Split(":foo:bar", ':', actual);
+ Split(":foo:bar", ':', &actual);
EXPECT_EQ(expected, actual);
actual.clear();
- Split("foo:bar:", ':', actual);
+ Split("foo:bar:", ':', &actual);
EXPECT_EQ(expected, actual);
actual.clear();
- Split(":foo:bar:", ':', actual);
+ Split(":foo:bar:", ':', &actual);
EXPECT_EQ(expected, actual);
expected.push_back("baz");
actual.clear();
- Split("foo:bar:baz", ':', actual);
+ Split("foo:bar:baz", ':', &actual);
EXPECT_EQ(expected, actual);
actual.clear();
- Split(":foo:bar:baz", ':', actual);
+ Split(":foo:bar:baz", ':', &actual);
EXPECT_EQ(expected, actual);
actual.clear();
- Split("foo:bar:baz:", ':', actual);
+ Split("foo:bar:baz:", ':', &actual);
EXPECT_EQ(expected, actual);
actual.clear();
- Split(":foo:bar:baz:", ':', actual);
+ Split(":foo:bar:baz:", ':', &actual);
EXPECT_EQ(expected, actual);
}