Bug 1465999 - Add ExpressionStatementEmitter. r=Waldo
authorTooru Fujisawa <arai_a@mac.com>
Tue, 09 Oct 2018 21:23:11 +0900
changeset 498909 1be0907510b948b7ba0693dc8410d1348e88e5c5
parent 498908 57d01ae278bcd80324b86a04b8736fc040320c3f
child 498910 0ed41dadd8cff2a4f9585dc250a6fcf1995a193c
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1465999
milestone64.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 1465999 - Add ExpressionStatementEmitter. r=Waldo
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/ExpressionStatementEmitter.cpp
js/src/frontend/ExpressionStatementEmitter.h
js/src/frontend/ValueUsage.h
js/src/moz.build
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -23,16 +23,17 @@
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "ds/Nestable.h"
 #include "frontend/BytecodeControlStructures.h"
 #include "frontend/CForEmitter.h"
 #include "frontend/DoWhileEmitter.h"
 #include "frontend/EmitterScope.h"
+#include "frontend/ExpressionStatementEmitter.h"
 #include "frontend/ForInEmitter.h"
 #include "frontend/ForOfEmitter.h"
 #include "frontend/ForOfLoopControl.h"
 #include "frontend/IfEmitter.h"
 #include "frontend/Parser.h"
 #include "frontend/SwitchEmitter.h"
 #include "frontend/TDZCheckCache.h"
 #include "frontend/TryEmitter.h"
