Diff
Modified: trunk/JSTests/ChangeLog (233376 => 233377)
--- trunk/JSTests/ChangeLog 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/JSTests/ChangeLog 2018-06-29 23:40:25 UTC (rev 233377)
@@ -1,3 +1,25 @@
+2018-06-29 Saam Barati <[email protected]>
+
+ 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 <[email protected]>
DFG's compileReallocatePropertyStorage() and compileAllocatePropertyStorage() slow paths should also clear unused properties.
Modified: trunk/JSTests/microbenchmarks/try-get-by-id-basic.js (233376 => 233377)
--- trunk/JSTests/microbenchmarks/try-get-by-id-basic.js 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/JSTests/microbenchmarks/try-get-by-id-basic.js 2018-06-29 23:40:25 UTC (rev 233377)
@@ -8,7 +8,7 @@
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);
}
Modified: trunk/JSTests/microbenchmarks/try-get-by-id-polymorphic.js (233376 => 233377)
--- trunk/JSTests/microbenchmarks/try-get-by-id-polymorphic.js 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/JSTests/microbenchmarks/try-get-by-id-polymorphic.js 2018-06-29 23:40:25 UTC (rev 233377)
@@ -6,7 +6,7 @@
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(); }
Modified: trunk/JSTests/stress/array-push-with-force-exit.js (233376 => 233377)
--- trunk/JSTests/stress/array-push-with-force-exit.js 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/JSTests/stress/array-push-with-force-exit.js 2018-06-29 23:40:25 UTC (rev 233377)
@@ -1,6 +1,6 @@
var createBuiltin = $vm.createBuiltin;
-var target = createBuiltin(`(function(array)
+var target = createBuiltin(`(function (array)
{
if (array) {
@idWithProfile(array, "SpecOther").push(42);
Added: trunk/JSTests/stress/dont-crash-on-stack-overflow-when-parsing-builtin.js (0 => 233377)
--- trunk/JSTests/stress/dont-crash-on-stack-overflow-when-parsing-builtin.js (rev 0)
+++ trunk/JSTests/stress/dont-crash-on-stack-overflow-when-parsing-builtin.js 2018-06-29 23:40:25 UTC (rev 233377)
@@ -0,0 +1,13 @@
+//@ 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()
Added: trunk/JSTests/stress/dont-crash-on-stack-overflow-when-parsing-default-constructor.js (0 => 233377)
--- trunk/JSTests/stress/dont-crash-on-stack-overflow-when-parsing-default-constructor.js (rev 0)
+++ trunk/JSTests/stress/dont-crash-on-stack-overflow-when-parsing-default-constructor.js 2018-06-29 23:40:25 UTC (rev 233377)
@@ -0,0 +1,17 @@
+//@ 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(); });
Modified: trunk/JSTests/stress/is-constructor.js (233376 => 233377)
--- trunk/JSTests/stress/is-constructor.js 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/JSTests/stress/is-constructor.js 2018-06-29 23:40:25 UTC (rev 233377)
@@ -5,7 +5,7 @@
throw Error("Bad");
}
-let isConstructor = createBuiltin("(function(c) { return @isConstructor(c); })");
+let isConstructor = createBuiltin("(function (c) { return @isConstructor(c); })");
// Functions.
assert(isConstructor(assert));
Modified: trunk/JSTests/stress/tailCallForwardArguments.js (233376 => 233377)
--- trunk/JSTests/stress/tailCallForwardArguments.js 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/JSTests/stress/tailCallForwardArguments.js 2018-06-29 23:40:25 UTC (rev 233377)
@@ -1,7 +1,7 @@
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) {
Modified: trunk/Source/_javascript_Core/ChangeLog (233376 => 233377)
--- trunk/Source/_javascript_Core/ChangeLog 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/ChangeLog 2018-06-29 23:40:25 UTC (rev 233377)
@@ -1,3 +1,57 @@
+2018-06-29 Saam Barati <[email protected]>
+
+ 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 <[email protected]>
IsoCellSet::sweepToFreeList() not safe when Full GC in process
Modified: trunk/Source/_javascript_Core/builtins/AsyncFromSyncIteratorPrototype.js (233376 => 233377)
--- trunk/Source/_javascript_Core/builtins/AsyncFromSyncIteratorPrototype.js 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/builtins/AsyncFromSyncIteratorPrototype.js 2018-06-29 23:40:25 UTC (rev 233377)
@@ -151,6 +151,8 @@
@globalPrivate
function createAsyncFromSyncIterator(syncIterator, nextMethod)
{
+ "use strict";
+
if (!@isObject(syncIterator))
@throwTypeError('Only objects can be wrapped by async-from-sync wrapper');
@@ -161,6 +163,8 @@
@constructor
function AsyncFromSyncIteratorConstructor(syncIterator, nextMethod)
{
+ "use strict";
+
@putByIdDirectPrivate(this, "syncIterator", syncIterator);
@putByIdDirectPrivate(this, "nextMethod", nextMethod);
}
Modified: trunk/Source/_javascript_Core/builtins/BuiltinExecutables.cpp (233376 => 233377)
--- trunk/Source/_javascript_Core/builtins/BuiltinExecutables.cpp 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/builtins/BuiltinExecutables.cpp 2018-06-29 23:40:25 UTC (rev 233377)
@@ -85,40 +85,174 @@
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;
}
Modified: trunk/Source/_javascript_Core/builtins/GlobalOperations.js (233376 => 233377)
--- trunk/Source/_javascript_Core/builtins/GlobalOperations.js 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/builtins/GlobalOperations.js 2018-06-29 23:40:25 UTC (rev 233377)
@@ -62,6 +62,7 @@
@overriddenName="get [Symbol.species]"
function speciesGetter()
{
+ "use strict";
return this;
}
@@ -68,6 +69,8 @@
@globalPrivate
function speciesConstructor(obj, defaultConstructor)
{
+ "use strict";
+
var constructor = obj.constructor;
if (constructor === @undefined)
return defaultConstructor;
@@ -84,6 +87,8 @@
@globalPrivate
function copyDataProperties(target, source, excludedSet)
{
+ "use strict";
+
if (!@isObject(target))
@throwTypeError("target needs to be an object");
@@ -109,6 +114,8 @@
@globalPrivate
function copyDataPropertiesNoExclusions(target, source)
{
+ "use strict";
+
if (!@isObject(target))
@throwTypeError("target needs to be an object");
Modified: trunk/Source/_javascript_Core/builtins/PromiseOperations.js (233376 => 233377)
--- trunk/Source/_javascript_Core/builtins/PromiseOperations.js 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/builtins/PromiseOperations.js 2018-06-29 23:40:25 UTC (rev 233377)
@@ -87,6 +87,7 @@
@globalPrivate
function newHandledRejectedPromise(error)
{
+ "use strict";
let promise = @Promise.@reject(error);
@putByIdDirectPrivate(promise, "promiseIsHandled", true);
return promise;
Modified: trunk/Source/_javascript_Core/builtins/RegExpPrototype.js (233376 => 233377)
--- trunk/Source/_javascript_Core/builtins/RegExpPrototype.js 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/builtins/RegExpPrototype.js 2018-06-29 23:40:25 UTC (rev 233377)
@@ -63,7 +63,10 @@
}
@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)
@@ -351,7 +354,10 @@
}
@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)
Modified: trunk/Source/_javascript_Core/builtins/StringPrototype.js (233376 => 233377)
--- trunk/Source/_javascript_Core/builtins/StringPrototype.js 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/builtins/StringPrototype.js 2018-06-29 23:40:25 UTC (rev 233377)
@@ -191,7 +191,10 @@
}
@globalPrivate
-function hasObservableSideEffectsForStringReplace(regexp, replacer) {
+function hasObservableSideEffectsForStringReplace(regexp, replacer)
+{
+ "use strict";
+
if (replacer !== @regExpPrototypeSymbolReplace)
return true;
@@ -235,6 +238,8 @@
@globalPrivate
function getDefaultCollator()
{
+ "use strict";
+
return @getDefaultCollator.collator || (@getDefaultCollator.collator = new @Collator());
}
Modified: trunk/Source/_javascript_Core/parser/Nodes.cpp (233376 => 233377)
--- trunk/Source/_javascript_Core/parser/Nodes.cpp 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/parser/Nodes.cpp 2018-06-29 23:40:25 UTC (rev 233377)
@@ -214,6 +214,29 @@
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;
@@ -227,6 +250,55 @@
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>&&)
Modified: trunk/Source/_javascript_Core/parser/Nodes.h (233376 => 233377)
--- trunk/Source/_javascript_Core/parser/Nodes.h 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/parser/Nodes.h 2018-06-29 23:40:25 UTC (rev 233377)
@@ -1988,7 +1988,15 @@
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);
void overrideName(const Identifier& ident) { m_ident = ident; }
@@ -2028,7 +2036,13 @@
}
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;
Modified: trunk/Source/_javascript_Core/parser/Parser.h (233376 => 233377)
--- trunk/Source/_javascript_Core/parser/Parser.h 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/parser/Parser.h 2018-06-29 23:40:25 UTC (rev 233377)
@@ -1964,8 +1964,11 @@
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");
Modified: trunk/Source/_javascript_Core/parser/ParserError.h (233376 => 233377)
--- trunk/Source/_javascript_Core/parser/ParserError.h 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/parser/ParserError.h 2018-06-29 23:40:25 UTC (rev 233377)
@@ -83,6 +83,7 @@
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,
Modified: trunk/Source/_javascript_Core/parser/ParserTokens.h (233376 => 233377)
--- trunk/Source/_javascript_Core/parser/ParserTokens.h 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/parser/ParserTokens.h 2018-06-29 23:40:25 UTC (rev 233377)
@@ -202,6 +202,17 @@
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;
Modified: trunk/Source/_javascript_Core/parser/SourceCode.h (233376 => 233377)
--- trunk/Source/_javascript_Core/parser/SourceCode.h 2018-06-29 23:33:30 UTC (rev 233376)
+++ trunk/Source/_javascript_Core/parser/SourceCode.h 2018-06-29 23:40:25 UTC (rev 233377)
@@ -79,8 +79,22 @@
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;
OrdinalNumber m_startColumn;
@@ -91,7 +105,7 @@
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);