Merge "Keep resolved String in HLoadString."
diff --git a/Android.mk b/Android.mk
index cf3a9e7..f3ab3c1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -341,56 +341,6 @@
endif # art_test_bother
-########################################################################
-# oat-target and oat-target-sync rules
-
-OAT_TARGET_RULES :=
-
-# $(1): input jar or apk target location
-define declare-oat-target-target
-OUT_OAT_FILE := $(PRODUCT_OUT)/$(basename $(1)).odex
-
-ifeq ($(ONE_SHOT_MAKEFILE),)
-# ONE_SHOT_MAKEFILE is empty for a top level build and we don't want
-# to define the oat-target-* rules there because they will conflict
-# with the build/core/dex_preopt.mk defined rules.
-.PHONY: oat-target-$(1)
-oat-target-$(1):
-
-else
-.PHONY: oat-target-$(1)
-oat-target-$(1): $$(OUT_OAT_FILE)
-
-$$(OUT_OAT_FILE): $(PRODUCT_OUT)/$(1) $(DEFAULT_DEX_PREOPT_BUILT_IMAGE) $(DEX2OAT_DEPENDENCY)
- @mkdir -p $$(dir $$@)
- $(DEX2OAT) --runtime-arg -Xms$(DEX2OAT_XMS) --runtime-arg -Xmx$(DEX2OAT_XMX) \
- --boot-image=$(DEFAULT_DEX_PREOPT_BUILT_IMAGE) --dex-file=$(PRODUCT_OUT)/$(1) \
- --dex-location=/$(1) --oat-file=$$@ \
- --instruction-set=$(DEX2OAT_TARGET_ARCH) \
- --instruction-set-variant=$(DEX2OAT_TARGET_CPU_VARIANT) \
- --instruction-set-features=$(DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES) \
- --android-root=$(PRODUCT_OUT)/system --include-patch-information \
- --runtime-arg -Xnorelocate
-
-endif
-
-OAT_TARGET_RULES += oat-target-$(1)
-endef
-
-$(foreach file,\
- $(filter-out\
- $(addprefix $(TARGET_OUT_JAVA_LIBRARIES)/,$(addsuffix .jar,$(LIBART_TARGET_BOOT_JARS))),\
- $(wildcard $(TARGET_OUT_APPS)/*.apk) $(wildcard $(TARGET_OUT_JAVA_LIBRARIES)/*.jar)),\
- $(eval $(call declare-oat-target-target,$(subst $(PRODUCT_OUT)/,,$(file)))))
-
-.PHONY: oat-target
-oat-target: $(ART_TARGET_DEPENDENCIES) $(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE) $(OAT_TARGET_RULES)
-
-.PHONY: oat-target-sync
-oat-target-sync: oat-target
- $(TEST_ART_ADB_ROOT_AND_REMOUNT)
- adb sync
-
####################################################################################################
# Fake packages to ensure generation of libopenjdkd when one builds with mm/mmm/mmma.
#
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index bd7f900..5bdfbc7 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -332,7 +332,7 @@
(adb shell "$(GCOV_ENV) LD_LIBRARY_PATH=$(4) ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \
valgrind --leak-check=full --error-exitcode=1 --workaround-gcc296-bugs=yes \
--suppressions=$(ART_TARGET_TEST_DIR)/valgrind-target-suppressions.txt \
- --num-callers=50 \
+ --num-callers=50 --show-mismatched-frees=no \
$$(PRIVATE_TARGET_EXE) && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID" \
&& (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID /tmp/ \
&& $$(call ART_TEST_PASSED,$$@)) \
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 86d92ff..4180e0e 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -487,7 +487,7 @@
EXPECT_EQ(72U, sizeof(OatHeader));
EXPECT_EQ(4U, sizeof(OatMethodOffsets));
EXPECT_EQ(20U, sizeof(OatQuickMethodHeader));
- EXPECT_EQ(164 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
+ EXPECT_EQ(163 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
sizeof(QuickEntryPoints));
}
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 3009103..541a1c5 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -3936,7 +3936,6 @@
} else {
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
- locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
}
locations->SetOut(Location::RegisterLocation(R0));
}
@@ -3954,7 +3953,7 @@
codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
} else {
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
- CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
+ CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
}
}
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 4b6a9be..9aaeadb 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -4744,7 +4744,6 @@
locations->AddTemp(LocationFrom(kArtMethodRegister));
} else {
locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
- locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
}
locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
}
@@ -4762,7 +4761,7 @@
codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
} else {
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
- CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
+ CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
}
}
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index b1f6d59..c769dec 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -3948,7 +3948,6 @@
} else {
InvokeRuntimeCallingConventionARMVIXL calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
- locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
}
locations->SetOut(LocationFrom(r0));
}
@@ -3970,7 +3969,7 @@
codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
} else {
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
- CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
+ CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
}
}
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 9af03e8..bc62854 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -5903,7 +5903,6 @@
locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
} else {
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
- locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
}
locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
}
@@ -5920,7 +5919,7 @@
codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
} else {
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
- CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
+ CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
}
}
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 046d59c..1b9c6da 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3844,7 +3844,6 @@
locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
} else {
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
- locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
}
locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
}
@@ -3862,7 +3861,7 @@
codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
} else {
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
- CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
+ CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
}
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index f13b60a..a9b717d 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4150,7 +4150,6 @@
} else {
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
- locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
}
}
@@ -4166,7 +4165,7 @@
codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
} else {
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
- CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
+ CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
DCHECK(!codegen_->IsLeafMethod());
}
}
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 89f4ae0..2614735 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -4038,7 +4038,6 @@
locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
} else {
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
- locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
}
locations->SetOut(Location::RegisterLocation(RAX));
}
@@ -4055,7 +4054,7 @@
codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
} else {
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
- CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
+ CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
DCHECK(!codegen_->IsLeafMethod());
}
}
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 879b4ce..e3f3df0 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -15,6 +15,7 @@
*/
#include <functional>
+#include <memory>
#include "arch/instruction_set.h"
#include "arch/arm/instruction_set_features_arm.h"
@@ -299,8 +300,8 @@
bool has_result,
Expected expected) {
CompilerOptions compiler_options;
- CodeGenerator* codegen = target_config.CreateCodeGenerator(graph, compiler_options);
- RunCode(codegen, graph, hook_before_codegen, has_result, expected);
+ std::unique_ptr<CodeGenerator> codegen(target_config.CreateCodeGenerator(graph, compiler_options));
+ RunCode(codegen.get(), graph, hook_before_codegen, has_result, expected);
}
#ifdef ART_ENABLE_CODEGEN_arm
diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc
index 437d35c..f8d37bd 100644
--- a/compiler/optimizing/gvn_test.cc
+++ b/compiler/optimizing/gvn_test.cc
@@ -28,7 +28,6 @@
TEST_F(GVNTest, LocalFieldElimination) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
- ScopedNullHandle<mirror::DexCache> dex_cache;
HGraph* graph = CreateGraph(&allocator);
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
@@ -45,53 +44,53 @@
entry->AddSuccessor(block);
block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimNot,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimNot,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
HInstruction* to_remove = block->GetLastInstruction();
block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimNot,
MemberOffset(43),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
HInstruction* different_offset = block->GetLastInstruction();
// Kill the value.
block->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
parameter,
+ nullptr,
Primitive::kPrimNot,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimNot,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
HInstruction* use_after_kill = block->GetLastInstruction();
block->AddInstruction(new (&allocator) HExit());
@@ -113,7 +112,6 @@
TEST_F(GVNTest, GlobalFieldElimination) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
- ScopedNullHandle<mirror::DexCache> dex_cache;
HGraph* graph = CreateGraph(&allocator);
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
@@ -129,13 +127,13 @@
graph->AddBlock(block);
entry->AddSuccessor(block);
block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimBoolean,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
block->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
@@ -152,33 +150,33 @@
else_->AddSuccessor(join);
then->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimBoolean,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
then->AddInstruction(new (&allocator) HGoto());
else_->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimBoolean,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
else_->AddInstruction(new (&allocator) HGoto());
join->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimBoolean,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
join->AddInstruction(new (&allocator) HExit());
@@ -196,7 +194,6 @@
TEST_F(GVNTest, LoopFieldElimination) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
- ScopedNullHandle<mirror::DexCache> dex_cache;
HGraph* graph = CreateGraph(&allocator);
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
@@ -213,13 +210,13 @@
graph->AddBlock(block);
entry->AddSuccessor(block);
block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimBoolean,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
block->AddInstruction(new (&allocator) HGoto());
@@ -236,13 +233,13 @@
loop_body->AddSuccessor(loop_header);
loop_header->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimBoolean,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
HInstruction* field_get_in_loop_header = loop_header->GetLastInstruction();
loop_header->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
@@ -251,35 +248,35 @@
// and the body to be GVN'ed.
loop_body->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
parameter,
+ nullptr,
Primitive::kPrimBoolean,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
HInstruction* field_set = loop_body->GetLastInstruction();
loop_body->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimBoolean,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
HInstruction* field_get_in_loop_body = loop_body->GetLastInstruction();
loop_body->AddInstruction(new (&allocator) HGoto());
exit->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimBoolean,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
HInstruction* field_get_in_exit = exit->GetLastInstruction();
exit->AddInstruction(new (&allocator) HExit());
@@ -319,7 +316,6 @@
TEST_F(GVNTest, LoopSideEffects) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
- ScopedNullHandle<mirror::DexCache> dex_cache;
static const SideEffects kCanTriggerGC = SideEffects::CanTriggerGC();
@@ -376,13 +372,13 @@
// Make one block with a side effect.
entry->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
parameter,
+ nullptr,
Primitive::kPrimNot,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0));
SideEffectsAnalysis side_effects(graph);
@@ -401,13 +397,13 @@
outer_loop_body->InsertInstructionBefore(
new (&allocator) HInstanceFieldSet(parameter,
parameter,
+ nullptr,
Primitive::kPrimNot,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0),
outer_loop_body->GetLastInstruction());
@@ -427,13 +423,13 @@
inner_loop_body->InsertInstructionBefore(
new (&allocator) HInstanceFieldSet(parameter,
parameter,
+ nullptr,
Primitive::kPrimNot,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0),
inner_loop_body->GetLastInstruction());
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 3b83e95..c970e5c 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -429,13 +429,13 @@
DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_");
HInstanceFieldGet* result = new (graph_->GetArena()) HInstanceFieldGet(
receiver,
+ field,
Primitive::kPrimNot,
field->GetOffset(),
field->IsVolatile(),
field->GetDexFieldIndex(),
field->GetDeclaringClass()->GetDexClassDefIndex(),
*field->GetDexFile(),
- handles_->NewHandle(field->GetDexCache()),
dex_pc);
// The class of a field is effectively final, and does not have any memory dependencies.
result->SetSideEffects(SideEffects::None());
@@ -618,6 +618,9 @@
} else {
one_target_inlined = true;
+ VLOG(compiler) << "Polymorphic call to " << ArtMethod::PrettyMethod(resolved_method)
+ << " has inlined " << ArtMethod::PrettyMethod(method);
+
// If we have inlined all targets before, and this receiver is the last seen,
// we deoptimize instead of keeping the original invoke instruction.
bool deoptimize = all_targets_inlined &&
@@ -655,6 +658,7 @@
<< " of its targets could be inlined";
return false;
}
+
MaybeRecordStat(kInlinedPolymorphicCall);
// Run type propagation to get the guards typed.
@@ -1161,13 +1165,13 @@
DCHECK(resolved_field != nullptr);
HInstanceFieldGet* iget = new (graph_->GetArena()) HInstanceFieldGet(
obj,
+ resolved_field,
resolved_field->GetTypeAsPrimitiveType(),
resolved_field->GetOffset(),
resolved_field->IsVolatile(),
field_index,
resolved_field->GetDeclaringClass()->GetDexClassDefIndex(),
*dex_cache->GetDexFile(),
- dex_cache,
// Read barrier generates a runtime call in slow path and we need a valid
// dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
/* dex_pc */ 0);
@@ -1190,13 +1194,13 @@
HInstanceFieldSet* iput = new (graph_->GetArena()) HInstanceFieldSet(
obj,
value,
+ resolved_field,
resolved_field->GetTypeAsPrimitiveType(),
resolved_field->GetOffset(),
resolved_field->IsVolatile(),
field_index,
resolved_field->GetDeclaringClass()->GetDexClassDefIndex(),
*dex_cache->GetDexFile(),
- dex_cache,
// Read barrier generates a runtime call in slow path and we need a valid
// dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
/* dex_pc */ 0);
@@ -1424,15 +1428,6 @@
return false;
}
- if (current->IsNewInstance() &&
- (current->AsNewInstance()->GetEntrypoint() == kQuickAllocObjectWithAccessCheck)) {
- VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index)
- << " could not be inlined because it is using an entrypoint"
- << " with access checks";
- // Allocation entrypoint does not handle inlined frames.
- return false;
- }
-
if (current->IsNewArray() &&
(current->AsNewArray()->GetEntrypoint() == kQuickAllocArrayWithAccessCheck)) {
VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index)
@@ -1579,6 +1574,13 @@
/* declared_can_be_null */ true,
return_replacement)) {
return true;
+ } else if (return_replacement->IsInstanceFieldGet()) {
+ HInstanceFieldGet* field_get = return_replacement->AsInstanceFieldGet();
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ if (field_get->GetFieldInfo().GetField() ==
+ class_linker->GetClassRoot(ClassLinker::kJavaLangObject)->GetInstanceField(0)) {
+ return true;
+ }
}
} else if (return_replacement->IsInstanceOf()) {
// Inlining InstanceOf into an If may put a tighter bound on reference types.
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index af8e2c8..009d549 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -917,11 +917,11 @@
bool finalizable;
bool needs_access_check = NeedsAccessCheck(type_index, dex_cache, &finalizable);
- // Only the non-resolved entrypoint handles the finalizable class case. If we
+ // Only the access check entrypoint handles the finalizable class case. If we
// need access checks, then we haven't resolved the method and the class may
// again be finalizable.
QuickEntrypointEnum entrypoint = (finalizable || needs_access_check)
- ? kQuickAllocObject
+ ? kQuickAllocObjectWithChecks
: kQuickAllocObjectInitialized;
if (outer_dex_cache.Get() != dex_cache.Get()) {
@@ -946,7 +946,6 @@
AppendInstruction(new (arena_) HNewInstance(
cls,
- graph_->GetCurrentMethod(),
dex_pc,
type_index,
*dex_compilation_unit_->GetDexFile(),
@@ -1235,13 +1234,13 @@
uint16_t class_def_index = resolved_field->GetDeclaringClass()->GetDexClassDefIndex();
field_set = new (arena_) HInstanceFieldSet(object,
value,
+ resolved_field,
field_type,
resolved_field->GetOffset(),
resolved_field->IsVolatile(),
field_index,
class_def_index,
*dex_file_,
- dex_compilation_unit_->GetDexCache(),
dex_pc);
}
AppendInstruction(field_set);
@@ -1256,13 +1255,13 @@
} else {
uint16_t class_def_index = resolved_field->GetDeclaringClass()->GetDexClassDefIndex();
field_get = new (arena_) HInstanceFieldGet(object,
+ resolved_field,
field_type,
resolved_field->GetOffset(),
resolved_field->IsVolatile(),
field_index,
class_def_index,
*dex_file_,
- dex_compilation_unit_->GetDexCache(),
dex_pc);
}
AppendInstruction(field_get);
@@ -1311,9 +1310,9 @@
}
void HInstructionBuilder::BuildUnresolvedStaticFieldAccess(const Instruction& instruction,
- uint32_t dex_pc,
- bool is_put,
- Primitive::Type field_type) {
+ uint32_t dex_pc,
+ bool is_put,
+ Primitive::Type field_type) {
uint32_t source_or_dest_reg = instruction.VRegA_21c();
uint16_t field_index = instruction.VRegB_21c();
@@ -1400,23 +1399,23 @@
DCHECK_EQ(HPhi::ToPhiType(value->GetType()), HPhi::ToPhiType(field_type));
AppendInstruction(new (arena_) HStaticFieldSet(cls,
value,
+ resolved_field,
field_type,
resolved_field->GetOffset(),
resolved_field->IsVolatile(),
field_index,
class_def_index,
*dex_file_,
- dex_cache_,
dex_pc));
} else {
AppendInstruction(new (arena_) HStaticFieldGet(cls,
+ resolved_field,
field_type,
resolved_field->GetOffset(),
resolved_field->IsVolatile(),
field_index,
class_def_index,
*dex_file_,
- dex_cache_,
dex_pc));
UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
}
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 439e3b6..911bfb9 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -1118,7 +1118,66 @@
VisitCondition(condition);
}
+// Recognize the following pattern:
+// obj.getClass() ==/!= Foo.class
+// And replace it with a constant value if the type of `obj` is statically known.
+static bool RecognizeAndSimplifyClassCheck(HCondition* condition) {
+ HInstruction* input_one = condition->InputAt(0);
+ HInstruction* input_two = condition->InputAt(1);
+ HLoadClass* load_class = input_one->IsLoadClass()
+ ? input_one->AsLoadClass()
+ : input_two->AsLoadClass();
+ if (load_class == nullptr) {
+ return false;
+ }
+
+ ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
+ if (!class_rti.IsValid()) {
+ // Unresolved class.
+ return false;
+ }
+
+ HInstanceFieldGet* field_get = (load_class == input_one)
+ ? input_two->AsInstanceFieldGet()
+ : input_one->AsInstanceFieldGet();
+ if (field_get == nullptr) {
+ return false;
+ }
+
+ HInstruction* receiver = field_get->InputAt(0);
+ ReferenceTypeInfo receiver_type = receiver->GetReferenceTypeInfo();
+ if (!receiver_type.IsExact()) {
+ return false;
+ }
+
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ ArtField* field = class_linker->GetClassRoot(ClassLinker::kJavaLangObject)->GetInstanceField(0);
+ DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_");
+ if (field_get->GetFieldInfo().GetField() != field) {
+ return false;
+ }
+
+ // We can replace the compare.
+ int value = 0;
+ if (receiver_type.IsEqual(class_rti)) {
+ value = condition->IsEqual() ? 1 : 0;
+ } else {
+ value = condition->IsNotEqual() ? 1 : 0;
+ }
+ condition->ReplaceWith(condition->GetBlock()->GetGraph()->GetIntConstant(value));
+ return true;
+ }
+}
+
void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
+ if (condition->IsEqual() || condition->IsNotEqual()) {
+ if (RecognizeAndSimplifyClassCheck(condition)) {
+ return;
+ }
+ }
+
// Reverse condition if left is constant. Our code generators prefer constant
// on the right hand side.
if (condition->GetLeft()->IsConstant() && !condition->GetRight()->IsConstant()) {
@@ -1843,11 +1902,11 @@
// so create the HArrayLength, HBoundsCheck and HArrayGet.
HArrayLength* length = new (arena) HArrayLength(str, dex_pc, /* is_string_length */ true);
invoke->GetBlock()->InsertInstructionBefore(length, invoke);
- HBoundsCheck* bounds_check =
- new (arena) HBoundsCheck(index, length, dex_pc, invoke->GetDexMethodIndex());
+ HBoundsCheck* bounds_check = new (arena) HBoundsCheck(
+ index, length, dex_pc, invoke->GetDexMethodIndex());
invoke->GetBlock()->InsertInstructionBefore(bounds_check, invoke);
- HArrayGet* array_get =
- new (arena) HArrayGet(str, index, Primitive::kPrimChar, dex_pc, /* is_string_char_at */ true);
+ HArrayGet* array_get = new (arena) HArrayGet(
+ str, bounds_check, Primitive::kPrimChar, dex_pc, /* is_string_char_at */ true);
invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, array_get);
bounds_check->CopyEnvironmentFrom(invoke->GetEnvironment());
GetGraph()->SetHasBoundsChecks(true);
diff --git a/compiler/optimizing/licm_test.cc b/compiler/optimizing/licm_test.cc
index 8c34dc6..5bcfa4c 100644
--- a/compiler/optimizing/licm_test.cc
+++ b/compiler/optimizing/licm_test.cc
@@ -111,20 +111,19 @@
BuildLoop();
// Populate the loop with instructions: set/get field with different types.
- ScopedNullHandle<mirror::DexCache> dex_cache;
HInstruction* get_field = new (&allocator_) HInstanceFieldGet(parameter_,
+ nullptr,
Primitive::kPrimLong,
MemberOffset(10),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph_->GetDexFile(),
- dex_cache,
0);
loop_body_->InsertInstructionBefore(get_field, loop_body_->GetLastInstruction());
HInstruction* set_field = new (&allocator_) HInstanceFieldSet(
- parameter_, int_constant_, Primitive::kPrimInt, MemberOffset(20),
- false, kUnknownFieldIndex, kUnknownClassDefIndex, graph_->GetDexFile(), dex_cache, 0);
+ parameter_, int_constant_, nullptr, Primitive::kPrimInt, MemberOffset(20),
+ false, kUnknownFieldIndex, kUnknownClassDefIndex, graph_->GetDexFile(), 0);
loop_body_->InsertInstructionBefore(set_field, loop_body_->GetLastInstruction());
EXPECT_EQ(get_field->GetBlock(), loop_body_);
@@ -140,24 +139,24 @@
// Populate the loop with instructions: set/get field with same types.
ScopedNullHandle<mirror::DexCache> dex_cache;
HInstruction* get_field = new (&allocator_) HInstanceFieldGet(parameter_,
+ nullptr,
Primitive::kPrimLong,
MemberOffset(10),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph_->GetDexFile(),
- dex_cache,
0);
loop_body_->InsertInstructionBefore(get_field, loop_body_->GetLastInstruction());
HInstruction* set_field = new (&allocator_) HInstanceFieldSet(parameter_,
get_field,
+ nullptr,
Primitive::kPrimLong,
MemberOffset(10),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph_->GetDexFile(),
- dex_cache,
0);
loop_body_->InsertInstructionBefore(set_field, loop_body_->GetLastInstruction());
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 6a3ccc7..ea9a94c 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -171,6 +171,7 @@
friend class HGraph;
friend class HInstruction;
friend class HInstructionIterator;
+ friend class HInstructionIteratorHandleChanges;
friend class HBackwardInstructionIterator;
DISALLOW_COPY_AND_ASSIGN(HInstructionList);
@@ -2312,6 +2313,9 @@
};
std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs);
+// Iterates over the instructions, while preserving the next instruction
+// in case the current instruction gets removed from the list by the user
+// of this iterator.
class HInstructionIterator : public ValueObject {
public:
explicit HInstructionIterator(const HInstructionList& instructions)
@@ -2333,6 +2337,28 @@
DISALLOW_COPY_AND_ASSIGN(HInstructionIterator);
};
+// Iterates over the instructions without saving the next instruction,
+// therefore handling changes in the graph potentially made by the user
+// of this iterator.
+class HInstructionIteratorHandleChanges : public ValueObject {
+ public:
+ explicit HInstructionIteratorHandleChanges(const HInstructionList& instructions)
+ : instruction_(instructions.first_instruction_) {
+ }
+
+ bool Done() const { return instruction_ == nullptr; }
+ HInstruction* Current() const { return instruction_; }
+ void Advance() {
+ instruction_ = instruction_->GetNext();
+ }
+
+ private:
+ HInstruction* instruction_;
+
+ DISALLOW_COPY_AND_ASSIGN(HInstructionIteratorHandleChanges);
+};
+
+
class HBackwardInstructionIterator : public ValueObject {
public:
explicit HBackwardInstructionIterator(const HInstructionList& instructions)
@@ -3748,10 +3774,9 @@
DISALLOW_COPY_AND_ASSIGN(HCompare);
};
-class HNewInstance FINAL : public HExpression<2> {
+class HNewInstance FINAL : public HExpression<1> {
public:
HNewInstance(HInstruction* cls,
- HCurrentMethod* current_method,
uint32_t dex_pc,
dex::TypeIndex type_index,
const DexFile& dex_file,
@@ -3765,7 +3790,6 @@
SetPackedFlag<kFlagNeedsAccessCheck>(needs_access_check);
SetPackedFlag<kFlagFinalizable>(finalizable);
SetRawInputAt(0, cls);
- SetRawInputAt(1, current_method);
}
dex::TypeIndex GetTypeIndex() const { return type_index_; }
@@ -5056,60 +5080,62 @@
DISALLOW_COPY_AND_ASSIGN(HNullCheck);
};
+// Embeds an ArtField and all the information required by the compiler. We cache
+// that information to avoid requiring the mutator lock every time we need it.
class FieldInfo : public ValueObject {
public:
- FieldInfo(MemberOffset field_offset,
+ FieldInfo(ArtField* field,
+ MemberOffset field_offset,
Primitive::Type field_type,
bool is_volatile,
uint32_t index,
uint16_t declaring_class_def_index,
- const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache)
- : field_offset_(field_offset),
+ const DexFile& dex_file)
+ : field_(field),
+ field_offset_(field_offset),
field_type_(field_type),
is_volatile_(is_volatile),
index_(index),
declaring_class_def_index_(declaring_class_def_index),
- dex_file_(dex_file),
- dex_cache_(dex_cache) {}
+ dex_file_(dex_file) {}
+ ArtField* GetField() const { return field_; }
MemberOffset GetFieldOffset() const { return field_offset_; }
Primitive::Type GetFieldType() const { return field_type_; }
uint32_t GetFieldIndex() const { return index_; }
uint16_t GetDeclaringClassDefIndex() const { return declaring_class_def_index_;}
const DexFile& GetDexFile() const { return dex_file_; }
bool IsVolatile() const { return is_volatile_; }
- Handle<mirror::DexCache> GetDexCache() const { return dex_cache_; }
private:
+ ArtField* const field_;
const MemberOffset field_offset_;
const Primitive::Type field_type_;
const bool is_volatile_;
const uint32_t index_;
const uint16_t declaring_class_def_index_;
const DexFile& dex_file_;
- const Handle<mirror::DexCache> dex_cache_;
};
class HInstanceFieldGet FINAL : public HExpression<1> {
public:
HInstanceFieldGet(HInstruction* value,
+ ArtField* field,
Primitive::Type field_type,
MemberOffset field_offset,
bool is_volatile,
uint32_t field_idx,
uint16_t declaring_class_def_index,
const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache,
uint32_t dex_pc)
: HExpression(field_type, SideEffects::FieldReadOfType(field_type, is_volatile), dex_pc),
- field_info_(field_offset,
+ field_info_(field,
+ field_offset,
field_type,
is_volatile,
field_idx,
declaring_class_def_index,
- dex_file,
- dex_cache) {
+ dex_file) {
SetRawInputAt(0, value);
}
@@ -5145,22 +5171,22 @@
public:
HInstanceFieldSet(HInstruction* object,
HInstruction* value,
+ ArtField* field,
Primitive::Type field_type,
MemberOffset field_offset,
bool is_volatile,
uint32_t field_idx,
uint16_t declaring_class_def_index,
const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache,
uint32_t dex_pc)
: HTemplateInstruction(SideEffects::FieldWriteOfType(field_type, is_volatile), dex_pc),
- field_info_(field_offset,
+ field_info_(field,
+ field_offset,
field_type,
is_volatile,
field_idx,
declaring_class_def_index,
- dex_file,
- dex_cache) {
+ dex_file) {
SetPackedFlag<kFlagValueCanBeNull>(true);
SetRawInputAt(0, object);
SetRawInputAt(1, value);
@@ -5907,22 +5933,22 @@
class HStaticFieldGet FINAL : public HExpression<1> {
public:
HStaticFieldGet(HInstruction* cls,
+ ArtField* field,
Primitive::Type field_type,
MemberOffset field_offset,
bool is_volatile,
uint32_t field_idx,
uint16_t declaring_class_def_index,
const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache,
uint32_t dex_pc)
: HExpression(field_type, SideEffects::FieldReadOfType(field_type, is_volatile), dex_pc),
- field_info_(field_offset,
+ field_info_(field,
+ field_offset,
field_type,
is_volatile,
field_idx,
declaring_class_def_index,
- dex_file,
- dex_cache) {
+ dex_file) {
SetRawInputAt(0, cls);
}
@@ -5955,22 +5981,22 @@
public:
HStaticFieldSet(HInstruction* cls,
HInstruction* value,
+ ArtField* field,
Primitive::Type field_type,
MemberOffset field_offset,
bool is_volatile,
uint32_t field_idx,
uint16_t declaring_class_def_index,
const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache,
uint32_t dex_pc)
: HTemplateInstruction(SideEffects::FieldWriteOfType(field_type, is_volatile), dex_pc),
- field_info_(field_offset,
+ field_info_(field,
+ field_offset,
field_type,
is_volatile,
field_idx,
declaring_class_def_index,
- dex_file,
- dex_cache) {
+ dex_file) {
SetPackedFlag<kFlagValueCanBeNull>(true);
SetRawInputAt(0, cls);
SetRawInputAt(1, value);
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
index f9ac3a0..db7c1fb 100644
--- a/compiler/optimizing/prepare_for_register_allocation.cc
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -134,39 +134,6 @@
}
}
-void PrepareForRegisterAllocation::VisitNewInstance(HNewInstance* instruction) {
- HLoadClass* load_class = instruction->InputAt(0)->AsLoadClass();
- const bool has_only_one_use = load_class->HasOnlyOneNonEnvironmentUse();
- // Change the entrypoint to kQuickAllocObject if either:
- // - the class is finalizable (only kQuickAllocObject handles finalizable classes),
- // - the class needs access checks (we do not know if it's finalizable),
- // - or the load class has only one use.
- if (instruction->IsFinalizable() || has_only_one_use || load_class->NeedsAccessCheck()) {
- instruction->SetEntrypoint(kQuickAllocObject);
- instruction->ReplaceInput(GetGraph()->GetIntConstant(load_class->GetTypeIndex().index_), 0);
- if (has_only_one_use) {
- // We've just removed the only use of the HLoadClass. Since we don't run DCE after this pass,
- // do it manually if possible.
- if (!load_class->CanThrow()) {
- // If the load class can not throw, it has no side effects and can be removed if there is
- // only one use.
- load_class->GetBlock()->RemoveInstruction(load_class);
- } else if (!instruction->GetEnvironment()->IsFromInlinedInvoke() &&
- CanMoveClinitCheck(load_class, instruction)) {
- // The allocation entry point that deals with access checks does not work with inlined
- // methods, so we need to check whether this allocation comes from an inlined method.
- // We also need to make the same check as for moving clinit check, whether the HLoadClass
- // has the clinit check responsibility or not (HLoadClass can throw anyway).
- // If it needed access checks, we delegate the access check to the allocation.
- if (load_class->NeedsAccessCheck()) {
- instruction->SetEntrypoint(kQuickAllocObjectWithAccessCheck);
- }
- load_class->GetBlock()->RemoveInstruction(load_class);
- }
- }
- }
-}
-
bool PrepareForRegisterAllocation::CanEmitConditionAt(HCondition* condition,
HInstruction* user) const {
if (condition->GetNext() != user) {
diff --git a/compiler/optimizing/prepare_for_register_allocation.h b/compiler/optimizing/prepare_for_register_allocation.h
index a679148..c128227 100644
--- a/compiler/optimizing/prepare_for_register_allocation.h
+++ b/compiler/optimizing/prepare_for_register_allocation.h
@@ -44,7 +44,6 @@
void VisitClinitCheck(HClinitCheck* check) OVERRIDE;
void VisitCondition(HCondition* condition) OVERRIDE;
void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE;
- void VisitNewInstance(HNewInstance* instruction) OVERRIDE;
bool CanMoveClinitCheck(HInstruction* input, HInstruction* user) const;
bool CanEmitConditionAt(HCondition* condition, HInstruction* user) const;
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 33b3875..f8a4469 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -76,6 +76,7 @@
worklist_(worklist),
is_first_run_(is_first_run) {}
+ void VisitDeoptimize(HDeoptimize* deopt) OVERRIDE;
void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
@@ -151,38 +152,6 @@
instruction->Accept(&visitor);
}
-void ReferenceTypePropagation::Run() {
- worklist_.reserve(kDefaultWorklistSize);
-
- // To properly propagate type info we need to visit in the dominator-based order.
- // Reverse post order guarantees a node's dominators are visited first.
- // We take advantage of this order in `VisitBasicBlock`.
- for (HBasicBlock* block : graph_->GetReversePostOrder()) {
- VisitBasicBlock(block);
- }
-
- ProcessWorklist();
- ValidateTypes();
-}
-
-void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
- RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_);
- // Handle Phis first as there might be instructions in the same block who depend on them.
- for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
- VisitPhi(it.Current()->AsPhi());
- }
-
- // Handle instructions.
- for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
- HInstruction* instr = it.Current();
- instr->Accept(&visitor);
- }
-
- // Add extra nodes to bound types.
- BoundTypeForIfNotNull(block);
- BoundTypeForIfInstanceOf(block);
-}
-
// Check if we should create a bound type for the given object at the specified
// position. Because of inlining and the fact we run RTP more than once and we
// might have a HBoundType already. If we do, we should not create a new one.
@@ -225,6 +194,153 @@
return false;
}
+// Helper method to bound the type of `receiver` for all instructions dominated
+// by `start_block`, or `start_instruction` if `start_block` is null. The new
+// bound type will have its upper bound be `class_rti`.
+static void BoundTypeIn(HInstruction* receiver,
+ HBasicBlock* start_block,
+ HInstruction* start_instruction,
+ const ReferenceTypeInfo& class_rti) {
+ // We only need to bound the type if we have uses in the relevant block.
+ // So start with null and create the HBoundType lazily, only if it's needed.
+ HBoundType* bound_type = nullptr;
+ DCHECK(!receiver->IsLoadClass()) << "We should not replace HLoadClass instructions";
+ const HUseList<HInstruction*>& uses = receiver->GetUses();
+ for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
+ HInstruction* user = it->GetUser();
+ size_t index = it->GetIndex();
+ // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
+ ++it;
+ bool dominates = (start_instruction != nullptr)
+ ? start_instruction->StrictlyDominates(user)
+ : start_block->Dominates(user->GetBlock());
+ if (!dominates) {
+ continue;
+ }
+ if (bound_type == nullptr) {
+ ScopedObjectAccess soa(Thread::Current());
+ HInstruction* insert_point = (start_instruction != nullptr)
+ ? start_instruction->GetNext()
+ : start_block->GetFirstInstruction();
+ if (ShouldCreateBoundType(
+ insert_point, receiver, class_rti, start_instruction, start_block)) {
+ bound_type = new (receiver->GetBlock()->GetGraph()->GetArena()) HBoundType(receiver);
+ bound_type->SetUpperBound(class_rti, /* bound_can_be_null */ false);
+ start_block->InsertInstructionBefore(bound_type, insert_point);
+ // To comply with the RTP algorithm, don't type the bound type just yet, it will
+ // be handled in RTPVisitor::VisitBoundType.
+ } else {
+ // We already have a bound type on the position we would need to insert
+ // the new one. The existing bound type should dominate all the users
+ // (dchecked) so there's no need to continue.
+ break;
+ }
+ }
+ user->ReplaceInput(bound_type, index);
+ }
+ // If the receiver is a null check, also bound the type of the actual
+ // receiver.
+ if (receiver->IsNullCheck()) {
+ BoundTypeIn(receiver->InputAt(0), start_block, start_instruction, class_rti);
+ }
+}
+
+// Recognize the patterns:
+// if (obj.shadow$_klass_ == Foo.class) ...
+// deoptimize if (obj.shadow$_klass_ == Foo.class)
+static void BoundTypeForClassCheck(HInstruction* check) {
+ if (!check->IsIf() && !check->IsDeoptimize()) {
+ return;
+ }
+ HInstruction* compare = check->InputAt(0);
+ if (!compare->IsEqual() && !compare->IsNotEqual()) {
+ return;
+ }
+ HInstruction* input_one = compare->InputAt(0);
+ HInstruction* input_two = compare->InputAt(1);
+ HLoadClass* load_class = input_one->IsLoadClass()
+ ? input_one->AsLoadClass()
+ : input_two->AsLoadClass();
+ if (load_class == nullptr) {
+ return;
+ }
+
+ ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
+ if (!class_rti.IsValid()) {
+ // We have loaded an unresolved class. Don't bother bounding the type.
+ return;
+ }
+
+ HInstanceFieldGet* field_get = (load_class == input_one)
+ ? input_two->AsInstanceFieldGet()
+ : input_one->AsInstanceFieldGet();
+ if (field_get == nullptr) {
+ return;
+ }
+ HInstruction* receiver = field_get->InputAt(0);
+ ReferenceTypeInfo receiver_type = receiver->GetReferenceTypeInfo();
+ if (receiver_type.IsExact()) {
+ // If we already know the receiver type, don't bother updating its users.
+ return;
+ }
+
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ ArtField* field = class_linker->GetClassRoot(ClassLinker::kJavaLangObject)->GetInstanceField(0);
+ DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_");
+ if (field_get->GetFieldInfo().GetField() != field) {
+ return;
+ }
+ }
+
+ if (check->IsIf()) {
+ HBasicBlock* trueBlock = check->IsEqual()
+ ? check->AsIf()->IfTrueSuccessor()
+ : check->AsIf()->IfFalseSuccessor();
+ BoundTypeIn(receiver, trueBlock, /* start_instruction */ nullptr, class_rti);
+ } else {
+ DCHECK(check->IsDeoptimize());
+ if (check->IsEqual()) {
+ BoundTypeIn(receiver, check->GetBlock(), check, class_rti);
+ }
+ }
+}
+
+void ReferenceTypePropagation::Run() {
+ worklist_.reserve(kDefaultWorklistSize);
+
+ // To properly propagate type info we need to visit in the dominator-based order.
+ // Reverse post order guarantees a node's dominators are visited first.
+ // We take advantage of this order in `VisitBasicBlock`.
+ for (HBasicBlock* block : graph_->GetReversePostOrder()) {
+ VisitBasicBlock(block);
+ }
+
+ ProcessWorklist();
+ ValidateTypes();
+}
+
+void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
+ RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_);
+ // Handle Phis first as there might be instructions in the same block who depend on them.
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+ VisitPhi(it.Current()->AsPhi());
+ }
+
+ // Handle instructions. Since RTP may add HBoundType instructions just after the
+ // last visited instruction, use `HInstructionIteratorHandleChanges` iterator.
+ for (HInstructionIteratorHandleChanges it(block->GetInstructions()); !it.Done(); it.Advance()) {
+ HInstruction* instr = it.Current();
+ instr->Accept(&visitor);
+ }
+
+ // Add extra nodes to bound types.
+ BoundTypeForIfNotNull(block);
+ BoundTypeForIfInstanceOf(block);
+ BoundTypeForClassCheck(block->GetLastInstruction());
+}
+
void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
HIf* ifInstruction = block->GetLastInstruction()->AsIf();
if (ifInstruction == nullptr) {
@@ -254,40 +370,14 @@
// We only need to bound the type if we have uses in the relevant block.
// So start with null and create the HBoundType lazily, only if it's needed.
- HBoundType* bound_type = nullptr;
HBasicBlock* notNullBlock = ifInput->IsNotEqual()
? ifInstruction->IfTrueSuccessor()
: ifInstruction->IfFalseSuccessor();
- const HUseList<HInstruction*>& uses = obj->GetUses();
- for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
- HInstruction* user = it->GetUser();
- size_t index = it->GetIndex();
- // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
- ++it;
- if (notNullBlock->Dominates(user->GetBlock())) {
- if (bound_type == nullptr) {
- ScopedObjectAccess soa(Thread::Current());
- HInstruction* insert_point = notNullBlock->GetFirstInstruction();
- ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
- handle_cache_.GetObjectClassHandle(), /* is_exact */ false);
- if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
- bound_type = new (graph_->GetArena()) HBoundType(obj);
- bound_type->SetUpperBound(object_rti, /* bound_can_be_null */ false);
- if (obj->GetReferenceTypeInfo().IsValid()) {
- bound_type->SetReferenceTypeInfo(obj->GetReferenceTypeInfo());
- }
- notNullBlock->InsertInstructionBefore(bound_type, insert_point);
- } else {
- // We already have a bound type on the position we would need to insert
- // the new one. The existing bound type should dominate all the users
- // (dchecked) so there's no need to continue.
- break;
- }
- }
- user->ReplaceInput(bound_type, index);
- }
- }
+ ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
+ handle_cache_.GetObjectClassHandle(), /* is_exact */ false);
+
+ BoundTypeIn(obj, notNullBlock, /* start_instruction */ nullptr, object_rti);
}
// Returns true if one of the patterns below has been recognized. If so, the
@@ -378,15 +468,10 @@
HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
- {
- if (!class_rti.IsValid()) {
- // He have loaded an unresolved class. Don't bother bounding the type.
- return;
- }
+ if (!class_rti.IsValid()) {
+ // He have loaded an unresolved class. Don't bother bounding the type.
+ return;
}
- // We only need to bound the type if we have uses in the relevant block.
- // So start with null and create the HBoundType lazily, only if it's needed.
- HBoundType* bound_type = nullptr;
HInstruction* obj = instanceOf->InputAt(0);
if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
@@ -398,33 +483,14 @@
// input.
return;
}
- DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
- const HUseList<HInstruction*>& uses = obj->GetUses();
- for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
- HInstruction* user = it->GetUser();
- size_t index = it->GetIndex();
- // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
- ++it;
- if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
- if (bound_type == nullptr) {
- ScopedObjectAccess soa(Thread::Current());
- HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction();
- if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) {
- bound_type = new (graph_->GetArena()) HBoundType(obj);
- bool is_exact = class_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes();
- bound_type->SetUpperBound(ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), is_exact),
- /* InstanceOf fails for null. */ false);
- instanceOfTrueBlock->InsertInstructionBefore(bound_type, insert_point);
- } else {
- // We already have a bound type on the position we would need to insert
- // the new one. The existing bound type should dominate all the users
- // (dchecked) so there's no need to continue.
- break;
- }
- }
- user->ReplaceInput(bound_type, index);
+
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ if (!class_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes()) {
+ class_rti = ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false);
}
}
+ BoundTypeIn(obj, instanceOfTrueBlock, /* start_instruction */ nullptr, class_rti);
}
void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
@@ -464,6 +530,10 @@
}
}
+void ReferenceTypePropagation::RTPVisitor::VisitDeoptimize(HDeoptimize* instr) {
+ BoundTypeForClassCheck(instr);
+}
+
void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
dex::TypeIndex type_idx,
const DexFile& dex_file,
@@ -515,16 +585,9 @@
ScopedObjectAccess soa(Thread::Current());
ObjPtr<mirror::Class> klass;
- // The field index is unknown only during tests.
- if (info.GetFieldIndex() != kUnknownFieldIndex) {
- ClassLinker* cl = Runtime::Current()->GetClassLinker();
- ArtField* field = cl->GetResolvedField(info.GetFieldIndex(),
- MakeObjPtr(info.GetDexCache().Get()));
- // TODO: There are certain cases where we can't resolve the field.
- // b/21914925 is open to keep track of a repro case for this issue.
- if (field != nullptr) {
- klass = field->GetType<false>();
- }
+ // The field is unknown only during tests.
+ if (info.GetField() != nullptr) {
+ klass = info.GetField()->GetType<false>();
}
SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 559f409..2227872 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -492,7 +492,6 @@
HInstruction** input2) {
HGraph* graph = CreateGraph(allocator);
HBasicBlock* entry = new (allocator) HBasicBlock(graph);
- ScopedNullHandle<mirror::DexCache> dex_cache;
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
@@ -504,13 +503,13 @@
entry->AddSuccessor(block);
HInstruction* test = new (allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimBoolean,
MemberOffset(22),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0);
block->AddInstruction(test);
block->AddInstruction(new (allocator) HIf(test));
@@ -531,22 +530,22 @@
*phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
join->AddPhi(*phi);
*input1 = new (allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimInt,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0);
*input2 = new (allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimInt,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0);
then->AddInstruction(*input1);
else_->AddInstruction(*input2);
@@ -654,7 +653,6 @@
HInstruction** field,
HInstruction** ret) {
HGraph* graph = CreateGraph(allocator);
- ScopedNullHandle<mirror::DexCache> dex_cache;
HBasicBlock* entry = new (allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
@@ -667,13 +665,13 @@
entry->AddSuccessor(block);
*field = new (allocator) HInstanceFieldGet(parameter,
+ nullptr,
Primitive::kPrimInt,
MemberOffset(42),
false,
kUnknownFieldIndex,
kUnknownClassDefIndex,
graph->GetDexFile(),
- dex_cache,
0);
block->AddInstruction(*field);
*ret = new (allocator) HReturn(*field);
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index ab4f9e9..a3fce02 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -5610,7 +5610,7 @@
" 214: ecbd 8a10 vpop {s16-s31}\n",
" 218: e8bd 8de0 ldmia.w sp!, {r5, r6, r7, r8, sl, fp, pc}\n",
" 21c: 4660 mov r0, ip\n",
- " 21e: f8d9 c2b0 ldr.w ip, [r9, #688] ; 0x2b0\n",
+ " 21e: f8d9 c2ac ldr.w ip, [r9, #684] ; 0x2ac\n",
" 222: 47e0 blx ip\n",
nullptr
};
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index ece81e3..21b03eb 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1095,9 +1095,6 @@
compiler_options_->GetNativeDebuggable() ? OatHeader::kTrueValue : OatHeader::kFalseValue);
key_value_store_->Put(OatHeader::kCompilerFilter,
CompilerFilter::NameOfFilter(compiler_options_->GetCompilerFilter()));
- key_value_store_->Put(OatHeader::kHasPatchInfoKey,
- compiler_options_->GetIncludePatchInformation() ? OatHeader::kTrueValue
- : OatHeader::kFalseValue);
}
// Parse the arguments from the command line. In case of an unrecognized option or impossible
diff --git a/runtime/arch/arm/instruction_set_features_arm.cc b/runtime/arch/arm/instruction_set_features_arm.cc
index 181b2ed..6c2c815 100644
--- a/runtime/arch/arm/instruction_set_features_arm.cc
+++ b/runtime/arch/arm/instruction_set_features_arm.cc
@@ -39,80 +39,69 @@
ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromVariant(
const std::string& variant, std::string* error_msg) {
- // Assume all ARM processors are SMP.
- // TODO: set the SMP support based on variant.
- const bool smp = true;
-
// Look for variants that have divide support.
static const char* arm_variants_with_div[] = {
- "cortex-a7", "cortex-a12", "cortex-a15", "cortex-a17", "cortex-a53", "cortex-a57",
- "cortex-a53.a57", "cortex-m3", "cortex-m4", "cortex-r4", "cortex-r5",
- "cyclone", "denver", "krait", "swift" };
+ "cortex-a7",
+ "cortex-a12",
+ "cortex-a15",
+ "cortex-a17",
+ "cortex-a53",
+ "cortex-a53.a57",
+ "cortex-a57",
+ "denver",
+ "krait",
+ };
- bool has_div = FindVariantInArray(arm_variants_with_div, arraysize(arm_variants_with_div),
+ bool has_div = FindVariantInArray(arm_variants_with_div,
+ arraysize(arm_variants_with_div),
variant);
// Look for variants that have LPAE support.
static const char* arm_variants_with_lpae[] = {
- "cortex-a7", "cortex-a15", "krait", "denver", "cortex-a53", "cortex-a57", "cortex-a53.a57"
+ "cortex-a7",
+ "cortex-a12",
+ "cortex-a15",
+ "cortex-a17",
+ "cortex-a53",
+ "cortex-a53.a57",
+ "cortex-a57",
+ "denver",
+ "krait",
};
- bool has_lpae = FindVariantInArray(arm_variants_with_lpae, arraysize(arm_variants_with_lpae),
+ bool has_lpae = FindVariantInArray(arm_variants_with_lpae,
+ arraysize(arm_variants_with_lpae),
variant);
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"
- };
- if (FindVariantInArray(unsupported_arm_variants, arraysize(unsupported_arm_variants),
- variant)) {
- *error_msg = StringPrintf("Attempt to use unsupported ARM variant: %s", variant.c_str());
- return ArmFeaturesUniquePtr();
- }
- // 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[] = {
+ static const char* arm_variants_with_default_features[] = {
+ "cortex-a5",
+ "cortex-a8",
+ "cortex-a9",
+ "cortex-a9-mp",
"default",
- "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"
+ "generic"
};
- if (!FindVariantInArray(arm_variants_without_known_features,
- arraysize(arm_variants_without_known_features),
+ if (!FindVariantInArray(arm_variants_with_default_features,
+ arraysize(arm_variants_with_default_features),
variant)) {
- LOG(WARNING) << "Unknown instruction set features for ARM CPU variant (" << variant
+ *error_msg = StringPrintf("Attempt to use unsupported ARM variant: %s", variant.c_str());
+ return nullptr;
+ } else {
+ // Warn if we use the default features.
+ LOG(WARNING) << "Using default instruction set features for ARM CPU variant (" << variant
<< ") using conservative defaults";
}
}
- return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(smp, has_div, has_lpae));
+ return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, has_lpae));
}
ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
- bool smp = (bitmap & kSmpBitfield) != 0;
bool has_div = (bitmap & kDivBitfield) != 0;
bool has_atomic_ldrd_strd = (bitmap & kAtomicLdrdStrdBitfield) != 0;
- return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(smp, has_div, has_atomic_ldrd_strd));
+ return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, has_atomic_ldrd_strd));
}
ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromCppDefines() {
- const bool smp = true;
#if defined(__ARM_ARCH_EXT_IDIV__)
const bool has_div = true;
#else
@@ -123,13 +112,12 @@
#else
const bool has_lpae = false;
#endif
- return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(smp, has_div, has_lpae));
+ return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, has_lpae));
}
ArmFeaturesUniquePtr 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 smp = false;
bool has_lpae = false;
bool has_div = false;
@@ -151,9 +139,6 @@
if (line.find("lpae") != std::string::npos) {
has_lpae = true;
}
- } else if (line.find("processor") != std::string::npos &&
- line.find(": 1") != std::string::npos) {
- smp = true;
}
}
}
@@ -161,12 +146,10 @@
} else {
LOG(ERROR) << "Failed to open /proc/cpuinfo";
}
- return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(smp, has_div, has_lpae));
+ return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, has_lpae));
}
ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromHwcap() {
- bool smp = sysconf(_SC_NPROCESSORS_CONF) > 1;
-
bool has_div = false;
bool has_lpae = false;
@@ -184,7 +167,7 @@
}
#endif
- return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(smp, has_div, has_lpae));
+ return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, has_lpae));
}
// A signal handler called by a fault for an illegal instruction. We record the fact in r0
@@ -203,8 +186,6 @@
}
ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromAssembly() {
- const bool smp = true;
-
// 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;
@@ -230,7 +211,7 @@
#else
const bool has_lpae = false;
#endif
- return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(smp, has_div, has_lpae));
+ return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, has_lpae));
}
bool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
@@ -238,28 +219,21 @@
return false;
}
const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures();
- return IsSmp() == other_as_arm->IsSmp() &&
- has_div_ == other_as_arm->has_div_ &&
+ return has_div_ == other_as_arm->has_div_ &&
has_atomic_ldrd_strd_ == other_as_arm->has_atomic_ldrd_strd_;
}
uint32_t ArmInstructionSetFeatures::AsBitmap() const {
- return (IsSmp() ? kSmpBitfield : 0) |
- (has_div_ ? kDivBitfield : 0) |
+ return (has_div_ ? kDivBitfield : 0) |
(has_atomic_ldrd_strd_ ? kAtomicLdrdStrdBitfield : 0);
}
std::string ArmInstructionSetFeatures::GetFeatureString() const {
std::string result;
- if (IsSmp()) {
- result += "smp";
- } else {
- result += "-smp";
- }
if (has_div_) {
- result += ",div";
+ result += "div";
} else {
- result += ",-div";
+ result += "-div";
}
if (has_atomic_ldrd_strd_) {
result += ",atomic_ldrd_strd";
@@ -271,7 +245,7 @@
std::unique_ptr<const InstructionSetFeatures>
ArmInstructionSetFeatures::AddFeaturesFromSplitString(
- const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+ const std::vector<std::string>& features, std::string* error_msg) const {
bool has_atomic_ldrd_strd = has_atomic_ldrd_strd_;
bool has_div = has_div_;
for (auto i = features.begin(); i != features.end(); i++) {
@@ -290,7 +264,7 @@
}
}
return std::unique_ptr<const InstructionSetFeatures>(
- new ArmInstructionSetFeatures(smp, has_div, has_atomic_ldrd_strd));
+ new ArmInstructionSetFeatures(has_div, has_atomic_ldrd_strd));
}
} // namespace art
diff --git a/runtime/arch/arm/instruction_set_features_arm.h b/runtime/arch/arm/instruction_set_features_arm.h
index 204d1d7..11f8bf0 100644
--- a/runtime/arch/arm/instruction_set_features_arm.h
+++ b/runtime/arch/arm/instruction_set_features_arm.h
@@ -74,20 +74,19 @@
protected:
// Parse a vector of the form "div", "lpae" adding these to a new ArmInstructionSetFeatures.
std::unique_ptr<const InstructionSetFeatures>
- AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+ AddFeaturesFromSplitString(const std::vector<std::string>& features,
std::string* error_msg) const OVERRIDE;
private:
- ArmInstructionSetFeatures(bool smp, bool has_div, bool has_atomic_ldrd_strd)
- : InstructionSetFeatures(smp),
+ ArmInstructionSetFeatures(bool has_div, bool has_atomic_ldrd_strd)
+ : InstructionSetFeatures(),
has_div_(has_div), has_atomic_ldrd_strd_(has_atomic_ldrd_strd) {
}
// Bitmap positions for encoding features as a bitmap.
enum {
- kSmpBitfield = 1,
- kDivBitfield = 2,
- kAtomicLdrdStrdBitfield = 4,
+ kDivBitfield = 1 << 0,
+ kAtomicLdrdStrdBitfield = 1 << 1,
};
const bool has_div_;
diff --git a/runtime/arch/arm/instruction_set_features_arm_test.cc b/runtime/arch/arm/instruction_set_features_arm_test.cc
index 44b1640..697ca90 100644
--- a/runtime/arch/arm/instruction_set_features_arm_test.cc
+++ b/runtime/arch/arm/instruction_set_features_arm_test.cc
@@ -31,8 +31,8 @@
EXPECT_TRUE(krait_features->Equals(krait_features.get()));
EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
- EXPECT_STREQ("smp,div,atomic_ldrd_strd", krait_features->GetFeatureString().c_str());
- EXPECT_EQ(krait_features->AsBitmap(), 7U);
+ EXPECT_STREQ("div,atomic_ldrd_strd", 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(
@@ -44,21 +44,21 @@
EXPECT_TRUE(krait_features->Equals(denver_features.get()));
EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
- EXPECT_STREQ("smp,div,atomic_ldrd_strd", denver_features->GetFeatureString().c_str());
- EXPECT_EQ(denver_features->AsBitmap(), 7U);
+ EXPECT_STREQ("div,atomic_ldrd_strd", 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;
+ std::unique_ptr<const InstructionSetFeatures> generic_features(
+ InstructionSetFeatures::FromVariant(kArm, "generic", &error_msg));
+ ASSERT_TRUE(generic_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()->HasAtomicLdrdAndStrd());
- EXPECT_STREQ("smp,-div,-atomic_ldrd_strd", arm7_features->GetFeatureString().c_str());
- EXPECT_EQ(arm7_features->AsBitmap(), 1U);
+ EXPECT_TRUE(generic_features->Equals(generic_features.get()));
+ EXPECT_FALSE(generic_features->Equals(krait_features.get()));
+ EXPECT_FALSE(krait_features->Equals(generic_features.get()));
+ EXPECT_FALSE(generic_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_FALSE(generic_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+ EXPECT_STREQ("-div,-atomic_ldrd_strd", generic_features->GetFeatureString().c_str());
+ EXPECT_EQ(generic_features->AsBitmap(), 0U);
// ARM6 is not a supported architecture variant.
std::unique_ptr<const InstructionSetFeatures> arm6_features(
@@ -70,7 +70,7 @@
TEST(ArmInstructionSetFeaturesTest, ArmAddFeaturesFromString) {
std::string error_msg;
std::unique_ptr<const InstructionSetFeatures> base_features(
- InstructionSetFeatures::FromVariant(kArm, "arm7", &error_msg));
+ InstructionSetFeatures::FromVariant(kArm, "generic", &error_msg));
ASSERT_TRUE(base_features.get() != nullptr) << error_msg;
// Build features for a 32-bit ARM with LPAE and div processor.
@@ -82,8 +82,8 @@
EXPECT_TRUE(krait_features->Equals(krait_features.get()));
EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
- EXPECT_STREQ("smp,div,atomic_ldrd_strd", krait_features->GetFeatureString().c_str());
- EXPECT_EQ(krait_features->AsBitmap(), 7U);
+ EXPECT_STREQ("div,atomic_ldrd_strd", 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(
@@ -95,21 +95,21 @@
EXPECT_TRUE(krait_features->Equals(denver_features.get()));
EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
- EXPECT_STREQ("smp,div,atomic_ldrd_strd", denver_features->GetFeatureString().c_str());
- EXPECT_EQ(denver_features->AsBitmap(), 7U);
+ EXPECT_STREQ("div,atomic_ldrd_strd", 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(
+ std::unique_ptr<const InstructionSetFeatures> generic_features(
base_features->AddFeaturesFromString("default", &error_msg));
- ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
+ ASSERT_TRUE(generic_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()->HasAtomicLdrdAndStrd());
- EXPECT_STREQ("smp,-div,-atomic_ldrd_strd", arm7_features->GetFeatureString().c_str());
- EXPECT_EQ(arm7_features->AsBitmap(), 1U);
+ EXPECT_TRUE(generic_features->Equals(generic_features.get()));
+ EXPECT_FALSE(generic_features->Equals(krait_features.get()));
+ EXPECT_FALSE(krait_features->Equals(generic_features.get()));
+ EXPECT_FALSE(generic_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_FALSE(generic_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+ EXPECT_STREQ("-div,-atomic_ldrd_strd", generic_features->GetFeatureString().c_str());
+ EXPECT_EQ(generic_features->AsBitmap(), 0U);
}
} // namespace art
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index a71ab4b..4d4ebdc 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1124,28 +1124,23 @@
// Generate the allocation entrypoints for each allocator.
GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc).
-ENTRY art_quick_alloc_object_rosalloc
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_RESOLVED_OBJECT(_rosalloc, RosAlloc).
+ENTRY art_quick_alloc_object_resolved_rosalloc
// Fast path rosalloc allocation.
- // r0: type_idx/return value, r1: ArtMethod*, r9: Thread::Current
- // r2, r3, r12: free.
- ldr r2, [r1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_32] // Load dex cache resolved types array
- // Load the class (r2)
- ldr r2, [r2, r0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
- cbz r2, .Lart_quick_alloc_object_rosalloc_slow_path // Check null class
-
+ // r0: type/return value, r9: Thread::Current
+ // r1, r2, r3, r12: free.
ldr r3, [r9, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET] // Check if the thread local
// allocation stack has room.
// TODO: consider using ldrd.
ldr r12, [r9, #THREAD_LOCAL_ALLOC_STACK_END_OFFSET]
cmp r3, r12
- bhs .Lart_quick_alloc_object_rosalloc_slow_path
+ bhs .Lart_quick_alloc_object_resolved_rosalloc_slow_path
- ldr r3, [r2, #MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET] // Load the object size (r3)
+ ldr r3, [r0, #MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET] // Load the object size (r3)
cmp r3, #ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE // Check if the size is for a thread
// local allocation. Also does the
// initialized and finalizable checks.
- bhs .Lart_quick_alloc_object_rosalloc_slow_path
+ bhs .Lart_quick_alloc_object_resolved_rosalloc_slow_path
// Compute the rosalloc bracket index
// from the size. Since the size is
// already aligned we can combine the
@@ -1159,7 +1154,7 @@
// Load the free list head (r3). This
// will be the return val.
ldr r3, [r12, #(ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)]
- cbz r3, .Lart_quick_alloc_object_rosalloc_slow_path
+ cbz r3, .Lart_quick_alloc_object_resolved_rosalloc_slow_path
// "Point of no slow path". Won't go to the slow path from here on. OK to clobber r0 and r1.
ldr r1, [r3, #ROSALLOC_SLOT_NEXT_OFFSET] // Load the next pointer of the head
// and update the list head with the
@@ -1172,8 +1167,8 @@
#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
#error "Class pointer needs to overwrite next pointer."
#endif
- POISON_HEAP_REF r2
- str r2, [r3, #MIRROR_OBJECT_CLASS_OFFSET]
+ POISON_HEAP_REF r0
+ str r0, [r3, #MIRROR_OBJECT_CLASS_OFFSET]
// Fence. This is "ish" not "ishst" so
// that it also ensures ordering of
// the class status load with respect
@@ -1204,20 +1199,20 @@
mov r0, r3 // Set the return value and return.
bx lr
-.Lart_quick_alloc_object_rosalloc_slow_path:
+.Lart_quick_alloc_object_resolved_rosalloc_slow_path:
SETUP_SAVE_REFS_ONLY_FRAME r2 @ save callee saves in case of GC
- mov r2, r9 @ pass Thread::Current
- bl artAllocObjectFromCodeRosAlloc @ (uint32_t type_idx, Method* method, Thread*)
+ mov r1, r9 @ pass Thread::Current
+ bl artAllocObjectFromCodeResolvedRosAlloc @ (mirror::Class* cls, Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-END art_quick_alloc_object_rosalloc
+END art_quick_alloc_object_resolved_rosalloc
-// The common fast path code for art_quick_alloc_object_tlab and art_quick_alloc_object_region_tlab.
+// The common fast path code for art_quick_alloc_object_resolved_tlab
+// and art_quick_alloc_object_resolved_region_tlab.
//
-// r0: type_idx/return value, r1: ArtMethod*, r2: class, r9: Thread::Current, r3, r12: free.
-// Need to preserve r0 and r1 to the slow path.
-.macro ALLOC_OBJECT_TLAB_FAST_PATH slowPathLabel
- cbz r2, \slowPathLabel // Check null class
+// r0: type r9: Thread::Current, r1, r2, r3, r12: free.
+// Need to preserve r0 to the slow path.
+.macro ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH slowPathLabel
// Load thread_local_pos (r12) and
// thread_local_end (r3) with ldrd.
// Check constraints for ldrd.
@@ -1232,14 +1227,14 @@
// "Point of no slow path". Won't go to the slow path from here on. OK to clobber r0 and r1.
// Reload old thread_local_pos (r0)
// for the return value.
- ldr r0, [r9, #THREAD_LOCAL_POS_OFFSET]
- add r1, r0, r3
+ ldr r2, [r9, #THREAD_LOCAL_POS_OFFSET]
+ add r1, r2, r3
str r1, [r9, #THREAD_LOCAL_POS_OFFSET] // Store new thread_local_pos.
ldr r1, [r9, #THREAD_LOCAL_OBJECTS_OFFSET] // Increment thread_local_objects.
add r1, r1, #1
str r1, [r9, #THREAD_LOCAL_OBJECTS_OFFSET]
- POISON_HEAP_REF r2
- str r2, [r0, #MIRROR_OBJECT_CLASS_OFFSET] // Store the class pointer.
+ POISON_HEAP_REF r0
+ str r0, [r2, #MIRROR_OBJECT_CLASS_OFFSET] // Store the class pointer.
// Fence. This is "ish" not "ishst" so
// that the code after this allocation
// site will see the right values in
@@ -1247,71 +1242,46 @@
// Alternatively we could use "ishst"
// if we use load-acquire for the
// object size load.)
+ mov r0, r2
dmb ish
bx lr
.endm
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB).
-ENTRY art_quick_alloc_object_tlab
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_RESOLVED_OBJECT(_tlab, TLAB).
+ENTRY art_quick_alloc_object_resolved_tlab
// Fast path tlab allocation.
- // r0: type_idx/return value, r1: ArtMethod*, r9: Thread::Current
- // r2, r3, r12: free.
+ // r0: type, r9: Thread::Current
+ // r1, r2, r3, r12: free.
#if defined(USE_READ_BARRIER)
mvn r0, #0 // Read barrier not supported here.
bx lr // Return -1.
#endif
- ldr r2, [r1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_32] // Load dex cache resolved types array
- // Load the class (r2)
- ldr r2, [r2, r0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
- ALLOC_OBJECT_TLAB_FAST_PATH .Lart_quick_alloc_object_tlab_slow_path
-.Lart_quick_alloc_object_tlab_slow_path:
+ ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lart_quick_alloc_object_resolved_tlab_slow_path
+.Lart_quick_alloc_object_resolved_tlab_slow_path:
SETUP_SAVE_REFS_ONLY_FRAME r2 // Save callee saves in case of GC.
- mov r2, r9 // Pass Thread::Current.
- bl artAllocObjectFromCodeTLAB // (uint32_t type_idx, Method* method, Thread*)
+ mov r1, r9 // Pass Thread::Current.
+ bl artAllocObjectFromCodeResolvedTLAB // (mirror::Class* klass, Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-END art_quick_alloc_object_tlab
+END art_quick_alloc_object_resolved_tlab
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB)
-ENTRY art_quick_alloc_object_region_tlab
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
+ENTRY art_quick_alloc_object_resolved_region_tlab
// Fast path tlab allocation.
- // r0: type_idx/return value, r1: ArtMethod*, r9: Thread::Current, r2, r3, r12: free.
+ // r0: type, r9: Thread::Current, r1, r2, r3, r12: free.
#if !defined(USE_READ_BARRIER)
eor r0, r0, r0 // Read barrier must be enabled here.
sub r0, r0, #1 // Return -1.
bx lr
#endif
- ldr r2, [r1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_32] // Load dex cache resolved types array
- // Load the class (r2)
- ldr r2, [r2, r0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
- // Read barrier for class load.
- ldr r3, [r9, #THREAD_IS_GC_MARKING_OFFSET]
- cbnz r3, .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_marking
-.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit:
- ALLOC_OBJECT_TLAB_FAST_PATH .Lart_quick_alloc_object_region_tlab_slow_path
-.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_marking:
- cbz r2, .Lart_quick_alloc_object_region_tlab_slow_path // Null check for loading lock word.
- // Check lock word for mark bit, if marked do the allocation.
- ldr r3, [r2, MIRROR_OBJECT_LOCK_WORD_OFFSET]
- ands r3, #LOCK_WORD_MARK_BIT_MASK_SHIFTED
- bne .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit
-.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path:
- // The read barrier slow path. Mark
- // the class.
- push {r0, r1, r3, lr} // Save registers. r3 is pushed only
- // to align sp by 16 bytes.
- mov r0, r2 // Pass the class as the first param.
- bl artReadBarrierMark
- mov r2, r0 // Get the (marked) class back.
- pop {r0, r1, r3, lr}
- b .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit
-.Lart_quick_alloc_object_region_tlab_slow_path:
+ ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lart_quick_alloc_object_resolved_region_tlab_slow_path
+.Lart_quick_alloc_object_resolved_region_tlab_slow_path:
SETUP_SAVE_REFS_ONLY_FRAME r2 // Save callee saves in case of GC.
- mov r2, r9 // Pass Thread::Current.
- bl artAllocObjectFromCodeRegionTLAB // (uint32_t type_idx, Method* method, Thread*)
+ mov r1, r9 // Pass Thread::Current.
+ bl artAllocObjectFromCodeResolvedRegionTLAB // (mirror::Class* klass, Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-END art_quick_alloc_object_region_tlab
+END art_quick_alloc_object_resolved_region_tlab
/*
* Called by managed code when the value in rSUSPEND has been decremented to 0.
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.cc b/runtime/arch/arm64/instruction_set_features_arm64.cc
index 52d8b3e..c598743 100644
--- a/runtime/arch/arm64/instruction_set_features_arm64.cc
+++ b/runtime/arch/arm64/instruction_set_features_arm64.cc
@@ -31,8 +31,6 @@
Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromVariant(
const std::string& variant, std::string* error_msg) {
- const bool smp = true; // Conservative default.
-
// Look for variants that need a fix for a53 erratum 835769.
static const char* arm64_variants_with_a53_835769_bug[] = {
"default", "generic", "cortex-a53" // Pessimistically assume all generic ARM64s are A53s.
@@ -58,50 +56,27 @@
bool needs_a53_843419_fix = needs_a53_835769_fix;
return Arm64FeaturesUniquePtr(
- new Arm64InstructionSetFeatures(smp, needs_a53_835769_fix, needs_a53_843419_fix));
+ new Arm64InstructionSetFeatures(needs_a53_835769_fix, needs_a53_843419_fix));
}
Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
- bool smp = (bitmap & kSmpBitfield) != 0;
bool is_a53 = (bitmap & kA53Bitfield) != 0;
- return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(smp, is_a53, is_a53));
+ return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(is_a53, is_a53));
}
Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromCppDefines() {
- const bool smp = true;
const bool is_a53 = true; // Pessimistically assume all ARM64s are A53s.
- return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(smp, is_a53, is_a53));
+ return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(is_a53, is_a53));
}
Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::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 smp = false;
const bool is_a53 = true; // Conservative default.
-
- 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("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
- smp = true;
- }
- }
- }
- in.close();
- } else {
- LOG(ERROR) << "Failed to open /proc/cpuinfo";
- }
- return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(smp, is_a53, is_a53));
+ return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(is_a53, is_a53));
}
Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromHwcap() {
- bool smp = sysconf(_SC_NPROCESSORS_CONF) > 1;
const bool is_a53 = true; // Pessimistically assume all ARM64s are A53s.
- return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(smp, is_a53, is_a53));
+ return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(is_a53, is_a53));
}
Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromAssembly() {
@@ -113,32 +88,28 @@
if (kArm64 != other->GetInstructionSet()) {
return false;
}
- const Arm64InstructionSetFeatures* other_as_arm = other->AsArm64InstructionSetFeatures();
- return fix_cortex_a53_835769_ == other_as_arm->fix_cortex_a53_835769_;
+ const Arm64InstructionSetFeatures* other_as_arm64 = other->AsArm64InstructionSetFeatures();
+ return fix_cortex_a53_835769_ == other_as_arm64->fix_cortex_a53_835769_ &&
+ fix_cortex_a53_843419_ == other_as_arm64->fix_cortex_a53_843419_;
}
uint32_t Arm64InstructionSetFeatures::AsBitmap() const {
- return (IsSmp() ? kSmpBitfield : 0) | (fix_cortex_a53_835769_ ? kA53Bitfield : 0);
+ return (fix_cortex_a53_835769_ ? kA53Bitfield : 0);
}
std::string Arm64InstructionSetFeatures::GetFeatureString() const {
std::string result;
- if (IsSmp()) {
- result += "smp";
- } else {
- result += "-smp";
- }
if (fix_cortex_a53_835769_) {
- result += ",a53";
+ result += "a53";
} else {
- result += ",-a53";
+ result += "-a53";
}
return result;
}
std::unique_ptr<const InstructionSetFeatures>
Arm64InstructionSetFeatures::AddFeaturesFromSplitString(
- const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+ const std::vector<std::string>& features, std::string* error_msg) const {
bool is_a53 = fix_cortex_a53_835769_;
for (auto i = features.begin(); i != features.end(); i++) {
std::string feature = android::base::Trim(*i);
@@ -152,7 +123,7 @@
}
}
return std::unique_ptr<const InstructionSetFeatures>(
- new Arm64InstructionSetFeatures(smp, is_a53, is_a53));
+ new Arm64InstructionSetFeatures(is_a53, is_a53));
}
} // namespace art
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.h b/runtime/arch/arm64/instruction_set_features_arm64.h
index e51aa1c..4243d32 100644
--- a/runtime/arch/arm64/instruction_set_features_arm64.h
+++ b/runtime/arch/arm64/instruction_set_features_arm64.h
@@ -73,20 +73,19 @@
protected:
// Parse a vector of the form "a53" adding these to a new ArmInstructionSetFeatures.
std::unique_ptr<const InstructionSetFeatures>
- AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+ AddFeaturesFromSplitString(const std::vector<std::string>& features,
std::string* error_msg) const OVERRIDE;
private:
- Arm64InstructionSetFeatures(bool smp, bool needs_a53_835769_fix, bool needs_a53_843419_fix)
- : InstructionSetFeatures(smp),
+ Arm64InstructionSetFeatures(bool needs_a53_835769_fix, bool needs_a53_843419_fix)
+ : InstructionSetFeatures(),
fix_cortex_a53_835769_(needs_a53_835769_fix),
fix_cortex_a53_843419_(needs_a53_843419_fix) {
}
// Bitmap positions for encoding features as a bitmap.
enum {
- kSmpBitfield = 1,
- kA53Bitfield = 2,
+ kA53Bitfield = 1 << 0,
};
const bool fix_cortex_a53_835769_;
diff --git a/runtime/arch/arm64/instruction_set_features_arm64_test.cc b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
index 027e59c..cefa499 100644
--- a/runtime/arch/arm64/instruction_set_features_arm64_test.cc
+++ b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
@@ -28,8 +28,8 @@
ASSERT_TRUE(arm64_features.get() != nullptr) << error_msg;
EXPECT_EQ(arm64_features->GetInstructionSet(), kArm64);
EXPECT_TRUE(arm64_features->Equals(arm64_features.get()));
- EXPECT_STREQ("smp,a53", arm64_features->GetFeatureString().c_str());
- EXPECT_EQ(arm64_features->AsBitmap(), 3U);
+ EXPECT_STREQ("a53", arm64_features->GetFeatureString().c_str());
+ EXPECT_EQ(arm64_features->AsBitmap(), 1U);
}
} // namespace art
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index b88515f..8b1e038 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1669,7 +1669,6 @@
// Generate the allocation entrypoints for each allocator.
GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_REGION_TLAB_ALLOCATORS
// Comment out allocators that have arm64 specific asm.
-// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB) implemented in asm
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
@@ -1682,27 +1681,23 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc).
-ENTRY art_quick_alloc_object_rosalloc
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc).
+ENTRY art_quick_alloc_object_resolved_rosalloc
// Fast path rosalloc allocation.
- // x0: type_idx/return value, x1: ArtMethod*, xSELF(x19): Thread::Current
- // x2-x7: free.
- ldr x2, [x1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_64] // Load dex cache resolved types array
- // Load the class (x2)
- ldr w2, [x2, x0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
- cbz x2, .Lart_quick_alloc_object_rosalloc_slow_path // Check null class
+ // x0: type, xSELF(x19): Thread::Current
+ // x1-x7: free.
ldr x3, [xSELF, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET] // Check if the thread local
// allocation stack has room.
// ldp won't work due to large offset.
ldr x4, [xSELF, #THREAD_LOCAL_ALLOC_STACK_END_OFFSET]
cmp x3, x4
- bhs .Lart_quick_alloc_object_rosalloc_slow_path
- ldr w3, [x2, #MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET] // Load the object size (x3)
+ bhs .Lart_quick_alloc_object_resolved_rosalloc_slow_path
+ ldr w3, [x0, #MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET] // Load the object size (x3)
cmp x3, #ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE // Check if the size is for a thread
// local allocation. Also does the
// finalizable and initialization
// checks.
- bhs .Lart_quick_alloc_object_rosalloc_slow_path
+ bhs .Lart_quick_alloc_object_resolved_rosalloc_slow_path
// Compute the rosalloc bracket index
// from the size. Since the size is
// already aligned we can combine the
@@ -1715,7 +1710,7 @@
// Load the free list head (x3). This
// will be the return val.
ldr x3, [x4, #(ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)]
- cbz x3, .Lart_quick_alloc_object_rosalloc_slow_path
+ cbz x3, .Lart_quick_alloc_object_resolved_rosalloc_slow_path
// "Point of no slow path". Won't go to the slow path from here on. OK to clobber x0 and x1.
ldr x1, [x3, #ROSALLOC_SLOT_NEXT_OFFSET] // Load the next pointer of the head
// and update the list head with the
@@ -1728,8 +1723,8 @@
#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
#error "Class pointer needs to overwrite next pointer."
#endif
- POISON_HEAP_REF w2
- str w2, [x3, #MIRROR_OBJECT_CLASS_OFFSET]
+ POISON_HEAP_REF w0
+ str w0, [x3, #MIRROR_OBJECT_CLASS_OFFSET]
// Fence. This is "ish" not "ishst" so
// that it also ensures ordering of
// the object size load with respect
@@ -1759,13 +1754,13 @@
mov x0, x3 // Set the return value and return.
ret
-.Lart_quick_alloc_object_rosalloc_slow_path:
- SETUP_SAVE_REFS_ONLY_FRAME // save callee saves in case of GC
- mov x2, xSELF // pass Thread::Current
- bl artAllocObjectFromCodeRosAlloc // (uint32_t type_idx, Method* method, Thread*)
+.Lart_quick_alloc_object_resolved_rosalloc_slow_path:
+ SETUP_SAVE_REFS_ONLY_FRAME // save callee saves in case of GC
+ mov x1, xSELF // pass Thread::Current
+ bl artAllocObjectFromCodeResolvedRosAlloc // (mirror::Class* klass, Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-END art_quick_alloc_object_rosalloc
+END art_quick_alloc_object_resolved_rosalloc
// The common fast path code for art_quick_alloc_array_region_tlab.
@@ -1834,16 +1829,6 @@
ret
.endm
-// The common fast path code for art_quick_alloc_object_tlab and art_quick_alloc_object_region_tlab.
-//
-// x0: type_idx/return value, x1: ArtMethod*, x2: Class*, xSELF(x19): Thread::Current
-// x3-x7: free.
-// Need to preserve x0 and x1 to the slow path.
-.macro ALLOC_OBJECT_TLAB_FAST_PATH slowPathLabel
- cbz x2, \slowPathLabel // Check null class
- ALLOC_OBJECT_TLAB_FAST_PATH_RESOLVED \slowPathLabel
-.endm
-
// TODO: delete ALLOC_OBJECT_TLAB_FAST_PATH_RESOLVED since it is the same as
// ALLOC_OBJECT_TLAB_FAST_PATH_INITIALIZED.
.macro ALLOC_OBJECT_TLAB_FAST_PATH_RESOLVED slowPathLabel
@@ -1853,20 +1838,18 @@
.macro ALLOC_OBJECT_TLAB_FAST_PATH_INITIALIZED slowPathLabel
ldr x4, [xSELF, #THREAD_LOCAL_POS_OFFSET]
ldr x5, [xSELF, #THREAD_LOCAL_END_OFFSET]
- ldr w7, [x2, #MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET] // Load the object size (x7).
+ ldr w7, [x0, #MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET] // Load the object size (x7).
add x6, x4, x7 // Add object size to tlab pos.
cmp x6, x5 // Check if it fits, overflow works
// since the tlab pos and end are 32
// bit values.
bhi \slowPathLabel
- // "Point of no slow path". Won't go to the slow path from here on. OK to clobber x0 and x1.
- mov x0, x4
str x6, [xSELF, #THREAD_LOCAL_POS_OFFSET] // Store new thread_local_pos.
ldr x5, [xSELF, #THREAD_LOCAL_OBJECTS_OFFSET] // Increment thread_local_objects.
add x5, x5, #1
str x5, [xSELF, #THREAD_LOCAL_OBJECTS_OFFSET]
- POISON_HEAP_REF w2
- str w2, [x0, #MIRROR_OBJECT_CLASS_OFFSET] // Store the class pointer.
+ POISON_HEAP_REF w0
+ str w0, [x4, #MIRROR_OBJECT_CLASS_OFFSET] // Store the class pointer.
// Fence. This is "ish" not "ishst" so
// that the code after this allocation
// site will see the right values in
@@ -1874,91 +1857,52 @@
// Alternatively we could use "ishst"
// if we use load-acquire for the
// object size load.)
+ mov x0, x4
dmb ish
ret
.endm
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB).
-ENTRY art_quick_alloc_object_tlab
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB).
+ENTRY art_quick_alloc_object_resolved_tlab
// Fast path tlab allocation.
- // x0: type_idx/return value, x1: ArtMethod*, xSELF(x19): Thread::Current
- // x2-x7: free.
+ // x0: type, xSELF(x19): Thread::Current
+ // x1-x7: free.
#if defined(USE_READ_BARRIER)
mvn x0, xzr // Read barrier not supported here.
ret // Return -1.
#endif
- ldr x2, [x1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_64] // Load dex cache resolved types array
- // Load the class (x2)
- ldr w2, [x2, x0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
- ALLOC_OBJECT_TLAB_FAST_PATH .Lart_quick_alloc_object_tlab_slow_path
-.Lart_quick_alloc_object_tlab_slow_path:
- SETUP_SAVE_REFS_ONLY_FRAME // Save callee saves in case of GC.
- mov x2, xSELF // Pass Thread::Current.
- bl artAllocObjectFromCodeTLAB // (uint32_t type_idx, Method* method, Thread*)
+ ALLOC_OBJECT_TLAB_FAST_PATH_RESOLVED .Lart_quick_alloc_object_resolved_tlab_slow_path
+.Lart_quick_alloc_object_resolved_tlab_slow_path:
+ SETUP_SAVE_REFS_ONLY_FRAME // Save callee saves in case of GC.
+ mov x1, xSELF // Pass Thread::Current.
+ bl artAllocObjectFromCodeResolvedTLAB // (mirror::Class*, Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-END art_quick_alloc_object_tlab
+END art_quick_alloc_object_resolved_tlab
// The common code for art_quick_alloc_object_*region_tlab
-.macro GENERATE_ALLOC_OBJECT_REGION_TLAB name, entrypoint, fast_path, is_resolved, read_barrier
+.macro GENERATE_ALLOC_OBJECT_RESOLVED_REGION_TLAB name, entrypoint, fast_path
ENTRY \name
// Fast path region tlab allocation.
- // x0: type_idx/resolved class/return value, x1: ArtMethod*, xSELF(x19): Thread::Current
- // If is_resolved is 1 then x0 is the resolved type, otherwise it is the index.
- // x2-x7: free.
+ // x0: type, xSELF(x19): Thread::Current
+ // x1-x7: free.
#if !defined(USE_READ_BARRIER)
mvn x0, xzr // Read barrier must be enabled here.
ret // Return -1.
#endif
-.if \is_resolved
- mov x2, x0 // class is actually stored in x0 already
-.else
- ldr x2, [x1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_64] // Load dex cache resolved types array
- // Load the class (x2)
- ldr w2, [x2, x0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
- // If the class is null, go slow path. The check is required to read the lock word.
- cbz w2, .Lslow_path\name
-.endif
-.if \read_barrier
- // Most common case: GC is not marking.
- ldr w3, [xSELF, #THREAD_IS_GC_MARKING_OFFSET]
- cbnz x3, .Lmarking\name
-.endif
.Ldo_allocation\name:
\fast_path .Lslow_path\name
-.Lmarking\name:
-.if \read_barrier
- // GC is marking, check the lock word of the class for the mark bit.
- // Class is not null, check mark bit in lock word.
- ldr w3, [x2, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
- // If the bit is not zero, do the allocation.
- tbnz w3, #LOCK_WORD_MARK_BIT_SHIFT, .Ldo_allocation\name
- // The read barrier slow path. Mark
- // the class.
- SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 32 // Save registers (x0, x1, lr).
- SAVE_REG xLR, 24 // Align sp by 16 bytes.
- mov x0, x2 // Pass the class as the first param.
- bl artReadBarrierMark
- mov x2, x0 // Get the (marked) class back.
- RESTORE_REG xLR, 24
- RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 32 // Restore registers.
- b .Ldo_allocation\name
-.endif
.Lslow_path\name:
SETUP_SAVE_REFS_ONLY_FRAME // Save callee saves in case of GC.
- mov x2, xSELF // Pass Thread::Current.
- bl \entrypoint // (uint32_t type_idx, Method* method, Thread*)
+ mov x1, xSELF // Pass Thread::Current.
+ bl \entrypoint // (mirror::Class*, Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
END \name
.endm
-// Use ALLOC_OBJECT_TLAB_FAST_PATH_RESOLVED since the null check is already done in GENERATE_ALLOC_OBJECT_TLAB.
-GENERATE_ALLOC_OBJECT_REGION_TLAB art_quick_alloc_object_region_tlab, artAllocObjectFromCodeRegionTLAB, ALLOC_OBJECT_TLAB_FAST_PATH_RESOLVED, 0, 1
-// No read barrier for the resolved or initialized cases since the caller is responsible for the
-// read barrier due to the to-space invariant.
-GENERATE_ALLOC_OBJECT_REGION_TLAB art_quick_alloc_object_resolved_region_tlab, artAllocObjectFromCodeResolvedRegionTLAB, ALLOC_OBJECT_TLAB_FAST_PATH_RESOLVED, 1, 0
-GENERATE_ALLOC_OBJECT_REGION_TLAB art_quick_alloc_object_initialized_region_tlab, artAllocObjectFromCodeInitializedRegionTLAB, ALLOC_OBJECT_TLAB_FAST_PATH_INITIALIZED, 1, 0
+GENERATE_ALLOC_OBJECT_RESOLVED_REGION_TLAB art_quick_alloc_object_resolved_region_tlab, artAllocObjectFromCodeResolvedRegionTLAB, ALLOC_OBJECT_TLAB_FAST_PATH_RESOLVED
+GENERATE_ALLOC_OBJECT_RESOLVED_REGION_TLAB art_quick_alloc_object_initialized_region_tlab, artAllocObjectFromCodeInitializedRegionTLAB, ALLOC_OBJECT_TLAB_FAST_PATH_INITIALIZED
// TODO: We could use this macro for the normal tlab allocator too.
diff --git a/runtime/arch/instruction_set_features.cc b/runtime/arch/instruction_set_features.cc
index db004e7..00d22c4 100644
--- a/runtime/arch/instruction_set_features.cc
+++ b/runtime/arch/instruction_set_features.cc
@@ -218,7 +218,6 @@
}
std::vector<std::string> features;
Split(feature_list, ',', &features);
- bool smp = smp_;
bool use_default = false; // Have we seen the 'default' feature?
bool first = false; // Is this first feature?
for (auto it = features.begin(); it != features.end();) {
@@ -236,14 +235,7 @@
*error_msg = "Unexpected instruction set features before 'default'";
return std::unique_ptr<const InstructionSetFeatures>();
}
- } else if (feature == "smp") {
- smp = true;
- erase = true;
- } else if (feature == "-smp") {
- smp = false;
- erase = true;
}
- // Erase the smp feature once processed.
if (!erase) {
++it;
} else {
@@ -252,11 +244,11 @@
first = true;
}
// Expectation: "default" is standalone, no other flags. But an empty features vector after
- // processing can also come along if the handled flags (at the moment only smp) are the only
- // ones in the list. So logically, we check "default -> features.empty."
+ // processing can also come along if the handled flags are the only ones in the list. So
+ // logically, we check "default -> features.empty."
DCHECK(!use_default || features.empty());
- return AddFeaturesFromSplitString(smp, features, error_msg);
+ return AddFeaturesFromSplitString(features, error_msg);
}
const ArmInstructionSetFeatures* InstructionSetFeatures::AsArmInstructionSetFeatures() const {
diff --git a/runtime/arch/instruction_set_features.h b/runtime/arch/instruction_set_features.h
index d84bc02..b6c5c71 100644
--- a/runtime/arch/instruction_set_features.h
+++ b/runtime/arch/instruction_set_features.h
@@ -76,11 +76,6 @@
// Return a string of the form "div,lpae" or "none".
virtual std::string GetFeatureString() const = 0;
- // Does the instruction set variant require instructions for correctness with SMP?
- bool IsSmp() const {
- return smp_;
- }
-
// Down cast this ArmInstructionFeatures.
const ArmInstructionSetFeatures* AsArmInstructionSetFeatures() const;
@@ -102,7 +97,7 @@
virtual ~InstructionSetFeatures() {}
protected:
- explicit InstructionSetFeatures(bool smp) : smp_(smp) {}
+ InstructionSetFeatures() {}
// Returns true if variant appears in the array variants.
static bool FindVariantInArray(const char* const variants[], size_t num_variants,
@@ -110,12 +105,10 @@
// Add architecture specific features in sub-classes.
virtual std::unique_ptr<const InstructionSetFeatures>
- AddFeaturesFromSplitString(bool smp, const std::vector<std::string>& features,
+ AddFeaturesFromSplitString(const std::vector<std::string>& features,
std::string* error_msg) const = 0;
private:
- const bool smp_;
-
DISALLOW_COPY_AND_ASSIGN(InstructionSetFeatures);
};
std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs);
diff --git a/runtime/arch/mips/instruction_set_features_mips.cc b/runtime/arch/mips/instruction_set_features_mips.cc
index 5b50573..3c5afc2 100644
--- a/runtime/arch/mips/instruction_set_features_mips.cc
+++ b/runtime/arch/mips/instruction_set_features_mips.cc
@@ -71,8 +71,6 @@
MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromVariant(
const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED) {
- bool smp = true; // Conservative default.
-
// Override defaults based on compiler flags.
// This is needed when running ART test where the variant is not defined.
bool fpu_32bit;
@@ -90,7 +88,7 @@
fpu_32bit = (variant[kPrefixLength] < '5');
mips_isa_gte2 = (variant[kPrefixLength] >= '2');
} else if (variant == "default") {
- // Default variant is: smp = true, has FPU, is gte2. This is the traditional setting.
+ // Default variant has FPU, is gte2. This is the traditional setting.
//
// Note, we get FPU bitness and R6-ness from the build (using cpp defines, see above)
// and don't override them because many things depend on the "default" variant being
@@ -102,58 +100,32 @@
LOG(WARNING) << "Unexpected CPU variant for Mips32 using defaults: " << variant;
}
- return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6));
+ return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6));
}
-MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromBitmap(
- uint32_t bitmap) {
- bool smp = (bitmap & kSmpBitfield) != 0;
+MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
bool fpu_32bit = (bitmap & kFpu32Bitfield) != 0;
bool mips_isa_gte2 = (bitmap & kIsaRevGte2Bitfield) != 0;
bool r6 = (bitmap & kR6) != 0;
- return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6));
+ return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6));
}
MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromCppDefines() {
- // Assume conservative defaults.
- const bool smp = true;
-
bool fpu_32bit;
bool mips_isa_gte2;
bool r6;
GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit);
- return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6));
+ return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6));
}
MipsFeaturesUniquePtr MipsInstructionSetFeatures::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.
- // Assume conservative defaults.
- bool smp = false;
-
bool fpu_32bit;
bool mips_isa_gte2;
bool r6;
GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit);
- 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("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
- smp = true;
- }
- }
- }
- in.close();
- } else {
- LOG(ERROR) << "Failed to open /proc/cpuinfo";
- }
- return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6));
+ return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6));
}
MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromHwcap() {
@@ -171,30 +143,23 @@
return false;
}
const MipsInstructionSetFeatures* other_as_mips = other->AsMipsInstructionSetFeatures();
- return (IsSmp() == other->IsSmp()) &&
- (fpu_32bit_ == other_as_mips->fpu_32bit_) &&
+ return (fpu_32bit_ == other_as_mips->fpu_32bit_) &&
(mips_isa_gte2_ == other_as_mips->mips_isa_gte2_) &&
(r6_ == other_as_mips->r6_);
}
uint32_t MipsInstructionSetFeatures::AsBitmap() const {
- return (IsSmp() ? kSmpBitfield : 0) |
- (fpu_32bit_ ? kFpu32Bitfield : 0) |
+ return (fpu_32bit_ ? kFpu32Bitfield : 0) |
(mips_isa_gte2_ ? kIsaRevGte2Bitfield : 0) |
(r6_ ? kR6 : 0);
}
std::string MipsInstructionSetFeatures::GetFeatureString() const {
std::string result;
- if (IsSmp()) {
- result += "smp";
- } else {
- result += "-smp";
- }
if (fpu_32bit_) {
- result += ",fpu32";
+ result += "fpu32";
} else {
- result += ",-fpu32";
+ result += "-fpu32";
}
if (mips_isa_gte2_) {
result += ",mips2";
@@ -209,7 +174,7 @@
std::unique_ptr<const InstructionSetFeatures>
MipsInstructionSetFeatures::AddFeaturesFromSplitString(
- const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+ const std::vector<std::string>& features, std::string* error_msg) const {
bool fpu_32bit = fpu_32bit_;
bool mips_isa_gte2 = mips_isa_gte2_;
bool r6 = r6_;
@@ -233,7 +198,7 @@
}
}
return std::unique_ptr<const InstructionSetFeatures>(
- new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6));
+ new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6));
}
} // namespace art
diff --git a/runtime/arch/mips/instruction_set_features_mips.h b/runtime/arch/mips/instruction_set_features_mips.h
index c2a28dc..1aec99f 100644
--- a/runtime/arch/mips/instruction_set_features_mips.h
+++ b/runtime/arch/mips/instruction_set_features_mips.h
@@ -80,12 +80,12 @@
protected:
// Parse a vector of the form "fpu32", "mips2" adding these to a new MipsInstructionSetFeatures.
std::unique_ptr<const InstructionSetFeatures>
- AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+ AddFeaturesFromSplitString(const std::vector<std::string>& features,
std::string* error_msg) const OVERRIDE;
private:
- MipsInstructionSetFeatures(bool smp, bool fpu_32bit, bool mips_isa_gte2, bool r6)
- : InstructionSetFeatures(smp),
+ MipsInstructionSetFeatures(bool fpu_32bit, bool mips_isa_gte2, bool r6)
+ : InstructionSetFeatures(),
fpu_32bit_(fpu_32bit),
mips_isa_gte2_(mips_isa_gte2),
r6_(r6) {
@@ -101,10 +101,9 @@
// Bitmap positions for encoding features as a bitmap.
enum {
- kSmpBitfield = 1,
- kFpu32Bitfield = 2,
- kIsaRevGte2Bitfield = 4,
- kR6 = 8,
+ kFpu32Bitfield = 1 << 0,
+ kIsaRevGte2Bitfield = 1 << 1,
+ kR6 = 1 << 2,
};
const bool fpu_32bit_;
diff --git a/runtime/arch/mips/instruction_set_features_mips_test.cc b/runtime/arch/mips/instruction_set_features_mips_test.cc
index 9b81ce2..6613b84 100644
--- a/runtime/arch/mips/instruction_set_features_mips_test.cc
+++ b/runtime/arch/mips/instruction_set_features_mips_test.cc
@@ -27,8 +27,8 @@
ASSERT_TRUE(mips_features.get() != nullptr) << error_msg;
EXPECT_EQ(mips_features->GetInstructionSet(), kMips);
EXPECT_TRUE(mips_features->Equals(mips_features.get()));
- EXPECT_STREQ("smp,fpu32,mips2", mips_features->GetFeatureString().c_str());
- EXPECT_EQ(mips_features->AsBitmap(), 7U);
+ EXPECT_STREQ("fpu32,mips2", mips_features->GetFeatureString().c_str());
+ EXPECT_EQ(mips_features->AsBitmap(), 3U);
}
} // namespace art
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index 3e8cdc9..964ea56 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -1831,116 +1831,10 @@
// Generate the allocation entrypoints for each allocator.
GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc).
-ENTRY art_quick_alloc_object_rosalloc
- # Fast path rosalloc allocation
- # a0: type_idx
- # a1: ArtMethod*
- # s1: Thread::Current
- # -----------------------------
- # t0: class
- # t1: object size
- # t2: rosalloc run
- # t3: thread stack top offset
- # t4: thread stack bottom offset
- # v0: free list head
- #
- # t5, t6 : temps
-
- lw $t0, ART_METHOD_DEX_CACHE_TYPES_OFFSET_32($a1) # Load dex cache resolved types
- # array.
-
- sll $t5, $a0, COMPRESSED_REFERENCE_SIZE_SHIFT # Shift the value.
- addu $t5, $t0, $t5 # Compute the index.
- lw $t0, 0($t5) # Load class (t0).
- beqz $t0, .Lart_quick_alloc_object_rosalloc_slow_path
-
- li $t6, MIRROR_CLASS_STATUS_INITIALIZED
- lw $t5, MIRROR_CLASS_STATUS_OFFSET($t0) # Check class status.
- bne $t5, $t6, .Lart_quick_alloc_object_rosalloc_slow_path
-
- # Add a fake dependence from the following access flag and size loads to the status load. This
- # is to prevent those loads from being reordered above the status load and reading wrong values.
- xor $t5, $t5, $t5
- addu $t0, $t0, $t5
-
- lw $t5, MIRROR_CLASS_ACCESS_FLAGS_OFFSET($t0) # Check if access flags has
- li $t6, ACCESS_FLAGS_CLASS_IS_FINALIZABLE # kAccClassIsFinalizable.
- and $t6, $t5, $t6
- bnez $t6, .Lart_quick_alloc_object_rosalloc_slow_path
-
- lw $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1) # Check if thread local allocation
- lw $t4, THREAD_LOCAL_ALLOC_STACK_END_OFFSET($s1) # stack has any room left.
- bgeu $t3, $t4, .Lart_quick_alloc_object_rosalloc_slow_path
-
- lw $t1, MIRROR_CLASS_OBJECT_SIZE_OFFSET($t0) # Load object size (t1).
- li $t5, ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE # Check if size is for a thread local
- # allocation.
- bgtu $t1, $t5, .Lart_quick_alloc_object_rosalloc_slow_path
-
- # Compute the rosalloc bracket index from the size. Allign up the size by the rosalloc bracket
- # quantum size and divide by the quantum size and subtract by 1.
-
- addiu $t1, $t1, -1 # Decrease obj size and shift right
- srl $t1, $t1, ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT # by quantum.
-
- sll $t2, $t1, POINTER_SIZE_SHIFT
- addu $t2, $t2, $s1
- lw $t2, THREAD_ROSALLOC_RUNS_OFFSET($t2) # Load rosalloc run (t2).
-
- # Load the free list head (v0).
- # NOTE: this will be the return val.
-
- lw $v0, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
- beqz $v0, .Lart_quick_alloc_object_rosalloc_slow_path
- nop
-
- # Load the next pointer of the head and update the list head with the next pointer.
-
- lw $t5, ROSALLOC_SLOT_NEXT_OFFSET($v0)
- sw $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
-
- # Store the class pointer in the header. This also overwrites the first pointer. The offsets are
- # asserted to match.
-
-#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
-#error "Class pointer needs to overwrite next pointer."
-#endif
-
- POISON_HEAP_REF $t0
- sw $t0, MIRROR_OBJECT_CLASS_OFFSET($v0)
-
- # Push the new object onto the thread local allocation stack and increment the thread local
- # allocation stack top.
-
- sw $v0, 0($t3)
- addiu $t3, $t3, COMPRESSED_REFERENCE_SIZE
- sw $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1)
-
- # Decrement the size of the free list.
-
- lw $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
- addiu $t5, $t5, -1
- sw $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
-
- sync # Fence.
-
- jalr $zero, $ra
- nop
-
- .Lart_quick_alloc_object_rosalloc_slow_path:
-
- SETUP_SAVE_REFS_ONLY_FRAME
- la $t9, artAllocObjectFromCodeRosAlloc
- jalr $t9
- move $a2, $s1 # Pass self as argument.
- RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-
-END art_quick_alloc_object_rosalloc
-
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
/*
* Entry from managed code to resolve a string, this stub will allocate a String and deliver an
diff --git a/runtime/arch/mips64/instruction_set_features_mips64.cc b/runtime/arch/mips64/instruction_set_features_mips64.cc
index 92c44e8..5606c1d 100644
--- a/runtime/arch/mips64/instruction_set_features_mips64.cc
+++ b/runtime/arch/mips64/instruction_set_features_mips64.cc
@@ -33,43 +33,19 @@
if (variant != "default" && variant != "mips64r6") {
LOG(WARNING) << "Unexpected CPU variant for Mips64 using defaults: " << variant;
}
- bool smp = true; // Conservative default.
- return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures(smp));
+ return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures());
}
-Mips64FeaturesUniquePtr Mips64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
- bool smp = (bitmap & kSmpBitfield) != 0;
- return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures(smp));
+Mips64FeaturesUniquePtr Mips64InstructionSetFeatures::FromBitmap(uint32_t bitmap ATTRIBUTE_UNUSED) {
+ return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures());
}
Mips64FeaturesUniquePtr Mips64InstructionSetFeatures::FromCppDefines() {
- const bool smp = true;
-
- return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures(smp));
+ return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures());
}
Mips64FeaturesUniquePtr Mips64InstructionSetFeatures::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 smp = 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("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
- smp = true;
- }
- }
- }
- in.close();
- } else {
- LOG(ERROR) << "Failed to open /proc/cpuinfo";
- }
- return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures(smp));
+ return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures());
}
Mips64FeaturesUniquePtr Mips64InstructionSetFeatures::FromHwcap() {
@@ -86,26 +62,20 @@
if (kMips64 != other->GetInstructionSet()) {
return false;
}
- return (IsSmp() == other->IsSmp());
+ return true;
}
uint32_t Mips64InstructionSetFeatures::AsBitmap() const {
- return (IsSmp() ? kSmpBitfield : 0);
+ return 0;
}
std::string Mips64InstructionSetFeatures::GetFeatureString() const {
- std::string result;
- if (IsSmp()) {
- result += "smp";
- } else {
- result += "-smp";
- }
- return result;
+ return "";
}
std::unique_ptr<const InstructionSetFeatures>
Mips64InstructionSetFeatures::AddFeaturesFromSplitString(
- const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+ const std::vector<std::string>& features, std::string* error_msg) const {
auto i = features.begin();
if (i != features.end()) {
// We don't have any features.
@@ -113,7 +83,7 @@
*error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
return nullptr;
}
- return std::unique_ptr<const InstructionSetFeatures>(new Mips64InstructionSetFeatures(smp));
+ return std::unique_ptr<const InstructionSetFeatures>(new Mips64InstructionSetFeatures());
}
} // namespace art
diff --git a/runtime/arch/mips64/instruction_set_features_mips64.h b/runtime/arch/mips64/instruction_set_features_mips64.h
index 2e66235..c80c466 100644
--- a/runtime/arch/mips64/instruction_set_features_mips64.h
+++ b/runtime/arch/mips64/instruction_set_features_mips64.h
@@ -29,7 +29,7 @@
public:
// Process a CPU variant string like "r4000" and create InstructionSetFeatures.
static Mips64FeaturesUniquePtr FromVariant(const std::string& variant,
- std::string* error_msg);
+ std::string* error_msg);
// Parse a bitmap and create an InstructionSetFeatures.
static Mips64FeaturesUniquePtr FromBitmap(uint32_t bitmap);
@@ -63,19 +63,13 @@
protected:
// Parse a vector of the form "fpu32", "mips2" adding these to a new Mips64InstructionSetFeatures.
std::unique_ptr<const InstructionSetFeatures>
- AddFeaturesFromSplitString(const bool smp,
- const std::vector<std::string>& features,
+ AddFeaturesFromSplitString(const std::vector<std::string>& features,
std::string* error_msg) const OVERRIDE;
private:
- explicit Mips64InstructionSetFeatures(bool smp) : InstructionSetFeatures(smp) {
+ Mips64InstructionSetFeatures() : InstructionSetFeatures() {
}
- // Bitmap positions for encoding features as a bitmap.
- enum {
- kSmpBitfield = 1,
- };
-
DISALLOW_COPY_AND_ASSIGN(Mips64InstructionSetFeatures);
};
diff --git a/runtime/arch/mips64/instruction_set_features_mips64_test.cc b/runtime/arch/mips64/instruction_set_features_mips64_test.cc
index dc34506..1d03794 100644
--- a/runtime/arch/mips64/instruction_set_features_mips64_test.cc
+++ b/runtime/arch/mips64/instruction_set_features_mips64_test.cc
@@ -27,8 +27,8 @@
ASSERT_TRUE(mips64_features.get() != nullptr) << error_msg;
EXPECT_EQ(mips64_features->GetInstructionSet(), kMips64);
EXPECT_TRUE(mips64_features->Equals(mips64_features.get()));
- EXPECT_STREQ("smp", mips64_features->GetFeatureString().c_str());
- EXPECT_EQ(mips64_features->AsBitmap(), 1U);
+ EXPECT_STREQ("", mips64_features->GetFeatureString().c_str());
+ EXPECT_EQ(mips64_features->AsBitmap(), 0U);
}
} // namespace art
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index 0861d2d..2a18d53 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -1775,107 +1775,9 @@
// Generate the allocation entrypoints for each allocator.
GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc).
-ENTRY art_quick_alloc_object_rosalloc
-
- # Fast path rosalloc allocation
- # a0: type_idx
- # a1: ArtMethod*
- # s1: Thread::Current
- # -----------------------------
- # t0: class
- # t1: object size
- # t2: rosalloc run
- # t3: thread stack top offset
- # a4: thread stack bottom offset
- # v0: free list head
- #
- # a5, a6 : temps
-
- ld $t0, ART_METHOD_DEX_CACHE_TYPES_OFFSET_64($a1) # Load dex cache resolved types array.
-
- dsll $a5, $a0, COMPRESSED_REFERENCE_SIZE_SHIFT # Shift the value.
- daddu $a5, $t0, $a5 # Compute the index.
- lwu $t0, 0($a5) # Load class (t0).
- beqzc $t0, .Lart_quick_alloc_object_rosalloc_slow_path
-
- li $a6, MIRROR_CLASS_STATUS_INITIALIZED
- lwu $a5, MIRROR_CLASS_STATUS_OFFSET($t0) # Check class status.
- bnec $a5, $a6, .Lart_quick_alloc_object_rosalloc_slow_path
-
- # Add a fake dependence from the following access flag and size loads to the status load. This
- # is to prevent those loads from being reordered above the status load and reading wrong values.
- xor $a5, $a5, $a5
- daddu $t0, $t0, $a5
-
- lwu $a5, MIRROR_CLASS_ACCESS_FLAGS_OFFSET($t0) # Check if access flags has
- li $a6, ACCESS_FLAGS_CLASS_IS_FINALIZABLE # kAccClassIsFinalizable.
- and $a6, $a5, $a6
- bnezc $a6, .Lart_quick_alloc_object_rosalloc_slow_path
-
- ld $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1) # Check if thread local allocation stack
- ld $a4, THREAD_LOCAL_ALLOC_STACK_END_OFFSET($s1) # has any room left.
- bgeuc $t3, $a4, .Lart_quick_alloc_object_rosalloc_slow_path
-
- lwu $t1, MIRROR_CLASS_OBJECT_SIZE_OFFSET($t0) # Load object size (t1).
- li $a5, ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE # Check if size is for a thread local
- # allocation.
- bltuc $a5, $t1, .Lart_quick_alloc_object_rosalloc_slow_path
-
- # Compute the rosalloc bracket index from the size. Allign up the size by the rosalloc bracket
- # quantum size and divide by the quantum size and subtract by 1.
- daddiu $t1, $t1, -1 # Decrease obj size and shift right by
- dsrl $t1, $t1, ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT # quantum.
-
- dsll $t2, $t1, POINTER_SIZE_SHIFT
- daddu $t2, $t2, $s1
- ld $t2, THREAD_ROSALLOC_RUNS_OFFSET($t2) # Load rosalloc run (t2).
-
- # Load the free list head (v0).
- # NOTE: this will be the return val.
- ld $v0, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
- beqzc $v0, .Lart_quick_alloc_object_rosalloc_slow_path
-
- # Load the next pointer of the head and update the list head with the next pointer.
- ld $a5, ROSALLOC_SLOT_NEXT_OFFSET($v0)
- sd $a5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
-
- # Store the class pointer in the header. This also overwrites the first pointer. The offsets are
- # asserted to match.
-
-#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
-#error "Class pointer needs to overwrite next pointer."
-#endif
-
- POISON_HEAP_REF $t0
- sw $t0, MIRROR_OBJECT_CLASS_OFFSET($v0)
-
- # Push the new object onto the thread local allocation stack and increment the thread local
- # allocation stack top.
- sd $v0, 0($t3)
- daddiu $t3, $t3, COMPRESSED_REFERENCE_SIZE
- sd $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1)
-
- # Decrement the size of the free list.
- lw $a5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
- addiu $a5, $a5, -1
- sw $a5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
-
- sync # Fence.
-
- jalr $zero, $ra
- .cpreturn # Restore gp from t8 in branch delay slot.
-
-.Lart_quick_alloc_object_rosalloc_slow_path:
- SETUP_SAVE_REFS_ONLY_FRAME
- jal artAllocObjectFromCodeRosAlloc
- move $a2 ,$s1 # Pass self as argument.
- RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-
-END art_quick_alloc_object_rosalloc
-
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
/*
* Entry from managed code to resolve a string, this stub will allocate a String and deliver an
diff --git a/runtime/arch/quick_alloc_entrypoints.S b/runtime/arch/quick_alloc_entrypoints.S
index db2fdca..abd9046 100644
--- a/runtime/arch/quick_alloc_entrypoints.S
+++ b/runtime/arch/quick_alloc_entrypoints.S
@@ -15,15 +15,13 @@
*/
.macro GENERATE_ALLOC_ENTRYPOINTS c_suffix, cxx_suffix
-// Called by managed code to allocate an object.
-TWO_ARG_DOWNCALL art_quick_alloc_object\c_suffix, artAllocObjectFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
// Called by managed code to allocate an object of a resolved class.
-TWO_ARG_DOWNCALL art_quick_alloc_object_resolved\c_suffix, artAllocObjectFromCodeResolved\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+ONE_ARG_DOWNCALL art_quick_alloc_object_resolved\c_suffix, artAllocObjectFromCodeResolved\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
// Called by managed code to allocate an object of an initialized class.
-TWO_ARG_DOWNCALL art_quick_alloc_object_initialized\c_suffix, artAllocObjectFromCodeInitialized\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+ONE_ARG_DOWNCALL art_quick_alloc_object_initialized\c_suffix, artAllocObjectFromCodeInitialized\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
// Called by managed code to allocate an object when the caller doesn't know whether it has access
// to the created type.
-TWO_ARG_DOWNCALL art_quick_alloc_object_with_access_check\c_suffix, artAllocObjectFromCodeWithAccessCheck\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+ONE_ARG_DOWNCALL art_quick_alloc_object_with_checks\c_suffix, artAllocObjectFromCodeWithChecks\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
// Called by managed code to allocate an array.
THREE_ARG_DOWNCALL art_quick_alloc_array\c_suffix, artAllocArrayFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
// Called by managed code to allocate an array of a resolve class.
@@ -61,14 +59,12 @@
// Generate the allocation entrypoints for each allocator. This is used as an alternative to
// GNERATE_ALL_ALLOC_ENTRYPOINTS for selectively implementing allocation fast paths in
// hand-written assembly.
-#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(c_suffix, cxx_suffix) \
- TWO_ARG_DOWNCALL art_quick_alloc_object ## c_suffix, artAllocObjectFromCode ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(c_suffix, cxx_suffix) \
- TWO_ARG_DOWNCALL art_quick_alloc_object_resolved ## c_suffix, artAllocObjectFromCodeResolved ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+ ONE_ARG_DOWNCALL art_quick_alloc_object_resolved ## c_suffix, artAllocObjectFromCodeResolved ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(c_suffix, cxx_suffix) \
- TWO_ARG_DOWNCALL art_quick_alloc_object_initialized ## c_suffix, artAllocObjectFromCodeInitialized ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+ ONE_ARG_DOWNCALL art_quick_alloc_object_initialized ## c_suffix, artAllocObjectFromCodeInitialized ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(c_suffix, cxx_suffix) \
- TWO_ARG_DOWNCALL art_quick_alloc_object_with_access_check ## c_suffix, artAllocObjectFromCodeWithAccessCheck ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+ ONE_ARG_DOWNCALL art_quick_alloc_object_with_checks ## c_suffix, artAllocObjectFromCodeWithChecks ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(c_suffix, cxx_suffix) \
THREE_ARG_DOWNCALL art_quick_alloc_array ## c_suffix, artAllocArrayFromCode ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(c_suffix, cxx_suffix) \
@@ -93,8 +89,7 @@
.macro GENERATE_ALLOC_ENTRYPOINTS_FOR_REGION_TLAB_ALLOCATOR
// This is to be separately defined for each architecture to allow a hand-written assembly fast path.
-// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_region_tlab, RegionTLAB)
@@ -109,8 +104,7 @@
.macro GENERATE_ALLOC_ENTRYPOINTS_FOR_TLAB_ALLOCATOR
// This is to be separately defined for each architecture to allow a hand-written assembly fast path.
-// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_tlab, TLAB)
@@ -129,7 +123,6 @@
.endm
.macro GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_TLAB_ALLOCATORS
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_dlmalloc, DlMalloc)
@@ -142,7 +135,6 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_dlmalloc, DlMalloc)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_dlmalloc_instrumented, DlMallocInstrumented)
@@ -156,8 +148,7 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_dlmalloc_instrumented, DlMallocInstrumented)
// This is to be separately defined for each architecture to allow a hand-written assembly fast path.
-// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_rosalloc, RosAlloc)
@@ -169,7 +160,6 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_rosalloc, RosAlloc)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_rosalloc_instrumented, RosAllocInstrumented)
@@ -182,7 +172,6 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_rosalloc_instrumented, RosAllocInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_bump_pointer, BumpPointer)
@@ -195,7 +184,6 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_bump_pointer, BumpPointer)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_bump_pointer_instrumented, BumpPointerInstrumented)
@@ -208,7 +196,6 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_bump_pointer_instrumented, BumpPointerInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab_instrumented, TLABInstrumented)
@@ -221,7 +208,6 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab_instrumented, TLABInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region, Region)
@@ -234,7 +220,6 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region, Region)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_instrumented, RegionInstrumented)
@@ -247,7 +232,6 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_instrumented, RegionInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab_instrumented, RegionTLABInstrumented)
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 9e385f8..ee65fa8 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -1062,12 +1062,8 @@
EXPECT_FALSE(self->IsExceptionPending());
{
- // Use an arbitrary method from c to use as referrer
- size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex().index_), // type_idx
- // arbitrary
- reinterpret_cast<size_t>(c->GetVirtualMethod(0, kRuntimePointerSize)),
- 0U,
- StubTest::GetEntrypoint(self, kQuickAllocObject),
+ size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), 0u, 0U,
+ StubTest::GetEntrypoint(self, kQuickAllocObjectWithChecks),
self);
EXPECT_FALSE(self->IsExceptionPending());
@@ -1078,8 +1074,6 @@
}
{
- // We can use null in the second argument as we do not need a method here (not used in
- // resolved/initialized cases)
size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), 0u, 0U,
StubTest::GetEntrypoint(self, kQuickAllocObjectResolved),
self);
@@ -1092,8 +1086,6 @@
}
{
- // We can use null in the second argument as we do not need a method here (not used in
- // resolved/initialized cases)
size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), 0u, 0U,
StubTest::GetEntrypoint(self, kQuickAllocObjectInitialized),
self);
diff --git a/runtime/arch/x86/instruction_set_features_x86.cc b/runtime/arch/x86/instruction_set_features_x86.cc
index c520d63..5788122 100644
--- a/runtime/arch/x86/instruction_set_features_x86.cc
+++ b/runtime/arch/x86/instruction_set_features_x86.cc
@@ -54,7 +54,6 @@
};
X86FeaturesUniquePtr X86InstructionSetFeatures::Create(bool x86_64,
- bool smp,
bool has_SSSE3,
bool has_SSE4_1,
bool has_SSE4_2,
@@ -62,16 +61,14 @@
bool has_AVX2,
bool has_POPCNT) {
if (x86_64) {
- return X86FeaturesUniquePtr(new X86_64InstructionSetFeatures(smp,
- has_SSSE3,
+ return X86FeaturesUniquePtr(new X86_64InstructionSetFeatures(has_SSSE3,
has_SSE4_1,
has_SSE4_2,
has_AVX,
has_AVX2,
has_POPCNT));
} else {
- return X86FeaturesUniquePtr(new X86InstructionSetFeatures(smp,
- has_SSSE3,
+ return X86FeaturesUniquePtr(new X86InstructionSetFeatures(has_SSSE3,
has_SSE4_1,
has_SSE4_2,
has_AVX,
@@ -83,7 +80,6 @@
X86FeaturesUniquePtr X86InstructionSetFeatures::FromVariant(
const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED,
bool x86_64) {
- bool smp = true; // Conservative default.
bool has_SSSE3 = FindVariantInArray(x86_variants_with_ssse3, arraysize(x86_variants_with_ssse3),
variant);
bool has_SSE4_1 = FindVariantInArray(x86_variants_with_sse4_1,
@@ -106,23 +102,20 @@
LOG(WARNING) << "Unexpected CPU variant for X86 using defaults: " << variant;
}
- return Create(x86_64, smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
+ return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
}
X86FeaturesUniquePtr X86InstructionSetFeatures::FromBitmap(uint32_t bitmap, bool x86_64) {
- bool smp = (bitmap & kSmpBitfield) != 0;
bool has_SSSE3 = (bitmap & kSsse3Bitfield) != 0;
bool has_SSE4_1 = (bitmap & kSse4_1Bitfield) != 0;
bool has_SSE4_2 = (bitmap & kSse4_2Bitfield) != 0;
bool has_AVX = (bitmap & kAvxBitfield) != 0;
bool has_AVX2 = (bitmap & kAvxBitfield) != 0;
bool has_POPCNT = (bitmap & kPopCntBitfield) != 0;
- return Create(x86_64, smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
+ return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
}
X86FeaturesUniquePtr X86InstructionSetFeatures::FromCppDefines(bool x86_64) {
- const bool smp = true;
-
#ifndef __SSSE3__
const bool has_SSSE3 = false;
#else
@@ -159,13 +152,12 @@
const bool has_POPCNT = true;
#endif
- return Create(x86_64, smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
+ return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
}
X86FeaturesUniquePtr X86InstructionSetFeatures::FromCpuInfo(bool x86_64) {
// 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 smp = false;
bool has_SSSE3 = false;
bool has_SSE4_1 = false;
bool has_SSE4_2 = false;
@@ -200,9 +192,6 @@
if (line.find("popcnt") != std::string::npos) {
has_POPCNT = true;
}
- } else if (line.find("processor") != std::string::npos &&
- line.find(": 1") != std::string::npos) {
- smp = true;
}
}
}
@@ -210,7 +199,7 @@
} else {
LOG(ERROR) << "Failed to open /proc/cpuinfo";
}
- return Create(x86_64, smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
+ return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
}
X86FeaturesUniquePtr X86InstructionSetFeatures::FromHwcap(bool x86_64) {
@@ -228,8 +217,7 @@
return false;
}
const X86InstructionSetFeatures* other_as_x86 = other->AsX86InstructionSetFeatures();
- return (IsSmp() == other->IsSmp()) &&
- (has_SSSE3_ == other_as_x86->has_SSSE3_) &&
+ return (has_SSSE3_ == other_as_x86->has_SSSE3_) &&
(has_SSE4_1_ == other_as_x86->has_SSE4_1_) &&
(has_SSE4_2_ == other_as_x86->has_SSE4_2_) &&
(has_AVX_ == other_as_x86->has_AVX_) &&
@@ -238,8 +226,7 @@
}
uint32_t X86InstructionSetFeatures::AsBitmap() const {
- return (IsSmp() ? kSmpBitfield : 0) |
- (has_SSSE3_ ? kSsse3Bitfield : 0) |
+ return (has_SSSE3_ ? kSsse3Bitfield : 0) |
(has_SSE4_1_ ? kSse4_1Bitfield : 0) |
(has_SSE4_2_ ? kSse4_2Bitfield : 0) |
(has_AVX_ ? kAvxBitfield : 0) |
@@ -249,15 +236,10 @@
std::string X86InstructionSetFeatures::GetFeatureString() const {
std::string result;
- if (IsSmp()) {
- result += "smp";
- } else {
- result += "-smp";
- }
if (has_SSSE3_) {
- result += ",ssse3";
+ result += "ssse3";
} else {
- result += ",-ssse3";
+ result += "-ssse3";
}
if (has_SSE4_1_) {
result += ",sse4.1";
@@ -288,7 +270,7 @@
}
std::unique_ptr<const InstructionSetFeatures> X86InstructionSetFeatures::AddFeaturesFromSplitString(
- const bool smp, const std::vector<std::string>& features, bool x86_64,
+ const std::vector<std::string>& features, bool x86_64,
std::string* error_msg) const {
bool has_SSSE3 = has_SSSE3_;
bool has_SSE4_1 = has_SSE4_1_;
@@ -327,7 +309,7 @@
return nullptr;
}
}
- return Create(x86_64, smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
+ return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
}
} // namespace art
diff --git a/runtime/arch/x86/instruction_set_features_x86.h b/runtime/arch/x86/instruction_set_features_x86.h
index 672892e..eb8a710 100644
--- a/runtime/arch/x86/instruction_set_features_x86.h
+++ b/runtime/arch/x86/instruction_set_features_x86.h
@@ -69,18 +69,23 @@
protected:
// Parse a string of the form "ssse3" adding these to a new InstructionSetFeatures.
virtual std::unique_ptr<const InstructionSetFeatures>
- AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+ AddFeaturesFromSplitString(const std::vector<std::string>& features,
std::string* error_msg) const OVERRIDE {
- return AddFeaturesFromSplitString(smp, features, false, error_msg);
+ return AddFeaturesFromSplitString(features, false, error_msg);
}
std::unique_ptr<const InstructionSetFeatures>
- AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
- bool x86_64, std::string* error_msg) const;
+ AddFeaturesFromSplitString(const std::vector<std::string>& features,
+ bool x86_64,
+ std::string* error_msg) const;
- X86InstructionSetFeatures(bool smp, bool has_SSSE3, bool has_SSE4_1, bool has_SSE4_2,
- bool has_AVX, bool has_AVX2, bool has_POPCNT)
- : InstructionSetFeatures(smp),
+ X86InstructionSetFeatures(bool has_SSSE3,
+ bool has_SSE4_1,
+ bool has_SSE4_2,
+ bool has_AVX,
+ bool has_AVX2,
+ bool has_POPCNT)
+ : InstructionSetFeatures(),
has_SSSE3_(has_SSSE3),
has_SSE4_1_(has_SSE4_1),
has_SSE4_2_(has_SSE4_2),
@@ -90,7 +95,6 @@
}
static X86FeaturesUniquePtr Create(bool x86_64,
- bool smp,
bool has_SSSE3,
bool has_SSE4_1,
bool has_SSE4_2,
@@ -101,13 +105,12 @@
private:
// Bitmap positions for encoding features as a bitmap.
enum {
- kSmpBitfield = 1,
- kSsse3Bitfield = 2,
- kSse4_1Bitfield = 4,
- kSse4_2Bitfield = 8,
- kAvxBitfield = 16,
- kAvx2Bitfield = 32,
- kPopCntBitfield = 64,
+ kSsse3Bitfield = 1 << 0,
+ kSse4_1Bitfield = 1 << 1,
+ kSse4_2Bitfield = 1 << 2,
+ kAvxBitfield = 1 << 3,
+ kAvx2Bitfield = 1 << 4,
+ kPopCntBitfield = 1 << 5,
};
const bool has_SSSE3_; // x86 128bit SIMD - Supplemental SSE.
diff --git a/runtime/arch/x86/instruction_set_features_x86_test.cc b/runtime/arch/x86/instruction_set_features_x86_test.cc
index 9e154c6..7e6ad3e 100644
--- a/runtime/arch/x86/instruction_set_features_x86_test.cc
+++ b/runtime/arch/x86/instruction_set_features_x86_test.cc
@@ -27,9 +27,9 @@
ASSERT_TRUE(x86_features.get() != nullptr) << error_msg;
EXPECT_EQ(x86_features->GetInstructionSet(), kX86);
EXPECT_TRUE(x86_features->Equals(x86_features.get()));
- EXPECT_STREQ("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt",
+ EXPECT_STREQ("-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt",
x86_features->GetFeatureString().c_str());
- EXPECT_EQ(x86_features->AsBitmap(), 1U);
+ EXPECT_EQ(x86_features->AsBitmap(), 0U);
}
TEST(X86InstructionSetFeaturesTest, X86FeaturesFromAtomVariant) {
@@ -40,9 +40,9 @@
ASSERT_TRUE(x86_features.get() != nullptr) << error_msg;
EXPECT_EQ(x86_features->GetInstructionSet(), kX86);
EXPECT_TRUE(x86_features->Equals(x86_features.get()));
- EXPECT_STREQ("smp,ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt",
+ EXPECT_STREQ("ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt",
x86_features->GetFeatureString().c_str());
- EXPECT_EQ(x86_features->AsBitmap(), 3U);
+ EXPECT_EQ(x86_features->AsBitmap(), 1U);
// Build features for a 32-bit x86 default processor.
std::unique_ptr<const InstructionSetFeatures> x86_default_features(
@@ -50,9 +50,9 @@
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("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt",
+ EXPECT_STREQ("-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt",
x86_default_features->GetFeatureString().c_str());
- EXPECT_EQ(x86_default_features->AsBitmap(), 1U);
+ 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(
@@ -60,9 +60,9 @@
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("smp,ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt",
+ EXPECT_STREQ("ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt",
x86_64_features->GetFeatureString().c_str());
- EXPECT_EQ(x86_64_features->AsBitmap(), 3U);
+ EXPECT_EQ(x86_64_features->AsBitmap(), 1U);
EXPECT_FALSE(x86_64_features->Equals(x86_features.get()));
EXPECT_FALSE(x86_64_features->Equals(x86_default_features.get()));
@@ -77,9 +77,9 @@
ASSERT_TRUE(x86_features.get() != nullptr) << error_msg;
EXPECT_EQ(x86_features->GetInstructionSet(), kX86);
EXPECT_TRUE(x86_features->Equals(x86_features.get()));
- EXPECT_STREQ("smp,ssse3,sse4.1,sse4.2,-avx,-avx2,popcnt",
+ EXPECT_STREQ("ssse3,sse4.1,sse4.2,-avx,-avx2,popcnt",
x86_features->GetFeatureString().c_str());
- EXPECT_EQ(x86_features->AsBitmap(), 79U);
+ EXPECT_EQ(x86_features->AsBitmap(), 39U);
// Build features for a 32-bit x86 default processor.
std::unique_ptr<const InstructionSetFeatures> x86_default_features(
@@ -87,9 +87,9 @@
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("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt",
+ EXPECT_STREQ("-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt",
x86_default_features->GetFeatureString().c_str());
- EXPECT_EQ(x86_default_features->AsBitmap(), 1U);
+ EXPECT_EQ(x86_default_features->AsBitmap(), 0U);
// Build features for a 64-bit x86-64 silvermont processor.
std::unique_ptr<const InstructionSetFeatures> x86_64_features(
@@ -97,9 +97,9 @@
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("smp,ssse3,sse4.1,sse4.2,-avx,-avx2,popcnt",
+ EXPECT_STREQ("ssse3,sse4.1,sse4.2,-avx,-avx2,popcnt",
x86_64_features->GetFeatureString().c_str());
- EXPECT_EQ(x86_64_features->AsBitmap(), 79U);
+ EXPECT_EQ(x86_64_features->AsBitmap(), 39U);
EXPECT_FALSE(x86_64_features->Equals(x86_features.get()));
EXPECT_FALSE(x86_64_features->Equals(x86_default_features.get()));
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index c6f4c03..62c29cf 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -956,52 +956,42 @@
// Generate the allocation entrypoints for each allocator.
GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc).
-DEFINE_FUNCTION art_quick_alloc_object_rosalloc
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc).
+DEFINE_FUNCTION art_quick_alloc_object_resolved_rosalloc
// Fast path rosalloc allocation.
- // eax: uint32_t type_idx/return value, ecx: ArtMethod*
- // ebx, edx: free
- PUSH edi
- movl ART_METHOD_DEX_CACHE_TYPES_OFFSET_32(%ecx), %edx // Load dex cache resolved types array
- // Load the class (edx)
- movl 0(%edx, %eax, COMPRESSED_REFERENCE_SIZE), %edx
- testl %edx, %edx // Check null class
- jz .Lart_quick_alloc_object_rosalloc_slow_path
-
+ // eax: type/return value
+ // ecx, ebx, edx: free
movl %fs:THREAD_SELF_OFFSET, %ebx // ebx = thread
// Check if the thread local allocation
// stack has room
- movl THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET(%ebx), %edi
- cmpl THREAD_LOCAL_ALLOC_STACK_END_OFFSET(%ebx), %edi
- jae .Lart_quick_alloc_object_rosalloc_slow_path
+ movl THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET(%ebx), %ecx
+ cmpl THREAD_LOCAL_ALLOC_STACK_END_OFFSET(%ebx), %ecx
+ jae .Lart_quick_alloc_object_resolved_rosalloc_slow_path
- movl MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET(%edx), %edi // Load the object size (edi)
+ movl MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET(%eax), %ecx // Load the object size (ecx)
// Check if the size is for a thread
// local allocation. Also does the
// finalizable and initialization check.
- cmpl LITERAL(ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE), %edi
- ja .Lart_quick_alloc_object_rosalloc_slow_path
- shrl LITERAL(ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT), %edi // Calculate the rosalloc bracket index
+ cmpl LITERAL(ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE), %ecx
+ ja .Lart_quick_alloc_object_resolved_rosalloc_slow_path
+ shrl LITERAL(ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT), %ecx // Calculate the rosalloc bracket index
// from object size.
// Load thread local rosalloc run (ebx)
// Subtract __SIZEOF_POINTER__ to subtract
// one from edi as there is no 0 byte run
// and the size is already aligned.
- movl (THREAD_ROSALLOC_RUNS_OFFSET - __SIZEOF_POINTER__)(%ebx, %edi, __SIZEOF_POINTER__), %ebx
+ movl (THREAD_ROSALLOC_RUNS_OFFSET - __SIZEOF_POINTER__)(%ebx, %ecx, __SIZEOF_POINTER__), %ebx
// Load free_list head (edi),
// this will be the return value.
- movl (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)(%ebx), %edi
- test %edi, %edi
- jz .Lart_quick_alloc_object_rosalloc_slow_path
+ movl (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)(%ebx), %ecx
+ jecxz .Lart_quick_alloc_object_resolved_rosalloc_slow_path
// Point of no slow path. Won't go to
- // the slow path from here on. Ok to
- // clobber eax and ecx.
- movl %edi, %eax
+ // the slow path from here on.
// Load the next pointer of the head
// and update head of free list with
// next pointer
- movl ROSALLOC_SLOT_NEXT_OFFSET(%eax), %edi
- movl %edi, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)(%ebx)
+ movl ROSALLOC_SLOT_NEXT_OFFSET(%ecx), %edx
+ movl %edx, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)(%ebx)
// Decrement size of free list by 1
decl (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)(%ebx)
// Store the class pointer in the
@@ -1011,141 +1001,104 @@
#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
#error "Class pointer needs to overwrite next pointer."
#endif
- POISON_HEAP_REF edx
- movl %edx, MIRROR_OBJECT_CLASS_OFFSET(%eax)
+ POISON_HEAP_REF eax
+ movl %eax, MIRROR_OBJECT_CLASS_OFFSET(%ecx)
movl %fs:THREAD_SELF_OFFSET, %ebx // ebx = thread
// Push the new object onto the thread
// local allocation stack and
// increment the thread local
// allocation stack top.
- movl THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET(%ebx), %edi
- movl %eax, (%edi)
- addl LITERAL(COMPRESSED_REFERENCE_SIZE), %edi
- movl %edi, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET(%ebx)
+ movl THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET(%ebx), %eax
+ movl %ecx, (%eax)
+ addl LITERAL(COMPRESSED_REFERENCE_SIZE), %eax
+ movl %eax, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET(%ebx)
// No fence needed for x86.
- POP edi
+ movl %ecx, %eax // Move object to return register
ret
-.Lart_quick_alloc_object_rosalloc_slow_path:
- POP edi
+.Lart_quick_alloc_object_resolved_rosalloc_slow_path:
SETUP_SAVE_REFS_ONLY_FRAME ebx, ebx // save ref containing registers for GC
// Outgoing argument set up
- PUSH eax // alignment padding
+ subl LITERAL(8), %esp // alignment padding
pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
CFI_ADJUST_CFA_OFFSET(4)
- PUSH ecx
PUSH eax
- call SYMBOL(artAllocObjectFromCodeRosAlloc) // cxx_name(arg0, arg1, Thread*)
+ call SYMBOL(artAllocObjectFromCodeResolvedRosAlloc) // cxx_name(arg0, Thread*)
addl LITERAL(16), %esp // pop arguments
CFI_ADJUST_CFA_OFFSET(-16)
RESTORE_SAVE_REFS_ONLY_FRAME // restore frame up to return address
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER // return or deliver exception
-END_FUNCTION art_quick_alloc_object_rosalloc
+END_FUNCTION art_quick_alloc_object_resolved_rosalloc
-// The common fast path code for art_quick_alloc_object_tlab and art_quick_alloc_object_region_tlab.
+// The common fast path code for art_quick_alloc_object_resolved_tlab
+// and art_quick_alloc_object_resolved_region_tlab.
//
-// EAX: type_idx/return_value, ECX: ArtMethod*, EDX: the class.
-MACRO1(ALLOC_OBJECT_TLAB_FAST_PATH, slowPathLabel)
- testl %edx, %edx // Check null class
- jz VAR(slowPathLabel)
+// EAX: type/return_value
+MACRO1(ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH, slowPathLabel)
movl %fs:THREAD_SELF_OFFSET, %ebx // ebx = thread
movl THREAD_LOCAL_END_OFFSET(%ebx), %edi // Load thread_local_end.
subl THREAD_LOCAL_POS_OFFSET(%ebx), %edi // Compute the remaining buffer size.
- movl MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET(%edx), %esi // Load the object size.
- cmpl %edi, %esi // Check if it fits.
+ movl MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET(%eax), %ecx // Load the object size.
+ cmpl %edi, %ecx // Check if it fits.
ja VAR(slowPathLabel)
- movl THREAD_LOCAL_POS_OFFSET(%ebx), %eax // Load thread_local_pos
+ movl THREAD_LOCAL_POS_OFFSET(%ebx), %edx // Load thread_local_pos
// as allocated object.
- addl %eax, %esi // Add the object size.
- movl %esi, THREAD_LOCAL_POS_OFFSET(%ebx) // Update thread_local_pos.
+ addl %edx, %ecx // Add the object size.
+ movl %ecx, THREAD_LOCAL_POS_OFFSET(%ebx) // Update thread_local_pos.
incl THREAD_LOCAL_OBJECTS_OFFSET(%ebx) // Increase thread_local_objects.
// Store the class pointer in the header.
// No fence needed for x86.
- POISON_HEAP_REF edx
- movl %edx, MIRROR_OBJECT_CLASS_OFFSET(%eax)
+ POISON_HEAP_REF eax
+ movl %eax, MIRROR_OBJECT_CLASS_OFFSET(%edx)
+ movl %edx, %eax
POP edi
- POP esi
ret // Fast path succeeded.
END_MACRO
-// The common slow path code for art_quick_alloc_object_tlab and art_quick_alloc_object_region_tlab.
-MACRO1(ALLOC_OBJECT_TLAB_SLOW_PATH, cxx_name)
+// The common slow path code for art_quick_alloc_object_resolved_tlab
+// and art_quick_alloc_object_resolved_region_tlab.
+MACRO1(ALLOC_OBJECT_RESOLVED_TLAB_SLOW_PATH, cxx_name)
POP edi
- POP esi
SETUP_SAVE_REFS_ONLY_FRAME ebx, ebx // save ref containing registers for GC
// Outgoing argument set up
- PUSH eax // alignment padding
+ subl LITERAL(8), %esp // alignment padding
+ CFI_ADJUST_CFA_OFFSET(8)
pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
CFI_ADJUST_CFA_OFFSET(4)
- PUSH ecx
PUSH eax
- call CALLVAR(cxx_name) // cxx_name(arg0, arg1, Thread*)
+ call CALLVAR(cxx_name) // cxx_name(arg0, Thread*)
addl LITERAL(16), %esp
CFI_ADJUST_CFA_OFFSET(-16)
RESTORE_SAVE_REFS_ONLY_FRAME // restore frame up to return address
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER // return or deliver exception
END_MACRO
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB). May be called
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB). May be called
// for CC if the GC is not marking.
-DEFINE_FUNCTION art_quick_alloc_object_tlab
+DEFINE_FUNCTION art_quick_alloc_object_resolved_tlab
// Fast path tlab allocation.
- // EAX: uint32_t type_idx/return value, ECX: ArtMethod*.
- // EBX, EDX: free.
- PUSH esi
+ // EAX: type
+ // EBX, ECX, EDX: free.
PUSH edi
- movl ART_METHOD_DEX_CACHE_TYPES_OFFSET_32(%ecx), %edx // Load dex cache resolved types array
- // Might need to break down into multiple instructions to get the base address in a register.
- // Load the class
- movl 0(%edx, %eax, COMPRESSED_REFERENCE_SIZE), %edx
- ALLOC_OBJECT_TLAB_FAST_PATH .Lart_quick_alloc_object_tlab_slow_path
-.Lart_quick_alloc_object_tlab_slow_path:
- ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeTLAB
-END_FUNCTION art_quick_alloc_object_tlab
+ ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lart_quick_alloc_object_resolved_tlab_slow_path
+.Lart_quick_alloc_object_resolved_tlab_slow_path:
+ ALLOC_OBJECT_RESOLVED_TLAB_SLOW_PATH artAllocObjectFromCodeResolvedTLAB
+END_FUNCTION art_quick_alloc_object_resolved_tlab
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB).
-DEFINE_FUNCTION art_quick_alloc_object_region_tlab
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB).
+DEFINE_FUNCTION art_quick_alloc_object_resolved_region_tlab
// Fast path region tlab allocation.
- // EAX: uint32_t type_idx/return value, ECX: ArtMethod*.
- // EBX, EDX: free.
+ // EAX: type/return value
+ // EBX, ECX, EDX: free.
#if !defined(USE_READ_BARRIER)
int3
int3
#endif
- PUSH esi
PUSH edi
- movl ART_METHOD_DEX_CACHE_TYPES_OFFSET_32(%ecx), %edx // Load dex cache resolved types array
- // Might need to break down into multiple instructions to get the base address in a register.
- // Load the class
- movl 0(%edx, %eax, COMPRESSED_REFERENCE_SIZE), %edx
- // Read barrier for class load.
- cmpl LITERAL(0), %fs:THREAD_IS_GC_MARKING_OFFSET
- jz .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit
- // Null check so that we can load the lock word.
- testl %edx, %edx
- jz .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit
- // Check the mark bit, if it is 1 return.
- testl LITERAL(LOCK_WORD_MARK_BIT_MASK_SHIFTED), MIRROR_OBJECT_LOCK_WORD_OFFSET(%edx)
- jz .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path
-.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit:
- ALLOC_OBJECT_TLAB_FAST_PATH .Lart_quick_alloc_object_region_tlab_slow_path
-.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path:
- // The read barrier slow path. Mark the class.
- PUSH eax
- PUSH ecx
- // Outgoing argument set up
- subl MACRO_LITERAL(8), %esp // Alignment padding
- CFI_ADJUST_CFA_OFFSET(8)
- PUSH edx // Pass the class as the first param.
- call SYMBOL(artReadBarrierMark) // cxx_name(mirror::Object* obj)
- movl %eax, %edx
- addl MACRO_LITERAL(12), %esp
- CFI_ADJUST_CFA_OFFSET(-12)
- POP ecx
- POP eax
- jmp .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit
-.Lart_quick_alloc_object_region_tlab_slow_path:
- ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeRegionTLAB
-END_FUNCTION art_quick_alloc_object_region_tlab
+ ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lart_quick_alloc_object_resolved_region_tlab_slow_path
+.Lart_quick_alloc_object_resolved_region_tlab_slow_path:
+ ALLOC_OBJECT_RESOLVED_TLAB_SLOW_PATH artAllocObjectFromCodeResolvedRegionTLAB
+END_FUNCTION art_quick_alloc_object_resolved_region_tlab
+
DEFINE_FUNCTION art_quick_resolve_string
SETUP_SAVE_EVERYTHING_FRAME ebx, ebx
diff --git a/runtime/arch/x86_64/instruction_set_features_x86_64.h b/runtime/arch/x86_64/instruction_set_features_x86_64.h
index bc0f708..83f4093 100644
--- a/runtime/arch/x86_64/instruction_set_features_x86_64.h
+++ b/runtime/arch/x86_64/instruction_set_features_x86_64.h
@@ -68,15 +68,19 @@
protected:
// Parse a string of the form "ssse3" adding these to a new InstructionSetFeatures.
std::unique_ptr<const InstructionSetFeatures>
- AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+ AddFeaturesFromSplitString(const std::vector<std::string>& features,
std::string* error_msg) const OVERRIDE {
- return X86InstructionSetFeatures::AddFeaturesFromSplitString(smp, features, true, error_msg);
+ return X86InstructionSetFeatures::AddFeaturesFromSplitString(features, true, error_msg);
}
private:
- X86_64InstructionSetFeatures(bool smp, bool has_SSSE3, bool has_SSE4_1, bool has_SSE4_2,
- bool has_AVX, bool has_AVX2, bool has_POPCNT)
- : X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+ X86_64InstructionSetFeatures(bool has_SSSE3,
+ bool has_SSE4_1,
+ bool has_SSE4_2,
+ bool has_AVX,
+ bool has_AVX2,
+ bool has_POPCNT)
+ : X86InstructionSetFeatures(has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
has_AVX2, has_POPCNT) {
}
diff --git a/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc b/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc
index f2b2cd8..3c2ceac 100644
--- a/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc
+++ b/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc
@@ -27,9 +27,9 @@
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("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt",
+ EXPECT_STREQ("-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt",
x86_64_features->GetFeatureString().c_str());
- EXPECT_EQ(x86_64_features->AsBitmap(), 1U);
+ EXPECT_EQ(x86_64_features->AsBitmap(), 0U);
}
} // namespace art
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 4c46b08..facd563 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -983,7 +983,6 @@
// Comment out allocators that have x86_64 specific asm.
// Region TLAB:
-// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
@@ -996,11 +995,9 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
// Normal TLAB:
-// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
-// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_tlab, TLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_tlab, TLAB)
@@ -1009,29 +1006,25 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB)
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc).
-DEFINE_FUNCTION art_quick_alloc_object_rosalloc
+
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc).
+DEFINE_FUNCTION art_quick_alloc_object_resolved_rosalloc
// Fast path rosalloc allocation.
- // RDI: type_idx, RSI: ArtMethod*, RAX: return value
- // RDX, RCX, R8, R9: free.
- movq ART_METHOD_DEX_CACHE_TYPES_OFFSET_64(%rsi), %rdx // Load dex cache resolved types array
- // Load the class (edx)
- movl 0(%rdx, %rdi, COMPRESSED_REFERENCE_SIZE), %edx
- testl %edx, %edx // Check null class
- jz .Lart_quick_alloc_object_rosalloc_slow_path
+ // RDI: mirror::Class*, RAX: return value
+ // RSI, RDX, RCX, R8, R9: free.
// Check if the thread local
// allocation stack has room.
movq %gs:THREAD_SELF_OFFSET, %r8 // r8 = thread
movq THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET(%r8), %rcx // rcx = alloc stack top.
cmpq THREAD_LOCAL_ALLOC_STACK_END_OFFSET(%r8), %rcx
- jae .Lart_quick_alloc_object_rosalloc_slow_path
+ jae .Lart_quick_alloc_object_resolved_rosalloc_slow_path
// Load the object size
- movl MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET(%rdx), %eax
+ movl MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET(%rdi), %eax
// Check if the size is for a thread
// local allocation. Also does the
// initialized and finalizable checks.
cmpl LITERAL(ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE), %eax
- ja .Lart_quick_alloc_object_rosalloc_slow_path
+ ja .Lart_quick_alloc_object_resolved_rosalloc_slow_path
// Compute the rosalloc bracket index
// from the size.
shrq LITERAL(ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT), %rax
@@ -1045,7 +1038,7 @@
// will be the return val.
movq (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)(%r9), %rax
testq %rax, %rax
- jz .Lart_quick_alloc_object_rosalloc_slow_path
+ jz .Lart_quick_alloc_object_resolved_rosalloc_slow_path
// "Point of no slow path". Won't go to the slow path from here on. OK to clobber rdi and rsi.
// Push the new object onto the thread
// local allocation stack and
@@ -1066,17 +1059,17 @@
#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
#error "Class pointer needs to overwrite next pointer."
#endif
- POISON_HEAP_REF edx
- movl %edx, MIRROR_OBJECT_CLASS_OFFSET(%rax)
+ POISON_HEAP_REF edi
+ movl %edi, MIRROR_OBJECT_CLASS_OFFSET(%rax)
// Decrement the size of the free list
decl (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)(%r9)
// No fence necessary for x86.
ret
-.Lart_quick_alloc_object_rosalloc_slow_path:
+.Lart_quick_alloc_object_resolved_rosalloc_slow_path:
SETUP_SAVE_REFS_ONLY_FRAME // save ref containing registers for GC
// Outgoing argument set up
- movq %gs:THREAD_SELF_OFFSET, %rdx // pass Thread::Current()
- call SYMBOL(artAllocObjectFromCodeRosAlloc) // cxx_name(arg0, arg1, Thread*)
+ movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current()
+ call SYMBOL(artAllocObjectFromCodeResolvedRosAlloc) // cxx_name(arg0, Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME // restore frame up to return address
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER // return or deliver exception
END_FUNCTION art_quick_alloc_object_rosalloc
@@ -1095,19 +1088,19 @@
// TODO: delete ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH since it is the same as
// ALLOC_OBJECT_INITIALIZED_TLAB_FAST_PATH.
//
-// RDI: type_idx, RSI: ArtMethod*, RDX/EDX: the class, RAX: return value.
-// RCX: scratch, r8: Thread::Current().
+// RDI: the class, RAX: return value.
+// RCX, RSI, RDX: scratch, r8: Thread::Current().
MACRO1(ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH, slowPathLabel)
ALLOC_OBJECT_INITIALIZED_TLAB_FAST_PATH(RAW_VAR(slowPathLabel))
END_MACRO
// The fast path code for art_quick_alloc_object_initialized_region_tlab.
//
-// RDI: type_idx, RSI: ArtMethod*, RDX/EDX: the class, RAX: return value.
-// RCX: scratch, r8: Thread::Current().
+// RDI: the class, RSI: ArtMethod*, RAX: return value.
+// RCX, RSI, RDX: scratch, r8: Thread::Current().
MACRO1(ALLOC_OBJECT_INITIALIZED_TLAB_FAST_PATH, slowPathLabel)
movq %gs:THREAD_SELF_OFFSET, %r8 // r8 = thread
- movl MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET(%rdx), %ecx // Load the object size.
+ movl MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET(%rdi), %ecx // Load the object size.
movq THREAD_LOCAL_POS_OFFSET(%r8), %rax
addq %rax, %rcx // Add size to pos, note that these
// are both 32 bit ints, overflow
@@ -1120,8 +1113,8 @@
// Store the class pointer in the
// header.
// No fence needed for x86.
- POISON_HEAP_REF edx
- movl %edx, MIRROR_OBJECT_CLASS_OFFSET(%rax)
+ POISON_HEAP_REF edi
+ movl %edi, MIRROR_OBJECT_CLASS_OFFSET(%rax)
ret // Fast path succeeded.
END_MACRO
@@ -1164,12 +1157,14 @@
ret // Fast path succeeded.
END_MACRO
-// The common slow path code for art_quick_alloc_object_tlab and art_quick_alloc_object_region_tlab.
+
+// The common slow path code for art_quick_alloc_object_{resolved, initialized}_tlab
+// and art_quick_alloc_object_{resolved, initialized}_region_tlab.
MACRO1(ALLOC_OBJECT_TLAB_SLOW_PATH, cxx_name)
SETUP_SAVE_REFS_ONLY_FRAME // save ref containing registers for GC
// Outgoing argument set up
- movq %gs:THREAD_SELF_OFFSET, %rdx // pass Thread::Current()
- call CALLVAR(cxx_name) // cxx_name(arg0, arg1, Thread*)
+ movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current()
+ call CALLVAR(cxx_name) // cxx_name(arg0, Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME // restore frame up to return address
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER // return or deliver exception
END_MACRO
@@ -1184,26 +1179,11 @@
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER // return or deliver exception
END_MACRO
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB). May be
-// called with CC if the GC is not active.
-DEFINE_FUNCTION art_quick_alloc_object_tlab
- // RDI: uint32_t type_idx, RSI: ArtMethod*
- // RDX, RCX, R8, R9: free. RAX: return val.
- movq ART_METHOD_DEX_CACHE_TYPES_OFFSET_64(%rsi), %rdx // Load dex cache resolved types array
- // Might need to break down into multiple instructions to get the base address in a register.
- // Load the class
- movl 0(%rdx, %rdi, COMPRESSED_REFERENCE_SIZE), %edx
- ALLOC_OBJECT_TLAB_FAST_PATH .Lart_quick_alloc_object_tlab_slow_path
-.Lart_quick_alloc_object_tlab_slow_path:
- ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeTLAB
-END_FUNCTION art_quick_alloc_object_tlab
-
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB). May be
// called with CC if the GC is not active.
DEFINE_FUNCTION art_quick_alloc_object_resolved_tlab
- // RDI: mirror::Class* klass, RSI: ArtMethod*
- // RDX, RCX, R8, R9: free. RAX: return val.
- movq %rdi, %rdx
+ // RDI: mirror::Class* klass
+ // RDX, RSI, RCX, R8, R9: free. RAX: return val.
ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lart_quick_alloc_object_resolved_tlab_slow_path
.Lart_quick_alloc_object_resolved_tlab_slow_path:
ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeResolvedTLAB
@@ -1212,9 +1192,8 @@
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB).
// May be called with CC if the GC is not active.
DEFINE_FUNCTION art_quick_alloc_object_initialized_tlab
- // RDI: mirror::Class* klass, RSI: ArtMethod*
- // RDX, RCX, R8, R9: free. RAX: return val.
- movq %rdi, %rdx
+ // RDI: mirror::Class* klass
+ // RDX, RSI, RCX, R8, R9: free. RAX: return val.
ALLOC_OBJECT_INITIALIZED_TLAB_FAST_PATH .Lart_quick_alloc_object_initialized_tlab_slow_path
.Lart_quick_alloc_object_initialized_tlab_slow_path:
ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeInitializedTLAB
@@ -1292,49 +1271,12 @@
ALLOC_ARRAY_TLAB_SLOW_PATH artAllocArrayFromCodeResolvedRegionTLAB
END_FUNCTION art_quick_alloc_array_resolved_region_tlab
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB).
-DEFINE_FUNCTION art_quick_alloc_object_region_tlab
- // Fast path region tlab allocation.
- // RDI: uint32_t type_idx, RSI: ArtMethod*
- // RDX, RCX, R8, R9: free. RAX: return val.
- ASSERT_USE_READ_BARRIER
- movq ART_METHOD_DEX_CACHE_TYPES_OFFSET_64(%rsi), %rdx // Load dex cache resolved types array
- movl 0(%rdx, %rdi, COMPRESSED_REFERENCE_SIZE), %edx // Load the class
- // Null check so that we can load the lock word.
- testl %edx, %edx
- jz .Lart_quick_alloc_object_region_tlab_slow_path
- // Since we have allocation entrypoint switching, we know the GC is marking.
- // Check the mark bit, if it is 0, do the read barrier mark.
- testl LITERAL(LOCK_WORD_MARK_BIT_MASK_SHIFTED), MIRROR_OBJECT_LOCK_WORD_OFFSET(%edx)
- jz .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path
-.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit:
- // Use resolved one since we already did the null check.
- ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lart_quick_alloc_object_region_tlab_slow_path
-.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path:
- // The read barrier slow path. Mark the class.
- PUSH rdi
- PUSH rsi
- subq LITERAL(8), %rsp // 16 byte alignment
- // Outgoing argument set up
- movq %rdx, %rdi // Pass the class as the first param.
- call SYMBOL(artReadBarrierMark) // cxx_name(mirror::Object* obj)
- movq %rax, %rdx
- addq LITERAL(8), %rsp
- POP rsi
- POP rdi
- jmp .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit
-.Lart_quick_alloc_object_region_tlab_slow_path:
- ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeRegionTLAB
-END_FUNCTION art_quick_alloc_object_region_tlab
-
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB).
DEFINE_FUNCTION art_quick_alloc_object_resolved_region_tlab
// Fast path region tlab allocation.
- // RDI: mirror::Class* klass, RSI: ArtMethod*
- // RDX, RCX, R8, R9: free. RAX: return val.
+ // RDI: mirror::Class* klass
+ // RDX, RSI, RCX, R8, R9: free. RAX: return val.
ASSERT_USE_READ_BARRIER
- // No read barrier since the caller is responsible for that.
- movq %rdi, %rdx
ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lart_quick_alloc_object_resolved_region_tlab_slow_path
.Lart_quick_alloc_object_resolved_region_tlab_slow_path:
ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeResolvedRegionTLAB
@@ -1343,10 +1285,9 @@
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB).
DEFINE_FUNCTION art_quick_alloc_object_initialized_region_tlab
// Fast path region tlab allocation.
- // RDI: mirror::Class* klass, RSI: ArtMethod*
- // RDX, RCX, R8, R9: free. RAX: return val.
+ // RDI: mirror::Class* klass
+ // RDX, RSI, RCX, R8, R9: free. RAX: return val.
ASSERT_USE_READ_BARRIER
- movq %rdi, %rdx
// No read barrier since the caller is responsible for that.
ALLOC_OBJECT_INITIALIZED_TLAB_FAST_PATH .Lart_quick_alloc_object_initialized_region_tlab_slow_path
.Lart_quick_alloc_object_initialized_region_tlab_slow_path:
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index e4972da..bfdddf7 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -98,7 +98,7 @@
ADD_TEST_EQ(THREAD_LOCAL_END_OFFSET,
art::Thread::ThreadLocalEndOffset<POINTER_SIZE>().Int32Value())
// Offset of field Thread::tlsPtr_.thread_local_objects.
-#define THREAD_LOCAL_OBJECTS_OFFSET (THREAD_LOCAL_END_OFFSET + 2 * __SIZEOF_POINTER__)
+#define THREAD_LOCAL_OBJECTS_OFFSET (THREAD_LOCAL_END_OFFSET + __SIZEOF_POINTER__)
ADD_TEST_EQ(THREAD_LOCAL_OBJECTS_OFFSET,
art::Thread::ThreadLocalObjectsOffset<POINTER_SIZE>().Int32Value())
// Offset of field Thread::tlsPtr_.mterp_current_ibase.
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5b8d4e4..8586b78 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4280,9 +4280,10 @@
void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out) {
// Create constructor for Proxy that must initialize the method.
- CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 18u);
+ CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 23u);
+
ArtMethod* proxy_constructor = GetClassRoot(kJavaLangReflectProxy)->GetDirectMethodUnchecked(
- 2, image_pointer_size_);
+ 8, image_pointer_size_);
DCHECK_EQ(std::string(proxy_constructor->GetName()), "<init>");
// Ensure constructor is in dex cache so that we can use the dex cache to look up the overridden
// constructor method.
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 14c9c21..469c45c 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -127,43 +127,21 @@
self->GetManagedStack()->GetTopQuickFrame(), type, true /* do_caller_check */);
}
-template <const bool kAccessCheck>
-ALWAYS_INLINE
-inline mirror::Class* CheckObjectAlloc(dex::TypeIndex type_idx,
- ArtMethod* method,
- Thread* self,
- bool* slow_path) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- PointerSize pointer_size = class_linker->GetImagePointerSize();
- mirror::Class* klass = method->GetDexCacheResolvedType<false>(type_idx, pointer_size);
- if (UNLIKELY(klass == nullptr)) {
- klass = class_linker->ResolveType(type_idx, method);
+ALWAYS_INLINE inline mirror::Class* CheckObjectAlloc(mirror::Class* klass,
+ Thread* self,
+ bool* slow_path)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_) {
+ if (UNLIKELY(!klass->IsInstantiable())) {
+ self->ThrowNewException("Ljava/lang/InstantiationError;", klass->PrettyDescriptor().c_str());
*slow_path = true;
- if (klass == nullptr) {
- DCHECK(self->IsExceptionPending());
- return nullptr; // Failure
- } else {
- DCHECK(!self->IsExceptionPending());
- }
+ return nullptr; // Failure
}
- if (kAccessCheck) {
- if (UNLIKELY(!klass->IsInstantiable())) {
- self->ThrowNewException("Ljava/lang/InstantiationError;", klass->PrettyDescriptor().c_str());
- *slow_path = true;
- return nullptr; // Failure
- }
- if (UNLIKELY(klass->IsClassClass())) {
- ThrowIllegalAccessError(nullptr, "Class %s is inaccessible",
- klass->PrettyDescriptor().c_str());
- *slow_path = true;
- return nullptr; // Failure
- }
- mirror::Class* referrer = method->GetDeclaringClass();
- if (UNLIKELY(!referrer->CanAccess(klass))) {
- ThrowIllegalAccessErrorClass(referrer, klass);
- *slow_path = true;
- return nullptr; // Failure
- }
+ if (UNLIKELY(klass->IsClassClass())) {
+ ThrowIllegalAccessError(nullptr, "Class %s is inaccessible",
+ klass->PrettyDescriptor().c_str());
+ *slow_path = true;
+ return nullptr; // Failure
}
if (UNLIKELY(!klass->IsInitialized())) {
StackHandleScope<1> hs(self);
@@ -191,7 +169,9 @@
ALWAYS_INLINE
inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* klass,
Thread* self,
- bool* slow_path) {
+ bool* slow_path)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_) {
if (UNLIKELY(!klass->IsInitialized())) {
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(klass));
@@ -213,18 +193,15 @@
return klass;
}
-// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
-// cannot be resolved, throw an error. If it can, use it to create an instance.
-// When verification/compiler hasn't been able to verify access, optionally perform an access
-// check.
-template <bool kAccessCheck, bool kInstrumented>
+// Allocate an instance of klass. Throws InstantationError if klass is not instantiable,
+// or IllegalAccessError if klass is j.l.Class. Performs a clinit check too.
+template <bool kInstrumented>
ALWAYS_INLINE
-inline mirror::Object* AllocObjectFromCode(dex::TypeIndex type_idx,
- ArtMethod* method,
+inline mirror::Object* AllocObjectFromCode(mirror::Class* klass,
Thread* self,
gc::AllocatorType allocator_type) {
bool slow_path = false;
- mirror::Class* klass = CheckObjectAlloc<kAccessCheck>(type_idx, method, self, &slow_path);
+ klass = CheckObjectAlloc(klass, self, &slow_path);
if (UNLIKELY(slow_path)) {
if (klass == nullptr) {
return nullptr;
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 7cc136e..4794610 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -45,27 +45,10 @@
class ScopedObjectAccessAlreadyRunnable;
class Thread;
-template <const bool kAccessCheck>
-ALWAYS_INLINE inline mirror::Class* CheckObjectAlloc(dex::TypeIndex type_idx,
- ArtMethod* method,
- Thread* self,
- bool* slow_path)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!Roles::uninterruptible_);
-
-ALWAYS_INLINE inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* klass,
- Thread* self,
- bool* slow_path)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!Roles::uninterruptible_);
-
// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
// cannot be resolved, throw an error. If it can, use it to create an instance.
-// When verification/compiler hasn't been able to verify access, optionally perform an access
-// check.
-template <bool kAccessCheck, bool kInstrumented>
-ALWAYS_INLINE inline mirror::Object* AllocObjectFromCode(dex::TypeIndex type_idx,
- ArtMethod* method,
+template <bool kInstrumented>
+ALWAYS_INLINE inline mirror::Object* AllocObjectFromCode(mirror::Class* klass,
Thread* self,
gc::AllocatorType allocator_type)
REQUIRES_SHARED(Locks::mutator_lock_)
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index 82bb8e5..2d06508 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -29,87 +29,58 @@
static constexpr bool kUseTlabFastPath = true;
+template <bool kInitialized,
+ bool kFinalize,
+ bool kInstrumented,
+ gc::AllocatorType allocator_type>
+static ALWAYS_INLINE inline mirror::Object* artAllocObjectFromCode(
+ mirror::Class* klass,
+ Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ScopedQuickEntrypointChecks sqec(self);
+ DCHECK(klass != nullptr);
+ if (kUseTlabFastPath && !kInstrumented && allocator_type == gc::kAllocatorTypeTLAB) {
+ if (kInitialized || klass->IsInitialized()) {
+ if (!kFinalize || !klass->IsFinalizable()) {
+ size_t byte_count = klass->GetObjectSize();
+ byte_count = RoundUp(byte_count, gc::space::BumpPointerSpace::kAlignment);
+ mirror::Object* obj;
+ if (LIKELY(byte_count < self->TlabSize())) {
+ obj = self->AllocTlab(byte_count);
+ DCHECK(obj != nullptr) << "AllocTlab can't fail";
+ obj->SetClass(klass);
+ if (kUseBakerReadBarrier) {
+ obj->AssertReadBarrierState();
+ }
+ QuasiAtomic::ThreadFenceForConstructor();
+ return obj;
+ }
+ }
+ }
+ }
+ if (kInitialized) {
+ return AllocObjectFromCodeInitialized<kInstrumented>(klass, self, allocator_type);
+ } else if (!kFinalize) {
+ return AllocObjectFromCodeResolved<kInstrumented>(klass, self, allocator_type);
+ } else {
+ return AllocObjectFromCode<kInstrumented>(klass, self, allocator_type);
+ }
+}
+
#define GENERATE_ENTRYPOINTS_FOR_ALLOCATOR_INST(suffix, suffix2, instrumented_bool, allocator_type) \
-extern "C" mirror::Object* artAllocObjectFromCode ##suffix##suffix2( \
- uint32_t type_idx, ArtMethod* method, Thread* self) \
+extern "C" mirror::Object* artAllocObjectFromCodeWithChecks##suffix##suffix2( \
+ mirror::Class* klass, Thread* self) \
REQUIRES_SHARED(Locks::mutator_lock_) { \
- ScopedQuickEntrypointChecks sqec(self); \
- if (kUseTlabFastPath && !(instrumented_bool) && (allocator_type) == gc::kAllocatorTypeTLAB) { \
- mirror::Class* klass = method->GetDexCacheResolvedType<false>(dex::TypeIndex(type_idx), \
- kRuntimePointerSize); \
- if (LIKELY(klass != nullptr && klass->IsInitialized() && !klass->IsFinalizable())) { \
- size_t byte_count = klass->GetObjectSize(); \
- byte_count = RoundUp(byte_count, gc::space::BumpPointerSpace::kAlignment); \
- mirror::Object* obj; \
- if (LIKELY(byte_count < self->TlabSize())) { \
- obj = self->AllocTlab(byte_count); \
- DCHECK(obj != nullptr) << "AllocTlab can't fail"; \
- obj->SetClass(klass); \
- if (kUseBakerReadBarrier) { \
- obj->AssertReadBarrierState(); \
- } \
- QuasiAtomic::ThreadFenceForConstructor(); \
- return obj; \
- } \
- } \
- } \
- return AllocObjectFromCode<false, instrumented_bool>(dex::TypeIndex(type_idx), \
- method, \
- self, \
- allocator_type); \
+ return artAllocObjectFromCode<false, true, instrumented_bool, allocator_type>(klass, self); \
} \
extern "C" mirror::Object* artAllocObjectFromCodeResolved##suffix##suffix2( \
- mirror::Class* klass, ArtMethod* method ATTRIBUTE_UNUSED, Thread* self) \
+ mirror::Class* klass, Thread* self) \
REQUIRES_SHARED(Locks::mutator_lock_) { \
- ScopedQuickEntrypointChecks sqec(self); \
- if (kUseTlabFastPath && !(instrumented_bool) && (allocator_type) == gc::kAllocatorTypeTLAB) { \
- if (LIKELY(klass->IsInitialized())) { \
- size_t byte_count = klass->GetObjectSize(); \
- byte_count = RoundUp(byte_count, gc::space::BumpPointerSpace::kAlignment); \
- mirror::Object* obj; \
- if (LIKELY(byte_count < self->TlabSize())) { \
- obj = self->AllocTlab(byte_count); \
- DCHECK(obj != nullptr) << "AllocTlab can't fail"; \
- obj->SetClass(klass); \
- if (kUseBakerReadBarrier) { \
- obj->AssertReadBarrierState(); \
- } \
- QuasiAtomic::ThreadFenceForConstructor(); \
- return obj; \
- } \
- } \
- } \
- return AllocObjectFromCodeResolved<instrumented_bool>(klass, self, allocator_type); \
+ return artAllocObjectFromCode<false, false, instrumented_bool, allocator_type>(klass, self); \
} \
extern "C" mirror::Object* artAllocObjectFromCodeInitialized##suffix##suffix2( \
- mirror::Class* klass, ArtMethod* method ATTRIBUTE_UNUSED, Thread* self) \
+ mirror::Class* klass, Thread* self) \
REQUIRES_SHARED(Locks::mutator_lock_) { \
- ScopedQuickEntrypointChecks sqec(self); \
- if (kUseTlabFastPath && !(instrumented_bool) && (allocator_type) == gc::kAllocatorTypeTLAB) { \
- size_t byte_count = klass->GetObjectSize(); \
- byte_count = RoundUp(byte_count, gc::space::BumpPointerSpace::kAlignment); \
- mirror::Object* obj; \
- if (LIKELY(byte_count < self->TlabSize())) { \
- obj = self->AllocTlab(byte_count); \
- DCHECK(obj != nullptr) << "AllocTlab can't fail"; \
- obj->SetClass(klass); \
- if (kUseBakerReadBarrier) { \
- obj->AssertReadBarrierState(); \
- } \
- QuasiAtomic::ThreadFenceForConstructor(); \
- return obj; \
- } \
- } \
- return AllocObjectFromCodeInitialized<instrumented_bool>(klass, self, allocator_type); \
-} \
-extern "C" mirror::Object* artAllocObjectFromCodeWithAccessCheck##suffix##suffix2( \
- uint32_t type_idx, ArtMethod* method, Thread* self) \
- REQUIRES_SHARED(Locks::mutator_lock_) { \
- ScopedQuickEntrypointChecks sqec(self); \
- return AllocObjectFromCode<true, instrumented_bool>(dex::TypeIndex(type_idx), \
- method, \
- self, \
- allocator_type); \
+ return artAllocObjectFromCode<true, false, instrumented_bool, allocator_type>(klass, self); \
} \
extern "C" mirror::Array* artAllocArrayFromCode##suffix##suffix2( \
uint32_t type_idx, int32_t component_count, ArtMethod* method, Thread* self) \
@@ -220,10 +191,9 @@
extern "C" void* art_quick_alloc_array##suffix(uint32_t, int32_t, ArtMethod* ref); \
extern "C" void* art_quick_alloc_array_resolved##suffix(mirror::Class* klass, int32_t, ArtMethod* ref); \
extern "C" void* art_quick_alloc_array_with_access_check##suffix(uint32_t, int32_t, ArtMethod* ref); \
-extern "C" void* art_quick_alloc_object##suffix(uint32_t type_idx, ArtMethod* ref); \
-extern "C" void* art_quick_alloc_object_resolved##suffix(mirror::Class* klass, ArtMethod* ref); \
-extern "C" void* art_quick_alloc_object_initialized##suffix(mirror::Class* klass, ArtMethod* ref); \
-extern "C" void* art_quick_alloc_object_with_access_check##suffix(uint32_t type_idx, ArtMethod* ref); \
+extern "C" void* art_quick_alloc_object_resolved##suffix(mirror::Class* klass); \
+extern "C" void* art_quick_alloc_object_initialized##suffix(mirror::Class* klass); \
+extern "C" void* art_quick_alloc_object_with_checks##suffix(mirror::Class* klass); \
extern "C" void* art_quick_check_and_alloc_array##suffix(uint32_t, int32_t, ArtMethod* ref); \
extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix(uint32_t, int32_t, ArtMethod* ref); \
extern "C" void* art_quick_alloc_string_from_bytes##suffix(void*, int32_t, int32_t, int32_t); \
@@ -233,9 +203,9 @@
extern "C" void* art_quick_alloc_array_resolved##suffix##_instrumented(mirror::Class* klass, int32_t, ArtMethod* ref); \
extern "C" void* art_quick_alloc_array_with_access_check##suffix##_instrumented(uint32_t, int32_t, ArtMethod* ref); \
extern "C" void* art_quick_alloc_object##suffix##_instrumented(uint32_t type_idx, ArtMethod* ref); \
-extern "C" void* art_quick_alloc_object_resolved##suffix##_instrumented(mirror::Class* klass, ArtMethod* ref); \
-extern "C" void* art_quick_alloc_object_initialized##suffix##_instrumented(mirror::Class* klass, ArtMethod* ref); \
-extern "C" void* art_quick_alloc_object_with_access_check##suffix##_instrumented(uint32_t type_idx, ArtMethod* ref); \
+extern "C" void* art_quick_alloc_object_resolved##suffix##_instrumented(mirror::Class* klass); \
+extern "C" void* art_quick_alloc_object_initialized##suffix##_instrumented(mirror::Class* klass); \
+extern "C" void* art_quick_alloc_object_with_checks##suffix##_instrumented(mirror::Class* klass); \
extern "C" void* art_quick_check_and_alloc_array##suffix##_instrumented(uint32_t, int32_t, ArtMethod* ref); \
extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix##_instrumented(uint32_t, int32_t, ArtMethod* ref); \
extern "C" void* art_quick_alloc_string_from_bytes##suffix##_instrumented(void*, int32_t, int32_t, int32_t); \
@@ -246,10 +216,9 @@
qpoints->pAllocArray = art_quick_alloc_array##suffix##_instrumented; \
qpoints->pAllocArrayResolved = art_quick_alloc_array_resolved##suffix##_instrumented; \
qpoints->pAllocArrayWithAccessCheck = art_quick_alloc_array_with_access_check##suffix##_instrumented; \
- qpoints->pAllocObject = art_quick_alloc_object##suffix##_instrumented; \
qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix##_instrumented; \
qpoints->pAllocObjectInitialized = art_quick_alloc_object_initialized##suffix##_instrumented; \
- qpoints->pAllocObjectWithAccessCheck = art_quick_alloc_object_with_access_check##suffix##_instrumented; \
+ qpoints->pAllocObjectWithChecks = art_quick_alloc_object_with_checks##suffix##_instrumented; \
qpoints->pCheckAndAllocArray = art_quick_check_and_alloc_array##suffix##_instrumented; \
qpoints->pCheckAndAllocArrayWithAccessCheck = art_quick_check_and_alloc_array_with_access_check##suffix##_instrumented; \
qpoints->pAllocStringFromBytes = art_quick_alloc_string_from_bytes##suffix##_instrumented; \
@@ -259,10 +228,9 @@
qpoints->pAllocArray = art_quick_alloc_array##suffix; \
qpoints->pAllocArrayResolved = art_quick_alloc_array_resolved##suffix; \
qpoints->pAllocArrayWithAccessCheck = art_quick_alloc_array_with_access_check##suffix; \
- qpoints->pAllocObject = art_quick_alloc_object##suffix; \
qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix; \
qpoints->pAllocObjectInitialized = art_quick_alloc_object_initialized##suffix; \
- qpoints->pAllocObjectWithAccessCheck = art_quick_alloc_object_with_access_check##suffix; \
+ qpoints->pAllocObjectWithChecks = art_quick_alloc_object_with_checks##suffix; \
qpoints->pCheckAndAllocArray = art_quick_check_and_alloc_array##suffix; \
qpoints->pCheckAndAllocArrayWithAccessCheck = art_quick_check_and_alloc_array_with_access_check##suffix; \
qpoints->pAllocStringFromBytes = art_quick_alloc_string_from_bytes##suffix; \
diff --git a/runtime/entrypoints/quick/quick_entrypoints_list.h b/runtime/entrypoints/quick/quick_entrypoints_list.h
index a1c5082..0911aeb 100644
--- a/runtime/entrypoints/quick/quick_entrypoints_list.h
+++ b/runtime/entrypoints/quick/quick_entrypoints_list.h
@@ -23,10 +23,9 @@
V(AllocArray, void*, uint32_t, int32_t, ArtMethod*) \
V(AllocArrayResolved, void*, mirror::Class*, int32_t, ArtMethod*) \
V(AllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*) \
- V(AllocObject, void*, uint32_t, ArtMethod*) \
- V(AllocObjectResolved, void*, mirror::Class*, ArtMethod*) \
- V(AllocObjectInitialized, void*, mirror::Class*, ArtMethod*) \
- V(AllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*) \
+ V(AllocObjectResolved, void*, mirror::Class*) \
+ V(AllocObjectInitialized, void*, mirror::Class*) \
+ V(AllocObjectWithChecks, void*, mirror::Class*) \
V(CheckAndAllocArray, void*, uint32_t, int32_t, ArtMethod*) \
V(CheckAndAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*) \
V(AllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t) \
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 1283660..6866abb 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -122,9 +122,9 @@
// Skip across the entrypoints structures.
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_start, thread_local_pos, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_pos, thread_local_end, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_end, thread_local_start, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_start, thread_local_objects, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_end, thread_local_objects, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, mterp_current_ibase, sizeof(size_t));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_current_ibase, mterp_default_ibase, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_default_ibase, mterp_alt_ibase, sizeof(void*));
@@ -156,13 +156,13 @@
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArray, pAllocArrayResolved, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArrayResolved, pAllocArrayWithAccessCheck,
sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArrayWithAccessCheck, pAllocObject, sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObject, pAllocObjectResolved, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArrayWithAccessCheck, pAllocObjectResolved,
+ sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObjectResolved, pAllocObjectInitialized,
sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObjectInitialized, pAllocObjectWithAccessCheck,
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObjectInitialized, pAllocObjectWithChecks,
sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObjectWithAccessCheck, pCheckAndAllocArray,
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObjectWithChecks, pCheckAndAllocArray,
sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCheckAndAllocArray, pCheckAndAllocArrayWithAccessCheck,
sizeof(void*));
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index cebb566..e1117e6 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -58,7 +58,7 @@
bool measure_read_barrier_slow_path)
: GarbageCollector(heap,
name_prefix + (name_prefix.empty() ? "" : " ") +
- "concurrent copying + mark sweep"),
+ "concurrent copying"),
region_space_(nullptr), gc_barrier_(new Barrier(0)),
gc_mark_stack_(accounting::ObjectStack::Create("concurrent copying gc mark stack",
kDefaultGcMarkStackSize,
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index a815b83..f2aa5a7 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -89,7 +89,7 @@
SemiSpace::SemiSpace(Heap* heap, bool generational, const std::string& name_prefix)
: GarbageCollector(heap,
- name_prefix + (name_prefix.empty() ? "" : " ") + "marksweep + semispace"),
+ name_prefix + (name_prefix.empty() ? "" : " ") + "semispace"),
mark_stack_(nullptr),
is_large_object_space_immune_(false),
to_space_(nullptr),
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index b0d7fb2..d7dfcd4 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -508,9 +508,8 @@
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
} else {
- obj = AllocObjectFromCode<do_access_check, true>(
- dex::TypeIndex(inst->VRegB_21c()),
- shadow_frame.GetMethod(),
+ obj = AllocObjectFromCode<true>(
+ c.Ptr(),
self,
Runtime::Current()->GetHeap()->GetCurrentAllocator());
}
diff --git a/runtime/interpreter/mterp/arm64/footer.S b/runtime/interpreter/mterp/arm64/footer.S
index 6ffbd3f..388fc8d 100644
--- a/runtime/interpreter/mterp/arm64/footer.S
+++ b/runtime/interpreter/mterp/arm64/footer.S
@@ -267,13 +267,7 @@
b MterpDone
MterpReturn:
ldr x2, [xFP, #OFF_FP_RESULT_REGISTER]
- ldr lr, [xSELF, #THREAD_FLAGS_OFFSET]
str x0, [x2]
- mov x0, xSELF
- ands lr, lr, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
- b.eq check2
- bl MterpSuspendCheck // (self)
-check2:
mov x0, #1 // signal return to caller.
MterpDone:
/*
diff --git a/runtime/interpreter/mterp/mips64/footer.S b/runtime/interpreter/mterp/mips64/footer.S
index 64772c8..312fa9c 100644
--- a/runtime/interpreter/mterp/mips64/footer.S
+++ b/runtime/interpreter/mterp/mips64/footer.S
@@ -222,13 +222,7 @@
*/
MterpReturn:
ld a2, OFF_FP_RESULT_REGISTER(rFP)
- lw ra, THREAD_FLAGS_OFFSET(rSELF)
sd a0, 0(a2)
- move a0, rSELF
- and ra, ra, THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
- beqzc ra, check2
- jal MterpSuspendCheck # (self)
-check2:
li v0, 1 # signal return to caller.
MterpDone:
/*
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index c8c1563..369c261 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -375,10 +375,9 @@
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
} else {
- obj = AllocObjectFromCode<false, true>(dex::TypeIndex(inst->VRegB_21c()),
- shadow_frame->GetMethod(),
- self,
- Runtime::Current()->GetHeap()->GetCurrentAllocator());
+ obj = AllocObjectFromCode<true>(c,
+ self,
+ Runtime::Current()->GetHeap()->GetCurrentAllocator());
}
}
if (UNLIKELY(obj == nullptr)) {
diff --git a/runtime/interpreter/mterp/out/mterp_arm64.S b/runtime/interpreter/mterp/out/mterp_arm64.S
index 34d99a8..681790d 100644
--- a/runtime/interpreter/mterp/out/mterp_arm64.S
+++ b/runtime/interpreter/mterp/out/mterp_arm64.S
@@ -7246,13 +7246,7 @@
b MterpDone
MterpReturn:
ldr x2, [xFP, #OFF_FP_RESULT_REGISTER]
- ldr lr, [xSELF, #THREAD_FLAGS_OFFSET]
str x0, [x2]
- mov x0, xSELF
- ands lr, lr, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
- b.eq check2
- bl MterpSuspendCheck // (self)
-check2:
mov x0, #1 // signal return to caller.
MterpDone:
/*
diff --git a/runtime/interpreter/mterp/out/mterp_mips64.S b/runtime/interpreter/mterp/out/mterp_mips64.S
index 037787f..bf09666 100644
--- a/runtime/interpreter/mterp/out/mterp_mips64.S
+++ b/runtime/interpreter/mterp/out/mterp_mips64.S
@@ -12293,13 +12293,7 @@
*/
MterpReturn:
ld a2, OFF_FP_RESULT_REGISTER(rFP)
- lw ra, THREAD_FLAGS_OFFSET(rSELF)
sd a0, 0(a2)
- move a0, rSELF
- and ra, ra, THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
- beqzc ra, check2
- jal MterpSuspendCheck # (self)
-check2:
li v0, 1 # signal return to caller.
MterpDone:
/*
diff --git a/runtime/oat.cc b/runtime/oat.cc
index cebe765..1a07cdc 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -469,10 +469,6 @@
return IsKeyEnabled(OatHeader::kPicKey);
}
-bool OatHeader::HasPatchInfo() const {
- return IsKeyEnabled(OatHeader::kHasPatchInfoKey);
-}
-
bool OatHeader::IsDebuggable() const {
return IsKeyEnabled(OatHeader::kDebuggableKey);
}
diff --git a/runtime/oat.h b/runtime/oat.h
index 0f4cbbb..dc103e2 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,13 +32,12 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- static constexpr uint8_t kOatVersion[] = { '0', '9', '3', '\0' };
+ static constexpr uint8_t kOatVersion[] = { '0', '9', '5', '\0' }; // alloc entrypoints change
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDex2OatHostKey = "dex2oat-host";
static constexpr const char* kPicKey = "pic";
- static constexpr const char* kHasPatchInfoKey = "has-patch-info";
static constexpr const char* kDebuggableKey = "debuggable";
static constexpr const char* kNativeDebuggableKey = "native-debuggable";
static constexpr const char* kCompilerFilter = "compiler-filter";
@@ -110,7 +109,6 @@
size_t GetHeaderSize() const;
bool IsPic() const;
- bool HasPatchInfo() const;
bool IsDebuggable() const;
bool IsNativeDebuggable() const;
CompilerFilter::Filter GetCompilerFilter() const;
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 0bf7136..38df427 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -710,7 +710,7 @@
return false;
}
#ifdef ART_TARGET_ANDROID
- android_dlextinfo extinfo;
+ android_dlextinfo extinfo = {};
extinfo.flags = ANDROID_DLEXT_FORCE_LOAD | // Force-load, don't reuse handle
// (open oat files multiple
// times).
@@ -1438,10 +1438,6 @@
method->SetEntryPointFromQuickCompiledCode(GetQuickCode());
}
-bool OatFile::HasPatchInfo() const {
- return GetOatHeader().HasPatchInfo();
-}
-
bool OatFile::IsPic() const {
return GetOatHeader().IsPic();
// TODO: Check against oat_patches. b/18144996
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 29add5b..62d99fb 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -104,8 +104,6 @@
return is_executable_;
}
- bool HasPatchInfo() const;
-
bool IsPic() const;
// Indicates whether the oat file was compiled with full debugging capability.
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index ee7cf9d..f12a5e7 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -203,10 +203,6 @@
case kDex2OatForRelocation:
case kDex2OatForFilter:
return GenerateOatFile(error_msg);
-
- case kPatchoatForRelocation: {
- return RelocateOatFile(info.Filename(), error_msg);
- }
}
UNREACHABLE();
}
@@ -420,58 +416,6 @@
}
OatFileAssistant::ResultOfAttemptToUpdate
-OatFileAssistant::RelocateOatFile(const std::string* input_file, std::string* error_msg) {
- CHECK(error_msg != nullptr);
-
- if (input_file == nullptr) {
- *error_msg = "Patching of oat file for dex location " + dex_location_
- + " not attempted because the input file name could not be determined.";
- return kUpdateNotAttempted;
- }
- const std::string& input_file_name = *input_file;
-
- if (oat_.Filename() == nullptr) {
- *error_msg = "Patching of oat file for dex location " + dex_location_
- + " not attempted because the oat file name could not be determined.";
- return kUpdateNotAttempted;
- }
- const std::string& oat_file_name = *oat_.Filename();
-
- const ImageInfo* image_info = GetImageInfo();
- Runtime* runtime = Runtime::Current();
- if (image_info == nullptr) {
- *error_msg = "Patching of oat file " + oat_file_name
- + " not attempted because no image location was found.";
- return kUpdateNotAttempted;
- }
-
- if (!runtime->IsDex2OatEnabled()) {
- *error_msg = "Patching of oat file " + oat_file_name
- + " not attempted because dex2oat is disabled";
- return kUpdateNotAttempted;
- }
-
- std::vector<std::string> argv;
- argv.push_back(runtime->GetPatchoatExecutable());
- argv.push_back("--instruction-set=" + std::string(GetInstructionSetString(isa_)));
- argv.push_back("--input-oat-file=" + input_file_name);
- argv.push_back("--output-oat-file=" + oat_file_name);
- argv.push_back("--patched-image-location=" + image_info->location);
-
- std::string command_line(android::base::Join(argv, ' '));
- if (!Exec(argv, error_msg)) {
- // Manually delete the file. This ensures there is no garbage left over if
- // the process unexpectedly died.
- unlink(oat_file_name.c_str());
- return kUpdateFailed;
- }
-
- // Mark that the oat file has changed and we should try to reload.
- oat_.Reset();
- return kUpdateSucceeded;
-}
-
-OatFileAssistant::ResultOfAttemptToUpdate
OatFileAssistant::GenerateOatFile(std::string* error_msg) {
CHECK(error_msg != nullptr);
@@ -852,13 +796,7 @@
return kNoDexOptNeeded;
}
- if (filter_okay && Status() == kOatRelocationOutOfDate && HasPatchInfo()) {
- return kPatchoatForRelocation;
- }
-
if (oat_file_assistant_->HasOriginalDexFiles()) {
- // Run dex2oat for relocation if we didn't have the patch info necessary
- // to use patchoat.
if (filter_okay && Status() == kOatRelocationOutOfDate) {
return kDex2OatForRelocation;
}
@@ -921,11 +859,6 @@
return (file != nullptr && file->IsExecutable());
}
-bool OatFileAssistant::OatFileInfo::HasPatchInfo() {
- const OatFile* file = GetFile();
- return (file != nullptr && file->HasPatchInfo());
-}
-
void OatFileAssistant::OatFileInfo::Reset() {
load_attempted_ = false;
file_.reset();
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index bed1edc..588a698 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -67,14 +67,9 @@
kDex2OatForFilter = 3,
// dex2oat should be run to update the apk/jar because the existing code
- // is not relocated to match the boot image and does not have the
- // necessary patch information to use patchoat.
+ // is not relocated to match the boot image.
// Matches Java: dalvik.system.DexFile.DEX2OAT_FOR_RELOCATION
kDex2OatForRelocation = 4,
-
- // patchoat should be run to update the apk/jar.
- // Matches Java: dalvik.system.DexFile.PATCHOAT_FOR_RELOCATION
- kPatchoatForRelocation = 5,
};
enum OatStatus {
@@ -237,15 +232,6 @@
// Returns the status of the oat file for the dex location.
OatStatus OatFileStatus();
- // Generates the oat file by relocation from the named input file.
- // This does not check the current status before attempting to relocate the
- // oat file.
- //
- // If the result is not kUpdateSucceeded, the value of error_msg will be set
- // to a string describing why there was a failure or the update was not
- // attempted. error_msg must not be null.
- ResultOfAttemptToUpdate RelocateOatFile(const std::string* input_file, std::string* error_msg);
-
// Generate the oat file from the dex file using the current runtime
// compiler options.
// This does not check the current status before attempting to generate the
@@ -328,8 +314,6 @@
// given target_compilation_filter.
// profile_changed should be true to indicate the profile has recently
// changed for this dex location.
- // If patchoat is needed, this function will return the kPatchOatNeeded
- // status, not the kSelfPatchOatNeeded status.
DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
bool profile_changed);
@@ -341,9 +325,6 @@
// Returns true if the file is opened executable.
bool IsExecutable();
- // Returns true if the file has patch info required to run patchoat.
- bool HasPatchInfo();
-
// Clear any cached information about the file that depends on the
// contents of the file. This does not reset the provided filename.
void Reset();
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 26dbaab..afa804c 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -85,7 +85,6 @@
CompilerFilter::Filter filter,
bool relocate,
bool pic,
- bool with_patch_info,
bool with_alternate_image) {
std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA));
std::string dalvik_cache_tmp = dalvik_cache + ".redirected";
@@ -111,10 +110,6 @@
args.push_back("--compile-pic");
}
- if (with_patch_info) {
- args.push_back("--include-patch-information");
- }
-
std::string image_location = GetImageLocation();
if (with_alternate_image) {
args.push_back("--boot-image=" + GetImageLocation2());
@@ -139,7 +134,6 @@
&error_msg));
ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
EXPECT_EQ(pic, odex_file->IsPic());
- EXPECT_EQ(with_patch_info, odex_file->HasPatchInfo());
EXPECT_EQ(filter, odex_file->GetCompilerFilter());
std::unique_ptr<ImageHeader> image_header(
@@ -181,7 +175,6 @@
filter,
/*relocate*/false,
/*pic*/false,
- /*with_patch_info*/true,
/*with_alternate_image*/false);
}
@@ -193,21 +186,6 @@
filter,
/*relocate*/false,
/*pic*/true,
- /*with_patch_info*/false,
- /*with_alternate_image*/false);
- }
-
- // Generate a non-PIC odex file without patch information for the purposes
- // of test. The generated odex file will be un-relocated.
- void GenerateNoPatchOdexForTest(const std::string& dex_location,
- const std::string& odex_location,
- CompilerFilter::Filter filter) {
- GenerateOatForTest(dex_location,
- odex_location,
- filter,
- /*relocate*/false,
- /*pic*/false,
- /*with_patch_info*/false,
/*with_alternate_image*/false);
}
@@ -216,7 +194,6 @@
CompilerFilter::Filter filter,
bool relocate,
bool pic,
- bool with_patch_info,
bool with_alternate_image) {
std::string oat_location;
std::string error_msg;
@@ -227,7 +204,6 @@
filter,
relocate,
pic,
- with_patch_info,
with_alternate_image);
}
@@ -237,7 +213,6 @@
filter,
/*relocate*/true,
/*pic*/false,
- /*with_patch_info*/false,
/*with_alternate_image*/false);
}
@@ -519,7 +494,6 @@
CompilerFilter::kSpeed,
/*relocate*/true,
/*pic*/false,
- /*with_patch_info*/false,
/*with_alternate_image*/true);
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
@@ -548,7 +522,6 @@
CompilerFilter::kVerifyAtRuntime,
/*relocate*/true,
/*pic*/false,
- /*with_patch_info*/false,
/*with_alternate_image*/true);
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
@@ -564,7 +537,6 @@
}
// Case: We have a DEX file and an ODEX file, but no OAT file.
-// Expect: The status is kPatchOatNeeded.
TEST_F(OatFileAssistantTest, DexOdexNoOat) {
std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar";
std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
@@ -578,7 +550,7 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(-OatFileAssistant::kPatchoatForRelocation,
+ EXPECT_EQ(-OatFileAssistant::kDex2OatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -591,15 +563,14 @@
ASSERT_TRUE(oat_file.get() != nullptr);
}
-// Case: We have a stripped DEX file and an ODEX file, but no OAT file.
-// Expect: The status is kPatchOatNeeded
+// Case: We have a stripped DEX file and a PIC ODEX file, but no OAT file.
TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar";
std::string odex_location = GetOdexDir() + "/StrippedDexOdexNoOat.odex";
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
+ GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Strip the dex file
Copy(GetStrippedDexSrc1(), dex_location);
@@ -607,28 +578,14 @@
// Verify the status.
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
- EXPECT_EQ(-OatFileAssistant::kPatchoatForRelocation,
+ EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
- // Make the oat file up to date.
- std::string error_msg;
- Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
- ASSERT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
-
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
-
- EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
- EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
-
// Verify we can load the dex files from it.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -638,8 +595,7 @@
EXPECT_EQ(1u, dex_files.size());
}
-// Case: We have a stripped DEX file, an ODEX file, and an out-of-date OAT file.
-// Expect: The status is kPatchOatNeeded.
+// Case: We have a stripped DEX file, a PIC ODEX file, and an out-of-date OAT file.
TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar";
std::string odex_location = GetOdexDir() + "/StrippedDexOdexOat.odex";
@@ -650,7 +606,7 @@
// Create the odex file
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
+ GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Strip the dex file.
Copy(GetStrippedDexSrc1(), dex_location);
@@ -660,30 +616,14 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(-OatFileAssistant::kPatchoatForRelocation,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, // Can't run dex2oat because dex file is stripped.
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
-
- EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
- EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
-
- // Make the oat file up to date.
- std::string error_msg;
- Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
- ASSERT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
-
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, // Can't run dex2oat because dex file is stripped.
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Verify we can load the dex files from it.
@@ -732,90 +672,9 @@
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
}
-// Case: We have a DEX file, no ODEX file and an OAT file that needs
-// relocation.
-// Expect: The status is kSelfPatchOatNeeded.
-TEST_F(OatFileAssistantTest, SelfRelocation) {
- std::string dex_location = GetScratchDir() + "/SelfRelocation.jar";
- std::string oat_location = GetOdexDir() + "/SelfRelocation.oat";
-
- // Create the dex and odex files
- Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, oat_location, CompilerFilter::kSpeed);
-
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- oat_location.c_str(), kRuntimeISA, true);
-
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
- EXPECT_EQ(OatFileAssistant::kPatchoatForRelocation,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
-
- EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
- EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OatFileStatus());
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
-
- // Make the oat file up to date.
- std::string error_msg;
- Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
- ASSERT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
-
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
-
- EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
- EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
-
- std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
- ASSERT_TRUE(oat_file.get() != nullptr);
- EXPECT_TRUE(oat_file->IsExecutable());
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
- EXPECT_EQ(1u, dex_files.size());
-}
-
-// Case: We have a DEX file, no ODEX file and an OAT file that needs
-// relocation but doesn't have patch info.
-// Expect: The status is kDex2OatNeeded, because we can't run patchoat.
-TEST_F(OatFileAssistantTest, NoSelfRelocation) {
- std::string dex_location = GetScratchDir() + "/NoSelfRelocation.jar";
- std::string oat_location = GetOdexDir() + "/NoSelfRelocation.oat";
-
- // Create the dex and odex files
- Copy(GetDexSrc1(), dex_location);
- GenerateNoPatchOdexForTest(dex_location, oat_location, CompilerFilter::kSpeed);
-
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- oat_location.c_str(), kRuntimeISA, true);
-
- EXPECT_EQ(OatFileAssistant::kDex2OatForRelocation,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
-
- // Make the oat file up to date.
- std::string error_msg;
- Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
- ASSERT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
-
- std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
- ASSERT_TRUE(oat_file.get() != nullptr);
- EXPECT_TRUE(oat_file->IsExecutable());
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
- EXPECT_EQ(1u, dex_files.size());
-}
-
// Case: We have a DEX file, an ODEX file and an OAT file, where the ODEX and
// OAT files both have patch delta of 0.
-// Expect: It shouldn't crash, and status is kSelfPatchOatNeeded.
+// Expect: It shouldn't crash.
TEST_F(OatFileAssistantTest, OdexOatOverlap) {
std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
std::string odex_location = GetOdexDir() + "/OdexOatOverlap.odex";
@@ -833,10 +692,10 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(),
oat_location.c_str(), kRuntimeISA, true);
- // kPatchoatForRelocation is expected rather than -kPatchoatForRelocation
+ // kDex2OatForRelocation is expected rather than -kDex2OatForRelocation
// based on the assumption that the oat location is more up-to-date than the odex
// location, even if they both need relocation.
- EXPECT_EQ(OatFileAssistant::kPatchoatForRelocation,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -1285,7 +1144,6 @@
{OatFileAssistant::kDex2OatForBootImage, "DEX2OAT_FOR_BOOT_IMAGE"},
{OatFileAssistant::kDex2OatForFilter, "DEX2OAT_FOR_FILTER"},
{OatFileAssistant::kDex2OatForRelocation, "DEX2OAT_FOR_RELOCATION"},
- {OatFileAssistant::kPatchoatForRelocation, "PATCHOAT_FOR_RELOCATION"}
};
ScopedObjectAccess soa(Thread::Current());
diff --git a/runtime/openjdkjvmti/Android.bp b/runtime/openjdkjvmti/Android.bp
index 6105fec..be06dd7 100644
--- a/runtime/openjdkjvmti/Android.bp
+++ b/runtime/openjdkjvmti/Android.bp
@@ -24,6 +24,8 @@
"ti_field.cc",
"ti_heap.cc",
"ti_method.cc",
+ "ti_object.cc",
+ "ti_properties.cc",
"ti_stack.cc",
"ti_redefine.cc",
"transform.cc"],
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index faaeff3..936049f 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -50,6 +50,8 @@
#include "ti_field.h"
#include "ti_heap.h"
#include "ti_method.h"
+#include "ti_object.h"
+#include "ti_properties.h"
#include "ti_redefine.h"
#include "ti_stack.h"
#include "transform.h"
@@ -598,7 +600,7 @@
static jvmtiError IsModifiableClass(jvmtiEnv* env,
jclass klass,
jboolean* is_modifiable_class_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return Redefiner::IsModifiableClass(env, klass, is_modifiable_class_ptr);
}
static jvmtiError GetClassLoader(jvmtiEnv* env, jclass klass, jobject* classloader_ptr) {
@@ -622,11 +624,11 @@
}
static jvmtiError GetObjectSize(jvmtiEnv* env, jobject object, jlong* size_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return ObjectUtil::GetObjectSize(env, object, size_ptr);
}
static jvmtiError GetObjectHashCode(jvmtiEnv* env, jobject object, jint* hash_code_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return ObjectUtil::GetObjectHashCode(env, object, hash_code_ptr);
}
static jvmtiError GetObjectMonitorUsage(jvmtiEnv* env,
@@ -688,13 +690,13 @@
static jvmtiError GetMaxLocals(jvmtiEnv* env,
jmethodID method,
jint* max_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return MethodUtil::GetMaxLocals(env, method, max_ptr);
}
static jvmtiError GetArgumentsSize(jvmtiEnv* env,
jmethodID method,
jint* size_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return MethodUtil::GetArgumentsSize(env, method, size_ptr);
}
static jvmtiError GetLineNumberTable(jvmtiEnv* env,
@@ -708,7 +710,7 @@
jmethodID method,
jlocation* start_location_ptr,
jlocation* end_location_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return MethodUtil::GetMethodLocation(env, method, start_location_ptr, end_location_ptr);
}
static jvmtiError GetLocalVariableTable(jvmtiEnv* env,
@@ -726,15 +728,15 @@
}
static jvmtiError IsMethodNative(jvmtiEnv* env, jmethodID method, jboolean* is_native_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return MethodUtil::IsMethodNative(env, method, is_native_ptr);
}
static jvmtiError IsMethodSynthetic(jvmtiEnv* env, jmethodID method, jboolean* is_synthetic_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return MethodUtil::IsMethodSynthetic(env, method, is_synthetic_ptr);
}
static jvmtiError IsMethodObsolete(jvmtiEnv* env, jmethodID method, jboolean* is_obsolete_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return MethodUtil::IsMethodObsolete(env, method, is_obsolete_ptr);
}
static jvmtiError SetNativeMethodPrefix(jvmtiEnv* env, const char* prefix) {
@@ -839,19 +841,28 @@
static jvmtiError GetExtensionFunctions(jvmtiEnv* env,
jint* extension_count_ptr,
jvmtiExtensionFunctionInfo** extensions) {
- return ERR(NOT_IMPLEMENTED);
+ // We do not have any extension functions.
+ *extension_count_ptr = 0;
+ *extensions = nullptr;
+
+ return ERR(NONE);
}
static jvmtiError GetExtensionEvents(jvmtiEnv* env,
jint* extension_count_ptr,
jvmtiExtensionEventInfo** extensions) {
- return ERR(NOT_IMPLEMENTED);
+ // We do not have any extension events.
+ *extension_count_ptr = 0;
+ *extensions = nullptr;
+
+ return ERR(NONE);
}
static jvmtiError SetExtensionEventCallback(jvmtiEnv* env,
jint extension_event_index,
jvmtiExtensionEvent callback) {
- return ERR(NOT_IMPLEMENTED);
+ // We do not have any extension events, so any call is illegal.
+ return ERR(ILLEGAL_ARGUMENT);
}
static jvmtiError GetPotentialCapabilities(jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr) {
@@ -1024,15 +1035,15 @@
}
static jvmtiError GetSystemProperties(jvmtiEnv* env, jint* count_ptr, char*** property_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return PropertiesUtil::GetSystemProperties(env, count_ptr, property_ptr);
}
static jvmtiError GetSystemProperty(jvmtiEnv* env, const char* property, char** value_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return PropertiesUtil::GetSystemProperty(env, property, value_ptr);
}
static jvmtiError SetSystemProperty(jvmtiEnv* env, const char* property, const char* value) {
- return ERR(NOT_IMPLEMENTED);
+ return PropertiesUtil::SetSystemProperty(env, property, value);
}
static jvmtiError GetPhase(jvmtiEnv* env, jvmtiPhase* phase_ptr) {
@@ -1180,7 +1191,7 @@
reinterpret_cast<uint8_t*>(dex_file),
&error);
if (ret != OK) {
- LOG(ERROR) << "FAILURE TO REDEFINE " << error;
+ LOG(WARNING) << "FAILURE TO REDEFINE " << error;
}
return ret;
}
diff --git a/runtime/openjdkjvmti/art_jvmti.h b/runtime/openjdkjvmti/art_jvmti.h
index 48b29a3..5eadc5a 100644
--- a/runtime/openjdkjvmti/art_jvmti.h
+++ b/runtime/openjdkjvmti/art_jvmti.h
@@ -105,9 +105,10 @@
using JvmtiUniquePtr = std::unique_ptr<unsigned char, JvmtiDeleter>;
+template <typename T>
ALWAYS_INLINE
-static inline JvmtiUniquePtr MakeJvmtiUniquePtr(jvmtiEnv* env, unsigned char* mem) {
- return JvmtiUniquePtr(mem, JvmtiDeleter(env));
+static inline JvmtiUniquePtr MakeJvmtiUniquePtr(jvmtiEnv* env, T* mem) {
+ return JvmtiUniquePtr(reinterpret_cast<unsigned char*>(mem), JvmtiDeleter(env));
}
ALWAYS_INLINE
diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc
index 02b6090..2ddd64a 100644
--- a/runtime/openjdkjvmti/ti_method.cc
+++ b/runtime/openjdkjvmti/ti_method.cc
@@ -41,6 +41,64 @@
namespace openjdkjvmti {
+jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jmethodID method,
+ jint* size_ptr) {
+ if (method == nullptr) {
+ return ERR(INVALID_METHODID);
+ }
+ art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
+
+ if (art_method->IsNative()) {
+ return ERR(NATIVE_METHOD);
+ }
+
+ if (size_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
+ // This isn't specified as an error case, so return 0.
+ *size_ptr = 0;
+ return ERR(NONE);
+ }
+
+ DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
+ *size_ptr = art_method->GetCodeItem()->ins_size_;
+
+ return ERR(NONE);
+}
+
+jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jmethodID method,
+ jint* max_ptr) {
+ if (method == nullptr) {
+ return ERR(INVALID_METHODID);
+ }
+ art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
+
+ if (art_method->IsNative()) {
+ return ERR(NATIVE_METHOD);
+ }
+
+ if (max_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
+ // This isn't specified as an error case, so return 0.
+ *max_ptr = 0;
+ return ERR(NONE);
+ }
+
+ DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
+ *max_ptr = art_method->GetCodeItem()->registers_size_;
+
+ return ERR(NONE);
+}
+
jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env,
jmethodID method,
char** name_ptr,
@@ -107,6 +165,38 @@
return ERR(NONE);
}
+jvmtiError MethodUtil::GetMethodLocation(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jmethodID method,
+ jlocation* start_location_ptr,
+ jlocation* end_location_ptr) {
+ if (method == nullptr) {
+ return ERR(INVALID_METHODID);
+ }
+ art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
+
+ if (art_method->IsNative()) {
+ return ERR(NATIVE_METHOD);
+ }
+
+ if (start_location_ptr == nullptr || end_location_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
+ // This isn't specified as an error case, so return 0/0.
+ *start_location_ptr = 0;
+ *end_location_ptr = 0;
+ return ERR(NONE);
+ }
+
+ DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
+ *start_location_ptr = 0;
+ *end_location_ptr = art_method->GetCodeItem()->insns_size_in_code_units_ - 1;
+
+ return ERR(NONE);
+}
+
jvmtiError MethodUtil::GetMethodModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
jmethodID method,
jint* modifiers_ptr) {
@@ -190,4 +280,43 @@
return ERR(NONE);
}
+template <typename T>
+static jvmtiError IsMethodT(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jmethodID method,
+ T test,
+ jboolean* is_t_ptr) {
+ if (method == nullptr) {
+ return ERR(INVALID_METHODID);
+ }
+ if (is_t_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
+ *is_t_ptr = test(art_method) ? JNI_TRUE : JNI_FALSE;
+
+ return ERR(NONE);
+}
+
+jvmtiError MethodUtil::IsMethodNative(jvmtiEnv* env, jmethodID m, jboolean* is_native_ptr) {
+ auto test = [](art::ArtMethod* method) {
+ return method->IsNative();
+ };
+ return IsMethodT(env, m, test, is_native_ptr);
+}
+
+jvmtiError MethodUtil::IsMethodObsolete(jvmtiEnv* env, jmethodID m, jboolean* is_obsolete_ptr) {
+ auto test = [](art::ArtMethod* method) {
+ return method->IsObsolete();
+ };
+ return IsMethodT(env, m, test, is_obsolete_ptr);
+}
+
+jvmtiError MethodUtil::IsMethodSynthetic(jvmtiEnv* env, jmethodID m, jboolean* is_synthetic_ptr) {
+ auto test = [](art::ArtMethod* method) {
+ return method->IsSynthetic();
+ };
+ return IsMethodT(env, m, test, is_synthetic_ptr);
+}
+
} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_method.h b/runtime/openjdkjvmti/ti_method.h
index fb2fbb2..e5c1705 100644
--- a/runtime/openjdkjvmti/ti_method.h
+++ b/runtime/openjdkjvmti/ti_method.h
@@ -39,6 +39,10 @@
class MethodUtil {
public:
+ static jvmtiError GetArgumentsSize(jvmtiEnv* env, jmethodID method, jint* size_ptr);
+
+ static jvmtiError GetMaxLocals(jvmtiEnv* env, jmethodID method, jint* max_ptr);
+
static jvmtiError GetMethodName(jvmtiEnv* env,
jmethodID method,
char** name_ptr,
@@ -49,6 +53,11 @@
jmethodID method,
jclass* declaring_class_ptr);
+ static jvmtiError GetMethodLocation(jvmtiEnv* env,
+ jmethodID method,
+ jlocation* start_location_ptr,
+ jlocation* end_location_ptr);
+
static jvmtiError GetMethodModifiers(jvmtiEnv* env,
jmethodID method,
jint* modifiers_ptr);
@@ -57,6 +66,10 @@
jmethodID method,
jint* entry_count_ptr,
jvmtiLineNumberEntry** table_ptr);
+
+ static jvmtiError IsMethodNative(jvmtiEnv* env, jmethodID method, jboolean* is_native_ptr);
+ static jvmtiError IsMethodObsolete(jvmtiEnv* env, jmethodID method, jboolean* is_obsolete_ptr);
+ static jvmtiError IsMethodSynthetic(jvmtiEnv* env, jmethodID method, jboolean* is_synthetic_ptr);
};
} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_object.cc b/runtime/openjdkjvmti/ti_object.cc
new file mode 100644
index 0000000..bf84499
--- /dev/null
+++ b/runtime/openjdkjvmti/ti_object.cc
@@ -0,0 +1,76 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jvmti.h. This implementation
+ * is licensed under the same terms as the file jvmti.h. The
+ * copyright and license information for the file jvmti.h follows.
+ *
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "ti_object.h"
+
+#include "art_jvmti.h"
+#include "mirror/object-inl.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread-inl.h"
+
+namespace openjdkjvmti {
+
+jvmtiError ObjectUtil::GetObjectSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jobject jobject,
+ jlong* size_ptr) {
+ if (jobject == nullptr) {
+ return ERR(INVALID_OBJECT);
+ }
+ if (size_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ art::ObjPtr<art::mirror::Object> object = soa.Decode<art::mirror::Object>(jobject);
+
+ *size_ptr = object->SizeOf();
+ return ERR(NONE);
+}
+
+jvmtiError ObjectUtil::GetObjectHashCode(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jobject jobject,
+ jint* hash_code_ptr) {
+ if (jobject == nullptr) {
+ return ERR(INVALID_OBJECT);
+ }
+ if (hash_code_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ art::ObjPtr<art::mirror::Object> object = soa.Decode<art::mirror::Object>(jobject);
+
+ *hash_code_ptr = object->IdentityHashCode();
+
+ return ERR(NONE);
+}
+
+} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_object.h b/runtime/openjdkjvmti/ti_object.h
new file mode 100644
index 0000000..09eee61
--- /dev/null
+++ b/runtime/openjdkjvmti/ti_object.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jvmti.h. This implementation
+ * is licensed under the same terms as the file jvmti.h. The
+ * copyright and license information for the file jvmti.h follows.
+ *
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_OBJECT_H_
+#define ART_RUNTIME_OPENJDKJVMTI_TI_OBJECT_H_
+
+#include "jni.h"
+#include "jvmti.h"
+
+namespace openjdkjvmti {
+
+class ObjectUtil {
+ public:
+ static jvmtiError GetObjectSize(jvmtiEnv* env, jobject object, jlong* size_ptr);
+
+ static jvmtiError GetObjectHashCode(jvmtiEnv* env, jobject object, jint* hash_code_ptr);
+};
+
+} // namespace openjdkjvmti
+
+#endif // ART_RUNTIME_OPENJDKJVMTI_TI_OBJECT_H_
diff --git a/runtime/openjdkjvmti/ti_properties.cc b/runtime/openjdkjvmti/ti_properties.cc
new file mode 100644
index 0000000..46b9e71
--- /dev/null
+++ b/runtime/openjdkjvmti/ti_properties.cc
@@ -0,0 +1,192 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jvmti.h. This implementation
+ * is licensed under the same terms as the file jvmti.h. The
+ * copyright and license information for the file jvmti.h follows.
+ *
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "ti_properties.h"
+
+#include <string.h>
+#include <vector>
+
+#include "art_jvmti.h"
+#include "runtime.h"
+
+namespace openjdkjvmti {
+
+// Hardcoded properties. Tests ensure that these are consistent with libcore's view, as seen
+// in System.java and AndroidHardcodedSystemProperties.java.
+static constexpr const char* kProperties[][2] = {
+ // Recommended by the spec.
+ { "java.vm.vendor", "The Android Project" },
+ { "java.vm.version", "2.1.0" }, // This is Runtime::GetVersion().
+ { "java.vm.name", "Dalvik" },
+ // Android does not provide java.vm.info.
+ //
+ // These are other values provided by AndroidHardcodedSystemProperties.
+ { "java.class.version", "50.0" },
+ { "java.version", "0" },
+ { "java.compiler", "" },
+ { "java.ext.dirs", "" },
+
+ { "java.specification.name", "Dalvik Core Library" },
+ { "java.specification.vendor", "The Android Project" },
+ { "java.specification.version", "0.9" },
+
+ { "java.vendor", "The Android Project" },
+ { "java.vendor.url", "http://www.android.com/" },
+ { "java.vm.name", "Dalvik" },
+ { "java.vm.specification.name", "Dalvik Virtual Machine Specification" },
+ { "java.vm.specification.vendor", "The Android Project" },
+ { "java.vm.specification.version", "0.9" },
+ { "java.vm.vendor", "The Android Project" },
+
+ { "java.vm.vendor.url", "http://www.android.com/" },
+
+ { "java.net.preferIPv6Addresses", "false" },
+
+ { "file.encoding", "UTF-8" },
+
+ { "file.separator", "/" },
+ { "line.separator", "\n" },
+ { "path.separator", ":" },
+
+ { "os.name", "Linux" },
+};
+static constexpr size_t kPropertiesSize = arraysize(kProperties);
+static constexpr const char* kPropertyLibraryPath = "java.library.path";
+static constexpr const char* kPropertyClassPath = "java.class.path";
+
+static jvmtiError Copy(jvmtiEnv* env, const char* in, char** out) {
+ unsigned char* data = nullptr;
+ jvmtiError result = CopyString(env, in, &data);
+ *out = reinterpret_cast<char*>(data);
+ return result;
+}
+
+jvmtiError PropertiesUtil::GetSystemProperties(jvmtiEnv* env,
+ jint* count_ptr,
+ char*** property_ptr) {
+ if (count_ptr == nullptr || property_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+ unsigned char* array_data;
+ jvmtiError array_alloc_result = env->Allocate((kPropertiesSize + 2) * sizeof(char*), &array_data);
+ if (array_alloc_result != ERR(NONE)) {
+ return array_alloc_result;
+ }
+ JvmtiUniquePtr array_data_ptr = MakeJvmtiUniquePtr(env, array_data);
+ char** array = reinterpret_cast<char**>(array_data);
+
+ std::vector<JvmtiUniquePtr> property_copies;
+
+ {
+ char* libpath_data;
+ jvmtiError libpath_result = Copy(env, kPropertyLibraryPath, &libpath_data);
+ if (libpath_result != ERR(NONE)) {
+ return libpath_result;
+ }
+ array[0] = libpath_data;
+ property_copies.push_back(MakeJvmtiUniquePtr(env, libpath_data));
+ }
+
+ {
+ char* classpath_data;
+ jvmtiError classpath_result = Copy(env, kPropertyClassPath, &classpath_data);
+ if (classpath_result != ERR(NONE)) {
+ return classpath_result;
+ }
+ array[1] = classpath_data;
+ property_copies.push_back(MakeJvmtiUniquePtr(env, classpath_data));
+ }
+
+ for (size_t i = 0; i != kPropertiesSize; ++i) {
+ char* data;
+ jvmtiError data_result = Copy(env, kProperties[i][0], &data);
+ if (data_result != ERR(NONE)) {
+ return data_result;
+ }
+ array[i + 2] = data;
+ property_copies.push_back(MakeJvmtiUniquePtr(env, data));
+ }
+
+ // Everything is OK, release the data.
+ array_data_ptr.release();
+ for (auto& uptr : property_copies) {
+ uptr.release();
+ }
+
+ *count_ptr = kPropertiesSize + 2;
+ *property_ptr = array;
+
+ return ERR(NONE);
+}
+
+jvmtiError PropertiesUtil::GetSystemProperty(jvmtiEnv* env,
+ const char* property,
+ char** value_ptr) {
+ if (property == nullptr || value_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ if (strcmp(property, kPropertyLibraryPath) == 0) {
+ // TODO: In the live phase, we should probably compare to System.getProperty. java.library.path
+ // may not be set initially, and is then freely modifiable.
+ const std::vector<std::string>& runtime_props = art::Runtime::Current()->GetProperties();
+ for (const std::string& prop_assignment : runtime_props) {
+ size_t assign_pos = prop_assignment.find('=');
+ if (assign_pos != std::string::npos && assign_pos > 0) {
+ if (prop_assignment.substr(0, assign_pos) == kPropertyLibraryPath) {
+ return Copy(env, prop_assignment.substr(assign_pos + 1).c_str(), value_ptr);
+ }
+ }
+ }
+ return ERR(NOT_AVAILABLE);
+ }
+
+ if (strcmp(property, kPropertyClassPath) == 0) {
+ return Copy(env, art::Runtime::Current()->GetClassPathString().c_str(), value_ptr);
+ }
+
+ for (size_t i = 0; i != kPropertiesSize; ++i) {
+ if (strcmp(property, kProperties[i][0]) == 0) {
+ return Copy(env, kProperties[i][1], value_ptr);
+ }
+ }
+
+ return ERR(NOT_AVAILABLE);
+}
+
+jvmtiError PropertiesUtil::SetSystemProperty(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ const char* property ATTRIBUTE_UNUSED,
+ const char* value ATTRIBUTE_UNUSED) {
+ // We do not allow manipulation of any property here.
+ return ERR(NOT_AVAILABLE);
+}
+
+} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_properties.h b/runtime/openjdkjvmti/ti_properties.h
new file mode 100644
index 0000000..7073481
--- /dev/null
+++ b/runtime/openjdkjvmti/ti_properties.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jvmti.h. This implementation
+ * is licensed under the same terms as the file jvmti.h. The
+ * copyright and license information for the file jvmti.h follows.
+ *
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_PROPERTIES_H_
+#define ART_RUNTIME_OPENJDKJVMTI_TI_PROPERTIES_H_
+
+#include "jni.h"
+#include "jvmti.h"
+
+namespace openjdkjvmti {
+
+class PropertiesUtil {
+ public:
+ static jvmtiError GetSystemProperties(jvmtiEnv* env, jint* count_ptr, char*** property_ptr);
+
+ static jvmtiError GetSystemProperty(jvmtiEnv* env, const char* property, char** value_ptr);
+
+ static jvmtiError SetSystemProperty(jvmtiEnv* env, const char* property, const char* value);
+};
+
+} // namespace openjdkjvmti
+
+#endif // ART_RUNTIME_OPENJDKJVMTI_TI_PROPERTIES_H_
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 926819d..5bf8445 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -37,6 +37,8 @@
#include "art_jvmti.h"
#include "base/logging.h"
+#include "dex_file.h"
+#include "dex_file_types.h"
#include "events-inl.h"
#include "gc/allocation_listener.h"
#include "gc/heap.h"
@@ -64,19 +66,14 @@
art::Thread* thread,
art::LinearAlloc* allocator,
const std::unordered_set<art::ArtMethod*>& obsoleted_methods,
- /*out*/std::unordered_map<art::ArtMethod*, art::ArtMethod*>* obsolete_maps,
- /*out*/bool* success,
- /*out*/std::string* error_msg)
+ /*out*/std::unordered_map<art::ArtMethod*, art::ArtMethod*>* obsolete_maps)
: StackVisitor(thread,
/*context*/nullptr,
StackVisitor::StackWalkKind::kIncludeInlinedFrames),
allocator_(allocator),
obsoleted_methods_(obsoleted_methods),
obsolete_maps_(obsolete_maps),
- success_(success),
- is_runtime_frame_(false),
- error_msg_(error_msg) {
- *success_ = true;
+ is_runtime_frame_(false) {
}
~ObsoleteMethodStackVisitor() OVERRIDE {}
@@ -85,34 +82,17 @@
// Returns true if we successfully installed obsolete methods on this thread, filling
// obsolete_maps_ with the translations if needed. Returns false and fills error_msg if we fail.
// The stack is cleaned up when we fail.
- static bool UpdateObsoleteFrames(
+ static void UpdateObsoleteFrames(
art::Thread* thread,
art::LinearAlloc* allocator,
const std::unordered_set<art::ArtMethod*>& obsoleted_methods,
- /*out*/std::unordered_map<art::ArtMethod*, art::ArtMethod*>* obsolete_maps,
- /*out*/std::string* error_msg) REQUIRES(art::Locks::mutator_lock_) {
- bool success = true;
+ /*out*/std::unordered_map<art::ArtMethod*, art::ArtMethod*>* obsolete_maps)
+ REQUIRES(art::Locks::mutator_lock_) {
ObsoleteMethodStackVisitor visitor(thread,
allocator,
obsoleted_methods,
- obsolete_maps,
- &success,
- error_msg);
+ obsolete_maps);
visitor.WalkStack();
- if (!success) {
- RestoreFrames(thread, *obsolete_maps, error_msg);
- return false;
- } else {
- return true;
- }
- }
-
- static void RestoreFrames(
- art::Thread* thread ATTRIBUTE_UNUSED,
- const std::unordered_map<art::ArtMethod*, art::ArtMethod*>& obsolete_maps ATTRIBUTE_UNUSED,
- std::string* error_msg)
- REQUIRES(art::Locks::mutator_lock_) {
- LOG(FATAL) << "Restoring stack frames is not yet supported. Error was: " << *error_msg;
}
bool VisitFrame() OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
@@ -130,9 +110,7 @@
// works through runtime methods.
// TODO b/33616143
if (!IsShadowFrame() && prev_was_runtime_frame_) {
- *error_msg_ = StringPrintf("Deoptimization failed due to runtime method in stack.");
- *success_ = false;
- return false;
+ LOG(FATAL) << "Deoptimization failed due to runtime method in stack. See b/33616143";
}
// We cannot ensure that the right dex file is used in inlined frames so we don't support
// redefining them.
@@ -150,12 +128,8 @@
auto ptr_size = cl->GetImagePointerSize();
const size_t method_size = art::ArtMethod::Size(ptr_size);
auto* method_storage = allocator_->Alloc(GetThread(), method_size);
- if (method_storage == nullptr) {
- *success_ = false;
- *error_msg_ = StringPrintf("Unable to allocate storage for obsolete version of '%s'",
- old_method->PrettyMethod().c_str());
- return false;
- }
+ CHECK(method_storage != nullptr) << "Unable to allocate storage for obsolete version of '"
+ << old_method->PrettyMethod() << "'";
new_obsolete_method = new (method_storage) art::ArtMethod();
new_obsolete_method->CopyFrom(old_method, ptr_size);
DCHECK_EQ(new_obsolete_method->GetDeclaringClass(), old_method->GetDeclaringClass());
@@ -186,13 +160,50 @@
// values in this map must be added to the obsolete_methods_ (and obsolete_dex_caches_) fields of
// the redefined classes ClassExt by the caller.
std::unordered_map<art::ArtMethod*, art::ArtMethod*>* obsolete_maps_;
- bool* success_;
// TODO REMOVE once either current_method doesn't stick around through suspend points or deopt
// works through runtime methods.
bool is_runtime_frame_;
- std::string* error_msg_;
};
+jvmtiError Redefiner::IsModifiableClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jclass klass,
+ jboolean* is_redefinable) {
+ // TODO Check for the appropriate feature flags once we have enabled them.
+ art::Thread* self = art::Thread::Current();
+ art::ScopedObjectAccess soa(self);
+ art::StackHandleScope<1> hs(self);
+ art::ObjPtr<art::mirror::Object> obj(self->DecodeJObject(klass));
+ if (obj.IsNull()) {
+ return ERR(INVALID_CLASS);
+ }
+ art::Handle<art::mirror::Class> h_klass(hs.NewHandle(obj->AsClass()));
+ std::string err_unused;
+ *is_redefinable =
+ Redefiner::GetClassRedefinitionError(h_klass, &err_unused) == OK ? JNI_TRUE : JNI_FALSE;
+ return OK;
+}
+
+jvmtiError Redefiner::GetClassRedefinitionError(art::Handle<art::mirror::Class> klass,
+ /*out*/std::string* error_msg) {
+ if (klass->IsPrimitive()) {
+ *error_msg = "Modification of primitive classes is not supported";
+ return ERR(UNMODIFIABLE_CLASS);
+ } else if (klass->IsInterface()) {
+ *error_msg = "Modification of Interface classes is currently not supported";
+ return ERR(UNMODIFIABLE_CLASS);
+ } else if (klass->IsArrayClass()) {
+ *error_msg = "Modification of Array classes is not supported";
+ return ERR(UNMODIFIABLE_CLASS);
+ } else if (klass->IsProxyClass()) {
+ *error_msg = "Modification of proxy classes is not supported";
+ return ERR(UNMODIFIABLE_CLASS);
+ }
+
+ // TODO We should check if the class has non-obsoletable methods on the stack
+ LOG(WARNING) << "presence of non-obsoletable methods on stacks is not currently checked";
+ return OK;
+}
+
// Moves dex data to an anonymous, read-only mmap'd region.
std::unique_ptr<art::MemMap> Redefiner::MoveDataToMemMap(const std::string& original_location,
jint data_len,
@@ -446,59 +457,38 @@
art::LinearAlloc* allocator;
std::unordered_map<art::ArtMethod*, art::ArtMethod*> obsolete_map;
std::unordered_set<art::ArtMethod*> obsolete_methods;
- bool success;
- std::string* error_msg;
- CallbackCtx(Redefiner* self, art::LinearAlloc* alloc, std::string* error)
- : r(self), allocator(alloc), success(true), error_msg(error) {}
+ CallbackCtx(Redefiner* self, art::LinearAlloc* alloc)
+ : r(self), allocator(alloc) {}
};
-void DoRestoreObsoleteMethodsCallback(art::Thread* t, void* vdata) NO_THREAD_SAFETY_ANALYSIS {
- CallbackCtx* data = reinterpret_cast<CallbackCtx*>(vdata);
- ObsoleteMethodStackVisitor::RestoreFrames(t, data->obsolete_map, data->error_msg);
-}
-
void DoAllocateObsoleteMethodsCallback(art::Thread* t, void* vdata) NO_THREAD_SAFETY_ANALYSIS {
CallbackCtx* data = reinterpret_cast<CallbackCtx*>(vdata);
- if (data->success) {
- // Don't do anything if we already failed once.
- data->success = ObsoleteMethodStackVisitor::UpdateObsoleteFrames(t,
- data->allocator,
- data->obsolete_methods,
- &data->obsolete_map,
- data->error_msg);
- }
+ ObsoleteMethodStackVisitor::UpdateObsoleteFrames(t,
+ data->allocator,
+ data->obsolete_methods,
+ &data->obsolete_map);
}
// This creates any ArtMethod* structures needed for obsolete methods and ensures that the stack is
// updated so they will be run.
-bool Redefiner::FindAndAllocateObsoleteMethods(art::mirror::Class* art_klass) {
+void Redefiner::FindAndAllocateObsoleteMethods(art::mirror::Class* art_klass) {
art::ScopedAssertNoThreadSuspension ns("No thread suspension during thread stack walking");
art::mirror::ClassExt* ext = art_klass->GetExtData();
CHECK(ext->GetObsoleteMethods() != nullptr);
- CallbackCtx ctx(this, art_klass->GetClassLoader()->GetAllocator(), error_msg_);
+ CallbackCtx ctx(this, art_klass->GetClassLoader()->GetAllocator());
// Add all the declared methods to the map
for (auto& m : art_klass->GetDeclaredMethods(art::kRuntimePointerSize)) {
ctx.obsolete_methods.insert(&m);
- }
- for (art::ArtMethod* old_method : ctx.obsolete_methods) {
- if (old_method->IsIntrinsic()) {
- *error_msg_ = StringPrintf("Method '%s' is intrinsic and cannot be made obsolete!",
- old_method->PrettyMethod().c_str());
- return false;
- }
+ // TODO Allow this or check in IsModifiableClass.
+ DCHECK(!m.IsIntrinsic());
}
{
art::MutexLock mu(self_, *art::Locks::thread_list_lock_);
art::ThreadList* list = art::Runtime::Current()->GetThreadList();
list->ForEach(DoAllocateObsoleteMethodsCallback, static_cast<void*>(&ctx));
- if (!ctx.success) {
- list->ForEach(DoRestoreObsoleteMethodsCallback, static_cast<void*>(&ctx));
- return false;
- }
}
FillObsoleteMethodMap(art_klass, ctx.obsolete_map);
- return true;
}
// Fills the obsolete method map in the art_klass's extData. This is so obsolete methods are able to
@@ -542,6 +532,107 @@
i->ReJitEverything("libOpenJkdJvmti - Class Redefinition");
}
+bool Redefiner::CheckClass() {
+ // TODO Might just want to put it in a ObjPtr and NoSuspend assert.
+ art::StackHandleScope<1> hs(self_);
+ // Easy check that only 1 class def is present.
+ if (dex_file_->NumClassDefs() != 1) {
+ RecordFailure(ERR(ILLEGAL_ARGUMENT),
+ StringPrintf("Expected 1 class def in dex file but found %d",
+ dex_file_->NumClassDefs()));
+ return false;
+ }
+ // Get the ClassDef from the new DexFile.
+ // Since the dex file has only a single class def the index is always 0.
+ const art::DexFile::ClassDef& def = dex_file_->GetClassDef(0);
+ // Get the class as it is now.
+ art::Handle<art::mirror::Class> current_class(hs.NewHandle(GetMirrorClass()));
+
+ // Check the access flags didn't change.
+ if (def.GetJavaAccessFlags() != (current_class->GetAccessFlags() & art::kAccValidClassFlags)) {
+ RecordFailure(ERR(UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED),
+ "Cannot change modifiers of class by redefinition");
+ return false;
+ }
+
+ // Check class name.
+ // These should have been checked by the dexfile verifier on load.
+ DCHECK_NE(def.class_idx_, art::dex::TypeIndex::Invalid()) << "Invalid type index";
+ const char* descriptor = dex_file_->StringByTypeIdx(def.class_idx_);
+ DCHECK(descriptor != nullptr) << "Invalid dex file structure!";
+ if (!current_class->DescriptorEquals(descriptor)) {
+ std::string storage;
+ RecordFailure(ERR(NAMES_DONT_MATCH),
+ StringPrintf("expected file to contain class called '%s' but found '%s'!",
+ current_class->GetDescriptor(&storage),
+ descriptor));
+ return false;
+ }
+ if (current_class->IsObjectClass()) {
+ if (def.superclass_idx_ != art::dex::TypeIndex::Invalid()) {
+ RecordFailure(ERR(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED), "Superclass added!");
+ return false;
+ }
+ } else {
+ const char* super_descriptor = dex_file_->StringByTypeIdx(def.superclass_idx_);
+ DCHECK(descriptor != nullptr) << "Invalid dex file structure!";
+ if (!current_class->GetSuperClass()->DescriptorEquals(super_descriptor)) {
+ RecordFailure(ERR(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED), "Superclass changed");
+ return false;
+ }
+ }
+ const art::DexFile::TypeList* interfaces = dex_file_->GetInterfacesList(def);
+ if (interfaces == nullptr) {
+ if (current_class->NumDirectInterfaces() != 0) {
+ RecordFailure(ERR(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED), "Interfaces added");
+ return false;
+ }
+ } else {
+ DCHECK(!current_class->IsProxyClass());
+ const art::DexFile::TypeList* current_interfaces = current_class->GetInterfaceTypeList();
+ if (current_interfaces == nullptr || current_interfaces->Size() != interfaces->Size()) {
+ RecordFailure(ERR(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED), "Interfaces added or removed");
+ return false;
+ }
+ // The order of interfaces is (barely) meaningful so we error if it changes.
+ const art::DexFile& orig_dex_file = current_class->GetDexFile();
+ for (uint32_t i = 0; i < interfaces->Size(); i++) {
+ if (strcmp(
+ dex_file_->StringByTypeIdx(interfaces->GetTypeItem(i).type_idx_),
+ orig_dex_file.StringByTypeIdx(current_interfaces->GetTypeItem(i).type_idx_)) != 0) {
+ RecordFailure(ERR(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED),
+ "Interfaces changed or re-ordered");
+ return false;
+ }
+ }
+ }
+ LOG(WARNING) << "No verification is done on annotations of redefined classes.";
+
+ return true;
+}
+
+// TODO Move this to use IsRedefinable when that function is made.
+bool Redefiner::CheckRedefinable() {
+ std::string err;
+ art::StackHandleScope<1> hs(self_);
+
+ art::Handle<art::mirror::Class> h_klass(hs.NewHandle(GetMirrorClass()));
+ jvmtiError res = Redefiner::GetClassRedefinitionError(h_klass, &err);
+ if (res != OK) {
+ RecordFailure(res, err);
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool Redefiner::CheckRedefinitionIsValid() {
+ return CheckRedefinable() &&
+ CheckClass() &&
+ CheckSameFields() &&
+ CheckSameMethods();
+}
+
jvmtiError Redefiner::Run() {
art::StackHandleScope<5> hs(self_);
// TODO We might want to have a global lock (or one based on the class being redefined at least)
@@ -552,7 +643,7 @@
// doing a try loop. The other allocations we need to ensure that nothing has changed in the time
// between allocating them and pausing all threads before we can update them so we need to do a
// try loop.
- if (!EnsureRedefinitionIsValid() || !EnsureClassAllocationsFinished()) {
+ if (!CheckRedefinitionIsValid() || !EnsureClassAllocationsFinished()) {
return result_;
}
art::MutableHandle<art::mirror::ClassLoader> source_class_loader(
@@ -601,31 +692,9 @@
// TODO We should really Retry if this fails instead of simply aborting.
// Set the new DexFileCookie returns the original so we can fix it back up if redefinition fails
art::ObjPtr<art::mirror::LongArray> original_dex_file_cookie(nullptr);
- if (!UpdateJavaDexFile(java_dex_file.Get(),
- new_dex_file_cookie.Get(),
- &original_dex_file_cookie) ||
- !FindAndAllocateObsoleteMethods(art_class.Get())) {
- // Release suspendAll
- runtime_->GetThreadList()->ResumeAll();
- // Get back shared mutator lock as expected for return.
- self_->TransitionFromSuspendedToRunnable();
- if (heap->IsGcConcurrentAndMoving()) {
- heap->DecrementDisableMovingGC(self_);
- }
- return result_;
- }
- if (!UpdateClass(art_class.Get(), new_dex_cache.Get())) {
- // TODO Should have some form of scope to do this.
- RestoreJavaDexFile(java_dex_file.Get(), original_dex_file_cookie);
- // Release suspendAll
- runtime_->GetThreadList()->ResumeAll();
- // Get back shared mutator lock as expected for return.
- self_->TransitionFromSuspendedToRunnable();
- if (heap->IsGcConcurrentAndMoving()) {
- heap->DecrementDisableMovingGC(self_);
- }
- return result_;
- }
+ UpdateJavaDexFile(java_dex_file.Get(), new_dex_file_cookie.Get(), &original_dex_file_cookie);
+ FindAndAllocateObsoleteMethods(art_class.Get());
+ UpdateClass(art_class.Get(), new_dex_cache.Get());
// Ensure that obsolete methods are deoptimized. This is needed since optimized methods may have
// pointers to their ArtMethod's stashed in registers that they then use to attempt to hit the
// DexCache.
@@ -652,21 +721,7 @@
return OK;
}
-void Redefiner::RestoreJavaDexFile(art::ObjPtr<art::mirror::Object> java_dex_file,
- art::ObjPtr<art::mirror::LongArray> orig_cookie) {
- art::ArtField* internal_cookie_field = java_dex_file->GetClass()->FindDeclaredInstanceField(
- "mInternalCookie", "Ljava/lang/Object;");
- art::ArtField* cookie_field = java_dex_file->GetClass()->FindDeclaredInstanceField(
- "mCookie", "Ljava/lang/Object;");
- art::ObjPtr<art::mirror::LongArray> new_cookie(
- cookie_field->GetObject(java_dex_file)->AsLongArray());
- internal_cookie_field->SetObject<false>(java_dex_file, orig_cookie);
- if (!new_cookie.IsNull()) {
- cookie_field->SetObject<false>(java_dex_file, orig_cookie);
- }
-}
-
-bool Redefiner::UpdateMethods(art::ObjPtr<art::mirror::Class> mclass,
+void Redefiner::UpdateMethods(art::ObjPtr<art::mirror::Class> mclass,
art::ObjPtr<art::mirror::DexCache> new_dex_cache,
const art::DexFile::ClassDef& class_def) {
art::ClassLinker* linker = runtime_->GetClassLinker();
@@ -709,10 +764,9 @@
jit->GetCodeCache()->NotifyMethodRedefined(&method);
}
}
- return true;
}
-bool Redefiner::UpdateFields(art::ObjPtr<art::mirror::Class> mclass) {
+void Redefiner::UpdateFields(art::ObjPtr<art::mirror::Class> mclass) {
// TODO The IFields & SFields pointers should be combined like the methods_ arrays were.
for (auto fields_iter : {mclass->GetIFields(), mclass->GetSFields()}) {
for (art::ArtField& field : fields_iter) {
@@ -730,28 +784,16 @@
field.SetDexFieldIndex(dex_file_->GetIndexForFieldId(*new_field_id));
}
}
- return true;
}
// Performs updates to class that will allow us to verify it.
-bool Redefiner::UpdateClass(art::ObjPtr<art::mirror::Class> mclass,
+void Redefiner::UpdateClass(art::ObjPtr<art::mirror::Class> mclass,
art::ObjPtr<art::mirror::DexCache> new_dex_cache) {
const art::DexFile::ClassDef* class_def = art::OatFile::OatDexFile::FindClassDef(
*dex_file_, class_sig_, art::ComputeModifiedUtf8Hash(class_sig_));
- if (class_def == nullptr) {
- RecordFailure(ERR(INVALID_CLASS_FORMAT), "Unable to find ClassDef!");
- return false;
- }
- if (!UpdateMethods(mclass, new_dex_cache, *class_def)) {
- // TODO Investigate appropriate error types.
- RecordFailure(ERR(INTERNAL), "Unable to update class methods.");
- return false;
- }
- if (!UpdateFields(mclass)) {
- // TODO Investigate appropriate error types.
- RecordFailure(ERR(INTERNAL), "Unable to update class fields.");
- return false;
- }
+ DCHECK(class_def != nullptr);
+ UpdateMethods(mclass, new_dex_cache, *class_def);
+ UpdateFields(mclass);
// Update the class fields.
// Need to update class last since the ArtMethod gets its DexFile from the class (which is needed
@@ -759,10 +801,9 @@
mclass->SetDexCache(new_dex_cache.Ptr());
mclass->SetDexClassDefIndex(dex_file_->GetIndexForClassDef(*class_def));
mclass->SetDexTypeIndex(dex_file_->GetIndexForTypeId(*dex_file_->FindTypeId(class_sig_)));
- return true;
}
-bool Redefiner::UpdateJavaDexFile(art::ObjPtr<art::mirror::Object> java_dex_file,
+void Redefiner::UpdateJavaDexFile(art::ObjPtr<art::mirror::Object> java_dex_file,
art::ObjPtr<art::mirror::LongArray> new_cookie,
/*out*/art::ObjPtr<art::mirror::LongArray>* original_cookie) {
art::ArtField* internal_cookie_field = java_dex_file->GetClass()->FindDeclaredInstanceField(
@@ -779,7 +820,6 @@
if (!orig_cookie.IsNull()) {
cookie_field->SetObject<false>(java_dex_file, new_cookie);
}
- return true;
}
// This function does all (java) allocations we need to do for the Class being redefined.
diff --git a/runtime/openjdkjvmti/ti_redefine.h b/runtime/openjdkjvmti/ti_redefine.h
index 9d23ce4..5852309 100644
--- a/runtime/openjdkjvmti/ti_redefine.h
+++ b/runtime/openjdkjvmti/ti_redefine.h
@@ -80,6 +80,8 @@
unsigned char* dex_data,
std::string* error_msg);
+ static jvmtiError IsModifiableClass(jvmtiEnv* env, jclass klass, jboolean* is_redefinable);
+
private:
jvmtiError result_;
art::Runtime* runtime_;
@@ -106,6 +108,10 @@
error_msg_(error_msg),
class_sig_(class_sig) { }
+ static jvmtiError GetClassRedefinitionError(art::Handle<art::mirror::Class> klass,
+ /*out*/std::string* error_msg)
+ REQUIRES_SHARED(art::Locks::mutator_lock_);
+
static std::unique_ptr<art::MemMap> MoveDataToMemMap(const std::string& original_location,
jint data_len,
unsigned char* dex_data,
@@ -152,36 +158,47 @@
void RecordFailure(jvmtiError result, const std::string& error_msg);
- // TODO Actually write this.
// This will check that no constraints are violated (more than 1 class in dex file, any changes in
// number/declaration of methods & fields, changes in access flags, etc.)
- bool EnsureRedefinitionIsValid() {
- LOG(WARNING) << "Redefinition is not checked for validity currently";
+ bool CheckRedefinitionIsValid() REQUIRES_SHARED(art::Locks::mutator_lock_);
+
+ // Checks that the class can even be redefined.
+ bool CheckRedefinable() REQUIRES_SHARED(art::Locks::mutator_lock_);
+
+ // Checks that the dex file does not add/remove methods.
+ bool CheckSameMethods() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ LOG(WARNING) << "methods are not checked for modification currently";
return true;
}
- bool UpdateJavaDexFile(art::ObjPtr<art::mirror::Object> java_dex_file,
+ // Checks that the dex file does not modify fields
+ bool CheckSameFields() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ LOG(WARNING) << "Fields are not checked for modification currently";
+ return true;
+ }
+
+ // Checks that the dex file contains only the single expected class and that the top-level class
+ // data has not been modified in an incompatible manner.
+ bool CheckClass() REQUIRES_SHARED(art::Locks::mutator_lock_);
+
+ void UpdateJavaDexFile(art::ObjPtr<art::mirror::Object> java_dex_file,
art::ObjPtr<art::mirror::LongArray> new_cookie,
/*out*/art::ObjPtr<art::mirror::LongArray>* original_cookie)
REQUIRES(art::Locks::mutator_lock_);
- void RestoreJavaDexFile(art::ObjPtr<art::mirror::Object> java_dex_file,
- art::ObjPtr<art::mirror::LongArray> original_cookie)
+ void UpdateFields(art::ObjPtr<art::mirror::Class> mclass)
REQUIRES(art::Locks::mutator_lock_);
- bool UpdateFields(art::ObjPtr<art::mirror::Class> mclass)
- REQUIRES(art::Locks::mutator_lock_);
-
- bool UpdateMethods(art::ObjPtr<art::mirror::Class> mclass,
+ void UpdateMethods(art::ObjPtr<art::mirror::Class> mclass,
art::ObjPtr<art::mirror::DexCache> new_dex_cache,
const art::DexFile::ClassDef& class_def)
REQUIRES(art::Locks::mutator_lock_);
- bool UpdateClass(art::ObjPtr<art::mirror::Class> mclass,
+ void UpdateClass(art::ObjPtr<art::mirror::Class> mclass,
art::ObjPtr<art::mirror::DexCache> new_dex_cache)
REQUIRES(art::Locks::mutator_lock_);
- bool FindAndAllocateObsoleteMethods(art::mirror::Class* art_klass)
+ void FindAndAllocateObsoleteMethods(art::mirror::Class* art_klass)
REQUIRES(art::Locks::mutator_lock_);
void FillObsoleteMethodMap(art::mirror::Class* art_klass,
diff --git a/runtime/thread.cc b/runtime/thread.cc
index aff12ff..33c6a40 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2627,10 +2627,9 @@
QUICK_ENTRY_POINT_INFO(pAllocArray)
QUICK_ENTRY_POINT_INFO(pAllocArrayResolved)
QUICK_ENTRY_POINT_INFO(pAllocArrayWithAccessCheck)
- QUICK_ENTRY_POINT_INFO(pAllocObject)
QUICK_ENTRY_POINT_INFO(pAllocObjectResolved)
QUICK_ENTRY_POINT_INFO(pAllocObjectInitialized)
- QUICK_ENTRY_POINT_INFO(pAllocObjectWithAccessCheck)
+ QUICK_ENTRY_POINT_INFO(pAllocObjectWithChecks)
QUICK_ENTRY_POINT_INFO(pCheckAndAllocArray)
QUICK_ENTRY_POINT_INFO(pCheckAndAllocArrayWithAccessCheck)
QUICK_ENTRY_POINT_INFO(pAllocStringFromBytes)
diff --git a/runtime/thread.h b/runtime/thread.h
index 411d85f..6308851 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -1416,7 +1416,7 @@
stacked_shadow_frame_record(nullptr), deoptimization_context_stack(nullptr),
frame_id_to_shadow_frame(nullptr), name(nullptr), pthread_self(0),
last_no_thread_suspension_cause(nullptr), checkpoint_function(nullptr),
- thread_local_pos(nullptr), thread_local_end(nullptr), thread_local_start(nullptr),
+ thread_local_start(nullptr), thread_local_pos(nullptr), thread_local_end(nullptr),
thread_local_objects(0), mterp_current_ibase(nullptr), mterp_default_ibase(nullptr),
mterp_alt_ibase(nullptr), thread_local_alloc_stack_top(nullptr),
thread_local_alloc_stack_end(nullptr), nested_signal_state(nullptr),
@@ -1540,12 +1540,12 @@
JniEntryPoints jni_entrypoints;
QuickEntryPoints quick_entrypoints;
+ // Thread-local allocation pointer. Moved here to force alignment for thread_local_pos on ARM.
+ uint8_t* thread_local_start;
// thread_local_pos and thread_local_end must be consecutive for ldrd and are 8 byte aligned for
// potentially better performance.
uint8_t* thread_local_pos;
uint8_t* thread_local_end;
- // Thread-local allocation pointer.
- uint8_t* thread_local_start;
size_t thread_local_objects;
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index bf9eef8..34f9043 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -653,7 +653,7 @@
// is done with a timeout so that we can detect problems.
#if ART_USE_FUTEXES
timespec wait_timeout;
- InitTimeSpec(true, CLOCK_MONOTONIC, 10000, 0, &wait_timeout);
+ InitTimeSpec(false, CLOCK_MONOTONIC, 10000, 0, &wait_timeout);
#endif
while (true) {
int32_t cur_val = pending_threads.LoadRelaxed();
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 7b5ced1..a5b275c 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -337,7 +337,6 @@
java_lang_ref_ReferenceQueue_add = CacheMethod(env, java_lang_ref_ReferenceQueue.get(), true, "add", "(Ljava/lang/ref/Reference;)V");
java_lang_reflect_Parameter_init = CacheMethod(env, java_lang_reflect_Parameter, false, "<init>", "(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V");
- java_lang_reflect_Proxy_invoke = CacheMethod(env, java_lang_reflect_Proxy, true, "invoke", "(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
java_lang_Thread_dispatchUncaughtException = CacheMethod(env, java_lang_Thread, false, "dispatchUncaughtException", "(Ljava/lang/Throwable;)V");
java_lang_Thread_init = CacheMethod(env, java_lang_Thread, false, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
java_lang_Thread_run = CacheMethod(env, java_lang_Thread, false, "run", "()V");
@@ -371,7 +370,6 @@
java_lang_Throwable_stackState = CacheField(env, java_lang_Throwable, false, "backtrace", "Ljava/lang/Object;");
java_lang_Throwable_suppressedExceptions = CacheField(env, java_lang_Throwable, false, "suppressedExceptions", "Ljava/util/List;");
java_lang_reflect_Executable_artMethod = CacheField(env, java_lang_reflect_Executable, false, "artMethod", "J");
- java_lang_reflect_Proxy_h = CacheField(env, java_lang_reflect_Proxy, false, "h", "Ljava/lang/reflect/InvocationHandler;");
java_nio_DirectByteBuffer_capacity = CacheField(env, java_nio_DirectByteBuffer, false, "capacity", "I");
java_nio_DirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_DirectByteBuffer, false, "address", "J");
java_util_ArrayList_array = CacheField(env, java_util_ArrayList, false, "elementData", "[Ljava/lang/Object;");
@@ -398,10 +396,20 @@
void WellKnownClasses::LateInit(JNIEnv* env) {
ScopedLocalRef<jclass> java_lang_Runtime(env, env->FindClass("java/lang/Runtime"));
+ // CacheField and CacheMethod will initialize their classes. Classes below
+ // have clinit sections that call JNI methods. Late init is required
+ // to make sure these JNI methods are available.
java_lang_Runtime_nativeLoad =
CacheMethod(env, java_lang_Runtime.get(), true, "nativeLoad",
"(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)"
"Ljava/lang/String;");
+ java_lang_reflect_Proxy_invoke =
+ CacheMethod(env, java_lang_reflect_Proxy, true, "invoke",
+ "(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;"
+ "[Ljava/lang/Object;)Ljava/lang/Object;");
+ java_lang_reflect_Proxy_h =
+ CacheField(env, java_lang_reflect_Proxy, false, "h",
+ "Ljava/lang/reflect/InvocationHandler;");
}
ObjPtr<mirror::Class> WellKnownClasses::ToClass(jclass global_jclass) {
diff --git a/test/529-checker-unresolved/src/Main.java b/test/529-checker-unresolved/src/Main.java
index 5fd51e1..89b9cb4 100644
--- a/test/529-checker-unresolved/src/Main.java
+++ b/test/529-checker-unresolved/src/Main.java
@@ -192,13 +192,13 @@
/// CHECK-START: void Main.testLicm(int) licm (before)
/// CHECK: <<Class:l\d+>> LoadClass loop:B2
/// CHECK-NEXT: <<Clinit:l\d+>> ClinitCheck [<<Class>>] loop:B2
- /// CHECK-NEXT: <<New:l\d+>> NewInstance [<<Clinit>>,<<Method:[i|j]\d+>>] loop:B2
+ /// CHECK-NEXT: <<New:l\d+>> NewInstance [<<Clinit>>] loop:B2
/// CHECK-NEXT: InvokeUnresolved [<<New>>] loop:B2
/// CHECK-START: void Main.testLicm(int) licm (after)
/// CHECK: <<Class:l\d+>> LoadClass loop:none
/// CHECK-NEXT: <<Clinit:l\d+>> ClinitCheck [<<Class>>] loop:none
- /// CHECK: <<New:l\d+>> NewInstance [<<Clinit>>,<<Method:[i|j]\d+>>] loop:B2
+ /// CHECK: <<New:l\d+>> NewInstance [<<Clinit>>] loop:B2
/// CHECK-NEXT: InvokeUnresolved [<<New>>] loop:B2
static public void testLicm(int count) {
// Test to make sure we keep the initialization check after loading an unresolved class.
diff --git a/test/536-checker-intrinsic-optimization/src/Main.java b/test/536-checker-intrinsic-optimization/src/Main.java
index 26475ae..ed7524c 100644
--- a/test/536-checker-intrinsic-optimization/src/Main.java
+++ b/test/536-checker-intrinsic-optimization/src/Main.java
@@ -153,8 +153,8 @@
/// CHECK-DAG: <<Pos:i\d+>> ParameterValue
/// CHECK-DAG: <<NullCk:l\d+>> NullCheck [<<String>>]
/// CHECK-DAG: <<Length:i\d+>> ArrayLength [<<NullCk>>] is_string_length:true
- /// CHECK-DAG: BoundsCheck [<<Pos>>,<<Length>>] is_string_char_at:true
- /// CHECK-DAG: <<Char:c\d+>> ArrayGet [<<NullCk>>,<<Pos>>] is_string_char_at:true
+ /// CHECK-DAG: <<Bounds:i\d+>> BoundsCheck [<<Pos>>,<<Length>>] is_string_char_at:true
+ /// CHECK-DAG: <<Char:c\d+>> ArrayGet [<<NullCk>>,<<Bounds>>] is_string_char_at:true
/// CHECK-DAG: Return [<<Char>>]
/// CHECK-START: char Main.$opt$noinline$stringCharAt(java.lang.String, int) instruction_simplifier (after)
@@ -174,8 +174,8 @@
/// CHECK-DAG: <<Pos:i\d+>> ParameterValue
/// CHECK-DAG: <<NullCk:l\d+>> NullCheck [<<String>>]
/// CHECK-DAG: <<Length:i\d+>> ArrayLength [<<NullCk>>] is_string_length:true
- /// CHECK-DAG: BoundsCheck [<<Pos>>,<<Length>>] is_string_char_at:true
- /// CHECK-DAG: <<Char:c\d+>> ArrayGet [<<NullCk>>,<<Pos>>] is_string_char_at:true
+ /// CHECK-DAG: <<Bounds:i\d+>> BoundsCheck [<<Pos>>,<<Length>>] is_string_char_at:true
+ /// CHECK-DAG: <<Char:c\d+>> ArrayGet [<<NullCk>>,<<Bounds>>] is_string_char_at:true
/// CHECK-DAG: Return [<<Char>>]
/// CHECK-START: char Main.$opt$noinline$stringCharAtCatch(java.lang.String, int) instruction_simplifier (after)
diff --git a/test/621-checker-new-instance/info.txt b/test/621-checker-new-instance/info.txt
deleted file mode 100644
index c27c45c..0000000
--- a/test/621-checker-new-instance/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Tests for removing useless load class.
diff --git a/test/621-checker-new-instance/src/Main.java b/test/621-checker-new-instance/src/Main.java
deleted file mode 100644
index 68a4644..0000000
--- a/test/621-checker-new-instance/src/Main.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-public class Main {
- /// CHECK-START: java.lang.Object Main.newObject() prepare_for_register_allocation (before)
- /// CHECK: LoadClass
- /// CHECK: NewInstance
-
- /// CHECK-START: java.lang.Object Main.newObject() prepare_for_register_allocation (after)
- /// CHECK-NOT: LoadClass
- /// CHECK: NewInstance
- public static Object newObject() {
- return new Object();
- }
-
- /// CHECK-START: java.lang.Object Main.newFinalizableMayThrow() prepare_for_register_allocation (after)
- /// CHECK: LoadClass
- /// CHECK: NewInstance
- public static Object newFinalizableMayThrow() {
- return $inline$newFinalizableMayThrow();
- }
-
- public static Object $inline$newFinalizableMayThrow() {
- return new FinalizableMayThrow();
- }
-
- public static void main(String[] args) {
- newFinalizableMayThrow();
- newObject();
- }
-}
-
-class FinalizableMayThrow {
- // clinit may throw OOME.
- static Object o = new Object();
- static String s;
- public void finalize() {
- s = "Test";
- }
-}
diff --git a/test/621-checker-new-instance/expected.txt b/test/631-checker-get-class/expected.txt
similarity index 100%
rename from test/621-checker-new-instance/expected.txt
rename to test/631-checker-get-class/expected.txt
diff --git a/test/631-checker-get-class/info.txt b/test/631-checker-get-class/info.txt
new file mode 100644
index 0000000..f236a22
--- /dev/null
+++ b/test/631-checker-get-class/info.txt
@@ -0,0 +1,4 @@
+Checker test to make sure we recognize the pattern:
+if (foo.getClass() == Foo.class)
+
+For doing better type propagation.
diff --git a/test/631-checker-get-class/src/Main.java b/test/631-checker-get-class/src/Main.java
new file mode 100644
index 0000000..61c0adf
--- /dev/null
+++ b/test/631-checker-get-class/src/Main.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+public class Main {
+
+ /// CHECK-START: int Main.bar(Main) inliner (before)
+ /// CHECK: InvokeVirtual
+ /// CHECK: InvokeVirtual
+
+ /// CHECK-START: int Main.bar(Main) inliner (after)
+ /// CHECK-NOT: InvokeVirtual
+ public static int bar(Main m) {
+ if (m.getClass() == Main.class) {
+ return m.foo();
+ }
+ return 4;
+ }
+
+ public int foo() {
+ return 42;
+ }
+
+ /// CHECK-START: boolean Main.classEquality1() instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Eq:z\d+>> {{Equal|NotEqual}}
+ /// CHECK-DAG: <<Select:i\d+>> Select [{{i\d+}},{{i\d+}},<<Eq>>]
+ /// CHECK-DAG: Return [<<Select>>]
+
+ /// CHECK-START: boolean Main.classEquality1() instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Constant:i\d+>> IntConstant 1
+ /// CHECK-DAG: Return [<<Constant>>]
+ public static boolean classEquality1() {
+ return new Main().getClass() == Main.class;
+ }
+
+ /// CHECK-START: boolean Main.classEquality2() instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Eq:z\d+>> {{Equal|NotEqual}}
+ /// CHECK-DAG: <<Select:i\d+>> Select [{{i\d+}},{{i\d+}},<<Eq>>]
+ /// CHECK-DAG: Return [<<Select>>]
+
+ /// CHECK-START: boolean Main.classEquality2() instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Constant:i\d+>> IntConstant 0
+ /// CHECK-DAG: Return [<<Constant>>]
+ public static boolean classEquality2() {
+ Object o = new SubMain();
+ return o.getClass() == Main.class;
+ }
+
+ /// CHECK-START: boolean Main.classEquality3() instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Eq:z\d+>> {{Equal|NotEqual}}
+ /// CHECK-DAG: <<Select:i\d+>> Select [{{i\d+}},{{i\d+}},<<Eq>>]
+ /// CHECK-DAG: Return [<<Select>>]
+
+ /// CHECK-START: boolean Main.classEquality3() instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Constant:i\d+>> IntConstant 0
+ /// CHECK-DAG: Return [<<Constant>>]
+ public static boolean classEquality3() {
+ return new Main().getClass() != Main.class;
+ }
+
+ /// CHECK-START: boolean Main.classEquality4() instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Eq:z\d+>> {{Equal|NotEqual}}
+ /// CHECK-DAG: <<Select:i\d+>> Select [{{i\d+}},{{i\d+}},<<Eq>>]
+ /// CHECK-DAG: Return [<<Select>>]
+
+ /// CHECK-START: boolean Main.classEquality4() instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Constant:i\d+>> IntConstant 1
+ /// CHECK-DAG: Return [<<Constant>>]
+ public static boolean classEquality4() {
+ Object o = new SubMain();
+ return o.getClass() != Main.class;
+ }
+
+ public static void main(String[] args) {
+ int actual = bar(new Main());
+ if (actual != 42) {
+ throw new Error("Expected 42, got " + actual);
+ }
+ actual = bar(new SubMain());
+ if (actual != 4) {
+ throw new Error("Expected 4, got " + actual);
+ }
+ }
+}
+
+class SubMain extends Main {
+}
diff --git a/test/621-checker-new-instance/expected.txt b/test/632-checker-char-at-bounds/expected.txt
similarity index 100%
copy from test/621-checker-new-instance/expected.txt
copy to test/632-checker-char-at-bounds/expected.txt
diff --git a/test/632-checker-char-at-bounds/info.txt b/test/632-checker-char-at-bounds/info.txt
new file mode 100644
index 0000000..10b9a44
--- /dev/null
+++ b/test/632-checker-char-at-bounds/info.txt
@@ -0,0 +1,2 @@
+Regression test for the optimization of String.charAt, which
+had its SSA dependency incorrect with its corresponding bound check.
diff --git a/test/632-checker-char-at-bounds/src/Main.java b/test/632-checker-char-at-bounds/src/Main.java
new file mode 100644
index 0000000..65022d0
--- /dev/null
+++ b/test/632-checker-char-at-bounds/src/Main.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class Main {
+
+ /// CHECK-START: void Main.main(java.lang.String[]) licm (after)
+ /// CHECK-DAG: <<NullCheck:l\d+>> NullCheck
+ /// CHECK-DAG: <<BoundsCheck:i\d+>> BoundsCheck
+ /// CHECK-DAG: ArrayGet [<<NullCheck>>,<<BoundsCheck>>]
+ public static void main(String[] args) {
+ try {
+ String foo = myString;
+ foo.getClass(); // Make sure the null check is not in the loop.
+ char c = 0;
+ for (int i = 0; i < 10; i++) {
+ // The charAt may be licm'ed, but it has to be licm'ed with its
+ // bounds check.
+ c = foo.charAt(10000000);
+ }
+ System.out.println(c);
+ } catch (StringIndexOutOfBoundsException e) {
+ // Expected
+ }
+ }
+
+ static String myString = "foo";
+}
diff --git a/test/910-methods/expected.txt b/test/910-methods/expected.txt
index 9a74799..c913b3f 100644
--- a/test/910-methods/expected.txt
+++ b/test/910-methods/expected.txt
@@ -1,15 +1,59 @@
[toString, ()Ljava/lang/String;, null]
class java.lang.Object
1
+Max locals: 3
+Argument size: 1
+Location start: 0
+Location end: 40
+Is native: false
+Is obsolete: false
+Is synthetic: false
[charAt, (I)C, null]
class java.lang.String
257
+Max locals: JVMTI_ERROR_NATIVE_METHOD
+Argument size: JVMTI_ERROR_NATIVE_METHOD
+Location start: JVMTI_ERROR_NATIVE_METHOD
+Location end: JVMTI_ERROR_NATIVE_METHOD
+Is native: true
+Is obsolete: false
+Is synthetic: false
[sqrt, (D)D, null]
class java.lang.Math
265
+Max locals: JVMTI_ERROR_NATIVE_METHOD
+Argument size: JVMTI_ERROR_NATIVE_METHOD
+Location start: JVMTI_ERROR_NATIVE_METHOD
+Location end: JVMTI_ERROR_NATIVE_METHOD
+Is native: true
+Is obsolete: false
+Is synthetic: false
[add, (Ljava/lang/Object;)Z, null]
interface java.util.List
1025
+Max locals: 0
+Argument size: 0
+Location start: 0
+Location end: 0
+Is native: false
+Is obsolete: false
+Is synthetic: false
[run, ()V, null]
class $Proxy0
17
+Max locals: 0
+Argument size: 0
+Location start: 0
+Location end: 0
+Is native: false
+Is obsolete: false
+Is synthetic: false
+class Main$NestedSynthetic
+4104
+Max locals: 1
+Argument size: 0
+Location start: 0
+Location end: 2
+Is native: false
+Is obsolete: false
+Is synthetic: true
diff --git a/test/910-methods/methods.cc b/test/910-methods/methods.cc
index b64952d..fa9679d 100644
--- a/test/910-methods/methods.cc
+++ b/test/910-methods/methods.cc
@@ -114,6 +114,99 @@
return modifiers;
}
+extern "C" JNIEXPORT jint JNICALL Java_Main_getMaxLocals(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method) {
+ jmethodID id = env->FromReflectedMethod(method);
+
+ jint max_locals;
+ jvmtiError result = jvmti_env->GetMaxLocals(id, &max_locals);
+ if (JvmtiErrorToException(env, result)) {
+ return -1;
+ }
+
+ return max_locals;
+}
+
+extern "C" JNIEXPORT jint JNICALL Java_Main_getArgumentsSize(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method) {
+ jmethodID id = env->FromReflectedMethod(method);
+
+ jint arguments;
+ jvmtiError result = jvmti_env->GetArgumentsSize(id, &arguments);
+ if (JvmtiErrorToException(env, result)) {
+ return -1;
+ }
+
+ return arguments;
+}
+
+extern "C" JNIEXPORT jlong JNICALL Java_Main_getMethodLocationStart(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method) {
+ jmethodID id = env->FromReflectedMethod(method);
+
+ jlong start;
+ jlong end;
+ jvmtiError result = jvmti_env->GetMethodLocation(id, &start, &end);
+ if (JvmtiErrorToException(env, result)) {
+ return -1;
+ }
+
+ return start;
+}
+
+extern "C" JNIEXPORT jlong JNICALL Java_Main_getMethodLocationEnd(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method) {
+ jmethodID id = env->FromReflectedMethod(method);
+
+ jlong start;
+ jlong end;
+ jvmtiError result = jvmti_env->GetMethodLocation(id, &start, &end);
+ if (JvmtiErrorToException(env, result)) {
+ return -1;
+ }
+
+ return end;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isMethodNative(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method) {
+ jmethodID id = env->FromReflectedMethod(method);
+
+ jboolean is_native;
+ jvmtiError result = jvmti_env->IsMethodNative(id, &is_native);
+ if (JvmtiErrorToException(env, result)) {
+ return JNI_FALSE;
+ }
+
+ return is_native;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isMethodObsolete(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method) {
+ jmethodID id = env->FromReflectedMethod(method);
+
+ jboolean is_obsolete;
+ jvmtiError result = jvmti_env->IsMethodObsolete(id, &is_obsolete);
+ if (JvmtiErrorToException(env, result)) {
+ return JNI_FALSE;
+ }
+
+ return is_obsolete;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isMethodSynthetic(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method) {
+ jmethodID id = env->FromReflectedMethod(method);
+
+ jboolean is_synthetic;
+ jvmtiError result = jvmti_env->IsMethodSynthetic(id, &is_synthetic);
+ if (JvmtiErrorToException(env, result)) {
+ return JNI_FALSE;
+ }
+
+ return is_synthetic;
+}
+
// Don't do anything
jint OnLoad(JavaVM* vm,
char* options ATTRIBUTE_UNUSED,
diff --git a/test/910-methods/src/Main.java b/test/910-methods/src/Main.java
index 3459134..bf25a0d 100644
--- a/test/910-methods/src/Main.java
+++ b/test/910-methods/src/Main.java
@@ -32,6 +32,10 @@
testMethod("java.util.List", "add", Object.class);
testMethod(getProxyClass(), "run");
+
+ // Find a synthetic method in the dummy inner class. Do not print the name. Javac and Jack
+ // disagree on the naming of synthetic accessors.
+ testMethod(findSyntheticMethod(), NestedSynthetic.class, false);
}
private static Class<?> proxyClass = null;
@@ -54,8 +58,17 @@
private static void testMethod(Class<?> base, String methodName, Class<?>... types)
throws Exception {
Method m = base.getDeclaredMethod(methodName, types);
+ testMethod(m, base, true);
+ }
+
+ private static void testMethod(Method m, Class<?> base, boolean printName) {
String[] result = getMethodName(m);
- System.out.println(Arrays.toString(result));
+ if (!result[0].equals(m.getName())) {
+ throw new RuntimeException("Name not equal: " + m.getName() + " vs " + result[0]);
+ }
+ if (printName) {
+ System.out.println(Arrays.toString(result));
+ }
Class<?> declClass = getMethodDeclaringClass(m);
if (base != declClass) {
@@ -68,9 +81,67 @@
throw new RuntimeException("Modifiers not equal: " + m.getModifiers() + " vs " + modifiers);
}
System.out.println(modifiers);
+
+ System.out.print("Max locals: ");
+ try {
+ System.out.println(getMaxLocals(m));
+ } catch (RuntimeException e) {
+ System.out.println(e.getMessage());
+ }
+
+ System.out.print("Argument size: ");
+ try {
+ System.out.println(getArgumentsSize(m));
+ } catch (RuntimeException e) {
+ System.out.println(e.getMessage());
+ }
+
+ System.out.print("Location start: ");
+ try {
+ System.out.println(getMethodLocationStart(m));
+ } catch (RuntimeException e) {
+ System.out.println(e.getMessage());
+ }
+
+ System.out.print("Location end: ");
+ try {
+ System.out.println(getMethodLocationEnd(m));
+ } catch (RuntimeException e) {
+ System.out.println(e.getMessage());
+ }
+
+ System.out.println("Is native: " + isMethodNative(m));
+ System.out.println("Is obsolete: " + isMethodObsolete(m));
+ System.out.println("Is synthetic: " + isMethodSynthetic(m));
+ }
+
+ private static class NestedSynthetic {
+ // Accessing this private field will create a synthetic accessor method;
+ private static String dummy;
+ }
+
+ private static void dummyAccess() {
+ System.out.println(NestedSynthetic.dummy);
+ }
+
+ private static Method findSyntheticMethod() throws Exception {
+ Method methods[] = NestedSynthetic.class.getDeclaredMethods();
+ for (Method m : methods) {
+ if (m.isSynthetic()) {
+ return m;
+ }
+ }
+ throw new RuntimeException("Could not find synthetic method");
}
private static native String[] getMethodName(Method m);
private static native Class<?> getMethodDeclaringClass(Method m);
private static native int getMethodModifiers(Method m);
+ private static native int getMaxLocals(Method m);
+ private static native int getArgumentsSize(Method m);
+ private static native long getMethodLocationStart(Method m);
+ private static native long getMethodLocationEnd(Method m);
+ private static native boolean isMethodNative(Method m);
+ private static native boolean isMethodObsolete(Method m);
+ private static native boolean isMethodSynthetic(Method m);
}
diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc
index 19d82c5..38a4f0e 100644
--- a/test/912-classes/classes.cc
+++ b/test/912-classes/classes.cc
@@ -29,6 +29,20 @@
namespace art {
namespace Test912Classes {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isModifiableClass(
+ JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+ jboolean res = JNI_FALSE;
+ jvmtiError result = jvmti_env->IsModifiableClass(klass, &res);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running IsModifiableClass: %s\n", err);
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ return JNI_FALSE;
+ }
+ return res;
+}
+
extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassSignature(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
char* sig;
diff --git a/test/912-classes/expected.txt b/test/912-classes/expected.txt
index 3507a1a..44c861a 100644
--- a/test/912-classes/expected.txt
+++ b/test/912-classes/expected.txt
@@ -12,13 +12,13 @@
411
[[D, null]
411
-int interface=false array=false
-$Proxy0 interface=false array=false
-java.lang.Runnable interface=true array=false
-java.lang.String interface=false array=false
-[I interface=false array=true
-[Ljava.lang.Runnable; interface=false array=true
-[Ljava.lang.String; interface=false array=true
+int interface=false array=false modifiable=false
+$Proxy0 interface=false array=false modifiable=false
+java.lang.Runnable interface=true array=false modifiable=false
+java.lang.String interface=false array=false modifiable=true
+[I interface=false array=true modifiable=false
+[Ljava.lang.Runnable; interface=false array=true modifiable=false
+[Ljava.lang.String; interface=false array=true modifiable=false
[public static final int java.lang.Integer.BYTES, static final char[] java.lang.Integer.DigitOnes, static final char[] java.lang.Integer.DigitTens, public static final int java.lang.Integer.MAX_VALUE, public static final int java.lang.Integer.MIN_VALUE, public static final int java.lang.Integer.SIZE, private static final java.lang.String[] java.lang.Integer.SMALL_NEG_VALUES, private static final java.lang.String[] java.lang.Integer.SMALL_NONNEG_VALUES, public static final java.lang.Class java.lang.Integer.TYPE, static final char[] java.lang.Integer.digits, private static final long java.lang.Integer.serialVersionUID, static final int[] java.lang.Integer.sizeTable, private final int java.lang.Integer.value]
[]
[]
diff --git a/test/912-classes/src/Main.java b/test/912-classes/src/Main.java
index 69e5a4c..e627d42 100644
--- a/test/912-classes/src/Main.java
+++ b/test/912-classes/src/Main.java
@@ -107,7 +107,9 @@
private static void testClassType(Class<?> c) throws Exception {
boolean isInterface = isInterface(c);
boolean isArray = isArrayClass(c);
- System.out.println(c.getName() + " interface=" + isInterface + " array=" + isArray);
+ boolean isModifiable = isModifiableClass(c);
+ System.out.println(c.getName() + " interface=" + isInterface + " array=" + isArray +
+ " modifiable=" + isModifiable);
}
private static void testClassFields(Class<?> c) throws Exception {
@@ -149,6 +151,7 @@
}
}
+ private static native boolean isModifiableClass(Class<?> c);
private static native String[] getClassSignature(Class<?> c);
private static native boolean isInterface(Class<?> c);
diff --git a/test/920-objects/build b/test/920-objects/build
new file mode 100755
index 0000000..898e2e5
--- /dev/null
+++ b/test/920-objects/build
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+./default-build "$@" --experimental agents
diff --git a/test/920-objects/expected.txt b/test/920-objects/expected.txt
new file mode 100644
index 0000000..80feeb9
--- /dev/null
+++ b/test/920-objects/expected.txt
@@ -0,0 +1,10 @@
+class java.lang.Object 8
+class java.lang.Object 8
+class [I 12
+class [I 16
+class [I 20
+class [D 16
+class [D 24
+class [D 32
+class java.lang.String 24
+class java.lang.String 24
diff --git a/test/920-objects/info.txt b/test/920-objects/info.txt
new file mode 100644
index 0000000..875a5f6
--- /dev/null
+++ b/test/920-objects/info.txt
@@ -0,0 +1 @@
+Tests basic functions in the jvmti plugin.
diff --git a/test/920-objects/objects.cc b/test/920-objects/objects.cc
new file mode 100644
index 0000000..886dd0e
--- /dev/null
+++ b/test/920-objects/objects.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2013 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 "objects.h"
+
+#include <stdio.h>
+
+#include "base/macros.h"
+#include "jni.h"
+#include "openjdkjvmti/jvmti.h"
+#include "ScopedLocalRef.h"
+
+#include "ti-agent/common_helper.h"
+#include "ti-agent/common_load.h"
+
+namespace art {
+namespace Test920Objects {
+
+extern "C" JNIEXPORT jlong JNICALL Java_Main_getObjectSize(
+ JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED, jobject object) {
+ jlong size;
+
+ jvmtiError result = jvmti_env->GetObjectSize(object, &size);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running GetObjectSize: %s\n", err);
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ return -1;
+ }
+
+ return size;
+}
+
+extern "C" JNIEXPORT jint JNICALL Java_Main_getObjectHashCode(
+ JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED, jobject object) {
+ jint hash;
+
+ jvmtiError result = jvmti_env->GetObjectHashCode(object, &hash);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running GetObjectHashCode: %s\n", err);
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ return -1;
+ }
+
+ return hash;
+}
+
+// Don't do anything
+jint OnLoad(JavaVM* vm,
+ char* options ATTRIBUTE_UNUSED,
+ void* reserved ATTRIBUTE_UNUSED) {
+ if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
+ printf("Unable to get jvmti env!\n");
+ return 1;
+ }
+ SetAllCapabilities(jvmti_env);
+ return 0;
+}
+
+} // namespace Test920Objects
+} // namespace art
diff --git a/test/920-objects/objects.h b/test/920-objects/objects.h
new file mode 100644
index 0000000..5f21e7b
--- /dev/null
+++ b/test/920-objects/objects.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 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_TEST_920_OBJECTS_OBJECTS_H_
+#define ART_TEST_920_OBJECTS_OBJECTS_H_
+
+#include <jni.h>
+
+namespace art {
+namespace Test920Objects {
+
+jint OnLoad(JavaVM* vm, char* options, void* reserved);
+
+} // namespace Test920Objects
+} // namespace art
+
+#endif // ART_TEST_920_OBJECTS_OBJECTS_H_
diff --git a/test/920-objects/run b/test/920-objects/run
new file mode 100755
index 0000000..4379349
--- /dev/null
+++ b/test/920-objects/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+./default-run "$@" --experimental agents \
+ --experimental runtime-plugins \
+ --jvmti
diff --git a/test/920-objects/src/Main.java b/test/920-objects/src/Main.java
new file mode 100644
index 0000000..5dbe1a7
--- /dev/null
+++ b/test/920-objects/src/Main.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 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.lang.reflect.Field;
+import java.util.Arrays;
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[1]);
+
+ doTest();
+ }
+
+ public static void doTest() throws Exception {
+ testObjectSize(new Object());
+ testObjectSize(new Object());
+
+ testObjectSize(new int[0]);
+ testObjectSize(new int[1]);
+ testObjectSize(new int[2]);
+
+ testObjectSize(new double[0]);
+ testObjectSize(new double[1]);
+ testObjectSize(new double[2]);
+
+ testObjectSize(new String("abc"));
+ testObjectSize(new String("wxyz"));
+
+ testObjectHash();
+ }
+
+ private static void testObjectSize(Object o) {
+ System.out.println(o.getClass() + " " + getObjectSize(o));
+ }
+
+ private static void testObjectHash() {
+ Object[] objects = new Object[] {
+ new Object(),
+ new Object(),
+
+ new MyHash(1),
+ new MyHash(1),
+ new MyHash(2)
+ };
+
+ int hashes[] = new int[objects.length];
+
+ for (int i = 0; i < objects.length; i++) {
+ hashes[i] = getObjectHashCode(objects[i]);
+ }
+
+ // Implementation detail: we use the identity hashcode, for simplicity.
+ for (int i = 0; i < objects.length; i++) {
+ int ihash = System.identityHashCode(objects[i]);
+ if (hashes[i] != ihash) {
+ throw new RuntimeException(objects[i] + ": " + hashes[i] + " vs " + ihash);
+ }
+ }
+
+ Runtime.getRuntime().gc();
+ Runtime.getRuntime().gc();
+
+ for (int i = 0; i < objects.length; i++) {
+ int newhash = getObjectHashCode(objects[i]);
+ if (hashes[i] != newhash) {
+ throw new RuntimeException(objects[i] + ": " + hashes[i] + " vs " + newhash);
+ }
+ }
+ }
+
+ private static native long getObjectSize(Object o);
+ private static native int getObjectHashCode(Object o);
+
+ private static class MyHash {
+ private int hash;
+
+ public MyHash(int h) {
+ hash = h;
+ }
+
+ public int hashCode() {
+ return hash;
+ }
+ }
+}
diff --git a/test/921-hello-failure/build b/test/921-hello-failure/build
new file mode 100755
index 0000000..898e2e5
--- /dev/null
+++ b/test/921-hello-failure/build
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+./default-build "$@" --experimental agents
diff --git a/test/921-hello-failure/expected.txt b/test/921-hello-failure/expected.txt
new file mode 100644
index 0000000..e2665ef
--- /dev/null
+++ b/test/921-hello-failure/expected.txt
@@ -0,0 +1,15 @@
+hello - NewName
+Transformation error : java.lang.Exception(Failed to redefine class <LTransform;> due to JVMTI_ERROR_NAMES_DONT_MATCH)
+hello - NewName
+hello - DifferentAccess
+Transformation error : java.lang.Exception(Failed to redefine class <LTransform;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED)
+hello - DifferentAccess
+hello2 - NewInterface
+Transformation error : java.lang.Exception(Failed to redefine class <LTransform2;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED)
+hello2 - NewInterface
+hello2 - MissingInterface
+Transformation error : java.lang.Exception(Failed to redefine class <LTransform2;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED)
+hello2 - MissingInterface
+hello2 - ReorderInterface
+Transformation error : java.lang.Exception(Failed to redefine class <LTransform2;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED)
+hello2 - ReorderInterface
diff --git a/test/921-hello-failure/info.txt b/test/921-hello-failure/info.txt
new file mode 100644
index 0000000..9d241c7
--- /dev/null
+++ b/test/921-hello-failure/info.txt
@@ -0,0 +1,7 @@
+Tests for redefinition failure modes.
+
+Tests
+----
+
+- NewName: The name of the class is changed
+- DifferentAccess: Class access is changed from <default> to 'public'
diff --git a/test/921-hello-failure/run b/test/921-hello-failure/run
new file mode 100755
index 0000000..3ef4832
--- /dev/null
+++ b/test/921-hello-failure/run
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+
+./default-run "$@" --experimental agents \
+ --experimental runtime-plugins \
+ --jvmti
diff --git a/test/921-hello-failure/src/DifferentAccess.java b/test/921-hello-failure/src/DifferentAccess.java
new file mode 100644
index 0000000..d4b16e0
--- /dev/null
+++ b/test/921-hello-failure/src/DifferentAccess.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 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.Base64;
+
+class DifferentAccess {
+ // The following is a base64 encoding of the following class.
+ // public class NotTransform {
+ // public void sayHi(String name) {
+ // throw new Error("Should not be called!");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAFQoABgAPBwAQCAARCgACABIHABMHABQBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAP" +
+ "TGluZU51bWJlclRhYmxlAQAFc2F5SGkBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAApTb3VyY2VG" +
+ "aWxlAQAOVHJhbnNmb3JtLmphdmEMAAcACAEAD2phdmEvbGFuZy9FcnJvcgEAFVNob3VsZCBub3Qg" +
+ "YmUgY2FsbGVkIQwABwAMAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVjdAAhAAUABgAAAAAA" +
+ "AgABAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAAAEAAQALAAwAAQAJAAAA" +
+ "IgADAAIAAAAKuwACWRIDtwAEvwAAAAEACgAAAAYAAQAAAAMAAQANAAAAAgAO");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQANVRT7zleRLG4E5DhtK7OtoDxZlUQMI5eQAgAAcAAAAHhWNBIAAAAAAAAAAPwBAAAL" +
+ "AAAAcAAAAAUAAACcAAAAAgAAALAAAAAAAAAAAAAAAAQAAADIAAAAAQAAAOgAAACIAQAACAEAAEoB" +
+ "AABSAQAAXwEAAHIBAACGAQAAmgEAALEBAADBAQAAxAEAAMgBAADcAQAAAQAAAAIAAAADAAAABAAA" +
+ "AAcAAAAHAAAABAAAAAAAAAAIAAAABAAAAEQBAAAAAAAAAAAAAAAAAQAKAAAAAQABAAAAAAACAAAA" +
+ "AAAAAAAAAAABAAAAAgAAAAAAAAAGAAAAAAAAAO4BAAAAAAAAAQABAAEAAADjAQAABAAAAHAQAwAA" +
+ "AA4ABAACAAIAAADoAQAACQAAACIAAQAbAQUAAABwIAIAEAAnAAAAAQAAAAMABjxpbml0PgALTFRy" +
+ "YW5zZm9ybTsAEUxqYXZhL2xhbmcvRXJyb3I7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xh" +
+ "bmcvU3RyaW5nOwAVU2hvdWxkIG5vdCBiZSBjYWxsZWQhAA5UcmFuc2Zvcm0uamF2YQABVgACVkwA" +
+ "EmVtaXR0ZXI6IGphY2stNC4yMAAFc2F5SGkAAQAHDgADAQAHDgAAAAEBAIGABIgCAQGgAgwAAAAA" +
+ "AAAAAQAAAAAAAAABAAAACwAAAHAAAAACAAAABQAAAJwAAAADAAAAAgAAALAAAAAFAAAABAAAAMgA" +
+ "AAAGAAAAAQAAAOgAAAABIAAAAgAAAAgBAAABEAAAAQAAAEQBAAACIAAACwAAAEoBAAADIAAAAgAA" +
+ "AOMBAAAAIAAAAQAAAO4BAAAAEAAAAQAAAPwBAAA=");
+
+ public static void doTest(Transform t) {
+ t.sayHi("DifferentAccess");
+ try {
+ Main.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ } catch (Exception e) {
+ System.out.println(
+ "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")");
+ }
+ t.sayHi("DifferentAccess");
+ }
+}
diff --git a/test/921-hello-failure/src/Iface1.java b/test/921-hello-failure/src/Iface1.java
new file mode 100644
index 0000000..f53275a
--- /dev/null
+++ b/test/921-hello-failure/src/Iface1.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+interface Iface1 {
+ void sayHi(String s);
+}
diff --git a/test/921-hello-failure/src/Iface2.java b/test/921-hello-failure/src/Iface2.java
new file mode 100644
index 0000000..54cdd90
--- /dev/null
+++ b/test/921-hello-failure/src/Iface2.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+interface Iface2 {
+ void sayHi(String s);
+}
diff --git a/test/921-hello-failure/src/Iface3.java b/test/921-hello-failure/src/Iface3.java
new file mode 100644
index 0000000..819134d
--- /dev/null
+++ b/test/921-hello-failure/src/Iface3.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+interface Iface3 {
+ void sayHi(String s);
+}
diff --git a/test/921-hello-failure/src/Main.java b/test/921-hello-failure/src/Main.java
new file mode 100644
index 0000000..69c48e2
--- /dev/null
+++ b/test/921-hello-failure/src/Main.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+public class Main {
+
+ public static void main(String[] args) {
+ System.loadLibrary(args[1]);
+ NewName.doTest(new Transform());
+ DifferentAccess.doTest(new Transform());
+ NewInterface.doTest(new Transform2());
+ MissingInterface.doTest(new Transform2());
+ ReorderInterface.doTest(new Transform2());
+ }
+
+ // Transforms the class. This throws an exception if something goes wrong.
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile) throws Exception;
+}
diff --git a/test/921-hello-failure/src/MissingInterface.java b/test/921-hello-failure/src/MissingInterface.java
new file mode 100644
index 0000000..d17a6de
--- /dev/null
+++ b/test/921-hello-failure/src/MissingInterface.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 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.Base64;
+
+class MissingInterface {
+ // The following is a base64 encoding of the following class.
+ // class Transform2 implements Iface1 {
+ // public void sayHi(String name) {
+ // throw new Error("Should not be called!");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAFwoABgAQBwARCAASCgACABMHABQHABUHABYBAAY8aW5pdD4BAAMoKVYBAARDb2Rl" +
+ "AQAPTGluZU51bWJlclRhYmxlAQAFc2F5SGkBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAApTb3Vy" +
+ "Y2VGaWxlAQAPVHJhbnNmb3JtMi5qYXZhDAAIAAkBAA9qYXZhL2xhbmcvRXJyb3IBABVTaG91bGQg" +
+ "bm90IGJlIGNhbGxlZCEMAAgADQEAClRyYW5zZm9ybTIBABBqYXZhL2xhbmcvT2JqZWN0AQAGSWZh" +
+ "Y2UxACAABQAGAAEABwAAAAIAAAAIAAkAAQAKAAAAHQABAAEAAAAFKrcAAbEAAAABAAsAAAAGAAEA" +
+ "AAABAAEADAANAAEACgAAACIAAwACAAAACrsAAlkSA7cABL8AAAABAAsAAAAGAAEAAAADAAEADgAA" +
+ "AAIADw==");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQDiWVay8/Z0/tXQaTTI+QtwTM65gRJVMOusAgAAcAAAAHhWNBIAAAAAAAAAABgCAAAM" +
+ "AAAAcAAAAAYAAACgAAAAAgAAALgAAAAAAAAAAAAAAAQAAADQAAAAAQAAAPAAAACcAQAAEAEAAFoB" +
+ "AABiAQAAbAEAAHoBAACNAQAAoQEAALUBAADMAQAA3QEAAOABAADkAQAA+AEAAAEAAAACAAAAAwAA" +
+ "AAQAAAAFAAAACAAAAAgAAAAFAAAAAAAAAAkAAAAFAAAAVAEAAAEAAAAAAAAAAQABAAsAAAACAAEA" +
+ "AAAAAAMAAAAAAAAAAQAAAAAAAAADAAAATAEAAAcAAAAAAAAACgIAAAAAAAABAAEAAQAAAP8BAAAE" +
+ "AAAAcBADAAAADgAEAAIAAgAAAAQCAAAJAAAAIgACABsBBgAAAHAgAgAQACcAAAABAAAAAAAAAAEA" +
+ "AAAEAAY8aW5pdD4ACExJZmFjZTE7AAxMVHJhbnNmb3JtMjsAEUxqYXZhL2xhbmcvRXJyb3I7ABJM" +
+ "amF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAVU2hvdWxkIG5vdCBiZSBjYWxs" +
+ "ZWQhAA9UcmFuc2Zvcm0yLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjAABXNheUhpAAEA" +
+ "Bw4AAwEABw4AAAABAQCAgASQAgEBqAIMAAAAAAAAAAEAAAAAAAAAAQAAAAwAAABwAAAAAgAAAAYA" +
+ "AACgAAAAAwAAAAIAAAC4AAAABQAAAAQAAADQAAAABgAAAAEAAADwAAAAASAAAAIAAAAQAQAAARAA" +
+ "AAIAAABMAQAAAiAAAAwAAABaAQAAAyAAAAIAAAD/AQAAACAAAAEAAAAKAgAAABAAAAEAAAAYAgAA");
+
+ public static void doTest(Transform2 t) {
+ t.sayHi("MissingInterface");
+ try {
+ Main.doCommonClassRedefinition(Transform2.class, CLASS_BYTES, DEX_BYTES);
+ } catch (Exception e) {
+ System.out.println(
+ "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")");
+ }
+ t.sayHi("MissingInterface");
+ }
+}
diff --git a/test/921-hello-failure/src/NewInterface.java b/test/921-hello-failure/src/NewInterface.java
new file mode 100644
index 0000000..fe77222
--- /dev/null
+++ b/test/921-hello-failure/src/NewInterface.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 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.Base64;
+
+class NewInterface {
+ // The following is a base64 encoding of the following class.
+ // class Transform2 implements Iface1, Iface2, Iface3 {
+ // public void sayHi(String name) {
+ // throw new Error("Should not be called!");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAGwoABgASBwATCAAUCgACABUHABYHABcHABgHABkHABoBAAY8aW5pdD4BAAMoKVYB" +
+ "AARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAFc2F5SGkBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYB" +
+ "AApTb3VyY2VGaWxlAQAPVHJhbnNmb3JtMi5qYXZhDAAKAAsBAA9qYXZhL2xhbmcvRXJyb3IBABVT" +
+ "aG91bGQgbm90IGJlIGNhbGxlZCEMAAoADwEAClRyYW5zZm9ybTIBABBqYXZhL2xhbmcvT2JqZWN0" +
+ "AQAGSWZhY2UxAQAGSWZhY2UyAQAGSWZhY2UzACAABQAGAAMABwAIAAkAAAACAAAACgALAAEADAAA" +
+ "AB0AAQABAAAABSq3AAGxAAAAAQANAAAABgABAAAAAQABAA4ADwABAAwAAAAiAAMAAgAAAAq7AAJZ" +
+ "EgO3AAS/AAAAAQANAAAABgABAAAAAwABABAAAAACABE=");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQCBWnko4SMXeuXSO3fGJBp0WSlc0HLRr63UAgAAcAAAAHhWNBIAAAAAAAAAAEACAAAO" +
+ "AAAAcAAAAAgAAACoAAAAAgAAAMgAAAAAAAAAAAAAAAQAAADgAAAAAQAAAAABAAC0AQAAIAEAAG4B" +
+ "AAB2AQAAgAEAAIoBAACUAQAAogEAALUBAADJAQAA3QEAAPQBAAAFAgAACAIAAAwCAAAgAgAAAQAA" +
+ "AAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAoAAAAKAAAABwAAAAAAAAALAAAABwAAAGgBAAADAAAA" +
+ "AAAAAAMAAQANAAAABAABAAAAAAAFAAAAAAAAAAMAAAAAAAAABQAAAFwBAAAJAAAAAAAAADICAAAA" +
+ "AAAAAQABAAEAAAAnAgAABAAAAHAQAwAAAA4ABAACAAIAAAAsAgAACQAAACIABAAbAQgAAABwIAIA" +
+ "EAAnAAAAAwAAAAAAAQACAAAAAQAAAAYABjxpbml0PgAITElmYWNlMTsACExJZmFjZTI7AAhMSWZh" +
+ "Y2UzOwAMTFRyYW5zZm9ybTI7ABFMamF2YS9sYW5nL0Vycm9yOwASTGphdmEvbGFuZy9PYmplY3Q7" +
+ "ABJMamF2YS9sYW5nL1N0cmluZzsAFVNob3VsZCBub3QgYmUgY2FsbGVkIQAPVHJhbnNmb3JtMi5q" +
+ "YXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00LjIwAAVzYXlIaQABAAcOAAMBAAcOAAAAAQEAgIAE" +
+ "oAIBAbgCDAAAAAAAAAABAAAAAAAAAAEAAAAOAAAAcAAAAAIAAAAIAAAAqAAAAAMAAAACAAAAyAAA" +
+ "AAUAAAAEAAAA4AAAAAYAAAABAAAAAAEAAAEgAAACAAAAIAEAAAEQAAACAAAAXAEAAAIgAAAOAAAA" +
+ "bgEAAAMgAAACAAAAJwIAAAAgAAABAAAAMgIAAAAQAAABAAAAQAIAAA==");
+
+ public static void doTest(Transform2 t) {
+ t.sayHi("NewInterface");
+ try {
+ Main.doCommonClassRedefinition(Transform2.class, CLASS_BYTES, DEX_BYTES);
+ } catch (Exception e) {
+ System.out.println(
+ "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")");
+ }
+ t.sayHi("NewInterface");
+ }
+}
diff --git a/test/921-hello-failure/src/NewName.java b/test/921-hello-failure/src/NewName.java
new file mode 100644
index 0000000..a6f249a
--- /dev/null
+++ b/test/921-hello-failure/src/NewName.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 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.Base64;
+
+class NewName {
+ // class NotTransform {
+ // public void sayHi(String name) {
+ // throw new Error("Should not be called!");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAFQoABgAPBwAQCAARCgACABIHABMHABQBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAP" +
+ "TGluZU51bWJlclRhYmxlAQAFc2F5SGkBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAApTb3VyY2VG" +
+ "aWxlAQARTm90VHJhbnNmb3JtLmphdmEMAAcACAEAD2phdmEvbGFuZy9FcnJvcgEAFVNob3VsZCBu" +
+ "b3QgYmUgY2FsbGVkIQwABwAMAQAMTm90VHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVjdAAgAAUA" +
+ "BgAAAAAAAgAAAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAAAEAAQALAAwA" +
+ "AQAJAAAAIgADAAIAAAAKuwACWRIDtwAEvwAAAAEACgAAAAYAAQAAAAMAAQANAAAAAgAO");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQDLV95i5xnv6iUi6uIeDoY5jP5Xe9NP1AiYAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAL" +
+ "AAAAcAAAAAUAAACcAAAAAgAAALAAAAAAAAAAAAAAAAQAAADIAAAAAQAAAOgAAACQAQAACAEAAEoB" +
+ "AABSAQAAYgEAAHUBAACJAQAAnQEAALABAADHAQAAygEAAM4BAADiAQAAAQAAAAIAAAADAAAABAAA" +
+ "AAcAAAAHAAAABAAAAAAAAAAIAAAABAAAAEQBAAAAAAAAAAAAAAAAAQAKAAAAAQABAAAAAAACAAAA" +
+ "AAAAAAAAAAAAAAAAAgAAAAAAAAAFAAAAAAAAAPQBAAAAAAAAAQABAAEAAADpAQAABAAAAHAQAwAA" +
+ "AA4ABAACAAIAAADuAQAACQAAACIAAQAbAQYAAABwIAIAEAAnAAAAAQAAAAMABjxpbml0PgAOTE5v" +
+ "dFRyYW5zZm9ybTsAEUxqYXZhL2xhbmcvRXJyb3I7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZh" +
+ "L2xhbmcvU3RyaW5nOwARTm90VHJhbnNmb3JtLmphdmEAFVNob3VsZCBub3QgYmUgY2FsbGVkIQAB" +
+ "VgACVkwAEmVtaXR0ZXI6IGphY2stNC4yMAAFc2F5SGkAAQAHDgADAQAHDgAAAAEBAICABIgCAQGg" +
+ "AgAADAAAAAAAAAABAAAAAAAAAAEAAAALAAAAcAAAAAIAAAAFAAAAnAAAAAMAAAACAAAAsAAAAAUA" +
+ "AAAEAAAAyAAAAAYAAAABAAAA6AAAAAEgAAACAAAACAEAAAEQAAABAAAARAEAAAIgAAALAAAASgEA" +
+ "AAMgAAACAAAA6QEAAAAgAAABAAAA9AEAAAAQAAABAAAABAIAAA==");
+
+ public static void doTest(Transform t) {
+ t.sayHi("NewName");
+ try {
+ Main.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ } catch (Exception e) {
+ System.out.println(
+ "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")");
+ }
+ t.sayHi("NewName");
+ }
+}
diff --git a/test/921-hello-failure/src/ReorderInterface.java b/test/921-hello-failure/src/ReorderInterface.java
new file mode 100644
index 0000000..ce78dbc
--- /dev/null
+++ b/test/921-hello-failure/src/ReorderInterface.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 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.Base64;
+
+class ReorderInterface {
+ // The following is a base64 encoding of the following class.
+ // class Transform2 implements Iface2, Iface1 {
+ // public void sayHi(String name) {
+ // throw new Error("Should not be called!");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAGQoABgARBwASCAATCgACABQHABUHABYHABcHABgBAAY8aW5pdD4BAAMoKVYBAARD" +
+ "b2RlAQAPTGluZU51bWJlclRhYmxlAQAFc2F5SGkBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAApT" +
+ "b3VyY2VGaWxlAQAPVHJhbnNmb3JtMi5qYXZhDAAJAAoBAA9qYXZhL2xhbmcvRXJyb3IBABVTaG91" +
+ "bGQgbm90IGJlIGNhbGxlZCEMAAkADgEAClRyYW5zZm9ybTIBABBqYXZhL2xhbmcvT2JqZWN0AQAG" +
+ "SWZhY2UyAQAGSWZhY2UxACAABQAGAAIABwAIAAAAAgAAAAkACgABAAsAAAAdAAEAAQAAAAUqtwAB" +
+ "sQAAAAEADAAAAAYAAQAAAAEAAQANAA4AAQALAAAAIgADAAIAAAAKuwACWRIDtwAEvwAAAAEADAAA" +
+ "AAYAAQAAAAMAAQAPAAAAAgAQ");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQChWfUC02YEHJZLC4V4pHrGMdqwD8NnzXvAAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAN" +
+ "AAAAcAAAAAcAAACkAAAAAgAAAMAAAAAAAAAAAAAAAAQAAADYAAAAAQAAAPgAAACoAQAAGAEAAGIB" +
+ "AABqAQAAdAEAAH4BAACMAQAAnwEAALMBAADHAQAA3gEAAO8BAADyAQAA9gEAAAoCAAABAAAAAgAA" +
+ "AAMAAAAEAAAABQAAAAYAAAAJAAAACQAAAAYAAAAAAAAACgAAAAYAAABcAQAAAgAAAAAAAAACAAEA" +
+ "DAAAAAMAAQAAAAAABAAAAAAAAAACAAAAAAAAAAQAAABUAQAACAAAAAAAAAAcAgAAAAAAAAEAAQAB" +
+ "AAAAEQIAAAQAAABwEAMAAAAOAAQAAgACAAAAFgIAAAkAAAAiAAMAGwEHAAAAcCACABAAJwAAAAIA" +
+ "AAABAAAAAQAAAAUABjxpbml0PgAITElmYWNlMTsACExJZmFjZTI7AAxMVHJhbnNmb3JtMjsAEUxq" +
+ "YXZhL2xhbmcvRXJyb3I7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAV" +
+ "U2hvdWxkIG5vdCBiZSBjYWxsZWQhAA9UcmFuc2Zvcm0yLmphdmEAAVYAAlZMABJlbWl0dGVyOiBq" +
+ "YWNrLTQuMjAABXNheUhpAAEABw4AAwEABw4AAAABAQCAgASYAgEBsAIAAAwAAAAAAAAAAQAAAAAA" +
+ "AAABAAAADQAAAHAAAAACAAAABwAAAKQAAAADAAAAAgAAAMAAAAAFAAAABAAAANgAAAAGAAAAAQAA" +
+ "APgAAAABIAAAAgAAABgBAAABEAAAAgAAAFQBAAACIAAADQAAAGIBAAADIAAAAgAAABECAAAAIAAA" +
+ "AQAAABwCAAAAEAAAAQAAACwCAAA=");
+
+ public static void doTest(Transform2 t) {
+ t.sayHi("ReorderInterface");
+ try {
+ Main.doCommonClassRedefinition(Transform2.class, CLASS_BYTES, DEX_BYTES);
+ } catch (Exception e) {
+ System.out.println(
+ "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")");
+ }
+ t.sayHi("ReorderInterface");
+ }
+}
diff --git a/test/921-hello-failure/src/Transform.java b/test/921-hello-failure/src/Transform.java
new file mode 100644
index 0000000..ee444f0
--- /dev/null
+++ b/test/921-hello-failure/src/Transform.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+class Transform {
+ public void sayHi(String name) {
+ System.out.println("hello - " + name);
+ }
+}
diff --git a/test/921-hello-failure/src/Transform2.java b/test/921-hello-failure/src/Transform2.java
new file mode 100644
index 0000000..9d949f3
--- /dev/null
+++ b/test/921-hello-failure/src/Transform2.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+class Transform2 implements Iface1, Iface2 {
+ public void sayHi(String name) {
+ System.out.println("hello2 - " + name);
+ }
+}
diff --git a/test/922-properties/build b/test/922-properties/build
new file mode 100755
index 0000000..898e2e5
--- /dev/null
+++ b/test/922-properties/build
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+./default-build "$@" --experimental agents
diff --git a/test/922-properties/expected.txt b/test/922-properties/expected.txt
new file mode 100644
index 0000000..0be939b
--- /dev/null
+++ b/test/922-properties/expected.txt
@@ -0,0 +1,59 @@
+Recommended properties:
+ "java.class.path": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.library.path": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.vm.info": OK !!!JVMTI_ERROR_NOT_AVAILABLE
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.vm.name": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.vm.vendor": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.vm.version": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+Missing recommended properties: [java.vm.info]
+Other properties:
+ "file.encoding": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "file.separator": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.class.version": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.compiler": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.ext.dirs": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.net.preferIPv6Addresses": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.specification.name": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.specification.vendor": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.specification.version": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.vendor": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.vendor.url": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.version": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.vm.specification.name": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.vm.specification.vendor": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.vm.specification.version": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "java.vm.vendor.url": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "line.separator": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "os.name": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+ "path.separator": OK
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+Non-specified property:
+ "java.boot.class.path": ERROR !!!JVMTI_ERROR_NOT_AVAILABLE
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
+Non-specified property (2):
+ "a": OK !!!JVMTI_ERROR_NOT_AVAILABLE
+ Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE
diff --git a/test/922-properties/info.txt b/test/922-properties/info.txt
new file mode 100644
index 0000000..875a5f6
--- /dev/null
+++ b/test/922-properties/info.txt
@@ -0,0 +1 @@
+Tests basic functions in the jvmti plugin.
diff --git a/test/922-properties/properties.cc b/test/922-properties/properties.cc
new file mode 100644
index 0000000..b1e7fce
--- /dev/null
+++ b/test/922-properties/properties.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 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 "properties.h"
+
+#include <stdio.h>
+
+#include "base/macros.h"
+#include "jni.h"
+#include "openjdkjvmti/jvmti.h"
+#include "ScopedUtfChars.h"
+
+#include "ti-agent/common_helper.h"
+#include "ti-agent/common_load.h"
+
+namespace art {
+namespace Test922Properties {
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getSystemProperties(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
+ jint count;
+ char** properties;
+ jvmtiError result = jvmti_env->GetSystemProperties(&count, &properties);
+ if (JvmtiErrorToException(env, result)) {
+ return nullptr;
+ }
+
+ auto callback = [&](jint i) -> jstring {
+ char* data = properties[i];
+ if (data == nullptr) {
+ return nullptr;
+ }
+ jstring ret = env->NewStringUTF(data);
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(data));
+ return ret;
+ };
+ jobjectArray ret = CreateObjectArray(env, count, "java/lang/String", callback);
+
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(properties));
+
+ return ret;
+}
+
+extern "C" JNIEXPORT jstring JNICALL Java_Main_getSystemProperty(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring key) {
+ ScopedUtfChars string(env, key);
+ if (string.c_str() == nullptr) {
+ return nullptr;
+ }
+
+ char* value = nullptr;
+ jvmtiError result = jvmti_env->GetSystemProperty(string.c_str(), &value);
+ if (JvmtiErrorToException(env, result)) {
+ return nullptr;
+ }
+
+ jstring ret = (value == nullptr) ? nullptr : env->NewStringUTF(value);
+
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(value));
+
+ return ret;
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_setSystemProperty(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring key, jstring value) {
+ ScopedUtfChars key_string(env, key);
+ if (key_string.c_str() == nullptr) {
+ return;
+ }
+ ScopedUtfChars value_string(env, value);
+ if (value_string.c_str() == nullptr) {
+ return;
+ }
+
+ jvmtiError result = jvmti_env->SetSystemProperty(key_string.c_str(), value_string.c_str());
+ if (JvmtiErrorToException(env, result)) {
+ return;
+ }
+}
+
+// Don't do anything
+jint OnLoad(JavaVM* vm,
+ char* options ATTRIBUTE_UNUSED,
+ void* reserved ATTRIBUTE_UNUSED) {
+ if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
+ printf("Unable to get jvmti env!\n");
+ return 1;
+ }
+ SetAllCapabilities(jvmti_env);
+ return 0;
+}
+
+} // namespace Test922Properties
+} // namespace art
diff --git a/test/922-properties/properties.h b/test/922-properties/properties.h
new file mode 100644
index 0000000..84feb10
--- /dev/null
+++ b/test/922-properties/properties.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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_TEST_922_PROPERTIES_PROPERTIES_H_
+#define ART_TEST_922_PROPERTIES_PROPERTIES_H_
+
+#include <jni.h>
+
+namespace art {
+namespace Test922Properties {
+
+jint OnLoad(JavaVM* vm, char* options, void* reserved);
+
+} // namespace Test922Properties
+} // namespace art
+
+#endif // ART_TEST_922_PROPERTIES_PROPERTIES_H_
diff --git a/test/922-properties/run b/test/922-properties/run
new file mode 100755
index 0000000..4379349
--- /dev/null
+++ b/test/922-properties/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+./default-run "$@" --experimental agents \
+ --experimental runtime-plugins \
+ --jvmti
diff --git a/test/922-properties/src/Main.java b/test/922-properties/src/Main.java
new file mode 100644
index 0000000..6cec6e9
--- /dev/null
+++ b/test/922-properties/src/Main.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 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.Set;
+import java.util.TreeSet;
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[1]);
+
+ doTest();
+ }
+
+ public static void doTest() throws Exception {
+ Set<String> recommendedProperties = getRecommendedProperties();
+
+ System.out.println("Recommended properties:");
+ for (String key : recommendedProperties) {
+ checkProperty(key);
+ }
+
+ Set<String> allProperties = getAllProperties();
+
+ Set<String> retained = new TreeSet<String>(recommendedProperties);
+ retained.retainAll(allProperties);
+ if (!retained.equals(recommendedProperties)) {
+ Set<String> missing = new TreeSet<String>(recommendedProperties);
+ missing.removeAll(retained);
+ System.out.println("Missing recommended properties: " + missing);
+ }
+
+ Set<String> nonRecommended = new TreeSet<String>(allProperties);
+ nonRecommended.removeAll(recommendedProperties);
+
+ System.out.println("Other properties:");
+ for (String key : nonRecommended) {
+ checkProperty(key);
+ }
+
+ System.out.println("Non-specified property:");
+ String key = generate(allProperties);
+ checkProperty(key);
+
+ System.out.println("Non-specified property (2):");
+ String key2 = generateUnique(allProperties);
+ checkProperty(key2);
+ }
+
+ private static Set<String> getRecommendedProperties() {
+ Set<String> keys = new TreeSet<String>();
+ keys.add("java.vm.vendor");
+ keys.add("java.vm.version");
+ keys.add("java.vm.name");
+ keys.add("java.vm.info");
+ keys.add("java.library.path");
+ keys.add("java.class.path");
+ return keys;
+ }
+
+ private static Set<String> getAllProperties() {
+ Set<String> keys = new TreeSet<String>();
+ String[] props = getSystemProperties();
+ for (String p : props) {
+ keys.add(p);
+ }
+ return keys;
+ }
+
+ private static boolean equals(String s1, String s2) {
+ if (s1 == null && s2 == null) {
+ return true;
+ } else if (s1 != null) {
+ return s1.equals(s2);
+ } else {
+ return false;
+ }
+ }
+
+ private static void checkProperty(String key) {
+ System.out.print(" \"" + key + "\": ");
+ String err = null;
+ String value = null;
+ try {
+ value = getSystemProperty(key);
+ } catch (RuntimeException e) {
+ err = e.getMessage();
+ }
+ String sysValue = System.getProperty(key);
+ if (equals(value, sysValue)) {
+ System.out.print("OK");
+ if (err != null) {
+ System.out.println(" !!!" + err);
+ } else {
+ System.out.println();
+ }
+ } else {
+ System.out.println("ERROR !!!" + err);
+ }
+
+ System.out.print(" Setting value to \"abc\": ");
+ try {
+ setSystemProperty(key, "abc");
+ System.out.println("SUCCEEDED");
+ } catch (RuntimeException e) {
+ System.out.println("!!!" + e.getMessage());
+ }
+ }
+
+ private static String generateUnique(Set<String> others) {
+ // Construct something. To be deterministic, just use "a+".
+ StringBuilder sb = new StringBuilder("a");
+ for (;;) {
+ String key = sb.toString();
+ if (!others.contains(key)) {
+ return key;
+ }
+ sb.append('a');
+ }
+ }
+
+ private static String generate(Set<String> others) {
+ // First check for something in the overall System properties.
+ TreeSet<String> sysProps = new TreeSet<String>(System.getProperties().stringPropertyNames());
+ sysProps.removeAll(others);
+ if (!sysProps.isEmpty()) {
+ // Find something that starts with "java" or "os," trying to be platform-independent.
+ for (String s: sysProps) {
+ if (s.startsWith("java.") || s.startsWith("os.")) {
+ return s;
+ }
+ }
+ // Just return the first thing.
+ return sysProps.iterator().next();
+ }
+
+ return generateUnique(others);
+ }
+
+ private static native String[] getSystemProperties();
+ private static native String getSystemProperty(String key);
+ private static native void setSystemProperty(String key, String value);
+}
diff --git a/test/Android.bp b/test/Android.bp
index 26c4f93..f6648d1 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -261,6 +261,8 @@
"912-classes/classes.cc",
"913-heaps/heaps.cc",
"918-fields/fields.cc",
+ "920-objects/objects.cc",
+ "922-properties/properties.cc",
],
shared_libs: [
"libbase",
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 670b103..a3f6864 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -292,6 +292,9 @@
917-fields-transformation \
918-fields \
919-obsolete-fields \
+ 920-objects \
+ 921-hello-failure \
+ 922-properties \
ifneq (,$(filter target,$(TARGET_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
@@ -1023,10 +1026,11 @@
test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_IMAGE_RULES
run_test_options += --no-image
# Add the core dependency. This is required for pre-building.
+ # Use the PIC image, as it is the default in run-test, to match dependencies.
ifeq ($(1),host)
- prereq_rule += $$(HOST_CORE_IMAGE_$$(image_suffix)_no-pic_$(13))
+ prereq_rule += $$(HOST_CORE_IMAGE_$$(image_suffix)_pic_$(13))
else
- prereq_rule += $$(TARGET_CORE_IMAGE_$$(image_suffix)_no-pic_$(13))
+ prereq_rule += $$(TARGET_CORE_IMAGE_$$(image_suffix)_pic_$(13))
endif
else
ifeq ($(9),npicimage)
diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc
index ebf1e46..6f98f10 100644
--- a/test/ti-agent/common_helper.cc
+++ b/test/ti-agent/common_helper.cc
@@ -17,6 +17,7 @@
#include "ti-agent/common_helper.h"
#include <stdio.h>
+#include <sstream>
#include "art_method.h"
#include "jni.h"
@@ -39,10 +40,46 @@
env->AddCapabilities(&caps);
}
+bool JvmtiErrorToException(JNIEnv* env, jvmtiError error) {
+ if (error == JVMTI_ERROR_NONE) {
+ return false;
+ }
+
+ ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
+ if (rt_exception.get() == nullptr) {
+ // CNFE should be pending.
+ return true;
+ }
+
+ char* err;
+ jvmti_env->GetErrorName(error, &err);
+
+ env->ThrowNew(rt_exception.get(), err);
+
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ return true;
+}
+
namespace common_redefine {
+static void throwRedefinitionError(jvmtiEnv* jvmti, JNIEnv* env, jclass target, jvmtiError res) {
+ std::stringstream err;
+ char* signature = nullptr;
+ char* generic = nullptr;
+ jvmti->GetClassSignature(target, &signature, &generic);
+ char* error = nullptr;
+ jvmti->GetErrorName(res, &error);
+ err << "Failed to redefine class <" << signature << "> due to " << error;
+ std::string message = err.str();
+ jvmti->Deallocate(reinterpret_cast<unsigned char*>(signature));
+ jvmti->Deallocate(reinterpret_cast<unsigned char*>(generic));
+ jvmti->Deallocate(reinterpret_cast<unsigned char*>(error));
+ env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str());
+}
+
using RedefineDirectFunction = jvmtiError (*)(jvmtiEnv*, jclass, jint, const unsigned char*);
-static void DoClassTransformation(jvmtiEnv* jvmti_env, JNIEnv* env,
+static void DoClassTransformation(jvmtiEnv* jvmti_env,
+ JNIEnv* env,
jclass target,
jbyteArray class_file_bytes,
jbyteArray dex_file_bytes) {
@@ -63,7 +100,7 @@
res = f(jvmti_env, target, len, redef_bytes);
}
if (res != JVMTI_ERROR_NONE) {
- printf("Redefinition failed!");
+ throwRedefinitionError(jvmti_env, env, target, res);
}
}
diff --git a/test/ti-agent/common_helper.h b/test/ti-agent/common_helper.h
index 76543fe..642ca03 100644
--- a/test/ti-agent/common_helper.h
+++ b/test/ti-agent/common_helper.h
@@ -65,6 +65,8 @@
void SetAllCapabilities(jvmtiEnv* env);
+bool JvmtiErrorToException(JNIEnv* env, jvmtiError error);
+
} // namespace art
#endif // ART_TEST_TI_AGENT_COMMON_HELPER_H_
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index d60cff3..e309a89 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -38,6 +38,8 @@
#include "912-classes/classes.h"
#include "913-heaps/heaps.h"
#include "918-fields/fields.h"
+#include "920-objects/objects.h"
+#include "922-properties/properties.h"
namespace art {
@@ -73,6 +75,9 @@
{ "917-fields-transformation", common_redefine::OnLoad, nullptr },
{ "918-fields", Test918Fields::OnLoad, nullptr },
{ "919-obsolete-fields", common_redefine::OnLoad, nullptr },
+ { "920-objects", Test920Objects::OnLoad, nullptr },
+ { "921-hello-failure", common_redefine::OnLoad, nullptr },
+ { "922-properties", Test922Properties::OnLoad, nullptr },
};
static AgentLib* FindAgent(char* name) {
diff --git a/test/valgrind-target-suppressions.txt b/test/valgrind-target-suppressions.txt
index fbc99b1..452a174 100644
--- a/test/valgrind-target-suppressions.txt
+++ b/test/valgrind-target-suppressions.txt
@@ -36,8 +36,7 @@
MemCpySelfAssign
Memcheck:Overlap
fun:memcpy
- fun:je_tsd_set
- fun:je_tsd_fetch
+ ...
fun:je_malloc_tsd_boot0
}
@@ -59,3 +58,12 @@
...
fun:_ZN3art7Runtime17InitNativeMethodsEv
}
+
+# art::MemMap::MapInternal() uses msync() to check for the existence of memory mappings.
+{
+ art::MemMap::MapInternal()
+ Memcheck:Param
+ msync(start)
+ fun:msync
+ fun:_ZN3art6MemMap11MapInternalEPvmiiilb
+}