Add verifier fallback for JVMTI Get/SetLocalVariable

The JVMTI Get/SetLocalVariable functions used to rely entirely on the
Dex DebugInfo to determine the types of each of the registers. This
could lead to problems since, to prevent possible stack corruption, we
would not allow stack modification if the data was not present.

In order to remove this restriction we will instead make use of the
method verifier to ensure the modification is sensible when the
DebugInfo is not present. Since reconstructing this information using
the verifier is quite slow (compared to reading it from a table) we
will only do this when the table is missing.

Since the verifier lacks some of the information available when
creating the DebugLocalInfo table some semantics will change depending
on if the table is present or not.

 - When the DebugLocalInfo table is not present we cannot always
   distinguish between floats, ints, and other single-register
   primitive types. For simplicity all single-register primitive
   types can be modified and read by both the Float and Int versions
   of the local variable functions.

 - Similarly we cannot always distinguish between long and double
   variables.

 - Reference types are checked against what the verifier thinks they
   need to be according to type unification. This might be more or
   less specific than the types recorded in the functions source code.

 - Constant int/float '0' values and 'null' cannot always be
   differentiated by the verifier. Therefore, one may not always be
   able to modify some null or constant 0 registers.

Test: ./test.py --host
Bug: 131711256

Change-Id: I1c9d857ccdec752bfd4ebad76cc9ad96e143866c
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index 408ce69..4c6ea21 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -31,22 +31,33 @@
 
 #include "ti_method.h"
 
+#include <initializer_list>
 #include <type_traits>
+#include <variant>
 
+#include "android-base/macros.h"
 #include "arch/context.h"
 #include "art_jvmti.h"
 #include "art_method-inl.h"
 #include "base/enums.h"
+#include "base/globals.h"
+#include "base/macros.h"
 #include "base/mutex-inl.h"
 #include "deopt_manager.h"
 #include "dex/code_item_accessors-inl.h"
+#include "dex/code_item_accessors.h"
 #include "dex/dex_file_annotations.h"
 #include "dex/dex_file_types.h"
+#include "dex/dex_instruction.h"
+#include "dex/dex_instruction_iterator.h"
 #include "dex/modifiers.h"
+#include "dex/primitive.h"
 #include "events-inl.h"
 #include "gc_root-inl.h"
+#include "handle.h"
 #include "jit/jit.h"
 #include "jni/jni_internal.h"
+#include "jvmti.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
@@ -56,13 +67,18 @@
 #include "obj_ptr.h"
 #include "runtime_callbacks.h"
 #include "scoped_thread_state_change-inl.h"
+#include "scoped_thread_state_change.h"
 #include "stack.h"
 #include "thread-current-inl.h"
 #include "thread.h"
 #include "thread_list.h"
+#include "ti_logging.h"
 #include "ti_stack.h"
 #include "ti_thread.h"
 #include "ti_phase.h"
