зеркало из https://github.com/mozilla/gecko-dev.git
Bug 755821 - Parse arguments of Function constructor properly. r=shu
This commit is contained in:
Родитель
4d122614c2
Коммит
78e10f98ab
|
@ -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, ¶meterListEnd))
|
||||
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)
|
||||
|
|
276
js/src/jsfun.cpp
276
js/src/jsfun.cpp
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче