mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-26 15:02:46 +00:00
import from UXP:
- Issue #960, Stage 1-1: Implement Function.prototype.toString revision proposal. (b68de773) - Issue #960, Stage 1-2: Remove a space after comma in parameter list for generated function source. (90817221) - Issue #960, Stage 1-3: Generate better source in Object.prototype.toSource. (f2622bd1) - Issue #960, Stage 1-4: Update tests (5676f63f)
This commit is contained in:
@@ -24,7 +24,7 @@ var inputTests = [
|
||||
{
|
||||
input: "(function() { return 42; })",
|
||||
output: "function ()",
|
||||
printOutput: "function () { return 42; }",
|
||||
printOutput: "function() { return 42; }",
|
||||
suppressClick: true
|
||||
},
|
||||
|
||||
@@ -40,7 +40,7 @@ var inputTests = [
|
||||
{
|
||||
input: "testobj1.testfn2",
|
||||
output: "function testfn2()",
|
||||
printOutput: "function () { return 42; }",
|
||||
printOutput: "function() { return 42; }",
|
||||
suppressClick: true
|
||||
},
|
||||
|
||||
|
||||
@@ -29,12 +29,12 @@ function run_test_with_server(server, cb) {
|
||||
addSources(debuggee);
|
||||
|
||||
threadClient.getSources(Task.async(function* (res) {
|
||||
do_check_true(res.sources.length === 3, "3 sources exist");
|
||||
do_check_eq(res.sources.length, 3, "3 sources exist");
|
||||
|
||||
yield threadClient.reconfigure({ useSourceMaps: false });
|
||||
|
||||
threadClient.getSources(function(res) {
|
||||
do_check_true(res.sources.length === 1, "1 source exist");
|
||||
do_check_eq(res.sources.length, 1, "1 source exist");
|
||||
client.close().then(cb);
|
||||
});
|
||||
}));
|
||||
|
||||
+193
-87
@@ -9,11 +9,13 @@
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jsstr.h"
|
||||
|
||||
#include "builtin/Eval.h"
|
||||
#include "frontend/BytecodeCompiler.h"
|
||||
#include "jit/InlinableNatives.h"
|
||||
#include "js/UniquePtr.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
@@ -124,6 +126,27 @@ obj_toSource(JSContext* cx, unsigned argc, Value* vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
static bool
|
||||
Consume(const CharT*& s, const CharT* e, const char *chars)
|
||||
{
|
||||
size_t len = strlen(chars);
|
||||
if (s + len >= e)
|
||||
return false;
|
||||
if (!EqualChars(s, chars, len))
|
||||
return false;
|
||||
s += len;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
static void
|
||||
ConsumeSpaces(const CharT*& s, const CharT* e)
|
||||
{
|
||||
while (*s == ' ' && s < e)
|
||||
s++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a function source string, return the offset and length of the part
|
||||
* between '(function $name' and ')'.
|
||||
@@ -133,37 +156,53 @@ static bool
|
||||
ArgsAndBodySubstring(mozilla::Range<const CharT> chars, size_t* outOffset, size_t* outLen)
|
||||
{
|
||||
const CharT* const start = chars.begin().get();
|
||||
const CharT* const end = chars.end().get();
|
||||
const CharT* s = start;
|
||||
const CharT* e = chars.end().get();
|
||||
|
||||
uint8_t parenChomp = 0;
|
||||
if (s[0] == '(') {
|
||||
if (s == e)
|
||||
return false;
|
||||
|
||||
// Remove enclosing parentheses.
|
||||
if (*s == '(' && *(e - 1) == ')') {
|
||||
s++;
|
||||
parenChomp = 1;
|
||||
e--;
|
||||
}
|
||||
|
||||
/* Try to jump "function" keyword. */
|
||||
s = js_strchr_limit(s, ' ', end);
|
||||
if (!s)
|
||||
return false;
|
||||
(void) Consume(s, e, "async");
|
||||
ConsumeSpaces(s, e);
|
||||
(void) (Consume(s, e, "function") || Consume(s, e, "get") || Consume(s, e, "set"));
|
||||
ConsumeSpaces(s, e);
|
||||
(void) Consume(s, e, "*");
|
||||
ConsumeSpaces(s, e);
|
||||
|
||||
/*
|
||||
* Jump over the function's name: it can't be encoded as part
|
||||
* of an ECMA getter or setter.
|
||||
*/
|
||||
s = js_strchr_limit(s, '(', end);
|
||||
if (!s)
|
||||
return false;
|
||||
|
||||
if (*s == ' ')
|
||||
// Jump over the function's name.
|
||||
if (Consume(s, e, "[")) {
|
||||
s = js_strchr_limit(s, ']', e);
|
||||
if (!s)
|
||||
return false;
|
||||
s++;
|
||||
ConsumeSpaces(s, e);
|
||||
if (*s != '(')
|
||||
return false;
|
||||
} else {
|
||||
s = js_strchr_limit(s, '(', e);
|
||||
if (!s)
|
||||
return false;
|
||||
}
|
||||
|
||||
*outOffset = s - start;
|
||||
*outLen = end - s - parenChomp;
|
||||
*outLen = e - s;
|
||||
MOZ_ASSERT(*outOffset + *outLen <= chars.length());
|
||||
return true;
|
||||
}
|
||||
|
||||
enum class PropertyKind {
|
||||
Getter,
|
||||
Setter,
|
||||
Method,
|
||||
Normal
|
||||
};
|
||||
|
||||
JSString*
|
||||
js::ObjectToSource(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
@@ -182,59 +221,28 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
|
||||
if (!buf.append('{'))
|
||||
return nullptr;
|
||||
|
||||
RootedValue v0(cx), v1(cx);
|
||||
MutableHandleValue val[2] = {&v0, &v1};
|
||||
|
||||
RootedString str0(cx), str1(cx);
|
||||
MutableHandleString gsop[2] = {&str0, &str1};
|
||||
|
||||
AutoIdVector idv(cx);
|
||||
if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_SYMBOLS, &idv))
|
||||
return nullptr;
|
||||
|
||||
bool comma = false;
|
||||
for (size_t i = 0; i < idv.length(); ++i) {
|
||||
RootedId id(cx, idv[i]);
|
||||
Rooted<PropertyDescriptor> desc(cx);
|
||||
if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
|
||||
return nullptr;
|
||||
|
||||
int valcnt = 0;
|
||||
if (desc.object()) {
|
||||
if (desc.isAccessorDescriptor()) {
|
||||
if (desc.hasGetterObject() && desc.getterObject()) {
|
||||
val[valcnt].setObject(*desc.getterObject());
|
||||
gsop[valcnt].set(cx->names().get);
|
||||
valcnt++;
|
||||
}
|
||||
if (desc.hasSetterObject() && desc.setterObject()) {
|
||||
val[valcnt].setObject(*desc.setterObject());
|
||||
gsop[valcnt].set(cx->names().set);
|
||||
valcnt++;
|
||||
}
|
||||
} else {
|
||||
valcnt = 1;
|
||||
val[0].set(desc.value());
|
||||
gsop[0].set(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
auto AddProperty = [cx, &comma, &buf](HandleId id, HandleValue val, PropertyKind kind) -> bool {
|
||||
/* Convert id to a string. */
|
||||
RootedString idstr(cx);
|
||||
if (JSID_IS_SYMBOL(id)) {
|
||||
RootedValue v(cx, SymbolValue(JSID_TO_SYMBOL(id)));
|
||||
idstr = ValueToSource(cx, v);
|
||||
if (!idstr)
|
||||
return nullptr;
|
||||
return false;
|
||||
} else {
|
||||
RootedValue idv(cx, IdToValue(id));
|
||||
idstr = ToString<CanGC>(cx, idv);
|
||||
if (!idstr)
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
/*
|
||||
* If id is a string that's not an identifier, or if it's a negative
|
||||
* integer, then it must be quoted.
|
||||
* If id is a string that's not an identifier, or if it's a
|
||||
* negative integer, then it must be quoted.
|
||||
*/
|
||||
if (JSID_IS_ATOM(id)
|
||||
? !IsIdentifier(JSID_TO_ATOM(id))
|
||||
@@ -242,28 +250,65 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
idstr = QuoteString(cx, idstr, char16_t('\''));
|
||||
if (!idstr)
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < valcnt; j++) {
|
||||
/* Convert val[j] to its canonical source form. */
|
||||
JSString* valsource = ValueToSource(cx, val[j]);
|
||||
if (!valsource)
|
||||
return nullptr;
|
||||
RootedString valsource(cx, ValueToSource(cx, val));
|
||||
if (!valsource)
|
||||
return false;
|
||||
|
||||
RootedLinearString valstr(cx, valsource->ensureLinear(cx));
|
||||
if (!valstr)
|
||||
return nullptr;
|
||||
RootedLinearString valstr(cx, valsource->ensureLinear(cx));
|
||||
if (!valstr)
|
||||
return false;
|
||||
|
||||
size_t voffset = 0;
|
||||
size_t vlength = valstr->length();
|
||||
if (comma && !buf.append(", "))
|
||||
return false;
|
||||
comma = true;
|
||||
|
||||
/*
|
||||
* Remove '(function ' from the beginning of valstr and ')' from the
|
||||
* end so that we can put "get" in front of the function definition.
|
||||
*/
|
||||
if (gsop[j] && IsFunctionObject(val[j])) {
|
||||
size_t voffset, vlength;
|
||||
|
||||
// Methods and accessors can return exact syntax of source, that fits
|
||||
// into property without adding property name or "get"/"set" prefix.
|
||||
// Use the exact syntax when the following conditions are met:
|
||||
//
|
||||
// * It's a function object
|
||||
// (exclude proxies)
|
||||
// * Function's kind and property's kind are same
|
||||
// (this can be false for dynamically defined properties)
|
||||
// * Function has explicit name
|
||||
// (this can be false for computed property and dynamically defined
|
||||
// properties)
|
||||
// * Function's name and property's name are same
|
||||
// (this can be false for dynamically defined properties)
|
||||
if (kind == PropertyKind::Getter || kind == PropertyKind::Setter ||
|
||||
kind == PropertyKind::Method)
|
||||
{
|
||||
RootedFunction fun(cx);
|
||||
if (val.toObject().is<JSFunction>()) {
|
||||
fun = &val.toObject().as<JSFunction>();
|
||||
// Method's case should be checked on caller.
|
||||
if (((fun->isGetter() && kind == PropertyKind::Getter) ||
|
||||
(fun->isSetter() && kind == PropertyKind::Setter) ||
|
||||
kind == PropertyKind::Method) &&
|
||||
fun->explicitName())
|
||||
{
|
||||
bool result;
|
||||
if (!EqualStrings(cx, fun->explicitName(), idstr, &result))
|
||||
return false;
|
||||
|
||||
if (result) {
|
||||
if (!buf.append(valstr))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// When falling back try to generate a better string
|
||||
// representation by skipping the prelude, and also removing
|
||||
// the enclosing parentheses.
|
||||
bool success;
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (valstr->hasLatin1Chars())
|
||||
@@ -271,29 +316,90 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
|
||||
else
|
||||
success = ArgsAndBodySubstring(valstr->twoByteRange(nogc), &voffset, &vlength);
|
||||
if (!success)
|
||||
gsop[j].set(nullptr);
|
||||
kind = PropertyKind::Normal;
|
||||
}
|
||||
|
||||
if (comma && !buf.append(", "))
|
||||
return nullptr;
|
||||
comma = true;
|
||||
if (kind == PropertyKind::Getter) {
|
||||
if (!buf.append("get "))
|
||||
return false;
|
||||
} else if (kind == PropertyKind::Setter) {
|
||||
if (!buf.append("set "))
|
||||
return false;
|
||||
} else if (kind == PropertyKind::Method && fun) {
|
||||
if (IsWrappedAsyncFunction(fun)) {
|
||||
if (!buf.append("async "))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gsop[j]) {
|
||||
if (!buf.append(gsop[j]) || !buf.append(' '))
|
||||
if (fun->isStarGenerator()) {
|
||||
if (!buf.append('*'))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool needsBracket = JSID_IS_SYMBOL(id);
|
||||
if (needsBracket && !buf.append('['))
|
||||
return false;
|
||||
if (!buf.append(idstr))
|
||||
return false;
|
||||
if (needsBracket && !buf.append(']'))
|
||||
return false;
|
||||
|
||||
if (kind == PropertyKind::Getter || kind == PropertyKind::Setter ||
|
||||
kind == PropertyKind::Method)
|
||||
{
|
||||
if (!buf.appendSubstring(valstr, voffset, vlength))
|
||||
return false;
|
||||
} else {
|
||||
if (!buf.append(':'))
|
||||
return false;
|
||||
if (!buf.append(valstr))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
RootedId id(cx);
|
||||
Rooted<PropertyDescriptor> desc(cx);
|
||||
RootedValue val(cx);
|
||||
RootedFunction fun(cx);
|
||||
for (size_t i = 0; i < idv.length(); ++i) {
|
||||
id = idv[i];
|
||||
if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
|
||||
return nullptr;
|
||||
|
||||
if (!desc.object())
|
||||
continue;
|
||||
|
||||
if (desc.isAccessorDescriptor()) {
|
||||
if (desc.hasGetterObject() && desc.getterObject()) {
|
||||
val.setObject(*desc.getterObject());
|
||||
if (!AddProperty(id, val, PropertyKind::Getter))
|
||||
return nullptr;
|
||||
}
|
||||
if (JSID_IS_SYMBOL(id) && !buf.append('['))
|
||||
return nullptr;
|
||||
if (!buf.append(idstr))
|
||||
return nullptr;
|
||||
if (JSID_IS_SYMBOL(id) && !buf.append(']'))
|
||||
return nullptr;
|
||||
if (!buf.append(gsop[j] ? ' ' : ':'))
|
||||
return nullptr;
|
||||
|
||||
if (!buf.appendSubstring(valstr, voffset, vlength))
|
||||
return nullptr;
|
||||
if (desc.hasSetterObject() && desc.setterObject()) {
|
||||
val.setObject(*desc.setterObject());
|
||||
if (!AddProperty(id, val, PropertyKind::Setter))
|
||||
return nullptr;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
val.set(desc.value());
|
||||
if (IsFunctionObject(val, fun.address())) {
|
||||
if (IsWrappedAsyncFunction(fun))
|
||||
fun = GetUnwrappedAsyncFunction(fun);
|
||||
|
||||
if (fun->isMethod()) {
|
||||
if (!AddProperty(id, val, PropertyKind::Method))
|
||||
return nullptr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AddProperty(id, val, PropertyKind::Normal))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!buf.append('}'))
|
||||
|
||||
@@ -77,7 +77,7 @@ class MOZ_STACK_CLASS BytecodeCompiler
|
||||
bool canLazilyParse();
|
||||
bool createParser();
|
||||
bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
|
||||
bool createScript();
|
||||
bool createScript(uint32_t preludeStart = 0);
|
||||
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
|
||||
bool handleParseFailure(const Directives& newDirectives);
|
||||
bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
|
||||
@@ -242,10 +242,11 @@ BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = No
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeCompiler::createScript()
|
||||
BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */)
|
||||
{
|
||||
script = JSScript::Create(cx, options,
|
||||
sourceObject, /* sourceStart = */ 0, sourceBuffer.length());
|
||||
sourceObject, /* sourceStart = */ 0, sourceBuffer.length(),
|
||||
preludeStart);
|
||||
return script != nullptr;
|
||||
}
|
||||
|
||||
@@ -457,7 +458,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
|
||||
if (fn->pn_funbox->function()->isInterpreted()) {
|
||||
MOZ_ASSERT(fun == fn->pn_funbox->function());
|
||||
|
||||
if (!createScript())
|
||||
if (!createScript(fn->pn_funbox->preludeStart))
|
||||
return false;
|
||||
|
||||
Maybe<BytecodeEmitter> emitter;
|
||||
@@ -651,7 +652,8 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
|
||||
MOZ_ASSERT(sourceObject);
|
||||
|
||||
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
|
||||
lazy->begin(), lazy->end()));
|
||||
lazy->begin(), lazy->end(),
|
||||
lazy->preludeStart()));
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -109,6 +109,8 @@ IsIdentifier(JSLinearString* str);
|
||||
* As above, but taking chars + length.
|
||||
*/
|
||||
bool
|
||||
IsIdentifier(const char* chars, size_t length);
|
||||
bool
|
||||
IsIdentifier(const char16_t* chars, size_t length);
|
||||
|
||||
/* True if str is a keyword. Defined in TokenStream.cpp. */
|
||||
|
||||
@@ -7846,7 +7846,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
|
||||
|
||||
Rooted<JSObject*> sourceObject(cx, script->sourceObject());
|
||||
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
|
||||
funbox->bufStart, funbox->bufEnd));
|
||||
funbox->bufStart, funbox->bufEnd,
|
||||
funbox->preludeStart));
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
|
||||
+103
-58
@@ -441,7 +441,8 @@ UsedNameTracker::rewind(RewindToken token)
|
||||
}
|
||||
|
||||
FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead,
|
||||
JSFunction* fun, Directives directives, bool extraWarnings,
|
||||
JSFunction* fun, uint32_t preludeStart,
|
||||
Directives directives, bool extraWarnings,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
|
||||
: ObjectBox(fun, traceListHead),
|
||||
SharedContext(cx, Kind::ObjectBox, directives, extraWarnings),
|
||||
@@ -454,6 +455,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac
|
||||
bufEnd(0),
|
||||
startLine(1),
|
||||
startColumn(0),
|
||||
preludeStart(preludeStart),
|
||||
length(0),
|
||||
generatorKindBits_(GeneratorKindAsBits(generatorKind)),
|
||||
asyncKindBits_(AsyncKindAsBits(asyncKind)),
|
||||
@@ -797,7 +799,8 @@ Parser<ParseHandler>::newObjectBox(JSObject* obj)
|
||||
|
||||
template <typename ParseHandler>
|
||||
FunctionBox*
|
||||
Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, Directives inheritedDirectives,
|
||||
Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart,
|
||||
Directives inheritedDirectives,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
bool tryAnnexB)
|
||||
{
|
||||
@@ -812,8 +815,9 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, Directives inheri
|
||||
* function.
|
||||
*/
|
||||
FunctionBox* funbox =
|
||||
alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, inheritedDirectives,
|
||||
options().extraWarningsOption, generatorKind, asyncKind);
|
||||
alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, preludeStart,
|
||||
inheritedDirectives, options().extraWarningsOption,
|
||||
generatorKind, asyncKind);
|
||||
if (!funbox) {
|
||||
ReportOutOfMemory(context);
|
||||
return nullptr;
|
||||
@@ -2258,6 +2262,7 @@ Parser<SyntaxParseHandler>::finishFunction(bool isStandaloneFunction /* = false
|
||||
LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(),
|
||||
pc->innerFunctionsForLazy, versionNumber(),
|
||||
funbox->bufStart, funbox->bufEnd,
|
||||
funbox->preludeStart,
|
||||
funbox->startLine, funbox->startColumn);
|
||||
if (!lazy)
|
||||
return false;
|
||||
@@ -2313,6 +2318,33 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
|
||||
{
|
||||
MOZ_ASSERT(checkOptionsCalled);
|
||||
|
||||
// Skip prelude.
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
if (asyncKind == AsyncFunction) {
|
||||
MOZ_ASSERT(tt == TOK_ASYNC);
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
}
|
||||
MOZ_ASSERT(tt == TOK_FUNCTION);
|
||||
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
if (generatorKind == StarGenerator && asyncKind == SyncFunction) {
|
||||
MOZ_ASSERT(tt == TOK_MUL);
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
}
|
||||
|
||||
// Skip function name, if present.
|
||||
if (tt == TOK_NAME || tt == TOK_YIELD) {
|
||||
MOZ_ASSERT(tokenStream.currentName() == fun->explicitName());
|
||||
} else {
|
||||
MOZ_ASSERT(fun->explicitName() == nullptr);
|
||||
tokenStream.ungetToken();
|
||||
}
|
||||
|
||||
Node fn = handler.newFunctionStatement();
|
||||
if (!fn)
|
||||
return null();
|
||||
@@ -2322,8 +2354,8 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
|
||||
return null();
|
||||
fn->pn_body = argsbody;
|
||||
|
||||
FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind,
|
||||
asyncKind, /* tryAnnexB = */ false);
|
||||
FunctionBox* funbox = newFunctionBox(fn, fun, /* preludeStart = */ 0, inheritedDirectives,
|
||||
generatorKind, asyncKind, /* tryAnnexB = */ false);
|
||||
if (!funbox)
|
||||
return null();
|
||||
funbox->initStandaloneFunction(enclosingScope);
|
||||
@@ -2341,7 +2373,6 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
|
||||
return null();
|
||||
}
|
||||
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
if (tt != TOK_EOF) {
|
||||
@@ -2995,8 +3026,8 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKind kind,
|
||||
bool tryAnnexB)
|
||||
Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart,
|
||||
FunctionSyntaxKind kind, bool tryAnnexB)
|
||||
{
|
||||
// When a lazily-parsed function is called, we only fully parse (and emit)
|
||||
// that function, not any of its nested children. The initial syntax-only
|
||||
@@ -3005,7 +3036,7 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin
|
||||
|
||||
RootedFunction fun(context, handler.nextLazyInnerFunction());
|
||||
MOZ_ASSERT(!fun->isLegacyGenerator());
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, Directives(/* strict = */ false),
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, Directives(/* strict = */ false),
|
||||
fun->generatorKind(), fun->asyncKind(), tryAnnexB);
|
||||
if (!funbox)
|
||||
return false;
|
||||
@@ -3042,8 +3073,8 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind,
|
||||
bool tryAnnexB)
|
||||
Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, uint32_t preludeStart,
|
||||
FunctionSyntaxKind kind, bool tryAnnexB)
|
||||
{
|
||||
MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing");
|
||||
}
|
||||
@@ -3119,7 +3150,7 @@ Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::functionDefinition(Node pn, InHandling inHandling,
|
||||
Parser<ParseHandler>::functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling,
|
||||
YieldHandling yieldHandling, HandleAtom funName,
|
||||
FunctionSyntaxKind kind,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
@@ -3132,7 +3163,7 @@ Parser<ParseHandler>::functionDefinition(Node pn, InHandling inHandling,
|
||||
// functions, which are also lazy. Instead, their free variables and
|
||||
// source extents are recorded and may be skipped.
|
||||
if (handler.canSkipLazyInnerFunctions()) {
|
||||
if (!skipLazyInnerFunction(pn, kind, tryAnnexB))
|
||||
if (!skipLazyInnerFunction(pn, preludeStart, kind, tryAnnexB))
|
||||
return null();
|
||||
return pn;
|
||||
}
|
||||
@@ -3165,8 +3196,9 @@ Parser<ParseHandler>::functionDefinition(Node pn, InHandling inHandling,
|
||||
// reparse a function due to failed syntax parsing and encountering new
|
||||
// "use foo" directives.
|
||||
while (true) {
|
||||
if (trySyntaxParseInnerFunction(pn, fun, inHandling, yieldHandling, kind, generatorKind,
|
||||
asyncKind, tryAnnexB, directives, &newDirectives))
|
||||
if (trySyntaxParseInnerFunction(pn, fun, preludeStart, inHandling, yieldHandling, kind,
|
||||
generatorKind, asyncKind, tryAnnexB, directives,
|
||||
&newDirectives))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -3193,6 +3225,7 @@ Parser<ParseHandler>::functionDefinition(Node pn, InHandling inHandling,
|
||||
template <>
|
||||
bool
|
||||
Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun,
|
||||
uint32_t preludeStart,
|
||||
InHandling inHandling,
|
||||
YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind,
|
||||
@@ -3226,14 +3259,15 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
|
||||
// Make a FunctionBox before we enter the syntax parser, because |pn|
|
||||
// still expects a FunctionBox to be attached to it during BCE, and
|
||||
// the syntax parser cannot attach one to it.
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind,
|
||||
asyncKind, tryAnnexB);
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives,
|
||||
generatorKind, asyncKind, tryAnnexB);
|
||||
if (!funbox)
|
||||
return false;
|
||||
funbox->initWithEnclosingParseContext(pc, kind);
|
||||
|
||||
if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, inHandling,
|
||||
yieldHandling, kind, inheritedDirectives, newDirectives))
|
||||
if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, preludeStart,
|
||||
inHandling, yieldHandling, kind,
|
||||
inheritedDirectives, newDirectives))
|
||||
{
|
||||
if (parser->hadAbortedSyntaxParse()) {
|
||||
// Try again with a full parse. UsedNameTracker needs to be
|
||||
@@ -3259,13 +3293,14 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
|
||||
} while (false);
|
||||
|
||||
// We failed to do a syntax parse above, so do the full parse.
|
||||
return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind,
|
||||
tryAnnexB, inheritedDirectives, newDirectives);
|
||||
return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind,
|
||||
generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction fun,
|
||||
uint32_t preludeStart,
|
||||
InHandling inHandling,
|
||||
YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind,
|
||||
@@ -3276,13 +3311,14 @@ Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction
|
||||
Directives* newDirectives)
|
||||
{
|
||||
// This is already a syntax parser, so just parse the inner function.
|
||||
return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind,
|
||||
tryAnnexB, inheritedDirectives, newDirectives);
|
||||
return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind,
|
||||
generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox,
|
||||
uint32_t preludeStart,
|
||||
InHandling inHandling, YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind, Directives inheritedDirectives,
|
||||
Directives* newDirectives)
|
||||
@@ -3306,6 +3342,7 @@ Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox*
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun,
|
||||
uint32_t preludeStart,
|
||||
InHandling inHandling, YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
@@ -3317,14 +3354,14 @@ Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFuncti
|
||||
// parser. In that case, outerpc is a ParseContext from the full parser
|
||||
// instead of the current top of the stack of the syntax parser.
|
||||
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind,
|
||||
asyncKind, tryAnnexB);
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives,
|
||||
generatorKind, asyncKind, tryAnnexB);
|
||||
if (!funbox)
|
||||
return false;
|
||||
funbox->initWithEnclosingParseContext(outerpc, kind);
|
||||
|
||||
return innerFunction(pn, outerpc, funbox, inHandling, yieldHandling, kind, inheritedDirectives,
|
||||
newDirectives);
|
||||
return innerFunction(pn, outerpc, funbox, preludeStart, inHandling, yieldHandling, kind,
|
||||
inheritedDirectives, newDirectives);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
@@ -3359,8 +3396,8 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
|
||||
return null();
|
||||
|
||||
Directives directives(strict);
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind,
|
||||
/* tryAnnexB = */ false);
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, /* preludeStart = */ 0, directives,
|
||||
generatorKind, asyncKind, /* tryAnnexB = */ false);
|
||||
if (!funbox)
|
||||
return null();
|
||||
funbox->initFromLazyFunction();
|
||||
@@ -3529,8 +3566,8 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling,
|
||||
FunctionAsyncKind asyncKind)
|
||||
Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHandling,
|
||||
DefaultHandling defaultHandling, FunctionAsyncKind asyncKind)
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
|
||||
|
||||
@@ -3614,13 +3651,14 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
|
||||
return null();
|
||||
|
||||
YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind);
|
||||
return functionDefinition(pn, InAllowed, newYieldHandling, name, Statement, generatorKind,
|
||||
return functionDefinition(preludeStart, pn, InAllowed, newYieldHandling, name, Statement, generatorKind,
|
||||
asyncKind, tryAnnexB);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind asyncKind)
|
||||
Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invoked,
|
||||
FunctionAsyncKind asyncKind)
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
|
||||
|
||||
@@ -3658,7 +3696,7 @@ Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind
|
||||
if (invoked)
|
||||
pn = handler.setLikelyIIFE(pn);
|
||||
|
||||
return functionDefinition(pn, InAllowed, yieldHandling, name, Expression, generatorKind,
|
||||
return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, name, Expression, generatorKind,
|
||||
asyncKind);
|
||||
}
|
||||
|
||||
@@ -5076,7 +5114,7 @@ Parser<FullParseHandler>::exportDeclaration()
|
||||
}
|
||||
|
||||
case TOK_FUNCTION:
|
||||
kid = functionStmt(YieldIsKeyword, NameRequired);
|
||||
kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired);
|
||||
if (!kid)
|
||||
return null();
|
||||
|
||||
@@ -5116,7 +5154,7 @@ Parser<FullParseHandler>::exportDeclaration()
|
||||
ParseNode* nameNode = nullptr;
|
||||
switch (tt) {
|
||||
case TOK_FUNCTION:
|
||||
kid = functionStmt(YieldIsKeyword, AllowDefaultName);
|
||||
kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName);
|
||||
if (!kid)
|
||||
return null();
|
||||
break;
|
||||
@@ -5136,7 +5174,7 @@ Parser<FullParseHandler>::exportDeclaration()
|
||||
|
||||
if (nextSameLine == TOK_FUNCTION) {
|
||||
tokenStream.consumeKnownToken(nextSameLine);
|
||||
kid = functionStmt(YieldIsName, AllowDefaultName, AsyncFunction);
|
||||
kid = functionStmt(pos().begin, YieldIsName, AllowDefaultName, AsyncFunction);
|
||||
if (!kid)
|
||||
return null();
|
||||
break;
|
||||
@@ -5246,7 +5284,7 @@ Parser<ParseHandler>::consequentOrAlternative(YieldHandling yieldHandling)
|
||||
// Peek only on the same line: ExpressionStatement's lookahead
|
||||
// restriction is phrased as
|
||||
//
|
||||
// [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }]
|
||||
// [lookahead ??{ {, function, async [no LineTerminator here] function, class, let [ }]
|
||||
//
|
||||
// meaning that code like this is valid:
|
||||
//
|
||||
@@ -5289,7 +5327,7 @@ Parser<ParseHandler>::consequentOrAlternative(YieldHandling yieldHandling)
|
||||
return null();
|
||||
|
||||
TokenPos funcPos = pos();
|
||||
Node fun = functionStmt(yieldHandling, NameRequired);
|
||||
Node fun = functionStmt(pos().begin, yieldHandling, NameRequired);
|
||||
if (!fun)
|
||||
return null();
|
||||
|
||||
@@ -5536,7 +5574,7 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
|
||||
MOZ_ASSERT(isForIn != isForOf);
|
||||
|
||||
// In a for-of loop, 'let' that starts the loop head is a |let| keyword,
|
||||
// per the [lookahead ≠ let] restriction on the LeftHandSideExpression
|
||||
// per the [lookahead ??let] restriction on the LeftHandSideExpression
|
||||
// variant of such loops. Expressions that start with |let| can't be used
|
||||
// here.
|
||||
//
|
||||
@@ -6230,7 +6268,7 @@ Parser<ParseHandler>::labeledItem(YieldHandling yieldHandling)
|
||||
return null();
|
||||
}
|
||||
|
||||
return functionStmt(yieldHandling, NameRequired);
|
||||
return functionStmt(pos().begin, yieldHandling, NameRequired);
|
||||
}
|
||||
|
||||
tokenStream.ungetToken();
|
||||
@@ -6709,7 +6747,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
||||
if (!tokenStream.isCurrentTokenType(TOK_RB))
|
||||
funName = propAtom;
|
||||
}
|
||||
Node fn = methodDefinition(propType, funName);
|
||||
Node fn = methodDefinition(nameOffset, propType, funName);
|
||||
if (!fn)
|
||||
return null();
|
||||
|
||||
@@ -6920,7 +6958,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
|
||||
}
|
||||
|
||||
// NOTE: It's unfortunately allowed to have a label named 'let' in
|
||||
// non-strict code. 💯
|
||||
// non-strict code. ?’¯
|
||||
if (next == TOK_COLON)
|
||||
return labeledStatement(yieldHandling);
|
||||
|
||||
@@ -7101,8 +7139,9 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
|
||||
if (!tokenStream.peekTokenSameLine(&nextSameLine))
|
||||
return null();
|
||||
if (nextSameLine == TOK_FUNCTION) {
|
||||
uint32_t preludeStart = pos().begin;
|
||||
tokenStream.consumeKnownToken(TOK_FUNCTION);
|
||||
return functionStmt(yieldHandling, NameRequired, AsyncFunction);
|
||||
return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7182,7 +7221,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
|
||||
|
||||
// HoistableDeclaration[?Yield, ~Default]
|
||||
case TOK_FUNCTION:
|
||||
return functionStmt(yieldHandling, NameRequired);
|
||||
return functionStmt(pos().begin, yieldHandling, NameRequired);
|
||||
|
||||
// ClassDeclaration[?Yield, ~Default]
|
||||
case TOK_CLASS:
|
||||
@@ -7650,8 +7689,10 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
||||
|
||||
tokenStream.seek(start);
|
||||
|
||||
if (!tokenStream.peekToken(&next, TokenStream::Operand))
|
||||
if (!tokenStream.getToken(&next, TokenStream::Operand))
|
||||
return null();
|
||||
uint32_t preludeStart = pos().begin;
|
||||
tokenStream.ungetToken();
|
||||
|
||||
GeneratorKind generatorKind = NotGenerator;
|
||||
FunctionAsyncKind asyncKind = SyncFunction;
|
||||
@@ -7681,7 +7722,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
||||
if (!pn)
|
||||
return null();
|
||||
|
||||
Node arrowFunc = functionDefinition(pn, inHandling, yieldHandling, nullptr,
|
||||
Node arrowFunc = functionDefinition(preludeStart, pn, inHandling, yieldHandling, nullptr,
|
||||
Arrow, generatorKind, asyncKind);
|
||||
if (!arrowFunc)
|
||||
return null();
|
||||
@@ -7997,8 +8038,8 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
|
||||
|
||||
// Create box for fun->object early to root it.
|
||||
Directives directives(/* strict = */ outerpc->sc()->strict());
|
||||
FunctionBox* genFunbox = newFunctionBox(genfn, fun, directives, StarGenerator, SyncFunction,
|
||||
/* tryAnnexB = */ false);
|
||||
FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* preludeStart = */ 0, directives,
|
||||
StarGenerator, SyncFunction, /* tryAnnexB = */ false);
|
||||
if (!genFunbox)
|
||||
return null();
|
||||
genFunbox->isGenexpLambda = true;
|
||||
@@ -8030,12 +8071,14 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
|
||||
|
||||
uint32_t end = pos().end;
|
||||
handler.setBeginPosition(comp, begin);
|
||||
handler.setEndPosition(comp, pos().end);
|
||||
handler.setEndPosition(comp, end);
|
||||
genFunbox->bufEnd = end;
|
||||
handler.addStatementToList(body, comp);
|
||||
handler.setEndPosition(body, pos().end);
|
||||
handler.setEndPosition(body, end);
|
||||
handler.setBeginPosition(genfn, begin);
|
||||
handler.setEndPosition(genfn, pos().end);
|
||||
handler.setEndPosition(genfn, end);
|
||||
|
||||
Node generator = newDotGeneratorName();
|
||||
if (!generator)
|
||||
@@ -9265,7 +9308,7 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
||||
}
|
||||
}
|
||||
|
||||
Node fn = methodDefinition(propType, funName);
|
||||
Node fn = methodDefinition(namePos.begin, propType, funName);
|
||||
if (!fn)
|
||||
return null();
|
||||
|
||||
@@ -9292,7 +9335,8 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::methodDefinition(PropertyType propType, HandleAtom funName)
|
||||
Parser<ParseHandler>::methodDefinition(uint32_t preludeStart, PropertyType propType,
|
||||
HandleAtom funName)
|
||||
{
|
||||
FunctionSyntaxKind kind;
|
||||
switch (propType) {
|
||||
@@ -9345,7 +9389,7 @@ Parser<ParseHandler>::methodDefinition(PropertyType propType, HandleAtom funName
|
||||
if (!pn)
|
||||
return null();
|
||||
|
||||
return functionDefinition(pn, InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind);
|
||||
return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
@@ -9406,7 +9450,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
|
||||
|
||||
switch (tt) {
|
||||
case TOK_FUNCTION:
|
||||
return functionExpr(invoked);
|
||||
return functionExpr(pos().begin, invoked);
|
||||
|
||||
case TOK_CLASS:
|
||||
return classDefinition(yieldHandling, ClassExpression, NameRequired);
|
||||
@@ -9474,8 +9518,9 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
|
||||
return null();
|
||||
|
||||
if (nextSameLine == TOK_FUNCTION) {
|
||||
uint32_t preludeStart = pos().begin;
|
||||
tokenStream.consumeKnownToken(TOK_FUNCTION);
|
||||
return functionExpr(PredictUninvoked, AsyncFunction);
|
||||
return functionExpr(preludeStart, PredictUninvoked, AsyncFunction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-10
@@ -1031,7 +1031,8 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
* cx->tempLifoAlloc.
|
||||
*/
|
||||
ObjectBox* newObjectBox(JSObject* obj);
|
||||
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, Directives directives,
|
||||
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart,
|
||||
Directives directives,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
bool tryAnnexB);
|
||||
|
||||
@@ -1103,8 +1104,9 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
|
||||
// Parse an inner function given an enclosing ParseContext and a
|
||||
// FunctionBox for the inner function.
|
||||
bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, InHandling inHandling,
|
||||
YieldHandling yieldHandling, FunctionSyntaxKind kind,
|
||||
bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t preludeStart,
|
||||
InHandling inHandling, YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind,
|
||||
Directives inheritedDirectives, Directives* newDirectives);
|
||||
|
||||
// Parse a function's formal parameters and its body assuming its function
|
||||
@@ -1136,9 +1138,10 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
* Some parsers have two versions: an always-inlined version (with an 'i'
|
||||
* suffix) and a never-inlined version (with an 'n' suffix).
|
||||
*/
|
||||
Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling,
|
||||
Node functionStmt(uint32_t preludeStart,
|
||||
YieldHandling yieldHandling, DefaultHandling defaultHandling,
|
||||
FunctionAsyncKind asyncKind = SyncFunction);
|
||||
Node functionExpr(InvokedPrediction invoked = PredictUninvoked,
|
||||
Node functionExpr(uint32_t preludeStart, InvokedPrediction invoked = PredictUninvoked,
|
||||
FunctionAsyncKind asyncKind = SyncFunction);
|
||||
|
||||
Node statementList(YieldHandling yieldHandling);
|
||||
@@ -1269,7 +1272,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
bool tryNewTarget(Node& newTarget);
|
||||
bool checkAndMarkSuperScope();
|
||||
|
||||
Node methodDefinition(PropertyType propType, HandleAtom funName);
|
||||
Node methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName);
|
||||
|
||||
/*
|
||||
* Additional JS parsers.
|
||||
@@ -1277,7 +1280,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
|
||||
Node funcpn);
|
||||
|
||||
Node functionDefinition(Node func, InHandling inHandling, YieldHandling yieldHandling,
|
||||
Node functionDefinition(uint32_t preludeStart, Node func, InHandling inHandling, YieldHandling yieldHandling,
|
||||
HandleAtom name, FunctionSyntaxKind kind,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
bool tryAnnexB = false);
|
||||
@@ -1355,13 +1358,13 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
Node newDotGeneratorName();
|
||||
bool declareDotGeneratorName();
|
||||
|
||||
bool skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, bool tryAnnexB);
|
||||
bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun,
|
||||
bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind, bool tryAnnexB);
|
||||
bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart,
|
||||
InHandling inHandling, YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
|
||||
Directives inheritedDirectives, Directives* newDirectives);
|
||||
bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, InHandling inHandling,
|
||||
bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t preludeStart, InHandling inHandling,
|
||||
YieldHandling yieldHandling, FunctionSyntaxKind kind,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
bool tryAnnexB,
|
||||
|
||||
@@ -450,6 +450,7 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||
uint32_t bufEnd;
|
||||
uint32_t startLine;
|
||||
uint32_t startColumn;
|
||||
uint32_t preludeStart;
|
||||
uint16_t length;
|
||||
|
||||
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
|
||||
@@ -479,8 +480,8 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||
FunctionContextFlags funCxFlags;
|
||||
|
||||
FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
|
||||
Directives directives, bool extraWarnings, GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind);
|
||||
uint32_t preludeStart, Directives directives, bool extraWarnings,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
|
||||
|
||||
MutableHandle<LexicalScope::Data*> namedLambdaBindings() {
|
||||
MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms());
|
||||
|
||||
@@ -173,6 +173,12 @@ frontend::IsIdentifier(JSLinearString* str)
|
||||
: ::IsIdentifierMaybeNonBMP(str->twoByteChars(nogc), str->length());
|
||||
}
|
||||
|
||||
bool
|
||||
frontend::IsIdentifier(const char* chars, size_t length)
|
||||
{
|
||||
return ::IsIdentifier(chars, length);
|
||||
}
|
||||
|
||||
bool
|
||||
frontend::IsIdentifier(const char16_t* chars, size_t length)
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ var f0 = function() {
|
||||
|
||||
}
|
||||
|
||||
funcBody1 = funcBody.replace('function f0','function ');
|
||||
funcBody1 = funcBody.replace('function f0','function');
|
||||
assertEq(f0.toString(), funcBody1);
|
||||
assertEq(f0.toSource(), '(' + funcBody1 + ')');
|
||||
|
||||
@@ -48,14 +48,14 @@ assertEq(g.toString(), funcBody2);
|
||||
assertEq(g.toSource(), '(' + funcBody2 + ')');
|
||||
|
||||
f0 = new Function(bodyOnly);
|
||||
assertEq(f0.toString(), "function anonymous() {\n" + bodyOnly + "\n}");
|
||||
assertEq(f0.toSource(), "(function anonymous() {\n" + bodyOnly + "\n})");
|
||||
assertEq(f0.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(f0.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})");
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
var m = new Function(bodyOnly);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(m.toString(), "function anonymous() {\n" + bodyOnly + "\n}");
|
||||
assertEq(m.toSource(), "(function anonymous() {\n" + bodyOnly + "\n})");
|
||||
assertEq(m.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(m.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})");
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -91,7 +91,7 @@ f1 = function(glob) {
|
||||
|
||||
}
|
||||
|
||||
funcBody1 = funcBody.replace('function f1', 'function ');
|
||||
funcBody1 = funcBody.replace('function f1', 'function');
|
||||
assertEq(f1.toString(), funcBody1);
|
||||
assertEq(f1.toSource(), '(' + funcBody1 + ')');
|
||||
|
||||
@@ -107,14 +107,14 @@ assertEq(g.toString(), funcBody2);
|
||||
assertEq(g.toSource(), '(' + funcBody2 + ')');
|
||||
|
||||
f1 = new Function('glob', bodyOnly);
|
||||
assertEq(f1.toString(), "function anonymous(glob) {\n" + bodyOnly + "\n}");
|
||||
assertEq(f1.toSource(), "(function anonymous(glob) {\n" + bodyOnly + "\n})");
|
||||
assertEq(f1.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(f1.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})");
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
var m = new Function('glob', bodyOnly);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(m.toString(), "function anonymous(glob) {\n" + bodyOnly + "\n}");
|
||||
assertEq(m.toSource(), "(function anonymous(glob) {\n" + bodyOnly + "\n})");
|
||||
assertEq(m.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(m.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})");
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -144,14 +144,14 @@ var funcBody = 'function f2(glob, ffi) {\n\
|
||||
assertEq(f2.toString(), funcBody);
|
||||
assertEq(f2.toSource(), funcBody);
|
||||
|
||||
f2 = function (glob, ffi) {
|
||||
f2 = function(glob, ffi) {
|
||||
"use asm";
|
||||
function g() {}
|
||||
return g;
|
||||
|
||||
}
|
||||
|
||||
funcBody1 = funcBody.replace('function f2', 'function ');
|
||||
funcBody1 = funcBody.replace('function f2', 'function');
|
||||
assertEq(f2.toString(), funcBody1);
|
||||
assertEq(f2.toSource(), '(' + funcBody1 + ')');
|
||||
|
||||
@@ -167,14 +167,14 @@ assertEq(g.toString(), funcBody2);
|
||||
assertEq(g.toSource(), '(' + funcBody2 + ')');
|
||||
|
||||
f2 = new Function('glob', 'ffi', bodyOnly);
|
||||
assertEq(f2.toString(), "function anonymous(glob, ffi) {\n" + bodyOnly + "\n}");
|
||||
assertEq(f2.toSource(), "(function anonymous(glob, ffi) {\n" + bodyOnly + "\n})");
|
||||
assertEq(f2.toString(), "function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(f2.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})");
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
var m = new Function('glob', 'ffi', bodyOnly);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(m.toString(), "function anonymous(glob, ffi) {\n" + bodyOnly + "\n}");
|
||||
assertEq(m.toSource(), "(function anonymous(glob, ffi) {\n" + bodyOnly + "\n})");
|
||||
assertEq(m.toString(), "function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(m.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})");
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -204,14 +204,14 @@ var funcBody = 'function f3(glob, ffi, heap) {\n\
|
||||
assertEq(f3.toString(), funcBody);
|
||||
assertEq(f3.toSource(), funcBody);
|
||||
|
||||
f3 = function (glob, ffi, heap) {
|
||||
f3 = function(glob, ffi, heap) {
|
||||
"use asm";
|
||||
function g() {}
|
||||
return g;
|
||||
|
||||
}
|
||||
|
||||
funcBody1 = funcBody.replace('function f3', 'function ');
|
||||
funcBody1 = funcBody.replace('function f3', 'function');
|
||||
assertEq(f3.toString(), funcBody1);
|
||||
assertEq(f3.toSource(), '(' + funcBody1 + ')');
|
||||
|
||||
@@ -227,14 +227,14 @@ assertEq(g.toString(), funcBody2);
|
||||
assertEq(g.toSource(), '(' + funcBody2 + ')');
|
||||
|
||||
f3 = new Function('glob', 'ffi', 'heap', bodyOnly);
|
||||
assertEq(f3.toString(), "function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n}");
|
||||
assertEq(f3.toSource(), "(function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n})");
|
||||
assertEq(f3.toString(), "function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(f3.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})");
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
var m = new Function('glob', 'ffi', 'heap', bodyOnly);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(m.toString(), "function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n}");
|
||||
assertEq(m.toSource(), "(function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n})");
|
||||
assertEq(m.toString(), "function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(m.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})");
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -243,7 +243,7 @@ if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
(function() {
|
||||
|
||||
var funcSource =
|
||||
`function (glob, ffi, heap) {
|
||||
`function(glob, ffi, heap) {
|
||||
"use asm";
|
||||
function g() {}
|
||||
return g;
|
||||
@@ -252,7 +252,7 @@ var funcSource =
|
||||
var f4 = eval("\"use strict\";\n(" + funcSource + ")");
|
||||
|
||||
var expectedToString = funcSource;
|
||||
var expectedToSource = '(' + expectedToString + ')'
|
||||
var expectedToSource = '(' + expectedToString + ')';
|
||||
|
||||
assertEq(f4.toString(), expectedToString);
|
||||
assertEq(f4.toSource(), expectedToSource);
|
||||
|
||||
@@ -5,4 +5,4 @@ for (var i=0; i<400; ++i) {
|
||||
x += String.fromCharCode(i * 289);
|
||||
}
|
||||
var s = "'" + x + "'";
|
||||
assertEq(Function("evt", s).toString(), "function anonymous(evt) {\n" + s + "\n}");
|
||||
assertEq(Function("evt", s).toString(), "function anonymous(evt\n) {\n" + s + "\n}");
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
var f = Function("a", "b", "return a + b;");
|
||||
assertEq(f.toString(), "function anonymous(a, b) {\nreturn a + b;\n}");
|
||||
assertEq(f.toSource(), "(function anonymous(a, b) {\nreturn a + b;\n})");
|
||||
assertEq(f.toString(), "function anonymous(a,b\n) {\nreturn a + b;\n}");
|
||||
assertEq(f.toSource(), "(function anonymous(a,b\n) {\nreturn a + b;\n})");
|
||||
assertEq(decompileFunction(f), f.toString());
|
||||
f = Function("a", "...rest", "return rest[42] + b;");
|
||||
assertEq(f.toString(), "function anonymous(a, ...rest) {\nreturn rest[42] + b;\n}");
|
||||
assertEq(f.toSource(), "(function anonymous(a, ...rest) {\nreturn rest[42] + b;\n})")
|
||||
assertEq(f.toString(), "function anonymous(a,...rest\n) {\nreturn rest[42] + b;\n}");
|
||||
assertEq(f.toSource(), "(function anonymous(a,...rest\n) {\nreturn rest[42] + b;\n})")
|
||||
assertEq(decompileFunction(f), f.toString());
|
||||
f = Function("");
|
||||
assertEq(f.toString(), "function anonymous() {\n\n}");
|
||||
assertEq(f.toString(), "function anonymous(\n) {\n\n}");
|
||||
f = Function("", "(abc)");
|
||||
assertEq(f.toString(), "function anonymous() {\n(abc)\n}");
|
||||
f = Function("", "return function (a, b) a + b;")();
|
||||
assertEq(f.toString(), "function (a, b) a + b");
|
||||
assertEq(f.toString(), "function anonymous(\n) {\n(abc)\n}");
|
||||
f = Function("", "return function (a,b) a + b;")();
|
||||
assertEq(f.toString(), "function (a,b) a + b");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
var o = {get prop() { a + b; }, set prop(x) { a + b; }};
|
||||
var prop = Object.getOwnPropertyDescriptor(o, "prop");
|
||||
assertEq(prop.get.toString(), "function get prop() { a + b; }");
|
||||
assertEq(prop.get.toSource(), "(function get prop() { a + b; })");
|
||||
assertEq(prop.set.toString(), "function set prop(x) { a + b; }");
|
||||
assertEq(prop.set.toSource(), "(function set prop(x) { a + b; })");
|
||||
assertEq(o.toSource(), "({get prop () { a + b; }, set prop (x) { a + b; }})");
|
||||
assertEq(prop.get.toString(), "get prop() { a + b; }");
|
||||
assertEq(prop.get.toSource(), "get prop() { a + b; }");
|
||||
assertEq(prop.set.toString(), "set prop(x) { a + b; }");
|
||||
assertEq(prop.set.toSource(), "set prop(x) { a + b; }");
|
||||
assertEq(o.toSource(), "({get prop() { a + b; }, set prop(x) { a + b; }})");
|
||||
|
||||
@@ -11,7 +11,7 @@ function test(str, arg, result)
|
||||
var fun = new Function('x', str);
|
||||
|
||||
var got = fun.toSource();
|
||||
var expect = '(function anonymous(x) {\n' + str + '\n})';
|
||||
var expect = '(function anonymous(x\n) {\n' + str + '\n})';
|
||||
if (got !== expect) {
|
||||
print("GOT: " + got);
|
||||
print("EXPECT: " + expect);
|
||||
|
||||
@@ -10,5 +10,5 @@ assertEq(arr.length, 10);
|
||||
gc();
|
||||
|
||||
for (var i = 0; i < arr.length; i++)
|
||||
assertEq(arr[i].lineCount, 3);
|
||||
assertEq(arr[i].lineCount, 4);
|
||||
|
||||
|
||||
@@ -10,6 +10,6 @@ assertEq(arr.length, 100);
|
||||
gc(g);
|
||||
|
||||
for (var i = 0; i < arr.length; i++)
|
||||
assertEq(arr[i].lineCount, 3);
|
||||
assertEq(arr[i].lineCount, 4);
|
||||
|
||||
gc();
|
||||
|
||||
@@ -20,6 +20,6 @@ function test(string, range) {
|
||||
}
|
||||
|
||||
test("eval('2 * 3')", [0, 5]);
|
||||
test("new Function('2 * 3')", [0, 12]);
|
||||
test("new Function('x', 'x * x')", [0, 13]);
|
||||
test("new Function('2 * 3')", [0, 31]);
|
||||
test("new Function('x', 'x * x')", [0, 32]);
|
||||
assertEq(count, 6);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
let g = newGlobal();
|
||||
let dbg = new Debugger(g);
|
||||
|
||||
var text;
|
||||
var count = 0;
|
||||
dbg.onNewScript = function (script) {
|
||||
++count;
|
||||
|
||||
@@ -12,18 +12,18 @@ var o = {};
|
||||
Object.defineProperty(o, "prop", {get: function() { return 1; },
|
||||
set: function() { return 2; },
|
||||
enumerable: true, configurable: true});
|
||||
assertEq(o.toSource(), "({get prop () { return 1; }, set prop () { return 2; }})");
|
||||
assertEq(o.toSource(), "({get prop() { return 1; }, set prop() { return 2; }})");
|
||||
|
||||
// obj.toSource TwoByte
|
||||
Object.defineProperty(o, "prop", {get: function() { return "\u1200"; },
|
||||
set: function() { return "\u1200"; },
|
||||
enumerable: true});
|
||||
assertEq(o.toSource(), '({get prop () { return "\\u1200"; }, set prop () { return "\\u1200"; }})');
|
||||
assertEq(o.toSource(), '({get prop() { return "\\u1200"; }, set prop() { return "\\u1200"; }})');
|
||||
|
||||
var ff = function() { return 10; };
|
||||
ff.toSource = function() { return "((11))"; }
|
||||
Object.defineProperty(o, "prop", {get: ff, set: ff, enumerable: true});
|
||||
assertEq(o.toSource(), "({prop:((11)), prop:((11))})");
|
||||
assertEq(o.toSource(), "({get prop(11), set prop(11)})");
|
||||
|
||||
// XDR
|
||||
load(libdir + 'bytecode-cache.js');
|
||||
|
||||
@@ -6,11 +6,11 @@ function test() {
|
||||
|
||||
var f = Function(arg1TwoByte, arg2Latin1, bodyLatin1);
|
||||
assertEq(f(10, 20), 60);
|
||||
assertEq(f.toSource().includes("arg1\u1200, arg2"), true);
|
||||
assertEq(f.toSource().includes("arg1\u1200,arg2"), true);
|
||||
|
||||
var bodyTwoByte = "return arg1\u1200 + arg2;";
|
||||
f = Function(arg1TwoByte, arg2Latin1, bodyTwoByte);
|
||||
assertEq(f(30, 40), 70);
|
||||
assertEq(f.toSource().includes("arg1\u1200, arg2"), true);
|
||||
assertEq(f.toSource().includes("arg1\u1200,arg2"), true);
|
||||
}
|
||||
test();
|
||||
|
||||
+35
-11
@@ -4286,7 +4286,7 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun)
|
||||
*/
|
||||
static bool
|
||||
CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
||||
const char* name,
|
||||
HandleAtom name, bool isInvalidName,
|
||||
SourceBufferHolder& srcBuf, uint32_t parameterListEnd,
|
||||
HandleObject enclosingEnv, HandleScope enclosingScope,
|
||||
MutableHandleFunction fun)
|
||||
@@ -4297,13 +4297,8 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
||||
assertSameCompartment(cx, enclosingEnv);
|
||||
RootedAtom funAtom(cx);
|
||||
|
||||
if (name) {
|
||||
funAtom = Atomize(cx, name, strlen(name));
|
||||
if (!funAtom)
|
||||
return false;
|
||||
}
|
||||
|
||||
fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom,
|
||||
fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL,
|
||||
isInvalidName ? nullptr : name,
|
||||
/* proto = */ nullptr,
|
||||
gc::AllocKind::FUNCTION, TenuredObject,
|
||||
enclosingEnv));
|
||||
@@ -4321,11 +4316,17 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
||||
return false;
|
||||
}
|
||||
|
||||
// When function name is not a valid identifier, the generated function
|
||||
// source in srcBuf doesn't have a function name. Set it here.
|
||||
if (isInvalidName)
|
||||
fun->setAtom(name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE bool
|
||||
BuildFunctionString(unsigned nargs, const char* const* argnames,
|
||||
BuildFunctionString(const char* name, size_t nameLen,
|
||||
unsigned nargs, const char* const* argnames,
|
||||
const SourceBufferHolder& srcBuf, StringBuffer* out,
|
||||
uint32_t* parameterListEnd)
|
||||
{
|
||||
@@ -4334,6 +4335,12 @@ BuildFunctionString(unsigned nargs, const char* const* argnames,
|
||||
|
||||
if (!out->ensureTwoByteChars())
|
||||
return false;
|
||||
if (!out->append("function "))
|
||||
return false;
|
||||
if (name) {
|
||||
if (!out->append(name, nameLen))
|
||||
return false;
|
||||
}
|
||||
if (!out->append("("))
|
||||
return false;
|
||||
for (unsigned i = 0; i < nargs; i++) {
|
||||
@@ -4370,15 +4377,32 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
|
||||
if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
|
||||
return false;
|
||||
|
||||
size_t nameLen = 0;
|
||||
bool isInvalidName = false;
|
||||
RootedAtom nameAtom(cx);
|
||||
if (name) {
|
||||
nameLen = strlen(name);
|
||||
nameAtom = Atomize(cx, name, nameLen);
|
||||
if (!nameAtom)
|
||||
return false;
|
||||
|
||||
// If name is not valid identifier
|
||||
if (!js::frontend::IsIdentifier(name, nameLen))
|
||||
isInvalidName = true;
|
||||
}
|
||||
|
||||
uint32_t parameterListEnd;
|
||||
StringBuffer funStr(cx);
|
||||
if (!BuildFunctionString(nargs, argnames, srcBuf, &funStr, ¶meterListEnd))
|
||||
if (!BuildFunctionString(isInvalidName ? nullptr : name, nameLen, 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);
|
||||
return CompileFunction(cx, options, nameAtom, isInvalidName, newSrcBuf, parameterListEnd, env,
|
||||
scope, fun);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
|
||||
+60
-32
@@ -794,8 +794,10 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
|
||||
|
||||
RootedFunction functionProto(cx, &functionProto_->as<JSFunction>());
|
||||
|
||||
const char* rawSource = "() {\n}";
|
||||
const char* rawSource = "function () {\n}";
|
||||
size_t sourceLen = strlen(rawSource);
|
||||
size_t begin = 9;
|
||||
MOZ_ASSERT(rawSource[begin] == '(');
|
||||
mozilla::UniquePtr<char16_t[], JS::FreePolicy> source(InflateString(cx, rawSource, &sourceLen));
|
||||
if (!source)
|
||||
return nullptr;
|
||||
@@ -817,8 +819,9 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
|
||||
RootedScript script(cx, JSScript::Create(cx,
|
||||
options,
|
||||
sourceObject,
|
||||
0,
|
||||
ss->length()));
|
||||
begin,
|
||||
ss->length(),
|
||||
0));
|
||||
if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto))
|
||||
return nullptr;
|
||||
|
||||
@@ -950,53 +953,62 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
|
||||
}
|
||||
}
|
||||
|
||||
if (fun->isAsync()) {
|
||||
if (!out.append("async "))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
|
||||
fun->isGetter() || fun->isSetter();
|
||||
bool funIsNonArrowLambda = fun->isLambda() && !fun->isArrow();
|
||||
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
|
||||
|
||||
// If we're not in pretty mode, put parentheses around lambda functions and methods.
|
||||
if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) {
|
||||
// If we're not in pretty mode, put parentheses around lambda functions
|
||||
// so that eval returns lambda, not function statement.
|
||||
if (haveSource && !prettyPrint && funIsNonArrowLambda) {
|
||||
if (!out.append("("))
|
||||
return nullptr;
|
||||
}
|
||||
if (!fun->isArrow()) {
|
||||
bool ok;
|
||||
if (fun->isStarGenerator() && !fun->isAsync())
|
||||
ok = out.append("function* ");
|
||||
else
|
||||
ok = out.append("function ");
|
||||
if (!ok)
|
||||
return nullptr;
|
||||
}
|
||||
if (fun->explicitName()) {
|
||||
if (!out.append(fun->explicitName()))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (haveSource && !script->scriptSource()->hasSourceData() &&
|
||||
!JSScript::loadSource(cx, script->scriptSource(), &haveSource))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto AppendPrelude = [&out, &fun]() {
|
||||
if (fun->isAsync()) {
|
||||
if (!out.append("async "))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fun->isArrow()) {
|
||||
if (!out.append("function"))
|
||||
return false;
|
||||
|
||||
if (fun->isStarGenerator()) {
|
||||
if (!out.append('*'))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fun->explicitName()) {
|
||||
if (!out.append(' '))
|
||||
return false;
|
||||
if (!out.append(fun->explicitName()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (haveSource) {
|
||||
Rooted<JSFlatString*> src(cx, JSScript::sourceData(cx, script));
|
||||
Rooted<JSFlatString*> src(cx, script->sourceDataWithPrelude(cx));
|
||||
if (!src)
|
||||
return nullptr;
|
||||
|
||||
if (!out.append(src))
|
||||
return nullptr;
|
||||
|
||||
if (!prettyPrint && funIsMethodOrNonArrowLambda) {
|
||||
if (!prettyPrint && funIsNonArrowLambda) {
|
||||
if (!out.append(")"))
|
||||
return nullptr;
|
||||
}
|
||||
} else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) {
|
||||
if (!out.append("() {\n ") ||
|
||||
if (!AppendPrelude() ||
|
||||
!out.append("() {\n ") ||
|
||||
!out.append("[sourceless code]") ||
|
||||
!out.append("\n}"))
|
||||
{
|
||||
@@ -1005,13 +1017,15 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
|
||||
} else {
|
||||
bool derived = fun->infallibleIsDefaultClassConstructor(cx);
|
||||
if (derived && fun->isDerivedClassConstructor()) {
|
||||
if (!out.append("(...args) {\n ") ||
|
||||
if (!AppendPrelude() ||
|
||||
!out.append("(...args) {\n ") ||
|
||||
!out.append("super(...args);\n}"))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
if (!out.append("() {\n "))
|
||||
if (!AppendPrelude() ||
|
||||
!out.append("() {\n "))
|
||||
return nullptr;
|
||||
|
||||
if (!derived) {
|
||||
@@ -1594,7 +1608,18 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
|
||||
|
||||
StringBuffer sb(cx);
|
||||
|
||||
if (!sb.append('('))
|
||||
if (isAsync) {
|
||||
if (!sb.append("async "))
|
||||
return false;
|
||||
}
|
||||
if (!sb.append("function"))
|
||||
return false;
|
||||
if (isStarGenerator && !isAsync) {
|
||||
if (!sb.append('*'))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sb.append(" anonymous("))
|
||||
return false;
|
||||
|
||||
if (args.length() > 1) {
|
||||
@@ -1615,12 +1640,15 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
|
||||
|
||||
if (i < args.length() - 2) {
|
||||
// Step 9.d.iii.
|
||||
if (!sb.append(", "))
|
||||
if (!sb.append(","))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sb.append('\n'))
|
||||
return false;
|
||||
|
||||
// Remember the position of ")".
|
||||
Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
|
||||
MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
|
||||
|
||||
+35
-12
@@ -235,6 +235,7 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
|
||||
{
|
||||
uint32_t begin = script->sourceStart();
|
||||
uint32_t end = script->sourceEnd();
|
||||
uint32_t preludeStart = script->preludeStart();
|
||||
uint32_t lineno = script->lineno();
|
||||
uint32_t column = script->column();
|
||||
|
||||
@@ -242,6 +243,7 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
|
||||
packedFields = lazy->packedFields();
|
||||
MOZ_ASSERT(begin == lazy->begin());
|
||||
MOZ_ASSERT(end == lazy->end());
|
||||
MOZ_ASSERT(preludeStart == lazy->preludeStart());
|
||||
MOZ_ASSERT(lineno == lazy->lineno());
|
||||
MOZ_ASSERT(column == lazy->column());
|
||||
// We can assert we have no inner functions because we don't
|
||||
@@ -255,7 +257,7 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, script,
|
||||
packedFields, begin, end, lineno, column));
|
||||
packedFields, begin, end, preludeStart, lineno, column));
|
||||
|
||||
// As opposed to XDRLazyScript, we need to restore the runtime bits
|
||||
// of the script, as we are trying to match the fact this function
|
||||
@@ -520,7 +522,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
||||
sourceObject = &enclosingScript->sourceObject()->as<ScriptSourceObject>();
|
||||
}
|
||||
|
||||
script = JSScript::Create(cx, options, sourceObject, 0, 0);
|
||||
script = JSScript::Create(cx, options, sourceObject, 0, 0, 0);
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
@@ -605,6 +607,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
||||
return false;
|
||||
if (!xdr->codeUint32(&script->sourceEnd_))
|
||||
return false;
|
||||
if (!xdr->codeUint32(&script->preludeStart_))
|
||||
return false;
|
||||
|
||||
if (!xdr->codeUint32(&lineno) ||
|
||||
!xdr->codeUint32(&column) ||
|
||||
@@ -938,6 +942,7 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript
|
||||
{
|
||||
uint32_t begin;
|
||||
uint32_t end;
|
||||
uint32_t preludeStart;
|
||||
uint32_t lineno;
|
||||
uint32_t column;
|
||||
uint64_t packedFields;
|
||||
@@ -951,12 +956,14 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript
|
||||
|
||||
begin = lazy->begin();
|
||||
end = lazy->end();
|
||||
preludeStart = lazy->preludeStart();
|
||||
lineno = lazy->lineno();
|
||||
column = lazy->column();
|
||||
packedFields = lazy->packedFields();
|
||||
}
|
||||
|
||||
if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) ||
|
||||
!xdr->codeUint32(&preludeStart) ||
|
||||
!xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) ||
|
||||
!xdr->codeUint64(&packedFields))
|
||||
{
|
||||
@@ -965,7 +972,7 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript,
|
||||
packedFields, begin, end, lineno, column));
|
||||
packedFields, begin, end, preludeStart, lineno, column));
|
||||
if (!lazy)
|
||||
return false;
|
||||
fun->initLazyScript(lazy);
|
||||
@@ -1438,6 +1445,13 @@ JSScript::sourceData(JSContext* cx, HandleScript script)
|
||||
return script->scriptSource()->substring(cx, script->sourceStart(), script->sourceEnd());
|
||||
}
|
||||
|
||||
JSFlatString*
|
||||
JSScript::sourceDataWithPrelude(JSContext* cx)
|
||||
{
|
||||
MOZ_ASSERT(scriptSource()->hasSourceData());
|
||||
return scriptSource()->substring(cx, preludeStart(), sourceEnd());
|
||||
}
|
||||
|
||||
UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry()
|
||||
: cache_(nullptr), sourceChunk_()
|
||||
{
|
||||
@@ -2436,7 +2450,8 @@ JSScript::initCompartment(ExclusiveContext* cx)
|
||||
|
||||
/* static */ JSScript*
|
||||
JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
|
||||
HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd)
|
||||
HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
|
||||
uint32_t preludeStart)
|
||||
{
|
||||
MOZ_ASSERT(bufStart <= bufEnd);
|
||||
|
||||
@@ -2458,6 +2473,7 @@ JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
|
||||
script->setSourceObject(sourceObject);
|
||||
script->sourceStart_ = bufStart;
|
||||
script->sourceEnd_ = bufEnd;
|
||||
script->preludeStart_ = preludeStart;
|
||||
|
||||
return script;
|
||||
}
|
||||
@@ -3393,7 +3409,8 @@ CreateEmptyScriptForClone(JSContext* cx, HandleScript src)
|
||||
.setNoScriptRval(src->noScriptRval())
|
||||
.setVersion(src->getVersion());
|
||||
|
||||
return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd());
|
||||
return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd(),
|
||||
src->preludeStart());
|
||||
}
|
||||
|
||||
JSScript*
|
||||
@@ -3943,7 +3960,8 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot)
|
||||
}
|
||||
|
||||
LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
|
||||
uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
|
||||
uint32_t begin, uint32_t end,
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column)
|
||||
: script_(nullptr),
|
||||
function_(fun),
|
||||
enclosingScope_(nullptr),
|
||||
@@ -3952,6 +3970,7 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
|
||||
packedFields_(packedFields),
|
||||
begin_(begin),
|
||||
end_(end),
|
||||
preludeStart_(preludeStart),
|
||||
lineno_(lineno),
|
||||
column_(column)
|
||||
{
|
||||
@@ -4001,7 +4020,7 @@ LazyScript::maybeForwardedScriptSource() const
|
||||
/* static */ LazyScript*
|
||||
LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
|
||||
uint64_t packedFields, uint32_t begin, uint32_t end,
|
||||
uint32_t lineno, uint32_t column)
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column)
|
||||
{
|
||||
union {
|
||||
PackedView p;
|
||||
@@ -4029,7 +4048,8 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
|
||||
|
||||
cx->compartment()->scheduleDelazificationForDebugger();
|
||||
|
||||
return new (res) LazyScript(fun, table.forget(), packed, begin, end, lineno, column);
|
||||
return new (res) LazyScript(fun, table.forget(), packed, begin, end,
|
||||
preludeStart, lineno, column);
|
||||
}
|
||||
|
||||
/* static */ LazyScript*
|
||||
@@ -4037,7 +4057,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
|
||||
const frontend::AtomVector& closedOverBindings,
|
||||
Handle<GCVector<JSFunction*, 8>> innerFunctions,
|
||||
JSVersion version,
|
||||
uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
|
||||
uint32_t begin, uint32_t end,
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column)
|
||||
{
|
||||
union {
|
||||
PackedView p;
|
||||
@@ -4061,7 +4082,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
|
||||
p.isDerivedClassConstructor = false;
|
||||
p.needsHomeObject = false;
|
||||
|
||||
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
|
||||
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart,
|
||||
lineno, column);
|
||||
if (!res)
|
||||
return nullptr;
|
||||
|
||||
@@ -4082,7 +4104,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
|
||||
HandleScript script, HandleScope enclosingScope,
|
||||
HandleScript enclosingScript,
|
||||
uint64_t packedFields, uint32_t begin, uint32_t end,
|
||||
uint32_t lineno, uint32_t column)
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column)
|
||||
{
|
||||
// Dummy atom which is not a valid property name.
|
||||
RootedAtom dummyAtom(cx, cx->names().comma);
|
||||
@@ -4091,7 +4113,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
|
||||
// holding this lazy script.
|
||||
HandleFunction dummyFun = fun;
|
||||
|
||||
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
|
||||
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart,
|
||||
lineno, column);
|
||||
if (!res)
|
||||
return nullptr;
|
||||
|
||||
|
||||
+35
-13
@@ -575,10 +575,6 @@ class ScriptSource
|
||||
introductionOffset_ = offset;
|
||||
hasIntroductionOffset_ = true;
|
||||
}
|
||||
|
||||
uint32_t parameterListEnd() const {
|
||||
return parameterListEnd_;
|
||||
}
|
||||
};
|
||||
|
||||
class ScriptSourceHolder
|
||||
@@ -857,9 +853,19 @@ class JSScript : public js::gc::TenuredCell
|
||||
|
||||
uint32_t bodyScopeIndex_; /* index into the scopes array of the body scope */
|
||||
|
||||
/* Range of characters in scriptSource which contains this script's source. */
|
||||
// Range of characters in scriptSource which contains this script's source.
|
||||
// each field points the following location.
|
||||
//
|
||||
// function * f(a, b) { return a + b; }
|
||||
// ^ ^ ^
|
||||
// | | |
|
||||
// | sourceStart_ sourceEnd_
|
||||
// |
|
||||
// preludeStart_
|
||||
//
|
||||
uint32_t sourceStart_;
|
||||
uint32_t sourceEnd_;
|
||||
uint32_t preludeStart_;
|
||||
|
||||
// Number of times the script has been called or has had backedges taken.
|
||||
// When running in ion, also increased for any inlined scripts. Reset if
|
||||
@@ -1021,7 +1027,7 @@ class JSScript : public js::gc::TenuredCell
|
||||
// instead of private to suppress -Wunused-private-field compiler warnings.
|
||||
protected:
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
// Currently no padding is needed.
|
||||
uint32_t padding;
|
||||
#endif
|
||||
|
||||
//
|
||||
@@ -1032,7 +1038,7 @@ class JSScript : public js::gc::TenuredCell
|
||||
static JSScript* Create(js::ExclusiveContext* cx,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
js::HandleObject sourceObject, uint32_t sourceStart,
|
||||
uint32_t sourceEnd);
|
||||
uint32_t sourceEnd, uint32_t preludeStart);
|
||||
|
||||
void initCompartment(js::ExclusiveContext* cx);
|
||||
|
||||
@@ -1179,6 +1185,10 @@ class JSScript : public js::gc::TenuredCell
|
||||
return sourceEnd_;
|
||||
}
|
||||
|
||||
size_t preludeStart() const {
|
||||
return preludeStart_;
|
||||
}
|
||||
|
||||
bool noScriptRval() const {
|
||||
return noScriptRval_;
|
||||
}
|
||||
@@ -1510,6 +1520,8 @@ class JSScript : public js::gc::TenuredCell
|
||||
|
||||
static JSFlatString* sourceData(JSContext* cx, JS::HandleScript script);
|
||||
|
||||
JSFlatString* sourceDataWithPrelude(JSContext* cx);
|
||||
|
||||
static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked);
|
||||
|
||||
void setSourceObject(JSObject* object);
|
||||
@@ -1928,7 +1940,8 @@ class LazyScript : public gc::TenuredCell
|
||||
// instead of private to suppress -Wunused-private-field compiler warnings.
|
||||
protected:
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
uint32_t padding;
|
||||
// uint32_t padding;
|
||||
// Currently no padding is needed.
|
||||
#endif
|
||||
|
||||
private:
|
||||
@@ -1973,20 +1986,25 @@ class LazyScript : public gc::TenuredCell
|
||||
};
|
||||
|
||||
// Source location for the script.
|
||||
// See the comment in JSScript for the details.
|
||||
uint32_t begin_;
|
||||
uint32_t end_;
|
||||
uint32_t preludeStart_;
|
||||
// Line and column of |begin_| position, that is the position where we
|
||||
// start parsing.
|
||||
uint32_t lineno_;
|
||||
uint32_t column_;
|
||||
|
||||
LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
|
||||
uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column);
|
||||
uint32_t begin, uint32_t end, uint32_t preludeStart,
|
||||
uint32_t lineno, uint32_t column);
|
||||
|
||||
// Create a LazyScript without initializing the closedOverBindings and the
|
||||
// innerFunctions. To be GC-safe, the caller must initialize both vectors
|
||||
// with valid atoms and functions.
|
||||
static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun,
|
||||
uint64_t packedData, uint32_t begin, uint32_t end,
|
||||
uint32_t lineno, uint32_t column);
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column);
|
||||
|
||||
public:
|
||||
static const uint32_t NumClosedOverBindingsLimit = 1 << NumClosedOverBindingsBits;
|
||||
@@ -1998,7 +2016,7 @@ class LazyScript : public gc::TenuredCell
|
||||
const frontend::AtomVector& closedOverBindings,
|
||||
Handle<GCVector<JSFunction*, 8>> innerFunctions,
|
||||
JSVersion version, uint32_t begin, uint32_t end,
|
||||
uint32_t lineno, uint32_t column);
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column);
|
||||
|
||||
// Create a LazyScript and initialize the closedOverBindings and the
|
||||
// innerFunctions with dummy values to be replaced in a later initialization
|
||||
@@ -2013,7 +2031,7 @@ class LazyScript : public gc::TenuredCell
|
||||
HandleScript script, HandleScope enclosingScope,
|
||||
HandleScript enclosingScript,
|
||||
uint64_t packedData, uint32_t begin, uint32_t end,
|
||||
uint32_t lineno, uint32_t column);
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column);
|
||||
|
||||
void initRuntimeFields(uint64_t packedFields);
|
||||
|
||||
@@ -2193,6 +2211,9 @@ class LazyScript : public gc::TenuredCell
|
||||
uint32_t end() const {
|
||||
return end_;
|
||||
}
|
||||
uint32_t preludeStart() const {
|
||||
return preludeStart_;
|
||||
}
|
||||
uint32_t lineno() const {
|
||||
return lineno_;
|
||||
}
|
||||
@@ -2219,7 +2240,8 @@ class LazyScript : public gc::TenuredCell
|
||||
};
|
||||
|
||||
/* If this fails, add/remove padding within LazyScript. */
|
||||
JS_STATIC_ASSERT(sizeof(LazyScript) % js::gc::CellSize == 0);
|
||||
static_assert(sizeof(LazyScript) % js::gc::CellSize == 0,
|
||||
"Size of LazyScript must be an integral multiple of js::gc::CellSize");
|
||||
|
||||
struct ScriptAndCounts
|
||||
{
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
var BUGNUMBER = 1317400;
|
||||
var summary = "Function string representation in Object.prototype.toSource";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
// Methods.
|
||||
|
||||
assertEq(({ foo(){} }).toSource(),
|
||||
"({foo(){}})");
|
||||
assertEq(({ *foo(){} }).toSource(),
|
||||
"({*foo(){}})");
|
||||
assertEq(({ async foo(){} }).toSource(),
|
||||
"({async foo(){}})");
|
||||
|
||||
assertEq(({ 1(){} }).toSource(),
|
||||
"({1(){}})");
|
||||
|
||||
// Methods with more spacing.
|
||||
// Spacing is kept.
|
||||
|
||||
assertEq(({ foo (){} }).toSource(),
|
||||
"({foo (){}})");
|
||||
assertEq(({ foo () {} }).toSource(),
|
||||
"({foo () {}})");
|
||||
|
||||
// Methods with computed name.
|
||||
// Method syntax is composed.
|
||||
|
||||
let name = "foo";
|
||||
assertEq(({ [name](){} }).toSource(),
|
||||
"({foo(){}})");
|
||||
assertEq(({ *[name](){} }).toSource(),
|
||||
"({*foo(){}})");
|
||||
assertEq(({ async [name](){} }).toSource(),
|
||||
"({async foo(){}})");
|
||||
|
||||
assertEq(({ [ Symbol.iterator ](){} }).toSource(),
|
||||
"({[Symbol.iterator](){}})");
|
||||
|
||||
// Accessors.
|
||||
|
||||
assertEq(({ get foo(){} }).toSource(),
|
||||
"({get foo(){}})");
|
||||
assertEq(({ set foo(v){} }).toSource(),
|
||||
"({set foo(v){}})");
|
||||
|
||||
// Accessors with computed name.
|
||||
// Method syntax is composed.
|
||||
|
||||
assertEq(({ get [name](){} }).toSource(),
|
||||
"({get foo(){}})");
|
||||
assertEq(({ set [name](v){} }).toSource(),
|
||||
"({set foo(v){}})");
|
||||
|
||||
assertEq(({ get [ Symbol.iterator ](){} }).toSource(),
|
||||
"({get [Symbol.iterator](){}})");
|
||||
assertEq(({ set [ Symbol.iterator ](v){} }).toSource(),
|
||||
"({set [Symbol.iterator](v){}})");
|
||||
|
||||
// Getter and setter with same name.
|
||||
// Getter always comes before setter.
|
||||
|
||||
assertEq(({ get foo(){}, set foo(v){} }).toSource(),
|
||||
"({get foo(){}, set foo(v){}})");
|
||||
assertEq(({ set foo(v){}, get foo(){} }).toSource(),
|
||||
"({get foo(){}, set foo(v){}})");
|
||||
|
||||
// Normal properties.
|
||||
|
||||
assertEq(({ foo: function(){} }).toSource(),
|
||||
"({foo:(function(){})})");
|
||||
assertEq(({ foo: function bar(){} }).toSource(),
|
||||
"({foo:(function bar(){})})");
|
||||
assertEq(({ foo: function*(){} }).toSource(),
|
||||
"({foo:(function*(){})})");
|
||||
assertEq(({ foo: async function(){} }).toSource(),
|
||||
"({foo:(async function(){})})");
|
||||
|
||||
// Normal properties with computed name.
|
||||
|
||||
assertEq(({ [ Symbol.iterator ]: function(){} }).toSource(),
|
||||
"({[Symbol.iterator]:(function(){})})");
|
||||
|
||||
// Dynamically defined properties with function expression.
|
||||
// Never become a method syntax.
|
||||
|
||||
let obj = {};
|
||||
obj.foo = function() {};
|
||||
assertEq(obj.toSource(),
|
||||
"({foo:(function() {})})");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {value: function() {}});
|
||||
assertEq(obj.toSource(),
|
||||
"({})");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {value: function() {}, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({foo:(function() {})})");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {value: function bar() {}, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({foo:(function bar() {})})");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, Symbol.iterator, {value: function() {}, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({[Symbol.iterator]:(function() {})})");
|
||||
|
||||
// Dynamically defined property with other object's method.
|
||||
// Method syntax is composed.
|
||||
|
||||
let method = ({foo() {}}).foo;
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {value: method, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({foo() {}})");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "bar", {value: method, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({bar() {}})");
|
||||
|
||||
method = ({*foo() {}}).foo;
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "bar", {value: method, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({*bar() {}})");
|
||||
|
||||
method = ({async foo() {}}).foo;
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "bar", {value: method, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({async bar() {}})");
|
||||
|
||||
// Dynamically defined accessors.
|
||||
// Accessor syntax is composed.
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {get: function() {}, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({get foo() {}})");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {set: function() {}, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({set foo() {}})");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, Symbol.iterator, {get: function() {}, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({get [Symbol.iterator]() {}})");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, Symbol.iterator, {set: function() {}, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({set [Symbol.iterator]() {}})");
|
||||
|
||||
// Dynamically defined accessors with other object's accessors.
|
||||
// Accessor syntax is composed.
|
||||
|
||||
let accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get;
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({get foo() {}})");
|
||||
|
||||
accessor = Object.getOwnPropertyDescriptor({ get bar() {} }, "bar").get;
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({get foo() {}})");
|
||||
|
||||
accessor = Object.getOwnPropertyDescriptor({ set foo(v) {} }, "foo").set;
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({get foo(v) {}})");
|
||||
|
||||
accessor = Object.getOwnPropertyDescriptor({ set bar(v) {} }, "bar").set;
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({get foo(v) {}})");
|
||||
|
||||
accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get;
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({set foo() {}})");
|
||||
|
||||
accessor = Object.getOwnPropertyDescriptor({ get bar() {} }, "bar").get;
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({set foo() {}})");
|
||||
|
||||
accessor = Object.getOwnPropertyDescriptor({ set foo(v) {} }, "foo").set;
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({set foo(v) {}})");
|
||||
|
||||
accessor = Object.getOwnPropertyDescriptor({ set bar(v) {} }, "bar").set;
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({set foo(v) {}})");
|
||||
|
||||
// Methods with proxy.
|
||||
// Treated as normal property.
|
||||
|
||||
method = ({foo() {}}).foo;
|
||||
let handler = {
|
||||
get(that, name) {
|
||||
if (name == "toSource") {
|
||||
return function() {
|
||||
return that.toSource();
|
||||
};
|
||||
}
|
||||
return that[name];
|
||||
}
|
||||
};
|
||||
let proxy = new Proxy(method, handler);
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {value: proxy, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({foo:foo() {}})");
|
||||
|
||||
// Accessors with proxy.
|
||||
// Accessor syntax is composed.
|
||||
|
||||
accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get;
|
||||
proxy = new Proxy(accessor, handler);
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {get: proxy, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({get foo() {}})");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {set: proxy, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({set foo() {}})");
|
||||
|
||||
// Methods from other global.
|
||||
// Treated as normal property.
|
||||
|
||||
let g = newGlobal();
|
||||
|
||||
method = g.eval("({ foo() {} }).foo");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {value: method, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({foo:foo() {}})");
|
||||
|
||||
// Accessors from other global.
|
||||
// Accessor syntax is composed.
|
||||
|
||||
accessor = g.eval("Object.getOwnPropertyDescriptor({ get foo() {} }, 'foo').get");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({get foo() {}})");
|
||||
|
||||
accessor = g.eval("Object.getOwnPropertyDescriptor({ get bar() {} }, 'bar').get");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({get foo() {}})");
|
||||
|
||||
accessor = g.eval("Object.getOwnPropertyDescriptor({ set foo(v) {} }, 'foo').set");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({get foo(v) {}})");
|
||||
|
||||
accessor = g.eval("Object.getOwnPropertyDescriptor({ set bar(v) {} }, 'bar').set");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({get foo(v) {}})");
|
||||
|
||||
accessor = g.eval("Object.getOwnPropertyDescriptor({ get foo() {} }, 'foo').get");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({set foo() {}})");
|
||||
|
||||
accessor = g.eval("Object.getOwnPropertyDescriptor({ get bar() {} }, 'bar').get");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({set foo() {}})");
|
||||
|
||||
accessor = g.eval("Object.getOwnPropertyDescriptor({ set foo(v) {} }, 'foo').set");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({set foo(v) {}})");
|
||||
|
||||
accessor = g.eval("Object.getOwnPropertyDescriptor({ set bar(v) {} }, 'bar').set");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({set foo(v) {}})");
|
||||
|
||||
// **** Some weird cases ****
|
||||
|
||||
// Accessors with generator or async.
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {get: function*() {}, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({get foo() {}})");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {set: async function() {}, enumerable: true});
|
||||
assertEq(obj.toSource(),
|
||||
"({set foo() {}})");
|
||||
|
||||
// Modified toSource.
|
||||
|
||||
obj = { foo() {} };
|
||||
obj.foo.toSource = () => "hello";
|
||||
assertEq(obj.toSource(),
|
||||
"({hello})");
|
||||
|
||||
obj = { foo() {} };
|
||||
obj.foo.toSource = () => "bar() {}";
|
||||
assertEq(obj.toSource(),
|
||||
"({bar() {}})");
|
||||
|
||||
// Modified toSource with different method name.
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {value: function bar() {}, enumerable: true});
|
||||
obj.foo.toSource = () => "hello";
|
||||
assertEq(obj.toSource(),
|
||||
"({foo:hello})");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {value: function* bar() {}, enumerable: true});
|
||||
obj.foo.toSource = () => "hello";
|
||||
assertEq(obj.toSource(),
|
||||
"({foo:hello})");
|
||||
|
||||
obj = {};
|
||||
Object.defineProperty(obj, "foo", {value: async function bar() {}, enumerable: true});
|
||||
obj.foo.toSource = () => "hello";
|
||||
assertEq(obj.toSource(),
|
||||
"({foo:hello})");
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
@@ -109,7 +109,7 @@ function TestGeneratorFunction() {
|
||||
// Doesn't matter particularly what string gets serialized, as long
|
||||
// as it contains "function*" and "yield 10".
|
||||
assertEq(GeneratorFunction('yield 10').toString(),
|
||||
"function* anonymous() {\nyield 10\n}");
|
||||
"function* anonymous(\n) {\nyield 10\n}");
|
||||
}
|
||||
TestGeneratorFunction();
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ with (x)
|
||||
}
|
||||
status = inSection(5);
|
||||
actual = x.g.toString();
|
||||
expect = (function () {}).toString();
|
||||
expect = (function() {}).toString();
|
||||
addThis();
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 354945;
|
||||
var summary = 'Do not crash with new Iterator';
|
||||
var expect = 'TypeError: trap __iterator__ for ({__iterator__:(function (){ })}) returned a primitive value';
|
||||
var expect = 'TypeError: trap __iterator__ for ({__iterator__:(function(){ })}) returned a primitive value';
|
||||
var actual;
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ function test()
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
expect = 'TypeError: trap __iterator__ for ({__iterator__:(function (){ })}) returned a primitive value';
|
||||
expect = 'TypeError: trap __iterator__ for ({__iterator__:(function(){ })}) returned a primitive value';
|
||||
var obj = {};
|
||||
obj.__iterator__ = function(){ };
|
||||
try
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
var actual;
|
||||
var expect = "function f() { ff (); }";
|
||||
var expect = "function f () { ff (); }";
|
||||
function fun() {
|
||||
(new Function ("function ff () { actual = '' + ff. caller; } function f () { ff (); } f ();")) ();
|
||||
}
|
||||
|
||||
+12
-10
@@ -320,6 +320,7 @@ struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod
|
||||
// Function constructor, this will be the first character in the function
|
||||
// source. Otherwise, it will be the opening parenthesis of the arguments
|
||||
// list.
|
||||
uint32_t preludeStart;
|
||||
uint32_t srcStart;
|
||||
uint32_t srcBodyStart;
|
||||
bool strict;
|
||||
@@ -1746,6 +1747,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
if (!asmJSMetadata_)
|
||||
return false;
|
||||
|
||||
asmJSMetadata_->preludeStart = moduleFunctionNode_->pn_funbox->preludeStart;
|
||||
asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin;
|
||||
asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end;
|
||||
asmJSMetadata_->strict = parser_.pc->sc()->strict() &&
|
||||
@@ -7036,6 +7038,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
|
||||
TokenStream& tokenStream = m.tokenStream();
|
||||
|
||||
tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand);
|
||||
uint32_t preludeStart = tokenStream.currentToken().pos.begin;
|
||||
*line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end);
|
||||
|
||||
TokenKind tk;
|
||||
@@ -7058,7 +7061,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
|
||||
|
||||
ParseContext* outerpc = m.parser().pc;
|
||||
Directives directives(outerpc);
|
||||
FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, directives, NotGenerator,
|
||||
FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, preludeStart, directives, NotGenerator,
|
||||
SyncFunction, /* tryAnnexB = */ false);
|
||||
if (!funbox)
|
||||
return false;
|
||||
@@ -8041,7 +8044,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t begin = metadata.srcStart;
|
||||
uint32_t begin = metadata.preludeStart;
|
||||
uint32_t end = metadata.srcEndAfterCurly();
|
||||
Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end));
|
||||
if (!src)
|
||||
@@ -8072,7 +8075,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
|
||||
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
|
||||
? SourceBufferHolder::GiveOwnership
|
||||
: SourceBufferHolder::NoOwnership;
|
||||
SourceBufferHolder srcBuf(chars, stableChars.twoByteRange().length(), ownership);
|
||||
SourceBufferHolder srcBuf(chars, end - begin, ownership);
|
||||
if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing()))
|
||||
return false;
|
||||
|
||||
@@ -8524,6 +8527,7 @@ LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loaded
|
||||
return true;
|
||||
|
||||
// See AsmJSMetadata comment as well as ModuleValidator::init().
|
||||
asmJSMetadata->preludeStart = parser.pc->functionBox()->preludeStart;
|
||||
asmJSMetadata->srcStart = parser.pc->functionBox()->functionNode->pn_body->pn_pos.begin;
|
||||
asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end;
|
||||
asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict();
|
||||
@@ -8821,7 +8825,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
|
||||
MOZ_ASSERT(IsAsmJSModule(fun));
|
||||
|
||||
const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS();
|
||||
uint32_t begin = metadata.srcStart;
|
||||
uint32_t begin = metadata.preludeStart;
|
||||
uint32_t end = metadata.srcEndAfterCurly();
|
||||
ScriptSource* source = metadata.scriptSource.get();
|
||||
|
||||
@@ -8830,17 +8834,15 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
|
||||
if (addParenToLambda && fun->isLambda() && !out.append("("))
|
||||
return nullptr;
|
||||
|
||||
if (!out.append("function "))
|
||||
return nullptr;
|
||||
|
||||
if (fun->explicitName() && !out.append(fun->explicitName()))
|
||||
return nullptr;
|
||||
|
||||
bool haveSource = source->hasSourceData();
|
||||
if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
|
||||
return nullptr;
|
||||
|
||||
if (!haveSource) {
|
||||
if (!out.append("function "))
|
||||
return nullptr;
|
||||
if (fun->explicitName() && !out.append(fun->explicitName()))
|
||||
return nullptr;
|
||||
if (!out.append("() {\n [sourceless code]\n}"))
|
||||
return nullptr;
|
||||
} else {
|
||||
|
||||
@@ -22,21 +22,21 @@
|
||||
storage.b = 0;
|
||||
assert_equals(storage.b, "0");
|
||||
storage.c = function(){};
|
||||
assert_equals(storage.c, "function (){}");
|
||||
assert_equals(storage.c, "function(){}");
|
||||
|
||||
storage.setItem('d', null);
|
||||
assert_equals(storage.d, "null");
|
||||
storage.setItem('e', 0);
|
||||
assert_equals(storage.e, "0");
|
||||
storage.setItem('f', function(){});
|
||||
assert_equals(storage.f, "function (){}");
|
||||
assert_equals(storage.f, "function(){}");
|
||||
|
||||
storage['g'] = null;
|
||||
assert_equals(storage.g, "null");
|
||||
storage['h'] = 0;
|
||||
assert_equals(storage.h, "0");
|
||||
storage['i'] = function(){};
|
||||
assert_equals(storage.f, "function (){}");
|
||||
assert_equals(storage.f, "function(){}");
|
||||
|
||||
}, name + " only stores strings");
|
||||
});
|
||||
|
||||
@@ -381,12 +381,12 @@ add_task(function* log_message_with_params() {
|
||||
ob = function() {};
|
||||
ob.toJSON = function() {throw "oh noes JSON"};
|
||||
do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}),
|
||||
"Fail is (function () {})");
|
||||
'Fail is (function() {})');
|
||||
|
||||
// Fall back to .toString if both .toJSON and .toSource fail.
|
||||
ob.toSource = function() {throw "oh noes SOURCE"};
|
||||
do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}),
|
||||
"Fail is function () {}");
|
||||
'Fail is function() {}');
|
||||
|
||||
// Fall back to '[object]' if .toJSON, .toSource and .toString fail.
|
||||
ob.toString = function() {throw "oh noes STRING"};
|
||||
@@ -451,7 +451,7 @@ add_task(function* log_message_with_params() {
|
||||
/* eslint-disable object-shorthand */
|
||||
let vOf = {a: 1, valueOf: function() {throw "oh noes valueOf"}};
|
||||
do_check_eq(formatMessage("Broken valueOf ${}", vOf),
|
||||
'Broken valueOf ({a:1, valueOf:(function () {throw "oh noes valueOf"})})');
|
||||
'Broken valueOf ({a:1, valueOf:(function() {throw "oh noes valueOf"})})');
|
||||
/* eslint-enable object-shorthand */
|
||||
|
||||
// Test edge cases of bad data to formatter:
|
||||
|
||||
Reference in New Issue
Block a user