https://bugs.webkit.org/show_bug.cgi?id=184074
<rdar://problem/
37165897>
Reviewed by Mark Lam.
JSTests:
* microbenchmarks/try-get-by-id-basic.js:
(const.bench.f.const.fooPlusBar.createBuiltin):
* microbenchmarks/try-get-by-id-polymorphic.js:
(fooPlusBar.createBuiltin):
* stress/array-push-with-force-exit.js:
* stress/dont-crash-on-stack-overflow-when-parsing-builtin.js: Added.
(f):
* stress/dont-crash-on-stack-overflow-when-parsing-default-constructor.js: Added.
(foo):
(prototype.runNearStackLimit):
* stress/is-constructor.js:
* stress/tailCallForwardArguments.js:
(putFuncToPrivateName.createBuiltin):
Source/JavaScriptCore:
Prior to this patch, when we made a builtin, we had to make an UnlinkedFunctionExecutable
for that builtin. This required calling into the parser. However, the parser
may throw a stack overflow. We were not able to recover from that. The only
reason we called into the parser here is that we were gathering text offsets
and various metadata for things in the builtin function. This patch writes a
mini parser that figures this information out without calling into the full
parser. (I've also added a debug assert that verifies the mini parser stays in
sync with the full parser.) The result of this is that BuiltinExecutbles::createExecutable
always succeeds.
* builtins/AsyncFromSyncIteratorPrototype.js:
(globalPrivate.createAsyncFromSyncIterator):
(globalPrivate.AsyncFromSyncIteratorConstructor):
* builtins/BuiltinExecutables.cpp:
(JSC::BuiltinExecutables::createExecutable):
* builtins/GlobalOperations.js:
(globalPrivate.getter.overriddenName.string_appeared_here.speciesGetter):
(globalPrivate.speciesConstructor):
(globalPrivate.copyDataProperties):
(globalPrivate.copyDataPropertiesNoExclusions):
* builtins/PromiseOperations.js:
(globalPrivate.newHandledRejectedPromise):
* builtins/RegExpPrototype.js:
(globalPrivate.hasObservableSideEffectsForRegExpMatch):
(globalPrivate.hasObservableSideEffectsForRegExpSplit):
* builtins/StringPrototype.js:
(globalPrivate.hasObservableSideEffectsForStringReplace):
(globalPrivate.getDefaultCollator):
* parser/Nodes.cpp:
(JSC::FunctionMetadataNode::FunctionMetadataNode):
(JSC::FunctionMetadataNode::operator== const):
(JSC::FunctionMetadataNode::dump const):
* parser/Nodes.h:
* parser/Parser.h:
(JSC::parse):
* parser/ParserError.h:
(JSC::ParserError::type const):
* parser/ParserTokens.h:
(JSC::JSTextPosition::operator== const):
(JSC::JSTextPosition::operator!= const):
* parser/SourceCode.h:
(JSC::SourceCode::operator== const):
(JSC::SourceCode::operator!= const):
(JSC::SourceCode::subExpression const):
(JSC::SourceCode::subExpression): Deleted.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@233377
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2018-06-29 Saam Barati <sbarati@apple.com>
+
+ We shouldn't recurse into the parser when gathering metadata about various function offsets
+ https://bugs.webkit.org/show_bug.cgi?id=184074
+ <rdar://problem/37165897>
+
+ Reviewed by Mark Lam.
+
+ * microbenchmarks/try-get-by-id-basic.js:
+ (const.bench.f.const.fooPlusBar.createBuiltin):
+ * microbenchmarks/try-get-by-id-polymorphic.js:
+ (fooPlusBar.createBuiltin):
+ * stress/array-push-with-force-exit.js:
+ * stress/dont-crash-on-stack-overflow-when-parsing-builtin.js: Added.
+ (f):
+ * stress/dont-crash-on-stack-overflow-when-parsing-default-constructor.js: Added.
+ (foo):
+ (prototype.runNearStackLimit):
+ * stress/is-constructor.js:
+ * stress/tailCallForwardArguments.js:
+ (putFuncToPrivateName.createBuiltin):
+
2018-06-27 Mark Lam <mark.lam@apple.com>
DFG's compileReallocatePropertyStorage() and compileAllocatePropertyStorage() slow paths should also clear unused properties.
const bench = f => {
// Re-create the builtin each time, so each benchmark gets its own value prediction.
- const fooPlusBar = createBuiltin(`(function(o) { return @tryGetById(o, "foo") + @tryGetById(o, "bar"); })`);
+ const fooPlusBar = createBuiltin(`(function (o) { return @tryGetById(o, "foo") + @tryGetById(o, "bar"); })`);
noInline(fooPlusBar);
f(fooPlusBar);
}
const check = (got, expect) => { if (got != expect) throw "Error: bad result got " + got + " expected " + expect; };
-fooPlusBar = createBuiltin(`(function(o) { return @tryGetById(o, "foo") + @tryGetById(o, "bar"); })`);
+fooPlusBar = createBuiltin(`(function (o) { return @tryGetById(o, "foo") + @tryGetById(o, "bar"); })`);
noInline(fooPlusBar);
const bench = f => { f(); }
var createBuiltin = $vm.createBuiltin;
-var target = createBuiltin(`(function(array)
+var target = createBuiltin(`(function (array)
{
if (array) {
@idWithProfile(array, "SpecOther").push(42);
--- /dev/null
+//@ runDefault("--softReservedZoneSize=16384", "--reservedZoneSize=0", "--useJIT=0", "--validateBytecode=1", "--maxPerThreadStackUsage=500000")
+
+function f() {
+ try {
+ f();
+ } catch (e) {
+ try {
+ Map.prototype.forEach.call('', {});
+ } catch (e) {}
+ }
+}
+
+f()
--- /dev/null
+//@ runDefault("--softReservedZoneSize=16384", "--reservedZoneSize=0", "--useJIT=0", "--validateBytecode=1", "--maxPerThreadStackUsage=500000")
+
+function runNearStackLimit(f) {
+ function t() {
+ try {
+ return t();
+ } catch (e) {
+ new class extends (class {}) {}();
+ return f();
+ }
+ }
+ return t();
+}
+function foo() {
+ new class extends (class {}) {}();
+}
+runNearStackLimit(() => { return foo(); });
throw Error("Bad");
}
-let isConstructor = createBuiltin("(function(c) { return @isConstructor(c); })");
+let isConstructor = createBuiltin("(function (c) { return @isConstructor(c); })");
// Functions.
assert(isConstructor(assert));
var createBuiltin = $vm.createBuiltin;
// This is pretty bad but I need a private name.
-var putFuncToPrivateName = createBuiltin(`(function(func) { @arrayIteratorIsDone = func })`)
+var putFuncToPrivateName = createBuiltin(`(function (func) { @arrayIteratorIsDone = func })`)
putFuncToPrivateName(function (a,b) { return b; })
function createTailCallForwardingFuncWith(body, thisValue) {
+2018-06-29 Saam Barati <sbarati@apple.com>
+
+ We shouldn't recurse into the parser when gathering metadata about various function offsets
+ https://bugs.webkit.org/show_bug.cgi?id=184074
+ <rdar://problem/37165897>
+
+ Reviewed by Mark Lam.
+
+ Prior to this patch, when we made a builtin, we had to make an UnlinkedFunctionExecutable
+ for that builtin. This required calling into the parser. However, the parser
+ may throw a stack overflow. We were not able to recover from that. The only
+ reason we called into the parser here is that we were gathering text offsets
+ and various metadata for things in the builtin function. This patch writes a
+ mini parser that figures this information out without calling into the full
+ parser. (I've also added a debug assert that verifies the mini parser stays in
+ sync with the full parser.) The result of this is that BuiltinExecutbles::createExecutable
+ always succeeds.
+
+ * builtins/AsyncFromSyncIteratorPrototype.js:
+ (globalPrivate.createAsyncFromSyncIterator):
+ (globalPrivate.AsyncFromSyncIteratorConstructor):
+ * builtins/BuiltinExecutables.cpp:
+ (JSC::BuiltinExecutables::createExecutable):
+ * builtins/GlobalOperations.js:
+ (globalPrivate.getter.overriddenName.string_appeared_here.speciesGetter):
+ (globalPrivate.speciesConstructor):
+ (globalPrivate.copyDataProperties):
+ (globalPrivate.copyDataPropertiesNoExclusions):
+ * builtins/PromiseOperations.js:
+ (globalPrivate.newHandledRejectedPromise):
+ * builtins/RegExpPrototype.js:
+ (globalPrivate.hasObservableSideEffectsForRegExpMatch):
+ (globalPrivate.hasObservableSideEffectsForRegExpSplit):
+ * builtins/StringPrototype.js:
+ (globalPrivate.hasObservableSideEffectsForStringReplace):
+ (globalPrivate.getDefaultCollator):
+ * parser/Nodes.cpp:
+ (JSC::FunctionMetadataNode::FunctionMetadataNode):
+ (JSC::FunctionMetadataNode::operator== const):
+ (JSC::FunctionMetadataNode::dump const):
+ * parser/Nodes.h:
+ * parser/Parser.h:
+ (JSC::parse):
+ * parser/ParserError.h:
+ (JSC::ParserError::type const):
+ * parser/ParserTokens.h:
+ (JSC::JSTextPosition::operator== const):
+ (JSC::JSTextPosition::operator!= const):
+ * parser/SourceCode.h:
+ (JSC::SourceCode::operator== const):
+ (JSC::SourceCode::operator!= const):
+ (JSC::SourceCode::subExpression const):
+ (JSC::SourceCode::subExpression): Deleted.
+
2018-06-28 Michael Saboff <msaboff@apple.com>
IsoCellSet::sweepToFreeList() not safe when Full GC in process
@globalPrivate
function createAsyncFromSyncIterator(syncIterator, nextMethod)
{
+ "use strict";
+
if (!@isObject(syncIterator))
@throwTypeError('Only objects can be wrapped by async-from-sync wrapper');
@constructor
function AsyncFromSyncIteratorConstructor(syncIterator, nextMethod)
{
+ "use strict";
+
@putByIdDirectPrivate(this, "syncIterator", syncIterator);
@putByIdDirectPrivate(this, "nextMethod", nextMethod);
}
UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const SourceCode& source, const Identifier& name, ConstructorKind constructorKind, ConstructAbility constructAbility)
{
+ // Someone should get mad at me for writing this code. But, it prevents us from recursing into
+ // the parser, and hence, from throwing stack overflow when parsing a builtin.
+ StringView view = source.view();
+ RELEASE_ASSERT(!view.isNull());
+ RELEASE_ASSERT(view.is8Bit());
+ auto* characters = view.characters8();
+ RELEASE_ASSERT(view.length() >= 15); // strlen("(function (){})") == 15
+ RELEASE_ASSERT(characters[0] == '(');
+ RELEASE_ASSERT(characters[1] == 'f');
+ RELEASE_ASSERT(characters[2] == 'u');
+ RELEASE_ASSERT(characters[3] == 'n');
+ RELEASE_ASSERT(characters[4] == 'c');
+ RELEASE_ASSERT(characters[5] == 't');
+ RELEASE_ASSERT(characters[6] == 'i');
+ RELEASE_ASSERT(characters[7] == 'o');
+ RELEASE_ASSERT(characters[8] == 'n');
+ RELEASE_ASSERT(characters[9] == ' ');
+ RELEASE_ASSERT(characters[10] == '(');
+
+ JSTokenLocation start;
+ start.line = -1;
+ start.lineStartOffset = -1;
+ start.startOffset = 10;
+ start.endOffset = -1;
+
+ JSTokenLocation end;
+ end.line = 1;
+ end.lineStartOffset = 0;
+ end.startOffset = 1;
+ end.endOffset = -1;
+
+ unsigned startColumn = 10; // strlen("function (") == 10
+ int functionKeywordStart = 1; // (f
+ int functionNameStart = 10;
+ int parametersStart = 10;
+ bool isInStrictContext = false;
+ bool isArrowFunctionBodyExpression = false;
+
+ unsigned parameterCount;
+ {
+ unsigned i = 11;
+ unsigned commas = 0;
+ bool sawOneParam = false;
+ bool hasRestParam = false;
+ while (true) {
+ ASSERT(i < view.length());
+ if (characters[i] == ')')
+ break;
+
+ if (characters[i] == ',')
+ ++commas;
+ else if (!Lexer<LChar>::isWhiteSpace(characters[i]))
+ sawOneParam = true;
+
+ if (i + 2 < view.length() && characters[i] == '.' && characters[i + 1] == '.' && characters[i + 2] == '.') {
+ hasRestParam = true;
+ i += 2;
+ }
+
+ ++i;
+ }
+
+ if (commas)
+ parameterCount = commas + 1;
+ else if (sawOneParam)
+ parameterCount = 1;
+ else
+ parameterCount = 0;
+
+ if (hasRestParam) {
+ RELEASE_ASSERT(parameterCount);
+ --parameterCount;
+ }
+ }
+
+ unsigned lineCount = 0;
+ unsigned endColumn = 0;
+ unsigned offsetOfLastNewline = 0;
+ std::optional<unsigned> offsetOfSecondToLastNewline;
+ for (unsigned i = 0; i < view.length(); ++i) {
+ if (characters[i] == '\n') {
+ if (lineCount)
+ offsetOfSecondToLastNewline = offsetOfLastNewline;
+ ++lineCount;
+ endColumn = 0;
+ offsetOfLastNewline = i;
+ } else
+ ++endColumn;
+
+ if (!isInStrictContext && (characters[i] == '"' || characters[i] == '\'')) {
+ const unsigned useStrictLength = strlen("use strict");
+ if (i + 1 + useStrictLength < view.length()) {
+ if (!memcmp(characters + i + 1, "use strict", useStrictLength)) {
+ isInStrictContext = true;
+ i += 1 + useStrictLength;
+ }
+ }
+ }
+ }
+
+ unsigned positionBeforeLastNewlineLineStartOffset = offsetOfSecondToLastNewline ? *offsetOfSecondToLastNewline + 1 : 0;
+
+ int closeBraceOffsetFromEnd = 1;
+ while (true) {
+ if (characters[view.length() - closeBraceOffsetFromEnd] == '}')
+ break;
+ ++closeBraceOffsetFromEnd;
+ }
+
JSTextPosition positionBeforeLastNewline;
- ParserError error;
+ positionBeforeLastNewline.line = lineCount;
+ positionBeforeLastNewline.offset = offsetOfLastNewline;
+ positionBeforeLastNewline.lineStartOffset = positionBeforeLastNewlineLineStartOffset;
+
+ SourceCode newSource = source.subExpression(10, view.length() - closeBraceOffsetFromEnd, 0, 10);
bool isBuiltinDefaultClassConstructor = constructorKind != ConstructorKind::None;
- JSParserBuiltinMode builtinMode = isBuiltinDefaultClassConstructor ? JSParserBuiltinMode::NotBuiltin : JSParserBuiltinMode::Builtin;
UnlinkedFunctionKind kind = isBuiltinDefaultClassConstructor ? UnlinkedNormalFunction : UnlinkedBuiltinFunction;
- std::unique_ptr<ProgramNode> program = parse<ProgramNode>(
- &vm, source, Identifier(), builtinMode,
- JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error,
- &positionBeforeLastNewline, constructorKind);
-
- if (!program) {
- dataLog("Fatal error compiling builtin function '", name.string(), "': ", error.message());
- CRASH();
+
+ FunctionMetadataNode metadata(
+ start, end, startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart,
+ isInStrictContext, constructorKind, constructorKind == ConstructorKind::Extends ? SuperBinding::Needed : SuperBinding::NotNeeded,
+ parameterCount, SourceParseMode::NormalFunctionMode, isArrowFunctionBodyExpression);
+
+ metadata.finishParsing(newSource, Identifier(), FunctionMode::FunctionExpression);
+ metadata.overrideName(name);
+ metadata.setEndPosition(positionBeforeLastNewline);
+
+ if (!ASSERT_DISABLED || Options::validateBytecode()) {
+ JSTextPosition positionBeforeLastNewlineFromParser;
+ ParserError error;
+ JSParserBuiltinMode builtinMode = isBuiltinDefaultClassConstructor ? JSParserBuiltinMode::NotBuiltin : JSParserBuiltinMode::Builtin;
+ std::unique_ptr<ProgramNode> program = parse<ProgramNode>(
+ &vm, source, Identifier(), builtinMode,
+ JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error,
+ &positionBeforeLastNewlineFromParser, constructorKind);
+
+ if (program) {
+ StatementNode* exprStatement = program->singleStatement();
+ RELEASE_ASSERT(exprStatement);
+ RELEASE_ASSERT(exprStatement->isExprStatement());
+ ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr();
+ RELEASE_ASSERT(funcExpr);
+ RELEASE_ASSERT(funcExpr->isFuncExprNode());
+ FunctionMetadataNode* metadataFromParser = static_cast<FuncExprNode*>(funcExpr)->metadata();
+ RELEASE_ASSERT(!program->hasCapturedVariables());
+
+ metadataFromParser->setEndPosition(positionBeforeLastNewlineFromParser);
+ RELEASE_ASSERT(metadataFromParser);
+ RELEASE_ASSERT(metadataFromParser->ident().isNull());
+
+ // This function assumes an input string that would result in a single anonymous function expression.
+ metadataFromParser->setEndPosition(positionBeforeLastNewlineFromParser);
+ RELEASE_ASSERT(metadataFromParser);
+ metadataFromParser->overrideName(name);
+ metadataFromParser->setEndPosition(positionBeforeLastNewlineFromParser);
+
+ if (metadata != *metadataFromParser || positionBeforeLastNewlineFromParser != positionBeforeLastNewline) {
+ WTFLogAlways("Metadata of parser and hand rolled parser don't match\n");
+ CRASH();
+ }
+ } else {
+ RELEASE_ASSERT(error.isValid());
+ RELEASE_ASSERT(error.type() == ParserError::StackOverflow);
+ }
}
- StatementNode* exprStatement = program->singleStatement();
- RELEASE_ASSERT(exprStatement);
- RELEASE_ASSERT(exprStatement->isExprStatement());
- ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr();
- RELEASE_ASSERT(funcExpr);
- RELEASE_ASSERT(funcExpr->isFuncExprNode());
- FunctionMetadataNode* metadata = static_cast<FuncExprNode*>(funcExpr)->metadata();
- RELEASE_ASSERT(!program->hasCapturedVariables());
-
- metadata->setEndPosition(positionBeforeLastNewline);
- RELEASE_ASSERT(metadata);
- RELEASE_ASSERT(metadata->ident().isNull());
-
- // This function assumes an input string that would result in a single anonymous function expression.
- metadata->setEndPosition(positionBeforeLastNewline);
- RELEASE_ASSERT(metadata);
- metadata->overrideName(name);
VariableEnvironment dummyTDZVariables;
- UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, kind, constructAbility, JSParserScriptMode::Classic, dummyTDZVariables, DerivedContextType::None, isBuiltinDefaultClassConstructor);
+ UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, &metadata, kind, constructAbility, JSParserScriptMode::Classic, dummyTDZVariables, DerivedContextType::None, isBuiltinDefaultClassConstructor);
return functionExecutable;
}
@overriddenName="get [Symbol.species]"
function speciesGetter()
{
+ "use strict";
return this;
}
@globalPrivate
function speciesConstructor(obj, defaultConstructor)
{
+ "use strict";
+
var constructor = obj.constructor;
if (constructor === @undefined)
return defaultConstructor;
@globalPrivate
function copyDataProperties(target, source, excludedSet)
{
+ "use strict";
+
if (!@isObject(target))
@throwTypeError("target needs to be an object");
@globalPrivate
function copyDataPropertiesNoExclusions(target, source)
{
+ "use strict";
+
if (!@isObject(target))
@throwTypeError("target needs to be an object");
@globalPrivate
function newHandledRejectedPromise(error)
{
+ "use strict";
let promise = @Promise.@reject(error);
@putByIdDirectPrivate(promise, "promiseIsHandled", true);
return promise;
}
@globalPrivate
-function hasObservableSideEffectsForRegExpMatch(regexp) {
+function hasObservableSideEffectsForRegExpMatch(regexp)
+{
+ "use strict";
+
// This is accessed by the RegExpExec internal function.
let regexpExec = @tryGetById(regexp, "exec");
if (regexpExec !== @regExpBuiltinExec)
}
@globalPrivate
-function hasObservableSideEffectsForRegExpSplit(regexp) {
+function hasObservableSideEffectsForRegExpSplit(regexp)
+{
+ "use strict";
+
// This is accessed by the RegExpExec internal function.
let regexpExec = @tryGetById(regexp, "exec");
if (regexpExec !== @regExpBuiltinExec)
}
@globalPrivate
-function hasObservableSideEffectsForStringReplace(regexp, replacer) {
+function hasObservableSideEffectsForStringReplace(regexp, replacer)
+{
+ "use strict";
+
if (replacer !== @regExpPrototypeSymbolReplace)
return true;
@globalPrivate
function getDefaultCollator()
{
+ "use strict";
+
return @getDefaultCollator.collator || (@getDefaultCollator.collator = new @Collator());
}
ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
}
+FunctionMetadataNode::FunctionMetadataNode(
+ const JSTokenLocation& startLocation,
+ const JSTokenLocation& endLocation, unsigned startColumn, unsigned endColumn,
+ int functionKeywordStart, int functionNameStart, int parametersStart, bool isInStrictContext,
+ ConstructorKind constructorKind, SuperBinding superBinding, unsigned parameterCount, SourceParseMode mode, bool isArrowFunctionBodyExpression)
+ : Node(endLocation)
+ , m_startColumn(startColumn)
+ , m_endColumn(endColumn)
+ , m_functionKeywordStart(functionKeywordStart)
+ , m_functionNameStart(functionNameStart)
+ , m_parametersStart(parametersStart)
+ , m_startStartOffset(startLocation.startOffset)
+ , m_parameterCount(parameterCount)
+ , m_parseMode(mode)
+ , m_isInStrictContext(isInStrictContext)
+ , m_superBinding(static_cast<unsigned>(superBinding))
+ , m_constructorKind(static_cast<unsigned>(constructorKind))
+ , m_isArrowFunctionBodyExpression(isArrowFunctionBodyExpression)
+{
+ ASSERT(m_superBinding == static_cast<unsigned>(superBinding));
+ ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
+}
+
void FunctionMetadataNode::finishParsing(const SourceCode& source, const Identifier& ident, FunctionMode functionMode)
{
m_source = source;
m_endColumn = position.offset - position.lineStartOffset;
}
+bool FunctionMetadataNode::operator==(const FunctionMetadataNode& other) const
+{
+ return m_ident == other.m_ident
+ && m_ecmaName == other.m_ecmaName
+ && m_inferredName == other.m_inferredName
+ && m_functionMode== other.m_functionMode
+ && m_startColumn== other.m_startColumn
+ && m_endColumn== other.m_endColumn
+ && m_functionKeywordStart== other.m_functionKeywordStart
+ && m_functionNameStart== other.m_functionNameStart
+ && m_parametersStart== other.m_parametersStart
+ && m_source== other.m_source
+ && m_classSource== other.m_classSource
+ && m_startStartOffset== other.m_startStartOffset
+ && m_parameterCount== other.m_parameterCount
+ && m_lastLine== other.m_lastLine
+ && m_parseMode== other.m_parseMode
+ && m_isInStrictContext == other.m_isInStrictContext
+ && m_superBinding == other.m_superBinding
+ && m_constructorKind == other.m_constructorKind
+ && m_isArrowFunctionBodyExpression == other.m_isArrowFunctionBodyExpression
+ && m_position == other.m_position;
+}
+
+void FunctionMetadataNode::dump(PrintStream& stream) const
+{
+ stream.println("m_ident ", m_ident);
+ stream.println("m_ecmaName ", m_ecmaName);
+ stream.println("m_inferredName ", m_inferredName);
+ stream.println("m_functionMode ", static_cast<uint32_t>(m_functionMode));
+ stream.println("m_startColumn ", m_startColumn);
+ stream.println("m_endColumn ", m_endColumn);
+ stream.println("m_functionKeywordStart ", m_functionKeywordStart);
+ stream.println("m_functionNameStart ", m_functionNameStart);
+ stream.println("m_parametersStart ", m_parametersStart);
+ stream.println("m_classSource.isNull() ", m_classSource.isNull());
+ stream.println("m_startStartOffset ", m_startStartOffset);
+ stream.println("m_parameterCount ", m_parameterCount);
+ stream.println("m_lastLine ", m_lastLine);
+ stream.println("m_parseMode ", static_cast<uint32_t>(m_parseMode));
+ stream.println("m_isInStrictContext ", m_isInStrictContext);
+ stream.println("m_superBinding ", m_superBinding);
+ stream.println("m_constructorKind ", m_constructorKind);
+ stream.println("m_isArrowFunctionBodyExpression ", m_isArrowFunctionBodyExpression);
+ stream.println("position().line ", position().line);
+ stream.println("position().offset ", position().offset);
+ stream.println("position().lineStartOffset ", position().lineStartOffset);
+}
+
// ------------------------------ FunctionNode -----------------------------
FunctionNode::FunctionNode(ParserArena& parserArena, const JSTokenLocation& startLocation, const JSTokenLocation& endLocation, unsigned startColumn, unsigned endColumn, SourceElements* children, VariableEnvironment& varEnvironment, FunctionStack&& funcStack, VariableEnvironment& lexicalVariables, UniquedStringImplPtrSet&& sloppyModeHoistedFunctions, FunctionParameters* parameters, const SourceCode& sourceCode, CodeFeatures features, InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures, int numConstants, RefPtr<ModuleScopeData>&&)
int functionNameStart, int parametersStart, bool isInStrictContext,
ConstructorKind, SuperBinding, unsigned parameterCount,
SourceParseMode, bool isArrowFunctionBodyExpression);
+ FunctionMetadataNode(
+ const JSTokenLocation& start, const JSTokenLocation& end,
+ unsigned startColumn, unsigned endColumn, int functionKeywordStart,
+ int functionNameStart, int parametersStart, bool isInStrictContext,
+ ConstructorKind, SuperBinding, unsigned parameterCount,
+ SourceParseMode, bool isArrowFunctionBodyExpression);
+
+ void dump(PrintStream&) const;
void finishParsing(const SourceCode&, const Identifier&, FunctionMode);
}
unsigned lastLine() const { return m_lastLine; }
- protected:
+ bool operator==(const FunctionMetadataNode&) const;
+ bool operator!=(const FunctionMetadataNode& other) const
+ {
+ return !(*this == other);
+ }
+
+ public:
Identifier m_ident;
Identifier m_ecmaName;
Identifier m_inferredName;
if (positionBeforeLastNewline)
*positionBeforeLastNewline = parser.positionBeforeLastNewline();
if (builtinMode == JSParserBuiltinMode::Builtin) {
- if (!result)
- dataLogLn("Error compiling builtin: ", error.message());
+ if (!result) {
+ ASSERT(error.isValid());
+ if (error.type() != ParserError::StackOverflow)
+ dataLogLn("Unexpected error compiling builtin: ", error.message());
+ }
}
} else {
ASSERT_WITH_MESSAGE(defaultConstructorKind == ConstructorKind::None, "BuiltinExecutables::createDefaultConstructor should always use a 8-bit string");
const JSToken& token() const { return m_token; }
const String& message() const { return m_message; }
int line() const { return m_line; }
+ ErrorType type() const { return m_type; }
JSObject* toErrorObject(
JSGlobalObject* globalObject, const SourceCode& source,
operator int() const { return offset; }
+ bool operator==(const JSTextPosition& other) const
+ {
+ return line == other.line
+ && offset == other.offset
+ && lineStartOffset == other.lineStartOffset;
+ }
+ bool operator!=(const JSTextPosition& other) const
+ {
+ return !(*this == other);
+ }
+
int line;
int offset;
int lineStartOffset;
SourceProvider* provider() const { return m_provider.get(); }
- SourceCode subExpression(unsigned openBrace, unsigned closeBrace, int firstLine, int startColumn);
+ SourceCode subExpression(unsigned openBrace, unsigned closeBrace, int firstLine, int startColumn) const;
+
+ bool operator==(const SourceCode& other) const
+ {
+ return m_firstLine == other.m_firstLine
+ && m_startColumn == other.m_startColumn
+ && m_provider == other.m_provider
+ && m_startOffset == other.m_startOffset
+ && m_endOffset == other.m_endOffset;
+ }
+
+ bool operator!=(const SourceCode& other) const
+ {
+ return !(*this == other);
+ }
private:
OrdinalNumber m_firstLine;
return SourceCode(StringSourceProvider::create(source, sourceOrigin, url, startPosition, sourceType), startPosition.m_line.oneBasedInt(), startPosition.m_column.oneBasedInt());
}
- inline SourceCode SourceCode::subExpression(unsigned openBrace, unsigned closeBrace, int firstLine, int startColumn)
+ inline SourceCode SourceCode::subExpression(unsigned openBrace, unsigned closeBrace, int firstLine, int startColumn) const
{
startColumn += 1; // Convert to base 1.
return SourceCode(RefPtr<SourceProvider> { provider() }, openBrace, closeBrace + 1, firstLine, startColumn);