Bug 755821 - Parse arguments of Function constructor properly. r=shu

This commit is contained in:
Tom Schuster 2016-10-15 11:47:00 +09:00
Родитель 4d122614c2
Коммит 78e10f98ab
24 изменённых файлов: 328 добавлений и 477 удалений

Просмотреть файл

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

Просмотреть файл

@ -175,7 +175,6 @@ function* testJSTerm(hud) {
"JSMSG_BAD_RADIX": "(42).toString(0);",
"JSMSG_BAD_ARRAY_LENGTH": "([]).length = -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);",
};

Просмотреть файл

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

Просмотреть файл

@ -102,16 +102,6 @@ function doPageErrors()
warning: false,
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; }": {
errorMessage: /unreachable code/,
errorMessageName: "JSMSG_STMT_AFTER_RETURN",

Просмотреть файл

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

Просмотреть файл

@ -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);
RootedScope scope(cx, enclosingScope);
if (!scope)
scope = &cx->global()->emptyGlobalScope();
// FIXME: make Function pass in two strings and parse them as arguments and
// ProgramElements respectively.
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);
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
TraceLogger_ParserCompileFunction);
return compiler.compileStandaloneFunction(fun, StarGenerator, SyncFunction, parameterListEnd);
}
bool
frontend::CompileStarGeneratorBody(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, SyncFunction);
}
bool
frontend::CompileAsyncFunctionBody(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, AsyncFunction);
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
TraceLogger_ParserCompileFunction);
return compiler.compileStandaloneFunction(fun, StarGenerator, AsyncFunction, parameterListEnd);
}

Просмотреть файл

@ -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);
// 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);
CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
JS::SourceBufferHolder& srcBuf,
mozilla::Maybe<uint32_t> parameterListEnd,
HandleScope enclosingScope = nullptr);
MOZ_MUST_USE bool
CompileStarGeneratorBody(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
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

Просмотреть файл

@ -2279,13 +2279,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);
@ -2308,25 +2308,14 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
if (!funpc.init())
return null();
funpc.setIsStandaloneFunctionBody();
funpc.functionScope().useAsVarScope(&funpc);
if (formals.length() >= ARGNO_LIMIT) {
error(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))
@ -2336,15 +2325,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;
@ -3396,7 +3377,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
@ -3428,6 +3410,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) {
error(JSMSG_UNEXPECTED_PARAMLIST_END);
return false;
}
// Parse the function body.
FunctionBodyType bodyType = StatementListBody;
TokenKind tt;
@ -3483,7 +3472,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
error(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);

Просмотреть файл

@ -1050,12 +1050,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.
@ -1071,7 +1071,8 @@ 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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -332,6 +332,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_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_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_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name")
MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 0, JSEXN_SYNTAXERR, "unterminated comment")

Просмотреть файл

@ -11,6 +11,7 @@
#include "jsapi.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Sprintf.h"
@ -107,6 +108,7 @@ using namespace js::gc;
using mozilla::Maybe;
using mozilla::PodCopy;
using mozilla::PodZero;
using mozilla::Some;
using JS::AutoGCRooter;
using JS::ToInt32;
@ -4205,15 +4207,15 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun)
}
/*
* enclosingScope is a static enclosing scope, if any (e.g. a WithScope). If
* the enclosing scope is the global scope, this must be null.
* enclosingScope is a scope, if any (e.g. a WithScope). If the scope is the
* 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
CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
const char* name, unsigned nargs, const char* const* argnames,
SourceBufferHolder& srcBuf,
const char* name,
SourceBufferHolder& srcBuf, uint32_t parameterListEnd,
HandleObject enclosingEnv, HandleScope enclosingScope,
MutableHandleFunction fun)
{
@ -4229,13 +4231,6 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
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,
/* proto = */ nullptr,
gc::AllocKind::FUNCTION, TenuredObject,
@ -4248,7 +4243,45 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(enclosingEnv),
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 true;
@ -4264,7 +4297,16 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
RootedScope scope(cx);
if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
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)

Просмотреть файл

