summaryrefslogtreecommitdiffstats
path: root/js/src/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend')
-rw-r--r--js/src/frontend/BytecodeCompiler.cpp127
-rw-r--r--js/src/frontend/BytecodeCompiler.h41
-rw-r--r--js/src/frontend/Parser.cpp55
-rw-r--r--js/src/frontend/Parser.h16
-rw-r--r--js/src/frontend/TokenStream.cpp149
-rw-r--r--js/src/frontend/TokenStream.h1
6 files changed, 253 insertions, 136 deletions
diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp
index d4c758b6c..3fbfdaa1a 100644
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -7,6 +7,7 @@
#include "frontend/BytecodeCompiler.h"
#include "mozilla/IntegerPrintfMacros.h"
+#include "mozilla/Maybe.h"
#include "jscntxt.h"
#include "jsscript.h"
@@ -28,6 +29,7 @@
using namespace js;
using namespace js::frontend;
using mozilla::Maybe;
+using mozilla::Nothing;
class MOZ_STACK_CLASS AutoCompilationTraceLogger
{
@@ -57,24 +59,24 @@ class MOZ_STACK_CLASS BytecodeCompiler
// Call setters for optional arguments.
void maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor);
- void setSourceArgumentsNotIncluded();
JSScript* compileGlobalScript(ScopeKind scopeKind);
JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
ModuleObject* compileModule();
- bool compileFunctionBody(MutableHandleFunction fun, Handle<PropertyNameVector> formals,
- GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
+ bool compileStandaloneFunction(MutableHandleFunction fun, GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind,
+ Maybe<uint32_t> parameterListEnd);
ScriptSourceObject* sourceObjectPtr() const;
private:
JSScript* compileScript(HandleObject environment, SharedContext* sc);
bool checkLength();
- bool createScriptSource();
+ bool createScriptSource(Maybe<uint32_t> parameterListEnd);
bool maybeCompressSource();
bool canLazilyParse();
bool createParser();
- bool createSourceAndParser();
+ bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
bool createScript();
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
bool handleParseFailure(const Directives& newDirectives);
@@ -90,7 +92,6 @@ class MOZ_STACK_CLASS BytecodeCompiler
SourceBufferHolder& sourceBuffer;
RootedScope enclosingScope;
- bool sourceArgumentsNotIncluded;
RootedScriptSource sourceObject;
ScriptSource* scriptSource;
@@ -130,7 +131,6 @@ BytecodeCompiler::BytecodeCompiler(ExclusiveContext* cx,
options(options),
sourceBuffer(sourceBuffer),
enclosingScope(cx, enclosingScope),
- sourceArgumentsNotIncluded(false),
sourceObject(cx),
scriptSource(nullptr),
sourceCompressor(nullptr),
@@ -147,12 +147,6 @@ BytecodeCompiler::maybeSetSourceCompressor(SourceCompressionTask* sourceCompress
this->sourceCompressor = sourceCompressor;
}
-void
-BytecodeCompiler::setSourceArgumentsNotIncluded()
-{
- sourceArgumentsNotIncluded = true;
-}
-
bool
BytecodeCompiler::checkLength()
{
@@ -169,12 +163,12 @@ BytecodeCompiler::checkLength()
}
bool
-BytecodeCompiler::createScriptSource()
+BytecodeCompiler::createScriptSource(Maybe<uint32_t> parameterListEnd)
{
if (!checkLength())
return false;
- sourceObject = CreateScriptSourceObject(cx, options);
+ sourceObject = CreateScriptSourceObject(cx, options, parameterListEnd);
if (!sourceObject)
return false;
@@ -193,9 +187,7 @@ BytecodeCompiler::maybeCompressSource()
if (!cx->compartment()->behaviors().discardSource()) {
if (options.sourceIsLazy) {
scriptSource->setSourceRetrievable();
- } else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceArgumentsNotIncluded,
- sourceCompressor))
- {
+ } else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceCompressor)) {
return false;
}
}
@@ -242,9 +234,9 @@ BytecodeCompiler::createParser()
}
bool
-BytecodeCompiler::createSourceAndParser()
+BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = Nothing() */)
{
- return createScriptSource() &&
+ return createScriptSource(parameterListEnd) &&
maybeCompressSource() &&
createParser();
}
@@ -432,18 +424,19 @@ BytecodeCompiler::compileModule()
return module;
}
+// Compile a standalone JS function, which might appear as the value of an
+// event handler attribute in an HTML <INPUT> tag, or in a Function()
+// constructor.
bool
-BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
- Handle<PropertyNameVector> formals,
- GeneratorKind generatorKind,
- FunctionAsyncKind asyncKind)
+BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
+ GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind,
+ Maybe<uint32_t> parameterListEnd)
{
MOZ_ASSERT(fun);
MOZ_ASSERT(fun->isTenured());
- fun->setArgCount(formals.length());
-
- if (!createSourceAndParser())
+ if (!createSourceAndParser(parameterListEnd))
return false;
// Speculatively parse using the default directives implied by the context.
@@ -454,8 +447,8 @@ BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
ParseNode* fn;
do {
Directives newDirectives = directives;
- fn = parser->standaloneFunctionBody(fun, enclosingScope, formals, generatorKind, asyncKind,
- directives, &newDirectives);
+ fn = parser->standaloneFunction(fun, enclosingScope, parameterListEnd, generatorKind,
+ asyncKind, directives, &newDirectives);
if (!fn && !handleParseFailure(newDirectives))
return false;
} while (!fn);
@@ -492,14 +485,15 @@ BytecodeCompiler::sourceObjectPtr() const
}
ScriptSourceObject*
-frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
+frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
+ Maybe<uint32_t> parameterListEnd /* = Nothing() */)
{
ScriptSource* ss = cx->new_<ScriptSource>();
if (!ss)
return nullptr;
ScriptSourceHolder ssHolder(ss);
- if (!ss->initFromOptions(cx, options))
+ if (!ss->initFromOptions(cx, options, parameterListEnd))
return nullptr;
RootedScriptSource sso(cx, ScriptSourceObject::create(cx, ss));
@@ -676,63 +670,44 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
return bce.emitFunctionScript(pn->pn_body);
}
-// Compile a JS function body, which might appear as the value of an event
-// handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
-static bool
-CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals, SourceBufferHolder& srcBuf,
- HandleScope enclosingScope, GeneratorKind generatorKind,
- FunctionAsyncKind asyncKind)
+bool
+frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ Maybe<uint32_t> parameterListEnd,
+ HandleScope enclosingScope /* = nullptr */)
{
- MOZ_ASSERT(!options.isRunOnce);
-
- // FIXME: make Function pass in two strings and parse them as arguments and
- // ProgramElements respectively.
+ RootedScope scope(cx, enclosingScope);
+ if (!scope)
+ scope = &cx->global()->emptyGlobalScope();
- BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, enclosingScope,
+ BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, scope,
TraceLogger_ParserCompileFunction);
- compiler.setSourceArgumentsNotIncluded();
- return compiler.compileFunctionBody(fun, formals, generatorKind, asyncKind);
+ return compiler.compileStandaloneFunction(fun, NotGenerator, SyncFunction, parameterListEnd);
}
bool
-frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
- HandleScope enclosingScope)
-{
- return CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingScope, NotGenerator,
- SyncFunction);
-}
-
-bool
-frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf)
+frontend::CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ Maybe<uint32_t> parameterListEnd)
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
- return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
- NotGenerator, SyncFunction);
-}
-bool
-frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals,
- JS::SourceBufferHolder& srcBuf)
-{
- RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
- return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
- StarGenerator, SyncFunction);
+ BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
+ TraceLogger_ParserCompileFunction);
+ return compiler.compileStandaloneFunction(fun, StarGenerator, SyncFunction, parameterListEnd);
}
bool
-frontend::CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals,
- JS::SourceBufferHolder& srcBuf)
+frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ Maybe<uint32_t> parameterListEnd)
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
- return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
- StarGenerator, AsyncFunction);
+
+ BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
+ TraceLogger_ParserCompileFunction);
+ return compiler.compileStandaloneFunction(fun, StarGenerator, AsyncFunction, parameterListEnd);
}
diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h
index 1d86f1160..72e967639 100644
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -7,6 +7,8 @@
#ifndef frontend_BytecodeCompiler_h
#define frontend_BytecodeCompiler_h
+#include "mozilla/Maybe.h"
+
#include "NamespaceImports.h"
#include "vm/Scope.h"
@@ -51,22 +53,36 @@ CompileModule(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
MOZ_MUST_USE bool
CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);
+//
+// Compile a single function. The source in srcBuf must match the ECMA-262
+// FunctionExpression production.
+//
+// If nonzero, parameterListEnd is the offset within srcBuf where the parameter
+// list is expected to end. During parsing, if we find that it ends anywhere
+// else, it's a SyntaxError. This is used to implement the Function constructor;
+// it's how we detect that these weird cases are SyntaxErrors:
+//
+// Function("/*", "*/x) {")
+// Function("x){ if (3", "return x;}")
+//
MOZ_MUST_USE bool
-CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
- HandleScope enclosingScope);
+CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ mozilla::Maybe<uint32_t> parameterListEnd,
+ HandleScope enclosingScope = nullptr);
-// As above, but defaults to the global lexical scope as the enclosing scope.
MOZ_MUST_USE bool
-CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
+CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ mozilla::Maybe<uint32_t> parameterListEnd);
MOZ_MUST_USE bool
-CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
- const ReadOnlyCompileOptions& options,
- Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
+CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ JS::SourceBufferHolder& srcBuf,
+ mozilla::Maybe<uint32_t> parameterListEnd);
MOZ_MUST_USE bool
CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
@@ -74,7 +90,8 @@ CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
ScriptSourceObject*
-CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options);
+CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
+ mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
/*
* True if str consists of an IdentifierStart character, followed by one or
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 49fef2bf9..f42546eb5 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2245,13 +2245,13 @@ GetYieldHandling(GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
template <>
ParseNode*
-Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
- HandleScope enclosingScope,
- Handle<PropertyNameVector> formals,
- GeneratorKind generatorKind,
- FunctionAsyncKind asyncKind,
- Directives inheritedDirectives,
- Directives* newDirectives)
+Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
+ HandleScope enclosingScope,
+ Maybe<uint32_t> parameterListEnd,
+ GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind,
+ Directives inheritedDirectives,
+ Directives* newDirectives)
{
MOZ_ASSERT(checkOptionsCalled);
@@ -2274,25 +2274,14 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
if (!funpc.init())
return null();
funpc.setIsStandaloneFunctionBody();
- funpc.functionScope().useAsVarScope(&funpc);
-
- if (formals.length() >= ARGNO_LIMIT) {
- report(ParseError, false, null(), JSMSG_TOO_MANY_FUN_ARGS);
- return null();
- }
-
- bool duplicatedParam = false;
- for (uint32_t i = 0; i < formals.length(); i++) {
- if (!notePositionalFormalParameter(fn, formals[i], false, &duplicatedParam))
- return null();
- }
- funbox->hasDuplicateParameters = duplicatedParam;
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction);
- ParseNode* pn = functionBody(InAllowed, yieldHandling, Statement, StatementListBody);
- if (!pn)
+ if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement,
+ parameterListEnd))
+ {
return null();
+ }
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
@@ -2303,15 +2292,7 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
return null();
}
- if (!FoldConstants(context, &pn, this))
- return null();
-
- fn->pn_pos.end = pos().end;
-
- MOZ_ASSERT(fn->pn_body->isKind(PNK_PARAMSBODY));
- fn->pn_body->append(pn);
-
- if (!finishFunction())
+ if (!FoldConstants(context, &fn, this))
return null();
return fn;
@@ -3415,7 +3396,8 @@ template <typename ParseHandler>
bool
Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
YieldHandling yieldHandling,
- Node pn, FunctionSyntaxKind kind)
+ Node pn, FunctionSyntaxKind kind,
+ Maybe<uint32_t> parameterListEnd /* = Nothing() */)
{
// Given a properly initialized parse context, try to parse an actual
// function without concern for conversion to strict mode, use of lazy
@@ -3447,6 +3429,13 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
}
}
+ // When parsing something for new Function() we have to make sure to
+ // only treat a certain part of the source as a parameter list.
+ if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) {
+ report(ParseError, false, null(), JSMSG_UNEXPECTED_PARAMLIST_END);
+ return false;
+ }
+
// Parse the function body.
FunctionBodyType bodyType = StatementListBody;
TokenKind tt;
@@ -3502,7 +3491,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
report(ParseError, false, null(), JSMSG_CURLY_AFTER_BODY);
return false;
}
- funbox->bufEnd = pos().begin + 1;
+ funbox->bufEnd = pos().end;
} else {
#if !JS_HAS_EXPR_CLOSURES
MOZ_ASSERT(kind == Arrow);
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
index 0ad4d56a0..b58b021cd 100644
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1020,12 +1020,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Parse a module.
Node moduleBody(ModuleSharedContext* modulesc);
- // Parse a function, given only its body. Used for the Function and
- // Generator constructors.
- Node standaloneFunctionBody(HandleFunction fun, HandleScope enclosingScope,
- Handle<PropertyNameVector> formals,
- GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
- Directives inheritedDirectives, Directives* newDirectives);
+ // Parse a function, used for the Function, GeneratorFunction, and
+ // AsyncFunction constructors.
+ Node standaloneFunction(HandleFunction fun, HandleScope enclosingScope,
+ mozilla::Maybe<uint32_t> parameterListEnd,
+ GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
+ Directives inheritedDirectives, Directives* newDirectives);
// Parse a function, given only its arguments and body. Used for lazily
// parsed functions.
@@ -1041,7 +1041,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Parse a function's formal parameters and its body assuming its function
// ParseContext is already on the stack.
bool functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling,
- Node pn, FunctionSyntaxKind kind);
+ Node pn, FunctionSyntaxKind kind,
+ mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
+
// Determine whether |yield| is a valid name in the current context, or
// whether it's prohibited due to strictness, JS version, or occurrence
diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
index c166ed414..179a7c244 100644
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -118,13 +118,57 @@ IsIdentifier(const CharT* chars, size_t length)
return true;
}
+static uint32_t
+GetSingleCodePoint(const char16_t** p, const char16_t* end)
+{
+ uint32_t codePoint;
+ if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(**p)) && *p + 1 < end) {
+ char16_t lead = **p;
+ char16_t maybeTrail = *(*p + 1);
+ if (unicode::IsTrailSurrogate(maybeTrail)) {
+ *p += 2;
+ return unicode::UTF16Decode(lead, maybeTrail);
+ }
+ }
+
+ codePoint = **p;
+ (*p)++;
+ return codePoint;
+}
+
+static bool
+IsIdentifierMaybeNonBMP(const char16_t* chars, size_t length)
+{
+ if (IsIdentifier(chars, length))
+ return true;
+
+ if (length == 0)
+ return false;
+
+ const char16_t* p = chars;
+ const char16_t* end = chars + length;
+ uint32_t codePoint;
+
+ codePoint = GetSingleCodePoint(&p, end);
+ if (!unicode::IsIdentifierStart(codePoint))
+ return false;
+
+ while (p < end) {
+ codePoint = GetSingleCodePoint(&p, end);
+ if (!unicode::IsIdentifierPart(codePoint))
+ return false;
+ }
+
+ return true;
+}
+
bool
frontend::IsIdentifier(JSLinearString* str)
{
JS::AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? ::IsIdentifier(str->latin1Chars(nogc), str->length())
- : ::IsIdentifier(str->twoByteChars(nogc), str->length());
+ : ::IsIdentifierMaybeNonBMP(str->twoByteChars(nogc), str->length());
}
bool
@@ -993,6 +1037,21 @@ IsTokenSane(Token* tp)
#endif
bool
+TokenStream::matchTrailForLeadSurrogate(char16_t lead, char16_t* trail, uint32_t* codePoint)
+{
+ int32_t maybeTrail = getCharIgnoreEOL();
+ if (!unicode::IsTrailSurrogate(maybeTrail)) {
+ ungetCharIgnoreEOL(maybeTrail);
+ return false;
+ }
+
+ if (trail)
+ *trail = maybeTrail;
+ *codePoint = unicode::UTF16Decode(lead, maybeTrail);
+ return true;
+}
+
+bool
TokenStream::putIdentInTokenbuf(const char16_t* identStart)
{
int32_t c;
@@ -1003,11 +1062,39 @@ TokenStream::putIdentInTokenbuf(const char16_t* identStart)
tokenbuf.clear();
for (;;) {
c = getCharIgnoreEOL();
+
+ if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(c))) {
+ char16_t trail;
+ uint32_t codePoint;
+ if (matchTrailForLeadSurrogate(c, &trail, &codePoint)) {
+ if (!unicode::IsIdentifierPart(codePoint))
+ break;
+
+ if (!tokenbuf.append(c) || !tokenbuf.append(trail)) {
+ userbuf.setAddressOfNextRawChar(tmp);
+ return false;
+ }
+ continue;
+ }
+ }
+
if (!unicode::IsIdentifierPart(char16_t(c))) {
if (c != '\\' || !matchUnicodeEscapeIdent(&qc))
break;
+
+ if (MOZ_UNLIKELY(unicode::IsSupplementary(qc))) {
+ char16_t lead, trail;
+ unicode::UTF16Encode(qc, &lead, &trail);
+ if (!tokenbuf.append(lead) || !tokenbuf.append(trail)) {
+ userbuf.setAddressOfNextRawChar(tmp);
+ return false;
+ }
+ continue;
+ }
+
c = qc;
}
+
if (!tokenbuf.append(c)) {
userbuf.setAddressOfNextRawChar(tmp);
return false;
@@ -1168,12 +1255,23 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
static_assert('_' < 128,
"IdentifierStart contains '_', but as !IsUnicodeIDStart('_'), "
"ensure that '_' is never handled here");
- if (unicode::IsUnicodeIDStart(c)) {
+ if (unicode::IsUnicodeIDStart(char16_t(c))) {
identStart = userbuf.addressOfNextRawChar() - 1;
hadUnicodeEscape = false;
goto identifier;
}
+ if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(c))) {
+ uint32_t codePoint;
+ if (matchTrailForLeadSurrogate(c, nullptr, &codePoint) &&
+ unicode::IsUnicodeIDStart(codePoint))
+ {
+ identStart = userbuf.addressOfNextRawChar() - 2;
+ hadUnicodeEscape = false;
+ goto identifier;
+ }
+ }
+
goto badchar;
}
@@ -1224,6 +1322,17 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
c = getCharIgnoreEOL();
if (c == EOF)
break;
+
+ if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(c))) {
+ uint32_t codePoint;
+ if (matchTrailForLeadSurrogate(c, nullptr, &codePoint)) {
+ if (!unicode::IsIdentifierPart(codePoint))
+ break;
+
+ continue;
+ }
+ }
+
if (!unicode::IsIdentifierPart(char16_t(c))) {
if (c != '\\' || !matchUnicodeEscapeIdent(&qc))
break;
@@ -1318,9 +1427,21 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
}
ungetCharIgnoreEOL(c);
- if (c != EOF && unicode::IsIdentifierStart(char16_t(c))) {
- reportError(JSMSG_IDSTART_AFTER_NUMBER);
- goto error;
+ if (c != EOF) {
+ if (unicode::IsIdentifierStart(char16_t(c))) {
+ reportError(JSMSG_IDSTART_AFTER_NUMBER);
+ goto error;
+ }
+
+ if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(c))) {
+ uint32_t codePoint;
+ if (matchTrailForLeadSurrogate(c, nullptr, &codePoint) &&
+ unicode::IsIdentifierStart(codePoint))
+ {
+ reportError(JSMSG_IDSTART_AFTER_NUMBER);
+ goto error;
+ }
+ }
}
// Unlike identifiers and strings, numbers cannot contain escaped
@@ -1425,9 +1546,21 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
}
ungetCharIgnoreEOL(c);
- if (c != EOF && unicode::IsIdentifierStart(char16_t(c))) {
- reportError(JSMSG_IDSTART_AFTER_NUMBER);
- goto error;
+ if (c != EOF) {
+ if (unicode::IsIdentifierStart(char16_t(c))) {
+ reportError(JSMSG_IDSTART_AFTER_NUMBER);
+ goto error;
+ }
+
+ if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(c))) {
+ uint32_t codePoint;
+ if (matchTrailForLeadSurrogate(c, nullptr, &codePoint) &&
+ unicode::IsIdentifierStart(codePoint))
+ {
+ reportError(JSMSG_IDSTART_AFTER_NUMBER);
+ goto error;
+ }
+ }
}
double dval;
diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
index 29dcead62..5d6b4b795 100644
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -952,6 +952,7 @@ class MOZ_STACK_CLASS TokenStream
uint32_t peekExtendedUnicodeEscape(uint32_t* codePoint);
uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
bool matchUnicodeEscapeIdent(uint32_t* codePoint);
+ bool matchTrailForLeadSurrogate(char16_t lead, char16_t* trail, uint32_t* codePoint);
bool peekChars(int n, char16_t* cp);
MOZ_MUST_USE bool getDirectives(bool isMultiline, bool shouldWarnDeprecated);