@@ -6754,26 +6755,26 @@ BytecodeEmitter::emitExpressionStatement
             innermostNestableControl->is<LabelControl>() &&
             innermostNestableControl->as<LabelControl>().startOffset() >= offset())
         {
             useful = true;
         }
     }
 
     if (useful) {
-        JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP;
+        MOZ_ASSERT_IF(expr->isKind(ParseNodeKind::Assign), expr->isOp(JSOP_NOP));
         ValueUsage valueUsage = wantval ? ValueUsage::WantValue : ValueUsage::IgnoreValue;
-        MOZ_ASSERT_IF(expr->isKind(ParseNodeKind::Assign), expr->isOp(JSOP_NOP));
-        if (!updateSourceCoordNotes(exprStmt->pn_pos.begin)) {
+        ExpressionStatementEmitter ese(this, valueUsage);
+        if (!ese.prepareForExpr(Some(exprStmt->pn_pos.begin))) {
             return false;
         }
         if (!emitTree(expr, valueUsage)) {
             return false;
         }
-        if (!emit1(op)) {
+        if (!ese.emitEnd()) {
             return false;
         }
     } else if (exprStmt->isDirectivePrologueMember()) {
         // Don't complain about directive prologue members; just don't emit
         // their code.
     } else {
         if (JSAtom* atom = exprStmt->isStringExprStatement()) {
             // Warn if encountering a non-directive prologue member string
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -14,16 +14,17 @@
 
 #include "ds/InlineTable.h"
 #include "frontend/BCEParserHandle.h"
 #include "frontend/EitherParser.h"
 #include "frontend/JumpList.h"
 #include "frontend/NameFunctions.h"
 #include "frontend/SharedContext.h"
 #include "frontend/SourceNotes.h"
+#include "frontend/ValueUsage.h"
 #include "vm/BytecodeUtil.h"
 #include "vm/Interpreter.h"
 #include "vm/Iteration.h"
 
 namespace js {
 namespace frontend {
 
 class CGNumberList {
@@ -104,28 +105,16 @@ struct CGYieldAndAwaitOffsetList {
     void finish(mozilla::Span<uint32_t> array, uint32_t prologueLength);
 };
 
 // Have a few inline elements, so as to avoid heap allocation for tiny
 // sequences.  See bug 1390526.
 typedef Vector<jsbytecode, 64> BytecodeVector;
 typedef Vector<jssrcnote, 64> SrcNotesVector;
 
-// Used to control whether JSOP_CALL_IGNORES_RV is emitted for function calls.
-enum class ValueUsage {
-    // Assume the value of the current expression may be used. This is always
-    // correct but prohibits JSOP_CALL_IGNORES_RV.
-    WantValue,
-
-    // Pass this when emitting an expression if the expression's value is
-    // definitely unused by later instructions. You must make sure the next
-    // instruction is JSOP_POP, a jump to a JSOP_POP, or something similar.
-    IgnoreValue
-};
-
 class EmitterScope;
 class NestableControl;
 class TDZCheckCache;
 
 struct MOZ_STACK_CLASS BytecodeEmitter
 {
     SharedContext* const sc;      /* context shared between parsing and bytecode generation */
 
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/ExpressionStatementEmitter.cpp
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "frontend/ExpressionStatementEmitter.h"
+
+#include "frontend/BytecodeEmitter.h"
+#include "vm/Opcodes.h"
+
+using namespace js;
+using namespace js::frontend;
+
+using mozilla::Maybe;
+
+ExpressionStatementEmitter::ExpressionStatementEmitter(BytecodeEmitter* bce,
+                                                       ValueUsage valueUsage)
+  : bce_(bce),
+    valueUsage_(valueUsage)
+{}
+
+bool
+ExpressionStatementEmitter::prepareForExpr(const Maybe<uint32_t>& beginPos)
+{
+    MOZ_ASSERT(state_ == State::Start);
+
+    if (beginPos) {
+        if (!bce_->updateSourceCoordNotes(*beginPos)) {
+            return false;
+        }
+    }
+
+#ifdef DEBUG
+    depth_ = bce_->stackDepth;
+    state_ = State::Expr;
+#endif
+    return true;
+}
+
+bool
+ExpressionStatementEmitter::emitEnd()
+{
+    MOZ_ASSERT(state_ == State::Expr);
+    MOZ_ASSERT(bce_->stackDepth == depth_ + 1);
+
+    JSOp op = valueUsage_ == ValueUsage::WantValue ? JSOP_SETRVAL : JSOP_POP;
+    if (!bce_->emit1(op)) {
+        return false;
+    }
+
+#ifdef DEBUG
+    state_ = State::End;
+#endif
+    return true;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/ExpressionStatementEmitter.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef frontend_ExpressionStatementEmitter_h
+#define frontend_ExpressionStatementEmitter_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Maybe.h"
+
+#include <stdint.h>
+
+#include "frontend/ValueUsage.h"
+
+namespace js {
+namespace frontend {
+
+struct BytecodeEmitter;
+
+// Class for emitting bytecode for expression statement.
+//
+// Usage: (check for the return value is omitted for simplicity)
+//
+//   `expr;`
+//     // IgnoreValue if this is in normal script.
+//     // WantValue if this is in eval script.
+//     ValueUsage valueUsage = ...;
+//
+//     ExpressionStatementEmitter ese(this, valueUsage);
+//     ese.prepareForExpr(Some(offset_of_expr));
+//     emit(expr);
+//     ese.emitEnd();
+//
+class MOZ_STACK_CLASS ExpressionStatementEmitter
+{
+    BytecodeEmitter* bce_;
+
+#ifdef DEBUG
+    // The stack depth before emitting expression.
+    int32_t depth_;
+#endif
+
+    // The usage of the value of the expression.
+    ValueUsage valueUsage_;
+
+#ifdef DEBUG
+    // The state of this emitter.
+    //
+    // +-------+ prepareForExpr +------+ emitEnd +-----+
+    // | Start |--------------->| Expr |-------->| End |
+    // +-------+                +------+         +-----+
+    enum class State
+    {
+        // The initial state.
+        Start,
+
+        // After calling prepareForExpr.
+        Expr,
+
+        // After calling emitEnd.
+        End
+    };
+    State state_ = State::Start;
+#endif
+
+  public:
+    ExpressionStatementEmitter(BytecodeEmitter* bce, ValueUsage valueUsage);
+
+    // Parameters are the offset in the source code for each character below:
+    //
+    //   expr;
+    //   ^
+    //   |
+    //   beginPos
+    //
+    // Can be Nothing() if not available.
+    MOZ_MUST_USE bool prepareForExpr(const mozilla::Maybe<uint32_t>& beginPos);
+    MOZ_MUST_USE bool emitEnd();
+};
+
+} // namespace frontend
+} // namespace js
+
+#endif /* frontend_ExpressionStatementEmitter_h */
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/ValueUsage.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef frontend_ValueUsage_h
+#define frontend_ValueUsage_h
+
+namespace js {
+namespace frontend {
+
+// Used to control whether JSOP_CALL_IGNORES_RV is emitted for function calls.
+enum class ValueUsage {
+    // Assume the value of the current expression may be used. This is always
+    // correct but prohibits JSOP_CALL_IGNORES_RV.
+    WantValue,
+
+    // Pass this when emitting an expression if the expression's value is
+    // definitely unused by later instructions. You must make sure the next
+    // instruction is JSOP_POP, a jump to a JSOP_POP, or something similar.
+    IgnoreValue
+};
+
+} /* namespace frontend */
+} /* namespace js */
+
+#endif /* frontend_ValueUsage_h */
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -224,16 +224,17 @@ UNIFIED_SOURCES += [
     'ds/LifoAlloc.cpp',
     'ds/MemoryProtectionExceptionHandler.cpp',
     'frontend/BytecodeCompiler.cpp',
     'frontend/BytecodeControlStructures.cpp',
     'frontend/BytecodeEmitter.cpp',
     'frontend/CForEmitter.cpp',
     'frontend/DoWhileEmitter.cpp',
     'frontend/EmitterScope.cpp',
+    'frontend/ExpressionStatementEmitter.cpp',
     'frontend/FoldConstants.cpp',
     'frontend/ForInEmitter.cpp',
     'frontend/ForOfEmitter.cpp',
     'frontend/ForOfLoopControl.cpp',
     'frontend/IfEmitter.cpp',
     'frontend/JumpList.cpp',
     'frontend/NameFunctions.cpp',
     'frontend/ParseNode.cpp',