Bug 1637392 - Pass base and offset when visiting typed object references r=jwalden
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 20 May 2020 10:53:58 +0000
changeset 531202 533322401d49a0ab57a7a4c2475d218cb3f10bfe
parent 531201 135acd548abffc587408d2d5f512d0595fd7d244
child 531203 e4f5894fe3fa5bf14a35c3ff35ce40b315cc38c0
push id37435
push userapavel@mozilla.com
push dateWed, 20 May 2020 15:28:23 +0000
treeherdermozilla-central@5415da14ec9a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs1637392
milestone78.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1637392 - Pass base and offset when visiting typed object references r=jwalden This removes the pointer arithetic based on nullptr, which is undefined behaviour. Differential Revision: https://phabricator.services.mozilla.com/D75274
js/src/builtin/TypedObject.cpp
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2699,45 +2699,46 @@ JS_FOR_EACH_SCALAR_BIGINT_TYPE_REPR(JS_S
 JS_FOR_EACH_SCALAR_BIGINT_TYPE_REPR(JS_LOAD_BIGINT_CLASS_IMPL)
 JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_STORE_REFERENCE_CLASS_IMPL)
 JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_LOAD_REFERENCE_CLASS_IMPL)
 
 ///////////////////////////////////////////////////////////////////////////
 // Walking memory
 
 template <typename V>
