Merge tracemonkey to mozilla-central. a=blockers. CLOSED TREE

This commit is contained in:
Robert Sayre 2011-02-22 13:02:50 -08:00
commit 8b068c79c2
26 changed files with 339 additions and 72 deletions

View File

@ -3480,6 +3480,12 @@ DOMGCCallback(JSContext *cx, JSGCStatus status)
nsJSContext::PokeCC();
}
}
// If we didn't end up scheduling a GC, and there are unused
// chunks waiting to expire, make sure we will GC again soon.
if (!sGCTimer && JS_GetGCParameter(cx->runtime, JSGC_UNUSED_CHUNKS) > 0) {
nsJSContext::PokeGC();
}
}
JSBool result = gOldJSGCCallback ? gOldJSGCCallback(cx, status) : JS_TRUE;

View File

@ -241,9 +241,13 @@ jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
JS_RestoreExceptionState(cx, exceptionState);
JS_LeaveCrossCompartmentCall(call);
stringval = STRING_TO_JSVAL(string);
call = JS_EnterCrossCompartmentCall(cx, jsdc->glob);
if(!call || !JS_WrapValue(cx, &stringval)) {
if(string) {
stringval = STRING_TO_JSVAL(string);
call = JS_EnterCrossCompartmentCall(cx, jsdc->glob);
}
if(!string || !call || !JS_WrapValue(cx, &stringval)) {
if(call)
JS_LeaveCrossCompartmentCall(call);
JS_EndRequest(cx);
return NULL;
}

View File

@ -0,0 +1,7 @@
var a = [];
for (var i = 0; i < RUNLOOP; i++)
a[i] = 0;
var b = #1=[x === "0" && (#1#.slow = 1) for (x in a)];
assertEq(b[0], 1);
for (var i = 1; i < RUNLOOP; i++)
assertEq(b[i], false);

View File

@ -0,0 +1,9 @@
// don't crash when tracing
function f(o) {
var prop = "arguments";
f[prop] = f[prop];
}
for(var i=0; i<10; i++) {
f();
}

View File

@ -0,0 +1,9 @@
// |jit-test| error:Error
var p = /./, x = resolver({}, p), y = resolver({lastIndex: 2}, p), v;
var a = [];
for (var i = 0; i < HOTLOOP; i++)
a[i] = x;
a[HOTLOOP] = y;
for (i = 0; i < a.length; i++)
v = a[i].lastIndex;
assertEq(v, 2); // fails due to bug 458271

View File

@ -0,0 +1,4 @@
this.__defineGetter__("x3", Function);
parseInt = x3;
parseInt.prototype = [];
for (var z = 0; z < 10; ++z) { new parseInt() }

View File

@ -1447,8 +1447,10 @@ js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
ctor = JS_GetConstructor(cx, fun_proto);
if (!ctor)
return NULL;
obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
ObjectValue(*ctor), 0, 0, 0);
if (!obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
ObjectValue(*ctor), 0, 0, 0)) {
return NULL;
}
}
/* Initialize the object class next so Object.prototype works. */
@ -2642,6 +2644,8 @@ JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
return rt->gcBytes;
case JSGC_MODE:
return uint32(rt->gcMode);
case JSGC_UNUSED_CHUNKS:
return uint32(rt->gcChunksWaitingToExpire);
default:
JS_ASSERT(key == JSGC_NUMBER);
return rt->gcNumber;

View File

