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