[ptr-compr] Introduce StrongTaggedValue and TaggedValue

... which represent potentially compressed Object and MaybeObject
values respectively. They provide methods for checking the smi/weak
tags which don't require decompression and conversion to Smi/HeapObject
combined with tag checks.

The new classes should help to write a bit more efficient runtime (C++)
code for the cases when we don't need the full decompressed value
immediately.

Drive-by-fix: fix ptr-compr build after Object::operator->() removal.

Bug: v8:7703
Change-Id: I7a3d747ab6679120a2cca14e45b0d8bcf33fc496
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1624786
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61804}
diff --git a/BUILD.gn b/BUILD.gn
index b9149e3..029a66a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -2628,6 +2628,8 @@
     "src/objects/tagged-impl-inl.h",
     "src/objects/tagged-impl.cc",
     "src/objects/tagged-impl.h",
+    "src/objects/tagged-value-inl.h",
+    "src/objects/tagged-value.h",
     "src/objects/template-objects-inl.h",
     "src/objects/template-objects.cc",
     "src/objects/template-objects.h",
diff --git a/src/execution/frames.cc b/src/execution/frames.cc
index 4eef4aa..cff51de 100644
--- a/src/execution/frames.cc
+++ b/src/execution/frames.cc
@@ -977,9 +977,7 @@
                          parameters_limit);
   }
 