@ -1785,7 +1785,10 @@ typedef enum JSGCParamKey {
JSGC_MAX_CODE_CACHE_BYTES = 6,
/* Select GC mode. */
JSGC_MODE = 7
JSGC_MODE = 7,
/* Number of GC chunks waiting to expire. */
JSGC_UNUSED_CHUNKS = 8
} JSGCParamKey;
typedef enum JSGCMode {

View File

@ -2059,28 +2059,34 @@ array_push1_dense(JSContext* cx, JSObject* obj, const Value &v, Value *rval)
JS_ALWAYS_INLINE JSBool
ArrayCompPushImpl(JSContext *cx, JSObject *obj, const Value &v)
{
uint32 length = obj->getArrayLength();
if (obj->isSlowArray()) {
/* This can happen in one evil case. See bug 630377. */
jsid id;
return js_IndexToId(cx, length, &id) &&
js_DefineProperty(cx, obj, id, &v, NULL, NULL, JSPROP_ENUMERATE);
}
JS_ASSERT(obj->isDenseArray());
uint32_t length = obj->getArrayLength();
JS_ASSERT(length <= obj->getDenseArrayCapacity());
if (length == obj->getDenseArrayCapacity()) {
if (length > JS_ARGS_LENGTH_MAX) {
JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
JSMSG_ARRAY_INIT_TOO_BIG);
return JS_FALSE;
return false;
}
/*
* Array comprehension cannot add holes to the array and never leaks
* the array before it is fully initialized. So we can use ensureSlots
* instead of ensureDenseArrayElements.
* An array comprehension cannot add holes to the array. So we can use
* ensureSlots instead of ensureDenseArrayElements.
*/
if (!obj->ensureSlots(cx, length + 1))
return false;
}
obj->setArrayLength(length + 1);
obj->setDenseArrayElement(length, v);
return JS_TRUE;
return true;
}
JSBool

View File

@ -1047,6 +1047,7 @@ struct JSRuntime {
size_t gcLastBytes;
size_t gcMaxBytes;
size_t gcMaxMallocBytes;
size_t gcChunksWaitingToExpire;
uint32 gcEmptyArenaPoolLifespan;
uint32 gcNumber;
js::GCMarker *gcMarkingTracer;

View File

@ -145,7 +145,7 @@ CompartmentHasLiveScripts(JSCompartment *comp)
JS_FRIEND_API(JSBool)
JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, JSBool debug)
{
if (comp->debugMode == debug)
if (comp->debugMode == !!debug)
return JS_TRUE;
// This should only be called when no scripts are live. It would even be
@ -154,7 +154,7 @@ JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, JSBool debug)
JS_ASSERT(!CompartmentHasLiveScripts(comp));
// All scripts compiled from this point on should be in the requested debugMode.
comp->debugMode = debug;
comp->debugMode = !!debug;
// Discard JIT code for any scripts that change debugMode. This function
// assumes that 'comp' is in the same thread as 'cx'.

View File