+#include "verifier/register_line-inl.h"
+#include "verifier/reg_type-inl.h"
+#include "verifier/method_verifier-inl.h"
 
 namespace openjdkjvmti {
 
@@ -526,10 +542,21 @@
 
 class CommonLocalVariableClosure : public art::Closure {
  public:
-  CommonLocalVariableClosure(jint depth, jint slot)
-      : result_(ERR(INTERNAL)), depth_(depth), slot_(slot) {}
+  // The verifier isn't always able to be as specific as the local-variable-table. We can only get
+  // 32-bit, 64-bit or reference.
+  enum class VerifierPrimitiveType {
+    k32BitValue,  // float, int, short, char, boolean, byte
+    k64BitValue,  // double, long
+    kReferenceValue,  // Object
+    kZeroValue,  // null or zero constant. Might be either k32BitValue or kReferenceValue
+  };
 
-  void Run(art::Thread* self) override REQUIRES(art::Locks::mutator_lock_) {
+  using SlotType = std::variant<art::Primitive::Type, VerifierPrimitiveType>;
+
+  CommonLocalVariableClosure(jvmtiEnv* jvmti, jint depth, jint slot)
+      : jvmti_(jvmti), result_(ERR(INTERNAL)), depth_(depth), slot_(slot) {}
+
+  void Run(art::Thread* self) override REQUIRES_SHARED(art::Locks::mutator_lock_) {
     art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
     bool needs_instrument;
     {
@@ -560,7 +587,7 @@
         return;
       }
       std::string descriptor;
-      art::Primitive::Type slot_type = art::Primitive::kPrimVoid;
+      SlotType slot_type{ art::Primitive::kPrimVoid };
       jvmtiError err = GetSlotType(method, pc, &descriptor, &slot_type);
       if (err != OK) {
         result_ = err;
@@ -587,56 +614,190 @@
   virtual jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
       REQUIRES_SHARED(art::Locks::mutator_lock_) = 0;
   virtual jvmtiError GetTypeError(art::ArtMethod* method,
-                                  art::Primitive::Type type,
+                                  SlotType type,
                                   const std::string& descriptor)
       REQUIRES_SHARED(art::Locks::mutator_lock_)  = 0;
 
   jvmtiError GetSlotType(art::ArtMethod* method,
                          uint32_t dex_pc,
                          /*out*/std::string* descriptor,
-                         /*out*/art::Primitive::Type* type)
-      REQUIRES(art::Locks::mutator_lock_) {
-    const art::DexFile* dex_file = method->GetDexFile();
-    if (dex_file == nullptr) {
+                         /*out*/SlotType* type)
+      REQUIRES_SHARED(art::Locks::mutator_lock_);
+
+  jvmtiError InferSlotTypeFromVerifier(art::ArtMethod* method,
+                                       uint32_t dex_pc,
+                                       /*out*/ std::string* descriptor,
+                                       /*out*/ SlotType* type)
+      REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    art::Thread* self = art::Thread::Current();
+    art::StackHandleScope<2> hs(self);
+    std::unique_ptr<art::verifier::MethodVerifier> verifier(
+        art::verifier::MethodVerifier::CalculateVerificationInfo(
+            self,
+            method,
+            hs.NewHandle(method->GetDexCache()),
+            hs.NewHandle(method->GetDeclaringClass()->GetClassLoader())));
+    if (verifier == nullptr) {
+      JVMTI_LOG(WARNING, jvmti_) << "Unable to extract verification information from "
+                                 << method->PrettyMethod() << " due to hard verification failures! "
+                                 << "How did this method even get loaded!";
+      return ERR(INTERNAL);
+    }
+    art::verifier::RegisterLine* line = verifier->GetRegLine(dex_pc);
+    if (line == nullptr) {
+      JVMTI_LOG(WARNING, jvmti_) << "Unable to determine register line at dex-pc " << dex_pc
+                                 << " for method " << method->PrettyMethod();
       return ERR(OPAQUE_FRAME);
     }
-    art::CodeItemDebugInfoAccessor accessor(method->DexInstructionDebugInfo());
-    if (!accessor.HasCodeItem()) {
-      return ERR(OPAQUE_FRAME);
-    }
-    bool found = false;
-    *type = art::Primitive::kPrimVoid;
-    descriptor->clear();
-    auto visitor = [&](const art::DexFile::LocalInfo& entry) {
-      if (!found &&
-          entry.start_address_ <= dex_pc &&
-          entry.end_address_ > dex_pc &&
-          entry.reg_ == slot_) {
-        found = true;
-        *type = art::Primitive::GetType(entry.descriptor_[0]);
-        *descriptor = entry.descriptor_;
-      }
-    };
-    if (!accessor.DecodeDebugLocalInfo(method->IsStatic(), method->GetDexMethodIndex(), visitor) ||
-        !found) {
-      // Something went wrong with decoding the debug information. It might as well not be there.
+    const art::verifier::RegType& rt = line->GetRegisterType(verifier.get(), slot_);
+    if (rt.IsUndefined()) {
+      return ERR(INVALID_SLOT);
+    } else if (rt.IsNonZeroReferenceTypes() || rt.IsNull()) {
+      *descriptor = (rt.HasClass() ? rt.GetDescriptor() : "Ljava/lang/Object;");
+      *type = VerifierPrimitiveType::kReferenceValue;
+      return OK;
+    } else if (rt.IsZero()) {
+      *descriptor = "I";
+      *type = VerifierPrimitiveType::kZeroValue;
+      return OK;
+    } else if (rt.IsCategory1Types()) {
+      *descriptor = "I";
+      *type = VerifierPrimitiveType::k32BitValue;
+      return OK;
+    } else if (rt.IsCategory2Types() && rt.IsLowHalf()) {
+      *descriptor = "J";
+      *type = VerifierPrimitiveType::k64BitValue;
+      return OK;
+    } else {
+      // The slot doesn't have a type. Must not be valid here.
       return ERR(INVALID_SLOT);
     }
-    return OK;
   }
 
+  constexpr VerifierPrimitiveType SquashType(SlotType t) {
+    if (std::holds_alternative<art::Primitive::Type>(t)) {
+      switch (std::get<art::Primitive::Type>(t)) {
+        // 32-bit primitives
+        case art::Primitive::kPrimByte:
+        case art::Primitive::kPrimChar:
+        case art::Primitive::kPrimInt:
+        case art::Primitive::kPrimShort:
+        case art::Primitive::kPrimBoolean:
+        case art::Primitive::kPrimFloat:
+          return VerifierPrimitiveType::k32BitValue;
+        // 64-bit primitives
+        case art::Primitive::kPrimLong:
+        case art::Primitive::kPrimDouble:
+          return VerifierPrimitiveType::k64BitValue;
+        case art::Primitive::kPrimNot:
+          return VerifierPrimitiveType::kReferenceValue;
+        case art::Primitive::kPrimVoid:
+          LOG(FATAL) << "Got kPrimVoid";
+          UNREACHABLE();
+      }
+    } else {
+      return std::get<VerifierPrimitiveType>(t);
+    }
+  }
+
+  jvmtiEnv* jvmti_;
   jvmtiError result_;
   jint depth_;
   jint slot_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CommonLocalVariableClosure);
 };
 
+std::ostream& operator<<(std::ostream& os,
+                         CommonLocalVariableClosure::VerifierPrimitiveType state) {
+  switch (state) {
+    case CommonLocalVariableClosure::VerifierPrimitiveType::k32BitValue:
+      return os << "32BitValue";
+    case CommonLocalVariableClosure::VerifierPrimitiveType::k64BitValue:
+      return os << "64BitValue";
+    case CommonLocalVariableClosure::VerifierPrimitiveType::kReferenceValue:
+      return os << "ReferenceValue";
+    case CommonLocalVariableClosure::VerifierPrimitiveType::kZeroValue:
+      return os << "ZeroValue";
+  }
+}
+
+std::ostream& operator<<(std::ostream& os, CommonLocalVariableClosure::SlotType state) {
+  if (std::holds_alternative<art::Primitive::Type>(state)) {
+    return os << "Primitive::Type[" << std::get<art::Primitive::Type>(state) << "]";
+  } else {
+    return os << "VerifierPrimitiveType["
+              << std::get<CommonLocalVariableClosure::VerifierPrimitiveType>(state) << "]";
+  }
+}
+
+jvmtiError CommonLocalVariableClosure::GetSlotType(art::ArtMethod* method,
+                                                   uint32_t dex_pc,
+                                                   /*out*/ std::string* descriptor,
+                                                   /*out*/ SlotType* type) {
+  const art::DexFile* dex_file = method->GetDexFile();
+  if (dex_file == nullptr) {
+    return ERR(OPAQUE_FRAME);
+  }
+  art::CodeItemDebugInfoAccessor accessor(method->DexInstructionDebugInfo());
+  if (!accessor.HasCodeItem()) {
+    return ERR(OPAQUE_FRAME);
+  }
+  bool found = false;
+  *type = art::Primitive::kPrimVoid;
+  descriptor->clear();
+  auto visitor = [&](const art::DexFile::LocalInfo& entry) {
+    if (!found && entry.start_address_ <= dex_pc && entry.end_address_ > dex_pc &&
+        entry.reg_ == slot_) {
+      found = true;
+      *type = art::Primitive::GetType(entry.descriptor_[0]);
+      *descriptor = entry.descriptor_;
+    }
+  };
+  if (!accessor.DecodeDebugLocalInfo(method->IsStatic(), method->GetDexMethodIndex(), visitor) ||
+      !found) {
+    // Something went wrong with decoding the debug information. It might as well not be there.
+    // Try to find the type with the verifier.
+    // TODO This is very slow.
+    return InferSlotTypeFromVerifier(method, dex_pc, descriptor, type);
+  } else if (art::kIsDebugBuild) {
+    std::string type_unused;
+    SlotType verifier_type{ art::Primitive::kPrimVoid };
+    DCHECK_EQ(InferSlotTypeFromVerifier(method, dex_pc, &type_unused, &verifier_type), OK)
+        << method->PrettyMethod() << " failed to verify!";
+    if (*type == SlotType{ art::Primitive::kPrimNot }) {
+      // We cannot distinguish between a constant 0 and a null reference so we return that it is a
+      // 32bit value (Due to the way references are read by the interpreter this is safe even if
+      // it's modified, the value will remain null). This is not ideal since it prevents modifying
+      // locals in some circumstances but generally is not a big deal (since one can just modify it
+      // later once it's been determined to be a reference by a later instruction).
+      DCHECK(verifier_type == SlotType { VerifierPrimitiveType::kZeroValue } ||
+             verifier_type == SlotType { VerifierPrimitiveType::kReferenceValue })
+          << "Verifier disagrees on type of slot! debug: " << *type
+          << " verifier: " << verifier_type;
+    } else if (verifier_type == SlotType { VerifierPrimitiveType::kZeroValue }) {
+      DCHECK(VerifierPrimitiveType::k32BitValue == SquashType(*type) ||
+             VerifierPrimitiveType::kReferenceValue == SquashType(*type))
+          << "Verifier disagrees on type of slot! debug: " << *type
+          << " verifier: " << verifier_type;
+    } else {
+      DCHECK_EQ(SquashType(verifier_type), SquashType(*type))
+          << "Verifier disagrees on type of slot! debug: " << *type
+          << " verifier: " << verifier_type;
+    }
+  }
+  return OK;
+}
+
 class GetLocalVariableClosure : public CommonLocalVariableClosure {
  public:
-  GetLocalVariableClosure(jint depth,
+  GetLocalVariableClosure(jvmtiEnv* jvmti,
+                          jint depth,
                           jint slot,
                           art::Primitive::Type type,
                           jvalue* val)
-      : CommonLocalVariableClosure(depth, slot),
+      : CommonLocalVariableClosure(jvmti, depth, slot),
         type_(type),
         val_(val),
         obj_val_(nullptr) {}
@@ -656,22 +817,61 @@
   }
 
  protected:
-  jvmtiError GetTypeError(art::ArtMethod* method ATTRIBUTE_UNUSED,
-                          art::Primitive::Type slot_type,
-                          const std::string& descriptor ATTRIBUTE_UNUSED)
-      override REQUIRES_SHARED(art::Locks::mutator_lock_) {
-    switch (slot_type) {
-      case art::Primitive::kPrimByte:
-      case art::Primitive::kPrimChar:
-      case art::Primitive::kPrimInt:
-      case art::Primitive::kPrimShort:
-      case art::Primitive::kPrimBoolean:
-        return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
-      case art::Primitive::kPrimLong:
+  jvmtiError
+  GetTypeError(art::ArtMethod* method, SlotType slot_type, const std::string& descriptor) override
+      REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    jvmtiError res = GetTypeErrorInner(method, slot_type, descriptor);
+    if (res == ERR(TYPE_MISMATCH)) {
+      JVMTI_LOG(INFO, jvmti_) << "Unable to Get local variable in slot " << slot_ << ". Expected"
+                              << " slot to be of type compatible with " << SlotType { type_ }
+                              << " but slot is " << slot_type;
+    } else if (res != OK) {
+      JVMTI_LOG(INFO, jvmti_) << "Unable to get local variable in slot " << slot_ << ".";
+    }
+    return res;
+  }
+
+  jvmtiError GetTypeErrorInner(art::ArtMethod* method ATTRIBUTE_UNUSED,
+                               SlotType slot_type,
+                               const std::string& descriptor ATTRIBUTE_UNUSED)
+      REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    switch (type_) {
       case art::Primitive::kPrimFloat:
-      case art::Primitive::kPrimDouble:
+      case art::Primitive::kPrimInt: {
+        if (std::holds_alternative<VerifierPrimitiveType>(slot_type)) {
+          return (slot_type == SlotType { VerifierPrimitiveType::k32BitValue } ||
+                  slot_type == SlotType { VerifierPrimitiveType::kZeroValue })
+                     ? OK
+                     : ERR(TYPE_MISMATCH);
+        } else if (type_ == art::Primitive::kPrimFloat ||
+                   slot_type == SlotType { art::Primitive::kPrimFloat }) {
+          // Check that we are actually a float.
+          return (SlotType { type_ } == slot_type) ? OK : ERR(TYPE_MISMATCH);
+        } else {
+          // Some smaller int type.
+          return SquashType(slot_type) == SquashType(SlotType { type_ }) ? OK : ERR(TYPE_MISMATCH);
+        }
+      }
+      case art::Primitive::kPrimLong:
+      case art::Primitive::kPrimDouble: {
+        // todo
+        if (std::holds_alternative<VerifierPrimitiveType>(slot_type)) {
+          return (slot_type == SlotType { VerifierPrimitiveType::k64BitValue })
+                     ? OK
+                     : ERR(TYPE_MISMATCH);
+        } else {
+          return slot_type == SlotType { type_ } ? OK : ERR(TYPE_MISMATCH);
+        }
+      }
       case art::Primitive::kPrimNot:
-        return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
+        return (SquashType(slot_type) == VerifierPrimitiveType::kReferenceValue ||
+                SquashType(slot_type) == VerifierPrimitiveType::kZeroValue)
+                   ? OK
+                   : ERR(TYPE_MISMATCH);
+      case art::Primitive::kPrimShort:
+      case art::Primitive::kPrimChar:
+      case art::Primitive::kPrimByte:
+      case art::Primitive::kPrimBoolean:
       case art::Primitive::kPrimVoid:
         LOG(FATAL) << "Unexpected primitive type " << slot_type;
         UNREACHABLE();
@@ -735,7 +935,7 @@
   jobject obj_val_;
 };
 
-jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
+jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env,
                                                jthread thread,
                                                jint depth,
                                                jint slot,
@@ -753,7 +953,7 @@
     art::Locks::thread_list_lock_->ExclusiveUnlock(self);
     return err;
   }
-  GetLocalVariableClosure c(depth, slot, type, val);
+  GetLocalVariableClosure c(env, depth, slot, type, val);
   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
   if (!target->RequestSynchronousCheckpoint(&c)) {
     return ERR(THREAD_NOT_ALIVE);
@@ -764,49 +964,100 @@
 
 class SetLocalVariableClosure : public CommonLocalVariableClosure {
  public:
-  SetLocalVariableClosure(art::Thread* caller,
+  SetLocalVariableClosure(jvmtiEnv* jvmti,
+                          art::Thread* caller,
                           jint depth,
                           jint slot,
                           art::Primitive::Type type,
                           jvalue val)
-      : CommonLocalVariableClosure(depth, slot), caller_(caller), type_(type), val_(val) {}
+      : CommonLocalVariableClosure(jvmti, depth, slot), caller_(caller), type_(type), val_(val) {}
 
  protected:
-  jvmtiError GetTypeError(art::ArtMethod* method,
-                          art::Primitive::Type slot_type,
-                          const std::string& descriptor)
-      override REQUIRES_SHARED(art::Locks::mutator_lock_) {
-    switch (slot_type) {
-      case art::Primitive::kPrimNot: {
-        if (type_ != art::Primitive::kPrimNot) {
+  jvmtiError
+  GetTypeError(art::ArtMethod* method, SlotType slot_type, const std::string& descriptor) override
+      REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    jvmtiError res = GetTypeErrorInner(method, slot_type, descriptor);
+    if (res != OK) {
+      if (res == ERR(TYPE_MISMATCH)) {
+        std::ostringstream desc_exp;
+        std::ostringstream desc_set;
+        if (type_ == art::Primitive::kPrimNot) {
+          desc_exp << " (type: " << descriptor << ")";
+          art::ObjPtr<art::mirror::Object> new_val(art::Thread::Current()->DecodeJObject(val_.l));
+          desc_set << " (type: "
+                  << (new_val.IsNull() ? "NULL" : new_val->GetClass()->PrettyDescriptor()) << ")";
+        }
+        JVMTI_LOG(INFO, jvmti_) << "Unable to Set local variable in slot " << slot_ << ". Expected"
+                                << " slot to be of type compatible with " << SlotType{ type_ }
+                                << desc_set.str() << " but slot is " << slot_type << desc_exp.str();
+      } else {
+        JVMTI_LOG(INFO, jvmti_) << "Unable to set local variable in slot " << slot_ << ". "
+                                << err_.str();
+      }
+    }
+    return res;
+  }
+
+  jvmtiError
+  GetTypeErrorInner(art::ArtMethod* method, SlotType slot_type, const std::string& descriptor)
+      REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    switch (SquashType(SlotType{ type_ })) {
+      case VerifierPrimitiveType::k32BitValue: {
+        if (slot_type == SlotType{ VerifierPrimitiveType::kZeroValue }) {
+          if (val_.i == 0) {
+            return OK;
+          } else {
+            err_ << "Cannot determine if slot " << slot_ << " is a null reference or 32bit "
+                 << "constant. Cannot allow writing to slot.";
+            return ERR(INTERNAL);
+          }
+        } else if (SquashType(slot_type) != VerifierPrimitiveType::k32BitValue) {
+          return ERR(TYPE_MISMATCH);
+        } else if (slot_type == SlotType { VerifierPrimitiveType::k32BitValue } ||
+                   slot_type == SlotType { type_ }) {
+          return OK;
+        } else if (type_ == art::Primitive::kPrimFloat ||
+                   slot_type == SlotType { art::Primitive::kPrimFloat }) {
+          // we should have hit the get == type_ above
+          return ERR(TYPE_MISMATCH);
+        } else {
+          // Some smaller type then int.
+          return OK;
+        }
+      }
+      case VerifierPrimitiveType::k64BitValue: {
+        if (slot_type == SlotType { VerifierPrimitiveType::k64BitValue } ||
+            slot_type == SlotType { type_ }) {
+          return OK;
+        } else {
+          return ERR(TYPE_MISMATCH);
+        }
+      }
+      case VerifierPrimitiveType::kReferenceValue: {
+        if (SquashType(slot_type) != VerifierPrimitiveType::kReferenceValue &&
+            SquashType(slot_type) != VerifierPrimitiveType::kZeroValue) {
           return ERR(TYPE_MISMATCH);
         } else if (val_.l == nullptr) {
           return OK;
+        } else if (slot_type == SlotType { VerifierPrimitiveType::kZeroValue }) {
+          err_ << "Cannot determine if slot " << slot_ << " is a null "
+               << "reference or 32bit constant. Cannot allow writing to slot.";
+          return ERR(INTERNAL);
         } else {
           art::ClassLinker* cl = art::Runtime::Current()->GetClassLinker();
-          art::ObjPtr<art::mirror::Class> set_class =
-              caller_->DecodeJObject(val_.l)->GetClass();
+          art::ObjPtr<art::mirror::Class> set_class = caller_->DecodeJObject(val_.l)->GetClass();
           art::ObjPtr<art::mirror::ClassLoader> loader =
               method->GetDeclaringClass()->GetClassLoader();
           art::ObjPtr<art::mirror::Class> slot_class =
               cl->LookupClass(caller_, descriptor.c_str(), loader);
-          DCHECK(!slot_class.IsNull());
+          DCHECK(!slot_class.IsNull()) << descriptor << " slot: " << slot_type;
           return slot_class->IsAssignableFrom(set_class) ? OK : ERR(TYPE_MISMATCH);
         }
       }
-      case art::Primitive::kPrimByte:
-      case art::Primitive::kPrimChar:
-      case art::Primitive::kPrimInt:
-      case art::Primitive::kPrimShort:
-      case art::Primitive::kPrimBoolean:
-        return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
-      case art::Primitive::kPrimLong:
-      case art::Primitive::kPrimFloat:
-      case art::Primitive::kPrimDouble:
-        return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
-      case art::Primitive::kPrimVoid:
-        LOG(FATAL) << "Unexpected primitive type " << slot_type;
+      case VerifierPrimitiveType::kZeroValue: {
+        LOG(FATAL) << "Illegal result from SquashType of art::Primitive::Type " << type_;
         UNREACHABLE();
+      }
     }
   }
 
@@ -857,9 +1108,10 @@
   art::Thread* caller_;
   art::Primitive::Type type_;
   jvalue val_;
+  std::ostringstream err_;
 };
 
-jvmtiError MethodUtil::SetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
+jvmtiError MethodUtil::SetLocalVariableGeneric(jvmtiEnv* env,
                                                jthread thread,
                                                jint depth,
                                                jint slot,
@@ -880,7 +1132,7 @@
     art::Locks::thread_list_lock_->ExclusiveUnlock(self);
     return err;
   }
-  SetLocalVariableClosure c(self, depth, slot, type, val);
+  SetLocalVariableClosure c(env, self, depth, slot, type, val);
   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
   if (!target->RequestSynchronousCheckpoint(&c)) {
     return ERR(THREAD_NOT_ALIVE);
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 73ae8e8..ff44828 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -63,6 +63,7 @@
 #include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "vdex_file.h"
+#include "verifier/method_verifier.h"
 #include "verifier_compiler_binding.h"
 #include "verifier_deps.h"
 
@@ -152,6 +153,7 @@
                  bool need_precise_constants,
                  bool verify_to_dump,
                  bool allow_thread_suspension,
+                 bool fill_register_lines_,
                  uint32_t api_level)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -630,6 +632,9 @@
   // Note: this flag is only valid once Verify() has started.
   bool is_constructor_;
 
+  // Whether to attempt to fill all register lines for (ex) debugger use.
+  bool fill_register_lines_;
+
   // API level, for dependent checks. Note: we do not use '0' for unset here, to simplify checks.
   // Instead, unset level should correspond to max().
   const uint32_t api_level_;
@@ -695,6 +700,7 @@
                                                bool need_precise_constants,
                                                bool verify_to_dump,
                                                bool allow_thread_suspension,
+                                               bool fill_register_lines,
                                                uint32_t api_level)
     : art::verifier::MethodVerifier(self,
                                     dex_file,
@@ -716,6 +722,7 @@
       verify_to_dump_(verify_to_dump),
       allow_thread_suspension_(allow_thread_suspension),
       is_constructor_(false),
+      fill_register_lines_(fill_register_lines),
       api_level_(api_level == 0 ? std::numeric_limits<uint32_t>::max() : api_level) {
 }
 
@@ -1578,7 +1585,7 @@
   const uint16_t registers_size = code_item_accessor_.RegistersSize();
 
   /* Create and initialize table holding register status */
-  reg_table_.Init(kTrackCompilerInterestPoints,
+  reg_table_.Init(fill_register_lines_ ? kTrackRegsAll : kTrackCompilerInterestPoints,
                   insn_flags_.get(),
                   code_item_accessor_.InsnsSizeInCodeUnits(),
                   registers_size,
@@ -5200,6 +5207,7 @@
                                                 need_precise_constants,
                                                 /* verify to dump */ false,
                                                 /* allow_thread_suspension= */ true,
+                                                /* fill_register_lines= */ false,
                                                 api_level);
   if (verifier.Verify()) {
     // Verification completed, however failures may be pending that didn't cause the verification
@@ -5322,6 +5330,41 @@
   return result;
 }
 
+MethodVerifier* MethodVerifier::CalculateVerificationInfo(
+      Thread* self,
+      ArtMethod* method,
+      Handle<mirror::DexCache> dex_cache,
+      Handle<mirror::ClassLoader> class_loader) {
+  std::unique_ptr<impl::MethodVerifier<false>> verifier(
+      new impl::MethodVerifier<false>(self,
+                                      method->GetDexFile(),
+                                      dex_cache,
+                                      class_loader,
+                                      *method->GetDeclaringClass()->GetClassDef(),
+                                      method->GetCodeItem(),
+                                      method->GetDexMethodIndex(),
+                                      method,
+                                      method->GetAccessFlags(),
+                                      /* can_load_classes= */ false,
+                                      /* allow_soft_failures= */ true,
+                                      /* need_precise_constants= */ true,
+                                      /* verify_to_dump= */ false,
+                                      /* allow_thread_suspension= */ false,
+                                      /* fill_register_lines= */ true,
+                                      /* api_level = */ 0));
+  verifier->Verify();
+  if (VLOG_IS_ON(verifier)) {
+    verifier->DumpFailures(VLOG_STREAM(verifier));
+    VLOG(verifier) << verifier->info_messages_.str();
+    verifier->Dump(VLOG_STREAM(verifier));
+  }
+  if (verifier->have_pending_hard_failure_) {
+    return nullptr;
+  } else {
+    return verifier.release();
+  }
+}
+
 MethodVerifier* MethodVerifier::VerifyMethodAndDump(Thread* self,
                                                     VariableIndentationOutputStream* vios,
                                                     uint32_t dex_method_idx,
@@ -5348,6 +5391,7 @@
       /* need_precise_constants= */ true,
       /* verify_to_dump= */ true,
       /* allow_thread_suspension= */ true,
+      /* fill_register_lines= */ false,
       api_level);
   verifier->Verify();
   verifier->DumpFailures(vios->Stream());
@@ -5385,6 +5429,7 @@
                                        /* need_precise_constants= */ false,
                                        /* verify_to_dump= */ false,
                                        /* allow_thread_suspension= */ false,
+                                       /* fill_register_lines= */ false,
                                        api_level);
   verifier.interesting_dex_pc_ = dex_pc;
   verifier.monitor_enter_dex_pcs_ = monitor_enter_dex_pcs;
@@ -5420,6 +5465,7 @@
                                          need_precise_constants,
                                          verify_to_dump,
                                          allow_thread_suspension,
+                                         /* fill_register_lines= */ false,
                                          api_level);
 }
 
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 0af09c3..bd320ce 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -118,6 +118,16 @@
                                              uint32_t api_level)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Calculates the verification information for every instruction of the given method. The given
+  // dex-cache and class-loader will be used for lookups. No classes will be loaded. If verification
+  // fails hard nullptr will be returned. This should only be used if one needs to examine what the
+  // verifier believes about the registers of a given method.
+  static MethodVerifier* CalculateVerificationInfo(Thread* self,
+                                                   ArtMethod* method,
+                                                   Handle<mirror::DexCache> dex_cache,
+                                                   Handle<mirror::ClassLoader> class_loader)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   const DexFile& GetDexFile() const {
     DCHECK(dex_file_ != nullptr);
     return *dex_file_;
diff --git a/test/1912-get-set-local-primitive/expected.txt b/test/1912-get-set-local-primitive/expected.txt
index f2c5ce8..8a03566 100644
--- a/test/1912-get-set-local-primitive/expected.txt
+++ b/test/1912-get-set-local-primitive/expected.txt
@@ -10,6 +10,9 @@
 Running public static void art.Test1912.IntMethod(java.lang.Runnable) with "GetDouble" on remote thread.
 "GetDouble" on public static void art.Test1912.IntMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '42' (class: class java.lang.Integer)
+Running public static void art.Test1912.IntMethod(java.lang.Runnable) with "GetObject" on remote thread.
+"GetObject" on public static void art.Test1912.IntMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
 Running public static void art.Test1912.IntMethod(java.lang.Runnable) with "SetInt" on remote thread.
 "SetInt" on public static void art.Test1912.IntMethod(java.lang.Runnable) set value: 2147483647
 	Value is '2147483647' (class: class java.lang.Integer)
@@ -22,6 +25,12 @@
 Running public static void art.Test1912.IntMethod(java.lang.Runnable) with "SetDouble" on remote thread.
 "SetDouble" on public static void art.Test1912.IntMethod(java.lang.Runnable) failed to set value 12.4 due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '42' (class: class java.lang.Integer)
+Running public static void art.Test1912.IntMethod(java.lang.Runnable) with "SetObject" on remote thread.
+"SetObject" on public static void art.Test1912.IntMethod(java.lang.Runnable) failed to set value NEW_VALUE_FOR_SET due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art.Test1912.IntMethod(java.lang.Runnable) with "SetNullObject" on remote thread.
+"SetNullObject" on public static void art.Test1912.IntMethod(java.lang.Runnable) failed to set value null due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
 Running public static void art.Test1912.LongMethod(java.lang.Runnable) with "GetInt" on remote thread.
 "GetInt" on public static void art.Test1912.LongMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '9001' (class: class java.lang.Long)
@@ -34,6 +43,9 @@
 Running public static void art.Test1912.LongMethod(java.lang.Runnable) with "GetDouble" on remote thread.
 "GetDouble" on public static void art.Test1912.LongMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '9001' (class: class java.lang.Long)
+Running public static void art.Test1912.LongMethod(java.lang.Runnable) with "GetObject" on remote thread.
+"GetObject" on public static void art.Test1912.LongMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '9001' (class: class java.lang.Long)
 Running public static void art.Test1912.LongMethod(java.lang.Runnable) with "SetInt" on remote thread.
 "SetInt" on public static void art.Test1912.LongMethod(java.lang.Runnable) failed to set value 2147483647 due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '9001' (class: class java.lang.Long)
@@ -46,6 +58,12 @@
 Running public static void art.Test1912.LongMethod(java.lang.Runnable) with "SetDouble" on remote thread.
 "SetDouble" on public static void art.Test1912.LongMethod(java.lang.Runnable) failed to set value 12.4 due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '9001' (class: class java.lang.Long)
+Running public static void art.Test1912.LongMethod(java.lang.Runnable) with "SetObject" on remote thread.
+"SetObject" on public static void art.Test1912.LongMethod(java.lang.Runnable) failed to set value NEW_VALUE_FOR_SET due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '9001' (class: class java.lang.Long)
+Running public static void art.Test1912.LongMethod(java.lang.Runnable) with "SetNullObject" on remote thread.
+"SetNullObject" on public static void art.Test1912.LongMethod(java.lang.Runnable) failed to set value null due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '9001' (class: class java.lang.Long)
 Running public static void art.Test1912.FloatMethod(java.lang.Runnable) with "GetInt" on remote thread.
 "GetInt" on public static void art.Test1912.FloatMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '1.618' (class: class java.lang.Float)
@@ -58,6 +76,9 @@
 Running public static void art.Test1912.FloatMethod(java.lang.Runnable) with "GetDouble" on remote thread.
 "GetDouble" on public static void art.Test1912.FloatMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '1.618' (class: class java.lang.Float)
+Running public static void art.Test1912.FloatMethod(java.lang.Runnable) with "GetObject" on remote thread.
+"GetObject" on public static void art.Test1912.FloatMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '1.618' (class: class java.lang.Float)
 Running public static void art.Test1912.FloatMethod(java.lang.Runnable) with "SetInt" on remote thread.
 "SetInt" on public static void art.Test1912.FloatMethod(java.lang.Runnable) failed to set value 2147483647 due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '1.618' (class: class java.lang.Float)
@@ -70,6 +91,12 @@
 Running public static void art.Test1912.FloatMethod(java.lang.Runnable) with "SetDouble" on remote thread.
 "SetDouble" on public static void art.Test1912.FloatMethod(java.lang.Runnable) failed to set value 12.4 due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '1.618' (class: class java.lang.Float)
+Running public static void art.Test1912.FloatMethod(java.lang.Runnable) with "SetObject" on remote thread.
+"SetObject" on public static void art.Test1912.FloatMethod(java.lang.Runnable) failed to set value NEW_VALUE_FOR_SET due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '1.618' (class: class java.lang.Float)
+Running public static void art.Test1912.FloatMethod(java.lang.Runnable) with "SetNullObject" on remote thread.
+"SetNullObject" on public static void art.Test1912.FloatMethod(java.lang.Runnable) failed to set value null due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '1.618' (class: class java.lang.Float)
 Running public static void art.Test1912.DoubleMethod(java.lang.Runnable) with "GetInt" on remote thread.
 "GetInt" on public static void art.Test1912.DoubleMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '3.1415' (class: class java.lang.Double)
@@ -82,6 +109,9 @@
 Running public static void art.Test1912.DoubleMethod(java.lang.Runnable) with "GetDouble" on remote thread.
 "GetDouble" on public static void art.Test1912.DoubleMethod(java.lang.Runnable) got value: 3.1415
 	Value is '3.1415' (class: class java.lang.Double)
+Running public static void art.Test1912.DoubleMethod(java.lang.Runnable) with "GetObject" on remote thread.
+"GetObject" on public static void art.Test1912.DoubleMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '3.1415' (class: class java.lang.Double)
 Running public static void art.Test1912.DoubleMethod(java.lang.Runnable) with "SetInt" on remote thread.
 "SetInt" on public static void art.Test1912.DoubleMethod(java.lang.Runnable) failed to set value 2147483647 due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '3.1415' (class: class java.lang.Double)
@@ -94,6 +124,78 @@
 Running public static void art.Test1912.DoubleMethod(java.lang.Runnable) with "SetDouble" on remote thread.
 "SetDouble" on public static void art.Test1912.DoubleMethod(java.lang.Runnable) set value: 12.4
 	Value is '12.4' (class: class java.lang.Double)
+Running public static void art.Test1912.DoubleMethod(java.lang.Runnable) with "SetObject" on remote thread.
+"SetObject" on public static void art.Test1912.DoubleMethod(java.lang.Runnable) failed to set value NEW_VALUE_FOR_SET due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '3.1415' (class: class java.lang.Double)
+Running public static void art.Test1912.DoubleMethod(java.lang.Runnable) with "SetNullObject" on remote thread.
+"SetNullObject" on public static void art.Test1912.DoubleMethod(java.lang.Runnable) failed to set value null due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '3.1415' (class: class java.lang.Double)
+Running public static void art.Test1912.ObjectMethod(java.lang.Runnable) with "GetInt" on remote thread.
+"GetInt" on public static void art.Test1912.ObjectMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET OBJECT' (class: class java.lang.String)
+Running public static void art.Test1912.ObjectMethod(java.lang.Runnable) with "GetLong" on remote thread.
+"GetLong" on public static void art.Test1912.ObjectMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET OBJECT' (class: class java.lang.String)
+Running public static void art.Test1912.ObjectMethod(java.lang.Runnable) with "GetFloat" on remote thread.
+"GetFloat" on public static void art.Test1912.ObjectMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET OBJECT' (class: class java.lang.String)
+Running public static void art.Test1912.ObjectMethod(java.lang.Runnable) with "GetDouble" on remote thread.
+"GetDouble" on public static void art.Test1912.ObjectMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET OBJECT' (class: class java.lang.String)
+Running public static void art.Test1912.ObjectMethod(java.lang.Runnable) with "GetObject" on remote thread.
+"GetObject" on public static void art.Test1912.ObjectMethod(java.lang.Runnable) got value: TARGET OBJECT
+	Value is 'TARGET OBJECT' (class: class java.lang.String)
+Running public static void art.Test1912.ObjectMethod(java.lang.Runnable) with "SetInt" on remote thread.
+"SetInt" on public static void art.Test1912.ObjectMethod(java.lang.Runnable) failed to set value 2147483647 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET OBJECT' (class: class java.lang.String)
+Running public static void art.Test1912.ObjectMethod(java.lang.Runnable) with "SetLong" on remote thread.
+"SetLong" on public static void art.Test1912.ObjectMethod(java.lang.Runnable) failed to set value 9223372036854775807 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET OBJECT' (class: class java.lang.String)
+Running public static void art.Test1912.ObjectMethod(java.lang.Runnable) with "SetFloat" on remote thread.
+"SetFloat" on public static void art.Test1912.ObjectMethod(java.lang.Runnable) failed to set value 9.2 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET OBJECT' (class: class java.lang.String)
+Running public static void art.Test1912.ObjectMethod(java.lang.Runnable) with "SetDouble" on remote thread.
+"SetDouble" on public static void art.Test1912.ObjectMethod(java.lang.Runnable) failed to set value 12.4 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET OBJECT' (class: class java.lang.String)
+Running public static void art.Test1912.ObjectMethod(java.lang.Runnable) with "SetObject" on remote thread.
+"SetObject" on public static void art.Test1912.ObjectMethod(java.lang.Runnable) set value: NEW_VALUE_FOR_SET
+	Value is 'NEW_VALUE_FOR_SET' (class: class java.lang.String)
+Running public static void art.Test1912.ObjectMethod(java.lang.Runnable) with "SetNullObject" on remote thread.
+"SetNullObject" on public static void art.Test1912.ObjectMethod(java.lang.Runnable) set value: null
+	Value is 'null' (class: null)
+Running public static void art.Test1912.NullObjectMethod(java.lang.Runnable) with "GetInt" on remote thread.
+"GetInt" on public static void art.Test1912.NullObjectMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: null)
+Running public static void art.Test1912.NullObjectMethod(java.lang.Runnable) with "GetLong" on remote thread.
+"GetLong" on public static void art.Test1912.NullObjectMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: null)
+Running public static void art.Test1912.NullObjectMethod(java.lang.Runnable) with "GetFloat" on remote thread.
+"GetFloat" on public static void art.Test1912.NullObjectMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: null)
+Running public static void art.Test1912.NullObjectMethod(java.lang.Runnable) with "GetDouble" on remote thread.
+"GetDouble" on public static void art.Test1912.NullObjectMethod(java.lang.Runnable) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: null)
+Running public static void art.Test1912.NullObjectMethod(java.lang.Runnable) with "GetObject" on remote thread.
+"GetObject" on public static void art.Test1912.NullObjectMethod(java.lang.Runnable) got value: null
+	Value is 'null' (class: null)
+Running public static void art.Test1912.NullObjectMethod(java.lang.Runnable) with "SetInt" on remote thread.
+"SetInt" on public static void art.Test1912.NullObjectMethod(java.lang.Runnable) failed to set value 2147483647 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: null)
+Running public static void art.Test1912.NullObjectMethod(java.lang.Runnable) with "SetLong" on remote thread.
+"SetLong" on public static void art.Test1912.NullObjectMethod(java.lang.Runnable) failed to set value 9223372036854775807 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: null)
+Running public static void art.Test1912.NullObjectMethod(java.lang.Runnable) with "SetFloat" on remote thread.
+"SetFloat" on public static void art.Test1912.NullObjectMethod(java.lang.Runnable) failed to set value 9.2 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: null)
+Running public static void art.Test1912.NullObjectMethod(java.lang.Runnable) with "SetDouble" on remote thread.
+"SetDouble" on public static void art.Test1912.NullObjectMethod(java.lang.Runnable) failed to set value 12.4 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: null)
+Running public static void art.Test1912.NullObjectMethod(java.lang.Runnable) with "SetObject" on remote thread.
+"SetObject" on public static void art.Test1912.NullObjectMethod(java.lang.Runnable) set value: NEW_VALUE_FOR_SET
+	Value is 'NEW_VALUE_FOR_SET' (class: class java.lang.String)
+Running public static void art.Test1912.NullObjectMethod(java.lang.Runnable) with "SetNullObject" on remote thread.
+"SetNullObject" on public static void art.Test1912.NullObjectMethod(java.lang.Runnable) set value: null
+	Value is 'null' (class: null)
 Running public static void art.Test1912.BooleanMethod(java.lang.Runnable) with "SetIntBoolSize" on remote thread.
 "SetIntBoolSize" on public static void art.Test1912.BooleanMethod(java.lang.Runnable) set value: 1
 	Value is 'true' (class: class java.lang.Boolean)
