Merge mozilla-central and tracemonkey.

This commit is contained in:
Chris Leary 2011-05-13 15:06:53 -07:00
Родитель 884b2a5bec 35e1d270ff
Коммит 277ecef0fa
77 изменённых файлов: 1618 добавлений и 1112 удалений

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

@ -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;
}
}

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

@ -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 = &regs.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;
}
}

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

@ -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);

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

@ -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
{

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

@ -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___ */

255
js/src/vm/ArgumentsObject.h Normal file
Просмотреть файл

@ -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);