Merge "Add support for vex coding scheme in x86 assembler"
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 3f4fb15..a9acf90 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1205,6 +1205,7 @@
// mr : Runtime reserved.
// ip1 : VIXL core temp.
// ip0 : VIXL core temp.
+ // x18 : Platform register.
//
// Blocked fp registers:
// d31 : VIXL fp temp.
@@ -1213,6 +1214,7 @@
while (!reserved_core_registers.IsEmpty()) {
blocked_core_registers_[reserved_core_registers.PopLowestIndex().GetCode()] = true;
}
+ blocked_core_registers_[X18] = true;
CPURegList reserved_fp_registers = vixl_reserved_fp_registers;
while (!reserved_fp_registers.IsEmpty()) {
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index 6f43527..7bdaebe 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -287,9 +287,8 @@
/*
* Creates ImageSection objects that describe most of the sections of a
- * boot or AppImage. The following sections are not included:
+ * boot or AppImage. The following sections are not included:
* - ImageHeader::kSectionImageBitmap
- * - ImageHeader::kSectionStringReferenceOffsets
*
* In addition, the ImageHeader is not covered here.
*
diff --git a/runtime/Android.bp b/runtime/Android.bp
index bedeaf7..5d99187 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -96,7 +96,10 @@
"interpreter/interpreter_cache.cc",
"interpreter/interpreter_common.cc",
"interpreter/interpreter_intrinsics.cc",
- "interpreter/interpreter_switch_impl.cc",
+ "interpreter/interpreter_switch_impl0.cc",
+ "interpreter/interpreter_switch_impl1.cc",
+ "interpreter/interpreter_switch_impl2.cc",
+ "interpreter/interpreter_switch_impl3.cc",
"interpreter/lock_count_data.cc",
"interpreter/shadow_frame.cc",
"interpreter/unstarted_runtime.cc",
diff --git a/runtime/arch/arm64/callee_save_frame_arm64.h b/runtime/arch/arm64/callee_save_frame_arm64.h
index bc36bfa..a5aea2a 100644
--- a/runtime/arch/arm64/callee_save_frame_arm64.h
+++ b/runtime/arch/arm64/callee_save_frame_arm64.h
@@ -54,7 +54,7 @@
(1 << art::arm64::X9) | (1 << art::arm64::X10) | (1 << art::arm64::X11) |
(1 << art::arm64::X12) | (1 << art::arm64::X13) | (1 << art::arm64::X14) |
(1 << art::arm64::X15) | (1 << art::arm64::X16) | (1 << art::arm64::X17) |
- (1 << art::arm64::X18) | (1 << art::arm64::X19);
+ (1 << art::arm64::X19);
static constexpr uint32_t kArm64CalleeSaveFpAlwaysSpills = 0;
static constexpr uint32_t kArm64CalleeSaveFpRefSpills = 0;
diff --git a/runtime/arch/arm64/entrypoints_init_arm64.cc b/runtime/arch/arm64/entrypoints_init_arm64.cc
index e681d63..22f0c28 100644
--- a/runtime/arch/arm64/entrypoints_init_arm64.cc
+++ b/runtime/arch/arm64/entrypoints_init_arm64.cc
@@ -103,7 +103,6 @@
qpoints->pReadBarrierMarkReg14 = is_active ? art_quick_read_barrier_mark_reg14 : nullptr;
qpoints->pReadBarrierMarkReg15 = is_active ? art_quick_read_barrier_mark_reg15 : nullptr;
qpoints->pReadBarrierMarkReg17 = is_active ? art_quick_read_barrier_mark_reg17 : nullptr;
- qpoints->pReadBarrierMarkReg18 = is_active ? art_quick_read_barrier_mark_reg18 : nullptr;
qpoints->pReadBarrierMarkReg19 = is_active ? art_quick_read_barrier_mark_reg19 : nullptr;
qpoints->pReadBarrierMarkReg20 = is_active ? art_quick_read_barrier_mark_reg20 : nullptr;
qpoints->pReadBarrierMarkReg21 = is_active ? art_quick_read_barrier_mark_reg21 : nullptr;
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 96ceecf..9f3377e 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -289,36 +289,33 @@
#endif
// Save FP registers.
- // For better performance, store d0 and d31 separately, so that all STPs are 16-byte aligned.
- str d0, [sp, #8]
- stp d1, d2, [sp, #16]
- stp d3, d4, [sp, #32]
- stp d5, d6, [sp, #48]
- stp d7, d8, [sp, #64]
- stp d9, d10, [sp, #80]
- stp d11, d12, [sp, #96]
- stp d13, d14, [sp, #112]
- stp d15, d16, [sp, #128]
- stp d17, d18, [sp, #144]
- stp d19, d20, [sp, #160]
- stp d21, d22, [sp, #176]
- stp d23, d24, [sp, #192]
- stp d25, d26, [sp, #208]
- stp d27, d28, [sp, #224]
- stp d29, d30, [sp, #240]
- str d31, [sp, #256]
+ stp d0, d1, [sp, #16]
+ stp d2, d3, [sp, #32]
+ stp d4, d5, [sp, #48]
+ stp d6, d7, [sp, #64]
+ stp d8, d9, [sp, #80]
+ stp d10, d11, [sp, #96]
+ stp d12, d13, [sp, #112]
+ stp d14, d15, [sp, #128]
+ stp d16, d17, [sp, #144]
+ stp d18, d19, [sp, #160]
+ stp d20, d21, [sp, #176]
+ stp d22, d23, [sp, #192]
+ stp d24, d25, [sp, #208]
+ stp d26, d27, [sp, #224]
+ stp d28, d29, [sp, #240]
+ stp d30, d31, [sp, #256]
// Save core registers.
- SAVE_REG x0, 264
- SAVE_TWO_REGS x1, x2, 272
- SAVE_TWO_REGS x3, x4, 288
- SAVE_TWO_REGS x5, x6, 304
- SAVE_TWO_REGS x7, x8, 320
- SAVE_TWO_REGS x9, x10, 336
- SAVE_TWO_REGS x11, x12, 352
- SAVE_TWO_REGS x13, x14, 368
- SAVE_TWO_REGS x15, x16, 384
- SAVE_TWO_REGS x17, x18, 400
+ SAVE_TWO_REGS x0, x1, 272
+ SAVE_TWO_REGS x2, x3, 288
+ SAVE_TWO_REGS x4, x5, 304
+ SAVE_TWO_REGS x6, x7, 320
+ SAVE_TWO_REGS x8, x9, 336
+ SAVE_TWO_REGS x10, x11, 352
+ SAVE_TWO_REGS x12, x13, 368
+ SAVE_TWO_REGS x14, x15, 384
+ SAVE_TWO_REGS x16, x17, 400 // Do not save the platform register.
SAVE_TWO_REGS x19, x20, 416
SAVE_TWO_REGS x21, x22, 432
SAVE_TWO_REGS x23, x24, 448
@@ -351,35 +348,33 @@
.macro RESTORE_SAVE_EVERYTHING_FRAME_KEEP_X0
// Restore FP registers.
- // For better performance, load d0 and d31 separately, so that all LDPs are 16-byte aligned.
- ldr d0, [sp, #8]
- ldp d1, d2, [sp, #16]
- ldp d3, d4, [sp, #32]
- ldp d5, d6, [sp, #48]
- ldp d7, d8, [sp, #64]
- ldp d9, d10, [sp, #80]
- ldp d11, d12, [sp, #96]
- ldp d13, d14, [sp, #112]
- ldp d15, d16, [sp, #128]
- ldp d17, d18, [sp, #144]
- ldp d19, d20, [sp, #160]
- ldp d21, d22, [sp, #176]
- ldp d23, d24, [sp, #192]
- ldp d25, d26, [sp, #208]
- ldp d27, d28, [sp, #224]
- ldp d29, d30, [sp, #240]
- ldr d31, [sp, #256]
+ ldp d0, d1, [sp, #16]
+ ldp d2, d3, [sp, #32]
+ ldp d4, d5, [sp, #48]
+ ldp d6, d7, [sp, #64]
+ ldp d8, d9, [sp, #80]
+ ldp d10, d11, [sp, #96]
+ ldp d12, d13, [sp, #112]
+ ldp d14, d15, [sp, #128]
+ ldp d16, d17, [sp, #144]
+ ldp d18, d19, [sp, #160]
+ ldp d20, d21, [sp, #176]
+ ldp d22, d23, [sp, #192]
+ ldp d24, d25, [sp, #208]
+ ldp d26, d27, [sp, #224]
+ ldp d28, d29, [sp, #240]
+ ldp d30, d31, [sp, #256]
// Restore core registers, except x0.
- RESTORE_TWO_REGS x1, x2, 272
- RESTORE_TWO_REGS x3, x4, 288
- RESTORE_TWO_REGS x5, x6, 304
- RESTORE_TWO_REGS x7, x8, 320
- RESTORE_TWO_REGS x9, x10, 336
- RESTORE_TWO_REGS x11, x12, 352
- RESTORE_TWO_REGS x13, x14, 368
- RESTORE_TWO_REGS x15, x16, 384
- RESTORE_TWO_REGS x17, x18, 400
+ RESTORE_REG x1, 280
+ RESTORE_TWO_REGS x2, x3, 288
+ RESTORE_TWO_REGS x4, x5, 304
+ RESTORE_TWO_REGS x6, x7, 320
+ RESTORE_TWO_REGS x8, x9, 336
+ RESTORE_TWO_REGS x10, x11, 352
+ RESTORE_TWO_REGS x12, x13, 368
+ RESTORE_TWO_REGS x14, x15, 384
+ RESTORE_TWO_REGS x16, x17, 400 // Do not restore the platform register.
RESTORE_TWO_REGS x19, x20, 416
RESTORE_TWO_REGS x21, x22, 432
RESTORE_TWO_REGS x23, x24, 448
@@ -391,7 +386,7 @@
.endm
.macro RESTORE_SAVE_EVERYTHING_FRAME
- RESTORE_REG x0, 264
+ RESTORE_REG x0, 272
RESTORE_SAVE_EVERYTHING_FRAME_KEEP_X0
.endm
@@ -1116,7 +1111,8 @@
ldp x12, x13, [x0, #96]
ldp x14, x15, [x0, #112]
// Do not load IP0 (x16) and IP1 (x17), these shall be clobbered below.
- ldp x18, x19, [x0, #144] // X18 and xSELF.
+ // Don't load the platform register (x18) either.
+ ldr x19, [x0, #152] // xSELF.
ldp x20, x21, [x0, #160] // For Baker RB, wMR (w20) is reloaded below.
ldp x22, x23, [x0, #176]
ldp x24, x25, [x0, #192]
@@ -2293,8 +2289,8 @@
mov xLR, #0 // Clobber LR for later checks.
SETUP_SAVE_EVERYTHING_FRAME
- add x3, sp, #8 // Pass floating-point result pointer, in kSaveEverything frame.
- add x2, sp, #264 // Pass integer result pointer, in kSaveEverything frame.
+ add x3, sp, #16 // Pass floating-point result pointer, in kSaveEverything frame.
+ add x2, sp, #272 // Pass integer result pointer, in kSaveEverything frame.
mov x1, sp // Pass SP.
mov x0, xSELF // Pass Thread.
bl artInstrumentationMethodExitFromCode // (Thread*, SP, gpr_res*, fpr_res*)
@@ -2496,7 +2492,8 @@
.Lslow_rb_\name:
/*
* Allocate 44 stack slots * 8 = 352 bytes:
- * - 20 slots for core registers X0-15, X17-X19, LR
+ * - 19 slots for core registers X0-15, X17, X19, LR
+ * - 1 slot padding
* - 24 slots for floating-point registers D0-D7 and D16-D31
*/
// We must not clobber IP1 since code emitted for HLoadClass and HLoadString
@@ -2510,8 +2507,8 @@
SAVE_TWO_REGS x10, x11, 80
SAVE_TWO_REGS x12, x13, 96
SAVE_TWO_REGS x14, x15, 112
- SAVE_TWO_REGS x17, x18, 128 // Skip x16, i.e. IP0.
- SAVE_TWO_REGS x19, xLR, 144 // Save also return address.
+ SAVE_TWO_REGS x17, x19, 128 // Skip x16, i.e. IP0, and x18, the platform register.
+ SAVE_REG xLR, 144 // Save also return address.
// Save all potentially live caller-save floating-point registers.
stp d0, d1, [sp, #160]
stp d2, d3, [sp, #176]
@@ -2544,8 +2541,8 @@
POP_REGS_NE x10, x11, 80, \xreg
POP_REGS_NE x12, x13, 96, \xreg
POP_REGS_NE x14, x15, 112, \xreg
- POP_REGS_NE x17, x18, 128, \xreg
- POP_REGS_NE x19, xLR, 144, \xreg // Restore also return address.
+ POP_REGS_NE x17, x19, 128, \xreg
+ POP_REG_NE xLR, 144, \xreg // Restore also return address.
// Restore floating-point registers.
ldp d0, d1, [sp, #160]
ldp d2, d3, [sp, #176]
@@ -2588,7 +2585,7 @@
READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg15, w15, x15
// READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg16, w16, x16 ip0 is blocked
READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg17, w17, x17
-READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg18, w18, x18
+// READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg18, w18, x18 x18 is blocked
READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg19, w19, x19
READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg20, w20, x20
READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg21, w21, x21
@@ -2629,7 +2626,7 @@
SELECT_X_OR_W_FOR_MACRO \macro_for_register, x15, w15, \xreg
\macro_for_reserved_register // IP0 is reserved
\macro_for_reserved_register // IP1 is reserved
- SELECT_X_OR_W_FOR_MACRO \macro_for_register, x18, w18, \xreg
+ \macro_for_reserved_register // x18 is reserved
SELECT_X_OR_W_FOR_MACRO \macro_for_register, x19, w19, \xreg
SELECT_X_OR_W_FOR_MACRO \macro_for_register, x20, w20, \xreg
SELECT_X_OR_W_FOR_MACRO \macro_for_register, x21, w21, \xreg
@@ -2673,13 +2670,12 @@
.macro READ_BARRIER_MARK_INTROSPECTION_SLOW_PATH ldr_offset
/*
- * Allocate 44 stack slots * 8 = 352 bytes:
- * - 19 slots for core registers X0-15, X18-X19, LR
- * - 1 slot padding
+ * Allocate 42 stack slots * 8 = 336 bytes:
+ * - 18 slots for core registers X0-15, X19, LR
* - 24 slots for floating-point registers D0-D7 and D16-D31
*/
// Save all potentially live caller-save core registers.
- SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 352
+ SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 336
SAVE_TWO_REGS x2, x3, 16
SAVE_TWO_REGS x4, x5, 32
SAVE_TWO_REGS x6, x7, 48
@@ -2687,21 +2683,21 @@
SAVE_TWO_REGS x10, x11, 80
SAVE_TWO_REGS x12, x13, 96
SAVE_TWO_REGS x14, x15, 112
- SAVE_TWO_REGS x18, x19, 128 // Skip x16, x17, i.e. IP0, IP1.
- SAVE_REG xLR, 144 // Save return address, skip padding at 152.
+ // Skip x16, x17, i.e. IP0, IP1, and x18, the platform register.
+ SAVE_TWO_REGS x19, xLR, 128 // Save return address.
// Save all potentially live caller-save floating-point registers.
- stp d0, d1, [sp, #160]
- stp d2, d3, [sp, #176]
- stp d4, d5, [sp, #192]
- stp d6, d7, [sp, #208]
- stp d16, d17, [sp, #224]
- stp d18, d19, [sp, #240]
- stp d20, d21, [sp, #256]
- stp d22, d23, [sp, #272]
- stp d24, d25, [sp, #288]
- stp d26, d27, [sp, #304]
- stp d28, d29, [sp, #320]
- stp d30, d31, [sp, #336]
+ stp d0, d1, [sp, #144]
+ stp d2, d3, [sp, #160]
+ stp d4, d5, [sp, #176]
+ stp d6, d7, [sp, #192]
+ stp d16, d17, [sp, #208]
+ stp d18, d19, [sp, #224]
+ stp d20, d21, [sp, #240]
+ stp d22, d23, [sp, #256]
+ stp d24, d25, [sp, #272]
+ stp d26, d27, [sp, #288]
+ stp d28, d29, [sp, #304]
+ stp d30, d31, [sp, #320]
mov x0, xIP0
bl artReadBarrierMark // artReadBarrierMark(obj)
@@ -2716,26 +2712,26 @@
RESTORE_TWO_REGS x10, x11, 80
RESTORE_TWO_REGS x12, x13, 96
RESTORE_TWO_REGS x14, x15, 112
- RESTORE_TWO_REGS x18, x19, 128 // Skip x16, x17, i.e. IP0, IP1.
- RESTORE_REG xLR, 144 // Restore return address.
+ // Skip x16, x17, i.e. IP0, IP1, and x18, the platform register.
+ RESTORE_TWO_REGS x19, xLR, 128 // Restore return address.
// Restore caller-save floating-point registers.
- ldp d0, d1, [sp, #160]
- ldp d2, d3, [sp, #176]
- ldp d4, d5, [sp, #192]
- ldp d6, d7, [sp, #208]
- ldp d16, d17, [sp, #224]
- ldp d18, d19, [sp, #240]
- ldp d20, d21, [sp, #256]
- ldp d22, d23, [sp, #272]
- ldp d24, d25, [sp, #288]
- ldp d26, d27, [sp, #304]
- ldp d28, d29, [sp, #320]
- ldp d30, d31, [sp, #336]
+ ldp d0, d1, [sp, #144]
+ ldp d2, d3, [sp, #160]
+ ldp d4, d5, [sp, #176]
+ ldp d6, d7, [sp, #192]
+ ldp d16, d17, [sp, #208]
+ ldp d18, d19, [sp, #224]
+ ldp d20, d21, [sp, #240]
+ ldp d22, d23, [sp, #256]
+ ldp d24, d25, [sp, #272]
+ ldp d26, d27, [sp, #288]
+ ldp d28, d29, [sp, #304]
+ ldp d30, d31, [sp, #320]
ldr x0, [lr, #\ldr_offset] // Load the instruction.
adr xIP1, .Lmark_introspection_return_switch
bfi xIP1, x0, #3, #5 // Calculate switch case address.
- RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 352
+ RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 336
br xIP1
.endm
diff --git a/runtime/image.h b/runtime/image.h
index 0496650..bd903da 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -289,14 +289,14 @@
return GetImageSection(kSectionClassTable);
}
- const ImageSection& GetImageBitmapSection() const {
- return GetImageSection(kSectionImageBitmap);
- }
-
const ImageSection& GetImageStringReferenceOffsetsSection() const {
return GetImageSection(kSectionStringReferenceOffsets);
}
+ const ImageSection& GetImageBitmapSection() const {
+ return GetImageSection(kSectionImageBitmap);
+ }
+
template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
ObjPtr<mirror::Object> GetImageRoot(ImageRoot image_root) const
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index d533054..cbcaaef 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -1360,38 +1360,56 @@
: StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
shorty('V') {}
+ static uint16_t GetMethodIndexOfInvoke(ArtMethod* caller,
+ const Instruction& inst,
+ uint32_t dex_pc)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ switch (inst.Opcode()) {
+ case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
+ case Instruction::INVOKE_VIRTUAL_QUICK: {
+ uint16_t method_idx = caller->GetIndexFromQuickening(dex_pc);
+ CHECK_NE(method_idx, DexFile::kDexNoIndex16);
+ return method_idx;
+ }
+ default: {
+ return inst.VRegB();
+ }
+ }
+ }
+
bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
ArtMethod* m = GetMethod();
- if (m != nullptr && !m->IsRuntimeMethod()) {
- // The first Java method.
- if (m->IsNative()) {
- // Use JNI method's shorty for the jni stub.
- shorty = m->GetShorty()[0];
- return false;
- }
- if (m->IsProxyMethod()) {
- // Proxy method just invokes its proxied method via
- // art_quick_proxy_invoke_handler.
- shorty = m->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty()[0];
- return false;
- }
+ if (m == nullptr || m->IsRuntimeMethod()) {
+ return true;
+ }
+ // The first Java method.
+ if (m->IsNative()) {
+ // Use JNI method's shorty for the jni stub.
+ shorty = m->GetShorty()[0];
+ } else if (m->IsProxyMethod()) {
+ // Proxy method just invokes its proxied method via
+ // art_quick_proxy_invoke_handler.
+ shorty = m->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty()[0];
+ } else {
const Instruction& instr = m->DexInstructions().InstructionAt(GetDexPc());
if (instr.IsInvoke()) {
+ uint16_t method_index = GetMethodIndexOfInvoke(m, instr, GetDexPc());
const DexFile* dex_file = m->GetDexFile();
- if (interpreter::IsStringInit(dex_file, instr.VRegB())) {
+ if (interpreter::IsStringInit(dex_file, method_index)) {
// Invoking string init constructor is turned into invoking
// StringFactory.newStringFromChars() which returns a string.
shorty = 'L';
- return false;
+ } else {
+ shorty = dex_file->GetMethodShorty(method_index)[0];
}
- // A regular invoke, use callee's shorty.
- uint32_t method_idx = instr.VRegB();
- shorty = dex_file->GetMethodShorty(method_idx)[0];
+ } else {
+ // It could be that a non-invoke opcode invokes a stub, which in turn
+ // invokes Java code. In such cases, we should never expect a return
+ // value from the stub.
}
- // Stop stack walking since we've seen a Java frame.
- return false;
}
- return true;
+ // Stop stack walking since we've seen a Java frame.
+ return false;
}
char shorty;
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl-inl.h
similarity index 99%
rename from runtime/interpreter/interpreter_switch_impl.cc
rename to runtime/interpreter/interpreter_switch_impl-inl.h
index 4757b57..4774d69 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#ifndef ART_RUNTIME_INTERPRETER_INTERPRETER_SWITCH_IMPL_INL_H_
+#define ART_RUNTIME_INTERPRETER_INTERPRETER_SWITCH_IMPL_INL_H_
+
#include "interpreter_switch_impl.h"
#include "base/enums.h"
@@ -2571,15 +2574,7 @@
return;
} // NOLINT(readability/fn_size)
-// Explicit definitions of ExecuteSwitchImplCpp.
-template HOT_ATTR
-void ExecuteSwitchImplCpp<true, false>(SwitchImplContext* ctx);
-template HOT_ATTR
-void ExecuteSwitchImplCpp<false, false>(SwitchImplContext* ctx);
-template
-void ExecuteSwitchImplCpp<true, true>(SwitchImplContext* ctx);
-template
-void ExecuteSwitchImplCpp<false, true>(SwitchImplContext* ctx);
-
} // namespace interpreter
} // namespace art
+
+#endif // ART_RUNTIME_INTERPRETER_INTERPRETER_SWITCH_IMPL_INL_H_
diff --git a/runtime/interpreter/interpreter_switch_impl0.cc b/runtime/interpreter/interpreter_switch_impl0.cc
new file mode 100644
index 0000000..00159ec
--- /dev/null
+++ b/runtime/interpreter/interpreter_switch_impl0.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// The interpreter function takes considerable time to compile and link.
+// We compile the explicit definitions separately to speed up the build.
+
+#include "interpreter_switch_impl-inl.h"
+
+namespace art {
+namespace interpreter {
+
+// Explicit definition of ExecuteSwitchImplCpp.
+template HOT_ATTR
+void ExecuteSwitchImplCpp<false, false>(SwitchImplContext* ctx);
+
+} // namespace interpreter
+} // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl1.cc b/runtime/interpreter/interpreter_switch_impl1.cc
new file mode 100644
index 0000000..3a86765
--- /dev/null
+++ b/runtime/interpreter/interpreter_switch_impl1.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// The interpreter function takes considerable time to compile and link.
+// We compile the explicit definitions separately to speed up the build.
+
+#include "interpreter_switch_impl-inl.h"
+
+namespace art {
+namespace interpreter {
+
+// Explicit definition of ExecuteSwitchImplCpp.
+template
+void ExecuteSwitchImplCpp<false, true>(SwitchImplContext* ctx);
+
+} // namespace interpreter
+} // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl2.cc b/runtime/interpreter/interpreter_switch_impl2.cc
new file mode 100644
index 0000000..c2739c1
--- /dev/null
+++ b/runtime/interpreter/interpreter_switch_impl2.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// The interpreter function takes considerable time to compile and link.
+// We compile the explicit definitions separately to speed up the build.
+
+#include "interpreter_switch_impl-inl.h"
+
+namespace art {
+namespace interpreter {
+
+// Explicit definition of ExecuteSwitchImplCpp.
+template HOT_ATTR
+void ExecuteSwitchImplCpp<true, false>(SwitchImplContext* ctx);
+
+} // namespace interpreter
+} // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl3.cc b/runtime/interpreter/interpreter_switch_impl3.cc
new file mode 100644
index 0000000..808e4bc
--- /dev/null
+++ b/runtime/interpreter/interpreter_switch_impl3.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// The interpreter function takes considerable time to compile and link.
+// We compile the explicit definitions separately to speed up the build.
+
+#include "interpreter_switch_impl-inl.h"
+
+namespace art {
+namespace interpreter {
+
+// Explicit definition of ExecuteSwitchImplCpp.
+template
+void ExecuteSwitchImplCpp<true, true>(SwitchImplContext* ctx);
+
+} // namespace interpreter
+} // namespace art
diff --git a/test/602-deoptimizeable/info.txt b/test/602-deoptimizeable/info.txt
index 4b6147f..d0952f9 100644
--- a/test/602-deoptimizeable/info.txt
+++ b/test/602-deoptimizeable/info.txt
@@ -1,8 +1 @@
Test various cases for full/partial-fragment deoptimization.
-
-TODO: we should remove this test as its expectations at point of
-writing was that debuggable apps could run un-deoptimizeable frames
-from the boot image. Today, we deoptimize the boot image as soon as
-we see the app being debuggable. Test 685-deoptimizeable is the proper
-version of this test, but we currently keep the 602 version around to
-try diagnosing a gcstress issue.
diff --git a/test/602-deoptimizeable/src/Main.java b/test/602-deoptimizeable/src/Main.java
index 7a3285d..46584b0 100644
--- a/test/602-deoptimizeable/src/Main.java
+++ b/test/602-deoptimizeable/src/Main.java
@@ -33,10 +33,7 @@
public int hashCode() {
sHashCodeInvoked = true;
- Main.assertIsManaged();
Main.deoptimizeAll();
- Main.assertIsInterpreted();
- Main.assertCallerIsManaged(); // Caller is from framework code HashMap.
return i % 64;
}
}
@@ -46,13 +43,6 @@
public static native void deoptimizeAll();
public static native void undeoptimizeAll();
- public static native void assertIsInterpreted();
- public static native void assertIsManaged();
- public static native void assertCallerIsInterpreted();
- public static native void assertCallerIsManaged();
- public static native void disableStackFrameAsserts();
- public static native boolean hasOatFile();
- public static native boolean isInterpreted();
public static void execute(Runnable runnable) throws Exception {
Thread t = new Thread(runnable);
@@ -62,19 +52,13 @@
public static void main(String[] args) throws Exception {
System.loadLibrary(args[0]);
- // TODO: Stack frame assertions are irrelevant in this test as we now
- // always run JIT with debuggable. 685-deoptimizeable is the proper version
- // of this test, but we keep this version around to diagnose a gcstress issue.
- disableStackFrameAsserts();
final HashMap<DummyObject, Long> map = new HashMap<DummyObject, Long>();
// Single-frame deoptimization that covers partial fragment.
execute(new Runnable() {
public void run() {
int[] arr = new int[3];
- assertIsManaged();
int res = $noinline$run1(arr);
- assertIsManaged(); // Only single frame is deoptimized.
if (res != 79) {
System.out.println("Failure 1!");
System.exit(0);
@@ -87,13 +71,11 @@
public void run() {
try {
int[] arr = new int[3];
- assertIsManaged();
// Use reflection to call $noinline$run2 so that it does
// full-fragment deoptimization since that is an upcall.
Class<?> cls = Class.forName("Main");
Method method = cls.getDeclaredMethod("$noinline$run2", int[].class);
double res = (double)method.invoke(Main.class, arr);
- assertIsManaged(); // Only single frame is deoptimized.
if (res != 79.3d) {
System.out.println("Failure 2!");
System.exit(0);
@@ -107,9 +89,7 @@
// Full-fragment deoptimization.
execute(new Runnable() {
public void run() {
- assertIsManaged();
float res = $noinline$run3B();
- assertIsInterpreted(); // Every deoptimizeable method is deoptimized.
if (res != 0.034f) {
System.out.println("Failure 3!");
System.exit(0);
@@ -123,9 +103,7 @@
execute(new Runnable() {
public void run() {
try {
- assertIsManaged();
map.put(new DummyObject(10), Long.valueOf(100));
- assertIsInterpreted(); // Every deoptimizeable method is deoptimized.
if (map.get(new DummyObject(10)) == null) {
System.out.println("Expected map to contain DummyObject(10)");
}
@@ -147,7 +125,6 @@
}
public static int $noinline$run1(int[] arr) {
- assertIsManaged();
// Prevent inlining.
if (sFlag) {
throw new Error();
@@ -161,18 +138,15 @@
// This causes AIOOBE and triggers deoptimization from compiled code.
arr[3] = 1;
} catch (ArrayIndexOutOfBoundsException e) {
- assertIsInterpreted(); // Single-frame deoptimization triggered.
caught = true;
}
if (!caught) {
System.out.println("Expected exception");
}
- assertIsInterpreted();
return 79;
}
public static double $noinline$run2(int[] arr) {
- assertIsManaged();
// Prevent inlining.
if (sFlag) {
throw new Error();
@@ -186,37 +160,30 @@
// This causes AIOOBE and triggers deoptimization from compiled code.
arr[3] = 1;
} catch (ArrayIndexOutOfBoundsException e) {
- assertIsInterpreted(); // Single-frame deoptimization triggered.
caught = true;
}
if (!caught) {
System.out.println("Expected exception");
}
- assertIsInterpreted();
return 79.3d;
}
public static float $noinline$run3A() {
- assertIsManaged();
// Prevent inlining.
if (sFlag) {
throw new Error();
}
// Deoptimize callers.
deoptimizeAll();
- assertIsInterpreted();
- assertCallerIsInterpreted(); // $noinline$run3B is deoptimizeable.
return 0.034f;
}
public static float $noinline$run3B() {
- assertIsManaged();
// Prevent inlining.
if (sFlag) {
throw new Error();
}
float res = $noinline$run3A();
- assertIsInterpreted();
return res;
}
}
diff --git a/test/687-deopt/expected.txt b/test/687-deopt/expected.txt
new file mode 100644
index 0000000..6a5618e
--- /dev/null
+++ b/test/687-deopt/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/687-deopt/info.txt b/test/687-deopt/info.txt
new file mode 100644
index 0000000..ef56f51
--- /dev/null
+++ b/test/687-deopt/info.txt
@@ -0,0 +1,2 @@
+Regression test for instrumentation deopt, which previously did not expect a
+quickened instruction when returning from instrumentation stub.
diff --git a/test/687-deopt/src/Main.java b/test/687-deopt/src/Main.java
new file mode 100644
index 0000000..afe90d6
--- /dev/null
+++ b/test/687-deopt/src/Main.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+import java.util.HashMap;
+
+public class Main {
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+
+ // Jit compile HashMap.hash method, so that instrumentation stubs
+ // will deoptimize it.
+ ensureJitCompiled(HashMap.class, "hash");
+
+ Main key = new Main();
+ Integer value = new Integer(10);
+ HashMap<Main, Integer> map = new HashMap<>();
+ map.put(key, value);
+ Integer res = map.get(key);
+ if (!value.equals(res)) {
+ throw new Error("Expected 10, got " + res);
+ }
+ }
+
+ public int hashCode() {
+ // The call stack at this point is:
+ // Main.main
+ // HashMap.put
+ // HashMap.hash
+ // Main.hashCode
+ //
+ // The opcode at HashMap.hash is invoke-virtual-quick which the
+ // instrumentation code did not expect and used to fetch the wrong
+ // method index for it.
+ deoptimizeAll();
+ return 42;
+ }
+
+ public static native void deoptimizeAll();
+ public static native void ensureJitCompiled(Class<?> cls, String methodName);
+}
diff --git a/test/knownfailures.json b/test/knownfailures.json
index d831993..7b40160 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -948,6 +948,7 @@
"685-deoptimizeable",
"685-shifts",
"686-get-this",
+ "687-deopt",
"706-checker-scheduler",
"707-checker-invalid-profile",
"714-invoke-custom-lambda-metafactory",