author | Eric Faust <efaustbmo@gmail.com> |
Fri, 27 Apr 2018 15:02:31 -0700 | |
changeset 416157 | e4ce5e759df5b08bfc1bf5f5f5f4892cf46b0dad |
parent 416156 | 60bdf6086590f974614e0b1d202ff4849f5a2c45 |
child 416158 | abedb29f91fd6b736ed109dcefad1951450c7271 |
push id | 33917 |
push user | apavel@mozilla.com |
push date | Sat, 28 Apr 2018 17:30:55 +0000 |
treeherder | mozilla-central@08f68e2c892c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | Waldo |
bugs | 1451826 |
milestone | 61.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
|
--- a/js/src/frontend/BCEParserHandle.h +++ b/js/src/frontend/BCEParserHandle.h @@ -9,17 +9,17 @@ #include "frontend/ErrorReporter.h" #include "frontend/FullParseHandler.h" #include "frontend/Parser.h" namespace js { namespace frontend { -class BCEParserHandle { +struct BCEParserHandle { virtual ErrorReporter& errorReporter() = 0; virtual const ErrorReporter& errorReporter() const = 0; virtual const JS::ReadOnlyCompileOptions& options() = 0; virtual FullParseHandler& astGenerator() = 0; virtual ObjectBox* newObjectBox(JSObject *obj) = 0; };
--- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -2135,29 +2135,29 @@ class ForOfLoopControl : public LoopCont if (!bce->emit1(JSOP_POP)) // return false; } return true; } }; + BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent, - const EitherParser& parser, SharedContext* sc, - HandleScript script, Handle<LazyScript*> lazyScript, + SharedContext* sc, HandleScript script, + Handle<LazyScript*> lazyScript, uint32_t lineNum, EmitterMode emitterMode) : sc(sc), cx(sc->context), parent(parent), script(cx, script), lazyScript(cx, lazyScript), prologue(cx, lineNum), main(cx, lineNum), current(&main), - parser(parser), atomIndices(cx->frontendCollectionPool()), firstLine(lineNum), maxFixedSlots(0), maxStackDepth(0), stackDepth(0), emitLevel(0), bodyScopeIndex(UINT32_MAX), varEmitterScope(nullptr), @@ -2176,22 +2176,36 @@ BytecodeEmitter::BytecodeEmitter(Bytecod emitterMode(emitterMode), scriptStartOffsetSet(false), functionBodyEndPosSet(false) { MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript); } BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent, + BCEParserHandle* handle, SharedContext* sc, + HandleScript script, Handle<LazyScript*> lazyScript, + uint32_t lineNum, EmitterMode emitterMode) + : BytecodeEmitter(parent, sc, script, lazyScript, lineNum, emitterMode) +{ + parser = handle; +} + +BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent, const EitherParser& parser, SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript, - TokenPos bodyPosition, EmitterMode emitterMode) - : BytecodeEmitter(parent, parser, sc, script, lazyScript, - parser.errorReporter().lineAt(bodyPosition.begin), - emitterMode) + uint32_t lineNum, EmitterMode emitterMode) + : BytecodeEmitter(parent, sc, script, lazyScript, lineNum, emitterMode) +{ + ep_.emplace(parser); + this->parser = ep_.ptr(); +} + +void +BytecodeEmitter::initFromBodyPosition(TokenPos bodyPosition) { setScriptStartOffsetIfUnset(bodyPosition); setFunctionBodyEndPos(bodyPosition); } bool BytecodeEmitter::init() { @@ -2523,17 +2537,17 @@ LengthOfSetLine(unsigned line) { return 1 /* SRC_SETLINE */ + (line > SN_4BYTE_OFFSET_MASK ? 4 : 1); } /* Updates line number notes, not column notes. */ bool BytecodeEmitter::updateLineNumberNotes(uint32_t offset) { - ErrorReporter* er = &parser.errorReporter(); + ErrorReporter* er = &parser->errorReporter(); bool onThisLine; if (!er->isOnThisLine(offset, currentLine(), &onThisLine)) { er->reportErrorNoOffset(JSMSG_OUT_OF_MEMORY); return false; } if (!onThisLine) { unsigned line = er->lineAt(offset); @@ -2567,17 +2581,17 @@ BytecodeEmitter::updateLineNumberNotes(u /* Updates the line number and column number information in the source notes. */ bool BytecodeEmitter::updateSourceCoordNotes(uint32_t offset) { if (!updateLineNumberNotes(offset)) return false; - uint32_t columnIndex = parser.errorReporter().columnAt(offset); + uint32_t columnIndex = parser->errorReporter().columnAt(offset); ptrdiff_t colspan = ptrdiff_t(columnIndex) - ptrdiff_t(current->lastColumn); if (colspan != 0) { // If the column span is so large that we can't store it, then just // discard this information. This can happen with minimized or otherwise // machine-generated code. Even gigantic column numbers are still // valuable if you have a source map to relate them to something real; // but it's better to fail soft here. if (!SN_REPRESENTABLE_COLSPAN(colspan)) @@ -3543,31 +3557,31 @@ void BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) { MOZ_ASSERT_IF(!pn, this->scriptStartOffsetSet); uint32_t offset = pn ? pn->pn_pos.begin : this->scriptStartOffset; va_list args; va_start(args, errorNumber); - parser.errorReporter().errorAtVA(offset, errorNumber, &args); + parser->errorReporter().errorAtVA(offset, errorNumber, &args); va_end(args); } bool BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...) { MOZ_ASSERT_IF(!pn, this->scriptStartOffsetSet); uint32_t offset = pn ? pn->pn_pos.begin : this->scriptStartOffset; va_list args; va_start(args, errorNumber); - bool result = parser.errorReporter().reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, &args); + bool result = parser->errorReporter().reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, &args); va_end(args); return result; } bool BytecodeEmitter::emitNewInit(JSProtoKey key) { @@ -3599,17 +3613,17 @@ BytecodeEmitter::iteratorResultShape(uns Rooted<jsid> value_id(cx, NameToId(cx->names().value)); Rooted<jsid> done_id(cx, NameToId(cx->names().done)); if (!NativeDefineDataProperty(cx, obj, value_id, UndefinedHandleValue, JSPROP_ENUMERATE)) return false; if (!NativeDefineDataProperty(cx, obj, done_id, UndefinedHandleValue, JSPROP_ENUMERATE)) return false; - ObjectBox* objbox = parser.newObjectBox(obj); + ObjectBox* objbox = parser->newObjectBox(obj); if (!objbox) return false; *shape = objectList.add(objbox); return true; } @@ -4808,17 +4822,17 @@ BytecodeEmitter::emitSetThis(ParseNode* } return emitSetOrInitializeNameAtLocation(name, lexicalLoc, emitRhs, true); } bool BytecodeEmitter::emitScript(ParseNode* body) { - AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, parser.errorReporter(), body); + AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, parser->errorReporter(), body); setScriptStartOffsetIfUnset(body->pn_pos); TDZCheckCache tdzCache(this); EmitterScope emitterScope(this); if (sc->isGlobalContext()) { switchToPrologue(); if (!emitterScope.enterGlobal(this, sc->asGlobalContext())) @@ -4877,17 +4891,17 @@ BytecodeEmitter::emitScript(ParseNode* b return true; } bool BytecodeEmitter::emitFunctionScript(ParseNode* body) { FunctionBox* funbox = sc->asFunctionBox(); - AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, parser.errorReporter(), funbox); + AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, parser->errorReporter(), funbox); setScriptStartOffsetIfUnset(body->pn_pos); // The ordering of these EmitterScopes is important. The named lambda // scope needs to enclose the function scope needs to enclose the extra // var scope. Maybe<EmitterScope> namedLambdaEmitterScope; @@ -6524,42 +6538,42 @@ BytecodeEmitter::emitSingletonInitialise (pn->getKind() == ParseNodeKind::Object) ? SingletonObject : TenuredObject; RootedValue value(cx); if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value, nullptr, 0, newKind)) return false; MOZ_ASSERT_IF(newKind == SingletonObject, value.toObject().isSingleton()); - ObjectBox* objbox = parser.newObjectBox(&value.toObject()); + ObjectBox* objbox = parser->newObjectBox(&value.toObject()); if (!objbox) return false; return emitObjectOp(objbox, JSOP_OBJECT); } bool BytecodeEmitter::emitCallSiteObject(ParseNode* pn) { RootedValue value(cx); if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value)) return false; MOZ_ASSERT(value.isObject()); - ObjectBox* objbox1 = parser.newObjectBox(&value.toObject()); + ObjectBox* objbox1 = parser->newObjectBox(&value.toObject()); if (!objbox1) return false; if (!pn->as<CallSiteNode>().getRawArrayValue(cx, &value)) return false; MOZ_ASSERT(value.isObject()); - ObjectBox* objbox2 = parser.newObjectBox(&value.toObject()); + ObjectBox* objbox2 = parser->newObjectBox(&value.toObject()); if (!objbox2) return false; return emitObjectPairOp(objbox1, objbox2, JSOP_CALLSITEOBJ); } /* See the SRC_FOR source note offsetBias comments later in this file. */ JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1); @@ -7064,30 +7078,30 @@ BytecodeEmitter::emitInitializeForInOrOf "must have a per-iteration value for initializing"); ParseNode* target = forHead->pn_kid1; MOZ_ASSERT(!forHead->pn_kid2); // If the for-in/of loop didn't have a variable declaration, per-loop // initialization is just assigning the iteration value to a target // expression. - if (!parser.astGenerator().isDeclarationList(target)) + if (!parser->astGenerator().isDeclarationList(target)) return emitAssignment(target, ParseNodeKind::Assign, nullptr); // ... ITERVAL // Otherwise, per-loop initialization is (possibly) declaration // initialization. If the declaration is a lexical declaration, it must be // initialized. If the declaration is a variable declaration, an // assignment to that name (which does *not* necessarily assign to the // variable!) must be generated. if (!updateSourceCoordNotes(target->pn_pos.begin)) return false; MOZ_ASSERT(target->isForLoopDeclaration()); - target = parser.astGenerator().singleBindingFromDeclaration(target); + target = parser->astGenerator().singleBindingFromDeclaration(target); if (target->isKind(ParseNodeKind::Name)) { auto emitSwapScopeAndRhs = [](BytecodeEmitter* bce, const NameLocation&, bool emittedBindOp) { if (emittedBindOp) { // Per-iteration initialization in for-in/of loops computes the // iteration value *before* initializing. Thus the @@ -7317,18 +7331,18 @@ BytecodeEmitter::emitForIn(ParseNode* fo ParseNode* forInHead = forInLoop->pn_left; MOZ_ASSERT(forInHead->isKind(ParseNodeKind::ForIn)); MOZ_ASSERT(forInHead->isArity(PN_TERNARY)); // Annex B: Evaluate the var-initializer expression if present. // |for (var i = initializer in expr) { ... }| ParseNode* forInTarget = forInHead->pn_kid1; - if (parser.astGenerator().isDeclarationList(forInTarget)) { - ParseNode* decl = parser.astGenerator().singleBindingFromDeclaration(forInTarget); + if (parser->astGenerator().isDeclarationList(forInTarget)) { + ParseNode* decl = parser->astGenerator().singleBindingFromDeclaration(forInTarget); if (decl->isKind(ParseNodeKind::Name)) { if (ParseNode* initializer = decl->expr()) { MOZ_ASSERT(forInTarget->isKind(ParseNodeKind::Var), "for-in initializers are only permitted for |var| declarations"); if (!updateSourceCoordNotes(decl->pn_pos.begin)) return false; @@ -7589,17 +7603,17 @@ BytecodeEmitter::emitCStyleFor(ParseNode if (!updateSourceCoordNotes(update->pn_pos.begin)) return false; if (!emitTree(update, ValueUsage::IgnoreValue)) return false; if (!emit1(JSOP_POP)) return false; /* Restore the absolute line number for source note readers. */ - uint32_t lineNum = parser.errorReporter().lineAt(pn->pn_pos.end); + uint32_t lineNum = parser->errorReporter().lineAt(pn->pn_pos.end); if (currentLine() != lineNum) { if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(lineNum))) return false; current->currentLine = lineNum; current->lastColumn = 0; } } @@ -7745,18 +7759,18 @@ BytecodeEmitter::emitFunction(ParseNode* if (emittingRunOnceLambda) fun->lazyScript()->setTreatAsRunOnce(); } else { MOZ_ASSERT_IF(outersc->strict(), funbox->strictScript); // Inherit most things (principals, version, etc) from the // parent. Use default values for the rest. Rooted<JSScript*> parent(cx, script); - MOZ_ASSERT(parent->mutedErrors() == parser.options().mutedErrors()); - const TransitiveCompileOptions& transitiveOptions = parser.options(); + MOZ_ASSERT(parent->mutedErrors() == parser->options().mutedErrors()); + const TransitiveCompileOptions& transitiveOptions = parser->options(); CompileOptions options(cx, transitiveOptions); Rooted<JSObject*> sourceObject(cx, script->sourceObject()); Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject, funbox->bufStart, funbox->bufEnd, funbox->toStringStart, funbox->toStringEnd)); if (!script) @@ -8031,18 +8045,18 @@ BytecodeEmitter::emitWhile(ParseNode* pn // If we have a single-line while, like "while (x) ;", we want to // emit the line note before the initial goto, so that the // debugger sees a single entry point. This way, if there is a // breakpoint on the line, it will only fire once; and "next"ing // will skip the whole loop. However, for the multi-line case we // want to emit the line note after the initial goto, so that // "cont" stops on each iteration -- but without a stop before the // first iteration. - if (parser.errorReporter().lineAt(pn->pn_pos.begin) == - parser.errorReporter().lineAt(pn->pn_pos.end)) + if (parser->errorReporter().lineAt(pn->pn_pos.begin) == + parser->errorReporter().lineAt(pn->pn_pos.end)) { if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false; } JumpTarget top{ -1 }; if (!emitJumpTarget(&top)) return false; @@ -9121,17 +9135,17 @@ BytecodeEmitter::emitCallee(ParseNode* c } else { if (!emitTree(callee)) return false; } *callop = false; break; case ParseNodeKind::SuperBase: MOZ_ASSERT(call->isKind(ParseNodeKind::SuperCall)); - MOZ_ASSERT(parser.astGenerator().isSuperBase(callee)); + MOZ_ASSERT(parser->astGenerator().isSuperBase(callee)); if (!emit1(JSOP_SUPERFUN)) return false; break; default: if (!emitTree(callee)) return false; *callop = false; /* trigger JSOP_UNDEFINED after */ break; @@ -9336,17 +9350,17 @@ BytecodeEmitter::emitCallOrNew(ParseNode return false; checkTypeSet(pn->getOp()); } if (pn->isOp(JSOP_EVAL) || pn->isOp(JSOP_STRICTEVAL) || pn->isOp(JSOP_SPREADEVAL) || pn->isOp(JSOP_STRICTSPREADEVAL)) { - uint32_t lineNum = parser.errorReporter().lineAt(pn->pn_pos.begin); + uint32_t lineNum = parser->errorReporter().lineAt(pn->pn_pos.begin); if (!emitUint32Operand(JSOP_LINENO, lineNum)) return false; } return true; } static const JSOp ParseNodeKindToJSOp[] = { @@ -9776,17 +9790,17 @@ BytecodeEmitter::emitObject(ParseNode* p } return true; } bool BytecodeEmitter::replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset) { - ObjectBox* objbox = parser.newObjectBox(obj); + ObjectBox* objbox = parser->newObjectBox(obj); if (!objbox) return false; static_assert(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH, "newinit and newobject must have equal length to edit in-place"); uint32_t index = objectList.add(objbox); jsbytecode* code = this->code(offset); @@ -9825,17 +9839,17 @@ BytecodeEmitter::emitArrayLiteral(ParseN // use ObjectGroup::getOrFixupCopyOnWriteObject to make sure the // group for the template is accurate. We don't do this here as we // want to use ObjectGroup::allocationSiteGroup, which requires a // finished script. JSObject* obj = &value.toObject(); MOZ_ASSERT(obj->is<ArrayObject>() && obj->as<ArrayObject>().denseElementsAreCopyOnWrite()); - ObjectBox* objbox = parser.newObjectBox(obj); + ObjectBox* objbox = parser->newObjectBox(obj); if (!objbox) return false; return emitObjectOp(objbox, JSOP_NEWARRAY_COPYONWRITE); } } }
--- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -7,16 +7,17 @@ /* JS bytecode generation. */ #ifndef frontend_BytecodeEmitter_h #define frontend_BytecodeEmitter_h #include "mozilla/Attributes.h" #include "ds/InlineTable.h" +#include "frontend/BCEParserHandle.h" #include "frontend/EitherParser.h" #include "frontend/SharedContext.h" #include "frontend/SourceNotes.h" #include "vm/BytecodeUtil.h" #include "vm/Interpreter.h" #include "vm/Iteration.h" #include "vm/JSContext.h" #include "vm/JSScript.h" @@ -215,17 +216,20 @@ struct MOZ_STACK_CLASS BytecodeEmitter EmitSection(JSContext* cx, uint32_t lineNum) : code(cx), notes(cx), lastNoteOffset(0), currentLine(lineNum), lastColumn(0), lastTarget{ -1 - ptrdiff_t(JSOP_JUMPTARGET_LENGTH) } {} }; EmitSection prologue, main, *current; - EitherParser parser; + // Private storage for parser wrapper. DO NOT REFERENCE INTERNALLY. May not be initialized. + // Use |parser| instead. + mozilla::Maybe<EitherParser> ep_; + BCEParserHandle *parser; PooledMapPtr<AtomIndexMap> atomIndices; /* literals indexed for mapping */ unsigned firstLine; /* first line, for JSScript::initFromEmitter */ uint32_t maxFixedSlots; /* maximum number of fixed frame slots so far */ uint32_t maxStackDepth; /* maximum number of expression stack slots so far */ int32_t stackDepth; /* current stack depth in script frame */ @@ -290,33 +294,62 @@ struct MOZ_STACK_CLASS BytecodeEmitter bool functionBodyEndPosSet; /* * Note that BytecodeEmitters are magic: they own the arena "top-of-stack" * space above their tempMark points. This means that you cannot alloc from * tempLifoAlloc and save the pointer beyond the next BytecodeEmitter * destruction. */ - BytecodeEmitter(BytecodeEmitter* parent, const EitherParser& parser, - SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript, - uint32_t lineNum, EmitterMode emitterMode = Normal); + private: + // Internal constructor, for delegation use only. + BytecodeEmitter(BytecodeEmitter* parent, SharedContext* sc, HandleScript script, + Handle<LazyScript*> lazyScript, uint32_t lineNum, EmitterMode emitterMode); + + void initFromBodyPosition(TokenPos bodyPosition); + + public: + + BytecodeEmitter(BytecodeEmitter* parent, BCEParserHandle* parser, SharedContext* sc, + HandleScript script, Handle<LazyScript*> lazyScript, uint32_t lineNum, + EmitterMode emitterMode = Normal); + + BytecodeEmitter(BytecodeEmitter* parent, const EitherParser& parser, SharedContext* sc, + HandleScript script, Handle<LazyScript*> lazyScript, uint32_t lineNum, + EmitterMode emitterMode = Normal); template<typename CharT> BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler, CharT>* parser, SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript, uint32_t lineNum, EmitterMode emitterMode = Normal) : BytecodeEmitter(parent, EitherParser(parser), sc, script, lazyScript, lineNum, emitterMode) {} // An alternate constructor that uses a TokenPos for the starting // line and that sets functionBodyEndPos as well. - BytecodeEmitter(BytecodeEmitter* parent, const EitherParser& parser, - SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript, - TokenPos bodyPosition, EmitterMode emitterMode = Normal); + BytecodeEmitter(BytecodeEmitter* parent, BCEParserHandle* parser, SharedContext* sc, + HandleScript script, Handle<LazyScript*> lazyScript, TokenPos bodyPosition, + EmitterMode emitterMode = Normal) + : BytecodeEmitter(parent, parser, sc, script, lazyScript, + parser->errorReporter().lineAt(bodyPosition.begin), + emitterMode) + { + initFromBodyPosition(bodyPosition); + } + + BytecodeEmitter(BytecodeEmitter* parent, const EitherParser& parser, SharedContext* sc, + HandleScript script, Handle<LazyScript*> lazyScript, TokenPos bodyPosition, + EmitterMode emitterMode = Normal) + : BytecodeEmitter(parent, parser, sc, script, lazyScript, + parser.errorReporter().lineAt(bodyPosition.begin), + emitterMode) + { + initFromBodyPosition(bodyPosition); + } template<typename CharT> BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler, CharT>* parser, SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript, TokenPos bodyPosition, EmitterMode emitterMode = Normal) : BytecodeEmitter(parent, EitherParser(parser), sc, script, lazyScript, bodyPosition, emitterMode) {}