зеркало из https://github.com/mozilla/pjs.git
Merge tracemonkey to mozilla-central. a=blockers
--HG-- rename : js/src/trace-test/tests/basic/bug616762.js => js/src/jit-test/tests/basic/bug616762.js
This commit is contained in:
Коммит
ecc4cfb7c4
|
@ -1911,13 +1911,13 @@ case "$host" in
|
||||||
esac
|
esac
|
||||||
|
|
||||||
dnl We require version 2.5 or newer of Python to build.
|
dnl We require version 2.5 or newer of Python to build.
|
||||||
AC_MSG_CHECKING([for minimum required Python version >= $PYTHON_VERSION])
|
AC_MSG_CHECKING([for Python version >= $PYTHON_VERSION but not 3.x])
|
||||||
changequote(,)
|
changequote(,)
|
||||||
$PYTHON -c "import sys; sys.exit(sys.version[:3] < sys.argv[1])" $PYTHON_VERSION
|
$PYTHON -c "import sys; sys.exit(sys.version[:3] < sys.argv[1] or sys.version[:2] != '2.')" $PYTHON_VERSION
|
||||||
_python_res=$?
|
_python_res=$?
|
||||||
changequote([,])
|
changequote([,])
|
||||||
if test "$_python_res" != 0; then
|
if test "$_python_res" != 0; then
|
||||||
AC_MSG_ERROR([Python $PYTHON_VERSION or higher is required.])
|
AC_MSG_ERROR([Python $PYTHON_VERSION or higher (but not Python 3.x) is required.])
|
||||||
fi
|
fi
|
||||||
AC_MSG_RESULT([yes])
|
AC_MSG_RESULT([yes])
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,6 @@ nsDOMWorkerFunctions::MakeTimeout(JSContext* aCx,
|
||||||
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
||||||
|
|
||||||
if (worker->IsCanceled()) {
|
if (worker->IsCanceled()) {
|
||||||
JS_ReportError(aCx, "Worker is canceled");
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +207,6 @@ nsDOMWorkerFunctions::KillTimeout(JSContext* aCx,
|
||||||
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
||||||
|
|
||||||
if (worker->IsCanceled()) {
|
if (worker->IsCanceled()) {
|
||||||
JS_ReportError(aCx, "Worker is canceled");
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +235,6 @@ nsDOMWorkerFunctions::LoadScripts(JSContext* aCx,
|
||||||
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
||||||
|
|
||||||
if (worker->IsCanceled()) {
|
if (worker->IsCanceled()) {
|
||||||
JS_ReportError(aCx, "Worker is canceled");
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +310,6 @@ nsDOMWorkerFunctions::NewXMLHttpRequest(JSContext* aCx,
|
||||||
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
||||||
|
|
||||||
if (worker->IsCanceled()) {
|
if (worker->IsCanceled()) {
|
||||||
JS_ReportError(aCx, "Worker is canceled");
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +359,6 @@ nsDOMWorkerFunctions::AtoB(JSContext* aCx,
|
||||||
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
||||||
|
|
||||||
if (worker->IsCanceled()) {
|
if (worker->IsCanceled()) {
|
||||||
JS_ReportError(aCx, "Worker is canceled");
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,39 +367,8 @@ nsDOMWorkerFunctions::AtoB(JSContext* aCx,
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSString* str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0]);
|
return nsXPConnect::Base64Decode(aCx, JS_ARGV(aCx, aVp)[0],
|
||||||
if (!str) {
|
&JS_RVAL(aCx, aVp));
|
||||||
NS_ASSERTION(JS_IsExceptionPending(aCx), "Need to set an exception!");
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len = JS_GetStringEncodingLength(aCx, str);
|
|
||||||
if (len == size_t(-1))
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
JSUint32 alloc_len = (len + 1) * sizeof(char);
|
|
||||||
char *buffer = static_cast<char *>(nsMemory::Alloc(alloc_len));
|
|
||||||
if (!buffer)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
JS_EncodeStringToBuffer(str, buffer, len);
|
|
||||||
buffer[len] = '\0';
|
|
||||||
|
|
||||||
nsDependentCString string(buffer, len);
|
|
||||||
nsCAutoString result;
|
|
||||||
|
|
||||||
if (NS_FAILED(nsXPConnect::Base64Decode(string, result))) {
|
|
||||||
JS_ReportError(aCx, "Failed to decode base64 string!");
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
str = JS_NewStringCopyN(aCx, result.get(), result.Length());
|
|
||||||
if (!str) {
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(str));
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
|
@ -416,7 +380,6 @@ nsDOMWorkerFunctions::BtoA(JSContext* aCx,
|
||||||
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
||||||
|
|
||||||
if (worker->IsCanceled()) {
|
if (worker->IsCanceled()) {
|
||||||
JS_ReportError(aCx, "Worker is canceled");
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,39 +388,8 @@ nsDOMWorkerFunctions::BtoA(JSContext* aCx,
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSString* str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0]);
|
return nsXPConnect::Base64Encode(aCx, JS_ARGV(aCx, aVp)[0],
|
||||||
if (!str) {
|
&JS_RVAL(aCx, aVp));
|
||||||
NS_ASSERTION(JS_IsExceptionPending(aCx), "Need to set an exception!");
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len = JS_GetStringEncodingLength(aCx, str);
|
|
||||||
if (len == size_t(-1))
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
JSUint32 alloc_len = (len + 1) * sizeof(char);
|
|
||||||
char *buffer = static_cast<char *>(nsMemory::Alloc(alloc_len));
|
|
||||||
if (!buffer)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
JS_EncodeStringToBuffer(str, buffer, len);
|
|
||||||
buffer[len] = '\0';
|
|
||||||
|
|
||||||
nsDependentCString string(buffer, len);
|
|
||||||
nsCAutoString result;
|
|
||||||
|
|
||||||
if (NS_FAILED(nsXPConnect::Base64Encode(string, result))) {
|
|
||||||
JS_ReportError(aCx, "Failed to encode base64 data!");
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
str = JS_NewStringCopyN(aCx, result.get(), result.Length());
|
|
||||||
if (!str) {
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(str));
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
|
@ -491,7 +423,6 @@ nsDOMWorkerFunctions::MakeNewWorker(JSContext* aCx,
|
||||||
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
||||||
|
|
||||||
if (worker->IsCanceled()) {
|
if (worker->IsCanceled()) {
|
||||||
JS_ReportError(aCx, "Worker is canceled");
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,7 +516,6 @@ nsDOMWorkerFunctions::CTypesLazyGetter(JSContext* aCx,
|
||||||
NS_ASSERTION(worker->IsPrivileged(), "This shouldn't be possible!");
|
NS_ASSERTION(worker->IsPrivileged(), "This shouldn't be possible!");
|
||||||
|
|
||||||
if (worker->IsCanceled()) {
|
if (worker->IsCanceled()) {
|
||||||
JS_ReportError(aCx, "Worker is canceled");
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
var data = [ -1, 0, 1, 1.5, undefined, true, false ];
|
var data = [ -1, 0, 1, 1.5, null, undefined, true, false, "foo",
|
||||||
|
"123456789012345", "1234567890123456", "12345678901234567"];
|
||||||
// XXXbent window.atob treats |null| as the empty string, whereas worker.atob
|
|
||||||
// and the js component loader treat it as the string 'null'. Meh.
|
|
||||||
|
|
||||||
var str = "";
|
var str = "";
|
||||||
for (var i = 0; i < 30; i++) {
|
for (var i = 0; i < 30; i++) {
|
||||||
|
|
|
@ -1168,6 +1168,19 @@ private:
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
#elif WTF_COMPILER_SUNPRO
|
#elif WTF_COMPILER_SUNPRO
|
||||||
|
#if WTF_CPU_X86_64
|
||||||
|
asm (
|
||||||
|
"movl $0x1, %%eax;"
|
||||||
|
"pushq %%rbx;"
|
||||||
|
"cpuid;"
|
||||||
|
"popq %%rbx;"
|
||||||
|
"movl %%ecx, (%rsi);"
|
||||||
|
"movl %%edx, (%rdi);"
|
||||||
|
:
|
||||||
|
: "S" (&flags_ecx), "D" (&flags_edx)
|
||||||
|
: "%eax", "%ecx", "%edx"
|
||||||
|
);
|
||||||
|
#else
|
||||||
asm (
|
asm (
|
||||||
"movl $0x1, %eax;"
|
"movl $0x1, %eax;"
|
||||||
"pushl %ebx;"
|
"pushl %ebx;"
|
||||||
|
@ -1179,6 +1192,7 @@ private:
|
||||||
: "S" (&flags_ecx), "D" (&flags_edx)
|
: "S" (&flags_ecx), "D" (&flags_edx)
|
||||||
: "%eax", "%ecx", "%edx"
|
: "%eax", "%ecx", "%edx"
|
||||||
);
|
);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
static const int SSEFeatureBit = 1 << 25;
|
static const int SSEFeatureBit = 1 << 25;
|
||||||
static const int SSE2FeatureBit = 1 << 26;
|
static const int SSE2FeatureBit = 1 << 26;
|
||||||
|
|
|
@ -986,7 +986,7 @@ else
|
||||||
AC_MSG_RESULT([yes])
|
AC_MSG_RESULT([yes])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
MOZ_PATH_PROGS(PYTHON, $PYTHON python2.6 python2.5 python2.4 python)
|
MOZ_PATH_PROGS(PYTHON, $PYTHON python2.7 python2.6 python2.5 python)
|
||||||
if test -z "$PYTHON"; then
|
if test -z "$PYTHON"; then
|
||||||
AC_MSG_ERROR([python was not found in \$PATH])
|
AC_MSG_ERROR([python was not found in \$PATH])
|
||||||
fi
|
fi
|
||||||
|
@ -1900,13 +1900,13 @@ esac
|
||||||
|
|
||||||
dnl We require version 2.4 or newer of Python to build,
|
dnl We require version 2.4 or newer of Python to build,
|
||||||
dnl and 2.5 or newer on Windows.
|
dnl and 2.5 or newer on Windows.
|
||||||
AC_MSG_CHECKING([for minimum required Python version >= $PYTHON_VERSION])
|
AC_MSG_CHECKING([for Python version >= $PYTHON_VERSION but not 3.x])
|
||||||
changequote(,)
|
changequote(,)
|
||||||
$PYTHON -c "import sys; sys.exit(sys.version[:3] < sys.argv[1])" $PYTHON_VERSION
|
$PYTHON -c "import sys; sys.exit(sys.version[:3] < sys.argv[1] or sys.version[:2] != '2.')" $PYTHON_VERSION
|
||||||
_python_res=$?
|
_python_res=$?
|
||||||
changequote([,])
|
changequote([,])
|
||||||
if test "$_python_res" != 0; then
|
if test "$_python_res" != 0; then
|
||||||
AC_MSG_ERROR([Python $PYTHON_VERSION or higher is required.])
|
AC_MSG_ERROR([Python $PYTHON_VERSION or higher (but not Python 3.x) is required.])
|
||||||
fi
|
fi
|
||||||
AC_MSG_RESULT([yes])
|
AC_MSG_RESULT([yes])
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
function s(f) { this._m = f; }
|
||||||
|
function C() {
|
||||||
|
Object.defineProperty(this, "m", {set: s});
|
||||||
|
this.m = function () {};
|
||||||
|
}
|
||||||
|
var last = {};
|
||||||
|
for (var i = 0; i < 20; i++) {
|
||||||
|
var a = new C;
|
||||||
|
assertEq(a._m === last._m, false);
|
||||||
|
last = a;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
for(var i = 0; i < RUNLOOP; i++) {
|
||||||
|
x = ''.charCodeAt(NaN);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var i = 0; i < RUNLOOP; i++) {
|
||||||
|
x = ''.charAt(NaN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't assert
|
|
@ -0,0 +1,5 @@
|
||||||
|
for (var i = 0; i < RUNLOOP; i++) {
|
||||||
|
Math.abs(-2147483648)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't assert
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
function a() {}
|
||||||
|
}
|
||||||
|
Math.floor(Math.d)
|
||||||
|
function c() {}
|
||||||
|
c()
|
||||||
|
for each(let b in [0, 0, 0, 0, 0, 0, 0, -2147483648]) {
|
||||||
|
print(Math.abs(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't assert
|
|
@ -0,0 +1,5 @@
|
||||||
|
var x = Uint32Array();
|
||||||
|
for (var i = 0; i < 100; i++)
|
||||||
|
x[77] = x[77];
|
||||||
|
|
||||||
|
// Don't assert.
|
|
@ -0,0 +1,10 @@
|
||||||
|
/* Bug 614653 - This test .2 seconds with the fix, 20 minutes without. */
|
||||||
|
for (var i = 0; i < 100; ++i) {
|
||||||
|
var arr = [];
|
||||||
|
var s = "abcdefghijklmnop";
|
||||||
|
for (var i = 0; i < 50000; ++i) {
|
||||||
|
s = "<" + s + ">";
|
||||||
|
arr.push(s);
|
||||||
|
}
|
||||||
|
gc();
|
||||||
|
}
|
|
@ -95,36 +95,3 @@ BEGIN_TEST(testXDR_bug516827)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
END_TEST(testXDR_bug516827)
|
END_TEST(testXDR_bug516827)
|
||||||
|
|
||||||
BEGIN_TEST(testXDR_bug525481)
|
|
||||||
{
|
|
||||||
// get the empty script const singleton
|
|
||||||
JSScript *script = JSScript::emptyScript();
|
|
||||||
CHECK(script);
|
|
||||||
|
|
||||||
// freeze with junk after the empty script shorthand
|
|
||||||
JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE);
|
|
||||||
CHECK(w);
|
|
||||||
CHECK(JS_XDRScript(w, &script));
|
|
||||||
const char s[] = "don't decode me; don't encode me";
|
|
||||||
char b[sizeof s - 1];
|
|
||||||
memcpy(b, s, sizeof b);
|
|
||||||
CHECK(JS_XDRBytes(w, b, sizeof b));
|
|
||||||
uint32 nbytes;
|
|
||||||
void *p = JS_XDRMemGetData(w, &nbytes);
|
|
||||||
CHECK(p);
|
|
||||||
void *frozen = JS_malloc(cx, nbytes);
|
|
||||||
CHECK(frozen);
|
|
||||||
memcpy(frozen, p, nbytes);
|
|
||||||
JS_XDRDestroy(w);
|
|
||||||
|
|
||||||
// thaw, reading junk if bug 525481 is not patched
|
|
||||||
script = NULL;
|
|
||||||
JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE);
|
|
||||||
JS_XDRMemSetData(r, frozen, nbytes);
|
|
||||||
CHECK(JS_XDRScript(r, &script));
|
|
||||||
JS_DestroyScript(cx, script);
|
|
||||||
JS_XDRDestroy(r); // this frees `frozen`
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
END_TEST(testXDR_bug525481)
|
|
||||||
|
|
|
@ -4023,7 +4023,7 @@ JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
/* NB: jsuint cast does ToUint32. */
|
/* NB: jsuint cast does ToUint32. */
|
||||||
assertSameCompartment(cx, JSValueArray(vector, vector ? (jsuint)length : 0));
|
assertSameCompartment(cx, JSValueArray(vector, vector ? (jsuint)length : 0));
|
||||||
return js_NewArrayObject(cx, (jsuint)length, Valueify(vector));
|
return NewDenseCopiedArray(cx, (jsuint)length, Valueify(vector));
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
|
@ -4672,7 +4672,6 @@ JS_NewScriptObject(JSContext *cx, JSScript *script)
|
||||||
* described in the comment for JSScript::u.object.
|
* described in the comment for JSScript::u.object.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(script->u.object);
|
JS_ASSERT(script->u.object);
|
||||||
JS_ASSERT(script != JSScript::emptyScript());
|
|
||||||
return script->u.object;
|
return script->u.object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4889,7 +4888,7 @@ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
assertSameCompartment(cx, obj, script);
|
assertSameCompartment(cx, obj, script);
|
||||||
/* This should receive only scripts handed out via the JSAPI. */
|
/* This should receive only scripts handed out via the JSAPI. */
|
||||||
JS_ASSERT(script == JSScript::emptyScript() || script->u.object);
|
JS_ASSERT(script->u.object);
|
||||||
ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
|
ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
|
||||||
LAST_FRAME_CHECKS(cx, ok);
|
LAST_FRAME_CHECKS(cx, ok);
|
||||||
return ok;
|
return ok;
|
||||||
|
@ -5166,32 +5165,6 @@ JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
JS_PUBLIC_API(JSString *)
|
|
||||||
JS_NewString(JSContext *cx, char *bytes, size_t nbytes)
|
|
||||||
{
|
|
||||||
size_t length = nbytes;
|
|
||||||
jschar *chars;
|
|
||||||
JSString *str;
|
|
||||||
|
|
||||||
CHECK_REQUEST(cx);
|
|
||||||
|
|
||||||
/* Make a UTF-16 vector from the 8-bit char codes in bytes. */
|
|
||||||
chars = js_InflateString(cx, bytes, &length);
|
|
||||||
if (!chars)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Free chars (but not bytes, which caller frees on error) if we fail. */
|
|
||||||
str = js_NewString(cx, chars, length);
|
|
||||||
if (!str) {
|
|
||||||
cx->free(chars);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
js_free(bytes);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_PUBLIC_API(JSString *)
|
JS_PUBLIC_API(JSString *)
|
||||||
JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
|
JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
|
||||||
{
|
{
|
||||||
|
|
172
js/src/jsapi.h
172
js/src/jsapi.h
|
@ -1335,63 +1335,23 @@ namespace js {
|
||||||
* than that, we have avoided all garbage collection hazards.
|
* than that, we have avoided all garbage collection hazards.
|
||||||
*/
|
*/
|
||||||
template<typename T> class AnchorPermitted;
|
template<typename T> class AnchorPermitted;
|
||||||
|
template<> class AnchorPermitted<JSObject *> { };
|
||||||
|
template<> class AnchorPermitted<const JSObject *> { };
|
||||||
|
template<> class AnchorPermitted<JSFunction *> { };
|
||||||
|
template<> class AnchorPermitted<const JSFunction *> { };
|
||||||
|
template<> class AnchorPermitted<JSString *> { };
|
||||||
|
template<> class AnchorPermitted<const JSString *> { };
|
||||||
|
template<> class AnchorPermitted<jsval> { };
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class Anchor: AnchorPermitted<T> {
|
class Anchor: AnchorPermitted<T> {
|
||||||
public:
|
public:
|
||||||
Anchor() { }
|
Anchor() { }
|
||||||
explicit Anchor(T t) { hold = t; }
|
explicit Anchor(T t) { hold = t; }
|
||||||
~Anchor() {
|
inline ~Anchor();
|
||||||
#ifdef __GNUC__
|
T &get() { return hold; }
|
||||||
/*
|
void set(const T &t) { hold = t; }
|
||||||
* No code is generated for this. But because this is marked 'volatile', G++ will
|
void clear() { hold = 0; }
|
||||||
* assume it has important side-effects, and won't delete it. (G++ never looks at
|
|
||||||
* the actual text and notices it's empty.) And because we have passed |hold| to
|
|
||||||
* it, GCC will keep |hold| alive until this point.
|
|
||||||
*
|
|
||||||
* The "memory" clobber operand ensures that G++ will not move prior memory
|
|
||||||
* accesses after the asm --- it's a barrier. Unfortunately, it also means that
|
|
||||||
* G++ will assume that all memory has changed after the asm, as it would for a
|
|
||||||
* call to an unknown function. I don't know of a way to avoid that consequence.
|
|
||||||
*/
|
|
||||||
asm volatile("":: "g" (hold) : "memory");
|
|
||||||
#else
|
|
||||||
/*
|
|
||||||
* An adequate portable substitute.
|
|
||||||
*
|
|
||||||
* The compiler promises that, by the end of an expression statement, the
|
|
||||||
* last-stored value to a volatile object is the same as it would be in an
|
|
||||||
* unoptimized, direct implementation (the "abstract machine" whose behavior the
|
|
||||||
* language spec describes). However, the compiler is still free to reorder
|
|
||||||
* non-volatile accesses across this store --- which is what we must prevent. So
|
|
||||||
* assigning the held value to a volatile variable, as we do here, is not enough.
|
|
||||||
*
|
|
||||||
* In our case, however, garbage collection only occurs at function calls, so it
|
|
||||||
* is sufficient to ensure that the destructor's store isn't moved earlier across
|
|
||||||
* any function calls that could collect. It is hard to imagine the compiler
|
|
||||||
* analyzing the program so thoroughly that it could prove that such motion was
|
|
||||||
* safe. In practice, compilers treat calls to the collector as opaque operations
|
|
||||||
* --- in particular, as operations which could access volatile variables, across
|
|
||||||
* which this destructor must not be moved.
|
|
||||||
*
|
|
||||||
* ("Objection, your honor! *Alleged* killer whale!")
|
|
||||||
*
|
|
||||||
* The disadvantage of this approach is that it does generate code for the store.
|
|
||||||
* We do need to use Anchors in some cases where cycles are tight.
|
|
||||||
*/
|
|
||||||
volatile T sink;
|
|
||||||
#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
|
|
||||||
/*
|
|
||||||
* Can't just do a simple assignment here.
|
|
||||||
*/
|
|
||||||
doAssignment(sink, hold);
|
|
||||||
#else
|
|
||||||
sink = hold;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
T &get() { return hold; }
|
|
||||||
void set(T t) { hold = t; }
|
|
||||||
void clear() { hold = 0; }
|
|
||||||
private:
|
private:
|
||||||
T hold;
|
T hold;
|
||||||
/* Anchors should not be assigned or passed to functions. */
|
/* Anchors should not be assigned or passed to functions. */
|
||||||
|
@ -1399,44 +1359,71 @@ class Anchor: AnchorPermitted<T> {
|
||||||
const Anchor &operator=(const Anchor &);
|
const Anchor &operator=(const Anchor &);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
template<typename T>
|
||||||
|
inline Anchor<T>::~Anchor() {
|
||||||
|
/*
|
||||||
|
* No code is generated for this. But because this is marked 'volatile', G++ will
|
||||||
|
* assume it has important side-effects, and won't delete it. (G++ never looks at
|
||||||
|
* the actual text and notices it's empty.) And because we have passed |hold| to
|
||||||
|
* it, GCC will keep |hold| alive until this point.
|
||||||
|
*
|
||||||
|
* The "memory" clobber operand ensures that G++ will not move prior memory
|
||||||
|
* accesses after the asm --- it's a barrier. Unfortunately, it also means that
|
||||||
|
* G++ will assume that all memory has changed after the asm, as it would for a
|
||||||
|
* call to an unknown function. I don't know of a way to avoid that consequence.
|
||||||
|
*/
|
||||||
|
asm volatile("":: "g" (hold) : "memory");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template<typename T>
|
||||||
|
inline Anchor<T>::~Anchor() {
|
||||||
|
/*
|
||||||
|
* An adequate portable substitute, for non-structure types.
|
||||||
|
*
|
||||||
|
* The compiler promises that, by the end of an expression statement, the
|
||||||
|
* last-stored value to a volatile object is the same as it would be in an
|
||||||
|
* unoptimized, direct implementation (the "abstract machine" whose behavior the
|
||||||
|
* language spec describes). However, the compiler is still free to reorder
|
||||||
|
* non-volatile accesses across this store --- which is what we must prevent. So
|
||||||
|
* assigning the held value to a volatile variable, as we do here, is not enough.
|
||||||
|
*
|
||||||
|
* In our case, however, garbage collection only occurs at function calls, so it
|
||||||
|
* is sufficient to ensure that the destructor's store isn't moved earlier across
|
||||||
|
* any function calls that could collect. It is hard to imagine the compiler
|
||||||
|
* analyzing the program so thoroughly that it could prove that such motion was
|
||||||
|
* safe. In practice, compilers treat calls to the collector as opaque operations
|
||||||
|
* --- in particular, as operations which could access volatile variables, across
|
||||||
|
* which this destructor must not be moved.
|
||||||
|
*
|
||||||
|
* ("Objection, your honor! *Alleged* killer whale!")
|
||||||
|
*
|
||||||
|
* The disadvantage of this approach is that it does generate code for the store.
|
||||||
|
* We do need to use Anchors in some cases where cycles are tight.
|
||||||
|
*/
|
||||||
|
volatile T sink;
|
||||||
|
sink = hold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
|
||||||
/*
|
/*
|
||||||
* Ensure that attempts to create Anchors for types the garbage collector's conservative
|
* The default assignment operator for |struct C| has the signature:
|
||||||
* scanner doesn't actually recgonize fail. Such anchors would have no effect.
|
*
|
||||||
|
* C& C::operator=(const C&)
|
||||||
|
*
|
||||||
|
* And in particular requires implicit conversion of |this| to type |C| for the return
|
||||||
|
* value. But |volatile C| cannot thus be converted to |C|, so just doing |sink = hold| as
|
||||||
|
* in the non-specialized version would fail to compile. Do the assignment on asBits
|
||||||
|
* instead, since I don't think we want to give jsval_layout an assignment operator
|
||||||
|
* returning |volatile jsval_layout|.
|
||||||
*/
|
*/
|
||||||
class Anchor_base {
|
template<>
|
||||||
protected:
|
inline Anchor<jsval>::~Anchor() {
|
||||||
#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
|
volatile jsval sink;
|
||||||
template<typename T> void doAssignment(volatile T &lhs, const T &rhs) {
|
sink.asBits = hold.asBits;
|
||||||
lhs = rhs;
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
};
|
|
||||||
template<> class AnchorPermitted<JSObject *> : protected Anchor_base { };
|
|
||||||
template<> class AnchorPermitted<const JSObject *> : protected Anchor_base { };
|
|
||||||
template<> class AnchorPermitted<JSFunction *> : protected Anchor_base { };
|
|
||||||
template<> class AnchorPermitted<const JSFunction *> : protected Anchor_base { };
|
|
||||||
template<> class AnchorPermitted<JSString *> : protected Anchor_base { };
|
|
||||||
template<> class AnchorPermitted<const JSString *> : protected Anchor_base { };
|
|
||||||
template<> class AnchorPermitted<jsval> : protected Anchor_base {
|
|
||||||
protected:
|
|
||||||
#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
|
|
||||||
void doAssignment(volatile jsval &lhs, const jsval &rhs) {
|
|
||||||
/*
|
|
||||||
* The default assignment operator for |struct C| has the signature:
|
|
||||||
*
|
|
||||||
* C& C::operator=(const C&)
|
|
||||||
*
|
|
||||||
* And in particular requires implicit conversion of |this| to
|
|
||||||
* type |C| for the return value. But |volatile C| cannot
|
|
||||||
* thus be converted to |C|, so just doing |sink = hold| here
|
|
||||||
* would fail to compile. Do the assignment on asBits
|
|
||||||
* instead, since I don't think we want to give jsval_layout
|
|
||||||
* an assignment operator returning |volatile jsval_layout|.
|
|
||||||
*/
|
|
||||||
lhs.asBits = rhs.asBits;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
};
|
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
|
@ -2932,15 +2919,12 @@ JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp);
|
||||||
/*
|
/*
|
||||||
* Strings.
|
* Strings.
|
||||||
*
|
*
|
||||||
* NB: JS_NewString takes ownership of bytes on success, avoiding a copy; but
|
* NB: JS_NewUCString takes ownership of bytes on success, avoiding a copy;
|
||||||
* on error (signified by null return), it leaves bytes owned by the caller.
|
* but on error (signified by null return), it leaves chars owned by the
|
||||||
* So the caller must free bytes in the error case, if it has no use for them.
|
* caller. So the caller must free bytes in the error case, if it has no use
|
||||||
* In contrast, all the JS_New*StringCopy* functions do not take ownership of
|
* for them. In contrast, all the JS_New*StringCopy* functions do not take
|
||||||
* the character memory passed to them -- they copy it.
|
* ownership of the character memory passed to them -- they copy it.
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API(JSString *)
|
|
||||||
JS_NewString(JSContext *cx, char *bytes, size_t length);
|
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSString *)
|
extern JS_PUBLIC_API(JSString *)
|
||||||
JS_NewStringCopyN(JSContext *cx, const char *s, size_t n);
|
JS_NewStringCopyN(JSContext *cx, const char *s, size_t n);
|
||||||
|
|
||||||
|
|
|
@ -52,13 +52,15 @@
|
||||||
* - The number of element slots (capacity), gettable with
|
* - The number of element slots (capacity), gettable with
|
||||||
* getDenseArrayCapacity().
|
* getDenseArrayCapacity().
|
||||||
*
|
*
|
||||||
* In dense mode, holes in the array are represented by (JS_ARRAY_HOLE) invalid
|
* In dense mode, holes in the array are represented by
|
||||||
* values. The final slot in fslots is unused.
|
* MagicValue(JS_ARRAY_HOLE) invalid values.
|
||||||
*
|
*
|
||||||
* NB: the capacity and length of a dense array are entirely unrelated! The
|
* NB: the capacity and length of a dense array are entirely unrelated! The
|
||||||
* length may be greater than, less than, or equal to the capacity. See
|
* length may be greater than, less than, or equal to the capacity. The first
|
||||||
* array_length_setter for an explanation of how the first, most surprising
|
* case may occur when the user writes "new Array(100), in which case the
|
||||||
* case may occur.
|
* length is 100 while the capacity remains 0 (indices below length and above
|
||||||
|
* capaicty must be treated as holes). See array_length_setter for another
|
||||||
|
* explanation of how the first case may occur.
|
||||||
*
|
*
|
||||||
* Arrays are converted to use js_SlowArrayClass when any of these conditions
|
* Arrays are converted to use js_SlowArrayClass when any of these conditions
|
||||||
* are met:
|
* are met:
|
||||||
|
@ -170,14 +172,16 @@ js_StringIsIndex(JSString *str, jsuint *indexp)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static jsuint
|
static bool
|
||||||
ValueIsLength(JSContext *cx, Value* vp)
|
ValueToLength(JSContext *cx, Value* vp, jsuint* plength)
|
||||||
{
|
{
|
||||||
if (vp->isInt32()) {
|
if (vp->isInt32()) {
|
||||||
int32_t i = vp->toInt32();
|
int32_t i = vp->toInt32();
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
goto error;
|
goto error;
|
||||||
return (jsuint) i;
|
|
||||||
|
*plength = (jsuint)(i);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
jsdouble d;
|
jsdouble d;
|
||||||
|
@ -186,18 +190,20 @@ ValueIsLength(JSContext *cx, Value* vp)
|
||||||
|
|
||||||
if (JSDOUBLE_IS_NaN(d))
|
if (JSDOUBLE_IS_NaN(d))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
jsuint length;
|
jsuint length;
|
||||||
length = (jsuint) d;
|
length = (jsuint) d;
|
||||||
if (d != (jsdouble) length)
|
if (d != (jsdouble) length)
|
||||||
goto error;
|
goto error;
|
||||||
vp->setNumber(length);
|
|
||||||
return length;
|
|
||||||
|
|
||||||
error:
|
|
||||||
|
*plength = length;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
JSMSG_BAD_ARRAY_LENGTH);
|
JSMSG_BAD_ARRAY_LENGTH);
|
||||||
vp->setNull();
|
return false;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
|
@ -557,8 +563,10 @@ js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
|
||||||
if (!ok)
|
if (!ok)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*lengthp = ValueIsLength(cx, tvr.addr());
|
if (!ValueToLength(cx, tvr.addr(), lengthp))
|
||||||
return !tvr.value().isNull();
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -581,27 +589,20 @@ array_length_getter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
{
|
{
|
||||||
jsuint newlen, oldlen, gap, index;
|
jsuint newlen, oldlen, gap, index;
|
||||||
Value junk;
|
Value junk;
|
||||||
|
|
||||||
/* Check for a sealed object first. */
|
|
||||||
if (!obj->isExtensible()) {
|
|
||||||
return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_READ_ONLY,
|
|
||||||
JSDVG_IGNORE_STACK, IdToValue(id), NULL,
|
|
||||||
NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!obj->isArray()) {
|
if (!obj->isArray()) {
|
||||||
jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||||
|
|
||||||
return obj->defineProperty(cx, lengthId, *vp, NULL, NULL, JSPROP_ENUMERATE);
|
return obj->defineProperty(cx, lengthId, *vp, NULL, NULL, JSPROP_ENUMERATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
newlen = ValueIsLength(cx, vp);
|
if (!ValueToLength(cx, vp, &newlen))
|
||||||
if (vp->isNull())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
oldlen = obj->getArrayLength();
|
oldlen = obj->getArrayLength();
|
||||||
|
|
||||||
if (oldlen == newlen)
|
if (oldlen == newlen)
|
||||||
|
@ -633,8 +634,6 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool str
|
||||||
}
|
}
|
||||||
if (!DeleteArrayElement(cx, obj, oldlen, true)) {
|
if (!DeleteArrayElement(cx, obj, oldlen, true)) {
|
||||||
obj->setArrayLength(oldlen + 1);
|
obj->setArrayLength(oldlen + 1);
|
||||||
if (strict)
|
|
||||||
return false;
|
|
||||||
JS_ClearPendingException(cx);
|
JS_ClearPendingException(cx);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -798,7 +797,7 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool stric
|
||||||
uint32 i;
|
uint32 i;
|
||||||
|
|
||||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
||||||
return array_length_setter(cx, obj, id, vp, strict);
|
return array_length_setter(cx, obj, id, vp);
|
||||||
|
|
||||||
if (!obj->isDenseArray())
|
if (!obj->isDenseArray())
|
||||||
return js_SetProperty(cx, obj, id, vp, strict);
|
return js_SetProperty(cx, obj, id, vp, strict);
|
||||||
|
@ -828,17 +827,6 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool stric
|
||||||
return js_SetProperty(cx, obj, id, vp, strict);
|
return js_SetProperty(cx, obj, id, vp, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSBool
|
|
||||||
slowarray_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
|
||||||
{
|
|
||||||
JS_ASSERT(obj->isSlowArray());
|
|
||||||
|
|
||||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
|
||||||
return array_length_setter(cx, obj, id, vp, strict);
|
|
||||||
|
|
||||||
return js_SetProperty(cx, obj, id, vp, strict);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
|
js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
|
||||||
{
|
{
|
||||||
|
@ -996,34 +984,7 @@ Class js_SlowArrayClass = {
|
||||||
PropertyStub, /* setProperty */
|
PropertyStub, /* setProperty */
|
||||||
EnumerateStub,
|
EnumerateStub,
|
||||||
ResolveStub,
|
ResolveStub,
|
||||||
js_TryValueOf,
|
js_TryValueOf
|
||||||
NULL, /* finalize */
|
|
||||||
NULL, /* reserved0 */
|
|
||||||
NULL, /* checkAccess */
|
|
||||||
NULL, /* call */
|
|
||||||
NULL, /* construct */
|
|
||||||
NULL, /* xdrObject */
|
|
||||||
NULL, /* hasInstance */
|
|
||||||
NULL, /* mark */
|
|
||||||
JS_NULL_CLASS_EXT,
|
|
||||||
{
|
|
||||||
NULL, /* lookupProperty */
|
|
||||||
NULL, /* defineProperty */
|
|
||||||
NULL, /* getProperty */
|
|
||||||
/*
|
|
||||||
* For assignments to 'length', we need to know the setter's strictness. A property's
|
|
||||||
* setter isn't passed that, but the ObjectOps member is, so use that.
|
|
||||||
*/
|
|
||||||
slowarray_setProperty,
|
|
||||||
NULL, /* getAttributes */
|
|
||||||
NULL, /* setAttributes */
|
|
||||||
NULL, /* deleteProperty */
|
|
||||||
NULL, /* enumerate */
|
|
||||||
NULL, /* typeOf */
|
|
||||||
NULL, /* trace */
|
|
||||||
NULL, /* thisObject */
|
|
||||||
NULL, /* clear */
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1053,7 +1014,7 @@ JSObject::makeDenseArraySlow(JSContext *cx)
|
||||||
* The getter/setter here will directly access the object's private value.
|
* The getter/setter here will directly access the object's private value.
|
||||||
*/
|
*/
|
||||||
if (!addProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
|
if (!addProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
|
||||||
array_length_getter, NULL,
|
array_length_getter, array_length_setter,
|
||||||
SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0)) {
|
SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0)) {
|
||||||
setMap(oldMap);
|
setMap(oldMap);
|
||||||
return false;
|
return false;
|
||||||
|
@ -2285,7 +2246,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
|
||||||
* arguments. We think this is best because it eliminates the need
|
* arguments. We think this is best because it eliminates the need
|
||||||
* for callers to do an extra test to handle the empty splice case.
|
* for callers to do an extra test to handle the empty splice case.
|
||||||
*/
|
*/
|
||||||
JSObject *obj2 = js_NewArrayObject(cx, 0, NULL);
|
JSObject *obj2 = NewDenseEmptyArray(cx);
|
||||||
if (!obj2)
|
if (!obj2)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
vp->setObject(*obj2);
|
vp->setObject(*obj2);
|
||||||
|
@ -2339,7 +2300,6 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
|
||||||
/* If there are elements to remove, put them into the return value. */
|
/* If there are elements to remove, put them into the return value. */
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
|
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
|
||||||
!js_PrototypeHasIndexedProperties(cx, obj2) &&
|
|
||||||
end <= obj->getDenseArrayCapacity()) {
|
end <= obj->getDenseArrayCapacity()) {
|
||||||
if (!InitArrayObject(cx, obj2, count, obj->getDenseArrayElements() + begin))
|
if (!InitArrayObject(cx, obj2, count, obj->getDenseArrayElements() + begin))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
@ -2459,7 +2419,7 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
||||||
*/
|
*/
|
||||||
length = aobj->getArrayLength();
|
length = aobj->getArrayLength();
|
||||||
jsuint capacity = aobj->getDenseArrayCapacity();
|
jsuint capacity = aobj->getDenseArrayCapacity();
|
||||||
nobj = js_NewArrayObject(cx, JS_MIN(length, capacity), aobj->getDenseArrayElements());
|
nobj = NewDenseCopiedArray(cx, JS_MIN(length, capacity), aobj->getDenseArrayElements());
|
||||||
if (!nobj)
|
if (!nobj)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
nobj->setArrayLength(length);
|
nobj->setArrayLength(length);
|
||||||
|
@ -2469,7 +2429,7 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
||||||
argc--;
|
argc--;
|
||||||
p++;
|
p++;
|
||||||
} else {
|
} else {
|
||||||
nobj = js_NewArrayObject(cx, 0, NULL);
|
nobj = NewDenseEmptyArray(cx);
|
||||||
if (!nobj)
|
if (!nobj)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
vp->setObject(*nobj);
|
vp->setObject(*nobj);
|
||||||
|
@ -2490,8 +2450,8 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
||||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||||
if (!aobj->getProperty(cx, id, tvr.addr()))
|
if (!aobj->getProperty(cx, id, tvr.addr()))
|
||||||
return false;
|
return false;
|
||||||
jsuint alength = ValueIsLength(cx, tvr.addr());
|
jsuint alength;
|
||||||
if (tvr.value().isNull())
|
if (!ValueToLength(cx, tvr.addr(), &alength))
|
||||||
return false;
|
return false;
|
||||||
for (jsuint slot = 0; slot < alength; slot++) {
|
for (jsuint slot = 0; slot < alength; slot++) {
|
||||||
JSBool hole;
|
JSBool hole;
|
||||||
|
@ -2572,7 +2532,7 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
|
||||||
|
|
||||||
if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
|
if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
|
||||||
!js_PrototypeHasIndexedProperties(cx, obj)) {
|
!js_PrototypeHasIndexedProperties(cx, obj)) {
|
||||||
nobj = js_NewArrayObject(cx, end - begin, obj->getDenseArrayElements() + begin);
|
nobj = NewDenseCopiedArray(cx, end - begin, obj->getDenseArrayElements() + begin);
|
||||||
if (!nobj)
|
if (!nobj)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
vp->setObject(*nobj);
|
vp->setObject(*nobj);
|
||||||
|
@ -2580,7 +2540,7 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a new Array object and root it using *vp. */
|
/* Create a new Array object and root it using *vp. */
|
||||||
nobj = js_NewArrayObject(cx, 0, NULL);
|
nobj = NewDenseAllocatedArray(cx, end - begin);
|
||||||
if (!nobj)
|
if (!nobj)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
vp->setObject(*nobj);
|
vp->setObject(*nobj);
|
||||||
|
@ -2595,7 +2555,7 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return js_SetLengthProperty(cx, nobj, end - begin);
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if JS_HAS_ARRAY_EXTRAS
|
#if JS_HAS_ARRAY_EXTRAS
|
||||||
|
@ -2757,7 +2717,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
|
||||||
case MAP:
|
case MAP:
|
||||||
case FILTER:
|
case FILTER:
|
||||||
newlen = (mode == MAP) ? length : 0;
|
newlen = (mode == MAP) ? length : 0;
|
||||||
newarr = js_NewArrayObject(cx, newlen, NULL);
|
newarr = NewDenseAllocatedArray(cx, newlen);
|
||||||
if (!newarr)
|
if (!newarr)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
vp->setObject(*newarr);
|
vp->setObject(*newarr);
|
||||||
|
@ -2964,86 +2924,31 @@ static JSFunctionSpec array_static_methods[] = {
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The count here is a guess for the final capacity. */
|
|
||||||
static inline JSObject *
|
|
||||||
NewDenseArrayObject(JSContext *cx, jsuint count)
|
|
||||||
{
|
|
||||||
gc::FinalizeKind kind = GuessObjectGCKind(count, true);
|
|
||||||
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_Array(JSContext *cx, uintN argc, Value *vp)
|
js_Array(JSContext *cx, uintN argc, Value *vp)
|
||||||
{
|
{
|
||||||
jsuint length;
|
JSObject *obj;
|
||||||
const Value *vector;
|
|
||||||
|
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
length = 0;
|
obj = NewDenseEmptyArray(cx);
|
||||||
vector = NULL;
|
|
||||||
} else if (argc > 1) {
|
} else if (argc > 1) {
|
||||||
length = (jsuint) argc;
|
obj = NewDenseCopiedArray(cx, argc, vp + 2);
|
||||||
vector = vp + 2;
|
|
||||||
} else if (!vp[2].isNumber()) {
|
} else if (!vp[2].isNumber()) {
|
||||||
length = 1;
|
obj = NewDenseCopiedArray(cx, 1, vp + 2);
|
||||||
vector = vp + 2;
|
|
||||||
} else {
|
} else {
|
||||||
length = ValueIsLength(cx, vp + 2);
|
jsuint length;
|
||||||
if (vp[2].isNull())
|
if (!ValueToLength(cx, vp + 2, &length))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
vector = NULL;
|
obj = NewDenseUnallocatedArray(cx, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Whether called with 'new' or not, use a new Array object. */
|
|
||||||
JSObject *obj = NewDenseArrayObject(cx, length);
|
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
vp->setObject(*obj);
|
vp->setObject(*obj);
|
||||||
|
|
||||||
return InitArrayObject(cx, obj, length, vector);
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* JS_FASTCALL
|
|
||||||
js_NewEmptyArray(JSContext* cx, JSObject* proto, int32 len)
|
|
||||||
{
|
|
||||||
if (len < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
JS_ASSERT(proto->isArray());
|
|
||||||
|
|
||||||
gc::FinalizeKind kind = GuessObjectGCKind(len, true);
|
|
||||||
JSObject* obj = js_NewGCObject(cx, kind);
|
|
||||||
if (!obj)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Initialize all fields of JSObject. */
|
|
||||||
obj->init(cx, &js_ArrayClass, proto, proto->getParent(),
|
|
||||||
(void*) len, true);
|
|
||||||
obj->setSharedNonNativeMap();
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
#ifdef JS_TRACER
|
|
||||||
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewEmptyArray, CONTEXT, OBJECT, INT32, 0,
|
|
||||||
nanojit::ACCSET_STORE_ANY)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JSObject* JS_FASTCALL
|
|
||||||
js_NewPreallocatedArray(JSContext* cx, JSObject* proto, int32 len)
|
|
||||||
{
|
|
||||||
JSObject *obj = js_NewEmptyArray(cx, proto, len);
|
|
||||||
if (!obj)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Avoid ensureDenseArrayElements to skip sparse array checks there. */
|
|
||||||
if (!obj->ensureSlots(cx, len))
|
|
||||||
return NULL;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
#ifdef JS_TRACER
|
|
||||||
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewPreallocatedArray, CONTEXT, OBJECT, INT32,
|
|
||||||
0, nanojit::ACCSET_STORE_ANY)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
js_InitArrayClass(JSContext *cx, JSObject *obj)
|
js_InitArrayClass(JSContext *cx, JSObject *obj)
|
||||||
{
|
{
|
||||||
|
@ -3062,31 +2967,83 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
|
||||||
return proto;
|
return proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *
|
/*
|
||||||
js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector)
|
* Array allocation functions.
|
||||||
|
*/
|
||||||
|
namespace js {
|
||||||
|
|
||||||
|
template<bool allocateCapacity>
|
||||||
|
static JS_ALWAYS_INLINE JSObject *
|
||||||
|
NewArray(JSContext *cx, jsuint length, JSObject *proto)
|
||||||
{
|
{
|
||||||
JSObject *obj = NewDenseArrayObject(cx, length);
|
JS_ASSERT_IF(proto, proto->isArray());
|
||||||
|
|
||||||
|
gc::FinalizeKind kind = GuessObjectGCKind(length, true);
|
||||||
|
JSObject *obj = detail::NewObject<WithProto::Class, false>(cx, &js_ArrayClass, proto, NULL, kind);
|
||||||
|
|
||||||
|
obj->setArrayLength(length);
|
||||||
|
|
||||||
|
if (allocateCapacity && !obj->ensureSlots(cx, length))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject * JS_FASTCALL
|
||||||
|
NewDenseEmptyArray(JSContext *cx, JSObject *proto)
|
||||||
|
{
|
||||||
|
return NewArray<false>(cx, 0, proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject * JS_FASTCALL
|
||||||
|
NewDenseAllocatedArray(JSContext *cx, uint32 length, JSObject *proto)
|
||||||
|
{
|
||||||
|
return NewArray<true>(cx, length, proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject * JS_FASTCALL
|
||||||
|
NewDenseUnallocatedArray(JSContext *cx, uint32 length, JSObject *proto)
|
||||||
|
{
|
||||||
|
return NewArray<false>(cx, length, proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject *
|
||||||
|
NewDenseCopiedArray(JSContext *cx, uintN length, Value *vp, JSObject *proto)
|
||||||
|
{
|
||||||
|
JSObject* obj = NewArray<true>(cx, length, proto);
|
||||||
|
JS_ASSERT(obj->getDenseArrayCapacity() >= length);
|
||||||
|
|
||||||
|
if (vp)
|
||||||
|
memcpy(obj->getDenseArrayElements(), vp, length * sizeof(Value));
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JS_TRACER
|
||||||
|
JS_DEFINE_CALLINFO_2(extern, OBJECT, NewDenseEmptyArray, CONTEXT, OBJECT, 0,
|
||||||
|
nanojit::ACCSET_STORE_ANY)
|
||||||
|
JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseAllocatedArray, CONTEXT, UINT32, OBJECT, 0,
|
||||||
|
nanojit::ACCSET_STORE_ANY)
|
||||||
|
JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseUnallocatedArray, CONTEXT, UINT32, OBJECT, 0,
|
||||||
|
nanojit::ACCSET_STORE_ANY)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
JSObject *
|
||||||
|
NewSlowEmptyArray(JSContext *cx)
|
||||||
|
{
|
||||||
|
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_SlowArrayClass, NULL, NULL);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*
|
obj->setArrayLength(0);
|
||||||
* If this fails, the global object was not initialized and its class does
|
|
||||||
* not have JSCLASS_IS_GLOBAL.
|
|
||||||
*/
|
|
||||||
JS_ASSERT(obj->getProto());
|
|
||||||
|
|
||||||
return InitArrayObject(cx, obj, length, vector) ? obj : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject *
|
|
||||||
js_NewSlowArrayObject(JSContext *cx)
|
|
||||||
{
|
|
||||||
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_SlowArrayClass, NULL, NULL);
|
|
||||||
if (obj)
|
|
||||||
obj->setArrayLength(0);
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JSBool
|
JSBool
|
||||||
js_ArrayInfo(JSContext *cx, uintN argc, jsval *vp)
|
js_ArrayInfo(JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
@ -3241,10 +3198,11 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
|
||||||
vector.append(val);
|
vector.append(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
*clone = js_NewArrayObject(cx, jsvalCount, vector.begin());
|
*clone = NewDenseCopiedArray(cx, jsvalCount, vector.begin());
|
||||||
if (!*clone)
|
if (!*clone)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
(*clone)->setArrayLength(length);
|
|
||||||
|
|
||||||
|
/* The length will be set to the JS_MIN, above, but length might be larger. */
|
||||||
|
(*clone)->setArrayLength(length);
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,12 +177,33 @@ js_InitArrayClass(JSContext *cx, JSObject *obj);
|
||||||
extern bool
|
extern bool
|
||||||
js_InitContextBusyArrayTable(JSContext *cx);
|
js_InitContextBusyArrayTable(JSContext *cx);
|
||||||
|
|
||||||
extern JSObject *
|
namespace js
|
||||||
js_NewArrayObject(JSContext *cx, jsuint length, const js::Value *vector);
|
{
|
||||||
|
|
||||||
/* Create an array object that starts out already made slow/sparse. */
|
/* Create a dense array with no capacity allocated, length set to 0. */
|
||||||
|
extern JSObject * JS_FASTCALL
|
||||||
|
NewDenseEmptyArray(JSContext *cx, JSObject *proto=NULL);
|
||||||
|
|
||||||
|
/* Create a dense array with length and capacity == 'length'. */
|
||||||
|
extern JSObject * JS_FASTCALL
|
||||||
|
NewDenseAllocatedArray(JSContext *cx, uint length, JSObject *proto=NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a dense array with a set length, but without allocating space for the
|
||||||
|
* contents. This is useful, e.g., when accepting length from the user.
|
||||||
|
*/
|
||||||
|
extern JSObject * JS_FASTCALL
|
||||||
|
NewDenseUnallocatedArray(JSContext *cx, uint length, JSObject *proto=NULL);
|
||||||
|
|
||||||
|
/* Create a dense array with a copy of vp. */
|
||||||
extern JSObject *
|
extern JSObject *
|
||||||
js_NewSlowArrayObject(JSContext *cx);
|
NewDenseCopiedArray(JSContext *cx, uint length, Value *vp, JSObject *proto=NULL);
|
||||||
|
|
||||||
|
/* Create a sparse array. */
|
||||||
|
extern JSObject *
|
||||||
|
NewSlowEmptyArray(JSContext *cx);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
|
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
|
||||||
|
@ -283,25 +304,6 @@ js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id,
|
||||||
JSBool
|
JSBool
|
||||||
js_Array(JSContext *cx, uintN argc, js::Value *vp);
|
js_Array(JSContext *cx, uintN argc, js::Value *vp);
|
||||||
|
|
||||||
/*
|
|
||||||
* Friend api function that allows direct creation of an array object with a
|
|
||||||
* given capacity. Non-null return value means allocation of the internal
|
|
||||||
* buffer for a capacity of at least |capacity| succeeded. A pointer to the
|
|
||||||
* first element of this internal buffer is returned in the |vector| out
|
|
||||||
* parameter. The caller promises to fill in the first |capacity| values
|
|
||||||
* starting from that pointer immediately after this function returns and
|
|
||||||
* without triggering GC (so this method is allowed to leave those
|
|
||||||
* uninitialized) and to set them to non-JS_ARRAY_HOLE-magic-why values, so
|
|
||||||
* that the resulting array has length and count both equal to |capacity|.
|
|
||||||
*
|
|
||||||
* FIXME: for some strange reason, when this file is included from
|
|
||||||
* dom/ipc/TabParent.cpp in MSVC, jsuint resolves to a slightly different
|
|
||||||
* builtin than when mozjs.dll is built, resulting in a link error in xul.dll.
|
|
||||||
* It would be useful to find out what is causing this insanity.
|
|
||||||
*/
|
|
||||||
JS_FRIEND_API(JSObject *)
|
|
||||||
js_NewArrayObjectWithCapacity(JSContext *cx, uint32_t capacity, jsval **vector);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Makes a fast clone of a dense array as long as the array only contains
|
* Makes a fast clone of a dense array as long as the array only contains
|
||||||
* primitive values.
|
* primitive values.
|
||||||
|
|
|
@ -575,8 +575,11 @@ js_dmod(jsdouble a, jsdouble b);
|
||||||
#endif /* !JS_TRACER */
|
#endif /* !JS_TRACER */
|
||||||
|
|
||||||
/* Defined in jsarray.cpp. */
|
/* Defined in jsarray.cpp. */
|
||||||
JS_DECLARE_CALLINFO(js_NewEmptyArray)
|
namespace js {
|
||||||
JS_DECLARE_CALLINFO(js_NewPreallocatedArray)
|
JS_DECLARE_CALLINFO(NewDenseEmptyArray)
|
||||||
|
JS_DECLARE_CALLINFO(NewDenseAllocatedArray)
|
||||||
|
JS_DECLARE_CALLINFO(NewDenseUnallocatedArray)
|
||||||
|
}
|
||||||
JS_DECLARE_CALLINFO(js_ArrayCompPush_tn)
|
JS_DECLARE_CALLINFO(js_ArrayCompPush_tn)
|
||||||
JS_DECLARE_CALLINFO(js_EnsureDenseArrayCapacity)
|
JS_DECLARE_CALLINFO(js_EnsureDenseArrayCapacity)
|
||||||
|
|
||||||
|
|
|
@ -763,7 +763,7 @@ JSStructuredCloneReader::startRead(Value *vp)
|
||||||
case SCTAG_ARRAY_OBJECT:
|
case SCTAG_ARRAY_OBJECT:
|
||||||
case SCTAG_OBJECT_OBJECT: {
|
case SCTAG_OBJECT_OBJECT: {
|
||||||
JSObject *obj = (tag == SCTAG_ARRAY_OBJECT)
|
JSObject *obj = (tag == SCTAG_ARRAY_OBJECT)
|
||||||
? js_NewArrayObject(context(), 0, NULL)
|
? NewDenseEmptyArray(context())
|
||||||
: NewBuiltinClassInstance(context(), &js_ObjectClass);
|
: NewBuiltinClassInstance(context(), &js_ObjectClass);
|
||||||
if (!obj || !objs.append(ObjectValue(*obj)))
|
if (!obj || !objs.append(ObjectValue(*obj)))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -591,7 +591,7 @@ class CompartmentChecker
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(JSScript *script) {
|
void check(JSScript *script) {
|
||||||
if (script && script != JSScript::emptyScript()) {
|
if (script) {
|
||||||
check(script->compartment);
|
check(script->compartment);
|
||||||
if (script->u.object)
|
if (script->u.object)
|
||||||
check(script->u.object);
|
check(script->u.object);
|
||||||
|
|
|
@ -265,12 +265,6 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||||
if (!CheckDebugMode(cx))
|
if (!CheckDebugMode(cx))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
if (script == JSScript::emptyScript()) {
|
|
||||||
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
|
|
||||||
NULL, JSMSG_READ_ONLY, "empty script");
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ASSERT((JSOp) *pc != JSOP_TRAP);
|
JS_ASSERT((JSOp) *pc != JSOP_TRAP);
|
||||||
junk = NULL;
|
junk = NULL;
|
||||||
rt = cx->runtime;
|
rt = cx->runtime;
|
||||||
|
@ -1761,7 +1755,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
|
||||||
continue;
|
continue;
|
||||||
nbytes += (sn - notes + 1) * sizeof *sn;
|
nbytes += (sn - notes + 1) * sizeof *sn;
|
||||||
|
|
||||||
if (script->objectsOffset != 0) {
|
if (JSScript::isValidOffset(script->objectsOffset)) {
|
||||||
objarray = script->objects();
|
objarray = script->objects();
|
||||||
i = objarray->length;
|
i = objarray->length;
|
||||||
nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
|
nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
|
||||||
|
@ -1770,7 +1764,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
|
||||||
} while (i != 0);
|
} while (i != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (script->regexpsOffset != 0) {
|
if (JSScript::isValidOffset(script->regexpsOffset)) {
|
||||||
objarray = script->regexps();
|
objarray = script->regexps();
|
||||||
i = objarray->length;
|
i = objarray->length;
|
||||||
nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
|
nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
|
||||||
|
@ -1779,7 +1773,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
|
||||||
} while (i != 0);
|
} while (i != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (script->trynotesOffset != 0) {
|
if (JSScript::isValidOffset(script->trynotesOffset)) {
|
||||||
nbytes += sizeof(JSTryNoteArray) +
|
nbytes += sizeof(JSTryNoteArray) +
|
||||||
script->trynotes()->length * sizeof(JSTryNote);
|
script->trynotes()->length * sizeof(JSTryNote);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1737,7 +1737,7 @@ LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while ((cg = (JSCodeGenerator *) cg->parent) != NULL);
|
} while (cg->parent && (cg = cg->parent->asCodeGenerator()));
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2161,13 +2161,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
*
|
*
|
||||||
* Turn JSOP_DELNAME into JSOP_FALSE if dn is known, as all declared
|
* Turn JSOP_DELNAME into JSOP_FALSE if dn is known, as all declared
|
||||||
* bindings visible to the compiler are permanent in JS unless the
|
* bindings visible to the compiler are permanent in JS unless the
|
||||||
* declaration originates in eval code. We detect eval code by testing
|
* declaration originates at top level in eval code.
|
||||||
* cg->parser->callerFrame, which is set only by eval or a debugger
|
|
||||||
* equivalent.
|
|
||||||
*
|
|
||||||
* Note that this callerFrame non-null test must be qualified by testing
|
|
||||||
* !cg->funbox to exclude function code nested in eval code, which is not
|
|
||||||
* subject to the deletable binding exception.
|
|
||||||
*/
|
*/
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case JSOP_NAME:
|
case JSOP_NAME:
|
||||||
|
@ -2175,7 +2169,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
break;
|
break;
|
||||||
case JSOP_DELNAME:
|
case JSOP_DELNAME:
|
||||||
if (dn_kind != JSDefinition::UNKNOWN) {
|
if (dn_kind != JSDefinition::UNKNOWN) {
|
||||||
if (cg->parser->callerFrame && !cg->funbox)
|
if (cg->parser->callerFrame && dn->isTopLevel())
|
||||||
JS_ASSERT(cg->compileAndGo());
|
JS_ASSERT(cg->compileAndGo());
|
||||||
else
|
else
|
||||||
pn->pn_op = JSOP_FALSE;
|
pn->pn_op = JSOP_FALSE;
|
||||||
|
@ -2353,9 +2347,8 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
JSTreeContext *tc = cg;
|
JSTreeContext *tc = cg;
|
||||||
while (tc->staticLevel != level)
|
while (tc->staticLevel != level)
|
||||||
tc = tc->parent;
|
tc = tc->parent;
|
||||||
JS_ASSERT(tc->compiling());
|
|
||||||
|
|
||||||
JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
|
JSCodeGenerator *evalcg = tc->asCodeGenerator();
|
||||||
JS_ASSERT(evalcg->compileAndGo());
|
JS_ASSERT(evalcg->compileAndGo());
|
||||||
JS_ASSERT(caller->isFunctionFrame());
|
JS_ASSERT(caller->isFunctionFrame());
|
||||||
JS_ASSERT(cg->parser->callerVarObj == evalcg->scopeChain());
|
JS_ASSERT(cg->parser->callerVarObj == evalcg->scopeChain());
|
||||||
|
@ -2433,10 +2426,9 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
JS_ASSERT(index == cg->upvarList.count - 1);
|
JS_ASSERT(index == cg->upvarList.count - 1);
|
||||||
|
|
||||||
UpvarCookie *vector = cg->upvarMap.vector;
|
UpvarCookie *vector = cg->upvarMap.vector;
|
||||||
if (!vector) {
|
uint32 length = cg->lexdeps.count;
|
||||||
uint32 length = cg->lexdeps.count;
|
if (!vector || cg->upvarMap.length != length) {
|
||||||
|
vector = (UpvarCookie *) js_realloc(vector, length * sizeof *vector);
|
||||||
vector = (UpvarCookie *) js_calloc(length * sizeof *vector);
|
|
||||||
if (!vector) {
|
if (!vector) {
|
||||||
JS_ReportOutOfMemory(cx);
|
JS_ReportOutOfMemory(cx);
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
@ -2455,6 +2447,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
slot += tc->fun()->nargs;
|
slot += tc->fun()->nargs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_ASSERT(index < cg->upvarMap.length);
|
||||||
vector[index].set(skip, slot);
|
vector[index].set(skip, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4601,11 +4594,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT_IF(cx->options & JSOPTION_ANONFUNFIX,
|
|
||||||
pn->pn_defn ||
|
|
||||||
(!pn->pn_used && !pn->isTopLevel()) ||
|
|
||||||
(fun->flags & JSFUN_LAMBDA));
|
|
||||||
|
|
||||||
JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
|
JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
|
||||||
FUN_KIND(fun) == JSFUN_INTERPRETED);
|
FUN_KIND(fun) == JSFUN_INTERPRETED);
|
||||||
|
|
||||||
|
@ -4625,7 +4613,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
if (!cg2->init())
|
if (!cg2->init())
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
cg2->flags = pn->pn_funbox->tcflags | TCF_IN_FUNCTION;
|
cg2->flags = pn->pn_funbox->tcflags | TCF_COMPILING | TCF_IN_FUNCTION;
|
||||||
#if JS_HAS_SHARP_VARS
|
#if JS_HAS_SHARP_VARS
|
||||||
if (cg2->flags & TCF_HAS_SHARPS) {
|
if (cg2->flags & TCF_HAS_SHARPS) {
|
||||||
cg2->sharpSlotBase = fun->sharpSlotBase(cx);
|
cg2->sharpSlotBase = fun->sharpSlotBase(cx);
|
||||||
|
|
|
@ -364,8 +364,16 @@ struct JSTreeContext { /* tree context for semantic checks */
|
||||||
JSObject *blockChain() {
|
JSObject *blockChain() {
|
||||||
return blockChainBox ? blockChainBox->object : NULL;
|
return blockChainBox ? blockChainBox->object : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool atTopLevel() { return !topStmt || (topStmt->flags & SIF_BODY_BLOCK); }
|
/*
|
||||||
|
* True if we are at the topmost level of a entire script or function body.
|
||||||
|
* For example, while parsing this code we would encounter f1 and f2 at
|
||||||
|
* body level, but we would not encounter f3 or f4 at body level:
|
||||||
|
*
|
||||||
|
* function f1() { function f2() { } }
|
||||||
|
* if (cond) { function f3() { if (cond) { function f4() { } } } }
|
||||||
|
*/
|
||||||
|
bool atBodyLevel() { return !topStmt || (topStmt->flags & SIF_BODY_BLOCK); }
|
||||||
|
|
||||||
/* Test whether we're in a statement of given type. */
|
/* Test whether we're in a statement of given type. */
|
||||||
bool inStatement(JSStmtType type);
|
bool inStatement(JSStmtType type);
|
||||||
|
@ -392,7 +400,9 @@ struct JSTreeContext { /* tree context for semantic checks */
|
||||||
|
|
||||||
bool compileAndGo() const { return flags & TCF_COMPILE_N_GO; }
|
bool compileAndGo() const { return flags & TCF_COMPILE_N_GO; }
|
||||||
bool inFunction() const { return flags & TCF_IN_FUNCTION; }
|
bool inFunction() const { return flags & TCF_IN_FUNCTION; }
|
||||||
|
|
||||||
bool compiling() const { return flags & TCF_COMPILING; }
|
bool compiling() const { return flags & TCF_COMPILING; }
|
||||||
|
inline JSCodeGenerator *asCodeGenerator();
|
||||||
|
|
||||||
bool usesArguments() const {
|
bool usesArguments() const {
|
||||||
return flags & TCF_FUN_USES_ARGUMENTS;
|
return flags & TCF_FUN_USES_ARGUMENTS;
|
||||||
|
@ -594,7 +604,7 @@ struct JSCodeGenerator : public JSTreeContext
|
||||||
SlotVector closedVars;
|
SlotVector closedVars;
|
||||||
|
|
||||||
uint16 traceIndex; /* index for the next JSOP_TRACE instruction */
|
uint16 traceIndex; /* index for the next JSOP_TRACE instruction */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize cg to allocate bytecode space from codePool, source note
|
* Initialize cg to allocate bytecode space from codePool, source note
|
||||||
* space from notePool, and all other arena-allocated temporaries from
|
* space from notePool, and all other arena-allocated temporaries from
|
||||||
|
@ -668,6 +678,13 @@ struct JSCodeGenerator : public JSTreeContext
|
||||||
#define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main)
|
#define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main)
|
||||||
#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog)
|
#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog)
|
||||||
|
|
||||||
|
inline JSCodeGenerator *
|
||||||
|
JSTreeContext::asCodeGenerator()
|
||||||
|
{
|
||||||
|
JS_ASSERT(compiling());
|
||||||
|
return static_cast<JSCodeGenerator *>(this);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Emit one bytecode.
|
* Emit one bytecode.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -389,20 +389,20 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSFunction *fun)
|
||||||
/* NB: GC must not occur before wscript is homed in wfun->u.i.script. */
|
/* NB: GC must not occur before wscript is homed in wfun->u.i.script. */
|
||||||
JSScript *wscript = JSScript::NewScript(cx, script->length, nsrcnotes,
|
JSScript *wscript = JSScript::NewScript(cx, script->length, nsrcnotes,
|
||||||
script->atomMap.length,
|
script->atomMap.length,
|
||||||
(script->objectsOffset != 0)
|
JSScript::isValidOffset(script->objectsOffset)
|
||||||
? script->objects()->length
|
? script->objects()->length
|
||||||
: 0,
|
: 0,
|
||||||
fun->u.i.nupvars,
|
fun->u.i.nupvars,
|
||||||
(script->regexpsOffset != 0)
|
JSScript::isValidOffset(script->regexpsOffset)
|
||||||
? script->regexps()->length
|
? script->regexps()->length
|
||||||
: 0,
|
: 0,
|
||||||
(script->trynotesOffset != 0)
|
JSScript::isValidOffset(script->trynotesOffset)
|
||||||
? script->trynotes()->length
|
? script->trynotes()->length
|
||||||
: 0,
|
: 0,
|
||||||
(script->constOffset != 0)
|
JSScript::isValidOffset(script->constOffset)
|
||||||
? script->consts()->length
|
? script->consts()->length
|
||||||
: 0,
|
: 0,
|
||||||
(script->globalsOffset != 0)
|
JSScript::isValidOffset(script->globalsOffset)
|
||||||
? script->globals()->length
|
? script->globals()->length
|
||||||
: 0,
|
: 0,
|
||||||
script->nClosedArgs,
|
script->nClosedArgs,
|
||||||
|
@ -416,19 +416,19 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSFunction *fun)
|
||||||
memcpy(wscript->notes(), snbase, nsrcnotes * sizeof(jssrcnote));
|
memcpy(wscript->notes(), snbase, nsrcnotes * sizeof(jssrcnote));
|
||||||
memcpy(wscript->atomMap.vector, script->atomMap.vector,
|
memcpy(wscript->atomMap.vector, script->atomMap.vector,
|
||||||
wscript->atomMap.length * sizeof(JSAtom *));
|
wscript->atomMap.length * sizeof(JSAtom *));
|
||||||
if (script->objectsOffset != 0) {
|
if (JSScript::isValidOffset(script->objectsOffset)) {
|
||||||
memcpy(wscript->objects()->vector, script->objects()->vector,
|
memcpy(wscript->objects()->vector, script->objects()->vector,
|
||||||
wscript->objects()->length * sizeof(JSObject *));
|
wscript->objects()->length * sizeof(JSObject *));
|
||||||
}
|
}
|
||||||
if (script->regexpsOffset != 0) {
|
if (JSScript::isValidOffset(script->regexpsOffset)) {
|
||||||
memcpy(wscript->regexps()->vector, script->regexps()->vector,
|
memcpy(wscript->regexps()->vector, script->regexps()->vector,
|
||||||
wscript->regexps()->length * sizeof(JSObject *));
|
wscript->regexps()->length * sizeof(JSObject *));
|
||||||
}
|
}
|
||||||
if (script->trynotesOffset != 0) {
|
if (JSScript::isValidOffset(script->trynotesOffset)) {
|
||||||
memcpy(wscript->trynotes()->vector, script->trynotes()->vector,
|
memcpy(wscript->trynotes()->vector, script->trynotes()->vector,
|
||||||
wscript->trynotes()->length * sizeof(JSTryNote));
|
wscript->trynotes()->length * sizeof(JSTryNote));
|
||||||
}
|
}
|
||||||
if (script->globalsOffset != 0) {
|
if (JSScript::isValidOffset(script->globalsOffset)) {
|
||||||
memcpy(wscript->globals()->vector, script->globals()->vector,
|
memcpy(wscript->globals()->vector, script->globals()->vector,
|
||||||
wscript->globals()->length * sizeof(GlobalSlotArray::Entry));
|
wscript->globals()->length * sizeof(GlobalSlotArray::Entry));
|
||||||
}
|
}
|
||||||
|
@ -1959,17 +1959,15 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
|
||||||
fun->freezeLocalNames(cx);
|
fun->freezeLocalNames(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!js_XDRScript(xdr, &fun->u.i.script, false, NULL))
|
if (!js_XDRScript(xdr, &fun->u.i.script, NULL))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (xdr->mode == JSXDR_DECODE) {
|
if (xdr->mode == JSXDR_DECODE) {
|
||||||
*objp = FUN_OBJECT(fun);
|
*objp = FUN_OBJECT(fun);
|
||||||
if (fun->u.i.script != JSScript::emptyScript()) {
|
|
||||||
#ifdef CHECK_SCRIPT_OWNER
|
#ifdef CHECK_SCRIPT_OWNER
|
||||||
fun->u.i.script->owner = NULL;
|
fun->script()->owner = NULL;
|
||||||
#endif
|
#endif
|
||||||
js_CallNewScriptHook(cx, fun->u.i.script, fun);
|
js_CallNewScriptHook(cx, fun->script(), fun);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -2717,7 +2715,18 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj)
|
||||||
if (!fun)
|
if (!fun)
|
||||||
return NULL;
|
return NULL;
|
||||||
fun->flags |= JSFUN_PROTOTYPE;
|
fun->flags |= JSFUN_PROTOTYPE;
|
||||||
fun->u.i.script = JSScript::emptyScript();
|
|
||||||
|
JSScript *script = JSScript::NewScript(cx, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
if (!script)
|
||||||
|
return NULL;
|
||||||
|
script->setVersion(JSVERSION_DEFAULT);
|
||||||
|
script->noScriptRval = true;
|
||||||
|
script->code[0] = JSOP_STOP;
|
||||||
|
script->code[1] = SRC_NULL;
|
||||||
|
#ifdef CHECK_SCRIPT_OWNER
|
||||||
|
script->owner = NULL;
|
||||||
|
#endif
|
||||||
|
fun->u.i.script = script;
|
||||||
|
|
||||||
if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
|
if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
|
||||||
/* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
|
/* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
|
||||||
|
@ -2821,18 +2830,16 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
|
||||||
if (cfun->isInterpreted()) {
|
if (cfun->isInterpreted()) {
|
||||||
JSScript *script = cfun->u.i.script;
|
JSScript *script = cfun->u.i.script;
|
||||||
JS_ASSERT(script);
|
JS_ASSERT(script);
|
||||||
if (script != JSScript::emptyScript()) {
|
JS_ASSERT(script->compartment == fun->compartment());
|
||||||
JS_ASSERT(script->compartment == fun->compartment());
|
JS_ASSERT(script->compartment != cx->compartment);
|
||||||
JS_ASSERT(script->compartment != cx->compartment);
|
|
||||||
cfun->u.i.script = js_CloneScript(cx, script);
|
cfun->u.i.script = js_CloneScript(cx, script);
|
||||||
if (!cfun->u.i.script)
|
if (!cfun->u.i.script)
|
||||||
return NULL;
|
return NULL;
|
||||||
JS_ASSERT(cfun->u.i.script != JSScript::emptyScript());
|
|
||||||
#ifdef CHECK_SCRIPT_OWNER
|
#ifdef CHECK_SCRIPT_OWNER
|
||||||
cfun->u.i.script->owner = NULL;
|
cfun->script()->owner = NULL;
|
||||||
#endif
|
#endif
|
||||||
js_CallNewScriptHook(cx, cfun->u.i.script, cfun);
|
js_CallNewScriptHook(cx, cfun->script(), cfun);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return clone;
|
return clone;
|
||||||
|
@ -2852,7 +2859,7 @@ JSObject * JS_FASTCALL
|
||||||
js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
|
js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
|
||||||
{
|
{
|
||||||
JS_ASSERT(FUN_FLAT_CLOSURE(fun));
|
JS_ASSERT(FUN_FLAT_CLOSURE(fun));
|
||||||
JS_ASSERT((fun->u.i.script->upvarsOffset
|
JS_ASSERT((JSScript::isValidOffset(fun->u.i.script->upvarsOffset)
|
||||||
? fun->u.i.script->upvars()->length
|
? fun->u.i.script->upvars()->length
|
||||||
: 0) == fun->u.i.nupvars);
|
: 0) == fun->u.i.nupvars);
|
||||||
|
|
||||||
|
|
|
@ -351,18 +351,24 @@ TypedMarker(JSTracer *trc, JSShortString *thing)
|
||||||
}
|
}
|
||||||
|
|
||||||
static JS_ALWAYS_INLINE void
|
static JS_ALWAYS_INLINE void
|
||||||
TypedMarker(JSTracer *trc, JSString *thing)
|
TypedMarker(JSTracer *trc, JSString *str)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Iterate through all nodes and leaves in the rope if this is part of a
|
* When marking any node of a rope, mark the entire rope. This means if
|
||||||
* rope; otherwise, we only iterate once: on the string itself.
|
* a given rope node is already marked, we are done.
|
||||||
*/
|
*/
|
||||||
JSRopeNodeIterator iter(thing);
|
JSRopeNodeIterator iter;
|
||||||
JSString *str = iter.init();
|
if (str->isRope()) {
|
||||||
|
if (str->asCell()->isMarked())
|
||||||
|
return;
|
||||||
|
str = iter.init(str);
|
||||||
|
goto not_static;
|
||||||
|
}
|
||||||
do {
|
do {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (JSString::isStatic(str))
|
if (JSString::isStatic(str))
|
||||||
break;
|
break;
|
||||||
|
not_static:
|
||||||
JS_ASSERT(JSTRACE_STRING == GetFinalizableTraceKind(str->asCell()->arena()->header()->thingKind));
|
JS_ASSERT(JSTRACE_STRING == GetFinalizableTraceKind(str->asCell()->arena()->header()->thingKind));
|
||||||
if (!str->asCell()->markIfUnmarked())
|
if (!str->asCell()->markIfUnmarked())
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -616,7 +616,7 @@ NoSuchMethod(JSContext *cx, uintN argc, Value *vp, uint32 flags)
|
||||||
args.callee() = obj->getSlot(JSSLOT_FOUND_FUNCTION);
|
args.callee() = obj->getSlot(JSSLOT_FOUND_FUNCTION);
|
||||||
args.thisv() = vp[1];
|
args.thisv() = vp[1];
|
||||||
args[0] = obj->getSlot(JSSLOT_SAVED_ID);
|
args[0] = obj->getSlot(JSSLOT_SAVED_ID);
|
||||||
JSObject *argsobj = js_NewArrayObject(cx, argc, vp + 2);
|
JSObject *argsobj = NewDenseCopiedArray(cx, argc, vp + 2);
|
||||||
if (!argsobj)
|
if (!argsobj)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
args[1].setObject(*argsobj);
|
args[1].setObject(*argsobj);
|
||||||
|
@ -908,7 +908,7 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||||
if (script->isEmpty()) {
|
if (script->isEmpty()) {
|
||||||
if (result)
|
if (result)
|
||||||
result->setUndefined();
|
result->setUndefined();
|
||||||
return JS_TRUE;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
|
@ -2506,9 +2506,6 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
||||||
Value *argv = regs.fp->maybeFormalArgs();
|
Value *argv = regs.fp->maybeFormalArgs();
|
||||||
CHECK_INTERRUPT_HANDLER();
|
CHECK_INTERRUPT_HANDLER();
|
||||||
|
|
||||||
JS_ASSERT(!script->isEmpty());
|
|
||||||
JS_ASSERT(script->length >= 1);
|
|
||||||
|
|
||||||
#if defined(JS_TRACER) && defined(JS_METHODJIT)
|
#if defined(JS_TRACER) && defined(JS_METHODJIT)
|
||||||
bool leaveOnSafePoint = (interpMode == JSINTERP_SAFEPOINT);
|
bool leaveOnSafePoint = (interpMode == JSINTERP_SAFEPOINT);
|
||||||
# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) (leaveOnSafePoint = false))
|
# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) (leaveOnSafePoint = false))
|
||||||
|
@ -4078,8 +4075,8 @@ BEGIN_CASE(JSOP_UNBRANDTHIS)
|
||||||
Value &thisv = regs.fp->thisValue();
|
Value &thisv = regs.fp->thisValue();
|
||||||
if (thisv.isObject()) {
|
if (thisv.isObject()) {
|
||||||
JSObject *obj = &thisv.toObject();
|
JSObject *obj = &thisv.toObject();
|
||||||
if (obj->isNative() && !obj->unbrand(cx))
|
if (obj->isNative())
|
||||||
goto error;
|
obj->unbrand(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
END_CASE(JSOP_UNBRANDTHIS)
|
END_CASE(JSOP_UNBRANDTHIS)
|
||||||
|
@ -4293,8 +4290,7 @@ END_CASE(JSOP_CALLPROP)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_UNBRAND)
|
BEGIN_CASE(JSOP_UNBRAND)
|
||||||
JS_ASSERT(regs.sp - regs.fp->slots() >= 1);
|
JS_ASSERT(regs.sp - regs.fp->slots() >= 1);
|
||||||
if (!regs.sp[-1].toObject().unbrand(cx))
|
regs.sp[-1].toObject().unbrand(cx);
|
||||||
goto error;
|
|
||||||
END_CASE(JSOP_UNBRAND)
|
END_CASE(JSOP_UNBRAND)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_SETGNAME)
|
BEGIN_CASE(JSOP_SETGNAME)
|
||||||
|
@ -4677,7 +4673,7 @@ BEGIN_CASE(JSOP_FUNCALL)
|
||||||
if (newfun->isInterpreted())
|
if (newfun->isInterpreted())
|
||||||
inline_call:
|
inline_call:
|
||||||
{
|
{
|
||||||
JSScript *newscript = newfun->u.i.script;
|
JSScript *newscript = newfun->script();
|
||||||
if (JS_UNLIKELY(newscript->isEmpty())) {
|
if (JS_UNLIKELY(newscript->isEmpty())) {
|
||||||
vp->setUndefined();
|
vp->setUndefined();
|
||||||
regs.sp = vp + 1;
|
regs.sp = vp + 1;
|
||||||
|
@ -5892,7 +5888,7 @@ BEGIN_CASE(JSOP_NEWINIT)
|
||||||
JSObject *obj;
|
JSObject *obj;
|
||||||
|
|
||||||
if (i == JSProto_Array) {
|
if (i == JSProto_Array) {
|
||||||
obj = js_NewArrayObject(cx, 0, NULL);
|
obj = NewDenseEmptyArray(cx);
|
||||||
} else {
|
} else {
|
||||||
gc::FinalizeKind kind = GuessObjectGCKind(0, false);
|
gc::FinalizeKind kind = GuessObjectGCKind(0, false);
|
||||||
obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
|
obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
|
||||||
|
@ -5909,10 +5905,8 @@ END_CASE(JSOP_NEWINIT)
|
||||||
BEGIN_CASE(JSOP_NEWARRAY)
|
BEGIN_CASE(JSOP_NEWARRAY)
|
||||||
{
|
{
|
||||||
unsigned count = GET_UINT24(regs.pc);
|
unsigned count = GET_UINT24(regs.pc);
|
||||||
JSObject *obj = js_NewArrayObject(cx, count, NULL);
|
JSObject *obj = NewDenseAllocatedArray(cx, count);
|
||||||
|
if (!obj)
|
||||||
/* Avoid ensureDenseArrayElements to skip sparse array checks there. */
|
|
||||||
if (!obj || !obj->ensureSlots(cx, count))
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
PUSH_OBJECT(*obj);
|
PUSH_OBJECT(*obj);
|
||||||
|
@ -6069,7 +6063,7 @@ BEGIN_CASE(JSOP_DEFSHARP)
|
||||||
obj = &lref.toObject();
|
obj = &lref.toObject();
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(lref.isUndefined());
|
JS_ASSERT(lref.isUndefined());
|
||||||
obj = js_NewArrayObject(cx, 0, NULL);
|
obj = NewDenseEmptyArray(cx);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
goto error;
|
goto error;
|
||||||
regs.fp->slots()[slot].setObject(*obj);
|
regs.fp->slots()[slot].setObject(*obj);
|
||||||
|
@ -6832,7 +6826,7 @@ END_CASE(JSOP_ARRAYPUSH)
|
||||||
/*
|
/*
|
||||||
* Look for a try block in script that can catch this exception.
|
* Look for a try block in script that can catch this exception.
|
||||||
*/
|
*/
|
||||||
if (script->trynotesOffset == 0)
|
if (!JSScript::isValidOffset(script->trynotesOffset))
|
||||||
goto no_catch;
|
goto no_catch;
|
||||||
|
|
||||||
offset = (uint32)(regs.pc - script->main);
|
offset = (uint32)(regs.pc - script->main);
|
||||||
|
|
|
@ -61,7 +61,7 @@ struct JSFrameRegs
|
||||||
/* Flags to toggle js::Interpret() execution. */
|
/* Flags to toggle js::Interpret() execution. */
|
||||||
enum JSInterpMode
|
enum JSInterpMode
|
||||||
{
|
{
|
||||||
JSINTERP_NORMAL = 0, /* Interpreter is running normally. */
|
JSINTERP_NORMAL = 0, /* interpreter is running normally */
|
||||||
JSINTERP_RECORD = 1, /* interpreter has been started to record/run traces */
|
JSINTERP_RECORD = 1, /* interpreter has been started to record/run traces */
|
||||||
JSINTERP_SAFEPOINT = 2, /* interpreter should leave on a method JIT safe point */
|
JSINTERP_SAFEPOINT = 2, /* interpreter should leave on a method JIT safe point */
|
||||||
JSINTERP_PROFILE = 3 /* interpreter should profile a loop */
|
JSINTERP_PROFILE = 3 /* interpreter should profile a loop */
|
||||||
|
@ -76,8 +76,8 @@ enum JSFrameFlags
|
||||||
JSFRAME_DUMMY = 0x4, /* frame pushed for bookkeeping */
|
JSFRAME_DUMMY = 0x4, /* frame pushed for bookkeeping */
|
||||||
|
|
||||||
/* Frame subtypes */
|
/* Frame subtypes */
|
||||||
JSFRAME_EVAL = 0x8, /* frame pushed by js::Execute */
|
JSFRAME_EVAL = 0x8, /* frame pushed for eval() or debugger eval */
|
||||||
JSFRAME_DEBUGGER = 0x10, /* frame pushed by JS_EvaluateInStackFrame */
|
JSFRAME_DEBUGGER = 0x10, /* frame pushed for debugger eval */
|
||||||
JSFRAME_GENERATOR = 0x20, /* frame is associated with a generator */
|
JSFRAME_GENERATOR = 0x20, /* frame is associated with a generator */
|
||||||
JSFRAME_FLOATING_GENERATOR = 0x40, /* frame is is in generator obj, not on stack */
|
JSFRAME_FLOATING_GENERATOR = 0x40, /* frame is is in generator obj, not on stack */
|
||||||
JSFRAME_CONSTRUCTING = 0x80, /* frame is for a constructor invocation */
|
JSFRAME_CONSTRUCTING = 0x80, /* frame is for a constructor invocation */
|
||||||
|
|
|
@ -165,7 +165,7 @@ NewKeyValuePair(JSContext *cx, jsid id, const Value &val, Value *rval)
|
||||||
Value vec[2] = { IdToValue(id), val };
|
Value vec[2] = { IdToValue(id), val };
|
||||||
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec);
|
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec);
|
||||||
|
|
||||||
JSObject *aobj = js_NewArrayObject(cx, 2, vec);
|
JSObject *aobj = NewDenseCopiedArray(cx, 2, vec);
|
||||||
if (!aobj)
|
if (!aobj)
|
||||||
return false;
|
return false;
|
||||||
rval->setObject(*aobj);
|
rval->setObject(*aobj);
|
||||||
|
@ -615,6 +615,14 @@ EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVe
|
||||||
|
|
||||||
typedef Vector<uint32, 8> ShapeVector;
|
typedef Vector<uint32, 8> ShapeVector;
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
UpdateNativeIterator(NativeIterator *ni, JSObject *obj)
|
||||||
|
{
|
||||||
|
// Update the object for which the native iterator is associated, so
|
||||||
|
// SuppressDeletedPropertyHelper will recognize the iterator as a match.
|
||||||
|
ni->obj = obj;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
||||||
{
|
{
|
||||||
|
@ -654,6 +662,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
||||||
proto->shape() == lastni->shapes_array[1] &&
|
proto->shape() == lastni->shapes_array[1] &&
|
||||||
!proto->getProto()) {
|
!proto->getProto()) {
|
||||||
vp->setObject(*last);
|
vp->setObject(*last);
|
||||||
|
UpdateNativeIterator(lastni, obj);
|
||||||
RegisterEnumerator(cx, last, lastni);
|
RegisterEnumerator(cx, last, lastni);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -691,6 +700,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
||||||
Compare(ni->shapes_array, shapes.begin(), ni->shapes_length)) {
|
Compare(ni->shapes_array, shapes.begin(), ni->shapes_length)) {
|
||||||
vp->setObject(*iterobj);
|
vp->setObject(*iterobj);
|
||||||
|
|
||||||
|
UpdateNativeIterator(ni, obj);
|
||||||
RegisterEnumerator(cx, iterobj, ni);
|
RegisterEnumerator(cx, iterobj, ni);
|
||||||
if (shapes.length() == 2)
|
if (shapes.length() == 2)
|
||||||
JS_THREAD_DATA(cx)->lastNativeIterator = iterobj;
|
JS_THREAD_DATA(cx)->lastNativeIterator = iterobj;
|
||||||
|
@ -967,6 +977,7 @@ public:
|
||||||
bool
|
bool
|
||||||
js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id)
|
js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id)
|
||||||
{
|
{
|
||||||
|
id = js_CheckForStringIndex(id);
|
||||||
return SuppressDeletedPropertyHelper(cx, obj, SingleIdPredicate(id));
|
return SuppressDeletedPropertyHelper(cx, obj, SingleIdPredicate(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1055,7 +1055,7 @@ EvalCacheLookup(JSContext *cx, JSString *str, JSStackFrame *caller, uintN static
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
||||||
if (objarray->length == 1) {
|
if (objarray->length == 1) {
|
||||||
if (script->regexpsOffset != 0) {
|
if (JSScript::isValidOffset(script->regexpsOffset)) {
|
||||||
objarray = script->regexps();
|
objarray = script->regexps();
|
||||||
i = 0;
|
i = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1806,7 +1806,7 @@ obj_keys(JSContext *cx, uintN argc, Value *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT(props.length() <= UINT32_MAX);
|
JS_ASSERT(props.length() <= UINT32_MAX);
|
||||||
JSObject *aobj = js_NewArrayObject(cx, jsuint(vals.length()), vals.begin());
|
JSObject *aobj = NewDenseCopiedArray(cx, jsuint(vals.length()), vals.begin());
|
||||||
if (!aobj)
|
if (!aobj)
|
||||||
return false;
|
return false;
|
||||||
vp->setObject(*aobj);
|
vp->setObject(*aobj);
|
||||||
|
@ -2516,7 +2516,7 @@ obj_getOwnPropertyNames(JSContext *cx, uintN argc, Value *vp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *aobj = js_NewArrayObject(cx, vals.length(), vals.begin());
|
JSObject *aobj = NewDenseCopiedArray(cx, vals.length(), vals.begin());
|
||||||
if (!aobj)
|
if (!aobj)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -3538,9 +3538,9 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp)
|
||||||
if (xdr->mode == JSXDR_ENCODE) {
|
if (xdr->mode == JSXDR_ENCODE) {
|
||||||
obj = *objp;
|
obj = *objp;
|
||||||
parent = obj->getParent();
|
parent = obj->getParent();
|
||||||
parentId = (xdr->script->objectsOffset == 0)
|
parentId = JSScript::isValidOffset(xdr->script->objectsOffset)
|
||||||
? NO_PARENT_INDEX
|
? FindObjectIndex(xdr->script->objects(), parent)
|
||||||
: FindObjectIndex(xdr->script->objects(), parent);
|
: NO_PARENT_INDEX;
|
||||||
depth = (uint16)OBJ_BLOCK_DEPTH(cx, obj);
|
depth = (uint16)OBJ_BLOCK_DEPTH(cx, obj);
|
||||||
count = (uint16)OBJ_BLOCK_COUNT(cx, obj);
|
count = (uint16)OBJ_BLOCK_COUNT(cx, obj);
|
||||||
depthAndCount = (uint32)(depth << 16) | count;
|
depthAndCount = (uint32)(depth << 16) | count;
|
||||||
|
@ -3835,10 +3835,10 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
|
||||||
* Pre-brand the prototype and constructor if they have built-in methods.
|
* Pre-brand the prototype and constructor if they have built-in methods.
|
||||||
* This avoids extra shape guard branch exits in the tracejitted code.
|
* This avoids extra shape guard branch exits in the tracejitted code.
|
||||||
*/
|
*/
|
||||||
if (fs && !proto->brand(cx))
|
if (fs)
|
||||||
goto bad;
|
proto->brand(cx);
|
||||||
if (ctor != proto && static_fs && !ctor->brand(cx))
|
if (ctor != proto && static_fs)
|
||||||
goto bad;
|
ctor->brand(cx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure proto's emptyShape is available to be shared by objects of
|
* Make sure proto's emptyShape is available to be shared by objects of
|
||||||
|
@ -5515,7 +5515,6 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JS_ASSERT(IsFunctionObject(*vp));
|
JS_ASSERT(IsFunctionObject(*vp));
|
||||||
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
|
|
||||||
|
|
||||||
JSObject *funobj = &vp->toObject();
|
JSObject *funobj = &vp->toObject();
|
||||||
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
||||||
|
|
|
@ -337,16 +337,19 @@ struct JSObject : js::gc::Cell {
|
||||||
inline bool nativeContains(const js::Shape &shape);
|
inline bool nativeContains(const js::Shape &shape);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
DELEGATE = 0x01,
|
DELEGATE = 0x01,
|
||||||
SYSTEM = 0x02,
|
SYSTEM = 0x02,
|
||||||
NOT_EXTENSIBLE = 0x04,
|
NOT_EXTENSIBLE = 0x04,
|
||||||
BRANDED = 0x08,
|
BRANDED = 0x08,
|
||||||
GENERIC = 0x10,
|
GENERIC = 0x10,
|
||||||
METHOD_BARRIER = 0x20,
|
METHOD_BARRIER = 0x20,
|
||||||
INDEXED = 0x40,
|
INDEXED = 0x40,
|
||||||
OWN_SHAPE = 0x80,
|
OWN_SHAPE = 0x80,
|
||||||
BOUND_FUNCTION = 0x100,
|
BOUND_FUNCTION = 0x100,
|
||||||
HAS_EQUALITY = 0x200
|
HAS_EQUALITY = 0x200,
|
||||||
|
METHOD_THRASH_COUNT_MASK = 0xc00,
|
||||||
|
METHOD_THRASH_COUNT_SHIFT = 10,
|
||||||
|
METHOD_THRASH_COUNT_MAX = METHOD_THRASH_COUNT_MASK >> METHOD_THRASH_COUNT_SHIFT
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -423,12 +426,26 @@ struct JSObject : js::gc::Cell {
|
||||||
*/
|
*/
|
||||||
bool branded() { return !!(flags & BRANDED); }
|
bool branded() { return !!(flags & BRANDED); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NB: these return false on shape overflow but do not report any error.
|
||||||
|
* Callers who depend on shape guarantees should therefore bail off trace,
|
||||||
|
* e.g., on false returns.
|
||||||
|
*/
|
||||||
bool brand(JSContext *cx);
|
bool brand(JSContext *cx);
|
||||||
bool unbrand(JSContext *cx);
|
bool unbrand(JSContext *cx);
|
||||||
|
|
||||||
bool generic() { return !!(flags & GENERIC); }
|
bool generic() { return !!(flags & GENERIC); }
|
||||||
void setGeneric() { flags |= GENERIC; }
|
void setGeneric() { flags |= GENERIC; }
|
||||||
|
|
||||||
|
uintN getMethodThrashCount() const {
|
||||||
|
return (flags & METHOD_THRASH_COUNT_MASK) >> METHOD_THRASH_COUNT_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMethodThrashCount(uintN count) {
|
||||||
|
JS_ASSERT(count <= METHOD_THRASH_COUNT_MAX);
|
||||||
|
flags = (flags & ~METHOD_THRASH_COUNT_MASK) | (count << METHOD_THRASH_COUNT_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
bool hasSpecialEquality() const { return !!(flags & HAS_EQUALITY); }
|
bool hasSpecialEquality() const { return !!(flags & HAS_EQUALITY); }
|
||||||
void assertSpecialEqualitySynced() const {
|
void assertSpecialEqualitySynced() const {
|
||||||
JS_ASSERT(!!clasp->ext.equality == hasSpecialEquality());
|
JS_ASSERT(!!clasp->ext.equality == hasSpecialEquality());
|
||||||
|
|
|
@ -105,8 +105,13 @@ inline bool
|
||||||
JSObject::unbrand(JSContext *cx)
|
JSObject::unbrand(JSContext *cx)
|
||||||
{
|
{
|
||||||
JS_ASSERT(isNative());
|
JS_ASSERT(isNative());
|
||||||
if (!branded())
|
if (branded()) {
|
||||||
setGeneric();
|
generateOwnShape(cx);
|
||||||
|
if (js_IsPropertyCacheDisabled(cx)) // check for rt->shapeGen overflow
|
||||||
|
return false;
|
||||||
|
flags &= ~BRANDED;
|
||||||
|
}
|
||||||
|
setGeneric();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,14 +194,12 @@ ChangesMethodValue(const js::Value &prev, const js::Value &v)
|
||||||
inline bool
|
inline bool
|
||||||
JSObject::methodWriteBarrier(JSContext *cx, const js::Shape &shape, const js::Value &v)
|
JSObject::methodWriteBarrier(JSContext *cx, const js::Shape &shape, const js::Value &v)
|
||||||
{
|
{
|
||||||
if (flags & (BRANDED | METHOD_BARRIER)) {
|
if (brandedOrHasMethodBarrier() && shape.slot != SHAPE_INVALID_SLOT) {
|
||||||
if (shape.slot != SHAPE_INVALID_SLOT) {
|
const js::Value &prev = nativeGetSlot(shape.slot);
|
||||||
const js::Value &prev = nativeGetSlot(shape.slot);
|
|
||||||
|
|
||||||
if (ChangesMethodValue(prev, v)) {
|
if (ChangesMethodValue(prev, v)) {
|
||||||
JS_FUNCTION_METER(cx, mwritebarrier);
|
JS_FUNCTION_METER(cx, mwritebarrier);
|
||||||
return methodShapeChange(cx, shape);
|
return methodShapeChange(cx, shape);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -205,7 +208,7 @@ JSObject::methodWriteBarrier(JSContext *cx, const js::Shape &shape, const js::Va
|
||||||
inline bool
|
inline bool
|
||||||
JSObject::methodWriteBarrier(JSContext *cx, uint32 slot, const js::Value &v)
|
JSObject::methodWriteBarrier(JSContext *cx, uint32 slot, const js::Value &v)
|
||||||
{
|
{
|
||||||
if (flags & (BRANDED | METHOD_BARRIER)) {
|
if (brandedOrHasMethodBarrier()) {
|
||||||
const js::Value &prev = nativeGetSlot(slot);
|
const js::Value &prev = nativeGetSlot(slot);
|
||||||
|
|
||||||
if (ChangesMethodValue(prev, v)) {
|
if (ChangesMethodValue(prev, v)) {
|
||||||
|
@ -931,6 +934,18 @@ namespace WithProto {
|
||||||
* Note that as a template, there will be lots of instantiations, which means
|
* Note that as a template, there will be lots of instantiations, which means
|
||||||
* the internals will be specialized based on the template parameters.
|
* the internals will be specialized based on the template parameters.
|
||||||
*/
|
*/
|
||||||
|
static JS_ALWAYS_INLINE bool
|
||||||
|
FindProto(JSContext *cx, js::Class *clasp, JSObject *parent, JSObject ** proto)
|
||||||
|
{
|
||||||
|
JSProtoKey protoKey = GetClassProtoKey(clasp);
|
||||||
|
if (!js_GetClassPrototype(cx, parent, protoKey, proto, clasp))
|
||||||
|
return false;
|
||||||
|
if (!(*proto) && !js_GetClassPrototype(cx, parent, JSProto_Object, proto))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
template <bool withProto, bool isFunction>
|
template <bool withProto, bool isFunction>
|
||||||
|
@ -940,11 +955,8 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
|
||||||
{
|
{
|
||||||
/* Bootstrap the ur-object, and make it the default prototype object. */
|
/* Bootstrap the ur-object, and make it the default prototype object. */
|
||||||
if (withProto == WithProto::Class && !proto) {
|
if (withProto == WithProto::Class && !proto) {
|
||||||
JSProtoKey protoKey = GetClassProtoKey(clasp);
|
if (!FindProto (cx, clasp, parent, &proto))
|
||||||
if (!js_GetClassPrototype(cx, parent, protoKey, &proto, clasp))
|
return NULL;
|
||||||
return NULL;
|
|
||||||
if (!proto && !js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1025,13 +1037,6 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
|
||||||
return NewObject<withProto>(cx, clasp, proto, parent, kind);
|
return NewObject<withProto>(cx, clasp, proto, parent, kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Creates a new array with a zero length and the given finalize kind. */
|
|
||||||
static inline JSObject *
|
|
||||||
NewArrayWithKind(JSContext* cx, gc::FinalizeKind kind)
|
|
||||||
{
|
|
||||||
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As for js_GetGCObjectKind, where numSlots is a guess at the final size of
|
* As for js_GetGCObjectKind, where numSlots is a guess at the final size of
|
||||||
* the object, zero if the final size is unknown.
|
* the object, zero if the final size is unknown.
|
||||||
|
|
|
@ -680,7 +680,7 @@ js_BeginJSONParse(JSContext *cx, Value *rootVal, bool suppressErrors /*= false*/
|
||||||
if (!cx)
|
if (!cx)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
JSObject *arr = js_NewArrayObject(cx, 0, NULL);
|
JSObject *arr = NewDenseEmptyArray(cx);
|
||||||
if (!arr)
|
if (!arr)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -856,7 +856,7 @@ static JSBool
|
||||||
OpenArray(JSContext *cx, JSONParser *jp)
|
OpenArray(JSContext *cx, JSONParser *jp)
|
||||||
{
|
{
|
||||||
// Add an array to an existing array or object
|
// Add an array to an existing array or object
|
||||||
JSObject *arr = js_NewArrayObject(cx, 0, NULL);
|
JSObject *arr = NewDenseEmptyArray(cx);
|
||||||
if (!arr)
|
if (!arr)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|
|
@ -1337,7 +1337,7 @@ GetLocal(SprintStack *ss, jsint i)
|
||||||
* not in a block. In either case, return GetStr(ss, i).
|
* not in a block. In either case, return GetStr(ss, i).
|
||||||
*/
|
*/
|
||||||
JSScript *script = ss->printer->script;
|
JSScript *script = ss->printer->script;
|
||||||
if (script->objectsOffset == 0)
|
if (!JSScript::isValidOffset(script->objectsOffset))
|
||||||
return GetStr(ss, i);
|
return GetStr(ss, i);
|
||||||
|
|
||||||
for (jsatomid j = 0, n = script->objects()->length; j != n; j++) {
|
for (jsatomid j = 0, n = script->objects()->length; j != n; j++) {
|
||||||
|
@ -2890,7 +2890,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||||
JS_ASSERT(fp->prev()->fun() == jp->fun);
|
JS_ASSERT(fp->prev()->fun() == jp->fun);
|
||||||
JS_ASSERT(FUN_INTERPRETED(jp->fun));
|
JS_ASSERT(FUN_INTERPRETED(jp->fun));
|
||||||
JS_ASSERT(jp->script != jp->fun->u.i.script);
|
JS_ASSERT(jp->script != jp->fun->u.i.script);
|
||||||
JS_ASSERT(jp->script->upvarsOffset != 0);
|
JS_ASSERT(JSScript::isValidOffset(jp->script->upvarsOffset));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
uva = jp->script->upvars();
|
uva = jp->script->upvars();
|
||||||
|
|
|
@ -640,9 +640,9 @@ NameNode::initCommon(JSTreeContext *tc)
|
||||||
{
|
{
|
||||||
pn_expr = NULL;
|
pn_expr = NULL;
|
||||||
pn_cookie.makeFree();
|
pn_cookie.makeFree();
|
||||||
pn_dflags = tc->atTopLevel() ? PND_TOPLEVEL : 0;
|
pn_dflags = (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)
|
||||||
if (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)
|
? PND_BLOCKCHILD
|
||||||
pn_dflags |= PND_BLOCKCHILD;
|
: 0;
|
||||||
pn_blockid = tc->blockid();
|
pn_blockid = tc->blockid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,6 +865,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inDirectivePrologue = true;
|
inDirectivePrologue = true;
|
||||||
|
tokenStream.setOctalCharacterEscape(false);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
tt = tokenStream.peekToken(TSF_OPERAND);
|
tt = tokenStream.peekToken(TSF_OPERAND);
|
||||||
if (tt <= TOK_EOF) {
|
if (tt <= TOK_EOF) {
|
||||||
|
@ -879,8 +880,8 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
|
||||||
goto out;
|
goto out;
|
||||||
JS_ASSERT(!cg.blockNode);
|
JS_ASSERT(!cg.blockNode);
|
||||||
|
|
||||||
if (inDirectivePrologue)
|
if (inDirectivePrologue && !parser.recognizeDirectivePrologue(pn, &inDirectivePrologue))
|
||||||
inDirectivePrologue = parser.recognizeDirectivePrologue(pn);
|
goto out;
|
||||||
|
|
||||||
if (!js_FoldConstants(cx, pn, &cg))
|
if (!js_FoldConstants(cx, pn, &cg))
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -978,7 +979,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
|
||||||
JS_DumpArenaStats(stdout);
|
JS_DumpArenaStats(stdout);
|
||||||
#endif
|
#endif
|
||||||
script = JSScript::NewScriptFromCG(cx, &cg);
|
script = JSScript::NewScriptFromCG(cx, &cg);
|
||||||
if (script && funbox && script != script->emptyScript())
|
if (script && funbox)
|
||||||
script->savedCallerFun = true;
|
script->savedCallerFun = true;
|
||||||
|
|
||||||
#ifdef JS_SCOPE_DEPTH_METER
|
#ifdef JS_SCOPE_DEPTH_METER
|
||||||
|
@ -1069,7 +1070,7 @@ Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *scrip
|
||||||
JSScript *inner = worklist.back();
|
JSScript *inner = worklist.back();
|
||||||
worklist.popBack();
|
worklist.popBack();
|
||||||
|
|
||||||
if (inner->objectsOffset != 0) {
|
if (JSScript::isValidOffset(inner->objectsOffset)) {
|
||||||
JSObjectArray *arr = inner->objects();
|
JSObjectArray *arr = inner->objects();
|
||||||
for (size_t i = 0; i < arr->length; i++) {
|
for (size_t i = 0; i < arr->length; i++) {
|
||||||
JSObject *obj = arr->vector[i];
|
JSObject *obj = arr->vector[i];
|
||||||
|
@ -1078,14 +1079,16 @@ Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *scrip
|
||||||
JSFunction *fun = obj->getFunctionPrivate();
|
JSFunction *fun = obj->getFunctionPrivate();
|
||||||
JS_ASSERT(fun->isInterpreted());
|
JS_ASSERT(fun->isInterpreted());
|
||||||
JSScript *inner = fun->u.i.script;
|
JSScript *inner = fun->u.i.script;
|
||||||
if (inner->globalsOffset == 0 && inner->objectsOffset == 0)
|
if (!JSScript::isValidOffset(inner->globalsOffset) &&
|
||||||
|
!JSScript::isValidOffset(inner->objectsOffset)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if (!worklist.append(inner))
|
if (!worklist.append(inner))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inner->globalsOffset == 0)
|
if (!JSScript::isValidOffset(inner->globalsOffset))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
GlobalSlotArray *globalUses = inner->globals();
|
GlobalSlotArray *globalUses = inner->globals();
|
||||||
|
@ -1479,6 +1482,8 @@ Define(JSParseNode *pn, JSAtom *atom, JSTreeContext *tc, bool let = false)
|
||||||
ALE_SET_DEFN(ale, pn);
|
ALE_SET_DEFN(ale, pn);
|
||||||
pn->pn_defn = true;
|
pn->pn_defn = true;
|
||||||
pn->pn_dflags &= ~PND_PLACEHOLDER;
|
pn->pn_dflags &= ~PND_PLACEHOLDER;
|
||||||
|
if (!tc->parent)
|
||||||
|
pn->pn_dflags |= PND_TOPLEVEL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1560,7 +1565,6 @@ MakeDefIntoUse(JSDefinition *dn, JSParseNode *pn, JSAtom *atom, JSTreeContext *t
|
||||||
|
|
||||||
dn->pn_op = (js_CodeSpec[dn->pn_op].format & JOF_SET) ? JSOP_SETNAME : JSOP_NAME;
|
dn->pn_op = (js_CodeSpec[dn->pn_op].format & JOF_SET) ? JSOP_SETNAME : JSOP_NAME;
|
||||||
} else if (dn->kind() == JSDefinition::FUNCTION) {
|
} else if (dn->kind() == JSDefinition::FUNCTION) {
|
||||||
JS_ASSERT(dn->isTopLevel());
|
|
||||||
JS_ASSERT(dn->pn_op == JSOP_NOP);
|
JS_ASSERT(dn->pn_op == JSOP_NOP);
|
||||||
dn->pn_type = TOK_NAME;
|
dn->pn_type = TOK_NAME;
|
||||||
dn->pn_arity = PN_NAME;
|
dn->pn_arity = PN_NAME;
|
||||||
|
@ -2543,8 +2547,6 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, JSAtom *funAtom = NULL,
|
||||||
funbox->tcflags |= funtc->flags & (TCF_FUN_FLAGS | TCF_COMPILE_N_GO | TCF_RETURN_EXPR);
|
funbox->tcflags |= funtc->flags & (TCF_FUN_FLAGS | TCF_COMPILE_N_GO | TCF_RETURN_EXPR);
|
||||||
|
|
||||||
fn->pn_dflags |= PND_INITIALIZED;
|
fn->pn_dflags |= PND_INITIALIZED;
|
||||||
JS_ASSERT_IF(tc->atTopLevel() && lambda == 0 && funAtom,
|
|
||||||
fn->pn_dflags & PND_TOPLEVEL);
|
|
||||||
if (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)
|
if (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)
|
||||||
fn->pn_dflags |= PND_BLOCKCHILD;
|
fn->pn_dflags |= PND_BLOCKCHILD;
|
||||||
|
|
||||||
|
@ -2864,12 +2866,12 @@ Parser::functionDef(JSAtom *funAtom, FunctionType type, uintN lambda)
|
||||||
* If a lambda, give up on JSOP_{GET,CALL}UPVAR usage unless this function
|
* If a lambda, give up on JSOP_{GET,CALL}UPVAR usage unless this function
|
||||||
* is immediately applied (we clear PND_FUNARG if so -- see memberExpr).
|
* is immediately applied (we clear PND_FUNARG if so -- see memberExpr).
|
||||||
*
|
*
|
||||||
* Also treat function sub-statements (non-lambda, non-top-level functions)
|
* Treat function sub-statements (non-lambda, non-body-level functions) as
|
||||||
* as escaping funargs, since we can't statically analyze their definitions
|
* escaping funargs, since we can't statically analyze their definitions
|
||||||
* and uses.
|
* and uses.
|
||||||
*/
|
*/
|
||||||
bool topLevel = tc->atTopLevel();
|
bool bodyLevel = tc->atBodyLevel();
|
||||||
pn->pn_dflags = (lambda || !topLevel) ? PND_FUNARG : 0;
|
pn->pn_dflags = (lambda || !bodyLevel) ? PND_FUNARG : 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record names for function statements in tc->decls so we know when to
|
* Record names for function statements in tc->decls so we know when to
|
||||||
|
@ -2897,7 +2899,7 @@ Parser::functionDef(JSAtom *funAtom, FunctionType type, uintN lambda)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (topLevel) {
|
if (bodyLevel) {
|
||||||
ALE_SET_DEFN(ale, pn);
|
ALE_SET_DEFN(ale, pn);
|
||||||
pn->pn_defn = true;
|
pn->pn_defn = true;
|
||||||
pn->dn_uses = dn; /* dn->dn_uses is now pn_link */
|
pn->dn_uses = dn; /* dn->dn_uses is now pn_link */
|
||||||
|
@ -2905,7 +2907,7 @@ Parser::functionDef(JSAtom *funAtom, FunctionType type, uintN lambda)
|
||||||
if (!MakeDefIntoUse(dn, pn, funAtom, tc))
|
if (!MakeDefIntoUse(dn, pn, funAtom, tc))
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else if (topLevel) {
|
} else if (bodyLevel) {
|
||||||
/*
|
/*
|
||||||
* If this function was used before it was defined, claim the
|
* If this function was used before it was defined, claim the
|
||||||
* pre-created definition node for this function that primaryExpr
|
* pre-created definition node for this function that primaryExpr
|
||||||
|
@ -2934,43 +2936,36 @@ Parser::functionDef(JSAtom *funAtom, FunctionType type, uintN lambda)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A function nested at top level inside another's body needs only a
|
* A function directly inside another's body needs only a local
|
||||||
* local variable to bind its name to its value, and not an activation
|
* variable to bind its name to its value, and not an activation object
|
||||||
* object property (it might also need the activation property, if the
|
* property (it might also need the activation property, if the outer
|
||||||
* outer function contains with statements, e.g., but the stack slot
|
* function contains with statements, e.g., but the stack slot wins
|
||||||
* wins when jsemit.c's BindNameToSlot can optimize a JSOP_NAME into a
|
* when jsemit.cpp's BindNameToSlot can optimize a JSOP_NAME into a
|
||||||
* JSOP_GETLOCAL bytecode).
|
* JSOP_GETLOCAL bytecode).
|
||||||
*/
|
*/
|
||||||
if (topLevel) {
|
if (bodyLevel && tc->inFunction()) {
|
||||||
pn->pn_dflags |= PND_TOPLEVEL;
|
/*
|
||||||
|
* Define a local in the outer function so that BindNameToSlot
|
||||||
|
* can properly optimize accesses. Note that we need a local
|
||||||
|
* variable, not an argument, for the function statement. Thus
|
||||||
|
* we add a variable even if a parameter with the given name
|
||||||
|
* already exists.
|
||||||
|
*/
|
||||||
|
uintN index;
|
||||||
|
switch (tc->fun()->lookupLocal(context, funAtom, &index)) {
|
||||||
|
case JSLOCAL_NONE:
|
||||||
|
case JSLOCAL_ARG:
|
||||||
|
index = tc->fun()->u.i.nvars;
|
||||||
|
if (!tc->fun()->addLocal(context, funAtom, JSLOCAL_VAR))
|
||||||
|
return NULL;
|
||||||
|
/* FALL THROUGH */
|
||||||
|
|
||||||
if (tc->inFunction()) {
|
case JSLOCAL_VAR:
|
||||||
JSLocalKind localKind;
|
pn->pn_cookie.set(tc->staticLevel, index);
|
||||||
uintN index;
|
pn->pn_dflags |= PND_BOUND;
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
default:;
|
||||||
* Define a local in the outer function so that BindNameToSlot
|
|
||||||
* can properly optimize accesses. Note that we need a local
|
|
||||||
* variable, not an argument, for the function statement. Thus
|
|
||||||
* we add a variable even if a parameter with the given name
|
|
||||||
* already exists.
|
|
||||||
*/
|
|
||||||
localKind = tc->fun()->lookupLocal(context, funAtom, &index);
|
|
||||||
switch (localKind) {
|
|
||||||
case JSLOCAL_NONE:
|
|
||||||
case JSLOCAL_ARG:
|
|
||||||
index = tc->fun()->u.i.nvars;
|
|
||||||
if (!tc->fun()->addLocal(context, funAtom, JSLOCAL_VAR))
|
|
||||||
return NULL;
|
|
||||||
/* FALL THROUGH */
|
|
||||||
|
|
||||||
case JSLOCAL_VAR:
|
|
||||||
pn->pn_cookie.set(tc->staticLevel, index);
|
|
||||||
pn->pn_dflags |= PND_BOUND;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3104,11 +3099,12 @@ Parser::functionDef(JSAtom *funAtom, FunctionType type, uintN lambda)
|
||||||
outertc->flags |= TCF_FUN_HEAVYWEIGHT;
|
outertc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* If this function is a named statement function not at top-level
|
* If this function is not at body level of a program or function (i.e.
|
||||||
* (i.e. not a top-level function definiton or expression), then our
|
* it is a function statement that is not a direct child of a program
|
||||||
* enclosing function, if any, must be heavyweight.
|
* or function), then our enclosing function, if any, must be
|
||||||
|
* heavyweight.
|
||||||
*/
|
*/
|
||||||
if (!topLevel && lambda == 0 && funAtom)
|
if (!bodyLevel && lambda == 0 && funAtom)
|
||||||
outertc->flags |= TCF_FUN_HEAVYWEIGHT;
|
outertc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3134,7 +3130,7 @@ Parser::functionDef(JSAtom *funAtom, FunctionType type, uintN lambda)
|
||||||
result->pn_pos = pn->pn_pos;
|
result->pn_pos = pn->pn_pos;
|
||||||
result->pn_kid = pn;
|
result->pn_kid = pn;
|
||||||
op = JSOP_LAMBDA;
|
op = JSOP_LAMBDA;
|
||||||
} else if (!topLevel) {
|
} else if (!bodyLevel) {
|
||||||
/*
|
/*
|
||||||
* ECMA ed. 3 extension: a function expression statement not at the
|
* ECMA ed. 3 extension: a function expression statement not at the
|
||||||
* top level, e.g., in a compound statement such as the "then" part
|
* top level, e.g., in a compound statement such as the "then" part
|
||||||
|
@ -3156,10 +3152,9 @@ Parser::functionDef(JSAtom *funAtom, FunctionType type, uintN lambda)
|
||||||
pn->pn_body = body;
|
pn->pn_body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!outertc->inFunction() && topLevel && funAtom && !lambda &&
|
if (!outertc->inFunction() && bodyLevel && funAtom && !lambda && outertc->compiling()) {
|
||||||
outertc->compiling()) {
|
|
||||||
JS_ASSERT(pn->pn_cookie.isFree());
|
JS_ASSERT(pn->pn_cookie.isFree());
|
||||||
if (!DefineGlobal(pn, (JSCodeGenerator *)outertc, funAtom))
|
if (!DefineGlobal(pn, outertc->asCodeGenerator(), funAtom))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3225,13 +3220,33 @@ Parser::functionExpr()
|
||||||
* if it can't possibly be a directive, now or in the future.
|
* if it can't possibly be a directive, now or in the future.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
Parser::recognizeDirectivePrologue(JSParseNode *pn)
|
Parser::recognizeDirectivePrologue(JSParseNode *pn, bool *isDirectivePrologueMember)
|
||||||
{
|
{
|
||||||
if (!pn->isDirectivePrologueMember())
|
*isDirectivePrologueMember = pn->isDirectivePrologueMember();
|
||||||
return false;
|
if (!*isDirectivePrologueMember)
|
||||||
|
return true;
|
||||||
if (pn->isDirective()) {
|
if (pn->isDirective()) {
|
||||||
JSAtom *directive = pn->pn_kid->pn_atom;
|
JSAtom *directive = pn->pn_kid->pn_atom;
|
||||||
if (directive == context->runtime->atomState.useStrictAtom) {
|
if (directive == context->runtime->atomState.useStrictAtom) {
|
||||||
|
/*
|
||||||
|
* Unfortunately, Directive Prologue members in general may contain
|
||||||
|
* escapes, even while "use strict" directives may not. Therefore
|
||||||
|
* we must check whether an octal character escape has been seen in
|
||||||
|
* any previous directives whenever we encounter a "use strict"
|
||||||
|
* directive, so that the octal escape is properly treated as a
|
||||||
|
* syntax error. An example of this case:
|
||||||
|
*
|
||||||
|
* function error()
|
||||||
|
* {
|
||||||
|
* "\145"; // octal escape
|
||||||
|
* "use strict"; // retroactively makes "\145" a syntax error
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
if (tokenStream.hasOctalCharacterEscape()) {
|
||||||
|
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_DEPRECATED_OCTAL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
tc->flags |= TCF_STRICT_MODE_CODE;
|
tc->flags |= TCF_STRICT_MODE_CODE;
|
||||||
tokenStream.setStrictMode();
|
tokenStream.setStrictMode();
|
||||||
}
|
}
|
||||||
|
@ -3249,7 +3264,6 @@ Parser::statements()
|
||||||
{
|
{
|
||||||
JSParseNode *pn, *pn2, *saveBlock;
|
JSParseNode *pn, *pn2, *saveBlock;
|
||||||
TokenKind tt;
|
TokenKind tt;
|
||||||
bool inDirectivePrologue = tc->atTopLevel();
|
|
||||||
|
|
||||||
JS_CHECK_RECURSION(context, return NULL);
|
JS_CHECK_RECURSION(context, return NULL);
|
||||||
|
|
||||||
|
@ -3262,6 +3276,8 @@ Parser::statements()
|
||||||
saveBlock = tc->blockNode;
|
saveBlock = tc->blockNode;
|
||||||
tc->blockNode = pn;
|
tc->blockNode = pn;
|
||||||
|
|
||||||
|
bool inDirectivePrologue = tc->atBodyLevel();
|
||||||
|
tokenStream.setOctalCharacterEscape(false);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
tt = tokenStream.peekToken(TSF_OPERAND);
|
tt = tokenStream.peekToken(TSF_OPERAND);
|
||||||
if (tt <= TOK_EOF || tt == TOK_RC) {
|
if (tt <= TOK_EOF || tt == TOK_RC) {
|
||||||
|
@ -3279,20 +3295,20 @@ Parser::statements()
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inDirectivePrologue)
|
if (inDirectivePrologue && !recognizeDirectivePrologue(pn2, &inDirectivePrologue))
|
||||||
inDirectivePrologue = recognizeDirectivePrologue(pn2);
|
return NULL;
|
||||||
|
|
||||||
if (pn2->pn_type == TOK_FUNCTION) {
|
if (pn2->pn_type == TOK_FUNCTION) {
|
||||||
/*
|
/*
|
||||||
* PNX_FUNCDEFS notifies the emitter that the block contains top-
|
* PNX_FUNCDEFS notifies the emitter that the block contains body-
|
||||||
* level function definitions that should be processed before the
|
* level function definitions that should be processed before the
|
||||||
* rest of nodes.
|
* rest of nodes.
|
||||||
*
|
*
|
||||||
* TCF_HAS_FUNCTION_STMT is for the TOK_LC case in Statement. It
|
* TCF_HAS_FUNCTION_STMT is for the TOK_LC case in Statement. It
|
||||||
* is relevant only for function definitions not at top-level,
|
* is relevant only for function definitions not at body-level,
|
||||||
* which we call function statements.
|
* which we call function statements.
|
||||||
*/
|
*/
|
||||||
if (tc->atTopLevel())
|
if (tc->atBodyLevel())
|
||||||
pn->pn_xflags |= PNX_FUNCDEFS;
|
pn->pn_xflags |= PNX_FUNCDEFS;
|
||||||
else
|
else
|
||||||
tc->flags |= TCF_HAS_FUNCTION_STMT;
|
tc->flags |= TCF_HAS_FUNCTION_STMT;
|
||||||
|
@ -3362,10 +3378,10 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||||
jsint n;
|
jsint n;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Top-level 'let' is the same as 'var' currently -- this may change in a
|
* Body-level 'let' is the same as 'var' currently -- this may change in a
|
||||||
* successor standard to ES3.1 that specifies 'let'.
|
* successor standard to ES5 that specifies 'let'.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(!tc->atTopLevel());
|
JS_ASSERT(!tc->atBodyLevel());
|
||||||
|
|
||||||
pn = data->pn;
|
pn = data->pn;
|
||||||
if (!CheckStrictBinding(cx, tc, atom, pn))
|
if (!CheckStrictBinding(cx, tc, atom, pn))
|
||||||
|
@ -3583,7 +3599,7 @@ BindGvar(JSParseNode *pn, JSTreeContext *tc)
|
||||||
if (!tc->compiling() || tc->parser->callerFrame)
|
if (!tc->compiling() || tc->parser->callerFrame)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
JSCodeGenerator *cg = (JSCodeGenerator *) tc;
|
JSCodeGenerator *cg = tc->asCodeGenerator();
|
||||||
|
|
||||||
if (pn->pn_dflags & PND_CONST)
|
if (pn->pn_dflags & PND_CONST)
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -479,7 +479,7 @@ public:
|
||||||
#define PND_CONST 0x02 /* const binding (orthogonal to let) */
|
#define PND_CONST 0x02 /* const binding (orthogonal to let) */
|
||||||
#define PND_INITIALIZED 0x04 /* initialized declaration */
|
#define PND_INITIALIZED 0x04 /* initialized declaration */
|
||||||
#define PND_ASSIGNED 0x08 /* set if ever LHS of assignment */
|
#define PND_ASSIGNED 0x08 /* set if ever LHS of assignment */
|
||||||
#define PND_TOPLEVEL 0x10 /* function at top of body or prog */
|
#define PND_TOPLEVEL 0x10 /* see isTopLevel() below */
|
||||||
#define PND_BLOCKCHILD 0x20 /* use or def is direct block child */
|
#define PND_BLOCKCHILD 0x20 /* use or def is direct block child */
|
||||||
#define PND_GVAR 0x40 /* gvar binding, can't close over
|
#define PND_GVAR 0x40 /* gvar binding, can't close over
|
||||||
because it could be deleted */
|
because it could be deleted */
|
||||||
|
@ -529,7 +529,6 @@ public:
|
||||||
bool isLet() const { return test(PND_LET); }
|
bool isLet() const { return test(PND_LET); }
|
||||||
bool isConst() const { return test(PND_CONST); }
|
bool isConst() const { return test(PND_CONST); }
|
||||||
bool isInitialized() const { return test(PND_INITIALIZED); }
|
bool isInitialized() const { return test(PND_INITIALIZED); }
|
||||||
bool isTopLevel() const { return test(PND_TOPLEVEL); }
|
|
||||||
bool isBlockChild() const { return test(PND_BLOCKCHILD); }
|
bool isBlockChild() const { return test(PND_BLOCKCHILD); }
|
||||||
bool isPlaceholder() const { return test(PND_PLACEHOLDER); }
|
bool isPlaceholder() const { return test(PND_PLACEHOLDER); }
|
||||||
bool isDeoptimized() const { return test(PND_DEOPTIMIZED); }
|
bool isDeoptimized() const { return test(PND_DEOPTIMIZED); }
|
||||||
|
@ -537,6 +536,20 @@ public:
|
||||||
bool isFunArg() const { return test(PND_FUNARG); }
|
bool isFunArg() const { return test(PND_FUNARG); }
|
||||||
bool isClosed() const { return test(PND_CLOSED); }
|
bool isClosed() const { return test(PND_CLOSED); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* True iff this definition creates a top-level binding in the overall
|
||||||
|
* script being compiled -- that is, it affects the whole program's
|
||||||
|
* bindings, not bindings for a specific function (unless this definition
|
||||||
|
* is in the outermost scope in eval code, executed within a function) or
|
||||||
|
* the properties of a specific object (through the with statement).
|
||||||
|
*
|
||||||
|
* NB: Function sub-statements found in overall program code and not nested
|
||||||
|
* within other functions are not currently top level, even though (if
|
||||||
|
* executed) they do create top-level bindings; there is no particular
|
||||||
|
* rationale for this behavior.
|
||||||
|
*/
|
||||||
|
bool isTopLevel() const { return test(PND_TOPLEVEL); }
|
||||||
|
|
||||||
/* Defined below, see after struct JSDefinition. */
|
/* Defined below, see after struct JSDefinition. */
|
||||||
void setFunArg();
|
void setFunArg();
|
||||||
|
|
||||||
|
@ -1118,7 +1131,7 @@ private:
|
||||||
/*
|
/*
|
||||||
* Additional JS parsers.
|
* Additional JS parsers.
|
||||||
*/
|
*/
|
||||||
bool recognizeDirectivePrologue(JSParseNode *pn);
|
bool recognizeDirectivePrologue(JSParseNode *pn, bool *isDirectivePrologueMember);
|
||||||
|
|
||||||
enum FunctionType { GETTER, SETTER, GENERAL };
|
enum FunctionType { GETTER, SETTER, GENERAL };
|
||||||
bool functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSFunction *fun,
|
bool functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSFunction *fun,
|
||||||
|
|
|
@ -335,8 +335,6 @@ GetDerivedTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp)
|
||||||
static bool
|
static bool
|
||||||
Trap(JSContext *cx, JSObject *handler, Value fval, uintN argc, Value* argv, Value *rval)
|
Trap(JSContext *cx, JSObject *handler, Value fval, uintN argc, Value* argv, Value *rval)
|
||||||
{
|
{
|
||||||
JS_CHECK_RECURSION(cx, return false);
|
|
||||||
|
|
||||||
return ExternalInvoke(cx, handler, fval, argc, argv, rval);
|
return ExternalInvoke(cx, handler, fval, argc, argv, rval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,6 +670,7 @@ bool
|
||||||
JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
|
JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
|
||||||
PropertyDescriptor *desc)
|
PropertyDescriptor *desc)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->getPropertyDescriptor(cx, proxy, id, set, desc);
|
return proxy->getProxyHandler()->getPropertyDescriptor(cx, proxy, id, set, desc);
|
||||||
}
|
}
|
||||||
|
@ -679,6 +678,7 @@ JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set
|
||||||
bool
|
bool
|
||||||
JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
|
JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
AutoPropertyDescriptorRooter desc(cx);
|
AutoPropertyDescriptorRooter desc(cx);
|
||||||
return JSProxy::getPropertyDescriptor(cx, proxy, id, set, &desc) &&
|
return JSProxy::getPropertyDescriptor(cx, proxy, id, set, &desc) &&
|
||||||
|
@ -689,6 +689,7 @@ bool
|
||||||
JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
|
JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
|
||||||
PropertyDescriptor *desc)
|
PropertyDescriptor *desc)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->getOwnPropertyDescriptor(cx, proxy, id, set, desc);
|
return proxy->getProxyHandler()->getOwnPropertyDescriptor(cx, proxy, id, set, desc);
|
||||||
}
|
}
|
||||||
|
@ -696,6 +697,7 @@ JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool
|
||||||
bool
|
bool
|
||||||
JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
|
JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
AutoPropertyDescriptorRooter desc(cx);
|
AutoPropertyDescriptorRooter desc(cx);
|
||||||
return JSProxy::getOwnPropertyDescriptor(cx, proxy, id, set, &desc) &&
|
return JSProxy::getOwnPropertyDescriptor(cx, proxy, id, set, &desc) &&
|
||||||
|
@ -705,6 +707,7 @@ JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool
|
||||||
bool
|
bool
|
||||||
JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc)
|
JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->defineProperty(cx, proxy, id, desc);
|
return proxy->getProxyHandler()->defineProperty(cx, proxy, id, desc);
|
||||||
}
|
}
|
||||||
|
@ -712,6 +715,7 @@ JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescrip
|
||||||
bool
|
bool
|
||||||
JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, const Value &v)
|
JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, const Value &v)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
AutoPropertyDescriptorRooter desc(cx);
|
AutoPropertyDescriptorRooter desc(cx);
|
||||||
return ParsePropertyDescriptorObject(cx, proxy, id, v, &desc) &&
|
return ParsePropertyDescriptorObject(cx, proxy, id, v, &desc) &&
|
||||||
|
@ -721,6 +725,7 @@ JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, const Value &v)
|
||||||
bool
|
bool
|
||||||
JSProxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
JSProxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->getOwnPropertyNames(cx, proxy, props);
|
return proxy->getProxyHandler()->getOwnPropertyNames(cx, proxy, props);
|
||||||
}
|
}
|
||||||
|
@ -728,6 +733,7 @@ JSProxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props
|
||||||
bool
|
bool
|
||||||
JSProxy::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
JSProxy::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->delete_(cx, proxy, id, bp);
|
return proxy->getProxyHandler()->delete_(cx, proxy, id, bp);
|
||||||
}
|
}
|
||||||
|
@ -735,6 +741,7 @@ JSProxy::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||||
bool
|
bool
|
||||||
JSProxy::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
JSProxy::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->enumerate(cx, proxy, props);
|
return proxy->getProxyHandler()->enumerate(cx, proxy, props);
|
||||||
}
|
}
|
||||||
|
@ -742,6 +749,7 @@ JSProxy::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
||||||
bool
|
bool
|
||||||
JSProxy::fix(JSContext *cx, JSObject *proxy, Value *vp)
|
JSProxy::fix(JSContext *cx, JSObject *proxy, Value *vp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->fix(cx, proxy, vp);
|
return proxy->getProxyHandler()->fix(cx, proxy, vp);
|
||||||
}
|
}
|
||||||
|
@ -749,6 +757,7 @@ JSProxy::fix(JSContext *cx, JSObject *proxy, Value *vp)
|
||||||
bool
|
bool
|
||||||
JSProxy::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
JSProxy::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->has(cx, proxy, id, bp);
|
return proxy->getProxyHandler()->has(cx, proxy, id, bp);
|
||||||
}
|
}
|
||||||
|
@ -756,6 +765,7 @@ JSProxy::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||||
bool
|
bool
|
||||||
JSProxy::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
JSProxy::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->hasOwn(cx, proxy, id, bp);
|
return proxy->getProxyHandler()->hasOwn(cx, proxy, id, bp);
|
||||||
}
|
}
|
||||||
|
@ -763,6 +773,7 @@ JSProxy::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||||
bool
|
bool
|
||||||
JSProxy::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
|
JSProxy::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->get(cx, proxy, receiver, id, vp);
|
return proxy->getProxyHandler()->get(cx, proxy, receiver, id, vp);
|
||||||
}
|
}
|
||||||
|
@ -770,6 +781,7 @@ JSProxy::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value
|
||||||
bool
|
bool
|
||||||
JSProxy::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
|
JSProxy::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->set(cx, proxy, receiver, id, vp);
|
return proxy->getProxyHandler()->set(cx, proxy, receiver, id, vp);
|
||||||
}
|
}
|
||||||
|
@ -777,6 +789,7 @@ JSProxy::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value
|
||||||
bool
|
bool
|
||||||
JSProxy::enumerateOwn(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
JSProxy::enumerateOwn(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->enumerateOwn(cx, proxy, props);
|
return proxy->getProxyHandler()->enumerateOwn(cx, proxy, props);
|
||||||
}
|
}
|
||||||
|
@ -784,6 +797,7 @@ JSProxy::enumerateOwn(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
||||||
bool
|
bool
|
||||||
JSProxy::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp)
|
JSProxy::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->iterate(cx, proxy, flags, vp);
|
return proxy->getProxyHandler()->iterate(cx, proxy, flags, vp);
|
||||||
}
|
}
|
||||||
|
@ -791,6 +805,7 @@ JSProxy::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp)
|
||||||
bool
|
bool
|
||||||
JSProxy::call(JSContext *cx, JSObject *proxy, uintN argc, Value *vp)
|
JSProxy::call(JSContext *cx, JSObject *proxy, uintN argc, Value *vp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->call(cx, proxy, argc, vp);
|
return proxy->getProxyHandler()->call(cx, proxy, argc, vp);
|
||||||
}
|
}
|
||||||
|
@ -798,6 +813,7 @@ JSProxy::call(JSContext *cx, JSObject *proxy, uintN argc, Value *vp)
|
||||||
bool
|
bool
|
||||||
JSProxy::construct(JSContext *cx, JSObject *proxy, uintN argc, Value *argv, Value *rval)
|
JSProxy::construct(JSContext *cx, JSObject *proxy, uintN argc, Value *argv, Value *rval)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->construct(cx, proxy, argc, argv, rval);
|
return proxy->getProxyHandler()->construct(cx, proxy, argc, argv, rval);
|
||||||
}
|
}
|
||||||
|
@ -805,6 +821,7 @@ JSProxy::construct(JSContext *cx, JSObject *proxy, uintN argc, Value *argv, Valu
|
||||||
bool
|
bool
|
||||||
JSProxy::hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *bp)
|
JSProxy::hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *bp)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->hasInstance(cx, proxy, vp, bp);
|
return proxy->getProxyHandler()->hasInstance(cx, proxy, vp, bp);
|
||||||
}
|
}
|
||||||
|
@ -812,6 +829,8 @@ JSProxy::hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *
|
||||||
JSType
|
JSType
|
||||||
JSProxy::typeOf(JSContext *cx, JSObject *proxy)
|
JSProxy::typeOf(JSContext *cx, JSObject *proxy)
|
||||||
{
|
{
|
||||||
|
// FIXME: API doesn't allow us to report error (bug 618906).
|
||||||
|
JS_CHECK_RECURSION(cx, return JSTYPE_OBJECT);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->typeOf(cx, proxy);
|
return proxy->getProxyHandler()->typeOf(cx, proxy);
|
||||||
}
|
}
|
||||||
|
@ -819,6 +838,7 @@ JSProxy::typeOf(JSContext *cx, JSObject *proxy)
|
||||||
JSString *
|
JSString *
|
||||||
JSProxy::obj_toString(JSContext *cx, JSObject *proxy)
|
JSProxy::obj_toString(JSContext *cx, JSObject *proxy)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return NULL);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->obj_toString(cx, proxy);
|
return proxy->getProxyHandler()->obj_toString(cx, proxy);
|
||||||
}
|
}
|
||||||
|
@ -826,6 +846,7 @@ JSProxy::obj_toString(JSContext *cx, JSObject *proxy)
|
||||||
JSString *
|
JSString *
|
||||||
JSProxy::fun_toString(JSContext *cx, JSObject *proxy, uintN indent)
|
JSProxy::fun_toString(JSContext *cx, JSObject *proxy, uintN indent)
|
||||||
{
|
{
|
||||||
|
JS_CHECK_RECURSION(cx, return NULL);
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
AutoPendingProxyOperation pending(cx, proxy);
|
||||||
return proxy->getProxyHandler()->fun_toString(cx, proxy, indent);
|
return proxy->getProxyHandler()->fun_toString(cx, proxy, indent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -510,7 +510,7 @@ NodeBuilder::newNode(ASTType type, TokenPos *pos, JSObject **dst)
|
||||||
bool
|
bool
|
||||||
NodeBuilder::newArray(NodeVector &elts, Value *dst)
|
NodeBuilder::newArray(NodeVector &elts, Value *dst)
|
||||||
{
|
{
|
||||||
JSObject *array = js_NewArrayObject(cx, 0, NULL);
|
JSObject *array = NewDenseEmptyArray(cx);
|
||||||
if (!array)
|
if (!array)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -246,7 +246,7 @@ RegExp::createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemC
|
||||||
* 0: matched string
|
* 0: matched string
|
||||||
* 1..pairCount-1: paren matches
|
* 1..pairCount-1: paren matches
|
||||||
*/
|
*/
|
||||||
JSObject *array = js_NewSlowArrayObject(cx);
|
JSObject *array = NewSlowEmptyArray(cx);
|
||||||
if (!array)
|
if (!array)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
@ -1192,6 +1192,7 @@ TokenStream::getTokenInternal()
|
||||||
JSMSG_DEPRECATED_OCTAL)) {
|
JSMSG_DEPRECATED_OCTAL)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
setOctalCharacterEscape();
|
||||||
}
|
}
|
||||||
if ('0' <= c && c < '8') {
|
if ('0' <= c && c < '8') {
|
||||||
val = 8 * val + JS7_UNDEC(c);
|
val = 8 * val + JS7_UNDEC(c);
|
||||||
|
@ -1586,7 +1587,7 @@ TokenStream::getTokenInternal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
filenameBuf[i] = '\0';
|
filenameBuf[i] = '\0';
|
||||||
if (c == '\n') {
|
if (c == EOF || c == '\n') {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
if (flags & TSF_OWNFILENAME)
|
if (flags & TSF_OWNFILENAME)
|
||||||
cx->free((void *) filename);
|
cx->free((void *) filename);
|
||||||
|
|
|
@ -263,6 +263,7 @@ enum TokenStreamFlags
|
||||||
TSF_XMLTAGMODE = 0x200, /* scanning within an XML tag in E4X */
|
TSF_XMLTAGMODE = 0x200, /* scanning within an XML tag in E4X */
|
||||||
TSF_XMLTEXTMODE = 0x400, /* scanning XMLText terminal from E4X */
|
TSF_XMLTEXTMODE = 0x400, /* scanning XMLText terminal from E4X */
|
||||||
TSF_XMLONLYMODE = 0x800, /* don't scan {expr} within text/tag */
|
TSF_XMLONLYMODE = 0x800, /* don't scan {expr} within text/tag */
|
||||||
|
TSF_OCTAL_CHAR = 0x1000, /* observed a octal character escape */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To handle the hard case of contiguous HTML comments, we want to clear the
|
* To handle the hard case of contiguous HTML comments, we want to clear the
|
||||||
|
@ -333,12 +334,15 @@ class TokenStream
|
||||||
void setXMLTagMode(bool enabled = true) { setFlag(enabled, TSF_XMLTAGMODE); }
|
void setXMLTagMode(bool enabled = true) { setFlag(enabled, TSF_XMLTAGMODE); }
|
||||||
void setXMLOnlyMode(bool enabled = true) { setFlag(enabled, TSF_XMLONLYMODE); }
|
void setXMLOnlyMode(bool enabled = true) { setFlag(enabled, TSF_XMLONLYMODE); }
|
||||||
void setUnexpectedEOF(bool enabled = true) { setFlag(enabled, TSF_UNEXPECTED_EOF); }
|
void setUnexpectedEOF(bool enabled = true) { setFlag(enabled, TSF_UNEXPECTED_EOF); }
|
||||||
|
void setOctalCharacterEscape(bool enabled = true) { setFlag(enabled, TSF_OCTAL_CHAR); }
|
||||||
|
|
||||||
bool isStrictMode() { return !!(flags & TSF_STRICT_MODE_CODE); }
|
bool isStrictMode() { return !!(flags & TSF_STRICT_MODE_CODE); }
|
||||||
bool isXMLTagMode() { return !!(flags & TSF_XMLTAGMODE); }
|
bool isXMLTagMode() { return !!(flags & TSF_XMLTAGMODE); }
|
||||||
bool isXMLOnlyMode() { return !!(flags & TSF_XMLONLYMODE); }
|
bool isXMLOnlyMode() { return !!(flags & TSF_XMLONLYMODE); }
|
||||||
bool isUnexpectedEOF() { return !!(flags & TSF_UNEXPECTED_EOF); }
|
bool isUnexpectedEOF() { return !!(flags & TSF_UNEXPECTED_EOF); }
|
||||||
bool isEOF() const { return !!(flags & TSF_EOF); }
|
bool isEOF() const { return !!(flags & TSF_EOF); }
|
||||||
bool isError() const { return !!(flags & TSF_ERROR); }
|
bool isError() const { return !!(flags & TSF_ERROR); }
|
||||||
|
bool hasOctalCharacterEscape() const { return flags & TSF_OCTAL_CHAR; }
|
||||||
|
|
||||||
/* Mutators. */
|
/* Mutators. */
|
||||||
bool reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, va_list ap);
|
bool reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, va_list ap);
|
||||||
|
|
|
@ -1385,6 +1385,18 @@ JSObject::methodShapeChange(JSContext *cx, const Shape &shape)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (branded()) {
|
||||||
|
uintN thrashCount = getMethodThrashCount();
|
||||||
|
if (thrashCount < JSObject::METHOD_THRASH_COUNT_MAX) {
|
||||||
|
++thrashCount;
|
||||||
|
setMethodThrashCount(thrashCount);
|
||||||
|
if (thrashCount == JSObject::METHOD_THRASH_COUNT_MAX) {
|
||||||
|
unbrand(cx);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generateOwnShape(cx);
|
generateOwnShape(cx);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,28 +73,6 @@
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
static const jsbytecode emptyScriptCode[] = {JSOP_STOP, SRC_NULL};
|
|
||||||
|
|
||||||
/* static */ const JSScript JSScript::emptyScriptConst = {
|
|
||||||
JS_INIT_STATIC_CLIST(NULL),
|
|
||||||
const_cast<jsbytecode*>(emptyScriptCode),
|
|
||||||
1, JSVERSION_DEFAULT, 0, 0, 0, 0, 0, 0, 0, true, false, false, false, false,
|
|
||||||
false, /* usesEval */
|
|
||||||
false, /* usesArguments */
|
|
||||||
true, /* warnedAboutTwoArgumentEval */
|
|
||||||
#ifdef JS_METHODJIT
|
|
||||||
false, /* debugMode */
|
|
||||||
#endif
|
|
||||||
const_cast<jsbytecode*>(emptyScriptCode),
|
|
||||||
{0, jsatomid(0)}, NULL, NULL, 0, 0, 0,
|
|
||||||
0, /* nClosedArgs */
|
|
||||||
0, /* nClosedVars */
|
|
||||||
NULL, {NULL},
|
|
||||||
#ifdef CHECK_SCRIPT_OWNER
|
|
||||||
reinterpret_cast<JSThread*>(1)
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#if JS_HAS_XDR
|
#if JS_HAS_XDR
|
||||||
|
|
||||||
enum ScriptBits {
|
enum ScriptBits {
|
||||||
|
@ -108,8 +86,7 @@ enum ScriptBits {
|
||||||
};
|
};
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
|
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
|
||||||
JSBool *hasMagic)
|
|
||||||
{
|
{
|
||||||
JSContext *cx;
|
JSContext *cx;
|
||||||
JSScript *script, *oldscript;
|
JSScript *script, *oldscript;
|
||||||
|
@ -133,7 +110,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
|
||||||
notes = NULL;
|
notes = NULL;
|
||||||
|
|
||||||
/* Should not XDR scripts optimized for a single global object. */
|
/* Should not XDR scripts optimized for a single global object. */
|
||||||
JS_ASSERT_IF(script, !script->globalsOffset);
|
JS_ASSERT_IF(script, !JSScript::isValidOffset(script->globalsOffset));
|
||||||
|
|
||||||
if (xdr->mode == JSXDR_ENCODE)
|
if (xdr->mode == JSXDR_ENCODE)
|
||||||
magic = JSXDR_MAGIC_SCRIPT_CURRENT;
|
magic = JSXDR_MAGIC_SCRIPT_CURRENT;
|
||||||
|
@ -152,45 +129,10 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
|
||||||
if (hasMagic)
|
if (hasMagic)
|
||||||
*hasMagic = JS_TRUE;
|
*hasMagic = JS_TRUE;
|
||||||
|
|
||||||
/*
|
|
||||||
* Since the shortest possible script has JSOP_STOP as its only bytecode,
|
|
||||||
* encode only the length 0 for the emptyScript singleton, and return the
|
|
||||||
* emptyScript instead of a new script when decoding a script of length 0.
|
|
||||||
*/
|
|
||||||
if (xdr->mode == JSXDR_ENCODE)
|
if (xdr->mode == JSXDR_ENCODE)
|
||||||
length = (script == JSScript::emptyScript()) ? 0 : script->length;
|
length = script->length;
|
||||||
if (!JS_XDRUint32(xdr, &length))
|
if (!JS_XDRUint32(xdr, &length))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (length == 0) {
|
|
||||||
if (xdr->mode == JSXDR_ENCODE) {
|
|
||||||
JS_ASSERT(*scriptp == JSScript::emptyScript());
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decoding: check whether we need a mutable empty script. */
|
|
||||||
if (cx->debugHooks->newScriptHook)
|
|
||||||
needMutableScript = true;
|
|
||||||
if (needMutableScript) {
|
|
||||||
/*
|
|
||||||
* We need a mutable empty script but the encoder serialized only
|
|
||||||
* the shorthand (0 length word) for us. Make a new mutable empty
|
|
||||||
* script here and return it immediately.
|
|
||||||
*/
|
|
||||||
script = JSScript::NewScript(cx, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
||||||
if (!script)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
script->setVersion(JSVERSION_DEFAULT);
|
|
||||||
script->noScriptRval = true;
|
|
||||||
script->code[0] = JSOP_STOP;
|
|
||||||
script->code[1] = SRC_NULL;
|
|
||||||
*scriptp = script;
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
*scriptp = JSScript::emptyScript();
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xdr->mode == JSXDR_ENCODE) {
|
if (xdr->mode == JSXDR_ENCODE) {
|
||||||
prologLength = script->main - script->code;
|
prologLength = script->main - script->code;
|
||||||
|
@ -208,15 +150,15 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
|
||||||
nsrcnotes = sn - notes;
|
nsrcnotes = sn - notes;
|
||||||
nsrcnotes++; /* room for the terminator */
|
nsrcnotes++; /* room for the terminator */
|
||||||
|
|
||||||
if (script->objectsOffset != 0)
|
if (JSScript::isValidOffset(script->objectsOffset))
|
||||||
nobjects = script->objects()->length;
|
nobjects = script->objects()->length;
|
||||||
if (script->upvarsOffset != 0)
|
if (JSScript::isValidOffset(script->upvarsOffset))
|
||||||
nupvars = script->upvars()->length;
|
nupvars = script->upvars()->length;
|
||||||
if (script->regexpsOffset != 0)
|
if (JSScript::isValidOffset(script->regexpsOffset))
|
||||||
nregexps = script->regexps()->length;
|
nregexps = script->regexps()->length;
|
||||||
if (script->trynotesOffset != 0)
|
if (JSScript::isValidOffset(script->trynotesOffset))
|
||||||
ntrynotes = script->trynotes()->length;
|
ntrynotes = script->trynotes()->length;
|
||||||
if (script->constOffset != 0)
|
if (JSScript::isValidOffset(script->constOffset))
|
||||||
nconsts = script->consts()->length;
|
nconsts = script->consts()->length;
|
||||||
|
|
||||||
nClosedArgs = script->nClosedArgs;
|
nClosedArgs = script->nClosedArgs;
|
||||||
|
@ -956,39 +898,52 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
||||||
script->length = length;
|
script->length = length;
|
||||||
script->setVersion(cx->findVersion());
|
script->setVersion(cx->findVersion());
|
||||||
|
|
||||||
|
uint8 *scriptEnd = reinterpret_cast<uint8 *>(script + 1);
|
||||||
|
|
||||||
cursor = (uint8 *)script + sizeof(JSScript);
|
cursor = (uint8 *)script + sizeof(JSScript);
|
||||||
if (nobjects != 0) {
|
if (nobjects != 0) {
|
||||||
script->objectsOffset = (uint8)(cursor - (uint8 *)script);
|
script->objectsOffset = (uint8)(cursor - scriptEnd);
|
||||||
cursor += sizeof(JSObjectArray);
|
cursor += sizeof(JSObjectArray);
|
||||||
|
} else {
|
||||||
|
script->objectsOffset = JSScript::INVALID_OFFSET;
|
||||||
}
|
}
|
||||||
if (nupvars != 0) {
|
if (nupvars != 0) {
|
||||||
script->upvarsOffset = (uint8)(cursor - (uint8 *)script);
|
script->upvarsOffset = (uint8)(cursor - scriptEnd);
|
||||||
cursor += sizeof(JSUpvarArray);
|
cursor += sizeof(JSUpvarArray);
|
||||||
|
} else {
|
||||||
|
script->upvarsOffset = JSScript::INVALID_OFFSET;
|
||||||
}
|
}
|
||||||
if (nregexps != 0) {
|
if (nregexps != 0) {
|
||||||
script->regexpsOffset = (uint8)(cursor - (uint8 *)script);
|
script->regexpsOffset = (uint8)(cursor - scriptEnd);
|
||||||
cursor += sizeof(JSObjectArray);
|
cursor += sizeof(JSObjectArray);
|
||||||
|
} else {
|
||||||
|
script->regexpsOffset = JSScript::INVALID_OFFSET;
|
||||||
}
|
}
|
||||||
if (ntrynotes != 0) {
|
if (ntrynotes != 0) {
|
||||||
script->trynotesOffset = (uint8)(cursor - (uint8 *)script);
|
script->trynotesOffset = (uint8)(cursor - scriptEnd);
|
||||||
cursor += sizeof(JSTryNoteArray);
|
cursor += sizeof(JSTryNoteArray);
|
||||||
|
} else {
|
||||||
|
script->trynotesOffset = JSScript::INVALID_OFFSET;
|
||||||
}
|
}
|
||||||
if (nglobals != 0) {
|
if (nglobals != 0) {
|
||||||
script->globalsOffset = (uint8)(cursor - (uint8 *)script);
|
script->globalsOffset = (uint8)(cursor - scriptEnd);
|
||||||
cursor += sizeof(GlobalSlotArray);
|
cursor += sizeof(GlobalSlotArray);
|
||||||
|
} else {
|
||||||
|
script->globalsOffset = JSScript::INVALID_OFFSET;
|
||||||
}
|
}
|
||||||
JS_ASSERT((cursor - (uint8 *)script) <= 0xFF);
|
JS_ASSERT((cursor - (uint8 *)script) < 0xFF);
|
||||||
if (nconsts != 0) {
|
if (nconsts != 0) {
|
||||||
script->constOffset = (uint8)(cursor - (uint8 *)script);
|
script->constOffset = (uint8)(cursor - scriptEnd);
|
||||||
cursor += sizeof(JSConstArray);
|
cursor += sizeof(JSConstArray);
|
||||||
|
} else {
|
||||||
|
script->constOffset = JSScript::INVALID_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_STATIC_ASSERT(sizeof(JSScript) +
|
JS_STATIC_ASSERT(sizeof(JSObjectArray) +
|
||||||
sizeof(JSObjectArray) +
|
|
||||||
sizeof(JSUpvarArray) +
|
sizeof(JSUpvarArray) +
|
||||||
sizeof(JSObjectArray) +
|
sizeof(JSObjectArray) +
|
||||||
sizeof(JSTryNoteArray) +
|
sizeof(JSTryNoteArray) +
|
||||||
sizeof(GlobalSlotArray) <= 0xFF);
|
sizeof(GlobalSlotArray) < 0xFF);
|
||||||
|
|
||||||
if (natoms != 0) {
|
if (natoms != 0) {
|
||||||
script->atomMap.length = natoms;
|
script->atomMap.length = natoms;
|
||||||
|
@ -1097,84 +1052,6 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||||
mainLength = CG_OFFSET(cg);
|
mainLength = CG_OFFSET(cg);
|
||||||
prologLength = CG_PROLOG_OFFSET(cg);
|
prologLength = CG_PROLOG_OFFSET(cg);
|
||||||
|
|
||||||
if (prologLength + mainLength <= 3 &&
|
|
||||||
!(cg->flags & TCF_IN_FUNCTION)) {
|
|
||||||
/*
|
|
||||||
* Check very short scripts to see whether they are "empty" and return
|
|
||||||
* the const empty-script singleton if so.
|
|
||||||
*/
|
|
||||||
jsbytecode *pc = prologLength ? CG_PROLOG_BASE(cg) : CG_BASE(cg);
|
|
||||||
|
|
||||||
if ((cg->flags & TCF_NO_SCRIPT_RVAL) && JSOp(*pc) == JSOP_FALSE)
|
|
||||||
++pc;
|
|
||||||
|
|
||||||
if (JSOp(*pc) == JSOP_STOP &&
|
|
||||||
!cx->debugHooks->newScriptHook &&
|
|
||||||
!(cg->flags & TCF_NEED_MUTABLE_SCRIPT))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We can probably use the immutable empty script singleton, just
|
|
||||||
* two hard cases (nupvars != 0, strict mode code) may stand in our
|
|
||||||
* way.
|
|
||||||
*/
|
|
||||||
JSScript *empty = JSScript::emptyScript();
|
|
||||||
|
|
||||||
if (cg->inFunction()) {
|
|
||||||
fun = cg->fun();
|
|
||||||
JS_ASSERT(fun->isInterpreted() && !FUN_SCRIPT(fun));
|
|
||||||
if (cg->flags & TCF_STRICT_MODE_CODE) {
|
|
||||||
/*
|
|
||||||
* We can't use a script singleton for empty strict mode
|
|
||||||
* functions because they have poison-pill caller and
|
|
||||||
* arguments properties:
|
|
||||||
*
|
|
||||||
* function strict() { "use strict"; }
|
|
||||||
* strict.caller; // calls [[ThrowTypeError]] function
|
|
||||||
*/
|
|
||||||
goto skip_empty;
|
|
||||||
}
|
|
||||||
if (fun->u.i.nupvars != 0) {
|
|
||||||
/*
|
|
||||||
* FIXME: upvar uses that were all optimized away may leave
|
|
||||||
* fun->u.i.nupvars non-zero, and since that count is added
|
|
||||||
* into fun->countLocalNames() in order to discriminate the
|
|
||||||
* fun->u.i.names union, we cannot force fun->u.i.nupvars
|
|
||||||
* to 0 to match JSScript::emptyScript()->upvars()->length.
|
|
||||||
* So we skip the empty script optimization.
|
|
||||||
*
|
|
||||||
* Fixing this requires the compiler to track upvar uses as
|
|
||||||
* it analyzes and optimizes closures, and subsequently as
|
|
||||||
* the emitter performs useless expression elimination.
|
|
||||||
*/
|
|
||||||
goto skip_empty;
|
|
||||||
}
|
|
||||||
fun->freezeLocalNames(cx);
|
|
||||||
fun->u.i.script = empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
{
|
|
||||||
jsrefcount newEmptyLive = JS_RUNTIME_METER(cx->runtime, liveEmptyScripts);
|
|
||||||
jsrefcount newLive = cx->runtime->liveScripts;
|
|
||||||
jsrefcount newTotal =
|
|
||||||
JS_RUNTIME_METER(cx->runtime, totalEmptyScripts) + cx->runtime->totalScripts;
|
|
||||||
|
|
||||||
jsrefcount oldHigh = cx->runtime->highWaterLiveScripts;
|
|
||||||
if (newEmptyLive + newLive > oldHigh) {
|
|
||||||
JS_ATOMIC_SET(&cx->runtime->highWaterLiveScripts, newEmptyLive + newLive);
|
|
||||||
if (getenv("JS_DUMP_LIVE_SCRIPTS")) {
|
|
||||||
fprintf(stderr, "high water script count: %d empty, %d not (total %d)\n",
|
|
||||||
newEmptyLive, newLive, newTotal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
skip_empty:
|
|
||||||
CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes);
|
CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes);
|
||||||
uint16 nClosedArgs = uint16(cg->closedArgs.length());
|
uint16 nClosedArgs = uint16(cg->closedArgs.length());
|
||||||
JS_ASSERT(nClosedArgs == cg->closedArgs.length());
|
JS_ASSERT(nClosedArgs == cg->closedArgs.length());
|
||||||
|
@ -1268,7 +1145,7 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||||
if (cg->inFunction()) {
|
if (cg->inFunction()) {
|
||||||
fun = cg->fun();
|
fun = cg->fun();
|
||||||
JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
|
JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
|
||||||
if (script->upvarsOffset != 0)
|
if (JSScript::isValidOffset(script->upvarsOffset))
|
||||||
JS_ASSERT(script->upvars()->length == fun->u.i.nupvars);
|
JS_ASSERT(script->upvars()->length == fun->u.i.nupvars);
|
||||||
else
|
else
|
||||||
fun->u.i.nupvars = 0;
|
fun->u.i.nupvars = 0;
|
||||||
|
@ -1286,10 +1163,19 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||||
js_CallNewScriptHook(cx, script, fun);
|
js_CallNewScriptHook(cx, script, fun);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{
|
{
|
||||||
jsrefcount newLive = JS_RUNTIME_METER(cx->runtime, liveScripts);
|
jsrefcount newEmptyLive, newLive, newTotal;
|
||||||
jsrefcount newEmptyLive = cx->runtime->liveEmptyScripts;
|
if (script->isEmpty()) {
|
||||||
jsrefcount newTotal =
|
newEmptyLive = JS_RUNTIME_METER(cx->runtime, liveEmptyScripts);
|
||||||
JS_RUNTIME_METER(cx->runtime, totalScripts) + cx->runtime->totalEmptyScripts;
|
newLive = cx->runtime->liveScripts;
|
||||||
|
newTotal =
|
||||||
|
JS_RUNTIME_METER(cx->runtime, totalEmptyScripts) + cx->runtime->totalScripts;
|
||||||
|
} else {
|
||||||
|
newEmptyLive = cx->runtime->liveEmptyScripts;
|
||||||
|
newLive = JS_RUNTIME_METER(cx->runtime, liveScripts);
|
||||||
|
newTotal =
|
||||||
|
cx->runtime->totalEmptyScripts + JS_RUNTIME_METER(cx->runtime, totalScripts);
|
||||||
|
}
|
||||||
|
|
||||||
jsrefcount oldHigh = cx->runtime->highWaterLiveScripts;
|
jsrefcount oldHigh = cx->runtime->highWaterLiveScripts;
|
||||||
if (newEmptyLive + newLive > oldHigh) {
|
if (newEmptyLive + newLive > oldHigh) {
|
||||||
JS_ATOMIC_SET(&cx->runtime->highWaterLiveScripts, newEmptyLive + newLive);
|
JS_ATOMIC_SET(&cx->runtime->highWaterLiveScripts, newEmptyLive + newLive);
|
||||||
|
@ -1311,8 +1197,6 @@ bad:
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
|
js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
|
||||||
{
|
{
|
||||||
JS_ASSERT(script != JSScript::emptyScript());
|
|
||||||
|
|
||||||
JSNewScriptHook hook;
|
JSNewScriptHook hook;
|
||||||
|
|
||||||
hook = cx->debugHooks->newScriptHook;
|
hook = cx->debugHooks->newScriptHook;
|
||||||
|
@ -1326,8 +1210,6 @@ js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
|
js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
|
||||||
{
|
{
|
||||||
JS_ASSERT(script != JSScript::emptyScript());
|
|
||||||
|
|
||||||
JSDestroyScriptHook hook;
|
JSDestroyScriptHook hook;
|
||||||
|
|
||||||
hook = cx->debugHooks->destroyScriptHook;
|
hook = cx->debugHooks->destroyScriptHook;
|
||||||
|
@ -1338,13 +1220,11 @@ js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
|
||||||
static void
|
static void
|
||||||
DestroyScript(JSContext *cx, JSScript *script, JSThreadData *data)
|
DestroyScript(JSContext *cx, JSScript *script, JSThreadData *data)
|
||||||
{
|
{
|
||||||
if (script == JSScript::emptyScript()) {
|
|
||||||
JS_RUNTIME_UNMETER(cx->runtime, liveEmptyScripts);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JS_RUNTIME_UNMETER(cx->runtime, liveScripts);
|
if (script->isEmpty())
|
||||||
|
JS_RUNTIME_UNMETER(cx->runtime, liveEmptyScripts);
|
||||||
|
else
|
||||||
|
JS_RUNTIME_UNMETER(cx->runtime, liveScripts);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
js_CallDestroyScriptHook(cx, script);
|
js_CallDestroyScriptHook(cx, script);
|
||||||
|
@ -1437,7 +1317,7 @@ js_TraceScript(JSTracer *trc, JSScript *script)
|
||||||
JSAtomMap *map = &script->atomMap;
|
JSAtomMap *map = &script->atomMap;
|
||||||
MarkAtomRange(trc, map->length, map->vector, "atomMap");
|
MarkAtomRange(trc, map->length, map->vector, "atomMap");
|
||||||
|
|
||||||
if (script->objectsOffset != 0) {
|
if (JSScript::isValidOffset(script->objectsOffset)) {
|
||||||
JSObjectArray *objarray = script->objects();
|
JSObjectArray *objarray = script->objects();
|
||||||
uintN i = objarray->length;
|
uintN i = objarray->length;
|
||||||
do {
|
do {
|
||||||
|
@ -1449,7 +1329,7 @@ js_TraceScript(JSTracer *trc, JSScript *script)
|
||||||
} while (i != 0);
|
} while (i != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (script->regexpsOffset != 0) {
|
if (JSScript::isValidOffset(script->regexpsOffset)) {
|
||||||
JSObjectArray *objarray = script->regexps();
|
JSObjectArray *objarray = script->regexps();
|
||||||
uintN i = objarray->length;
|
uintN i = objarray->length;
|
||||||
do {
|
do {
|
||||||
|
@ -1461,7 +1341,7 @@ js_TraceScript(JSTracer *trc, JSScript *script)
|
||||||
} while (i != 0);
|
} while (i != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (script->constOffset != 0) {
|
if (JSScript::isValidOffset(script->constOffset)) {
|
||||||
JSConstArray *constarray = script->consts();
|
JSConstArray *constarray = script->consts();
|
||||||
MarkValueRange(trc, constarray->length, constarray->vector, "consts");
|
MarkValueRange(trc, constarray->length, constarray->vector, "consts");
|
||||||
}
|
}
|
||||||
|
@ -1481,7 +1361,6 @@ js_NewScriptObject(JSContext *cx, JSScript *script)
|
||||||
AutoScriptRooter root(cx, script);
|
AutoScriptRooter root(cx, script);
|
||||||
|
|
||||||
JS_ASSERT(!script->u.object);
|
JS_ASSERT(!script->u.object);
|
||||||
JS_ASSERT(script != JSScript::emptyScript());
|
|
||||||
|
|
||||||
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
|
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
|
@ -1733,7 +1612,6 @@ class DisablePrincipalsTranscoding {
|
||||||
JSScript *
|
JSScript *
|
||||||
js_CloneScript(JSContext *cx, JSScript *script)
|
js_CloneScript(JSContext *cx, JSScript *script)
|
||||||
{
|
{
|
||||||
JS_ASSERT(script != JSScript::emptyScript());
|
|
||||||
JS_ASSERT(cx->compartment != script->compartment);
|
JS_ASSERT(cx->compartment != script->compartment);
|
||||||
JS_ASSERT(script->compartment);
|
JS_ASSERT(script->compartment);
|
||||||
|
|
||||||
|
@ -1770,7 +1648,7 @@ js_CloneScript(JSContext *cx, JSScript *script)
|
||||||
JS_XDRMemSetData(w, NULL, 0);
|
JS_XDRMemSetData(w, NULL, 0);
|
||||||
|
|
||||||
// We can't use the public API because it makes a script object.
|
// We can't use the public API because it makes a script object.
|
||||||
if (!js_XDRScript(r, &script, true, NULL))
|
if (!js_XDRScript(r, &script, NULL))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
JS_XDRDestroy(r);
|
JS_XDRDestroy(r);
|
||||||
|
@ -1789,4 +1667,3 @@ JSScript::copyClosedSlotsTo(JSScript *other)
|
||||||
{
|
{
|
||||||
memcpy(other->closedSlots, closedSlots, nClosedArgs + nClosedVars);
|
memcpy(other->closedSlots, closedSlots, nClosedArgs + nClosedVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -198,12 +198,6 @@ struct JSScript {
|
||||||
* to the newly made script's function, if any -- so callers of NewScript
|
* to the newly made script's function, if any -- so callers of NewScript
|
||||||
* are responsible for notifying the debugger after successfully creating any
|
* are responsible for notifying the debugger after successfully creating any
|
||||||
* kind (function or other) of new JSScript.
|
* kind (function or other) of new JSScript.
|
||||||
*
|
|
||||||
* NB: NewScript always creates a new script; it never returns the empty
|
|
||||||
* script singleton (JSScript::emptyScript()). Callers who know they can use
|
|
||||||
* that read-only singleton are responsible for choosing it instead of calling
|
|
||||||
* NewScript with length and nsrcnotes equal to 1 and other parameters save
|
|
||||||
* cx all zero.
|
|
||||||
*/
|
*/
|
||||||
static JSScript *NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
|
static JSScript *NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
|
||||||
uint32 nobjects, uint32 nupvars, uint32 nregexps,
|
uint32 nobjects, uint32 nupvars, uint32 nregexps,
|
||||||
|
@ -219,19 +213,22 @@ struct JSScript {
|
||||||
uint16 version; /* JS version under which script was compiled */
|
uint16 version; /* JS version under which script was compiled */
|
||||||
uint16 nfixed; /* number of slots besides stack operands in
|
uint16 nfixed; /* number of slots besides stack operands in
|
||||||
slot array */
|
slot array */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Offsets to various array structures from the end of this script, or
|
||||||
|
* JSScript::INVALID_OFFSET if the array has length 0.
|
||||||
|
*/
|
||||||
uint8 objectsOffset; /* offset to the array of nested function,
|
uint8 objectsOffset; /* offset to the array of nested function,
|
||||||
block, scope, xml and one-time regexps
|
block, scope, xml and one-time regexps
|
||||||
objects or 0 if none */
|
objects */
|
||||||
uint8 upvarsOffset; /* offset of the array of display ("up")
|
uint8 upvarsOffset; /* offset of the array of display ("up")
|
||||||
closure vars or 0 if none */
|
closure vars */
|
||||||
uint8 regexpsOffset; /* offset to the array of to-be-cloned
|
uint8 regexpsOffset; /* offset to the array of to-be-cloned
|
||||||
regexps or 0 if none. */
|
regexps */
|
||||||
uint8 trynotesOffset; /* offset to the array of try notes or
|
uint8 trynotesOffset; /* offset to the array of try notes */
|
||||||
0 if none */
|
uint8 globalsOffset; /* offset to the array of global slots */
|
||||||
uint8 globalsOffset; /* offset to the array of global slots or
|
uint8 constOffset; /* offset to the array of constants */
|
||||||
0 if none */
|
|
||||||
uint8 constOffset; /* offset to the array of constants or
|
|
||||||
0 if none */
|
|
||||||
bool noScriptRval:1; /* no need for result value of last
|
bool noScriptRval:1; /* no need for result value of last
|
||||||
expression statement */
|
expression statement */
|
||||||
bool savedCallerFun:1; /* object 0 is caller function */
|
bool savedCallerFun:1; /* object 0 is caller function */
|
||||||
|
@ -322,34 +319,37 @@ struct JSScript {
|
||||||
/* Script notes are allocated right after the code. */
|
/* Script notes are allocated right after the code. */
|
||||||
jssrcnote *notes() { return (jssrcnote *)(code + length); }
|
jssrcnote *notes() { return (jssrcnote *)(code + length); }
|
||||||
|
|
||||||
|
static const uint8 INVALID_OFFSET = 0xFF;
|
||||||
|
static bool isValidOffset(uint8 offset) { return offset != INVALID_OFFSET; }
|
||||||
|
|
||||||
JSObjectArray *objects() {
|
JSObjectArray *objects() {
|
||||||
JS_ASSERT(objectsOffset != 0);
|
JS_ASSERT(isValidOffset(objectsOffset));
|
||||||
return (JSObjectArray *)((uint8 *) this + objectsOffset);
|
return (JSObjectArray *)((uint8 *) (this + 1) + objectsOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSUpvarArray *upvars() {
|
JSUpvarArray *upvars() {
|
||||||
JS_ASSERT(upvarsOffset != 0);
|
JS_ASSERT(isValidOffset(upvarsOffset));
|
||||||
return (JSUpvarArray *) ((uint8 *) this + upvarsOffset);
|
return (JSUpvarArray *) ((uint8 *) (this + 1) + upvarsOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObjectArray *regexps() {
|
JSObjectArray *regexps() {
|
||||||
JS_ASSERT(regexpsOffset != 0);
|
JS_ASSERT(isValidOffset(regexpsOffset));
|
||||||
return (JSObjectArray *) ((uint8 *) this + regexpsOffset);
|
return (JSObjectArray *) ((uint8 *) (this + 1) + regexpsOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSTryNoteArray *trynotes() {
|
JSTryNoteArray *trynotes() {
|
||||||
JS_ASSERT(trynotesOffset != 0);
|
JS_ASSERT(isValidOffset(trynotesOffset));
|
||||||
return (JSTryNoteArray *) ((uint8 *) this + trynotesOffset);
|
return (JSTryNoteArray *) ((uint8 *) (this + 1) + trynotesOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
js::GlobalSlotArray *globals() {
|
js::GlobalSlotArray *globals() {
|
||||||
JS_ASSERT(globalsOffset != 0);
|
JS_ASSERT(isValidOffset(globalsOffset));
|
||||||
return (js::GlobalSlotArray *) ((uint8 *)this + globalsOffset);
|
return (js::GlobalSlotArray *) ((uint8 *) (this + 1) + globalsOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSConstArray *consts() {
|
JSConstArray *consts() {
|
||||||
JS_ASSERT(constOffset != 0);
|
JS_ASSERT(isValidOffset(constOffset));
|
||||||
return (JSConstArray *) ((uint8 *) this + constOffset);
|
return (JSConstArray *) ((uint8 *) (this + 1) + constOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSAtom *getAtom(size_t index) {
|
JSAtom *getAtom(size_t index) {
|
||||||
|
@ -397,20 +397,10 @@ struct JSScript {
|
||||||
/*
|
/*
|
||||||
* The isEmpty method tells whether this script has code that computes any
|
* The isEmpty method tells whether this script has code that computes any
|
||||||
* result (not return value, result AKA normal completion value) other than
|
* result (not return value, result AKA normal completion value) other than
|
||||||
* JSVAL_VOID, or any other effects. It has a fast path for the case where
|
* JSVAL_VOID, or any other effects.
|
||||||
* |this| is the emptyScript singleton, but it also checks this->length and
|
|
||||||
* this->code, to handle debugger-generated mutable empty scripts.
|
|
||||||
*/
|
*/
|
||||||
inline bool isEmpty() const;
|
inline bool isEmpty() const;
|
||||||
|
|
||||||
/*
|
|
||||||
* Accessor for the emptyScriptConst singleton, to consolidate const_cast.
|
|
||||||
* See the private member declaration.
|
|
||||||
*/
|
|
||||||
static JSScript *emptyScript() {
|
|
||||||
return const_cast<JSScript *>(&emptyScriptConst);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 getClosedArg(uint32 index) {
|
uint32 getClosedArg(uint32 index) {
|
||||||
JS_ASSERT(index < nClosedArgs);
|
JS_ASSERT(index < nClosedArgs);
|
||||||
return closedSlots[index];
|
return closedSlots[index];
|
||||||
|
@ -422,16 +412,6 @@ struct JSScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyClosedSlotsTo(JSScript *other);
|
void copyClosedSlotsTo(JSScript *other);
|
||||||
|
|
||||||
private:
|
|
||||||
/*
|
|
||||||
* Use const to put this in read-only memory if possible. We are stuck with
|
|
||||||
* non-const JSScript * and jsbytecode * by legacy code (back in the 1990s,
|
|
||||||
* const wasn't supported correctly on all target platforms). The debugger
|
|
||||||
* does mutate bytecode, and script->u.object may be set after construction
|
|
||||||
* in some cases, so making JSScript pointers const will be "hard".
|
|
||||||
*/
|
|
||||||
static const JSScript emptyScriptConst;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SHARP_NSLOTS 2 /* [#array, #depth] slots if the script
|
#define SHARP_NSLOTS 2 /* [#array, #depth] slots if the script
|
||||||
|
@ -575,18 +555,11 @@ js_CloneScript(JSContext *cx, JSScript *script);
|
||||||
* If magic is null, js_XDRScript returns false on bad magic number errors,
|
* If magic is null, js_XDRScript returns false on bad magic number errors,
|
||||||
* which it reports.
|
* which it reports.
|
||||||
*
|
*
|
||||||
* NB: after a successful JSXDR_DECODE, and provided that *scriptp is not the
|
* NB: after a successful JSXDR_DECODE, js_XDRScript callers must do any
|
||||||
* JSScript::emptyScript() immutable singleton, js_XDRScript callers must do
|
* required subsequent set-up of owning function or script object and then call
|
||||||
* any required subsequent set-up of owning function or script object and then
|
* js_CallNewScriptHook.
|
||||||
* call js_CallNewScriptHook.
|
|
||||||
*
|
|
||||||
* If the caller requires a mutable empty script (for debugging or u.object
|
|
||||||
* ownership setting), pass true for needMutableScript. Otherwise pass false.
|
|
||||||
* Call js_CallNewScriptHook only with a mutable script, i.e. never with the
|
|
||||||
* JSScript::emptyScript() singleton.
|
|
||||||
*/
|
*/
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
|
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic);
|
||||||
JSBool *hasMagic);
|
|
||||||
|
|
||||||
#endif /* jsscript_h___ */
|
#endif /* jsscript_h___ */
|
||||||
|
|
|
@ -70,23 +70,13 @@ JSScript::getRegExp(size_t index)
|
||||||
inline bool
|
inline bool
|
||||||
JSScript::isEmpty() const
|
JSScript::isEmpty() const
|
||||||
{
|
{
|
||||||
return (this == emptyScript());
|
if (length > 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
// See bug 603044 comment #21.
|
jsbytecode *pc = code;
|
||||||
#if 0
|
if (noScriptRval && JSOp(*pc) == JSOP_FALSE)
|
||||||
if (this == emptyScript())
|
++pc;
|
||||||
return true;
|
return JSOp(*pc) == JSOP_STOP;
|
||||||
|
|
||||||
if (length <= 3) {
|
|
||||||
jsbytecode *pc = code;
|
|
||||||
|
|
||||||
if (noScriptRval && JSOp(*pc) == JSOP_FALSE)
|
|
||||||
++pc;
|
|
||||||
if (JSOp(*pc) == JSOP_STOP)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* jsscriptinlines_h___ */
|
#endif /* jsscriptinlines_h___ */
|
||||||
|
|
|
@ -1384,8 +1384,8 @@ RopeMatch(JSString *textstr, const jschar *pat, jsuint patlen)
|
||||||
*/
|
*/
|
||||||
size_t textstrlen = textstr->length();
|
size_t textstrlen = textstr->length();
|
||||||
size_t threshold = textstrlen >> sRopeMatchThresholdRatioLog2;
|
size_t threshold = textstrlen >> sRopeMatchThresholdRatioLog2;
|
||||||
JSRopeLeafIterator iter(textstr);
|
JSRopeLeafIterator iter;
|
||||||
for (JSString *str = iter.init(); str; str = iter.next()) {
|
for (JSString *str = iter.init(textstr); str; str = iter.next()) {
|
||||||
if (threshold-- == 0 || !strs.append(str))
|
if (threshold-- == 0 || !strs.append(str))
|
||||||
return StringMatch(textstr->chars(), textstrlen, pat, patlen);
|
return StringMatch(textstr->chars(), textstrlen, pat, patlen);
|
||||||
}
|
}
|
||||||
|
@ -1871,7 +1871,7 @@ BuildFlatMatchArray(JSContext *cx, JSString *textstr, const FlatMatch &fm, Value
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For this non-global match, produce a RegExp.exec-style array. */
|
/* For this non-global match, produce a RegExp.exec-style array. */
|
||||||
JSObject *obj = js_NewSlowArrayObject(cx);
|
JSObject *obj = NewSlowEmptyArray(cx);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return false;
|
return false;
|
||||||
vp->setObject(*obj);
|
vp->setObject(*obj);
|
||||||
|
@ -1896,7 +1896,7 @@ MatchCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p)
|
||||||
|
|
||||||
JSObject *&arrayobj = *static_cast<MatchArgType>(p);
|
JSObject *&arrayobj = *static_cast<MatchArgType>(p);
|
||||||
if (!arrayobj) {
|
if (!arrayobj) {
|
||||||
arrayobj = js_NewArrayObject(cx, 0, NULL);
|
arrayobj = NewDenseEmptyArray(cx);
|
||||||
if (!arrayobj)
|
if (!arrayobj)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2242,9 +2242,9 @@ BuildFlatReplacement(JSContext *cx, JSString *textstr, JSString *repstr,
|
||||||
* If we are replacing over a rope, avoid flattening it by iterating
|
* If we are replacing over a rope, avoid flattening it by iterating
|
||||||
* through it, building a new rope.
|
* through it, building a new rope.
|
||||||
*/
|
*/
|
||||||
JSRopeLeafIterator iter(textstr);
|
JSRopeLeafIterator iter;
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
for (JSString *str = iter.init(); str; str = iter.next()) {
|
for (JSString *str = iter.init(textstr); str; str = iter.next()) {
|
||||||
size_t len = str->length();
|
size_t len = str->length();
|
||||||
size_t strEnd = pos + len;
|
size_t strEnd = pos + len;
|
||||||
if (pos < matchEnd && strEnd > match) {
|
if (pos < matchEnd && strEnd > match) {
|
||||||
|
@ -2679,7 +2679,7 @@ str_split(JSContext *cx, uintN argc, Value *vp)
|
||||||
|
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
Value v = StringValue(str);
|
Value v = StringValue(str);
|
||||||
JSObject *aobj = js_NewArrayObject(cx, 1, &v);
|
JSObject *aobj = NewDenseCopiedArray(cx, 1, &v);
|
||||||
if (!aobj)
|
if (!aobj)
|
||||||
return false;
|
return false;
|
||||||
vp->setObject(*aobj);
|
vp->setObject(*aobj);
|
||||||
|
@ -2762,7 +2762,7 @@ str_split(JSContext *cx, uintN argc, Value *vp)
|
||||||
if (j == -2)
|
if (j == -2)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JSObject *aobj = js_NewArrayObject(cx, splits.length(), splits.begin());
|
JSObject *aobj = NewDenseCopiedArray(cx, splits.length(), splits.begin());
|
||||||
if (!aobj)
|
if (!aobj)
|
||||||
return false;
|
return false;
|
||||||
vp->setObject(*aobj);
|
vp->setObject(*aobj);
|
||||||
|
|
|
@ -630,20 +630,13 @@ class JSRopeNodeIterator {
|
||||||
static const size_t DONE_RIGHT = 0x2;
|
static const size_t DONE_RIGHT = 0x2;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JSRopeNodeIterator(JSString *str)
|
JSRopeNodeIterator()
|
||||||
: mUsedFlags(0)
|
: mStr(NULL), mUsedFlags(0)
|
||||||
{
|
{}
|
||||||
mStr = str;
|
|
||||||
}
|
JSString *init(JSString *str) {
|
||||||
|
|
||||||
JSString *init() {
|
|
||||||
/* If we were constructed with a non-rope string, just return that. */
|
|
||||||
if (!mStr->isRope()) {
|
|
||||||
JSString *oldStr = mStr;
|
|
||||||
mStr = NULL;
|
|
||||||
return oldStr;
|
|
||||||
}
|
|
||||||
/* Move to the farthest-left leaf in the rope. */
|
/* Move to the farthest-left leaf in the rope. */
|
||||||
|
mStr = str;
|
||||||
while (mStr->isInteriorNode())
|
while (mStr->isInteriorNode())
|
||||||
mStr = mStr->interiorNodeParent();
|
mStr = mStr->interiorNodeParent();
|
||||||
while (mStr->ropeLeft()->isInteriorNode())
|
while (mStr->ropeLeft()->isInteriorNode())
|
||||||
|
@ -697,14 +690,9 @@ class JSRopeLeafIterator {
|
||||||
JSRopeNodeIterator mNodeIterator;
|
JSRopeNodeIterator mNodeIterator;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
inline JSString *init(JSString *str) {
|
||||||
JSRopeLeafIterator(JSString *topNode) :
|
JS_ASSERT(str->isTopNode());
|
||||||
mNodeIterator(topNode) {
|
str = mNodeIterator.init(str);
|
||||||
JS_ASSERT(topNode->isTopNode());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline JSString *init() {
|
|
||||||
JSString *str = mNodeIterator.init();
|
|
||||||
while (str->isRope()) {
|
while (str->isRope()) {
|
||||||
str = mNodeIterator.next();
|
str = mNodeIterator.next();
|
||||||
JS_ASSERT(str);
|
JS_ASSERT(str);
|
||||||
|
|
|
@ -2221,7 +2221,7 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag
|
||||||
global_slots(NULL),
|
global_slots(NULL),
|
||||||
callDepth(anchor ? anchor->calldepth : 0),
|
callDepth(anchor ? anchor->calldepth : 0),
|
||||||
atoms(FrameAtomBase(cx, cx->fp())),
|
atoms(FrameAtomBase(cx, cx->fp())),
|
||||||
consts(cx->fp()->script()->constOffset
|
consts(JSScript::isValidOffset(cx->fp()->script()->constOffset)
|
||||||
? cx->fp()->script()->consts()->vector
|
? cx->fp()->script()->consts()->vector
|
||||||
: NULL),
|
: NULL),
|
||||||
strictModeCode_ins(NULL),
|
strictModeCode_ins(NULL),
|
||||||
|
@ -2446,7 +2446,7 @@ TraceRecorder::finishAbort(const char* reason)
|
||||||
|
|
||||||
AUDIT(recorderAborted);
|
AUDIT(recorderAborted);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
debug_only_printf(LC_TMMinimal,
|
debug_only_printf(LC_TMMinimal | LC_TMAbort,
|
||||||
"Abort recording of tree %s:%d@%d at %s:%d@%d: %s.\n",
|
"Abort recording of tree %s:%d@%d at %s:%d@%d: %s.\n",
|
||||||
tree->treeFileName,
|
tree->treeFileName,
|
||||||
tree->treeLineNumber,
|
tree->treeLineNumber,
|
||||||
|
@ -2788,6 +2788,13 @@ TraceMonitor::sweep()
|
||||||
JS_ASSERT(!ontrace());
|
JS_ASSERT(!ontrace());
|
||||||
debug_only_print0(LC_TMTracer, "Purging fragments with dead things");
|
debug_only_print0(LC_TMTracer, "Purging fragments with dead things");
|
||||||
|
|
||||||
|
bool shouldAbortRecording = false;
|
||||||
|
TreeFragment *recorderTree = NULL;
|
||||||
|
if (recorder) {
|
||||||
|
recorderTree = recorder->getTree();
|
||||||
|
shouldAbortRecording = HasUnreachableGCThings(recorderTree);
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < FRAGMENT_TABLE_SIZE; ++i) {
|
for (size_t i = 0; i < FRAGMENT_TABLE_SIZE; ++i) {
|
||||||
TreeFragment** fragp = &vmfragments[i];
|
TreeFragment** fragp = &vmfragments[i];
|
||||||
while (TreeFragment* frag = *fragp) {
|
while (TreeFragment* frag = *fragp) {
|
||||||
|
@ -2805,7 +2812,9 @@ TraceMonitor::sweep()
|
||||||
JS_ASSERT(frag->root == frag);
|
JS_ASSERT(frag->root == frag);
|
||||||
*fragp = frag->next;
|
*fragp = frag->next;
|
||||||
do {
|
do {
|
||||||
verbose_only( FragProfiling_FragFinalizer(frag, this); )
|
verbose_only( FragProfiling_FragFinalizer(frag, this); );
|
||||||
|
if (recorderTree == frag)
|
||||||
|
shouldAbortRecording = true;
|
||||||
TrashTree(frag);
|
TrashTree(frag);
|
||||||
frag = frag->peer;
|
frag = frag->peer;
|
||||||
} while (frag);
|
} while (frag);
|
||||||
|
@ -2815,7 +2824,7 @@ TraceMonitor::sweep()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recorder && HasUnreachableGCThings(recorder->getTree()))
|
if (shouldAbortRecording)
|
||||||
recorder->finishAbort("dead GC things");
|
recorder->finishAbort("dead GC things");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4289,7 +4298,7 @@ TraceRecorder::guard(bool expected, LIns* cond, VMSideExit* exit,
|
||||||
RETURN_STOP("Constantly false guard detected");
|
RETURN_STOP("Constantly false guard detected");
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* If this assertion fails, first decide if you want recording to
|
* If you hit this assertion, first decide if you want recording to
|
||||||
* abort in the case where the guard always exits. If not, find a way
|
* abort in the case where the guard always exits. If not, find a way
|
||||||
* to detect that case and avoid calling guard(). Otherwise, change
|
* to detect that case and avoid calling guard(). Otherwise, change
|
||||||
* the invocation of guard() so it passes in abortIfAlwaysExits=true,
|
* the invocation of guard() so it passes in abortIfAlwaysExits=true,
|
||||||
|
@ -4298,7 +4307,7 @@ TraceRecorder::guard(bool expected, LIns* cond, VMSideExit* exit,
|
||||||
* insGuard() below and an always-exits guard will be inserted, which
|
* insGuard() below and an always-exits guard will be inserted, which
|
||||||
* is correct but sub-optimal.)
|
* is correct but sub-optimal.)
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(0);
|
JS_NOT_REACHED("unexpected constantly false guard detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -7884,9 +7893,9 @@ TraceRecorder::updateAtoms()
|
||||||
{
|
{
|
||||||
JSScript *script = cx->fp()->script();
|
JSScript *script = cx->fp()->script();
|
||||||
atoms = FrameAtomBase(cx, cx->fp());
|
atoms = FrameAtomBase(cx, cx->fp());
|
||||||
consts = cx->fp()->hasImacropc() || script->constOffset == 0
|
consts = (cx->fp()->hasImacropc() || !JSScript::isValidOffset(script->constOffset))
|
||||||
? 0
|
? 0
|
||||||
: script->consts()->vector;
|
: script->consts()->vector;
|
||||||
strictModeCode_ins = w.name(w.immi(script->strictModeCode), "strict");
|
strictModeCode_ins = w.name(w.immi(script->strictModeCode), "strict");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7894,7 +7903,7 @@ JS_REQUIRES_STACK void
|
||||||
TraceRecorder::updateAtoms(JSScript *script)
|
TraceRecorder::updateAtoms(JSScript *script)
|
||||||
{
|
{
|
||||||
atoms = script->atomMap.vector;
|
atoms = script->atomMap.vector;
|
||||||
consts = script->constOffset == 0 ? 0 : script->consts()->vector;
|
consts = JSScript::isValidOffset(script->constOffset) ? script->consts()->vector : 0;
|
||||||
strictModeCode_ins = w.name(w.immi(script->strictModeCode), "strict");
|
strictModeCode_ins = w.name(w.immi(script->strictModeCode), "strict");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10839,13 +10848,20 @@ TraceRecorder::newArray(JSObject* ctor, uint32 argc, Value* argv, Value* rval)
|
||||||
CHECK_STATUS(getClassPrototype(ctor, proto_ins));
|
CHECK_STATUS(getClassPrototype(ctor, proto_ins));
|
||||||
|
|
||||||
LIns *arr_ins;
|
LIns *arr_ins;
|
||||||
if (argc == 0 || (argc == 1 && argv[0].isNumber())) {
|
if (argc == 0) {
|
||||||
LIns *args[] = { argc == 0 ? w.immi(0) : d2i(get(argv)), proto_ins, cx_ins };
|
LIns *args[] = { proto_ins, cx_ins };
|
||||||
arr_ins = w.call(&js_NewEmptyArray_ci, args);
|
arr_ins = w.call(&js::NewDenseEmptyArray_ci, args);
|
||||||
guard(false, w.eqp0(arr_ins), OOM_EXIT);
|
guard(false, w.eqp0(arr_ins), OOM_EXIT);
|
||||||
|
|
||||||
|
} else if (argc == 1 && argv[0].isNumber()) {
|
||||||
|
/* Abort on RangeError if the double doesn't fit in a uint. */
|
||||||
|
LIns *args[] = { proto_ins, d2i(get(argv)), cx_ins };
|
||||||
|
arr_ins = w.call(&js::NewDenseUnallocatedArray_ci, args);
|
||||||
|
guard(false, w.eqp0(arr_ins), OOM_EXIT);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LIns *args[] = { w.nameImmi(argc), proto_ins, cx_ins };
|
LIns *args[] = { proto_ins, w.nameImmi(argc), cx_ins };
|
||||||
arr_ins = w.call(&js_NewPreallocatedArray_ci, args);
|
arr_ins = w.call(&js::NewDenseAllocatedArray_ci, args);
|
||||||
guard(false, w.eqp0(arr_ins), OOM_EXIT);
|
guard(false, w.eqp0(arr_ins), OOM_EXIT);
|
||||||
|
|
||||||
// arr->slots[i] = box_jsval(vp[i]); for i in 0..argc
|
// arr->slots[i] = box_jsval(vp[i]); for i in 0..argc
|
||||||
|
@ -11165,7 +11181,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
|
||||||
}
|
}
|
||||||
} else if (native == js_math_abs) {
|
} else if (native == js_math_abs) {
|
||||||
LIns* a = get(&vp[2]);
|
LIns* a = get(&vp[2]);
|
||||||
if (IsPromoteInt(a)) {
|
if (IsPromoteInt(a) && vp[2].toNumber() != INT_MIN) {
|
||||||
a = w.demote(a);
|
a = w.demote(a);
|
||||||
/* abs(INT_MIN) can't be done using integers; exit if we see it. */
|
/* abs(INT_MIN) can't be done using integers; exit if we see it. */
|
||||||
LIns* intMin_ins = w.name(w.immi(0x80000000), "INT_MIN");
|
LIns* intMin_ins = w.name(w.immi(0x80000000), "INT_MIN");
|
||||||
|
@ -11183,6 +11199,8 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
|
||||||
JSString *str = vp[1].toString();
|
JSString *str = vp[1].toString();
|
||||||
if (native == js_str_charAt) {
|
if (native == js_str_charAt) {
|
||||||
jsdouble i = vp[2].toNumber();
|
jsdouble i = vp[2].toNumber();
|
||||||
|
if (JSDOUBLE_IS_NaN(i))
|
||||||
|
i = 0;
|
||||||
if (i < 0 || i >= str->length())
|
if (i < 0 || i >= str->length())
|
||||||
RETURN_STOP("charAt out of bounds");
|
RETURN_STOP("charAt out of bounds");
|
||||||
LIns* str_ins = get(&vp[1]);
|
LIns* str_ins = get(&vp[1]);
|
||||||
|
@ -11194,6 +11212,8 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
|
||||||
return RECORD_CONTINUE;
|
return RECORD_CONTINUE;
|
||||||
} else if (native == js_str_charCodeAt) {
|
} else if (native == js_str_charCodeAt) {
|
||||||
jsdouble i = vp[2].toNumber();
|
jsdouble i = vp[2].toNumber();
|
||||||
|
if (JSDOUBLE_IS_NaN(i))
|
||||||
|
i = 0;
|
||||||
if (i < 0 || i >= str->length())
|
if (i < 0 || i >= str->length())
|
||||||
RETURN_STOP("charCodeAt out of bounds");
|
RETURN_STOP("charCodeAt out of bounds");
|
||||||
LIns* str_ins = get(&vp[1]);
|
LIns* str_ins = get(&vp[1]);
|
||||||
|
@ -11447,7 +11467,7 @@ TraceRecorder::functionCall(uintN argc, JSOp mode)
|
||||||
|
|
||||||
if (Probes::callTrackingActive(cx)) {
|
if (Probes::callTrackingActive(cx)) {
|
||||||
JSScript *script = FUN_SCRIPT(fun);
|
JSScript *script = FUN_SCRIPT(fun);
|
||||||
if (! script || ! script->isEmpty()) {
|
if (!script || !script->isEmpty()) {
|
||||||
LIns* args[] = { w.immi(1), w.nameImmpNonGC(fun), cx_ins };
|
LIns* args[] = { w.immi(1), w.nameImmpNonGC(fun), cx_ins };
|
||||||
LIns* call_ins = w.call(&functionProbe_ci, args);
|
LIns* call_ins = w.call(&functionProbe_ci, args);
|
||||||
guard(false, w.eqi0(call_ins), MISMATCH_EXIT);
|
guard(false, w.eqi0(call_ins), MISMATCH_EXIT);
|
||||||
|
@ -12773,9 +12793,10 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
|
||||||
CHECK_STATUS_A(makeNumberInt32(idx_ins, &idx_ins));
|
CHECK_STATUS_A(makeNumberInt32(idx_ins, &idx_ins));
|
||||||
|
|
||||||
// Ensure idx >= 0 && idx < length (by using uint32)
|
// Ensure idx >= 0 && idx < length (by using uint32)
|
||||||
guard(true,
|
CHECK_STATUS_A(guard(true,
|
||||||
w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)),
|
w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)),
|
||||||
OVERFLOW_EXIT);
|
"inRange"),
|
||||||
|
OVERFLOW_EXIT, /* abortIfAlwaysExits = */true));
|
||||||
|
|
||||||
// We're now ready to store
|
// We're now ready to store
|
||||||
LIns* data_ins = w.ldpConstTypedArrayData(priv_ins);
|
LIns* data_ins = w.ldpConstTypedArrayData(priv_ins);
|
||||||
|
@ -13198,13 +13219,11 @@ TraceRecorder::interpretedFunctionCall(Value& fval, JSFunction* fun, uintN argc,
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* The function's identity (JSFunction and therefore JSScript) is guarded,
|
* The function's identity (JSFunction and therefore JSScript) is guarded,
|
||||||
* so we can optimize for the empty script singleton right away. No need to
|
* so we can optimize away the function call if the corresponding script is
|
||||||
* worry about crossing globals or relocating argv, even, in this case!
|
* empty. No need to worry about crossing globals or relocating argv, even,
|
||||||
*
|
* in this case!
|
||||||
* Note that the interpreter shortcuts empty-script call and construct too,
|
|
||||||
* and does not call any TR::record_*CallComplete hook.
|
|
||||||
*/
|
*/
|
||||||
if (fun->u.i.script->isEmpty()) {
|
if (fun->script()->isEmpty()) {
|
||||||
LIns* rval_ins;
|
LIns* rval_ins;
|
||||||
if (constructing) {
|
if (constructing) {
|
||||||
LIns* args[] = { get(&fval), w.nameImmpNonGC(&js_ObjectClass), cx_ins };
|
LIns* args[] = { get(&fval), w.nameImmpNonGC(&js_ObjectClass), cx_ins };
|
||||||
|
@ -13829,7 +13848,7 @@ TraceRecorder::typedArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_
|
||||||
* length.
|
* length.
|
||||||
*/
|
*/
|
||||||
guard(true,
|
guard(true,
|
||||||
w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)),
|
w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)), "inRange"),
|
||||||
BRANCH_EXIT);
|
BRANCH_EXIT);
|
||||||
|
|
||||||
/* We are now ready to load. Do a different type of load
|
/* We are now ready to load. Do a different type of load
|
||||||
|
@ -14075,8 +14094,8 @@ TraceRecorder::record_JSOP_NEWINIT()
|
||||||
|
|
||||||
LIns *v_ins;
|
LIns *v_ins;
|
||||||
if (key == JSProto_Array) {
|
if (key == JSProto_Array) {
|
||||||
LIns *args[] = { w.immi(0), proto_ins, cx_ins };
|
LIns *args[] = { proto_ins, cx_ins };
|
||||||
v_ins = w.call(&js_NewPreallocatedArray_ci, args);
|
v_ins = w.call(&NewDenseEmptyArray_ci, args);
|
||||||
} else {
|
} else {
|
||||||
LIns *args[] = { w.immpNull(), proto_ins, cx_ins };
|
LIns *args[] = { w.immpNull(), proto_ins, cx_ins };
|
||||||
v_ins = w.call(&js_InitializerObject_ci, args);
|
v_ins = w.call(&js_InitializerObject_ci, args);
|
||||||
|
@ -14095,8 +14114,8 @@ TraceRecorder::record_JSOP_NEWARRAY()
|
||||||
CHECK_STATUS_A(getClassPrototype(JSProto_Array, proto_ins));
|
CHECK_STATUS_A(getClassPrototype(JSProto_Array, proto_ins));
|
||||||
|
|
||||||
unsigned count = GET_UINT24(cx->regs->pc);
|
unsigned count = GET_UINT24(cx->regs->pc);
|
||||||
LIns *args[] = { w.immi(count), proto_ins, cx_ins };
|
LIns *args[] = { proto_ins, w.immi(count), cx_ins };
|
||||||
LIns *v_ins = w.call(&js_NewPreallocatedArray_ci, args);
|
LIns *v_ins = w.call(&NewDenseAllocatedArray_ci, args);
|
||||||
|
|
||||||
guard(false, w.eqp0(v_ins), OOM_EXIT);
|
guard(false, w.eqp0(v_ins), OOM_EXIT);
|
||||||
stack(0, v_ins);
|
stack(0, v_ins);
|
||||||
|
|
|
@ -1213,7 +1213,7 @@ class TypedArrayTemplate
|
||||||
bool
|
bool
|
||||||
copyFromWithOverlap(JSContext *cx, TypedArray *tarray, jsuint offset = 0)
|
copyFromWithOverlap(JSContext *cx, TypedArray *tarray, jsuint offset = 0)
|
||||||
{
|
{
|
||||||
JS_ASSERT(offset < length);
|
JS_ASSERT(offset <= length);
|
||||||
|
|
||||||
NativeType *dest = static_cast<NativeType*>(data) + offset;
|
NativeType *dest = static_cast<NativeType*>(data) + offset;
|
||||||
|
|
||||||
|
|
|
@ -789,10 +789,10 @@ extern "C++"
|
||||||
# endif /* defined(__cplusplus) */
|
# endif /* defined(__cplusplus) */
|
||||||
|
|
||||||
/* Internal helper macros */
|
/* Internal helper macros */
|
||||||
#define JSVAL_BITS(v) (v.asBits)
|
#define JSVAL_BITS(v) ((v).asBits)
|
||||||
#define JSVAL_FROM_LAYOUT(l) (l)
|
#define JSVAL_FROM_LAYOUT(l) (l)
|
||||||
#define IMPL_TO_JSVAL(v) (v)
|
#define IMPL_TO_JSVAL(v) (v)
|
||||||
#define JSID_BITS(id) (id.asBits)
|
#define JSID_BITS(id) ((id).asBits)
|
||||||
|
|
||||||
#else /* defined(JS_USE_JSVAL_JSID_STRUCT_TYPES) */
|
#else /* defined(JS_USE_JSVAL_JSID_STRUCT_TYPES) */
|
||||||
|
|
||||||
|
|
|
@ -526,12 +526,27 @@ CanReify(Value *vp)
|
||||||
(obj->getNativeIterator()->flags & JSITER_ENUMERATE);
|
(obj->getNativeIterator()->flags & JSITER_ENUMERATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AutoCloseIterator
|
||||||
|
{
|
||||||
|
AutoCloseIterator(JSContext *cx, JSObject *obj) : cx(cx), obj(obj) {}
|
||||||
|
|
||||||
|
~AutoCloseIterator() { if (obj) js_CloseIterator(cx, obj); }
|
||||||
|
|
||||||
|
void clear() { obj = NULL; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSContext *cx;
|
||||||
|
JSObject *obj;
|
||||||
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
Reify(JSContext *cx, JSCompartment *origin, Value *vp)
|
Reify(JSContext *cx, JSCompartment *origin, Value *vp)
|
||||||
{
|
{
|
||||||
JSObject *iterObj = &vp->toObject();
|
JSObject *iterObj = &vp->toObject();
|
||||||
NativeIterator *ni = iterObj->getNativeIterator();
|
NativeIterator *ni = iterObj->getNativeIterator();
|
||||||
|
|
||||||
|
AutoCloseIterator close(cx, iterObj);
|
||||||
|
|
||||||
/* Wrap the iteratee. */
|
/* Wrap the iteratee. */
|
||||||
JSObject *obj = ni->obj;
|
JSObject *obj = ni->obj;
|
||||||
if (!origin->wrap(cx, &obj))
|
if (!origin->wrap(cx, &obj))
|
||||||
|
@ -556,6 +571,7 @@ Reify(JSContext *cx, JSCompartment *origin, Value *vp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close.clear();
|
||||||
return js_CloseIterator(cx, iterObj) &&
|
return js_CloseIterator(cx, iterObj) &&
|
||||||
VectorToKeyIterator(cx, obj, ni->flags, keys, vp);
|
VectorToKeyIterator(cx, obj, ni->flags, keys, vp);
|
||||||
}
|
}
|
||||||
|
@ -573,6 +589,7 @@ Reify(JSContext *cx, JSCompartment *origin, Value *vp)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close.clear();
|
||||||
return js_CloseIterator(cx, iterObj) &&
|
return js_CloseIterator(cx, iterObj) &&
|
||||||
VectorToValueIterator(cx, obj, ni->flags, vals, vp);
|
VectorToValueIterator(cx, obj, ni->flags, vals, vp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -669,13 +669,12 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **atomp)
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||||
{
|
{
|
||||||
if (!js_XDRScript(xdr, scriptp, true, NULL))
|
if (!js_XDRScript(xdr, scriptp, NULL))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
if (xdr->mode == JSXDR_DECODE) {
|
if (xdr->mode == JSXDR_DECODE) {
|
||||||
js_CallNewScriptHook(xdr->cx, *scriptp, NULL);
|
js_CallNewScriptHook(xdr->cx, *scriptp, NULL);
|
||||||
if (*scriptp != JSScript::emptyScript() &&
|
if (!js_NewScriptObject(xdr->cx, *scriptp)) {
|
||||||
!js_NewScriptObject(xdr->cx, *scriptp)) {
|
|
||||||
js_DestroyScript(xdr->cx, *scriptp);
|
js_DestroyScript(xdr->cx, *scriptp);
|
||||||
*scriptp = NULL;
|
*scriptp = NULL;
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
|
@ -5774,7 +5774,7 @@ FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray)
|
||||||
static bool
|
static bool
|
||||||
NamespacesToJSArray(JSContext *cx, JSXMLArray *array, jsval *rval)
|
NamespacesToJSArray(JSContext *cx, JSXMLArray *array, jsval *rval)
|
||||||
{
|
{
|
||||||
JSObject *arrayobj = js_NewArrayObject(cx, 0, NULL);
|
JSObject *arrayobj = NewDenseEmptyArray(cx);
|
||||||
if (!arrayobj)
|
if (!arrayobj)
|
||||||
return false;
|
return false;
|
||||||
*rval = OBJECT_TO_JSVAL(arrayobj);
|
*rval = OBJECT_TO_JSVAL(arrayobj);
|
||||||
|
@ -7466,7 +7466,7 @@ GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||||
if (VALUE_IS_FUNCTION(cx, *vp))
|
if (VALUE_IS_FUNCTION(cx, *vp))
|
||||||
return true;
|
return true;
|
||||||
target = target->getProto();
|
target = target->getProto();
|
||||||
if (target == NULL)
|
if (target == NULL || !target->isNative())
|
||||||
break;
|
break;
|
||||||
tvr.setObject(target);
|
tvr.setObject(target);
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,6 @@ mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp)
|
||||||
CompileStatus
|
CompileStatus
|
||||||
mjit::Compiler::compile()
|
mjit::Compiler::compile()
|
||||||
{
|
{
|
||||||
JS_ASSERT(!script->isEmpty());
|
|
||||||
JS_ASSERT_IF(isConstructing, !script->jitCtor);
|
JS_ASSERT_IF(isConstructing, !script->jitCtor);
|
||||||
JS_ASSERT_IF(!isConstructing, !script->jitNormal);
|
JS_ASSERT_IF(!isConstructing, !script->jitNormal);
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ FindExceptionHandler(JSContext *cx)
|
||||||
JSScript *script = fp->script();
|
JSScript *script = fp->script();
|
||||||
|
|
||||||
top:
|
top:
|
||||||
if (cx->throwing && script->trynotesOffset) {
|
if (cx->throwing && JSScript::isValidOffset(script->trynotesOffset)) {
|
||||||
// The PC is updated before every stub call, so we can use it here.
|
// The PC is updated before every stub call, so we can use it here.
|
||||||
unsigned offset = cx->regs->pc - script->main;
|
unsigned offset = cx->regs->pc - script->main;
|
||||||
|
|
||||||
|
@ -308,18 +308,6 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
||||||
*/
|
*/
|
||||||
fp->initCallFrameEarlyPrologue(fun, nactual);
|
fp->initCallFrameEarlyPrologue(fun, nactual);
|
||||||
|
|
||||||
/* Empty script does nothing. */
|
|
||||||
bool callingNew = fp->isConstructing();
|
|
||||||
if (script->isEmpty()) {
|
|
||||||
RemovePartialFrame(cx, fp);
|
|
||||||
Value *vp = f.regs.sp - (nactual + 2);
|
|
||||||
if (callingNew)
|
|
||||||
vp[0] = vp[1];
|
|
||||||
else
|
|
||||||
vp[0].setUndefined();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nactual != fp->numFormalArgs()) {
|
if (nactual != fp->numFormalArgs()) {
|
||||||
fp = (JSStackFrame *)FixupArity(f, nactual);
|
fp = (JSStackFrame *)FixupArity(f, nactual);
|
||||||
if (!fp)
|
if (!fp)
|
||||||
|
@ -339,7 +327,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
||||||
|
|
||||||
CompileStatus status = CanMethodJIT(cx, script, fp);
|
CompileStatus status = CanMethodJIT(cx, script, fp);
|
||||||
if (status == Compile_Okay)
|
if (status == Compile_Okay)
|
||||||
return script->getJIT(callingNew)->invokeEntry;
|
return script->getJIT(fp->isConstructing())->invokeEntry;
|
||||||
|
|
||||||
/* Function did not compile... interpret it. */
|
/* Function did not compile... interpret it. */
|
||||||
JSBool ok = Interpret(cx, fp);
|
JSBool ok = Interpret(cx, fp);
|
||||||
|
@ -422,9 +410,7 @@ stubs::UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
|
||||||
Value *vp = f.regs.sp - (argc + 2);
|
Value *vp = f.regs.sp - (argc + 2);
|
||||||
|
|
||||||
/* Try to do a fast inline call before the general Invoke path. */
|
/* Try to do a fast inline call before the general Invoke path. */
|
||||||
if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpreted() &&
|
if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpreted()) {
|
||||||
!ucr->fun->script()->isEmpty())
|
|
||||||
{
|
|
||||||
ucr->callee = &vp->toObject();
|
ucr->callee = &vp->toObject();
|
||||||
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, argc))
|
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, argc))
|
||||||
THROW();
|
THROW();
|
||||||
|
@ -476,12 +462,6 @@ stubs::UncachedCallHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
|
||||||
ucr->fun = GET_FUNCTION_PRIVATE(cx, ucr->callee);
|
ucr->fun = GET_FUNCTION_PRIVATE(cx, ucr->callee);
|
||||||
|
|
||||||
if (ucr->fun->isInterpreted()) {
|
if (ucr->fun->isInterpreted()) {
|
||||||
if (ucr->fun->u.i.script->isEmpty()) {
|
|
||||||
vp->setUndefined();
|
|
||||||
f.regs.sp = vp + 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UncachedInlineCall(f, 0, &ucr->codeAddr, argc))
|
if (!UncachedInlineCall(f, 0, &ucr->codeAddr, argc))
|
||||||
THROW();
|
THROW();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1368,14 +1368,10 @@ stubs::Neg(VMFrame &f)
|
||||||
JSObject * JS_FASTCALL
|
JSObject * JS_FASTCALL
|
||||||
stubs::NewInitArray(VMFrame &f, uint32 count)
|
stubs::NewInitArray(VMFrame &f, uint32 count)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSObject *obj = NewDenseAllocatedArray(f.cx, count);
|
||||||
gc::FinalizeKind kind = GuessObjectGCKind(count, true);
|
if (!obj)
|
||||||
|
|
||||||
JSObject *obj = NewArrayWithKind(cx, kind);
|
|
||||||
if (!obj || !obj->ensureSlots(cx, count))
|
|
||||||
THROWV(NULL);
|
THROWV(NULL);
|
||||||
|
|
||||||
obj->setArrayLength(count);
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2574,8 +2570,8 @@ stubs::Unbrand(VMFrame &f)
|
||||||
if (!thisv.isObject())
|
if (!thisv.isObject())
|
||||||
return;
|
return;
|
||||||
JSObject *obj = &thisv.toObject();
|
JSObject *obj = &thisv.toObject();
|
||||||
if (obj->isNative() && !obj->unbrand(f.cx))
|
if (obj->isNative())
|
||||||
THROW();
|
obj->unbrand(f.cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
|
|
|
@ -1975,7 +1975,7 @@ TryNotes(JSContext *cx, JSScript *script)
|
||||||
{
|
{
|
||||||
JSTryNote *tn, *tnlimit;
|
JSTryNote *tn, *tnlimit;
|
||||||
|
|
||||||
if (script->trynotesOffset == 0)
|
if (!JSScript::isValidOffset(script->trynotesOffset))
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
tn = script->trynotes()->vector;
|
tn = script->trynotes()->vector;
|
||||||
|
@ -2053,7 +2053,7 @@ DisassembleValue(JSContext *cx, jsval v, bool lines, bool recursive)
|
||||||
SrcNotes(cx, script);
|
SrcNotes(cx, script);
|
||||||
TryNotes(cx, script);
|
TryNotes(cx, script);
|
||||||
|
|
||||||
if (recursive && script->objectsOffset != 0) {
|
if (recursive && JSScript::isValidOffset(script->objectsOffset)) {
|
||||||
JSObjectArray *objects = script->objects();
|
JSObjectArray *objects = script->objects();
|
||||||
for (uintN i = 0; i != objects->length; ++i) {
|
for (uintN i = 0; i != objects->length; ++i) {
|
||||||
JSObject *obj = objects->vector[i];
|
JSObject *obj = objects->vector[i];
|
||||||
|
@ -2139,11 +2139,6 @@ DisassFile(JSContext *cx, uintN argc, jsval *vp)
|
||||||
if (!script)
|
if (!script)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
if (script->isEmpty()) {
|
|
||||||
JS_SET_RVAL(cx, vp, JSVAL_VOID);
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject *obj = JS_NewScriptObject(cx, script);
|
JSObject *obj = JS_NewScriptObject(cx, script);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
@ -4293,7 +4288,7 @@ static JSFunctionSpec shell_functions[] = {
|
||||||
JS_FN("startTraceVis", StartTraceVisNative, 1,0),
|
JS_FN("startTraceVis", StartTraceVisNative, 1,0),
|
||||||
JS_FN("stopTraceVis", StopTraceVisNative, 0,0),
|
JS_FN("stopTraceVis", StopTraceVisNative, 0,0),
|
||||||
#endif
|
#endif
|
||||||
#ifdef DEBUG_ARRAYS
|
#ifdef DEBUG
|
||||||
JS_FN("arrayInfo", js_ArrayInfo, 1,0),
|
JS_FN("arrayInfo", js_ArrayInfo, 1,0),
|
||||||
#endif
|
#endif
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
|
@ -4420,7 +4415,7 @@ static const char *const shell_help_messages[] = {
|
||||||
"startTraceVis(filename) Start TraceVis recording (stops any current recording)",
|
"startTraceVis(filename) Start TraceVis recording (stops any current recording)",
|
||||||
"stopTraceVis() Stop TraceVis recording",
|
"stopTraceVis() Stop TraceVis recording",
|
||||||
#endif
|
#endif
|
||||||
#ifdef DEBUG_ARRAYS
|
#ifdef DEBUG
|
||||||
"arrayInfo(a1, a2, ...) Report statistics about arrays",
|
"arrayInfo(a1, a2, ...) Report statistics about arrays",
|
||||||
#endif
|
#endif
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
|
|
|
@ -2,4 +2,5 @@ url-prefix ../../jsreftest.html?test=ecma_5/Array/
|
||||||
script sort-01.js
|
script sort-01.js
|
||||||
script toString-01.js
|
script toString-01.js
|
||||||
script toLocaleString-01.js
|
script toLocaleString-01.js
|
||||||
|
script regress-599159.js
|
||||||
script unshift-01.js
|
script unshift-01.js
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/
|
||||||
|
*/
|
||||||
|
|
||||||
|
var b = Object.create(Array.prototype);
|
||||||
|
b.length = 12;
|
||||||
|
assertEq(b.length, 12);
|
||||||
|
|
||||||
|
reportCompare(true,true);
|
|
@ -1,4 +1,5 @@
|
||||||
url-prefix ../../jsreftest.html?test=ecma_5/Expressions/
|
url-prefix ../../jsreftest.html?test=ecma_5/Expressions/
|
||||||
script 11.1.5-01.js
|
script 11.1.5-01.js
|
||||||
script named-accessor-function.js
|
script named-accessor-function.js
|
||||||
|
script nested-delete-name-in-evalcode.js
|
||||||
script object-literal-accessor-arguments.js
|
script object-literal-accessor-arguments.js
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
// Any copyright is dedicated to the Public Domain.
|
||||||
|
// http://creativecommons.org/licenses/publicdomain/
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
var BUGNUMBER = 616294;
|
||||||
|
var summary =
|
||||||
|
"|delete x| inside a function in eval code, where that eval code includes " +
|
||||||
|
"|var x| at top level, actually does delete the binding for x";
|
||||||
|
|
||||||
|
print(BUGNUMBER + ": " + summary);
|
||||||
|
|
||||||
|
/**************
|
||||||
|
* BEGIN TEST *
|
||||||
|
**************/
|
||||||
|
|
||||||
|
var f;
|
||||||
|
|
||||||
|
function testOuterVar()
|
||||||
|
{
|
||||||
|
return eval("var x; (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testOuterVar();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable, so remove => true
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testOuterFunction()
|
||||||
|
{
|
||||||
|
return eval("function x() { } (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testOuterFunction();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable, so remove => true
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testOuterForVar()
|
||||||
|
{
|
||||||
|
return eval("for (var x; false; ); (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testOuterForVar();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable, so remove => true
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testOuterForInVar()
|
||||||
|
{
|
||||||
|
return eval("for (var x in {}); (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testOuterForInVar();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable, so remove => true
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testOuterNestedVar()
|
||||||
|
{
|
||||||
|
return eval("for (var q = 0; q < 5; q++) { var x; } (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testOuterNestedVar();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable, so remove => true
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testOuterNestedConditionalVar()
|
||||||
|
{
|
||||||
|
return eval("for (var q = 0; q < 5; q++) { if (false) { var x; } } (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testOuterNestedConditionalVar();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable, so remove => true
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testVarInWith()
|
||||||
|
{
|
||||||
|
return eval("with ({}) { var x; } (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testVarInWith();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable, so remove => true
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testForVarInWith()
|
||||||
|
{
|
||||||
|
return eval("with ({}) { for (var x = 0; x < 5; x++); } (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testForVarInWith();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable, so remove => true
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testForInVarInWith()
|
||||||
|
{
|
||||||
|
return eval("with ({}) { for (var x in {}); } (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testForInVarInWith();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable, so remove => true
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testUnknown()
|
||||||
|
{
|
||||||
|
return eval("nameToDelete = 17; (function() { return delete nameToDelete; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testUnknown();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable global property, so remove => true
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testArgumentShadow()
|
||||||
|
{
|
||||||
|
return eval("var x; (function(x) { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testArgumentShadow();
|
||||||
|
|
||||||
|
assertEq(f(), false); // non-configurable argument => false
|
||||||
|
|
||||||
|
|
||||||
|
function testArgument()
|
||||||
|
{
|
||||||
|
return eval("(function(x) { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testArgument();
|
||||||
|
|
||||||
|
assertEq(f(), false); // non-configurable argument => false
|
||||||
|
|
||||||
|
|
||||||
|
function testFunctionLocal()
|
||||||
|
{
|
||||||
|
return eval("(function() { var x; return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testFunctionLocal();
|
||||||
|
|
||||||
|
assertEq(f(), false); // defined by function code => not configurable => false
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
||||||
|
|
||||||
|
print("All tests passed!");
|
|
@ -15,3 +15,4 @@ script watchpoint-deletes-JSPropertyOp-setter.js
|
||||||
script eval-native-callback-is-indirect.js
|
script eval-native-callback-is-indirect.js
|
||||||
script regress-bug607284.js
|
script regress-bug607284.js
|
||||||
script Object-keys-and-object-ids.js
|
script Object-keys-and-object-ids.js
|
||||||
|
fails script nested-delete-name-in-evalcode.js # bug 604301, at a minimum
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
// Any copyright is dedicated to the Public Domain.
|
||||||
|
// http://creativecommons.org/licenses/publicdomain/
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
var BUGNUMBER = 616294;
|
||||||
|
var summary =
|
||||||
|
"|delete x| inside a function in eval code, where that eval code includes " +
|
||||||
|
"|var x| at top level, actually does delete the binding for x";
|
||||||
|
|
||||||
|
print(BUGNUMBER + ": " + summary);
|
||||||
|
|
||||||
|
/**************
|
||||||
|
* BEGIN TEST *
|
||||||
|
**************/
|
||||||
|
|
||||||
|
var f;
|
||||||
|
|
||||||
|
function testOuterLet()
|
||||||
|
{
|
||||||
|
return eval("let x; (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testOuterLet();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable, so remove => true
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testOuterForLet()
|
||||||
|
{
|
||||||
|
return eval("for (let x; false; ); (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testOuterForLet();
|
||||||
|
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testOuterForInLet()
|
||||||
|
{
|
||||||
|
return eval("for (let x in {}); (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testOuterForInLet();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable, so remove => true
|
||||||
|
assertEq(f(), true); // not there => true (only non-configurable => false)
|
||||||
|
|
||||||
|
|
||||||
|
function testOuterNestedVarInLetBlock()
|
||||||
|
{
|
||||||
|
return eval("let (x = 7) { var x = 9; } (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testOuterNestedVarInLetBlock();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable var, so remove => true
|
||||||
|
assertEq(f(), true); // let still there, configurable => true
|
||||||
|
assertEq(f(), true); // nothing at all => true
|
||||||
|
|
||||||
|
|
||||||
|
function testOuterNestedVarInForLet()
|
||||||
|
{
|
||||||
|
return eval("for (let q = 0; q < 5; q++) { var x; } (function() { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testOuterNestedVarInForLet();
|
||||||
|
|
||||||
|
assertEq(f(), true); // configurable, so remove => true
|
||||||
|
assertEq(f(), true); // there => true
|
||||||
|
|
||||||
|
|
||||||
|
function testArgumentShadowLet()
|
||||||
|
{
|
||||||
|
return eval("let x; (function(x) { return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testArgumentShadowLet();
|
||||||
|
|
||||||
|
assertEq(f(), false); // non-configurable argument => false
|
||||||
|
|
||||||
|
|
||||||
|
function testFunctionLocal()
|
||||||
|
{
|
||||||
|
return eval("(function() { let x; return delete x; })");
|
||||||
|
}
|
||||||
|
|
||||||
|
f = testFunctionLocal();
|
||||||
|
|
||||||
|
assertEq(f(), false); // defined by function code => not configurable => false
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
||||||
|
|
||||||
|
print("All tests passed!");
|
|
@ -0,0 +1,78 @@
|
||||||
|
// Any copyright is dedicated to the Public Domain.
|
||||||
|
// http://creativecommons.org/licenses/publicdomain/
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
var BUGNUMBER = 601262;
|
||||||
|
var summary =
|
||||||
|
"A string literal containing an octal escape before a strict mode " +
|
||||||
|
"directive should be a syntax error";
|
||||||
|
|
||||||
|
print(BUGNUMBER + ": " + summary);
|
||||||
|
|
||||||
|
/**************
|
||||||
|
* BEGIN TEST *
|
||||||
|
**************/
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
eval(" '\\145'; 'use strict'; ");
|
||||||
|
throw new Error("no error thrown for eval");
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
assertEq(e instanceof SyntaxError, true,
|
||||||
|
"wrong error for octal-escape before strict directive in eval");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Function(" '\\145'; 'use strict'; ");
|
||||||
|
throw new Error("no error thrown for Function");
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
assertEq(e instanceof SyntaxError, true,
|
||||||
|
"wrong error for octal-escape before strict directive in Function");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
eval(" function f(){ '\\145'; 'use strict'; } ");
|
||||||
|
throw new Error("no error thrown for eval of function");
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
assertEq(e instanceof SyntaxError, true,
|
||||||
|
"wrong error for octal-escape before strict directive in eval of " +
|
||||||
|
"function");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Function(" function f(){ '\\145'; 'use strict'; } ");
|
||||||
|
throw new Error("no error thrown for eval of function");
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
assertEq(e instanceof SyntaxError, true,
|
||||||
|
"wrong error for octal-escape before strict directive in eval of " +
|
||||||
|
"function");
|
||||||
|
}
|
||||||
|
|
||||||
|
eval("function notAnError1() { 5; '\\145'; function g() { 'use strict'; } }");
|
||||||
|
|
||||||
|
Function("function notAnError2() { 5; '\\145'; function g() { 'use strict'; } }");
|
||||||
|
|
||||||
|
function notAnError3()
|
||||||
|
{
|
||||||
|
5;
|
||||||
|
"\145";
|
||||||
|
function g() { "use strict"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
||||||
|
|
||||||
|
print("All tests passed!");
|
|
@ -25,7 +25,7 @@ script 15.4.4.8.js
|
||||||
script 15.4.4.9.js
|
script 15.4.4.9.js
|
||||||
script 15.4.4.12.js
|
script 15.4.4.12.js
|
||||||
script 15.4.4.13.js
|
script 15.4.4.13.js
|
||||||
script 15.4.5.1.js
|
skip script 15.4.5.1.js # Waiting for bug 537873 to be fully resolved.
|
||||||
script 15.5.5.1.js
|
script 15.5.5.1.js
|
||||||
script 15.5.5.2.js
|
script 15.5.5.2.js
|
||||||
script 15.10.7.js
|
script 15.10.7.js
|
||||||
|
@ -37,3 +37,4 @@ script regress-532254.js
|
||||||
script regress-532041.js
|
script regress-532041.js
|
||||||
script unbrand-this.js
|
script unbrand-this.js
|
||||||
script this-for-function-expression-recursion.js
|
script this-for-function-expression-recursion.js
|
||||||
|
script directive-prologue-01.js
|
||||||
|
|
|
@ -236,6 +236,7 @@ function test()
|
||||||
|
|
||||||
empty.set([]);
|
empty.set([]);
|
||||||
empty.set([], 0);
|
empty.set([], 0);
|
||||||
|
empty.set(empty);
|
||||||
|
|
||||||
checkThrows(function() empty.set([1]));
|
checkThrows(function() empty.set([1]));
|
||||||
checkThrows(function() empty.set([1], 0));
|
checkThrows(function() empty.set([1], 0));
|
||||||
|
@ -244,6 +245,7 @@ function test()
|
||||||
a.set([]);
|
a.set([]);
|
||||||
a.set([], 3);
|
a.set([], 3);
|
||||||
a.set([], 9);
|
a.set([], 9);
|
||||||
|
a.set(a);
|
||||||
|
|
||||||
a.set(empty);
|
a.set(empty);
|
||||||
a.set(empty, 3);
|
a.set(empty, 3);
|
||||||
|
|
|
@ -56,3 +56,5 @@ script regress-610026.js
|
||||||
script regress-609617.js
|
script regress-609617.js
|
||||||
script regress-617405-1.js
|
script regress-617405-1.js
|
||||||
script regress-617405-2.js
|
script regress-617405-2.js
|
||||||
|
skip-if(!xulRuntime.shell) script regress-618576.js # uses evalcx
|
||||||
|
fails-if(!xulRuntime.shell) script regress-618652.js
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/
|
||||||
|
* Contributors: Gary Kwong and Jason Orendorff
|
||||||
|
*/
|
||||||
|
|
||||||
|
var x = <x/>;
|
||||||
|
x.function::__proto__ = evalcx('');
|
||||||
|
for (a in x) // don't assert
|
||||||
|
;
|
||||||
|
|
||||||
|
reportCompare(0, 0, 'ok');
|
|
@ -0,0 +1,10 @@
|
||||||
|
options('atline')
|
||||||
|
|
||||||
|
var F, L;
|
||||||
|
|
||||||
|
eval('//@line 42 "foo"\n' +
|
||||||
|
'try { nosuchname; } catch (e) { F = e.fileName; L = e.lineNumber; }');
|
||||||
|
assertEq(F, "foo");
|
||||||
|
assertEq(L, 42);
|
||||||
|
|
||||||
|
reportCompare(0, 0, "ok");
|
|
@ -221,36 +221,7 @@ Atob(JSContext *cx, uintN argc, jsval *vp)
|
||||||
if (!argc)
|
if (!argc)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
JSString *str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
|
return nsXPConnect::Base64Decode(cx, JS_ARGV(cx, vp)[0], &JS_RVAL(cx, vp));
|
||||||
if (!str)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
size_t len = JS_GetStringEncodingLength(cx, str);
|
|
||||||
if (len == size_t(-1))
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
JSUint32 alloc_len = (len + 1) * sizeof(char);
|
|
||||||
char *buffer = static_cast<char *>(nsMemory::Alloc(alloc_len));
|
|
||||||
if (!buffer)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
JS_EncodeStringToBuffer(str, buffer, len);
|
|
||||||
buffer[len] = '\0';
|
|
||||||
|
|
||||||
nsDependentCString string(buffer, JS_GetStringLength(str));
|
|
||||||
nsCAutoString result;
|
|
||||||
|
|
||||||
if (NS_FAILED(nsXPConnect::Base64Decode(string, result))) {
|
|
||||||
JS_ReportError(cx, "Failed to decode base64 string!");
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
str = JS_NewStringCopyN(cx, result.get(), result.Length());
|
|
||||||
if (!str)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
|
@ -259,36 +230,7 @@ Btoa(JSContext *cx, uintN argc, jsval *vp)
|
||||||
if (!argc)
|
if (!argc)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
JSString *str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
|
return nsXPConnect::Base64Encode(cx, JS_ARGV(cx, vp)[0], &JS_RVAL(cx, vp));
|
||||||
if (!str)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
size_t len = JS_GetStringEncodingLength(cx, str);
|
|
||||||
if (len == size_t(-1))
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
JSUint32 alloc_len = (len + 1) * sizeof(char);
|
|
||||||
char *buffer = static_cast<char *>(nsMemory::Alloc(alloc_len));
|
|
||||||
if (!buffer)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
JS_EncodeStringToBuffer(str, buffer, len);
|
|
||||||
buffer[len] = '\0';
|
|
||||||
|
|
||||||
nsDependentCString data(buffer, len);
|
|
||||||
nsCAutoString result;
|
|
||||||
|
|
||||||
if (NS_FAILED(nsXPConnect::Base64Encode(data, result))) {
|
|
||||||
JS_ReportError(cx, "Failed to encode base64 data!");
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
str = JS_NewStringCopyN(cx, result.get(), result.Length());
|
|
||||||
if (!str)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSFunctionSpec gGlobalFun[] = {
|
static JSFunctionSpec gGlobalFun[] = {
|
||||||
|
|
|
@ -64,6 +64,8 @@
|
||||||
|
|
||||||
#include "jsdIDebuggerService.h"
|
#include "jsdIDebuggerService.h"
|
||||||
|
|
||||||
|
#include "xpcquickstubs.h"
|
||||||
|
|
||||||
NS_IMPL_THREADSAFE_ISUPPORTS6(nsXPConnect,
|
NS_IMPL_THREADSAFE_ISUPPORTS6(nsXPConnect,
|
||||||
nsIXPConnect,
|
nsIXPConnect,
|
||||||
nsISupportsWeakReference,
|
nsISupportsWeakReference,
|
||||||
|
@ -2615,8 +2617,7 @@ nsXPConnect::GetCaller(JSContext **aJSContext, JSObject **aObj)
|
||||||
|
|
||||||
// static
|
// static
|
||||||
nsresult
|
nsresult
|
||||||
nsXPConnect::Base64Encode(const nsACString &aBinaryData,
|
nsXPConnect::Base64Encode(const nsACString &aBinaryData, nsACString &aString)
|
||||||
nsACString &aString)
|
|
||||||
{
|
{
|
||||||
// Check for overflow.
|
// Check for overflow.
|
||||||
if(aBinaryData.Length() > (PR_UINT32_MAX / 4) * 3)
|
if(aBinaryData.Length() > (PR_UINT32_MAX / 4) * 3)
|
||||||
|
@ -2645,8 +2646,7 @@ nsXPConnect::Base64Encode(const nsACString &aBinaryData,
|
||||||
|
|
||||||
// static
|
// static
|
||||||
nsresult
|
nsresult
|
||||||
nsXPConnect::Base64Encode(const nsAString &aString,
|
nsXPConnect::Base64Encode(const nsAString &aString, nsAString &aBinaryData)
|
||||||
nsAString &aBinaryData)
|
|
||||||
{
|
{
|
||||||
NS_LossyConvertUTF16toASCII string(aString);
|
NS_LossyConvertUTF16toASCII string(aString);
|
||||||
nsCAutoString binaryData;
|
nsCAutoString binaryData;
|
||||||
|
@ -2660,10 +2660,37 @@ nsXPConnect::Base64Encode(const nsAString &aString,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
JSBool
|
||||||
|
nsXPConnect::Base64Encode(JSContext *cx, jsval val, jsval *out)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(cx, "Null context!");
|
||||||
|
NS_ASSERTION(out, "Null jsval pointer!");
|
||||||
|
|
||||||
|
jsval root = val;
|
||||||
|
xpc_qsACString encodedString(cx, root, &root, xpc_qsACString::eNull,
|
||||||
|
xpc_qsACString::eStringify);
|
||||||
|
if(!encodedString.IsValid())
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
nsCAutoString result;
|
||||||
|
if(NS_FAILED(nsXPConnect::Base64Encode(encodedString, result)))
|
||||||
|
{
|
||||||
|
JS_ReportError(cx, "Failed to encode base64 data!");
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSString *str = JS_NewStringCopyN(cx, result.get(), result.Length());
|
||||||
|
if (!str)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
*out = STRING_TO_JSVAL(str);
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
nsresult
|
nsresult
|
||||||
nsXPConnect::Base64Decode(const nsACString &aString,
|
nsXPConnect::Base64Decode(const nsACString &aString, nsACString &aBinaryData)
|
||||||
nsACString &aBinaryData)
|
|
||||||
{
|
{
|
||||||
// Check for overflow.
|
// Check for overflow.
|
||||||
if(aString.Length() > PR_UINT32_MAX / 3)
|
if(aString.Length() > PR_UINT32_MAX / 3)
|
||||||
|
@ -2700,8 +2727,7 @@ nsXPConnect::Base64Decode(const nsACString &aString,
|
||||||
|
|
||||||
// static
|
// static
|
||||||
nsresult
|
nsresult
|
||||||
nsXPConnect::Base64Decode(const nsAString &aBinaryData,
|
nsXPConnect::Base64Decode(const nsAString &aBinaryData, nsAString &aString)
|
||||||
nsAString &aString)
|
|
||||||
{
|
{
|
||||||
NS_LossyConvertUTF16toASCII binaryData(aBinaryData);
|
NS_LossyConvertUTF16toASCII binaryData(aBinaryData);
|
||||||
nsCAutoString string;
|
nsCAutoString string;
|
||||||
|
@ -2715,6 +2741,34 @@ nsXPConnect::Base64Decode(const nsAString &aBinaryData,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
JSBool
|
||||||
|
nsXPConnect::Base64Decode(JSContext *cx, jsval val, jsval *out)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(cx, "Null context!");
|
||||||
|
NS_ASSERTION(out, "Null jsval pointer!");
|
||||||
|
|
||||||
|
jsval root = val;
|
||||||
|
xpc_qsACString encodedString(cx, root, &root, xpc_qsACString::eNull,
|
||||||
|
xpc_qsACString::eNull);
|
||||||
|
if(!encodedString.IsValid())
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
nsCAutoString result;
|
||||||
|
if(NS_FAILED(nsXPConnect::Base64Decode(encodedString, result)))
|
||||||
|
{
|
||||||
|
JS_ReportError(cx, "Failed to decode base64 string!");
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSString *str = JS_NewStringCopyN(cx, result.get(), result.Length());
|
||||||
|
if(!str)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
*out = STRING_TO_JSVAL(str);
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXPConnect::SetDebugModeWhenPossible(PRBool mode)
|
nsXPConnect::SetDebugModeWhenPossible(PRBool mode)
|
||||||
{
|
{
|
||||||
|
|
|
@ -570,12 +570,18 @@ public:
|
||||||
static nsresult Base64Encode(const nsAString &aString,
|
static nsresult Base64Encode(const nsAString &aString,
|
||||||
nsAString &aBinaryData);
|
nsAString &aBinaryData);
|
||||||
|
|
||||||
|
// If this returns JS_FALSE then an exception will be set on cx.
|
||||||
|
static JSBool Base64Encode(JSContext *cx, jsval val, jsval *out);
|
||||||
|
|
||||||
static nsresult Base64Decode(const nsACString &aBinaryData,
|
static nsresult Base64Decode(const nsACString &aBinaryData,
|
||||||
nsACString &aString);
|
nsACString &aString);
|
||||||
|
|
||||||
static nsresult Base64Decode(const nsAString &aBinaryData,
|
static nsresult Base64Decode(const nsAString &aBinaryData,
|
||||||
nsAString &aString);
|
nsAString &aString);
|
||||||
|
|
||||||
|
// If this returns JS_FALSE then an exception will be set on cx.
|
||||||
|
static JSBool Base64Decode(JSContext *cx, jsval val, jsval *out);
|
||||||
|
|
||||||
// nsCycleCollectionParticipant
|
// nsCycleCollectionParticipant
|
||||||
NS_IMETHOD RootAndUnlinkJSObjects(void *p);
|
NS_IMETHOD RootAndUnlinkJSObjects(void *p);
|
||||||
NS_IMETHOD Unlink(void *p);
|
NS_IMETHOD Unlink(void *p);
|
||||||
|
|
|
@ -709,14 +709,24 @@ xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval,
|
||||||
mValid = JS_TRUE;
|
mValid = JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
xpc_qsACString::xpc_qsACString(JSContext *cx, jsval v, jsval *pval)
|
xpc_qsACString::xpc_qsACString(JSContext *cx, jsval v, jsval *pval,
|
||||||
|
StringificationBehavior nullBehavior,
|
||||||
|
StringificationBehavior undefinedBehavior)
|
||||||
{
|
{
|
||||||
typedef implementation_type::char_traits traits;
|
typedef implementation_type::char_traits traits;
|
||||||
// From the T_CSTRING case in XPCConvert::JSData2Native.
|
// From the T_CSTRING case in XPCConvert::JSData2Native.
|
||||||
JSString *s = InitOrStringify<traits>(cx, v, pval, eNull, eNull);
|
JSString *s = InitOrStringify<traits>(cx, v, pval, nullBehavior,
|
||||||
|
undefinedBehavior);
|
||||||
if (!s)
|
if (!s)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
size_t len = JS_GetStringEncodingLength(cx, s);
|
||||||
|
if(len == size_t(-1))
|
||||||
|
{
|
||||||
|
mValid = JS_FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
JSAutoByteString bytes(cx, s);
|
JSAutoByteString bytes(cx, s);
|
||||||
if(!bytes)
|
if(!bytes)
|
||||||
{
|
{
|
||||||
|
@ -724,7 +734,7 @@ xpc_qsACString::xpc_qsACString(JSContext *cx, jsval v, jsval *pval)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
new(mBuf) implementation_type(bytes.ptr(), strlen(bytes.ptr()));
|
new(mBuf) implementation_type(bytes.ptr(), len);
|
||||||
mValid = JS_TRUE;
|
mValid = JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -439,7 +439,9 @@ public:
|
||||||
class xpc_qsACString : public xpc_qsBasicString<nsACString, nsCString>
|
class xpc_qsACString : public xpc_qsBasicString<nsACString, nsCString>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
xpc_qsACString(JSContext *cx, jsval v, jsval *pval);
|
xpc_qsACString(JSContext *cx, jsval v, jsval *pval,
|
||||||
|
StringificationBehavior nullBehavior = eNull,
|
||||||
|
StringificationBehavior undefinedBehavior = eNull);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Загрузка…
Ссылка в новой задаче