@ -360,14 +360,6 @@ Chunk::releaseArena(Arena<T> *arena)
info.age = 0;
}
bool
Chunk::expire()
{
if (!unused())
return false;
return info.age++ > MaxAge;
}
JSRuntime *
Chunk::getRuntime()
{
@ -456,16 +448,22 @@ PickChunk(JSRuntime *rt)
static void
ExpireGCChunks(JSRuntime *rt)
{
static const size_t MaxAge = 3;
/* Remove unused chunks. */
AutoLockGC lock(rt);
rt->gcChunksWaitingToExpire = 0;
for (GCChunkSet::Enum e(rt->gcChunkSet); !e.empty(); e.popFront()) {
Chunk *chunk = e.front();
JS_ASSERT(chunk->info.runtime == rt);
if (chunk->expire()) {
e.removeFront();
ReleaseGCChunk(rt, chunk);
continue;
if (chunk->unused()) {
if (chunk->info.age++ > MaxAge) {
e.removeFront();
ReleaseGCChunk(rt, chunk);
continue;
}
rt->gcChunksWaitingToExpire++;
}
}
}

View File

@ -340,7 +340,6 @@ struct Chunk {
sizeof(MarkingDelay);
static const size_t ArenasPerChunk = (GC_CHUNK_SIZE - sizeof(ChunkInfo)) / BytesPerArena;
static const size_t MaxAge = 3;
Arena<FreeCell> arenas[ArenasPerChunk];
ArenaBitmap bitmaps[ArenasPerChunk];
@ -362,7 +361,6 @@ struct Chunk {
void releaseArena(Arena<T> *a);
JSRuntime *getRuntime();
bool expire();
};
JS_STATIC_ASSERT(sizeof(Chunk) <= GC_CHUNK_SIZE);
JS_STATIC_ASSERT(sizeof(Chunk) + Chunk::BytesPerArena > GC_CHUNK_SIZE);

View File

@ -4772,7 +4772,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &valu
JS_ASSERT(existingShape->getter() != getter);
if (!obj->methodReadBarrier(cx, *existingShape, &valueCopy))
return NULL;
return false;
}
} else {
adding = true;
@ -6794,20 +6794,30 @@ js_DumpId(jsid id)
}
static void
DumpShape(const Shape &shape)
DumpProperty(JSObject *obj, const Shape &shape)
{
jsid id = shape.id;
uint8 attrs = shape.attributes();
fprintf(stderr, " ");
fprintf(stderr, " ((Shape *) %p) ", (void *) &shape);
if (attrs & JSPROP_ENUMERATE) fprintf(stderr, "enumerate ");
if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly ");
if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent ");
if (attrs & JSPROP_GETTER) fprintf(stderr, "getter ");
if (attrs & JSPROP_SETTER) fprintf(stderr, "setter ");
if (attrs & JSPROP_SHARED) fprintf(stderr, "shared ");
if (shape.isAlias()) fprintf(stderr, "alias ");
if (shape.isMethod()) fprintf(stderr, "method(%p) ", (void *) &shape.methodObject());
if (shape.isMethod()) fprintf(stderr, "method=%p ", (void *) &shape.methodObject());
if (shape.hasGetterValue())
fprintf(stderr, "getterValue=%p ", (void *) shape.getterObject());
else if (!shape.hasDefaultGetter())
fprintf(stderr, "getterOp=%p ", JS_FUNC_TO_DATA_PTR(void *, shape.getterOp()));
if (shape.hasSetterValue())
fprintf(stderr, "setterValue=%p ", (void *) shape.setterObject());
else if (shape.setterOp() == js_watch_set)
fprintf(stderr, "setterOp=js_watch_set ");
else if (!shape.hasDefaultSetter())
fprintf(stderr, "setterOp=%p ", JS_FUNC_TO_DATA_PTR(void *, shape.setterOp()));
if (JSID_IS_ATOM(id))
dumpString(JSID_TO_STRING(id));
@ -6816,6 +6826,12 @@ DumpShape(const Shape &shape)
else
fprintf(stderr, "unknown jsid %p", (void *) JSID_BITS(id));
fprintf(stderr, ": slot %d", shape.slot);
if (obj->containsSlot(shape.slot)) {
fprintf(stderr, " = ");
dumpValue(obj->getSlot(shape.slot));
} else if (shape.slot != SHAPE_INVALID_SLOT) {
fprintf(stderr, " (INVALID!)");
}
fprintf(stderr, "\n");
}
@ -6830,7 +6846,7 @@ js_DumpObject(JSObject *obj)
uint32 flags = obj->flags;
if (flags & JSObject::DELEGATE) fprintf(stderr, " delegate");
if (flags & JSObject::SYSTEM) fprintf(stderr, " system");
if (flags & JSObject::NOT_EXTENSIBLE) fprintf(stderr, " not extensible");
if (flags & JSObject::NOT_EXTENSIBLE) fprintf(stderr, " not_extensible");
if (flags & JSObject::BRANDED) fprintf(stderr, " branded");
if (flags & JSObject::GENERIC) fprintf(stderr, " generic");
if (flags & JSObject::METHOD_BARRIER) fprintf(stderr, " method_barrier");
@ -6865,15 +6881,6 @@ js_DumpObject(JSObject *obj)
return;
}
if (obj->isNative()) {
fprintf(stderr, "properties:\n");
for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront())
DumpShape(r.front());
} else {
if (!obj->isNative())
fprintf(stderr, "not native\n");
}
fprintf(stderr, "proto ");
dumpValue(ObjectOrNullValue(obj->getProto()));
fputc('\n', stderr);
@ -6885,10 +6892,15 @@ js_DumpObject(JSObject *obj)
if (clasp->flags & JSCLASS_HAS_PRIVATE)
fprintf(stderr, "private %p\n", obj->getPrivate());
fprintf(stderr, "slots:\n");
if (!obj->isNative())
fprintf(stderr, "not native\n");
unsigned reservedEnd = JSCLASS_RESERVED_SLOTS(clasp);
unsigned slots = obj->slotSpan();
for (unsigned i = 0; i < slots; i++) {
unsigned stop = obj->isNative() ? reservedEnd : slots;
if (stop > 0)
fprintf(stderr, obj->isNative() ? "reserved slots:\n" : "slots:\n");
for (unsigned i = 0; i < stop; i++) {
fprintf(stderr, " %3d ", i);
if (i < reservedEnd)
fprintf(stderr, "(reserved) ");
@ -6896,6 +6908,15 @@ js_DumpObject(JSObject *obj)
dumpValue(obj->getSlot(i));
fputc('\n', stderr);
}
if (obj->isNative()) {
fprintf(stderr, "properties:\n");
Vector<const Shape *, 8, SystemAllocPolicy> props;
for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront())
props.append(&r.front());
for (size_t i = props.length(); i-- != 0;)
DumpProperty(obj, *props[i]);
}
fputc('\n', stderr);
}

