зеркало из https://github.com/mozilla/gecko-dev.git
Bug 619283 - Built-in JS methods must not box undefined or null into the global object when called, both to comply with ES5 and to prevent inadvertent global object exposure to secure JS variants. r=dmandelin, a=blocking
This commit is contained in:
Родитель
d19fc49cf0
Коммит
6eedfa38e8
|
@ -6,7 +6,7 @@ function f() {
|
|||
(eval("\
|
||||
(function(){\
|
||||
with(\
|
||||
__defineGetter__(\"x\", function(){for(a = 0; a < 3; a++){c=a}})\
|
||||
this.__defineGetter__(\"x\", function(){for(a = 0; a < 3; a++){c=a}})\
|
||||
){}\
|
||||
})\
|
||||
"))()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
a = b = c = d = 0;
|
||||
__defineGetter__("e", function () { throw StopIteration; })
|
||||
this.__defineGetter__("e", function () { throw StopIteration; })
|
||||
try {
|
||||
for each(f in this) {}
|
||||
} catch (exc) {
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
__defineGetter__('x', Float32Array);
|
||||
this.__defineGetter__('x', Float32Array);
|
||||
with(this)
|
||||
x;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
this.watch("x", Object.create)
|
||||
try {
|
||||
(function() {
|
||||
__defineGetter__("x",
|
||||
this.__defineGetter__("x",
|
||||
function() {
|
||||
return this
|
||||
})
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
__defineSetter__("x", function(){});
|
||||
this.__defineSetter__("x", function(){});
|
||||
this.watch("x", eval);
|
||||
x = 0;
|
||||
|
|
|
@ -10,7 +10,7 @@ function f() {
|
|||
})\
|
||||
"))();
|
||||
}
|
||||
__defineSetter__("x", eval)
|
||||
this.__defineSetter__("x", eval)
|
||||
f()
|
||||
appendToActual(x);
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
x = __defineSetter__("x", function(z) function() { z })
|
||||
x = this.__defineSetter__("x", function(z) function() { z })
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
eval("for(w in ((function(x,y){b:0})())) ;");
|
||||
})();
|
||||
|
||||
__defineSetter__("l", function() { gc() });
|
||||
this.__defineSetter__("l", function() { gc() });
|
||||
this.watch("l", function(x) { yield #1={} });
|
||||
l = true;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Function("\n\
|
||||
for (a = 0; a < 3; a++) {\n\
|
||||
if (a == 0) {} else {\n\
|
||||
__defineSetter__(\"\",1)\n\
|
||||
this.__defineSetter__(\"\",1)\n\
|
||||
}\n\
|
||||
}\n\
|
||||
")()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// |jit-test| error: InternalError
|
||||
(function() {
|
||||
try {
|
||||
(Function("__defineGetter__(\"x\",(Function(\"for(z=0;z<6;z++)(x)\")))"))()
|
||||
(Function("this.__defineGetter__(\"x\",(Function(\"for(z=0;z<6;z++)(x)\")))"))()
|
||||
} catch(e) {}
|
||||
})()
|
||||
((function f(d, aaaaaa) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
setDebug(true);
|
||||
|
||||
__defineGetter__("someProperty", function () { evalInFrame(1, "var x = 'success'"); });
|
||||
this.__defineGetter__("someProperty", function () { evalInFrame(1, "var x = 'success'"); });
|
||||
function caller(obj) {
|
||||
assertJit();
|
||||
obj.someProperty;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
setDebug(true);
|
||||
|
||||
__defineGetter__("someProperty", function () { evalInFrame(1, "var x = 'success'"); });
|
||||
this.__defineGetter__("someProperty", function () { evalInFrame(1, "var x = 'success'"); });
|
||||
function caller(obj) {
|
||||
assertJit();
|
||||
var x = ({ dana : 'zuul' });
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
setDebug(true);
|
||||
|
||||
__defineGetter__("someProperty", function () { evalInFrame(1, "x = 'success'"); });
|
||||
this.__defineGetter__("someProperty", function () { evalInFrame(1, "x = 'success'"); });
|
||||
function caller(obj) {
|
||||
assertJit();
|
||||
var x = "failure";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// |jit-test| error: ReferenceError
|
||||
__defineSetter__("x", function () {})
|
||||
this.__defineSetter__("x", function () {})
|
||||
try {
|
||||
__defineGetter__("d", (Function("x")))
|
||||
this.__defineGetter__("d", (Function("x")))
|
||||
} catch (e) {}
|
||||
d
|
||||
print(delete x)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
__defineSetter__("x",/a/)
|
||||
this.__defineSetter__("x",/a/)
|
||||
Function("\
|
||||
for each(w in[0,0,0]) {\
|
||||
for each(y in[0,0,0,0,0,0,0,0,x,0,0,0,0,0,0,0,0,0,x,0,0,0,0,0,0,0,x]) {}\
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
__defineGetter__("x", Float64Array)
|
||||
this.__defineGetter__("x", Float64Array)
|
||||
Function("\
|
||||
with(this) {\
|
||||
eval(\"x\")\
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// vim: set ts=4 sw=4 tw=99 et:
|
||||
|
||||
var count = 0;
|
||||
watch("x", function() {
|
||||
this.watch("x", function() {
|
||||
count++;
|
||||
});
|
||||
for(var i=0; i<10; i++) {
|
||||
|
|
|
@ -1955,9 +1955,7 @@ JS_PUBLIC_API(jsval)
|
|||
JS_ComputeThis(JSContext *cx, jsval *vp)
|
||||
{
|
||||
assertSameCompartment(cx, JSValueArray(vp, 2));
|
||||
if (!ComputeThisFromVp(cx, Valueify(vp)))
|
||||
return JSVAL_NULL;
|
||||
return vp[1];
|
||||
return BoxThisForVp(cx, Valueify(vp)) ? vp[1] : JSVAL_NULL;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void *)
|
||||
|
@ -4260,11 +4258,7 @@ JS_ObjectIsCallable(JSContext *cx, JSObject *obj)
|
|||
static JSBool
|
||||
js_generic_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSFunctionSpec *fs;
|
||||
JSObject *tmp;
|
||||
Native native;
|
||||
|
||||
fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate();
|
||||
JSFunctionSpec *fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate();
|
||||
JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
|
||||
|
||||
if (argc < 1) {
|
||||
|
@ -4272,16 +4266,6 @@ js_generic_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp)
|
|||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (vp[2].isPrimitive()) {
|
||||
/*
|
||||
* Make sure that this is an object or null, as required by the generic
|
||||
* functions.
|
||||
*/
|
||||
if (!js_ValueToObjectOrNull(cx, vp[2], &tmp))
|
||||
return JS_FALSE;
|
||||
vp[2].setObjectOrNull(tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy all actual (argc) arguments down over our |this| parameter, vp[1],
|
||||
* which is almost always the class constructor object, e.g. Array. Then
|
||||
|
@ -4290,23 +4274,16 @@ js_generic_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp)
|
|||
*/
|
||||
memmove(vp + 1, vp + 2, argc * sizeof(jsval));
|
||||
|
||||
/*
|
||||
* Follow Function.prototype.apply and .call by using the global object as
|
||||
* the 'this' param if no args.
|
||||
*/
|
||||
if (!ComputeThisFromArgv(cx, vp + 2))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Clear the last parameter in case too few arguments were passed. */
|
||||
vp[2 + --argc].setUndefined();
|
||||
|
||||
native =
|
||||
Native native =
|
||||
#ifdef JS_TRACER
|
||||
(fs->flags & JSFUN_TRCINFO)
|
||||
? JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native
|
||||
:
|
||||
(fs->flags & JSFUN_TRCINFO)
|
||||
? JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native
|
||||
:
|
||||
#endif
|
||||
Valueify(fs->call);
|
||||
Valueify(fs->call);
|
||||
return native(cx, argc, vp);
|
||||
}
|
||||
|
||||
|
@ -5037,11 +5014,10 @@ JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, jsval
|
|||
jsval *rval)
|
||||
{
|
||||
JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
|
||||
JSBool ok;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc));
|
||||
ok = ExternalInvoke(cx, obj, ObjectValue(*fun), argc, Valueify(argv), Valueify(rval));
|
||||
JSBool ok = ExternalInvoke(cx, ObjectOrNullValue(obj), ObjectValue(*fun), argc,
|
||||
Valueify(argv), Valueify(rval));
|
||||
LAST_FRAME_CHECKS(cx, ok);
|
||||
return ok;
|
||||
}
|
||||
|
@ -5056,9 +5032,11 @@ JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
|
|||
|
||||
AutoValueRooter tvr(cx);
|
||||
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
|
||||
JSBool ok = atom &&
|
||||
js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) &&
|
||||
ExternalInvoke(cx, obj, tvr.value(), argc, Valueify(argv), Valueify(rval));
|
||||
JSBool ok =
|
||||
atom &&
|
||||
js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) &&
|
||||
ExternalInvoke(cx, ObjectOrNullValue(obj), tvr.value(), argc, Valueify(argv),
|
||||
Valueify(rval));
|
||||
LAST_FRAME_CHECKS(cx, ok);
|
||||
return ok;
|
||||
}
|
||||
|
@ -5068,11 +5046,11 @@ JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval
|
|||
jsval *rval)
|
||||
{
|
||||
JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
|
||||
JSBool ok;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc));
|
||||
ok = ExternalInvoke(cx, obj, Valueify(fval), argc, Valueify(argv), Valueify(rval));
|
||||
JSBool ok = ExternalInvoke(cx, ObjectOrNullValue(obj), Valueify(fval), argc, Valueify(argv),
|
||||
Valueify(rval));
|
||||
LAST_FRAME_CHECKS(cx, ok);
|
||||
return ok;
|
||||
}
|
||||
|
|
|
@ -1181,6 +1181,20 @@ JS_THIS(JSContext *cx, jsval *vp)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* |this| is passed to functions in ES5 without change. Functions themselves
|
||||
* do any post-processing they desire to box |this|, compute the global object,
|
||||
* &c. Use this macro to retrieve a function's unboxed |this| value.
|
||||
*
|
||||
* This macro must not be used in conjunction with JS_THIS or JS_THIS_OBJECT,
|
||||
* or vice versa. Either use the provided this value with this macro, or
|
||||
* compute the boxed this value using those.
|
||||
*
|
||||
* N.B. constructors must not use JS_THIS_VALUE, as no 'this' object has been
|
||||
* created.
|
||||
*/
|
||||
#define JS_THIS_VALUE(cx,vp) ((vp)[1])
|
||||
|
||||
extern JS_PUBLIC_API(void *)
|
||||
JS_malloc(JSContext *cx, size_t nbytes);
|
||||
|
||||
|
|
|
@ -1095,12 +1095,11 @@ array_toSource(JSContext *cx, uintN argc, Value *vp)
|
|||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj ||
|
||||
(obj->getClass() != &js_SlowArrayClass &&
|
||||
!InstanceOf(cx, obj, &js_ArrayClass, vp + 2))) {
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
if (!obj->isSlowArray() && !InstanceOf(cx, obj, &js_ArrayClass, vp + 2))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Find joins or cycles in the reachable object graph. */
|
||||
jschar *sharpchars;
|
||||
|
@ -1301,7 +1300,7 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
|||
static JSBool
|
||||
array_toString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
@ -1335,7 +1334,7 @@ array_toString(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
array_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
@ -1441,17 +1440,22 @@ array_join(JSContext *cx, uintN argc, Value *vp)
|
|||
return JS_FALSE;
|
||||
vp[2].setString(str);
|
||||
}
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
return obj && array_toString_sub(cx, obj, JS_FALSE, str, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
return array_toString_sub(cx, obj, JS_FALSE, str, vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_reverse(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
jsuint len;
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !js_GetLengthProperty(cx, obj, &len))
|
||||
return JS_FALSE;
|
||||
if (!js_GetLengthProperty(cx, obj, &len))
|
||||
return false;
|
||||
vp->setObject(*obj);
|
||||
|
||||
do {
|
||||
|
@ -1462,7 +1466,7 @@ array_reverse(JSContext *cx, uintN argc, Value *vp)
|
|||
|
||||
/* An empty array or an array with no elements is already reversed. */
|
||||
if (len == 0 || obj->getDenseArrayCapacity() == 0)
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
|
||||
/*
|
||||
* It's actually surprisingly complicated to reverse an array due to the
|
||||
|
@ -1759,8 +1763,10 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp)
|
|||
fval.setNull();
|
||||
}
|
||||
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !js_GetLengthProperty(cx, obj, &len))
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
if (!js_GetLengthProperty(cx, obj, &len))
|
||||
return false;
|
||||
if (len == 0) {
|
||||
vp->setObject(*obj);
|
||||
|
@ -2077,10 +2083,11 @@ JS_DEFINE_CALLINFO_3(extern, BOOL_FAIL, js_ArrayCompPush_tn, CONTEXT, OBJECT,
|
|||
static JSBool
|
||||
array_push(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
/* Insist on one argument and obj of the expected class. */
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
/* Insist on one argument and obj of the expected class. */
|
||||
if (argc != 1 || !obj->isDenseArray())
|
||||
return array_push_slowly(cx, obj, argc, vp + 2, vp);
|
||||
|
||||
|
@ -2132,9 +2139,9 @@ array_pop_dense(JSContext *cx, JSObject* obj, Value *vp)
|
|||
static JSBool
|
||||
array_pop(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
if (obj->isDenseArray())
|
||||
return array_pop_dense(cx, obj, vp);
|
||||
return array_pop_slowly(cx, obj, vp);
|
||||
|
@ -2143,11 +2150,12 @@ array_pop(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
array_shift(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsuint length, i;
|
||||
JSBool hole;
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !js_GetLengthProperty(cx, obj, &length))
|
||||
jsuint length;
|
||||
if (!js_GetLengthProperty(cx, obj, &length))
|
||||
return JS_FALSE;
|
||||
|
||||
if (length == 0) {
|
||||
|
@ -2170,12 +2178,13 @@ array_shift(JSContext *cx, uintN argc, Value *vp)
|
|||
}
|
||||
|
||||
/* Get the to-be-deleted property's value into vp ASAP. */
|
||||
JSBool hole;
|
||||
if (!GetElement(cx, obj, 0, &hole, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Slide down the array above the first element. */
|
||||
AutoValueRooter tvr(cx);
|
||||
for (i = 0; i != length; i++) {
|
||||
for (jsuint i = 0; i < length; i++) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!GetElement(cx, obj, i + 1, &hole, tvr.addr()) ||
|
||||
!SetOrDeleteArrayElement(cx, obj, i, hole, tvr.value())) {
|
||||
|
@ -2194,12 +2203,15 @@ static JSBool
|
|||
array_unshift(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
Value *argv;
|
||||
jsuint length;
|
||||
JSBool hole;
|
||||
jsdouble last, newlen;
|
||||
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !js_GetLengthProperty(cx, obj, &length))
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
jsuint length;
|
||||
if (!js_GetLengthProperty(cx, obj, &length))
|
||||
return JS_FALSE;
|
||||
newlen = length;
|
||||
if (argc > 0) {
|
||||
|
@ -2258,15 +2270,14 @@ array_unshift(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
array_splice(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
jsuint length, begin, end, count, delta, last;
|
||||
JSBool hole;
|
||||
|
||||
/*
|
||||
* Create a new array value to return. Our ECMA v2 proposal specs
|
||||
* that splice always returns an array value, even when given no
|
||||
* arguments. We think this is best because it eliminates the need
|
||||
* for callers to do an extra test to handle the empty splice case.
|
||||
*/
|
||||
/* Create a new array value to return. */
|
||||
JSObject *obj2 = NewDenseEmptyArray(cx);
|
||||
if (!obj2)
|
||||
return JS_FALSE;
|
||||
|
@ -2276,8 +2287,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
|
|||
if (argc == 0)
|
||||
return JS_TRUE;
|
||||
Value *argv = JS_ARGV(cx, vp);
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !js_GetLengthProperty(cx, obj, &length))
|
||||
if (!js_GetLengthProperty(cx, obj, &length))
|
||||
return JS_FALSE;
|
||||
jsuint origlength = length;
|
||||
|
||||
|
@ -2428,7 +2438,10 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
|||
Value *p = JS_ARGV(cx, vp) - 1;
|
||||
|
||||
/* Create a new Array object and root it using *vp. */
|
||||
JSObject *aobj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *aobj = ToObject(cx, &vp[1]);
|
||||
if (!aobj)
|
||||
return false;
|
||||
|
||||
JSObject *nobj;
|
||||
jsuint length;
|
||||
if (aobj->isDenseArray()) {
|
||||
|
@ -2513,8 +2526,11 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
|
|||
|
||||
argv = JS_ARGV(cx, vp);
|
||||
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !js_GetLengthProperty(cx, obj, &length))
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!js_GetLengthProperty(cx, obj, &length))
|
||||
return JS_FALSE;
|
||||
begin = 0;
|
||||
end = length;
|
||||
|
@ -2589,8 +2605,10 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp)
|
|||
jsint direction;
|
||||
JSBool hole;
|
||||
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !js_GetLengthProperty(cx, obj, &length))
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
if (!js_GetLengthProperty(cx, obj, &length))
|
||||
return JS_FALSE;
|
||||
if (length == 0)
|
||||
goto not_found;
|
||||
|
@ -2683,9 +2701,12 @@ typedef enum ArrayExtraMode {
|
|||
static JSBool
|
||||
array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
jsuint length;
|
||||
if (!obj || !js_GetLengthProperty(cx, obj, &length))
|
||||
if (!js_GetLengthProperty(cx, obj, &length))
|
||||
return JS_FALSE;
|
||||
|
||||
/*
|
||||
|
|
|
@ -1403,6 +1403,15 @@ GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *time = N
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
GetThisUTCTime(JSContext *cx, Value *vp, jsdouble *dp)
|
||||
{
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
return GetUTCTime(cx, obj, vp, dp);
|
||||
}
|
||||
|
||||
/*
|
||||
* See ECMA 15.9.5.4 thru 15.9.5.23
|
||||
*/
|
||||
|
@ -1410,19 +1419,21 @@ static JSBool
|
|||
date_getTime(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
return JS_FALSE;
|
||||
if (!GetThisUTCTime(cx, vp, &result))
|
||||
return false;
|
||||
vp->setNumber(result);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getYear(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
Value yearVal = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
|
||||
if (yearVal.isInt32()) {
|
||||
|
@ -1433,13 +1444,16 @@ date_getYear(JSContext *cx, uintN argc, Value *vp)
|
|||
*vp = yearVal;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getFullYear(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
|
@ -1451,113 +1465,120 @@ static JSBool
|
|||
date_getUTCFullYear(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
return JS_FALSE;
|
||||
if (!GetThisUTCTime(cx, vp, &result))
|
||||
return false;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = YearFromTime(result);
|
||||
|
||||
vp->setNumber(result);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getMonth(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getUTCMonth(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
return JS_FALSE;
|
||||
if (!GetThisUTCTime(cx, vp, &result))
|
||||
return false;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = MonthFromTime(result);
|
||||
|
||||
vp->setNumber(result);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getDate(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getUTCDate(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
return JS_FALSE;
|
||||
if (!GetThisUTCTime(cx, vp, &result))
|
||||
return false;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = DateFromTime(result);
|
||||
|
||||
vp->setNumber(result);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getDay(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getUTCDay(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
return JS_FALSE;
|
||||
if (!GetThisUTCTime(cx, vp, &result))
|
||||
return false;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = WeekDay(result);
|
||||
|
||||
vp->setNumber(result);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getHours(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getUTCHours(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
return JS_FALSE;
|
||||
if (!GetThisUTCTime(cx, vp, &result))
|
||||
return false;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = HourFromTime(result);
|
||||
|
@ -1569,27 +1590,29 @@ date_getUTCHours(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_getMinutes(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getUTCMinutes(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
return JS_FALSE;
|
||||
if (!GetThisUTCTime(cx, vp, &result))
|
||||
return false;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = MinFromTime(result);
|
||||
|
||||
vp->setNumber(result);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Date.getSeconds is mapped to getUTCSeconds */
|
||||
|
@ -1597,12 +1620,15 @@ date_getUTCMinutes(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_getUTCSeconds(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj, vp))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Date.getMilliseconds is mapped to getUTCMilliseconds */
|
||||
|
@ -1611,43 +1637,48 @@ static JSBool
|
|||
date_getUTCMilliseconds(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble result;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
|
||||
return JS_FALSE;
|
||||
if (!GetThisUTCTime(cx, vp, &result))
|
||||
return false;
|
||||
|
||||
if (JSDOUBLE_IS_FINITE(result))
|
||||
result = msFromTime(result);
|
||||
|
||||
vp->setNumber(result);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_getTimezoneOffset(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
jsdouble utctime, localtime, result;
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
obj = ComputeThisFromVp(cx, vp);
|
||||
jsdouble utctime;
|
||||
if (!GetUTCTime(cx, obj, vp, &utctime))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
jsdouble localtime;
|
||||
if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Return the time zone offset in minutes for the current locale that is
|
||||
* appropriate for this time. This value would be a constant except for
|
||||
* daylight savings time.
|
||||
*/
|
||||
result = (utctime - localtime) / msPerMinute;
|
||||
jsdouble result = (utctime - localtime) / msPerMinute;
|
||||
vp->setNumber(result);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_setTime(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!InstanceOf(cx, obj, &js_DateClass, vp + 2))
|
||||
return false;
|
||||
|
||||
|
@ -1666,7 +1697,6 @@ date_setTime(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
Value *argv;
|
||||
uintN i;
|
||||
jsdouble args[4], *argp, *stop;
|
||||
|
@ -1676,7 +1706,10 @@ date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, Value *vp)
|
|||
jsdouble msec_time;
|
||||
jsdouble result;
|
||||
|
||||
obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!GetUTCTime(cx, obj, vp, &result))
|
||||
return false;
|
||||
|
||||
|
@ -1805,7 +1838,6 @@ date_setUTCHours(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
Value *argv;
|
||||
uintN i;
|
||||
jsdouble lorutime; /* local or UTC version of *date */
|
||||
|
@ -1813,7 +1845,10 @@ date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, Value *vp)
|
|||
jsdouble year, month, day;
|
||||
jsdouble result;
|
||||
|
||||
obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!GetUTCTime(cx, obj, vp, &result))
|
||||
return false;
|
||||
|
||||
|
@ -1914,7 +1949,9 @@ date_setUTCFullYear(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_setYear(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
jsdouble result;
|
||||
if (!GetUTCTime(cx, obj, vp, &result))
|
||||
|
@ -1989,23 +2026,21 @@ static JSBool
|
|||
date_utc_format(JSContext *cx, Value *vp,
|
||||
void (*printFunc)(char*, size_t, jsdouble))
|
||||
{
|
||||
char buf[100];
|
||||
JSString *str;
|
||||
jsdouble utctime;
|
||||
if (!GetThisUTCTime(cx, vp, &utctime))
|
||||
return false;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &utctime))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!JSDOUBLE_IS_FINITE(utctime)) {
|
||||
char buf[100];
|
||||
if (!JSDOUBLE_IS_FINITE(utctime))
|
||||
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
|
||||
} else {
|
||||
else
|
||||
(*printFunc)(buf, sizeof buf, utctime);
|
||||
}
|
||||
str = JS_NewStringCopyZ(cx, buf);
|
||||
|
||||
JSString *str = JS_NewStringCopyZ(cx, buf);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
vp->setString(str);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -2025,7 +2060,7 @@ static JSBool
|
|||
date_toJSON(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
/* Step 1. */
|
||||
JSObject *obj = js_ValueToNonNullObject(cx, vp[1]);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
@ -2208,17 +2243,15 @@ date_format(JSContext *cx, jsdouble date, formatspec format, Value *rval)
|
|||
}
|
||||
|
||||
static JSBool
|
||||
date_toLocaleHelper(JSContext *cx, const char *format, Value *vp)
|
||||
date_toLocaleHelper(JSContext *cx, JSObject *obj, const char *format, Value *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
char buf[100];
|
||||
JSString *str;
|
||||
PRMJTime split;
|
||||
jsdouble utctime;
|
||||
|
||||
obj = ComputeThisFromVp(cx, vp);
|
||||
if (!GetUTCTime(cx, obj, vp, &utctime))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
if (!JSDOUBLE_IS_FINITE(utctime)) {
|
||||
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
|
||||
|
@ -2254,19 +2287,23 @@ date_toLocaleHelper(JSContext *cx, const char *format, Value *vp)
|
|||
|
||||
str = JS_NewStringCopyZ(cx, buf);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
vp->setString(str);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
/* Use '%#c' for windows, because '%c' is
|
||||
* backward-compatible and non-y2k with msvc; '%#c' requests that a
|
||||
* full year be used in the result string.
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
|
||||
* with msvc; '%#c' requests that a full year be used in the result string.
|
||||
*/
|
||||
return date_toLocaleHelper(cx,
|
||||
return date_toLocaleHelper(cx, obj,
|
||||
#if defined(_WIN32) && !defined(__MWERKS__)
|
||||
"%#c"
|
||||
#else
|
||||
|
@ -2278,11 +2315,15 @@ date_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_toLocaleDateString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
/* Use '%#x' for windows, because '%x' is
|
||||
* backward-compatible and non-y2k with msvc; '%#x' requests that a
|
||||
* full year be used in the result string.
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Use '%#x' for windows, because '%x' is backward-compatible and non-y2k
|
||||
* with msvc; '%#x' requests that a full year be used in the result string.
|
||||
*/
|
||||
return date_toLocaleHelper(cx,
|
||||
return date_toLocaleHelper(cx, obj,
|
||||
#if defined(_WIN32) && !defined(__MWERKS__)
|
||||
"%#x"
|
||||
#else
|
||||
|
@ -2294,7 +2335,11 @@ date_toLocaleDateString(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
date_toLocaleTimeString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
return date_toLocaleHelper(cx, "%X", vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
return date_toLocaleHelper(cx, obj, "%X", vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -2303,24 +2348,27 @@ date_toLocaleFormat(JSContext *cx, uintN argc, Value *vp)
|
|||
if (argc == 0)
|
||||
return date_toLocaleString(cx, argc, vp);
|
||||
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSString *fmt = js_ValueToString(cx, vp[2]);
|
||||
if (!fmt)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
vp[2].setString(fmt);
|
||||
JSAutoByteString fmtbytes(cx, fmt);
|
||||
if (!fmtbytes)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
return date_toLocaleHelper(cx, fmtbytes.ptr(), vp);
|
||||
return date_toLocaleHelper(cx, obj, fmtbytes.ptr(), vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_toTimeString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble utctime;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &utctime))
|
||||
return JS_FALSE;
|
||||
if (!GetThisUTCTime(cx, vp, &utctime))
|
||||
return false;
|
||||
return date_format(cx, utctime, FORMATSPEC_TIME, vp);
|
||||
}
|
||||
|
||||
|
@ -2328,9 +2376,8 @@ static JSBool
|
|||
date_toDateString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble utctime;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &utctime))
|
||||
return JS_FALSE;
|
||||
if (!GetThisUTCTime(cx, vp, &utctime))
|
||||
return false;
|
||||
return date_format(cx, utctime, FORMATSPEC_DATE, vp);
|
||||
}
|
||||
|
||||
|
@ -2342,31 +2389,28 @@ static JSBool
|
|||
date_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble utctime;
|
||||
char *numStr, *bytes;
|
||||
JSString *str;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &utctime))
|
||||
return JS_FALSE;
|
||||
if (!GetThisUTCTime(cx, vp, &utctime))
|
||||
return false;
|
||||
|
||||
ToCStringBuf cbuf;
|
||||
numStr = NumberToCString(cx, &cbuf, utctime);
|
||||
char *numStr = NumberToCString(cx, &cbuf, utctime);
|
||||
if (!numStr) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes = JS_smprintf("(new %s(%s))", js_Date_str, numStr);
|
||||
char *bytes = JS_smprintf("(new %s(%s))", js_Date_str, numStr);
|
||||
if (!bytes) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
str = JS_NewStringCopyZ(cx, bytes);
|
||||
JSString *str = JS_NewStringCopyZ(cx, bytes);
|
||||
js_free(bytes);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
vp->setString(str);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2374,16 +2418,17 @@ static JSBool
|
|||
date_toString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsdouble utctime;
|
||||
if (!GetThisUTCTime(cx, vp, &utctime))
|
||||
return false;
|
||||
|
||||
if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &utctime))
|
||||
return JS_FALSE;
|
||||
return date_format(cx, utctime, FORMATSPEC_FULL, vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
date_valueOf(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
/* It is an error to call date_valueOf on a non-date object, but we don't
|
||||
/*
|
||||
* It is an error to call date_valueOf on a non-date object, but we don't
|
||||
* need to check for that explicitly here because every path calls
|
||||
* GetUTCTime, which does the check.
|
||||
*/
|
||||
|
@ -2392,13 +2437,18 @@ date_valueOf(JSContext *cx, uintN argc, Value *vp)
|
|||
if (argc == 0)
|
||||
return date_getTime(cx, argc, vp);
|
||||
|
||||
/* Verify this before extracting a string from the first argument. */
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
/* Convert to number only if the hint was given, otherwise favor string. */
|
||||
JSString *str = js_ValueToString(cx, vp[2]);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
JSLinearString *linear_str = str->ensureLinear(cx);
|
||||
if (!linear_str)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
JSAtom *number_str = cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER];
|
||||
if (EqualStrings(linear_str, number_str))
|
||||
return date_getTime(cx, argc, vp);
|
||||
|
|
|
@ -737,7 +737,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
*/
|
||||
JSBool ok = !wp->setter ||
|
||||
(shape->hasSetterValue()
|
||||
? ExternalInvoke(cx, obj,
|
||||
? ExternalInvoke(cx, ObjectValue(*obj),
|
||||
ObjectValue(*CastAsObject(wp->setter)),
|
||||
1, vp, vp)
|
||||
: CallJSPropertyOpSetter(cx, wp->setter, obj, userid, vp));
|
||||
|
@ -753,7 +753,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
static JSBool
|
||||
js_watch_set_wrapper(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -788,14 +788,15 @@ Exception(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
exn_toString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
jsval v;
|
||||
JSString *name, *message, *result;
|
||||
jschar *chars, *cp;
|
||||
size_t name_length, message_length, length;
|
||||
|
||||
obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), Valueify(&v)))
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), Valueify(&v)))
|
||||
return JS_FALSE;
|
||||
name = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : cx->runtime->emptyString;
|
||||
vp->setString(name);
|
||||
|
@ -848,14 +849,15 @@ exn_toString(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
exn_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
JSString *name, *message, *filename, *lineno_as_str, *result;
|
||||
jsval localroots[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL};
|
||||
size_t lineno_length, name_length, message_length, filename_length, length;
|
||||
jschar *chars, *cp;
|
||||
|
||||
obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), vp))
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), vp))
|
||||
return false;
|
||||
name = js_ValueToString(cx, *vp);
|
||||
if (!name)
|
||||
|
|
|
@ -2051,7 +2051,7 @@ fun_toString(JSContext *cx, uintN argc, Value *vp)
|
|||
if (argc != 0 && !ValueToECMAUint32(cx, vp[2], &indent))
|
||||
return false;
|
||||
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
@ -2069,7 +2069,7 @@ fun_toSource(JSContext *cx, uintN argc, Value *vp)
|
|||
{
|
||||
JS_ASSERT(IsFunctionObject(vp[0]));
|
||||
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
@ -2086,15 +2086,10 @@ JSBool
|
|||
js_fun_call(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
LeaveTrace(cx);
|
||||
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
Value fval = vp[1];
|
||||
|
||||
if (!js_IsCallable(fval)) {
|
||||
JSString *str = js_ValueToString(cx, fval);
|
||||
if (str) {
|
||||
if (JSString *str = js_ValueToString(cx, fval)) {
|
||||
JSAutoByteString bytes(cx, str);
|
||||
if (!!bytes) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
|
@ -2103,7 +2098,7 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp)
|
|||
bytes.ptr());
|
||||
}
|
||||
}
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
Value *argv = vp + 2;
|
||||
|
@ -2136,10 +2131,6 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp)
|
|||
JSBool
|
||||
js_fun_apply(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
/* Step 1. */
|
||||
Value fval = vp[1];
|
||||
if (!js_IsCallable(fval)) {
|
||||
|
@ -2314,13 +2305,11 @@ static JSBool
|
|||
fun_bind(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
/* Step 1. */
|
||||
JSObject *target = ComputeThisFromVp(cx, vp);
|
||||
if (!target)
|
||||
return false;
|
||||
Value &thisv = vp[1];
|
||||
|
||||
/* Step 2. */
|
||||
if (!target->isCallable()) {
|
||||
if (JSString *str = js_ValueToString(cx, vp[1])) {
|
||||
if (!js_IsCallable(thisv)) {
|
||||
if (JSString *str = js_ValueToString(cx, thisv)) {
|
||||
JSAutoByteString bytes(cx, str);
|
||||
if (!!bytes) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
|
@ -2331,6 +2320,8 @@ fun_bind(JSContext *cx, uintN argc, Value *vp)
|
|||
return false;
|
||||
}
|
||||
|
||||
JSObject *target = &thisv.toObject();
|
||||
|
||||
/* Step 3. */
|
||||
Value *args = NULL;
|
||||
uintN argslen = 0;
|
||||
|
|
|
@ -455,12 +455,12 @@ CallThisObjectHook(JSContext *cx, JSObject *obj, Value *argv)
|
|||
* The alert should display "true".
|
||||
*/
|
||||
JS_STATIC_INTERPRET bool
|
||||
ComputeGlobalThis(JSContext *cx, Value *argv)
|
||||
ComputeGlobalThis(JSContext *cx, Value *vp)
|
||||
{
|
||||
JSObject *thisp = argv[-2].toObject().getGlobal()->thisObject(cx);
|
||||
JSObject *thisp = vp[0].toObject().getGlobal()->thisObject(cx);
|
||||
if (!thisp)
|
||||
return false;
|
||||
argv[-1].setObject(*thisp);
|
||||
vp[1].setObject(*thisp);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -508,21 +508,25 @@ ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp)
|
|||
}
|
||||
|
||||
bool
|
||||
ComputeThisFromArgv(JSContext *cx, Value *argv)
|
||||
BoxThisForVp(JSContext *cx, Value *vp)
|
||||
{
|
||||
/*
|
||||
* Check for SynthesizeFrame poisoning and fast constructors which
|
||||
* didn't check their vp properly.
|
||||
*/
|
||||
JS_ASSERT(!argv[-1].isMagic());
|
||||
JS_ASSERT(!vp[1].isMagic());
|
||||
#ifdef DEBUG
|
||||
JSFunction *fun = vp[0].toObject().isFunction() ? vp[0].toObject().getFunctionPrivate() : NULL;
|
||||
JS_ASSERT_IF(fun && fun->isInterpreted(), !fun->inStrictMode());
|
||||
#endif
|
||||
|
||||
if (argv[-1].isNullOrUndefined())
|
||||
return ComputeGlobalThis(cx, argv);
|
||||
if (vp[1].isNullOrUndefined())
|
||||
return ComputeGlobalThis(cx, vp);
|
||||
|
||||
if (!argv[-1].isObject())
|
||||
return !!js_PrimitiveToObject(cx, &argv[-1]);
|
||||
if (!vp[1].isObject())
|
||||
return !!js_PrimitiveToObject(cx, &vp[1]);
|
||||
|
||||
JS_ASSERT(IsSaneThisObject(argv[-1].toObject()));
|
||||
JS_ASSERT(IsSaneThisObject(vp[1].toObject()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -895,7 +899,7 @@ ExternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, const Value &fval,
|
|||
*/
|
||||
JS_CHECK_RECURSION(cx, return JS_FALSE);
|
||||
|
||||
return ExternalInvoke(cx, obj, fval, argc, argv, rval);
|
||||
return ExternalInvoke(cx, ObjectValue(*obj), fval, argc, argv, rval);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -841,27 +841,13 @@ inline void
|
|||
PutActivationObjects(JSContext *cx, JSStackFrame *fp);
|
||||
|
||||
/*
|
||||
* For a call with arguments argv including argv[-1] (nominal |this|) and
|
||||
* argv[-2] (callee) replace null |this| with callee's parent and replace
|
||||
* primitive values with the equivalent wrapper objects. argv[-1] must
|
||||
* not be JSVAL_VOID or an activation object.
|
||||
* For a call's vp (which necessarily includes callee at vp[0] and the original
|
||||
* specified |this| at vp[1]), convert null/undefined |this| into the global
|
||||
* object for the callee and replace other primitives with boxed versions. The
|
||||
* callee must not be strict mode code.
|
||||
*/
|
||||
extern bool
|
||||
ComputeThisFromArgv(JSContext *cx, js::Value *argv);
|
||||
|
||||
JS_ALWAYS_INLINE JSObject *
|
||||
ComputeThisFromVp(JSContext *cx, js::Value *vp)
|
||||
{
|
||||
extern bool ComputeThisFromArgv(JSContext *, js::Value *);
|
||||
return ComputeThisFromArgv(cx, vp + 2) ? &vp[1].toObject() : NULL;
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE bool
|
||||
ComputeThisFromVpInPlace(JSContext *cx, js::Value *vp)
|
||||
{
|
||||
extern bool ComputeThisFromArgv(JSContext *, js::Value *);
|
||||
return ComputeThisFromArgv(cx, vp + 2);
|
||||
}
|
||||
BoxThisForVp(JSContext *cx, js::Value *vp);
|
||||
|
||||
/*
|
||||
* Abstracts the layout of the stack passed to natives from the engine and from
|
||||
|
@ -882,10 +868,6 @@ struct CallArgs
|
|||
Value *argv() const { return argv_; }
|
||||
uintN argc() const { return argc_; }
|
||||
Value &rval() const { return argv_[-2]; }
|
||||
|
||||
bool computeThis(JSContext *cx) const {
|
||||
return ComputeThisFromArgv(cx, argv_);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -954,13 +936,6 @@ extern bool
|
|||
ExternalInvoke(JSContext *cx, const Value &thisv, const Value &fval,
|
||||
uintN argc, Value *argv, Value *rval);
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
ExternalInvoke(JSContext *cx, JSObject *obj, const Value &fval,
|
||||
uintN argc, Value *argv, Value *rval)
|
||||
{
|
||||
return ExternalInvoke(cx, ObjectOrNullValue(obj), fval, argc, argv, rval);
|
||||
}
|
||||
|
||||
extern bool
|
||||
ExternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, const Value &fval,
|
||||
JSAccessMode mode, uintN argc, Value *argv, Value *rval);
|
||||
|
|
|
@ -372,7 +372,7 @@ JSStackFrame::computeThis(JSContext *cx)
|
|||
*/
|
||||
JS_ASSERT(!isEvalFrame());
|
||||
}
|
||||
if (!js::ComputeThisFromArgv(cx, &thisv + 1))
|
||||
if (!js::BoxThisForVp(cx, &thisv - 1))
|
||||
return NULL;
|
||||
JS_ASSERT(IsSaneThisObject(thisv.toObject()));
|
||||
return &thisv.toObject();
|
||||
|
@ -662,13 +662,7 @@ GetPrimitiveThis(JSContext *cx, Value *vp, T *v)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (thisv.isObjectOrNull()) {
|
||||
JSObject *obj = thisv.toObjectOrNull();
|
||||
if (!obj || obj->getClass() != Behavior::getClass()) {
|
||||
obj = ComputeThisFromVp(cx, vp);
|
||||
if (!InstanceOf(cx, obj, Behavior::getClass(), vp + 2))
|
||||
return false;
|
||||
}
|
||||
if (thisv.isObject() && thisv.toObject().getClass() == Behavior::getClass()) {
|
||||
*v = Behavior::extract(thisv.toObject().getPrimitiveThis());
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -375,7 +375,7 @@ GetCustomIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
|||
/* Otherwise call it and return that object. */
|
||||
LeaveTrace(cx);
|
||||
Value arg = BooleanValue((flags & JSITER_FOREACH) == 0);
|
||||
if (!ExternalInvoke(cx, obj, *vp, 1, &arg, vp))
|
||||
if (!ExternalInvoke(cx, ObjectValue(*obj), *vp, 1, &arg, vp))
|
||||
return false;
|
||||
if (vp->isPrimitive()) {
|
||||
/*
|
||||
|
@ -710,10 +710,8 @@ js_ThrowStopIteration(JSContext *cx)
|
|||
static JSBool
|
||||
iterator_next(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
|
||||
obj = ComputeThisFromVp(cx, vp);
|
||||
if (!InstanceOf(cx, obj, &js_IteratorClass, vp + 2))
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj || !InstanceOf(cx, obj, &js_IteratorClass, vp + 2))
|
||||
return false;
|
||||
|
||||
if (!js_IteratorMore(cx, obj, vp))
|
||||
|
@ -953,7 +951,7 @@ js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval)
|
|||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom);
|
||||
if (!js_GetMethod(cx, iterobj, id, JSGET_METHOD_BARRIER, rval))
|
||||
return false;
|
||||
if (!ExternalInvoke(cx, iterobj, *rval, 0, NULL, rval)) {
|
||||
if (!ExternalInvoke(cx, ObjectValue(*iterobj), *rval, 0, NULL, rval)) {
|
||||
/* Check for StopIteration. */
|
||||
if (!cx->isExceptionPending() || !js_ValueIsStopIteration(cx->getPendingException()))
|
||||
return false;
|
||||
|
@ -1339,11 +1337,10 @@ CloseGenerator(JSContext *cx, JSObject *obj)
|
|||
static JSBool
|
||||
generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc)
|
||||
{
|
||||
JSObject *obj;
|
||||
LeaveTrace(cx);
|
||||
|
||||
obj = ComputeThisFromVp(cx, vp);
|
||||
if (!InstanceOf(cx, obj, &js_GeneratorClass, vp + 2))
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj || !InstanceOf(cx, obj, &js_GeneratorClass, vp + 2))
|
||||
return JS_FALSE;
|
||||
|
||||
JSGenerator *gen = (JSGenerator *) obj->getPrivate();
|
||||
|
|
204
js/src/jsobj.cpp
204
js/src/jsobj.cpp
|
@ -472,8 +472,7 @@ js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map)
|
|||
static JSBool
|
||||
obj_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSBool ok, outermost;
|
||||
JSObject *obj;
|
||||
JSBool ok;
|
||||
JSHashEntry *he;
|
||||
JSIdArray *ida;
|
||||
jschar *chars, *ochars, *vsharp;
|
||||
|
@ -494,9 +493,13 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
|
|||
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroot), localroot);
|
||||
|
||||
/* If outermost, we need parentheses to be an expression, not a block. */
|
||||
outermost = (cx->sharpObjectMap.depth == 0);
|
||||
obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !(he = js_EnterSharpObject(cx, obj, &ida, &chars))) {
|
||||
JSBool outermost = (cx->sharpObjectMap.depth == 0);
|
||||
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!(he = js_EnterSharpObject(cx, obj, &ida, &chars))) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
@ -850,24 +853,25 @@ obj_toString(JSContext *cx, uintN argc, Value *vp)
|
|||
{
|
||||
Value &thisv = vp[1];
|
||||
|
||||
/* ES5 15.2.4.2 step 1. */
|
||||
/* Step 1. */
|
||||
if (thisv.isUndefined()) {
|
||||
vp->setString(ATOM_TO_STRING(cx->runtime->atomState.objectUndefinedAtom));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ES5 15.2.4.2 step 2. */
|
||||
/* Step 2. */
|
||||
if (thisv.isNull()) {
|
||||
vp->setString(ATOM_TO_STRING(cx->runtime->atomState.objectNullAtom));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ES5 15.2.4.2 step 3. */
|
||||
if (!thisv.isObject() && !js_PrimitiveToObject(cx, &thisv))
|
||||
/* Step 3. */
|
||||
JSObject *obj = ToObject(cx, &thisv);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
/* ES5 15.2.4.2 steps 4-5. */
|
||||
JSString *str = js::obj_toStringHelper(cx, &thisv.toObject());
|
||||
/* Steps 4-5. */
|
||||
JSString *str = js::obj_toStringHelper(cx, obj);
|
||||
if (!str)
|
||||
return false;
|
||||
vp->setString(str);
|
||||
|
@ -877,10 +881,11 @@ obj_toString(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
obj_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
if (!ComputeThisFromVp(cx, vp))
|
||||
return JS_FALSE;
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSString *str = js_ValueToString(cx, vp[1]);
|
||||
JSString *str = js_ValueToString(cx, ObjectValue(*obj));
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
|
||||
|
@ -891,10 +896,11 @@ obj_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
obj_valueOf(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
if (!ComputeThisFromVp(cx, vp))
|
||||
return JS_FALSE;
|
||||
*vp = vp[1];
|
||||
return JS_TRUE;
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
vp->setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1340,7 +1346,8 @@ obj_watch_handler(JSContext *cx, JSObject *obj, jsid id, jsval old,
|
|||
argv[0] = IdToValue(id);
|
||||
argv[1] = Valueify(old);
|
||||
argv[2] = Valueify(*nvp);
|
||||
ok = ExternalInvoke(cx, obj, ObjectOrNullValue(callable), 3, argv, Valueify(nvp));
|
||||
ok = ExternalInvoke(cx, ObjectValue(*obj), ObjectOrNullValue(callable), 3, argv,
|
||||
Valueify(nvp));
|
||||
js_StopResolving(cx, &key, JSRESFLAG_WATCH, entry, generation);
|
||||
return ok;
|
||||
}
|
||||
|
@ -1362,10 +1369,13 @@ obj_watch(JSContext *cx, uintN argc, Value *vp)
|
|||
if (!ValueToId(cx, vp[2], &propid))
|
||||
return JS_FALSE;
|
||||
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
Value tmp;
|
||||
uintN attrs;
|
||||
if (!obj || !CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs))
|
||||
if (!CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs))
|
||||
return JS_FALSE;
|
||||
|
||||
vp->setUndefined();
|
||||
|
@ -1380,9 +1390,9 @@ obj_watch(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
obj_unwatch(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
vp->setUndefined();
|
||||
jsid id;
|
||||
if (argc != 0) {
|
||||
|
@ -1405,9 +1415,10 @@ obj_unwatch(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
obj_hasOwnProperty(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
return obj &&
|
||||
js_HasOwnPropertyHelper(cx, obj->getOps()->lookupProperty, argc, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
return js_HasOwnPropertyHelper(cx, obj->getOps()->lookupProperty, argc, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -1418,11 +1429,11 @@ js_HasOwnPropertyHelper(JSContext *cx, LookupPropOp lookup, uintN argc,
|
|||
if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id))
|
||||
return JS_FALSE;
|
||||
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj2;
|
||||
JSProperty *prop;
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
JSObject *obj2;
|
||||
JSProperty *prop;
|
||||
if (obj->isProxy()) {
|
||||
bool has;
|
||||
if (!JSProxy::hasOwn(cx, obj, id, &has))
|
||||
|
@ -1484,28 +1495,42 @@ js_HasOwnProperty(JSContext *cx, LookupPropOp lookup, JSObject *obj, jsid id,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Proposed ECMA 15.2.4.6. */
|
||||
/* ES5 15.2.4.6. */
|
||||
static JSBool
|
||||
obj_isPrototypeOf(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
/* Step 1. */
|
||||
if (argc < 1 || !vp[2].isObject()) {
|
||||
vp->setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Step 2. */
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
const Value &v = argc != 0 ? vp[2] : UndefinedValue();
|
||||
vp->setBoolean(js_IsDelegate(cx, obj, v));
|
||||
return JS_TRUE;
|
||||
return false;
|
||||
|
||||
/* Step 3. */
|
||||
vp->setBoolean(js_IsDelegate(cx, obj, vp[2]));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Proposed ECMA 15.2.4.7. */
|
||||
/* ES5 15.2.4.7. */
|
||||
static JSBool
|
||||
obj_propertyIsEnumerable(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
/* Step 1. */
|
||||
jsid id;
|
||||
if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
return obj && js_PropertyIsEnumerable(cx, obj, id, vp);
|
||||
/* Step 2. */
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
/* Steps 3-5. */
|
||||
return js_PropertyIsEnumerable(cx, obj, id, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -1561,6 +1586,10 @@ const char js_lookupSetter_str[] = "__lookupSetter__";
|
|||
JS_FRIEND_API(JSBool)
|
||||
js_obj_defineGetter(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
if (!BoxThisForVp(cx, vp))
|
||||
return false;
|
||||
JSObject *obj = &vp[1].toObject();
|
||||
|
||||
if (argc <= 1 || !js_IsCallable(vp[3])) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_GETTER_OR_SETTER,
|
||||
|
@ -1572,8 +1601,7 @@ js_obj_defineGetter(JSContext *cx, uintN argc, Value *vp)
|
|||
jsid id;
|
||||
if (!ValueToId(cx, vp[2], &id))
|
||||
return JS_FALSE;
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !CheckRedeclaration(cx, obj, id, JSPROP_GETTER, NULL, NULL))
|
||||
if (!CheckRedeclaration(cx, obj, id, JSPROP_GETTER, NULL, NULL))
|
||||
return JS_FALSE;
|
||||
/*
|
||||
* Getters and setters are just like watchpoints from an access
|
||||
|
@ -1591,6 +1619,10 @@ js_obj_defineGetter(JSContext *cx, uintN argc, Value *vp)
|
|||
JS_FRIEND_API(JSBool)
|
||||
js_obj_defineSetter(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
if (!BoxThisForVp(cx, vp))
|
||||
return false;
|
||||
JSObject *obj = &vp[1].toObject();
|
||||
|
||||
if (argc <= 1 || !js_IsCallable(vp[3])) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_GETTER_OR_SETTER,
|
||||
|
@ -1602,8 +1634,7 @@ js_obj_defineSetter(JSContext *cx, uintN argc, Value *vp)
|
|||
jsid id;
|
||||
if (!ValueToId(cx, vp[2], &id))
|
||||
return JS_FALSE;
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !CheckRedeclaration(cx, obj, id, JSPROP_SETTER, NULL, NULL))
|
||||
if (!CheckRedeclaration(cx, obj, id, JSPROP_SETTER, NULL, NULL))
|
||||
return JS_FALSE;
|
||||
/*
|
||||
* Getters and setters are just like watchpoints from an access
|
||||
|
@ -1624,10 +1655,12 @@ obj_lookupGetter(JSContext *cx, uintN argc, Value *vp)
|
|||
jsid id;
|
||||
if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id))
|
||||
return JS_FALSE;
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
JSObject *pobj;
|
||||
JSProperty *prop;
|
||||
if (!obj || !obj->lookupProperty(cx, id, &pobj, &prop))
|
||||
if (!obj->lookupProperty(cx, id, &pobj, &prop))
|
||||
return JS_FALSE;
|
||||
vp->setUndefined();
|
||||
if (prop) {
|
||||
|
@ -1646,10 +1679,12 @@ obj_lookupSetter(JSContext *cx, uintN argc, Value *vp)
|
|||
jsid id;
|
||||
if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id))
|
||||
return JS_FALSE;
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
JSObject *pobj;
|
||||
JSProperty *prop;
|
||||
if (!obj || !obj->lookupProperty(cx, id, &pobj, &prop))
|
||||
if (!obj->lookupProperty(cx, id, &pobj, &prop))
|
||||
return JS_FALSE;
|
||||
vp->setUndefined();
|
||||
if (prop) {
|
||||
|
@ -5863,28 +5898,6 @@ HasNativeMethod(JSObject *obj, jsid methodid, Native native)
|
|||
return funobj;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we have an object of a builtin class, we don't quite know what its
|
||||
* valueOf/toString methods are, since these methods may have been overwritten
|
||||
* or shadowed. However, we can still do better than js_TryMethod by
|
||||
* hard-coding the necessary properties for us to find the native we expect.
|
||||
*
|
||||
* TODO: a per-thread shape-based cache would be faster and simpler.
|
||||
*/
|
||||
static JS_ALWAYS_INLINE bool
|
||||
ClassMethodIsNative(JSContext *cx, JSObject *obj, Class *clasp, jsid methodid,
|
||||
Native native)
|
||||
{
|
||||
JS_ASSERT(obj->getClass() == clasp);
|
||||
|
||||
if (HasNativeMethod(obj, methodid, native))
|
||||
return true;
|
||||
|
||||
JSObject *pobj = obj->getProto();
|
||||
return pobj && pobj->getClass() == clasp &&
|
||||
HasNativeMethod(pobj, methodid, native);
|
||||
}
|
||||
|
||||
bool
|
||||
DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp)
|
||||
{
|
||||
|
@ -6167,10 +6180,9 @@ js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, uintN attrs
|
|||
ObjectOrNullValue(ctor), PropertyStub, PropertyStub, 0);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_PrimitiveToObject(JSContext *cx, Value *vp)
|
||||
JSObject *
|
||||
PrimitiveToObject(JSContext *cx, const Value &v)
|
||||
{
|
||||
Value v = *vp;
|
||||
JS_ASSERT(v.isPrimitive());
|
||||
|
||||
Class *clasp;
|
||||
|
@ -6185,11 +6197,21 @@ js_PrimitiveToObject(JSContext *cx, Value *vp)
|
|||
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, clasp);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
return NULL;
|
||||
|
||||
obj->setPrimitiveThis(v);
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_PrimitiveToObject(JSContext *cx, Value *vp)
|
||||
{
|
||||
JSObject *obj = PrimitiveToObject(cx, *vp);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
vp->setObject(*obj);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -6202,13 +6224,35 @@ js_ValueToObjectOrNull(JSContext *cx, const Value &v, JSObject **objp)
|
|||
} else if (v.isUndefined()) {
|
||||
obj = NULL;
|
||||
} else {
|
||||
Value tmp = v;
|
||||
if (!js_PrimitiveToObject(cx, &tmp))
|
||||
return JS_FALSE;
|
||||
obj = &tmp.toObject();
|
||||
obj = PrimitiveToObject(cx, v);
|
||||
if (!obj)
|
||||
return false;
|
||||
}
|
||||
*objp = obj;
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
/* Callers must handle the already-object case . */
|
||||
JSObject *
|
||||
ToObjectSlow(JSContext *cx, Value *vp)
|
||||
{
|
||||
JS_ASSERT(!vp->isMagic());
|
||||
JS_ASSERT(!vp->isObject());
|
||||
|
||||
if (vp->isNullOrUndefined()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
|
||||
vp->isNull() ? "null" : "undefined", "object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSObject *obj = PrimitiveToObject(cx, *vp);
|
||||
if (obj)
|
||||
vp->setObject(*obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
@ -6254,7 +6298,7 @@ js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom,
|
|||
|
||||
if (fval.isPrimitive())
|
||||
return JS_TRUE;
|
||||
return ExternalInvoke(cx, obj, fval, argc, argv, rval);
|
||||
return ExternalInvoke(cx, ObjectValue(*obj), fval, argc, argv, rval);
|
||||
}
|
||||
|
||||
#if JS_HAS_XDR
|
||||
|
|
|
@ -1787,6 +1787,25 @@ js_PrimitiveToObject(JSContext *cx, js::Value *vp);
|
|||
extern JSBool
|
||||
js_ValueToObjectOrNull(JSContext *cx, const js::Value &v, JSObject **objp);
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Invokes the ES5 ToObject algorithm on *vp, writing back the object to vp.
|
||||
* If *vp might already be an object, use ToObject.
|
||||
*/
|
||||
extern JSObject *
|
||||
ToObjectSlow(JSContext *cx, js::Value *vp);
|
||||
|
||||
JS_ALWAYS_INLINE JSObject *
|
||||
ToObject(JSContext *cx, js::Value *vp)
|
||||
{
|
||||
if (vp->isObject())
|
||||
return &vp->toObject();
|
||||
return ToObjectSlow(cx, vp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* v and vp may alias. On successful return, vp->isObject(). If vp is not
|
||||
* rooted, the caller must root vp before the next possible GC.
|
||||
|
|
|
@ -1178,6 +1178,28 @@ CopyInitializerObject(JSContext *cx, JSObject *baseobj)
|
|||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we have an object of a builtin class, we don't quite know what its
|
||||
* valueOf/toString methods are, since these methods may have been overwritten
|
||||
* or shadowed. However, we can still do better than js_TryMethod by
|
||||
* hard-coding the necessary properties for us to find the native we expect.
|
||||
*
|
||||
* TODO: a per-thread shape-based cache would be faster and simpler.
|
||||
*/
|
||||
static JS_ALWAYS_INLINE bool
|
||||
ClassMethodIsNative(JSContext *cx, JSObject *obj, Class *clasp, jsid methodid,
|
||||
Native native)
|
||||
{
|
||||
JS_ASSERT(obj->getClass() == clasp);
|
||||
|
||||
if (HasNativeMethod(obj, methodid, native))
|
||||
return true;
|
||||
|
||||
JSObject *pobj = obj->getProto();
|
||||
return pobj && pobj->getClass() == clasp &&
|
||||
HasNativeMethod(pobj, methodid, native);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsobjinlines_h___ */
|
||||
|
|
|
@ -259,14 +259,7 @@ JSProxyHandler::construct(JSContext *cx, JSObject *proxy,
|
|||
Value fval = GetConstruct(proxy);
|
||||
if (fval.isUndefined())
|
||||
return ExternalInvokeConstructor(cx, GetCall(proxy), argc, argv, rval);
|
||||
|
||||
/*
|
||||
* FIXME: The Proxy proposal says to pass undefined as the this argument,
|
||||
* but primitive this is not supported yet. See bug 576644.
|
||||
*/
|
||||
JS_ASSERT(fval.isObject());
|
||||
JSObject *thisobj = fval.toObject().getGlobal();
|
||||
return ExternalInvoke(cx, thisobj, fval, argc, argv, rval);
|
||||
return ExternalInvoke(cx, UndefinedValue(), fval, argc, argv, rval);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -335,7 +328,7 @@ GetDerivedTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp)
|
|||
static bool
|
||||
Trap(JSContext *cx, JSObject *handler, Value fval, uintN argc, Value* argv, Value *rval)
|
||||
{
|
||||
return ExternalInvoke(cx, handler, fval, argc, argv, rval);
|
||||
return ExternalInvoke(cx, ObjectValue(*handler), fval, argc, argv, rval);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -1279,15 +1272,12 @@ static const uint32 JSSLOT_CALLABLE_CONSTRUCT = 1;
|
|||
static JSBool
|
||||
callable_Call(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *thisobj = ComputeThisFromVp(cx, vp);
|
||||
if (!thisobj)
|
||||
return false;
|
||||
|
||||
JSObject *callable = &JS_CALLEE(cx, vp).toObject();
|
||||
JS_ASSERT(callable->getClass() == &CallableObjectClass);
|
||||
const Value &fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
|
||||
const Value &thisval = vp[1];
|
||||
Value rval;
|
||||
bool ok = ExternalInvoke(cx, thisobj, fval, argc, JS_ARGV(cx, vp), &rval);
|
||||
bool ok = ExternalInvoke(cx, thisval, fval, argc, JS_ARGV(cx, vp), &rval);
|
||||
*vp = rval;
|
||||
return ok;
|
||||
}
|
||||
|
@ -1326,7 +1316,7 @@ callable_Construct(JSContext *cx, uintN argc, Value *vp)
|
|||
|
||||
/* If the call returns an object, return that, otherwise the original newobj. */
|
||||
Value rval;
|
||||
if (!ExternalInvoke(cx, newobj, callable->getSlot(JSSLOT_CALLABLE_CALL),
|
||||
if (!ExternalInvoke(cx, ObjectValue(*newobj), callable->getSlot(JSSLOT_CALLABLE_CALL),
|
||||
argc, vp + 2, &rval)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1338,7 +1328,7 @@ callable_Construct(JSContext *cx, uintN argc, Value *vp)
|
|||
}
|
||||
|
||||
Value rval;
|
||||
bool ok = ExternalInvoke(cx, thisobj, fval, argc, vp + 2, &rval);
|
||||
bool ok = ExternalInvoke(cx, ObjectValue(*thisobj), fval, argc, vp + 2, &rval);
|
||||
*vp = rval;
|
||||
return ok;
|
||||
}
|
||||
|
|
|
@ -619,8 +619,10 @@ js_regexp_toString(JSContext *cx, JSObject *obj, Value *vp)
|
|||
static JSBool
|
||||
regexp_toString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = JS_THIS_OBJECT(cx, Jsvalify(vp));
|
||||
return obj && js_regexp_toString(cx, obj, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
return js_regexp_toString(cx, obj, vp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -758,13 +760,19 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, JSBool te
|
|||
JSBool
|
||||
js_regexp_exec(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
return regexp_exec_sub(cx, JS_THIS_OBJECT(cx, Jsvalify(vp)), argc, vp + 2, JS_FALSE, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
return regexp_exec_sub(cx, obj, argc, vp + 2, JS_FALSE, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_regexp_test(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
if (!regexp_exec_sub(cx, JS_THIS_OBJECT(cx, Jsvalify(vp)), argc, vp + 2, JS_TRUE, vp))
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
if (!regexp_exec_sub(cx, obj, argc, vp + 2, JS_TRUE, vp))
|
||||
return false;
|
||||
if (!vp->isTrue())
|
||||
vp->setBoolean(false);
|
||||
|
|
208
js/src/jsstr.cpp
208
js/src/jsstr.cpp
|
@ -436,7 +436,7 @@ static const uint8 urlCharType[256] =
|
|||
|
||||
/* See ECMA-262 Edition 3 B.2.1 */
|
||||
JSBool
|
||||
js_str_escape(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval)
|
||||
js_str_escape(JSContext *cx, uintN argc, Value *vp, Value *rval)
|
||||
{
|
||||
const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
@ -444,7 +444,7 @@ js_str_escape(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval
|
|||
jsint mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
|
||||
if (argc > 1) {
|
||||
double d;
|
||||
if (!ValueToNumber(cx, argv[1], &d))
|
||||
if (!ValueToNumber(cx, vp[3], &d))
|
||||
return JS_FALSE;
|
||||
if (!JSDOUBLE_IS_FINITE(d) ||
|
||||
(mask = (jsint)d) != d ||
|
||||
|
@ -458,7 +458,7 @@ js_str_escape(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval
|
|||
}
|
||||
}
|
||||
|
||||
JSLinearString *str = ArgToRootedString(cx, argc, argv - 2, 0);
|
||||
JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
|
||||
|
@ -535,8 +535,7 @@ js_str_escape(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval
|
|||
static JSBool
|
||||
str_escape(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
return obj && js_str_escape(cx, obj, argc, vp + 2, vp);
|
||||
return js_str_escape(cx, argc, vp, vp);
|
||||
}
|
||||
|
||||
/* See ECMA-262 Edition 3 B.2.2 */
|
||||
|
@ -713,38 +712,33 @@ Class js_StringClass = {
|
|||
ConvertStub
|
||||
};
|
||||
|
||||
#define NORMALIZE_THIS(cx,vp,str) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (vp[1].isString()) { \
|
||||
str = vp[1].toString(); \
|
||||
} else { \
|
||||
str = NormalizeThis(cx, vp); \
|
||||
if (!str) \
|
||||
return JS_FALSE; \
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
static JSString *
|
||||
NormalizeThis(JSContext *cx, Value *vp)
|
||||
/*
|
||||
* Returns a JSString * for the |this| value associated with vp, or throws a
|
||||
* TypeError if |this| is null or undefined. This algorithm is the same as
|
||||
* calling CheckObjectCoercible(this), then returning ToString(this), as all
|
||||
* String.prototype.* methods do.
|
||||
*/
|
||||
static JS_ALWAYS_INLINE JSString *
|
||||
ThisToStringForStringProto(JSContext *cx, Value *vp)
|
||||
{
|
||||
if (vp[1].isNullOrUndefined() && !ComputeThisFromVp(cx, vp))
|
||||
return NULL;
|
||||
if (vp[1].isString())
|
||||
return vp[1].toString();
|
||||
|
||||
/*
|
||||
* String.prototype.{toString,toSource,valueOf} throw a TypeError if the
|
||||
* this-argument is not a string or a String object. So those methods use
|
||||
* js::GetPrimitiveThis which provides that behavior.
|
||||
*
|
||||
* By standard, the rest of the String methods must ToString the
|
||||
* this-argument rather than throw a TypeError. So those methods use
|
||||
* NORMALIZE_THIS (and thus NormalizeThis) instead.
|
||||
*/
|
||||
if (vp[1].isObject()) {
|
||||
JSObject *obj = &vp[1].toObject();
|
||||
if (obj->getClass() == &js_StringClass) {
|
||||
if (obj->getClass() == &js_StringClass &&
|
||||
ClassMethodIsNative(cx, obj,
|
||||
&js_StringClass,
|
||||
ATOM_TO_JSID(cx->runtime->atomState.toStringAtom),
|
||||
js_str_toString))
|
||||
{
|
||||
vp[1] = obj->getPrimitiveThis();
|
||||
return vp[1].toString();
|
||||
}
|
||||
} else if (vp[1].isNullOrUndefined()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
|
||||
vp[1].isNull() ? "null" : "undefined", "object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSString *str = js_ValueToString(cx, vp[1]);
|
||||
|
@ -763,14 +757,14 @@ NormalizeThis(JSContext *cx, Value *vp)
|
|||
static JSBool
|
||||
str_quote(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *str;
|
||||
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
str = js_QuoteString(cx, str, '"');
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
vp->setString(str);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -857,11 +851,11 @@ ValueToIntegerRange(JSContext *cx, const Value &v, int32 *out)
|
|||
static JSBool
|
||||
str_substring(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *str;
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
int32 length, begin, end;
|
||||
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
|
||||
if (argc > 0) {
|
||||
end = length = int32(str->length());
|
||||
|
||||
|
@ -924,29 +918,30 @@ js_toLowerCase(JSContext *cx, JSString *str)
|
|||
static JSBool
|
||||
str_toLowerCase(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *str;
|
||||
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
str = js_toLowerCase(cx, str);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
vp->setString(str);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
str_toLocaleLowerCase(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *str;
|
||||
|
||||
/*
|
||||
* Forcefully ignore the first (or any) argument and return toLowerCase(),
|
||||
* ECMA has reserved that argument, presumably for defining the locale.
|
||||
*/
|
||||
if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) {
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
return cx->localeCallbacks->localeToLowerCase(cx, str, Jsvalify(vp));
|
||||
}
|
||||
|
||||
return str_toLowerCase(cx, 0, vp);
|
||||
}
|
||||
|
||||
|
@ -974,54 +969,56 @@ js_toUpperCase(JSContext *cx, JSString *str)
|
|||
static JSBool
|
||||
str_toUpperCase(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *str;
|
||||
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
str = js_toUpperCase(cx, str);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
vp->setString(str);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
str_toLocaleUpperCase(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *str;
|
||||
|
||||
/*
|
||||
* Forcefully ignore the first (or any) argument and return toUpperCase(),
|
||||
* ECMA has reserved that argument, presumably for defining the locale.
|
||||
*/
|
||||
if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
return cx->localeCallbacks->localeToUpperCase(cx, str, Jsvalify(vp));
|
||||
}
|
||||
|
||||
return str_toUpperCase(cx, 0, vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
str_localeCompare(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *str, *thatStr;
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
if (argc == 0) {
|
||||
vp->setInt32(0);
|
||||
} else {
|
||||
thatStr = js_ValueToString(cx, vp[2]);
|
||||
JSString *thatStr = js_ValueToString(cx, vp[2]);
|
||||
if (!thatStr)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
if (cx->localeCallbacks && cx->localeCallbacks->localeCompare) {
|
||||
vp[2].setString(thatStr);
|
||||
return cx->localeCallbacks->localeCompare(cx, str, thatStr, Jsvalify(vp));
|
||||
}
|
||||
int32 result;
|
||||
if (!CompareStrings(cx, str, thatStr, &result))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
vp->setInt32(result);
|
||||
}
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -1037,13 +1034,15 @@ js_str_charAt(JSContext *cx, uintN argc, Value *vp)
|
|||
if ((size_t)i >= str->length())
|
||||
goto out_of_range;
|
||||
} else {
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
if (argc == 0) {
|
||||
d = 0.0;
|
||||
} else {
|
||||
if (!ValueToNumber(cx, vp[2], &d))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
d = js_DoubleToInteger(d);
|
||||
}
|
||||
|
||||
|
@ -1054,13 +1053,13 @@ js_str_charAt(JSContext *cx, uintN argc, Value *vp)
|
|||
|
||||
str = JSString::getUnitString(cx, str, size_t(i));
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
vp->setString(str);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
|
||||
out_of_range:
|
||||
out_of_range:
|
||||
vp->setString(cx->runtime->emptyString);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -1074,7 +1073,9 @@ js_str_charCodeAt(JSContext *cx, uintN argc, Value *vp)
|
|||
if ((size_t)i >= str->length())
|
||||
goto out_of_range;
|
||||
} else {
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
double d;
|
||||
if (argc == 0) {
|
||||
|
@ -1376,9 +1377,9 @@ RopeMatch(JSContext *cx, JSString *textstr, const jschar *pat, jsuint patlen, js
|
|||
static JSBool
|
||||
str_indexOf(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
|
||||
JSString *str;
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
JSLinearString *patstr = ArgToRootedString(cx, argc, vp, 0);
|
||||
if (!patstr)
|
||||
|
@ -1434,8 +1435,9 @@ str_indexOf(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
str_lastIndexOf(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *textstr;
|
||||
NORMALIZE_THIS(cx, vp, textstr);
|
||||
JSString *textstr = ThisToStringForStringProto(cx, vp);
|
||||
if (!textstr)
|
||||
return false;
|
||||
size_t textlen = textstr->length();
|
||||
const jschar *text = textstr->getChars(cx);
|
||||
if (!text)
|
||||
|
@ -1506,8 +1508,9 @@ str_lastIndexOf(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
js_TrimString(JSContext *cx, Value *vp, JSBool trimLeft, JSBool trimRight)
|
||||
{
|
||||
JSString *str;
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
size_t length = str->length();
|
||||
const jschar *chars = str->getChars(cx);
|
||||
if (!chars)
|
||||
|
@ -1855,8 +1858,9 @@ MatchCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p)
|
|||
static JSBool
|
||||
str_match(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *str;
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
RegExpGuard g(cx);
|
||||
if (!g.init(argc, vp))
|
||||
|
@ -1885,8 +1889,9 @@ str_match(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
str_search(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *str;
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
RegExpGuard g(cx);
|
||||
if (!g.init(argc, vp))
|
||||
|
@ -2432,7 +2437,9 @@ JSBool
|
|||
js::str_replace(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
ReplaceData rdata(cx);
|
||||
NORMALIZE_THIS(cx, vp, rdata.str);
|
||||
rdata.str = ThisToStringForStringProto(cx, vp);
|
||||
if (!rdata.str)
|
||||
return false;
|
||||
static const uint32 optarg = 2;
|
||||
|
||||
/* Extract replacement string/function. */
|
||||
|
@ -2634,8 +2641,9 @@ find_split(JSContext *cx, RegExpStatics *res, JSString *str, js::RegExp *re, jsi
|
|||
static JSBool
|
||||
str_split(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *str;
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
if (argc == 0) {
|
||||
Value v = StringValue(str);
|
||||
|
@ -2736,11 +2744,11 @@ str_split(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
str_substr(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *str;
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
int32 length, len, begin;
|
||||
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
|
||||
if (argc > 0) {
|
||||
length = int32(str->length());
|
||||
if (!ValueToIntegerRange(cx, vp[2], &begin))
|
||||
|
@ -2788,28 +2796,28 @@ out:
|
|||
static JSBool
|
||||
str_concat(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSString *str, *str2;
|
||||
Value *argv;
|
||||
uintN i;
|
||||
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
/* Set vp (aka rval) early to handle the argc == 0 case. */
|
||||
vp->setString(str);
|
||||
|
||||
Value *argv;
|
||||
uintN i;
|
||||
for (i = 0, argv = vp + 2; i < argc; i++) {
|
||||
str2 = js_ValueToString(cx, argv[i]);
|
||||
JSString *str2 = js_ValueToString(cx, argv[i]);
|
||||
if (!str2)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
argv[i].setString(str2);
|
||||
|
||||
str = js_ConcatStrings(cx, str, str2);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
vp->setString(str);
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -2837,8 +2845,9 @@ str_slice(JSContext *cx, uintN argc, Value *vp)
|
|||
}
|
||||
}
|
||||
|
||||
JSString *str;
|
||||
NORMALIZE_THIS(cx, vp, str);
|
||||
JSString *str = ThisToStringForStringProto(cx, vp);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
if (argc != 0) {
|
||||
double begin, end, length;
|
||||
|
@ -2890,8 +2899,9 @@ static bool
|
|||
tagify(JSContext *cx, const char *begin, JSLinearString *param, const char *end,
|
||||
Value *vp)
|
||||
{
|
||||
JSString *thisstr;
|
||||
NORMALIZE_THIS(cx, vp, thisstr);
|
||||
JSString *thisstr = ThisToStringForStringProto(cx, vp);
|
||||
if (!thisstr)
|
||||
return false;
|
||||
JSLinearString *str = thisstr->ensureLinear(cx);
|
||||
if (!str)
|
||||
return false;
|
||||
|
|
|
@ -1007,8 +1007,7 @@ js_DeflateStringToUTF8Buffer(JSContext *cx, const jschar *chars,
|
|||
|
||||
/* Export a few natives and a helper to other files in SpiderMonkey. */
|
||||
extern JSBool
|
||||
js_str_escape(JSContext *cx, JSObject *obj, uintN argc, js::Value *argv,
|
||||
js::Value *rval);
|
||||
js_str_escape(JSContext *cx, uintN argc, js::Value *argv, js::Value *rval);
|
||||
|
||||
/*
|
||||
* The String.prototype.replace fast-native entry point is exported for joined
|
||||
|
|
|
@ -824,10 +824,11 @@ class TypedArrayTemplate
|
|||
static JSBool
|
||||
fun_slice(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
Value *argv = JS_ARGV(cx, vp);
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp+2))
|
||||
if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp + 2))
|
||||
return false;
|
||||
|
||||
if (obj->getClass() != fastClass()) {
|
||||
|
@ -847,6 +848,7 @@ class TypedArrayTemplate
|
|||
int32_t length = int32(tarray->length);
|
||||
|
||||
if (argc > 0) {
|
||||
Value *argv = JS_ARGV(cx, vp);
|
||||
if (!ValueToInt32(cx, argv[0], &begin))
|
||||
return false;
|
||||
if (begin < 0) {
|
||||
|
@ -898,10 +900,11 @@ class TypedArrayTemplate
|
|||
static JSBool
|
||||
fun_set(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
Value *argv = JS_ARGV(cx, vp);
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp+2))
|
||||
if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp + 2))
|
||||
return false;
|
||||
|
||||
if (obj->getClass() != fastClass()) {
|
||||
|
@ -919,6 +922,7 @@ class TypedArrayTemplate
|
|||
// these are the default values
|
||||
int32_t offset = 0;
|
||||
|
||||
Value *argv = JS_ARGV(cx, vp);
|
||||
if (argc > 1) {
|
||||
if (!ValueToInt32(cx, argv[1], &offset))
|
||||
return false;
|
||||
|
|
|
@ -261,9 +261,9 @@ static JSPropertySpec namespace_props[] = {
|
|||
static JSBool
|
||||
namespace_toString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
|
||||
obj = ComputeThisFromVp(cx, vp);
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
if (!JS_InstanceOf(cx, obj, Jsvalify(&js_NamespaceClass), Jsvalify(vp + 2)))
|
||||
return JS_FALSE;
|
||||
*vp = Valueify(obj->getNameURIVal());
|
||||
|
@ -451,8 +451,11 @@ ConvertQNameToString(JSContext *cx, JSObject *obj)
|
|||
static JSBool
|
||||
qname_toString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj = ComputeThisFromVp(cx, vp);
|
||||
if (!obj || !InstanceOf(cx, obj, &js_QNameClass, vp + 2))
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!InstanceOf(cx, obj, &js_QNameClass, vp + 2))
|
||||
return false;
|
||||
|
||||
JSString *str = ConvertQNameToString(cx, obj);
|
||||
|
@ -5155,7 +5158,9 @@ StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp)
|
|||
|
||||
JS_ASSERT(VALUE_IS_FUNCTION(cx, *vp));
|
||||
|
||||
*objp = JS_THIS_OBJECT(cx, vp);
|
||||
*objp = ToObject(cx, Valueify(&vp[1]));
|
||||
if (!*objp)
|
||||
return NULL;
|
||||
xml = (JSXML *) GetInstancePrivate(cx, *objp, &js_XMLClass, Valueify(vp + 2));
|
||||
if (!xml || xml->xml_class != JSXML_CLASS_LIST)
|
||||
return xml;
|
||||
|
@ -5183,7 +5188,9 @@ StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp)
|
|||
|
||||
/* Beware: these two are not bracketed by JS_BEGIN/END_MACRO. */
|
||||
#define XML_METHOD_PROLOG \
|
||||
JSObject *obj = JS_THIS_OBJECT(cx, vp); \
|
||||
JSObject *obj = ToObject(cx, Valueify(&vp[1])); \
|
||||
if (!obj) \
|
||||
return JS_FALSE; \
|
||||
JSXML *xml = (JSXML *)GetInstancePrivate(cx, obj, &js_XMLClass, Valueify(vp+2)); \
|
||||
if (!xml) \
|
||||
return JS_FALSE
|
||||
|
@ -5274,7 +5281,10 @@ xml_attribute(JSContext *cx, uintN argc, jsval *vp)
|
|||
vp[2] = OBJECT_TO_JSVAL(qn); /* local root */
|
||||
|
||||
jsid id = OBJECT_TO_JSID(qn);
|
||||
return GetProperty(cx, JS_THIS_OBJECT(cx, vp), id, vp);
|
||||
JSObject *obj = ToObject(cx, Valueify(&vp[1]));
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
return GetProperty(cx, obj, id, vp);
|
||||
}
|
||||
|
||||
/* XML and XMLList */
|
||||
|
@ -5288,7 +5298,10 @@ xml_attributes(JSContext *cx, uintN argc, jsval *vp)
|
|||
|
||||
AutoObjectRooter tvr(cx, qn);
|
||||
jsid id = OBJECT_TO_JSID(qn);
|
||||
return GetProperty(cx, JS_THIS_OBJECT(cx, vp), id, vp);
|
||||
JSObject *obj = ToObject(cx, Valueify(&vp[1]));
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
return GetProperty(cx, obj, id, vp);
|
||||
}
|
||||
|
||||
static JSXML *
|
||||
|
@ -5443,8 +5456,11 @@ xml_childIndex(JSContext *cx, uintN argc, jsval *vp)
|
|||
static JSBool
|
||||
xml_children(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
JSObject *obj = ToObject(cx, Valueify(&vp[1]));
|
||||
if (!obj)
|
||||
return false;
|
||||
jsid name = ATOM_TO_JSID(cx->runtime->atomState.starAtom);
|
||||
return GetProperty(cx, JS_THIS_OBJECT(cx, vp), name, vp);
|
||||
return GetProperty(cx, obj, name, vp);
|
||||
}
|
||||
|
||||
/* XML and XMLList */
|
||||
|
@ -5653,11 +5669,12 @@ xml_elements(JSContext *cx, uintN argc, jsval *vp)
|
|||
static JSBool
|
||||
xml_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
jsval name;
|
||||
JSBool found;
|
||||
|
||||
obj = JS_THIS_OBJECT(cx, vp);
|
||||
JSObject *obj = ToObject(cx, Valueify(&vp[1]));
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
if (!InstanceOf(cx, obj, &js_XMLClass, Valueify(vp + 2)))
|
||||
return JS_FALSE;
|
||||
|
||||
|
@ -6691,13 +6708,10 @@ xml_toString_helper(JSContext *cx, JSXML *xml)
|
|||
static JSBool
|
||||
xml_toSource(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
jsval thisv;
|
||||
JSString *str;
|
||||
|
||||
thisv = JS_THIS(cx, vp);
|
||||
if (JSVAL_IS_NULL(thisv))
|
||||
JSObject *obj = ToObject(cx, Valueify(&vp[1]));
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
str = ToXMLString(cx, thisv, TO_SOURCE_FLAG);
|
||||
JSString *str = ToXMLString(cx, OBJECT_TO_JSVAL(obj), TO_SOURCE_FLAG);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
*vp = STRING_TO_JSVAL(str);
|
||||
|
@ -6721,13 +6735,10 @@ xml_toString(JSContext *cx, uintN argc, jsval *vp)
|
|||
static JSBool
|
||||
xml_toXMLString(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
jsval thisv;
|
||||
JSString *str;
|
||||
|
||||
thisv = JS_THIS(cx, vp);
|
||||
if (JSVAL_IS_NULL(thisv))
|
||||
JSObject *obj = ToObject(cx, Valueify(&vp[1]));
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
str = ToXMLString(cx, thisv, 0);
|
||||
JSString *str = ToXMLString(cx, OBJECT_TO_JSVAL(obj), 0);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
*vp = STRING_TO_JSVAL(str);
|
||||
|
@ -6738,8 +6749,11 @@ xml_toXMLString(JSContext *cx, uintN argc, jsval *vp)
|
|||
static JSBool
|
||||
xml_valueOf(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
*vp = JS_THIS(cx, vp);
|
||||
return !JSVAL_IS_NULL(*vp);
|
||||
JSObject *obj = ToObject(cx, Valueify(&vp[1]));
|
||||
if (!obj)
|
||||
return false;
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSFunctionSpec xml_methods[] = {
|
||||
|
@ -6831,25 +6845,24 @@ SetDefaultXMLSettings(JSContext *cx, JSObject *obj)
|
|||
static JSBool
|
||||
xml_settings(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
JSObject *settings;
|
||||
JSObject *obj;
|
||||
|
||||
settings = JS_NewObject(cx, NULL, NULL, NULL);
|
||||
JSObject *settings = JS_NewObject(cx, NULL, NULL, NULL);
|
||||
if (!settings)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
*vp = OBJECT_TO_JSVAL(settings);
|
||||
obj = JS_THIS_OBJECT(cx, vp);
|
||||
return obj && CopyXMLSettings(cx, obj, settings);
|
||||
JSObject *obj = ToObject(cx, Valueify(&vp[1]));
|
||||
if (!obj)
|
||||
return false;
|
||||
return CopyXMLSettings(cx, obj, settings);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_setSettings(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
JSObject *obj, *settings;
|
||||
JSObject *settings;
|
||||
jsval v;
|
||||
JSBool ok;
|
||||
|
||||
obj = JS_THIS_OBJECT(cx, vp);
|
||||
JSObject *obj = ToObject(cx, Valueify(&vp[1]));
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
v = (argc == 0) ? JSVAL_VOID : vp[2];
|
||||
|
|
|
@ -189,11 +189,6 @@ new TestCase( SECTION,
|
|||
2,
|
||||
eval("var obj = new Object(); obj.indexOf = String.prototype.indexOf; obj.indexOf('bject')") );
|
||||
|
||||
new TestCase( SECTION,
|
||||
"var f = new Object( String.prototype.indexOf ); f('"+GLOBAL+"')",
|
||||
0,
|
||||
eval("var f = new Object( String.prototype.indexOf ); f('"+GLOBAL+"')") );
|
||||
|
||||
new TestCase( SECTION,
|
||||
"var f = new Function(); f.toString = Object.prototype.toString; f.indexOf = String.prototype.indexOf; f.indexOf('[object Function]')",
|
||||
0,
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var gTestfile = 'isPrototypeOf.js';
|
||||
var BUGNUMBER = 619283;
|
||||
var summary = "Object.prototype.isPrototypeOf";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
function expectThrowTypeError(fun)
|
||||
{
|
||||
try
|
||||
{
|
||||
var r = fun();
|
||||
throw new Error("didn't throw TypeError, returned " + r);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"didn't throw TypeError, got: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
var isPrototypeOf = Object.prototype.isPrototypeOf;
|
||||
|
||||
/*
|
||||
* 1. If V is not an Object, return false.
|
||||
*/
|
||||
assertEq(isPrototypeOf(), false);
|
||||
assertEq(isPrototypeOf(1), false);
|
||||
assertEq(isPrototypeOf(Number.MAX_VALUE), false);
|
||||
assertEq(isPrototypeOf(NaN), false);
|
||||
assertEq(isPrototypeOf(""), false);
|
||||
assertEq(isPrototypeOf("sesquicentennial"), false);
|
||||
assertEq(isPrototypeOf(true), false);
|
||||
assertEq(isPrototypeOf(false), false);
|
||||
assertEq(isPrototypeOf(0.72), false);
|
||||
assertEq(isPrototypeOf(undefined), false);
|
||||
assertEq(isPrototypeOf(null), false);
|
||||
|
||||
|
||||
/*
|
||||
* 2. Let O be the result of calling ToObject passing the this value as the
|
||||
* argument.
|
||||
*/
|
||||
var protoGlobal = Object.create(this);
|
||||
expectThrowTypeError(function() { isPrototypeOf.call(null, {}); });
|
||||
expectThrowTypeError(function() { isPrototypeOf.call(undefined, {}); });
|
||||
expectThrowTypeError(function() { isPrototypeOf({}); });
|
||||
expectThrowTypeError(function() { isPrototypeOf.call(null, protoGlobal); });
|
||||
expectThrowTypeError(function() { isPrototypeOf.call(undefined, protoGlobal); });
|
||||
expectThrowTypeError(function() { isPrototypeOf(protoGlobal); });
|
||||
|
||||
|
||||
/*
|
||||
* 3. Repeat
|
||||
*/
|
||||
|
||||
/*
|
||||
* 3a. Let V be the value of the [[Prototype]] internal property of V.
|
||||
* 3b. If V is null, return false.
|
||||
*/
|
||||
assertEq(Object.prototype.isPrototypeOf(Object.prototype), false);
|
||||
assertEq(String.prototype.isPrototypeOf({}), false);
|
||||
assertEq(Object.prototype.isPrototypeOf(Object.create(null)), false);
|
||||
|
||||
/* 3c. If O and V refer to the same object, return true. */
|
||||
assertEq(Object.prototype.isPrototypeOf({}), true);
|
||||
assertEq(this.isPrototypeOf(protoGlobal), true);
|
||||
assertEq(Object.prototype.isPrototypeOf({}), true);
|
||||
assertEq(Object.prototype.isPrototypeOf(new Number(17)), true);
|
||||
assertEq(Object.prototype.isPrototypeOf(function(){}), true);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
|
@ -42,3 +42,5 @@ script vacuous-accessor-unqualified-name.js
|
|||
script add-property-non-extensible.js
|
||||
skip-if(!xulRuntime.shell) script freeze-global-eval-const.js # uses evalcx
|
||||
script preventExtensions-idempotent.js
|
||||
script isPrototypeOf.js
|
||||
script propertyIsEnumerable.js
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var gTestfile = 'propertyIsEnumerable.js';
|
||||
var BUGNUMBER = 619283;
|
||||
var summary = "Object.prototype.propertyIsEnumerable";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
function expectThrowError(errorCtor, fun)
|
||||
{
|
||||
try
|
||||
{
|
||||
var r = fun();
|
||||
throw "didn't throw TypeError, returned " + r;
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof errorCtor, true,
|
||||
"didn't throw " + errorCtor.prototype.name + ", got: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
function expectThrowTypeError(fun)
|
||||
{
|
||||
expectThrowError(TypeError, fun);
|
||||
}
|
||||
|
||||
function withToString(fun)
|
||||
{
|
||||
return { toString: fun };
|
||||
}
|
||||
|
||||
function withValueOf(fun)
|
||||
{
|
||||
return { toString: null, valueOf: fun };
|
||||
}
|
||||
|
||||
var propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
|
||||
|
||||
/*
|
||||
* 1. Let P be ToString(V).
|
||||
*/
|
||||
expectThrowError(ReferenceError, function()
|
||||
{
|
||||
propertyIsEnumerable(withToString(function() { fahslkjdfhlkjdsl; }));
|
||||
});
|
||||
expectThrowError(ReferenceError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(null, withToString(function() { fahslkjdfhlkjdsl; }));
|
||||
});
|
||||
expectThrowError(ReferenceError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(undefined, withToString(function() { fahslkjdfhlkjdsl; }));
|
||||
});
|
||||
|
||||
expectThrowError(ReferenceError, function()
|
||||
{
|
||||
propertyIsEnumerable(withValueOf(function() { fahslkjdfhlkjdsl; }));
|
||||
});
|
||||
expectThrowError(ReferenceError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(null, withValueOf(function() { fahslkjdfhlkjdsl; }));
|
||||
});
|
||||
expectThrowError(ReferenceError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(undefined, withValueOf(function() { fahslkjdfhlkjdsl; }));
|
||||
});
|
||||
|
||||
expectThrowError(SyntaxError, function()
|
||||
{
|
||||
propertyIsEnumerable(withToString(function() { eval("}"); }));
|
||||
});
|
||||
expectThrowError(SyntaxError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(null, withToString(function() { eval("}"); }));
|
||||
});
|
||||
expectThrowError(SyntaxError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(undefined, withToString(function() { eval("}"); }));
|
||||
});
|
||||
|
||||
expectThrowError(SyntaxError, function()
|
||||
{
|
||||
propertyIsEnumerable(withValueOf(function() { eval("}"); }));
|
||||
});
|
||||
expectThrowError(SyntaxError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(null, withValueOf(function() { eval("}"); }));
|
||||
});
|
||||
expectThrowError(SyntaxError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(undefined, withValueOf(function() { eval("}"); }));
|
||||
});
|
||||
|
||||
expectThrowError(RangeError, function()
|
||||
{
|
||||
propertyIsEnumerable(withToString(function() { [].length = -1; }));
|
||||
});
|
||||
expectThrowError(RangeError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(null, withToString(function() { [].length = -1; }));
|
||||
});
|
||||
expectThrowError(RangeError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(undefined, withToString(function() { [].length = -1; }));
|
||||
});
|
||||
|
||||
expectThrowError(RangeError, function()
|
||||
{
|
||||
propertyIsEnumerable(withValueOf(function() { [].length = -1; }));
|
||||
});
|
||||
expectThrowError(RangeError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(null, withValueOf(function() { [].length = -1; }));
|
||||
});
|
||||
expectThrowError(RangeError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(undefined, withValueOf(function() { [].length = -1; }));
|
||||
});
|
||||
|
||||
expectThrowError(RangeError, function()
|
||||
{
|
||||
propertyIsEnumerable(withToString(function() { [].length = 0.7; }));
|
||||
});
|
||||
expectThrowError(RangeError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(null, withToString(function() { [].length = 0.7; }));
|
||||
});
|
||||
expectThrowError(RangeError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(undefined, withToString(function() { [].length = 0.7; }));
|
||||
});
|
||||
|
||||
expectThrowError(RangeError, function()
|
||||
{
|
||||
propertyIsEnumerable(withValueOf(function() { [].length = 0.7; }));
|
||||
});
|
||||
expectThrowError(RangeError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(null, withValueOf(function() { [].length = 0.7; }));
|
||||
});
|
||||
expectThrowError(RangeError, function()
|
||||
{
|
||||
propertyIsEnumerable.call(undefined, withValueOf(function() { [].length = 0.7; }));
|
||||
});
|
||||
|
||||
/*
|
||||
* 2. Let O be the result of calling ToObject passing the this value as the
|
||||
* argument.
|
||||
*/
|
||||
expectThrowTypeError(function() { propertyIsEnumerable("s"); });
|
||||
expectThrowTypeError(function() { propertyIsEnumerable.call(null, "s"); });
|
||||
expectThrowTypeError(function() { propertyIsEnumerable.call(undefined, "s"); });
|
||||
expectThrowTypeError(function() { propertyIsEnumerable(true); });
|
||||
expectThrowTypeError(function() { propertyIsEnumerable.call(null, true); });
|
||||
expectThrowTypeError(function() { propertyIsEnumerable.call(undefined, true); });
|
||||
expectThrowTypeError(function() { propertyIsEnumerable(NaN); });
|
||||
expectThrowTypeError(function() { propertyIsEnumerable.call(null, NaN); });
|
||||
expectThrowTypeError(function() { propertyIsEnumerable.call(undefined, NaN); });
|
||||
|
||||
expectThrowTypeError(function() { propertyIsEnumerable({}); });
|
||||
expectThrowTypeError(function() { propertyIsEnumerable.call(null, {}); });
|
||||
expectThrowTypeError(function() { propertyIsEnumerable.call(undefined, {}); });
|
||||
|
||||
/*
|
||||
* 3. Let desc be the result of calling the [[GetOwnProperty]] internal method
|
||||
* of O passing P as the argument.
|
||||
* 4. If desc is undefined, return false.
|
||||
*/
|
||||
assertEq(propertyIsEnumerable.call({}, "valueOf"), false);
|
||||
assertEq(propertyIsEnumerable.call({}, "toString"), false);
|
||||
assertEq(propertyIsEnumerable.call("s", 1), false);
|
||||
assertEq(propertyIsEnumerable.call({}, "dsfiodjfs"), false);
|
||||
assertEq(propertyIsEnumerable.call(true, "toString"), false);
|
||||
assertEq(propertyIsEnumerable.call({}, "__proto__"), false);
|
||||
|
||||
assertEq(propertyIsEnumerable.call(Object, "getOwnPropertyDescriptor"), false);
|
||||
assertEq(propertyIsEnumerable.call(this, "expectThrowTypeError"), true);
|
||||
assertEq(propertyIsEnumerable.call("s", "length"), false);
|
||||
assertEq(propertyIsEnumerable.call("s", 0), true);
|
||||
assertEq(propertyIsEnumerable.call(Number, "MAX_VALUE"), false);
|
||||
assertEq(propertyIsEnumerable.call({ x: 9 }, "x"), true);
|
||||
assertEq(propertyIsEnumerable.call(function() { }, "prototype"), false);
|
||||
assertEq(propertyIsEnumerable.call(function() { }, "length"), false);
|
||||
assertEq(propertyIsEnumerable.call(function() { "use strict"; }, "caller"), false);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 619283;
|
||||
var summary =
|
||||
"ECMAScript built-in methods that immediately throw when |this| is " +
|
||||
"|undefined| or |null| (due to CheckObjectCoercible, ToObject, or ToString)";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
// This test fills out for the non-standard methods which
|
||||
// ecma_5/misc/builtin-methods-reject-null-undefined-this.js declines to test.
|
||||
|
||||
var ClassToMethodMap =
|
||||
{
|
||||
Object: [/*
|
||||
* Don't box this just yet for these methods -- they're used too
|
||||
* much without qualification to do that. :-(
|
||||
*/
|
||||
/* "__defineGetter__", "__defineSetter__", */
|
||||
"__lookupGetter__", "__lookupSetter__", "watch", "unwatch",
|
||||
"toSource"],
|
||||
Function: ["toSource"],
|
||||
Array: ["toSource"],
|
||||
String: ["toSource", "quote", "bold", "italics", "fixed", "fontsize",
|
||||
"fontcolor", "link", "anchor", "strike", "small", "big", "blink",
|
||||
"sup", "sub", "substr", "trimLeft", "trimRight", "toJSON"],
|
||||
Boolean: ["toSource", "toJSON"],
|
||||
Number: ["toSource", "toJSON"],
|
||||
Date: ["toSource", "toLocaleFormat", "getYear", "setYear",
|
||||
"toGMTString"],
|
||||
RegExp: ["toSource"],
|
||||
Error: ["toSource"],
|
||||
};
|
||||
|
||||
var badThisValues = [null, undefined];
|
||||
|
||||
function testMethod(Class, className, method)
|
||||
{
|
||||
var expr;
|
||||
|
||||
// Try out explicit this values
|
||||
for (var i = 0, sz = badThisValues.length; i < sz; i++)
|
||||
{
|
||||
var badThis = badThisValues[i];
|
||||
|
||||
expr = className + ".prototype." + method + ".call(" + badThis + ")";
|
||||
try
|
||||
{
|
||||
Class.prototype[method].call(badThis);
|
||||
throw new Error(expr + " didn't throw a TypeError");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"wrong error for " + expr + ", instead threw " + e);
|
||||
}
|
||||
|
||||
expr = className + ".prototype." + method + ".apply(" + badThis + ")";
|
||||
try
|
||||
{
|
||||
Class.prototype[method].apply(badThis);
|
||||
throw new Error(expr + " didn't throw a TypeError");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"wrong error for " + expr + ", instead threw " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// ..and for good measure..
|
||||
|
||||
expr = "(0, " + className + ".prototype." + method + ")()"
|
||||
try
|
||||
{
|
||||
// comma operator to call GetValue() on the method and de-Reference it
|
||||
(0, Class.prototype[method])();
|
||||
throw new Error(expr + " didn't throw a TypeError");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"wrong error for " + expr + ", instead threw " + e);
|
||||
}
|
||||
}
|
||||
|
||||
for (var className in ClassToMethodMap)
|
||||
{
|
||||
var Class = this[className];
|
||||
|
||||
var methodNames = ClassToMethodMap[className];
|
||||
for (var i = 0, sz = methodNames.length; i < sz; i++)
|
||||
{
|
||||
var method = methodNames[i];
|
||||
testMethod(Class, className, method);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
|
@ -24,3 +24,4 @@ script bug566661.js
|
|||
script iterator-in-catch.js
|
||||
script strict-function-statements.js
|
||||
skip-if(!xulRuntime.shell) script function-definition-with.js # needs evaluate()
|
||||
script extension-methods-reject-null-undefined-this.js
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
var global = this;
|
||||
|
||||
(function() {
|
||||
function f() {
|
||||
this.b = function() {};
|
||||
Object.defineProperty(this, "b", ({
|
||||
configurable: __defineSetter__("", function() {})
|
||||
configurable: global.__defineSetter__("", function() {})
|
||||
}));
|
||||
}
|
||||
for each(y in [0]) {
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 619283;
|
||||
var summary =
|
||||
"ECMAScript built-in methods that immediately throw when |this| is " +
|
||||
"|undefined| or |null| (due to CheckObjectCoercible, ToObject, or ToString)";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
// We can't just exhaustively loop over everything because 1) method properties
|
||||
// might be extensions with special |this| handling, and 2) some methods don't
|
||||
// *quite* immediately throw a TypeError, first thing, if |this| is |undefined|
|
||||
// or |null|, or their algorithms are very slightly ambiguous about whether they
|
||||
// do. Why? Ipse-dixitism. *shrug*
|
||||
|
||||
var ClassToMethodMap =
|
||||
{
|
||||
Object: [/* "toString" has special |this| handling */
|
||||
"toLocaleString", "valueOf", "hasOwnProperty",
|
||||
/*
|
||||
* "isPrototypeOf" has special |this| handling already tested in
|
||||
* ecma_5/Object/isPrototypeOf.js.
|
||||
*/
|
||||
/*
|
||||
* "isPrototypeOf" has special |this| handling already tested in
|
||||
* ecma_5/Object/propertyIsEnumerable.js.
|
||||
*/],
|
||||
// Function methods often don't ToObject(this) as their very first step,
|
||||
// and they're already stepwise well-tested such that manual tests here
|
||||
// would be redundant.
|
||||
Array: ["toString", "toLocaleString", "concat", "join", "pop", "push",
|
||||
"reverse", "shift", "slice", "sort", "splice", "unshift",
|
||||
"indexOf", "lastIndexOf", "every", "some", "forEach", "map",
|
||||
"filter", "reduce", "reduceRight"],
|
||||
String: ["toString", "valueOf", "charAt", "charCodeAt", "concat",
|
||||
"indexOf", "lastIndexOf", "localeCompare", "match", "replace",
|
||||
"search", "slice", "split", "substring", "toLowerCase",
|
||||
"toLocaleLowerCase", "toUpperCase", "toLocaleUpperCase", "trim",
|
||||
/*
|
||||
* "trimLeft" and "trimRight" are non-standard and thus are tested
|
||||
* in ecma_5/extensions/trim-extensions.js.
|
||||
*/
|
||||
],
|
||||
Boolean: ["toString", "valueOf"],
|
||||
Number: ["toString", "toLocaleString", "valueOf",
|
||||
/*
|
||||
* toFixed doesn't *immediately* test |this| for number or
|
||||
* Number-ness, but because the ToInteger(void 0) which arguably
|
||||
* precedes it in the toFixed algorithm won't throw in this test,
|
||||
* we don't need to specially test it.
|
||||
*/
|
||||
"toFixed",
|
||||
"toExponential", "toPrecision"],
|
||||
Date: ["toString", "toDateString", "toTimeString", "toLocaleString",
|
||||
"toLocaleDateString", "toLocaleTimeString", "valueOf", "getTime",
|
||||
"getFullYear", "getUTCFullYear", "getMonth", "getUTCMonth",
|
||||
"getDate", "getUTCDate", "getDay", "getUTCDay", "getHours",
|
||||
"getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds",
|
||||
"getUTCSeconds", "getMilliseconds", "getUTCMilliseconds",
|
||||
/*
|
||||
* toFixed doesn't *immediately* test |this| for number or
|
||||
* Number-ness, but because the TimeClip(ToNumber(void 0)) which
|
||||
* arguably precedes it in the setTime algorithm won't throw in
|
||||
* this test, we don't need to specially test it.
|
||||
*/
|
||||
"setTime",
|
||||
"getTimezoneOffset", "setMilliseconds", "setUTCMilliseconds",
|
||||
"setSeconds", "setUTCSeconds", "setMinutes", "setUTCMinutes",
|
||||
"setHours", "setUTCHours", "setDate", "setUTCDate", "setMonth",
|
||||
"setUTCMonth", "setFullYear", "setUTCFullYear", "toUTCString",
|
||||
"toISOString", "toJSON"],
|
||||
RegExp: ["exec", "test", "toString"],
|
||||
Error: ["toString"],
|
||||
};
|
||||
|
||||
var badThisValues = [null, undefined];
|
||||
|
||||
function testMethod(Class, className, method)
|
||||
{
|
||||
var expr;
|
||||
|
||||
// Try out explicit this values
|
||||
for (var i = 0, sz = badThisValues.length; i < sz; i++)
|
||||
{
|
||||
var badThis = badThisValues[i];
|
||||
|
||||
expr = className + ".prototype." + method + ".call(" + badThis + ")";
|
||||
try
|
||||
{
|
||||
Class.prototype[method].call(badThis);
|
||||
throw new Error(expr + " didn't throw a TypeError");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"wrong error for " + expr + ", instead threw " + e);
|
||||
}
|
||||
|
||||
expr = className + ".prototype." + method + ".apply(" + badThis + ")";
|
||||
try
|
||||
{
|
||||
Class.prototype[method].apply(badThis);
|
||||
throw new Error(expr + " didn't throw a TypeError");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"wrong error for " + expr + ", instead threw " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// ..and for good measure..
|
||||
|
||||
expr = "(0, " + className + ".prototype." + method + ")()"
|
||||
try
|
||||
{
|
||||
// comma operator to call GetValue() on the method and de-Reference it
|
||||
(0, Class.prototype[method])();
|
||||
throw new Error(expr + " didn't throw a TypeError");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"wrong error for " + expr + ", instead threw " + e);
|
||||
}
|
||||
}
|
||||
|
||||
for (var className in ClassToMethodMap)
|
||||
{
|
||||
var Class = this[className];
|
||||
|
||||
var methodNames = ClassToMethodMap[className];
|
||||
for (var i = 0, sz = methodNames.length; i < sz; i++)
|
||||
{
|
||||
var method = methodNames[i];
|
||||
testMethod(Class, className, method);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
|
@ -7,3 +7,4 @@ script explicit-undefined-optional-argument.js
|
|||
script function-definition-eval.js
|
||||
skip-if(!xulRuntime.shell) script function-definition-evaluate.js # needs evaluate()
|
||||
script future-reserved-words.js
|
||||
script builtin-methods-reject-null-undefined-this.js
|
||||
|
|
|
@ -44,6 +44,15 @@ var expect = 'No Crash';
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
"".match.apply();
|
||||
try
|
||||
{
|
||||
"".match.apply();
|
||||
throw new Error("should have thrown for undefined this");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"No TypeError for String.prototype.match");
|
||||
}
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
|
|
@ -51,8 +51,16 @@ function test()
|
|||
enterFunc ('test');
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
(function() { var s = function(){}.prototype.toSource; s(); })();
|
||||
|
||||
try
|
||||
{
|
||||
(function() { var s = function(){}.prototype.toSource; s(); })();
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"No TypeError for Object.prototype.toSource");
|
||||
}
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -57,13 +57,30 @@ function test()
|
|||
n.__defineGetter__("prototype", n.toSource);
|
||||
p = n.__lookupGetter__("prototype");
|
||||
n = p;
|
||||
|
||||
assertEq(n, Object.prototype.toSource);
|
||||
assertEq(p, Object.prototype.toSource);
|
||||
|
||||
n["prototype"] = [n];
|
||||
n = p;
|
||||
|
||||
assertEq(n, Object.prototype.toSource);
|
||||
assertEq(p, Object.prototype.toSource);
|
||||
|
||||
p2 = n["prototype"];
|
||||
|
||||
assertEq(Array.isArray(p2), true);
|
||||
assertEq(p2[0], Object.prototype.toSource);
|
||||
|
||||
n = p2;
|
||||
|
||||
assertEq(n.toString, Array.prototype.toString);
|
||||
n.__defineGetter__("0", n.toString);
|
||||
n = p;
|
||||
n();
|
||||
|
||||
assertEq(n, Object.prototype.toSource);
|
||||
|
||||
n.call(this);
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
|
|
|
@ -60,11 +60,16 @@ actual = String.toUpperCase(new Boolean(true));
|
|||
reportCompare(expect, actual, summary +
|
||||
" String.toUpperCase(new Boolean(true))");
|
||||
|
||||
// null means the global object is passed
|
||||
expect = (typeof window == 'undefined') ? 9 : -1;
|
||||
actual = String.indexOf(null, 'l');
|
||||
reportCompare(expect, actual, summary +
|
||||
" String.indexOf(null, 'l')");
|
||||
try
|
||||
{
|
||||
String.indexOf(null, 'l');
|
||||
throw new Error("should have thrown a TypeError");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"String.indexOf(null [, ...]) didn't work correctly");
|
||||
}
|
||||
|
||||
expect = 2;
|
||||
actual = String.indexOf(String(null), 'l');
|
||||
|
@ -86,11 +91,16 @@ actual = String.toUpperCase(true);
|
|||
reportCompare(expect, actual, summary +
|
||||
" String.toUpperCase(true)");
|
||||
|
||||
// null means the global object is passed
|
||||
expect = (typeof window == 'undefined') ? -1 : 11;
|
||||
actual = String.indexOf(undefined, 'd');
|
||||
reportCompare(expect, actual, summary +
|
||||
" String.indexOf(undefined, 'd')");
|
||||
try
|
||||
{
|
||||
String.indexOf(undefined, 'd');
|
||||
throw new Error("should have thrown a TypeError");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"String.indexOf(undefined [, ...]) didn't work correctly");
|
||||
}
|
||||
|
||||
expect = 2;
|
||||
actual = String.indexOf(String(undefined), 'd');
|
||||
|
|
|
@ -58,15 +58,17 @@ function test()
|
|||
actual = f + '';
|
||||
compareSource(expect, actual, summary);
|
||||
|
||||
expect = 'TypeError: "a" is not a function';
|
||||
try
|
||||
{
|
||||
f();
|
||||
throw new Error("no TypeError thrown calling map with undefined this");
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
actual = ex + '';
|
||||
assertEq(ex instanceof TypeError, true,
|
||||
"No TypeError for Array.prototype.map with undefined this");
|
||||
}
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
reportCompare(true, true, summary);
|
||||
exitFunc ('test');
|
||||
}
|
||||
|
|
|
@ -58,15 +58,17 @@ function test()
|
|||
actual = f + '';
|
||||
compareSource(expect, actual, summary);
|
||||
|
||||
expect = 'TypeError: "a" is not a function';
|
||||
try
|
||||
{
|
||||
f();
|
||||
throw new Error("no TypeError thrown calling map with undefined this");
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
actual = ex + '';
|
||||
assertEq(ex instanceof TypeError, true,
|
||||
"No TypeError for Array.prototype.map with undefined this");
|
||||
}
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
reportCompare(true, true, summary);
|
||||
exitFunc ('test');
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ var actual = '';
|
|||
var expect = true;
|
||||
var voids = [null, undefined];
|
||||
|
||||
|
||||
function noop() { }
|
||||
|
||||
var generics = {
|
||||
String: [{ quote: [] },
|
||||
{ substring: [] },
|
||||
|
@ -85,6 +88,8 @@ var generics = {
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
var global = this;
|
||||
|
||||
for (var c in generics)
|
||||
{
|
||||
var methods = generics[c];
|
||||
|
@ -96,59 +101,62 @@ for (var c in generics)
|
|||
{
|
||||
for (var v = 0; v < voids.length; v++)
|
||||
{
|
||||
var lhs = c + '.' + methodname +
|
||||
'(' + voids[v] + (method[methodname].length ?(', ' + method[methodname].toString()):'') + ')';
|
||||
var Constructor = global[c]
|
||||
|
||||
var rhs = c + '.prototype.' + methodname +
|
||||
'.apply(' + voids[v] + ', ' + method[methodname].toSource() + ')';
|
||||
var argsLen = method[methodname].length;
|
||||
assertEq(argsLen === 0 || argsLen === 1, true, "not all arities handled");
|
||||
|
||||
var expr = lhs + ' == ' + rhs;
|
||||
printStatus('Testing ' + expr);
|
||||
var generic = Constructor[methodname];
|
||||
var prototypy = Constructor.prototype[methodname];
|
||||
|
||||
assertEq(typeof generic, "function");
|
||||
assertEq(typeof prototypy, "function");
|
||||
|
||||
// GENERIC METHOD TESTING
|
||||
|
||||
try
|
||||
{
|
||||
printStatus('lhs ' + lhs + ': ' + eval(lhs));
|
||||
switch (method[methodname].length)
|
||||
{
|
||||
case 0:
|
||||
generic(voids[v]);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
generic(voids[v], method[methodname][0]);
|
||||
break;
|
||||
}
|
||||
throw new Error(c + "." + methodname + " must throw for null or " +
|
||||
"undefined first argument");
|
||||
}
|
||||
catch(ex)
|
||||
catch (e)
|
||||
{
|
||||
printStatus(ex + '');
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"Didn't get a TypeError for " + c + "." + methodname +
|
||||
" called with null or undefined first argument");
|
||||
}
|
||||
|
||||
|
||||
// PROTOTYPE METHOD TESTING
|
||||
|
||||
try
|
||||
{
|
||||
printStatus('rhs ' + rhs + ': ' + eval(rhs));
|
||||
prototypy.apply(voids[v], method[methodname][0]);
|
||||
throw new Error(c + ".prototype." + methodname + " must throw " +
|
||||
"for null or undefined this");
|
||||
}
|
||||
catch(ex)
|
||||
catch (e)
|
||||
{
|
||||
printStatus(ex + '');
|
||||
assertEq(e instanceof TypeError, true,
|
||||
c + ".prototype." + methodname + "didn't throw a " +
|
||||
"TypeError when called with null or undefined this");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
actual = comparelr(eval(lhs), eval(rhs));
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
actual = ex + '';
|
||||
}
|
||||
reportCompare(expect, actual, expr);
|
||||
printStatus('');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function comparelr(lhs, rhs)
|
||||
{
|
||||
|
||||
if (lhs.constructor.name != 'Array')
|
||||
{
|
||||
return (lhs == rhs);
|
||||
}
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
return (lhs.toSource() == rhs.toSource());
|
||||
}
|
||||
|
||||
function noop()
|
||||
{
|
||||
}
|
||||
print("Tests finished.");
|
||||
|
|
|
@ -46,7 +46,7 @@ printBugNumber(BUGNUMBER);
|
|||
printStatus (summary);
|
||||
|
||||
this.watch("b", "".substring);
|
||||
__defineGetter__("a", gc);
|
||||
this.__defineGetter__("a", gc);
|
||||
for each (b in [this, null, null]);
|
||||
a;
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ for (var j = 0; j < 10; j++)
|
|||
for (var i = 0; i < j; ++i)
|
||||
this["n" + i] = 1;
|
||||
|
||||
__defineGetter__('w', (function(){}));
|
||||
this.__defineGetter__('w', (function(){}));
|
||||
|
||||
[1 for each (g in this) for each (t in /x/g)];
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ printStatus (summary);
|
|||
// Assertion failure: !OBJ_GET_CLASS(cx, proto)->getObjectOps, at ../jsobj.cpp:2030
|
||||
|
||||
jit(true);
|
||||
__defineGetter__("x3", Function);
|
||||
this.__defineGetter__("x3", Function);
|
||||
parseInt = x3;
|
||||
parseInt.prototype = [];
|
||||
for (var z = 0; z < 4; ++z) { new parseInt() }
|
||||
|
|
|
@ -55,7 +55,7 @@ function test()
|
|||
|
||||
// Assertion failure: afunbox->parent, at ../jsparse.cpp:1912
|
||||
|
||||
watch("x", Function);
|
||||
this.watch("x", Function);
|
||||
NaN = uneval({ get \u3056 (){ return undefined } });
|
||||
x+=NaN;
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ function test()
|
|||
|
||||
// Assertion failure: localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST, at ../jsfun.cpp:916
|
||||
|
||||
watch("x", Function);
|
||||
this.watch("x", Function);
|
||||
NaN = uneval({ get \u3056 (){ return undefined } });
|
||||
x+=NaN;
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ function test()
|
|||
reportCompare(expect, actual, summary + ': 1');
|
||||
|
||||
// crash [@ js_Interpret]
|
||||
(eval("(function(){ watch(\"x\", function () { new function ()y } ); const y });"))();
|
||||
(eval("(function(){ this.watch(\"x\", function () { new function ()y } ); const y });"))();
|
||||
x = NaN;
|
||||
reportCompare(expect, actual, summary + ': 2');
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ function f(code) {
|
|||
code.replace(/s/, "")
|
||||
eval(code)
|
||||
}
|
||||
__defineGetter__("x", /x/)
|
||||
this.__defineGetter__("x", /x/)
|
||||
f("function a() {\
|
||||
x = Proxy.createFunction((function () {\
|
||||
return {\
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
|
||||
eval("\
|
||||
(function(){for(d in[0,Number]) {\
|
||||
__defineGetter__(\"\",function(){}),\
|
||||
[(__defineGetter__(\"x\",Math.pow))]\
|
||||
this.__defineGetter__(\"\",function(){}),\
|
||||
[(this.__defineGetter__(\"x\",Math.pow))]\
|
||||
}})\
|
||||
")()
|
||||
delete gc
|
||||
eval("\
|
||||
(function() {\
|
||||
for(e in __defineSetter__(\"x\",function(){})){}\
|
||||
for(e in this.__defineSetter__(\"x\",function(){})){}\
|
||||
})\
|
||||
")()
|
||||
delete gc
|
||||
|
|
Загрузка…
Ссылка в новой задаче