Bug 1229399: Allow to peek into the internal wasm IR; r=luke
authorBenjamin Bouvier <benj@benj.me>
Thu, 21 Jan 2016 13:36:57 +0100
changeset 323964 9809139812ebe073b84d0fa12705062b1b50845b
parent 323963 a8b5e254799b4ba7050c2291cc3b07cf6c7ee98d
child 323965 939930dcd5556706be3d57b903eed82503a28e13
child 324333 a59befb97f314a4c8d861c2e7b94d7bdcc73aa2a
push id9816
push userdburns@mozilla.com
push dateThu, 21 Jan 2016 16:52:33 +0000
reviewersluke
bugs1229399
milestone46.0a1
Bug 1229399: Allow to peek into the internal wasm IR; r=luke
js/src/asmjs/WasmBinary.h
js/src/asmjs/WasmIonCompile.cpp
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -440,20 +440,33 @@ class Decoder
         uint8_t u8;
         if (!read(&u8))
             return false;
         *out = T(u8);
         return true;
     }
 
     template <class T>
-    T uncheckedRead() {
+    T uncheckedPeek() const {
         MOZ_ASSERT(uintptr_t(end_ - cur_) >= sizeof(T));
         T ret;
         memcpy(&ret, cur_, sizeof(T));
+        return ret;
+    }
+
+    template <class T>
+    T uncheckedPeekEnum() const {
+        // See Encoder::writeEnum.
+        static_assert(mozilla::IsEnum<T>::value, "is an enum");
+        return (T)uncheckedPeek<uint8_t>();
+    }
+
+    template <class T>
+    T uncheckedRead() {
+        T ret = uncheckedPeek<T>();
         cur_ += sizeof(T);
         return ret;
     }
 
     template <class T>
     T uncheckedReadEnum() {
         // See Encoder::writeEnum.
         static_assert(mozilla::IsEnum<T>::value, "is an enum");
@@ -563,16 +576,19 @@ class Decoder
         byte = uncheckedReadU8();
         MOZ_ASSERT(!(byte & 0xF0));
         decoded |= uint32_t(byte) << 28;
         return decoded;
     }
     Expr uncheckedReadExpr() {
         return uncheckedReadEnum<Expr>();
     }
+    Expr uncheckedPeekExpr() const {
+        return uncheckedPeekEnum<Expr>();
+    }
 };
 
 // Source coordinates for a call site. As they're read sequentially, we
 // don't need to store the call's bytecode offset, unless we want to
 // check its correctness in debug mode.
 struct SourceCoords {
     DebugOnly<size_t> offset; // after call opcode
     uint32_t line;
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -1178,16 +1178,17 @@ class FunctionCompiler
     uint32_t       readU32()    { return decoder_.uncheckedReadU32(); }
     uint32_t       readVarU32() { return decoder_.uncheckedReadVarU32(); }
     int32_t        readI32()    { return decoder_.uncheckedReadI32(); }
     float          readF32()    { return decoder_.uncheckedReadF32(); }
     double         readF64()    { return decoder_.uncheckedReadF64(); }
     SimdConstant   readI32X4()  { return decoder_.uncheckedReadI32X4(); }
     SimdConstant   readF32X4()  { return decoder_.uncheckedReadF32X4(); }
     Expr           readOpcode() { return decoder_.uncheckedReadExpr(); }
+    Expr           peekOpcode() { return decoder_.uncheckedPeekExpr(); }
 
     void readCallLineCol(uint32_t* line, uint32_t* column) {
         const SourceCoords& sc = func_.sourceCoords(lastReadCallSite_++);
         decoder_.assertCurrentIs(sc.offset);
         *line = sc.line;
         *column = sc.column;
     }
 
@@ -1286,26 +1287,30 @@ class FunctionCompiler
                 return false;
             unlabeledBreaks_.remove(p);
         }
         return true;
     }
 };
 
 // A Type or Undefined, implicitly constructed from an ExprType and usabled as