View File

@ -915,7 +915,6 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
JSObject *parent, gc::FinalizeKind kind)
{
JS_ASSERT(proto);
JS_ASSERT(proto->isNative());
JS_ASSERT(parent);
/*

View File

@ -5489,8 +5489,8 @@ ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target,
return ReconstructImacroPCStack(cx, script, imacstart, target, pcstack);
#endif
LOCAL_ASSERT(script->main <= target && target < script->code + script->length);
jsbytecode *pc = script->main;
LOCAL_ASSERT(script->code <= target && target < script->code + script->length);
jsbytecode *pc = script->code;
uintN pcdepth = 0;
ptrdiff_t oplen;
for (; pc < target; pc += oplen) {

View File

@ -857,6 +857,7 @@ TokenStream::getTokenInternal()
c = getChar();
} while (JS_ISXMLSPACE(c));
ungetChar(c);
tp->pos.end.lineno = lineno;
tt = TOK_XMLSPACE;
goto out;
}

View File

@ -10328,7 +10328,7 @@ class BoxArg
* argument values into the object as properties in case it is used after
* this frame returns.
*/
JS_REQUIRES_STACK void
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::putActivationObjects()
{
JSStackFrame *const fp = cx->fp();
@ -10336,7 +10336,20 @@ TraceRecorder::putActivationObjects()
bool have_call = fp->isFunctionFrame() && fp->fun()->isHeavyweight();
if (!have_args && !have_call)
return;
return ARECORD_CONTINUE;
if (have_args && !fp->script()->usesArguments) {
/*
* have_args is true, so |arguments| has been accessed, but
* usesArguments is false, so there's no statically visible access.
* It must have been a dodgy access like |f["arguments"]|; just
* abort. (In the case where the record-time property name is not
* "arguments" but a later run-time property name is, we wouldn't have
* emitted the call to js_PutArgumentsOnTrace(), and js_GetArgsValue()
* will deep bail asking for the top JSStackFrame.)
*/
RETURN_STOP_A("dodgy arguments access");
}
uintN nformal = fp->numFormalArgs();
uintN nactual = fp->numActualArgs();
@ -10380,6 +10393,8 @@ TraceRecorder::putActivationObjects()
w.nameImmi(fp->numFormalArgs()), scopeChain_ins, cx_ins };
w.call(&js_PutCallObjectOnTrace_ci, args);
}
return ARECORD_CONTINUE;
}
JS_REQUIRES_STACK AbortableRecordingStatus
@ -10572,7 +10587,7 @@ TraceRecorder::record_JSOP_RETURN()
return endLoop();
}
putActivationObjects();
CHECK_STATUS_A(putActivationObjects());
if (Probes::callTrackingActive(cx)) {
LIns* args[] = { w.immi(0), w.nameImmpNonGC(cx->fp()->fun()), cx_ins };
@ -10639,7 +10654,7 @@ TraceRecorder::record_JSOP_IFNE()
}
LIns*
TraceRecorder::newArguments(LIns* callee_ins, bool strict)
TraceRecorder::newArguments(LIns* callee_ins)
{
LIns* global_ins = w.immpObjGC(globalObj);
LIns* argc_ins = w.nameImmi(cx->fp()->numActualArgs());
@ -10648,13 +10663,6 @@ TraceRecorder::newArguments(LIns* callee_ins, bool strict)
LIns* argsobj_ins = w.call(&js_NewArgumentsOnTrace_ci, args);
guard(false, w.eqp0(argsobj_ins), OOM_EXIT);
if (strict) {
LIns* argsData_ins = w.getObjPrivatizedSlot(argsobj_ins, JSObject::JSSLOT_ARGS_DATA);
ptrdiff_t slotsOffset = offsetof(ArgumentsData, slots);
cx->fp()->forEachCanonicalActualArg(BoxArg(this, ArgsSlotOffsetAddress(argsData_ins,
slotsOffset)));
}
return argsobj_ins;
}
@ -10668,14 +10676,15 @@ TraceRecorder::record_JSOP_ARGUMENTS()
if (fp->hasOverriddenArgs())
RETURN_STOP_A("Can't trace |arguments| if |arguments| is assigned to");
if (fp->fun()->inStrictMode())
RETURN_STOP_A("Can't trace strict-mode arguments");
LIns* a_ins = getFrameObjPtr(fp->addressOfArgs());
LIns* args_ins;
LIns* callee_ins = get(&fp->calleeValue());
bool strict = fp->fun()->inStrictMode();
if (a_ins->isImmP()) {
// |arguments| is set to 0 by EnterFrame on this trace, so call to create it.
args_ins = newArguments(callee_ins, strict);
args_ins = newArguments(callee_ins);
} else {
// Generate LIR to create arguments only if it has not already been created.
@ -10685,7 +10694,7 @@ TraceRecorder::record_JSOP_ARGUMENTS()
if (isZero_ins->isImmI(0)) {
w.stAlloc(a_ins, mem_ins);
} else if (isZero_ins->isImmI(1)) {
LIns* call_ins = newArguments(callee_ins, strict);
LIns* call_ins = newArguments(callee_ins);
w.stAlloc(call_ins, mem_ins);
} else {
LIns* br1 = w.jtUnoptimizable(isZero_ins);
@ -10693,7 +10702,7 @@ TraceRecorder::record_JSOP_ARGUMENTS()
LIns* br2 = w.j(NULL);
w.label(br1);
LIns* call_ins = newArguments(callee_ins, strict);
LIns* call_ins = newArguments(callee_ins);
w.stAlloc(call_ins, mem_ins);
w.label(br2);
}
@ -12843,10 +12852,9 @@ GetPropertyWithNativeGetter(JSContext* cx, JSObject* obj, Shape* shape, Value* v
LeaveTraceIfGlobalObject(cx, obj);
#ifdef DEBUG
JSProperty* prop;
JSObject* pobj;
JS_ASSERT(obj->lookupProperty(cx, shape->id, &pobj, &prop));
JS_ASSERT(prop == (JSProperty*) shape);
const Shape* shape2;
JS_ASSERT_IF(SafeLookup(cx, obj, shape->id, &pobj, &shape2), shape == shape2);
#endif
// Shape::get contains a special case for With objects. We can elide it
@ -13793,7 +13801,7 @@ TraceRecorder::interpretedFunctionCall(Value& fval, JSFunction* fun, uintN argc,
if (constructing) {
LIns* thisobj_ins;
CHECK_STATUS(createThis(fval.toObject(), get(&fval), &thisobj_ins));
stack(-argc - 1, thisobj_ins);
stack(-int(argc) - 1, thisobj_ins);
}
// Generate a type map for the outgoing frame and stash it in the LIR
@ -16219,7 +16227,7 @@ TraceRecorder::record_JSOP_STOP()
return ARECORD_CONTINUE;
}
putActivationObjects();
CHECK_STATUS_A(putActivationObjects());
if (Probes::callTrackingActive(cx)) {
LIns* args[] = { w.immi(0), w.nameImmpNonGC(cx->fp()->fun()), cx_ins };
@ -16309,7 +16317,6 @@ TraceRecorder::record_JSOP_ARRAYPUSH()
JS_ASSERT(cx->fp()->slots() + slot < cx->regs->sp - 1);
Value &arrayval = cx->fp()->slots()[slot];
JS_ASSERT(arrayval.isObject());
JS_ASSERT(arrayval.toObject().isDenseArray());
LIns *array_ins = get(&arrayval);
Value &elt = stackval(-1);
LIns *elt_ins = box_value_for_native_call(elt, get(&elt));

View File

@ -1290,7 +1290,7 @@ class TraceRecorder
JS_REQUIRES_STACK RecordingStatus makeNumberUint32(nanojit::LIns* d, nanojit::LIns** num_ins);
JS_REQUIRES_STACK nanojit::LIns* stringify(const Value& v);
JS_REQUIRES_STACK nanojit::LIns* newArguments(nanojit::LIns* callee_ins, bool strict);
JS_REQUIRES_STACK nanojit::LIns* newArguments(nanojit::LIns* callee_ins);
JS_REQUIRES_STACK bool canCallImacro() const;
JS_REQUIRES_STACK RecordingStatus callImacro(jsbytecode* imacro);
@ -1482,7 +1482,7 @@ class TraceRecorder
VMSideExit* exit);
JS_REQUIRES_STACK RecordingStatus guardNativeConversion(Value& v);
JS_REQUIRES_STACK void clearReturningFrameFromNativeTracker();
JS_REQUIRES_STACK void putActivationObjects();
JS_REQUIRES_STACK AbortableRecordingStatus putActivationObjects();
JS_REQUIRES_STACK RecordingStatus createThis(JSObject& ctor, nanojit::LIns* ctor_ins,
nanojit::LIns** thisobj_insp);
JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee);

View File

@ -3564,6 +3564,127 @@ ShapeOf(JSContext *cx, uintN argc, jsval *vp)
return JS_NewNumberValue(cx, obj->shape(), vp);
}
/*
* If referent has an own property named id, copy that property to obj[id].
* Since obj is native, this isn't totally transparent; properties of a
* non-native referent may be simplified to data properties.
*/
static JSBool
CopyProperty(JSContext *cx, JSObject *obj, JSObject *referent, jsid id,
uintN lookupFlags, JSObject **objp)
{
JSProperty *prop;
PropertyDescriptor desc;
uintN propFlags = 0;
JSObject *obj2;
*objp = NULL;
if (referent->isNative()) {
if (js_LookupPropertyWithFlags(cx, referent, id, lookupFlags, &obj2, &prop) < 0)
return false;
if (obj2 != referent)
return true;
const Shape *shape = (Shape *) prop;
if (shape->isMethod()) {
shape = referent->methodReadBarrier(cx, *shape, &desc.value);
if (!shape)
return false;
} else if (shape->hasSlot()) {
desc.value = referent->nativeGetSlot(shape->slot);
} else {
desc.value.setUndefined();
}
desc.attrs = shape->attributes();
desc.getter = shape->getter();
if (!desc.getter && !(desc.attrs & JSPROP_GETTER))
desc.getter = PropertyStub;
desc.setter = shape->setter();
if (!desc.setter && !(desc.attrs & JSPROP_SETTER))
desc.setter = StrictPropertyStub;
desc.shortid = shape->shortid;
propFlags = shape->getFlags();
} else if (referent->isProxy()) {
PropertyDescriptor desc;
if (!JSProxy::getOwnPropertyDescriptor(cx, referent, id, false, &desc))
return false;
if (!desc.obj)
return true;
} else {
if (!referent->lookupProperty(cx, id, objp, &prop))
return false;
if (*objp != referent)
return true;
if (!referent->getProperty(cx, id, &desc.value) ||
!referent->getAttributes(cx, id, &desc.attrs)) {
return false;
}
desc.attrs &= JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
desc.getter = PropertyStub;
desc.setter = StrictPropertyStub;
desc.shortid = 0;
}
*objp = obj;
return js_DefineNativeProperty(cx, obj, id, desc.value,
desc.getter, desc.setter, desc.attrs, propFlags,
desc.shortid, &prop);
}
static JSBool
resolver_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
{
jsval v;
JS_ALWAYS_TRUE(JS_GetReservedSlot(cx, obj, 0, &v));
return CopyProperty(cx, obj, JSVAL_TO_OBJECT(v), id, flags, objp);
}
static JSNewResolveOp resolver_resolve_check = resolver_resolve;
static JSBool
resolver_enumerate(JSContext *cx, JSObject *obj)
{
jsval v;
JS_ALWAYS_TRUE(JS_GetReservedSlot(cx, obj, 0, &v));
JSObject *referent = JSVAL_TO_OBJECT(v);
AutoIdArray ida(cx, JS_Enumerate(cx, referent));
bool ok = !!ida;
JSObject *ignore;
for (size_t i = 0; ok && i < ida.length(); i++)
ok = CopyProperty(cx, obj, referent, ida[i], JSRESOLVE_QUALIFIED, &ignore);
return ok;
}
static JSClass resolver_class = {
"resolver",
JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1),
JS_PropertyStub, JS_PropertyStub,
JS_PropertyStub, JS_StrictPropertyStub,
resolver_enumerate, (JSResolveOp)resolver_resolve,
JS_ConvertStub, NULL,
JSCLASS_NO_OPTIONAL_MEMBERS
};
static JSBool
Resolver(JSContext *cx, uintN argc, jsval *vp)
{
JSObject *referent, *proto = NULL;
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "o/o", &referent, &proto))
return false;
JSObject *result = (argc > 1
? JS_NewObjectWithGivenProto
: JS_NewObject)(cx, &resolver_class, proto, JS_GetParent(cx, referent));
if (!result)
return false;
JS_ALWAYS_TRUE(JS_SetReservedSlot(cx, result, 0, OBJECT_TO_JSVAL(referent)));
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
return true;
}
#ifdef JS_THREADSAFE
/*
@ -4416,6 +4537,7 @@ static JSFunctionSpec shell_functions[] = {
JS_FN("evalcx", EvalInContext, 1,0),
JS_FN("evalInFrame", EvalInFrame, 2,0),
JS_FN("shapeOf", ShapeOf, 1,0),
JS_FN("resolver", Resolver, 1,0),
#ifdef MOZ_CALLGRIND
JS_FN("startCallgrind", js_StartCallgrind, 0,0),
JS_FN("stopCallgrind", js_StopCallgrind, 0,0),
@ -4543,6 +4665,8 @@ static const char *const shell_help_messages[] = {
"evalInFrame(n,str,save) Evaluate 'str' in the nth up frame.\n"
" If 'save' (default false), save the frame chain",
"shapeOf(obj) Get the shape of obj (an implementation detail)",
"resolver(src[, proto]) Create object with resolve hook that copies properties\n"
" from src. If proto is omitted, use Object.prototype.",
#ifdef MOZ_CALLGRIND
"startCallgrind() Start callgrind instrumentation",
"stopCallgrind() Stop callgrind instrumentation",

View File

@ -0,0 +1,35 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
//-----------------------------------------------------------------------------
var BUGNUMBER = 621432;
var summary =
"If a var statement can't create a global property because the global " +
"object isn't extensible, and an error is thrown while decompiling the " +
"global, don't assert";
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
var toSource = [];
Object.preventExtensions(this);
try
{
eval("var x;");
throw new Error("no error thrown");
}
catch (e)
{
reportCompare(e instanceof TypeError, true, "expected TypeError, got: " + e);
}
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("All tests passed!");

View File

@ -1,4 +1,5 @@
url-prefix ../../jsreftest.html?test=ecma_5/Global/
fails-if(!xulRuntime.shell) script adding-global-var-nonextensible-error.js
script parseInt-01.js
script parseFloat-01.js
script eval-01.js

View File

@ -32,4 +32,5 @@ script regress-627984-4.js
script regress-627984-5.js
script regress-627984-6.js
script regress-627984-7.js
script regress-630377.js
script regress-631723.js

View File

@ -0,0 +1,11 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
function f(x) {
x.q = 1;
}
var a = #1=[f(#1#) for (i in [0])];
assertEq(a.q, 1);
assertEq(a[0], void 0);
reportCompare(0, 0, 'ok');

View File

@ -84,6 +84,7 @@ script regress-624199.js
script regress-624547.js
script regress-624968.js
script regress-626436.js
fails-if(xulRuntime.shell) script regress-633741.js
script regress-634210-1.js
script regress-634210-2.js
script regress-634210-3.js

View File

@ -0,0 +1,17 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
* Contributors: Jan de Mooij
*/
Object.preventExtensions(this);
delete Function;
try {
/* Don't assert. */
Object.getOwnPropertyNames(this);
} catch(e) {
reportCompare(true, false, "this shouldn't have thrown");
}
reportCompare(0, 0, "ok");