diff --git a/test/1912-get-set-local-primitive/src/art/Test1912.java b/test/1912-get-set-local-primitive/src/art/Test1912.java
index 24149f4..f0a6065 100644
--- a/test/1912-get-set-local-primitive/src/art/Test1912.java
+++ b/test/1912-get-set-local-primitive/src/art/Test1912.java
@@ -20,29 +20,39 @@
 import java.lang.reflect.Executable;
 import java.lang.reflect.Method;
 import java.nio.ByteBuffer;
-import java.util.concurrent.Semaphore;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Semaphore;
+import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
-import java.util.function.Consumer;
 
 // TODO Rename test to set-get-local-prim
 
 public class Test1912 {
   public static final String TARGET_VAR = "TARGET";
 
-
   public static void reportValue(Object val) {
     if (val instanceof Character) {
       val = "<Char: " + Character.getNumericValue(((Character)val).charValue()) + ">";
     }
-    System.out.println("\tValue is '" + val + "' (class: " + val.getClass() + ")");
+    System.out.println("\tValue is '" + val +
+                       "' (class: " + (val != null ? val.getClass().toString() : "null") + ")");
   }
 
+  public static void NullObjectMethod(Runnable safepoint) {
+    Object TARGET = null;
+    safepoint.run();
+    reportValue(TARGET);
+  }
+  public static void ObjectMethod(Runnable safepoint) {
+    Object TARGET = "TARGET OBJECT";
+    safepoint.run();
+    reportValue(TARGET);
+  }
   public static void BooleanMethod(Runnable safepoint) {
     boolean TARGET = false;
     safepoint.run();
@@ -85,31 +95,27 @@
   }
 
   public static interface SafepointFunction {
-    public void invoke(
-        Thread thread,
-        Method target,
-        Locals.VariableDescription TARGET_desc,
-        int depth) throws Exception;
+    public void
+    invoke(Thread thread, Method target, Locals.VariableDescription TARGET_desc, int depth)
+        throws Exception;
   }
 
   public static interface SetterFunction {
     public void SetVar(Thread t, int depth, int slot, Object v);
   }
 
-  public static interface GetterFunction {
-    public Object GetVar(Thread t, int depth, int slot);
-  }
+  public static interface GetterFunction { public Object GetVar(Thread t, int depth, int slot); }
 
-  public static SafepointFunction NamedSet(
-      final String type, final SetterFunction get, final Object v) {
+  public static SafepointFunction
+  NamedSet(final String type, final SetterFunction get, final Object v) {
     return new SafepointFunction() {
       public void invoke(Thread t, Method method, Locals.VariableDescription desc, int depth) {
         try {
           get.SetVar(t, depth, desc.slot, v);
           System.out.println(this + " on " + method + " set value: " + v);
         } catch (Exception e) {
-          System.out.println(
-              this + " on " + method + " failed to set value " + v + " due to " + e.getMessage());
+          System.out.println(this + " on " + method + " failed to set value " + v + " due to " +
+                             e.getMessage());
         }
       }
       public String toString() {
@@ -171,15 +177,13 @@
     public void exec(final SafepointFunction safepoint) throws Exception {
       System.out.println("Running " + target + " with " + safepoint + " on remote thread.");
       final ThreadPauser pause = new ThreadPauser();
-      Thread remote = new Thread(
-          () -> {
-            try {
-              target.invoke(null, pause);
-            } catch (Exception e) {
-              throw new Error("Error invoking remote thread " + Thread.currentThread(), e);
-            }
-          },
-          "remote thread for " + target + " with " + safepoint);
+      Thread remote = new Thread(() -> {
+        try {
+          target.invoke(null, pause);
+        } catch (Exception e) {
+          throw new Error("Error invoking remote thread " + Thread.currentThread(), e);
+        }
+      }, "remote thread for " + target + " with " + safepoint);
       remote.start();
       pause.waitForOtherThreadToPause();
       try {
@@ -196,14 +200,12 @@
 
     private Locals.VariableDescription findTargetVar(long loc) {
       for (Locals.VariableDescription var : Locals.GetLocalVariableTable(target)) {
-        if (var.start_location <= loc &&
-            var.length + var.start_location > loc &&
+        if (var.start_location <= loc && var.length + var.start_location > loc &&
             var.name.equals(TARGET_VAR)) {
           return var;
         }
       }
-      throw new Error(
-          "Unable to find variable " + TARGET_VAR + " in " + target + " at loc " + loc);
+      throw new Error("Unable to find variable " + TARGET_VAR + " in " + target + " at loc " + loc);
     }
 
     private StackTrace.StackFrameData findStackFrame(Thread thr) {
@@ -222,10 +224,9 @@
   public static void run() throws Exception {
     Locals.EnableLocalVariableAccess();
     final TestCase[] MAIN_TEST_CASES = new TestCase[] {
-      new TestCase(getMethod("IntMethod")),
-      new TestCase(getMethod("LongMethod")),
-      new TestCase(getMethod("FloatMethod")),
-      new TestCase(getMethod("DoubleMethod")),
+      new TestCase(getMethod("IntMethod")),    new TestCase(getMethod("LongMethod")),
+      new TestCase(getMethod("FloatMethod")),  new TestCase(getMethod("DoubleMethod")),
+      new TestCase(getMethod("ObjectMethod")), new TestCase(getMethod("NullObjectMethod")),
     };
 
     final SafepointFunction[] SAFEPOINTS = new SafepointFunction[] {
@@ -233,28 +234,30 @@
       NamedGet("Long", Locals::GetLocalVariableLong),
       NamedGet("Float", Locals::GetLocalVariableFloat),
       NamedGet("Double", Locals::GetLocalVariableDouble),
+      NamedGet("Object", Locals::GetLocalVariableObject),
       NamedSet("Int", Locals::SetLocalVariableInt, Integer.MAX_VALUE),
       NamedSet("Long", Locals::SetLocalVariableLong, Long.MAX_VALUE),
       NamedSet("Float", Locals::SetLocalVariableFloat, 9.2f),
       NamedSet("Double", Locals::SetLocalVariableDouble, 12.4d),
+      NamedSet("Object", Locals::SetLocalVariableObject, "NEW_VALUE_FOR_SET"),
+      NamedSet("NullObject", Locals::SetLocalVariableObject, null),
     };
 
-    for (TestCase t: MAIN_TEST_CASES) {
+    for (TestCase t : MAIN_TEST_CASES) {
       for (SafepointFunction s : SAFEPOINTS) {
         t.exec(s);
       }
     }
 
     // Test int for small values.
-    new TestCase(getMethod("BooleanMethod")).exec(
-        NamedSet("IntBoolSize", Locals::SetLocalVariableInt, 1));
-    new TestCase(getMethod("ByteMethod")).exec(
-      NamedSet("IntByteSize", Locals::SetLocalVariableInt, Byte.MAX_VALUE - 1));
+    new TestCase(getMethod("BooleanMethod"))
+        .exec(NamedSet("IntBoolSize", Locals::SetLocalVariableInt, 1));
+    new TestCase(getMethod("ByteMethod"))
+        .exec(NamedSet("IntByteSize", Locals::SetLocalVariableInt, Byte.MAX_VALUE - 1));
 
-    new TestCase(getMethod("CharMethod")).exec(
-      NamedSet("IntCharSize", Locals::SetLocalVariableInt, Character.MAX_VALUE - 1));
-    new TestCase(getMethod("ShortMethod")).exec(
-      NamedSet("IntShortSize", Locals::SetLocalVariableInt, Short.MAX_VALUE - 1));
+    new TestCase(getMethod("CharMethod"))
+        .exec(NamedSet("IntCharSize", Locals::SetLocalVariableInt, Character.MAX_VALUE - 1));
+    new TestCase(getMethod("ShortMethod"))
+        .exec(NamedSet("IntShortSize", Locals::SetLocalVariableInt, Short.MAX_VALUE - 1));
   }
 }
-
diff --git a/test/1913-get-set-local-objects/expected.txt b/test/1913-get-set-local-objects/expected.txt
index 23f4992..2338915 100644
--- a/test/1913-get-set-local-objects/expected.txt
+++ b/test/1913-get-set-local-objects/expected.txt
@@ -70,3 +70,57 @@
 Running public static void art.Test1913.PrimitiveMethod(java.lang.Runnable) with "SetTestClass2impl" on remote thread.
 "SetTestClass2impl" on public static void art.Test1913.PrimitiveMethod(java.lang.Runnable) failed to set value TestClass2impl("TestClass2("Set TestClass2impl")") due to JVMTI_ERROR_TYPE_MISMATCH
 	Value is '42' (class: class java.lang.Integer)
+Running public static void art.Test1913.NullObjectMethod(java.lang.Runnable) with "GetGetObject" on remote thread.
+"GetGetObject" on public static void art.Test1913.NullObjectMethod(java.lang.Runnable) got value: null
+	Value is 'null' (class: NULL)
+Running public static void art.Test1913.NullObjectMethod(java.lang.Runnable) with "SetNull" on remote thread.
+"SetNull" on public static void art.Test1913.NullObjectMethod(java.lang.Runnable) set value: null
+	Value is 'null' (class: NULL)
+Running public static void art.Test1913.NullObjectMethod(java.lang.Runnable) with "SetTestClass1" on remote thread.
+"SetTestClass1" on public static void art.Test1913.NullObjectMethod(java.lang.Runnable) set value: TestClass1("Set TestClass1")
+	Value is 'TestClass1("Set TestClass1")' (class: class art.Test1913$TestClass1)
+Running public static void art.Test1913.NullObjectMethod(java.lang.Runnable) with "SetTestClass1ext" on remote thread.
+"SetTestClass1ext" on public static void art.Test1913.NullObjectMethod(java.lang.Runnable) set value: TestClass1ext("TestClass1("Set TestClass1ext")")
+	Value is 'TestClass1ext("TestClass1("Set TestClass1ext")")' (class: class art.Test1913$TestClass1ext)
+Running public static void art.Test1913.NullObjectMethod(java.lang.Runnable) with "SetTestClass2" on remote thread.
+"SetTestClass2" on public static void art.Test1913.NullObjectMethod(java.lang.Runnable) set value: TestClass2("Set TestClass2")
+	Value is 'TestClass2("Set TestClass2")' (class: class art.Test1913$TestClass2)
+Running public static void art.Test1913.NullObjectMethod(java.lang.Runnable) with "SetTestClass2impl" on remote thread.
+"SetTestClass2impl" on public static void art.Test1913.NullObjectMethod(java.lang.Runnable) set value: TestClass2impl("TestClass2("Set TestClass2impl")")
+	Value is 'TestClass2impl("TestClass2("Set TestClass2impl")")' (class: class art.Test1913$TestClass2impl)
+Running public static void art.Test1913.NullInterfaceMethod(java.lang.Runnable) with "GetGetObject" on remote thread.
+"GetGetObject" on public static void art.Test1913.NullInterfaceMethod(java.lang.Runnable) got value: null
+	Value is 'null' (class: NULL)
+Running public static void art.Test1913.NullInterfaceMethod(java.lang.Runnable) with "SetNull" on remote thread.
+"SetNull" on public static void art.Test1913.NullInterfaceMethod(java.lang.Runnable) set value: null
+	Value is 'null' (class: NULL)
+Running public static void art.Test1913.NullInterfaceMethod(java.lang.Runnable) with "SetTestClass1" on remote thread.
+"SetTestClass1" on public static void art.Test1913.NullInterfaceMethod(java.lang.Runnable) set value: TestClass1("Set TestClass1")
+	Value is 'TestClass1("Set TestClass1")' (class: class art.Test1913$TestClass1)
+Running public static void art.Test1913.NullInterfaceMethod(java.lang.Runnable) with "SetTestClass1ext" on remote thread.
+"SetTestClass1ext" on public static void art.Test1913.NullInterfaceMethod(java.lang.Runnable) set value: TestClass1ext("TestClass1("Set TestClass1ext")")
+	Value is 'TestClass1ext("TestClass1("Set TestClass1ext")")' (class: class art.Test1913$TestClass1ext)
+Running public static void art.Test1913.NullInterfaceMethod(java.lang.Runnable) with "SetTestClass2" on remote thread.
+"SetTestClass2" on public static void art.Test1913.NullInterfaceMethod(java.lang.Runnable) failed to set value TestClass2("Set TestClass2") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: NULL)
+Running public static void art.Test1913.NullInterfaceMethod(java.lang.Runnable) with "SetTestClass2impl" on remote thread.
+"SetTestClass2impl" on public static void art.Test1913.NullInterfaceMethod(java.lang.Runnable) set value: TestClass2impl("TestClass2("Set TestClass2impl")")
+	Value is 'TestClass2impl("TestClass2("Set TestClass2impl")")' (class: class art.Test1913$TestClass2impl)
+Running public static void art.Test1913.NullSpecificClassMethod(java.lang.Runnable) with "GetGetObject" on remote thread.
+"GetGetObject" on public static void art.Test1913.NullSpecificClassMethod(java.lang.Runnable) got value: null
+	Value is 'null' (class: NULL)
+Running public static void art.Test1913.NullSpecificClassMethod(java.lang.Runnable) with "SetNull" on remote thread.
+"SetNull" on public static void art.Test1913.NullSpecificClassMethod(java.lang.Runnable) set value: null
+	Value is 'null' (class: NULL)
+Running public static void art.Test1913.NullSpecificClassMethod(java.lang.Runnable) with "SetTestClass1" on remote thread.
+"SetTestClass1" on public static void art.Test1913.NullSpecificClassMethod(java.lang.Runnable) set value: TestClass1("Set TestClass1")
+	Value is 'TestClass1("Set TestClass1")' (class: class art.Test1913$TestClass1)
+Running public static void art.Test1913.NullSpecificClassMethod(java.lang.Runnable) with "SetTestClass1ext" on remote thread.
+"SetTestClass1ext" on public static void art.Test1913.NullSpecificClassMethod(java.lang.Runnable) set value: TestClass1ext("TestClass1("Set TestClass1ext")")
+	Value is 'TestClass1ext("TestClass1("Set TestClass1ext")")' (class: class art.Test1913$TestClass1ext)
+Running public static void art.Test1913.NullSpecificClassMethod(java.lang.Runnable) with "SetTestClass2" on remote thread.
+"SetTestClass2" on public static void art.Test1913.NullSpecificClassMethod(java.lang.Runnable) failed to set value TestClass2("Set TestClass2") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: NULL)
+Running public static void art.Test1913.NullSpecificClassMethod(java.lang.Runnable) with "SetTestClass2impl" on remote thread.
+"SetTestClass2impl" on public static void art.Test1913.NullSpecificClassMethod(java.lang.Runnable) failed to set value TestClass2impl("TestClass2("Set TestClass2impl")") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: NULL)
diff --git a/test/1913-get-set-local-objects/src/art/Test1913.java b/test/1913-get-set-local-objects/src/art/Test1913.java
index 417138a..df86493 100644
--- a/test/1913-get-set-local-objects/src/art/Test1913.java
+++ b/test/1913-get-set-local-objects/src/art/Test1913.java
@@ -20,15 +20,15 @@
 import java.lang.reflect.Executable;
 import java.lang.reflect.Method;
 import java.nio.ByteBuffer;
-import java.util.concurrent.Semaphore;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Semaphore;
+import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
-import java.util.function.Consumer;
 
 public class Test1913 {
   public static final String TARGET_VAR = "TARGET";
@@ -38,27 +38,43 @@
   }
   public static class TestClass1 implements TestInterface {
     public String id;
-    public TestClass1(String id) { this.id = id; }
-    public String toString() { return String.format("TestClass1(\"%s\")", id); }
+    public TestClass1(String id) {
+      this.id = id;
+    }
+    public String toString() {
+      return String.format("TestClass1(\"%s\")", id);
+    }
   }
 
   public static class TestClass1ext extends TestClass1 {
-    public TestClass1ext(String id) { super(id); }
-    public String toString() { return String.format("TestClass1ext(\"%s\")", super.toString()); }
+    public TestClass1ext(String id) {
+      super(id);
+    }
+    public String toString() {
+      return String.format("TestClass1ext(\"%s\")", super.toString());
+    }
   }
   public static class TestClass2 {
     public String id;
-    public TestClass2(String id) { this.id = id; }
-    public String toString() { return String.format("TestClass2(\"%s\")", id); }
+    public TestClass2(String id) {
+      this.id = id;
+    }
+    public String toString() {
+      return String.format("TestClass2(\"%s\")", id);
+    }
   }
   public static class TestClass2impl extends TestClass2 implements TestInterface {
-    public TestClass2impl(String id) { super(id); }
-    public String toString() { return String.format("TestClass2impl(\"%s\")", super.toString()); }
+    public TestClass2impl(String id) {
+      super(id);
+    }
+    public String toString() {
+      return String.format("TestClass2impl(\"%s\")", super.toString());
+    }
   }
 
   public static void reportValue(Object val) {
-    System.out.println("\tValue is '" + val + "' (class: "
-        + (val != null ? val.getClass() : "NULL") + ")");
+    System.out.println("\tValue is '" + val +
+                       "' (class: " + (val != null ? val.getClass() : "NULL") + ")");
   }
 
   public static void PrimitiveMethod(Runnable safepoint) {
@@ -68,7 +84,28 @@
   }
 
   // b/64115302: Needed to make sure that DX doesn't change the type of TARGET to TestClass1.
-  private static Object AsObject(Object o) { return o; }
+  private static Object AsObject(Object o) {
+    return o;
+  }
+
+  public static void NullObjectMethod(Runnable safepoint) {
+    Object TARGET = null;
+    safepoint.run();
+    reportValue(TARGET);
+  }
+
+  public static void NullInterfaceMethod(Runnable safepoint) {
+    TestInterface TARGET = null;
+    safepoint.run();
+    reportValue(TARGET);
+  }
+
+  public static void NullSpecificClassMethod(Runnable safepoint) {
+    TestClass1 TARGET = null;
+    safepoint.run();
+    reportValue(TARGET);
+  }
+
   public static void ObjectMethod(Runnable safepoint) {
     Object TARGET = AsObject(new TestClass1("ObjectMethod"));
     safepoint.run();
@@ -88,31 +125,27 @@
   }
 
   public static interface SafepointFunction {
-    public void invoke(
-        Thread thread,
-        Method target,
-        Locals.VariableDescription TARGET_desc,
-        int depth) throws Exception;
+    public void
+    invoke(Thread thread, Method target, Locals.VariableDescription TARGET_desc, int depth)
+        throws Exception;
   }
 
   public static interface SetterFunction {
     public void SetVar(Thread t, int depth, int slot, Object v);
   }
 
-  public static interface GetterFunction {
-    public Object GetVar(Thread t, int depth, int slot);
-  }
+  public static interface GetterFunction { public Object GetVar(Thread t, int depth, int slot); }
 
-  public static SafepointFunction NamedSet(
-      final String type, final SetterFunction get, final Object v) {
+  public static SafepointFunction
+  NamedSet(final String type, final SetterFunction get, final Object v) {
     return new SafepointFunction() {
       public void invoke(Thread t, Method method, Locals.VariableDescription desc, int depth) {
         try {
           get.SetVar(t, depth, desc.slot, v);
           System.out.println(this + " on " + method + " set value: " + v);
         } catch (Exception e) {
-          System.out.println(
-              this + " on " + method + " failed to set value " + v + " due to " + e.getMessage());
+          System.out.println(this + " on " + method + " failed to set value " + v + " due to " +
+                             e.getMessage());
         }
       }
       public String toString() {
@@ -174,15 +207,13 @@
     public void exec(final SafepointFunction safepoint) throws Exception {
       System.out.println("Running " + target + " with " + safepoint + " on remote thread.");
       final ThreadPauser pause = new ThreadPauser();
-      Thread remote = new Thread(
-          () -> {
-            try {
-              target.invoke(null, pause);
-            } catch (Exception e) {
-              throw new Error("Error invoking remote thread " + Thread.currentThread(), e);
-            }
-          },
-          "remote thread for " + target + " with " + safepoint);
+      Thread remote = new Thread(() -> {
+        try {
+          target.invoke(null, pause);
+        } catch (Exception e) {
+          throw new Error("Error invoking remote thread " + Thread.currentThread(), e);
+        }
+      }, "remote thread for " + target + " with " + safepoint);
       remote.start();
       pause.waitForOtherThreadToPause();
       try {
@@ -199,14 +230,12 @@
 
     private Locals.VariableDescription findTargetVar(long loc) {
       for (Locals.VariableDescription var : Locals.GetLocalVariableTable(target)) {
-        if (var.start_location <= loc &&
-            var.length + var.start_location > loc &&
+        if (var.start_location <= loc && var.length + var.start_location > loc &&
             var.name.equals(TARGET_VAR)) {
           return var;
         }
       }
-      throw new Error(
-          "Unable to find variable " + TARGET_VAR + " in " + target + " at loc " + loc);
+      throw new Error("Unable to find variable " + TARGET_VAR + " in " + target + " at loc " + loc);
     }
 
     private StackTrace.StackFrameData findStackFrame(Thread thr) {
@@ -225,27 +254,27 @@
   public static void run() throws Exception {
     Locals.EnableLocalVariableAccess();
     final TestCase[] MAIN_TEST_CASES = new TestCase[] {
-      new TestCase(getMethod("ObjectMethod")),
-      new TestCase(getMethod("InterfaceMethod")),
-      new TestCase(getMethod("SpecificClassMethod")),
-      new TestCase(getMethod("PrimitiveMethod")),
+      new TestCase(getMethod("ObjectMethod")),        new TestCase(getMethod("InterfaceMethod")),
+      new TestCase(getMethod("SpecificClassMethod")), new TestCase(getMethod("PrimitiveMethod")),
+      new TestCase(getMethod("NullObjectMethod")),
+      new TestCase(getMethod("NullInterfaceMethod")),
+      new TestCase(getMethod("NullSpecificClassMethod")),
     };
 
     final SetterFunction set_obj = Locals::SetLocalVariableObject;
     final SafepointFunction[] SAFEPOINTS = new SafepointFunction[] {
-      NamedGet("GetObject",      Locals::GetLocalVariableObject),
-      NamedSet("Null",           set_obj, null),
-      NamedSet("TestClass1",     set_obj, new TestClass1("Set TestClass1")),
-      NamedSet("TestClass1ext",  set_obj, new TestClass1ext("Set TestClass1ext")),
-      NamedSet("TestClass2",     set_obj, new TestClass2("Set TestClass2")),
+      NamedGet("GetObject", Locals::GetLocalVariableObject),
+      NamedSet("Null", set_obj, null),
+      NamedSet("TestClass1", set_obj, new TestClass1("Set TestClass1")),
+      NamedSet("TestClass1ext", set_obj, new TestClass1ext("Set TestClass1ext")),
+      NamedSet("TestClass2", set_obj, new TestClass2("Set TestClass2")),
       NamedSet("TestClass2impl", set_obj, new TestClass2impl("Set TestClass2impl")),
     };
 
-    for (TestCase t: MAIN_TEST_CASES) {
+    for (TestCase t : MAIN_TEST_CASES) {
       for (SafepointFunction s : SAFEPOINTS) {
         t.exec(s);
       }
     }
   }
 }
-
diff --git a/test/1965-get-set-local-primitive-no-tables/build b/test/1965-get-set-local-primitive-no-tables/build
new file mode 100644
index 0000000..6631df9
--- /dev/null
+++ b/test/1965-get-set-local-primitive-no-tables/build
@@ -0,0 +1,25 @@
+#!/bin/bash
+#
+# Copyright 2019 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.
+
+# make us exit on a failure
+set -e
+
+if [[ $@ != *"--jvm"* ]]; then
+  mv jasmin jasmin-unused
+else
+  mv smali smali-unused
+fi
+./default-build "$@" 
diff --git a/test/1965-get-set-local-primitive-no-tables/expected.txt b/test/1965-get-set-local-primitive-no-tables/expected.txt
new file mode 100644
index 0000000..97f8ab0
--- /dev/null
+++ b/test/1965-get-set-local-primitive-no-tables/expected.txt
@@ -0,0 +1,210 @@
+Running public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetInt" on remote thread.
+"GetInt" on public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) got value: 42
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetLong" on remote thread.
+"GetLong" on public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetFloat" on remote thread.
+"GetFloat" on public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) got value: 5.9E-44
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetDouble" on remote thread.
+"GetDouble" on public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetObject" on remote thread.
+"GetObject" on public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetInt" on remote thread.
+"SetInt" on public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: 2147483647
+	Value is '2147483647' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetLong" on remote thread.
+"SetLong" on public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 9223372036854775807 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetFloat" on remote thread.
+"SetFloat" on public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: 9.2
+	Value is '1091777331' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetDouble" on remote thread.
+"SetDouble" on public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 12.4 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetObject" on remote thread.
+"SetObject" on public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value NEW_VALUE_FOR_SET due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetNullObject" on remote thread.
+"SetNullObject" on public static void art_test.TestCases1965.IntMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value null due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetInt" on remote thread.
+"GetInt" on public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '9001' (class: class java.lang.Long)
+Running public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetLong" on remote thread.
+"GetLong" on public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) got value: 9001
+	Value is '9001' (class: class java.lang.Long)
+Running public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetFloat" on remote thread.
+"GetFloat" on public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '9001' (class: class java.lang.Long)
+Running public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetDouble" on remote thread.
+"GetDouble" on public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) got value: 4.447E-320
+	Value is '9001' (class: class java.lang.Long)
+Running public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetObject" on remote thread.
+"GetObject" on public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '9001' (class: class java.lang.Long)
+Running public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetInt" on remote thread.
+"SetInt" on public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 2147483647 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '9001' (class: class java.lang.Long)
+Running public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetLong" on remote thread.
+"SetLong" on public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: 9223372036854775807
+	Value is '9223372036854775807' (class: class java.lang.Long)
+Running public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetFloat" on remote thread.
+"SetFloat" on public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 9.2 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '9001' (class: class java.lang.Long)
+Running public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetDouble" on remote thread.
+"SetDouble" on public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: 12.4
+	Value is '4623170197477182669' (class: class java.lang.Long)
+Running public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetObject" on remote thread.
+"SetObject" on public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value NEW_VALUE_FOR_SET due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '9001' (class: class java.lang.Long)
+Running public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetNullObject" on remote thread.
+"SetNullObject" on public static void art_test.TestCases1965.LongMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value null due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '9001' (class: class java.lang.Long)
+Running public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetInt" on remote thread.
+"GetInt" on public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) got value: 1070537376
+	Value is '1.618' (class: class java.lang.Float)
+Running public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetLong" on remote thread.
+"GetLong" on public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '1.618' (class: class java.lang.Float)
+Running public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetFloat" on remote thread.
+"GetFloat" on public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) got value: 1.618
+	Value is '1.618' (class: class java.lang.Float)
+Running public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetDouble" on remote thread.
+"GetDouble" on public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '1.618' (class: class java.lang.Float)
+Running public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetObject" on remote thread.
+"GetObject" on public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '1.618' (class: class java.lang.Float)
+Running public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetInt" on remote thread.
+"SetInt" on public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: 2147483647
+	Value is 'NaN' (class: class java.lang.Float)
+Running public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetLong" on remote thread.
+"SetLong" on public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 9223372036854775807 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '1.618' (class: class java.lang.Float)
+Running public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetFloat" on remote thread.
+"SetFloat" on public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: 9.2
+	Value is '9.2' (class: class java.lang.Float)
+Running public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetDouble" on remote thread.
+"SetDouble" on public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 12.4 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '1.618' (class: class java.lang.Float)
+Running public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetObject" on remote thread.
+"SetObject" on public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value NEW_VALUE_FOR_SET due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '1.618' (class: class java.lang.Float)
+Running public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetNullObject" on remote thread.
+"SetNullObject" on public static void art_test.TestCases1965.FloatMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value null due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '1.618' (class: class java.lang.Float)
+Running public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetInt" on remote thread.
+"GetInt" on public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '3.1415' (class: class java.lang.Double)
+Running public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetLong" on remote thread.
+"GetLong" on public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) got value: 4614256447914709615
+	Value is '3.1415' (class: class java.lang.Double)
+Running public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetFloat" on remote thread.
+"GetFloat" on public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '3.1415' (class: class java.lang.Double)
+Running public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetDouble" on remote thread.
+"GetDouble" on public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) got value: 3.1415
+	Value is '3.1415' (class: class java.lang.Double)
+Running public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetObject" on remote thread.
+"GetObject" on public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '3.1415' (class: class java.lang.Double)
+Running public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetInt" on remote thread.
+"SetInt" on public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 2147483647 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '3.1415' (class: class java.lang.Double)
+Running public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetLong" on remote thread.
+"SetLong" on public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: 9223372036854775807
+	Value is 'NaN' (class: class java.lang.Double)
+Running public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetFloat" on remote thread.
+"SetFloat" on public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 9.2 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '3.1415' (class: class java.lang.Double)
+Running public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetDouble" on remote thread.
+"SetDouble" on public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: 12.4
+	Value is '12.4' (class: class java.lang.Double)
+Running public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetObject" on remote thread.
+"SetObject" on public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value NEW_VALUE_FOR_SET due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '3.1415' (class: class java.lang.Double)
+Running public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetNullObject" on remote thread.
+"SetNullObject" on public static void art_test.TestCases1965.DoubleMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value null due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '3.1415' (class: class java.lang.Double)
+Running public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetInt" on remote thread.
+"GetInt" on public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET_VALUE' (class: class java.lang.String)
+Running public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetLong" on remote thread.
+"GetLong" on public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET_VALUE' (class: class java.lang.String)
+Running public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetFloat" on remote thread.
+"GetFloat" on public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET_VALUE' (class: class java.lang.String)
+Running public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetDouble" on remote thread.
+"GetDouble" on public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET_VALUE' (class: class java.lang.String)
+Running public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetObject" on remote thread.
+"GetObject" on public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) got value: TARGET_VALUE
+	Value is 'TARGET_VALUE' (class: class java.lang.String)
+Running public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetInt" on remote thread.
+"SetInt" on public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 2147483647 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET_VALUE' (class: class java.lang.String)
+Running public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetLong" on remote thread.
+"SetLong" on public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 9223372036854775807 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET_VALUE' (class: class java.lang.String)
+Running public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetFloat" on remote thread.
+"SetFloat" on public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 9.2 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET_VALUE' (class: class java.lang.String)
+Running public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetDouble" on remote thread.
+"SetDouble" on public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 12.4 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TARGET_VALUE' (class: class java.lang.String)
+Running public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetObject" on remote thread.
+"SetObject" on public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: NEW_VALUE_FOR_SET
+	Value is 'NEW_VALUE_FOR_SET' (class: class java.lang.String)
+Running public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetNullObject" on remote thread.
+"SetNullObject" on public static void art_test.TestCases1965.ObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: null
+	Value is 'null' (class: null)
+Running public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetInt" on remote thread.
+"GetInt" on public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) got value: 0
+	Value is 'null' (class: null)
+Running public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetLong" on remote thread.
+"GetLong" on public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: null)
+Running public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetFloat" on remote thread.
+"GetFloat" on public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) got value: 0.0
+	Value is 'null' (class: null)
+Running public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetDouble" on remote thread.
+"GetDouble" on public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: null)
+Running public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "GetObject" on remote thread.
+"GetObject" on public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) got value: null
+	Value is 'null' (class: null)
+Running public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetInt" on remote thread.
+"SetInt" on public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 2147483647 due to JVMTI_ERROR_INTERNAL
+	Value is 'null' (class: null)
+Running public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetLong" on remote thread.
+"SetLong" on public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 9223372036854775807 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: null)
+Running public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetFloat" on remote thread.
+"SetFloat" on public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 9.2 due to JVMTI_ERROR_INTERNAL
+	Value is 'null' (class: null)
+Running public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetDouble" on remote thread.
+"SetDouble" on public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 12.4 due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: null)
+Running public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetObject" on remote thread.
+"SetObject" on public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value NEW_VALUE_FOR_SET due to JVMTI_ERROR_INTERNAL
+	Value is 'null' (class: null)
+Running public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetNullObject" on remote thread.
+"SetNullObject" on public static void art_test.TestCases1965.NullObjectMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: null
+	Value is 'null' (class: null)
+Running public static void art_test.TestCases1965.BooleanMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetIntBoolSize" on remote thread.
+"SetIntBoolSize" on public static void art_test.TestCases1965.BooleanMethod(java.util.function.IntConsumer,java.util.function.Consumer) failed to set value 1 due to JVMTI_ERROR_INTERNAL
+	Value is 'false' (class: class java.lang.Boolean)
+Running public static void art_test.TestCases1965.ByteMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetIntByteSize" on remote thread.
+"SetIntByteSize" on public static void art_test.TestCases1965.ByteMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: 126
+	Value is '126' (class: class java.lang.Byte)
+Running public static void art_test.TestCases1965.CharMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetIntCharSize" on remote thread.
+"SetIntCharSize" on public static void art_test.TestCases1965.CharMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: 65534
+	Value is '<Char: -1>' (class: class java.lang.String)
+Running public static void art_test.TestCases1965.ShortMethod(java.util.function.IntConsumer,java.util.function.Consumer) with "SetIntShortSize" on remote thread.
+"SetIntShortSize" on public static void art_test.TestCases1965.ShortMethod(java.util.function.IntConsumer,java.util.function.Consumer) set value: 32766
+	Value is '32766' (class: class java.lang.Short)
diff --git a/test/1965-get-set-local-primitive-no-tables/info.txt b/test/1965-get-set-local-primitive-no-tables/info.txt
new file mode 100644
index 0000000..87a7b35
--- /dev/null
+++ b/test/1965-get-set-local-primitive-no-tables/info.txt
@@ -0,0 +1,2 @@
+Tests for jvmti get/set Local variable primitives.
+
diff --git a/test/1965-get-set-local-primitive-no-tables/jasmin/TestCases1965.j b/test/1965-get-set-local-primitive-no-tables/jasmin/TestCases1965.j
new file mode 100644
index 0000000..6374262
--- /dev/null
+++ b/test/1965-get-set-local-primitive-no-tables/jasmin/TestCases1965.j
@@ -0,0 +1,173 @@
+; Copyright (C) 2019 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 public final art_test/TestCases1965
+.super java/lang/Object
+
+.method public <init>()V
+  .limit stack 1
+  .limit locals 1
+  0: aload_0
+  1: invokespecial java/lang/Object/<init>()V
+  4: return
+.end method
+
+; NB We limit locals 4 so that every method has space to fit a long/double in it.
+.method public static NullObjectMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+  .limit stack 2
+  .limit locals 4
+  0: aconst_null
+  1: astore_2
+  2: aload_0
+  3: sipush 2
+  6: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  11: aload_1
+  12: aload_2
+  13: invokeinterface java/util/function/Consumer/accept(Ljava/lang/Object;)V 2
+  18: return
+.end method
+
+.method public static ObjectMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+  .limit stack 2
+  .limit locals 4
+  0: ldc "TARGET_VALUE"
+  2: astore_2
+  3: aload_0
+  4: sipush 2
+  7: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  12: aload_1
+  13: aload_2
+  14: invokeinterface java/util/function/Consumer/accept(Ljava/lang/Object;)V 2
+  19: return
+.end method
+
+.method public static BooleanMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+  .limit stack 2
+  .limit locals 4
+  0: iconst_0
+  1: istore_2
+  2: aload_0
+  3: sipush 2
+  6: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  11: aload_1
+  12: iload_2
+  13: invokestatic java/lang/Boolean/valueOf(Z)Ljava/lang/Boolean;
+  16: invokeinterface java/util/function/Consumer/accept(Ljava/lang/Object;)V 2
+  21: return
+.end method
+
+.method public static ByteMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+  .limit stack 2
+  .limit locals 4
+  0: bipush 8
+  2: istore_2
+  3: aload_0
+  4: sipush 2
+  7: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  12: aload_1
+  13: iload_2
+  14: invokestatic java/lang/Byte/valueOf(B)Ljava/lang/Byte;
+  17: invokeinterface java/util/function/Consumer/accept(Ljava/lang/Object;)V 2
+  22: return
+.end method
+
+.method public static CharMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+  .limit stack 2
+  .limit locals 4
+  0: bipush 113
+  2: istore_2
+  3: aload_0
+  4: sipush 2
+  7: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  12: aload_1
+  13: iload_2
+  14: invokestatic java/lang/Character/valueOf(C)Ljava/lang/Character;
+  17: invokeinterface java/util/function/Consumer/accept(Ljava/lang/Object;)V 2
+  22: return
+.end method
+
+.method public static ShortMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+  .limit stack 2
+  .limit locals 4
+  0: sipush 321
+  3: istore_2
+  4: aload_0
+  5: sipush 2
+  8: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  13: aload_1
+  14: iload_2
+  15: invokestatic java/lang/Short/valueOf(S)Ljava/lang/Short;
+  18: invokeinterface java/util/function/Consumer/accept(Ljava/lang/Object;)V 2
+  23: return
+.end method
+
+.method public static IntMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+  .limit stack 2
+  .limit locals 4
+  0: bipush 42
+  2: istore_2
+  3: aload_0
+  4: sipush 2
+  7: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  12: aload_1
+  13: iload_2
+  14: invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;
+  17: invokeinterface java/util/function/Consumer/accept(Ljava/lang/Object;)V 2
+  22: return
+.end method
+
+.method public static LongMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+  .limit stack 3
+  .limit locals 4
+  0: ldc2_w 9001
+  3: lstore_2
+  4: aload_0
+  5: sipush 2
+  8: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  13: aload_1
+  14: lload_2
+  15: invokestatic java/lang/Long/valueOf(J)Ljava/lang/Long;
+  18: invokeinterface java/util/function/Consumer/accept(Ljava/lang/Object;)V 2
+  23: return
+.end method
+
+.method public static FloatMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+  .limit stack 2
+  .limit locals 4
+  0: ldc 1.618
+  2: fstore_2
+  3: aload_0
+  4: sipush 2
+  7: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  12: aload_1
+  13: fload_2
+  14: invokestatic java/lang/Float/valueOf(F)Ljava/lang/Float;
+  17: invokeinterface java/util/function/Consumer/accept(Ljava/lang/Object;)V 2
+  22: return
+.end method
+
+.method public static DoubleMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+  .limit stack 3
+  .limit locals 4
+  0: ldc2_w 3.1415
+  3: dstore_2
+  4: aload_0
+  5: sipush 2
+  8: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  13: aload_1
+  14: dload_2
+  15: invokestatic java/lang/Double/valueOf(D)Ljava/lang/Double;
+  18: invokeinterface java/util/function/Consumer/accept(Ljava/lang/Object;)V 2
+  23: return
+.end method
diff --git a/test/1965-get-set-local-primitive-no-tables/run b/test/1965-get-set-local-primitive-no-tables/run
new file mode 100755
index 0000000..9b741ee
--- /dev/null
+++ b/test/1965-get-set-local-primitive-no-tables/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright 2019 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.
+
+# If we compile the .oat files non-debuggable we could end up with dex2dex running over the files
+# which will cause some instructions to be removed from smali/TestCases1966.smali. This test relies
+# on the instructions being exactly as written so pass --debuggable to 'dex2oat' only to prevent
+# this from happening.
+./default-run "$@" --jvmti --compiler-only-option --debuggable
diff --git a/test/1965-get-set-local-primitive-no-tables/smali/TestCases1965.smali b/test/1965-get-set-local-primitive-no-tables/smali/TestCases1965.smali
new file mode 100644
index 0000000..29aa08c
--- /dev/null
+++ b/test/1965-get-set-local-primitive-no-tables/smali/TestCases1965.smali
@@ -0,0 +1,140 @@
+# Copyright (C) 2019 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 public final Lart_test/TestCases1965;
+.super Ljava/lang/Object;
+
+
+# direct methods
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public static BooleanMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+    .registers 4
+    const/4 v0, 0x0
+    # Slot for value.
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;
+    move-result-object v1
+    invoke-interface {p1, v1}, Ljava/util/function/Consumer;->accept(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static ByteMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+    .registers 4
+    const/16 v0, 0x8
+    # Slot for value.
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Ljava/lang/Byte;->valueOf(B)Ljava/lang/Byte;
+    move-result-object v1
+    invoke-interface {p1, v1}, Ljava/util/function/Consumer;->accept(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static CharMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+    .registers 4
+    const/16 v0, 0x71
+    # Slot for value
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Ljava/lang/Character;->valueOf(C)Ljava/lang/Character;
+    move-result-object v1
+    invoke-interface {p1, v1}, Ljava/util/function/Consumer;->accept(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static DoubleMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+    .registers 5
+    const-wide v0, 0x400921cac083126fL    # 3.1415
+    # Slot for value
+    const/16 v2, 0x0
+    invoke-interface {p0, v2}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0, v1}, Ljava/lang/Double;->valueOf(D)Ljava/lang/Double;
+    move-result-object v2
+    invoke-interface {p1, v2}, Ljava/util/function/Consumer;->accept(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static FloatMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+    .registers 4
+    const v0, 0x3fcf1aa0    # 1.618f
+    # Slot for value
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Ljava/lang/Float;->valueOf(F)Ljava/lang/Float;
+    move-result-object v1
+    invoke-interface {p1, v1}, Ljava/util/function/Consumer;->accept(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static IntMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+    .registers 4
+    const/16 v0, 0x2a
+    # Slot for value
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
+    move-result-object v1
+    invoke-interface {p1, v1}, Ljava/util/function/Consumer;->accept(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static LongMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+    .registers 5
+    const-wide/16 v0, 0x2329
+    # Slot for value
+    const/16 v2, 0x0
+    invoke-interface {p0, v2}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0, v1}, Ljava/lang/Long;->valueOf(J)Ljava/lang/Long;
+    move-result-object v2
+    invoke-interface {p1, v2}, Ljava/util/function/Consumer;->accept(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static NullObjectMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+    .registers 4
+    const/4 v0, 0x0
+    # Slot for value
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-interface {p1, v0}, Ljava/util/function/Consumer;->accept(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static ObjectMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+    .registers 4
+    const-string v0, "TARGET_VALUE"
+    # Slot for value
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-interface {p1, v0}, Ljava/util/function/Consumer;->accept(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static ShortMethod(Ljava/util/function/IntConsumer;Ljava/util/function/Consumer;)V
+    .registers 4
+    const/16 v0, 0x141
+    # slot for value
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Ljava/lang/Short;->valueOf(S)Ljava/lang/Short;
+    move-result-object v1
+    invoke-interface {p1, v1}, Ljava/util/function/Consumer;->accept(Ljava/lang/Object;)V
+    return-void
+.end method
diff --git a/test/1965-get-set-local-primitive-no-tables/src/Main.java b/test/1965-get-set-local-primitive-no-tables/src/Main.java
new file mode 100644
index 0000000..73ce85f
--- /dev/null
+++ b/test/1965-get-set-local-primitive-no-tables/src/Main.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.
+ */
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    art.Test1965.run();
+  }
+}
diff --git a/test/1965-get-set-local-primitive-no-tables/src/art/Breakpoint.java b/test/1965-get-set-local-primitive-no-tables/src/art/Breakpoint.java
new file mode 120000
index 0000000..3673916
--- /dev/null
+++ b/test/1965-get-set-local-primitive-no-tables/src/art/Breakpoint.java
@@ -0,0 +1 @@
+../../../jvmti-common/Breakpoint.java
\ No newline at end of file
diff --git a/test/1965-get-set-local-primitive-no-tables/src/art/Locals.java b/test/1965-get-set-local-primitive-no-tables/src/art/Locals.java
new file mode 120000
index 0000000..2998386
--- /dev/null
+++ b/test/1965-get-set-local-primitive-no-tables/src/art/Locals.java
@@ -0,0 +1 @@
+../../../jvmti-common/Locals.java
\ No newline at end of file
diff --git a/test/1965-get-set-local-primitive-no-tables/src/art/StackTrace.java b/test/1965-get-set-local-primitive-no-tables/src/art/StackTrace.java
new file mode 120000
index 0000000..e1a08aa
--- /dev/null
+++ b/test/1965-get-set-local-primitive-no-tables/src/art/StackTrace.java
@@ -0,0 +1 @@
+../../../jvmti-common/StackTrace.java
\ No newline at end of file
diff --git a/test/1965-get-set-local-primitive-no-tables/src/art/Suspension.java b/test/1965-get-set-local-primitive-no-tables/src/art/Suspension.java
new file mode 120000
index 0000000..bcef96f
--- /dev/null
+++ b/test/1965-get-set-local-primitive-no-tables/src/art/Suspension.java
@@ -0,0 +1 @@
+../../../jvmti-common/Suspension.java
\ No newline at end of file
diff --git a/test/1965-get-set-local-primitive-no-tables/src/art/Test1965.java b/test/1965-get-set-local-primitive-no-tables/src/art/Test1965.java
new file mode 100644
index 0000000..f516d18
--- /dev/null
+++ b/test/1965-get-set-local-primitive-no-tables/src/art/Test1965.java
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+
+package art;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Semaphore;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+public class Test1965 {
+  public static final String TARGET_VAR = "TARGET";
+
+  public static void reportValue(Object val) {
+    if (val instanceof Character) {
+      val = "<Char: " + Character.getNumericValue(((Character)val).charValue()) + ">";
+    }
+    System.out.println("\tValue is '" + val +
+                       "' (class: " + (val != null ? val.getClass().toString() : "null") + ")");
+  }
+
+  public static interface SafepointFunction {
+    public void invoke(Thread thread, Method target, int slot, int depth) throws Exception;
+  }
+
+  public static interface SetterFunction {
+    public void SetVar(Thread t, int depth, int slot, Object v);
+  }
+
+  public static interface GetterFunction { public Object GetVar(Thread t, int depth, int slot); }
+
+  public static SafepointFunction
+  NamedSet(final String type, final SetterFunction get, final Object v) {
+    return new SafepointFunction() {
+      public void invoke(Thread t, Method method, int slot, int depth) {
+        try {
+          get.SetVar(t, depth, slot, v);
+          System.out.println(this + " on " + method + " set value: " + v);
+        } catch (Exception e) {
+          System.out.println(this + " on " + method + " failed to set value " + v + " due to " +
+                             e.getMessage());
+        }
+      }
+      public String toString() {
+        return "\"Set" + type + "\"";
+      }
+    };
+  }
+
+  public static SafepointFunction NamedGet(final String type, final GetterFunction get) {
+    return new SafepointFunction() {
+      public void invoke(Thread t, Method method, int slot, int depth) {
+        try {
+          Object res = get.GetVar(t, depth, slot);
+          System.out.println(this + " on " + method + " got value: " + res);
+        } catch (Exception e) {
+          System.out.println(this + " on " + method + " failed due to " + e.getMessage());
+        }
+      }
+      public String toString() {
+        return "\"Get" + type + "\"";
+      }
+    };
+  }
+
+  public static class TestCase {
+    public final Method target;
+
+    public TestCase(Method target) {
+      this.target = target;
+    }
+
+    public static class ThreadPauser implements IntConsumer {
+      public final Semaphore sem_wakeup_main;
+      public final Semaphore sem_wait;
+      public int slot = -1;
+
+      public ThreadPauser() {
+        sem_wakeup_main = new Semaphore(0);
+        sem_wait = new Semaphore(0);
+      }
+
+      public void accept(int v) {
+        try {
+          slot = v;
+          sem_wakeup_main.release();
+          sem_wait.acquire();
+        } catch (Exception e) {
+          throw new Error("Error with semaphores!", e);
+        }
+      }
+
+      public void waitForOtherThreadToPause() throws Exception {
+        sem_wakeup_main.acquire();
+      }
+
+      public void wakeupOtherThread() throws Exception {
+        sem_wait.release();
+      }
+    }
+
+    public void exec(final SafepointFunction safepoint) throws Exception {
+      System.out.println("Running " + target + " with " + safepoint + " on remote thread.");
+      final ThreadPauser pause = new ThreadPauser();
+      final Consumer<?> reporter = Test1965::reportValue;
+      Thread remote = new Thread(() -> {
+        try {
+          target.invoke(null, pause, reporter);
+        } catch (Exception e) {
+          throw new Error("Error invoking remote thread " + Thread.currentThread(), e);
+        }
+      }, "remote thread for " + target + " with " + safepoint);
+      remote.start();
+      pause.waitForOtherThreadToPause();
+      try {
+        Suspension.suspend(remote);
+        StackTrace.StackFrameData frame = findStackFrame(remote);
+        safepoint.invoke(remote, target, pause.slot, frame.depth);
+      } finally {
+        Suspension.resume(remote);
+        pause.wakeupOtherThread();
+        remote.join();
+      }
+    }
+
+    private Locals.VariableDescription findTargetVar(long loc) {
+      for (Locals.VariableDescription var : Locals.GetLocalVariableTable(target)) {
+        if (var.start_location <= loc && var.length + var.start_location > loc &&
+            var.name.equals(TARGET_VAR)) {
+          return var;
+        }
+      }
+      throw new Error("Unable to find variable " + TARGET_VAR + " in " + target + " at loc " + loc);
+    }
+
+    private StackTrace.StackFrameData findStackFrame(Thread thr) {
+      for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(thr)) {
+        if (frame.method.equals(target)) {
+          return frame;
+        }
+      }
+      throw new Error("Unable to find stack frame in method " + target + " on thread " + thr);
+    }
+  }
+  public static Method getMethod(String name) throws Exception {
+    return Class.forName("art_test.TestCases1965")
+        .getDeclaredMethod(name, IntConsumer.class, Consumer.class);
+  }
+
+  public static void run() throws Exception {
+    Locals.EnableLocalVariableAccess();
+    final TestCase[] MAIN_TEST_CASES = new TestCase[] {
+      new TestCase(getMethod("IntMethod")),    new TestCase(getMethod("LongMethod")),
+      new TestCase(getMethod("FloatMethod")),  new TestCase(getMethod("DoubleMethod")),
+      new TestCase(getMethod("ObjectMethod")), new TestCase(getMethod("NullObjectMethod")),
+    };
+
+    final SafepointFunction[] SAFEPOINTS = new SafepointFunction[] {
+      NamedGet("Int", Locals::GetLocalVariableInt),
+      NamedGet("Long", Locals::GetLocalVariableLong),
+      NamedGet("Float", Locals::GetLocalVariableFloat),
+      NamedGet("Double", Locals::GetLocalVariableDouble),
+      NamedGet("Object", Locals::GetLocalVariableObject),
+      NamedSet("Int", Locals::SetLocalVariableInt, Integer.MAX_VALUE),
+      NamedSet("Long", Locals::SetLocalVariableLong, Long.MAX_VALUE),
+      NamedSet("Float", Locals::SetLocalVariableFloat, 9.2f),
+      NamedSet("Double", Locals::SetLocalVariableDouble, 12.4d),
+      NamedSet("Object", Locals::SetLocalVariableObject, "NEW_VALUE_FOR_SET"),
+      NamedSet("NullObject", Locals::SetLocalVariableObject, null),
+    };
+
+    for (TestCase t : MAIN_TEST_CASES) {
+      for (SafepointFunction s : SAFEPOINTS) {
+        t.exec(s);
+      }
+    }
+
+    // Test int for small values.
+    new TestCase(getMethod("BooleanMethod"))
+        .exec(NamedSet("IntBoolSize", Locals::SetLocalVariableInt, 1));
+    new TestCase(getMethod("ByteMethod"))
+        .exec(NamedSet("IntByteSize", Locals::SetLocalVariableInt, Byte.MAX_VALUE - 1));
+
+    new TestCase(getMethod("CharMethod"))
+        .exec(NamedSet("IntCharSize", Locals::SetLocalVariableInt, Character.MAX_VALUE - 1));
+    new TestCase(getMethod("ShortMethod"))
+        .exec(NamedSet("IntShortSize", Locals::SetLocalVariableInt, Short.MAX_VALUE - 1));
+  }
+}
diff --git a/test/1966-get-set-local-objects-no-table/build b/test/1966-get-set-local-objects-no-table/build
new file mode 100644
index 0000000..6631df9
--- /dev/null
+++ b/test/1966-get-set-local-objects-no-table/build
@@ -0,0 +1,25 @@
+#!/bin/bash
+#
+# Copyright 2019 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.
+
+# make us exit on a failure
+set -e
+
+if [[ $@ != *"--jvm"* ]]; then
+  mv jasmin jasmin-unused
+else
+  mv smali smali-unused
+fi
+./default-build "$@" 
diff --git a/test/1966-get-set-local-objects-no-table/expected.txt b/test/1966-get-set-local-objects-no-table/expected.txt
new file mode 100644
index 0000000..f24dfe7
--- /dev/null
+++ b/test/1966-get-set-local-objects-no-table/expected.txt
@@ -0,0 +1,162 @@
+Running public static void art_test.TestCases1966.ObjectMethod(java.util.function.IntConsumer) with "GetGetObject" on remote thread.
+"GetGetObject" on public static void art_test.TestCases1966.ObjectMethod(java.util.function.IntConsumer) got value: TestClass1("ObjectMethod")
+	Value is 'TestClass1("ObjectMethod")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.ObjectMethod(java.util.function.IntConsumer) with "SetNull" on remote thread.
+"SetNull" on public static void art_test.TestCases1966.ObjectMethod(java.util.function.IntConsumer) set value: null
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.ObjectMethod(java.util.function.IntConsumer) with "SetTestClass1" on remote thread.
+"SetTestClass1" on public static void art_test.TestCases1966.ObjectMethod(java.util.function.IntConsumer) set value: TestClass1("Set TestClass1")
+	Value is 'TestClass1("Set TestClass1")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.ObjectMethod(java.util.function.IntConsumer) with "SetTestClass1ext" on remote thread.
+"SetTestClass1ext" on public static void art_test.TestCases1966.ObjectMethod(java.util.function.IntConsumer) set value: TestClass1ext("TestClass1("Set TestClass1ext")")
+	Value is 'TestClass1ext("TestClass1("Set TestClass1ext")")' (class: class art.Test1966$TestClass1ext)
+Running public static void art_test.TestCases1966.ObjectMethod(java.util.function.IntConsumer) with "SetTestClass2" on remote thread.
+"SetTestClass2" on public static void art_test.TestCases1966.ObjectMethod(java.util.function.IntConsumer) set value: TestClass2("Set TestClass2")
+	Value is 'TestClass2("Set TestClass2")' (class: class art.Test1966$TestClass2)
+Running public static void art_test.TestCases1966.ObjectMethod(java.util.function.IntConsumer) with "SetTestClass2impl" on remote thread.
+"SetTestClass2impl" on public static void art_test.TestCases1966.ObjectMethod(java.util.function.IntConsumer) set value: TestClass2impl("TestClass2("Set TestClass2impl")")
+	Value is 'TestClass2impl("TestClass2("Set TestClass2impl")")' (class: class art.Test1966$TestClass2impl)
+Running public static void art_test.TestCases1966.CastInterfaceMethod(java.util.function.IntConsumer) with "GetGetObject" on remote thread.
+"GetGetObject" on public static void art_test.TestCases1966.CastInterfaceMethod(java.util.function.IntConsumer) got value: TestClass1("ObjectMethod")
+	Value is 'TestClass1("ObjectMethod")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.CastInterfaceMethod(java.util.function.IntConsumer) with "SetNull" on remote thread.
+"SetNull" on public static void art_test.TestCases1966.CastInterfaceMethod(java.util.function.IntConsumer) set value: null
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.CastInterfaceMethod(java.util.function.IntConsumer) with "SetTestClass1" on remote thread.
+"SetTestClass1" on public static void art_test.TestCases1966.CastInterfaceMethod(java.util.function.IntConsumer) set value: TestClass1("Set TestClass1")
+	Value is 'TestClass1("Set TestClass1")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.CastInterfaceMethod(java.util.function.IntConsumer) with "SetTestClass1ext" on remote thread.
+"SetTestClass1ext" on public static void art_test.TestCases1966.CastInterfaceMethod(java.util.function.IntConsumer) set value: TestClass1ext("TestClass1("Set TestClass1ext")")
+	Value is 'TestClass1ext("TestClass1("Set TestClass1ext")")' (class: class art.Test1966$TestClass1ext)
+Running public static void art_test.TestCases1966.CastInterfaceMethod(java.util.function.IntConsumer) with "SetTestClass2" on remote thread.
+"SetTestClass2" on public static void art_test.TestCases1966.CastInterfaceMethod(java.util.function.IntConsumer) failed to set value TestClass2("Set TestClass2") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TestClass1("ObjectMethod")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.CastInterfaceMethod(java.util.function.IntConsumer) with "SetTestClass2impl" on remote thread.
+"SetTestClass2impl" on public static void art_test.TestCases1966.CastInterfaceMethod(java.util.function.IntConsumer) failed to set value TestClass2impl("TestClass2("Set TestClass2impl")") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TestClass1("ObjectMethod")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.CastExactMethod(java.util.function.IntConsumer) with "GetGetObject" on remote thread.
+"GetGetObject" on public static void art_test.TestCases1966.CastExactMethod(java.util.function.IntConsumer) got value: TestClass1("ObjectMethod")
+	Value is 'TestClass1("ObjectMethod")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.CastExactMethod(java.util.function.IntConsumer) with "SetNull" on remote thread.
+"SetNull" on public static void art_test.TestCases1966.CastExactMethod(java.util.function.IntConsumer) set value: null
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.CastExactMethod(java.util.function.IntConsumer) with "SetTestClass1" on remote thread.
+"SetTestClass1" on public static void art_test.TestCases1966.CastExactMethod(java.util.function.IntConsumer) set value: TestClass1("Set TestClass1")
+	Value is 'TestClass1("Set TestClass1")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.CastExactMethod(java.util.function.IntConsumer) with "SetTestClass1ext" on remote thread.
+"SetTestClass1ext" on public static void art_test.TestCases1966.CastExactMethod(java.util.function.IntConsumer) set value: TestClass1ext("TestClass1("Set TestClass1ext")")
+	Value is 'TestClass1ext("TestClass1("Set TestClass1ext")")' (class: class art.Test1966$TestClass1ext)
+Running public static void art_test.TestCases1966.CastExactMethod(java.util.function.IntConsumer) with "SetTestClass2" on remote thread.
+"SetTestClass2" on public static void art_test.TestCases1966.CastExactMethod(java.util.function.IntConsumer) failed to set value TestClass2("Set TestClass2") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TestClass1("ObjectMethod")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.CastExactMethod(java.util.function.IntConsumer) with "SetTestClass2impl" on remote thread.
+"SetTestClass2impl" on public static void art_test.TestCases1966.CastExactMethod(java.util.function.IntConsumer) failed to set value TestClass2impl("TestClass2("Set TestClass2impl")") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TestClass1("ObjectMethod")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.InterfaceMethod(java.util.function.IntConsumer) with "GetGetObject" on remote thread.
+"GetGetObject" on public static void art_test.TestCases1966.InterfaceMethod(java.util.function.IntConsumer) got value: TestClass1("InterfaceMethod")
+	Value is 'TestClass1("InterfaceMethod")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.InterfaceMethod(java.util.function.IntConsumer) with "SetNull" on remote thread.
+"SetNull" on public static void art_test.TestCases1966.InterfaceMethod(java.util.function.IntConsumer) set value: null
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.InterfaceMethod(java.util.function.IntConsumer) with "SetTestClass1" on remote thread.
+"SetTestClass1" on public static void art_test.TestCases1966.InterfaceMethod(java.util.function.IntConsumer) set value: TestClass1("Set TestClass1")
+	Value is 'TestClass1("Set TestClass1")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.InterfaceMethod(java.util.function.IntConsumer) with "SetTestClass1ext" on remote thread.
+"SetTestClass1ext" on public static void art_test.TestCases1966.InterfaceMethod(java.util.function.IntConsumer) set value: TestClass1ext("TestClass1("Set TestClass1ext")")
+	Value is 'TestClass1ext("TestClass1("Set TestClass1ext")")' (class: class art.Test1966$TestClass1ext)
+Running public static void art_test.TestCases1966.InterfaceMethod(java.util.function.IntConsumer) with "SetTestClass2" on remote thread.
+"SetTestClass2" on public static void art_test.TestCases1966.InterfaceMethod(java.util.function.IntConsumer) failed to set value TestClass2("Set TestClass2") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TestClass1("InterfaceMethod")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.InterfaceMethod(java.util.function.IntConsumer) with "SetTestClass2impl" on remote thread.
+"SetTestClass2impl" on public static void art_test.TestCases1966.InterfaceMethod(java.util.function.IntConsumer) set value: TestClass2impl("TestClass2("Set TestClass2impl")")
+	Value is 'TestClass2impl("TestClass2("Set TestClass2impl")")' (class: class art.Test1966$TestClass2impl)
+Running public static void art_test.TestCases1966.ExactClassMethod(java.util.function.IntConsumer) with "GetGetObject" on remote thread.
+"GetGetObject" on public static void art_test.TestCases1966.ExactClassMethod(java.util.function.IntConsumer) got value: TestClass1("SpecificClassMethod")
+	Value is 'TestClass1("SpecificClassMethod")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.ExactClassMethod(java.util.function.IntConsumer) with "SetNull" on remote thread.
+"SetNull" on public static void art_test.TestCases1966.ExactClassMethod(java.util.function.IntConsumer) set value: null
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.ExactClassMethod(java.util.function.IntConsumer) with "SetTestClass1" on remote thread.
+"SetTestClass1" on public static void art_test.TestCases1966.ExactClassMethod(java.util.function.IntConsumer) set value: TestClass1("Set TestClass1")
+	Value is 'TestClass1("Set TestClass1")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.ExactClassMethod(java.util.function.IntConsumer) with "SetTestClass1ext" on remote thread.
+"SetTestClass1ext" on public static void art_test.TestCases1966.ExactClassMethod(java.util.function.IntConsumer) set value: TestClass1ext("TestClass1("Set TestClass1ext")")
+	Value is 'TestClass1ext("TestClass1("Set TestClass1ext")")' (class: class art.Test1966$TestClass1ext)
+Running public static void art_test.TestCases1966.ExactClassMethod(java.util.function.IntConsumer) with "SetTestClass2" on remote thread.
+"SetTestClass2" on public static void art_test.TestCases1966.ExactClassMethod(java.util.function.IntConsumer) failed to set value TestClass2("Set TestClass2") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TestClass1("SpecificClassMethod")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.ExactClassMethod(java.util.function.IntConsumer) with "SetTestClass2impl" on remote thread.
+"SetTestClass2impl" on public static void art_test.TestCases1966.ExactClassMethod(java.util.function.IntConsumer) failed to set value TestClass2impl("TestClass2("Set TestClass2impl")") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'TestClass1("SpecificClassMethod")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.PrimitiveMethod(java.util.function.IntConsumer) with "GetGetObject" on remote thread.
+"GetGetObject" on public static void art_test.TestCases1966.PrimitiveMethod(java.util.function.IntConsumer) failed due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1966.PrimitiveMethod(java.util.function.IntConsumer) with "SetNull" on remote thread.
+"SetNull" on public static void art_test.TestCases1966.PrimitiveMethod(java.util.function.IntConsumer) failed to set value null due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1966.PrimitiveMethod(java.util.function.IntConsumer) with "SetTestClass1" on remote thread.
+"SetTestClass1" on public static void art_test.TestCases1966.PrimitiveMethod(java.util.function.IntConsumer) failed to set value TestClass1("Set TestClass1") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1966.PrimitiveMethod(java.util.function.IntConsumer) with "SetTestClass1ext" on remote thread.
+"SetTestClass1ext" on public static void art_test.TestCases1966.PrimitiveMethod(java.util.function.IntConsumer) failed to set value TestClass1ext("TestClass1("Set TestClass1ext")") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1966.PrimitiveMethod(java.util.function.IntConsumer) with "SetTestClass2" on remote thread.
+"SetTestClass2" on public static void art_test.TestCases1966.PrimitiveMethod(java.util.function.IntConsumer) failed to set value TestClass2("Set TestClass2") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1966.PrimitiveMethod(java.util.function.IntConsumer) with "SetTestClass2impl" on remote thread.
+"SetTestClass2impl" on public static void art_test.TestCases1966.PrimitiveMethod(java.util.function.IntConsumer) failed to set value TestClass2impl("TestClass2("Set TestClass2impl")") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is '42' (class: class java.lang.Integer)
+Running public static void art_test.TestCases1966.NullMethod(java.util.function.IntConsumer) with "GetGetObject" on remote thread.
+"GetGetObject" on public static void art_test.TestCases1966.NullMethod(java.util.function.IntConsumer) got value: null
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.NullMethod(java.util.function.IntConsumer) with "SetNull" on remote thread.
+"SetNull" on public static void art_test.TestCases1966.NullMethod(java.util.function.IntConsumer) set value: null
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.NullMethod(java.util.function.IntConsumer) with "SetTestClass1" on remote thread.
+"SetTestClass1" on public static void art_test.TestCases1966.NullMethod(java.util.function.IntConsumer) failed to set value TestClass1("Set TestClass1") due to JVMTI_ERROR_INTERNAL
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.NullMethod(java.util.function.IntConsumer) with "SetTestClass1ext" on remote thread.
+"SetTestClass1ext" on public static void art_test.TestCases1966.NullMethod(java.util.function.IntConsumer) failed to set value TestClass1ext("TestClass1("Set TestClass1ext")") due to JVMTI_ERROR_INTERNAL
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.NullMethod(java.util.function.IntConsumer) with "SetTestClass2" on remote thread.
+"SetTestClass2" on public static void art_test.TestCases1966.NullMethod(java.util.function.IntConsumer) failed to set value TestClass2("Set TestClass2") due to JVMTI_ERROR_INTERNAL
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.NullMethod(java.util.function.IntConsumer) with "SetTestClass2impl" on remote thread.
+"SetTestClass2impl" on public static void art_test.TestCases1966.NullMethod(java.util.function.IntConsumer) failed to set value TestClass2impl("TestClass2("Set TestClass2impl")") due to JVMTI_ERROR_INTERNAL
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.CastExactNullMethod(java.util.function.IntConsumer) with "GetGetObject" on remote thread.
+"GetGetObject" on public static void art_test.TestCases1966.CastExactNullMethod(java.util.function.IntConsumer) got value: null
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.CastExactNullMethod(java.util.function.IntConsumer) with "SetNull" on remote thread.
+"SetNull" on public static void art_test.TestCases1966.CastExactNullMethod(java.util.function.IntConsumer) set value: null
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.CastExactNullMethod(java.util.function.IntConsumer) with "SetTestClass1" on remote thread.
+"SetTestClass1" on public static void art_test.TestCases1966.CastExactNullMethod(java.util.function.IntConsumer) set value: TestClass1("Set TestClass1")
+	Value is 'TestClass1("Set TestClass1")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.CastExactNullMethod(java.util.function.IntConsumer) with "SetTestClass1ext" on remote thread.
+"SetTestClass1ext" on public static void art_test.TestCases1966.CastExactNullMethod(java.util.function.IntConsumer) set value: TestClass1ext("TestClass1("Set TestClass1ext")")
+	Value is 'TestClass1ext("TestClass1("Set TestClass1ext")")' (class: class art.Test1966$TestClass1ext)
+Running public static void art_test.TestCases1966.CastExactNullMethod(java.util.function.IntConsumer) with "SetTestClass2" on remote thread.
+"SetTestClass2" on public static void art_test.TestCases1966.CastExactNullMethod(java.util.function.IntConsumer) failed to set value TestClass2("Set TestClass2") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.CastExactNullMethod(java.util.function.IntConsumer) with "SetTestClass2impl" on remote thread.
+"SetTestClass2impl" on public static void art_test.TestCases1966.CastExactNullMethod(java.util.function.IntConsumer) failed to set value TestClass2impl("TestClass2("Set TestClass2impl")") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.CastInterfaceNullMethod(java.util.function.IntConsumer) with "GetGetObject" on remote thread.
+"GetGetObject" on public static void art_test.TestCases1966.CastInterfaceNullMethod(java.util.function.IntConsumer) got value: null
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.CastInterfaceNullMethod(java.util.function.IntConsumer) with "SetNull" on remote thread.
+"SetNull" on public static void art_test.TestCases1966.CastInterfaceNullMethod(java.util.function.IntConsumer) set value: null
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.CastInterfaceNullMethod(java.util.function.IntConsumer) with "SetTestClass1" on remote thread.
+"SetTestClass1" on public static void art_test.TestCases1966.CastInterfaceNullMethod(java.util.function.IntConsumer) set value: TestClass1("Set TestClass1")
+	Value is 'TestClass1("Set TestClass1")' (class: class art.Test1966$TestClass1)
+Running public static void art_test.TestCases1966.CastInterfaceNullMethod(java.util.function.IntConsumer) with "SetTestClass1ext" on remote thread.
+"SetTestClass1ext" on public static void art_test.TestCases1966.CastInterfaceNullMethod(java.util.function.IntConsumer) set value: TestClass1ext("TestClass1("Set TestClass1ext")")
+	Value is 'TestClass1ext("TestClass1("Set TestClass1ext")")' (class: class art.Test1966$TestClass1ext)
+Running public static void art_test.TestCases1966.CastInterfaceNullMethod(java.util.function.IntConsumer) with "SetTestClass2" on remote thread.
+"SetTestClass2" on public static void art_test.TestCases1966.CastInterfaceNullMethod(java.util.function.IntConsumer) failed to set value TestClass2("Set TestClass2") due to JVMTI_ERROR_TYPE_MISMATCH
+	Value is 'null' (class: NULL)
+Running public static void art_test.TestCases1966.CastInterfaceNullMethod(java.util.function.IntConsumer) with "SetTestClass2impl" on remote thread.
+"SetTestClass2impl" on public static void art_test.TestCases1966.CastInterfaceNullMethod(java.util.function.IntConsumer) set value: TestClass2impl("TestClass2("Set TestClass2impl")")
+	Value is 'TestClass2impl("TestClass2("Set TestClass2impl")")' (class: class art.Test1966$TestClass2impl)
diff --git a/test/1966-get-set-local-objects-no-table/info.txt b/test/1966-get-set-local-objects-no-table/info.txt
new file mode 100644
index 0000000..86ac743
--- /dev/null
+++ b/test/1966-get-set-local-objects-no-table/info.txt
@@ -0,0 +1,2 @@
+Tests for jvmti get and set local variable object.
+
diff --git a/test/1966-get-set-local-objects-no-table/jasmin/TestCases1966.j b/test/1966-get-set-local-objects-no-table/jasmin/TestCases1966.j
new file mode 100644
index 0000000..721f7ce
--- /dev/null
+++ b/test/1966-get-set-local-objects-no-table/jasmin/TestCases1966.j
@@ -0,0 +1,161 @@
+; Copyright (C) 2019 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 public art_test/TestCases1966
+.super java/lang/Object
+.inner class public static TestClass1 inner art/Test1966$TestClass1 outer art/Test1966
+.inner interface public static abstract TestInterface inner art/Test1966$TestInterface outer art/Test1966
+
+.method public <init>()V
+  .limit stack 1
+  .limit locals 1
+  0: aload_0
+  1: invokespecial java/lang/Object/<init>()V
+  4: return
+.end method
+
+.method public static PrimitiveMethod(Ljava/util/function/IntConsumer;)V
+  .limit stack 2
+  .limit locals 2
+  0: bipush 42
+  2: istore_1
+  3: aload_0
+  4: sipush 1
+  7: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  12: iload_1
+  13: invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;
+  16: invokestatic art/Test1966/reportValue(Ljava/lang/Object;)V
+  19: return
+.end method
+
+.method public static CastInterfaceMethod(Ljava/util/function/IntConsumer;)V
+  .limit stack 2
+  .limit locals 3
+  0: ldc "ObjectMethod"
+  2: invokestatic art/Test1966$TestClass1/create(Ljava/lang/String;)Ljava/lang/Object;
+  5: astore_1
+  6: aload_1
+  7: checkcast art/Test1966$TestClass1
+  10: astore_2
+  11: aload_0
+  12: sipush 2
+  15: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  20: aload_2
+  21: invokestatic art/Test1966/reportValue(Ljava/lang/Object;)V
+  24: return
+.end method
+
+.method public static CastExactMethod(Ljava/util/function/IntConsumer;)V
+  .limit stack 2
+  .limit locals 3
+  0: ldc "ObjectMethod"
+  2: invokestatic art/Test1966$TestClass1/create(Ljava/lang/String;)Ljava/lang/Object;
+  5: astore_1
+  6: aload_1
+  7: checkcast art/Test1966$TestClass1
+  10: astore_2
+  11: aload_0
+  12: sipush 2
+  15: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  20: aload_2
+  21: invokestatic art/Test1966/reportValue(Ljava/lang/Object;)V
+  24: return
+.end method
+
+.method public static ObjectMethod(Ljava/util/function/IntConsumer;)V
+  .limit stack 2
+  .limit locals 2
+  0: ldc "ObjectMethod"
+  2: invokestatic art/Test1966$TestClass1/create(Ljava/lang/String;)Ljava/lang/Object;
+  5: astore_1
+  6: aload_0
+  7: sipush 1
+  10: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  15: aload_1
+  16: invokestatic art/Test1966/reportValue(Ljava/lang/Object;)V
+  19: return
+.end method
+
+.method public static InterfaceMethod(Ljava/util/function/IntConsumer;)V
+  .limit stack 2
+  .limit locals 2
+  0: ldc "InterfaceMethod"
+  2: invokestatic art/Test1966$TestClass1/createInterface(Ljava/lang/String;)Lart/Test1966$TestInterface;
+  5: astore_1
+  6: aload_0
+  7: sipush 1
+  10: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  15: aload_1
+  16: invokestatic art/Test1966/reportValue(Ljava/lang/Object;)V
+  19: return
+.end method
+
+.method public static ExactClassMethod(Ljava/util/function/IntConsumer;)V
+  .limit stack 2
+  .limit locals 2
+  0: ldc "SpecificClassMethod"
+  2: invokestatic art/Test1966$TestClass1/createExact(Ljava/lang/String;)Lart/Test1966$TestClass1;
+  5: astore_1
+  6: aload_0
+  7: sipush 1
+  10: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  15: aload_1
+  16: invokestatic art/Test1966/reportValue(Ljava/lang/Object;)V
+  19: return
+.end method
+
+.method public static CastExactNullMethod(Ljava/util/function/IntConsumer;)V
+  .limit stack 2
+  .limit locals 3
+  0: aconst_null
+  1: astore_1
+  2: aload_1
+  3: checkcast art/Test1966$TestClass1
+  6: astore_2
+  7: aload_0
+  8: sipush 2
+  11: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  16: aload_2
+  17: invokestatic art/Test1966/reportValue(Ljava/lang/Object;)V
+  20: return
+.end method
+
+.method public static CastInterfaceNullMethod(Ljava/util/function/IntConsumer;)V
+  .limit stack 2
+  .limit locals 3
+  0: aconst_null
+  1: astore_1
+  2: aload_1
+  3: checkcast art/Test1966$TestInterface
+  6: astore_2
+  7: aload_0
+  8: sipush 2
+  11: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  16: aload_2
+  17: invokestatic art/Test1966/reportValue(Ljava/lang/Object;)V
+  20: return
+.end method
+
+.method public static NullMethod(Ljava/util/function/IntConsumer;)V
+  .limit stack 2
+  .limit locals 2
+  0: aconst_null
+  1: astore_1
+  2: aload_0
+  3: sipush 1
+  6: invokeinterface java/util/function/IntConsumer/accept(I)V 2
+  11: aload_1
+  12: invokestatic art/Test1966/reportValue(Ljava/lang/Object;)V
+  15: return
+.end method
diff --git a/test/1966-get-set-local-objects-no-table/run b/test/1966-get-set-local-objects-no-table/run
new file mode 100755
index 0000000..9b741ee
--- /dev/null
+++ b/test/1966-get-set-local-objects-no-table/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright 2019 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.
+
+# If we compile the .oat files non-debuggable we could end up with dex2dex running over the files
+# which will cause some instructions to be removed from smali/TestCases1966.smali. This test relies
+# on the instructions being exactly as written so pass --debuggable to 'dex2oat' only to prevent
+# this from happening.
+./default-run "$@" --jvmti --compiler-only-option --debuggable
diff --git a/test/1966-get-set-local-objects-no-table/smali/TestCases1966.smali b/test/1966-get-set-local-objects-no-table/smali/TestCases1966.smali
new file mode 100644
index 0000000..d460dcd
--- /dev/null
+++ b/test/1966-get-set-local-objects-no-table/smali/TestCases1966.smali
@@ -0,0 +1,121 @@
+# Copyright (C) 2019 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 public Lart_test/TestCases1966;
+.super Ljava/lang/Object;
+
+# direct methods
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public static CastExactMethod(Ljava/util/function/IntConsumer;)V
+    .registers 3
+    const-string v0, "ObjectMethod"
+    invoke-static {v0}, Lart/Test1966$TestClass1;->create(Ljava/lang/String;)Ljava/lang/Object;
+    move-result-object v0
+    check-cast v0, Lart/Test1966$TestClass1;
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Lart/Test1966;->reportValue(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static CastInterfaceMethod(Ljava/util/function/IntConsumer;)V
+    .registers 3
+    const-string v0, "ObjectMethod"
+    invoke-static {v0}, Lart/Test1966$TestClass1;->create(Ljava/lang/String;)Ljava/lang/Object;
+    move-result-object v0
+    check-cast v0, Lart/Test1966$TestClass1;
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Lart/Test1966;->reportValue(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static ExactClassMethod(Ljava/util/function/IntConsumer;)V
+    .registers 3
+    const-string v0, "SpecificClassMethod"
+    invoke-static {v0}, Lart/Test1966$TestClass1;->createExact(Ljava/lang/String;)Lart/Test1966$TestClass1;
+    move-result-object v0
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Lart/Test1966;->reportValue(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static InterfaceMethod(Ljava/util/function/IntConsumer;)V
+    .registers 3
+    const-string v0, "InterfaceMethod"
+    invoke-static {v0}, Lart/Test1966$TestClass1;->createInterface(Ljava/lang/String;)Lart/Test1966$TestInterface;
+    move-result-object v0
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Lart/Test1966;->reportValue(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static ObjectMethod(Ljava/util/function/IntConsumer;)V
+    .registers 3
+    const-string v0, "ObjectMethod"
+    invoke-static {v0}, Lart/Test1966$TestClass1;->create(Ljava/lang/String;)Ljava/lang/Object;
+    move-result-object v0
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Lart/Test1966;->reportValue(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static PrimitiveMethod(Ljava/util/function/IntConsumer;)V
+    .registers 3
+    const/16 v0, 0x2a
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
+    move-result-object p0
+    invoke-static {p0}, Lart/Test1966;->reportValue(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static NullMethod(Ljava/util/function/IntConsumer;)V
+    .registers 3
+    const/4 v0, 0x0
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Lart/Test1966;->reportValue(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static CastInterfaceNullMethod(Ljava/util/function/IntConsumer;)V
+    .registers 3
+    const/4 v0, 0x0
+    check-cast v0, Lart/Test1966$TestInterface;
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Lart/Test1966;->reportValue(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public static CastExactNullMethod(Ljava/util/function/IntConsumer;)V
+    .registers 3
+    const/4 v0, 0x0
+    check-cast v0, Lart/Test1966$TestClass1;
+    const/16 v1, 0x0
+    invoke-interface {p0, v1}, Ljava/util/function/IntConsumer;->accept(I)V
+    invoke-static {v0}, Lart/Test1966;->reportValue(Ljava/lang/Object;)V
+    return-void
+.end method
\ No newline at end of file
diff --git a/test/1966-get-set-local-objects-no-table/src/Main.java b/test/1966-get-set-local-objects-no-table/src/Main.java
new file mode 100644
index 0000000..198f319
--- /dev/null
+++ b/test/1966-get-set-local-objects-no-table/src/Main.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.
+ */
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    art.Test1966.run();
+  }
+}
diff --git a/test/1966-get-set-local-objects-no-table/src/art/Breakpoint.java b/test/1966-get-set-local-objects-no-table/src/art/Breakpoint.java
new file mode 120000
index 0000000..3673916
--- /dev/null
+++ b/test/1966-get-set-local-objects-no-table/src/art/Breakpoint.java
@@ -0,0 +1 @@
+../../../jvmti-common/Breakpoint.java
\ No newline at end of file
diff --git a/test/1966-get-set-local-objects-no-table/src/art/Locals.java b/test/1966-get-set-local-objects-no-table/src/art/Locals.java
new file mode 120000
index 0000000..2998386
--- /dev/null
+++ b/test/1966-get-set-local-objects-no-table/src/art/Locals.java
@@ -0,0 +1 @@
+../../../jvmti-common/Locals.java
\ No newline at end of file
diff --git a/test/1966-get-set-local-objects-no-table/src/art/StackTrace.java b/test/1966-get-set-local-objects-no-table/src/art/StackTrace.java
new file mode 120000
index 0000000..e1a08aa
--- /dev/null
+++ b/test/1966-get-set-local-objects-no-table/src/art/StackTrace.java
@@ -0,0 +1 @@
+../../../jvmti-common/StackTrace.java
\ No newline at end of file
diff --git a/test/1966-get-set-local-objects-no-table/src/art/Suspension.java b/test/1966-get-set-local-objects-no-table/src/art/Suspension.java
new file mode 120000
index 0000000..bcef96f
--- /dev/null
+++ b/test/1966-get-set-local-objects-no-table/src/art/Suspension.java
@@ -0,0 +1 @@
+../../../jvmti-common/Suspension.java
\ No newline at end of file
diff --git a/test/1966-get-set-local-objects-no-table/src/art/Test1966.java b/test/1966-get-set-local-objects-no-table/src/art/Test1966.java
new file mode 100644
index 0000000..00f3c4e
--- /dev/null
+++ b/test/1966-get-set-local-objects-no-table/src/art/Test1966.java
@@ -0,0 +1,237 @@
+/*
+ * 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.
+ */
+
+package art;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Semaphore;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+public class Test1966 {
+  public static final String TARGET_VAR = "TARGET";
+
+  public static interface TestInterface {
+    public default void doNothing() {}
+  }
+  public static class TestClass1 implements TestInterface {
+    public String id;
+    public TestClass1(String id) {
+      this.id = id;
+    }
+    public String toString() {
+      return String.format("TestClass1(\"%s\")", id);
+    }
+
+    public static TestInterface createInterface(String id) {
+      return new TestClass1(id);
+    }
+    public static TestClass1 createExact(String id) {
+      return new TestClass1(id);
+    }
+    public static Object create(String id) {
+      return new TestClass1(id);
+    }
+  }
+
+  public static class TestClass1ext extends TestClass1 {
+    public TestClass1ext(String id) {
+      super(id);
+    }
+    public String toString() {
+      return String.format("TestClass1ext(\"%s\")", super.toString());
+    }
+  }
+  public static class TestClass2 {
+    public String id;
+    public TestClass2(String id) {
+      this.id = id;
+    }
+    public String toString() {
+      return String.format("TestClass2(\"%s\")", id);
+    }
+  }
+  public static class TestClass2impl extends TestClass2 implements TestInterface {
+    public TestClass2impl(String id) {
+      super(id);
+    }
+    public String toString() {
+      return String.format("TestClass2impl(\"%s\")", super.toString());
+    }
+  }
+
+  public static void reportValue(Object val) {
+    System.out.println("\tValue is '" + val +
+                       "' (class: " + (val != null ? val.getClass() : "NULL") + ")");
+  }
+
+  public static interface SafepointFunction {
+    public void invoke(Thread thread, Method target, int slot, int depth) throws Exception;
+  }
+
+  public static interface SetterFunction {
+    public void SetVar(Thread t, int depth, int slot, Object v);
+  }
+
+  public static interface GetterFunction { public Object GetVar(Thread t, int depth, int slot); }
+
+  public static SafepointFunction
+  NamedSet(final String type, final SetterFunction get, final Object v) {
+    return new SafepointFunction() {
+      public void invoke(Thread t, Method method, int slot, int depth) {
+        try {
+          get.SetVar(t, depth, slot, v);
+          System.out.println(this + " on " + method + " set value: " + v);
+        } catch (Exception e) {
+          System.out.println(this + " on " + method + " failed to set value " + v + " due to " +
+                             e.getMessage());
+        }
+      }
+      public String toString() {
+        return "\"Set" + type + "\"";
+      }
+    };
+  }
+
+  public static SafepointFunction NamedGet(final String type, final GetterFunction get) {
+    return new SafepointFunction() {
+      public void invoke(Thread t, Method method, int slot, int depth) {
+        try {
+          Object res = get.GetVar(t, depth, slot);
+          System.out.println(this + " on " + method + " got value: " + res);
+        } catch (Exception e) {
+          System.out.println(this + " on " + method + " failed due to " + e.getMessage());
+        }
+      }
+      public String toString() {
+        return "\"Get" + type + "\"";
+      }
+    };
+  }
+
+  public static class TestCase {
+    public final Method target;
+
+    public TestCase(Method target) {
+      this.target = target;
+    }
+
+    public static class ThreadPauser implements IntConsumer {
+      public final Semaphore sem_wakeup_main;
+      public final Semaphore sem_wait;
+      public int slot = -1;
+
+      public ThreadPauser() {
+        sem_wakeup_main = new Semaphore(0);
+        sem_wait = new Semaphore(0);
+      }
+
+      public void accept(int i) {
+        try {
+          slot = i;
+          sem_wakeup_main.release();
+          sem_wait.acquire();
+        } catch (Exception e) {
+          throw new Error("Error with semaphores!", e);
+        }
+      }
+
+      public void waitForOtherThreadToPause() throws Exception {
+        sem_wakeup_main.acquire();
+      }
+
+      public void wakeupOtherThread() throws Exception {
+        sem_wait.release();
+      }
+    }
+
+    public void exec(final SafepointFunction safepoint) throws Exception {
+      System.out.println("Running " + target + " with " + safepoint + " on remote thread.");
+      final ThreadPauser pause = new ThreadPauser();
+      Thread remote = new Thread(() -> {
+        try {
+          target.invoke(null, pause);
+        } catch (Exception e) {
+          throw new Error("Error invoking remote thread " + Thread.currentThread(), e);
+        }
+      }, "remote thread for " + target + " with " + safepoint);
+      remote.start();
+      pause.waitForOtherThreadToPause();
+      try {
+        Suspension.suspend(remote);
+        StackTrace.StackFrameData frame = findStackFrame(remote);
+        safepoint.invoke(remote, target, pause.slot, frame.depth);
+      } finally {
+        Suspension.resume(remote);
+        pause.wakeupOtherThread();
+        remote.join();
+      }
+    }
+
+    private StackTrace.StackFrameData findStackFrame(Thread thr) {
+      for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(thr)) {
+        if (frame.method.equals(target)) {
+          return frame;
+        }
+      }
+      throw new Error("Unable to find stack frame in method " + target + " on thread " + thr);
+    }
+  }
+  public static Method getMethod(String name) throws Exception {
+    return Class.forName("art_test.TestCases1966").getDeclaredMethod(name, IntConsumer.class);
+  }
+
+  public static void run() throws Exception {
+    Locals.EnableLocalVariableAccess();
+    final TestCase[] MAIN_TEST_CASES = new TestCase[] {
+      new TestCase(getMethod("ObjectMethod")),
+      new TestCase(getMethod("CastInterfaceMethod")),
+      new TestCase(getMethod("CastExactMethod")),
+      new TestCase(getMethod("InterfaceMethod")),
+      new TestCase(getMethod("ExactClassMethod")),
+      new TestCase(getMethod("PrimitiveMethod")),
+      new TestCase(getMethod("NullMethod")),
+      new TestCase(getMethod("CastExactNullMethod")),
+      new TestCase(getMethod("CastInterfaceNullMethod")),
+    };
+
+    final SetterFunction set_obj = Locals::SetLocalVariableObject;
+    final SafepointFunction[] SAFEPOINTS = new SafepointFunction[] {
+      NamedGet("GetObject", Locals::GetLocalVariableObject),
+      NamedSet("Null", set_obj, null),
+      NamedSet("TestClass1", set_obj, new TestClass1("Set TestClass1")),
+      NamedSet("TestClass1ext", set_obj, new TestClass1ext("Set TestClass1ext")),
+      NamedSet("TestClass2", set_obj, new TestClass2("Set TestClass2")),
+      NamedSet("TestClass2impl", set_obj, new TestClass2impl("Set TestClass2impl")),
+    };
+
+    for (TestCase t : MAIN_TEST_CASES) {
+      for (SafepointFunction s : SAFEPOINTS) {
+        t.exec(s);
+      }
+    }
+  }
+}
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index bcd35e6..6804091 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -157,6 +157,11 @@
         fi
         ARGS="${ARGS} $1"
         shift
+    elif [ "x$1" = "x--compiler-only-option" ]; then
+        shift
+        option="$1"
+        COMPILE_FLAGS="${COMPILE_FLAGS} $option"
+        shift
     elif [ "x$1" = "x-Xcompiler-option" ]; then
         shift
         option="$1"
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 963d335..ad0cbe8 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -777,6 +777,18 @@
         "description": ["Requires zip, which isn't available on device"]
     },
     {
+        "tests": [
+          "1965-get-set-local-primitive-no-tables",
+          "1966-get-set-local-objects-no-table"
+        ],
+        "variant": "jvm",
+        "bug": "133241695",
+        "description": [
+          "The RI is wildly inconsistent about how it handles Get/SetLocalVariable when classes ",
+          "lack debug info."
+        ]
+    },
+    {
         "tests": ["683-clinit-inline-static-invoke"],
         "variant": "jvm",
         "description": ["Uses android-specific boot image class."]