@ -12,6 +12,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Range.h"
@ -60,8 +61,10 @@ using namespace js::gc;
using namespace js::frontend;
using mozilla::ArrayLength;
using mozilla::Maybe;
using mozilla::PodCopy;
using mozilla::RangedPtr;
using mozilla::Some;
static bool
fun_enumerate(JSContext* cx, HandleObject obj)
@ -933,19 +936,19 @@ const Class JSFunction::class_ = {
const Class* const js::FunctionClassPtr = &JSFunction::class_;
JSString*
js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
{
if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
return nullptr;
if (IsAsmJSModule(fun))
return AsmJSModuleToString(cx, fun, !lambdaParen);
return AsmJSModuleToString(cx, fun, !prettyPrint);
if (IsAsmJSFunction(fun))
return AsmJSFunctionToString(cx, fun);
if (IsWrappedAsyncFunction(fun)) {
RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
return FunctionToString(cx, unwrapped, lambdaParen);
return FunctionToString(cx, unwrapped, prettyPrint);
}
StringBuffer out(cx);
@ -971,11 +974,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
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 (fun->isInterpreted() && !lambdaParen && funIsMethodOrNonArrowLambda &&
!fun->isSelfHostedBuiltin())
{
if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) {
if (!out.append("("))
return nullptr;
}
@ -993,7 +995,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
return nullptr;
}
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
if (haveSource && !script->scriptSource()->hasSourceData() &&
!JSScript::loadSource(cx, script->scriptSource(), &haveSource))
{
@ -1004,54 +1005,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
if (!src)
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))
return nullptr;
if (buildBody) {
if (!out.append("\n}"))
return nullptr;
}
if (!lambdaParen && funIsMethodOrNonArrowLambda) {
if (!prettyPrint && funIsMethodOrNonArrowLambda) {
if (!out.append(")"))
return nullptr;
}
@ -1062,8 +1019,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
{
return nullptr;
}
if (!lambdaParen && fun->isLambda() && !fun->isArrow() && !out.append(")"))
return nullptr;
} else {
MOZ_ASSERT(!fun->isExprBody());
@ -1605,17 +1560,6 @@ fun_isGenerator(JSContext* cx, unsigned argc, Value* vp)
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[] = {
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, fun_toSource, 0,0),
@ -1629,11 +1573,12 @@ const JSFunctionSpec js::function_methods[] = {
JS_FS_END
};
// ES 2017 draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077 19.2.1.1.1.
static bool
FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind,
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());
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
@ -1665,83 +1610,66 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
introducerFilename = maybeScript->scriptSource()->introducerFilename();
CompileOptions options(cx);
// Use line 0 to make the function body starts from line 1.
options.setMutedErrors(mutedErrors)
.setFileAndLine(filename, 1)
.setFileAndLine(filename, 0)
.setNoScriptRval(false)
.setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset);
Vector<char16_t> paramStr(cx);
RootedString bodyText(cx);
StringBuffer sb(cx);
if (args.length() == 0) {
bodyText = cx->names().empty;
} else {
// Collect the function-argument arguments into one string, separated
// by commas, then make a tokenstream from that string, and scan it to
// get the arguments. We need to throw the full scanner at the
// problem because the argument string may contain comments, newlines,
// 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.
if (!sb.append('('))
return false;
if (args.length() > 1) {
RootedString str(cx);
// Steps 5-6, 9.
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++) {
// Steps 9.a-b, 9.d.i-ii.
str = ToString<CanGC>(cx, args[i]);
if (!str)
return false;
args[i].setString(str);
paramStrLen += str->length();
// Steps 9.b, 9.d.iii.
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.
if (n > 0)
paramStrLen += n - 1;
// Check for integer and string-size overflow.
if (!paramStrLen.isValid() || paramStrLen.value() > JSString::MAX_LENGTH) {
ReportAllocationOverflow(cx);
return false;
}
uint32_t paramsLen = paramStrLen.value();
// 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;
CopyChars(cp, *argLinear);
cp += argLinear->length();
if (i + 1 < n)
*cp++ = ',';
}
MOZ_ASSERT(cp == paramStr.end());
bodyText = ToString(cx, args[n]);
if (!bodyText)
return false;
}
// Remember the position of ")".
Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
if (!sb.append(FunctionConstructorMedialSigils))
return false;
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;
}
if (!sb.append(FunctionConstructorFinalBrace))
return false;
// The parser only accepts two byte strings.
if (!sb.ensureTwoByteChars())
return false;
RootedString functionText(cx, sb.finishString());
if (!functionText)
return false;
/*
* NB: (new Function) is not lexically closed by its caller, it's just an
* anonymous function in the top-level scope that its constructor inhabits.
@ -1750,24 +1678,22 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
*/
RootedAtom anonymousAtom(cx, cx->names().anonymous);
// ES2017, draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077
// 19.2.1.1.1 Runtime Semantics: CreateDynamicFunction, step 24.
// Step 24.
RootedObject proto(cx);
if (!isAsync) {
if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
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.
if (!proto && isStarGenerator) {
// Unwrapped function of async function should use GeneratorFunction,
// while wrapped function isn't generator.
proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
if (!proto)
return false;
}
// Step 25-32 (reordered).
RootedObject globalLexical(cx, &global->lexicalEnvironment());
AllocKind allocKind = isAsync ? AllocKind::FUNCTION_EXTENDED : AllocKind::FUNCTION;
RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
@ -1780,81 +1706,11 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
if (!JSFunction::setTypeForScriptedFunction(cx, fun))
return false;
// Steps 2.a-b, 3.a-b, 4.a-b, 11-23.
AutoStableStringChars stableChars(cx);
if (!stableChars.initTwoByte(cx, bodyText))
if (!stableChars.initTwoByte(cx, functionText))
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();
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
@ -1862,11 +1718,13 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
bool ok;
SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership);
if (isAsync)
ok = frontend::CompileAsyncFunctionBody(cx, &fun, options, formals, srcBuf);
ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf, parameterListEnd);
else if (isStarGenerator)
ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf);
ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd);
else
ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf);
ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd);
// Step 33.
args.rval().setObject(*fun);
return ok;
}

