Bug 755821: Function() should use the parser's argument parsing code

This commit is contained in:
janekptacijarabaci 2018-03-16 11:35:57 +01:00 • committed by Roy Tam
commit 0e7a16c088
24 changed files with 321 additions and 469 deletions

View file

@ -115,7 +115,7 @@ const TEST_DATA = [ // eslint-disable-line
expected: [ expected: [
{ {
type: "click", type: "click",
filename: TEST_URL + ":1", filename: TEST_URL + ":0",
attributes: [ attributes: [
"Bubbling", "Bubbling",
"DOM2" "DOM2"
@ -129,7 +129,7 @@ const TEST_DATA = [ // eslint-disable-line
expected: [ expected: [
{ {
type: "click", type: "click",
filename: TEST_URL + ":1", filename: TEST_URL + ":0",
attributes: [ attributes: [
"Bubbling", "Bubbling",
"DOM2" "DOM2"

View file

@ -175,7 +175,6 @@ function* testJSTerm(hud) {
"JSMSG_BAD_RADIX": "(42).toString(0);", "JSMSG_BAD_RADIX": "(42).toString(0);",
"JSMSG_BAD_ARRAY_LENGTH": "([]).length = -1", "JSMSG_BAD_ARRAY_LENGTH": "([]).length = -1",
"JSMSG_NEGATIVE_REPETITION_COUNT": "'abc'.repeat(-1);", "JSMSG_NEGATIVE_REPETITION_COUNT": "'abc'.repeat(-1);",
"JSMSG_BAD_FORMAL": "var f = Function('x y', 'return x + y;');",
"JSMSG_PRECISION_RANGE": "77.1234.toExponential(-1);", "JSMSG_PRECISION_RANGE": "77.1234.toExponential(-1);",
}; };

View file

@ -18,7 +18,6 @@ const ErrorDocs = {
JSMSG_RESULTING_STRING_TOO_LARGE: "Resulting_string_too_large", JSMSG_RESULTING_STRING_TOO_LARGE: "Resulting_string_too_large",
JSMSG_BAD_RADIX: "Bad_radix", JSMSG_BAD_RADIX: "Bad_radix",
JSMSG_PRECISION_RANGE: "Precision_range", JSMSG_PRECISION_RANGE: "Precision_range",
JSMSG_BAD_FORMAL: "Malformed_formal_parameter",
JSMSG_STMT_AFTER_RETURN: "Stmt_after_return", JSMSG_STMT_AFTER_RETURN: "Stmt_after_return",
JSMSG_NOT_A_CODEPOINT: "Not_a_codepoint", JSMSG_NOT_A_CODEPOINT: "Not_a_codepoint",
JSMSG_BAD_SORT_ARG: "Array_sort_argument", JSMSG_BAD_SORT_ARG: "Array_sort_argument",

View file

@ -102,16 +102,6 @@ function doPageErrors()
warning: false, warning: false,
exception: true, exception: true,
}, },
"var f = Function('x y', 'return x + y;');": {
errorMessage: /malformed formal/,
errorMessageName: "JSMSG_BAD_FORMAL",
sourceName: /test_page_errors/,
category: "chrome javascript",
timeStamp: /^\d+$/,
error: false,
warning: false,
exception: true,
},
"function a() { return; 1 + 1; }": { "function a() { return; 1 + 1; }": {
errorMessage: /unreachable code/, errorMessage: /unreachable code/,
errorMessageName: "JSMSG_STMT_AFTER_RETURN", errorMessageName: "JSMSG_STMT_AFTER_RETURN",

View file

@ -996,14 +996,12 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
} }
aListener = nullptr; aListener = nullptr;
uint32_t lineNo = 0;
nsAutoCString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener")); nsAutoCString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
MOZ_ASSERT(body); MOZ_ASSERT(body);
MOZ_ASSERT(aElement); MOZ_ASSERT(aElement);
nsIURI *uri = aElement->OwnerDoc()->GetDocumentURI(); nsIURI *uri = aElement->OwnerDoc()->GetDocumentURI();
if (uri) { if (uri) {
uri->GetSpec(url); uri->GetSpec(url);
lineNo = 1;
} }
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mTarget); nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mTarget);
@ -1073,8 +1071,9 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
JS::CompileOptions options(cx); JS::CompileOptions options(cx);
// Use line 0 to make the function body starts from line 1.
options.setIntroductionType("eventHandler") options.setIntroductionType("eventHandler")
.setFileAndLine(url.get(), lineNo) .setFileAndLine(url.get(), 0)
.setVersion(JSVERSION_DEFAULT) .setVersion(JSVERSION_DEFAULT)
.setElement(&v.toObject()) .setElement(&v.toObject())
.setElementAttributeName(jsStr); .setElementAttributeName(jsStr);

View file

@ -7,6 +7,7 @@
#include "frontend/BytecodeCompiler.h" #include "frontend/BytecodeCompiler.h"
#include "mozilla/IntegerPrintfMacros.h" #include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Maybe.h"
#include "jscntxt.h" #include "jscntxt.h"
#include "jsscript.h" #include "jsscript.h"
@ -28,6 +29,7 @@
using namespace js; using namespace js;
using namespace js::frontend; using namespace js::frontend;
using mozilla::Maybe; using mozilla::Maybe;
using mozilla::Nothing;
class MOZ_STACK_CLASS AutoCompilationTraceLogger class MOZ_STACK_CLASS AutoCompilationTraceLogger
{ {
@ -57,24 +59,24 @@ class MOZ_STACK_CLASS BytecodeCompiler
// Call setters for optional arguments. // Call setters for optional arguments.
void maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor); void maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor);
void setSourceArgumentsNotIncluded();
JSScript* compileGlobalScript(ScopeKind scopeKind); JSScript* compileGlobalScript(ScopeKind scopeKind);
JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope); JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
ModuleObject* compileModule(); ModuleObject* compileModule();
bool compileFunctionBody(MutableHandleFunction fun, Handle<PropertyNameVector> formals, bool compileStandaloneFunction(MutableHandleFunction fun, GeneratorKind generatorKind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind); FunctionAsyncKind asyncKind,
Maybe<uint32_t> parameterListEnd);
ScriptSourceObject* sourceObjectPtr() const; ScriptSourceObject* sourceObjectPtr() const;
private: private:
JSScript* compileScript(HandleObject environment, SharedContext* sc); JSScript* compileScript(HandleObject environment, SharedContext* sc);
bool checkLength(); bool checkLength();
bool createScriptSource(); bool createScriptSource(Maybe<uint32_t> parameterListEnd);
bool maybeCompressSource(); bool maybeCompressSource();
bool canLazilyParse(); bool canLazilyParse();
bool createParser(); bool createParser();
bool createSourceAndParser(); bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
bool createScript(); bool createScript();
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext); bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
bool handleParseFailure(const Directives& newDirectives); bool handleParseFailure(const Directives& newDirectives);
@ -90,7 +92,6 @@ class MOZ_STACK_CLASS BytecodeCompiler
SourceBufferHolder& sourceBuffer; SourceBufferHolder& sourceBuffer;
RootedScope enclosingScope; RootedScope enclosingScope;
bool sourceArgumentsNotIncluded;
RootedScriptSource sourceObject; RootedScriptSource sourceObject;
ScriptSource* scriptSource; ScriptSource* scriptSource;
@ -130,7 +131,6 @@ BytecodeCompiler::BytecodeCompiler(ExclusiveContext* cx,
options(options), options(options),
sourceBuffer(sourceBuffer), sourceBuffer(sourceBuffer),
enclosingScope(cx, enclosingScope), enclosingScope(cx, enclosingScope),
sourceArgumentsNotIncluded(false),
sourceObject(cx), sourceObject(cx),
scriptSource(nullptr), scriptSource(nullptr),
sourceCompressor(nullptr), sourceCompressor(nullptr),
@ -147,12 +147,6 @@ BytecodeCompiler::maybeSetSourceCompressor(SourceCompressionTask* sourceCompress
this->sourceCompressor = sourceCompressor; this->sourceCompressor = sourceCompressor;
} }
void
BytecodeCompiler::setSourceArgumentsNotIncluded()
{
sourceArgumentsNotIncluded = true;
}
bool bool
BytecodeCompiler::checkLength() BytecodeCompiler::checkLength()
{ {
@ -169,12 +163,12 @@ BytecodeCompiler::checkLength()
} }
bool bool
BytecodeCompiler::createScriptSource() BytecodeCompiler::createScriptSource(Maybe<uint32_t> parameterListEnd)
{ {
if (!checkLength()) if (!checkLength())
return false; return false;
sourceObject = CreateScriptSourceObject(cx, options); sourceObject = CreateScriptSourceObject(cx, options, parameterListEnd);
if (!sourceObject) if (!sourceObject)
return false; return false;
@ -193,9 +187,7 @@ BytecodeCompiler::maybeCompressSource()
if (!cx->compartment()->behaviors().discardSource()) { if (!cx->compartment()->behaviors().discardSource()) {
if (options.sourceIsLazy) { if (options.sourceIsLazy) {
scriptSource->setSourceRetrievable(); scriptSource->setSourceRetrievable();
} else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceArgumentsNotIncluded, } else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceCompressor)) {
sourceCompressor))
{
return false; return false;
} }
} }
@ -242,9 +234,9 @@ BytecodeCompiler::createParser()
} }
bool bool
BytecodeCompiler::createSourceAndParser() BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = Nothing() */)
{ {
return createScriptSource() && return createScriptSource(parameterListEnd) &&
maybeCompressSource() && maybeCompressSource() &&
createParser(); createParser();
} }
@ -432,18 +424,19 @@ BytecodeCompiler::compileModule()
return module; 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 bool
BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun, BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
Handle<PropertyNameVector> formals,
GeneratorKind generatorKind, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind) FunctionAsyncKind asyncKind,
Maybe<uint32_t> parameterListEnd)
{ {
MOZ_ASSERT(fun); MOZ_ASSERT(fun);
MOZ_ASSERT(fun->isTenured()); MOZ_ASSERT(fun->isTenured());
fun->setArgCount(formals.length()); if (!createSourceAndParser(parameterListEnd))
if (!createSourceAndParser())
return false; return false;
// Speculatively parse using the default directives implied by the context. // Speculatively parse using the default directives implied by the context.
@ -454,8 +447,8 @@ BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
ParseNode* fn; ParseNode* fn;
do { do {
Directives newDirectives = directives; Directives newDirectives = directives;
fn = parser->standaloneFunctionBody(fun, enclosingScope, formals, generatorKind, asyncKind, fn = parser->standaloneFunction(fun, enclosingScope, parameterListEnd, generatorKind,
directives, &newDirectives); asyncKind, directives, &newDirectives);
if (!fn && !handleParseFailure(newDirectives)) if (!fn && !handleParseFailure(newDirectives))
return false; return false;
} while (!fn); } while (!fn);
@ -492,14 +485,15 @@ BytecodeCompiler::sourceObjectPtr() const
} }
ScriptSourceObject* 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>(); ScriptSource* ss = cx->new_<ScriptSource>();
if (!ss) if (!ss)
return nullptr; return nullptr;
ScriptSourceHolder ssHolder(ss); ScriptSourceHolder ssHolder(ss);
if (!ss->initFromOptions(cx, options)) if (!ss->initFromOptions(cx, options, parameterListEnd))
return nullptr; return nullptr;
RootedScriptSource sso(cx, ScriptSourceObject::create(cx, ss)); 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); return bce.emitFunctionScript(pn->pn_body);
} }
// Compile a JS function body, which might appear as the value of an event bool
// handler attribute in an HTML <INPUT> tag, or in a Function() constructor. frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
static bool const ReadOnlyCompileOptions& options,
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options, JS::SourceBufferHolder& srcBuf,
Handle<PropertyNameVector> formals, SourceBufferHolder& srcBuf, Maybe<uint32_t> parameterListEnd,
HandleScope enclosingScope, GeneratorKind generatorKind, HandleScope enclosingScope /* = nullptr */)
FunctionAsyncKind asyncKind)
{ {
MOZ_ASSERT(!options.isRunOnce); RootedScope scope(cx, enclosingScope);
if (!scope)
scope = &cx->global()->emptyGlobalScope();
// FIXME: make Function pass in two strings and parse them as arguments and BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, scope,
// ProgramElements respectively.
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, enclosingScope,
TraceLogger_ParserCompileFunction); TraceLogger_ParserCompileFunction);
compiler.setSourceArgumentsNotIncluded(); return compiler.compileStandaloneFunction(fun, NotGenerator, SyncFunction, parameterListEnd);
return compiler.compileFunctionBody(fun, formals, generatorKind, asyncKind);
} }
bool bool
frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, frontend::CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options, const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf, JS::SourceBufferHolder& srcBuf,
HandleScope enclosingScope) Maybe<uint32_t> parameterListEnd)
{
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)
{ {
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope()); RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
NotGenerator, SyncFunction); BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
TraceLogger_ParserCompileFunction);
return compiler.compileStandaloneFunction(fun, StarGenerator, SyncFunction, parameterListEnd);
} }
bool bool
frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun, frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options, const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
JS::SourceBufferHolder& srcBuf) Maybe<uint32_t> parameterListEnd)
{ {
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope()); RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
StarGenerator, SyncFunction);
}
bool BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
frontend::CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun, TraceLogger_ParserCompileFunction);
const ReadOnlyCompileOptions& options, return compiler.compileStandaloneFunction(fun, StarGenerator, AsyncFunction, parameterListEnd);
Handle<PropertyNameVector> formals,
JS::SourceBufferHolder& srcBuf)
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
StarGenerator, AsyncFunction);
} }