-static void visitReferences(TypeDescr& descr, uint8_t* mem, V& visitor) {
+static void VisitReferences(TypeDescr& descr, uint8_t* base, V& visitor,
+                            size_t offset) {
   if (descr.transparent()) {
     return;
   }
 
   switch (descr.kind()) {
     case type::Scalar:
       return;
 
     case type::Reference:
-      visitor.visitReference(descr.as<ReferenceTypeDescr>(), mem);
+      visitor.visitReference(descr.as<ReferenceTypeDescr>(), base, offset);
       return;
 
     case type::Array: {
       ArrayTypeDescr& arrayDescr = descr.as<ArrayTypeDescr>();
       TypeDescr& elementDescr = arrayDescr.elementType();
       for (uint32_t i = 0; i < arrayDescr.length(); i++) {
-        visitReferences(elementDescr, mem, visitor);
-        mem += elementDescr.size();
+        VisitReferences(elementDescr, base, visitor, offset);
+        offset += elementDescr.size();
       }
       return;
     }
 
     case type::Struct: {
       StructTypeDescr& structDescr = descr.as<StructTypeDescr>();
       for (size_t i = 0; i < structDescr.fieldCount(); i++) {
         TypeDescr& descr = structDescr.fieldDescr(i);
-        size_t offset = structDescr.fieldOffset(i);
-        visitReferences(descr, mem + offset, visitor);
+        VisitReferences(descr, base, visitor,
+                        offset + structDescr.fieldOffset(i));
       }
       return;
     }
   }
 
   MOZ_CRASH("Invalid type repr kind");
 }
 
@@ -2747,122 +2748,132 @@ static void visitReferences(TypeDescr& d
 namespace {
 
 class MemoryInitVisitor {
   const JSRuntime* rt_;
 
  public:
   explicit MemoryInitVisitor(const JSRuntime* rt) : rt_(rt) {}
 
-  void visitReference(ReferenceTypeDescr& descr, uint8_t* mem);
+  void visitReference(ReferenceTypeDescr& descr, uint8_t* base, size_t offset);
 };
 
 }  // namespace
 
-void MemoryInitVisitor::visitReference(ReferenceTypeDescr& descr,
-                                       uint8_t* mem) {
+void MemoryInitVisitor::visitReference(ReferenceTypeDescr& descr, uint8_t* base,
+                                       size_t offset) {
   switch (descr.type()) {
     case ReferenceType::TYPE_ANY: {
-      js::GCPtrValue* heapValue = reinterpret_cast<js::GCPtrValue*>(mem);
+      js::GCPtrValue* heapValue =
+          reinterpret_cast<js::GCPtrValue*>(base + offset);
       heapValue->init(UndefinedValue());
       return;
     }
 
     case ReferenceType::TYPE_WASM_ANYREF:
     case ReferenceType::TYPE_OBJECT: {
-      js::GCPtrObject* objectPtr = reinterpret_cast<js::GCPtrObject*>(mem);
+      js::GCPtrObject* objectPtr =
+          reinterpret_cast<js::GCPtrObject*>(base + offset);
       objectPtr->init(nullptr);
       return;
     }
 
     case ReferenceType::TYPE_STRING: {
-      js::GCPtrString* stringPtr = reinterpret_cast<js::GCPtrString*>(mem);
+      js::GCPtrString* stringPtr =
+          reinterpret_cast<js::GCPtrString*>(base + offset);
       stringPtr->init(rt_->emptyString);
       return;
     }
   }
 
   MOZ_CRASH("Invalid kind");
 }
 
 void TypeDescr::initInstance(const JSRuntime* rt, uint8_t* mem) {
   MemoryInitVisitor visitor(rt);
 
   // Initialize the instance
   memset(mem, 0, size());
   if (opaque()) {
-    visitReferences(*this, mem, visitor);
+    VisitReferences(*this, mem, visitor, 0);
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Tracing instances
 
 namespace {
 
 class MemoryTracingVisitor {
   JSTracer* trace_;
 
  public:
   explicit MemoryTracingVisitor(JSTracer* trace) : trace_(trace) {}
 
-  void visitReference(ReferenceTypeDescr& descr, uint8_t* mem);
+  void visitReference(ReferenceTypeDescr& descr, uint8_t* base, size_t offset);
 };
 
 }  // namespace
 
 void MemoryTracingVisitor::visitReference(ReferenceTypeDescr& descr,
-                                          uint8_t* mem) {
+                                          uint8_t* base, size_t offset) {
   switch (descr.type()) {
     case ReferenceType::TYPE_ANY: {
-      GCPtrValue* heapValue = reinterpret_cast<js::GCPtrValue*>(mem);
+      GCPtrValue* heapValue = reinterpret_cast<js::GCPtrValue*>(base + offset);
       TraceEdge(trace_, heapValue, "reference-val");
       return;
     }
 
     case ReferenceType::TYPE_WASM_ANYREF:
       // TODO/AnyRef-boxing: With boxed immediates and strings the tracing code
       // will be more complicated.  For now, tracing as an object is fine.
     case ReferenceType::TYPE_OBJECT: {
-      GCPtrObject* objectPtr = reinterpret_cast<js::GCPtrObject*>(mem);
+      GCPtrObject* objectPtr =
+          reinterpret_cast<js::GCPtrObject*>(base + offset);
       TraceNullableEdge(trace_, objectPtr, "reference-obj");
       return;
     }
 
     case ReferenceType::TYPE_STRING: {
-      GCPtrString* stringPtr = reinterpret_cast<js::GCPtrString*>(mem);
+      GCPtrString* stringPtr =
+          reinterpret_cast<js::GCPtrString*>(base + offset);
       TraceNullableEdge(trace_, stringPtr, "reference-str");
       return;
     }
   }
 
   MOZ_CRASH("Invalid kind");
 }
 
 void TypeDescr::traceInstance(JSTracer* trace, uint8_t* mem) {
   MemoryTracingVisitor visitor(trace);
 
-  visitReferences(*this, mem, visitor);
+  VisitReferences(*this, mem, visitor, 0);
 }
 
 namespace {
 
 struct TraceListVisitor {
-  typedef Vector<int32_t, 0, SystemAllocPolicy> VectorType;
-  VectorType stringOffsets, objectOffsets, valueOffsets;
-
-  void visitReference(ReferenceTypeDescr& descr, uint8_t* mem);
+  using OffsetVector = Vector<uint32_t, 0, SystemAllocPolicy>;
+  OffsetVector stringOffsets;
+  OffsetVector objectOffsets;
+  OffsetVector valueOffsets;
+
+  void visitReference(ReferenceTypeDescr& descr, uint8_t* base, size_t offset);
 
   bool fillList(Vector<uint32_t>& entries);
 };
 
 }  // namespace
 
-void TraceListVisitor::visitReference(ReferenceTypeDescr& descr, uint8_t* mem) {
-  VectorType* offsets;
+void TraceListVisitor::visitReference(ReferenceTypeDescr& descr, uint8_t* base,
+                                      size_t offset) {
+  MOZ_ASSERT(!base);
+
+  OffsetVector* offsets;
   // TODO/AnyRef-boxing: Once a WasmAnyRef is no longer just a JSObject*
   // we must revisit this structure.
   switch (descr.type()) {
     case ReferenceType::TYPE_ANY:
       offsets = &valueOffsets;
       break;
     case ReferenceType::TYPE_OBJECT:
       offsets = &objectOffsets;
@@ -2873,17 +2884,19 @@ void TraceListVisitor::visitReference(Re
     case ReferenceType::TYPE_STRING:
       offsets = &stringOffsets;
       break;
     default:
       MOZ_CRASH("Invalid kind");
   }
 
   AutoEnterOOMUnsafeRegion oomUnsafe;
-  if (!offsets->append((uintptr_t)mem)) {
+
+  MOZ_ASSERT(offset <= UINT32_MAX);
+  if (!offsets->append(offset)) {
     oomUnsafe.crash("TraceListVisitor::visitReference");
   }
 }
 
 bool TraceListVisitor::fillList(Vector<uint32_t>& entries) {
   return entries.append(stringOffsets.length()) &&
          entries.append(objectOffsets.length()) &&
          entries.append(valueOffsets.length()) &&
@@ -2896,17 +2909,17 @@ static bool CreateTraceList(JSContext* c
   // for larger objects, both to limit the size of the trace lists and
   // because tracing outline typed objects is considerably more complicated
   // than inline ones.
   if (!InlineTypedObject::canAccommodateType(descr) || descr->transparent()) {
     return true;
   }
 
   TraceListVisitor visitor;
-  visitReferences(*descr, nullptr, visitor);
+  VisitReferences(*descr, nullptr, visitor, 0);
 
   Vector<uint32_t> entries(cx);
   if (!visitor.fillList(entries)) {
     return false;
   }
 
   // Trace lists aren't necessary for descriptors with no references.
   MOZ_ASSERT(entries.length() >= 3);