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 b68509ebc2
26 changed files with 339 additions and 72 deletions

View File

@ -3480,6 +3480,12 @@ DOMGCCallback(JSContext *cx, JSGCStatus status)
nsJSContext::PokeCC(); 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; 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_RestoreExceptionState(cx, exceptionState);
JS_LeaveCrossCompartmentCall(call); JS_LeaveCrossCompartmentCall(call);
stringval = STRING_TO_JSVAL(string); if(string) {
call = JS_EnterCrossCompartmentCall(cx, jsdc->glob); stringval = STRING_TO_JSVAL(string);
if(!call || !JS_WrapValue(cx, &stringval)) { call = JS_EnterCrossCompartmentCall(cx, jsdc->glob);
}
if(!string || !call || !JS_WrapValue(cx, &stringval)) {
if(call)
JS_LeaveCrossCompartmentCall(call);
JS_EndRequest(cx); JS_EndRequest(cx);
return NULL; 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); ctor = JS_GetConstructor(cx, fun_proto);
if (!ctor) if (!ctor)
return NULL; return NULL;
obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)), if (!obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
ObjectValue(*ctor), 0, 0, 0); ObjectValue(*ctor), 0, 0, 0)) {
return NULL;
}
} }
/* Initialize the object class next so Object.prototype works. */ /* Initialize the object class next so Object.prototype works. */
@ -2642,6 +2644,8 @@ JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
return rt->gcBytes; return rt->gcBytes;
case JSGC_MODE: case JSGC_MODE:
return uint32(rt->gcMode); return uint32(rt->gcMode);
case JSGC_UNUSED_CHUNKS:
return uint32(rt->gcChunksWaitingToExpire);
default: default:
JS_ASSERT(key == JSGC_NUMBER); JS_ASSERT(key == JSGC_NUMBER);
return rt->gcNumber; return rt->gcNumber;

View File

@ -1785,7 +1785,10 @@ typedef enum JSGCParamKey {
JSGC_MAX_CODE_CACHE_BYTES = 6, JSGC_MAX_CODE_CACHE_BYTES = 6,
/* Select GC mode. */ /* Select GC mode. */
JSGC_MODE = 7 JSGC_MODE = 7,
/* Number of GC chunks waiting to expire. */
JSGC_UNUSED_CHUNKS = 8
} JSGCParamKey; } JSGCParamKey;
typedef enum JSGCMode { 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 JS_ALWAYS_INLINE JSBool
ArrayCompPushImpl(JSContext *cx, JSObject *obj, const Value &v) 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()); JS_ASSERT(obj->isDenseArray());
uint32_t length = obj->getArrayLength();
JS_ASSERT(length <= obj->getDenseArrayCapacity()); JS_ASSERT(length <= obj->getDenseArrayCapacity());
if (length == obj->getDenseArrayCapacity()) { if (length == obj->getDenseArrayCapacity()) {
if (length > JS_ARGS_LENGTH_MAX) { if (length > JS_ARGS_LENGTH_MAX) {
JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL, JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
JSMSG_ARRAY_INIT_TOO_BIG); JSMSG_ARRAY_INIT_TOO_BIG);
return JS_FALSE; return false;
} }
/* /*
* Array comprehension cannot add holes to the array and never leaks * An array comprehension cannot add holes to the array. So we can use
* the array before it is fully initialized. So we can use ensureSlots * ensureSlots instead of ensureDenseArrayElements.
* instead of ensureDenseArrayElements.
*/ */
if (!obj->ensureSlots(cx, length + 1)) if (!obj->ensureSlots(cx, length + 1))
return false; return false;
} }
obj->setArrayLength(length + 1); obj->setArrayLength(length + 1);
obj->setDenseArrayElement(length, v); obj->setDenseArrayElement(length, v);
return JS_TRUE; return true;
} }
JSBool JSBool

View File

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

View File

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

View File

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

View File