View file

@ -7,6 +7,8 @@
#ifndef frontend_BytecodeCompiler_h #ifndef frontend_BytecodeCompiler_h
#define frontend_BytecodeCompiler_h #define frontend_BytecodeCompiler_h
#include "mozilla/Maybe.h"
#include "NamespaceImports.h" #include "NamespaceImports.h"
#include "vm/Scope.h" #include "vm/Scope.h"
@ -51,22 +53,36 @@ CompileModule(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
MOZ_MUST_USE bool MOZ_MUST_USE bool
CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length); 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 MOZ_MUST_USE bool
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options, const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf, JS::SourceBufferHolder& srcBuf,
HandleScope enclosingScope); 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);
MOZ_MUST_USE bool MOZ_MUST_USE bool
CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun, CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options, const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf); JS::SourceBufferHolder& srcBuf,
mozilla::Maybe<uint32_t> parameterListEnd);
MOZ_MUST_USE bool
CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
JS::SourceBufferHolder& srcBuf,
mozilla::Maybe<uint32_t> parameterListEnd);
MOZ_MUST_USE bool MOZ_MUST_USE bool
CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun, CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
@ -74,7 +90,8 @@ CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf); Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
ScriptSourceObject* 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 * True if str consists of an IdentifierStart character, followed by one or

