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:
Robert Sayre 2010-12-15 12:21:50 -08:00
Родитель 8e7827bf42 e46d5e99d6
Коммит ecc4cfb7c4
75 изменённых файлов: 1286 добавлений и 1074 удалений

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

@ -1911,13 +1911,13 @@ case "$host" in
esac
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(,)
$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=$?
changequote([,])
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
AC_MSG_RESULT([yes])

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

@ -159,7 +159,6 @@ nsDOMWorkerFunctions::MakeTimeout(JSContext* aCx,
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
if (worker->IsCanceled()) {
JS_ReportError(aCx, "Worker is canceled");
return JS_FALSE;
}
@ -208,7 +207,6 @@ nsDOMWorkerFunctions::KillTimeout(JSContext* aCx,
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
if (worker->IsCanceled()) {
JS_ReportError(aCx, "Worker is canceled");
return JS_FALSE;
}
@ -237,7 +235,6 @@ nsDOMWorkerFunctions::LoadScripts(JSContext* aCx,
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
if (worker->IsCanceled()) {
JS_ReportError(aCx, "Worker is canceled");
return JS_FALSE;
}
@ -313,7 +310,6 @@ nsDOMWorkerFunctions::NewXMLHttpRequest(JSContext* aCx,
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
if (worker->IsCanceled()) {
JS_ReportError(aCx, "Worker is canceled");
return JS_FALSE;
}
@ -363,7 +359,6 @@ nsDOMWorkerFunctions::AtoB(JSContext* aCx,
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
if (worker->IsCanceled()) {
JS_ReportError(aCx, "Worker is canceled");
return JS_FALSE;
}
@ -372,39 +367,8 @@ nsDOMWorkerFunctions::AtoB(JSContext* aCx,
return JS_FALSE;
}
JSString* str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0]);
if (!str) {
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;
return nsXPConnect::Base64Decode(aCx, JS_ARGV(aCx, aVp)[0],
&JS_RVAL(aCx, aVp));
}
JSBool
@ -416,7 +380,6 @@ nsDOMWorkerFunctions::BtoA(JSContext* aCx,
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
if (worker->IsCanceled()) {
JS_ReportError(aCx, "Worker is canceled");
return JS_FALSE;
}
@ -425,39 +388,8 @@ nsDOMWorkerFunctions::BtoA(JSContext* aCx,
return JS_FALSE;
}
JSString* str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0]);
if (!str) {
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;
return nsXPConnect::Base64Encode(aCx, JS_ARGV(aCx, aVp)[0],
&JS_RVAL(aCx, aVp));
}
JSBool
@ -491,7 +423,6 @@ nsDOMWorkerFunctions::MakeNewWorker(JSContext* aCx,
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
if (worker->IsCanceled()) {
JS_ReportError(aCx, "Worker is canceled");
return JS_FALSE;
}
@ -585,7 +516,6 @@ nsDOMWorkerFunctions::CTypesLazyGetter(JSContext* aCx,
NS_ASSERTION(worker->IsPrivileged(), "This shouldn't be possible!");
if (worker->IsCanceled()) {
JS_ReportError(aCx, "Worker is canceled");
return JS_FALSE;
}

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

@ -1,7 +1,5 @@
var data = [ -1, 0, 1, 1.5, undefined, true, false ];
// 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 data = [ -1, 0, 1, 1.5, null, undefined, true, false, "foo",
"123456789012345", "1234567890123456", "12345678901234567"];
var str = "";
for (var i = 0; i < 30; i++) {

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

@ -1168,6 +1168,19 @@ private:
);
#endif
#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 (
"movl $0x1, %eax;"
"pushl %ebx;"
@ -1179,6 +1192,7 @@ private:
: "S" (&flags_ecx), "D" (&flags_edx)
: "%eax", "%ecx", "%edx"
);
#endif
#endif
static const int SSEFeatureBit = 1 << 25;
static const int SSE2FeatureBit = 1 << 26;

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

@ -986,7 +986,7 @@ else
AC_MSG_RESULT([yes])
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
AC_MSG_ERROR([python was not found in \$PATH])
fi
@ -1900,13 +1900,13 @@ esac
dnl We require version 2.4 or newer of Python to build,
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(,)
$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=$?
changequote([,])
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
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;
}
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);
/* NB: jsuint cast does ToUint32. */
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)
@ -4672,7 +4672,6 @@ JS_NewScriptObject(JSContext *cx, JSScript *script)
* described in the comment for JSScript::u.object.
*/
JS_ASSERT(script->u.object);
JS_ASSERT(script != JSScript::emptyScript());
return script->u.object;
}
@ -4889,7 +4888,7 @@ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, script);
/* 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));
LAST_FRAME_CHECKS(cx, 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_NewStringCopyN(JSContext *cx, const char *s, size_t n)
{

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

@ -1335,63 +1335,23 @@ namespace js {
* than that, we have avoided all garbage collection hazards.
*/
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>
class Anchor: AnchorPermitted<T> {
public:
Anchor() { }
explicit Anchor(T t) { hold = t; }
~Anchor() {
#ifdef __GNUC__
/*
* 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
/*
* 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; }
inline ~Anchor();
T &get() { return hold; }
void set(const T &t) { hold = t; }
void clear() { hold = 0; }
private:
T hold;
/* Anchors should not be assigned or passed to functions. */
@ -1399,44 +1359,71 @@ class Anchor: AnchorPermitted<T> {
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
* scanner doesn't actually recgonize fail. Such anchors would have no effect.
* 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| 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 {
protected:
#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
template<typename T> void doAssignment(volatile T &lhs, const T &rhs) {
lhs = rhs;
}
template<>
inline Anchor<jsval>::~Anchor() {
volatile jsval sink;
sink.asBits = hold.asBits;
}
#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
};
} /* namespace js */
@ -2932,15 +2919,12 @@ JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp);
/*
* Strings.
*
* NB: JS_NewString takes ownership of bytes on success, avoiding a copy; but
* on error (signified by null return), it leaves bytes owned by the caller.
* So the caller must free bytes in the error case, if it has no use for them.
* In contrast, all the JS_New*StringCopy* functions do not take ownership of
* the character memory passed to them -- they copy it.
* NB: JS_NewUCString takes ownership of bytes on success, avoiding a copy;
* but on error (signified by null return), it leaves chars owned by the
* caller. So the caller must free bytes in the error case, if it has no use
* for them. In contrast, all the JS_New*StringCopy* functions do not take
* 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 *)
JS_NewStringCopyN(JSContext *cx, const char *s, size_t n);

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

@ -52,13 +52,15 @@
* - The number of element slots (capacity), gettable with
* getDenseArrayCapacity().
*
* In dense mode, holes in the array are represented by (JS_ARRAY_HOLE) invalid
* values. The final slot in fslots is unused.
* In dense mode, holes in the array are represented by
* MagicValue(JS_ARRAY_HOLE) invalid values.
*
* 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
* array_length_setter for an explanation of how the first, most surprising
* case may occur.
* length may be greater than, less than, or equal to the capacity. The first
* case may occur when the user writes "new Array(100), in which case the
* 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
* are met:
@ -170,14 +172,16 @@ js_StringIsIndex(JSString *str, jsuint *indexp)
return JS_FALSE;
}
static jsuint
ValueIsLength(JSContext *cx, Value* vp)
static bool
ValueToLength(JSContext *cx, Value* vp, jsuint* plength)
{
if (vp->isInt32()) {
int32_t i = vp->toInt32();
if (i < 0)
goto error;
return (jsuint) i;
*plength = (jsuint)(i);
return true;
}
jsdouble d;
@ -186,18 +190,20 @@ ValueIsLength(JSContext *cx, Value* vp)
if (JSDOUBLE_IS_NaN(d))
goto error;
jsuint length;
length = (jsuint) d;
if (d != (jsdouble) length)
goto error;
vp->setNumber(length);
return length;
error:
*plength = length;
return true;
error:
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_ARRAY_LENGTH);
vp->setNull();
return 0;
return false;
}
JSBool
@ -557,8 +563,10 @@ js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
if (!ok)
return false;
*lengthp = ValueIsLength(cx, tvr.addr());
return !tvr.value().isNull();
if (!ValueToLength(cx, tvr.addr(), lengthp))
return false;
return true;
}
/*
@ -581,27 +589,20 @@ array_length_getter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
}
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;
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()) {
jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
return obj->defineProperty(cx, lengthId, *vp, NULL, NULL, JSPROP_ENUMERATE);
}
newlen = ValueIsLength(cx, vp);
if (vp->isNull())
if (!ValueToLength(cx, vp, &newlen))
return false;
oldlen = obj->getArrayLength();
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)) {
obj->setArrayLength(oldlen + 1);
if (strict)
return false;
JS_ClearPendingException(cx);
return true;
}
@ -798,7 +797,7 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool stric
uint32 i;
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())
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);
}
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
js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
{
@ -996,34 +984,7 @@ Class js_SlowArrayClass = {
PropertyStub, /* setProperty */
EnumerateStub,
ResolveStub,
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 */
}
js_TryValueOf
};
/*
@ -1053,7 +1014,7 @@ JSObject::makeDenseArraySlow(JSContext *cx)
* The getter/setter here will directly access the object's private value.
*/
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)) {
setMap(oldMap);
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
* 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)
return JS_FALSE;
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 (count > 0) {
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
!js_PrototypeHasIndexedProperties(cx, obj2) &&
end <= obj->getDenseArrayCapacity()) {
if (!InitArrayObject(cx, obj2, count, obj->getDenseArrayElements() + begin))
return JS_FALSE;
@ -2459,7 +2419,7 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
*/
length = aobj->getArrayLength();
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)
return JS_FALSE;
nobj->setArrayLength(length);
@ -2469,7 +2429,7 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
argc--;
p++;
} else {
nobj = js_NewArrayObject(cx, 0, NULL);
nobj = NewDenseEmptyArray(cx);
if (!nobj)
return JS_FALSE;
vp->setObject(*nobj);
@ -2490,8 +2450,8 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
if (!aobj->getProperty(cx, id, tvr.addr()))
return false;
jsuint alength = ValueIsLength(cx, tvr.addr());
if (tvr.value().isNull())
jsuint alength;
if (!ValueToLength(cx, tvr.addr(), &alength))
return false;
for (jsuint slot = 0; slot < alength; slot++) {
JSBool hole;
@ -2572,7 +2532,7 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
!js_PrototypeHasIndexedProperties(cx, obj)) {
nobj = js_NewArrayObject(cx, end - begin, obj->getDenseArrayElements() + begin);
nobj = NewDenseCopiedArray(cx, end - begin, obj->getDenseArrayElements() + begin);
if (!nobj)
return JS_FALSE;
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. */
nobj = js_NewArrayObject(cx, 0, NULL);
nobj = NewDenseAllocatedArray(cx, end - begin);
if (!nobj)
return JS_FALSE;
vp->setObject(*nobj);
@ -2595,7 +2555,7 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
}
return js_SetLengthProperty(cx, nobj, end - begin);
return JS_TRUE;
}
#if JS_HAS_ARRAY_EXTRAS
@ -2757,7 +2717,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
case MAP:
case FILTER:
newlen = (mode == MAP) ? length : 0;
newarr = js_NewArrayObject(cx, newlen, NULL);
newarr = NewDenseAllocatedArray(cx, newlen);
if (!newarr)
return JS_FALSE;
vp->setObject(*newarr);
@ -2964,86 +2924,31 @@ static JSFunctionSpec array_static_methods[] = {
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
js_Array(JSContext *cx, uintN argc, Value *vp)
{
jsuint length;
const Value *vector;
JSObject *obj;
if (argc == 0) {
length = 0;
vector = NULL;
obj = NewDenseEmptyArray(cx);
} else if (argc > 1) {
length = (jsuint) argc;
vector = vp + 2;
obj = NewDenseCopiedArray(cx, argc, vp + 2);
} else if (!vp[2].isNumber()) {
length = 1;
vector = vp + 2;
obj = NewDenseCopiedArray(cx, 1, vp + 2);
} else {
length = ValueIsLength(cx, vp + 2);
if (vp[2].isNull())
jsuint length;
if (!ValueToLength(cx, vp + 2, &length))
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)
return JS_FALSE;
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 *
js_InitArrayClass(JSContext *cx, JSObject *obj)
{
@ -3062,31 +2967,83 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
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)
return NULL;
/*
* 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);
obj->setArrayLength(0);
return obj;
}
}
#ifdef DEBUG
JSBool
js_ArrayInfo(JSContext *cx, uintN argc, jsval *vp)
@ -3241,10 +3198,11 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
vector.append(val);
}
*clone = js_NewArrayObject(cx, jsvalCount, vector.begin());
*clone = NewDenseCopiedArray(cx, jsvalCount, vector.begin());
if (!*clone)
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;
}

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

@ -177,12 +177,33 @@ js_InitArrayClass(JSContext *cx, JSObject *obj);
extern bool
js_InitContextBusyArrayTable(JSContext *cx);
extern JSObject *
js_NewArrayObject(JSContext *cx, jsuint length, const js::Value *vector);
namespace js
{
/* 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 *
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
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
@ -283,25 +304,6 @@ js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id,
JSBool
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
* primitive values.

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

@ -575,8 +575,11 @@ js_dmod(jsdouble a, jsdouble b);
#endif /* !JS_TRACER */
/* Defined in jsarray.cpp. */
JS_DECLARE_CALLINFO(js_NewEmptyArray)
JS_DECLARE_CALLINFO(js_NewPreallocatedArray)
namespace js {
JS_DECLARE_CALLINFO(NewDenseEmptyArray)
JS_DECLARE_CALLINFO(NewDenseAllocatedArray)
JS_DECLARE_CALLINFO(NewDenseUnallocatedArray)
}
JS_DECLARE_CALLINFO(js_ArrayCompPush_tn)
JS_DECLARE_CALLINFO(js_EnsureDenseArrayCapacity)

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

@ -763,7 +763,7 @@ JSStructuredCloneReader::startRead(Value *vp)
case SCTAG_ARRAY_OBJECT:
case SCTAG_OBJECT_OBJECT: {
JSObject *obj = (tag == SCTAG_ARRAY_OBJECT)
? js_NewArrayObject(context(), 0, NULL)
? NewDenseEmptyArray(context())
: NewBuiltinClassInstance(context(), &js_ObjectClass);
if (!obj || !objs.append(ObjectValue(*obj)))
return false;

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

@ -591,7 +591,7 @@ class CompartmentChecker
}
void check(JSScript *script) {
if (script && script != JSScript::emptyScript()) {
if (script) {
check(script->compartment);
if (script->u.object)
check(script->u.object);

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

@ -265,12 +265,6 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
if (!CheckDebugMode(cx))
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);
junk = NULL;
rt = cx->runtime;
@ -1761,7 +1755,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
continue;
nbytes += (sn - notes + 1) * sizeof *sn;
if (script->objectsOffset != 0) {
if (JSScript::isValidOffset(script->objectsOffset)) {
objarray = script->objects();
i = objarray->length;
nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
@ -1770,7 +1764,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
} while (i != 0);
}
if (script->regexpsOffset != 0) {
if (JSScript::isValidOffset(script->regexpsOffset)) {
objarray = script->regexps();
i = objarray->length;
nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
@ -1779,7 +1773,7 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
} while (i != 0);
}
if (script->trynotesOffset != 0) {
if (JSScript::isValidOffset(script->trynotesOffset)) {
nbytes += sizeof(JSTryNoteArray) +
script->trynotes()->length * sizeof(JSTryNote);
}

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

@ -1737,7 +1737,7 @@ LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
break;
}
}
} while ((cg = (JSCodeGenerator *) cg->parent) != NULL);
} while (cg->parent && (cg = cg->parent->asCodeGenerator()));
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
* bindings visible to the compiler are permanent in JS unless the
* declaration originates in eval code. We detect eval code by testing
* 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.
* declaration originates at top level in eval code.
*/
switch (op) {
case JSOP_NAME:
@ -2175,7 +2169,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
break;
case JSOP_DELNAME:
if (dn_kind != JSDefinition::UNKNOWN) {
if (cg->parser->callerFrame && !cg->funbox)
if (cg->parser->callerFrame && dn->isTopLevel())
JS_ASSERT(cg->compileAndGo());
else
pn->pn_op = JSOP_FALSE;
@ -2353,9 +2347,8 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JSTreeContext *tc = cg;
while (tc->staticLevel != level)
tc = tc->parent;
JS_ASSERT(tc->compiling());
JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
JSCodeGenerator *evalcg = tc->asCodeGenerator();
JS_ASSERT(evalcg->compileAndGo());
JS_ASSERT(caller->isFunctionFrame());
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);
UpvarCookie *vector = cg->upvarMap.vector;
if (!vector) {
uint32 length = cg->lexdeps.count;
vector = (UpvarCookie *) js_calloc(length * sizeof *vector);
uint32 length = cg->lexdeps.count;
if (!vector || cg->upvarMap.length != length) {
vector = (UpvarCookie *) js_realloc(vector, length * sizeof *vector);
if (!vector) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
@ -2455,6 +2447,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
slot += tc->fun()->nargs;
}
JS_ASSERT(index < cg->upvarMap.length);
vector[index].set(skip, slot);
}
@ -4601,11 +4594,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
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,
FUN_KIND(fun) == JSFUN_INTERPRETED);
@ -4625,7 +4613,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (!cg2->init())
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 (cg2->flags & TCF_HAS_SHARPS) {
cg2->sharpSlotBase = fun->sharpSlotBase(cx);

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

@ -364,8 +364,16 @@ struct JSTreeContext { /* tree context for semantic checks */
JSObject *blockChain() {
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. */
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 inFunction() const { return flags & TCF_IN_FUNCTION; }
bool compiling() const { return flags & TCF_COMPILING; }
inline JSCodeGenerator *asCodeGenerator();
bool usesArguments() const {
return flags & TCF_FUN_USES_ARGUMENTS;
@ -594,7 +604,7 @@ struct JSCodeGenerator : public JSTreeContext
SlotVector closedVars;
uint16 traceIndex; /* index for the next JSOP_TRACE instruction */
/*
* Initialize cg to allocate bytecode space from codePool, source note
* 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_PROLOG(cg) ((cg)->current = &(cg)->prolog)
inline JSCodeGenerator *
JSTreeContext::asCodeGenerator()
{
JS_ASSERT(compiling());
return static_cast<JSCodeGenerator *>(this);
}
/*
* 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. */
JSScript *wscript = JSScript::NewScript(cx, script->length, nsrcnotes,
script->atomMap.length,
(script->objectsOffset != 0)
JSScript::isValidOffset(script->objectsOffset)
? script->objects()->length
: 0,
fun->u.i.nupvars,
(script->regexpsOffset != 0)
JSScript::isValidOffset(script->regexpsOffset)
? script->regexps()->length
: 0,
(script->trynotesOffset != 0)
JSScript::isValidOffset(script->trynotesOffset)
? script->trynotes()->length
: 0,
(script->constOffset != 0)
JSScript::isValidOffset(script->constOffset)
? script->consts()->length
: 0,
(script->globalsOffset != 0)
JSScript::isValidOffset(script->globalsOffset)
? script->globals()->length
: 0,
script->nClosedArgs,
@ -416,19 +416,19 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSFunction *fun)
memcpy(wscript->notes(), snbase, nsrcnotes * sizeof(jssrcnote));
memcpy(wscript->atomMap.vector, script->atomMap.vector,
wscript->atomMap.length * sizeof(JSAtom *));
if (script->objectsOffset != 0) {
if (JSScript::isValidOffset(script->objectsOffset)) {
memcpy(wscript->objects()->vector, script->objects()->vector,
wscript->objects()->length * sizeof(JSObject *));
}
if (script->regexpsOffset != 0) {
if (JSScript::isValidOffset(script->regexpsOffset)) {
memcpy(wscript->regexps()->vector, script->regexps()->vector,
wscript->regexps()->length * sizeof(JSObject *));
}
if (script->trynotesOffset != 0) {
if (JSScript::isValidOffset(script->trynotesOffset)) {
memcpy(wscript->trynotes()->vector, script->trynotes()->vector,
wscript->trynotes()->length * sizeof(JSTryNote));
}
if (script->globalsOffset != 0) {
if (JSScript::isValidOffset(script->globalsOffset)) {
memcpy(wscript->globals()->vector, script->globals()->vector,
wscript->globals()->length * sizeof(GlobalSlotArray::Entry));
}
@ -1959,17 +1959,15 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
fun->freezeLocalNames(cx);
}
if (!js_XDRScript(xdr, &fun->u.i.script, false, NULL))
if (!js_XDRScript(xdr, &fun->u.i.script, NULL))
return false;
if (xdr->mode == JSXDR_DECODE) {
*objp = FUN_OBJECT(fun);
if (fun->u.i.script != JSScript::emptyScript()) {
#ifdef CHECK_SCRIPT_OWNER
fun->u.i.script->owner = NULL;
fun->script()->owner = NULL;
#endif
js_CallNewScriptHook(cx, fun->u.i.script, fun);
}
js_CallNewScriptHook(cx, fun->script(), fun);
}
return true;
@ -2717,7 +2715,18 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj)
if (!fun)
return NULL;
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) {
/* 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()) {
JSScript *script = cfun->u.i.script;
JS_ASSERT(script);
if (script != JSScript::emptyScript()) {
JS_ASSERT(script->compartment == fun->compartment());
JS_ASSERT(script->compartment != cx->compartment);
cfun->u.i.script = js_CloneScript(cx, script);
if (!cfun->u.i.script)
return NULL;
JS_ASSERT(cfun->u.i.script != JSScript::emptyScript());
JS_ASSERT(script->compartment == fun->compartment());
JS_ASSERT(script->compartment != cx->compartment);
cfun->u.i.script = js_CloneScript(cx, script);
if (!cfun->u.i.script)
return NULL;
#ifdef CHECK_SCRIPT_OWNER
cfun->u.i.script->owner = NULL;
cfun->script()->owner = NULL;
#endif
js_CallNewScriptHook(cx, cfun->u.i.script, cfun);
}
js_CallNewScriptHook(cx, cfun->script(), cfun);
}
}
return clone;
@ -2852,7 +2859,7 @@ JSObject * JS_FASTCALL
js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
{
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
: 0) == fun->u.i.nupvars);

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

@ -351,18 +351,24 @@ TypedMarker(JSTracer *trc, JSShortString *thing)
}
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
* rope; otherwise, we only iterate once: on the string itself.
* When marking any node of a rope, mark the entire rope. This means if
* a given rope node is already marked, we are done.
*/
JSRopeNodeIterator iter(thing);
JSString *str = iter.init();
JSRopeNodeIterator iter;
if (str->isRope()) {
if (str->asCell()->isMarked())
return;
str = iter.init(str);
goto not_static;
}
do {
for (;;) {
if (JSString::isStatic(str))
break;
not_static:
JS_ASSERT(JSTRACE_STRING == GetFinalizableTraceKind(str->asCell()->arena()->header()->thingKind));
if (!str->asCell()->markIfUnmarked())
break;

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

@ -616,7 +616,7 @@ NoSuchMethod(JSContext *cx, uintN argc, Value *vp, uint32 flags)
args.callee() = obj->getSlot(JSSLOT_FOUND_FUNCTION);
args.thisv() = vp[1];
args[0] = obj->getSlot(JSSLOT_SAVED_ID);
JSObject *argsobj = js_NewArrayObject(cx, argc, vp + 2);
JSObject *argsobj = NewDenseCopiedArray(cx, argc, vp + 2);
if (!argsobj)
return JS_FALSE;
args[1].setObject(*argsobj);
@ -908,7 +908,7 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
if (script->isEmpty()) {
if (result)
result->setUndefined();
return JS_TRUE;
return true;
}
LeaveTrace(cx);
@ -2506,9 +2506,6 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
Value *argv = regs.fp->maybeFormalArgs();
CHECK_INTERRUPT_HANDLER();
JS_ASSERT(!script->isEmpty());
JS_ASSERT(script->length >= 1);
#if defined(JS_TRACER) && defined(JS_METHODJIT)
bool leaveOnSafePoint = (interpMode == JSINTERP_SAFEPOINT);
# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) (leaveOnSafePoint = false))
@ -4078,8 +4075,8 @@ BEGIN_CASE(JSOP_UNBRANDTHIS)
Value &thisv = regs.fp->thisValue();
if (thisv.isObject()) {
JSObject *obj = &thisv.toObject();
if (obj->isNative() && !obj->unbrand(cx))
goto error;
if (obj->isNative())
obj->unbrand(cx);
}
}
END_CASE(JSOP_UNBRANDTHIS)
@ -4293,8 +4290,7 @@ END_CASE(JSOP_CALLPROP)
BEGIN_CASE(JSOP_UNBRAND)
JS_ASSERT(regs.sp - regs.fp->slots() >= 1);
if (!regs.sp[-1].toObject().unbrand(cx))
goto error;
regs.sp[-1].toObject().unbrand(cx);
END_CASE(JSOP_UNBRAND)
BEGIN_CASE(JSOP_SETGNAME)
@ -4677,7 +4673,7 @@ BEGIN_CASE(JSOP_FUNCALL)
if (newfun->isInterpreted())
inline_call:
{
JSScript *newscript = newfun->u.i.script;
JSScript *newscript = newfun->script();
if (JS_UNLIKELY(newscript->isEmpty())) {
vp->setUndefined();
regs.sp = vp + 1;
@ -5892,7 +5888,7 @@ BEGIN_CASE(JSOP_NEWINIT)
JSObject *obj;
if (i == JSProto_Array) {
obj = js_NewArrayObject(cx, 0, NULL);
obj = NewDenseEmptyArray(cx);
} else {
gc::FinalizeKind kind = GuessObjectGCKind(0, false);
obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
@ -5909,10 +5905,8 @@ END_CASE(JSOP_NEWINIT)
BEGIN_CASE(JSOP_NEWARRAY)
{
unsigned count = GET_UINT24(regs.pc);
JSObject *obj = js_NewArrayObject(cx, count, NULL);
/* Avoid ensureDenseArrayElements to skip sparse array checks there. */
if (!obj || !obj->ensureSlots(cx, count))
JSObject *obj = NewDenseAllocatedArray(cx, count);
if (!obj)
goto error;
PUSH_OBJECT(*obj);
@ -6069,7 +6063,7 @@ BEGIN_CASE(JSOP_DEFSHARP)
obj = &lref.toObject();
} else {
JS_ASSERT(lref.isUndefined());
obj = js_NewArrayObject(cx, 0, NULL);
obj = NewDenseEmptyArray(cx);
if (!obj)
goto error;
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.
*/
if (script->trynotesOffset == 0)
if (!JSScript::isValidOffset(script->trynotesOffset))
goto no_catch;
offset = (uint32)(regs.pc - script->main);

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

@ -61,7 +61,7 @@ struct JSFrameRegs
/* Flags to toggle js::Interpret() execution. */
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_SAFEPOINT = 2, /* interpreter should leave on a method JIT safe point */
JSINTERP_PROFILE = 3 /* interpreter should profile a loop */
@ -76,8 +76,8 @@ enum JSFrameFlags
JSFRAME_DUMMY = 0x4, /* frame pushed for bookkeeping */
/* Frame subtypes */
JSFRAME_EVAL = 0x8, /* frame pushed by js::Execute */
JSFRAME_DEBUGGER = 0x10, /* frame pushed by JS_EvaluateInStackFrame */
JSFRAME_EVAL = 0x8, /* frame pushed for eval() or debugger eval */
JSFRAME_DEBUGGER = 0x10, /* frame pushed for debugger eval */
JSFRAME_GENERATOR = 0x20, /* frame is associated with a generator */
JSFRAME_FLOATING_GENERATOR = 0x40, /* frame is is in generator obj, not on stack */
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 };
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec);
JSObject *aobj = js_NewArrayObject(cx, 2, vec);
JSObject *aobj = NewDenseCopiedArray(cx, 2, vec);
if (!aobj)
return false;
rval->setObject(*aobj);
@ -615,6 +615,14 @@ EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVe
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
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->getProto()) {
vp->setObject(*last);
UpdateNativeIterator(lastni, obj);
RegisterEnumerator(cx, last, lastni);
return true;
}
@ -691,6 +700,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
Compare(ni->shapes_array, shapes.begin(), ni->shapes_length)) {
vp->setObject(*iterobj);
UpdateNativeIterator(ni, obj);
RegisterEnumerator(cx, iterobj, ni);
if (shapes.length() == 2)
JS_THREAD_DATA(cx)->lastNativeIterator = iterobj;
@ -967,6 +977,7 @@ public:
bool
js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id)
{
id = js_CheckForStringIndex(id);
return SuppressDeletedPropertyHelper(cx, obj, SingleIdPredicate(id));
}

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

@ -1055,7 +1055,7 @@ EvalCacheLookup(JSContext *cx, JSString *str, JSStackFrame *caller, uintN static
int i = 1;
if (objarray->length == 1) {
if (script->regexpsOffset != 0) {
if (JSScript::isValidOffset(script->regexpsOffset)) {
objarray = script->regexps();
i = 0;
} else {
@ -1806,7 +1806,7 @@ obj_keys(JSContext *cx, uintN argc, Value *vp)
}
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)
return false;
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)
return false;
@ -3538,9 +3538,9 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp)
if (xdr->mode == JSXDR_ENCODE) {
obj = *objp;
parent = obj->getParent();
parentId = (xdr->script->objectsOffset == 0)
? NO_PARENT_INDEX
: FindObjectIndex(xdr->script->objects(), parent);
parentId = JSScript::isValidOffset(xdr->script->objectsOffset)
? FindObjectIndex(xdr->script->objects(), parent)
: NO_PARENT_INDEX;
depth = (uint16)OBJ_BLOCK_DEPTH(cx, obj);
count = (uint16)OBJ_BLOCK_COUNT(cx, obj);
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.
* This avoids extra shape guard branch exits in the tracejitted code.
*/
if (fs && !proto->brand(cx))
goto bad;
if (ctor != proto && static_fs && !ctor->brand(cx))
goto bad;
if (fs)
proto->brand(cx);
if (ctor != proto && static_fs)
ctor->brand(cx);
/*
* 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;
JS_ASSERT(IsFunctionObject(*vp));
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
JSObject *funobj = &vp->toObject();
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);

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

@ -337,16 +337,19 @@ struct JSObject : js::gc::Cell {
inline bool nativeContains(const js::Shape &shape);
enum {
DELEGATE = 0x01,
SYSTEM = 0x02,
NOT_EXTENSIBLE = 0x04,
BRANDED = 0x08,
GENERIC = 0x10,
METHOD_BARRIER = 0x20,
INDEXED = 0x40,
OWN_SHAPE = 0x80,
BOUND_FUNCTION = 0x100,
HAS_EQUALITY = 0x200
DELEGATE = 0x01,
SYSTEM = 0x02,
NOT_EXTENSIBLE = 0x04,
BRANDED = 0x08,
GENERIC = 0x10,
METHOD_BARRIER = 0x20,
INDEXED = 0x40,
OWN_SHAPE = 0x80,
BOUND_FUNCTION = 0x100,
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); }
/*
* 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 unbrand(JSContext *cx);
bool generic() { return !!(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); }
void assertSpecialEqualitySynced() const {
JS_ASSERT(!!clasp->ext.equality == hasSpecialEquality());

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

@ -105,8 +105,13 @@ inline bool
JSObject::unbrand(JSContext *cx)
{
JS_ASSERT(isNative());
if (!branded())
setGeneric();
if (branded()) {
generateOwnShape(cx);
if (js_IsPropertyCacheDisabled(cx)) // check for rt->shapeGen overflow
return false;
flags &= ~BRANDED;
}
setGeneric();
return true;
}
@ -189,14 +194,12 @@ ChangesMethodValue(const js::Value &prev, const js::Value &v)
inline bool
JSObject::methodWriteBarrier(JSContext *cx, const js::Shape &shape, const js::Value &v)
{
if (flags & (BRANDED | METHOD_BARRIER)) {
if (shape.slot != SHAPE_INVALID_SLOT) {
const js::Value &prev = nativeGetSlot(shape.slot);
if (brandedOrHasMethodBarrier() && shape.slot != SHAPE_INVALID_SLOT) {
const js::Value &prev = nativeGetSlot(shape.slot);
if (ChangesMethodValue(prev, v)) {
JS_FUNCTION_METER(cx, mwritebarrier);
return methodShapeChange(cx, shape);
}
if (ChangesMethodValue(prev, v)) {
JS_FUNCTION_METER(cx, mwritebarrier);
return methodShapeChange(cx, shape);
}
}
return true;
@ -205,7 +208,7 @@ JSObject::methodWriteBarrier(JSContext *cx, const js::Shape &shape, const js::Va
inline bool
JSObject::methodWriteBarrier(JSContext *cx, uint32 slot, const js::Value &v)
{
if (flags & (BRANDED | METHOD_BARRIER)) {
if (brandedOrHasMethodBarrier()) {
const js::Value &prev = nativeGetSlot(slot);
if (ChangesMethodValue(prev, v)) {
@ -931,6 +934,18 @@ namespace WithProto {
* Note that as a template, there will be lots of instantiations, which means
* 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
{
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. */
if (withProto == WithProto::Class && !proto) {
JSProtoKey protoKey = GetClassProtoKey(clasp);
if (!js_GetClassPrototype(cx, parent, protoKey, &proto, clasp))
return NULL;
if (!proto && !js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
return NULL;
if (!FindProto (cx, clasp, parent, &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);
}
/* 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
* the object, zero if the final size is unknown.

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

@ -680,7 +680,7 @@ js_BeginJSONParse(JSContext *cx, Value *rootVal, bool suppressErrors /*= false*/
if (!cx)
return NULL;
JSObject *arr = js_NewArrayObject(cx, 0, NULL);
JSObject *arr = NewDenseEmptyArray(cx);
if (!arr)
return NULL;
@ -856,7 +856,7 @@ static JSBool
OpenArray(JSContext *cx, JSONParser *jp)
{
// Add an array to an existing array or object
JSObject *arr = js_NewArrayObject(cx, 0, NULL);
JSObject *arr = NewDenseEmptyArray(cx);
if (!arr)
return JS_FALSE;

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

@ -1337,7 +1337,7 @@ GetLocal(SprintStack *ss, jsint i)
* not in a block. In either case, return GetStr(ss, i).
*/
JSScript *script = ss->printer->script;
if (script->objectsOffset == 0)
if (!JSScript::isValidOffset(script->objectsOffset))
return GetStr(ss, i);
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(FUN_INTERPRETED(jp->fun));
JS_ASSERT(jp->script != jp->fun->u.i.script);
JS_ASSERT(jp->script->upvarsOffset != 0);
JS_ASSERT(JSScript::isValidOffset(jp->script->upvarsOffset));
}
#endif
uva = jp->script->upvars();

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

@ -640,9 +640,9 @@ NameNode::initCommon(JSTreeContext *tc)
{
pn_expr = NULL;
pn_cookie.makeFree();
pn_dflags = tc->atTopLevel() ? PND_TOPLEVEL : 0;
if (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)
pn_dflags |= PND_BLOCKCHILD;
pn_dflags = (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)
? PND_BLOCKCHILD
: 0;
pn_blockid = tc->blockid();
}
@ -865,6 +865,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
#endif
inDirectivePrologue = true;
tokenStream.setOctalCharacterEscape(false);
for (;;) {
tt = tokenStream.peekToken(TSF_OPERAND);
if (tt <= TOK_EOF) {
@ -879,8 +880,8 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
goto out;
JS_ASSERT(!cg.blockNode);
if (inDirectivePrologue)
inDirectivePrologue = parser.recognizeDirectivePrologue(pn);
if (inDirectivePrologue && !parser.recognizeDirectivePrologue(pn, &inDirectivePrologue))
goto out;
if (!js_FoldConstants(cx, pn, &cg))
goto out;
@ -978,7 +979,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
JS_DumpArenaStats(stdout);
#endif
script = JSScript::NewScriptFromCG(cx, &cg);
if (script && funbox && script != script->emptyScript())
if (script && funbox)
script->savedCallerFun = true;
#ifdef JS_SCOPE_DEPTH_METER
@ -1069,7 +1070,7 @@ Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *scrip
JSScript *inner = worklist.back();
worklist.popBack();
if (inner->objectsOffset != 0) {
if (JSScript::isValidOffset(inner->objectsOffset)) {
JSObjectArray *arr = inner->objects();
for (size_t i = 0; i < arr->length; i++) {
JSObject *obj = arr->vector[i];
@ -1078,14 +1079,16 @@ Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *scrip
JSFunction *fun = obj->getFunctionPrivate();
JS_ASSERT(fun->isInterpreted());
JSScript *inner = fun->u.i.script;
if (inner->globalsOffset == 0 && inner->objectsOffset == 0)
if (!JSScript::isValidOffset(inner->globalsOffset) &&
!JSScript::isValidOffset(inner->objectsOffset)) {
continue;
}
if (!worklist.append(inner))
return false;
}
}
if (inner->globalsOffset == 0)
if (!JSScript::isValidOffset(inner->globalsOffset))
continue;
GlobalSlotArray *globalUses = inner->globals();
@ -1479,6 +1482,8 @@ Define(JSParseNode *pn, JSAtom *atom, JSTreeContext *tc, bool let = false)
ALE_SET_DEFN(ale, pn);
pn->pn_defn = true;
pn->pn_dflags &= ~PND_PLACEHOLDER;
if (!tc->parent)
pn->pn_dflags |= PND_TOPLEVEL;
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;
} else if (dn->kind() == JSDefinition::FUNCTION) {
JS_ASSERT(dn->isTopLevel());
JS_ASSERT(dn->pn_op == JSOP_NOP);
dn->pn_type = TOK_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);
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)
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
* is immediately applied (we clear PND_FUNARG if so -- see memberExpr).
*
* Also treat function sub-statements (non-lambda, non-top-level functions)
* as escaping funargs, since we can't statically analyze their definitions
* Treat function sub-statements (non-lambda, non-body-level functions) as
* escaping funargs, since we can't statically analyze their definitions
* and uses.
*/
bool topLevel = tc->atTopLevel();
pn->pn_dflags = (lambda || !topLevel) ? PND_FUNARG : 0;
bool bodyLevel = tc->atBodyLevel();
pn->pn_dflags = (lambda || !bodyLevel) ? PND_FUNARG : 0;
/*
* 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);
pn->pn_defn = true;
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))
return NULL;
}
} else if (topLevel) {
} else if (bodyLevel) {
/*
* If this function was used before it was defined, claim the
* 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
* local variable to bind its name to its value, and not an activation
* object property (it might also need the activation property, if the
* outer function contains with statements, e.g., but the stack slot
* wins when jsemit.c's BindNameToSlot can optimize a JSOP_NAME into a
* A function directly inside another's body needs only a local
* variable to bind its name to its value, and not an activation object
* property (it might also need the activation property, if the outer
* function contains with statements, e.g., but the stack slot wins
* when jsemit.cpp's BindNameToSlot can optimize a JSOP_NAME into a
* JSOP_GETLOCAL bytecode).
*/
if (topLevel) {
pn->pn_dflags |= PND_TOPLEVEL;
if (bodyLevel && tc->inFunction()) {
/*
* 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()) {
JSLocalKind localKind;
uintN index;
case JSLOCAL_VAR:
pn->pn_cookie.set(tc->staticLevel, index);
pn->pn_dflags |= PND_BOUND;
break;
/*
* 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:;
}
default:;
}
}
}
@ -3104,11 +3099,12 @@ Parser::functionDef(JSAtom *funAtom, FunctionType type, uintN lambda)
outertc->flags |= TCF_FUN_HEAVYWEIGHT;
} else {
/*
* If this function is a named statement function not at top-level
* (i.e. not a top-level function definiton or expression), then our
* enclosing function, if any, must be heavyweight.
* If this function is not at body level of a program or function (i.e.
* it is a function statement that is not a direct child of a program
* 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;
}
@ -3134,7 +3130,7 @@ Parser::functionDef(JSAtom *funAtom, FunctionType type, uintN lambda)
result->pn_pos = pn->pn_pos;
result->pn_kid = pn;
op = JSOP_LAMBDA;
} else if (!topLevel) {
} else if (!bodyLevel) {
/*
* ECMA ed. 3 extension: a function expression statement not at the
* 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;
}
if (!outertc->inFunction() && topLevel && funAtom && !lambda &&
outertc->compiling()) {
if (!outertc->inFunction() && bodyLevel && funAtom && !lambda && outertc->compiling()) {
JS_ASSERT(pn->pn_cookie.isFree());
if (!DefineGlobal(pn, (JSCodeGenerator *)outertc, funAtom))
if (!DefineGlobal(pn, outertc->asCodeGenerator(), funAtom))
return false;
}
@ -3225,13 +3220,33 @@ Parser::functionExpr()
* if it can't possibly be a directive, now or in the future.
*/
bool
Parser::recognizeDirectivePrologue(JSParseNode *pn)
Parser::recognizeDirectivePrologue(JSParseNode *pn, bool *isDirectivePrologueMember)
{
if (!pn->isDirectivePrologueMember())
return false;
*isDirectivePrologueMember = pn->isDirectivePrologueMember();
if (!*isDirectivePrologueMember)
return true;
if (pn->isDirective()) {
JSAtom *directive = pn->pn_kid->pn_atom;
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;
tokenStream.setStrictMode();
}
@ -3249,7 +3264,6 @@ Parser::statements()
{
JSParseNode *pn, *pn2, *saveBlock;
TokenKind tt;
bool inDirectivePrologue = tc->atTopLevel();
JS_CHECK_RECURSION(context, return NULL);
@ -3262,6 +3276,8 @@ Parser::statements()
saveBlock = tc->blockNode;
tc->blockNode = pn;
bool inDirectivePrologue = tc->atBodyLevel();
tokenStream.setOctalCharacterEscape(false);
for (;;) {
tt = tokenStream.peekToken(TSF_OPERAND);
if (tt <= TOK_EOF || tt == TOK_RC) {
@ -3279,20 +3295,20 @@ Parser::statements()
return NULL;
}
if (inDirectivePrologue)
inDirectivePrologue = recognizeDirectivePrologue(pn2);
if (inDirectivePrologue && !recognizeDirectivePrologue(pn2, &inDirectivePrologue))
return NULL;
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
* rest of nodes.
*
* 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.
*/
if (tc->atTopLevel())
if (tc->atBodyLevel())
pn->pn_xflags |= PNX_FUNCDEFS;
else
tc->flags |= TCF_HAS_FUNCTION_STMT;
@ -3362,10 +3378,10 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
jsint n;
/*
* Top-level 'let' is the same as 'var' currently -- this may change in a
* successor standard to ES3.1 that specifies 'let'.
* Body-level 'let' is the same as 'var' currently -- this may change in a
* successor standard to ES5 that specifies 'let'.
*/
JS_ASSERT(!tc->atTopLevel());
JS_ASSERT(!tc->atBodyLevel());
pn = data->pn;
if (!CheckStrictBinding(cx, tc, atom, pn))
@ -3583,7 +3599,7 @@ BindGvar(JSParseNode *pn, JSTreeContext *tc)
if (!tc->compiling() || tc->parser->callerFrame)
return true;
JSCodeGenerator *cg = (JSCodeGenerator *) tc;
JSCodeGenerator *cg = tc->asCodeGenerator();
if (pn->pn_dflags & PND_CONST)
return true;

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

@ -479,7 +479,7 @@ public:
#define PND_CONST 0x02 /* const binding (orthogonal to let) */
#define PND_INITIALIZED 0x04 /* initialized declaration */
#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_GVAR 0x40 /* gvar binding, can't close over
because it could be deleted */
@ -529,7 +529,6 @@ public:
bool isLet() const { return test(PND_LET); }
bool isConst() const { return test(PND_CONST); }
bool isInitialized() const { return test(PND_INITIALIZED); }
bool isTopLevel() const { return test(PND_TOPLEVEL); }
bool isBlockChild() const { return test(PND_BLOCKCHILD); }
bool isPlaceholder() const { return test(PND_PLACEHOLDER); }
bool isDeoptimized() const { return test(PND_DEOPTIMIZED); }
@ -537,6 +536,20 @@ public:
bool isFunArg() const { return test(PND_FUNARG); }
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. */
void setFunArg();
@ -1118,7 +1131,7 @@ private:
/*
* Additional JS parsers.
*/
bool recognizeDirectivePrologue(JSParseNode *pn);
bool recognizeDirectivePrologue(JSParseNode *pn, bool *isDirectivePrologueMember);
enum FunctionType { GETTER, SETTER, GENERAL };
bool functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSFunction *fun,

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

@ -335,8 +335,6 @@ GetDerivedTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp)
static bool
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);
}
@ -672,6 +670,7 @@ bool
JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
PropertyDescriptor *desc)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->getPropertyDescriptor(cx, proxy, id, set, desc);
}
@ -679,6 +678,7 @@ JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set
bool
JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
AutoPropertyDescriptorRooter desc(cx);
return JSProxy::getPropertyDescriptor(cx, proxy, id, set, &desc) &&
@ -689,6 +689,7 @@ bool
JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
PropertyDescriptor *desc)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->getOwnPropertyDescriptor(cx, proxy, id, set, desc);
}
@ -696,6 +697,7 @@ JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool
bool
JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
AutoPropertyDescriptorRooter desc(cx);
return JSProxy::getOwnPropertyDescriptor(cx, proxy, id, set, &desc) &&
@ -705,6 +707,7 @@ JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool
bool
JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->defineProperty(cx, proxy, id, desc);
}
@ -712,6 +715,7 @@ JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescrip
bool
JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, const Value &v)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
AutoPropertyDescriptorRooter desc(cx);
return ParsePropertyDescriptorObject(cx, proxy, id, v, &desc) &&
@ -721,6 +725,7 @@ JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, const Value &v)
bool
JSProxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->getOwnPropertyNames(cx, proxy, props);
}
@ -728,6 +733,7 @@ JSProxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props
bool
JSProxy::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->delete_(cx, proxy, id, bp);
}
@ -735,6 +741,7 @@ JSProxy::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
bool
JSProxy::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->enumerate(cx, proxy, props);
}
@ -742,6 +749,7 @@ JSProxy::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
bool
JSProxy::fix(JSContext *cx, JSObject *proxy, Value *vp)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->fix(cx, proxy, vp);
}
@ -749,6 +757,7 @@ JSProxy::fix(JSContext *cx, JSObject *proxy, Value *vp)
bool
JSProxy::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->has(cx, proxy, id, bp);
}
@ -756,6 +765,7 @@ JSProxy::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
bool
JSProxy::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->hasOwn(cx, proxy, id, bp);
}
@ -763,6 +773,7 @@ JSProxy::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
bool
JSProxy::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
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
JSProxy::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
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
JSProxy::enumerateOwn(JSContext *cx, JSObject *proxy, AutoIdVector &props)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->enumerateOwn(cx, proxy, props);
}
@ -784,6 +797,7 @@ JSProxy::enumerateOwn(JSContext *cx, JSObject *proxy, AutoIdVector &props)
bool
JSProxy::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->iterate(cx, proxy, flags, vp);
}
@ -791,6 +805,7 @@ JSProxy::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp)
bool
JSProxy::call(JSContext *cx, JSObject *proxy, uintN argc, Value *vp)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->call(cx, proxy, argc, vp);
}
@ -798,6 +813,7 @@ JSProxy::call(JSContext *cx, JSObject *proxy, uintN argc, Value *vp)
bool
JSProxy::construct(JSContext *cx, JSObject *proxy, uintN argc, Value *argv, Value *rval)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
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
JSProxy::hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *bp)
{
JS_CHECK_RECURSION(cx, return false);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->hasInstance(cx, proxy, vp, bp);
}
@ -812,6 +829,8 @@ JSProxy::hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *
JSType
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);
return proxy->getProxyHandler()->typeOf(cx, proxy);
}
@ -819,6 +838,7 @@ JSProxy::typeOf(JSContext *cx, JSObject *proxy)
JSString *
JSProxy::obj_toString(JSContext *cx, JSObject *proxy)
{
JS_CHECK_RECURSION(cx, return NULL);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->obj_toString(cx, proxy);
}
@ -826,6 +846,7 @@ JSProxy::obj_toString(JSContext *cx, JSObject *proxy)
JSString *
JSProxy::fun_toString(JSContext *cx, JSObject *proxy, uintN indent)
{
JS_CHECK_RECURSION(cx, return NULL);
AutoPendingProxyOperation pending(cx, proxy);
return proxy->getProxyHandler()->fun_toString(cx, proxy, indent);
}

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