Просмотреть файл

@ -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_ARGS = 4;
static const char FunctionConstructorMedialSigils[] = ") {\n";
static const char FunctionConstructorFinalBrace[] = "\n}";
class JSFunction : public js::NativeObject
{
public:
@ -812,7 +815,7 @@ JSFunction::getExtendedSlot(size_t which) const
namespace js {
JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen);
JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPring);
template<XDRMode mode>
bool

Просмотреть файл

@ -1675,6 +1675,16 @@ ScriptSource::substringDontDeflate(JSContext* cx, size_t start, size_t stop)
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
ScriptSource::setSource(ExclusiveContext* cx,
mozilla::UniquePtr<char16_t[], JS::FreePolicy>&& source,
@ -1726,10 +1736,9 @@ ScriptSource::setCompressedSource(SharedImmutableString&& raw, size_t uncompress
bool
ScriptSource::setSourceCopy(ExclusiveContext* cx, SourceBufferHolder& srcBuf,
bool argumentsNotIncluded, SourceCompressionTask* task)
SourceCompressionTask* task)
{
MOZ_ASSERT(!hasSourceData());
argumentsNotIncluded_ = argumentsNotIncluded;
auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
auto deduped = cache.getOrCreate(srcBuf.get(), srcBuf.length(), [&]() {
@ -1926,16 +1935,6 @@ ScriptSource::performXDR(XDRState<mode>* xdr)
if (!xdr->codeUint32(&compressedLength))
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));
if (mode == XDR_DECODE) {
uint8_t* p = xdr->cx()->template pod_malloc<uint8_t>(Max<size_t>(byteLen, 1));
@ -2060,7 +2059,8 @@ FormatIntroducedFilename(ExclusiveContext* cx, const char* filename, unsigned li
}
bool
ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
Maybe<uint32_t> parameterListEnd)
{
MOZ_ASSERT(!filename_);
MOZ_ASSERT(!introducerFilename_);
@ -2069,6 +2069,7 @@ ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions
introductionType_ = options.introductionType;
setIntroductionOffset(options.introductionOffset);
parameterListEnd_ = parameterListEnd.isSome() ? parameterListEnd.value() : 0;
if (options.hasIntroductionInfo) {
MOZ_ASSERT(options.introductionType != nullptr);

Просмотреть файл

@ -10,6 +10,7 @@
#define jsscript_h
#include "mozilla/Atomics.h"
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Variant.h"
@ -399,6 +400,11 @@ class ScriptSource
// scripts.
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
// 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
@ -428,7 +434,6 @@ class ScriptSource
// demand. If sourceRetrievable_ and hasSourceData() are false, it is not
// possible to get source at all.
bool sourceRetrievable_:1;
bool argumentsNotIncluded_:1;
bool hasIntroductionOffset_:1;
const char16_t* chunkChars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
@ -443,10 +448,10 @@ class ScriptSource
sourceMapURL_(nullptr),
mutedErrors_(false),
introductionOffset_(0),
parameterListEnd_(0),
introducerFilename_(nullptr),
introductionType_(nullptr),
sourceRetrievable_(false),
argumentsNotIncluded_(false),
hasIntroductionOffset_(false)
{
}
@ -461,10 +466,10 @@ class ScriptSource
if (--refs == 0)
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,
JS::SourceBufferHolder& srcBuf,
bool argumentsNotIncluded,
SourceCompressionTask* tok);
void setSourceRetrievable() { sourceRetrievable_ = true; }
bool sourceRetrievable() const { return sourceRetrievable_; }
@ -492,11 +497,6 @@ class ScriptSource
return data.match(LengthMatcher());
}
bool argumentsNotIncluded() const {
MOZ_ASSERT(hasSourceData());
return argumentsNotIncluded_;
}
// Return a string containing the chars starting at |begin| and ending at
// |begin + len|.
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* substringDontDeflate(JSContext* cx, size_t start, size_t stop);
bool isFunctionBody() {
return parameterListEnd_ != 0;
}
JSFlatString* functionBodyString(JSContext* cx);
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
JS::ScriptSourceInfo* info) const;
@ -567,6 +573,10 @@ class ScriptSource
introductionOffset_ = offset;
hasIntroductionOffset_ = true;
}
uint32_t parameterListEnd() const {
return parameterListEnd_;
}
};
class ScriptSourceHolder