View file

@ -2245,9 +2245,9 @@ GetYieldHandling(GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
template <> template <>
ParseNode* ParseNode*
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
HandleScope enclosingScope, HandleScope enclosingScope,
Handle<PropertyNameVector> formals, Maybe<uint32_t> parameterListEnd,
GeneratorKind generatorKind, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind, FunctionAsyncKind asyncKind,
Directives inheritedDirectives, Directives inheritedDirectives,
@ -2274,25 +2274,14 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
if (!funpc.init()) if (!funpc.init())
return null(); return null();
funpc.setIsStandaloneFunctionBody(); 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); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction); AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction);
ParseNode* pn = functionBody(InAllowed, yieldHandling, Statement, StatementListBody); if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement,
if (!pn) parameterListEnd))
{
return null(); return null();
}
TokenKind tt; TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) if (!tokenStream.getToken(&tt, TokenStream::Operand))
@ -2303,15 +2292,7 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
return null(); return null();
} }
if (!FoldConstants(context, &pn, this)) if (!FoldConstants(context, &fn, this))
return null();
fn->pn_pos.end = pos().end;
MOZ_ASSERT(fn->pn_body->isKind(PNK_PARAMSBODY));
fn->pn_body->append(pn);
if (!finishFunction())
return null(); return null();
return fn; return fn;
@ -3415,7 +3396,8 @@ template <typename ParseHandler>
bool bool
Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling, Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
YieldHandling yieldHandling, 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 // Given a properly initialized parse context, try to parse an actual
// function without concern for conversion to strict mode, use of lazy // 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. // Parse the function body.
FunctionBodyType bodyType = StatementListBody; FunctionBodyType bodyType = StatementListBody;
TokenKind tt; TokenKind tt;
@ -3502,7 +3491,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
report(ParseError, false, null(), JSMSG_CURLY_AFTER_BODY); report(ParseError, false, null(), JSMSG_CURLY_AFTER_BODY);
return false; return false;
} }
funbox->bufEnd = pos().begin + 1; funbox->bufEnd = pos().end;
} else { } else {
#if !JS_HAS_EXPR_CLOSURES #if !JS_HAS_EXPR_CLOSURES
MOZ_ASSERT(kind == Arrow); MOZ_ASSERT(kind == Arrow);

View file

@ -1020,10 +1020,10 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Parse a module. // Parse a module.
Node moduleBody(ModuleSharedContext* modulesc); Node moduleBody(ModuleSharedContext* modulesc);
// Parse a function, given only its body. Used for the Function and // Parse a function, used for the Function, GeneratorFunction, and
// Generator constructors. // AsyncFunction constructors.
Node standaloneFunctionBody(HandleFunction fun, HandleScope enclosingScope, Node standaloneFunction(HandleFunction fun, HandleScope enclosingScope,
Handle<PropertyNameVector> formals, mozilla::Maybe<uint32_t> parameterListEnd,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
Directives inheritedDirectives, Directives* newDirectives); Directives inheritedDirectives, Directives* newDirectives);
@ -1041,7 +1041,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Parse a function's formal parameters and its body assuming its function // Parse a function's formal parameters and its body assuming its function
// ParseContext is already on the stack. // ParseContext is already on the stack.
bool functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling, 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 // Determine whether |yield| is a valid name in the current context, or
// whether it's prohibited due to strictness, JS version, or occurrence // whether it's prohibited due to strictness, JS version, or occurrence

View file

@ -84,10 +84,7 @@ function testArgumentFunction(pattern, input) {
'return [a, b, c, d, e, f];' 'return [a, b, c, d, e, f];'
)(input); )(input);
} }
// XXX: ES6 requires the `Function` constructor to accept arbitrary testAll(testArgumentFunction);
// `BindingElement`s as formal parameters. See Bug 1037939.
// Once fixed, please update the assertions below.
assertThrowsInstanceOf(() => testAll(testArgumentFunction), SyntaxError);
function testThrow(pattern, input) { function testThrow(pattern, input) {
return new Function('input', return new Function('input',

View file

@ -132,10 +132,9 @@ function testArgumentFunction(pattern, input, binding) {
'return ' + binding 'return ' + binding
)(input); )(input);
} }
// XXX: ES6 requires the `Function` constructor to accept arbitrary // ES6 requires the `Function` constructor to accept arbitrary
// `BindingElement`s as formal parameters. See Bug 1037939. // `BindingElement`s as formal parameters.
// Once fixed, please update the assertions below. testDeclaration(testArgumentFunction);
assertThrowsInstanceOf(() => testDeclaration(testArgumentFunction), SyntaxError);
function testThrow(pattern, input, binding) { function testThrow(pattern, input, binding) {
binding = binding || 'rest'; binding = binding || 'rest';

View file

@ -10,5 +10,5 @@ assertEq(arr.length, 10);
gc(); gc();
for (var i = 0; i < arr.length; i++) for (var i = 0; i < arr.length; i++)
assertEq(arr[i].lineCount, 1); assertEq(arr[i].lineCount, 3);

View file

@ -10,6 +10,6 @@ assertEq(arr.length, 100);
gc(g); gc(g);
for (var i = 0; i < arr.length; i++) for (var i = 0; i < arr.length; i++)
assertEq(arr[i].lineCount, 1); assertEq(arr[i].lineCount, 3);
gc(); gc();

View file

@ -20,6 +20,6 @@ function test(string, range) {
} }
test("eval('2 * 3')", [0, 5]); test("eval('2 * 3')", [0, 5]);
test("new Function('2 * 3')", [0, 5]); test("new Function('2 * 3')", [0, 12]);
test("new Function('x', 'x * x')", [0, 5]); test("new Function('x', 'x * x')", [0, 13]);
assertEq(count, 6); assertEq(count, 6);

View file

@ -329,6 +329,7 @@ MSG_DEF(JSMSG_TOO_MANY_LOCALS, 0, JSEXN_SYNTAXERR, "too many local varia
MSG_DEF(JSMSG_TOO_MANY_YIELDS, 0, JSEXN_SYNTAXERR, "too many yield expressions") MSG_DEF(JSMSG_TOO_MANY_YIELDS, 0, JSEXN_SYNTAXERR, "too many yield expressions")
MSG_DEF(JSMSG_TOUGH_BREAK, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch") MSG_DEF(JSMSG_TOUGH_BREAK, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch")
MSG_DEF(JSMSG_UNEXPECTED_TOKEN, 2, JSEXN_SYNTAXERR, "expected {0}, got {1}") MSG_DEF(JSMSG_UNEXPECTED_TOKEN, 2, JSEXN_SYNTAXERR, "expected {0}, got {1}")
MSG_DEF(JSMSG_UNEXPECTED_PARAMLIST_END,0, JSEXN_SYNTAXERR, "unexpected end of function parameter list")
MSG_DEF(JSMSG_UNNAMED_CLASS_STMT, 0, JSEXN_SYNTAXERR, "class statement requires a name") MSG_DEF(JSMSG_UNNAMED_CLASS_STMT, 0, JSEXN_SYNTAXERR, "class statement requires a name")
MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name") MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name")
MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 0, JSEXN_SYNTAXERR, "unterminated comment") MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 0, JSEXN_SYNTAXERR, "unterminated comment")