-#ifdef V8_COMPRESS_POINTERS
-  Address isolate_root = isolate()->isolate_root();
-#endif
+  DEFINE_ROOT_VALUE(isolate());
   // Visit pointer spill slots and locals.
   for (unsigned index = 0; index < stack_slots; index++) {
     int byte_index = index >> kBitsPerByteLog2;
@@ -998,8 +996,7 @@
       if (!HAS_SMI_TAG(compressed_value)) {
         // We don't need to update smi values.
         *spill_slot.location() =
-            DecompressTaggedPointer<OnHeapAddressKind::kIsolateRoot>(
-                isolate_root, compressed_value);
+            DecompressTaggedPointer(ROOT_VALUE, compressed_value);
       }
 #endif
       v->VisitRootPointer(Root::kTop, nullptr, spill_slot);
diff --git a/src/globals.h b/src/globals.h
index c5a1525..229123a 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -212,6 +212,15 @@
 
 STATIC_ASSERT(kSystemPointerSize == (1 << kSystemPointerSizeLog2));
 
+// This macro is used for declaring and defining HeapObject getter methods that
+// are a bit more efficient for the pointer compression case than the default
+// parameterless getters because isolate root doesn't have to be computed from
+// arbitrary field address but it comes "for free" instead.
+// These alternatives are always defined (in order to avoid #ifdef mess but
+// are not supposed to be used when pointer compression is not enabled.
+#define ROOT_VALUE isolate_for_root
+#define ROOT_PARAM Isolate* const ROOT_VALUE
+
 #ifdef V8_COMPRESS_POINTERS
 static_assert(
     kSystemPointerSize == kInt64Size,
@@ -225,6 +234,11 @@
 using Tagged_t = int32_t;
 using AtomicTagged_t = base::Atomic32;
 
+#define DEFINE_ROOT_VALUE(isolate) ROOT_PARAM = isolate
+#define WITH_ROOT_PARAM(...) ROOT_PARAM, ##__VA_ARGS__
+#define WITH_ROOT_VALUE(...) ROOT_VALUE, ##__VA_ARGS__
+#define WITH_ROOT(isolate_for_root, ...) isolate_for_root, ##__VA_ARGS__
+
 #else
 
 constexpr int kTaggedSize = kSystemPointerSize;
@@ -235,6 +249,11 @@
 using Tagged_t = Address;
 using AtomicTagged_t = base::AtomicWord;
 
+#define DEFINE_ROOT_VALUE(isolate)
+#define WITH_ROOT_PARAM(...) __VA_ARGS__
+#define WITH_ROOT_VALUE(...) __VA_ARGS__
+#define WITH_ROOT(isolate_for_root, ...) __VA_ARGS__
+
 #endif  // V8_COMPRESS_POINTERS
 
 // Defines whether the branchless or branchful implementation of pointer
@@ -614,6 +633,8 @@
 class Object;
 template <HeapObjectReferenceType kRefType, typename StorageType>
 class TaggedImpl;
+class StrongTaggedValue;
+class TaggedValue;
 class CompressedObjectSlot;
 class CompressedMaybeObjectSlot;
 class CompressedMapWordSlot;
diff --git a/src/objects-body-descriptors-inl.h b/src/objects-body-descriptors-inl.h
index 6009f6b..b08c7ca 100644
--- a/src/objects-body-descriptors-inl.h
+++ b/src/objects-body-descriptors-inl.h
@@ -41,7 +41,7 @@
 #ifdef V8_COMPRESS_POINTERS
   STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
   int embedder_fields_offset = JSObject::GetEmbedderFieldsStartOffset(map);
-  int inobject_fields_offset = map->GetInObjectPropertyOffset(0);
+  int inobject_fields_offset = map.GetInObjectPropertyOffset(0);
   // |embedder_fields_offset| may be greater than |inobject_fields_offset| if
   // the object does not have embedder fields but the check handles this
   // case properly.
@@ -77,7 +77,7 @@
 #ifdef V8_COMPRESS_POINTERS
   STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
   int header_size = JSObject::GetHeaderSize(map);
-  int inobject_fields_offset = map->GetInObjectPropertyOffset(0);
+  int inobject_fields_offset = map.GetInObjectPropertyOffset(0);
   // We are always requested to process header and embedder fields.
   DCHECK_LE(inobject_fields_offset, end_offset);
   // Embedder fields are located between header and inobject properties.
diff --git a/src/objects/compressed-slots-inl.h b/src/objects/compressed-slots-inl.h
index 9c55de9..70638e0 100644
--- a/src/objects/compressed-slots-inl.h
+++ b/src/objects/compressed-slots-inl.h
@@ -28,7 +28,7 @@
 }
 
 void CompressedObjectSlot::store(Object value) const {
-  *location() = CompressTagged(value->ptr());
+  *location() = CompressTagged(value.ptr());
 }
 
 Object CompressedObjectSlot::Acquire_Load() const {
@@ -42,19 +42,19 @@
 }
 
 void CompressedObjectSlot::Relaxed_Store(Object value) const {
-  Tagged_t ptr = CompressTagged(value->ptr());
+  Tagged_t ptr = CompressTagged(value.ptr());
   AsAtomicTagged::Relaxed_Store(location(), ptr);
 }
 
 void CompressedObjectSlot::Release_Store(Object value) const {
-  Tagged_t ptr = CompressTagged(value->ptr());
+  Tagged_t ptr = CompressTagged(value.ptr());
   AsAtomicTagged::Release_Store(location(), ptr);
 }
 
 Object CompressedObjectSlot::Release_CompareAndSwap(Object old,
                                                     Object target) const {
-  Tagged_t old_ptr = CompressTagged(old->ptr());
-  Tagged_t target_ptr = CompressTagged(target->ptr());
+  Tagged_t old_ptr = CompressTagged(old.ptr());
+  Tagged_t target_ptr = CompressTagged(target.ptr());
   Tagged_t result =
       AsAtomicTagged::Release_CompareAndSwap(location(), old_ptr, target_ptr);
   return Object(DecompressTaggedAny(address(), result));
@@ -95,14 +95,14 @@
 }
 
 void CompressedMapWordSlot::Release_Store(Object value) const {
-  Tagged_t ptr = CompressTagged(value->ptr());
+  Tagged_t ptr = CompressTagged(value.ptr());
   AsAtomicTagged::Release_Store(location(), ptr);
 }
 
 Object CompressedMapWordSlot::Release_CompareAndSwap(Object old,
                                                      Object target) const {
-  Tagged_t old_ptr = CompressTagged(old->ptr());
-  Tagged_t target_ptr = CompressTagged(target->ptr());
+  Tagged_t old_ptr = CompressTagged(old.ptr());
+  Tagged_t target_ptr = CompressTagged(target.ptr());
   Tagged_t result =
       AsAtomicTagged::Release_CompareAndSwap(location(), old_ptr, target_ptr);
   return Object(DecompressTaggedPointer(address(), result));
@@ -118,7 +118,7 @@
 }
 
 void CompressedMaybeObjectSlot::store(MaybeObject value) const {
-  *location() = CompressTagged(value->ptr());
+  *location() = CompressTagged(value.ptr());
 }
 
 MaybeObject CompressedMaybeObjectSlot::Relaxed_Load() const {
@@ -127,14 +127,14 @@
 }
 
 void CompressedMaybeObjectSlot::Relaxed_Store(MaybeObject value) const {
-  Tagged_t ptr = CompressTagged(value->ptr());
+  Tagged_t ptr = CompressTagged(value.ptr());
   AsAtomicTagged::Relaxed_Store(location(), ptr);
 }
 
 void CompressedMaybeObjectSlot::Release_CompareAndSwap(
     MaybeObject old, MaybeObject target) const {
-  Tagged_t old_ptr = CompressTagged(old->ptr());
-  Tagged_t target_ptr = CompressTagged(target->ptr());
+  Tagged_t old_ptr = CompressTagged(old.ptr());
+  Tagged_t target_ptr = CompressTagged(target.ptr());
   AsAtomicTagged::Release_CompareAndSwap(location(), old_ptr, target_ptr);
 }
 
@@ -158,7 +158,7 @@
 }
 
 void CompressedHeapObjectSlot::StoreHeapObject(HeapObject value) const {
-  *location() = CompressTagged(value->ptr());
+  *location() = CompressTagged(value.ptr());
 }
 
 }  // namespace internal