Просмотреть файл

@ -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');

Просмотреть файл

@ -6885,8 +6885,13 @@ class DebuggerSourceGetTextMatcher
bool hasSourceData = ss->hasSourceData();
if (!ss->hasSourceData() && !JSScript::loadSource(cx_, ss, &hasSourceData))
return nullptr;
return hasSourceData ? ss->substring(cx_, 0, ss->length())
: NewStringCopyZ<CanGC>(cx_, "[no source]");
if (!hasSourceData)
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) {

Просмотреть файл

@ -21,6 +21,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/Compression.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Maybe.h"
#include "jsmath.h"
#include "jsprf.h"
@ -8035,21 +8036,6 @@ TryInstantiate(JSContext* cx, CallArgs args, Module& module, const AsmJSMetadata
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
HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& metadata)
{
@ -8070,8 +8056,8 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
return false;
}
uint32_t begin = metadata.srcBodyStart; // starts right after 'use asm'
uint32_t end = metadata.srcEndBeforeCurly();
uint32_t begin = metadata.srcStart;
uint32_t end = metadata.srcEndAfterCurly();
Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end));
if (!src)
return false;
@ -8082,18 +8068,11 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
if (!fun)
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);
options.setMutedErrors(source->mutedErrors())
.setFile(source->filename())
.setNoScriptRval(false);
options.asmJSOption = AsmJSOption::Disabled;
// The exported function inherits an implicit strict context if the module
// also inherited it somehow.
@ -8108,8 +8087,8 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
: SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, end - begin, ownership);
if (!frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf))
SourceBufferHolder srcBuf(chars, stableChars.twoByteRange().length(), ownership);
if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing()))
return false;
// Call the function we just recompiled.
@ -8853,23 +8832,6 @@ js::IsAsmJSModuleLoadedFromCache(JSContext* cx, unsigned argc, Value* vp)
/*****************************************************************************/
// 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*
js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda)
{
@ -8899,33 +8861,12 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
if (!out.append("() {\n [sourceless code]\n}"))
return nullptr;
} 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));
if (!src)
return nullptr;
if (!out.append(src))
return nullptr;
if (funCtor && !out.append("\n}"))
return nullptr;
}
if (addParenToLambda && fun->isLambda() && !out.append(")"))
@ -8963,10 +8904,6 @@ js::AsmJSFunctionToString(JSContext* cx, HandleFunction fun)
if (!out.append("() {\n [sourceless code]\n}"))
return nullptr;
} 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));
if (!src)
return nullptr;

Просмотреть файл

@ -129,7 +129,9 @@ PrepareScript(nsIURI* uri,
MutableHandleFunction function)
{
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);
if (!charset.IsVoid()) {
char16_t* scriptBuf = nullptr;