View file

@ -11,6 +11,7 @@
#include "jsapi.h" #include "jsapi.h"
#include "mozilla/FloatingPoint.h" #include "mozilla/FloatingPoint.h"
#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h" #include "mozilla/PodOperations.h"
#include "mozilla/Sprintf.h" #include "mozilla/Sprintf.h"
@ -107,6 +108,7 @@ using namespace js::gc;
using mozilla::Maybe; using mozilla::Maybe;
using mozilla::PodCopy; using mozilla::PodCopy;
using mozilla::PodZero; using mozilla::PodZero;
using mozilla::Some;
using JS::AutoGCRooter; using JS::AutoGCRooter;
using JS::ToInt32; using JS::ToInt32;
@ -4232,15 +4234,15 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun)
} }
/* /*
* enclosingScope is a static enclosing scope, if any (e.g. a WithScope). If * enclosingScope is a scope, if any (e.g. a WithScope). If the scope is the
* the enclosing scope is the global scope, this must be null. * global scope, this must be null.
* *
* enclosingDynamicScope is a dynamic scope to use, if it's not the global. * enclosingEnv is an environment to use, if it's not the global.
*/ */
static bool static bool
CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
const char* name, unsigned nargs, const char* const* argnames, const char* name,
SourceBufferHolder& srcBuf, SourceBufferHolder& srcBuf, uint32_t parameterListEnd,
HandleObject enclosingEnv, HandleScope enclosingScope, HandleObject enclosingEnv, HandleScope enclosingScope,
MutableHandleFunction fun) MutableHandleFunction fun)
{ {
@ -4256,13 +4258,6 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
return false; return false;
} }
Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
for (unsigned i = 0; i < nargs; i++) {
RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i])));
if (!argAtom || !formals.append(argAtom->asPropertyName()))
return false;
}
fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom, fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom,
/* proto = */ nullptr, /* proto = */ nullptr,
gc::AllocKind::FUNCTION, TenuredObject, gc::AllocKind::FUNCTION, TenuredObject,
@ -4275,7 +4270,45 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(enclosingEnv), MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(enclosingEnv),
enclosingScope->hasOnChain(ScopeKind::NonSyntactic)); enclosingScope->hasOnChain(ScopeKind::NonSyntactic));
if (!frontend::CompileFunctionBody(cx, fun, optionsArg, formals, srcBuf, enclosingScope)) if (!frontend::CompileStandaloneFunction(cx, fun, optionsArg, srcBuf,
Some(parameterListEnd), enclosingScope))
{
return false;
}
return true;
}
static MOZ_MUST_USE bool
BuildFunctionString(unsigned nargs, const char* const* argnames,
const SourceBufferHolder& srcBuf, StringBuffer* out,
uint32_t* parameterListEnd)
{
MOZ_ASSERT(out);
MOZ_ASSERT(parameterListEnd);
if (!out->ensureTwoByteChars())
return false;
if (!out->append("("))
return false;
for (unsigned i = 0; i < nargs; i++) {
if (i != 0) {
if (!out->append(", "))
return false;
}
if (!out->append(argnames[i], strlen(argnames[i])))
return false;
}
// Remember the position of ")".
*parameterListEnd = out->length();
MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
if (!out->append(FunctionConstructorMedialSigils))
return false;
if (!out->append(srcBuf.get(), srcBuf.length()))
return false;
if (!out->append(FunctionConstructorFinalBrace))
return false; return false;
return true; return true;
@ -4291,7 +4324,16 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
RootedScope scope(cx); RootedScope scope(cx);
if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope)) if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
return false; return false;
return CompileFunction(cx, options, name, nargs, argnames, srcBuf, env, scope, fun);
uint32_t parameterListEnd;
StringBuffer funStr(cx);
if (!BuildFunctionString(nargs, argnames, srcBuf, &funStr, &parameterListEnd))
return false;
size_t newLen = funStr.length();
SourceBufferHolder newSrcBuf(funStr.stealChars(), newLen, SourceBufferHolder::GiveOwnership);
return CompileFunction(cx, options, name, newSrcBuf, parameterListEnd, env, scope, fun);
} }
JS_PUBLIC_API(bool) JS_PUBLIC_API(bool)

View file