-// an ExprType. Will assert if we're trying to access the type although we
+// an ExprType. Has two functions:
+// - in debug, will ensure that the expected type and the actual type of some
+// expressions match.
+// - provides a way to mean "no type" in the context of expression statements,
+// and will provoke assertions if we're trying to use an expected type when we
 // don't have one.
 class MaybeType
 {
     Maybe<ExprType> maybe_;
     MaybeType() {}
   public:
     MOZ_IMPLICIT MaybeType(ExprType t) : maybe_() { maybe_.emplace(t); }
     static MaybeType Undefined() { return MaybeType(); }
-    operator bool() { return maybe_.isSome(); }
+    explicit operator bool() { return maybe_.isSome(); }
     MOZ_IMPLICIT operator ExprType() { return maybe_.value(); }
 };
 
 static bool
 EmitLiteral(FunctionCompiler& f, ExprType type, MDefinition**def)
 {
     switch (type) {
       case ExprType::I32: {
@@ -1363,20 +1368,18 @@ EmitLoadGlobal(FunctionCompiler& f, Mayb
 {
     uint32_t index = f.readVarU32();
     const AsmJSGlobalVariable& global = f.mg().globalVar(index);
     *def = f.loadGlobalVar(global.globalDataOffset, global.isConst, ToMIRType(global.type));
     MOZ_ASSERT_IF(type, global.type == type);
     return true;
 }
 
-static bool EmitExpr(FunctionCompiler&, MaybeType, Expr, MDefinition**, LabelVector* = nullptr);
 static bool EmitExpr(FunctionCompiler&, MaybeType, MDefinition**, LabelVector* = nullptr);
 static bool EmitExprStmt(FunctionCompiler&, MDefinition**, LabelVector* = nullptr);
-static bool EmitExprStmt(FunctionCompiler&, Expr, MDefinition**, LabelVector* = nullptr);
 static bool EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition** def);
 
 static bool
 EmitLoadArray(FunctionCompiler& f, Scalar::Type scalarType, MDefinition** def)
 {
     NeedsBoundsCheck needsBoundsCheck = NeedsBoundsCheck(f.readU8());
     MDefinition* ptr;
     if (!EmitExpr(f, ExprType::I32, &ptr))
@@ -2442,28 +2445,25 @@ EmitIfElse(FunctionCompiler& f, bool has
         return false;
 
     if (!f.appendThenBlock(&thenBlocks))
         return false;
 
     if (hasElse) {
         f.switchToElse(elseOrJoinBlock);
 
-        Expr nextStmt(f.readOpcode());
-        if (nextStmt == Expr::If) {
-            hasElse = false;
-            goto recurse;
-        }
-        if (nextStmt == Expr::IfElse) {
-            hasElse = true;
+        Expr nextStmt = f.peekOpcode();
+        if (nextStmt == Expr::If || nextStmt == Expr::IfElse) {
+            hasElse = nextStmt == Expr::IfElse;
+            JS_ALWAYS_TRUE(f.readOpcode() == nextStmt);
             goto recurse;
         }
 
         MDefinition* _;
-        if (!EmitExprStmt(f, nextStmt, &_))
+        if (!EmitExprStmt(f, &_))
             return false;
 
         return f.joinIfElse(thenBlocks);
     } else {
         return f.joinIf(thenBlocks, elseOrJoinBlock);
     }
 }
 
@@ -2561,22 +2561,22 @@ EmitBreak(FunctionCompiler& f, bool hasL
 {
     if (!hasLabel)
         return f.addBreak(nullptr);
     uint32_t labelId = f.readU32();
     return f.addBreak(&labelId);
 }
 
 static bool
-EmitExpr(FunctionCompiler& f, MaybeType type, Expr op, MDefinition** def, LabelVector* maybeLabels)
+EmitExpr(FunctionCompiler& f, MaybeType type, MDefinition** def, LabelVector* maybeLabels)
 {
     if (!f.mirGen().ensureBallast())
         return false;
 
-    switch (op) {
+    switch (Expr op = f.readOpcode()) {
       case Expr::Nop:
         return true;
       case Expr::Block:
         return EmitBlock(f, type, def);
       case Expr::If:
       case Expr::IfElse:
         return EmitIfElse(f, HasElseBlock(op == Expr::IfElse));
       case Expr::TableSwitch:
@@ -2932,31 +2932,19 @@ EmitExpr(FunctionCompiler& f, MaybeType 
       case Expr::Unreachable:
         break;
     }
 
     MOZ_CRASH("unexpected wasm opcode");
 }
 
 static bool
-EmitExpr(FunctionCompiler& f, MaybeType type, MDefinition** def, LabelVector* maybeLabels)
-{
-    return EmitExpr(f, type, f.readOpcode(), def, maybeLabels);
-}
-
-static bool
-EmitExprStmt(FunctionCompiler& f, Expr op, MDefinition** def, LabelVector* maybeLabels)
-{
-    return EmitExpr(f, MaybeType::Undefined(), op, def, maybeLabels);
-}
-
-static bool
 EmitExprStmt(FunctionCompiler& f, MDefinition** def, LabelVector* maybeLabels)
 {
-    return EmitExprStmt(f, f.readOpcode(), def, maybeLabels);
+    return EmitExpr(f, MaybeType::Undefined(), def, maybeLabels);
 }
 
 bool
 wasm::IonCompileFunction(IonCompileTask* task)
 {
     int64_t before = PRMJ_Now();
 
     const FuncBytecode& func = task->func();