@ -510,7 +510,7 @@ NodeBuilder::newNode(ASTType type, TokenPos *pos, JSObject **dst)
bool
NodeBuilder::newArray(NodeVector &elts, Value *dst)
{
JSObject *array = js_NewArrayObject(cx, 0, NULL);
JSObject *array = NewDenseEmptyArray(cx);
if (!array)
return false;

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

@ -246,7 +246,7 @@ RegExp::createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemC
* 0: matched string
* 1..pairCount-1: paren matches
*/
JSObject *array = js_NewSlowArrayObject(cx);
JSObject *array = NewSlowEmptyArray(cx);
if (!array)
return NULL;

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

@ -1192,6 +1192,7 @@ TokenStream::getTokenInternal()
JSMSG_DEPRECATED_OCTAL)) {
goto error;
}
setOctalCharacterEscape();
}
if ('0' <= c && c < '8') {
val = 8 * val + JS7_UNDEC(c);
@ -1586,7 +1587,7 @@ TokenStream::getTokenInternal()
}
}
filenameBuf[i] = '\0';
if (c == '\n') {
if (c == EOF || c == '\n') {
if (i > 0) {
if (flags & TSF_OWNFILENAME)
cx->free((void *) filename);

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

@ -263,6 +263,7 @@ enum TokenStreamFlags
TSF_XMLTAGMODE = 0x200, /* scanning within an XML tag in E4X */
TSF_XMLTEXTMODE = 0x400, /* scanning XMLText terminal from E4X */
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
@ -333,12 +334,15 @@ class TokenStream
void setXMLTagMode(bool enabled = true) { setFlag(enabled, TSF_XMLTAGMODE); }
void setXMLOnlyMode(bool enabled = true) { setFlag(enabled, TSF_XMLONLYMODE); }
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 isXMLTagMode() { return !!(flags & TSF_XMLTAGMODE); }
bool isXMLOnlyMode() { return !!(flags & TSF_XMLONLYMODE); }
bool isUnexpectedEOF() { return !!(flags & TSF_UNEXPECTED_EOF); }
bool isEOF() const { return !!(flags & TSF_EOF); }
bool isError() const { return !!(flags & TSF_ERROR); }
bool hasOctalCharacterEscape() const { return flags & TSF_OCTAL_CHAR; }
/* Mutators. */
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);
return true;
}

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

@ -73,28 +73,6 @@
using namespace js;
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
enum ScriptBits {
@ -108,8 +86,7 @@ enum ScriptBits {
};
JSBool
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
JSBool *hasMagic)
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
{
JSContext *cx;
JSScript *script, *oldscript;
@ -133,7 +110,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
notes = NULL;
/* 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)
magic = JSXDR_MAGIC_SCRIPT_CURRENT;
@ -152,45 +129,10 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
if (hasMagic)
*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)
length = (script == JSScript::emptyScript()) ? 0 : script->length;
length = script->length;
if (!JS_XDRUint32(xdr, &length))
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) {
prologLength = script->main - script->code;
@ -208,15 +150,15 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
nsrcnotes = sn - notes;
nsrcnotes++; /* room for the terminator */
if (script->objectsOffset != 0)
if (JSScript::isValidOffset(script->objectsOffset))
nobjects = script->objects()->length;
if (script->upvarsOffset != 0)
if (JSScript::isValidOffset(script->upvarsOffset))
nupvars = script->upvars()->length;
if (script->regexpsOffset != 0)
if (JSScript::isValidOffset(script->regexpsOffset))
nregexps = script->regexps()->length;
if (script->trynotesOffset != 0)
if (JSScript::isValidOffset(script->trynotesOffset))
ntrynotes = script->trynotes()->length;
if (script->constOffset != 0)
if (JSScript::isValidOffset(script->constOffset))
nconsts = script->consts()->length;
nClosedArgs = script->nClosedArgs;
@ -956,39 +898,52 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
script->length = length;
script->setVersion(cx->findVersion());
uint8 *scriptEnd = reinterpret_cast<uint8 *>(script + 1);
cursor = (uint8 *)script + sizeof(JSScript);
if (nobjects != 0) {
script->objectsOffset = (uint8)(cursor - (uint8 *)script);
script->objectsOffset = (uint8)(cursor - scriptEnd);
cursor += sizeof(JSObjectArray);
} else {
script->objectsOffset = JSScript::INVALID_OFFSET;
}
if (nupvars != 0) {
script->upvarsOffset = (uint8)(cursor - (uint8 *)script);
script->upvarsOffset = (uint8)(cursor - scriptEnd);
cursor += sizeof(JSUpvarArray);
} else {
script->upvarsOffset = JSScript::INVALID_OFFSET;
}
if (nregexps != 0) {
script->regexpsOffset = (uint8)(cursor - (uint8 *)script);
script->regexpsOffset = (uint8)(cursor - scriptEnd);
cursor += sizeof(JSObjectArray);
} else {
script->regexpsOffset = JSScript::INVALID_OFFSET;
}
if (ntrynotes != 0) {
script->trynotesOffset = (uint8)(cursor - (uint8 *)script);
script->trynotesOffset = (uint8)(cursor - scriptEnd);
cursor += sizeof(JSTryNoteArray);
} else {
script->trynotesOffset = JSScript::INVALID_OFFSET;
}
if (nglobals != 0) {
script->globalsOffset = (uint8)(cursor - (uint8 *)script);
script->globalsOffset = (uint8)(cursor - scriptEnd);
cursor += sizeof(GlobalSlotArray);
} else {
script->globalsOffset = JSScript::INVALID_OFFSET;
}
JS_ASSERT((cursor - (uint8 *)script) <= 0xFF);
JS_ASSERT((cursor - (uint8 *)script) < 0xFF);
if (nconsts != 0) {
script->constOffset = (uint8)(cursor - (uint8 *)script);
script->constOffset = (uint8)(cursor - scriptEnd);
cursor += sizeof(JSConstArray);
} else {
script->constOffset = JSScript::INVALID_OFFSET;
}
JS_STATIC_ASSERT(sizeof(JSScript) +
sizeof(JSObjectArray) +
JS_STATIC_ASSERT(sizeof(JSObjectArray) +
sizeof(JSUpvarArray) +
sizeof(JSObjectArray) +
sizeof(JSTryNoteArray) +
sizeof(GlobalSlotArray) <= 0xFF);
sizeof(GlobalSlotArray) < 0xFF);
if (natoms != 0) {
script->atomMap.length = natoms;
@ -1097,84 +1052,6 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
mainLength = CG_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);
uint16 nClosedArgs = uint16(cg->closedArgs.length());
JS_ASSERT(nClosedArgs == cg->closedArgs.length());
@ -1268,7 +1145,7 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
if (cg->inFunction()) {
fun = cg->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);
else
fun->u.i.nupvars = 0;
@ -1286,10 +1163,19 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
js_CallNewScriptHook(cx, script, fun);
#ifdef DEBUG
{
jsrefcount newLive = JS_RUNTIME_METER(cx->runtime, liveScripts);
jsrefcount newEmptyLive = cx->runtime->liveEmptyScripts;
jsrefcount newTotal =
JS_RUNTIME_METER(cx->runtime, totalScripts) + cx->runtime->totalEmptyScripts;
jsrefcount newEmptyLive, newLive, newTotal;
if (script->isEmpty()) {
newEmptyLive = JS_RUNTIME_METER(cx->runtime, liveEmptyScripts);
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;
if (newEmptyLive + newLive > oldHigh) {
JS_ATOMIC_SET(&cx->runtime->highWaterLiveScripts, newEmptyLive + newLive);
@ -1311,8 +1197,6 @@ bad:
JS_FRIEND_API(void)
js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
{
JS_ASSERT(script != JSScript::emptyScript());
JSNewScriptHook hook;
hook = cx->debugHooks->newScriptHook;
@ -1326,8 +1210,6 @@ js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
JS_FRIEND_API(void)
js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
{
JS_ASSERT(script != JSScript::emptyScript());
JSDestroyScriptHook hook;
hook = cx->debugHooks->destroyScriptHook;
@ -1338,13 +1220,11 @@ js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
static void
DestroyScript(JSContext *cx, JSScript *script, JSThreadData *data)
{
if (script == JSScript::emptyScript()) {
JS_RUNTIME_UNMETER(cx->runtime, liveEmptyScripts);
return;
}
#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
js_CallDestroyScriptHook(cx, script);
@ -1437,7 +1317,7 @@ js_TraceScript(JSTracer *trc, JSScript *script)
JSAtomMap *map = &script->atomMap;
MarkAtomRange(trc, map->length, map->vector, "atomMap");
if (script->objectsOffset != 0) {
if (JSScript::isValidOffset(script->objectsOffset)) {
JSObjectArray *objarray = script->objects();
uintN i = objarray->length;
do {
@ -1449,7 +1329,7 @@ js_TraceScript(JSTracer *trc, JSScript *script)
} while (i != 0);
}
if (script->regexpsOffset != 0) {
if (JSScript::isValidOffset(script->regexpsOffset)) {
JSObjectArray *objarray = script->regexps();
uintN i = objarray->length;
do {
@ -1461,7 +1341,7 @@ js_TraceScript(JSTracer *trc, JSScript *script)
} while (i != 0);
}
if (script->constOffset != 0) {
if (JSScript::isValidOffset(script->constOffset)) {
JSConstArray *constarray = script->consts();
MarkValueRange(trc, constarray->length, constarray->vector, "consts");
}
@ -1481,7 +1361,6 @@ js_NewScriptObject(JSContext *cx, JSScript *script)
AutoScriptRooter root(cx, script);
JS_ASSERT(!script->u.object);
JS_ASSERT(script != JSScript::emptyScript());
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
if (!obj)
@ -1733,7 +1612,6 @@ class DisablePrincipalsTranscoding {
JSScript *
js_CloneScript(JSContext *cx, JSScript *script)
{
JS_ASSERT(script != JSScript::emptyScript());
JS_ASSERT(cx->compartment != script->compartment);
JS_ASSERT(script->compartment);
@ -1770,7 +1648,7 @@ js_CloneScript(JSContext *cx, JSScript *script)
JS_XDRMemSetData(w, NULL, 0);
// 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;
JS_XDRDestroy(r);
@ -1789,4 +1667,3 @@ JSScript::copyClosedSlotsTo(JSScript *other)
{
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
* are responsible for notifying the debugger after successfully creating any
* 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,
uint32 nobjects, uint32 nupvars, uint32 nregexps,
@ -219,19 +213,22 @@ struct JSScript {
uint16 version; /* JS version under which script was compiled */
uint16 nfixed; /* number of slots besides stack operands in
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,
block, scope, xml and one-time regexps
objects or 0 if none */
objects */
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
regexps or 0 if none. */
uint8 trynotesOffset; /* offset to the array of try notes or
0 if none */
uint8 globalsOffset; /* offset to the array of global slots or
0 if none */
uint8 constOffset; /* offset to the array of constants or
0 if none */
regexps */
uint8 trynotesOffset; /* offset to the array of try notes */
uint8 globalsOffset; /* offset to the array of global slots */
uint8 constOffset; /* offset to the array of constants */
bool noScriptRval:1; /* no need for result value of last
expression statement */
bool savedCallerFun:1; /* object 0 is caller function */
@ -322,34 +319,37 @@ struct JSScript {
/* Script notes are allocated right after the code. */
jssrcnote *notes() { return (jssrcnote *)(code + length); }
static const uint8 INVALID_OFFSET = 0xFF;
static bool isValidOffset(uint8 offset) { return offset != INVALID_OFFSET; }
JSObjectArray *objects() {
JS_ASSERT(objectsOffset != 0);
return (JSObjectArray *)((uint8 *) this + objectsOffset);
JS_ASSERT(isValidOffset(objectsOffset));
return (JSObjectArray *)((uint8 *) (this + 1) + objectsOffset);
}
JSUpvarArray *upvars() {
JS_ASSERT(upvarsOffset != 0);
return (JSUpvarArray *) ((uint8 *) this + upvarsOffset);
JS_ASSERT(isValidOffset(upvarsOffset));
return (JSUpvarArray *) ((uint8 *) (this + 1) + upvarsOffset);
}
JSObjectArray *regexps() {
JS_ASSERT(regexpsOffset != 0);
return (JSObjectArray *) ((uint8 *) this + regexpsOffset);
JS_ASSERT(isValidOffset(regexpsOffset));
return (JSObjectArray *) ((uint8 *) (this + 1) + regexpsOffset);
}
JSTryNoteArray *trynotes() {
JS_ASSERT(trynotesOffset != 0);
return (JSTryNoteArray *) ((uint8 *) this + trynotesOffset);
JS_ASSERT(isValidOffset(trynotesOffset));
return (JSTryNoteArray *) ((uint8 *) (this + 1) + trynotesOffset);
}
js::GlobalSlotArray *globals() {
JS_ASSERT(globalsOffset != 0);
return (js::GlobalSlotArray *) ((uint8 *)this + globalsOffset);
JS_ASSERT(isValidOffset(globalsOffset));
return (js::GlobalSlotArray *) ((uint8 *) (this + 1) + globalsOffset);
}
JSConstArray *consts() {
JS_ASSERT(constOffset != 0);
return (JSConstArray *) ((uint8 *) this + constOffset);
JS_ASSERT(isValidOffset(constOffset));
return (JSConstArray *) ((uint8 *) (this + 1) + constOffset);
}
JSAtom *getAtom(size_t index) {
@ -397,20 +397,10 @@ struct JSScript {
/*
* The isEmpty method tells whether this script has code that computes any
* 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
* |this| is the emptyScript singleton, but it also checks this->length and
* this->code, to handle debugger-generated mutable empty scripts.
* JSVAL_VOID, or any other effects.
*/
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) {
JS_ASSERT(index < nClosedArgs);
return closedSlots[index];
@ -422,16 +412,6 @@ struct JSScript {
}
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
@ -575,18 +555,11 @@ js_CloneScript(JSContext *cx, JSScript *script);
* If magic is null, js_XDRScript returns false on bad magic number errors,
* which it reports.
*
* NB: after a successful JSXDR_DECODE, and provided that *scriptp is not the
* JSScript::emptyScript() immutable singleton, js_XDRScript callers must do
* any required subsequent set-up of owning function or script object and then
* 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.
* NB: after a successful JSXDR_DECODE, js_XDRScript callers must do any
* required subsequent set-up of owning function or script object and then call
* js_CallNewScriptHook.
*/
extern JSBool
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
JSBool *hasMagic);
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic);
#endif /* jsscript_h___ */

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

@ -70,23 +70,13 @@ JSScript::getRegExp(size_t index)
inline bool
JSScript::isEmpty() const
{
return (this == emptyScript());
if (length > 3)
return false;
// See bug 603044 comment #21.
#if 0
if (this == emptyScript())
return true;
if (length <= 3) {
jsbytecode *pc = code;
if (noScriptRval && JSOp(*pc) == JSOP_FALSE)
++pc;
if (JSOp(*pc) == JSOP_STOP)
return true;
}
return false;
#endif
jsbytecode *pc = code;
if (noScriptRval && JSOp(*pc) == JSOP_FALSE)
++pc;
return JSOp(*pc) == JSOP_STOP;
}
#endif /* jsscriptinlines_h___ */

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

@ -1384,8 +1384,8 @@ RopeMatch(JSString *textstr, const jschar *pat, jsuint patlen)
*/
size_t textstrlen = textstr->length();
size_t threshold = textstrlen >> sRopeMatchThresholdRatioLog2;
JSRopeLeafIterator iter(textstr);
for (JSString *str = iter.init(); str; str = iter.next()) {
JSRopeLeafIterator iter;
for (JSString *str = iter.init(textstr); str; str = iter.next()) {
if (threshold-- == 0 || !strs.append(str))
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. */
JSObject *obj = js_NewSlowArrayObject(cx);
JSObject *obj = NewSlowEmptyArray(cx);
if (!obj)
return false;
vp->setObject(*obj);
@ -1896,7 +1896,7 @@ MatchCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p)
JSObject *&arrayobj = *static_cast<MatchArgType>(p);
if (!arrayobj) {
arrayobj = js_NewArrayObject(cx, 0, NULL);
arrayobj = NewDenseEmptyArray(cx);
if (!arrayobj)
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
* through it, building a new rope.
*/
JSRopeLeafIterator iter(textstr);
JSRopeLeafIterator iter;
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 strEnd = pos + len;
if (pos < matchEnd && strEnd > match) {
@ -2679,7 +2679,7 @@ str_split(JSContext *cx, uintN argc, Value *vp)
if (argc == 0) {
Value v = StringValue(str);
JSObject *aobj = js_NewArrayObject(cx, 1, &v);
JSObject *aobj = NewDenseCopiedArray(cx, 1, &v);
if (!aobj)
return false;
vp->setObject(*aobj);
@ -2762,7 +2762,7 @@ str_split(JSContext *cx, uintN argc, Value *vp)
if (j == -2)
return false;
JSObject *aobj = js_NewArrayObject(cx, splits.length(), splits.begin());
JSObject *aobj = NewDenseCopiedArray(cx, splits.length(), splits.begin());
if (!aobj)
return false;
vp->setObject(*aobj);

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

@ -630,20 +630,13 @@ class JSRopeNodeIterator {
static const size_t DONE_RIGHT = 0x2;
public:
JSRopeNodeIterator(JSString *str)
: mUsedFlags(0)
{
mStr = 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;
}
JSRopeNodeIterator()
: mStr(NULL), mUsedFlags(0)
{}
JSString *init(JSString *str) {
/* Move to the farthest-left leaf in the rope. */
mStr = str;
while (mStr->isInteriorNode())
mStr = mStr->interiorNodeParent();
while (mStr->ropeLeft()->isInteriorNode())
@ -697,14 +690,9 @@ class JSRopeLeafIterator {
JSRopeNodeIterator mNodeIterator;
public:
JSRopeLeafIterator(JSString *topNode) :
mNodeIterator(topNode) {
JS_ASSERT(topNode->isTopNode());
}
inline JSString *init() {
JSString *str = mNodeIterator.init();
inline JSString *init(JSString *str) {
JS_ASSERT(str->isTopNode());
str = mNodeIterator.init(str);
while (str->isRope()) {
str = mNodeIterator.next();
JS_ASSERT(str);

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

@ -2221,7 +2221,7 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag
global_slots(NULL),
callDepth(anchor ? anchor->calldepth : 0),
atoms(FrameAtomBase(cx, cx->fp())),
consts(cx->fp()->script()->constOffset
consts(JSScript::isValidOffset(cx->fp()->script()->constOffset)
? cx->fp()->script()->consts()->vector
: NULL),
strictModeCode_ins(NULL),
@ -2446,7 +2446,7 @@ TraceRecorder::finishAbort(const char* reason)
AUDIT(recorderAborted);
#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",
tree->treeFileName,
tree->treeLineNumber,
@ -2788,6 +2788,13 @@ TraceMonitor::sweep()
JS_ASSERT(!ontrace());
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) {
TreeFragment** fragp = &vmfragments[i];
while (TreeFragment* frag = *fragp) {
@ -2805,7 +2812,9 @@ TraceMonitor::sweep()
JS_ASSERT(frag->root == frag);
*fragp = frag->next;
do {
verbose_only( FragProfiling_FragFinalizer(frag, this); )
verbose_only( FragProfiling_FragFinalizer(frag, this); );
if (recorderTree == frag)
shouldAbortRecording = true;
TrashTree(frag);
frag = frag->peer;
} while (frag);
@ -2815,7 +2824,7 @@ TraceMonitor::sweep()
}
}
if (recorder && HasUnreachableGCThings(recorder->getTree()))
if (shouldAbortRecording)
recorder->finishAbort("dead GC things");
}
@ -4289,7 +4298,7 @@ TraceRecorder::guard(bool expected, LIns* cond, VMSideExit* exit,
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
* to detect that case and avoid calling guard(). Otherwise, change
* 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
* 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();
atoms = FrameAtomBase(cx, cx->fp());
consts = cx->fp()->hasImacropc() || script->constOffset == 0
? 0
: script->consts()->vector;
consts = (cx->fp()->hasImacropc() || !JSScript::isValidOffset(script->constOffset))
? 0
: script->consts()->vector;
strictModeCode_ins = w.name(w.immi(script->strictModeCode), "strict");
}
@ -7894,7 +7903,7 @@ JS_REQUIRES_STACK void
TraceRecorder::updateAtoms(JSScript *script)
{
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");
}
@ -10839,13 +10848,20 @@ TraceRecorder::newArray(JSObject* ctor, uint32 argc, Value* argv, Value* rval)
CHECK_STATUS(getClassPrototype(ctor, proto_ins));
LIns *arr_ins;
if (argc == 0 || (argc == 1 && argv[0].isNumber())) {
LIns *args[] = { argc == 0 ? w.immi(0) : d2i(get(argv)), proto_ins, cx_ins };
arr_ins = w.call(&js_NewEmptyArray_ci, args);
if (argc == 0) {
LIns *args[] = { proto_ins, cx_ins };
arr_ins = w.call(&js::NewDenseEmptyArray_ci, args);
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 {
LIns *args[] = { w.nameImmi(argc), proto_ins, cx_ins };
arr_ins = w.call(&js_NewPreallocatedArray_ci, args);
LIns *args[] = { proto_ins, w.nameImmi(argc), cx_ins };
arr_ins = w.call(&js::NewDenseAllocatedArray_ci, args);
guard(false, w.eqp0(arr_ins), OOM_EXIT);
// 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) {
LIns* a = get(&vp[2]);
if (IsPromoteInt(a)) {
if (IsPromoteInt(a) && vp[2].toNumber() != INT_MIN) {
a = w.demote(a);
/* abs(INT_MIN) can't be done using integers; exit if we see it. */
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();
if (native == js_str_charAt) {
jsdouble i = vp[2].toNumber();
if (JSDOUBLE_IS_NaN(i))
i = 0;
if (i < 0 || i >= str->length())
RETURN_STOP("charAt out of bounds");
LIns* str_ins = get(&vp[1]);
@ -11194,6 +11212,8 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
return RECORD_CONTINUE;
} else if (native == js_str_charCodeAt) {
jsdouble i = vp[2].toNumber();
if (JSDOUBLE_IS_NaN(i))
i = 0;
if (i < 0 || i >= str->length())
RETURN_STOP("charCodeAt out of bounds");
LIns* str_ins = get(&vp[1]);
@ -11447,7 +11467,7 @@ TraceRecorder::functionCall(uintN argc, JSOp mode)
if (Probes::callTrackingActive(cx)) {
JSScript *script = FUN_SCRIPT(fun);
if (! script || ! script->isEmpty()) {
if (!script || !script->isEmpty()) {
LIns* args[] = { w.immi(1), w.nameImmpNonGC(fun), cx_ins };
LIns* call_ins = w.call(&functionProbe_ci, args);
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));
// Ensure idx >= 0 && idx < length (by using uint32)
guard(true,
w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)),
OVERFLOW_EXIT);
CHECK_STATUS_A(guard(true,
w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)),
"inRange"),
OVERFLOW_EXIT, /* abortIfAlwaysExits = */true));
// We're now ready to store
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,
* so we can optimize for the empty script singleton right away. 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.
* so we can optimize away the function call if the corresponding script is
* empty. No need to worry about crossing globals or relocating argv, even,
* in this case!
*/
if (fun->u.i.script->isEmpty()) {
if (fun->script()->isEmpty()) {
LIns* rval_ins;
if (constructing) {
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.
*/
guard(true,
w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)),
w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)), "inRange"),
BRANCH_EXIT);
/* We are now ready to load. Do a different type of load
@ -14075,8 +14094,8 @@ TraceRecorder::record_JSOP_NEWINIT()
LIns *v_ins;
if (key == JSProto_Array) {
LIns *args[] = { w.immi(0), proto_ins, cx_ins };
v_ins = w.call(&js_NewPreallocatedArray_ci, args);
LIns *args[] = { proto_ins, cx_ins };
v_ins = w.call(&NewDenseEmptyArray_ci, args);
} else {
LIns *args[] = { w.immpNull(), proto_ins, cx_ins };
v_ins = w.call(&js_InitializerObject_ci, args);
@ -14095,8 +14114,8 @@ TraceRecorder::record_JSOP_NEWARRAY()
CHECK_STATUS_A(getClassPrototype(JSProto_Array, proto_ins));
unsigned count = GET_UINT24(cx->regs->pc);
LIns *args[] = { w.immi(count), proto_ins, cx_ins };
LIns *v_ins = w.call(&js_NewPreallocatedArray_ci, args);
LIns *args[] = { proto_ins, w.immi(count), cx_ins };
LIns *v_ins = w.call(&NewDenseAllocatedArray_ci, args);
guard(false, w.eqp0(v_ins), OOM_EXIT);
stack(0, v_ins);

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

@ -1213,7 +1213,7 @@ class TypedArrayTemplate
bool
copyFromWithOverlap(JSContext *cx, TypedArray *tarray, jsuint offset = 0)
{
JS_ASSERT(offset < length);
JS_ASSERT(offset <= length);
NativeType *dest = static_cast<NativeType*>(data) + offset;

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

@ -789,10 +789,10 @@ extern "C++"
# endif /* defined(__cplusplus) */
/* Internal helper macros */
#define JSVAL_BITS(v) (v.asBits)
#define JSVAL_BITS(v) ((v).asBits)
#define JSVAL_FROM_LAYOUT(l) (l)
#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) */

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

@ -526,12 +526,27 @@ CanReify(Value *vp)
(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
Reify(JSContext *cx, JSCompartment *origin, Value *vp)
{
JSObject *iterObj = &vp->toObject();
NativeIterator *ni = iterObj->getNativeIterator();
AutoCloseIterator close(cx, iterObj);
/* Wrap the iteratee. */
JSObject *obj = ni->obj;
if (!origin->wrap(cx, &obj))
@ -556,6 +571,7 @@ Reify(JSContext *cx, JSCompartment *origin, Value *vp)
}
}
close.clear();
return js_CloseIterator(cx, iterObj) &&
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) &&
VectorToValueIterator(cx, obj, ni->flags, vals, vp);
}

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

@ -669,13 +669,12 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **atomp)
JS_PUBLIC_API(JSBool)
JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
{
if (!js_XDRScript(xdr, scriptp, true, NULL))
if (!js_XDRScript(xdr, scriptp, NULL))
return JS_FALSE;
if (xdr->mode == JSXDR_DECODE) {
js_CallNewScriptHook(xdr->cx, *scriptp, NULL);
if (*scriptp != JSScript::emptyScript() &&
!js_NewScriptObject(xdr->cx, *scriptp)) {
if (!js_NewScriptObject(xdr->cx, *scriptp)) {
js_DestroyScript(xdr->cx, *scriptp);
*scriptp = NULL;
return JS_FALSE;

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

@ -5774,7 +5774,7 @@ FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray)
static bool
NamespacesToJSArray(JSContext *cx, JSXMLArray *array, jsval *rval)
{
JSObject *arrayobj = js_NewArrayObject(cx, 0, NULL);
JSObject *arrayobj = NewDenseEmptyArray(cx);
if (!arrayobj)
return false;
*rval = OBJECT_TO_JSVAL(arrayobj);
@ -7466,7 +7466,7 @@ GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
if (VALUE_IS_FUNCTION(cx, *vp))
return true;
target = target->getProto();
if (target == NULL)
if (target == NULL || !target->isNative())
break;
tvr.setObject(target);
}

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

@ -122,7 +122,6 @@ mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp)
CompileStatus
mjit::Compiler::compile()
{
JS_ASSERT(!script->isEmpty());
JS_ASSERT_IF(isConstructing, !script->jitCtor);
JS_ASSERT_IF(!isConstructing, !script->jitNormal);

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

@ -81,7 +81,7 @@ FindExceptionHandler(JSContext *cx)
JSScript *script = fp->script();
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.
unsigned offset = cx->regs->pc - script->main;
@ -308,18 +308,6 @@ stubs::CompileFunction(VMFrame &f, uint32 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()) {
fp = (JSStackFrame *)FixupArity(f, nactual);
if (!fp)
@ -339,7 +327,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
CompileStatus status = CanMethodJIT(cx, script, fp);
if (status == Compile_Okay)
return script->getJIT(callingNew)->invokeEntry;
return script->getJIT(fp->isConstructing())->invokeEntry;
/* Function did not compile... interpret it. */
JSBool ok = Interpret(cx, fp);
@ -422,9 +410,7 @@ stubs::UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
Value *vp = f.regs.sp - (argc + 2);
/* Try to do a fast inline call before the general Invoke path. */
if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpreted() &&
!ucr->fun->script()->isEmpty())
{
if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpreted()) {
ucr->callee = &vp->toObject();
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, argc))
THROW();
@ -476,12 +462,6 @@ stubs::UncachedCallHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
ucr->fun = GET_FUNCTION_PRIVATE(cx, ucr->callee);
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))
THROW();
return;

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

@ -1368,14 +1368,10 @@ stubs::Neg(VMFrame &f)
JSObject * JS_FASTCALL
stubs::NewInitArray(VMFrame &f, uint32 count)
{
JSContext *cx = f.cx;
gc::FinalizeKind kind = GuessObjectGCKind(count, true);
JSObject *obj = NewArrayWithKind(cx, kind);
if (!obj || !obj->ensureSlots(cx, count))
JSObject *obj = NewDenseAllocatedArray(f.cx, count);
if (!obj)
THROWV(NULL);
obj->setArrayLength(count);
return obj;
}
@ -2574,8 +2570,8 @@ stubs::Unbrand(VMFrame &f)
if (!thisv.isObject())
return;
JSObject *obj = &thisv.toObject();
if (obj->isNative() && !obj->unbrand(f.cx))
THROW();
if (obj->isNative())
obj->unbrand(f.cx);
}
void JS_FASTCALL

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

@ -1975,7 +1975,7 @@ TryNotes(JSContext *cx, JSScript *script)
{
JSTryNote *tn, *tnlimit;
if (script->trynotesOffset == 0)
if (!JSScript::isValidOffset(script->trynotesOffset))
return JS_TRUE;
tn = script->trynotes()->vector;
@ -2053,7 +2053,7 @@ DisassembleValue(JSContext *cx, jsval v, bool lines, bool recursive)
SrcNotes(cx, script);
TryNotes(cx, script);
if (recursive && script->objectsOffset != 0) {
if (recursive && JSScript::isValidOffset(script->objectsOffset)) {
JSObjectArray *objects = script->objects();
for (uintN i = 0; i != objects->length; ++i) {
JSObject *obj = objects->vector[i];
@ -2139,11 +2139,6 @@ DisassFile(JSContext *cx, uintN argc, jsval *vp)
if (!script)
return JS_FALSE;
if (script->isEmpty()) {
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
JSObject *obj = JS_NewScriptObject(cx, script);
if (!obj)
return JS_FALSE;
@ -4293,7 +4288,7 @@ static JSFunctionSpec shell_functions[] = {
JS_FN("startTraceVis", StartTraceVisNative, 1,0),
JS_FN("stopTraceVis", StopTraceVisNative, 0,0),
#endif
#ifdef DEBUG_ARRAYS
#ifdef DEBUG
JS_FN("arrayInfo", js_ArrayInfo, 1,0),
#endif
#ifdef JS_THREADSAFE
@ -4420,7 +4415,7 @@ static const char *const shell_help_messages[] = {
"startTraceVis(filename) Start TraceVis recording (stops any current recording)",
"stopTraceVis() Stop TraceVis recording",
#endif
#ifdef DEBUG_ARRAYS
#ifdef DEBUG
"arrayInfo(a1, a2, ...) Report statistics about arrays",
#endif
#ifdef JS_THREADSAFE

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

@ -2,4 +2,5 @@ url-prefix ../../jsreftest.html?test=ecma_5/Array/
script sort-01.js
script toString-01.js
script toLocaleString-01.js
script regress-599159.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/
script 11.1.5-01.js
script named-accessor-function.js
script nested-delete-name-in-evalcode.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 regress-bug607284.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.12.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.2.js
script 15.10.7.js
@ -37,3 +37,4 @@ script regress-532254.js
script regress-532041.js
script unbrand-this.js
script this-for-function-expression-recursion.js
script directive-prologue-01.js

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

@ -236,6 +236,7 @@ function test()
empty.set([]);
empty.set([], 0);
empty.set(empty);
checkThrows(function() empty.set([1]));
checkThrows(function() empty.set([1], 0));
@ -244,6 +245,7 @@ function test()
a.set([]);
a.set([], 3);
a.set([], 9);
a.set(a);
a.set(empty);
a.set(empty, 3);

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

@ -56,3 +56,5 @@ script regress-610026.js
script regress-609617.js
script regress-617405-1.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)
return JS_TRUE;
JSString *str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
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;
return nsXPConnect::Base64Decode(cx, JS_ARGV(cx, vp)[0], &JS_RVAL(cx, vp));
}
static JSBool
@ -259,36 +230,7 @@ Btoa(JSContext *cx, uintN argc, jsval *vp)
if (!argc)
return JS_TRUE;
JSString *str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
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;
return nsXPConnect::Base64Encode(cx, JS_ARGV(cx, vp)[0], &JS_RVAL(cx, vp));
}
static JSFunctionSpec gGlobalFun[] = {

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

@ -64,6 +64,8 @@
#include "jsdIDebuggerService.h"
#include "xpcquickstubs.h"
NS_IMPL_THREADSAFE_ISUPPORTS6(nsXPConnect,
nsIXPConnect,
nsISupportsWeakReference,
@ -2615,8 +2617,7 @@ nsXPConnect::GetCaller(JSContext **aJSContext, JSObject **aObj)
// static
nsresult
nsXPConnect::Base64Encode(const nsACString &aBinaryData,
nsACString &aString)
nsXPConnect::Base64Encode(const nsACString &aBinaryData, nsACString &aString)
{
// Check for overflow.
if(aBinaryData.Length() > (PR_UINT32_MAX / 4) * 3)
@ -2645,8 +2646,7 @@ nsXPConnect::Base64Encode(const nsACString &aBinaryData,
// static
nsresult
nsXPConnect::Base64Encode(const nsAString &aString,
nsAString &aBinaryData)
nsXPConnect::Base64Encode(const nsAString &aString, nsAString &aBinaryData)
{
NS_LossyConvertUTF16toASCII string(aString);
nsCAutoString binaryData;
@ -2660,10 +2660,37 @@ nsXPConnect::Base64Encode(const nsAString &aString,
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
nsresult
nsXPConnect::Base64Decode(const nsACString &aString,
nsACString &aBinaryData)
nsXPConnect::Base64Decode(const nsACString &aString, nsACString &aBinaryData)
{
// Check for overflow.
if(aString.Length() > PR_UINT32_MAX / 3)
@ -2700,8 +2727,7 @@ nsXPConnect::Base64Decode(const nsACString &aString,
// static
nsresult
nsXPConnect::Base64Decode(const nsAString &aBinaryData,
nsAString &aString)
nsXPConnect::Base64Decode(const nsAString &aBinaryData, nsAString &aString)
{
NS_LossyConvertUTF16toASCII binaryData(aBinaryData);
nsCAutoString string;
@ -2715,6 +2741,34 @@ nsXPConnect::Base64Decode(const nsAString &aBinaryData,
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
nsXPConnect::SetDebugModeWhenPossible(PRBool mode)
{

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

@ -570,12 +570,18 @@ public:
static nsresult Base64Encode(const nsAString &aString,
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,
nsACString &aString);
static nsresult Base64Decode(const nsAString &aBinaryData,
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
NS_IMETHOD RootAndUnlinkJSObjects(void *p);
NS_IMETHOD Unlink(void *p);

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

@ -709,14 +709,24 @@ xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval,
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;
// 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)
return;
size_t len = JS_GetStringEncodingLength(cx, s);
if(len == size_t(-1))
{
mValid = JS_FALSE;
return;
}
JSAutoByteString bytes(cx, s);
if(!bytes)
{
@ -724,7 +734,7 @@ xpc_qsACString::xpc_qsACString(JSContext *cx, jsval v, jsval *pval)
return;
}
new(mBuf) implementation_type(bytes.ptr(), strlen(bytes.ptr()));
new(mBuf) implementation_type(bytes.ptr(), len);
mValid = JS_TRUE;
}

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

@ -439,7 +439,9 @@ public:
class xpc_qsACString : public xpc_qsBasicString<nsACString, nsCString>
{
public:
xpc_qsACString(JSContext *cx, jsval v, jsval *pval);
xpc_qsACString(JSContext *cx, jsval v, jsval *pval,
StringificationBehavior nullBehavior = eNull,
StringificationBehavior undefinedBehavior = eNull);
};
/**