Update js parser
This commit is contained in:
parent
0437f42ca6
commit
bafa2e7e3f
|
@ -24,7 +24,7 @@ var inputTests = [
|
||||||
{
|
{
|
||||||
input: "(function() { return 42; })",
|
input: "(function() { return 42; })",
|
||||||
output: "function ()",
|
output: "function ()",
|
||||||
printOutput: "function () { return 42; }",
|
printOutput: "function() { return 42; }",
|
||||||
suppressClick: true
|
suppressClick: true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ var inputTests = [
|
||||||
{
|
{
|
||||||
input: "testobj1.testfn2",
|
input: "testobj1.testfn2",
|
||||||
output: "function testfn2()",
|
output: "function testfn2()",
|
||||||
printOutput: "function () { return 42; }",
|
printOutput: "function() { return 42; }",
|
||||||
suppressClick: true
|
suppressClick: true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -29,12 +29,12 @@ function run_test_with_server(server, cb) {
|
||||||
addSources(debuggee);
|
addSources(debuggee);
|
||||||
|
|
||||||
threadClient.getSources(Task.async(function* (res) {
|
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 });
|
yield threadClient.reconfigure({ useSourceMaps: false });
|
||||||
|
|
||||||
threadClient.getSources(function(res) {
|
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);
|
client.close().then(cb);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -9,11 +9,13 @@
|
||||||
#include "mozilla/ArrayUtils.h"
|
#include "mozilla/ArrayUtils.h"
|
||||||
|
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
|
#include "jsstr.h"
|
||||||
|
|
||||||
#include "builtin/Eval.h"
|
#include "builtin/Eval.h"
|
||||||
#include "frontend/BytecodeCompiler.h"
|
#include "frontend/BytecodeCompiler.h"
|
||||||
#include "jit/InlinableNatives.h"
|
#include "jit/InlinableNatives.h"
|
||||||
#include "js/UniquePtr.h"
|
#include "js/UniquePtr.h"
|
||||||
|
#include "vm/AsyncFunction.h"
|
||||||
#include "vm/StringBuffer.h"
|
#include "vm/StringBuffer.h"
|
||||||
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
@ -124,6 +126,27 @@ obj_toSource(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return true;
|
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
|
* Given a function source string, return the offset and length of the part
|
||||||
* between '(function $name' and ')'.
|
* between '(function $name' and ')'.
|
||||||
|
@ -133,37 +156,53 @@ static bool
|
||||||
ArgsAndBodySubstring(mozilla::Range<const CharT> chars, size_t* outOffset, size_t* outLen)
|
ArgsAndBodySubstring(mozilla::Range<const CharT> chars, size_t* outOffset, size_t* outLen)
|
||||||
{
|
{
|
||||||
const CharT* const start = chars.begin().get();
|
const CharT* const start = chars.begin().get();
|
||||||
const CharT* const end = chars.end().get();
|
|
||||||
const CharT* s = start;
|
const CharT* s = start;
|
||||||
|
const CharT* e = chars.end().get();
|
||||||
|
|
||||||
uint8_t parenChomp = 0;
|
if (s == e)
|
||||||
if (s[0] == '(') {
|
return false;
|
||||||
|
|
||||||
|
// Remove enclosing parentheses.
|
||||||
|
if (*s == '(' && *(e - 1) == ')') {
|
||||||
s++;
|
s++;
|
||||||
parenChomp = 1;
|
e--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to jump "function" keyword. */
|
(void) Consume(s, e, "async");
|
||||||
s = js_strchr_limit(s, ' ', end);
|
ConsumeSpaces(s, e);
|
||||||
if (!s)
|
(void) (Consume(s, e, "function") || Consume(s, e, "get") || Consume(s, e, "set"));
|
||||||
return false;
|
ConsumeSpaces(s, e);
|
||||||
|
(void) Consume(s, e, "*");
|
||||||
|
ConsumeSpaces(s, e);
|
||||||
|
|
||||||
/*
|
// Jump over the function's name.
|
||||||
* Jump over the function's name: it can't be encoded as part
|
if (Consume(s, e, "[")) {
|
||||||
* of an ECMA getter or setter.
|
s = js_strchr_limit(s, ']', e);
|
||||||
*/
|
if (!s)
|
||||||
s = js_strchr_limit(s, '(', end);
|
return false;
|
||||||
if (!s)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (*s == ' ')
|
|
||||||
s++;
|
s++;
|
||||||
|
ConsumeSpaces(s, e);
|
||||||
|
if (*s != '(')
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
s = js_strchr_limit(s, '(', e);
|
||||||
|
if (!s)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
*outOffset = s - start;
|
*outOffset = s - start;
|
||||||
*outLen = end - s - parenChomp;
|
*outLen = e - s;
|
||||||
MOZ_ASSERT(*outOffset + *outLen <= chars.length());
|
MOZ_ASSERT(*outOffset + *outLen <= chars.length());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class PropertyKind {
|
||||||
|
Getter,
|
||||||
|
Setter,
|
||||||
|
Method,
|
||||||
|
Normal
|
||||||
|
};
|
||||||
|
|
||||||
JSString*
|
JSString*
|
||||||
js::ObjectToSource(JSContext* cx, HandleObject obj)
|
js::ObjectToSource(JSContext* cx, HandleObject obj)
|
||||||
{
|
{
|
||||||
|
@ -182,59 +221,28 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
|
||||||
if (!buf.append('{'))
|
if (!buf.append('{'))
|
||||||
return nullptr;
|
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);
|
AutoIdVector idv(cx);
|
||||||
if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_SYMBOLS, &idv))
|
if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_SYMBOLS, &idv))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
bool comma = false;
|
bool comma = false;
|
||||||
for (size_t i = 0; i < idv.length(); ++i) {
|
auto AddProperty = [cx, &comma, &buf](HandleId id, HandleValue val, PropertyKind kind) -> bool {
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert id to a string. */
|
/* Convert id to a string. */
|
||||||
RootedString idstr(cx);
|
RootedString idstr(cx);
|
||||||
if (JSID_IS_SYMBOL(id)) {
|
if (JSID_IS_SYMBOL(id)) {
|
||||||
RootedValue v(cx, SymbolValue(JSID_TO_SYMBOL(id)));
|
RootedValue v(cx, SymbolValue(JSID_TO_SYMBOL(id)));
|
||||||
idstr = ValueToSource(cx, v);
|
idstr = ValueToSource(cx, v);
|
||||||
if (!idstr)
|
if (!idstr)
|
||||||
return nullptr;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
RootedValue idv(cx, IdToValue(id));
|
RootedValue idv(cx, IdToValue(id));
|
||||||
idstr = ToString<CanGC>(cx, idv);
|
idstr = ToString<CanGC>(cx, idv);
|
||||||
if (!idstr)
|
if (!idstr)
|
||||||
return nullptr;
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If id is a string that's not an identifier, or if it's a negative
|
* If id is a string that's not an identifier, or if it's a
|
||||||
* integer, then it must be quoted.
|
* negative integer, then it must be quoted.
|
||||||
*/
|
*/
|
||||||
if (JSID_IS_ATOM(id)
|
if (JSID_IS_ATOM(id)
|
||||||
? !IsIdentifier(JSID_TO_ATOM(id))
|
? !IsIdentifier(JSID_TO_ATOM(id))
|
||||||
|
@ -242,28 +250,65 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
|
||||||
{
|
{
|
||||||
idstr = QuoteString(cx, idstr, char16_t('\''));
|
idstr = QuoteString(cx, idstr, char16_t('\''));
|
||||||
if (!idstr)
|
if (!idstr)
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < valcnt; j++) {
|
RootedString valsource(cx, ValueToSource(cx, val));
|
||||||
/* Convert val[j] to its canonical source form. */
|
if (!valsource)
|
||||||
JSString* valsource = ValueToSource(cx, val[j]);
|
return false;
|
||||||
if (!valsource)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
RootedLinearString valstr(cx, valsource->ensureLinear(cx));
|
RootedLinearString valstr(cx, valsource->ensureLinear(cx));
|
||||||
if (!valstr)
|
if (!valstr)
|
||||||
return nullptr;
|
return false;
|
||||||
|
|
||||||
size_t voffset = 0;
|
if (comma && !buf.append(", "))
|
||||||
size_t vlength = valstr->length();
|
return false;
|
||||||
|
comma = true;
|
||||||
|
|
||||||
/*
|
size_t voffset, vlength;
|
||||||
* Remove '(function ' from the beginning of valstr and ')' from the
|
|
||||||
* end so that we can put "get" in front of the function definition.
|
// Methods and accessors can return exact syntax of source, that fits
|
||||||
*/
|
// into property without adding property name or "get"/"set" prefix.
|
||||||
if (gsop[j] && IsFunctionObject(val[j])) {
|
// 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;
|
bool success;
|
||||||
JS::AutoCheckCannotGC nogc;
|
JS::AutoCheckCannotGC nogc;
|
||||||
if (valstr->hasLatin1Chars())
|
if (valstr->hasLatin1Chars())
|
||||||
|
@ -271,29 +316,90 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
|
||||||
else
|
else
|
||||||
success = ArgsAndBodySubstring(valstr->twoByteRange(nogc), &voffset, &vlength);
|
success = ArgsAndBodySubstring(valstr->twoByteRange(nogc), &voffset, &vlength);
|
||||||
if (!success)
|
if (!success)
|
||||||
gsop[j].set(nullptr);
|
kind = PropertyKind::Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comma && !buf.append(", "))
|
if (kind == PropertyKind::Getter) {
|
||||||
return nullptr;
|
if (!buf.append("get "))
|
||||||
comma = true;
|
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 (fun->isStarGenerator()) {
|
||||||
if (!buf.append(gsop[j]) || !buf.append(' '))
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (JSID_IS_SYMBOL(id) && !buf.append('['))
|
if (desc.hasSetterObject() && desc.setterObject()) {
|
||||||
return nullptr;
|
val.setObject(*desc.setterObject());
|
||||||
if (!buf.append(idstr))
|
if (!AddProperty(id, val, PropertyKind::Setter))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (JSID_IS_SYMBOL(id) && !buf.append(']'))
|
}
|
||||||
return nullptr;
|
continue;
|
||||||
if (!buf.append(gsop[j] ? ' ' : ':'))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (!buf.appendSubstring(valstr, voffset, vlength))
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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('}'))
|
if (!buf.append('}'))
|
||||||
|
|
|
@ -77,7 +77,7 @@ class MOZ_STACK_CLASS BytecodeCompiler
|
||||||
bool canLazilyParse();
|
bool canLazilyParse();
|
||||||
bool createParser();
|
bool createParser();
|
||||||
bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
|
bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
|
||||||
bool createScript();
|
bool createScript(uint32_t preludeStart = 0);
|
||||||
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
|
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
|
||||||
bool handleParseFailure(const Directives& newDirectives);
|
bool handleParseFailure(const Directives& newDirectives);
|
||||||
bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
|
bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
|
||||||
|
@ -242,10 +242,11 @@ BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = No
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeCompiler::createScript()
|
BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */)
|
||||||
{
|
{
|
||||||
script = JSScript::Create(cx, options,
|
script = JSScript::Create(cx, options,
|
||||||
sourceObject, /* sourceStart = */ 0, sourceBuffer.length());
|
sourceObject, /* sourceStart = */ 0, sourceBuffer.length(),
|
||||||
|
preludeStart);
|
||||||
return script != nullptr;
|
return script != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,7 +457,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
|
||||||
if (fn->pn_funbox->function()->isInterpreted()) {
|
if (fn->pn_funbox->function()->isInterpreted()) {
|
||||||
MOZ_ASSERT(fun == fn->pn_funbox->function());
|
MOZ_ASSERT(fun == fn->pn_funbox->function());
|
||||||
|
|
||||||
if (!createScript())
|
if (!createScript(fn->pn_funbox->preludeStart))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Maybe<BytecodeEmitter> emitter;
|
Maybe<BytecodeEmitter> emitter;
|
||||||
|
@ -650,7 +651,8 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
|
||||||
MOZ_ASSERT(sourceObject);
|
MOZ_ASSERT(sourceObject);
|
||||||
|
|
||||||
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
|
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
|
||||||
lazy->begin(), lazy->end()));
|
lazy->begin(), lazy->end(),
|
||||||
|
lazy->preludeStart()));
|
||||||
if (!script)
|
if (!script)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,8 @@ IsIdentifier(JSLinearString* str);
|
||||||
* As above, but taking chars + length.
|
* As above, but taking chars + length.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
|
IsIdentifier(const char* chars, size_t length);
|
||||||
|
bool
|
||||||
IsIdentifier(const char16_t* chars, size_t length);
|
IsIdentifier(const char16_t* chars, size_t length);
|
||||||
|
|
||||||
/* True if str is a keyword. Defined in TokenStream.cpp. */
|
/* True if str is a keyword. Defined in TokenStream.cpp. */
|
||||||
|
|
|
@ -3559,9 +3559,11 @@ BytecodeEmitter::maybeSetSourceMap()
|
||||||
if (parser->options().sourceMapURL()) {
|
if (parser->options().sourceMapURL()) {
|
||||||
// Warn about the replacement, but use the new one.
|
// Warn about the replacement, but use the new one.
|
||||||
if (parser->ss->hasSourceMapURL()) {
|
if (parser->ss->hasSourceMapURL()) {
|
||||||
if(!parser->report(ParseWarning, false, nullptr, JSMSG_ALREADY_HAS_PRAGMA,
|
if (!parser->reportNoOffset(ParseWarning, false, JSMSG_ALREADY_HAS_PRAGMA,
|
||||||
parser->ss->filename(), "//# sourceMappingURL"))
|
parser->ss->filename(), "//# sourceMappingURL"))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parser->ss->setSourceMapURL(cx, parser->options().sourceMapURL()))
|
if (!parser->ss->setSourceMapURL(cx, parser->options().sourceMapURL()))
|
||||||
|
@ -3606,13 +3608,13 @@ BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...)
|
BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...)
|
||||||
{
|
{
|
||||||
TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos;
|
TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos;
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, errorNumber);
|
va_start(args, errorNumber);
|
||||||
bool result = tokenStream()->reportStrictWarningErrorNumberVA(pos.begin, errorNumber, args);
|
bool result = tokenStream()->reportExtraWarningErrorNumberVA(pos.begin, errorNumber, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -7834,7 +7836,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
|
||||||
|
|
||||||
Rooted<JSObject*> sourceObject(cx, script->sourceObject());
|
Rooted<JSObject*> sourceObject(cx, script->sourceObject());
|
||||||
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
|
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
|
||||||
funbox->bufStart, funbox->bufEnd));
|
funbox->bufStart, funbox->bufEnd,
|
||||||
|
funbox->preludeStart));
|
||||||
if (!script)
|
if (!script)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -8704,13 +8707,13 @@ BytecodeEmitter::emitStatement(ParseNode* pn)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (directive) {
|
if (directive) {
|
||||||
if (!reportStrictWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive))
|
if (!reportExtraWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
current->currentLine = parser->tokenStream.srcCoords.lineNum(pn2->pn_pos.begin);
|
current->currentLine = parser->tokenStream.srcCoords.lineNum(pn2->pn_pos.begin);
|
||||||
current->lastColumn = 0;
|
current->lastColumn = 0;
|
||||||
if (!reportStrictWarning(pn2, JSMSG_USELESS_EXPR))
|
if (!reportExtraWarning(pn2, JSMSG_USELESS_EXPR))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -388,7 +388,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
||||||
}
|
}
|
||||||
|
|
||||||
bool reportError(ParseNode* pn, unsigned errorNumber, ...);
|
bool reportError(ParseNode* pn, unsigned errorNumber, ...);
|
||||||
bool reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...);
|
bool reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...);
|
||||||
bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...);
|
bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...);
|
||||||
|
|
||||||
// If pn contains a useful expression, return true with *answer set to true.
|
// If pn contains a useful expression, return true with *answer set to true.
|
||||||
|
|
|
@ -670,9 +670,18 @@ class FullParseHandler
|
||||||
pn->setDirectRHSAnonFunction(true);
|
pn->setDirectRHSAnonFunction(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newFunctionDefinition() {
|
ParseNode* newFunctionStatement() {
|
||||||
return new_<CodeNode>(PNK_FUNCTION, pos());
|
return new_<CodeNode>(PNK_FUNCTION, JSOP_NOP, pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParseNode* newFunctionExpression() {
|
||||||
|
return new_<CodeNode>(PNK_FUNCTION, JSOP_LAMBDA, pos());
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseNode* newArrowFunction() {
|
||||||
|
return new_<CodeNode>(PNK_FUNCTION, JSOP_LAMBDA_ARROW, pos());
|
||||||
|
}
|
||||||
|
|
||||||
bool setComprehensionLambdaBody(ParseNode* pn, ParseNode* body) {
|
bool setComprehensionLambdaBody(ParseNode* pn, ParseNode* body) {
|
||||||
MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
|
MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
|
||||||
ParseNode* paramsBody = newList(PNK_PARAMSBODY, body);
|
ParseNode* paramsBody = newList(PNK_PARAMSBODY, body);
|
||||||
|
@ -699,7 +708,7 @@ class FullParseHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newModule() {
|
ParseNode* newModule() {
|
||||||
return new_<CodeNode>(PNK_MODULE, pos());
|
return new_<CodeNode>(PNK_MODULE, JSOP_NOP, pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) {
|
ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) {
|
||||||
|
@ -845,7 +854,7 @@ class FullParseHandler
|
||||||
MOZ_MUST_USE ParseNode* setLikelyIIFE(ParseNode* pn) {
|
MOZ_MUST_USE ParseNode* setLikelyIIFE(ParseNode* pn) {
|
||||||
return parenthesize(pn);
|
return parenthesize(pn);
|
||||||
}
|
}
|
||||||
void setPrologue(ParseNode* pn) {
|
void setInDirectivePrologue(ParseNode* pn) {
|
||||||
pn->pn_prologue = true;
|
pn->pn_prologue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -926,10 +926,14 @@ struct ListNode : public ParseNode
|
||||||
|
|
||||||
struct CodeNode : public ParseNode
|
struct CodeNode : public ParseNode
|
||||||
{
|
{
|
||||||
CodeNode(ParseNodeKind kind, const TokenPos& pos)
|
CodeNode(ParseNodeKind kind, JSOp op, const TokenPos& pos)
|
||||||
: ParseNode(kind, JSOP_NOP, PN_CODE, pos)
|
: ParseNode(kind, op, PN_CODE, pos)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(kind == PNK_FUNCTION || kind == PNK_MODULE);
|
MOZ_ASSERT(kind == PNK_FUNCTION || kind == PNK_MODULE);
|
||||||
|
MOZ_ASSERT_IF(kind == PNK_MODULE, op == JSOP_NOP);
|
||||||
|
MOZ_ASSERT(op == JSOP_NOP || // statement, module
|
||||||
|
op == JSOP_LAMBDA_ARROW || // arrow function
|
||||||
|
op == JSOP_LAMBDA); // expression, method, comprehension, accessor, &c.
|
||||||
MOZ_ASSERT(!pn_body);
|
MOZ_ASSERT(!pn_body);
|
||||||
MOZ_ASSERT(!pn_objbox);
|
MOZ_ASSERT(!pn_objbox);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -769,13 +769,13 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
*
|
*
|
||||||
* Ex:
|
* Ex:
|
||||||
* PossibleError possibleError(*this);
|
* PossibleError possibleError(*this);
|
||||||
* possibleError.setPendingExpressionError(pn, JSMSG_BAD_PROP_ID);
|
* possibleError.setPendingExpressionErrorAt(pos, JSMSG_BAD_PROP_ID);
|
||||||
* // A JSMSG_BAD_PROP_ID ParseError is reported, returns false.
|
* // A JSMSG_BAD_PROP_ID ParseError is reported, returns false.
|
||||||
* if (!possibleError.checkForExpressionError())
|
* if (!possibleError.checkForExpressionError())
|
||||||
* return false; // we reach this point with a pending exception
|
* return false; // we reach this point with a pending exception
|
||||||
*
|
*
|
||||||
* PossibleError possibleError(*this);
|
* PossibleError possibleError(*this);
|
||||||
* possibleError.setPendingExpressionError(pn, JSMSG_BAD_PROP_ID);
|
* possibleError.setPendingExpressionErrorAt(pos, JSMSG_BAD_PROP_ID);
|
||||||
* // Returns true, no error is reported.
|
* // Returns true, no error is reported.
|
||||||
* if (!possibleError.checkForDestructuringError())
|
* if (!possibleError.checkForDestructuringError())
|
||||||
* return false; // not reached, no pending exception
|
* return false; // not reached, no pending exception
|
||||||
|
@ -815,7 +815,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
|
|
||||||
// Set a pending error. Only a single error may be set per instance and
|
// Set a pending error. Only a single error may be set per instance and
|
||||||
// error kind.
|
// error kind.
|
||||||
void setPending(ErrorKind kind, Node pn, unsigned errorNumber);
|
void setPending(ErrorKind kind, const TokenPos& pos, unsigned errorNumber);
|
||||||
|
|
||||||
// If there is a pending error, report it and return false, otherwise
|
// If there is a pending error, report it and return false, otherwise
|
||||||
// return true.
|
// return true.
|
||||||
|
@ -830,12 +830,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
// Set a pending destructuring error. Only a single error may be set
|
// Set a pending destructuring error. Only a single error may be set
|
||||||
// per instance, i.e. subsequent calls to this method are ignored and
|
// per instance, i.e. subsequent calls to this method are ignored and
|
||||||
// won't overwrite the existing pending error.
|
// won't overwrite the existing pending error.
|
||||||
void setPendingDestructuringError(Node pn, unsigned errorNumber);
|
void setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber);
|
||||||
|
|
||||||
// Set a pending expression error. Only a single error may be set per
|
// Set a pending expression error. Only a single error may be set per
|
||||||
// instance, i.e. subsequent calls to this method are ignored and won't
|
// instance, i.e. subsequent calls to this method are ignored and won't
|
||||||
// overwrite the existing pending error.
|
// overwrite the existing pending error.
|
||||||
void setPendingExpressionError(Node pn, unsigned errorNumber);
|
void setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber);
|
||||||
|
|
||||||
// If there is a pending destructuring error, report it and return
|
// If there is a pending destructuring error, report it and return
|
||||||
// false, otherwise return true. Clears any pending expression error.
|
// false, otherwise return true. Clears any pending expression error.
|
||||||
|
@ -903,14 +903,40 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
void prepareNodeForMutation(Node node) { handler.prepareNodeForMutation(node); }
|
void prepareNodeForMutation(Node node) { handler.prepareNodeForMutation(node); }
|
||||||
void freeTree(Node node) { handler.freeTree(node); }
|
void freeTree(Node node) { handler.freeTree(node); }
|
||||||
|
|
||||||
private:
|
|
||||||
bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
|
|
||||||
unsigned errorNumber, va_list args);
|
|
||||||
public:
|
public:
|
||||||
bool report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...);
|
|
||||||
bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...);
|
bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...);
|
||||||
bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber,
|
|
||||||
...);
|
/* Report the given error at the current offset. */
|
||||||
|
void error(unsigned errorNumber, ...);
|
||||||
|
|
||||||
|
/* Report the given error at the given offset. */
|
||||||
|
void errorAt(uint32_t offset, unsigned errorNumber, ...);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle a strict mode error at the current offset. Report an error if in
|
||||||
|
* strict mode code, or warn if not, using the given error number and
|
||||||
|
* arguments.
|
||||||
|
*/
|
||||||
|
MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle a strict mode error at the given offset. Report an error if in
|
||||||
|
* strict mode code, or warn if not, using the given error number and
|
||||||
|
* arguments.
|
||||||
|
*/
|
||||||
|
MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...);
|
||||||
|
|
||||||
|
/* Report the given warning at the current offset. */
|
||||||
|
MOZ_MUST_USE bool warning(unsigned errorNumber, ...);
|
||||||
|
|
||||||
|
/* Report the given warning at the given offset. */
|
||||||
|
MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If extra warnings are enabled, report the given warning at the current
|
||||||
|
* offset.
|
||||||
|
*/
|
||||||
|
MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...);
|
||||||
|
|
||||||
Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
|
Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
|
||||||
const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames,
|
const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames,
|
||||||
|
@ -954,7 +980,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
* cx->tempLifoAlloc.
|
* cx->tempLifoAlloc.
|
||||||
*/
|
*/
|
||||||
ObjectBox* newObjectBox(JSObject* obj);
|
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,
|
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||||
bool tryAnnexB);
|
bool tryAnnexB);
|
||||||
|
|
||||||
|
@ -1034,8 +1061,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
|
|
||||||
// Parse an inner function given an enclosing ParseContext and a
|
// Parse an inner function given an enclosing ParseContext and a
|
||||||
// FunctionBox for the inner function.
|
// FunctionBox for the inner function.
|
||||||
bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, InHandling inHandling,
|
bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t preludeStart,
|
||||||
YieldHandling yieldHandling, FunctionSyntaxKind kind,
|
InHandling inHandling, YieldHandling yieldHandling,
|
||||||
|
FunctionSyntaxKind kind,
|
||||||
Directives inheritedDirectives, Directives* newDirectives);
|
Directives inheritedDirectives, Directives* newDirectives);
|
||||||
|
|
||||||
// Parse a function's formal parameters and its body assuming its function
|
// Parse a function's formal parameters and its body assuming its function
|
||||||
|
@ -1088,9 +1116,10 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
* Some parsers have two versions: an always-inlined version (with an 'i'
|
* Some parsers have two versions: an always-inlined version (with an 'i'
|
||||||
* suffix) and a never-inlined version (with an 'n' suffix).
|
* 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);
|
FunctionAsyncKind asyncKind = SyncFunction);
|
||||||
Node functionExpr(InvokedPrediction invoked = PredictUninvoked,
|
Node functionExpr(uint32_t preludeStart, InvokedPrediction invoked = PredictUninvoked,
|
||||||
FunctionAsyncKind asyncKind = SyncFunction);
|
FunctionAsyncKind asyncKind = SyncFunction);
|
||||||
|
|
||||||
Node statementList(YieldHandling yieldHandling);
|
Node statementList(YieldHandling yieldHandling);
|
||||||
|
@ -1106,7 +1135,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
Node* forInitialPart,
|
Node* forInitialPart,
|
||||||
mozilla::Maybe<ParseContext::Scope>& forLetImpliedScope,
|
mozilla::Maybe<ParseContext::Scope>& forLetImpliedScope,
|
||||||
Node* forInOrOfExpression);
|
Node* forInOrOfExpression);
|
||||||
bool validateForInOrOfLHSExpression(Node target, PossibleError* possibleError);
|
|
||||||
Node expressionAfterForInOrOf(ParseNodeKind forHeadKind, YieldHandling yieldHandling);
|
Node expressionAfterForInOrOf(ParseNodeKind forHeadKind, YieldHandling yieldHandling);
|
||||||
|
|
||||||
Node switchStatement(YieldHandling yieldHandling);
|
Node switchStatement(YieldHandling yieldHandling);
|
||||||
|
@ -1222,7 +1250,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
bool tryNewTarget(Node& newTarget);
|
bool tryNewTarget(Node& newTarget);
|
||||||
bool checkAndMarkSuperScope();
|
bool checkAndMarkSuperScope();
|
||||||
|
|
||||||
Node methodDefinition(PropertyType propType, HandleAtom funName);
|
Node methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Additional JS parsers.
|
* Additional JS parsers.
|
||||||
|
@ -1230,10 +1258,11 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
|
bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
|
||||||
Node funcpn);
|
Node funcpn);
|
||||||
|
|
||||||
Node functionDefinition(InHandling inHandling, YieldHandling yieldHandling, HandleAtom name,
|
Node functionDefinition(uint32_t preludeStart, Node pn,
|
||||||
|
InHandling inHandling, YieldHandling yieldHandling, HandleAtom name,
|
||||||
FunctionSyntaxKind kind,
|
FunctionSyntaxKind kind,
|
||||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||||
InvokedPrediction invoked = PredictUninvoked);
|
bool tryAnnexB = false);
|
||||||
|
|
||||||
// Parse a function body. Pass StatementListBody if the body is a list of
|
// Parse a function body. Pass StatementListBody if the body is a list of
|
||||||
// statements; pass ExpressionBody if the body is a single expression.
|
// statements; pass ExpressionBody if the body is a single expression.
|
||||||
|
@ -1298,17 +1327,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AssignmentFlavor {
|
|
||||||
PlainAssignment,
|
|
||||||
CompoundAssignment,
|
|
||||||
KeyedDestructuringAssignment,
|
|
||||||
IncrementAssignment,
|
|
||||||
DecrementAssignment,
|
|
||||||
ForInOrOfTarget
|
|
||||||
};
|
|
||||||
|
|
||||||
bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor,
|
|
||||||
PossibleError* possibleError=nullptr);
|
|
||||||
bool matchInOrOf(bool* isForInp, bool* isForOfp);
|
bool matchInOrOf(bool* isForInp, bool* isForOfp);
|
||||||
|
|
||||||
bool hasUsedFunctionSpecialName(HandlePropertyName name);
|
bool hasUsedFunctionSpecialName(HandlePropertyName name);
|
||||||
|
@ -1319,16 +1337,16 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
Node newDotGeneratorName();
|
Node newDotGeneratorName();
|
||||||
bool declareDotGeneratorName();
|
bool declareDotGeneratorName();
|
||||||
|
|
||||||
bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind,
|
bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind,
|
||||||
GeneratorKind generatorKind, bool* tryAnnexB);
|
bool tryAnnexB);
|
||||||
bool skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, bool tryAnnexB);
|
bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart,
|
||||||
bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun,
|
|
||||||
InHandling inHandling, YieldHandling yieldHandling,
|
InHandling inHandling, YieldHandling yieldHandling,
|
||||||
FunctionSyntaxKind kind,
|
FunctionSyntaxKind kind,
|
||||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
|
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
|
||||||
Directives inheritedDirectives, Directives* newDirectives);
|
Directives inheritedDirectives, Directives* newDirectives);
|
||||||
bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, InHandling inHandling,
|
bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t preludeStart,
|
||||||
YieldHandling yieldHandling, FunctionSyntaxKind kind,
|
InHandling inHandling, YieldHandling yieldHandling,
|
||||||
|
FunctionSyntaxKind kind,
|
||||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||||
bool tryAnnexB,
|
bool tryAnnexB,
|
||||||
Directives inheritedDirectives, Directives* newDirectives);
|
Directives inheritedDirectives, Directives* newDirectives);
|
||||||
|
@ -1346,10 +1364,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls);
|
FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool reportIfArgumentsEvalTarget(Node nameNode);
|
bool checkIncDecOperand(Node operand, uint32_t operandOffset);
|
||||||
bool reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor);
|
|
||||||
|
|
||||||
bool checkAndMarkAsIncOperand(Node kid, AssignmentFlavor flavor);
|
|
||||||
bool checkStrictAssignment(Node lhs);
|
bool checkStrictAssignment(Node lhs);
|
||||||
bool checkStrictBinding(PropertyName* name, TokenPos pos);
|
bool checkStrictBinding(PropertyName* name, TokenPos pos);
|
||||||
|
|
||||||
|
@ -1404,16 +1419,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
bool checkDestructuringObject(Node objectPattern, mozilla::Maybe<DeclarationKind> maybeDecl);
|
bool checkDestructuringObject(Node objectPattern, mozilla::Maybe<DeclarationKind> maybeDecl);
|
||||||
bool checkDestructuringName(Node expr, mozilla::Maybe<DeclarationKind> maybeDecl);
|
bool checkDestructuringName(Node expr, mozilla::Maybe<DeclarationKind> maybeDecl);
|
||||||
|
|
||||||
bool checkAssignmentToCall(Node node, unsigned errnum);
|
|
||||||
|
|
||||||
Node newNumber(const Token& tok) {
|
Node newNumber(const Token& tok) {
|
||||||
return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
|
return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Node null() { return ParseHandler::null(); }
|
static Node null() { return ParseHandler::null(); }
|
||||||
|
|
||||||
bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum);
|
|
||||||
|
|
||||||
JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom);
|
JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom);
|
||||||
|
|
||||||
TokenPos pos() const { return tokenStream.currentToken().pos; }
|
TokenPos pos() const { return tokenStream.currentToken().pos; }
|
||||||
|
|
|
@ -450,6 +450,7 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||||
uint32_t bufEnd;
|
uint32_t bufEnd;
|
||||||
uint32_t startLine;
|
uint32_t startLine;
|
||||||
uint32_t startColumn;
|
uint32_t startColumn;
|
||||||
|
uint32_t preludeStart;
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
|
|
||||||
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
|
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
|
||||||
|
@ -476,8 +477,8 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||||
FunctionContextFlags funCxFlags;
|
FunctionContextFlags funCxFlags;
|
||||||
|
|
||||||
FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
|
FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
|
||||||
Directives directives, bool extraWarnings, GeneratorKind generatorKind,
|
uint32_t preludeStart, Directives directives, bool extraWarnings,
|
||||||
FunctionAsyncKind asyncKind);
|
GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
|
||||||
|
|
||||||
MutableHandle<LexicalScope::Data*> namedLambdaBindings() {
|
MutableHandle<LexicalScope::Data*> namedLambdaBindings() {
|
||||||
MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms());
|
MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms());
|
||||||
|
|
|
@ -342,7 +342,10 @@ class SyntaxParseHandler
|
||||||
|
|
||||||
void checkAndSetIsDirectRHSAnonFunction(Node pn) {}
|
void checkAndSetIsDirectRHSAnonFunction(Node pn) {}
|
||||||
|
|
||||||
Node newFunctionDefinition() { return NodeFunctionDefinition; }
|
Node newFunctionStatement() { return NodeFunctionDefinition; }
|
||||||
|
Node newFunctionExpression() { return NodeFunctionDefinition; }
|
||||||
|
Node newArrowFunction() { return NodeFunctionDefinition; }
|
||||||
|
|
||||||
bool setComprehensionLambdaBody(Node pn, Node body) { return true; }
|
bool setComprehensionLambdaBody(Node pn, Node body) { return true; }
|
||||||
void setFunctionFormalParametersAndBody(Node pn, Node kid) {}
|
void setFunctionFormalParametersAndBody(Node pn, Node kid) {}
|
||||||
void setFunctionBody(Node pn, Node kid) {}
|
void setFunctionBody(Node pn, Node kid) {}
|
||||||
|
@ -519,7 +522,7 @@ class SyntaxParseHandler
|
||||||
MOZ_MUST_USE Node setLikelyIIFE(Node pn) {
|
MOZ_MUST_USE Node setLikelyIIFE(Node pn) {
|
||||||
return pn; // Remain in syntax-parse mode.
|
return pn; // Remain in syntax-parse mode.
|
||||||
}
|
}
|
||||||
void setPrologue(Node pn) {}
|
void setInDirectivePrologue(Node pn) {}
|
||||||
|
|
||||||
bool isConstant(Node pn) { return false; }
|
bool isConstant(Node pn) { return false; }
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,12 @@ frontend::IsIdentifier(JSLinearString* str)
|
||||||
: ::IsIdentifierMaybeNonBMP(str->twoByteChars(nogc), str->length());
|
: ::IsIdentifierMaybeNonBMP(str->twoByteChars(nogc), str->length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
frontend::IsIdentifier(const char* chars, size_t length)
|
||||||
|
{
|
||||||
|
return ::IsIdentifier(chars, length);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
frontend::IsIdentifier(const char16_t* chars, size_t length)
|
frontend::IsIdentifier(const char16_t* chars, size_t length)
|
||||||
{
|
{
|
||||||
|
@ -780,7 +786,7 @@ TokenStream::reportWarning(unsigned errorNumber, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TokenStream::reportStrictWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args)
|
TokenStream::reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args)
|
||||||
{
|
{
|
||||||
if (!options().extraWarningsOption)
|
if (!options().extraWarningsOption)
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -375,8 +375,7 @@ class MOZ_STACK_CLASS TokenStream
|
||||||
va_list args);
|
va_list args);
|
||||||
bool reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber,
|
bool reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber,
|
||||||
va_list args);
|
va_list args);
|
||||||
bool reportStrictWarningErrorNumberVA(uint32_t offset, unsigned errorNumber,
|
bool reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args);
|
||||||
va_list args);
|
|
||||||
|
|
||||||
// asm.js reporter
|
// asm.js reporter
|
||||||
void reportAsmJSError(uint32_t offset, unsigned errorNumber, ...);
|
void reportAsmJSError(uint32_t offset, unsigned errorNumber, ...);
|
||||||
|
@ -570,6 +569,13 @@ class MOZ_STACK_CLASS TokenStream
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOZ_MUST_USE bool peekOffset(uint32_t* offset, Modifier modifier = None) {
|
||||||
|
TokenPos pos;
|
||||||
|
if (!peekTokenPos(&pos, modifier))
|
||||||
|
return false;
|
||||||
|
*offset = pos.begin;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
// This is like peekToken(), with one exception: if there is an EOL
|
// This is like peekToken(), with one exception: if there is an EOL
|
||||||
// between the end of the current token and the start of the next token, it
|
// between the end of the current token and the start of the next token, it
|
||||||
// return true and store TOK_EOL in |*ttp|. In that case, no token with
|
// return true and store TOK_EOL in |*ttp|. In that case, no token with
|
||||||
|
|
|
@ -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.toString(), funcBody1);
|
||||||
assertEq(f0.toSource(), '(' + funcBody1 + ')');
|
assertEq(f0.toSource(), '(' + funcBody1 + ')');
|
||||||
|
|
||||||
|
@ -48,14 +48,14 @@ assertEq(g.toString(), funcBody2);
|
||||||
assertEq(g.toSource(), '(' + funcBody2 + ')');
|
assertEq(g.toSource(), '(' + funcBody2 + ')');
|
||||||
|
|
||||||
f0 = new Function(bodyOnly);
|
f0 = new Function(bodyOnly);
|
||||||
assertEq(f0.toString(), "function anonymous() {\n" + bodyOnly + "\n}");
|
assertEq(f0.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}");
|
||||||
assertEq(f0.toSource(), "(function anonymous() {\n" + bodyOnly + "\n})");
|
assertEq(f0.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})");
|
||||||
|
|
||||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||||
var m = new Function(bodyOnly);
|
var m = new Function(bodyOnly);
|
||||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||||
assertEq(m.toString(), "function anonymous() {\n" + bodyOnly + "\n}");
|
assertEq(m.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}");
|
||||||
assertEq(m.toSource(), "(function anonymous() {\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.toString(), funcBody1);
|
||||||
assertEq(f1.toSource(), '(' + funcBody1 + ')');
|
assertEq(f1.toSource(), '(' + funcBody1 + ')');
|
||||||
|
|
||||||
|
@ -107,14 +107,14 @@ assertEq(g.toString(), funcBody2);
|
||||||
assertEq(g.toSource(), '(' + funcBody2 + ')');
|
assertEq(g.toSource(), '(' + funcBody2 + ')');
|
||||||
|
|
||||||
f1 = new Function('glob', bodyOnly);
|
f1 = new Function('glob', bodyOnly);
|
||||||
assertEq(f1.toString(), "function anonymous(glob) {\n" + bodyOnly + "\n}");
|
assertEq(f1.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}");
|
||||||
assertEq(f1.toSource(), "(function anonymous(glob) {\n" + bodyOnly + "\n})");
|
assertEq(f1.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})");
|
||||||
|
|
||||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||||
var m = new Function('glob', bodyOnly);
|
var m = new Function('glob', bodyOnly);
|
||||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||||
assertEq(m.toString(), "function anonymous(glob) {\n" + bodyOnly + "\n}");
|
assertEq(m.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}");
|
||||||
assertEq(m.toSource(), "(function anonymous(glob) {\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.toString(), funcBody);
|
||||||
assertEq(f2.toSource(), funcBody);
|
assertEq(f2.toSource(), funcBody);
|
||||||
|
|
||||||
f2 = function (glob, ffi) {
|
f2 = function(glob, ffi) {
|
||||||
"use asm";
|
"use asm";
|
||||||
function g() {}
|
function g() {}
|
||||||
return g;
|
return g;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
funcBody1 = funcBody.replace('function f2', 'function ');
|
funcBody1 = funcBody.replace('function f2', 'function');
|
||||||
assertEq(f2.toString(), funcBody1);
|
assertEq(f2.toString(), funcBody1);
|
||||||
assertEq(f2.toSource(), '(' + funcBody1 + ')');
|
assertEq(f2.toSource(), '(' + funcBody1 + ')');
|
||||||
|
|
||||||
|
@ -167,14 +167,14 @@ assertEq(g.toString(), funcBody2);
|
||||||
assertEq(g.toSource(), '(' + funcBody2 + ')');
|
assertEq(g.toSource(), '(' + funcBody2 + ')');
|
||||||
|
|
||||||
f2 = new Function('glob', 'ffi', bodyOnly);
|
f2 = new Function('glob', 'ffi', bodyOnly);
|
||||||
assertEq(f2.toString(), "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" + bodyOnly + "\n})");
|
assertEq(f2.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})");
|
||||||
|
|
||||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||||
var m = new Function('glob', 'ffi', bodyOnly);
|
var m = new Function('glob', 'ffi', bodyOnly);
|
||||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||||
assertEq(m.toString(), "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" + 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.toString(), funcBody);
|
||||||
assertEq(f3.toSource(), funcBody);
|
assertEq(f3.toSource(), funcBody);
|
||||||
|
|
||||||
f3 = function (glob, ffi, heap) {
|
f3 = function(glob, ffi, heap) {
|
||||||
"use asm";
|
"use asm";
|
||||||
function g() {}
|
function g() {}
|
||||||
return g;
|
return g;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
funcBody1 = funcBody.replace('function f3', 'function ');
|
funcBody1 = funcBody.replace('function f3', 'function');
|
||||||
assertEq(f3.toString(), funcBody1);
|
assertEq(f3.toString(), funcBody1);
|
||||||
assertEq(f3.toSource(), '(' + funcBody1 + ')');
|
assertEq(f3.toSource(), '(' + funcBody1 + ')');
|
||||||
|
|
||||||
|
@ -227,14 +227,14 @@ assertEq(g.toString(), funcBody2);
|
||||||
assertEq(g.toSource(), '(' + funcBody2 + ')');
|
assertEq(g.toSource(), '(' + funcBody2 + ')');
|
||||||
|
|
||||||
f3 = new Function('glob', 'ffi', 'heap', bodyOnly);
|
f3 = new Function('glob', 'ffi', 'heap', bodyOnly);
|
||||||
assertEq(f3.toString(), "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" + bodyOnly + "\n})");
|
assertEq(f3.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})");
|
||||||
|
|
||||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||||
var m = new Function('glob', 'ffi', 'heap', bodyOnly);
|
var m = new Function('glob', 'ffi', 'heap', bodyOnly);
|
||||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||||
assertEq(m.toString(), "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" + bodyOnly + "\n})");
|
assertEq(m.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})");
|
||||||
}
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -243,7 +243,7 @@ if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
var funcSource =
|
var funcSource =
|
||||||
`function (glob, ffi, heap) {
|
`function(glob, ffi, heap) {
|
||||||
"use asm";
|
"use asm";
|
||||||
function g() {}
|
function g() {}
|
||||||
return g;
|
return g;
|
||||||
|
@ -252,7 +252,7 @@ var funcSource =
|
||||||
var f4 = eval("\"use strict\";\n(" + funcSource + ")");
|
var f4 = eval("\"use strict\";\n(" + funcSource + ")");
|
||||||
|
|
||||||
var expectedToString = funcSource;
|
var expectedToString = funcSource;
|
||||||
var expectedToSource = '(' + expectedToString + ')'
|
var expectedToSource = '(' + expectedToString + ')';
|
||||||
|
|
||||||
assertEq(f4.toString(), expectedToString);
|
assertEq(f4.toString(), expectedToString);
|
||||||
assertEq(f4.toSource(), expectedToSource);
|
assertEq(f4.toSource(), expectedToSource);
|
||||||
|
|
|
@ -5,4 +5,4 @@ for (var i=0; i<400; ++i) {
|
||||||
x += String.fromCharCode(i * 289);
|
x += String.fromCharCode(i * 289);
|
||||||
}
|
}
|
||||||
var s = "'" + x + "'";
|
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;");
|
var f = Function("a", "b", "return a + b;");
|
||||||
assertEq(f.toString(), "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) {\nreturn a + b;\n})");
|
assertEq(f.toSource(), "(function anonymous(a,b\n) {\nreturn a + b;\n})");
|
||||||
assertEq(decompileFunction(f), f.toString());
|
assertEq(decompileFunction(f), f.toString());
|
||||||
f = Function("a", "...rest", "return rest[42] + b;");
|
f = Function("a", "...rest", "return rest[42] + b;");
|
||||||
assertEq(f.toString(), "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) {\nreturn rest[42] + b;\n})")
|
assertEq(f.toSource(), "(function anonymous(a,...rest\n) {\nreturn rest[42] + b;\n})")
|
||||||
assertEq(decompileFunction(f), f.toString());
|
assertEq(decompileFunction(f), f.toString());
|
||||||
f = Function("");
|
f = Function("");
|
||||||
assertEq(f.toString(), "function anonymous() {\n\n}");
|
assertEq(f.toString(), "function anonymous(\n) {\n\n}");
|
||||||
f = Function("", "(abc)");
|
f = Function("", "(abc)");
|
||||||
assertEq(f.toString(), "function anonymous() {\n(abc)\n}");
|
assertEq(f.toString(), "function anonymous(\n) {\n(abc)\n}");
|
||||||
f = Function("", "return function (a, b) a + b;")();
|
f = Function("", "return function (a,b) a + b;")();
|
||||||
assertEq(f.toString(), "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 o = {get prop() a + b, set prop(x) a + b};
|
||||||
var prop = Object.getOwnPropertyDescriptor(o, "prop");
|
var prop = Object.getOwnPropertyDescriptor(o, "prop");
|
||||||
assertEq(prop.get.toString(), "function get prop() a + b");
|
assertEq(prop.get.toString(), "get prop() { a + b; }");
|
||||||
assertEq(prop.get.toSource(), "(function get prop() a + b)");
|
assertEq(prop.get.toSource(), "get prop() { a + b; }");
|
||||||
assertEq(prop.set.toString(), "function set prop(x) a + b");
|
assertEq(prop.set.toString(), "set prop(x) { a + b; }");
|
||||||
assertEq(prop.set.toSource(), "(function 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})");
|
assertEq(o.toSource(), "({get prop() { a + b; }, set prop(x) { a + b; }})");
|
||||||
|
|
|
@ -9,7 +9,7 @@ function test(str, arg, result)
|
||||||
var fun = new Function('x', str);
|
var fun = new Function('x', str);
|
||||||
|
|
||||||
var got = fun.toSource();
|
var got = fun.toSource();
|
||||||
var expect = '(function anonymous(x) {\n' + str + '\n})';
|
var expect = '(function anonymous(x\n) {\n' + str + '\n})';
|
||||||
if (got !== expect) {
|
if (got !== expect) {
|
||||||
print("GOT: " + got);
|
print("GOT: " + got);
|
||||||
print("EXPECT: " + expect);
|
print("EXPECT: " + expect);
|
||||||
|
|
|
@ -10,5 +10,5 @@ assertEq(arr.length, 10);
|
||||||
gc();
|
gc();
|
||||||
|
|
||||||
for (var i = 0; i < arr.length; i++)
|
for (var i = 0; i < arr.length; i++)
|
||||||
assertEq(arr[i].lineCount, 3);
|
assertEq(arr[i].lineCount, 4);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,6 @@ assertEq(arr.length, 100);
|
||||||
gc(g);
|
gc(g);
|
||||||
|
|
||||||
for (var i = 0; i < arr.length; i++)
|
for (var i = 0; i < arr.length; i++)
|
||||||
assertEq(arr[i].lineCount, 3);
|
assertEq(arr[i].lineCount, 4);
|
||||||
|
|
||||||
gc();
|
gc();
|
||||||
|
|
|
@ -20,6 +20,6 @@ function test(string, range) {
|
||||||
}
|
}
|
||||||
|
|
||||||
test("eval('2 * 3')", [0, 5]);
|
test("eval('2 * 3')", [0, 5]);
|
||||||
test("new Function('2 * 3')", [0, 12]);
|
test("new Function('2 * 3')", [0, 31]);
|
||||||
test("new Function('x', 'x * x')", [0, 13]);
|
test("new Function('x', 'x * x')", [0, 32]);
|
||||||
assertEq(count, 6);
|
assertEq(count, 6);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
let g = newGlobal();
|
let g = newGlobal();
|
||||||
let dbg = new Debugger(g);
|
let dbg = new Debugger(g);
|
||||||
|
|
||||||
|
var text;
|
||||||
var count = 0;
|
var count = 0;
|
||||||
dbg.onNewScript = function (script) {
|
dbg.onNewScript = function (script) {
|
||||||
++count;
|
++count;
|
||||||
|
|
|
@ -12,18 +12,18 @@ var o = {};
|
||||||
Object.defineProperty(o, "prop", {get: function() { return 1; },
|
Object.defineProperty(o, "prop", {get: function() { return 1; },
|
||||||
set: function() { return 2; },
|
set: function() { return 2; },
|
||||||
enumerable: true, configurable: true});
|
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
|
// obj.toSource TwoByte
|
||||||
Object.defineProperty(o, "prop", {get: function() { return "\u1200"; },
|
Object.defineProperty(o, "prop", {get: function() { return "\u1200"; },
|
||||||
set: function() { return "\u1200"; },
|
set: function() { return "\u1200"; },
|
||||||
enumerable: true});
|
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; };
|
var ff = function() { return 10; };
|
||||||
ff.toSource = function() { return "((11))"; }
|
ff.toSource = function() { return "((11))"; }
|
||||||
Object.defineProperty(o, "prop", {get: ff, set: ff, enumerable: true});
|
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
|
// XDR
|
||||||
load(libdir + 'bytecode-cache.js');
|
load(libdir + 'bytecode-cache.js');
|
||||||
|
|
|
@ -6,11 +6,11 @@ function test() {
|
||||||
|
|
||||||
var f = Function(arg1TwoByte, arg2Latin1, bodyLatin1);
|
var f = Function(arg1TwoByte, arg2Latin1, bodyLatin1);
|
||||||
assertEq(f(10, 20), 60);
|
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;";
|
var bodyTwoByte = "return arg1\u1200 + arg2;";
|
||||||
f = Function(arg1TwoByte, arg2Latin1, bodyTwoByte);
|
f = Function(arg1TwoByte, arg2Latin1, bodyTwoByte);
|
||||||
assertEq(f(30, 40), 70);
|
assertEq(f(30, 40), 70);
|
||||||
assertEq(f.toSource().includes("arg1\u1200, arg2"), true);
|
assertEq(f.toSource().includes("arg1\u1200,arg2"), true);
|
||||||
}
|
}
|
||||||
test();
|
test();
|
||||||
|
|
|
@ -186,7 +186,6 @@ MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as'
|
||||||
MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
|
MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
|
||||||
MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async")
|
MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async")
|
||||||
MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression")
|
MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression")
|
||||||
MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value")
|
|
||||||
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
|
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
|
||||||
MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
|
MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
|
||||||
MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration")
|
MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration")
|
||||||
|
@ -200,12 +199,12 @@ MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loo
|
||||||
MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side")
|
MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side")
|
||||||
MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding")
|
MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding")
|
||||||
MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with 'let'")
|
MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with 'let'")
|
||||||
MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value")
|
MSG_DEF(JSMSG_BAD_FUNCTION_YIELD, 0, JSEXN_TYPEERR, "can't use 'yield' in a function that can return a value")
|
||||||
|
MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "generator function can't return a value")
|
||||||
MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression")
|
MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression")
|
||||||
MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand")
|
MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand")
|
||||||
MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition")
|
MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition")
|
||||||
MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant")
|
MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant")
|
||||||
MSG_DEF(JSMSG_BAD_OPERAND, 1, JSEXN_SYNTAXERR, "invalid {0} operand")
|
|
||||||
MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unary expression can't appear on the left-hand side of '**'")
|
MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unary expression can't appear on the left-hand side of '**'")
|
||||||
MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id")
|
MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id")
|
||||||
MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function")
|
MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function")
|
||||||
|
@ -262,6 +261,8 @@ MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage a
|
||||||
MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal")
|
MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal")
|
||||||
MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character")
|
MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character")
|
||||||
MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module")
|
MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module")
|
||||||
|
MSG_DEF(JSMSG_OF_AFTER_FOR_LOOP_DECL, 0, JSEXN_SYNTAXERR, "a declaration in the head of a for-of loop can't have an initializer")
|
||||||
|
MSG_DEF(JSMSG_IN_AFTER_LEXICAL_FOR_DECL,0,JSEXN_SYNTAXERR, "a lexical declaration in the head of a for-in loop can't have an initializer")
|
||||||
MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers")
|
MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers")
|
||||||
MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found")
|
MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found")
|
||||||
MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
|
MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
|
||||||
|
|
|
@ -4250,7 +4250,7 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun)
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
||||||
const char* name,
|
HandleAtom name, bool isInvalidName,
|
||||||
SourceBufferHolder& srcBuf, uint32_t parameterListEnd,
|
SourceBufferHolder& srcBuf, uint32_t parameterListEnd,
|
||||||
HandleObject enclosingEnv, HandleScope enclosingScope,
|
HandleObject enclosingEnv, HandleScope enclosingScope,
|
||||||
MutableHandleFunction fun)
|
MutableHandleFunction fun)
|
||||||
|
@ -4261,13 +4261,8 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
||||||
assertSameCompartment(cx, enclosingEnv);
|
assertSameCompartment(cx, enclosingEnv);
|
||||||
RootedAtom funAtom(cx);
|
RootedAtom funAtom(cx);
|
||||||
|
|
||||||
if (name) {
|
fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL,
|
||||||
funAtom = Atomize(cx, name, strlen(name));
|
isInvalidName ? nullptr : name,
|
||||||
if (!funAtom)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom,
|
|
||||||
/* proto = */ nullptr,
|
/* proto = */ nullptr,
|
||||||
gc::AllocKind::FUNCTION, TenuredObject,
|
gc::AllocKind::FUNCTION, TenuredObject,
|
||||||
enclosingEnv));
|
enclosingEnv));
|
||||||
|
@ -4285,11 +4280,17 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MOZ_MUST_USE bool
|
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,
|
const SourceBufferHolder& srcBuf, StringBuffer* out,
|
||||||
uint32_t* parameterListEnd)
|
uint32_t* parameterListEnd)
|
||||||
{
|
{
|
||||||
|
@ -4298,6 +4299,12 @@ BuildFunctionString(unsigned nargs, const char* const* argnames,
|
||||||
|
|
||||||
if (!out->ensureTwoByteChars())
|
if (!out->ensureTwoByteChars())
|
||||||
return false;
|
return false;
|
||||||
|
if (!out->append("function "))
|
||||||
|
return false;
|
||||||
|
if (name) {
|
||||||
|
if (!out->append(name, nameLen))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!out->append("("))
|
if (!out->append("("))
|
||||||
return false;
|
return false;
|
||||||
for (unsigned i = 0; i < nargs; i++) {
|
for (unsigned i = 0; i < nargs; i++) {
|
||||||
|
@ -4334,15 +4341,32 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
|
||||||
if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
|
if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
|
||||||
return false;
|
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;
|
uint32_t parameterListEnd;
|
||||||
StringBuffer funStr(cx);
|
StringBuffer funStr(cx);
|
||||||
if (!BuildFunctionString(nargs, argnames, srcBuf, &funStr, ¶meterListEnd))
|
if (!BuildFunctionString(isInvalidName ? nullptr : name, nameLen, nargs, argnames, srcBuf,
|
||||||
|
&funStr, ¶meterListEnd)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
size_t newLen = funStr.length();
|
size_t newLen = funStr.length();
|
||||||
SourceBufferHolder newSrcBuf(funStr.stealChars(), newLen, SourceBufferHolder::GiveOwnership);
|
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)
|
JS_PUBLIC_API(bool)
|
||||||
|
|
|
@ -781,8 +781,10 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
|
||||||
|
|
||||||
RootedFunction functionProto(cx, &functionProto_->as<JSFunction>());
|
RootedFunction functionProto(cx, &functionProto_->as<JSFunction>());
|
||||||
|
|
||||||
const char* rawSource = "() {\n}";
|
const char* rawSource = "function () {\n}";
|
||||||
size_t sourceLen = strlen(rawSource);
|
size_t sourceLen = strlen(rawSource);
|
||||||
|
size_t begin = 9;
|
||||||
|
MOZ_ASSERT(rawSource[begin] == '(');
|
||||||
mozilla::UniquePtr<char16_t[], JS::FreePolicy> source(InflateString(cx, rawSource, &sourceLen));
|
mozilla::UniquePtr<char16_t[], JS::FreePolicy> source(InflateString(cx, rawSource, &sourceLen));
|
||||||
if (!source)
|
if (!source)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -804,8 +806,9 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
|
||||||
RootedScript script(cx, JSScript::Create(cx,
|
RootedScript script(cx, JSScript::Create(cx,
|
||||||
options,
|
options,
|
||||||
sourceObject,
|
sourceObject,
|
||||||
0,
|
begin,
|
||||||
ss->length()));
|
ss->length(),
|
||||||
|
0));
|
||||||
if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto))
|
if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -985,53 +988,62 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fun->isAsync()) {
|
bool funIsNonArrowLambda = fun->isLambda() && !fun->isArrow();
|
||||||
if (!out.append("async "))
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
|
|
||||||
fun->isGetter() || fun->isSetter();
|
|
||||||
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
|
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
|
||||||
|
|
||||||
// If we're not in pretty mode, put parentheses around lambda functions and methods.
|
// If we're not in pretty mode, put parentheses around lambda functions
|
||||||
if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) {
|
// so that eval returns lambda, not function statement.
|
||||||
|
if (haveSource && !prettyPrint && funIsNonArrowLambda) {
|
||||||
if (!out.append("("))
|
if (!out.append("("))
|
||||||
return nullptr;
|
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() &&
|
if (haveSource && !script->scriptSource()->hasSourceData() &&
|
||||||
!JSScript::loadSource(cx, script->scriptSource(), &haveSource))
|
!JSScript::loadSource(cx, script->scriptSource(), &haveSource))
|
||||||
{
|
{
|
||||||
return nullptr;
|
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) {
|
if (haveSource) {
|
||||||
Rooted<JSFlatString*> src(cx, script->sourceData(cx));
|
Rooted<JSFlatString*> src(cx, script->sourceDataWithPrelude(cx));
|
||||||
if (!src)
|
if (!src)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (!out.append(src))
|
if (!out.append(src))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (!prettyPrint && funIsMethodOrNonArrowLambda) {
|
if (!prettyPrint && funIsNonArrowLambda) {
|
||||||
if (!out.append(")"))
|
if (!out.append(")"))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
} else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) {
|
} else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) {
|
||||||
if (!out.append("() {\n ") ||
|
if (!AppendPrelude() ||
|
||||||
|
!out.append("() {\n ") ||
|
||||||
!out.append("[sourceless code]") ||
|
!out.append("[sourceless code]") ||
|
||||||
!out.append("\n}"))
|
!out.append("\n}"))
|
||||||
{
|
{
|
||||||
|
@ -1042,13 +1054,15 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
|
||||||
|
|
||||||
bool derived = fun->infallibleIsDefaultClassConstructor(cx);
|
bool derived = fun->infallibleIsDefaultClassConstructor(cx);
|
||||||
if (derived && fun->isDerivedClassConstructor()) {
|
if (derived && fun->isDerivedClassConstructor()) {
|
||||||
if (!out.append("(...args) {\n ") ||
|
if (!AppendPrelude() ||
|
||||||
|
!out.append("(...args) {\n ") ||
|
||||||
!out.append("super(...args);\n}"))
|
!out.append("super(...args);\n}"))
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!out.append("() {\n "))
|
if (!AppendPrelude() ||
|
||||||
|
!out.append("() {\n "))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (!derived) {
|
if (!derived) {
|
||||||
|
@ -1635,7 +1649,18 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
|
||||||
|
|
||||||
StringBuffer sb(cx);
|
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;
|
return false;
|
||||||
|
|
||||||
if (args.length() > 1) {
|
if (args.length() > 1) {
|
||||||
|
@ -1656,12 +1681,15 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
|
||||||
|
|
||||||
if (i < args.length() - 2) {
|
if (i < args.length() - 2) {
|
||||||
// Step 9.d.iii.
|
// Step 9.d.iii.
|
||||||
if (!sb.append(", "))
|
if (!sb.append(","))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!sb.append('\n'))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Remember the position of ")".
|
// Remember the position of ")".
|
||||||
Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
|
Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
|
||||||
MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
|
MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
|
||||||
|
|
|
@ -235,6 +235,7 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
|
||||||
{
|
{
|
||||||
uint32_t begin = script->sourceStart();
|
uint32_t begin = script->sourceStart();
|
||||||
uint32_t end = script->sourceEnd();
|
uint32_t end = script->sourceEnd();
|
||||||
|
uint32_t preludeStart = script->preludeStart();
|
||||||
uint32_t lineno = script->lineno();
|
uint32_t lineno = script->lineno();
|
||||||
uint32_t column = script->column();
|
uint32_t column = script->column();
|
||||||
|
|
||||||
|
@ -242,6 +243,7 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
|
||||||
packedFields = lazy->packedFields();
|
packedFields = lazy->packedFields();
|
||||||
MOZ_ASSERT(begin == lazy->begin());
|
MOZ_ASSERT(begin == lazy->begin());
|
||||||
MOZ_ASSERT(end == lazy->end());
|
MOZ_ASSERT(end == lazy->end());
|
||||||
|
MOZ_ASSERT(preludeStart == lazy->preludeStart());
|
||||||
MOZ_ASSERT(lineno == lazy->lineno());
|
MOZ_ASSERT(lineno == lazy->lineno());
|
||||||
MOZ_ASSERT(column == lazy->column());
|
MOZ_ASSERT(column == lazy->column());
|
||||||
// We can assert we have no inner functions because we don't
|
// 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) {
|
if (mode == XDR_DECODE) {
|
||||||
lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, script,
|
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
|
// As opposed to XDRLazyScript, we need to restore the runtime bits
|
||||||
// of the script, as we are trying to match the fact this function
|
// of the script, as we are trying to match the fact this function
|
||||||
|
@ -517,7 +519,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
||||||
sourceObject = &enclosingScript->sourceObject()->as<ScriptSourceObject>();
|
sourceObject = &enclosingScript->sourceObject()->as<ScriptSourceObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
script = JSScript::Create(cx, options, sourceObject, 0, 0);
|
script = JSScript::Create(cx, options, sourceObject, 0, 0, 0);
|
||||||
if (!script)
|
if (!script)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -600,6 +602,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
||||||
return false;
|
return false;
|
||||||
if (!xdr->codeUint32(&script->sourceEnd_))
|
if (!xdr->codeUint32(&script->sourceEnd_))
|
||||||
return false;
|
return false;
|
||||||
|
if (!xdr->codeUint32(&script->preludeStart_))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!xdr->codeUint32(&lineno) ||
|
if (!xdr->codeUint32(&lineno) ||
|
||||||
!xdr->codeUint32(&column) ||
|
!xdr->codeUint32(&column) ||
|
||||||
|
@ -930,6 +934,7 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript
|
||||||
{
|
{
|
||||||
uint32_t begin;
|
uint32_t begin;
|
||||||
uint32_t end;
|
uint32_t end;
|
||||||
|
uint32_t preludeStart;
|
||||||
uint32_t lineno;
|
uint32_t lineno;
|
||||||
uint32_t column;
|
uint32_t column;
|
||||||
uint64_t packedFields;
|
uint64_t packedFields;
|
||||||
|
@ -943,12 +948,14 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript
|
||||||
|
|
||||||
begin = lazy->begin();
|
begin = lazy->begin();
|
||||||
end = lazy->end();
|
end = lazy->end();
|
||||||
|
preludeStart = lazy->preludeStart();
|
||||||
lineno = lazy->lineno();
|
lineno = lazy->lineno();
|
||||||
column = lazy->column();
|
column = lazy->column();
|
||||||
packedFields = lazy->packedFields();
|
packedFields = lazy->packedFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) ||
|
if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) ||
|
||||||
|
!xdr->codeUint32(&preludeStart) ||
|
||||||
!xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) ||
|
!xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) ||
|
||||||
!xdr->codeUint64(&packedFields))
|
!xdr->codeUint64(&packedFields))
|
||||||
{
|
{
|
||||||
|
@ -957,7 +964,7 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript
|
||||||
|
|
||||||
if (mode == XDR_DECODE) {
|
if (mode == XDR_DECODE) {
|
||||||
lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript,
|
lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript,
|
||||||
packedFields, begin, end, lineno, column));
|
packedFields, begin, end, preludeStart, lineno, column));
|
||||||
if (!lazy)
|
if (!lazy)
|
||||||
return false;
|
return false;
|
||||||
fun->initLazyScript(lazy);
|
fun->initLazyScript(lazy);
|
||||||
|
@ -1430,6 +1437,13 @@ JSScript::sourceData(JSContext* cx)
|
||||||
return scriptSource()->substring(cx, sourceStart(), sourceEnd());
|
return scriptSource()->substring(cx, sourceStart(), sourceEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSFlatString*
|
||||||
|
JSScript::sourceDataWithPrelude(JSContext* cx)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(scriptSource()->hasSourceData());
|
||||||
|
return scriptSource()->substring(cx, preludeStart(), sourceEnd());
|
||||||
|
}
|
||||||
|
|
||||||
UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry()
|
UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry()
|
||||||
: cache_(nullptr), sourceChunk_()
|
: cache_(nullptr), sourceChunk_()
|
||||||
{
|
{
|
||||||
|
@ -2428,7 +2442,8 @@ JSScript::initCompartment(ExclusiveContext* cx)
|
||||||
|
|
||||||
/* static */ JSScript*
|
/* static */ JSScript*
|
||||||
JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
|
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);
|
MOZ_ASSERT(bufStart <= bufEnd);
|
||||||
|
|
||||||
|
@ -2450,6 +2465,7 @@ JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
|
||||||
script->setSourceObject(sourceObject);
|
script->setSourceObject(sourceObject);
|
||||||
script->sourceStart_ = bufStart;
|
script->sourceStart_ = bufStart;
|
||||||
script->sourceEnd_ = bufEnd;
|
script->sourceEnd_ = bufEnd;
|
||||||
|
script->preludeStart_ = preludeStart;
|
||||||
|
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
@ -3382,7 +3398,8 @@ CreateEmptyScriptForClone(JSContext* cx, HandleScript src)
|
||||||
.setNoScriptRval(src->noScriptRval())
|
.setNoScriptRval(src->noScriptRval())
|
||||||
.setVersion(src->getVersion());
|
.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*
|
JSScript*
|
||||||
|
@ -3932,7 +3949,8 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot)
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
|
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),
|
: script_(nullptr),
|
||||||
function_(fun),
|
function_(fun),
|
||||||
enclosingScope_(nullptr),
|
enclosingScope_(nullptr),
|
||||||
|
@ -3941,6 +3959,7 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
|
||||||
packedFields_(packedFields),
|
packedFields_(packedFields),
|
||||||
begin_(begin),
|
begin_(begin),
|
||||||
end_(end),
|
end_(end),
|
||||||
|
preludeStart_(preludeStart),
|
||||||
lineno_(lineno),
|
lineno_(lineno),
|
||||||
column_(column)
|
column_(column)
|
||||||
{
|
{
|
||||||
|
@ -3990,7 +4009,7 @@ LazyScript::maybeForwardedScriptSource() const
|
||||||
/* static */ LazyScript*
|
/* static */ LazyScript*
|
||||||
LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
|
LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
|
||||||
uint64_t packedFields, uint32_t begin, uint32_t end,
|
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 {
|
union {
|
||||||
PackedView p;
|
PackedView p;
|
||||||
|
@ -4018,7 +4037,8 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
|
||||||
|
|
||||||
cx->compartment()->scheduleDelazificationForDebugger();
|
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*
|
/* static */ LazyScript*
|
||||||
|
@ -4026,7 +4046,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
|
||||||
const frontend::AtomVector& closedOverBindings,
|
const frontend::AtomVector& closedOverBindings,
|
||||||
Handle<GCVector<JSFunction*, 8>> innerFunctions,
|
Handle<GCVector<JSFunction*, 8>> innerFunctions,
|
||||||
JSVersion version,
|
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 {
|
union {
|
||||||
PackedView p;
|
PackedView p;
|
||||||
|
@ -4049,7 +4070,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
|
||||||
p.isDerivedClassConstructor = false;
|
p.isDerivedClassConstructor = false;
|
||||||
p.needsHomeObject = 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)
|
if (!res)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -4070,7 +4092,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
|
||||||
HandleScript script, HandleScope enclosingScope,
|
HandleScript script, HandleScope enclosingScope,
|
||||||
HandleScript enclosingScript,
|
HandleScript enclosingScript,
|
||||||
uint64_t packedFields, uint32_t begin, uint32_t end,
|
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.
|
// Dummy atom which is not a valid property name.
|
||||||
RootedAtom dummyAtom(cx, cx->names().comma);
|
RootedAtom dummyAtom(cx, cx->names().comma);
|
||||||
|
@ -4079,7 +4101,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
|
||||||
// holding this lazy script.
|
// holding this lazy script.
|
||||||
HandleFunction dummyFun = fun;
|
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)
|
if (!res)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|
|
@ -575,10 +575,6 @@ class ScriptSource
|
||||||
introductionOffset_ = offset;
|
introductionOffset_ = offset;
|
||||||
hasIntroductionOffset_ = true;
|
hasIntroductionOffset_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t parameterListEnd() const {
|
|
||||||
return parameterListEnd_;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScriptSourceHolder
|
class ScriptSourceHolder
|
||||||
|
@ -857,9 +853,19 @@ class JSScript : public js::gc::TenuredCell
|
||||||
|
|
||||||
uint32_t bodyScopeIndex_; /* index into the scopes array of the body scope */
|
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 sourceStart_;
|
||||||
uint32_t sourceEnd_;
|
uint32_t sourceEnd_;
|
||||||
|
uint32_t preludeStart_;
|
||||||
|
|
||||||
// Number of times the script has been called or has had backedges taken.
|
// 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
|
// When running in ion, also increased for any inlined scripts. Reset if
|
||||||
|
@ -1020,7 +1026,7 @@ class JSScript : public js::gc::TenuredCell
|
||||||
// instead of private to suppress -Wunused-private-field compiler warnings.
|
// instead of private to suppress -Wunused-private-field compiler warnings.
|
||||||
protected:
|
protected:
|
||||||
#if JS_BITS_PER_WORD == 32
|
#if JS_BITS_PER_WORD == 32
|
||||||
// Currently no padding is needed.
|
uint32_t padding;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1031,7 +1037,7 @@ class JSScript : public js::gc::TenuredCell
|
||||||
static JSScript* Create(js::ExclusiveContext* cx,
|
static JSScript* Create(js::ExclusiveContext* cx,
|
||||||
const JS::ReadOnlyCompileOptions& options,
|
const JS::ReadOnlyCompileOptions& options,
|
||||||
js::HandleObject sourceObject, uint32_t sourceStart,
|
js::HandleObject sourceObject, uint32_t sourceStart,
|
||||||
uint32_t sourceEnd);
|
uint32_t sourceEnd, uint32_t preludeStart);
|
||||||
|
|
||||||
void initCompartment(js::ExclusiveContext* cx);
|
void initCompartment(js::ExclusiveContext* cx);
|
||||||
|
|
||||||
|
@ -1178,6 +1184,10 @@ class JSScript : public js::gc::TenuredCell
|
||||||
return sourceEnd_;
|
return sourceEnd_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t preludeStart() const {
|
||||||
|
return preludeStart_;
|
||||||
|
}
|
||||||
|
|
||||||
bool noScriptRval() const {
|
bool noScriptRval() const {
|
||||||
return noScriptRval_;
|
return noScriptRval_;
|
||||||
}
|
}
|
||||||
|
@ -1501,7 +1511,8 @@ class JSScript : public js::gc::TenuredCell
|
||||||
bool mayReadFrameArgsDirectly();
|
bool mayReadFrameArgsDirectly();
|
||||||
|
|
||||||
JSFlatString* sourceData(JSContext* cx);
|
JSFlatString* sourceData(JSContext* cx);
|
||||||
|
JSFlatString* sourceDataWithPrelude(JSContext* cx);
|
||||||
|
|
||||||
static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked);
|
static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked);
|
||||||
|
|
||||||
void setSourceObject(JSObject* object);
|
void setSourceObject(JSObject* object);
|
||||||
|
@ -1920,7 +1931,8 @@ class LazyScript : public gc::TenuredCell
|
||||||
// instead of private to suppress -Wunused-private-field compiler warnings.
|
// instead of private to suppress -Wunused-private-field compiler warnings.
|
||||||
protected:
|
protected:
|
||||||
#if JS_BITS_PER_WORD == 32
|
#if JS_BITS_PER_WORD == 32
|
||||||
uint32_t padding;
|
// uint32_t padding;
|
||||||
|
// Currently no padding is needed.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1960,20 +1972,25 @@ class LazyScript : public gc::TenuredCell
|
||||||
};
|
};
|
||||||
|
|
||||||
// Source location for the script.
|
// Source location for the script.
|
||||||
|
// See the comment in JSScript for the details.
|
||||||
uint32_t begin_;
|
uint32_t begin_;
|
||||||
uint32_t end_;
|
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 lineno_;
|
||||||
uint32_t column_;
|
uint32_t column_;
|
||||||
|
|
||||||
LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
|
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
|
// Create a LazyScript without initializing the closedOverBindings and the
|
||||||
// innerFunctions. To be GC-safe, the caller must initialize both vectors
|
// innerFunctions. To be GC-safe, the caller must initialize both vectors
|
||||||
// with valid atoms and functions.
|
// with valid atoms and functions.
|
||||||
static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun,
|
static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun,
|
||||||
uint64_t packedData, uint32_t begin, uint32_t end,
|
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:
|
public:
|
||||||
static const uint32_t NumClosedOverBindingsLimit = 1 << NumClosedOverBindingsBits;
|
static const uint32_t NumClosedOverBindingsLimit = 1 << NumClosedOverBindingsBits;
|
||||||
|
@ -1985,7 +2002,7 @@ class LazyScript : public gc::TenuredCell
|
||||||
const frontend::AtomVector& closedOverBindings,
|
const frontend::AtomVector& closedOverBindings,
|
||||||
Handle<GCVector<JSFunction*, 8>> innerFunctions,
|
Handle<GCVector<JSFunction*, 8>> innerFunctions,
|
||||||
JSVersion version, uint32_t begin, uint32_t end,
|
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
|
// Create a LazyScript and initialize the closedOverBindings and the
|
||||||
// innerFunctions with dummy values to be replaced in a later initialization
|
// innerFunctions with dummy values to be replaced in a later initialization
|
||||||
|
@ -2000,7 +2017,7 @@ class LazyScript : public gc::TenuredCell
|
||||||
HandleScript script, HandleScope enclosingScope,
|
HandleScript script, HandleScope enclosingScope,
|
||||||
HandleScript enclosingScript,
|
HandleScript enclosingScript,
|
||||||
uint64_t packedData, uint32_t begin, uint32_t end,
|
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);
|
void initRuntimeFields(uint64_t packedFields);
|
||||||
|
|
||||||
|
@ -2173,6 +2190,9 @@ class LazyScript : public gc::TenuredCell
|
||||||
uint32_t end() const {
|
uint32_t end() const {
|
||||||
return end_;
|
return end_;
|
||||||
}
|
}
|
||||||
|
uint32_t preludeStart() const {
|
||||||
|
return preludeStart_;
|
||||||
|
}
|
||||||
uint32_t lineno() const {
|
uint32_t lineno() const {
|
||||||
return lineno_;
|
return lineno_;
|
||||||
}
|
}
|
||||||
|
@ -2199,7 +2219,8 @@ class LazyScript : public gc::TenuredCell
|
||||||
};
|
};
|
||||||
|
|
||||||
/* If this fails, add/remove padding within LazyScript. */
|
/* 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
|
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
|
// Doesn't matter particularly what string gets serialized, as long
|
||||||
// as it contains "function*" and "yield 10".
|
// as it contains "function*" and "yield 10".
|
||||||
assertEq(GeneratorFunction('yield 10').toString(),
|
assertEq(GeneratorFunction('yield 10').toString(),
|
||||||
"function* anonymous() {\nyield 10\n}");
|
"function* anonymous(\n) {\nyield 10\n}");
|
||||||
}
|
}
|
||||||
TestGeneratorFunction();
|
TestGeneratorFunction();
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ with (x)
|
||||||
}
|
}
|
||||||
status = inSection(5);
|
status = inSection(5);
|
||||||
actual = x.g.toString();
|
actual = x.g.toString();
|
||||||
expect = (function () {}).toString();
|
expect = (function() {}).toString();
|
||||||
addThis();
|
addThis();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
var BUGNUMBER = 354945;
|
var BUGNUMBER = 354945;
|
||||||
var summary = 'Do not crash with new Iterator';
|
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;
|
var actual;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ function test()
|
||||||
printBugNumber(BUGNUMBER);
|
printBugNumber(BUGNUMBER);
|
||||||
printStatus (summary);
|
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 = {};
|
var obj = {};
|
||||||
obj.__iterator__ = function(){ };
|
obj.__iterator__ = function(){ };
|
||||||
try
|
try
|
||||||
|
|
|
@ -20,7 +20,7 @@ function test()
|
||||||
printBugNumber(BUGNUMBER);
|
printBugNumber(BUGNUMBER);
|
||||||
printStatus (summary);
|
printStatus (summary);
|
||||||
|
|
||||||
expect = /TypeError: anonymous generator function returns a value/;
|
expect = /TypeError: can't use 'yield' in a function that can return a value/;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var gen = eval('(function() { { return 5; } yield 3; })');
|
var gen = eval('(function() { { return 5; } yield 3; })');
|
||||||
|
|
|
@ -20,7 +20,7 @@ function test()
|
||||||
printBugNumber(BUGNUMBER);
|
printBugNumber(BUGNUMBER);
|
||||||
printStatus (summary);
|
printStatus (summary);
|
||||||
|
|
||||||
expect = "generator function foo returns a value";
|
expect = "can't use 'yield' in a function that can return a value";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
actual = 'No Error';
|
actual = 'No Error';
|
||||||
|
@ -32,7 +32,7 @@ function test()
|
||||||
}
|
}
|
||||||
reportCompare(expect, actual, summary + ": 1");
|
reportCompare(expect, actual, summary + ": 1");
|
||||||
|
|
||||||
expect = "generator function foo returns a value";
|
expect = "generator function can't return a value";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
actual = 'No Error';
|
actual = 'No Error';
|
||||||
|
@ -44,7 +44,7 @@ function test()
|
||||||
}
|
}
|
||||||
reportCompare(expect, actual, summary + ": 2");
|
reportCompare(expect, actual, summary + ": 2");
|
||||||
|
|
||||||
expect = "generator function foo returns a value";
|
expect = "can't use 'yield' in a function that can return a value";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
actual = 'No Error';
|
actual = 'No Error';
|
||||||
|
@ -56,7 +56,7 @@ function test()
|
||||||
}
|
}
|
||||||
reportCompare(expect, actual, summary + ": 3");
|
reportCompare(expect, actual, summary + ": 3");
|
||||||
|
|
||||||
expect = "generator function foo returns a value";
|
expect = "generator function can't return a value";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
actual = 'No Error';
|
actual = 'No Error';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
var actual;
|
var actual;
|
||||||
var expect = "function f() { ff (); }";
|
var expect = "function f () { ff (); }";
|
||||||
function fun() {
|
function fun() {
|
||||||
(new Function ("function ff () { actual = '' + ff. caller; } function f () { ff (); } f ();")) ();
|
(new Function ("function ff () { actual = '' + ff. caller; } function f () { ff (); } f ();")) ();
|
||||||
}
|
}
|
||||||
|
|
|
@ -318,6 +318,7 @@ struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod
|
||||||
// Function constructor, this will be the first character in the function
|
// Function constructor, this will be the first character in the function
|
||||||
// source. Otherwise, it will be the opening parenthesis of the arguments
|
// source. Otherwise, it will be the opening parenthesis of the arguments
|
||||||
// list.
|
// list.
|
||||||
|
uint32_t preludeStart;
|
||||||
uint32_t srcStart;
|
uint32_t srcStart;
|
||||||
uint32_t srcBodyStart;
|
uint32_t srcBodyStart;
|
||||||
bool strict;
|
bool strict;
|
||||||
|
@ -1758,6 +1759,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||||
if (!asmJSMetadata_)
|
if (!asmJSMetadata_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
asmJSMetadata_->preludeStart = moduleFunctionNode_->pn_funbox->preludeStart;
|
||||||
asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin;
|
asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin;
|
||||||
asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end;
|
asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end;
|
||||||
asmJSMetadata_->strict = parser_.pc->sc()->strict() &&
|
asmJSMetadata_->strict = parser_.pc->sc()->strict() &&
|
||||||
|
@ -7049,6 +7051,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
|
||||||
TokenStream& tokenStream = m.tokenStream();
|
TokenStream& tokenStream = m.tokenStream();
|
||||||
|
|
||||||
tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand);
|
tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand);
|
||||||
|
uint32_t preludeStart = tokenStream.currentToken().pos.begin;
|
||||||
*line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end);
|
*line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end);
|
||||||
|
|
||||||
TokenKind tk;
|
TokenKind tk;
|
||||||
|
@ -7061,7 +7064,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
|
||||||
if (!name)
|
if (!name)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ParseNode* fn = m.parser().handler.newFunctionDefinition();
|
ParseNode* fn = m.parser().handler.newFunctionStatement();
|
||||||
if (!fn)
|
if (!fn)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -7071,7 +7074,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
|
||||||
|
|
||||||
ParseContext* outerpc = m.parser().pc;
|
ParseContext* outerpc = m.parser().pc;
|
||||||
Directives directives(outerpc);
|
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);
|
SyncFunction, /* tryAnnexB = */ false);
|
||||||
if (!funbox)
|
if (!funbox)
|
||||||
return false;
|
return false;
|
||||||
|
@ -8054,7 +8057,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t begin = metadata.srcStart;
|
uint32_t begin = metadata.preludeStart;
|
||||||
uint32_t end = metadata.srcEndAfterCurly();
|
uint32_t end = metadata.srcEndAfterCurly();
|
||||||
Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end));
|
Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end));
|
||||||
if (!src)
|
if (!src)
|
||||||
|
@ -8085,7 +8088,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
|
||||||
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
|
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
|
||||||
? SourceBufferHolder::GiveOwnership
|
? SourceBufferHolder::GiveOwnership
|
||||||
: SourceBufferHolder::NoOwnership;
|
: SourceBufferHolder::NoOwnership;
|
||||||
SourceBufferHolder srcBuf(chars, stableChars.twoByteRange().length(), ownership);
|
SourceBufferHolder srcBuf(chars, end - begin, ownership);
|
||||||
if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing()))
|
if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -8537,6 +8540,7 @@ LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loaded
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// See AsmJSMetadata comment as well as ModuleValidator::init().
|
// 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->srcStart = parser.pc->functionBox()->functionNode->pn_body->pn_pos.begin;
|
||||||
asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end;
|
asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end;
|
||||||
asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict();
|
asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict();
|
||||||
|
@ -8834,7 +8838,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
|
||||||
MOZ_ASSERT(IsAsmJSModule(fun));
|
MOZ_ASSERT(IsAsmJSModule(fun));
|
||||||
|
|
||||||
const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS();
|
const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS();
|
||||||
uint32_t begin = metadata.srcStart;
|
uint32_t begin = metadata.preludeStart;
|
||||||
uint32_t end = metadata.srcEndAfterCurly();
|
uint32_t end = metadata.srcEndAfterCurly();
|
||||||
ScriptSource* source = metadata.scriptSource.get();
|
ScriptSource* source = metadata.scriptSource.get();
|
||||||
|
|
||||||
|
@ -8843,17 +8847,15 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
|
||||||
if (addParenToLambda && fun->isLambda() && !out.append("("))
|
if (addParenToLambda && fun->isLambda() && !out.append("("))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (!out.append("function "))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (fun->explicitName() && !out.append(fun->explicitName()))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
bool haveSource = source->hasSourceData();
|
bool haveSource = source->hasSourceData();
|
||||||
if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
|
if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (!haveSource) {
|
if (!haveSource) {
|
||||||
|
if (!out.append("function "))
|
||||||
|
return nullptr;
|
||||||
|
if (fun->explicitName() && !out.append(fun->explicitName()))
|
||||||
|
return nullptr;
|
||||||
if (!out.append("() {\n [sourceless code]\n}"))
|
if (!out.append("() {\n [sourceless code]\n}"))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -22,21 +22,21 @@
|
||||||
storage.b = 0;
|
storage.b = 0;
|
||||||
assert_equals(storage.b, "0");
|
assert_equals(storage.b, "0");
|
||||||
storage.c = function(){};
|
storage.c = function(){};
|
||||||
assert_equals(storage.c, "function (){}");
|
assert_equals(storage.c, "function(){}");
|
||||||
|
|
||||||
storage.setItem('d', null);
|
storage.setItem('d', null);
|
||||||
assert_equals(storage.d, "null");
|
assert_equals(storage.d, "null");
|
||||||
storage.setItem('e', 0);
|
storage.setItem('e', 0);
|
||||||
assert_equals(storage.e, "0");
|
assert_equals(storage.e, "0");
|
||||||
storage.setItem('f', function(){});
|
storage.setItem('f', function(){});
|
||||||
assert_equals(storage.f, "function (){}");
|
assert_equals(storage.f, "function(){}");
|
||||||
|
|
||||||
storage['g'] = null;
|
storage['g'] = null;
|
||||||
assert_equals(storage.g, "null");
|
assert_equals(storage.g, "null");
|
||||||
storage['h'] = 0;
|
storage['h'] = 0;
|
||||||
assert_equals(storage.h, "0");
|
assert_equals(storage.h, "0");
|
||||||
storage['i'] = function(){};
|
storage['i'] = function(){};
|
||||||
assert_equals(storage.f, "function (){}");
|
assert_equals(storage.f, "function(){}");
|
||||||
|
|
||||||
}, name + " only stores strings");
|
}, name + " only stores strings");
|
||||||
});
|
});
|
||||||
|
|
|
@ -1162,7 +1162,7 @@ add_test({
|
||||||
|
|
||||||
self.assertTestResult(False)
|
self.assertTestResult(False)
|
||||||
self.assertInLog(TEST_FAIL_STRING)
|
self.assertInLog(TEST_FAIL_STRING)
|
||||||
self.assertInLog("TypeError: generator function run_test returns a value at")
|
self.assertInLog("TypeError: generator function can't return a value at")
|
||||||
self.assertInLog("test_error.js:4")
|
self.assertInLog("test_error.js:4")
|
||||||
self.assertNotInLog(TEST_PASS_STRING)
|
self.assertNotInLog(TEST_PASS_STRING)
|
||||||
|
|
||||||
|
|
|
@ -381,12 +381,12 @@ add_task(function* log_message_with_params() {
|
||||||
ob = function() {};
|
ob = function() {};
|
||||||
ob.toJSON = function() {throw "oh noes JSON"};
|
ob.toJSON = function() {throw "oh noes JSON"};
|
||||||
do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}),
|
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.
|
// Fall back to .toString if both .toJSON and .toSource fail.
|
||||||
ob.toSource = function() {throw "oh noes SOURCE"};
|
ob.toSource = function() {throw "oh noes SOURCE"};
|
||||||
do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}),
|
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.
|
// Fall back to '[object]' if .toJSON, .toSource and .toString fail.
|
||||||
ob.toString = function() {throw "oh noes STRING"};
|
ob.toString = function() {throw "oh noes STRING"};
|
||||||
|
@ -450,7 +450,7 @@ add_task(function* log_message_with_params() {
|
||||||
// doesn't cause the logger to fail.
|
// doesn't cause the logger to fail.
|
||||||
let vOf = {a: 1, valueOf: function() {throw "oh noes valueOf"}};
|
let vOf = {a: 1, valueOf: function() {throw "oh noes valueOf"}};
|
||||||
do_check_eq(formatMessage("Broken valueOf ${}", vOf),
|
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"})})');
|
||||||
|
|
||||||
// Test edge cases of bad data to formatter:
|
// Test edge cases of bad data to formatter:
|
||||||
// If 'params' is not an object, format it as a basic type.
|
// If 'params' is not an object, format it as a basic type.
|
||||||
|
|
Loading…
Reference in New Issue