Bug 1624793 part 1 - Simplify MThrow and IonBuilder::visitThrow. r=iain
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 26 Mar 2020 08:29:50 +0000
changeset 520480 f0a1f1eade8b279ed64881620b509aaf7fc5b366
parent 520479 fff410e32a31f0849fc3d65048ed07d32fa12a08
child 520481 635cc9ec177ccc0d0f6dbd3c60a87318b7e6f3d4
push id37252
push usermalexandru@mozilla.com
push dateThu, 26 Mar 2020 15:34:27 +0000
treeherdermozilla-central@31360ced8ff8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersiain
bugs1624793
milestone76.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 1624793 part 1 - Simplify MThrow and IonBuilder::visitThrow. r=iain The changes: * Make MThrow a non-control-instruction (followed by the MUnreachable control instruction). * This allows us to remove the separate MNop and attach the resume point to MThrow itself. * WarpBuilder only allows resumeAfter() on effectful instructions, so make sure MThrow isEffectful() by giving it a store AliasSet. Differential Revision: https://phabricator.services.mozilla.com/D68164
js/src/jit/AliasAnalysis.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/MIR.h
--- a/js/src/jit/AliasAnalysis.cpp
+++ b/js/src/jit/AliasAnalysis.cpp
@@ -145,16 +145,17 @@ static inline const MDefinition* GetObje
     case MDefinition::Opcode::HomeObjectSuperBase:
       object = ins->getOperand(0);
       break;
     case MDefinition::Opcode::GetPropertyCache:
     case MDefinition::Opcode::CallGetProperty:
     case MDefinition::Opcode::GetDOMProperty:
     case MDefinition::Opcode::GetDOMMember:
     case MDefinition::Opcode::Call:
+    case MDefinition::Opcode::Throw:
     case MDefinition::Opcode::GetArgumentsObjectArg:
     case MDefinition::Opcode::SetArgumentsObjectArg:
     case MDefinition::Opcode::CompareExchangeTypedArrayElement:
     case MDefinition::Opcode::AtomicExchangeTypedArrayElement:
     case MDefinition::Opcode::AtomicTypedArrayElementBinop:
     case MDefinition::Opcode::AsmJSLoadHeap:
     case MDefinition::Opcode::AsmJSStoreHeap:
     case MDefinition::Opcode::WasmHeapBase:
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -3324,52 +3324,22 @@ AbortReasonOr<Ok> IonBuilder::visitRetur
   setTerminatedBlock();
 
   return Ok();
 }
 
 AbortReasonOr<Ok> IonBuilder::visitThrow() {
   MDefinition* def = current->pop();
 
-  // MThrow is not marked as effectful. This means when it throws and we
-  // are inside a try block, we could use an earlier resume point and this
-  // resume point may not be up-to-date, for example:
-  //
-  // (function() {
-  //     try {
-  //         var x = 1;
-  //         foo(); // resume point
-  //         x = 2;
-  //         throw foo;
-  //     } catch(e) {
-  //         print(x);
-  //     }
-  // ])();
-  //
-  // If we use the resume point after the call, this will print 1 instead
-  // of 2. To fix this, we create a resume point right before the MThrow.
-  //
-  // Note that this is not a problem for instructions other than MThrow
-  // because they are either marked as effectful (have their own resume
-  // point) or cannot throw a catchable exception.
-  //
-  // We always install this resume point (instead of only when the function
-  // has a try block) in order to handle the Debugger onExceptionUnwind
-  // hook. When we need to handle the hook, we bail out to baseline right
-  // after the throw and propagate the exception when debug mode is on. This
-  // is opposed to the normal behavior of resuming directly in the
-  // associated catch block.
-  MNop* nop = MNop::New(alloc());
-  current->add(nop);
-
-  MOZ_TRY(resumeAfter(nop));
-
   MThrow* ins = MThrow::New(alloc(), def);
-  current->end(ins);
-
+  current->add(ins);
+  MOZ_TRY(resumeAfter(ins));
+
+  // Terminate the block.
+  current->end(MUnreachable::New(alloc()));
   setTerminatedBlock();
 
   return Ok();
 }
 
 AbortReasonOr<Ok> IonBuilder::visitTableSwitch() {
   jsbytecode* defaultpc = pc + GET_JUMP_OFFSET(pc);
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -356,20 +356,28 @@ class AliasSet {
     WasmGlobalVar = 1 << 6,   // An asm.js/wasm private global var
     WasmHeap = 1 << 7,        // An asm.js/wasm heap load
     WasmHeapMeta = 1 << 8,    // The asm.js/wasm heap base pointer and
                               // bounds check limit, in Tls.
     TypedArrayLengthOrOffset = 1 << 9,  // A typed array's length or byteOffset
     WasmGlobalCell = 1 << 10,           // A wasm global cell
     WasmTableElement = 1 << 11,         // An element of a wasm table
     WasmStackResult = 1 << 12,  // A stack result from the current function
-    Last = WasmStackResult,
+
+    // JSContext's exception state. This is used on instructions like MThrow
+    // that throw exceptions (other than OOM) but have no other side effect, to
+    // ensure that they get their own up-to-date resume point. (This resume
+    // point will be used when constructing the Baseline frame during exception
+    // bailouts.)
+    ExceptionState = 1 << 13,
+
+    Last = ExceptionState,
     Any = Last | (Last - 1),
 
-    NumCategories = 13,
+    NumCategories = 14,
 
     // Indicates load or store.
     Store_ = 1 << 31
   };
 
   static_assert((1 << NumCategories) - 1 == Any,
                 "NumCategories must include all flags present in Any");
 
@@ -1969,27 +1977,26 @@ class MReturn : public MAryControlInstru
  public:
   INSTRUCTION_HEADER(Return)
   TRIVIAL_NEW_WRAPPERS
   NAMED_OPERANDS((0, input))
 
   AliasSet getAliasSet() const override { return AliasSet::None(); }
 };
 
-class MThrow : public MAryControlInstruction<1, 0>,
-               public BoxInputsPolicy::Data {
-  explicit MThrow(MDefinition* ins) : MAryControlInstruction(classOpcode) {
-    initOperand(0, ins);
-  }
+class MThrow : public MUnaryInstruction, public BoxInputsPolicy::Data {
+  explicit MThrow(MDefinition* ins) : MUnaryInstruction(classOpcode, ins) {}
 
  public:
   INSTRUCTION_HEADER(Throw)
   TRIVIAL_NEW_WRAPPERS
 
-  virtual AliasSet getAliasSet() const override { return AliasSet::None(); }
+  virtual AliasSet getAliasSet() const override {
+    return AliasSet::Store(AliasSet::ExceptionState);
+  }
   bool possiblyCalls() const override { return true; }
 };
 
 // Fabricate a type set containing only the type of the specified object.
 TemporaryTypeSet* MakeSingletonTypeSet(TempAllocator& alloc,
                                        CompilerConstraintList* constraints,
                                        JSObject* obj);