зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central and tracemonkey.
This commit is contained in:
Коммит
277ecef0fa
|
@ -1698,16 +1698,6 @@ public:
|
|||
*/
|
||||
static nsresult CreateStructuredClone(JSContext* cx, jsval val, jsval* rval);
|
||||
|
||||
/**
|
||||
* Reparents the given object and all subobjects to the given scope. Also
|
||||
* fixes all the prototypes. Assumes obj is properly rooted, that obj has no
|
||||
* getter functions that can cause side effects, and that the only types of
|
||||
* objects nested within obj are the types that are cloneable via the
|
||||
* CreateStructuredClone function above.
|
||||
*/
|
||||
static nsresult ReparentClonedObjectToScope(JSContext* cx, JSObject* obj,
|
||||
JSObject* scope);
|
||||
|
||||
/**
|
||||
* Strip all \n, \r and nulls from the given string
|
||||
* @param aString the string to remove newlines from [in/out]
|
||||
|
|
|
@ -6100,89 +6100,6 @@ nsContentUtils::CreateStructuredClone(JSContext* cx,
|
|||
*rval = output;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsContentUtils::ReparentClonedObjectToScope(JSContext* cx,
|
||||
JSObject* obj,
|
||||
JSObject* scope)
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
scope = JS_GetGlobalForObject(cx, scope);
|
||||
|
||||
nsAutoTArray<ReparentObjectData, 20> objectData;
|
||||
objectData.AppendElement(ReparentObjectData(cx, obj));
|
||||
|
||||
while (!objectData.IsEmpty()) {
|
||||
ReparentObjectData& data = objectData[objectData.Length() - 1];
|
||||
|
||||
if (!data.ids) {
|
||||
NS_ASSERTION(!data.index, "Shouldn't have index here");
|
||||
|
||||
// Typed arrays are special and don't need to be enumerated.
|
||||
if (js_IsTypedArray(data.obj)) {
|
||||
if (!js_ReparentTypedArrayToScope(cx, data.obj, scope)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// No need to enumerate anything here.
|
||||
objectData.RemoveElementAt(objectData.Length() - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(JS_GET_CLASS(cx, data.obj));
|
||||
if (!key) {
|
||||
// We should never be reparenting an object that doesn't have a standard
|
||||
// proto key.
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Fix the prototype and parent first.
|
||||
JSObject* proto;
|
||||
if (!js_GetClassPrototype(cx, scope, key, &proto) ||
|
||||
!JS_SetPrototype(cx, data.obj, proto) ||
|
||||
!JS_SetParent(cx, data.obj, scope)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Primitive arrays don't need to be enumerated either but the proto and
|
||||
// parent needed to be fixed above. Now we can just move on.
|
||||
if (js_IsDensePrimitiveArray(data.obj)) {
|
||||
objectData.RemoveElementAt(objectData.Length() - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// And now enumerate the object's properties.
|
||||
if (!(data.ids = JS_Enumerate(cx, data.obj))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// If we've gone through all the object's properties then we're done with
|
||||
// this frame.
|
||||
if (data.index == data.ids->length) {
|
||||
objectData.RemoveElementAt(objectData.Length() - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the id and increment!
|
||||
jsid id = data.ids->vector[data.index++];
|
||||
|
||||
jsval prop;
|
||||
if (!JS_GetPropertyById(cx, data.obj, id, &prop)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Push a new frame if this property is an object.
|
||||
if (!JSVAL_IS_PRIMITIVE(prop)) {
|
||||
objectData.AppendElement(ReparentObjectData(cx, JSVAL_TO_OBJECT(prop)));
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
struct ClassMatchingInfo {
|
||||
nsAttrValue::AtomArray mClasses;
|
||||
nsCaseTreatment mCaseTreatment;
|
||||
|
|
|
@ -3646,14 +3646,6 @@ SetMemoryMaxPrefChangedCallback(const char* aPrefName, void* aClosure)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
SetMemoryGCFrequencyPrefChangedCallback(const char* aPrefName, void* aClosure)
|
||||
{
|
||||
PRInt32 triggerFactor = nsContentUtils::GetIntPref(aPrefName, 300);
|
||||
JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_TRIGGER_FACTOR, triggerFactor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
SetMemoryGCModePrefChangedCallback(const char* aPrefName, void* aClosure)
|
||||
{
|
||||
|
@ -3796,12 +3788,6 @@ nsJSRuntime::Init()
|
|||
SetMemoryMaxPrefChangedCallback("javascript.options.mem.max",
|
||||
nsnull);
|
||||
|
||||
nsContentUtils::RegisterPrefCallback("javascript.options.mem.gc_frequency",
|
||||
SetMemoryGCFrequencyPrefChangedCallback,
|
||||
nsnull);
|
||||
SetMemoryGCFrequencyPrefChangedCallback("javascript.options.mem.gc_frequency",
|
||||
nsnull);
|
||||
|
||||
nsContentUtils::RegisterPrefCallback("javascript.options.mem.gc_per_compartment",
|
||||
SetMemoryGCModePrefChangedCallback,
|
||||
nsnull);
|
||||
|
|
|
@ -277,6 +277,7 @@ VPATH += \
|
|||
EXPORTS_NAMESPACES = vm
|
||||
|
||||
EXPORTS_vm = \
|
||||
ArgumentsObject.h \
|
||||
GlobalObject.h \
|
||||
Stack.h \
|
||||
StringObject.h \
|
||||
|
@ -415,7 +416,7 @@ CPPSRCS += checks.cc \
|
|||
# END enclude sources for V8 dtoa
|
||||
#############################################
|
||||
|
||||
ifeq (,$(filter arm% %86 x86_64,$(TARGET_CPU)))
|
||||
ifeq (,$(filter arm% sparc %86 x86_64,$(TARGET_CPU)))
|
||||
|
||||
VPATH += $(srcdir)/assembler \
|
||||
$(srcdir)/assembler/wtf \
|
||||
|
|
|
@ -2651,15 +2651,11 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
|
|||
case JSGC_STACKPOOL_LIFESPAN:
|
||||
rt->gcEmptyArenaPoolLifespan = value;
|
||||
break;
|
||||
case JSGC_MODE:
|
||||
default:
|
||||
JS_ASSERT(key == JSGC_MODE);
|
||||
rt->gcMode = JSGCMode(value);
|
||||
JS_ASSERT(rt->gcMode == JSGC_MODE_GLOBAL ||
|
||||
rt->gcMode == JSGC_MODE_COMPARTMENT);
|
||||
break;
|
||||
default:
|
||||
JS_ASSERT(key == JSGC_TRIGGER_FACTOR);
|
||||
JS_ASSERT(value >= 100);
|
||||
rt->setGCTriggerFactor(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2674,8 +2670,6 @@ JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
|
|||
return rt->gcMaxMallocBytes;
|
||||
case JSGC_STACKPOOL_LIFESPAN:
|
||||
return rt->gcEmptyArenaPoolLifespan;
|
||||
case JSGC_TRIGGER_FACTOR:
|
||||
return rt->gcTriggerFactor;
|
||||
case JSGC_BYTES:
|
||||
return rt->gcBytes;
|
||||
case JSGC_MODE:
|
||||
|
@ -3263,7 +3257,7 @@ JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, uintN flag
|
|||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, id);
|
||||
ok = obj->isNative()
|
||||
? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0
|
||||
? LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop)
|
||||
: obj->lookupProperty(cx, id, objp, &prop);
|
||||
return ok && LookupResult(cx, obj, *objp, id, prop, Valueify(vp));
|
||||
}
|
||||
|
@ -3366,8 +3360,8 @@ DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value,
|
|||
|
||||
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
|
||||
if (flags != 0 && obj->isNative()) {
|
||||
return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter,
|
||||
attrs, flags, tinyid, NULL);
|
||||
return !!DefineNativeProperty(cx, obj, id, value, getter, setter,
|
||||
attrs, flags, tinyid);
|
||||
}
|
||||
return obj->defineProperty(cx, id, value, getter, setter, attrs);
|
||||
}
|
||||
|
|
|
@ -1786,30 +1786,20 @@ typedef enum JSGCParamKey {
|
|||
/* Hoard stackPools for this long, in ms, default is 30 seconds. */
|
||||
JSGC_STACKPOOL_LIFESPAN = 2,
|
||||
|
||||
/*
|
||||
* The factor that defines when the GC is invoked. The factor is a
|
||||
* percent of the memory allocated by the GC after the last run of
|
||||
* the GC. When the current memory allocated by the GC is more than
|
||||
* this percent then the GC is invoked. The factor cannot be less
|
||||
* than 100 since the current memory allocated by the GC cannot be less
|
||||
* than the memory allocated after the last run of the GC.
|
||||
*/
|
||||
JSGC_TRIGGER_FACTOR = 3,
|
||||
|
||||
/* Amount of bytes allocated by the GC. */
|
||||
JSGC_BYTES = 4,
|
||||
JSGC_BYTES = 3,
|
||||
|
||||
/* Number of times when GC was invoked. */
|
||||
JSGC_NUMBER = 5,
|
||||
JSGC_NUMBER = 4,
|
||||
|
||||
/* Max size of the code cache in bytes. */
|
||||
JSGC_MAX_CODE_CACHE_BYTES = 6,
|
||||
JSGC_MAX_CODE_CACHE_BYTES = 5,
|
||||
|
||||
/* Select GC mode. */
|
||||
JSGC_MODE = 7,
|
||||
JSGC_MODE = 6,
|
||||
|
||||
/* Number of GC chunks waiting to expire. */
|
||||
JSGC_UNUSED_CHUNKS = 8
|
||||
JSGC_UNUSED_CHUNKS = 7
|
||||
} JSGCParamKey;
|
||||
|
||||
typedef enum JSGCMode {
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
#include "jstypes.h"
|
||||
#include "jsstdint.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsarray.h"
|
||||
#include "jsatom.h"
|
||||
|
@ -105,12 +106,15 @@
|
|||
#include "jsvector.h"
|
||||
#include "jswrapper.h"
|
||||
|
||||
#include "vm/ArgumentsObject.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsinterpinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsstrinlines.h"
|
||||
|
||||
#include "vm/ArgumentsObject-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
@ -217,9 +221,12 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (obj->isArguments() && !obj->isArgsLengthOverridden()) {
|
||||
*lengthp = obj->getArgsInitialLength();
|
||||
return true;
|
||||
if (obj->isArguments()) {
|
||||
ArgumentsObject *argsobj = obj->asArguments();
|
||||
if (!argsobj->hasOverriddenLength()) {
|
||||
*lengthp = argsobj->initialLength();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
AutoValueRooter tvr(cx);
|
||||
|
@ -263,7 +270,7 @@ BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom,
|
|||
*/
|
||||
if (!createAtom &&
|
||||
((clasp = obj->getClass()) == &js_SlowArrayClass ||
|
||||
clasp == &js_ArgumentsClass ||
|
||||
obj->isArguments() ||
|
||||
clasp == &js_ObjectClass)) {
|
||||
atom = js_GetExistingStringAtom(cx, start, JS_ARRAY_END(buf) - start);
|
||||
if (!atom) {
|
||||
|
@ -349,15 +356,17 @@ GetElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, Value *vp
|
|||
*hole = JS_FALSE;
|
||||
return JS_TRUE;
|
||||
}
|
||||
if (obj->isArguments() &&
|
||||
index < obj->getArgsInitialLength() &&
|
||||
!(*vp = obj->getArgsElement(uint32(index))).isMagic(JS_ARGS_HOLE)) {
|
||||
*hole = JS_FALSE;
|
||||
StackFrame *fp = (StackFrame *)obj->getPrivate();
|
||||
if (fp != JS_ARGUMENTS_OBJECT_ON_TRACE) {
|
||||
if (fp)
|
||||
*vp = fp->canonicalActualArg(index);
|
||||
return JS_TRUE;
|
||||
if (obj->isArguments()) {
|
||||
ArgumentsObject *argsobj = obj->asArguments();
|
||||
if (index < argsobj->initialLength() &&
|
||||
!(*vp = argsobj->element(uint32(index))).isMagic(JS_ARGS_HOLE)) {
|
||||
*hole = JS_FALSE;
|
||||
StackFrame *fp = reinterpret_cast<StackFrame *>(argsobj->getPrivate());
|
||||
if (fp != JS_ARGUMENTS_OBJECT_ON_TRACE) {
|
||||
if (fp)
|
||||
*vp = fp->canonicalActualArg(index);
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,17 +399,28 @@ namespace js {
|
|||
|
||||
struct STATIC_SKIP_INFERENCE CopyNonHoleArgsTo
|
||||
{
|
||||
CopyNonHoleArgsTo(JSObject *aobj, Value *dst) : aobj(aobj), dst(dst) {}
|
||||
JSObject *aobj;
|
||||
CopyNonHoleArgsTo(ArgumentsObject *argsobj, Value *dst) : argsobj(argsobj), dst(dst) {}
|
||||
ArgumentsObject *argsobj;
|
||||
Value *dst;
|
||||
bool operator()(uintN argi, Value *src) {
|
||||
if (aobj->getArgsElement(argi).isMagic(JS_ARGS_HOLE))
|
||||
if (argsobj->element(argi).isMagic(JS_ARGS_HOLE))
|
||||
return false;
|
||||
*dst++ = *src;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static bool
|
||||
GetElementsSlow(JSContext *cx, JSObject *aobj, uint32 length, Value *vp)
|
||||
{
|
||||
for (uint32 i = 0; i < length; i++) {
|
||||
if (!aobj->getProperty(cx, INT_TO_JSID(jsint(i)), &vp[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetElements(JSContext *cx, JSObject *aobj, jsuint length, Value *vp)
|
||||
{
|
||||
|
@ -411,38 +431,38 @@ GetElements(JSContext *cx, JSObject *aobj, jsuint length, Value *vp)
|
|||
Value *srcend = srcbeg + length;
|
||||
for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src)
|
||||
*dst = src->isMagic(JS_ARRAY_HOLE) ? UndefinedValue() : *src;
|
||||
} else if (aobj->isArguments() && !aobj->isArgsLengthOverridden() &&
|
||||
!js_PrototypeHasIndexedProperties(cx, aobj)) {
|
||||
/*
|
||||
* If the argsobj is for an active call, then the elements are the
|
||||
* live args on the stack. Otherwise, the elements are the args that
|
||||
* were copied into the argsobj by PutActivationObjects when the
|
||||
* function returned. In both cases, it is necessary to fall off the
|
||||
* fast path for deleted properties (MagicValue(JS_ARGS_HOLE) since
|
||||
* this requires general-purpose property lookup.
|
||||
*/
|
||||
if (StackFrame *fp = (StackFrame *) aobj->getPrivate()) {
|
||||
JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX);
|
||||
if (!fp->forEachCanonicalActualArg(CopyNonHoleArgsTo(aobj, vp)))
|
||||
goto found_deleted_prop;
|
||||
} else {
|
||||
Value *srcbeg = aobj->getArgsElements();
|
||||
Value *srcend = srcbeg + length;
|
||||
for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src) {
|
||||
if (src->isMagic(JS_ARGS_HOLE))
|
||||
goto found_deleted_prop;
|
||||
*dst = *src;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aobj->isArguments()) {
|
||||
ArgumentsObject *argsobj = aobj->asArguments();
|
||||
if (!argsobj->hasOverriddenLength() && !js_PrototypeHasIndexedProperties(cx, argsobj)) {
|
||||
/*
|
||||
* If the argsobj is for an active call, then the elements are the
|
||||
* live args on the stack. Otherwise, the elements are the args that
|
||||
* were copied into the argsobj by PutActivationObjects when the
|
||||
* function returned. In both cases, it is necessary to fall off the
|
||||
* fast path for deleted properties (MagicValue(JS_ARGS_HOLE) since
|
||||
* this requires general-purpose property lookup.
|
||||
*/
|
||||
if (StackFrame *fp = reinterpret_cast<StackFrame *>(argsobj->getPrivate())) {
|
||||
JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX);
|
||||
if (fp->forEachCanonicalActualArg(CopyNonHoleArgsTo(argsobj, vp)))
|
||||
return true;
|
||||
} else {
|
||||
Value *srcbeg = argsobj->elements();
|
||||
Value *srcend = srcbeg + length;
|
||||
for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src) {
|
||||
if (src->isMagic(JS_ARGS_HOLE))
|
||||
return GetElementsSlow(cx, argsobj, length, vp);
|
||||
*dst = *src;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
found_deleted_prop:
|
||||
for (uintN i = 0; i < length; i++) {
|
||||
if (!aobj->getProperty(cx, INT_TO_JSID(jsint(i)), &vp[i]))
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return GetElementsSlow(cx, aobj, length, vp);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -780,8 +800,7 @@ array_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Val
|
|||
}
|
||||
|
||||
vp->setUndefined();
|
||||
if (js_LookupPropertyWithFlags(cx, proto, id, cx->resolveFlags,
|
||||
&obj2, &prop) < 0)
|
||||
if (!LookupPropertyWithFlags(cx, proto, id, cx->resolveFlags, &obj2, &prop))
|
||||
return JS_FALSE;
|
||||
|
||||
if (prop && obj2->isNative()) {
|
||||
|
@ -873,7 +892,9 @@ js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
|
|||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
namespace js {
|
||||
|
||||
JSBool
|
||||
array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
|
@ -908,6 +929,8 @@ array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
|||
return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
static JSBool
|
||||
array_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
|
@ -924,7 +947,9 @@ array_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
|||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
namespace js {
|
||||
|
||||
JSBool
|
||||
array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
{
|
||||
uint32 i;
|
||||
|
@ -947,6 +972,8 @@ array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
static void
|
||||
array_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
|
|
|
@ -199,6 +199,13 @@ js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
|
|||
|
||||
namespace js {
|
||||
|
||||
extern JSBool
|
||||
array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs);
|
||||
|
||||
extern JSBool
|
||||
array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict);
|
||||
|
||||
/*
|
||||
* This function assumes 'length' is effectively the result of calling
|
||||
* js_GetLengthProperty on aobj.
|
||||
|
|
|
@ -458,11 +458,14 @@ js_SweepAtomState(JSContext *cx)
|
|||
}
|
||||
|
||||
/*
|
||||
* This call takes ownership of 'chars' if ATOM_NOCOPY is set.
|
||||
* Callers passing ATOM_NOCOPY have freshly allocated *pchars and thus this
|
||||
* memory can be used as a new JSAtom's buffer without copying. When this flag
|
||||
* is set, the contract is that callers will free *pchars iff *pchars == NULL.
|
||||
*/
|
||||
static JSAtom *
|
||||
Atomize(JSContext *cx, const jschar *chars, size_t length, uintN flags)
|
||||
Atomize(JSContext *cx, const jschar **pchars, size_t length, uintN flags)
|
||||
{
|
||||
const jschar *chars = *pchars;
|
||||
JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_NOCOPY)));
|
||||
|
||||
if (JSAtom *s = JSAtom::lookupStatic(chars, length))
|
||||
|
@ -482,10 +485,9 @@ Atomize(JSContext *cx, const jschar *chars, size_t length, uintN flags)
|
|||
JSFixedString *key;
|
||||
if (flags & ATOM_NOCOPY) {
|
||||
key = js_NewString(cx, const_cast<jschar *>(chars), length);
|
||||
if (!key) {
|
||||
cx->free_(const_cast<jschar *>(chars));
|
||||
if (!key)
|
||||
return NULL;
|
||||
}
|
||||
*pchars = NULL; /* Caller should not free *pchars. */
|
||||
} else {
|
||||
key = js_NewStringCopyN(cx, chars, length);
|
||||
if (!key)
|
||||
|
@ -523,7 +525,7 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
|
|||
return NULL;
|
||||
|
||||
JS_ASSERT(length <= JSString::MAX_LENGTH);
|
||||
return Atomize(cx, chars, length, flags);
|
||||
return Atomize(cx, &chars, length, flags);
|
||||
}
|
||||
|
||||
JSAtom *
|
||||
|
@ -562,7 +564,10 @@ js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags, bool us
|
|||
flags |= ATOM_NOCOPY;
|
||||
}
|
||||
|
||||
return Atomize(cx, chars, inflatedLength, flags);
|
||||
JSAtom *atom = Atomize(cx, &chars, inflatedLength, flags);
|
||||
if ((flags & ATOM_NOCOPY) && chars)
|
||||
cx->free_((void *)chars);
|
||||
return atom;
|
||||
}
|
||||
|
||||
JSAtom *
|
||||
|
@ -574,7 +579,7 @@ js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
|
|||
if (!CheckStringLength(cx, length))
|
||||
return NULL;
|
||||
|
||||
return Atomize(cx, chars, length, flags);
|
||||
return Atomize(cx, &chars, length, flags);
|
||||
}
|
||||
|
||||
JSAtom *
|
||||
|
|
|
@ -252,7 +252,7 @@ HasProperty(JSContext* cx, JSObject* obj, jsid id)
|
|||
|
||||
JSObject* obj2;
|
||||
JSProperty* prop;
|
||||
if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0)
|
||||
if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
|
||||
return JS_NEITHER;
|
||||
return prop != NULL;
|
||||
}
|
||||
|
|
|
@ -420,7 +420,6 @@ struct JSRuntime {
|
|||
uint32 gcEmptyArenaPoolLifespan;
|
||||
uint32 gcNumber;
|
||||
js::GCMarker *gcMarkingTracer;
|
||||
uint32 gcTriggerFactor;
|
||||
int64 gcJitReleaseTime;
|
||||
JSGCMode gcMode;
|
||||
volatile bool gcIsNeeded;
|
||||
|
@ -711,7 +710,6 @@ struct JSRuntime {
|
|||
|
||||
bool init(uint32 maxbytes);
|
||||
|
||||
void setGCTriggerFactor(uint32 factor);
|
||||
void setGCLastBytes(size_t lastBytes);
|
||||
void reduceGCTriggerBytes(uint32 amount);
|
||||
|
||||
|
|
|
@ -1099,11 +1099,10 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
|
|||
JSWatchPoint *wp = FindWatchPoint(rt, obj, propid);
|
||||
if (!wp) {
|
||||
/* Make a new property in obj so we can watch for the first set. */
|
||||
if (!js_DefineNativeProperty(cx, obj, propid, UndefinedValue(), NULL, NULL,
|
||||
JSPROP_ENUMERATE, 0, 0, &prop)) {
|
||||
shape = DefineNativeProperty(cx, obj, propid, UndefinedValue(), NULL, NULL,
|
||||
JSPROP_ENUMERATE, 0, 0);
|
||||
if (!shape)
|
||||
return false;
|
||||
}
|
||||
shape = (Shape *) prop;
|
||||
}
|
||||
} else if (pobj != obj) {
|
||||
/* Clone the prototype property so we can watch the right object. */
|
||||
|
@ -1141,12 +1140,10 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
|
|||
}
|
||||
|
||||
/* Recall that obj is native, whether or not pobj is native. */
|
||||
if (!js_DefineNativeProperty(cx, obj, propid, valroot.value(),
|
||||
getter, setter, attrs, flags,
|
||||
shortid, &prop)) {
|
||||
shape = DefineNativeProperty(cx, obj, propid, valroot.value(), getter, setter,
|
||||
attrs, flags, shortid);
|
||||
if (!shape)
|
||||
return false;
|
||||
}
|
||||
shape = (Shape *) prop;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -4487,10 +4487,10 @@ JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp)
|
|||
JS_ASSERT(pnid->pn_type == TOK_NAME ||
|
||||
pnid->pn_type == TOK_STRING);
|
||||
jsid id = ATOM_TO_JSID(pnid->pn_atom);
|
||||
if (!((pnid->pn_atom == cx->runtime->atomState.protoAtom)
|
||||
? js_SetPropertyHelper(cx, obj, id, 0, &value, strictChecks)
|
||||
: js_DefineNativeProperty(cx, obj, id, value, NULL, NULL,
|
||||
JSPROP_ENUMERATE, 0, 0, NULL, 0))) {
|
||||
if ((pnid->pn_atom == cx->runtime->atomState.protoAtom)
|
||||
? !js_SetPropertyHelper(cx, obj, id, 0, &value, strictChecks)
|
||||
: !DefineNativeProperty(cx, obj, id, value, NULL, NULL,
|
||||
JSPROP_ENUMERATE, 0, 0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -6988,10 +6988,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
|
||||
if (obj) {
|
||||
JS_ASSERT(!obj->inDictionaryMode());
|
||||
if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(pn3->pn_atom),
|
||||
UndefinedValue(), NULL, NULL,
|
||||
JSPROP_ENUMERATE, 0, 0, NULL)) {
|
||||
return JS_FALSE;
|
||||
if (!DefineNativeProperty(cx, obj, ATOM_TO_JSID(pn3->pn_atom),
|
||||
UndefinedValue(), NULL, NULL,
|
||||
JSPROP_ENUMERATE, 0, 0)) {
|
||||
return false;
|
||||
}
|
||||
if (obj->inDictionaryMode())
|
||||
obj = NULL;
|
||||
|
|
|
@ -1043,18 +1043,14 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj)
|
|||
|
||||
/* Add properties to the prototype. */
|
||||
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
|
||||
if (!js_DefineNativeProperty(cx, proto, nameId, StringValue(atom),
|
||||
PropertyStub, StrictPropertyStub,
|
||||
0, 0, 0, NULL) ||
|
||||
!js_DefineNativeProperty(cx, proto, messageId, empty,
|
||||
PropertyStub, StrictPropertyStub,
|
||||
0, 0, 0, NULL) ||
|
||||
!js_DefineNativeProperty(cx, proto, fileNameId, empty,
|
||||
PropertyStub, StrictPropertyStub,
|
||||
JSPROP_ENUMERATE, 0, 0, NULL) ||
|
||||
!js_DefineNativeProperty(cx, proto, lineNumberId, Valueify(JSVAL_ZERO),
|
||||
PropertyStub, StrictPropertyStub,
|
||||
JSPROP_ENUMERATE, 0, 0, NULL)) {
|
||||
if (!DefineNativeProperty(cx, proto, nameId, StringValue(atom),
|
||||
PropertyStub, StrictPropertyStub, 0, 0, 0) ||
|
||||
!DefineNativeProperty(cx, proto, messageId, empty,
|
||||
PropertyStub, StrictPropertyStub, 0, 0, 0) ||
|
||||
!DefineNativeProperty(cx, proto, fileNameId, empty,
|
||||
PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE, 0, 0) ||
|
||||
!DefineNativeProperty(cx, proto, lineNumberId, Valueify(JSVAL_ZERO),
|
||||
PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE, 0, 0)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
243
js/src/jsfun.cpp
243
js/src/jsfun.cpp
|
@ -90,6 +90,7 @@
|
|||
#include "jsobjinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "vm/ArgumentsObject-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
@ -145,10 +146,10 @@ js_GetArgsProperty(JSContext *cx, StackFrame *fp, jsid id, Value *vp)
|
|||
vp->setUndefined();
|
||||
if (JSID_IS_INT(id)) {
|
||||
uint32 arg = uint32(JSID_TO_INT(id));
|
||||
JSObject *argsobj = fp->maybeArgsObj();
|
||||
ArgumentsObject *argsobj = fp->maybeArgsObj();
|
||||
if (arg < fp->numActualArgs()) {
|
||||
if (argsobj) {
|
||||
const Value &v = argsobj->getArgsElement(arg);
|
||||
const Value &v = argsobj->element(arg);
|
||||
if (v.isMagic(JS_ARGS_HOLE))
|
||||
return argsobj->getProperty(cx, id, vp);
|
||||
if (fp->functionScript()->strictModeCode) {
|
||||
|
@ -174,24 +175,27 @@ js_GetArgsProperty(JSContext *cx, StackFrame *fp, jsid id, Value *vp)
|
|||
return argsobj->getProperty(cx, id, vp);
|
||||
}
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||
JSObject *argsobj = fp->maybeArgsObj();
|
||||
if (argsobj && argsobj->isArgsLengthOverridden())
|
||||
ArgumentsObject *argsobj = fp->maybeArgsObj();
|
||||
if (argsobj && argsobj->hasOverriddenLength())
|
||||
return argsobj->getProperty(cx, id, vp);
|
||||
vp->setInt32(fp->numActualArgs());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
|
||||
js::ArgumentsObject *
|
||||
ArgumentsObject::create(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
|
||||
{
|
||||
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||
|
||||
JSObject *proto;
|
||||
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
||||
return NULL;
|
||||
|
||||
JS_STATIC_ASSERT(JSObject::ARGS_CLASS_RESERVED_SLOTS == 2);
|
||||
JSObject *argsobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
|
||||
if (!argsobj)
|
||||
JS_STATIC_ASSERT(NormalArgumentsObject::RESERVED_SLOTS == 2);
|
||||
JS_STATIC_ASSERT(StrictArgumentsObject::RESERVED_SLOTS == 2);
|
||||
JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx);
|
||||
|
@ -206,16 +210,18 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
|
|||
SetValueRangeToUndefined(data->slots, argc);
|
||||
|
||||
/* Can't fail from here on, so initialize everything in argsobj. */
|
||||
argsobj->init(cx, callee.getFunctionPrivate()->inStrictMode()
|
||||
? &StrictArgumentsClass
|
||||
: &js_ArgumentsClass,
|
||||
proto, parent, NULL, false);
|
||||
obj->init(cx, callee.getFunctionPrivate()->inStrictMode()
|
||||
? &StrictArgumentsObject::jsClass
|
||||
: &NormalArgumentsObject::jsClass,
|
||||
proto, parent, NULL, false);
|
||||
obj->setMap(emptyArgumentsShape);
|
||||
|
||||
argsobj->setMap(emptyArgumentsShape);
|
||||
ArgumentsObject *argsobj = obj->asArguments();
|
||||
|
||||
argsobj->setArgsLength(argc);
|
||||
argsobj->setArgsData(data);
|
||||
data->callee.setObject(callee);
|
||||
JS_ASSERT(UINT32_MAX > (uint64(argc) << PACKED_BITS_COUNT));
|
||||
argsobj->setInitialLength(argc);
|
||||
|
||||
argsobj->setCalleeAndData(callee, data);
|
||||
|
||||
return argsobj;
|
||||
}
|
||||
|
@ -250,7 +256,8 @@ js_GetArgsObject(JSContext *cx, StackFrame *fp)
|
|||
|
||||
/* Compute the arguments object's parent slot from fp's scope chain. */
|
||||
JSObject *global = fp->scopeChain().getGlobal();
|
||||
JSObject *argsobj = NewArguments(cx, global, fp->numActualArgs(), fp->callee());
|
||||
ArgumentsObject *argsobj =
|
||||
ArgumentsObject::create(cx, global, fp->numActualArgs(), fp->callee());
|
||||
if (!argsobj)
|
||||
return argsobj;
|
||||
|
||||
|
@ -264,7 +271,7 @@ js_GetArgsObject(JSContext *cx, StackFrame *fp)
|
|||
* retrieve up-to-date parameter values.
|
||||
*/
|
||||
if (argsobj->isStrictArguments())
|
||||
fp->forEachCanonicalActualArg(PutArg(argsobj->getArgsData()->slots));
|
||||
fp->forEachCanonicalActualArg(PutArg(argsobj->data()->slots));
|
||||
else
|
||||
argsobj->setPrivate(fp);
|
||||
|
||||
|
@ -275,10 +282,10 @@ js_GetArgsObject(JSContext *cx, StackFrame *fp)
|
|||
void
|
||||
js_PutArgsObject(StackFrame *fp)
|
||||
{
|
||||
JSObject &argsobj = fp->argsObj();
|
||||
ArgumentsObject &argsobj = fp->argsObj();
|
||||
if (argsobj.isNormalArguments()) {
|
||||
JS_ASSERT(argsobj.getPrivate() == fp);
|
||||
fp->forEachCanonicalActualArg(PutArg(argsobj.getArgsData()->slots));
|
||||
fp->forEachCanonicalActualArg(PutArg(argsobj.data()->slots));
|
||||
argsobj.setPrivate(NULL);
|
||||
} else {
|
||||
JS_ASSERT(!argsobj.getPrivate());
|
||||
|
@ -293,7 +300,7 @@ js_PutArgsObject(StackFrame *fp)
|
|||
JSObject * JS_FASTCALL
|
||||
js_NewArgumentsOnTrace(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
|
||||
{
|
||||
JSObject *argsobj = NewArguments(cx, parent, argc, *callee);
|
||||
ArgumentsObject *argsobj = ArgumentsObject::create(cx, parent, argc, *callee);
|
||||
if (!argsobj)
|
||||
return NULL;
|
||||
|
||||
|
@ -314,9 +321,10 @@ JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewArgumentsOnTrace, CONTEXT, OBJECT, UI
|
|||
|
||||
/* FIXME change the return type to void. */
|
||||
JSBool JS_FASTCALL
|
||||
js_PutArgumentsOnTrace(JSContext *cx, JSObject *argsobj, Value *args)
|
||||
js_PutArgumentsOnTrace(JSContext *cx, JSObject *obj, Value *argv)
|
||||
{
|
||||
JS_ASSERT(argsobj->isNormalArguments());
|
||||
NormalArgumentsObject *argsobj = obj->asNormalArguments();
|
||||
|
||||
JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE);
|
||||
|
||||
/*
|
||||
|
@ -324,9 +332,9 @@ js_PutArgumentsOnTrace(JSContext *cx, JSObject *argsobj, Value *args)
|
|||
* the arguments, regardless of whether #actuals > #formals so there is no
|
||||
* need to worry about actual vs. formal arguments.
|
||||
*/
|
||||
Value *srcend = args + argsobj->getArgsInitialLength();
|
||||
Value *dst = argsobj->getArgsData()->slots;
|
||||
for (Value *src = args; src != srcend; ++src, ++dst) {
|
||||
Value *srcend = argv + argsobj->initialLength();
|
||||
Value *dst = argsobj->data()->slots;
|
||||
for (Value *src = argv; src < srcend; ++src, ++dst) {
|
||||
if (!dst->isMagic(JS_ARGS_HOLE))
|
||||
*dst = *src;
|
||||
}
|
||||
|
@ -342,16 +350,15 @@ JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArgumentsOnTrace, CONTEXT, OBJECT, VALU
|
|||
static JSBool
|
||||
args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
JS_ASSERT(obj->isArguments());
|
||||
|
||||
ArgumentsObject *argsobj = obj->asArguments();
|
||||
if (JSID_IS_INT(id)) {
|
||||
uintN arg = uintN(JSID_TO_INT(id));
|
||||
if (arg < obj->getArgsInitialLength())
|
||||
obj->setArgsElement(arg, MagicValue(JS_ARGS_HOLE));
|
||||
if (arg < argsobj->initialLength())
|
||||
argsobj->setElement(arg, MagicValue(JS_ARGS_HOLE));
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||
obj->setArgsLengthOverridden();
|
||||
argsobj->markLengthOverridden();
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
|
||||
obj->setArgsCallee(MagicValue(JS_ARGS_HOLE));
|
||||
argsobj->asNormalArguments()->clearCallee();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -518,25 +525,26 @@ ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
if (!obj->isNormalArguments())
|
||||
return true;
|
||||
|
||||
NormalArgumentsObject *argsobj = obj->asNormalArguments();
|
||||
if (JSID_IS_INT(id)) {
|
||||
/*
|
||||
* arg can exceed the number of arguments if a script changed the
|
||||
* prototype to point to another Arguments object with a bigger argc.
|
||||
*/
|
||||
uintN arg = uintN(JSID_TO_INT(id));
|
||||
if (arg < obj->getArgsInitialLength()) {
|
||||
JS_ASSERT(!obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE));
|
||||
if (StackFrame *fp = (StackFrame *) obj->getPrivate())
|
||||
if (arg < argsobj->initialLength()) {
|
||||
JS_ASSERT(!argsobj->element(arg).isMagic(JS_ARGS_HOLE));
|
||||
if (StackFrame *fp = reinterpret_cast<StackFrame *>(argsobj->getPrivate()))
|
||||
*vp = fp->canonicalActualArg(arg);
|
||||
else
|
||||
*vp = obj->getArgsElement(arg);
|
||||
*vp = argsobj->element(arg);
|
||||
}
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||
if (!obj->isArgsLengthOverridden())
|
||||
vp->setInt32(obj->getArgsInitialLength());
|
||||
if (!argsobj->hasOverriddenLength())
|
||||
vp->setInt32(argsobj->initialLength());
|
||||
} else {
|
||||
JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
|
||||
const Value &v = obj->getArgsCallee();
|
||||
const Value &v = argsobj->callee();
|
||||
if (!v.isMagic(JS_ARGS_HOLE)) {
|
||||
/*
|
||||
* If this function or one in it needs upvars that reach above it
|
||||
|
@ -572,11 +580,12 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
|||
if (!obj->isNormalArguments())
|
||||
return true;
|
||||
|
||||
NormalArgumentsObject *argsobj = obj->asNormalArguments();
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
uintN arg = uintN(JSID_TO_INT(id));
|
||||
if (arg < obj->getArgsInitialLength()) {
|
||||
StackFrame *fp = (StackFrame *) obj->getPrivate();
|
||||
if (fp) {
|
||||
if (arg < argsobj->initialLength()) {
|
||||
if (StackFrame *fp = reinterpret_cast<StackFrame *>(argsobj->getPrivate())) {
|
||||
JSScript *script = fp->functionScript();
|
||||
if (script->usesArguments)
|
||||
fp->canonicalActualArg(arg) = *vp;
|
||||
|
@ -597,54 +606,54 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
|||
* that has a setter for this id.
|
||||
*/
|
||||
AutoValueRooter tvr(cx);
|
||||
return js_DeleteProperty(cx, obj, id, tvr.addr(), false) &&
|
||||
js_DefineProperty(cx, obj, id, vp, NULL, NULL, JSPROP_ENUMERATE);
|
||||
return js_DeleteProperty(cx, argsobj, id, tvr.addr(), false) &&
|
||||
js_DefineProperty(cx, argsobj, id, vp, NULL, NULL, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
JSObject **objp)
|
||||
{
|
||||
JS_ASSERT(obj->isNormalArguments());
|
||||
|
||||
*objp = NULL;
|
||||
|
||||
NormalArgumentsObject *argsobj = obj->asNormalArguments();
|
||||
|
||||
uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
|
||||
if (JSID_IS_INT(id)) {
|
||||
uint32 arg = uint32(JSID_TO_INT(id));
|
||||
if (arg >= obj->getArgsInitialLength() || obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
|
||||
if (arg >= argsobj->initialLength() || argsobj->element(arg).isMagic(JS_ARGS_HOLE))
|
||||
return true;
|
||||
|
||||
attrs |= JSPROP_ENUMERATE;
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||
if (obj->isArgsLengthOverridden())
|
||||
if (argsobj->hasOverriddenLength())
|
||||
return true;
|
||||
} else {
|
||||
if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
|
||||
return true;
|
||||
|
||||
if (obj->getArgsCallee().isMagic(JS_ARGS_HOLE))
|
||||
if (argsobj->callee().isMagic(JS_ARGS_HOLE))
|
||||
return true;
|
||||
}
|
||||
|
||||
Value undef = UndefinedValue();
|
||||
if (!js_DefineProperty(cx, obj, id, &undef, ArgGetter, ArgSetter, attrs))
|
||||
if (!js_DefineProperty(cx, argsobj, id, &undef, ArgGetter, ArgSetter, attrs))
|
||||
return JS_FALSE;
|
||||
|
||||
*objp = obj;
|
||||
*objp = argsobj;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
args_enumerate(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isNormalArguments());
|
||||
NormalArgumentsObject *argsobj = obj->asNormalArguments();
|
||||
|
||||
/*
|
||||
* Trigger reflection in args_resolve using a series of js_LookupProperty
|
||||
* calls.
|
||||
*/
|
||||
int argc = int(obj->getArgsInitialLength());
|
||||
int argc = int(argsobj->initialLength());
|
||||
for (int i = -2; i != argc; i++) {
|
||||
jsid id = (i == -2)
|
||||
? ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)
|
||||
|
@ -654,7 +663,7 @@ args_enumerate(JSContext *cx, JSObject *obj)
|
|||
|
||||
JSObject *pobj;
|
||||
JSProperty *prop;
|
||||
if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
|
||||
if (!js_LookupProperty(cx, argsobj, id, &pobj, &prop))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -668,21 +677,23 @@ StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
if (!obj->isStrictArguments())
|
||||
return true;
|
||||
|
||||
StrictArgumentsObject *argsobj = obj->asStrictArguments();
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
/*
|
||||
* arg can exceed the number of arguments if a script changed the
|
||||
* prototype to point to another Arguments object with a bigger argc.
|
||||
*/
|
||||
uintN arg = uintN(JSID_TO_INT(id));
|
||||
if (arg < obj->getArgsInitialLength()) {
|
||||
const Value &v = obj->getArgsElement(arg);
|
||||
if (arg < argsobj->initialLength()) {
|
||||
const Value &v = argsobj->element(arg);
|
||||
if (!v.isMagic(JS_ARGS_HOLE))
|
||||
*vp = v;
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
|
||||
if (!obj->isArgsLengthOverridden())
|
||||
vp->setInt32(obj->getArgsInitialLength());
|
||||
if (!argsobj->hasOverriddenLength())
|
||||
vp->setInt32(argsobj->initialLength());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -694,10 +705,12 @@ StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
|||
if (!obj->isStrictArguments())
|
||||
return true;
|
||||
|
||||
StrictArgumentsObject *argsobj = obj->asStrictArguments();
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
uintN arg = uintN(JSID_TO_INT(id));
|
||||
if (arg < obj->getArgsInitialLength()) {
|
||||
obj->setArgsElement(arg, *vp);
|
||||
if (arg < argsobj->initialLength()) {
|
||||
argsobj->setElement(arg, *vp);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
@ -711,29 +724,29 @@ StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
|||
* collect its value.
|
||||
*/
|
||||
AutoValueRooter tvr(cx);
|
||||
return js_DeleteProperty(cx, obj, id, tvr.addr(), strict) &&
|
||||
js_SetProperty(cx, obj, id, vp, strict);
|
||||
return js_DeleteProperty(cx, argsobj, id, tvr.addr(), strict) &&
|
||||
js_SetProperty(cx, argsobj, id, vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
|
||||
{
|
||||
JS_ASSERT(obj->isStrictArguments());
|
||||
|
||||
*objp = NULL;
|
||||
|
||||
StrictArgumentsObject *argsobj = obj->asStrictArguments();
|
||||
|
||||
uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
|
||||
PropertyOp getter = StrictArgGetter;
|
||||
StrictPropertyOp setter = StrictArgSetter;
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
uint32 arg = uint32(JSID_TO_INT(id));
|
||||
if (arg >= obj->getArgsInitialLength() || obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
|
||||
if (arg >= argsobj->initialLength() || argsobj->element(arg).isMagic(JS_ARGS_HOLE))
|
||||
return true;
|
||||
|
||||
attrs |= JSPROP_ENUMERATE;
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||
if (obj->isArgsLengthOverridden())
|
||||
if (argsobj->hasOverriddenLength())
|
||||
return true;
|
||||
} else {
|
||||
if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom) &&
|
||||
|
@ -742,22 +755,22 @@ strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject
|
|||
}
|
||||
|
||||
attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
|
||||
getter = CastAsPropertyOp(obj->getThrowTypeError());
|
||||
setter = CastAsStrictPropertyOp(obj->getThrowTypeError());
|
||||
getter = CastAsPropertyOp(argsobj->getThrowTypeError());
|
||||
setter = CastAsStrictPropertyOp(argsobj->getThrowTypeError());
|
||||
}
|
||||
|
||||
Value undef = UndefinedValue();
|
||||
if (!js_DefineProperty(cx, obj, id, &undef, getter, setter, attrs))
|
||||
if (!js_DefineProperty(cx, argsobj, id, &undef, getter, setter, attrs))
|
||||
return false;
|
||||
|
||||
*objp = obj;
|
||||
*objp = argsobj;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
strictargs_enumerate(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isStrictArguments());
|
||||
StrictArgumentsObject *argsobj = obj->asStrictArguments();
|
||||
|
||||
/*
|
||||
* Trigger reflection in strictargs_resolve using a series of
|
||||
|
@ -767,19 +780,19 @@ strictargs_enumerate(JSContext *cx, JSObject *obj)
|
|||
JSProperty *prop;
|
||||
|
||||
// length
|
||||
if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &pobj, &prop))
|
||||
if (!js_LookupProperty(cx, argsobj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &pobj, &prop))
|
||||
return false;
|
||||
|
||||
// callee
|
||||
if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), &pobj, &prop))
|
||||
if (!js_LookupProperty(cx, argsobj, ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), &pobj, &prop))
|
||||
return false;
|
||||
|
||||
// caller
|
||||
if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.callerAtom), &pobj, &prop))
|
||||
if (!js_LookupProperty(cx, argsobj, ATOM_TO_JSID(cx->runtime->atomState.callerAtom), &pobj, &prop))
|
||||
return false;
|
||||
|
||||
for (uint32 i = 0, argc = obj->getArgsInitialLength(); i < argc; i++) {
|
||||
if (!js_LookupProperty(cx, obj, INT_TO_JSID(i), &pobj, &prop))
|
||||
for (uint32 i = 0, argc = argsobj->initialLength(); i < argc; i++) {
|
||||
if (!js_LookupProperty(cx, argsobj, INT_TO_JSID(i), &pobj, &prop))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -789,7 +802,7 @@ strictargs_enumerate(JSContext *cx, JSObject *obj)
|
|||
static void
|
||||
args_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
cx->free_((void *) obj->getArgsData());
|
||||
cx->free_(reinterpret_cast<void *>(obj->asArguments()->data()));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -815,43 +828,39 @@ MaybeMarkGenerator(JSTracer *trc, JSObject *obj)
|
|||
static void
|
||||
args_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isArguments());
|
||||
if (obj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE) {
|
||||
JS_ASSERT(!obj->isStrictArguments());
|
||||
ArgumentsObject *argsobj = obj->asArguments();
|
||||
if (argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE) {
|
||||
JS_ASSERT(!argsobj->isStrictArguments());
|
||||
return;
|
||||
}
|
||||
|
||||
ArgumentsData *data = obj->getArgsData();
|
||||
ArgumentsData *data = argsobj->data();
|
||||
if (data->callee.isObject())
|
||||
MarkObject(trc, data->callee.toObject(), js_callee_str);
|
||||
MarkValueRange(trc, obj->getArgsInitialLength(), data->slots, js_arguments_str);
|
||||
MarkValueRange(trc, argsobj->initialLength(), data->slots, js_arguments_str);
|
||||
|
||||
MaybeMarkGenerator(trc, obj);
|
||||
MaybeMarkGenerator(trc, argsobj);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* The Arguments classes aren't initialized via js_InitClass, because arguments
|
||||
* objects have the initial value of Object.prototype as their [[Prototype]].
|
||||
* However, Object.prototype.toString.call(arguments) === "[object Arguments]"
|
||||
* per ES5 (although not ES3), so the class name is "Arguments" rather than
|
||||
* "Object".
|
||||
*
|
||||
* The JSClass functions below collaborate to lazily reflect and synchronize
|
||||
* actual argument values, argument count, and callee function object stored
|
||||
* in a StackFrame with their corresponding property values in the frame's
|
||||
* The classes below collaborate to lazily reflect and synchronize actual
|
||||
* argument values, argument count, and callee function object stored in a
|
||||
* StackFrame with their corresponding property values in the frame's
|
||||
* arguments object.
|
||||
*/
|
||||
Class js_ArgumentsClass = {
|
||||
Class NormalArgumentsObject::jsClass = {
|
||||
"Arguments",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_CLASS_RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
|
||||
PropertyStub, /* addProperty */
|
||||
args_delProperty,
|
||||
PropertyStub, /* getProperty */
|
||||
StrictPropertyStub, /* setProperty */
|
||||
args_enumerate,
|
||||
(JSResolveOp) args_resolve,
|
||||
reinterpret_cast<JSResolveOp>(args_resolve),
|
||||
ConvertStub,
|
||||
args_finalize, /* finalize */
|
||||
NULL, /* reserved0 */
|
||||
|
@ -863,17 +872,15 @@ Class js_ArgumentsClass = {
|
|||
args_trace
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Strict mode arguments is significantly less magical than non-strict mode
|
||||
* arguments, so it is represented by a different class while sharing some
|
||||
* functionality.
|
||||
*/
|
||||
Class StrictArgumentsClass = {
|
||||
Class StrictArgumentsObject::jsClass = {
|
||||
"Arguments",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_CLASS_RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
|
||||
PropertyStub, /* addProperty */
|
||||
args_delProperty,
|
||||
|
@ -1029,11 +1036,9 @@ CreateFunCallObject(JSContext *cx, StackFrame *fp)
|
|||
if (!scopeChain)
|
||||
return NULL;
|
||||
|
||||
if (!js_DefineNativeProperty(cx, scopeChain, ATOM_TO_JSID(lambdaName),
|
||||
ObjectValue(fp->callee()),
|
||||
CalleeGetter, NULL,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
0, 0, NULL)) {
|
||||
if (!DefineNativeProperty(cx, scopeChain, ATOM_TO_JSID(lambdaName),
|
||||
ObjectValue(fp->callee()), CalleeGetter, NULL,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1361,10 +1366,10 @@ call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
* rebinding-Call-property logic.
|
||||
*/
|
||||
if (callee && id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) {
|
||||
if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(),
|
||||
GetCallArguments, SetCallArguments,
|
||||
JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE,
|
||||
0, 0, NULL, JSDNP_DONT_PURGE)) {
|
||||
if (!DefineNativeProperty(cx, obj, id, UndefinedValue(),
|
||||
GetCallArguments, SetCallArguments,
|
||||
JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE,
|
||||
0, 0, DNP_DONT_PURGE)) {
|
||||
return false;
|
||||
}
|
||||
*objp = obj;
|
||||
|
@ -1783,9 +1788,9 @@ fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
|
||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||
JS_ASSERT(!IsInternalFunctionObject(obj));
|
||||
if (!js_DefineNativeProperty(cx, obj, id, Int32Value(fun->nargs),
|
||||
PropertyStub, StrictPropertyStub,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY, 0, 0, NULL)) {
|
||||
if (!DefineNativeProperty(cx, obj, id, Int32Value(fun->nargs),
|
||||
PropertyStub, StrictPropertyStub,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) {
|
||||
return false;
|
||||
}
|
||||
*objp = obj;
|
||||
|
@ -1797,11 +1802,9 @@ fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
|
||||
if (JSID_IS_ATOM(id, OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset))) {
|
||||
JS_ASSERT(!IsInternalFunctionObject(obj));
|
||||
|
||||
if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(),
|
||||
fun_getProperty, StrictPropertyStub,
|
||||
lfp->attrs, Shape::HAS_SHORTID,
|
||||
lfp->tinyid, NULL)) {
|
||||
if (!DefineNativeProperty(cx, obj, id, UndefinedValue(),
|
||||
fun_getProperty, StrictPropertyStub,
|
||||
lfp->attrs, Shape::HAS_SHORTID, lfp->tinyid)) {
|
||||
return false;
|
||||
}
|
||||
*objp = obj;
|
||||
|
@ -1829,10 +1832,8 @@ fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
setter = StrictPropertyStub;
|
||||
}
|
||||
|
||||
if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(),
|
||||
getter, setter,
|
||||
attrs, Shape::HAS_SHORTID,
|
||||
p.tinyid, NULL)) {
|
||||
if (!DefineNativeProperty(cx, obj, id, UndefinedValue(), getter, setter,
|
||||
attrs, Shape::HAS_SHORTID, p.tinyid)) {
|
||||
return false;
|
||||
}
|
||||
*objp = obj;
|
||||
|
|
|
@ -247,53 +247,6 @@ struct JSFunction : public JSObject_Slots2
|
|||
JS_FN(name, fastcall, nargs, flags)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* NB: the Arguments classes are uninitialized internal classes that masquerade
|
||||
* (according to Object.prototype.toString.call(arguments)) as "Arguments",
|
||||
* while having Object.getPrototypeOf(arguments) === Object.prototype.
|
||||
*
|
||||
* WARNING (to alert embedders reading this private .h file): arguments objects
|
||||
* are *not* thread-safe and should not be used concurrently -- they should be
|
||||
* used by only one thread at a time, preferably by only one thread over their
|
||||
* lifetime (a JS worker that migrates from one OS thread to another but shares
|
||||
* nothing is ok).
|
||||
*
|
||||
* Yes, this is an incompatible change, which prefigures the impending move to
|
||||
* single-threaded objects and GC heaps.
|
||||
*/
|
||||
extern js::Class js_ArgumentsClass;
|
||||
|
||||
namespace js {
|
||||
|
||||
extern Class StrictArgumentsClass;
|
||||
|
||||
struct ArgumentsData {
|
||||
js::Value callee;
|
||||
js::Value slots[1];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isNormalArguments() const
|
||||
{
|
||||
return getClass() == &js_ArgumentsClass;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isStrictArguments() const
|
||||
{
|
||||
return getClass() == &js::StrictArgumentsClass;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isArguments() const
|
||||
{
|
||||
return isNormalArguments() || isStrictArguments();
|
||||
}
|
||||
|
||||
#define JS_ARGUMENTS_OBJECT_ON_TRACE ((void *)0xa126)
|
||||
|
||||
extern JS_PUBLIC_DATA(js::Class) js_CallClass;
|
||||
extern JS_PUBLIC_DATA(js::Class) js_FunctionClass;
|
||||
extern JS_FRIEND_DATA(js::Class) js_DeclEnvClass;
|
||||
|
|
|
@ -595,11 +595,8 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
|
|||
*/
|
||||
rt->gcMaxBytes = maxbytes;
|
||||
rt->setGCMaxMallocBytes(maxbytes);
|
||||
|
||||
rt->gcEmptyArenaPoolLifespan = 30000;
|
||||
|
||||
rt->gcTriggerFactor = uint32(100.0f * GC_HEAP_GROWTH_FACTOR);
|
||||
|
||||
/*
|
||||
* The assigned value prevents GC from running when GC memory is too low
|
||||
* (during JS engine start).
|
||||
|
@ -1065,29 +1062,12 @@ js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
|
|||
return ct;
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::setGCTriggerFactor(uint32 factor)
|
||||
{
|
||||
JS_ASSERT(factor >= 100);
|
||||
|
||||
gcTriggerFactor = factor;
|
||||
setGCLastBytes(gcLastBytes);
|
||||
|
||||
for (JSCompartment **c = compartments.begin(); c != compartments.end(); ++c)
|
||||
(*c)->setGCLastBytes(gcLastBytes);
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::setGCLastBytes(size_t lastBytes)
|
||||
{
|
||||
gcLastBytes = lastBytes;
|
||||
|
||||
/* FIXME bug 603916 - we should unify the triggers here. */
|
||||
float trigger1 = float(lastBytes) * float(gcTriggerFactor) / 100.0f;
|
||||
float trigger2 = float(Max(lastBytes, GC_ARENA_ALLOCATION_TRIGGER)) *
|
||||
GC_HEAP_GROWTH_FACTOR;
|
||||
float maxtrigger = Max(trigger1, trigger2);
|
||||
gcTriggerBytes = (float(gcMaxBytes) < maxtrigger) ? gcMaxBytes : size_t(maxtrigger);
|
||||
float trigger = float(Max(lastBytes, GC_ARENA_ALLOCATION_TRIGGER)) * GC_HEAP_GROWTH_FACTOR;
|
||||
gcTriggerBytes = size_t(Min(float(gcMaxBytes), trigger));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1103,13 +1083,8 @@ void
|
|||
JSCompartment::setGCLastBytes(size_t lastBytes)
|
||||
{
|
||||
gcLastBytes = lastBytes;
|
||||
|
||||
/* FIXME bug 603916 - we should unify the triggers here. */
|
||||
float trigger1 = float(lastBytes) * float(rt->gcTriggerFactor) / 100.0f;
|
||||
float trigger2 = float(Max(lastBytes, GC_ARENA_ALLOCATION_TRIGGER)) *
|
||||
GC_HEAP_GROWTH_FACTOR;
|
||||
float maxtrigger = Max(trigger1, trigger2);
|
||||
gcTriggerBytes = (float(rt->gcMaxBytes) < maxtrigger) ? rt->gcMaxBytes : size_t(maxtrigger);
|
||||
float trigger = float(Max(lastBytes, GC_ARENA_ALLOCATION_TRIGGER)) * GC_HEAP_GROWTH_FACTOR;
|
||||
gcTriggerBytes = size_t(Min(float(rt->gcMaxBytes), trigger));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1131,8 +1106,13 @@ FreeLists::purge()
|
|||
* Return the free list back to the arena so the GC finalization will not
|
||||
* run the finalizers over unitialized bytes from free things.
|
||||
*/
|
||||
for (FreeCell ***p = finalizables; p != JS_ARRAY_END(finalizables); ++p)
|
||||
*p = NULL;
|
||||
for (FreeCell **p = finalizables; p != JS_ARRAY_END(finalizables); ++p) {
|
||||
if (FreeCell *thing = *p) {
|
||||
JS_ASSERT(!thing->arenaHeader()->freeList);
|
||||
thing->arenaHeader()->freeList = thing;
|
||||
*p = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline ArenaHeader *
|
||||
|
@ -1330,9 +1310,6 @@ ArenaList::backgroundFinalize(JSContext *cx, ArenaHeader *listHead)
|
|||
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
CheckAllocation(JSContext *cx)
|
||||
|
@ -1383,16 +1360,11 @@ RunLastDitchGC(JSContext *cx)
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool
|
||||
inline Cell *
|
||||
RefillTypedFreeList(JSContext *cx, unsigned thingKind)
|
||||
{
|
||||
JSCompartment *compartment = cx->compartment;
|
||||
JS_ASSERT_IF(compartment->freeLists.finalizables[thingKind],
|
||||
!*compartment->freeLists.finalizables[thingKind]);
|
||||
|
||||
JS_ASSERT(!cx->runtime->gcRunning);
|
||||
if (cx->runtime->gcRunning)
|
||||
return false;
|
||||
JS_ASSERT(!compartment->freeLists.finalizables[thingKind]);
|
||||
|
||||
bool canGC = !JS_ON_TRACE(cx) && !JS_THREAD_DATA(cx)->waiveGCQuota;
|
||||
bool runGC = canGC && JS_UNLIKELY(NeedLastDitchGC(cx));
|
||||
|
@ -1406,15 +1378,13 @@ RefillTypedFreeList(JSContext *cx, unsigned thingKind)
|
|||
* things and populate the free list. If that happens, just
|
||||
* return that list head.
|
||||
*/
|
||||
if (compartment->freeLists.finalizables[thingKind])
|
||||
return true;
|
||||
if (Cell *thing = compartment->freeLists.getNext(thingKind))
|
||||
return thing;
|
||||
}
|
||||
ArenaHeader *aheader = compartment->arenas[thingKind].getArenaWithFreeList<T>(cx, thingKind);
|
||||
if (aheader) {
|
||||
JS_ASSERT(aheader->freeList);
|
||||
JS_ASSERT(sizeof(T) == aheader->getThingSize());
|
||||
compartment->freeLists.populate(aheader, thingKind);
|
||||
return true;
|
||||
return compartment->freeLists.populate(aheader, thingKind);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1428,10 +1398,10 @@ RefillTypedFreeList(JSContext *cx, unsigned thingKind)
|
|||
|
||||
METER(cx->runtime->gcStats.fail++);
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
Cell *
|
||||
RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
|
||||
{
|
||||
switch (thingKind) {
|
||||
|
@ -1469,10 +1439,13 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
|
|||
#endif
|
||||
default:
|
||||
JS_NOT_REACHED("bad finalize kind");
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
||||
uint32
|
||||
js_GetGCThingTraceKind(void *thing)
|
||||
{
|
||||
|
@ -2168,6 +2141,7 @@ GCHelperThread::doSweep()
|
|||
for (ArenaHeader **i = finalizeVector.begin(); i != finalizeVector.end(); ++i)
|
||||
ArenaList::backgroundFinalize(cx, *i);
|
||||
finalizeVector.resize(0);
|
||||
ExpireGCChunks(cx->runtime);
|
||||
cx = NULL;
|
||||
|
||||
if (freeCursor) {
|
||||
|
@ -2441,11 +2415,14 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
|
|||
js_SweepScriptFilenames(rt);
|
||||
}
|
||||
|
||||
#ifndef JS_THREADSAFE
|
||||
/*
|
||||
* Destroy arenas after we finished the sweeping so finalizers can safely
|
||||
* use IsAboutToBeFinalized().
|
||||
* This is done on the GCHelperThread if JS_THREADSAFE is defined.
|
||||
*/
|
||||
ExpireGCChunks(rt);
|
||||
#endif
|
||||
TIMESTAMP(sweepDestroyEnd);
|
||||
|
||||
if (rt->gcCallback)
|
||||
|
|
|
@ -72,7 +72,7 @@ js_TraceXML(JSTracer *trc, JSXML* thing);
|
|||
|
||||
namespace js {
|
||||
|
||||
struct GCHelperThread;
|
||||
class GCHelperThread;
|
||||
struct Shape;
|
||||
|
||||
namespace gc {
|
||||
|
@ -692,26 +692,49 @@ class ArenaList {
|
|||
}
|
||||
};
|
||||
|
||||
inline void
|
||||
CheckGCFreeListLink(FreeCell *cell)
|
||||
{
|
||||
/*
|
||||
* The GC things on the free lists come from one arena and the things on
|
||||
* the free list are linked in ascending address order.
|
||||
*/
|
||||
JS_ASSERT_IF(cell->link, cell->arenaHeader() == cell->link->arenaHeader());
|
||||
JS_ASSERT_IF(cell->link, cell < cell->link);
|
||||
}
|
||||
|
||||
/*
|
||||
* For a given arena, finalizables[thingKind] points to the next object to be
|
||||
* allocated. It gets initialized, in RefillTypedFreeList, to the first free
|
||||
* cell in an arena. For each allocation, it is advanced to the next free cell
|
||||
* in the same arena. While finalizables[thingKind] points to a cell in an
|
||||
* arena, that arena's freeList pointer is NULL. Before doing a GC, we copy
|
||||
* finalizables[thingKind] back to the arena header's freeList pointer and set
|
||||
* finalizables[thingKind] to NULL. Thus, we only have to maintain one free
|
||||
* list pointer at any time and avoid accessing and updating the arena header
|
||||
* on each allocation.
|
||||
*/
|
||||
struct FreeLists {
|
||||
FreeCell **finalizables[FINALIZE_LIMIT];
|
||||
FreeCell *finalizables[FINALIZE_LIMIT];
|
||||
|
||||
void purge();
|
||||
|
||||
inline FreeCell *getNext(uint32 kind) {
|
||||
FreeCell *top = NULL;
|
||||
if (finalizables[kind]) {
|
||||
top = *finalizables[kind];
|
||||
if (top) {
|
||||
*finalizables[kind] = top->link;
|
||||
} else {
|
||||
finalizables[kind] = NULL;
|
||||
}
|
||||
FreeCell *getNext(unsigned kind) {
|
||||
FreeCell *top = finalizables[kind];
|
||||
if (top) {
|
||||
CheckGCFreeListLink(top);
|
||||
finalizables[kind] = top->link;
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
void populate(ArenaHeader *aheader, uint32 thingKind) {
|
||||
finalizables[thingKind] = &aheader->freeList;
|
||||
Cell *populate(ArenaHeader *aheader, uint32 thingKind) {
|
||||
FreeCell *cell = aheader->freeList;
|
||||
JS_ASSERT(cell);
|
||||
CheckGCFreeListLink(cell);
|
||||
aheader->freeList = NULL;
|
||||
finalizables[thingKind] = cell->link;
|
||||
return cell;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -724,7 +747,11 @@ struct FreeLists {
|
|||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
extern Cell *
|
||||
RefillFinalizableFreeList(JSContext *cx, unsigned thingKind);
|
||||
|
||||
} /* namespace gc */
|
||||
|
||||
typedef Vector<gc::Chunk *, 32, SystemAllocPolicy> GCChunks;
|
||||
|
||||
|
@ -772,21 +799,8 @@ typedef HashMap<Value, Value, WrapperHasher, SystemAllocPolicy> WrapperMap;
|
|||
|
||||
class AutoValueVector;
|
||||
class AutoIdVector;
|
||||
}
|
||||
|
||||
static inline void
|
||||
CheckGCFreeListLink(js::gc::FreeCell *cell)
|
||||
{
|
||||
/*
|
||||
* The GC things on the free lists come from one arena and the things on
|
||||
* the free list are linked in ascending address order.
|
||||
*/
|
||||
JS_ASSERT_IF(cell->link, cell->arenaHeader() == cell->link->arenaHeader());
|
||||
JS_ASSERT_IF(cell->link, cell < cell->link);
|
||||
}
|
||||
|
||||
extern bool
|
||||
RefillFinalizableFreeList(JSContext *cx, unsigned thingKind);
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef DEBUG
|
||||
extern bool
|
||||
|
|
|
@ -181,17 +181,11 @@ NewFinalizableGCThing(JSContext *cx, unsigned thingKind)
|
|||
(thingKind == js::gc::FINALIZE_STRING) ||
|
||||
(thingKind == js::gc::FINALIZE_SHORT_STRING));
|
||||
#endif
|
||||
JS_ASSERT(!cx->runtime->gcRunning);
|
||||
|
||||
METER(cx->compartment->arenas[thingKind].stats.alloc++);
|
||||
do {
|
||||
js::gc::FreeCell *cell = cx->compartment->freeLists.getNext(thingKind);
|
||||
if (cell) {
|
||||
CheckGCFreeListLink(cell);
|
||||
return (T *)cell;
|
||||
}
|
||||
if (!RefillFinalizableFreeList(cx, thingKind))
|
||||
return NULL;
|
||||
} while (true);
|
||||
js::gc::Cell *cell = cx->compartment->freeLists.getNext(thingKind);
|
||||
return static_cast<T *>(cell ? cell : js::gc::RefillFinalizableFreeList(cx, thingKind));
|
||||
}
|
||||
|
||||
#undef METER
|
||||
|
|
|
@ -2138,7 +2138,7 @@ Interpret(JSContext *cx, StackFrame *entryFrame, uintN inlineCallCount, InterpMo
|
|||
#ifdef MOZ_TRACEVIS
|
||||
TraceVisStateObj tvso(cx, S_INTERP);
|
||||
#endif
|
||||
JSAutoResolveFlags rf(cx, JSRESOLVE_INFER);
|
||||
JSAutoResolveFlags rf(cx, RESOLVE_INFER);
|
||||
|
||||
# ifdef DEBUG
|
||||
/*
|
||||
|
@ -4096,20 +4096,28 @@ BEGIN_CASE(JSOP_LENGTH)
|
|||
vp = ®s.sp[-1];
|
||||
if (vp->isString()) {
|
||||
vp->setInt32(vp->toString()->length());
|
||||
} else if (vp->isObject()) {
|
||||
JSObject *obj = &vp->toObject();
|
||||
if (obj->isArray()) {
|
||||
jsuint length = obj->getArrayLength();
|
||||
regs.sp[-1].setNumber(length);
|
||||
} else if (obj->isArguments() && !obj->isArgsLengthOverridden()) {
|
||||
uint32 length = obj->getArgsInitialLength();
|
||||
JS_ASSERT(length < INT32_MAX);
|
||||
regs.sp[-1].setInt32(int32_t(length));
|
||||
} else {
|
||||
i = -2;
|
||||
goto do_getprop_with_lval;
|
||||
}
|
||||
} else {
|
||||
if (vp->isObject()) {
|
||||
JSObject *obj = &vp->toObject();
|
||||
if (obj->isArray()) {
|
||||
jsuint length = obj->getArrayLength();
|
||||
regs.sp[-1].setNumber(length);
|
||||
len = JSOP_LENGTH_LENGTH;
|
||||
DO_NEXT_OP(len);
|
||||
}
|
||||
|
||||
if (obj->isArguments()) {
|
||||
ArgumentsObject *argsobj = obj->asArguments();
|
||||
if (!argsobj->hasOverriddenLength()) {
|
||||
uint32 length = argsobj->initialLength();
|
||||
JS_ASSERT(length < INT32_MAX);
|
||||
regs.sp[-1].setInt32(int32_t(length));
|
||||
len = JSOP_LENGTH_LENGTH;
|
||||
DO_NEXT_OP(len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = -2;
|
||||
goto do_getprop_with_lval;
|
||||
}
|
||||
|
@ -4353,11 +4361,11 @@ BEGIN_CASE(JSOP_SETMETHOD)
|
|||
if (entry && JS_LIKELY(!obj->getOps()->setProperty)) {
|
||||
uintN defineHow;
|
||||
if (op == JSOP_SETMETHOD)
|
||||
defineHow = JSDNP_CACHE_RESULT | JSDNP_SET_METHOD;
|
||||
defineHow = DNP_CACHE_RESULT | DNP_SET_METHOD;
|
||||
else if (op == JSOP_SETNAME)
|
||||
defineHow = JSDNP_CACHE_RESULT | JSDNP_UNQUALIFIED;
|
||||
defineHow = DNP_CACHE_RESULT | DNP_UNQUALIFIED;
|
||||
else
|
||||
defineHow = JSDNP_CACHE_RESULT;
|
||||
defineHow = DNP_CACHE_RESULT;
|
||||
if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rval, script->strictModeCode))
|
||||
goto error;
|
||||
} else {
|
||||
|
@ -4405,11 +4413,12 @@ BEGIN_CASE(JSOP_GETELEM)
|
|||
}
|
||||
} else if (obj->isArguments()) {
|
||||
uint32 arg = uint32(i);
|
||||
ArgumentsObject *argsobj = obj->asArguments();
|
||||
|
||||
if (arg < obj->getArgsInitialLength()) {
|
||||
copyFrom = obj->addressOfArgsElement(arg);
|
||||
if (arg < argsobj->initialLength()) {
|
||||
copyFrom = argsobj->addressOfElement(arg);
|
||||
if (!copyFrom->isMagic(JS_ARGS_HOLE)) {
|
||||
if (StackFrame *afp = (StackFrame *) obj->getPrivate())
|
||||
if (StackFrame *afp = reinterpret_cast<StackFrame *>(argsobj->getPrivate()))
|
||||
copyFrom = &afp->canonicalActualArg(arg);
|
||||
goto end_getelem;
|
||||
}
|
||||
|
@ -5235,8 +5244,8 @@ BEGIN_CASE(JSOP_DEFVAR)
|
|||
|
||||
/* Bind a variable only if it's not yet defined. */
|
||||
if (shouldDefine &&
|
||||
!js_DefineNativeProperty(cx, obj, id, UndefinedValue(),
|
||||
PropertyStub, StrictPropertyStub, attrs, 0, 0, NULL)) {
|
||||
!DefineNativeProperty(cx, obj, id, UndefinedValue(), PropertyStub, StrictPropertyStub,
|
||||
attrs, 0, 0)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
@ -5841,13 +5850,12 @@ BEGIN_CASE(JSOP_INITMETHOD)
|
|||
jsid id = ATOM_TO_JSID(atom);
|
||||
|
||||
uintN defineHow = (op == JSOP_INITMETHOD)
|
||||
? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD
|
||||
: JSDNP_CACHE_RESULT;
|
||||
if (!(JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
|
||||
? js_SetPropertyHelper(cx, obj, id, defineHow, &rval, script->strictModeCode)
|
||||
: js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
|
||||
JSPROP_ENUMERATE, 0, 0, NULL,
|
||||
defineHow))) {
|
||||
? DNP_CACHE_RESULT | DNP_SET_METHOD
|
||||
: DNP_CACHE_RESULT;
|
||||
if (JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
|
||||
? !js_SetPropertyHelper(cx, obj, id, defineHow, &rval, script->strictModeCode)
|
||||
: !DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
|
||||
JSPROP_ENUMERATE, 0, 0, defineHow)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
|
245
js/src/jsobj.cpp
245
js/src/jsobj.cpp
|
@ -892,19 +892,19 @@ obj_toString(JSContext *cx, uintN argc, Value *vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* ES5 15.2.4.3. */
|
||||
static JSBool
|
||||
obj_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
|
||||
/* Step 1. */
|
||||
JSObject *obj = ToObject(cx, &vp[1]);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSString *str = js_ValueToString(cx, ObjectValue(*obj));
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
|
||||
vp->setString(str);
|
||||
return JS_TRUE;
|
||||
/* Steps 2-4. */
|
||||
return obj->callMethod(cx, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom), 0, NULL, vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -1337,7 +1337,7 @@ PrincipalsForCompiledCode(const CallArgs &call, JSContext *cx)
|
|||
* fp->script()->compartment() != fp->compartment().
|
||||
*/
|
||||
|
||||
JSPrincipals *calleePrincipals = call.callee().compartment()->principals;
|
||||
JSPrincipals *calleePrincipals = call.callee().principals(cx);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (calleePrincipals) {
|
||||
|
@ -3119,7 +3119,7 @@ with_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
|||
{
|
||||
/* Fixes bug 463997 */
|
||||
uintN flags = cx->resolveFlags;
|
||||
if (flags == JSRESOLVE_INFER)
|
||||
if (flags == RESOLVE_INFER)
|
||||
flags = js_InferFlags(cx, flags);
|
||||
flags |= JSRESOLVE_WITH;
|
||||
JSAutoResolveFlags rf(cx, flags);
|
||||
|
@ -4263,19 +4263,19 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
|
|||
obj = cx->globalObject;
|
||||
if (!obj) {
|
||||
vp->setUndefined();
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
OBJ_TO_INNER_OBJECT(cx, obj);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
if (protoKey != JSProto_Null) {
|
||||
JS_ASSERT(JSProto_Null < protoKey);
|
||||
JS_ASSERT(protoKey < JSProto_LIMIT);
|
||||
if (!js_GetClassObject(cx, obj, protoKey, &cobj))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
if (cobj) {
|
||||
vp->setObject(*cobj);
|
||||
return JS_TRUE;
|
||||
|
@ -4289,10 +4289,8 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
|
|||
}
|
||||
|
||||
JS_ASSERT(obj->isNative());
|
||||
if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_CLASSNAME,
|
||||
&pobj, &prop) < 0) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_CLASSNAME, &pobj, &prop))
|
||||
return false;
|
||||
Value v = UndefinedValue();
|
||||
if (prop && pobj->isNative()) {
|
||||
shape = (Shape *) prop;
|
||||
|
@ -4303,7 +4301,7 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
|
|||
}
|
||||
}
|
||||
*vp = v;
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
@ -4618,8 +4616,7 @@ JSBool
|
|||
js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
return js_DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs,
|
||||
0, 0, NULL);
|
||||
return !!DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4644,13 +4641,14 @@ CallAddPropertyHook(JSContext *cx, Class *clasp, JSObject *obj, const Shape *sha
|
|||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs,
|
||||
uintN flags, intN shortid, JSProperty **propp,
|
||||
uintN defineHow /* = 0 */)
|
||||
namespace js {
|
||||
|
||||
const Shape *
|
||||
DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs,
|
||||
uintN flags, intN shortid, uintN defineHow /* = 0 */)
|
||||
{
|
||||
JS_ASSERT((defineHow & ~(JSDNP_CACHE_RESULT | JSDNP_DONT_PURGE | JSDNP_SET_METHOD)) == 0);
|
||||
JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_DONT_PURGE | DNP_SET_METHOD)) == 0);
|
||||
LeaveTraceIfGlobalObject(cx, obj);
|
||||
|
||||
/* Convert string indices to integers if appropriate. */
|
||||
|
@ -4667,31 +4665,28 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &valu
|
|||
JSProperty *prop;
|
||||
|
||||
/*
|
||||
* If JS_THREADSAFE and id is found, js_LookupProperty returns with
|
||||
* shape non-null and pobj locked. If pobj == obj, the property is
|
||||
* already in obj and obj has its own (mutable) scope. So if we are
|
||||
* defining a getter whose setter was already defined, or vice versa,
|
||||
* finish the job via obj->changeProperty, and refresh the property
|
||||
* cache line for (obj, id) to map shape.
|
||||
* If we are defining a getter whose setter was already defined, or
|
||||
* vice versa, finish the job via obj->changeProperty, and refresh the
|
||||
* property cache line for (obj, id) to map shape.
|
||||
*/
|
||||
if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
|
||||
return JS_FALSE;
|
||||
shape = (Shape *) prop;
|
||||
if (shape && pobj == obj && shape->isAccessorDescriptor()) {
|
||||
shape = obj->changeProperty(cx, shape, attrs,
|
||||
JSPROP_GETTER | JSPROP_SETTER,
|
||||
(attrs & JSPROP_GETTER)
|
||||
? getter
|
||||
: shape->getter(),
|
||||
(attrs & JSPROP_SETTER)
|
||||
? setter
|
||||
: shape->setter());
|
||||
|
||||
if (!shape)
|
||||
return false;
|
||||
} else if (prop) {
|
||||
prop = NULL;
|
||||
shape = NULL;
|
||||
return NULL;
|
||||
if (prop && pobj == obj) {
|
||||
shape = (const Shape *) prop;
|
||||
if (shape->isAccessorDescriptor()) {
|
||||
shape = obj->changeProperty(cx, shape, attrs,
|
||||
JSPROP_GETTER | JSPROP_SETTER,
|
||||
(attrs & JSPROP_GETTER)
|
||||
? getter
|
||||
: shape->getter(),
|
||||
(attrs & JSPROP_SETTER)
|
||||
? setter
|
||||
: shape->setter());
|
||||
if (!shape)
|
||||
return NULL;
|
||||
} else {
|
||||
shape = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4700,7 +4695,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &valu
|
|||
* to be shadowed in obj's scope chain unless it is known a priori that it
|
||||
* is not possible. We do this before locking obj to avoid nesting locks.
|
||||
*/
|
||||
if (!(defineHow & JSDNP_DONT_PURGE))
|
||||
if (!(defineHow & DNP_DONT_PURGE))
|
||||
js_PurgeScopeChain(cx, obj, id);
|
||||
|
||||
/*
|
||||
|
@ -4713,7 +4708,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &valu
|
|||
|
||||
/* Use the object's class getter and setter by default. */
|
||||
Class *clasp = obj->getClass();
|
||||
if (!(defineHow & JSDNP_SET_METHOD)) {
|
||||
if (!(defineHow & DNP_SET_METHOD)) {
|
||||
if (!getter && !(attrs & JSPROP_GETTER))
|
||||
getter = clasp->getProperty;
|
||||
if (!setter && !(attrs & JSPROP_SETTER))
|
||||
|
@ -4722,7 +4717,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &valu
|
|||
|
||||
/* Get obj's own scope if it has one, or create a new one for obj. */
|
||||
if (!obj->ensureClassReservedSlots(cx))
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Make a local copy of value, in case a method barrier needs to update the
|
||||
|
@ -4733,7 +4728,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &valu
|
|||
|
||||
if (!shape) {
|
||||
/* Add a new property, or replace an existing one of the same id. */
|
||||
if (defineHow & JSDNP_SET_METHOD) {
|
||||
if (defineHow & DNP_SET_METHOD) {
|
||||
JS_ASSERT(clasp == &js_ObjectClass);
|
||||
JS_ASSERT(IsFunctionObject(value));
|
||||
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
|
||||
|
@ -4767,7 +4762,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &valu
|
|||
JS_ASSERT(existingShape->getter() != getter);
|
||||
|
||||
if (!obj->methodReadBarrier(cx, *existingShape, &valueCopy))
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
adding = true;
|
||||
|
@ -4777,7 +4772,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &valu
|
|||
shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT,
|
||||
attrs, flags, shortid);
|
||||
if (!shape)
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If shape is a joined method, the above call to putProperty suffices
|
||||
|
@ -4803,28 +4798,26 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &valu
|
|||
/* XXXbe called with lock held */
|
||||
if (!CallAddPropertyHook(cx, clasp, obj, shape, &valueCopy)) {
|
||||
obj->removeProperty(cx, id);
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (defineHow & JSDNP_CACHE_RESULT) {
|
||||
if (defineHow & DNP_CACHE_RESULT) {
|
||||
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||
if (adding) {
|
||||
JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, shape, true);
|
||||
JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, obj, shape, true);
|
||||
TRACE_1(AddProperty, obj);
|
||||
}
|
||||
}
|
||||
if (propp)
|
||||
*propp = (JSProperty *) shape;
|
||||
return true;
|
||||
return shape;
|
||||
|
||||
#ifdef JS_TRACER
|
||||
error: // TRACE_1 jumps here on error.
|
||||
error:
|
||||
/* TRACE_1 jumps here on error. */
|
||||
return NULL;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#define SCOPE_DEPTH_ACCUM(bs,val) \
|
||||
JS_SCOPE_DEPTH_METERING(JS_BASIC_STATS_ACCUM(bs, val))
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
* Call obj's resolve hook.
|
||||
|
@ -4873,7 +4866,7 @@ CallResolveOp(JSContext *cx, JSObject *start, JSObject *obj, jsid id, uintN flag
|
|||
|
||||
if (clasp->flags & JSCLASS_NEW_RESOLVE) {
|
||||
JSNewResolveOp newresolve = reinterpret_cast<JSNewResolveOp>(resolve);
|
||||
if (flags == JSRESOLVE_INFER)
|
||||
if (flags == RESOLVE_INFER)
|
||||
flags = js_InferFlags(cx, 0);
|
||||
JSObject *obj2 = (clasp->flags & JSCLASS_NEW_RESOLVE_GETS_START) ? start : NULL;
|
||||
if (!newresolve(cx, obj, id, flags, &obj2))
|
||||
|
@ -4909,39 +4902,43 @@ CallResolveOp(JSContext *cx, JSObject *start, JSObject *obj, jsid id, uintN flag
|
|||
return true;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE int
|
||||
js_LookupPropertyWithFlagsInline(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
JSObject **objp, JSProperty **propp)
|
||||
#define SCOPE_DEPTH_ACCUM(bs,val) JS_SCOPE_DEPTH_METERING(JS_BASIC_STATS_ACCUM(bs, val))
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
LookupPropertyWithFlagsInline(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
JSObject **objp, JSProperty **propp)
|
||||
{
|
||||
/* We should not get string indices which aren't already integers here. */
|
||||
JS_ASSERT(id == js_CheckForStringIndex(id));
|
||||
|
||||
/* Search scopes starting with obj and following the prototype link. */
|
||||
JSObject *start = obj;
|
||||
int protoIndex;
|
||||
for (protoIndex = 0; ; protoIndex++) {
|
||||
#ifdef JS_SCOPE_DEPTH_METER
|
||||
int protoIndex = 0;
|
||||
#endif
|
||||
for (; ; JS_SCOPE_DEPTH_METERING(protoIndex++)) {
|
||||
const Shape *shape = obj->nativeLookup(id);
|
||||
if (shape) {
|
||||
SCOPE_DEPTH_ACCUM(&cx->runtime->protoLookupDepthStats, protoIndex);
|
||||
*objp = obj;
|
||||
*propp = (JSProperty *) shape;
|
||||
return protoIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Try obj's class resolve hook if id was not found in obj's scope. */
|
||||
if (!shape && obj->getClass()->resolve != JS_ResolveStub) {
|
||||
if (obj->getClass()->resolve != JS_ResolveStub) {
|
||||
bool recursed;
|
||||
if (!CallResolveOp(cx, start, obj, id, flags, objp, propp, &recursed))
|
||||
return -1;
|
||||
return false;
|
||||
if (recursed)
|
||||
break;
|
||||
if (*propp) {
|
||||
/* Recalculate protoIndex in case it was resolved on some other object. */
|
||||
protoIndex = 0;
|
||||
for (JSObject *proto = start; proto && proto != *objp; proto = proto->getProto())
|
||||
protoIndex++;
|
||||
/*
|
||||
* For stats we do not recalculate protoIndex even if it was
|
||||
* resolved on some other object.
|
||||
*/
|
||||
SCOPE_DEPTH_ACCUM(&cx->runtime->protoLookupDepthStats, protoIndex);
|
||||
return protoIndex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4950,7 +4947,7 @@ js_LookupPropertyWithFlagsInline(JSContext *cx, JSObject *obj, jsid id, uintN fl
|
|||
break;
|
||||
if (!proto->isNative()) {
|
||||
if (!proto->lookupProperty(cx, id, objp, propp))
|
||||
return -1;
|
||||
return false;
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* Non-native objects must have either non-native lookup results,
|
||||
|
@ -4966,7 +4963,7 @@ js_LookupPropertyWithFlagsInline(JSContext *cx, JSObject *obj, jsid id, uintN fl
|
|||
JS_ASSERT(proto);
|
||||
}
|
||||
#endif
|
||||
return protoIndex + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
obj = proto;
|
||||
|
@ -4974,7 +4971,7 @@ js_LookupPropertyWithFlagsInline(JSContext *cx, JSObject *obj, jsid id, uintN fl
|
|||
|
||||
*objp = NULL;
|
||||
*propp = NULL;
|
||||
return protoIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
|
@ -4984,26 +4981,30 @@ js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
|||
/* Convert string indices to integers if appropriate. */
|
||||
id = js_CheckForStringIndex(id);
|
||||
|
||||
return js_LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, objp, propp) >= 0;
|
||||
return LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, objp, propp);
|
||||
}
|
||||
|
||||
int
|
||||
js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
JSObject **objp, JSProperty **propp)
|
||||
namespace js {
|
||||
|
||||
bool
|
||||
LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
JSObject **objp, JSProperty **propp)
|
||||
{
|
||||
/* Convert string indices to integers if appropriate. */
|
||||
id = js_CheckForStringIndex(id);
|
||||
|
||||
return js_LookupPropertyWithFlagsInline(cx, obj, id, flags, objp, propp);
|
||||
return LookupPropertyWithFlagsInline(cx, obj, id, flags, objp, propp);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
PropertyCacheEntry *
|
||||
js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
|
||||
JSObject **objp, JSObject **pobjp, JSProperty **propp)
|
||||
{
|
||||
JSObject *scopeChain, *obj, *parent, *pobj;
|
||||
PropertyCacheEntry *entry;
|
||||
int scopeIndex, protoIndex;
|
||||
int scopeIndex;
|
||||
JSProperty *prop;
|
||||
|
||||
JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx));
|
||||
|
@ -5018,10 +5019,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
|
|||
? IsCacheableNonGlobalScope(obj)
|
||||
: !obj->getOps()->lookupProperty;
|
||||
++scopeIndex) {
|
||||
protoIndex =
|
||||
js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,
|
||||
&pobj, &prop);
|
||||
if (protoIndex < 0)
|
||||
if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
|
||||
return NULL;
|
||||
|
||||
if (prop) {
|
||||
|
@ -5032,17 +5030,16 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
|
|||
JS_ASSERT(pobj->getClass() == clasp);
|
||||
if (clasp == &js_BlockClass) {
|
||||
/*
|
||||
* A block instance on the scope chain is immutable and it
|
||||
* shares its shapes with its compile-time prototype.
|
||||
* A block instance on the scope chain is immutable and
|
||||
* shares its shape with the compile-time prototype. Thus
|
||||
* we cannot find any property on the prototype.
|
||||
*/
|
||||
JS_ASSERT(pobj == obj);
|
||||
JS_ASSERT(pobj->isClonedBlock());
|
||||
JS_ASSERT(protoIndex == 0);
|
||||
} else {
|
||||
/* Call and DeclEnvClass objects have no prototypes. */
|
||||
JS_ASSERT(!obj->getProto());
|
||||
JS_ASSERT(protoIndex == 0);
|
||||
}
|
||||
JS_ASSERT(pobj == obj);
|
||||
} else {
|
||||
JS_ASSERT(obj->isNative());
|
||||
}
|
||||
|
@ -5052,8 +5049,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
|
|||
* non-native prototype.
|
||||
*/
|
||||
if (cacheResult && pobj->isNative()) {
|
||||
entry = JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex,
|
||||
protoIndex, pobj,
|
||||
entry = JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj,
|
||||
(Shape *) prop);
|
||||
}
|
||||
SCOPE_DEPTH_ACCUM(&cx->runtime->scopeSearchDepthStats, scopeIndex);
|
||||
|
@ -5133,10 +5129,7 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
|
|||
scopeIndex++) {
|
||||
JSObject *pobj;
|
||||
JSProperty *prop;
|
||||
int protoIndex = js_LookupPropertyWithFlags(cx, obj, id,
|
||||
cx->resolveFlags,
|
||||
&pobj, &prop);
|
||||
if (protoIndex < 0)
|
||||
if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
|
||||
return NULL;
|
||||
if (prop) {
|
||||
if (!pobj->isNative()) {
|
||||
|
@ -5145,8 +5138,7 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
|
|||
}
|
||||
JS_ASSERT_IF(obj->getParent(), pobj->getClass() == obj->getClass());
|
||||
DebugOnly<PropertyCacheEntry*> entry =
|
||||
JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, protoIndex, pobj,
|
||||
(Shape *) prop);
|
||||
JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj, (Shape *) prop);
|
||||
JS_ASSERT(entry);
|
||||
return obj;
|
||||
}
|
||||
|
@ -5298,7 +5290,6 @@ js_GetPropertyHelperWithShapeInline(JSContext *cx, JSObject *obj, JSObject *rece
|
|||
const Shape **shapeOut, JSObject **holderOut)
|
||||
{
|
||||
JSObject *aobj, *obj2;
|
||||
int protoIndex;
|
||||
JSProperty *prop;
|
||||
const Shape *shape;
|
||||
|
||||
|
@ -5310,11 +5301,9 @@ js_GetPropertyHelperWithShapeInline(JSContext *cx, JSObject *obj, JSObject *rece
|
|||
id = js_CheckForStringIndex(id);
|
||||
|
||||
aobj = js_GetProtoIfDenseArray(obj);
|
||||
/* This call site is hot -- use the always-inlined variant of js_LookupPropertyWithFlags(). */
|
||||
protoIndex = js_LookupPropertyWithFlagsInline(cx, aobj, id, cx->resolveFlags,
|
||||
&obj2, &prop);
|
||||
if (protoIndex < 0)
|
||||
return JS_FALSE;
|
||||
/* This call site is hot -- use the always-inlined variant of LookupPropertyWithFlags(). */
|
||||
if (!LookupPropertyWithFlagsInline(cx, aobj, id, cx->resolveFlags, &obj2, &prop))
|
||||
return false;
|
||||
|
||||
*holderOut = obj2;
|
||||
|
||||
|
@ -5357,7 +5346,7 @@ js_GetPropertyHelperWithShapeInline(JSContext *cx, JSObject *obj, JSObject *rece
|
|||
return JS_TRUE;
|
||||
|
||||
/* Do not warn about tests like (obj[prop] == undefined). */
|
||||
if (cx->resolveFlags == JSRESOLVE_INFER) {
|
||||
if (cx->resolveFlags == RESOLVE_INFER) {
|
||||
LeaveTrace(cx);
|
||||
pc += js_CodeSpec[op].length;
|
||||
if (Detecting(cx, pc))
|
||||
|
@ -5390,7 +5379,7 @@ js_GetPropertyHelperWithShapeInline(JSContext *cx, JSObject *obj, JSObject *rece
|
|||
|
||||
if (getHow & JSGET_CACHE_RESULT) {
|
||||
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||
JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, protoIndex, obj2, shape);
|
||||
JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, obj2, shape);
|
||||
}
|
||||
|
||||
/* This call site is hot -- use the always-inlined variant of js_NativeGet(). */
|
||||
|
@ -5436,7 +5425,7 @@ js::GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, const Value &def,
|
|||
{
|
||||
JSProperty *prop;
|
||||
JSObject *obj2;
|
||||
if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0)
|
||||
if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
|
||||
return false;
|
||||
|
||||
if (!prop) {
|
||||
|
@ -5525,7 +5514,6 @@ JSBool
|
|||
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
Value *vp, JSBool strict)
|
||||
{
|
||||
int protoIndex;
|
||||
JSObject *pobj;
|
||||
JSProperty *prop;
|
||||
const Shape *shape;
|
||||
|
@ -5536,18 +5524,15 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
|||
StrictPropertyOp setter;
|
||||
bool added;
|
||||
|
||||
JS_ASSERT((defineHow &
|
||||
~(JSDNP_CACHE_RESULT | JSDNP_SET_METHOD | JSDNP_UNQUALIFIED)) == 0);
|
||||
if (defineHow & JSDNP_CACHE_RESULT)
|
||||
JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_SET_METHOD | DNP_UNQUALIFIED)) == 0);
|
||||
if (defineHow & DNP_CACHE_RESULT)
|
||||
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||
|
||||
/* Convert string indices to integers if appropriate. */
|
||||
id = js_CheckForStringIndex(id);
|
||||
|
||||
protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,
|
||||
&pobj, &prop);
|
||||
if (protoIndex < 0)
|
||||
return JS_FALSE;
|
||||
if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
|
||||
return false;
|
||||
if (prop) {
|
||||
if (!pobj->isNative()) {
|
||||
if (pobj->isProxy()) {
|
||||
|
@ -5576,7 +5561,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
|||
JS_ASSERT(!obj->isBlock());
|
||||
|
||||
if (!obj->getParent() &&
|
||||
(defineHow & JSDNP_UNQUALIFIED) &&
|
||||
(defineHow & DNP_UNQUALIFIED) &&
|
||||
!js_CheckUndeclaredVarAssignment(cx, JSID_TO_STRING(id))) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -5620,8 +5605,8 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
|||
* We found id in a prototype object: prepare to share or shadow.
|
||||
*/
|
||||
if (!shape->shadowable()) {
|
||||
if (defineHow & JSDNP_CACHE_RESULT)
|
||||
JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, protoIndex, pobj, shape);
|
||||
if (defineHow & DNP_CACHE_RESULT)
|
||||
JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, pobj, shape);
|
||||
|
||||
if (shape->hasDefaultSetter() && !shape->hasGetterValue())
|
||||
return JS_TRUE;
|
||||
|
@ -5645,7 +5630,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
|||
* about to create in obj.
|
||||
*/
|
||||
if (!shape->hasSlot()) {
|
||||
defineHow &= ~JSDNP_SET_METHOD;
|
||||
defineHow &= ~DNP_SET_METHOD;
|
||||
if (shape->hasShortID()) {
|
||||
flags = Shape::HAS_SHORTID;
|
||||
shortid = shape->shortid;
|
||||
|
@ -5668,7 +5653,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
|||
JS_ASSERT_IF(shape && shape->isMethod(), pobj->hasMethodBarrier());
|
||||
JS_ASSERT_IF(shape && shape->isMethod(),
|
||||
pobj->getSlot(shape->slot).toObject() == shape->methodObject());
|
||||
if (shape && (defineHow & JSDNP_SET_METHOD)) {
|
||||
if (shape && (defineHow & DNP_SET_METHOD)) {
|
||||
/*
|
||||
* JSOP_SETMETHOD is assigning to an existing own property. If it
|
||||
* is an identical method property, do nothing. Otherwise downgrade
|
||||
|
@ -5720,7 +5705,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
|||
* Check for Object class here to avoid defining a method on a class
|
||||
* with magic resolve, addProperty, getProperty, etc. hooks.
|
||||
*/
|
||||
if ((defineHow & JSDNP_SET_METHOD) && obj->canHaveMethodBarrier()) {
|
||||
if ((defineHow & DNP_SET_METHOD) && obj->canHaveMethodBarrier()) {
|
||||
JS_ASSERT(IsFunctionObject(*vp));
|
||||
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
|
||||
|
||||
|
@ -5737,13 +5722,13 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
|||
if (!shape)
|
||||
return JS_FALSE;
|
||||
|
||||
if (defineHow & JSDNP_CACHE_RESULT)
|
||||
if (defineHow & DNP_CACHE_RESULT)
|
||||
TRACE_1(AddProperty, obj);
|
||||
|
||||
/*
|
||||
* Initialize the new property value (passed to setter) to undefined.
|
||||
* Note that we store before calling addProperty, to match the order
|
||||
* in js_DefineNativeProperty.
|
||||
* in DefineNativeProperty.
|
||||
*/
|
||||
if (obj->containsSlot(shape->slot))
|
||||
obj->nativeSetSlot(shape->slot, UndefinedValue());
|
||||
|
@ -5756,8 +5741,8 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
|||
added = true;
|
||||
}
|
||||
|
||||
if (defineHow & JSDNP_CACHE_RESULT)
|
||||
JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, shape, added);
|
||||
if (defineHow & DNP_CACHE_RESULT)
|
||||
JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, obj, shape, added);
|
||||
|
||||
return js_NativeSet(cx, obj, shape, added, strict, vp);
|
||||
|
||||
|
|
143
js/src/jsobj.h
143
js/src/jsobj.h
|
@ -209,10 +209,9 @@ enum {
|
|||
};
|
||||
|
||||
/*
|
||||
* Unlike js_DefineNativeProperty, propp must be non-null. On success, and if
|
||||
* id was found, return true with *objp non-null and with a property of *objp
|
||||
* stored in *propp. If successful but id was not found, return true with both
|
||||
* *objp and *propp null.
|
||||
* On success, and if id was found, return true with *objp non-null and with a
|
||||
* property of *objp stored in *propp. If successful but id was not found,
|
||||
* return true with both *objp and *propp null.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
||||
|
@ -261,7 +260,11 @@ namespace js {
|
|||
|
||||
struct NativeIterator;
|
||||
class RegExp;
|
||||
|
||||
class GlobalObject;
|
||||
class ArgumentsObject;
|
||||
class NormalArgumentsObject;
|
||||
class StrictArgumentsObject;
|
||||
class StringObject;
|
||||
|
||||
}
|
||||
|
@ -794,93 +797,10 @@ struct JSObject : js::gc::Cell {
|
|||
|
||||
JSBool makeDenseArraySlow(JSContext *cx);
|
||||
|
||||
/*
|
||||
* Arguments-specific getters and setters.
|
||||
*/
|
||||
|
||||
private:
|
||||
/*
|
||||
* We represent arguments objects using js_ArgumentsClass and
|
||||
* js::StrictArgumentsClass. The two are structured similarly, and methods
|
||||
* valid on arguments objects of one class are also generally valid on
|
||||
* arguments objects of the other.
|
||||
*
|
||||
* Arguments objects of either class store arguments length in a slot:
|
||||
*
|
||||
* JSSLOT_ARGS_LENGTH - the number of actual arguments and a flag
|
||||
* indicating whether arguments.length was
|
||||
* overwritten. This slot is not used to represent
|
||||
* arguments.length after that property has been
|
||||
* assigned, even if the new value is integral: it's
|
||||
* always the original length.
|
||||
*
|
||||
* Both arguments classes use a slot for storing arguments data:
|
||||
*
|
||||
* JSSLOT_ARGS_DATA - pointer to an ArgumentsData structure
|
||||
*
|
||||
* ArgumentsData for normal arguments stores the value of arguments.callee,
|
||||
* as long as that property has not been overwritten. If arguments.callee
|
||||
* is overwritten, the corresponding value in ArgumentsData is set to
|
||||
* MagicValue(JS_ARGS_HOLE). Strict arguments do not store this value
|
||||
* because arguments.callee is a poison pill for strict mode arguments.
|
||||
*
|
||||
* The ArgumentsData structure also stores argument values. For normal
|
||||
* arguments this occurs after the corresponding function has returned, and
|
||||
* for strict arguments this occurs when the arguments object is created,
|
||||
* or sometimes shortly after (but not observably so). arguments[i] is
|
||||
* stored in ArgumentsData.slots[i], accessible via getArgsElement() and
|
||||
* setArgsElement(). Deletion of arguments[i] overwrites that slot with
|
||||
* MagicValue(JS_ARGS_HOLE); subsequent redefinition of arguments[i] will
|
||||
* use a normal property to store the value, ignoring the slot.
|
||||
*
|
||||
* Non-strict arguments have a private:
|
||||
*
|
||||
* private - the function's stack frame until the function
|
||||
* returns, when it is replaced with null; also,
|
||||
* JS_ARGUMENTS_OBJECT_ON_TRACE while on trace, if
|
||||
* arguments was created on trace
|
||||
*
|
||||
* Technically strict arguments have a private, but it's always null.
|
||||
* Conceptually it would be better to remove this oddity, but preserving it
|
||||
* allows us to work with arguments objects of either kind more abstractly,
|
||||
* so we keep it for now.
|
||||
*/
|
||||
static const uint32 JSSLOT_ARGS_DATA = 1;
|
||||
|
||||
public:
|
||||
/* Number of extra fixed arguments object slots besides JSSLOT_PRIVATE. */
|
||||
static const uint32 JSSLOT_ARGS_LENGTH = 0;
|
||||
static const uint32 ARGS_CLASS_RESERVED_SLOTS = 2;
|
||||
static const uint32 ARGS_FIRST_FREE_SLOT = ARGS_CLASS_RESERVED_SLOTS + 1;
|
||||
|
||||
/* Lower-order bit stolen from the length slot. */
|
||||
static const uint32 ARGS_LENGTH_OVERRIDDEN_BIT = 0x1;
|
||||
static const uint32 ARGS_PACKED_BITS_COUNT = 1;
|
||||
|
||||
/*
|
||||
* Set the initial length of the arguments, and mark it as not overridden.
|
||||
*/
|
||||
inline void setArgsLength(uint32 argc);
|
||||
|
||||
/*
|
||||
* Return the initial length of the arguments. This may differ from the
|
||||
* current value of arguments.length!
|
||||
*/
|
||||
inline uint32 getArgsInitialLength() const;
|
||||
|
||||
inline void setArgsLengthOverridden();
|
||||
inline bool isArgsLengthOverridden() const;
|
||||
|
||||
inline js::ArgumentsData *getArgsData() const;
|
||||
inline void setArgsData(js::ArgumentsData *data);
|
||||
|
||||
inline const js::Value &getArgsCallee() const;
|
||||
inline void setArgsCallee(const js::Value &callee);
|
||||
|
||||
inline const js::Value &getArgsElement(uint32 i) const;
|
||||
inline js::Value *getArgsElements() const;
|
||||
inline js::Value *addressOfArgsElement(uint32 i);
|
||||
inline void setArgsElement(uint32 i, const js::Value &v);
|
||||
inline js::ArgumentsObject *asArguments();
|
||||
inline js::NormalArgumentsObject *asNormalArguments();
|
||||
inline js::StrictArgumentsObject *asStrictArguments();
|
||||
|
||||
private:
|
||||
/*
|
||||
|
@ -1649,48 +1569,43 @@ extern JSBool
|
|||
js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id,
|
||||
const js::Value &descriptor, JSBool *bp);
|
||||
|
||||
extern JS_FRIEND_DATA(js::Class) js_CallClass;
|
||||
extern JS_FRIEND_DATA(js::Class) js_DeclEnvClass;
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Flags for the defineHow parameter of js_DefineNativeProperty.
|
||||
*/
|
||||
const uintN JSDNP_CACHE_RESULT = 1; /* an interpreter call from JSOP_INITPROP */
|
||||
const uintN JSDNP_DONT_PURGE = 2; /* suppress js_PurgeScopeChain */
|
||||
const uintN JSDNP_SET_METHOD = 4; /* js_{DefineNativeProperty,SetPropertyHelper}
|
||||
const uintN DNP_CACHE_RESULT = 1; /* an interpreter call from JSOP_INITPROP */
|
||||
const uintN DNP_DONT_PURGE = 2; /* suppress js_PurgeScopeChain */
|
||||
const uintN DNP_SET_METHOD = 4; /* DefineNativeProperty,js_SetPropertyHelper
|
||||
must pass the js::Shape::METHOD
|
||||
flag on to JSObject::{add,put}Property */
|
||||
const uintN JSDNP_UNQUALIFIED = 8; /* Unqualified property set. Only used in
|
||||
const uintN DNP_UNQUALIFIED = 8; /* Unqualified property set. Only used in
|
||||
the defineHow argument of
|
||||
js_SetPropertyHelper. */
|
||||
|
||||
/*
|
||||
* On error, return false. On success, if propp is non-null, return true with
|
||||
* obj locked and with a held property in *propp; if propp is null, return true
|
||||
* but release obj's lock first.
|
||||
* Return successfully added or changed shape or NULL on error.
|
||||
*/
|
||||
extern JSBool
|
||||
js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value &value,
|
||||
js::PropertyOp getter, js::StrictPropertyOp setter, uintN attrs,
|
||||
uintN flags, intN shortid, JSProperty **propp,
|
||||
uintN defineHow = 0);
|
||||
extern const Shape *
|
||||
DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value &value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs,
|
||||
uintN flags, intN shortid, uintN defineHow = 0);
|
||||
|
||||
/*
|
||||
* Specialized subroutine that allows caller to preset JSRESOLVE_* flags and
|
||||
* returns the index along the prototype chain in which *propp was found, or
|
||||
* the last index if not found, or -1 on error.
|
||||
* Specialized subroutine that allows caller to preset JSRESOLVE_* flags.
|
||||
*/
|
||||
extern int
|
||||
js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
JSObject **objp, JSProperty **propp);
|
||||
extern bool
|
||||
LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
JSObject **objp, JSProperty **propp);
|
||||
|
||||
/*
|
||||
* Constant to pass to js_LookupPropertyWithFlags to infer bits from current
|
||||
* bytecode.
|
||||
*/
|
||||
static const uintN JSRESOLVE_INFER = 0xffff;
|
||||
|
||||
extern JS_FRIEND_DATA(js::Class) js_CallClass;
|
||||
extern JS_FRIEND_DATA(js::Class) js_DeclEnvClass;
|
||||
|
||||
namespace js {
|
||||
static const uintN RESOLVE_INFER = 0xffff;
|
||||
|
||||
/*
|
||||
* We cache name lookup results only for the global object or for native
|
||||
|
|
|
@ -409,97 +409,6 @@ JSObject::shrinkDenseArrayElements(JSContext *cx, uintN cap)
|
|||
shrinkSlots(cx, cap);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setArgsLength(uint32 argc)
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||
JS_ASSERT(UINT32_MAX > (uint64(argc) << ARGS_PACKED_BITS_COUNT));
|
||||
getSlotRef(JSSLOT_ARGS_LENGTH).setInt32(argc << ARGS_PACKED_BITS_COUNT);
|
||||
JS_ASSERT(!isArgsLengthOverridden());
|
||||
}
|
||||
|
||||
inline uint32
|
||||
JSObject::getArgsInitialLength() const
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
uint32 argc = uint32(getSlot(JSSLOT_ARGS_LENGTH).toInt32()) >> ARGS_PACKED_BITS_COUNT;
|
||||
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||
return argc;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setArgsLengthOverridden()
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
getSlotRef(JSSLOT_ARGS_LENGTH).getInt32Ref() |= ARGS_LENGTH_OVERRIDDEN_BIT;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isArgsLengthOverridden() const
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
const js::Value &v = getSlot(JSSLOT_ARGS_LENGTH);
|
||||
return v.toInt32() & ARGS_LENGTH_OVERRIDDEN_BIT;
|
||||
}
|
||||
|
||||
inline js::ArgumentsData *
|
||||
JSObject::getArgsData() const
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
return (js::ArgumentsData *) getSlot(JSSLOT_ARGS_DATA).toPrivate();
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setArgsData(js::ArgumentsData *data)
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
getSlotRef(JSSLOT_ARGS_DATA).setPrivate(data);
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
JSObject::getArgsCallee() const
|
||||
{
|
||||
return getArgsData()->callee;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setArgsCallee(const js::Value &callee)
|
||||
{
|
||||
getArgsData()->callee = callee;
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
JSObject::getArgsElement(uint32 i) const
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
JS_ASSERT(i < getArgsInitialLength());
|
||||
return getArgsData()->slots[i];
|
||||
}
|
||||
|
||||
inline js::Value *
|
||||
JSObject::getArgsElements() const
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
return getArgsData()->slots;
|
||||
}
|
||||
|
||||
inline js::Value *
|
||||
JSObject::addressOfArgsElement(uint32 i)
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
JS_ASSERT(i < getArgsInitialLength());
|
||||
return &getArgsData()->slots[i];
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setArgsElement(uint32 i, const js::Value &v)
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
JS_ASSERT(i < getArgsInitialLength());
|
||||
getArgsData()->slots[i] = v;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::callIsForEval() const
|
||||
{
|
||||
|
|
106
js/src/json.cpp
106
js/src/json.cpp
|
@ -777,8 +777,8 @@ js_Stringify(JSContext *cx, Value *vp, JSObject *replacer, Value space, StringBu
|
|||
|
||||
/* Step 10. */
|
||||
jsid emptyId = ATOM_TO_JSID(cx->runtime->atomState.emptyAtom);
|
||||
if (!js_DefineNativeProperty(cx, wrapper, emptyId, *vp, PropertyStub, StrictPropertyStub,
|
||||
JSPROP_ENUMERATE, 0, 0, NULL))
|
||||
if (!DefineNativeProperty(cx, wrapper, emptyId, *vp, PropertyStub, StrictPropertyStub,
|
||||
JSPROP_ENUMERATE, 0, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -808,50 +808,80 @@ static JSBool HandleDataNumber(JSContext *cx, JSONParser *jp);
|
|||
static JSBool HandleDataKeyword(JSContext *cx, JSONParser *jp);
|
||||
static JSBool PopState(JSContext *cx, JSONParser *jp);
|
||||
|
||||
/* ES5 15.12.2 Walk. */
|
||||
static bool
|
||||
Walk(JSContext *cx, jsid id, JSObject *holder, const Value &reviver, Value *vp)
|
||||
Walk(JSContext *cx, JSObject *holder, jsid name, const Value &reviver, Value *vp)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
|
||||
if (!holder->getProperty(cx, id, vp))
|
||||
/* Step 1. */
|
||||
Value val;
|
||||
if (!holder->getProperty(cx, name, &val))
|
||||
return false;
|
||||
|
||||
JSObject *obj;
|
||||
/* Step 2. */
|
||||
if (val.isObject()) {
|
||||
JSObject *obj = &val.toObject();
|
||||
|
||||
if (vp->isObject() && !(obj = &vp->toObject())->isCallable()) {
|
||||
AutoValueRooter propValue(cx);
|
||||
|
||||
if(obj->isArray()) {
|
||||
jsuint length = 0;
|
||||
if (!js_GetLengthProperty(cx, obj, &length))
|
||||
return false;
|
||||
if (obj->isArray()) {
|
||||
/* Step 2a(ii). */
|
||||
jsuint length = obj->getArrayLength();
|
||||
|
||||
/* Step 2a(i), 2a(iii-iv). */
|
||||
for (jsuint i = 0; i < length; i++) {
|
||||
jsid index;
|
||||
if (!IndexToId(cx, i, &index))
|
||||
jsid id;
|
||||
if (!IndexToId(cx, i, &id))
|
||||
return false;
|
||||
|
||||
if (!Walk(cx, index, obj, reviver, propValue.addr()))
|
||||
/* Step 2a(iii)(1). */
|
||||
Value newElement;
|
||||
if (!Walk(cx, obj, id, reviver, &newElement))
|
||||
return false;
|
||||
|
||||
if (!obj->defineProperty(cx, index, propValue.value(), NULL, NULL, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
/*
|
||||
* Arrays which begin empty and whose properties are always
|
||||
* incrementally appended are always dense, no matter their
|
||||
* length, under current dense/slow array heuristics.
|
||||
* Also, deleting a property from a dense array which is not
|
||||
* currently being enumerated never makes it slow. This array
|
||||
* is never exposed until the reviver sees it below, so it must
|
||||
* be dense and isn't currently being enumerated. Therefore
|
||||
* property definition and deletion will always succeed,
|
||||
* and we need not check for failure.
|
||||
*/
|
||||
if (newElement.isUndefined()) {
|
||||
/* Step 2a(iii)(2). */
|
||||
JS_ALWAYS_TRUE(array_deleteProperty(cx, obj, id, &newElement, false));
|
||||
} else {
|
||||
/* Step 2a(iii)(3). */
|
||||
JS_ALWAYS_TRUE(array_defineProperty(cx, obj, id, &newElement, PropertyStub,
|
||||
StrictPropertyStub, JSPROP_ENUMERATE));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AutoIdVector props(cx);
|
||||
if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props))
|
||||
/* Step 2b(i). */
|
||||
AutoIdVector keys(cx);
|
||||
if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &keys))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0, len = props.length(); i < len; i++) {
|
||||
jsid idName = props[i];
|
||||
if (!Walk(cx, idName, obj, reviver, propValue.addr()))
|
||||
/* Step 2b(ii). */
|
||||
for (size_t i = 0, len = keys.length(); i < len; i++) {
|
||||
/* Step 2b(ii)(1). */
|
||||
Value newElement;
|
||||
jsid id = keys[i];
|
||||
if (!Walk(cx, obj, id, reviver, &newElement))
|
||||
return false;
|
||||
if (propValue.value().isUndefined()) {
|
||||
if (!js_DeleteProperty(cx, obj, idName, propValue.addr(), false))
|
||||
|
||||
if (newElement.isUndefined()) {
|
||||
/* Step 2b(ii)(2). */
|
||||
if (!js_DeleteProperty(cx, obj, id, &newElement, false))
|
||||
return false;
|
||||
} else {
|
||||
if (!obj->defineProperty(cx, idName, propValue.value(), NULL, NULL,
|
||||
JSPROP_ENUMERATE)) {
|
||||
/* Step 2b(ii)(3). */
|
||||
JS_ASSERT(obj->isNative());
|
||||
if (!DefineNativeProperty(cx, obj, id, newElement, PropertyStub,
|
||||
StrictPropertyStub, JSPROP_ENUMERATE, 0, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -859,20 +889,24 @@ Walk(JSContext *cx, jsid id, JSObject *holder, const Value &reviver, Value *vp)
|
|||
}
|
||||
}
|
||||
|
||||
// return reviver.call(holder, key, value);
|
||||
const Value &value = *vp;
|
||||
JSString *key = js_ValueToString(cx, IdToValue(id));
|
||||
/* Step 3. */
|
||||
JSString *key = IdToString(cx, name);
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
Value vec[2] = { StringValue(key), value };
|
||||
Value reviverResult;
|
||||
if (!JS_CallFunctionValue(cx, holder, Jsvalify(reviver),
|
||||
2, Jsvalify(vec), Jsvalify(&reviverResult))) {
|
||||
LeaveTrace(cx);
|
||||
InvokeArgsGuard args;
|
||||
if (!cx->stack.pushInvokeArgs(cx, 2, &args))
|
||||
return false;
|
||||
}
|
||||
|
||||
*vp = reviverResult;
|
||||
args.calleev() = reviver;
|
||||
args.thisv() = ObjectValue(*holder);
|
||||
args[0] = StringValue(key);
|
||||
args[1] = val;
|
||||
|
||||
if (!Invoke(cx, args))
|
||||
return false;
|
||||
*vp = args.rval();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -898,7 +932,7 @@ Revive(JSContext *cx, const Value &reviver, Value *vp)
|
|||
return false;
|
||||
}
|
||||
|
||||
return Walk(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), obj, reviver, vp);
|
||||
return Walk(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), reviver, vp);
|
||||
}
|
||||
|
||||
JSONParser *
|
||||
|
|
|
@ -538,9 +538,9 @@ JSONSourceParser::parse(Value *vp)
|
|||
* js_CheckForStringIndex.
|
||||
*/
|
||||
jsid propid = ATOM_TO_JSID(&valueStack.popCopy().toString()->asAtom());
|
||||
if (!js_DefineNativeProperty(cx, &valueStack.back().toObject(), propid, v,
|
||||
PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE,
|
||||
0, 0, NULL))
|
||||
if (!DefineNativeProperty(cx, &valueStack.back().toObject(), propid, v,
|
||||
PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE,
|
||||
0, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -270,13 +270,29 @@ public:
|
|||
|
||||
#ifdef DEBUG
|
||||
|
||||
/* If pc != NULL, includes a prefix indicating whether the PC is at the current line. */
|
||||
/*
|
||||
* If pc != NULL, include a prefix indicating whether the PC is at the current line.
|
||||
* If counts != NULL, include a counter of the number of times each op was executed.
|
||||
*/
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_DisassembleAtPC(JSContext *cx, JSScript *script, JSBool lines, jsbytecode *pc, Sprinter *sp)
|
||||
js_DisassembleAtPC(JSContext *cx, JSScript *script, JSBool lines, jsbytecode *pc, int* counts, Sprinter *sp)
|
||||
{
|
||||
jsbytecode *next, *end;
|
||||
uintN len;
|
||||
|
||||
if (counts)
|
||||
SprintCString(sp, "count x ");
|
||||
SprintCString(sp, "off ");
|
||||
if (lines)
|
||||
SprintCString(sp, "line");
|
||||
SprintCString(sp, " op\n");
|
||||
if (counts)
|
||||
SprintCString(sp, "-------- ");
|
||||
SprintCString(sp, "----- ");
|
||||
if (lines)
|
||||
SprintCString(sp, "----");
|
||||
SprintCString(sp, " --\n");
|
||||
|
||||
next = script->code;
|
||||
end = next + script->length;
|
||||
while (next < end) {
|
||||
|
@ -290,7 +306,7 @@ js_DisassembleAtPC(JSContext *cx, JSScript *script, JSBool lines, jsbytecode *pc
|
|||
}
|
||||
len = js_Disassemble1(cx, script, next,
|
||||
next - script->code,
|
||||
lines, sp);
|
||||
lines, sp, counts);
|
||||
if (!len)
|
||||
return JS_FALSE;
|
||||
next += len;
|
||||
|
@ -299,18 +315,18 @@ js_DisassembleAtPC(JSContext *cx, JSScript *script, JSBool lines, jsbytecode *pc
|
|||
}
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, Sprinter *sp)
|
||||
js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, Sprinter *sp, int* counts)
|
||||
{
|
||||
return js_DisassembleAtPC(cx, script, lines, NULL, sp);
|
||||
return js_DisassembleAtPC(cx, script, lines, NULL, counts, sp);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_DumpPC(JSContext *cx)
|
||||
js_DumpPC(JSContext *cx, int* counts = NULL)
|
||||
{
|
||||
void *mark = JS_ARENA_MARK(&cx->tempPool);
|
||||
Sprinter sprinter;
|
||||
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
|
||||
JSBool ok = js_DisassembleAtPC(cx, cx->fp()->script(), true, cx->regs().pc, &sprinter);
|
||||
JSBool ok = js_DisassembleAtPC(cx, cx->fp()->script(), true, cx->regs().pc, counts, &sprinter);
|
||||
fprintf(stdout, "%s", sprinter.base);
|
||||
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
||||
return ok;
|
||||
|
@ -383,7 +399,7 @@ ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes)
|
|||
|
||||
JS_FRIEND_API(uintN)
|
||||
js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
uintN loc, JSBool lines, Sprinter *sp)
|
||||
uintN loc, JSBool lines, Sprinter *sp, int* counts)
|
||||
{
|
||||
JSOp op;
|
||||
const JSCodeSpec *cs;
|
||||
|
@ -409,6 +425,8 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
|
|||
cs = &js_CodeSpec[op];
|
||||
len = (ptrdiff_t) cs->length;
|
||||
Sprint(sp, "%05u:", loc);
|
||||
if (counts)
|
||||
Sprint(sp, "% 8d x ", counts[loc]);
|
||||
if (lines)
|
||||
Sprint(sp, "%4u", JS_PCToLineNumber(cx, script, pc));
|
||||
Sprint(sp, " %s", js_CodeName[op]);
|
||||
|
|
|
@ -523,18 +523,18 @@ CallResultEscapes(jsbytecode *pc);
|
|||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef __cplusplus
|
||||
/*
|
||||
* Disassemblers, for debugging only.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#ifdef __cplusplus
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, js::Sprinter *sp);
|
||||
js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, js::Sprinter *sp, int *counts = NULL);
|
||||
|
||||
extern JS_FRIEND_API(uintN)
|
||||
js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
|
||||
JSBool lines, js::Sprinter *sp);
|
||||
#endif /* __cplusplus */
|
||||
JSBool lines, js::Sprinter *sp, int *counts = NULL);
|
||||
#endif
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
|
|
|
@ -1199,15 +1199,11 @@ Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *scrip
|
|||
rval.setUndefined();
|
||||
}
|
||||
|
||||
JSProperty *prop;
|
||||
|
||||
if (!js_DefineNativeProperty(cx, globalObj, id, rval, PropertyStub, StrictPropertyStub,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT, 0, 0, &prop)) {
|
||||
const Shape *shape =
|
||||
DefineNativeProperty(cx, globalObj, id, rval, PropertyStub, StrictPropertyStub,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT, 0, 0);
|
||||
if (!shape)
|
||||
return false;
|
||||
}
|
||||
|
||||
JS_ASSERT(prop);
|
||||
const Shape *shape = (const Shape *)prop;
|
||||
def.knownSlot = shape->slot;
|
||||
}
|
||||
|
||||
|
@ -4381,11 +4377,11 @@ CheckDestructuring(JSContext *cx, BindData *data, JSParseNode *left, JSTreeConte
|
|||
if (data &&
|
||||
data->binder == BindLet &&
|
||||
OBJ_BLOCK_COUNT(cx, tc->blockChain()) == 0 &&
|
||||
!js_DefineNativeProperty(cx, tc->blockChain(),
|
||||
ATOM_TO_JSID(cx->runtime->atomState.emptyAtom),
|
||||
UndefinedValue(), NULL, NULL,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT,
|
||||
Shape::HAS_SHORTID, 0, NULL)) {
|
||||
!DefineNativeProperty(cx, tc->blockChain(),
|
||||
ATOM_TO_JSID(cx->runtime->atomState.emptyAtom),
|
||||
UndefinedValue(), NULL, NULL,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT,
|
||||
Shape::HAS_SHORTID, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,8 +49,8 @@ using namespace js;
|
|||
JS_STATIC_ASSERT(sizeof(PCVal) == sizeof(jsuword));
|
||||
|
||||
JS_REQUIRES_STACK PropertyCacheEntry *
|
||||
PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoIndex,
|
||||
JSObject *pobj, const Shape *shape, JSBool adding)
|
||||
PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, JSObject *pobj,
|
||||
const Shape *shape, JSBool adding)
|
||||
{
|
||||
jsbytecode *pc;
|
||||
jsuword kshape, vshape;
|
||||
|
@ -88,42 +88,34 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI
|
|||
/*
|
||||
* Check for overdeep scope and prototype chain. Because resolve, getter,
|
||||
* and setter hooks can change the prototype chain using JS_SetPrototype
|
||||
* after js_LookupPropertyWithFlags has returned the nominal protoIndex,
|
||||
* we have to validate protoIndex if it is non-zero. If it is zero, then
|
||||
* we know thanks to the pobj->nativeContains test above, combined with the
|
||||
* fact that obj == pobj, that protoIndex is invariant.
|
||||
* after LookupPropertyWithFlags has returned, we calculate the protoIndex
|
||||
* here and not in LookupPropertyWithFlags.
|
||||
*
|
||||
* The scopeIndex can't be wrong. We require JS_SetParent calls to happen
|
||||
* before any running script might consult a parent-linked scope chain. If
|
||||
* this requirement is not satisfied, the fill in progress will never hit,
|
||||
* but vcap vs. scope shape tests ensure nothing malfunctions.
|
||||
*/
|
||||
JS_ASSERT_IF(scopeIndex == 0 && protoIndex == 0, obj == pobj);
|
||||
JS_ASSERT_IF(obj == pobj, scopeIndex == 0);
|
||||
|
||||
if (protoIndex != 0) {
|
||||
JSObject *tmp = obj;
|
||||
JSObject *tmp = obj;
|
||||
for (uintN i = 0; i != scopeIndex; i++)
|
||||
tmp = tmp->getParent();
|
||||
|
||||
for (uintN i = 0; i != scopeIndex; i++)
|
||||
tmp = tmp->getParent();
|
||||
JS_ASSERT(tmp != pobj);
|
||||
uintN protoIndex = 0;
|
||||
while (tmp != pobj) {
|
||||
tmp = tmp->getProto();
|
||||
|
||||
protoIndex = 1;
|
||||
for (;;) {
|
||||
tmp = tmp->getProto();
|
||||
|
||||
/*
|
||||
* We cannot cache properties coming from native objects behind
|
||||
* non-native ones on the prototype chain. The non-natives can
|
||||
* mutate in arbitrary way without changing any shapes.
|
||||
*/
|
||||
if (!tmp || !tmp->isNative()) {
|
||||
PCMETER(noprotos++);
|
||||
return JS_NO_PROP_CACHE_FILL;
|
||||
}
|
||||
if (tmp == pobj)
|
||||
break;
|
||||
++protoIndex;
|
||||
/*
|
||||
* We cannot cache properties coming from native objects behind
|
||||
* non-native ones on the prototype chain. The non-natives can
|
||||
* mutate in arbitrary way without changing any shapes.
|
||||
*/
|
||||
if (!tmp || !tmp->isNative()) {
|
||||
PCMETER(noprotos++);
|
||||
return JS_NO_PROP_CACHE_FILL;
|
||||
}
|
||||
++protoIndex;
|
||||
}
|
||||
|
||||
if (scopeIndex > PCVCAP_SCOPEMASK || protoIndex > PCVCAP_PROTOMASK) {
|
||||
|
|
|
@ -271,8 +271,8 @@ class PropertyCache
|
|||
* not possible.
|
||||
*/
|
||||
JS_REQUIRES_STACK PropertyCacheEntry *fill(JSContext *cx, JSObject *obj, uintN scopeIndex,
|
||||
uintN protoIndex, JSObject *pobj,
|
||||
const js::Shape *shape, JSBool adding = false);
|
||||
JSObject *pobj, const js::Shape *shape,
|
||||
JSBool adding = false);
|
||||
|
||||
void purge(JSContext *cx);
|
||||
void purgeForScript(JSContext *cx, JSScript *script);
|
||||
|
|
|
@ -1107,7 +1107,6 @@ JSObject::removeProperty(JSContext *cx, jsid id)
|
|||
JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals);
|
||||
}
|
||||
|
||||
|
||||
/* If shape is not the last property added, switch to dictionary mode. */
|
||||
if (shape != lastProp && !inDictionaryMode()) {
|
||||
if (!toDictionaryMode(cx))
|
||||
|
@ -1168,16 +1167,19 @@ JSObject::removeProperty(JSContext *cx, jsid id)
|
|||
JS_ASSERT_IF(hadSlot, shape->slot + 1 <= shape->slotSpan);
|
||||
|
||||
/*
|
||||
* Maintain slot freelist consistency. The only constraint we
|
||||
* have is that slot numbers on the freelist are less than
|
||||
* lastProp->slotSpan. Thus, if the freelist is non-empty,
|
||||
* then lastProp->slotSpan may not decrease.
|
||||
*/
|
||||
* Maintain slot freelist consistency. Slot numbers on the
|
||||
* freelist are less than lastProp->slotSpan; so if the
|
||||
* freelist is non-empty, then lastProp->slotSpan may not
|
||||
* decrease.
|
||||
*/
|
||||
if (table->freelist != SHAPE_INVALID_SLOT) {
|
||||
lastProp->slotSpan = shape->slotSpan;
|
||||
|
||||
/* Add the slot to the freelist if it wasn't added in freeSlot. */
|
||||
if (hadSlot && !addedToFreelist) {
|
||||
|
||||
/*
|
||||
* Add the slot to the freelist if it wasn't added in
|
||||
* freeSlot and it is not a reserved slot.
|
||||
*/
|
||||
if (hadSlot && !addedToFreelist && JSSLOT_FREE(clasp) <= shape->slot) {
|
||||
getSlotRef(shape->slot).setPrivateUint32(table->freelist);
|
||||
table->freelist = shape->slot;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#endif
|
||||
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jscompartment.h"
|
||||
#include "jshashtable.h"
|
||||
|
@ -634,9 +635,7 @@ struct EmptyShape : public js::Shape
|
|||
return shape;
|
||||
}
|
||||
|
||||
static EmptyShape *getEmptyArgumentsShape(JSContext *cx) {
|
||||
return ensure(cx, &js_ArgumentsClass, &cx->compartment->emptyArgumentsShape);
|
||||
}
|
||||
static inline EmptyShape *getEmptyArgumentsShape(JSContext *cx);
|
||||
|
||||
static EmptyShape *getEmptyBlockShape(JSContext *cx) {
|
||||
return ensure(cx, &js_BlockClass, &cx->compartment->emptyBlockShape);
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "jsscope.h"
|
||||
#include "jsgc.h"
|
||||
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/StringObject.h"
|
||||
|
||||
#include "jscntxtinlines.h"
|
||||
|
@ -355,6 +356,13 @@ EmptyShape::EmptyShape(JSCompartment *comp, js::Class *aclasp)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* static */ inline EmptyShape *
|
||||
EmptyShape::getEmptyArgumentsShape(JSContext *cx)
|
||||
{
|
||||
return ensure(cx, &NormalArgumentsObject::jsClass, &cx->compartment->emptyArgumentsShape);
|
||||
}
|
||||
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsscopeinlines_h___ */
|
||||
|
|
|
@ -2076,7 +2076,7 @@ FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t
|
|||
|
||||
JSObject *holder;
|
||||
JSProperty *prop = NULL;
|
||||
if (js_LookupPropertyWithFlags(cx, base, id, JSRESOLVE_QUALIFIED, &holder, &prop) < 0)
|
||||
if (!LookupPropertyWithFlags(cx, base, id, JSRESOLVE_QUALIFIED, &holder, &prop))
|
||||
return false;
|
||||
|
||||
/* Only handle the case where the property exists and is on this object. */
|
||||
|
|
|
@ -3158,8 +3158,7 @@ public:
|
|||
if (p == fp->addressOfArgs()) {
|
||||
if (frameobj) {
|
||||
JS_ASSERT_IF(fp->hasArgsObj(), frameobj == &fp->argsObj());
|
||||
fp->setArgsObj(*frameobj);
|
||||
JS_ASSERT(frameobj->isArguments());
|
||||
fp->setArgsObj(*frameobj->asArguments());
|
||||
if (frameobj->isNormalArguments())
|
||||
frameobj->setPrivate(fp);
|
||||
else
|
||||
|
@ -9521,22 +9520,17 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
|
|||
RETURN_STOP_A("cannot cache name");
|
||||
} else {
|
||||
TraceMonitor &localtm = *traceMonitor;
|
||||
int protoIndex = js_LookupPropertyWithFlags(cx, aobj, id,
|
||||
cx->resolveFlags,
|
||||
&obj2, &prop);
|
||||
if (!LookupPropertyWithFlags(cx, aobj, id, cx->resolveFlags, &obj2, &prop))
|
||||
RETURN_ERROR_A("error in LookupPropertyWithFlags");
|
||||
|
||||
if (protoIndex < 0)
|
||||
RETURN_ERROR_A("error in js_LookupPropertyWithFlags");
|
||||
|
||||
/* js_LookupPropertyWithFlags can reenter the interpreter and kill |this|. */
|
||||
/* LookupPropertyWithFlags can reenter the interpreter and kill |this|. */
|
||||
if (!localtm.recorder)
|
||||
return ARECORD_ABORTED;
|
||||
|
||||
if (prop) {
|
||||
if (!obj2->isNative())
|
||||
RETURN_STOP_A("property found on non-native object");
|
||||
entry = JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, protoIndex, obj2,
|
||||
(Shape*) prop);
|
||||
entry = JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, obj2, (Shape*) prop);
|
||||
JS_ASSERT(entry);
|
||||
if (entry == JS_NO_PROP_CACHE_FILL)
|
||||
entry = NULL;
|
||||
|
@ -12881,7 +12875,7 @@ JS_REQUIRES_STACK void
|
|||
TraceRecorder::guardNotHole(LIns *argsobj_ins, LIns *idx_ins)
|
||||
{
|
||||
// vp = &argsobj->slots[JSSLOT_ARGS_DATA].slots[idx]
|
||||
LIns* argsData_ins = w.getObjPrivatizedSlot(argsobj_ins, JSObject::JSSLOT_ARGS_DATA);
|
||||
LIns* argsData_ins = w.getObjPrivatizedSlot(argsobj_ins, ArgumentsObject::DATA_SLOT);
|
||||
LIns* slotOffset_ins = w.addp(w.nameImmw(offsetof(ArgumentsData, slots)),
|
||||
w.ui2p(w.muliN(idx_ins, sizeof(Value))));
|
||||
LIns* vp_ins = w.addp(argsData_ins, slotOffset_ins);
|
||||
|
@ -12934,17 +12928,18 @@ TraceRecorder::record_JSOP_GETELEM()
|
|||
}
|
||||
|
||||
if (obj->isArguments()) {
|
||||
ArgumentsObject *argsobj = obj->asArguments();
|
||||
|
||||
// Don't even try to record if out of range or reading a deleted arg
|
||||
int32 int_idx = idx.toInt32();
|
||||
if (int_idx < 0 || int_idx >= (int32)obj->getArgsInitialLength())
|
||||
if (int_idx < 0 || int_idx >= (int32)argsobj->initialLength())
|
||||
RETURN_STOP_A("cannot trace arguments with out of range index");
|
||||
if (obj->getArgsElement(int_idx).isMagic(JS_ARGS_HOLE))
|
||||
if (argsobj->element(int_idx).isMagic(JS_ARGS_HOLE))
|
||||
RETURN_STOP_A("reading deleted args element");
|
||||
|
||||
// Only trace reading arguments out of active, tracked frame
|
||||
unsigned depth;
|
||||
StackFrame *afp = guardArguments(obj, obj_ins, &depth);
|
||||
if (afp) {
|
||||
if (StackFrame *afp = guardArguments(obj, obj_ins, &depth)) {
|
||||
Value* vp = &afp->canonicalActualArg(int_idx);
|
||||
if (idx_ins->isImmD()) {
|
||||
JS_ASSERT(int_idx == (int32)idx_ins->immD());
|
||||
|
@ -13863,7 +13858,7 @@ TraceRecorder::record_JSOP_FUNAPPLY()
|
|||
StackFrame *afp = guardArguments(aobj, aobj_ins, &depth);
|
||||
if (!afp)
|
||||
RETURN_STOP_A("can't reach arguments object's frame");
|
||||
if (aobj->isArgsLengthOverridden())
|
||||
if (aobj->asArguments()->hasOverriddenLength())
|
||||
RETURN_STOP_A("can't trace arguments with overridden length");
|
||||
guardArgsLengthNotAssigned(aobj_ins);
|
||||
length = afp->numActualArgs();
|
||||
|
@ -15671,13 +15666,27 @@ TraceRecorder::record_JSOP_ARGSUB()
|
|||
RETURN_STOP_A("can't trace JSOP_ARGSUB hard case");
|
||||
}
|
||||
|
||||
namespace tjit {
|
||||
|
||||
nj::LIns *
|
||||
Writer::getArgsLength(nj::LIns *args) const
|
||||
{
|
||||
uint32 slot = js::ArgumentsObject::INITIAL_LENGTH_SLOT;
|
||||
nj::LIns *vaddr_ins = ldpObjSlots(args);
|
||||
return name(lir->insLoad(nj::LIR_ldi, vaddr_ins, slot * sizeof(Value) + sPayloadOffset,
|
||||
ACCSET_SLOTS),
|
||||
"argsLength");
|
||||
}
|
||||
|
||||
} // namespace tjit
|
||||
|
||||
JS_REQUIRES_STACK LIns*
|
||||
TraceRecorder::guardArgsLengthNotAssigned(LIns* argsobj_ins)
|
||||
{
|
||||
// The following implements JSObject::isArgsLengthOverridden on trace.
|
||||
// ARGS_LENGTH_OVERRIDDEN_BIT is set if length was overridden.
|
||||
LIns *len_ins = w.getArgsLength(argsobj_ins);
|
||||
LIns *ovr_ins = w.andi(len_ins, w.nameImmi(JSObject::ARGS_LENGTH_OVERRIDDEN_BIT));
|
||||
LIns *ovr_ins = w.andi(len_ins, w.nameImmi(ArgumentsObject::LENGTH_OVERRIDDEN_BIT));
|
||||
guard(true, w.eqi0(ovr_ins), MISMATCH_EXIT);
|
||||
return len_ins;
|
||||
}
|
||||
|
@ -15696,7 +15705,7 @@ TraceRecorder::record_JSOP_ARGCNT()
|
|||
// We also have to check that arguments.length has not been mutated
|
||||
// at record time, because if so we will generate incorrect constant
|
||||
// LIR, which will assert in tryToDemote().
|
||||
if (fp->hasArgsObj() && fp->argsObj().isArgsLengthOverridden())
|
||||
if (fp->hasArgsObj() && fp->argsObj().hasOverriddenLength())
|
||||
RETURN_STOP_A("can't trace JSOP_ARGCNT if arguments.length has been modified");
|
||||
LIns *a_ins = getFrameObjPtr(fp->addressOfArgs());
|
||||
if (callDepth == 0) {
|
||||
|
@ -16359,13 +16368,13 @@ TraceRecorder::record_JSOP_LENGTH()
|
|||
|
||||
// We must both check at record time and guard at run time that
|
||||
// arguments.length has not been reassigned, redefined or deleted.
|
||||
if (obj->isArgsLengthOverridden())
|
||||
if (obj->asArguments()->hasOverriddenLength())
|
||||
RETURN_STOP_A("can't trace JSOP_ARGCNT if arguments.length has been modified");
|
||||
LIns* slot_ins = guardArgsLengthNotAssigned(obj_ins);
|
||||
|
||||
// slot_ins is the value from the slot; right-shift to get the length
|
||||
// (see JSObject::getArgsInitialLength in jsfun.cpp).
|
||||
LIns* v_ins = w.i2d(w.rshiN(slot_ins, JSObject::ARGS_PACKED_BITS_COUNT));
|
||||
// slot_ins is the value from the slot; right-shift to get the length;
|
||||
// see ArgumentsObject.h.
|
||||
LIns* v_ins = w.i2d(w.rshiN(slot_ins, ArgumentsObject::PACKED_BITS_COUNT));
|
||||
set(&l, v_ins);
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
|
|
@ -542,7 +542,7 @@ class TypedArrayTemplate
|
|||
}
|
||||
|
||||
vp->setUndefined();
|
||||
if (js_LookupPropertyWithFlags(cx, proto, id, cx->resolveFlags, &obj2, &prop) < 0)
|
||||
if (!LookupPropertyWithFlags(cx, proto, id, cx->resolveFlags, &obj2, &prop))
|
||||
return false;
|
||||
|
||||
if (prop) {
|
||||
|
@ -1709,39 +1709,3 @@ js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg,
|
|||
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
|
||||
return TypedArrayConstruct(cx, atype, argc, &vals[0]);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_ReparentTypedArrayToScope(JSContext *cx, JSObject *obj, JSObject *scope)
|
||||
{
|
||||
JS_ASSERT(obj);
|
||||
|
||||
scope = JS_GetGlobalForObject(cx, scope);
|
||||
if (!scope)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!js_IsTypedArray(obj))
|
||||
return JS_FALSE;
|
||||
|
||||
TypedArray *typedArray = TypedArray::fromJSObject(obj);
|
||||
|
||||
JSObject *buffer = typedArray->bufferJS;
|
||||
JS_ASSERT(js_IsArrayBuffer(buffer));
|
||||
|
||||
JSObject *proto;
|
||||
JSProtoKey key =
|
||||
JSCLASS_CACHED_PROTO_KEY(&TypedArray::slowClasses[typedArray->type]);
|
||||
if (!js_GetClassPrototype(cx, scope, key, &proto))
|
||||
return JS_FALSE;
|
||||
|
||||
obj->setProto(proto);
|
||||
obj->setParent(scope);
|
||||
|
||||
key = JSCLASS_CACHED_PROTO_KEY(&ArrayBuffer::jsclass);
|
||||
if (!js_GetClassPrototype(cx, scope, key, &proto))
|
||||
return JS_FALSE;
|
||||
|
||||
buffer->setProto(proto);
|
||||
buffer->setParent(scope);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
|
|
@ -222,15 +222,6 @@ JS_FRIEND_API(JSObject *)
|
|||
js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg,
|
||||
jsint byteoffset, jsint length);
|
||||
|
||||
/*
|
||||
* Reparent a typed array to a new scope. This should only be used to reparent
|
||||
* a typed array that does not share its underlying ArrayBuffer with another
|
||||
* typed array to avoid having a parent mismatch with the other typed array and
|
||||
* its ArrayBuffer.
|
||||
*/
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_ReparentTypedArrayToScope(JSContext *cx, JSObject *obj, JSObject *scope);
|
||||
|
||||
extern int32 JS_FASTCALL
|
||||
js_TypedArray_uint8_clamp_double(const double x);
|
||||
|
||||
|
|
|
@ -120,6 +120,9 @@ mjit::Compiler::Compiler(JSContext *cx, StackFrame *fp)
|
|||
#endif
|
||||
oomInVector(false),
|
||||
applyTricks(NoApplyTricks)
|
||||
#if defined DEBUG
|
||||
,pcProfile(NULL)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -197,6 +200,15 @@ mjit::Compiler::performCompilation(JITScript **jitp)
|
|||
jumpMap[i] = Label();
|
||||
#endif
|
||||
|
||||
#if defined(JS_METHODJIT_SPEW) && defined(DEBUG)
|
||||
if (IsJaegerSpewChannelActive(JSpew_PCProf)) {
|
||||
pcProfile = (int *)cx->malloc_(sizeof(int) * script->length);
|
||||
if (!pcProfile)
|
||||
return Compile_Error;
|
||||
memset(pcProfile, 0, script->length * sizeof(int));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JS_METHODJIT_SPEW
|
||||
Profiler prof;
|
||||
prof.start();
|
||||
|
@ -219,6 +231,12 @@ mjit::Compiler::performCompilation(JITScript **jitp)
|
|||
CHECK_STATUS(generateEpilogue());
|
||||
CHECK_STATUS(finishThisUp(jitp));
|
||||
|
||||
#if defined(JS_METHODJIT_SPEW) && defined(DEBUG)
|
||||
/* Transfer ownership to JITScript */
|
||||
(*jitp)->pcProfile = pcProfile;
|
||||
pcProfile = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef JS_METHODJIT_SPEW
|
||||
prof.stop();
|
||||
JaegerSpew(JSpew_Prof, "compilation took %d us\n", prof.time_us());
|
||||
|
@ -234,6 +252,10 @@ mjit::Compiler::performCompilation(JITScript **jitp)
|
|||
|
||||
mjit::Compiler::~Compiler()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (pcProfile)
|
||||
cx->free_(pcProfile);
|
||||
#endif
|
||||
cx->free_(jumpMap);
|
||||
cx->free_(savedTraps);
|
||||
}
|
||||
|
@ -879,6 +901,24 @@ mjit::Compiler::generateMethod()
|
|||
JSOp op = JSOp(*PC);
|
||||
int trap = stubs::JSTRAP_NONE;
|
||||
if (op == JSOP_TRAP) {
|
||||
|
||||
#if defined(JS_METHODJIT_SPEW) && defined(DEBUG)
|
||||
if (IsJaegerSpewChannelActive(JSpew_PCProf)) {
|
||||
RegisterID r1 = frame.allocReg();
|
||||
RegisterID r2 = frame.allocReg();
|
||||
|
||||
if (IsJaegerSpewChannelActive(JSpew_PCProf)) {
|
||||
masm.move(ImmPtr(pcProfile), r1);
|
||||
Address pcCounter(r1, sizeof(int) * (PC - script->code));
|
||||
masm.load32(pcCounter, r2);
|
||||
masm.add32(Imm32(1), r2);
|
||||
masm.store32(r2, pcCounter);
|
||||
}
|
||||
|
||||
frame.freeReg(r1);
|
||||
frame.freeReg(r2);
|
||||
}
|
||||
#endif
|
||||
if (!trapper.untrap(PC))
|
||||
return Compile_Error;
|
||||
op = JSOp(*PC);
|
||||
|
|
|
@ -363,6 +363,9 @@ class Compiler : public BaseCompiler
|
|||
bool addTraceHints;
|
||||
bool oomInVector; // True if we have OOM'd appending to a vector.
|
||||
enum { NoApplyTricks, LazyArgsObj } applyTricks;
|
||||
#ifdef DEBUG
|
||||
int *pcProfile;
|
||||
#endif
|
||||
|
||||
Compiler *thisFromCtor() { return this; }
|
||||
|
||||
|
|
|
@ -1560,6 +1560,10 @@ mjit::Compiler::jsop_stricteq(JSOp op)
|
|||
masm.lshiftPtr(Imm32(1), treg);
|
||||
#ifndef JS_CPU_X64
|
||||
static const int ShiftedCanonicalNaNType = 0x7FF80000 << 1;
|
||||
#ifdef JS_CPU_SPARC
|
||||
/* On Sparc the result 0/0 is 0x7FFFFFFF not 0x7FF80000 */
|
||||
masm.and32(Imm32(ShiftedCanonicalNaNType), treg);
|
||||
#endif
|
||||
masm.setPtr(oppositeCond, treg, Imm32(ShiftedCanonicalNaNType), result);
|
||||
#else
|
||||
static const void *ShiftedCanonicalNaNType = (void *)(0x7FF8000000000000 << 1);
|
||||
|
@ -1805,11 +1809,11 @@ mjit::Compiler::jsop_initprop()
|
|||
JSObject *holder;
|
||||
JSProperty *prop = NULL;
|
||||
#ifdef DEBUG
|
||||
int res =
|
||||
bool res =
|
||||
#endif
|
||||
js_LookupPropertyWithFlags(cx, baseobj, ATOM_TO_JSID(atom),
|
||||
JSRESOLVE_QUALIFIED, &holder, &prop);
|
||||
JS_ASSERT(res >= 0 && prop && holder == baseobj);
|
||||
LookupPropertyWithFlags(cx, baseobj, ATOM_TO_JSID(atom),
|
||||
JSRESOLVE_QUALIFIED, &holder, &prop);
|
||||
JS_ASSERT(res && prop && holder == baseobj);
|
||||
|
||||
RegisterID objReg = frame.copyDataIntoReg(obj);
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
|
||||
|
|
|
@ -79,6 +79,7 @@ js::JMCheckLogging()
|
|||
" scripts ???\n"
|
||||
" profile ???\n"
|
||||
#ifdef DEBUG
|
||||
" pcprofile Runtime hit counts of every JS opcode executed\n"
|
||||
" jsops JS opcodes\n"
|
||||
#endif
|
||||
" insns JS opcodes and generated insns\n"
|
||||
|
@ -99,6 +100,8 @@ js::JMCheckLogging()
|
|||
if (strstr(env, "profile"))
|
||||
LoggingBits |= (1 << uint32(JSpew_Prof));
|
||||
#ifdef DEBUG
|
||||
if (strstr(env, "pcprofile"))
|
||||
LoggingBits |= (1 << uint32(JSpew_PCProf));
|
||||
if (strstr(env, "jsops"))
|
||||
LoggingBits |= (1 << uint32(JSpew_JSOps));
|
||||
#endif
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace js {
|
|||
#define JSPEW_CHAN_MAP(_) \
|
||||
_(Abort) \
|
||||
_(Scripts) \
|
||||
_(PCProf) \
|
||||
_(Prof) \
|
||||
_(JSOps) \
|
||||
_(Insns) \
|
||||
|
|
|
@ -681,7 +681,7 @@ mjit::EnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, Value *stackLimi
|
|||
JSBool ok;
|
||||
{
|
||||
AssertCompartmentUnchanged pcc(cx);
|
||||
JSAutoResolveFlags rf(cx, JSRESOLVE_INFER);
|
||||
JSAutoResolveFlags rf(cx, RESOLVE_INFER);
|
||||
ok = JaegerTrampoline(cx, fp, code, stackLimit);
|
||||
}
|
||||
|
||||
|
@ -910,6 +910,12 @@ mjit::ReleaseScriptCode(JSContext *cx, JSScript *script)
|
|||
|
||||
if ((jscr = script->jitNormal)) {
|
||||
cx->runtime->mjitDataSize -= jscr->scriptDataSize();
|
||||
#ifdef DEBUG
|
||||
if (jscr->pcProfile) {
|
||||
cx->free_(jscr->pcProfile);
|
||||
jscr->pcProfile = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
jscr->~JITScript();
|
||||
cx->free_(jscr);
|
||||
|
@ -919,6 +925,12 @@ mjit::ReleaseScriptCode(JSContext *cx, JSScript *script)
|
|||
|
||||
if ((jscr = script->jitCtor)) {
|
||||
cx->runtime->mjitDataSize -= jscr->scriptDataSize();
|
||||
#ifdef DEBUG
|
||||
if (jscr->pcProfile) {
|
||||
cx->free_(jscr->pcProfile);
|
||||
jscr->pcProfile = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
jscr->~JITScript();
|
||||
cx->free_(jscr);
|
||||
|
@ -1016,3 +1028,41 @@ JITScript::nativeToPC(void *returnAddress) const
|
|||
return ic.pc;
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT_SPEW
|
||||
static void
|
||||
DumpProfile(JSContext *cx, JSScript *script, JITScript* jit, bool isCtor)
|
||||
{
|
||||
JS_ASSERT(!cx->runtime->gcRunning);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (IsJaegerSpewChannelActive(JSpew_PCProf) && jit->pcProfile) {
|
||||
// Display hit counts for every JS code line
|
||||
AutoArenaAllocator(&cx->tempPool);
|
||||
Sprinter sprinter;
|
||||
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
|
||||
js_Disassemble(cx, script, true, &sprinter, jit->pcProfile);
|
||||
fprintf(stdout, "--- PC PROFILE %s:%d%s ---\n", script->filename, script->lineno,
|
||||
isCtor ? " (constructor)" : "");
|
||||
fprintf(stdout, "%s\n", sprinter.base);
|
||||
fprintf(stdout, "--- END PC PROFILE %s:%d%s ---\n", script->filename, script->lineno,
|
||||
isCtor ? " (constructor)" : "");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
mjit::DumpAllProfiles(JSContext *cx)
|
||||
{
|
||||
#ifdef JS_METHODJIT_SPEW
|
||||
for (JSScript *script = (JSScript *) JS_LIST_HEAD(&cx->compartment->scripts);
|
||||
script != (JSScript *) &cx->compartment->scripts;
|
||||
script = (JSScript *) JS_NEXT_LINK((JSCList *)script))
|
||||
{
|
||||
if (script->jitCtor)
|
||||
DumpProfile(cx, script, script->jitCtor, true);
|
||||
if (script->jitNormal)
|
||||
DumpProfile(cx, script, script->jitNormal, false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -181,7 +181,11 @@ struct VMFrame
|
|||
StackFrame *fp() { return regs.fp(); }
|
||||
mjit::JITScript *jit() { return fp()->jit(); }
|
||||
|
||||
#if defined(JS_CPU_SPARC)
|
||||
static const size_t offsetOfFp = 31 * sizeof(void *) + FrameRegs::offsetOfFp;
|
||||
#else
|
||||
static const size_t offsetOfFp = 5 * sizeof(void *) + FrameRegs::offsetOfFp;
|
||||
#endif
|
||||
static void staticAssert() {
|
||||
JS_STATIC_ASSERT(offsetOfFp == offsetof(VMFrame, regs) + FrameRegs::offsetOfFp);
|
||||
}
|
||||
|
@ -414,7 +418,10 @@ struct JITScript {
|
|||
void purgePICs();
|
||||
|
||||
size_t scriptDataSize();
|
||||
|
||||
#ifdef DEBUG
|
||||
/* length script->length array of execution counters for every JSOp in the compiled script */
|
||||
int *pcProfile;
|
||||
#endif
|
||||
jsbytecode *nativeToPC(void *returnAddress) const;
|
||||
|
||||
private:
|
||||
|
@ -486,6 +493,9 @@ ResetTraceHint(JSScript *script, jsbytecode *pc, uint16_t index, bool full);
|
|||
uintN
|
||||
GetCallTargetCount(JSScript *script, jsbytecode *pc);
|
||||
|
||||
void
|
||||
DumpAllProfiles(JSContext *cx);
|
||||
|
||||
inline void * bsearch_nmap(NativeMapEntry *nmap, size_t nPairs, size_t bcOff)
|
||||
{
|
||||
size_t lo = 1, hi = nPairs;
|
||||
|
|
|
@ -770,12 +770,12 @@ class GetPropCompiler : public PICStubCompiler
|
|||
Jump notArgs = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass());
|
||||
|
||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
|
||||
masm.load32(Address(pic.objReg, JSObject::JSSLOT_ARGS_LENGTH * sizeof(Value)),
|
||||
masm.load32(Address(pic.objReg, ArgumentsObject::INITIAL_LENGTH_SLOT * sizeof(Value)),
|
||||
pic.objReg);
|
||||
masm.move(pic.objReg, pic.shapeReg);
|
||||
Jump overridden = masm.branchTest32(Assembler::NonZero, pic.shapeReg,
|
||||
Imm32(JSObject::ARGS_LENGTH_OVERRIDDEN_BIT));
|
||||
masm.rshift32(Imm32(JSObject::ARGS_PACKED_BITS_COUNT), pic.objReg);
|
||||
Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT));
|
||||
masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), pic.objReg);
|
||||
|
||||
masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg);
|
||||
Jump done = masm.jump();
|
||||
|
@ -1648,7 +1648,8 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
|
|||
return;
|
||||
} else if (!f.regs.sp[-1].isPrimitive()) {
|
||||
JSObject *obj = &f.regs.sp[-1].toObject();
|
||||
if (obj->isArray() || (obj->isArguments() && !obj->isArgsLengthOverridden()) ||
|
||||
if (obj->isArray() ||
|
||||
(obj->isArguments() && !obj->asArguments()->hasOverriddenLength()) ||
|
||||
obj->isString()) {
|
||||
GetPropCompiler cc(f, script, obj, *pic, NULL, DisabledLengthIC);
|
||||
if (obj->isArray()) {
|
||||
|
@ -1660,7 +1661,7 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
|
|||
LookupStatus status = cc.generateArgsLengthStub();
|
||||
if (status == Lookup_Error)
|
||||
THROW();
|
||||
f.regs.sp[-1].setInt32(int32_t(obj->getArgsInitialLength()));
|
||||
f.regs.sp[-1].setInt32(int32_t(obj->asArguments()->initialLength()));
|
||||
} else if (obj->isString()) {
|
||||
LookupStatus status = cc.generateStringObjLengthStub();
|
||||
if (status == Lookup_Error)
|
||||
|
|
|
@ -252,11 +252,11 @@ stubs::SetName(VMFrame &f, JSAtom *origAtom)
|
|||
uintN defineHow;
|
||||
JSOp op = JSOp(*f.regs.pc);
|
||||
if (op == JSOP_SETMETHOD)
|
||||
defineHow = JSDNP_CACHE_RESULT | JSDNP_SET_METHOD;
|
||||
defineHow = DNP_CACHE_RESULT | DNP_SET_METHOD;
|
||||
else if (op == JSOP_SETNAME)
|
||||
defineHow = JSDNP_CACHE_RESULT | JSDNP_UNQUALIFIED;
|
||||
defineHow = DNP_CACHE_RESULT | DNP_UNQUALIFIED;
|
||||
else
|
||||
defineHow = JSDNP_CACHE_RESULT;
|
||||
defineHow = DNP_CACHE_RESULT;
|
||||
if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rval, strict))
|
||||
THROW();
|
||||
} else {
|
||||
|
@ -447,11 +447,12 @@ stubs::GetElem(VMFrame &f)
|
|||
}
|
||||
} else if (obj->isArguments()) {
|
||||
uint32 arg = uint32(i);
|
||||
ArgumentsObject *argsobj = obj->asArguments();
|
||||
|
||||
if (arg < obj->getArgsInitialLength()) {
|
||||
copyFrom = obj->addressOfArgsElement(arg);
|
||||
if (arg < argsobj->initialLength()) {
|
||||
copyFrom = argsobj->addressOfElement(arg);
|
||||
if (!copyFrom->isMagic()) {
|
||||
if (StackFrame *afp = (StackFrame *) obj->getPrivate())
|
||||
if (StackFrame *afp = (StackFrame *) argsobj->getPrivate())
|
||||
copyFrom = &afp->canonicalActualArg(arg);
|
||||
goto end_getelem;
|
||||
}
|
||||
|
@ -2011,17 +2012,24 @@ stubs::Length(VMFrame &f)
|
|||
if (vp->isString()) {
|
||||
vp->setInt32(vp->toString()->length());
|
||||
return;
|
||||
} else if (vp->isObject()) {
|
||||
}
|
||||
|
||||
if (vp->isObject()) {
|
||||
JSObject *obj = &vp->toObject();
|
||||
if (obj->isArray()) {
|
||||
jsuint length = obj->getArrayLength();
|
||||
regs.sp[-1].setNumber(length);
|
||||
return;
|
||||
} else if (obj->isArguments() && !obj->isArgsLengthOverridden()) {
|
||||
uint32 length = obj->getArgsInitialLength();
|
||||
JS_ASSERT(length < INT32_MAX);
|
||||
regs.sp[-1].setInt32(int32_t(length));
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj->isArguments()) {
|
||||
ArgumentsObject *argsobj = obj->asArguments();
|
||||
if (!argsobj->hasOverriddenLength()) {
|
||||
uint32 length = argsobj->initialLength();
|
||||
JS_ASSERT(length < INT32_MAX);
|
||||
regs.sp[-1].setInt32(int32_t(length));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2101,13 +2109,12 @@ InitPropOrMethod(VMFrame &f, JSAtom *atom, JSOp op)
|
|||
jsid id = ATOM_TO_JSID(atom);
|
||||
|
||||
uintN defineHow = (op == JSOP_INITMETHOD)
|
||||
? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD
|
||||
: JSDNP_CACHE_RESULT;
|
||||
if (!(JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
|
||||
? js_SetPropertyHelper(cx, obj, id, defineHow, &rval, false)
|
||||
: js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
|
||||
JSPROP_ENUMERATE, 0, 0, NULL,
|
||||
defineHow))) {
|
||||
? DNP_CACHE_RESULT | DNP_SET_METHOD
|
||||
: DNP_CACHE_RESULT;
|
||||
if (JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
|
||||
? !js_SetPropertyHelper(cx, obj, id, defineHow, &rval, false)
|
||||
: !DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
|
||||
JSPROP_ENUMERATE, 0, 0, defineHow)) {
|
||||
THROW();
|
||||
}
|
||||
}
|
||||
|
@ -2588,8 +2595,8 @@ stubs::DefVarOrConst(VMFrame &f, JSAtom *atom)
|
|||
|
||||
/* Bind a variable only if it's not yet defined. */
|
||||
if (shouldDefine &&
|
||||
!js_DefineNativeProperty(cx, obj, id, UndefinedValue(), PropertyStub, StrictPropertyStub,
|
||||
attrs, 0, 0, NULL)) {
|
||||
!DefineNativeProperty(cx, obj, id, UndefinedValue(), PropertyStub, StrictPropertyStub,
|
||||
attrs, 0, 0)) {
|
||||
THROW();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@
|
|||
#include "jsinterpinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
#include "methodjit/MethodJIT.h"
|
||||
|
||||
#ifdef XP_UNIX
|
||||
#include <unistd.h>
|
||||
|
@ -1505,7 +1506,6 @@ GCParameter(JSContext *cx, uintN argc, jsval *vp)
|
|||
{"gcStackpoolLifespan", JSGC_STACKPOOL_LIFESPAN},
|
||||
{"gcBytes", JSGC_BYTES},
|
||||
{"gcNumber", JSGC_NUMBER},
|
||||
{"gcTriggerFactor", JSGC_TRIGGER_FACTOR},
|
||||
};
|
||||
|
||||
JSString *str;
|
||||
|
@ -1528,8 +1528,8 @@ GCParameter(JSContext *cx, uintN argc, jsval *vp)
|
|||
if (paramIndex == JS_ARRAY_LENGTH(paramMap)) {
|
||||
JS_ReportError(cx,
|
||||
"the first argument argument must be maxBytes, "
|
||||
"maxMallocBytes, gcStackpoolLifespan, gcBytes, "
|
||||
"gcNumber or gcTriggerFactor");
|
||||
"maxMallocBytes, gcStackpoolLifespan, gcBytes or "
|
||||
"gcNumber");
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (JS_FlatStringEqualsAscii(flatStr, paramMap[paramIndex].name))
|
||||
|
@ -1556,11 +1556,6 @@ GCParameter(JSContext *cx, uintN argc, jsval *vp)
|
|||
"with non-zero value");
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (param == JSGC_TRIGGER_FACTOR && value < 100) {
|
||||
JS_ReportError(cx,
|
||||
"the gcTriggerFactor value must be >= 100");
|
||||
return JS_FALSE;
|
||||
}
|
||||
JS_SetGCParameter(cx->runtime, param, value);
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
|
@ -3726,7 +3721,7 @@ CopyProperty(JSContext *cx, JSObject *obj, JSObject *referent, jsid id,
|
|||
|
||||
*objp = NULL;
|
||||
if (referent->isNative()) {
|
||||
if (js_LookupPropertyWithFlags(cx, referent, id, lookupFlags, &obj2, &prop) < 0)
|
||||
if (!LookupPropertyWithFlags(cx, referent, id, lookupFlags, &obj2, &prop))
|
||||
return false;
|
||||
if (obj2 != referent)
|
||||
return true;
|
||||
|
@ -3773,9 +3768,8 @@ CopyProperty(JSContext *cx, JSObject *obj, JSObject *referent, jsid id,
|
|||
}
|
||||
|
||||
*objp = obj;
|
||||
return js_DefineNativeProperty(cx, obj, id, desc.value,
|
||||
desc.getter, desc.setter, desc.attrs, propFlags,
|
||||
desc.shortid, &prop);
|
||||
return !!DefineNativeProperty(cx, obj, id, desc.value, desc.getter, desc.setter,
|
||||
desc.attrs, propFlags, desc.shortid);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -5940,6 +5934,10 @@ Shell(JSContext *cx, int argc, char **argv, char **envp)
|
|||
}
|
||||
#endif /* JSDEBUGGER */
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
mjit::DumpAllProfiles(cx);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,6 @@ script regress-352789.js
|
|||
script regress-355101.js
|
||||
script regress-355474-01.js
|
||||
skip script regress-373678.js # obsolete test
|
||||
skip script regress-429249.js
|
||||
require-or(debugMode,skip) script regress-429249.js
|
||||
script regress-461233.js
|
||||
script regress-463360.js
|
||||
|
|
|
@ -32,4 +32,4 @@ script 15.8-1.js
|
|||
script 15.9.5.js
|
||||
script 8.6.2.1-1.js
|
||||
script 9.9-1.js
|
||||
skip script trapflatclosure.js
|
||||
require-or(debugMode,skip) script trapflatclosure.js
|
||||
|
|
|
@ -11,5 +11,5 @@ script regress-320854.js
|
|||
script regress-327170.js
|
||||
script regress-368516.js
|
||||
script regress-385393-03.js
|
||||
skip script regress-429248.js
|
||||
require-or(debugMode,skip) script regress-429248.js
|
||||
script regress-430740.js
|
||||
|
|
|
@ -6,6 +6,7 @@ script parse-arguments.js
|
|||
script parse-crockford-01.js
|
||||
script parse-primitives.js
|
||||
script parse-reviver.js
|
||||
script parse-reviver-array-delete.js
|
||||
script parse-syntax-errors-01.js
|
||||
script parse-syntax-errors-02.js
|
||||
script stringify.js
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
var gTestfile = 'parse-reviver-array-delete.js';
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 999999;
|
||||
var summary = "JSON.parse with a reviver which elides array elements";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
/*
|
||||
* The reviver deletes all properties from the to-be-returned array. Thus
|
||||
* stringification reveals properties on the prototype chain -- but there are
|
||||
* none, so this result is unsurprising.
|
||||
*/
|
||||
assertEq(JSON.parse('[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]',
|
||||
function revive(k, v)
|
||||
{
|
||||
if (k === "")
|
||||
return v;
|
||||
return undefined;
|
||||
}) + "",
|
||||
",,,,,,,,,,,,,,,,,,,");
|
||||
|
||||
/*
|
||||
* Now let's try a reviver that deletes every property but a mega-huge one.
|
||||
*/
|
||||
var str = "[";
|
||||
var expected = "";
|
||||
var expected2 = "";
|
||||
for (var i = 0; i < 2048; i++)
|
||||
{
|
||||
str += "1,";
|
||||
if (i === 2047)
|
||||
{
|
||||
expected += "1";
|
||||
expected2 += "1";
|
||||
}
|
||||
if (i === 3)
|
||||
expected2 += "17";
|
||||
expected += ",";
|
||||
expected2 += ",";
|
||||
}
|
||||
str += "1]";
|
||||
|
||||
assertEq(JSON.parse(str,
|
||||
function reviver(k, v)
|
||||
{
|
||||
if (k === "" || k === "2047")
|
||||
return v;
|
||||
return undefined;
|
||||
}) + "",
|
||||
expected);
|
||||
|
||||
|
||||
Array.prototype[3] = 17;
|
||||
|
||||
/* Now, with a property on the prototype chain, it'll show through. */
|
||||
assertEq(JSON.parse('[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]',
|
||||
function revive(k, v)
|
||||
{
|
||||
if (k === "")
|
||||
return v;
|
||||
return undefined;
|
||||
}) + "",
|
||||
",,,17,,,,,,,,,,,,,,,,");
|
||||
|
||||
|
||||
/* And here too. */
|
||||
assertEq(JSON.parse(str,
|
||||
function reviver(k, v)
|
||||
{
|
||||
if (k === "" || k === "2047")
|
||||
return v;
|
||||
return undefined;
|
||||
}) + "",
|
||||
expected2);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
|
@ -44,3 +44,4 @@ skip-if(!xulRuntime.shell) script freeze-global-eval-const.js # uses evalcx
|
|||
script preventExtensions-idempotent.js
|
||||
script isPrototypeOf.js
|
||||
script propertyIsEnumerable.js
|
||||
script toLocaleString.js
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var gTestfile = 'toLocaleString.js';
|
||||
var BUGNUMBER = 653789;
|
||||
var summary = "Object.prototype.toLocaleString";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
function expectThrowTypeError(fun)
|
||||
{
|
||||
try
|
||||
{
|
||||
var r = fun();
|
||||
throw "didn't throw TypeError, returned " + r;
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"didn't throw TypeError, got: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
var toLocaleString = Object.prototype.toLocaleString;
|
||||
|
||||
/*
|
||||
* 1. Let O be the result of calling ToObject passing the this value as the
|
||||
* argument.
|
||||
*/
|
||||
expectThrowTypeError(function() { toLocaleString.call(null); });
|
||||
expectThrowTypeError(function() { toLocaleString.call(undefined); });
|
||||
expectThrowTypeError(function() { toLocaleString.apply(null); });
|
||||
expectThrowTypeError(function() { toLocaleString.apply(undefined); });
|
||||
|
||||
|
||||
/*
|
||||
* 2. Let toString be the result of calling the [[Get]] internal method of O
|
||||
* passing "toString" as the argument.
|
||||
*/
|
||||
try
|
||||
{
|
||||
toLocaleString.call({ get toString() { throw 17; } });
|
||||
throw new Error("didn't throw");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e, 17);
|
||||
}
|
||||
|
||||
|
||||
/* 3. If IsCallable(toString) is false, throw a TypeError exception. */
|
||||
expectThrowTypeError(function() { toLocaleString.call({ toString: 12 }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ toString: 0.3423423452352e9 }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ toString: undefined }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ toString: false }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ toString: [] }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ toString: {} }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ toString: new String }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ toString: new Number(7.7) }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ toString: new Boolean(true) }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ toString: JSON }); });
|
||||
|
||||
expectThrowTypeError(function() { toLocaleString.call({ valueOf: 0, toString: 12 }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ valueOf: 0, toString: 0.3423423452352e9 }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ valueOf: 0, toString: undefined }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ valueOf: 0, toString: false }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ valueOf: 0, toString: [] }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ valueOf: 0, toString: {} }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ valueOf: 0, toString: new String }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ valueOf: 0, toString: new Number(7.7) }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ valueOf: 0, toString: new Boolean(true) }); });
|
||||
expectThrowTypeError(function() { toLocaleString.call({ valueOf: 0, toString: JSON }); });
|
||||
|
||||
|
||||
/*
|
||||
* 4. Return the result of calling the [[Call]] internal method of toString
|
||||
* passing O as the this value and no arguments.
|
||||
*/
|
||||
assertEq(toLocaleString.call({ get toString() { return function() { return "foo"; } } }),
|
||||
"foo");
|
||||
|
||||
var obj = { toString: function() { assertEq(this, obj); assertEq(arguments.length, 0); return 5; } };
|
||||
assertEq(toLocaleString.call(obj), 5);
|
||||
|
||||
assertEq(toLocaleString.call({ toString: function() { return obj; } }), obj);
|
||||
|
||||
assertEq(toLocaleString.call({ toString: function() { return obj; },
|
||||
valueOf: function() { return "abc"; } }),
|
||||
obj);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
|
@ -24,6 +24,7 @@ script regress-bug629723.js
|
|||
script strict-function-statements.js
|
||||
script strict-option-redeclared-parameter.js
|
||||
script string-literal-getter-setter-decompilation.js
|
||||
script toLocaleString-infinite-recursion.js
|
||||
script toSource-infinite-recursion.js
|
||||
script uneval-strict-functions.js
|
||||
script watch-array-length.js
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 653789;
|
||||
var summary = 'Check for too-deep stack when calling toLocaleString';
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
try
|
||||
{
|
||||
"" + { toString: Object.prototype.toLocaleString };
|
||||
throw new Error("should have thrown on over-recursion");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof InternalError, true);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("All tests passed!");
|
|
@ -164,16 +164,16 @@ skip script regress-418730.js # obsolete test
|
|||
script regress-420612.js
|
||||
script regress-420869-01.js
|
||||
skip script regress-421621.js # obsolete test
|
||||
skip script regress-422137.js
|
||||
require-or(debugMode,skip) script regress-422137.js
|
||||
script regress-422592.js
|
||||
script regress-424683-01.js
|
||||
script regress-426711.js
|
||||
script regress-427196-01.js
|
||||
script regress-427196-02.js
|
||||
script regress-427196-03.js
|
||||
skip script regress-429264.js
|
||||
require-or(debugMode,skip) script regress-429264.js
|
||||
script regress-429739.js
|
||||
skip script regress-431428.js
|
||||
require-or(debugMode,skip) script regress-431428.js
|
||||
skip script regress-432075.js # obsolete test
|
||||
script regress-434837-01.js
|
||||
fails script regress-435345-01.js
|
||||
|
|
|
@ -46,4 +46,4 @@ script regress-379925.js
|
|||
script regress-380506.js
|
||||
script regress-410571.js
|
||||
script regress-410649.js
|
||||
skip script regress-429252.js
|
||||
require-or(debugMode,skip) script regress-429252.js
|
||||
|
|
|
@ -358,6 +358,7 @@ if __name__ == '__main__':
|
|||
call(cmd)
|
||||
sys.exit()
|
||||
|
||||
results = None
|
||||
if not test_list:
|
||||
print 'no tests selected'
|
||||
else:
|
||||
|
@ -374,5 +375,5 @@ if __name__ == '__main__':
|
|||
if output_file != sys.stdout:
|
||||
output_file.close()
|
||||
|
||||
if not results.all_passed():
|
||||
if results is None or not results.all_passed():
|
||||
sys.exit(1)
|
||||
|
|
|
@ -15,6 +15,7 @@ def split_path_into_dirs(path):
|
|||
path, tail = os.path.split(path)
|
||||
if not tail:
|
||||
break
|
||||
dirs.append(path)
|
||||
return dirs
|
||||
|
||||
class XULInfo:
|
||||
|
@ -130,6 +131,7 @@ def parse(filename, xul_tester, reldir = ''):
|
|||
expect = True
|
||||
random = False
|
||||
slow = False
|
||||
debugMode = False
|
||||
|
||||
pos = 0
|
||||
while pos < len(parts):
|
||||
|
@ -161,6 +163,25 @@ def parse(filename, xul_tester, reldir = ''):
|
|||
if xul_tester.test(cond):
|
||||
random = True
|
||||
pos += 1
|
||||
elif parts[pos].startswith('require-or'):
|
||||
cond = parts[pos][len('require-or('):-1]
|
||||
(preconditions, fallback_action) = re.split(",", cond)
|
||||
for precondition in re.split("&&", preconditions):
|
||||
if precondition == 'debugMode':
|
||||
debugMode = True
|
||||
elif precondition == 'true':
|
||||
pass
|
||||
else:
|
||||
if fallback_action == "skip":
|
||||
expect = enable = False
|
||||
elif fallback_action == "fail":
|
||||
expect = False
|
||||
elif fallback_action == "random":
|
||||
random = True
|
||||
else:
|
||||
raise Exception("Invalid precondition '%s' or fallback action '%s'" % (precondition, fallback_action))
|
||||
break
|
||||
pos += 1
|
||||
elif parts[pos] == 'script':
|
||||
script = parts[pos+1]
|
||||
pos += 2
|
||||
|
@ -177,6 +198,6 @@ def parse(filename, xul_tester, reldir = ''):
|
|||
pos += 1
|
||||
|
||||
assert script is not None
|
||||
ans.append(TestCase(os.path.join(reldir, script),
|
||||
enable, expect, random, slow))
|
||||
ans.append(TestCase(os.path.join(reldir, script),
|
||||
enable, expect, random, slow, debugMode))
|
||||
return ans
|
||||
|
|
|
@ -76,8 +76,12 @@ class Test(object):
|
|||
|
||||
def get_command(self, js_cmd_prefix):
|
||||
dir, filename = os.path.split(self.path)
|
||||
cmd = js_cmd_prefix + Test.prefix_command(dir)
|
||||
if self.debugMode:
|
||||
cmd += [ '-d' ]
|
||||
# There is a test that requires the path to start with './'.
|
||||
return js_cmd_prefix + Test.prefix_command(dir) + [ '-f', './' + self.path ]
|
||||
cmd += [ '-f', './' + self.path ]
|
||||
return cmd
|
||||
|
||||
def run(self, js_cmd_prefix, timeout=30.0):
|
||||
cmd = self.get_command(js_cmd_prefix)
|
||||
|
@ -87,12 +91,13 @@ class Test(object):
|
|||
class TestCase(Test):
|
||||
"""A test case consisting of a test and an expected result."""
|
||||
|
||||
def __init__(self, path, enable, expect, random, slow):
|
||||
def __init__(self, path, enable, expect, random, slow, debugMode):
|
||||
Test.__init__(self, path)
|
||||
self.enable = enable # bool: True => run test, False => don't run
|
||||
self.expect = expect # bool: expected result, True => pass
|
||||
self.random = random # bool: True => ignore output as 'random'
|
||||
self.slow = slow # bool: True => test may run slowly
|
||||
self.debugMode = debugMode # bool: True => must be run in debug mode
|
||||
|
||||
def __str__(self):
|
||||
ans = self.path
|
||||
|
@ -104,6 +109,8 @@ class TestCase(Test):
|
|||
ans += ', random'
|
||||
if self.slow:
|
||||
ans += ', slow'
|
||||
if self.debugMode:
|
||||
ans += ', debugMode'
|
||||
return ans
|
||||
|
||||
class TestOutput:
|
||||
|
|
|
@ -39,10 +39,13 @@
|
|||
|
||||
#include "jsprf.h"
|
||||
#include "jstl.h"
|
||||
|
||||
#include "jscompartment.h"
|
||||
#include "Writer.h"
|
||||
#include "nanojit.h"
|
||||
|
||||
#include "vm/ArgumentsObject.h"
|
||||
|
||||
namespace js {
|
||||
namespace tjit {
|
||||
|
||||
|
@ -544,9 +547,9 @@ void ValidateWriter::checkAccSet(LOpcode op, LIns *base, int32_t disp, AccSet ac
|
|||
// base_oprnd1 = <const private ptr slots[JSSLOT_ARGS_DATA]>
|
||||
// base = addp base_oprnd1, ...
|
||||
// ins = {ld,st}X.argsdata base[...]
|
||||
ok = (isConstPrivatePtr(base, JSObject::JSSLOT_ARGS_DATA) ||
|
||||
ok = (isConstPrivatePtr(base, ArgumentsObject::DATA_SLOT) ||
|
||||
(base->isop(LIR_addp) &&
|
||||
isConstPrivatePtr(base->oprnd1(), JSObject::JSSLOT_ARGS_DATA)));
|
||||
isConstPrivatePtr(base->oprnd1(), ArgumentsObject::DATA_SLOT)));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -565,7 +568,7 @@ void ValidateWriter::checkAccSet(LOpcode op, LIns *base, int32_t disp, AccSet ac
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace nanojit
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#define tracejit_Writer_h___
|
||||
|
||||
#include "jsiter.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsstr.h"
|
||||
#include "jstypedarray.h"
|
||||
#include "nanojit.h"
|
||||
|
@ -1217,13 +1216,7 @@ class Writer
|
|||
"strChar");
|
||||
}
|
||||
|
||||
nj::LIns *getArgsLength(nj::LIns *args) const {
|
||||
uint32 slot = JSObject::JSSLOT_ARGS_LENGTH;
|
||||
nj::LIns *vaddr_ins = ldpObjSlots(args);
|
||||
return name(lir->insLoad(nj::LIR_ldi, vaddr_ins, slot * sizeof(Value) + sPayloadOffset,
|
||||
ACCSET_SLOTS),
|
||||
"argsLength");
|
||||
}
|
||||
inline nj::LIns *getArgsLength(nj::LIns *args) const;
|
||||
};
|
||||
|
||||
} /* namespace tjit */
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is SpiderMonkey arguments object code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jeff Walden <jwalden+code@mit.edu> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef ArgumentsObject_inl_h___
|
||||
#define ArgumentsObject_inl_h___
|
||||
|
||||
#include "ArgumentsObject.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
inline void
|
||||
ArgumentsObject::setInitialLength(uint32 length)
|
||||
{
|
||||
JS_ASSERT(getSlot(INITIAL_LENGTH_SLOT).isUndefined());
|
||||
setSlot(INITIAL_LENGTH_SLOT, Int32Value(length << PACKED_BITS_COUNT));
|
||||
JS_ASSERT((getSlot(INITIAL_LENGTH_SLOT).toInt32() >> PACKED_BITS_COUNT) == int32(length));
|
||||
JS_ASSERT(!hasOverriddenLength());
|
||||
}
|
||||
|
||||
inline uint32
|
||||
ArgumentsObject::initialLength() const
|
||||
{
|
||||
uint32 argc = uint32(getSlot(INITIAL_LENGTH_SLOT).toInt32()) >> PACKED_BITS_COUNT;
|
||||
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||
return argc;
|
||||
}
|
||||
|
||||
inline void
|
||||
ArgumentsObject::markLengthOverridden()
|
||||
{
|
||||
getSlotRef(INITIAL_LENGTH_SLOT).getInt32Ref() |= LENGTH_OVERRIDDEN_BIT;
|
||||
}
|
||||
|
||||
inline bool
|
||||
ArgumentsObject::hasOverriddenLength() const
|
||||
{
|
||||
const js::Value &v = getSlot(INITIAL_LENGTH_SLOT);
|
||||
return v.toInt32() & LENGTH_OVERRIDDEN_BIT;
|
||||
}
|
||||
|
||||
inline void
|
||||
ArgumentsObject::setCalleeAndData(JSObject &callee, ArgumentsData *data)
|
||||
{
|
||||
JS_ASSERT(getSlot(DATA_SLOT).isUndefined());
|
||||
setSlot(DATA_SLOT, PrivateValue(data));
|
||||
data->callee.setObject(callee);
|
||||
}
|
||||
|
||||
inline ArgumentsData *
|
||||
ArgumentsObject::data() const
|
||||
{
|
||||
return reinterpret_cast<js::ArgumentsData *>(getSlot(DATA_SLOT).toPrivate());
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
ArgumentsObject::element(uint32 i) const
|
||||
{
|
||||
JS_ASSERT(i < initialLength());
|
||||
return data()->slots[i];
|
||||
}
|
||||
|
||||
inline js::Value *
|
||||
ArgumentsObject::elements() const
|
||||
{
|
||||
return data()->slots;
|
||||
}
|
||||
|
||||
inline Value *
|
||||
ArgumentsObject::addressOfElement(uint32 i)
|
||||
{
|
||||
JS_ASSERT(i < initialLength());
|
||||
return &data()->slots[i];
|
||||
}
|
||||
|
||||
inline void
|
||||
ArgumentsObject::setElement(uint32 i, const js::Value &v)
|
||||
{
|
||||
JS_ASSERT(i < initialLength());
|
||||
data()->slots[i] = v;
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
NormalArgumentsObject::callee() const
|
||||
{
|
||||
return data()->callee;
|
||||
}
|
||||
|
||||
inline void
|
||||
NormalArgumentsObject::clearCallee()
|
||||
{
|
||||
data()->callee = MagicValue(JS_ARGS_HOLE);
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* ArgumentsObject_inl_h___ */
|
|
@ -0,0 +1,255 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is SpiderMonkey arguments object code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jeff Walden <jwalden+code@mit.edu> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef ArgumentsObject_h___
|
||||
#define ArgumentsObject_h___
|
||||
|
||||
#include "jsfun.h"
|
||||
|
||||
#ifdef JS_POLYIC
|
||||
class GetPropCompiler;
|
||||
#endif
|
||||
|
||||
#define JS_ARGUMENTS_OBJECT_ON_TRACE ((void *)0xa126)
|
||||
|
||||
#ifdef JS_TRACER
|
||||
namespace nanojit {
|
||||
class ValidateWriter;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
||||
#ifdef JS_POLYIC
|
||||
struct VMFrame;
|
||||
namespace mjit {
|
||||
namespace ic {
|
||||
struct PICInfo;
|
||||
|
||||
/* Aargh, Windows. */
|
||||
#ifdef GetProp
|
||||
#undef GetProp
|
||||
#endif
|
||||
void JS_FASTCALL GetProp(VMFrame &f, ic::PICInfo *pic);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JS_TRACER
|
||||
namespace tjit {
|
||||
class Writer;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct EmptyShape;
|
||||
|
||||
struct ArgumentsData
|
||||
{
|
||||
/*
|
||||
* arguments.callee, or MagicValue(JS_ARGS_HOLE) if arguments.callee has
|
||||
* been modified.
|
||||
*/
|
||||
js::Value callee;
|
||||
|
||||
/*
|
||||
* Values of the arguments for this object, or MagicValue(JS_ARGS_HOLE) if
|
||||
* the indexed argument has been modified.
|
||||
*/
|
||||
js::Value slots[1];
|
||||
};
|
||||
|
||||
class ArgumentsObject : public ::JSObject
|
||||
{
|
||||
/*
|
||||
* Stores the initial arguments length, plus a flag indicating whether
|
||||
* arguments.length has been overwritten. Use initialLength() to access the
|
||||
* initial arguments length.
|
||||
*/
|
||||
static const uint32 INITIAL_LENGTH_SLOT = 0;
|
||||
|
||||
/* Stores an ArgumentsData for these arguments; access with data(). */
|
||||
static const uint32 DATA_SLOT = 1;
|
||||
|
||||
protected:
|
||||
static const uint32 RESERVED_SLOTS = 2;
|
||||
|
||||
private:
|
||||
/* Lower-order bit stolen from the length slot. */
|
||||
static const uint32 LENGTH_OVERRIDDEN_BIT = 0x1;
|
||||
static const uint32 PACKED_BITS_COUNT = 1;
|
||||
|
||||
#ifdef JS_TRACER
|
||||
/*
|
||||
* Needs access to INITIAL_LENGTH_SLOT -- technically just getArgsLength,
|
||||
* but nanojit's including windows.h makes that difficult.
|
||||
*/
|
||||
friend class tjit::Writer;
|
||||
|
||||
/*
|
||||
* Needs access to DATA_SLOT -- technically just checkAccSet needs it, but
|
||||
* that's private, and exposing turns into a mess.
|
||||
*/
|
||||
friend class ::nanojit::ValidateWriter;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Need access to DATA_SLOT, INITIAL_LENGTH_SLOT, LENGTH_OVERRIDDEN_BIT, and
|
||||
* PACKED_BIT_COUNT.
|
||||
*/
|
||||
#ifdef JS_TRACER
|
||||
friend class TraceRecorder;
|
||||
#endif
|
||||
#ifdef JS_POLYIC
|
||||
friend class ::GetPropCompiler;
|
||||
#endif
|
||||
|
||||
void setInitialLength(uint32 length);
|
||||
|
||||
void setCalleeAndData(JSObject &callee, ArgumentsData *data);
|
||||
|
||||
public:
|
||||
/*
|
||||
* Create arguments parented to parent, for the given callee function.
|
||||
* Is parent redundant with callee->getGlobal()?
|
||||
*/
|
||||
static ArgumentsObject *create(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee);
|
||||
|
||||
/*
|
||||
* Return the initial length of the arguments. This may differ from the
|
||||
* current value of arguments.length!
|
||||
*/
|
||||
inline uint32 initialLength() const;
|
||||
|
||||
/* True iff arguments.length has been assigned or its attributes changed. */
|
||||
inline bool hasOverriddenLength() const;
|
||||
inline void markLengthOverridden();
|
||||
|
||||
inline js::ArgumentsData *data() const;
|
||||
|
||||
inline const js::Value &element(uint32 i) const;
|
||||
inline js::Value *elements() const;
|
||||
inline js::Value *addressOfElement(uint32 i);
|
||||
inline void setElement(uint32 i, const js::Value &v);
|
||||
};
|
||||
|
||||
/*
|
||||
* Non-strict arguments have a private: the function's stack frame until the
|
||||
* function returns, when it is replaced with null. When an arguments object
|
||||
* is created on-trace its private is JS_ARGUMENTS_OBJECT_ON_TRACE, and when
|
||||
* the trace exits its private is replaced with the stack frame or null, as
|
||||
* appropriate.
|
||||
*/
|
||||
class NormalArgumentsObject : public ArgumentsObject
|
||||
{
|
||||
static js::Class jsClass;
|
||||
|
||||
friend bool JSObject::isNormalArguments() const;
|
||||
friend struct EmptyShape; // for EmptyShape::getEmptyArgumentsShape
|
||||
friend ArgumentsObject *
|
||||
ArgumentsObject::create(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee);
|
||||
|
||||
public:
|
||||
/*
|
||||
* Stores arguments.callee, or MagicValue(JS_ARGS_HOLE) if the callee has
|
||||
* been cleared.
|
||||
*/
|
||||
inline const js::Value &callee() const;
|
||||
|
||||
/* Clear the location storing arguments.callee's initial value. */
|
||||
inline void clearCallee();
|
||||
};
|
||||
|
||||
/*
|
||||
* Technically strict arguments have a private, but it's always null.
|
||||
* Conceptually it would be better to remove this oddity, but preserving it
|
||||
* allows us to work with arguments objects of either kind more abstractly,
|
||||
* so we keep it for now.
|
||||
*/
|
||||
class StrictArgumentsObject : public ArgumentsObject
|
||||
{
|
||||
static js::Class jsClass;
|
||||
|
||||
friend bool JSObject::isStrictArguments() const;
|
||||
friend ArgumentsObject *
|
||||
ArgumentsObject::create(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee);
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
inline bool
|
||||
JSObject::isNormalArguments() const
|
||||
{
|
||||
return getClass() == &js::NormalArgumentsObject::jsClass;
|
||||
}
|
||||
|
||||
js::NormalArgumentsObject *
|
||||
JSObject::asNormalArguments()
|
||||
{
|
||||
JS_ASSERT(isNormalArguments());
|
||||
return reinterpret_cast<js::NormalArgumentsObject *>(this);
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isStrictArguments() const
|
||||
{
|
||||
return getClass() == &js::StrictArgumentsObject::jsClass;
|
||||
}
|
||||
|
||||
js::StrictArgumentsObject *
|
||||
JSObject::asStrictArguments()
|
||||
{
|
||||
JS_ASSERT(isStrictArguments());
|
||||
return reinterpret_cast<js::StrictArgumentsObject *>(this);
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isArguments() const
|
||||
{
|
||||
return isNormalArguments() || isStrictArguments();
|
||||
}
|
||||
|
||||
js::ArgumentsObject *
|
||||
JSObject::asArguments()
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
return reinterpret_cast<js::ArgumentsObject *>(this);
|
||||
}
|
||||
|
||||
#endif /* ArgumentsObject_h___ */
|
|
@ -43,6 +43,8 @@
|
|||
|
||||
#include "Stack.h"
|
||||
|
||||
#include "ArgumentsObject-inl.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -494,12 +496,11 @@ StackFrame::stealFrameAndSlots(Value *vp, StackFrame *otherfp,
|
|||
}
|
||||
}
|
||||
if (hasArgsObj()) {
|
||||
JSObject &args = argsObj();
|
||||
JS_ASSERT(args.isArguments());
|
||||
if (args.isNormalArguments())
|
||||
args.setPrivate(this);
|
||||
ArgumentsObject &argsobj = argsObj();
|
||||
if (argsobj.isNormalArguments())
|
||||
argsobj.setPrivate(this);
|
||||
else
|
||||
JS_ASSERT(!args.getPrivate());
|
||||
JS_ASSERT(!argsobj.getPrivate());
|
||||
otherfp->flags_ &= ~HAS_ARGS_OBJ;
|
||||
}
|
||||
}
|
||||
|
@ -580,7 +581,7 @@ StackFrame::numActualArgs() const
|
|||
{
|
||||
JS_ASSERT(hasArgs());
|
||||
if (JS_UNLIKELY(flags_ & (OVERFLOW_ARGS | UNDERFLOW_ARGS)))
|
||||
return hasArgsObj() ? argsObj().getArgsInitialLength() : args.nactual;
|
||||
return hasArgsObj() ? argsObj().initialLength() : args.nactual;
|
||||
return numFormalArgs();
|
||||
}
|
||||
|
||||
|
@ -590,7 +591,7 @@ StackFrame::actualArgs() const
|
|||
JS_ASSERT(hasArgs());
|
||||
Value *argv = formalArgs();
|
||||
if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS)) {
|
||||
uintN nactual = hasArgsObj() ? argsObj().getArgsInitialLength() : args.nactual;
|
||||
uintN nactual = hasArgsObj() ? argsObj().initialLength() : args.nactual;
|
||||
return argv - (2 + nactual);
|
||||
}
|
||||
return argv;
|
||||
|
@ -606,10 +607,10 @@ StackFrame::actualArgsEnd() const
|
|||
}
|
||||
|
||||
inline void
|
||||
StackFrame::setArgsObj(JSObject &obj)
|
||||
StackFrame::setArgsObj(ArgumentsObject &obj)
|
||||
{
|
||||
JS_ASSERT_IF(hasArgsObj(), &obj == args.obj);
|
||||
JS_ASSERT_IF(!hasArgsObj(), numActualArgs() == obj.getArgsInitialLength());
|
||||
JS_ASSERT_IF(!hasArgsObj(), numActualArgs() == obj.initialLength());
|
||||
args.obj = &obj;
|
||||
flags_ |= HAS_ARGS_OBJ;
|
||||
}
|
||||
|
@ -674,7 +675,7 @@ StackFrame::markActivationObjectsAsPut()
|
|||
{
|
||||
if (flags_ & (HAS_ARGS_OBJ | HAS_CALL_OBJ)) {
|
||||
if (hasArgsObj() && !argsObj().getPrivate()) {
|
||||
args.nactual = args.obj->getArgsInitialLength();
|
||||
args.nactual = args.obj->initialLength();
|
||||
flags_ &= ~HAS_ARGS_OBJ;
|
||||
}
|
||||
if (hasCallObj() && !callObj().getPrivate()) {
|
||||
|
|
|
@ -58,6 +58,8 @@ class ExecuteFrameGuard;
|
|||
class DummyFrameGuard;
|
||||
class GeneratorFrameGuard;
|
||||
|
||||
class ArgumentsObject;
|
||||
|
||||
namespace mjit { struct JITScript; }
|
||||
namespace detail { struct OOMCheck; }
|
||||
|
||||
|
@ -259,8 +261,8 @@ class StackFrame
|
|||
JSFunction *fun; /* function frame, pre GetScopeChain */
|
||||
} exec;
|
||||
union { /* describes the arguments of a function */
|
||||
uintN nactual; /* pre GetArgumentsObject */
|
||||
JSObject *obj; /* post GetArgumentsObject */
|
||||
uintN nactual; /* before js_GetArgsObject */
|
||||
ArgumentsObject *obj; /* after js_GetArgsObject */
|
||||
JSScript *script; /* eval has no args, but needs a script */
|
||||
} args;
|
||||
mutable JSObject *scopeChain_; /* current scope chain */
|
||||
|
@ -547,17 +549,17 @@ class StackFrame
|
|||
return !!(flags_ & HAS_ARGS_OBJ);
|
||||
}
|
||||
|
||||
JSObject &argsObj() const {
|
||||
ArgumentsObject &argsObj() const {
|
||||
JS_ASSERT(hasArgsObj());
|
||||
JS_ASSERT(!isEvalFrame());
|
||||
return *args.obj;
|
||||
}
|
||||
|
||||
JSObject *maybeArgsObj() const {
|
||||
ArgumentsObject *maybeArgsObj() const {
|
||||
return hasArgsObj() ? &argsObj() : NULL;
|
||||
}
|
||||
|
||||
inline void setArgsObj(JSObject &obj);
|
||||
inline void setArgsObj(ArgumentsObject &obj);
|
||||
|
||||
/*
|
||||
* This value
|
||||
|
|
|
@ -1753,6 +1753,12 @@ GetCurrentWorkingDirectory(nsAString& workingDirectory)
|
|||
return true;
|
||||
}
|
||||
|
||||
static JSPrincipals *
|
||||
FindObjectPrincipals(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
return gJSPrincipals;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv, char **envp)
|
||||
{
|
||||
|
@ -1889,6 +1895,11 @@ main(int argc, char **argv, char **envp)
|
|||
}
|
||||
}
|
||||
|
||||
JSSecurityCallbacks *cb = JS_GetRuntimeSecurityCallbacks(rt);
|
||||
NS_ASSERTION(cb, "We are assuming that nsScriptSecurityManager::Init() has been run");
|
||||
NS_ASSERTION(!cb->findObjectPrincipals, "Your pigeon is in my hole!");
|
||||
cb->findObjectPrincipals = FindObjectPrincipals;
|
||||
|
||||
#ifdef TEST_TranslateThis
|
||||
nsCOMPtr<nsIXPCFunctionThisTranslator>
|
||||
translator(new nsXPCFunctionThisTranslator);
|
||||
|
|
|
@ -73,7 +73,8 @@ UnwrapNW(JSContext *cx, uintN argc, jsval *vp)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
|
||||
if (xpc::WrapperFactory::IsXrayWrapper(obj) &&
|
||||
!xpc::WrapperFactory::IsPartiallyTransparent(obj)) {
|
||||
return JS_GetProperty(cx, obj, "wrappedJSObject", vp);
|
||||
}
|
||||
|
||||
|
|
|
@ -294,8 +294,23 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
|
|||
return nsnull;
|
||||
}
|
||||
}
|
||||
wrapper = &FilteringWrapper<JSCrossCompartmentWrapper,
|
||||
ExposedPropertiesOnly>::singleton;
|
||||
|
||||
JSObject *inner = obj;
|
||||
OBJ_TO_INNER_OBJECT(cx, inner);
|
||||
XPCWrappedNative *wn;
|
||||
if (IS_WN_WRAPPER(inner) &&
|
||||
(wn = static_cast<XPCWrappedNative *>(inner->getPrivate()))->HasProto() &&
|
||||
wn->GetProto()->ClassIsDOMObject()) {
|
||||
typedef XrayWrapper<JSCrossCompartmentWrapper> Xray;
|
||||
wrapper = &FilteringWrapper<Xray,
|
||||
CrossOriginAccessiblePropertiesOnly>::singleton;
|
||||
xrayHolder = Xray::createHolder(cx, obj, parent);
|
||||
if (!xrayHolder)
|
||||
return nsnull;
|
||||
} else {
|
||||
wrapper = &FilteringWrapper<JSCrossCompartmentWrapper,
|
||||
ExposedPropertiesOnly>::singleton;
|
||||
}
|
||||
} else if (AccessCheck::isSameOrigin(origin, target)) {
|
||||
// Same origin we use a transparent wrapper, unless the compartment asks
|
||||
// for an Xray or the wrapper needs a SOW.
|
||||
|
@ -332,7 +347,7 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
|
|||
wrapper = &FilteringWrapper<Xray,
|
||||
SameOriginOrCrossOriginAccessiblePropertiesOnly>::singleton;
|
||||
} else {
|
||||
wrapper= &FilteringWrapper<Xray,
|
||||
wrapper = &FilteringWrapper<Xray,
|
||||
CrossOriginAccessiblePropertiesOnly>::singleton;
|
||||
}
|
||||
|
||||
|
|
|
@ -437,7 +437,10 @@ XrayWrapper<Base>::resolveOwnProperty(JSContext *cx, JSObject *wrapper, jsid id,
|
|||
{
|
||||
JSPropertyDescriptor *desc = Jsvalify(desc_in);
|
||||
|
||||
if (id == nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) {
|
||||
// Partially transparent wrappers (which used to be known as XOWs) don't
|
||||
// have a .wrappedJSObject property.
|
||||
if (!WrapperFactory::IsPartiallyTransparent(wrapper) &&
|
||||
id == nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) {
|
||||
bool status;
|
||||
JSWrapper::Action action = set ? JSWrapper::SET : JSWrapper::GET;
|
||||
desc->obj = NULL; // default value
|
||||
|
|
|
@ -26,11 +26,7 @@
|
|||
SimpleTest.finish();
|
||||
} else {
|
||||
|
||||
// Run the test in a separate window so we get a clean browser window.
|
||||
window.open("data:text/html,<html style='overflow:scroll'><script>opener.doTest(window);</script>",
|
||||
"", "scrollbars=yes,toolbar,menubar,width=500,height=500");
|
||||
|
||||
function doTest(win) {
|
||||
function doTest(evt) {
|
||||
var initialCount = win.mozPaintCount;
|
||||
|
||||
function nextStep() {
|
||||
|
@ -54,6 +50,12 @@
|
|||
|
||||
SimpleTest.executeSoon(nextStep);
|
||||
}
|
||||
|
||||
// Run the test in a separate window so we get a clean browser window.
|
||||
var win = window.open("data:text/html,<html style='overflow:scroll'>",
|
||||
"", "scrollbars=yes,toolbar,menubar,width=500,height=500");
|
||||
win.addEventListener('load', doTest, false);
|
||||
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
|
|
|
@ -92,3 +92,11 @@ skip-if(!browserIsRemote) != test-displayport-2.html test-displayport-ref.html #
|
|||
|
||||
# IPC Position-fixed frames/layers test
|
||||
== test-pos-fixed.html test-pos-fixed-ref.html
|
||||
|
||||
# reftest syntax: require-or
|
||||
require-or(unrecognizedCondition,skip) script scripttest-fail.html
|
||||
require-or(true&&unrecognizedCondition,skip) script scripttest-fail.html
|
||||
require-or(unrecognizedCondition&&true,skip) script scripttest-fail.html
|
||||
require-or(unrecognizedCondition,fails) script scripttest-fail.html
|
||||
require-or(true,fails) script scripttest-pass.html
|
||||
require-or(true&&true,fails) script scripttest-pass.html
|
||||
|
|
|
@ -106,6 +106,13 @@ must be one of the following:
|
|||
fast on a 32-bit system but inordinately slow on a
|
||||
64-bit system).
|
||||
|
||||
require-or(cond1&&cond2&&...,fallback)
|
||||
Require some particular setup be performed or environmental
|
||||
condition(s) made true (eg setting debug mode) before the test
|
||||
is run. If any condition is unknown, unimplemented, or fails,
|
||||
revert to the fallback failure-type.
|
||||
Example: require-or(debugMode,skip)
|
||||
|
||||
asserts(count)
|
||||
Loading the test and reference is known to assert exactly
|
||||
count times.
|
||||
|
|
|
@ -547,7 +547,7 @@ function ReadManifest(aURL, inherited_status)
|
|||
}
|
||||
var streamBuf = getStreamContent(inputStream);
|
||||
inputStream.close();
|
||||
var lines = streamBuf.split(/(\n|\r|\r\n)/);
|
||||
var lines = streamBuf.split(/\n|\r|\r\n/);
|
||||
|
||||
// Build the sandbox for fails-if(), etc., condition evaluation.
|
||||
var sandbox = BuildConditionSandbox(aURL);
|
||||
|
@ -581,7 +581,7 @@ function ReadManifest(aURL, inherited_status)
|
|||
var needs_focus = false;
|
||||
var slow = false;
|
||||
|
||||
while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|silentfail)/)) {
|
||||
while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail)/)) {
|
||||
var item = items.shift();
|
||||
var stat;
|
||||
var cond;
|
||||
|
@ -612,6 +612,30 @@ function ReadManifest(aURL, inherited_status)
|
|||
} else if (item == "slow") {
|
||||
cond = false;
|
||||
slow = true;
|
||||
} else if ((m = item.match(/^require-or\((.*?)\)$/))) {
|
||||
var args = m[1].split(/,/);
|
||||
if (args.length != 2) {
|
||||
throw "Error 7 in manifest file " + aURL.spec + " line " + lineNo + ": wrong number of args to require-or";
|
||||
}
|
||||
var [precondition_str, fallback_action] = args;
|
||||
var preconditions = precondition_str.split(/&&/);
|
||||
cond = false;
|
||||
for each (var precondition in preconditions) {
|
||||
if (precondition === "debugMode") {
|
||||
// Currently unimplemented. Requires asynchronous
|
||||
// JSD call + getting an event while no JS is running
|
||||
stat = fallback_action;
|
||||
cond = true;
|
||||
break;
|
||||
} else if (precondition === "true") {
|
||||
// For testing
|
||||
} else {
|
||||
// Unknown precondition. Assume it is unimplemented.
|
||||
stat = fallback_action;
|
||||
cond = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if ((m = item.match(/^slow-if\((.*?)\)$/))) {
|
||||
cond = false;
|
||||
if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox))
|
||||
|
|
|
@ -67,7 +67,7 @@ function getTabModalPromptBox(domWin) {
|
|||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler.ownerDocument.defaultView;
|
||||
return chromeWin;
|
||||
return XPCNativeWrapper.unwrap(chromeWin);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -76,7 +76,7 @@ function getTabModalPromptBox(domWin) {
|
|||
|
||||
// Get the chrome window for the content window we're using.
|
||||
// (Unwrap because we need a non-IDL property below.)
|
||||
var chromeWin = getChromeWindow(promptWin).wrappedJSObject;
|
||||
var chromeWin = getChromeWindow(promptWin);
|
||||
|
||||
if (chromeWin.getTabModalPromptBox)
|
||||
promptBox = chromeWin.getTabModalPromptBox(promptWin);
|
||||
|
|
Загрузка…
Ссылка в новой задаче