@ -340,7 +340,6 @@ struct Chunk {
sizeof(MarkingDelay); sizeof(MarkingDelay);
static const size_t ArenasPerChunk = (GC_CHUNK_SIZE - sizeof(ChunkInfo)) / BytesPerArena; static const size_t ArenasPerChunk = (GC_CHUNK_SIZE - sizeof(ChunkInfo)) / BytesPerArena;
static const size_t MaxAge = 3;
Arena<FreeCell> arenas[ArenasPerChunk]; Arena<FreeCell> arenas[ArenasPerChunk];
ArenaBitmap bitmaps[ArenasPerChunk]; ArenaBitmap bitmaps[ArenasPerChunk];
@ -362,7 +361,6 @@ struct Chunk {
void releaseArena(Arena<T> *a); void releaseArena(Arena<T> *a);
JSRuntime *getRuntime(); JSRuntime *getRuntime();
bool expire();
}; };
JS_STATIC_ASSERT(sizeof(Chunk) <= GC_CHUNK_SIZE); JS_STATIC_ASSERT(sizeof(Chunk) <= GC_CHUNK_SIZE);
JS_STATIC_ASSERT(sizeof(Chunk) + Chunk::BytesPerArena > 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); JS_ASSERT(existingShape->getter() != getter);
if (!obj->methodReadBarrier(cx, *existingShape, &valueCopy)) if (!obj->methodReadBarrier(cx, *existingShape, &valueCopy))
return NULL; return false;
} }
} else { } else {
adding = true; adding = true;
@ -6794,20 +6794,30 @@ js_DumpId(jsid id)
} }
static void static void
DumpShape(const Shape &shape) DumpProperty(JSObject *obj, const Shape &shape)
{ {
jsid id = shape.id; jsid id = shape.id;
uint8 attrs = shape.attributes(); uint8 attrs = shape.attributes();
fprintf(stderr, " "); fprintf(stderr, " ((Shape *) %p) ", (void *) &shape);
if (attrs & JSPROP_ENUMERATE) fprintf(stderr, "enumerate "); if (attrs & JSPROP_ENUMERATE) fprintf(stderr, "enumerate ");
if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly "); if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly ");
if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent "); 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 (attrs & JSPROP_SHARED) fprintf(stderr, "shared ");
if (shape.isAlias()) fprintf(stderr, "alias "); 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)) if (JSID_IS_ATOM(id))
dumpString(JSID_TO_STRING(id)); dumpString(JSID_TO_STRING(id));
@ -6816,6 +6826,12 @@ DumpShape(const Shape &shape)
else else
fprintf(stderr, "unknown jsid %p", (void *) JSID_BITS(id)); fprintf(stderr, "unknown jsid %p", (void *) JSID_BITS(id));
fprintf(stderr, ": slot %d", shape.slot); 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"); fprintf(stderr, "\n");
} }
@ -6830,7 +6846,7 @@ js_DumpObject(JSObject *obj)
uint32 flags = obj->flags; uint32 flags = obj->flags;
if (flags & JSObject::DELEGATE) fprintf(stderr, " delegate"); if (flags & JSObject::DELEGATE) fprintf(stderr, " delegate");
if (flags & JSObject::SYSTEM) fprintf(stderr, " system"); 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::BRANDED) fprintf(stderr, " branded");
if (flags & JSObject::GENERIC) fprintf(stderr, " generic"); if (flags & JSObject::GENERIC) fprintf(stderr, " generic");
if (flags & JSObject::METHOD_BARRIER) fprintf(stderr, " method_barrier"); if (flags & JSObject::METHOD_BARRIER) fprintf(stderr, " method_barrier");
@ -6865,15 +6881,6 @@ js_DumpObject(JSObject *obj)
return; 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 "); fprintf(stderr, "proto ");
dumpValue(ObjectOrNullValue(obj->getProto())); dumpValue(ObjectOrNullValue(obj->getProto()));
fputc('\n', stderr); fputc('\n', stderr);
@ -6885,10 +6892,15 @@ js_DumpObject(JSObject *obj)
if (clasp->flags & JSCLASS_HAS_PRIVATE) if (clasp->flags & JSCLASS_HAS_PRIVATE)
fprintf(stderr, "private %p\n", obj->getPrivate()); 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 reservedEnd = JSCLASS_RESERVED_SLOTS(clasp);
unsigned slots = obj->slotSpan(); 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); fprintf(stderr, " %3d ", i);
if (i < reservedEnd) if (i < reservedEnd)
fprintf(stderr, "(reserved) "); fprintf(stderr, "(reserved) ");
@ -6896,6 +6908,15 @@ js_DumpObject(JSObject *obj)
dumpValue(obj->getSlot(i)); dumpValue(obj->getSlot(i));
fputc('\n', stderr); 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); fputc('\n', stderr);
} }

View File

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

View File

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

View File

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

View File

