Merge "Disable 677-fsi2 on RI."
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 42031f9..24dc2ee 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -448,11 +448,9 @@
invoke_type,
target_method,
HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+ RangeInstructionOperands operands(graph_->GetNumberOfVRegs() - in_vregs, in_vregs);
HandleInvoke(invoke,
- in_vregs,
- /* args */ nullptr,
- graph_->GetNumberOfVRegs() - in_vregs,
- /* is_range */ true,
+ operands,
dex_file_->GetMethodShorty(method_idx),
/* clinit_check */ nullptr,
/* is_unresolved */ false);
@@ -916,10 +914,7 @@
bool HInstructionBuilder::BuildInvoke(const Instruction& instruction,
uint32_t dex_pc,
uint32_t method_idx,
- uint32_t number_of_vreg_arguments,
- bool is_range,
- uint32_t* args,
- uint32_t register_index) {
+ const InstructionOperands& operands) {
InvokeType invoke_type = GetInvokeTypeFromOpCode(instruction.Opcode());
const char* descriptor = dex_file_->GetMethodShorty(method_idx);
DataType::Type return_type = DataType::FromShorty(descriptor[0]);
@@ -943,12 +938,9 @@
method_idx,
invoke_type);
return HandleInvoke(invoke,
- number_of_vreg_arguments,
- args,
- register_index,
- is_range,
+ operands,
descriptor,
- nullptr, /* clinit_check */
+ nullptr /* clinit_check */,
true /* is_unresolved */);
}
@@ -976,12 +968,7 @@
invoke_type,
target_method,
HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit);
- return HandleStringInit(invoke,
- number_of_vreg_arguments,
- args,
- register_index,
- is_range,
- descriptor);
+ return HandleStringInit(invoke, operands, descriptor);
}
// Potential class initialization check, in the case of a static method call.
@@ -1042,26 +1029,16 @@
ImTable::GetImtIndex(resolved_method));
}
- return HandleInvoke(invoke,
- number_of_vreg_arguments,
- args,
- register_index,
- is_range,
- descriptor,
- clinit_check,
- false /* is_unresolved */);
+ return HandleInvoke(invoke, operands, descriptor, clinit_check, false /* is_unresolved */);
}
bool HInstructionBuilder::BuildInvokePolymorphic(const Instruction& instruction ATTRIBUTE_UNUSED,
uint32_t dex_pc,
uint32_t method_idx,
dex::ProtoIndex proto_idx,
- uint32_t number_of_vreg_arguments,
- bool is_range,
- uint32_t* args,
- uint32_t register_index) {
+ const InstructionOperands& operands) {
const char* descriptor = dex_file_->GetShorty(proto_idx);
- DCHECK_EQ(1 + ArtMethod::NumArgRegisters(descriptor), number_of_vreg_arguments);
+ DCHECK_EQ(1 + ArtMethod::NumArgRegisters(descriptor), operands.GetNumberOfOperands());
DataType::Type return_type = DataType::FromShorty(descriptor[0]);
size_t number_of_arguments = strlen(descriptor);
HInvoke* invoke = new (allocator_) HInvokePolymorphic(allocator_,
@@ -1070,10 +1047,7 @@
dex_pc,
method_idx);
return HandleInvoke(invoke,
- number_of_vreg_arguments,
- args,
- register_index,
- is_range,
+ operands,
descriptor,
nullptr /* clinit_check */,
false /* is_unresolved */);
@@ -1222,26 +1196,22 @@
}
bool HInstructionBuilder::SetupInvokeArguments(HInvoke* invoke,
- uint32_t number_of_vreg_arguments,
- uint32_t* args,
- uint32_t register_index,
- bool is_range,
+ const InstructionOperands& operands,
const char* descriptor,
size_t start_index,
size_t* argument_index) {
uint32_t descriptor_index = 1; // Skip the return type.
-
+ const size_t number_of_operands = operands.GetNumberOfOperands();
for (size_t i = start_index;
// Make sure we don't go over the expected arguments or over the number of
// dex registers given. If the instruction was seen as dead by the verifier,
// it hasn't been properly checked.
- (i < number_of_vreg_arguments) && (*argument_index < invoke->GetNumberOfArguments());
+ (i < number_of_operands) && (*argument_index < invoke->GetNumberOfArguments());
i++, (*argument_index)++) {
DataType::Type type = DataType::FromShorty(descriptor[descriptor_index++]);
bool is_wide = (type == DataType::Type::kInt64) || (type == DataType::Type::kFloat64);
- if (!is_range
- && is_wide
- && ((i + 1 == number_of_vreg_arguments) || (args[i] + 1 != args[i + 1]))) {
+ if (is_wide && ((i + 1 == number_of_operands) ||
+ (operands.GetOperand(i) + 1 != operands.GetOperand(i + 1)))) {
// Longs and doubles should be in pairs, that is, sequential registers. The verifier should
// reject any class where this is violated. However, the verifier only does these checks
// on non trivially dead instructions, so we just bailout the compilation.
@@ -1252,7 +1222,7 @@
MethodCompilationStat::kNotCompiledMalformedOpcode);
return false;
}
- HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type);
+ HInstruction* arg = LoadLocal(operands.GetOperand(i), type);
invoke->SetArgumentAt(*argument_index, arg);
if (is_wide) {
i++;
@@ -1279,10 +1249,7 @@
}
bool HInstructionBuilder::HandleInvoke(HInvoke* invoke,
- uint32_t number_of_vreg_arguments,
- uint32_t* args,
- uint32_t register_index,
- bool is_range,
+ const InstructionOperands& operands,
const char* descriptor,
HClinitCheck* clinit_check,
bool is_unresolved) {
@@ -1291,7 +1258,7 @@
size_t start_index = 0;
size_t argument_index = 0;
if (invoke->GetInvokeType() != InvokeType::kStatic) { // Instance call.
- uint32_t obj_reg = is_range ? register_index : args[0];
+ uint32_t obj_reg = operands.GetOperand(0);
HInstruction* arg = is_unresolved
? LoadLocal(obj_reg, DataType::Type::kReference)
: LoadNullCheckedLocal(obj_reg, invoke->GetDexPc());
@@ -1300,14 +1267,7 @@
argument_index = 1;
}
- if (!SetupInvokeArguments(invoke,
- number_of_vreg_arguments,
- args,
- register_index,
- is_range,
- descriptor,
- start_index,
- &argument_index)) {
+ if (!SetupInvokeArguments(invoke, operands, descriptor, start_index, &argument_index)) {
return false;
}
@@ -1327,24 +1287,14 @@
}
bool HInstructionBuilder::HandleStringInit(HInvoke* invoke,
- uint32_t number_of_vreg_arguments,
- uint32_t* args,
- uint32_t register_index,
- bool is_range,
+ const InstructionOperands& operands,
const char* descriptor) {
DCHECK(invoke->IsInvokeStaticOrDirect());
DCHECK(invoke->AsInvokeStaticOrDirect()->IsStringInit());
size_t start_index = 1;
size_t argument_index = 0;
- if (!SetupInvokeArguments(invoke,
- number_of_vreg_arguments,
- args,
- register_index,
- is_range,
- descriptor,
- start_index,
- &argument_index)) {
+ if (!SetupInvokeArguments(invoke, operands, descriptor, start_index, &argument_index)) {
return false;
}
@@ -1352,7 +1302,7 @@
// This is a StringFactory call, not an actual String constructor. Its result
// replaces the empty String pre-allocated by NewInstance.
- uint32_t orig_this_reg = is_range ? register_index : args[0];
+ uint32_t orig_this_reg = operands.GetOperand(0);
HInstruction* arg_this = LoadLocal(orig_this_reg, DataType::Type::kReference);
// Replacing the NewInstance might render it redundant. Keep a list of these
@@ -1705,11 +1655,9 @@
HNewArray* HInstructionBuilder::BuildFilledNewArray(uint32_t dex_pc,
dex::TypeIndex type_index,
- uint32_t number_of_vreg_arguments,
- bool is_range,
- uint32_t* args,
- uint32_t register_index) {
- HInstruction* length = graph_->GetIntConstant(number_of_vreg_arguments, dex_pc);
+ const InstructionOperands& operands) {
+ const size_t number_of_operands = operands.GetNumberOfOperands();
+ HInstruction* length = graph_->GetIntConstant(number_of_operands, dex_pc);
HLoadClass* cls = BuildLoadClass(type_index, dex_pc);
HNewArray* const object = new (allocator_) HNewArray(cls, length, dex_pc);
AppendInstruction(object);
@@ -1723,8 +1671,8 @@
bool is_reference_array = (primitive == 'L') || (primitive == '[');
DataType::Type type = is_reference_array ? DataType::Type::kReference : DataType::Type::kInt32;
- for (size_t i = 0; i < number_of_vreg_arguments; ++i) {
- HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type);
+ for (size_t i = 0; i < number_of_operands; ++i) {
+ HInstruction* value = LoadLocal(operands.GetOperand(i), type);
HInstruction* index = graph_->GetIntConstant(i, dex_pc);
HArraySet* aset = new (allocator_) HArraySet(object, index, value, type, dex_pc);
ssa_builder_->MaybeAddAmbiguousArraySet(aset);
@@ -2157,11 +2105,10 @@
} else {
method_idx = instruction.VRegB_35c();
}
- uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
uint32_t args[5];
- instruction.GetVarArgs(args);
- if (!BuildInvoke(instruction, dex_pc, method_idx,
- number_of_vreg_arguments, false, args, -1)) {
+ uint32_t number_of_vreg_arguments = instruction.GetVarArgs(args);
+ VarArgsInstructionOperands operands(args, number_of_vreg_arguments);
+ if (!BuildInvoke(instruction, dex_pc, method_idx, operands)) {
return false;
}
break;
@@ -2184,10 +2131,8 @@
} else {
method_idx = instruction.VRegB_3rc();
}
- uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
- uint32_t register_index = instruction.VRegC();
- if (!BuildInvoke(instruction, dex_pc, method_idx,
- number_of_vreg_arguments, true, nullptr, register_index)) {
+ RangeInstructionOperands operands(instruction.VRegC(), instruction.VRegA_3rc());
+ if (!BuildInvoke(instruction, dex_pc, method_idx, operands)) {
return false;
}
break;
@@ -2196,32 +2141,17 @@
case Instruction::INVOKE_POLYMORPHIC: {
uint16_t method_idx = instruction.VRegB_45cc();
dex::ProtoIndex proto_idx(instruction.VRegH_45cc());
- uint32_t number_of_vreg_arguments = instruction.VRegA_45cc();
uint32_t args[5];
- instruction.GetVarArgs(args);
- return BuildInvokePolymorphic(instruction,
- dex_pc,
- method_idx,
- proto_idx,
- number_of_vreg_arguments,
- false,
- args,
- -1);
+ uint32_t number_of_vreg_arguments = instruction.GetVarArgs(args);
+ VarArgsInstructionOperands operands(args, number_of_vreg_arguments);
+ return BuildInvokePolymorphic(instruction, dex_pc, method_idx, proto_idx, operands);
}
case Instruction::INVOKE_POLYMORPHIC_RANGE: {
uint16_t method_idx = instruction.VRegB_4rcc();
dex::ProtoIndex proto_idx(instruction.VRegH_4rcc());
- uint32_t number_of_vreg_arguments = instruction.VRegA_4rcc();
- uint32_t register_index = instruction.VRegC_4rcc();
- return BuildInvokePolymorphic(instruction,
- dex_pc,
- method_idx,
- proto_idx,
- number_of_vreg_arguments,
- true,
- nullptr,
- register_index);
+ RangeInstructionOperands operands(instruction.VRegC_4rcc(), instruction.VRegA_4rcc());
+ return BuildInvokePolymorphic(instruction, dex_pc, method_idx, proto_idx, operands);
}
case Instruction::NEG_INT: {
@@ -2769,30 +2699,19 @@
}
case Instruction::FILLED_NEW_ARRAY: {
- uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
dex::TypeIndex type_index(instruction.VRegB_35c());
uint32_t args[5];
- instruction.GetVarArgs(args);
- HNewArray* new_array = BuildFilledNewArray(dex_pc,
- type_index,
- number_of_vreg_arguments,
- /* is_range */ false,
- args,
- /* register_index */ 0);
+ uint32_t number_of_vreg_arguments = instruction.GetVarArgs(args);
+ VarArgsInstructionOperands operands(args, number_of_vreg_arguments);
+ HNewArray* new_array = BuildFilledNewArray(dex_pc, type_index, operands);
BuildConstructorFenceForAllocation(new_array);
break;
}
case Instruction::FILLED_NEW_ARRAY_RANGE: {
- uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
dex::TypeIndex type_index(instruction.VRegB_3rc());
- uint32_t register_index = instruction.VRegC_3rc();
- HNewArray* new_array = BuildFilledNewArray(dex_pc,
- type_index,
- number_of_vreg_arguments,
- /* is_range */ true,
- /* args*/ nullptr,
- register_index);
+ RangeInstructionOperands operands(instruction.VRegC_3rc(), instruction.VRegA_3rc());
+ HNewArray* new_array = BuildFilledNewArray(dex_pc, type_index, operands);
BuildConstructorFenceForAllocation(new_array);
break;
}
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index 9d886a8..2218a69 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -38,6 +38,7 @@
class DexCompilationUnit;
class HBasicBlockBuilder;
class Instruction;
+class InstructionOperands;
class OptimizingCompilerStats;
class ScopedObjectAccess;
class SsaBuilder;
@@ -168,10 +169,7 @@
bool BuildInvoke(const Instruction& instruction,
uint32_t dex_pc,
uint32_t method_idx,
- uint32_t number_of_vreg_arguments,
- bool is_range,
- uint32_t* args,
- uint32_t register_index);
+ const InstructionOperands& operands);
// Builds an invocation node for invoke-polymorphic and returns whether the
// instruction is supported.
@@ -179,18 +177,12 @@
uint32_t dex_pc,
uint32_t method_idx,
dex::ProtoIndex proto_idx,
- uint32_t number_of_vreg_arguments,
- bool is_range,
- uint32_t* args,
- uint32_t register_index);
+ const InstructionOperands& operands);
// Builds a new array node and the instructions that fill it.
HNewArray* BuildFilledNewArray(uint32_t dex_pc,
dex::TypeIndex type_index,
- uint32_t number_of_vreg_arguments,
- bool is_range,
- uint32_t* args,
- uint32_t register_index);
+ const InstructionOperands& operands);
void BuildFillArrayData(const Instruction& instruction, uint32_t dex_pc);
@@ -260,28 +252,19 @@
HInvoke* invoke);
bool SetupInvokeArguments(HInvoke* invoke,
- uint32_t number_of_vreg_arguments,
- uint32_t* args,
- uint32_t register_index,
- bool is_range,
+ const InstructionOperands& operands,
const char* descriptor,
size_t start_index,
size_t* argument_index);
bool HandleInvoke(HInvoke* invoke,
- uint32_t number_of_vreg_arguments,
- uint32_t* args,
- uint32_t register_index,
- bool is_range,
+ const InstructionOperands& operands,
const char* descriptor,
HClinitCheck* clinit_check,
bool is_unresolved);
bool HandleStringInit(HInvoke* invoke,
- uint32_t number_of_vreg_arguments,
- uint32_t* args,
- uint32_t register_index,
- bool is_range,
+ const InstructionOperands& operands,
const char* descriptor);
void HandleStringInitResult(HInvokeStaticOrDirect* invoke);
diff --git a/libartbase/base/file_utils.cc b/libartbase/base/file_utils.cc
index 9450e1e..56934ac 100644
--- a/libartbase/base/file_utils.cc
+++ b/libartbase/base/file_utils.cc
@@ -264,7 +264,8 @@
bool LocationIsOnSystem(const char* path) {
UniqueCPtr<const char[]> full_path(realpath(path, nullptr));
- return path != nullptr && android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str());
+ return full_path != nullptr &&
+ android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str());
}
bool LocationIsOnSystemFramework(const char* full_path) {
diff --git a/libdexfile/dex/dex_instruction-inl.h b/libdexfile/dex/dex_instruction-inl.h
index 6bef18c..e0cffdd 100644
--- a/libdexfile/dex/dex_instruction-inl.h
+++ b/libdexfile/dex/dex_instruction-inl.h
@@ -508,7 +508,7 @@
return (FormatOf(Opcode()) == k35c) || (FormatOf(Opcode()) == k45cc);
}
-inline void Instruction::GetVarArgs(uint32_t arg[kMaxVarArgRegs], uint16_t inst_data) const {
+inline uint32_t Instruction::GetVarArgs(uint32_t arg[kMaxVarArgRegs], uint16_t inst_data) const {
DCHECK(HasVarArgs());
/*
@@ -551,6 +551,7 @@
default: // case 0
break; // Valid, but no need to do anything.
}
+ return count;
}
} // namespace art
diff --git a/libdexfile/dex/dex_instruction.h b/libdexfile/dex/dex_instruction.h
index bf50836..6807025 100644
--- a/libdexfile/dex/dex_instruction.h
+++ b/libdexfile/dex/dex_instruction.h
@@ -462,8 +462,8 @@
// Fills the given array with the 'arg' array of the instruction.
bool HasVarArgs() const;
- void GetVarArgs(uint32_t args[kMaxVarArgRegs], uint16_t inst_data) const;
- void GetVarArgs(uint32_t args[kMaxVarArgRegs]) const {
+ uint32_t GetVarArgs(uint32_t args[kMaxVarArgRegs], uint16_t inst_data) const;
+ uint32_t GetVarArgs(uint32_t args[kMaxVarArgRegs]) const {
return GetVarArgs(args, Fetch16(0));
}
diff --git a/test/677-fsi2/expected.txt b/test/677-fsi2/expected.txt
new file mode 100644
index 0000000..de00847
--- /dev/null
+++ b/test/677-fsi2/expected.txt
@@ -0,0 +1,4 @@
+Run default
+Hello World
+Run without dex2oat
+Hello World
diff --git a/test/677-fsi2/info.txt b/test/677-fsi2/info.txt
new file mode 100644
index 0000000..ed0a0f2
--- /dev/null
+++ b/test/677-fsi2/info.txt
@@ -0,0 +1 @@
+Test that -Xonly-use-system-oat-files works.
diff --git a/test/677-fsi2/run b/test/677-fsi2/run
new file mode 100644
index 0000000..039a6a7
--- /dev/null
+++ b/test/677-fsi2/run
@@ -0,0 +1,25 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+echo "Run default"
+${RUN} $@ --runtime-option -Xonly-use-system-oat-files
+return_status1=$?
+
+echo "Run without dex2oat"
+${RUN} $@ --no-dex2oat --runtime-option -Xonly-use-system-oat-files
+return_status2=$?
+
+(exit $return_status1) && (exit $return_status2)
diff --git a/test/677-fsi2/src/Main.java b/test/677-fsi2/src/Main.java
new file mode 100644
index 0000000..834075f
--- /dev/null
+++ b/test/677-fsi2/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void main(String[] args) {
+ System.out.println("Hello World");
+ }
+}
diff --git a/tools/tracefast-plugin/Android.bp b/tools/tracefast-plugin/Android.bp
new file mode 100644
index 0000000..1d7dd30
--- /dev/null
+++ b/tools/tracefast-plugin/Android.bp
@@ -0,0 +1,108 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Build variants {target,host} x {debug,ndebug} x {32,64}
+
+cc_defaults {
+ name: "tracefast-defaults",
+ host_supported: true,
+ srcs: ["tracefast.cc"],
+ defaults: ["art_defaults"],
+
+ // Note that this tool needs to be built for both 32-bit and 64-bit since it requires
+ // to be same ISA as what it is attached to.
+ compile_multilib: "both",
+
+ shared_libs: [
+ "libbase",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "libcutils",
+ ],
+ },
+ darwin: {
+ enabled: false,
+ },
+ },
+ header_libs: [
+ "libnativehelper_header_only",
+ ],
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+ symlink_preferred_arch: true,
+}
+
+cc_defaults {
+ name: "tracefast-interpreter-defaults",
+ defaults: ["tracefast-defaults"],
+ cflags: ["-DTRACEFAST_INTERPRETER=1"],
+}
+
+cc_defaults {
+ name: "tracefast-trampoline-defaults",
+ defaults: ["tracefast-defaults"],
+ cflags: ["-DTRACEFAST_TRAMPOLINE=1"],
+}
+
+art_cc_library {
+ name: "libtracefast-interpreter",
+ defaults: ["tracefast-interpreter-defaults"],
+ shared_libs: [
+ "libart",
+ "libartbase",
+ ],
+}
+
+art_cc_library {
+ name: "libtracefast-interpreterd",
+ defaults: [
+ "art_debug_defaults",
+ "tracefast-interpreter-defaults",
+ ],
+ shared_libs: [
+ "libartd",
+ "libartbased",
+ ],
+}
+
+art_cc_library {
+ name: "libtracefast-trampoline",
+ defaults: ["tracefast-trampoline-defaults"],
+ shared_libs: [
+ "libart",
+ "libartbase",
+ ],
+}
+
+art_cc_library {
+ name: "libtracefast-trampolined",
+ defaults: [
+ "art_debug_defaults",
+ "tracefast-trampoline-defaults",
+ ],
+ shared_libs: [
+ "libartd",
+ "libartbased",
+ ],
+}
diff --git a/tools/tracefast-plugin/tracefast.cc b/tools/tracefast-plugin/tracefast.cc
new file mode 100644
index 0000000..ed6ac3d
--- /dev/null
+++ b/tools/tracefast-plugin/tracefast.cc
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gc/scoped_gc_critical_section.h"
+#include "instrumentation.h"
+#include "runtime.h"
+#include "runtime_callbacks.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread-inl.h"
+#include "thread_list.h"
+
+namespace tracefast {
+
+#if ((!defined(TRACEFAST_INTERPRETER) && !defined(TRACEFAST_TRAMPOLINE)) || \
+ (defined(TRACEFAST_INTERPRETER) && defined(TRACEFAST_TRAMPOLINE)))
+#error Must set one of TRACEFAST_TRAMPOLINE or TRACEFAST_INTERPRETER during build
+#endif
+
+
+#ifdef TRACEFAST_INTERPRETER
+static constexpr const char* kTracerInstrumentationKey = "tracefast_INTERPRETER";
+static constexpr bool kNeedsInterpreter = true;
+#else // defined(TRACEFAST_TRAMPOLINE)
+static constexpr const char* kTracerInstrumentationKey = "tracefast_TRAMPOLINE";
+static constexpr bool kNeedsInterpreter = false;
+#endif // TRACEFAST_INITERPRETER
+
+class Tracer FINAL : public art::instrumentation::InstrumentationListener {
+ public:
+ Tracer() {}
+
+ void MethodEntered(art::Thread* thread ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED,
+ art::ArtMethod* method ATTRIBUTE_UNUSED,
+ uint32_t dex_pc ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ void MethodExited(art::Thread* thread ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED,
+ art::ArtMethod* method ATTRIBUTE_UNUSED,
+ uint32_t dex_pc ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Object> return_value ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ void MethodExited(art::Thread* thread ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED,
+ art::ArtMethod* method ATTRIBUTE_UNUSED,
+ uint32_t dex_pc ATTRIBUTE_UNUSED,
+ const art::JValue& return_value ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ void MethodUnwind(art::Thread* thread ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED,
+ art::ArtMethod* method ATTRIBUTE_UNUSED,
+ uint32_t dex_pc ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ void DexPcMoved(art::Thread* thread ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED,
+ art::ArtMethod* method ATTRIBUTE_UNUSED,
+ uint32_t new_dex_pc ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ void FieldRead(art::Thread* thread ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED,
+ art::ArtMethod* method ATTRIBUTE_UNUSED,
+ uint32_t dex_pc ATTRIBUTE_UNUSED,
+ art::ArtField* field ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ void FieldWritten(art::Thread* thread ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED,
+ art::ArtMethod* method ATTRIBUTE_UNUSED,
+ uint32_t dex_pc ATTRIBUTE_UNUSED,
+ art::ArtField* field ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Object> field_value ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ void FieldWritten(art::Thread* thread ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED,
+ art::ArtMethod* method ATTRIBUTE_UNUSED,
+ uint32_t dex_pc ATTRIBUTE_UNUSED,
+ art::ArtField* field ATTRIBUTE_UNUSED,
+ const art::JValue& field_value ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ void ExceptionThrown(art::Thread* thread ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Throwable> exception_object ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ void ExceptionHandled(art::Thread* self ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Throwable> throwable ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ void Branch(art::Thread* thread ATTRIBUTE_UNUSED,
+ art::ArtMethod* method ATTRIBUTE_UNUSED,
+ uint32_t dex_pc ATTRIBUTE_UNUSED,
+ int32_t dex_pc_offset ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ void InvokeVirtualOrInterface(art::Thread* thread ATTRIBUTE_UNUSED,
+ art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED,
+ art::ArtMethod* caller ATTRIBUTE_UNUSED,
+ uint32_t dex_pc ATTRIBUTE_UNUSED,
+ art::ArtMethod* callee ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ void WatchedFramePop(art::Thread* thread ATTRIBUTE_UNUSED,
+ const art::ShadowFrame& frame ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Tracer);
+};
+
+Tracer gEmptyTracer;
+
+static void StartTracing() REQUIRES(!art::Locks::mutator_lock_,
+ !art::Locks::thread_list_lock_,
+ !art::Locks::thread_suspend_count_lock_) {
+ art::Thread* self = art::Thread::Current();
+ art::Runtime* runtime = art::Runtime::Current();
+ art::gc::ScopedGCCriticalSection gcs(self,
+ art::gc::kGcCauseInstrumentation,
+ art::gc::kCollectorTypeInstrumentation);
+ art::ScopedSuspendAll ssa("starting fast tracing");
+ runtime->GetInstrumentation()->AddListener(&gEmptyTracer,
+ art::instrumentation::Instrumentation::kMethodEntered |
+ art::instrumentation::Instrumentation::kMethodExited |
+ art::instrumentation::Instrumentation::kMethodUnwind);
+ runtime->GetInstrumentation()->EnableMethodTracing(kTracerInstrumentationKey, kNeedsInterpreter);
+}
+
+class TraceFastPhaseCB : public art::RuntimePhaseCallback {
+ public:
+ TraceFastPhaseCB() {}
+
+ void NextRuntimePhase(art::RuntimePhaseCallback::RuntimePhase phase)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (phase == art::RuntimePhaseCallback::RuntimePhase::kInit) {
+ art::ScopedThreadSuspension sts(art::Thread::Current(),
+ art::ThreadState::kWaitingForMethodTracingStart);
+ StartTracing();
+ }
+ }
+};
+TraceFastPhaseCB gPhaseCallback;
+
+// The plugin initialization function.
+extern "C" bool ArtPlugin_Initialize() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ art::Runtime* runtime = art::Runtime::Current();
+ art::ScopedThreadSuspension stsc(art::Thread::Current(),
+ art::ThreadState::kWaitingForMethodTracingStart);
+ art::ScopedSuspendAll ssa("Add phase callback");
+ runtime->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&gPhaseCallback);
+ return true;
+}
+
+extern "C" bool ArtPlugin_Deinitialize() {
+ // Don't need to bother doing anything.
+ return true;
+}
+
+} // namespace tracefast