Bug 1462104: Add magic bits to ICStub and verify them before tracing r=tcampbell
authorIain Ireland <iireland@mozilla.com>
Mon, 08 Apr 2019 13:08:21 +0000
changeset 468361 7ae898cd5fa7d588df0042cd12a42dcecb4cc4ba
parent 468360 cb98b130573d272d2f3ba4fd6a33499137f381ba
child 468362 dc07d7bcb95768783d3fbb7f0141fa834cc2f2e0
push id35835
push useraciure@mozilla.com
push dateMon, 08 Apr 2019 19:00:29 +0000
treeherdermozilla-central@40456af7da1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1462104
milestone68.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 1462104: Add magic bits to ICStub and verify them before tracing r=tcampbell Differential Revision: https://phabricator.services.mozilla.com/D25864
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -576,16 +576,18 @@ bool ICStub::makesGCCalls() const {
 void ICStub::updateCode(JitCode* code) {
   // Write barrier on the old code.
   JitCode::writeBarrierPre(jitCode());
   stubCode_ = code->raw();
 }
 
 /* static */
 void ICStub::trace(JSTracer* trc) {
+  checkTraceMagic();
+
   // Fallback stubs use runtime-wide trampoline code we don't need to trace.
   if (!usesTrampolineCode()) {
     JitCode* stubJitCode = jitCode();
     TraceManuallyBarrieredEdge(trc, &stubJitCode, "baseline-ic-stub-code");
   }
 
   // If the stub is a monitored fallback stub, then trace the monitor ICs
   // hanging off of that stub.  We don't need to worry about the regular
@@ -979,16 +981,17 @@ void ICFallbackStub::unlinkStub(Zone* zo
     // pointer when purgeOptimizedStubs destroys all optimized monitor
     // stubs (unlinked stubs won't be updated).
     ICTypeMonitor_Fallback* monitorFallback =
         toMonitoredFallbackStub()->maybeFallbackMonitorStub();
     MOZ_ASSERT(monitorFallback);
     stub->toMonitoredStub()->resetFirstMonitorStub(monitorFallback);
   }
 
+  stub->checkTraceMagic();
 #ifdef DEBUG
   // Poison stub code to ensure we don't call this stub again. However, if
   // this stub can make calls, a pointer to it may be stored in a stub frame
   // on the stack, so we can't touch the stubCode_ or GC will crash when
   // tracing this pointer.
   if (!stub->makesGCCalls()) {
     stub->stubCode_ = (uint8_t*)0xbad;
   }
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -463,17 +463,17 @@ class ICStubIterator {
 
 //
 // Base class for all IC stubs.
 //
 class ICStub {
   friend class ICFallbackStub;
 
  public:
-  enum Kind {
+  enum Kind : uint16_t {
     INVALID = 0,
 #define DEF_ENUM_KIND(kindName) kindName,
     IC_BASELINE_STUB_KIND_LIST(DEF_ENUM_KIND)
 #undef DEF_ENUM_KIND
         LIMIT
   };
 
   static bool IsValidKind(Kind k) { return (k > INVALID) && (k < LIMIT); }
@@ -489,27 +489,29 @@ class ICStub {
     return #kindName;
       IC_BASELINE_STUB_KIND_LIST(DEF_KIND_STR)
 #undef DEF_KIND_STR
       default:
         MOZ_CRASH("Invalid kind.");
     }
   }
 
-  enum Trait {
+  enum Trait : uint16_t {
     Regular = 0x0,
     Fallback = 0x1,
     Monitored = 0x2,
     MonitoredFallback = 0x3,
     Updated = 0x4
   };
 
   void updateCode(JitCode* stubCode);
   void trace(JSTracer* trc);
 
+  static const uint16_t EXPECTED_TRACE_MAGIC = 0b1100011;
+
   template <typename T, typename... Args>
   static T* New(JSContext* cx, ICStubSpace* space, JitCode* code,
                 Args&&... args) {
     if (!code) {
       return nullptr;
     }
     T* result = space->allocate<T>(code, std::forward<Args>(args)...);
     if (!result) {
@@ -529,60 +531,78 @@ class ICStub {
   }
 
  protected:
   // The raw jitcode to call for this stub.
   uint8_t* stubCode_;
 
   // Pointer to next IC stub.  This is null for the last IC stub, which should
   // either be a fallback or inert IC stub.
-  ICStub* next_;
+  ICStub* next_ = nullptr;
 
   // A 16-bit field usable by subtypes of ICStub for subtype-specific small-info
-  uint16_t extra_;
-
-  // The kind of the stub.
-  //  High bit is 'isFallback' flag.
-  //  Second high bit is 'isMonitored' flag.
-  Trait trait_ : 3;
-  Kind kind_ : 13;
-
-  inline ICStub(Kind kind, uint8_t* stubCode)
-      : stubCode_(stubCode),
-        next_(nullptr),
-        extra_(0),
-        trait_(Regular),
-        kind_(kind) {
+  uint16_t extra_ = 0;
+
+  // A 16-bit field storing the trait and kind.
+  // Unused bits are filled with a magic value and verified when tracing.
+  uint16_t traitKindBits_;
+
+  static const uint16_t TRAIT_OFFSET = 0;
+  static const uint16_t TRAIT_BITS = 3;
+  static const uint16_t TRAIT_MASK = (1 << TRAIT_BITS) - 1;
+  static const uint16_t KIND_OFFSET = TRAIT_OFFSET + TRAIT_BITS;
+  static const uint16_t KIND_BITS = 6;
+  static const uint16_t KIND_MASK = (1 << KIND_BITS) - 1;
+  static const uint16_t MAGIC_OFFSET = KIND_OFFSET + KIND_BITS;
+  static const uint16_t MAGIC_BITS = 7;
+  static const uint16_t MAGIC_MASK = (1 << MAGIC_BITS) - 1;
+  static const uint16_t EXPECTED_MAGIC = 0b1100011;
+
+  static_assert(LIMIT <= (1 << KIND_BITS), "Not enough kind bits");
+  static_assert(LIMIT > (1 << (KIND_BITS - 1)), "Too many kind bits");
+  static_assert(TRAIT_BITS + KIND_BITS + MAGIC_BITS == 16, "Unused bits");
+
+  inline ICStub(Kind kind, uint8_t* stubCode) : stubCode_(stubCode) {
+    setTraitKind(Regular, kind);
     MOZ_ASSERT(stubCode != nullptr);
   }
 
   inline ICStub(Kind kind, JitCode* stubCode) : ICStub(kind, stubCode->raw()) {
     MOZ_ASSERT(stubCode != nullptr);
   }
 
   inline ICStub(Kind kind, Trait trait, uint8_t* stubCode)
-      : stubCode_(stubCode),
-        next_(nullptr),
-        extra_(0),
-        trait_(trait),
-        kind_(kind) {
+      : stubCode_(stubCode) {
+    setTraitKind(trait, kind);
     MOZ_ASSERT(stubCode != nullptr);
   }
+
   inline ICStub(Kind kind, Trait trait, JitCode* stubCode)
       : ICStub(kind, trait, stubCode->raw()) {
     MOZ_ASSERT(stubCode != nullptr);
   }
 
   inline Trait trait() const {
-    // Workaround for MSVC reading trait_ as signed value.
-    return (Trait)(trait_ & 0x7);
+    return (Trait)((traitKindBits_ >> TRAIT_OFFSET) & TRAIT_MASK);
+  }
+
+  inline void setTraitKind(Trait trait, Kind kind) {
+    traitKindBits_ = (trait << TRAIT_OFFSET) | (kind << KIND_OFFSET) |
+                     (EXPECTED_MAGIC << MAGIC_OFFSET);
+  }
+
+  inline void checkTraceMagic() {
+    uint16_t magic = (traitKindBits_ >> MAGIC_OFFSET) & MAGIC_MASK;
+    MOZ_DIAGNOSTIC_ASSERT(magic == EXPECTED_MAGIC);
   }
 
  public:
-  inline Kind kind() const { return static_cast<Kind>(kind_); }
+  inline Kind kind() const {
+    return (Kind)((traitKindBits_ >> KIND_OFFSET) & KIND_MASK);
+  }
 
   inline bool isFallback() const {
     return trait() == Fallback || trait() == MonitoredFallback;
   }
 
   inline bool isMonitored() const { return trait() == Monitored; }
 
   inline bool isUpdated() const { return trait() == Updated; }