@ -10328,7 +10328,7 @@ class BoxArg
* argument values into the object as properties in case it is used after * argument values into the object as properties in case it is used after
* this frame returns. * this frame returns.
*/ */
JS_REQUIRES_STACK void JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::putActivationObjects() TraceRecorder::putActivationObjects()
{ {
JSStackFrame *const fp = cx->fp(); JSStackFrame *const fp = cx->fp();
@ -10336,7 +10336,20 @@ TraceRecorder::putActivationObjects()
bool have_call = fp->isFunctionFrame() && fp->fun()->isHeavyweight(); bool have_call = fp->isFunctionFrame() && fp->fun()->isHeavyweight();
if (!have_args && !have_call) 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 nformal = fp->numFormalArgs();
uintN nactual = fp->numActualArgs(); uintN nactual = fp->numActualArgs();
@ -10380,6 +10393,8 @@ TraceRecorder::putActivationObjects()
w.nameImmi(fp->numFormalArgs()), scopeChain_ins, cx_ins }; w.nameImmi(fp->numFormalArgs()), scopeChain_ins, cx_ins };
w.call(&js_PutCallObjectOnTrace_ci, args); w.call(&js_PutCallObjectOnTrace_ci, args);
} }
return ARECORD_CONTINUE;
} }
JS_REQUIRES_STACK AbortableRecordingStatus JS_REQUIRES_STACK AbortableRecordingStatus
@ -10572,7 +10587,7 @@ TraceRecorder::record_JSOP_RETURN()
return endLoop(); return endLoop();
} }
putActivationObjects(); CHECK_STATUS_A(putActivationObjects());
if (Probes::callTrackingActive(cx)) { if (Probes::callTrackingActive(cx)) {
LIns* args[] = { w.immi(0), w.nameImmpNonGC(cx->fp()->fun()), cx_ins }; LIns* args[] = { w.immi(0), w.nameImmpNonGC(cx->fp()->fun()), cx_ins };
@ -10639,7 +10654,7 @@ TraceRecorder::record_JSOP_IFNE()
} }
LIns* LIns*
TraceRecorder::newArguments(LIns* callee_ins, bool strict) TraceRecorder::newArguments(LIns* callee_ins)
{ {
LIns* global_ins = w.immpObjGC(globalObj); LIns* global_ins = w.immpObjGC(globalObj);
LIns* argc_ins = w.nameImmi(cx->fp()->numActualArgs()); 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); LIns* argsobj_ins = w.call(&js_NewArgumentsOnTrace_ci, args);
guard(false, w.eqp0(argsobj_ins), OOM_EXIT); 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; return argsobj_ins;
} }
@ -10668,14 +10676,15 @@ TraceRecorder::record_JSOP_ARGUMENTS()
if (fp->hasOverriddenArgs()) if (fp->hasOverriddenArgs())
RETURN_STOP_A("Can't trace |arguments| if |arguments| is assigned to"); 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* a_ins = getFrameObjPtr(fp->addressOfArgs());
LIns* args_ins; LIns* args_ins;
LIns* callee_ins = get(&fp->calleeValue()); LIns* callee_ins = get(&fp->calleeValue());
bool strict = fp->fun()->inStrictMode();
if (a_ins->isImmP()) { if (a_ins->isImmP()) {
// |arguments| is set to 0 by EnterFrame on this trace, so call to create it. // |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 { } else {
// Generate LIR to create arguments only if it has not already been created. // 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)) { if (isZero_ins->isImmI(0)) {
w.stAlloc(a_ins, mem_ins); w.stAlloc(a_ins, mem_ins);
} else if (isZero_ins->isImmI(1)) { } 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); w.stAlloc(call_ins, mem_ins);
} else { } else {
LIns* br1 = w.jtUnoptimizable(isZero_ins); LIns* br1 = w.jtUnoptimizable(isZero_ins);
@ -10693,7 +10702,7 @@ TraceRecorder::record_JSOP_ARGUMENTS()
LIns* br2 = w.j(NULL); LIns* br2 = w.j(NULL);
w.label(br1); w.label(br1);
LIns* call_ins = newArguments(callee_ins, strict); LIns* call_ins = newArguments(callee_ins);
w.stAlloc(call_ins, mem_ins); w.stAlloc(call_ins, mem_ins);
w.label(br2); w.label(br2);
} }
@ -12843,10 +12852,9 @@ GetPropertyWithNativeGetter(JSContext* cx, JSObject* obj, Shape* shape, Value* v
LeaveTraceIfGlobalObject(cx, obj); LeaveTraceIfGlobalObject(cx, obj);
#ifdef DEBUG #ifdef DEBUG
JSProperty* prop;
JSObject* pobj; JSObject* pobj;
JS_ASSERT(obj->lookupProperty(cx, shape->id, &pobj, &prop)); const Shape* shape2;
JS_ASSERT(prop == (JSProperty*) shape); JS_ASSERT_IF(SafeLookup(cx, obj, shape->id, &pobj, &shape2), shape == shape2);
#endif #endif
// Shape::get contains a special case for With objects. We can elide it // 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) { if (constructing) {
LIns* thisobj_ins; LIns* thisobj_ins;
CHECK_STATUS(createThis(fval.toObject(), get(&fval), &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 // 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; return ARECORD_CONTINUE;
} }
putActivationObjects(); CHECK_STATUS_A(putActivationObjects());
if (Probes::callTrackingActive(cx)) { if (Probes::callTrackingActive(cx)) {
LIns* args[] = { w.immi(0), w.nameImmpNonGC(cx->fp()->fun()), cx_ins }; 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); JS_ASSERT(cx->fp()->slots() + slot < cx->regs->sp - 1);
Value &arrayval = cx->fp()->slots()[slot]; Value &arrayval = cx->fp()->slots()[slot];
JS_ASSERT(arrayval.isObject()); JS_ASSERT(arrayval.isObject());
JS_ASSERT(arrayval.toObject().isDenseArray());
LIns *array_ins = get(&arrayval); LIns *array_ins = get(&arrayval);
Value &elt = stackval(-1); Value &elt = stackval(-1);
LIns *elt_ins = box_value_for_native_call(elt, get(&elt)); 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 RecordingStatus makeNumberUint32(nanojit::LIns* d, nanojit::LIns** num_ins);
JS_REQUIRES_STACK nanojit::LIns* stringify(const Value& v); 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 bool canCallImacro() const;
JS_REQUIRES_STACK RecordingStatus callImacro(jsbytecode* imacro); JS_REQUIRES_STACK RecordingStatus callImacro(jsbytecode* imacro);
@ -1482,7 +1482,7 @@ class TraceRecorder
VMSideExit* exit); VMSideExit* exit);
JS_REQUIRES_STACK RecordingStatus guardNativeConversion(Value& v); JS_REQUIRES_STACK RecordingStatus guardNativeConversion(Value& v);
JS_REQUIRES_STACK void clearReturningFrameFromNativeTracker(); 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, JS_REQUIRES_STACK RecordingStatus createThis(JSObject& ctor, nanojit::LIns* ctor_ins,
nanojit::LIns** thisobj_insp); nanojit::LIns** thisobj_insp);
JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee); 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); 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 #ifdef JS_THREADSAFE
/* /*
@ -4416,6 +4537,7 @@ static JSFunctionSpec shell_functions[] = {
JS_FN("evalcx", EvalInContext, 1,0), JS_FN("evalcx", EvalInContext, 1,0),
JS_FN("evalInFrame", EvalInFrame, 2,0), JS_FN("evalInFrame", EvalInFrame, 2,0),
JS_FN("shapeOf", ShapeOf, 1,0), JS_FN("shapeOf", ShapeOf, 1,0),
JS_FN("resolver", Resolver, 1,0),
#ifdef MOZ_CALLGRIND #ifdef MOZ_CALLGRIND
JS_FN("startCallgrind", js_StartCallgrind, 0,0), JS_FN("startCallgrind", js_StartCallgrind, 0,0),
JS_FN("stopCallgrind", js_StopCallgrind, 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" "evalInFrame(n,str,save) Evaluate 'str' in the nth up frame.\n"
" If 'save' (default false), save the frame chain", " If 'save' (default false), save the frame chain",
"shapeOf(obj) Get the shape of obj (an implementation detail)", "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 #ifdef MOZ_CALLGRIND
"startCallgrind() Start callgrind instrumentation", "startCallgrind() Start callgrind instrumentation",
"stopCallgrind() Stop 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/ url-prefix ../../jsreftest.html?test=ecma_5/Global/
fails-if(!xulRuntime.shell) script adding-global-var-nonextensible-error.js
script parseInt-01.js script parseInt-01.js
script parseFloat-01.js script parseFloat-01.js
script eval-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-5.js
script regress-627984-6.js script regress-627984-6.js
script regress-627984-7.js script regress-627984-7.js
script regress-630377.js
script regress-631723.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-624547.js
script regress-624968.js script regress-624968.js
script regress-626436.js script regress-626436.js
fails-if(xulRuntime.shell) script regress-633741.js
script regress-634210-1.js script regress-634210-1.js
script regress-634210-2.js script regress-634210-2.js
script regress-634210-3.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");