☠☠ backed out by 8bb016a281c0 ☠ ☠ | |
author | Bill McCloskey <wmccloskey@mozilla.com> |
Tue, 21 Dec 2010 15:54:25 -0800 | |
changeset 59910 | d75da3b1209855955b1081854fb469f728a422a4 |
parent 59909 | 8f24dc55e1696c83de795ed31ffbe43ac664e25e |
child 59911 | 8bb016a281c0911c309aba008e10c58b5c3a9289 |
push id | 17820 |
push user | cleary@mozilla.com |
push date | Tue, 04 Jan 2011 21:40:57 +0000 |
treeherder | mozilla-central@969691cfe40e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | lw |
bugs | 547327 |
milestone | 2.0b8pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
js/src/jsobj.cpp | file | annotate | diff | comparison | revisions | |
js/src/jsobj.h | file | annotate | diff | comparison | revisions | |
js/src/jsobjinlines.h | file | annotate | diff | comparison | revisions |
--- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -73,16 +73,17 @@ #include "jsscript.h" #include "jsstaticcheck.h" #include "jsstdint.h" #include "jsstr.h" #include "jstracer.h" #include "jsdbgapi.h" #include "json.h" #include "jswrapper.h" +#include "jstl.h" #include "jsinterpinlines.h" #include "jsscopeinlines.h" #include "jsscriptinlines.h" #include "jsobjinlines.h" #if JS_HAS_GENERATORS #include "jsiter.h" @@ -2813,20 +2814,61 @@ js_CreateThis(JSContext *cx, JSObject *c JSObject *parent = callee->getParent(); gc::FinalizeKind kind = NewObjectGCKind(cx, newclasp); JSObject *obj = NewObject<WithProto::Class>(cx, newclasp, proto, parent, kind); if (obj) obj->syncSpecialEquality(); return obj; } +static uintN +GuessObjectSizeFromConstructor(JSObject *callee) +{ + JSFunction *fun = callee->getFunctionPrivate(); + JSScript *script = fun->script(); + jsbytecode *pc = script->code; + jsbytecode *end = script->code + script->length; + uintN count = 0; + + while (pc < end) { + if (JSOp(*pc) == JSOP_SETPROP) + count++; + + const JSCodeSpec *cs = &js_CodeSpec[JSOp(*pc)]; + ptrdiff_t oplen = cs->length; + if (oplen < 0) + oplen = js_GetVariableBytecodeLength(pc); + pc += oplen; + } + + return count; +} + +static gc::FinalizeKind +GuessObjectGCKindByFlags(JSContext *cx, JSObject *callee, JSObject *proto, Class *clasp) +{ + gc::FinalizeKind kind; + if (proto && clasp == &js_ObjectClass) { + if (proto->hasStoredGCKind()) { + kind = gc::FinalizeKind(proto->getStoredGCKind()); + } else { + uintN count = GuessObjectSizeFromConstructor(callee); + kind = gc::GetGCObjectKind(count); + proto->setStoredGCKind(kind); + } + } else { + kind = NewObjectGCKind(cx, clasp); + } + return kind; +} + JSObject * js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto) { - gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass); + gc::FinalizeKind kind = GuessObjectGCKindByFlags(cx, callee, proto, &js_ObjectClass); return NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, callee->getParent(), kind); } JSObject * js_CreateThisForFunction(JSContext *cx, JSObject *callee) { Value protov; if (!callee->getProperty(cx, @@ -2934,17 +2976,17 @@ js_CreateThisFromTrace(JSContext *cx, Cl */ } } /* * FIXME: 561785 at least. Quasi-natives including XML objects prevent us * from easily or unconditionally calling NewNativeClassInstance here. */ - gc::FinalizeKind kind = NewObjectGCKind(cx, clasp); + gc::FinalizeKind kind = GuessObjectGCKindByFlags(cx, ctor, proto, &js_ObjectClass); return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind); } JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, CLASS, OBJECT, 0, nanojit::ACCSET_STORE_ANY) #else /* !JS_TRACER */ @@ -3966,16 +4008,27 @@ JSObject::growSlots(JSContext *cx, size_ actualCapacity = SLOT_CAPACITY_MIN; /* Don't let nslots get close to wrapping around uint32. */ if (actualCapacity >= NSLOTS_LIMIT) { JS_ReportOutOfMemory(cx); return false; } + /* This is a heuristic to make later constructor invocations use a larger size. */ + if (clasp == &js_ObjectClass && proto) { + uint32 stored; + if (proto->hasStoredGCKind()) + stored = GetGCKindSlots(gc::FinalizeKind(proto->getStoredGCKind())); + else + stored = actualCapacity; + uint32 slots = Max(actualCapacity, stored); + proto->setStoredGCKind(GetGCObjectKind(slots)); + } + /* If nothing was allocated yet, treat it as initial allocation. */ if (!hasSlotsArray()) return allocSlots(cx, actualCapacity); Value *tmpslots = (Value*) cx->realloc(slots, oldcap * sizeof(Value), actualCapacity * sizeof(Value)); if (!tmpslots) return false; /* Leave dslots as its old size. */ slots = tmpslots;
--- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -344,19 +344,32 @@ struct JSObject : js::gc::Cell { GENERIC = 0x10, METHOD_BARRIER = 0x20, INDEXED = 0x40, OWN_SHAPE = 0x80, BOUND_FUNCTION = 0x100, HAS_EQUALITY = 0x200, METHOD_THRASH_COUNT_MASK = 0xc00, METHOD_THRASH_COUNT_SHIFT = 10, - METHOD_THRASH_COUNT_MAX = METHOD_THRASH_COUNT_MASK >> METHOD_THRASH_COUNT_SHIFT + METHOD_THRASH_COUNT_MAX = METHOD_THRASH_COUNT_MASK >> METHOD_THRASH_COUNT_SHIFT, + + GCKIND_BIT0 = 0x20000000, + GCKIND_BIT1 = 0x40000000, + GCKIND_BIT2 = 0x80000000 }; + const static int32 FLAGS_GCKIND_SHIFT = 29; + const static uint32 FLAGS_GCKIND_MASK = 0xe0000000; + const static uint32 FLAGS_GCKIND_INITIAL = FLAGS_GCKIND_MASK; + + const static uint32 INITIAL_FLAGS = FLAGS_GCKIND_INITIAL; + + JS_STATIC_ASSERT(GCKIND_BIT0 == 1 << FLAGS_GCKIND_SHIFT); + JS_STATIC_ASSERT(FLAGS_GCKIND_MASK == (GCKIND_BIT0 | GCKIND_BIT1 | GCKIND_BIT2)); + /* * Impose a sane upper bound, originally checked only for dense arrays, on * number of slots in an object. */ enum { NSLOTS_BITS = 29, NSLOTS_LIMIT = JS_BIT(NSLOTS_BITS) }; @@ -449,16 +462,23 @@ struct JSObject : js::gc::Cell { bool hasSpecialEquality() const { return !!(flags & HAS_EQUALITY); } void assertSpecialEqualitySynced() const { JS_ASSERT(!!clasp->ext.equality == hasSpecialEquality()); } /* Sets an object's HAS_EQUALITY flag based on its clasp. */ inline void syncSpecialEquality(); + bool hasStoredGCKind() { return (flags & FLAGS_GCKIND_MASK) != FLAGS_GCKIND_INITIAL; } + unsigned /* gc::FinalizeKind */ getStoredGCKind() { return flags >> FLAGS_GCKIND_SHIFT; } + void setStoredGCKind(unsigned /* gc::FinalizeKind */ kind) { + flags = (flags & ~FLAGS_GCKIND_MASK) | (kind << FLAGS_GCKIND_SHIFT); + JS_ASSERT(getStoredGCKind() == kind); + } + private: void generateOwnShape(JSContext *cx); void setOwnShape(uint32 s) { flags |= OWN_SHAPE; objShape = s; } void clearOwnShape() { flags &= ~OWN_SHAPE; objShape = map->shape; } public: inline bool nativeEmpty() const; @@ -578,17 +598,17 @@ struct JSObject : js::gc::Cell { inline js::Value* fixedSlots() const; inline size_t numFixedSlots() const; static inline size_t getFixedSlotOffset(size_t slot); public: /* Minimum size for dynamically allocated slots. */ - static const uint32 SLOT_CAPACITY_MIN = 8; + static const uint32 SLOT_CAPACITY_MIN = 2; bool allocSlots(JSContext *cx, size_t nslots); bool growSlots(JSContext *cx, size_t nslots); void shrinkSlots(JSContext *cx, size_t nslots); bool ensureSlots(JSContext *cx, size_t nslots) { if (numSlots() < nslots) return growSlots(cx, nslots);
--- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -629,17 +629,17 @@ JSObject::setWithThis(JSObject *thisp) getSlotRef(JSSLOT_WITH_THIS).setObject(*thisp); } inline void JSObject::init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *parent, void *priv, bool useHoles) { clasp = aclasp; - flags = 0; + flags = INITIAL_FLAGS; #ifdef DEBUG /* * NB: objShape must not be set here; rather, the caller must call setMap * or setSharedNonNativeMap after calling init. To defend this requirement * we set map to null in DEBUG builds, and set objShape to a value we then * assert obj->shape() never returns. */