@ -12,6 +12,7 @@
#include "mozilla/ArrayUtils.h" #include "mozilla/ArrayUtils.h"
#include "mozilla/CheckedInt.h" #include "mozilla/CheckedInt.h"
#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h" #include "mozilla/PodOperations.h"
#include "mozilla/Range.h" #include "mozilla/Range.h"
@ -60,8 +61,10 @@ using namespace js::gc;
using namespace js::frontend; using namespace js::frontend;
using mozilla::ArrayLength; using mozilla::ArrayLength;
using mozilla::Maybe;
using mozilla::PodCopy; using mozilla::PodCopy;
using mozilla::RangedPtr; using mozilla::RangedPtr;
using mozilla::Some;
static bool static bool
fun_enumerate(JSContext* cx, HandleObject obj) fun_enumerate(JSContext* cx, HandleObject obj)
@ -985,19 +988,19 @@ js::FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t*
} }
JSString* JSString*
js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen) js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
{ {
if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx)) if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
return nullptr; return nullptr;
if (IsAsmJSModule(fun)) if (IsAsmJSModule(fun))
return AsmJSModuleToString(cx, fun, !lambdaParen); return AsmJSModuleToString(cx, fun, !prettyPrint);
if (IsAsmJSFunction(fun)) if (IsAsmJSFunction(fun))
return AsmJSFunctionToString(cx, fun); return AsmJSFunctionToString(cx, fun);
if (IsWrappedAsyncFunction(fun)) { if (IsWrappedAsyncFunction(fun)) {
RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun)); RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
return FunctionToString(cx, unwrapped, lambdaParen); return FunctionToString(cx, unwrapped, prettyPrint);
} }
StringBuffer out(cx); StringBuffer out(cx);
@ -1023,11 +1026,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() || bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
fun->isGetter() || fun->isSetter(); fun->isGetter() || fun->isSetter();
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
// If we're not in pretty mode, put parentheses around lambda functions and methods. // If we're not in pretty mode, put parentheses around lambda functions and methods.
if (fun->isInterpreted() && !lambdaParen && funIsMethodOrNonArrowLambda && if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) {
!fun->isSelfHostedBuiltin())
{
if (!out.append("(")) if (!out.append("("))
return nullptr; return nullptr;
} }
@ -1045,7 +1047,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
return nullptr; return nullptr;
} }
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
if (haveSource && !script->scriptSource()->hasSourceData() && if (haveSource && !script->scriptSource()->hasSourceData() &&
!JSScript::loadSource(cx, script->scriptSource(), &haveSource)) !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
{ {
@ -1056,54 +1057,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
if (!src) if (!src)
return nullptr; return nullptr;
// The source data for functions created by calling the Function
// constructor is only the function's body. This depends on the fact,
// asserted below, that in Function("function f() {}"), the inner
// function's sourceStart points to the '(', not the 'f'.
bool funCon = !fun->isArrow() &&
script->sourceStart() == 0 &&
script->sourceEnd() == script->scriptSource()->length() &&
script->scriptSource()->argumentsNotIncluded();
// Functions created with the constructor can't be arrow functions or
// expression closures.
MOZ_ASSERT_IF(funCon, !fun->isArrow());
MOZ_ASSERT_IF(funCon, !fun->isExprBody());
MOZ_ASSERT_IF(!funCon && !fun->isArrow(),
src->length() > 0 && src->latin1OrTwoByteChar(0) == '(');
bool buildBody = funCon;
if (buildBody) {
// This function was created with the Function constructor. We don't
// have source for the arguments, so we have to generate that. Part
// of bug 755821 should be cobbling the arguments passed into the
// Function constructor into the source string.
if (!out.append("("))
return nullptr;
// Fish out the argument names.
MOZ_ASSERT(script->numArgs() == fun->nargs());
BindingIter bi(script);
for (unsigned i = 0; i < fun->nargs(); i++, bi++) {
MOZ_ASSERT(bi.argumentSlot() == i);
if (i && !out.append(", "))
return nullptr;
if (i == unsigned(fun->nargs() - 1) && fun->hasRest() && !out.append("..."))
return nullptr;
if (!out.append(bi.name()))
return nullptr;
}
if (!out.append(") {\n"))
return nullptr;
}
if (!out.append(src)) if (!out.append(src))
return nullptr; return nullptr;
if (buildBody) {
if (!out.append("\n}")) if (!prettyPrint && funIsMethodOrNonArrowLambda) {
return nullptr;
}
if (!lambdaParen && funIsMethodOrNonArrowLambda) {
if (!out.append(")")) if (!out.append(")"))
return nullptr; return nullptr;
} }
@ -1114,8 +1071,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
{ {
return nullptr; return nullptr;
} }
if (!lambdaParen && fun->isLambda() && !fun->isArrow() && !out.append(")"))
return nullptr;
} else { } else {
MOZ_ASSERT(!fun->isExprBody()); MOZ_ASSERT(!fun->isExprBody());
@ -1657,17 +1612,6 @@ fun_isGenerator(JSContext* cx, unsigned argc, Value* vp)
return true; return true;
} }
/*
* Report "malformed formal parameter" iff no illegal char or similar scanner
* error was already reported.
*/
static bool
OnBadFormal(JSContext* cx)
{
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_FORMAL);
return false;
}
const JSFunctionSpec js::function_methods[] = { const JSFunctionSpec js::function_methods[] = {
#if JS_HAS_TOSOURCE #if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, fun_toSource, 0,0), JS_FN(js_toSource_str, fun_toSource, 0,0),
@ -1681,11 +1625,12 @@ const JSFunctionSpec js::function_methods[] = {
JS_FS_END JS_FS_END
}; };
// ES 2017 draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077 19.2.1.1.1.
static bool static bool
FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind, FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind) FunctionAsyncKind asyncKind)
{ {
/* Block this call if security callbacks forbid it. */ // Block this call if security callbacks forbid it.
Rooted<GlobalObject*> global(cx, &args.callee().global()); Rooted<GlobalObject*> global(cx, &args.callee().global());
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) { if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION); JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
@ -1717,82 +1662,65 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
introducerFilename = maybeScript->scriptSource()->introducerFilename(); introducerFilename = maybeScript->scriptSource()->introducerFilename();
CompileOptions options(cx); CompileOptions options(cx);
// Use line 0 to make the function body starts from line 1.
options.setMutedErrors(mutedErrors) options.setMutedErrors(mutedErrors)
.setFileAndLine(filename, 1) .setFileAndLine(filename, 0)
.setNoScriptRval(false) .setNoScriptRval(false)
.setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset); .setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset);
Vector<char16_t> paramStr(cx); StringBuffer sb(cx);
RootedString bodyText(cx);
if (args.length() == 0) { if (!sb.append('('))
bodyText = cx->names().empty; return false;
} else {
// Collect the function-argument arguments into one string, separated if (args.length() > 1) {
// by commas, then make a tokenstream from that string, and scan it to RootedString str(cx);
// get the arguments. We need to throw the full scanner at the
// problem because the argument string may contain comments, newlines, // Steps 5-6, 9.
// destructuring arguments, and similar manner of insanities. ("I have
// a feeling we're not in simple-comma-separated-parameters land any
// more, Toto....")
//
// XXX It'd be better if the parser provided utility methods to parse
// an argument list, and to parse a function body given a parameter
// list. But our parser provides no such pleasant interface now.
unsigned n = args.length() - 1; unsigned n = args.length() - 1;
// Convert the parameters-related arguments to strings, and determine
// the length of the string containing the overall parameter list.
mozilla::CheckedInt<uint32_t> paramStrLen = 0;
RootedString str(cx);
for (unsigned i = 0; i < n; i++) { for (unsigned i = 0; i < n; i++) {
// Steps 9.a-b, 9.d.i-ii.
str = ToString<CanGC>(cx, args[i]); str = ToString<CanGC>(cx, args[i]);
if (!str) if (!str)
return false; return false;
args[i].setString(str); // Steps 9.b, 9.d.iii.
paramStrLen += str->length(); if (!sb.append(str))
return false;
if (i < args.length() - 2) {
// Step 9.d.iii.
if (!sb.append(", "))
return false;
}
}
} }
// Tack in space for any combining commas. // Remember the position of ")".
if (n > 0) Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
paramStrLen += n - 1; MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
// Check for integer and string-size overflow. if (!sb.append(FunctionConstructorMedialSigils))
if (!paramStrLen.isValid() || paramStrLen.value() > JSString::MAX_LENGTH) { return false;
ReportAllocationOverflow(cx);
if (args.length() > 0) {
// Steps 7-8, 10.
RootedString body(cx, ToString<CanGC>(cx, args[args.length() - 1]));
if (!body || !sb.append(body))
return false; return false;
} }
uint32_t paramsLen = paramStrLen.value(); if (!sb.append(FunctionConstructorFinalBrace))
// Fill a vector with the comma-joined arguments. Careful! This
// string is *not* null-terminated!
MOZ_ASSERT(paramStr.length() == 0);
if (!paramStr.growBy(paramsLen)) {
ReportOutOfMemory(cx);
return false;
}
char16_t* cp = paramStr.begin();
for (unsigned i = 0; i < n; i++) {
JSLinearString* argLinear = args[i].toString()->ensureLinear(cx);
if (!argLinear)
return false; return false;
CopyChars(cp, *argLinear); // The parser only accepts two byte strings.
cp += argLinear->length(); if (!sb.ensureTwoByteChars())
return false;
if (i + 1 < n)
*cp++ = ','; RootedString functionText(cx, sb.finishString());
} if (!functionText)
MOZ_ASSERT(cp == paramStr.end());
bodyText = ToString(cx, args[n]);
if (!bodyText)
return false; return false;
}
/* /*
* NB: (new Function) is not lexically closed by its caller, it's just an * NB: (new Function) is not lexically closed by its caller, it's just an
@ -1802,24 +1730,22 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
*/ */
RootedAtom anonymousAtom(cx, cx->names().anonymous); RootedAtom anonymousAtom(cx, cx->names().anonymous);
// ES2017, draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077 // Step 24.
// 19.2.1.1.1 Runtime Semantics: CreateDynamicFunction, step 24.
RootedObject proto(cx); RootedObject proto(cx);
if (!isAsync) { if (!isAsync) {
if (!GetPrototypeFromCallableConstructor(cx, args, &proto)) if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
return false; return false;
} }
// 19.2.1.1.1, step 4.d, use %Generator% as the fallback prototype. // Step 4.d, use %Generator% as the fallback prototype.
// Also use %Generator% for the unwrapped function of async functions. // Also use %Generator% for the unwrapped function of async functions.
if (!proto && isStarGenerator) { if (!proto && isStarGenerator) {
// Unwrapped function of async function should use GeneratorFunction,
// while wrapped function isn't generator.
proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global); proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
if (!proto) if (!proto)
return false; return false;
} }
// Step 25-32 (reordered).
RootedObject globalLexical(cx, &global->lexicalEnvironment()); RootedObject globalLexical(cx, &global->lexicalEnvironment());
AllocKind allocKind = isAsync ? AllocKind::FUNCTION_EXTENDED : AllocKind::FUNCTION; AllocKind allocKind = isAsync ? AllocKind::FUNCTION_EXTENDED : AllocKind::FUNCTION;
RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0, RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
@ -1832,81 +1758,11 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
if (!JSFunction::setTypeForScriptedFunction(cx, fun)) if (!JSFunction::setTypeForScriptedFunction(cx, fun))
return false; return false;
// Steps 2.a-b, 3.a-b, 4.a-b, 11-23.
AutoStableStringChars stableChars(cx); AutoStableStringChars stableChars(cx);
if (!stableChars.initTwoByte(cx, bodyText)) if (!stableChars.initTwoByte(cx, functionText))
return false; return false;
bool hasRest = false;
Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
if (args.length() > 1) {
// Initialize a tokenstream to parse the new function's arguments. No
// StrictModeGetter is needed because this TokenStream won't report any
// strict mode errors. Strict mode errors that might be reported here
// (duplicate argument names, etc.) will be detected when we compile
// the function body.
//
// XXX Bug! We have to parse the body first to determine strictness.
// We have to know strictness to parse arguments correctly, in case
// arguments contains a strict mode violation. And we should be
// using full-fledged arguments parsing here, in order to handle
// destructuring and other exotic syntaxes.
AutoKeepAtoms keepAtoms(cx->perThreadData);
TokenStream ts(cx, options, paramStr.begin(), paramStr.length(),
/* strictModeGetter = */ nullptr);
bool yieldIsValidName = ts.versionNumber() < JSVERSION_1_7 && !isStarGenerator;
// The argument string may be empty or contain no tokens.
TokenKind tt;
if (!ts.getToken(&tt))
return false;
if (tt != TOK_EOF) {
while (true) {
// Check that it's a name.
if (hasRest) {
ts.reportError(JSMSG_PARAMETER_AFTER_REST);
return false;
}
if (tt == TOK_YIELD && yieldIsValidName)
tt = TOK_NAME;
if (tt != TOK_NAME) {
if (tt == TOK_TRIPLEDOT) {
hasRest = true;
if (!ts.getToken(&tt))
return false;
if (tt == TOK_YIELD && yieldIsValidName)
tt = TOK_NAME;
if (tt != TOK_NAME) {
ts.reportError(JSMSG_NO_REST_NAME);
return false;
}
} else {
return OnBadFormal(cx);
}
}
if (!formals.append(ts.currentName()))
return false;
// Get the next token. Stop on end of stream. Otherwise
// insist on a comma, get another name, and iterate.
if (!ts.getToken(&tt))
return false;
if (tt == TOK_EOF)
break;
if (tt != TOK_COMMA)
return OnBadFormal(cx);
if (!ts.getToken(&tt))
return false;
}
}
}
if (hasRest)
fun->setHasRest();
mozilla::Range<const char16_t> chars = stableChars.twoByteRange(); mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller() SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership ? SourceBufferHolder::GiveOwnership
@ -1914,11 +1770,13 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
bool ok; bool ok;
SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership); SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership);
if (isAsync) if (isAsync)
ok = frontend::CompileAsyncFunctionBody(cx, &fun, options, formals, srcBuf); ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf, parameterListEnd);
else if (isStarGenerator) else if (isStarGenerator)
ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf); ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd);
else else
ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf); ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd);
// Step 33.
args.rval().setObject(*fun); args.rval().setObject(*fun);
return ok; return ok;
} }