diff --git a/src/objects/elements.cc b/src/objects/elements.cc
index a08f1c5..f2a5998 100644
--- a/src/objects/elements.cc
+++ b/src/objects/elements.cc
@@ -476,8 +476,9 @@
   AtomicSlot end(start + sort_size);
   std::sort(start, end, [isolate](Tagged_t elementA, Tagged_t elementB) {
 #ifdef V8_COMPRESS_POINTERS
-    Object a(DecompressTaggedAny(isolate->isolate_root(), elementA));
-    Object b(DecompressTaggedAny(isolate->isolate_root(), elementB));
+    DEFINE_ROOT_VALUE(isolate);
+    Object a(DecompressTaggedAny(ROOT_VALUE, elementA));
+    Object b(DecompressTaggedAny(ROOT_VALUE, elementB));
 #else
     Object a(elementA);
     Object b(elementB);
diff --git a/src/objects/tagged-impl-inl.h b/src/objects/tagged-impl-inl.h
index 83437e3..a1b91e9 100644
--- a/src/objects/tagged-impl-inl.h
+++ b/src/objects/tagged-impl-inl.h
@@ -12,6 +12,8 @@
 #endif
 #include "src/objects/heap-object.h"
 #include "src/objects/smi.h"
+#include "src/ptr-compr-inl.h"
+#include "src/roots-inl.h"
 
 namespace v8 {
 namespace internal {
@@ -19,7 +21,7 @@
 template <HeapObjectReferenceType kRefType, typename StorageType>
 bool TaggedImpl<kRefType, StorageType>::ToSmi(Smi* value) const {
   if (HAS_SMI_TAG(ptr_)) {
-    *value = Smi::cast(Object(ptr_));
+    *value = ToSmi();
     return true;
   }
   return false;
@@ -28,12 +30,21 @@
 template <HeapObjectReferenceType kRefType, typename StorageType>
 Smi TaggedImpl<kRefType, StorageType>::ToSmi() const {
   DCHECK(HAS_SMI_TAG(ptr_));
-  return Smi::cast(Object(ptr_));
+  if (kIsFull) {
+    return Smi(ptr_);
+  }
+  // Implementation for compressed pointers.
+  return Smi(DecompressTaggedSigned(static_cast<Tagged_t>(ptr_)));
 }
 
+//
+// TaggedImpl::GetHeapObject(HeapObject* result) implementation.
+//
+
 template <HeapObjectReferenceType kRefType, typename StorageType>
 bool TaggedImpl<kRefType, StorageType>::GetHeapObject(
     HeapObject* result) const {
+  CHECK(kIsFull);
   if (!IsStrongOrWeak()) return false;
   *result = GetHeapObject();
   return true;
@@ -41,7 +52,24 @@
 
 template <HeapObjectReferenceType kRefType, typename StorageType>
 bool TaggedImpl<kRefType, StorageType>::GetHeapObject(
+    ROOT_PARAM, HeapObject* result) const {
+  if (kIsFull) return GetHeapObject(result);
+  // Implementation for compressed pointers.
+  if (!IsStrongOrWeak()) return false;
+  *result = GetHeapObject(ROOT_VALUE);
+  return true;
+}
+
+//
+// TaggedImpl::GetHeapObject(HeapObject* result,
+//                           HeapObjectReferenceType* reference_type)
+// implementation.
+//
+
+template <HeapObjectReferenceType kRefType, typename StorageType>
+bool TaggedImpl<kRefType, StorageType>::GetHeapObject(
     HeapObject* result, HeapObjectReferenceType* reference_type) const {
+  CHECK(kIsFull);
   if (!IsStrongOrWeak()) return false;
   *reference_type = IsWeakOrCleared() ? HeapObjectReferenceType::WEAK
                                       : HeapObjectReferenceType::STRONG;
@@ -50,8 +78,26 @@
 }
 
 template <HeapObjectReferenceType kRefType, typename StorageType>
+bool TaggedImpl<kRefType, StorageType>::GetHeapObject(
+    ROOT_PARAM, HeapObject* result,
+    HeapObjectReferenceType* reference_type) const {
+  if (kIsFull) return GetHeapObject(result, reference_type);
+  // Implementation for compressed pointers.
+  if (!IsStrongOrWeak()) return false;
+  *reference_type = IsWeakOrCleared() ? HeapObjectReferenceType::WEAK
+                                      : HeapObjectReferenceType::STRONG;
+  *result = GetHeapObject(ROOT_VALUE);
+  return true;
+}
+
+//
+// TaggedImpl::GetHeapObjectIfStrong(HeapObject* result) implementation.
+//
+
+template <HeapObjectReferenceType kRefType, typename StorageType>
 bool TaggedImpl<kRefType, StorageType>::GetHeapObjectIfStrong(
     HeapObject* result) const {
+  CHECK(kIsFull);
   if (IsStrong()) {
     *result = HeapObject::cast(Object(ptr_));
     return true;
@@ -60,15 +106,47 @@
 }
 
 template <HeapObjectReferenceType kRefType, typename StorageType>
+bool TaggedImpl<kRefType, StorageType>::GetHeapObjectIfStrong(
+    ROOT_PARAM, HeapObject* result) const {
+  if (kIsFull) return GetHeapObjectIfStrong(result);
+  // Implementation for compressed pointers.
+  if (IsStrong()) {
+    *result =
+        HeapObject::cast(Object(DecompressTaggedPointer(ROOT_VALUE, ptr_)));
+    return true;
+  }
+  return false;
+}
+
+//
+// TaggedImpl::GetHeapObjectAssumeStrong() implementation.
+//
+
+template <HeapObjectReferenceType kRefType, typename StorageType>
 HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObjectAssumeStrong()
     const {
+  CHECK(kIsFull);
   DCHECK(IsStrong());
   return HeapObject::cast(Object(ptr_));
 }
 
 template <HeapObjectReferenceType kRefType, typename StorageType>
+HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObjectAssumeStrong(
+    ROOT_PARAM) const {
+  if (kIsFull) return GetHeapObjectAssumeStrong();
+  // Implementation for compressed pointers.
+  DCHECK(IsStrong());
+  return HeapObject::cast(Object(DecompressTaggedPointer(ROOT_VALUE, ptr_)));
+}
+
+//
+// TaggedImpl::GetHeapObjectIfWeak(HeapObject* result) implementation
+//
+
+template <HeapObjectReferenceType kRefType, typename StorageType>
 bool TaggedImpl<kRefType, StorageType>::GetHeapObjectIfWeak(
     HeapObject* result) const {
+  CHECK(kIsFull);
   if (kCanBeWeak) {
     if (IsWeak()) {
       *result = GetHeapObject();
@@ -82,13 +160,49 @@
 }
 
 template <HeapObjectReferenceType kRefType, typename StorageType>
+bool TaggedImpl<kRefType, StorageType>::GetHeapObjectIfWeak(
+    ROOT_PARAM, HeapObject* result) const {
+  if (kIsFull) return GetHeapObjectIfWeak(result);
+  // Implementation for compressed pointers.
+  if (kCanBeWeak) {
+    if (IsWeak()) {
+      *result = GetHeapObject(ROOT_VALUE);
+      return true;
+    }
+    return false;
+  } else {
+    DCHECK(!HAS_WEAK_HEAP_OBJECT_TAG(ptr_));
+    return false;
+  }
+}
+
+//
+// TaggedImpl::GetHeapObjectAssumeWeak() implementation.
+//
+
+template <HeapObjectReferenceType kRefType, typename StorageType>
 HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObjectAssumeWeak() const {
+  CHECK(kIsFull);
   DCHECK(IsWeak());
   return GetHeapObject();
 }
 
 template <HeapObjectReferenceType kRefType, typename StorageType>
+HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObjectAssumeWeak(
+    ROOT_PARAM) const {
+  if (kIsFull) return GetHeapObjectAssumeWeak();
+  // Implementation for compressed pointers.
+  DCHECK(IsWeak());
+  return GetHeapObject(ROOT_VALUE);
+}
+
+//
+// TaggedImpl::GetHeapObject() implementation.
+//
+
+template <HeapObjectReferenceType kRefType, typename StorageType>
 HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObject() const {
+  CHECK(kIsFull);
   DCHECK(!IsSmi());
   if (kCanBeWeak) {
     DCHECK(!IsCleared());
@@ -100,13 +214,43 @@
 }
 
 template <HeapObjectReferenceType kRefType, typename StorageType>
+HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObject(ROOT_PARAM) const {
+  if (kIsFull) return GetHeapObject();
+  // Implementation for compressed pointers.
+  DCHECK(!IsSmi());
+  if (kCanBeWeak) {
+    DCHECK(!IsCleared());
+    return HeapObject::cast(Object(
+        DecompressTaggedPointer(ROOT_VALUE, ptr_ & ~kWeakHeapObjectMask)));
+  } else {
+    DCHECK(!HAS_WEAK_HEAP_OBJECT_TAG(ptr_));
+    return HeapObject::cast(Object(DecompressTaggedPointer(ROOT_VALUE, ptr_)));
+  }
+}
+
+//
+// TaggedImpl::GetHeapObjectOrSmi() implementation.
+//
+
+template <HeapObjectReferenceType kRefType, typename StorageType>
 Object TaggedImpl<kRefType, StorageType>::GetHeapObjectOrSmi() const {
+  CHECK(kIsFull);
   if (IsSmi()) {
     return Object(ptr_);
   }
   return GetHeapObject();
 }
 
+template <HeapObjectReferenceType kRefType, typename StorageType>
+Object TaggedImpl<kRefType, StorageType>::GetHeapObjectOrSmi(ROOT_PARAM) const {
+  if (kIsFull) return GetHeapObjectOrSmi();
+  // Implementation for compressed pointers.
+  if (IsSmi()) {
+    return Object(DecompressTaggedSigned(ptr_));
+  }
+  return GetHeapObject(ROOT_VALUE);
+}
+
 }  // namespace internal
 }  // namespace v8
 
diff --git a/src/objects/tagged-impl.h b/src/objects/tagged-impl.h
index 8e62cf5..8802698 100644
--- a/src/objects/tagged-impl.h
+++ b/src/objects/tagged-impl.h
@@ -23,6 +23,15 @@
 template <HeapObjectReferenceType kRefType, typename StorageType>
 class TaggedImpl {
  public:
+  static_assert(std::is_same<StorageType, Address>::value ||
+                    std::is_same<StorageType, Tagged_t>::value,
+                "StorageType must be either Address or Tagged_t");
+
+  // True for those TaggedImpl instantiations that represent uncompressed
+  // tagged values and false for TaggedImpl instantiations that represent
+  // compressed tagged values.
+  static const bool kIsFull = sizeof(StorageType) == kSystemPointerSize;
+
   static const bool kCanBeWeak = kRefType == HeapObjectReferenceType::WEAK;
 
   constexpr TaggedImpl() : ptr_{} {}
@@ -88,38 +97,57 @@
     return kCanBeWeak && HAS_WEAK_HEAP_OBJECT_TAG(ptr_);
   }
 
+  //
+  // The following set of methods get HeapObject out of the tagged value
+  // which may involve decompression in which case the ROOT_PARAM is required.
+  // If the pointer compression is not enabled then the variants with
+  // ROOT_PARAM will be exactly the same as non-ROOT_PARAM ones.
+  //
+
   // If this tagged value is a strong pointer to a HeapObject, returns true and
   // sets *result. Otherwise returns false.
   inline bool GetHeapObjectIfStrong(HeapObject* result) const;
+  inline bool GetHeapObjectIfStrong(ROOT_PARAM, HeapObject* result) const;
 
   // DCHECKs that this tagged value is a strong pointer to a HeapObject and
   // returns the HeapObject.
   inline HeapObject GetHeapObjectAssumeStrong() const;
+  inline HeapObject GetHeapObjectAssumeStrong(ROOT_PARAM) const;
 
   // If this tagged value is a weak pointer to a HeapObject, returns true and
   // sets *result. Otherwise returns false.
   inline bool GetHeapObjectIfWeak(HeapObject* result) const;
+  inline bool GetHeapObjectIfWeak(ROOT_PARAM, HeapObject* result) const;
 
   // DCHECKs that this tagged value is a weak pointer to a HeapObject and
   // returns the HeapObject.
   inline HeapObject GetHeapObjectAssumeWeak() const;
+  inline HeapObject GetHeapObjectAssumeWeak(ROOT_PARAM) const;
 
   // If this tagged value is a strong or weak pointer to a HeapObject, returns
   // true and sets *result. Otherwise returns false.
   inline bool GetHeapObject(HeapObject* result) const;
+  inline bool GetHeapObject(ROOT_PARAM, HeapObject* result) const;
+
   inline bool GetHeapObject(HeapObject* result,
                             HeapObjectReferenceType* reference_type) const;
+  inline bool GetHeapObject(ROOT_PARAM, HeapObject* result,
+                            HeapObjectReferenceType* reference_type) const;
 
   // DCHECKs that this tagged value is a strong or a weak pointer to a
   // HeapObject and returns the HeapObject.
   inline HeapObject GetHeapObject() const;
+  inline HeapObject GetHeapObject(ROOT_PARAM) const;
 
   // DCHECKs that this tagged value is a strong or a weak pointer to a
   // HeapObject or a Smi and returns the HeapObject or Smi.
   inline Object GetHeapObjectOrSmi() const;
+  inline Object GetHeapObjectOrSmi(ROOT_PARAM) const;
 
+  // Cast operation is available only for full non-weak tagged values.
   template <typename T>
   T cast() const {
+    CHECK(kIsFull);
     DCHECK(!HAS_WEAK_HEAP_OBJECT_TAG(ptr_));
     return T::cast(Object(ptr_));
   }
diff --git a/src/objects/tagged-value-inl.h b/src/objects/tagged-value-inl.h
new file mode 100644
index 0000000..2569fa9
--- /dev/null
+++ b/src/objects/tagged-value-inl.h
@@ -0,0 +1,39 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_OBJECTS_TAGGED_VALUE_INL_H_
+#define V8_OBJECTS_TAGGED_VALUE_INL_H_
+
+#include "src/objects/tagged-value.h"
+
+#include "include/v8-internal.h"
+#include "src/objects/heap-object-inl.h"
+#include "src/objects/oddball.h"
+#include "src/objects/tagged-impl-inl.h"
+#include "src/ptr-compr-inl.h"
+#include "src/roots-inl.h"
+
+namespace v8 {
+namespace internal {
+
+Object StrongTaggedValue::ToObject(WITH_ROOT_PARAM(StrongTaggedValue object)) {
+#ifdef V8_COMPRESS_POINTERS
+  return Object(DecompressTaggedAny(ROOT_VALUE, object.ptr()));
+#else
+  return Object(object.ptr());
+#endif
+}
+
+MaybeObject TaggedValue::ToMaybeObject(WITH_ROOT_PARAM(TaggedValue object)) {
+#ifdef V8_COMPRESS_POINTERS
+  return MaybeObject(DecompressTaggedAny(ROOT_VALUE, object.ptr()));
+#else
+  return MaybeObject(object.ptr());
+#endif
+}
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_OBJECTS_TAGGED_VALUE_INL_H_
diff --git a/src/objects/tagged-value.h b/src/objects/tagged-value.h
new file mode 100644
index 0000000..bb7609f
--- /dev/null
+++ b/src/objects/tagged-value.h
@@ -0,0 +1,42 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_OBJECTS_TAGGED_VALUE_H_
+#define V8_OBJECTS_TAGGED_VALUE_H_
+
+#include "src/objects/objects.h"
+
+#include "include/v8-internal.h"
+#include "src/objects/tagged-impl.h"
+
+namespace v8 {
+namespace internal {
+
+// Almost same as Object but this one deals with in-heap and potentially
+// compressed representation of Objects and provide only limited functionality
+// which doesn't require decompression.
+class StrongTaggedValue
+    : public TaggedImpl<HeapObjectReferenceType::STRONG, Tagged_t> {
+ public:
+  constexpr StrongTaggedValue() : TaggedImpl() {}
+  explicit constexpr StrongTaggedValue(Tagged_t ptr) : TaggedImpl(ptr) {}
+
+  inline static Object ToObject(WITH_ROOT_PARAM(StrongTaggedValue object));
+};
+
+// Almost same as MaybeObject but this one deals with in-heap and potentially
+// compressed representation of Objects and provide only limited functionality
+// which doesn't require decompression.
+class TaggedValue : public TaggedImpl<HeapObjectReferenceType::WEAK, Tagged_t> {
+ public:
+  constexpr TaggedValue() : TaggedImpl() {}
+  explicit constexpr TaggedValue(Tagged_t ptr) : TaggedImpl(ptr) {}
+
+  inline static MaybeObject ToMaybeObject(WITH_ROOT_PARAM(TaggedValue object));
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_OBJECTS_TAGGED_VALUE_H_
diff --git a/src/ptr-compr-inl.h b/src/ptr-compr-inl.h
index 98f94b3..d05650f 100644
--- a/src/ptr-compr-inl.h
+++ b/src/ptr-compr-inl.h
@@ -5,8 +5,8 @@
 #ifndef V8_PTR_COMPR_INL_H_
 #define V8_PTR_COMPR_INL_H_
 
-
 #include "include/v8-internal.h"
+#include "src/execution/isolate.h"
 #include "src/ptr-compr.h"
 
 namespace v8 {
@@ -19,34 +19,49 @@
   return static_cast<Tagged_t>(static_cast<uint32_t>(tagged));
 }
 
-enum class OnHeapAddressKind {
-  kAnyOnHeapAddress,
-  kIsolateRoot,
-};
-
 // Calculates isolate root value from any on-heap address.
-template <OnHeapAddressKind kAddressKind = OnHeapAddressKind::kAnyOnHeapAddress>
-V8_INLINE Address GetRootFromOnHeapAddress(Address on_heap_addr) {
-  if (kAddressKind == OnHeapAddressKind::kIsolateRoot) return on_heap_addr;
-  return RoundDown(on_heap_addr + kPtrComprIsolateRootBias,
-                   kPtrComprIsolateRootAlignment);
+template <typename TOnHeapAddress>
+V8_INLINE Address GetIsolateRoot(TOnHeapAddress on_heap_addr);
+
+template <>
+V8_INLINE Address GetIsolateRoot<Address>(Address on_heap_addr) {
+  return RoundDown<kPtrComprIsolateRootAlignment>(on_heap_addr +
+                                                  kPtrComprIsolateRootBias);
+}
+
+template <>
+V8_INLINE Address GetIsolateRoot<Isolate*>(Isolate* isolate) {
+  return isolate->isolate_root();
+}
+
+template <>
+V8_INLINE Address GetIsolateRoot<const Isolate*>(const Isolate* isolate) {
+  return isolate->isolate_root();
+}
+
+// Decompresses smi value.
+V8_INLINE Address DecompressTaggedSigned(Tagged_t raw_value) {
+  // Current compression scheme requires |raw_value| to be sign-extended
+  // from int32_t to intptr_t.
+  intptr_t value = static_cast<intptr_t>(static_cast<int32_t>(raw_value));
+  return static_cast<Address>(value);
 }
 
 // Decompresses weak or strong heap object pointer or forwarding pointer,
 // preserving both weak- and smi- tags.
-template <OnHeapAddressKind kAddressKind = OnHeapAddressKind::kAnyOnHeapAddress>
-V8_INLINE Address DecompressTaggedPointer(Address on_heap_addr,
+template <typename TOnHeapAddress>
+V8_INLINE Address DecompressTaggedPointer(TOnHeapAddress on_heap_addr,
                                           Tagged_t raw_value) {
   // Current compression scheme requires |raw_value| to be sign-extended
   // from int32_t to intptr_t.
   intptr_t value = static_cast<intptr_t>(static_cast<int32_t>(raw_value));
-  Address root = GetRootFromOnHeapAddress<kAddressKind>(on_heap_addr);
+  Address root = GetIsolateRoot(on_heap_addr);
   return root + static_cast<Address>(value);
 }
 
 // Decompresses any tagged value, preserving both weak- and smi- tags.
-template <OnHeapAddressKind kAddressKind = OnHeapAddressKind::kAnyOnHeapAddress>
-V8_INLINE Address DecompressTaggedAny(Address on_heap_addr,
+template <typename TOnHeapAddress>
+V8_INLINE Address DecompressTaggedAny(TOnHeapAddress on_heap_addr,
                                       Tagged_t raw_value) {
   // Current compression scheme requires |raw_value| to be sign-extended
   // from int32_t to intptr_t.
@@ -54,14 +69,12 @@
   if (kUseBranchlessPtrDecompression) {
     // |root_mask| is 0 if the |value| was a smi or -1 otherwise.
     Address root_mask = static_cast<Address>(-(value & kSmiTagMask));
-    Address root_or_zero =
-        root_mask & GetRootFromOnHeapAddress<kAddressKind>(on_heap_addr);
+    Address root_or_zero = root_mask & GetIsolateRoot(on_heap_addr);
     return root_or_zero + static_cast<Address>(value);
   } else {
     return HAS_SMI_TAG(value)
                ? static_cast<Address>(value)
-               : (GetRootFromOnHeapAddress<kAddressKind>(on_heap_addr) +
-                  static_cast<Address>(value));
+               : (GetIsolateRoot(on_heap_addr) + static_cast<Address>(value));
   }
 }
 
@@ -79,6 +92,20 @@
 
 V8_INLINE Tagged_t CompressTagged(Address tagged) { UNREACHABLE(); }
 
+V8_INLINE Address DecompressTaggedSigned(Tagged_t raw_value) { UNREACHABLE(); }
+
+template <typename TOnHeapAddress>
+V8_INLINE Address DecompressTaggedPointer(TOnHeapAddress on_heap_addr,
+                                          Tagged_t raw_value) {
+  UNREACHABLE();
+}
+
+template <typename TOnHeapAddress>
+V8_INLINE Address DecompressTaggedAny(TOnHeapAddress on_heap_addr,
+                                      Tagged_t raw_value) {
+  UNREACHABLE();
+}
+
 #endif  // V8_TARGET_ARCH_64_BIT
 }  // namespace internal
 }  // namespace v8
diff --git a/src/x64/assembler-x64-inl.h b/src/x64/assembler-x64-inl.h
index 0370ef9..07b4baf 100644
--- a/src/x64/assembler-x64-inl.h
+++ b/src/x64/assembler-x64-inl.h
@@ -326,11 +326,10 @@
 HeapObject RelocInfo::target_object_no_host(Isolate* isolate) {
   DCHECK(IsCodeTarget(rmode_) || IsEmbeddedObjectMode(rmode_));
   if (IsCompressedEmbeddedObject(rmode_)) {
-    Address root = isolate->isolate_root();
-    Object o = static_cast<Object>(
-        DecompressTaggedPointer<OnHeapAddressKind::kIsolateRoot>(
-            root, ReadUnalignedValue<Tagged_t>(pc_)));
-    return HeapObject::cast(o);
+    Tagged_t compressed = ReadUnalignedValue<Tagged_t>(pc_);
+    DCHECK(!HAS_SMI_TAG(compressed));
+    Object obj(DecompressTaggedPointer(isolate, compressed));
+    return HeapObject::cast(obj);
   }
   return HeapObject::cast(Object(ReadUnalignedValue<Address>(pc_)));
 }
@@ -377,10 +376,9 @@
                                   ICacheFlushMode icache_flush_mode) {
   DCHECK(IsCodeTarget(rmode_) || IsEmbeddedObjectMode(rmode_));
   if (IsCompressedEmbeddedObject(rmode_)) {
-#ifdef V8_COMPRESS_POINTERS
-    Tagged_t tagged = CompressTagged(target->ptr());
+    DCHECK(COMPRESS_POINTERS_BOOL);
+    Tagged_t tagged = CompressTagged(target.ptr());
     WriteUnalignedValue(pc_, tagged);
-#endif  // V8_COMPRESS_POINTERS
   } else {
     WriteUnalignedValue(pc_, target.ptr());
   }