Bug 1501576 - Add LabelEmitter. r=jwalden
authorTooru Fujisawa <arai_a@mac.com>
Fri, 18 Jan 2019 11:52:33 +0900
changeset 514390 fa2cc1a9e81f5646a4f550b1eed01dce465542ac
parent 514389 b2ed817b75234cbc7f40355ca4e01542a618e16f
child 514391 fe634797760796afcba95f49d9288c34f3de4865
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs1501576
milestone66.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 1501576 - Add LabelEmitter. r=jwalden
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/LabelEmitter.cpp
js/src/frontend/LabelEmitter.h
js/src/frontend/moz.build
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -32,16 +32,17 @@
 #include "frontend/DoWhileEmitter.h"
 #include "frontend/ElemOpEmitter.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/LabelEmitter.h"  // LabelEmitter
 #include "frontend/ModuleSharedContext.h"
 #include "frontend/NameOpEmitter.h"
 #include "frontend/ParseNode.h"
 #include "frontend/Parser.h"
 #include "frontend/PropOpEmitter.h"
 #include "frontend/SwitchEmitter.h"
 #include "frontend/TDZCheckCache.h"
 #include "frontend/TryEmitter.h"
@@ -7493,43 +7494,25 @@ MOZ_NEVER_INLINE bool BytecodeEmitter::e
     default:
       return emitNameIncDec(incDec);
   }
 }
 
 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
 // the comment on emitSwitch.
 MOZ_NEVER_INLINE bool BytecodeEmitter::emitLabeledStatement(
-    const LabeledStatement* pn) {
-  /*
-   * Emit a JSOP_LABEL instruction. The argument is the offset to the statement
-   * following the labeled statement.
-   */
-  uint32_t index;
-  if (!makeAtomIndex(pn->label(), &index)) {
-    return false;
-  }
-
-  JumpList top;
-  if (!emitJump(JSOP_LABEL, &top)) {
-    return false;
-  }
-
-  /* Emit code for the labeled statement. */
-  LabelControl controlInfo(this, pn->label(), offset());
-
-  if (!emitTree(pn->statement())) {
-    return false;
-  }
-
-  /* Patch the JSOP_LABEL offset. */
-  JumpTarget brk{lastNonJumpTargetOffset()};
-  patchJumpsToTarget(top, brk);
-
-  if (!controlInfo.patchBreaks(this)) {
+    const LabeledStatement* labeledStmt) {
+  LabelEmitter label(this);
+  if (!label.emitLabel(labeledStmt->label())) {
+    return false;
+  }
+  if (!emitTree(labeledStmt->statement())) {
+    return false;
+  }
+  if (!label.emitEnd()) {
     return false;
   }
 
   return true;
 }
 
 bool BytecodeEmitter::emitConditionalExpression(
     ConditionalExpression& conditional,
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -682,17 +682,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
   MOZ_MUST_USE bool emitElemOp(PropertyByValue* elem, JSOp op);
   MOZ_MUST_USE bool emitElemIncDec(UnaryNode* incDec);
 
   MOZ_MUST_USE bool emitCatch(BinaryNode* catchClause);
   MOZ_MUST_USE bool emitIf(TernaryNode* ifNode);
   MOZ_MUST_USE bool emitWith(BinaryNode* withNode);
 
   MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLabeledStatement(
-      const LabeledStatement* pn);
+      const LabeledStatement* labeledStmt);
   MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLexicalScope(
       LexicalScopeNode* lexicalScope);
   MOZ_MUST_USE bool emitLexicalScopeBody(
       ParseNode* body, EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
   MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(SwitchStatement* switchStmt);
   MOZ_NEVER_INLINE MOZ_MUST_USE bool emitTry(TryNode* tryNode);
 
   MOZ_MUST_USE bool emitGoSub(JumpList* jump);
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/LabelEmitter.cpp
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * 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/LabelEmitter.h"
+
+#include "mozilla/Assertions.h"  // MOZ_ASSERT
+
+#include "frontend/BytecodeEmitter.h"  // BytecodeEmitter
+#include "vm/Opcodes.h"                // JSOP_*
+
+using namespace js;
+using namespace js::frontend;
+
+bool LabelEmitter::emitLabel(JSAtom* name) {
+  MOZ_ASSERT(state_ == State::Start);
+
+  // Emit a JSOP_LABEL instruction. The operand is the offset to the
+  // statement following the labeled statement.
+  uint32_t index;
+  if (!bce_->makeAtomIndex(name, &index)) {
+    return false;
+  }
+  if (!bce_->emitJump(JSOP_LABEL, &top_)) {
+    return false;
+  }
+
+  controlInfo_.emplace(bce_, name, bce_->offset());
+
+#ifdef DEBUG
+  state_ = State::Label;
+#endif
+  return true;
+}
+
+bool LabelEmitter::emitEnd() {
+  MOZ_ASSERT(state_ == State::Label);
+
+  // Patch the JSOP_LABEL offset.
+  JumpTarget brk{bce_->lastNonJumpTargetOffset()};
+  bce_->patchJumpsToTarget(top_, brk);
+
+  // Patch the break/continue to this label.
+  if (!controlInfo_->patchBreaks(bce_)) {
+    return false;
+  }
+
+  controlInfo_.reset();
+
+#ifdef DEBUG
+  state_ = State::End;
+#endif
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/LabelEmitter.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * 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_LabelEmitter_h
+#define frontend_LabelEmitter_h
+
+#include "mozilla/Attributes.h"  // MOZ_MUST_USE, MOZ_STACK_CLASS
+#include "mozilla/Maybe.h"       // Maybe
+
+#include "frontend/BytecodeControlStructures.h"  // LabelControl
+#include "frontend/JumpList.h"                   // JumpList
+
+class JSAtom;
+
+namespace js {
+namespace frontend {
+
+struct BytecodeEmitter;
+
+// Class for emitting labeled statement.
+//
+// Usage: (check for the return value is omitted for simplicity)
+//
+//   `label: expr;`
+//     LabelEmitter le(this);
+//     le.emitLabel(name_of_label);
+//     emit(expr);
+//     le.emitEnd();
+//
+class MOZ_STACK_CLASS LabelEmitter {
+  BytecodeEmitter* bce_;
+
+  // The offset of the JSOP_LABEL.
+  JumpList top_;
+
+  mozilla::Maybe<LabelControl> controlInfo_;
+
+#ifdef DEBUG
+  // The state of this emitter.
+  //
+  // +-------+ emitLabel +-------+ emitEnd +-----+
+  // | Start |---------->| Label |-------->| End |
+  // +-------+           +-------+         +-----+
+  enum class State {
+    // The initial state.
+    Start,
+
+    // After calling emitLabel.
+    Label,
+
+    // After calling emitEnd.
+    End
+  };
+  State state_ = State::Start;
+#endif
+
+ public:
+  explicit LabelEmitter(BytecodeEmitter* bce) : bce_(bce) {}
+
+  MOZ_MUST_USE bool emitLabel(JSAtom* name);
+  MOZ_MUST_USE bool emitEnd();
+};
+
+} /* namespace frontend */
+} /* namespace js */
+
+#endif /* frontend_LabelEmitter_h */
--- a/js/src/frontend/moz.build
+++ b/js/src/frontend/moz.build
@@ -36,16 +36,17 @@ UNIFIED_SOURCES += [
     'EmitterScope.cpp',
     'ExpressionStatementEmitter.cpp',
     'FoldConstants.cpp',
     'ForInEmitter.cpp',
     'ForOfEmitter.cpp',
     'ForOfLoopControl.cpp',
     'IfEmitter.cpp',
     'JumpList.cpp',
+    'LabelEmitter.cpp',
     'NameFunctions.cpp',
     'NameOpEmitter.cpp',
     'ParseContext.cpp',
     'ParseNode.cpp',
     'PropOpEmitter.cpp',
     'SharedContext.cpp',
     'SwitchEmitter.cpp',
     'TDZCheckCache.cpp',