View file

@ -28,6 +28,9 @@ static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET = 2;
static const uint32_t JSSLOT_BOUND_FUNCTION_THIS = 3; static const uint32_t JSSLOT_BOUND_FUNCTION_THIS = 3;
static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS = 4; static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS = 4;
static const char FunctionConstructorMedialSigils[] = ") {\n";
static const char FunctionConstructorFinalBrace[] = "\n}";
class JSFunction : public js::NativeObject class JSFunction : public js::NativeObject
{ {
public: public:
@ -816,7 +819,7 @@ JSFunction::getExtendedSlot(size_t which) const
namespace js { namespace js {
JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen); JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPring);
template<XDRMode mode> template<XDRMode mode>
bool bool

View file

@ -1689,6 +1689,16 @@ ScriptSource::substringDontDeflate(JSContext* cx, size_t start, size_t stop)
return NewStringCopyNDontDeflate<CanGC>(cx, chars, len); return NewStringCopyNDontDeflate<CanGC>(cx, chars, len);
} }
JSFlatString*
ScriptSource::functionBodyString(JSContext* cx)
{
MOZ_ASSERT(isFunctionBody());
size_t start = parameterListEnd_ + (sizeof(FunctionConstructorMedialSigils) - 1);
size_t stop = length() - (sizeof(FunctionConstructorFinalBrace) - 1);
return substring(cx, start, stop);
}
MOZ_MUST_USE bool MOZ_MUST_USE bool
ScriptSource::setSource(ExclusiveContext* cx, ScriptSource::setSource(ExclusiveContext* cx,
mozilla::UniquePtr<char16_t[], JS::FreePolicy>&& source, mozilla::UniquePtr<char16_t[], JS::FreePolicy>&& source,
@ -1740,10 +1750,9 @@ ScriptSource::setCompressedSource(SharedImmutableString&& raw, size_t uncompress
bool bool
ScriptSource::setSourceCopy(ExclusiveContext* cx, SourceBufferHolder& srcBuf, ScriptSource::setSourceCopy(ExclusiveContext* cx, SourceBufferHolder& srcBuf,
bool argumentsNotIncluded, SourceCompressionTask* task) SourceCompressionTask* task)
{ {
MOZ_ASSERT(!hasSourceData()); MOZ_ASSERT(!hasSourceData());
argumentsNotIncluded_ = argumentsNotIncluded;
auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings(); auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
auto deduped = cache.getOrCreate(srcBuf.get(), srcBuf.length(), [&]() { auto deduped = cache.getOrCreate(srcBuf.get(), srcBuf.length(), [&]() {
@ -1940,16 +1949,6 @@ ScriptSource::performXDR(XDRState<mode>* xdr)
if (!xdr->codeUint32(&compressedLength)) if (!xdr->codeUint32(&compressedLength))
return false; return false;
{
uint8_t argumentsNotIncluded;
if (mode == XDR_ENCODE)
argumentsNotIncluded = argumentsNotIncluded_;
if (!xdr->codeUint8(&argumentsNotIncluded))
return false;
if (mode == XDR_DECODE)
argumentsNotIncluded_ = argumentsNotIncluded;
}
size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t)); size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t));
if (mode == XDR_DECODE) { if (mode == XDR_DECODE) {
uint8_t* p = xdr->cx()->template pod_malloc<uint8_t>(Max<size_t>(byteLen, 1)); uint8_t* p = xdr->cx()->template pod_malloc<uint8_t>(Max<size_t>(byteLen, 1));
@ -2074,7 +2073,8 @@ FormatIntroducedFilename(ExclusiveContext* cx, const char* filename, unsigned li
} }
bool bool
ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options) ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
Maybe<uint32_t> parameterListEnd)
{ {
MOZ_ASSERT(!filename_); MOZ_ASSERT(!filename_);
MOZ_ASSERT(!introducerFilename_); MOZ_ASSERT(!introducerFilename_);
@ -2083,6 +2083,7 @@ ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions
introductionType_ = options.introductionType; introductionType_ = options.introductionType;
setIntroductionOffset(options.introductionOffset); setIntroductionOffset(options.introductionOffset);
parameterListEnd_ = parameterListEnd.isSome() ? parameterListEnd.value() : 0;
if (options.hasIntroductionInfo) { if (options.hasIntroductionInfo) {
MOZ_ASSERT(options.introductionType != nullptr); MOZ_ASSERT(options.introductionType != nullptr);

View file

@ -10,6 +10,7 @@
#define jsscript_h #define jsscript_h
#include "mozilla/Atomics.h" #include "mozilla/Atomics.h"
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h" #include "mozilla/PodOperations.h"
#include "mozilla/Variant.h" #include "mozilla/Variant.h"
@ -399,6 +400,11 @@ class ScriptSource
// scripts. // scripts.
uint32_t introductionOffset_; uint32_t introductionOffset_;
// If this source is for Function constructor, the position of ")" after
// parameter list in the source. This is used to get function body.
// 0 for other cases.
uint32_t parameterListEnd_;
// If this ScriptSource was generated by a code-introduction mechanism such // If this ScriptSource was generated by a code-introduction mechanism such
// as |eval| or |new Function|, the debugger needs access to the "raw" // as |eval| or |new Function|, the debugger needs access to the "raw"
// filename of the top-level script that contains the eval-ing code. To // filename of the top-level script that contains the eval-ing code. To
@ -428,7 +434,6 @@ class ScriptSource
// demand. If sourceRetrievable_ and hasSourceData() are false, it is not // demand. If sourceRetrievable_ and hasSourceData() are false, it is not
// possible to get source at all. // possible to get source at all.
bool sourceRetrievable_:1; bool sourceRetrievable_:1;
bool argumentsNotIncluded_:1;
bool hasIntroductionOffset_:1; bool hasIntroductionOffset_:1;
const char16_t* chunkChars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder, const char16_t* chunkChars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
@ -443,10 +448,10 @@ class ScriptSource
sourceMapURL_(nullptr), sourceMapURL_(nullptr),
mutedErrors_(false), mutedErrors_(false),
introductionOffset_(0), introductionOffset_(0),
parameterListEnd_(0),
introducerFilename_(nullptr), introducerFilename_(nullptr),
introductionType_(nullptr), introductionType_(nullptr),
sourceRetrievable_(false), sourceRetrievable_(false),
argumentsNotIncluded_(false),
hasIntroductionOffset_(false) hasIntroductionOffset_(false)
{ {
} }
@ -461,10 +466,10 @@ class ScriptSource
if (--refs == 0) if (--refs == 0)
js_delete(this); js_delete(this);
} }
bool initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options); bool initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
bool setSourceCopy(ExclusiveContext* cx, bool setSourceCopy(ExclusiveContext* cx,
JS::SourceBufferHolder& srcBuf, JS::SourceBufferHolder& srcBuf,
bool argumentsNotIncluded,
SourceCompressionTask* tok); SourceCompressionTask* tok);
void setSourceRetrievable() { sourceRetrievable_ = true; } void setSourceRetrievable() { sourceRetrievable_ = true; }
bool sourceRetrievable() const { return sourceRetrievable_; } bool sourceRetrievable() const { return sourceRetrievable_; }
@ -492,11 +497,6 @@ class ScriptSource
return data.match(LengthMatcher()); return data.match(LengthMatcher());
} }
bool argumentsNotIncluded() const {
MOZ_ASSERT(hasSourceData());
return argumentsNotIncluded_;
}
// Return a string containing the chars starting at |begin| and ending at // Return a string containing the chars starting at |begin| and ending at
// |begin + len|. // |begin + len|.
const char16_t* chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& asp, const char16_t* chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& asp,
@ -504,6 +504,12 @@ class ScriptSource
JSFlatString* substring(JSContext* cx, size_t start, size_t stop); JSFlatString* substring(JSContext* cx, size_t start, size_t stop);
JSFlatString* substringDontDeflate(JSContext* cx, size_t start, size_t stop); JSFlatString* substringDontDeflate(JSContext* cx, size_t start, size_t stop);
bool isFunctionBody() {
return parameterListEnd_ != 0;
}
JSFlatString* functionBodyString(JSContext* cx);
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
JS::ScriptSourceInfo* info) const; JS::ScriptSourceInfo* info) const;
@ -567,6 +573,10 @@ class ScriptSource
introductionOffset_ = offset; introductionOffset_ = offset;
hasIntroductionOffset_ = true; hasIntroductionOffset_ = true;
} }
uint32_t parameterListEnd() const {
return parameterListEnd_;
}
}; };
class ScriptSourceHolder class ScriptSourceHolder

View file

@ -0,0 +1,27 @@
// This constructor behaves like `Function` without checking
// if the parameter list end is at the expected position.
// We use this to make sure that the tests we use are otherwise
// syntactically correct.
function DumpFunction(...args) {
let code = "function anonymous(";
code += args.slice(0, -1).join(", ");
code += ") {\n";
code += args[args.length -1];
code += "\n}";
eval(code);
}
const tests = [
["/*", "*/) {"],
["//", ") {"],
["a = `", "` ) {"],
[") { var x = function (", "} "],
["x = function (", "}) {"]
];
for (const test of tests) {
DumpFunction(...test);
assertThrowsInstanceOf(() => new Function(...test), SyntaxError);
}
reportCompare(0, 0, 'ok');

View file

@ -6890,8 +6890,13 @@ class DebuggerSourceGetTextMatcher
bool hasSourceData = ss->hasSourceData(); bool hasSourceData = ss->hasSourceData();
if (!ss->hasSourceData() && !JSScript::loadSource(cx_, ss, &hasSourceData)) if (!ss->hasSourceData() && !JSScript::loadSource(cx_, ss, &hasSourceData))
return nullptr; return nullptr;
return hasSourceData ? ss->substring(cx_, 0, ss->length()) if (!hasSourceData)
: NewStringCopyZ<CanGC>(cx_, "[no source]"); return NewStringCopyZ<CanGC>(cx_, "[no source]");
if (ss->isFunctionBody())
return ss->functionBodyString(cx_);
return ss->substring(cx_, 0, ss->length());
} }
ReturnType match(Handle<WasmInstanceObject*> wasmInstance) { ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {

View file

@ -21,6 +21,7 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/Compression.h" #include "mozilla/Compression.h"
#include "mozilla/MathAlgorithms.h" #include "mozilla/MathAlgorithms.h"
#include "mozilla/Maybe.h"
#include "jsmath.h" #include "jsmath.h"
#include "jsprf.h" #include "jsprf.h"
@ -8033,21 +8034,6 @@ TryInstantiate(JSContext* cx, CallArgs args, Module& module, const AsmJSMetadata
return true; return true;
} }
static MOZ_MUST_USE bool
MaybeAppendUTF8Name(JSContext* cx, const char* utf8Chars, MutableHandle<PropertyNameVector> names)
{
if (!utf8Chars)
return true;
UTF8Chars utf8(utf8Chars, strlen(utf8Chars));
JSAtom* atom = AtomizeUTF8Chars(cx, utf8Chars, strlen(utf8Chars));
if (!atom)
return false;
return names.append(atom->asPropertyName());
}
static bool static bool
HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& metadata) HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& metadata)
{ {
@ -8068,8 +8054,8 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
return false; return false;
} }
uint32_t begin = metadata.srcBodyStart; // starts right after 'use asm' uint32_t begin = metadata.srcStart;
uint32_t end = metadata.srcEndBeforeCurly(); uint32_t end = metadata.srcEndAfterCurly();
Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end)); Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end));
if (!src) if (!src)
return false; return false;
@ -8080,18 +8066,11 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
if (!fun) if (!fun)
return false; return false;
Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
if (!MaybeAppendUTF8Name(cx, metadata.globalArgumentName.get(), &formals))
return false;
if (!MaybeAppendUTF8Name(cx, metadata.importArgumentName.get(), &formals))
return false;
if (!MaybeAppendUTF8Name(cx, metadata.bufferArgumentName.get(), &formals))
return false;
CompileOptions options(cx); CompileOptions options(cx);
options.setMutedErrors(source->mutedErrors()) options.setMutedErrors(source->mutedErrors())
.setFile(source->filename()) .setFile(source->filename())
.setNoScriptRval(false); .setNoScriptRval(false);
options.asmJSOption = AsmJSOption::Disabled;
// The exported function inherits an implicit strict context if the module // The exported function inherits an implicit strict context if the module
// also inherited it somehow. // also inherited it somehow.
@ -8106,8 +8085,8 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller() SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership ? SourceBufferHolder::GiveOwnership
: SourceBufferHolder::NoOwnership; : SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, end - begin, ownership); SourceBufferHolder srcBuf(chars, stableChars.twoByteRange().length(), ownership);
if (!frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf)) if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing()))
return false; return false;
// Call the function we just recompiled. // Call the function we just recompiled.
@ -8849,23 +8828,6 @@ js::IsAsmJSModuleLoadedFromCache(JSContext* cx, unsigned argc, Value* vp)
/*****************************************************************************/ /*****************************************************************************/
// asm.js toString/toSource support // asm.js toString/toSource support
static MOZ_MUST_USE bool
MaybeAppendUTF8Chars(JSContext* cx, const char* sep, const char* utf8Chars, StringBuffer* sb)
{
if (!utf8Chars)
return true;
UTF8Chars utf8(utf8Chars, strlen(utf8Chars));
size_t length;
UniqueTwoByteChars twoByteChars(UTF8CharsToNewTwoByteCharsZ(cx, utf8, &length).get());
if (!twoByteChars)
return false;
return sb->append(sep, strlen(sep)) &&
sb->append(twoByteChars.get(), length);
}
JSString* JSString*
js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda) js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda)
{ {
@ -8895,33 +8857,12 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
if (!out.append("() {\n [sourceless code]\n}")) if (!out.append("() {\n [sourceless code]\n}"))
return nullptr; return nullptr;
} else { } else {
// Whether the function has been created with a Function ctor
bool funCtor = begin == 0 && end == source->length() && source->argumentsNotIncluded();
if (funCtor) {
// Functions created with the function constructor don't have arguments in their source.
if (!out.append("("))
return nullptr;
if (!MaybeAppendUTF8Chars(cx, "", metadata.globalArgumentName.get(), &out))
return nullptr;
if (!MaybeAppendUTF8Chars(cx, ", ", metadata.importArgumentName.get(), &out))
return nullptr;
if (!MaybeAppendUTF8Chars(cx, ", ", metadata.bufferArgumentName.get(), &out))
return nullptr;
if (!out.append(") {\n"))
return nullptr;
}
Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end)); Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
if (!src) if (!src)
return nullptr; return nullptr;
if (!out.append(src)) if (!out.append(src))
return nullptr; return nullptr;
if (funCtor && !out.append("\n}"))
return nullptr;
} }
if (addParenToLambda && fun->isLambda() && !out.append(")")) if (addParenToLambda && fun->isLambda() && !out.append(")"))
@ -8959,10 +8900,6 @@ js::AsmJSFunctionToString(JSContext* cx, HandleFunction fun)
if (!out.append("() {\n [sourceless code]\n}")) if (!out.append("() {\n [sourceless code]\n}"))
return nullptr; return nullptr;
} else { } else {
// asm.js functions cannot have been created with a Function constructor
// as they belong within a module.
MOZ_ASSERT(!(begin == 0 && end == source->length() && source->argumentsNotIncluded()));
Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end)); Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
if (!src) if (!src)
return nullptr; return nullptr;

View file

@ -130,7 +130,9 @@ PrepareScript(nsIURI* uri,
MutableHandleFunction function) MutableHandleFunction function)
{ {
JS::CompileOptions options(cx); JS::CompileOptions options(cx);
options.setFileAndLine(uriStr, 1) // Use line 0 to make the function body starts from line 1 when
// |reuseGlobal == true|.
options.setFileAndLine(uriStr, reuseGlobal ? 0 : 1)
.setVersion(JSVERSION_LATEST); .setVersion(JSVERSION_LATEST);
if (!charset.IsVoid()) { if (!charset.IsVoid()) {
char16_t* scriptBuf = nullptr; char16_t* scriptBuf = nullptr;