[INFER] Fix OOM handling in type inference, convert inference to runtime option, bug 637674.

This commit is contained in:
Brian Hackett 2011-03-03 14:07:48 -08:00
parent 70aee16fea
commit 41091b1bb6
59 changed files with 2233 additions and 1955 deletions

View File

@ -915,6 +915,7 @@ static const char js_methodjit_chrome_str[] = JS_OPTIONS_DOT_STR "methodjit.ch
static const char js_profiling_content_str[] = JS_OPTIONS_DOT_STR "jitprofiling.content";
static const char js_profiling_chrome_str[] = JS_OPTIONS_DOT_STR "jitprofiling.chrome";
static const char js_methodjit_always_str[] = JS_OPTIONS_DOT_STR "methodjit_always";
static const char js_typeinfer_str[] = JS_OPTIONS_DOT_STR "typeinference";
static const char js_memlog_option_str[] = JS_OPTIONS_DOT_STR "mem.log";
int
@ -947,6 +948,7 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
js_profiling_chrome_str :
js_profiling_content_str);
PRBool useMethodJITAlways = nsContentUtils::GetBoolPref(js_methodjit_always_str);
PRBool useTypeInference = !chromeWindow && nsContentUtils::GetBoolPref(js_typeinfer_str);
nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
if (xr) {
PRBool safeMode = PR_FALSE;
@ -955,6 +957,7 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
useTraceJIT = PR_FALSE;
useMethodJIT = PR_FALSE;
useProfiling = PR_FALSE;
useTypeInference = PR_FALSE;
useMethodJITAlways = PR_TRUE;
}
}
@ -979,6 +982,11 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
else
newDefaultJSOptions &= ~JSOPTION_METHODJIT_ALWAYS;
if (useTypeInference)
newDefaultJSOptions |= JSOPTION_TYPE_INFERENCE;
else
newDefaultJSOptions &= ~JSOPTION_TYPE_INFERENCE;
#ifdef DEBUG
// In debug builds, warnings are enabled in chrome context if
// javascript.options.strict.debug is true

View File

@ -147,6 +147,7 @@ CPPSRCS = \
jsgcchunk.cpp \
jsgcstats.cpp \
jshash.cpp \
jsinfer.cpp \
jsinterp.cpp \
jsinvoke.cpp \
jsiter.cpp \
@ -488,10 +489,6 @@ ifeq (,$(filter-out WINNT WINCE,$(OS_ARCH)))
INSTALLED_HEADERS += jscpucfg.h
endif
ifdef JS_TYPE_INFERENCE
CPPSRCS += jsinfer.cpp
endif
EXPORTS = $(INSTALLED_HEADERS)
DASH_R = -r

View File

@ -91,7 +91,6 @@ MOZ_SHARK = @MOZ_SHARK@
MOZ_CALLGRIND = @MOZ_CALLGRIND@
MOZ_VTUNE = @MOZ_VTUNE@
JS_HAS_CTYPES = @JS_HAS_CTYPES@
JS_TYPE_INFERENCE = @JS_TYPE_INFERENCE@
DEHYDRA_PATH = @DEHYDRA_PATH@
NS_TRACE_MALLOC = @NS_TRACE_MALLOC@

View File

@ -5011,18 +5011,6 @@ if test -n "$MOZ_TRACE_JSCALLS"; then
AC_DEFINE(MOZ_TRACE_JSCALLS)
fi
dnl ========================================================
dnl = Enable type inference
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(type-inference,
[ --enable-type-inference Enable JS type inference (default=no)],
JS_TYPE_INFERENCE=1,
JS_TYPE_INFERENCE= )
if test -n "$JS_TYPE_INFERENCE"; then
AC_DEFINE(JS_TYPE_INFERENCE)
fi
AC_SUBST(JS_TYPE_INFERENCE)
dnl ========================================================
dnl = Use TraceVis
dnl ========================================================

View File

@ -295,7 +295,7 @@ def parse_jitflags():
for flags in OPTIONS.jitflags.split(',') ]
for flags in jitflags:
for flag in flags:
if flag not in ('-j', '-m', '-p', '-d'):
if flag not in ('-j', '-m', '-p', '-d', '-n'):
print('Invalid jit flag: "%s"'%flag)
sys.exit(1)
return jitflags

View File

@ -51,9 +51,6 @@
/* Define to 1 if SpiderMonkey should include ctypes support. */
#undef JS_HAS_CTYPES
/* Define to 1 if SpiderMonkey should perform type inference. */
#undef JS_TYPE_INFERENCE
/* Define to 1 if SpiderMonkey should support the ability to perform
entirely too much GC. */
#undef JS_GC_ZEAL

View File

@ -42,427 +42,6 @@
#include "jscompartment.h"
#include "jscntxt.h"
#include "jsinferinlines.h"
#include "jsobjinlines.h"
/////////////////////////////////////////////////////////////////////
// TypeCompartment
/////////////////////////////////////////////////////////////////////
/*
* These are the definitions needed for skeleton TypeCompartments and TypeObjects
* as used when type inference is disabled.
*/
namespace js {
namespace types {
void
TypeCompartment::init()
{
PodZero(this);
#ifdef DEBUG
emptyObject.name_ = JSID_VOID;
#endif
emptyObject.unknownProperties = true;
}
types::TypeObject *
TypeCompartment::newTypeObject(JSContext *cx, JSScript *script, const char *name,
bool isFunction, JSObject *proto)
{
#ifdef DEBUG
#if 1 /* Define to get unique printed names, including when there are multiple globals. */
static unsigned nameCount = 0;
unsigned len = strlen(name) + 15;
char *newName = (char *) alloca(len);
JS_snprintf(newName, len, "%u:%s", ++nameCount, name);
name = newName;
#endif
jsid id = ATOM_TO_JSID(js_Atomize(cx, name, strlen(name), ATOM_PINNED));
#else
jsid id = JSID_VOID;
#endif
TypeObject *object;
if (isFunction) {
object = (TypeFunction *) cx->calloc(sizeof(TypeFunction));
new(object) TypeFunction(id, proto);
} else {
object = (TypeObject *) cx->calloc(sizeof(TypeObject));
new(object) TypeObject(id, proto);
}
#ifdef JS_TYPE_INFERENCE
TypeObject *&objects = script ? script->typeObjects : this->objects;
object->next = objects;
objects = object;
#else
object->next = this->objects;
this->objects = object;
#endif
return object;
}
#ifdef JS_TYPE_INFERENCE
TypeObject *
TypeCompartment::newInitializerTypeObject(JSContext *cx, JSScript *script,
uint32 offset, bool isArray)
{
char *name = NULL;
#ifdef DEBUG
name = (char *) alloca(40);
JS_snprintf(name, 40, "#%lu:%lu:%s", script->id(), offset, isArray ? "Array" : "Object");
#endif
JSObject *proto;
JSProtoKey key = isArray ? JSProto_Array : JSProto_Object;
if (!js_GetClassPrototype(cx, script->getGlobal(), key, &proto, NULL))
return NULL;
TypeObject *res = newTypeObject(cx, script, name, false, proto);
if (isArray)
res->initializerArray = true;
else
res->initializerObject = true;
res->initializerOffset = offset;
return res;
}
#endif
const char *
TypeIdStringImpl(jsid id)
{
if (JSID_IS_VOID(id))
return "(index)";
if (JSID_IS_EMPTY(id))
return "(new)";
static char bufs[4][100];
static unsigned which = 0;
which = (which + 1) & 3;
PutEscapedString(bufs[which], 100, JSID_TO_FLAT_STRING(id), 0);
return bufs[which];
}
void
TypeObject::splicePrototype(JSContext *cx, JSObject *proto)
{
JS_ASSERT(!this->proto);
this->proto = proto;
this->instanceNext = proto->getType()->instanceList;
proto->getType()->instanceList = this;
/*
* Note: we require (but do not assert) that any property in the prototype
* or its own prototypes must not share a name with a property already
* added to an instance of this object.
*/
#ifdef JS_TYPE_INFERENCE
if (propertyCount >= 2) {
unsigned capacity = HashSetCapacity(propertyCount);
for (unsigned i = 0; i < capacity; i++) {
Property *prop = propertySet[i];
if (prop)
getFromPrototypes(cx, prop);
}
} else if (propertyCount == 1) {
Property *prop = (Property *) propertySet;
getFromPrototypes(cx, prop);
}
#endif
}
} } /* namespace js::types */
js::types::TypeFunction *
JSContext::newTypeFunction(const char *name, JSObject *proto)
{
return (js::types::TypeFunction *) compartment->types.newTypeObject(this, NULL, name, true, proto);
}
js::types::TypeObject *
JSContext::newTypeObject(const char *name, JSObject *proto)
{
return compartment->types.newTypeObject(this, NULL, name, false, proto);
}
js::types::TypeObject *
JSContext::newTypeObject(const char *base, const char *postfix, JSObject *proto)
{
char *name = NULL;
#ifdef DEBUG
unsigned len = strlen(base) + strlen(postfix) + 5;
name = (char *)alloca(len);
JS_snprintf(name, len, "%s:%s", base, postfix);
#endif
return compartment->types.newTypeObject(this, NULL, name, false, proto);
}
void
JSObject::makeNewType(JSContext *cx)
{
JS_ASSERT(!newType);
setDelegate();
newType = cx->newTypeObject(getType()->name(), "new", this);
#ifdef JS_TYPE_INFERENCE
if (!getType()->unknownProperties) {
/* Update the possible 'new' types for all prototype objects sharing the same type object. */
js::types::TypeSet *types = getType()->getProperty(cx, JSID_EMPTY, true);
cx->compartment->types.addDynamicType(cx, types, (js::types::jstype) newType);
}
#endif
}
/////////////////////////////////////////////////////////////////////
// Tracing
/////////////////////////////////////////////////////////////////////
namespace js {
namespace types {
void
types::TypeObject::trace(JSTracer *trc)
{
JS_ASSERT(!marked);
/*
* Only mark types if the Mark/Sweep GC is running; the bit won't be cleared
* by the cycle collector.
*/
if (trc->context->runtime->gcMarkAndSweep)
marked = true;
if (emptyShapes) {
int count = gc::FINALIZE_OBJECT_LAST - gc::FINALIZE_OBJECT0 + 1;
for (int i = 0; i < count; i++) {
if (emptyShapes[i])
emptyShapes[i]->trace(trc);
}
}
if (proto)
gc::MarkObject(trc, *proto, "type_proto");
}
#ifdef JS_TYPE_INFERENCE
/*
* Condense any constraints on a type set which were generated during analysis
* of a script, and sweep all type objects and references to type objects
* which no longer exist.
*/
void
CondenseSweepTypeSet(JSContext *cx, HashSet<JSScript*> &condensed, TypeSet *types)
{
if (types->objectCount >= 2) {
bool removed = false;
unsigned objectCapacity = HashSetCapacity(types->objectCount);
for (unsigned i = 0; i < objectCapacity; i++) {
TypeObject *object = types->objectSet[i];
if (object && !object->marked) {
removed = true;
types->objectSet[i] = NULL;
}
}
if (removed) {
/* Reconstruct the type set to re-resolve hash collisions. */
TypeObject **oldArray = types->objectSet;
types->objectSet = NULL;
types->objectCount = 0;
for (unsigned i = 0; i < objectCapacity; i++) {
TypeObject *object = oldArray[i];
if (object) {
TypeObject *&entry = HashSetInsert<TypeObject *,TypeObject,TypeObjectKey>
(cx, types->objectSet, types->objectCount, object);
entry = object;
}
}
cx->free(oldArray);
}
} else if (types->objectCount == 1) {
TypeObject *object = (TypeObject*) types->objectSet;
if (!object->marked) {
types->objectSet = NULL;
types->objectCount = 0;
}
}
TypeConstraint *constraint = types->constraintList;
types->constraintList = NULL;
/*
* Keep track of all the scripts we have found or generated
* condensed constraints for, in the condensed table. We reuse the
* same table for each type set to avoid extra initialization cost,
* but the table is emptied after each set is processed.
*/
while (constraint) {
TypeConstraint *next = constraint->next;
TypeObject *object = constraint->baseSubset();
if (object) {
/*
* Constraint propagating data between objects. If the target
* is not being collected (these are weak references) then
* keep the constraint.
*/
if (object->marked) {
constraint->next = types->constraintList;
types->constraintList = constraint;
} else {
cx->free(constraint);
}
constraint = next;
continue;
}
/*
* Throw away constraints propagating types into scripts which
* are about to be destroyed. :FIXME: not handling eval-cache
* scripts right, which have already been destroyed and can
* lead to use of garbage pointers here.
*/
JSScript *script = constraint->script;
if (script->isCachedEval ||
(script->u.object && IsAboutToBeFinalized(cx, script->u.object)) ||
(script->fun && IsAboutToBeFinalized(cx, script->fun))) {
if (constraint->condensed())
cx->free(constraint);
constraint = next;
continue;
}
HashSet<JSScript*>::AddPtr p =
condensed.lookupForAdd(script);
if (!p) {
if (!condensed.add(p, script))
JS_NOT_REACHED("FIXME");
types->addCondensed(cx, script);
}
if (constraint->condensed())
cx->free(constraint);
constraint = next;
}
condensed.clear();
}
void
CondenseTypeObjectList(JSContext *cx, TypeObject *objects)
{
HashSet<JSScript *> condensed(cx);
if (!condensed.init())
JS_NOT_REACHED("FIXME");
TypeObject *object = objects;
while (object) {
if (object->propertyCount >= 2) {
unsigned capacity = HashSetCapacity(object->propertyCount);
for (unsigned i = 0; i < capacity; i++) {
Property *prop = object->propertySet[i];
if (prop) {
CondenseSweepTypeSet(cx, condensed, &prop->types);
CondenseSweepTypeSet(cx, condensed, &prop->ownTypes);
}
}
} else if (object->propertyCount == 1) {
Property *prop = (Property *) object->propertySet;
CondenseSweepTypeSet(cx, condensed, &prop->types);
CondenseSweepTypeSet(cx, condensed, &prop->ownTypes);
}
object = object->next;
}
}
static void
DestroyTypeSet(JSContext *cx, const TypeSet &types)
{
if (types.objectCount >= 2)
cx->free(types.objectSet);
}
static void
DestroyProperty(JSContext *cx, Property *prop)
{
DestroyTypeSet(cx, prop->types);
DestroyTypeSet(cx, prop->ownTypes);
cx->free(prop);
}
#endif /* JS_TYPE_INFERENCE */
void
SweepTypeObjectList(JSContext *cx, TypeObject *&objects)
{
TypeObject **pobject = &objects;
while (*pobject) {
TypeObject *object = *pobject;
if (object->marked) {
object->marked = false;
pobject = &object->next;
} else {
if (object->emptyShapes)
cx->free(object->emptyShapes);
*pobject = object->next;
#ifdef JS_TYPE_INFERENCE
if (object->propertyCount >= 2) {
unsigned capacity = HashSetCapacity(object->propertyCount);
for (unsigned i = 0; i < capacity; i++) {
Property *prop = object->propertySet[i];
if (prop)
DestroyProperty(cx, prop);
}
cx->free(object->propertySet);
} else if (object->propertyCount == 1) {
Property *prop = (Property *) object->propertySet;
DestroyProperty(cx, prop);
}
#endif
cx->free(object);
}
}
}
} } /* namespace js::types */
void
JSScript::condenseTypes(JSContext *cx)
{
#ifdef JS_TYPE_INFERENCE
js::types::CondenseTypeObjectList(cx, typeObjects);
if (varTypes) {
js::HashSet<JSScript *> condensed(cx);
if (!condensed.init())
JS_NOT_REACHED("FIXME");
unsigned num = 2 + nfixed + (fun ? fun->nargs : 0) + bindings.countUpvars();
for (unsigned i = 0; i < num; i++)
js::types::CondenseSweepTypeSet(cx, condensed, &varTypes[i]);
}
#endif
}
void
JSScript::sweepTypes(JSContext *cx)
{
#ifdef JS_TYPE_INFERENCE
SweepTypeObjectList(cx, typeObjects);
if (types)
js::types::DestroyScriptTypes(cx, this);
#endif
}
namespace js {
namespace analyze {
@ -575,7 +154,7 @@ Script::addJump(JSContext *cx, unsigned offset,
Bytecode *&code = codeArray[offset];
bool initial = (code == NULL);
if (initial) {
code = ArenaNew<Bytecode>(pool, this, offset);
code = ArenaNew<Bytecode>(pool);
if (!code) {
setOOM(cx);
return false;
@ -721,7 +300,7 @@ Script::analyze(JSContext *cx, JSScript *script)
unsigned forwardCatch = 0;
/* Fill in stack depth and definitions at initial bytecode. */
Bytecode *startcode = ArenaNew<Bytecode>(pool, this, 0);
Bytecode *startcode = ArenaNew<Bytecode>(pool);
if (!startcode) {
setOOM(cx);
return;
@ -939,11 +518,11 @@ Script::analyze(JSContext *cx, JSScript *script)
break;
case JSOP_CALLLOCAL:
case JSOP_GETLOCALPROP:
case JSOP_INCLOCAL:
case JSOP_DECLOCAL:
case JSOP_LOCALINC:
case JSOP_LOCALDEC:
case JSOP_GETLOCALPROP: {
case JSOP_LOCALDEC: {
uint32 local = GET_SLOTNO(pc);
if (local < nfixed && !localDefined(local, offset))
setLocal(local, LOCAL_USE_BEFORE_DEF);
@ -1029,7 +608,7 @@ Script::analyze(JSContext *cx, JSScript *script)
bool initial = (nextcode == NULL);
if (initial) {
nextcode = ArenaNew<Bytecode>(pool, this, successorOffset);
nextcode = ArenaNew<Bytecode>(pool);
if (!nextcode) {
setOOM(cx);
return;
@ -1106,6 +685,8 @@ LifetimeScript::analyze(JSContext *cx, analyze::Script *analysis, JSScript *scri
PodZero(&thisVar);
saved = ArenaArray<LifetimeVariable*>(pool, script->nfixed + (fun ? fun->nargs : 0));
if (!saved)
return false;
savedCount = 0;
uint32 offset = script->length - 1;

View File

@ -95,7 +95,7 @@ struct Bytecode
uint32 defineCount;
uint32 *defineArray;
Bytecode(Script *script, unsigned offset)
Bytecode()
{
PodZero(this);
}
@ -108,8 +108,8 @@ struct Bytecode
bool isDefined(uint32 slot)
{
JS_ASSERT(analyzed);
for (unsigned ind = 0; ind < defineCount; ind++) {
if (defineArray[ind] == slot)
for (unsigned i = 0; i < defineCount; i++) {
if (defineArray[i] == slot)
return true;
}
return false;

View File

@ -83,10 +83,6 @@ DEFINES += -DEXPORT_JS_API
LIBS = $(DEPTH)/$(LIB_PREFIX)js_static.$(LIB_SUFFIX) $(NSPR_LIBS)
ifdef JS_TYPE_INFERENCE
LIBS += -lz
endif
LOCAL_INCLUDES += -I$(topsrcdir) -I..
ifdef _MSC_VER

View File

@ -47,19 +47,13 @@ int main(int argc, char *argv[])
{
int total = 0;
int failures = 0;
const char *filter = (argc == 2) ? argv[1] : NULL;
JS_SetCStringsAreUTF8();
for (JSAPITest *test = JSAPITest::list; test; test = test->next) {
const char *name = test->name();
bool run = (argc <= 1); // if no params, run everything
for (int i = 1; i < argc; i++)
{
const char *filter = argv[i];
if (filter && strstr(name, filter) != NULL)
run = true;
}
if (!run)
if (filter && strstr(name, filter) == NULL)
continue;
total += 1;

View File

@ -653,7 +653,7 @@ JSRuntime::init(uint32 maxbytes)
#endif
if (!(atomsCompartment = js_new<JSCompartment>(this)) ||
!atomsCompartment->init() ||
!atomsCompartment->init(NULL) ||
!compartments.append(atomsCompartment)) {
return false;
}
@ -2985,7 +2985,8 @@ JS_NewGlobalObject(JSContext *cx, JSClass *clasp)
return NULL;
}
cx->addTypeProperty(obj->getType(), js_undefined_str, UndefinedValue());
if (!cx->addTypeProperty(obj->getType(), js_undefined_str, UndefinedValue()))
return NULL;
return obj;
}
@ -3023,7 +3024,8 @@ JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent);
if (obj) {
obj->syncSpecialEquality();
cx->markTypeObjectUnknownProperties(obj->getType());
if (!cx->markTypeObjectUnknownProperties(obj->getType()))
return NULL;
}
JS_ASSERT_IF(obj, obj->getParent());
@ -3047,7 +3049,8 @@ JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSO
JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
if (obj) {
obj->syncSpecialEquality();
cx->markTypeObjectUnknownProperties(obj->getType());
if (!cx->markTypeObjectUnknownProperties(obj->getType()))
return NULL;
}
return obj;
}
@ -3124,16 +3127,16 @@ JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *proto
return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv));
}
JS_PUBLIC_API(void)
JS_PUBLIC_API(JSBool)
JS_AddTypeProperty(JSContext *cx, JSObject *obj, const char *name, jsval value)
{
cx->addTypeProperty(obj->getType(), name, Valueify(value));
return cx->addTypeProperty(obj->getType(), name, Valueify(value));
}
JS_PUBLIC_API(void)
JS_PUBLIC_API(JSBool)
JS_AddTypePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value)
{
cx->addTypePropertyId(obj->getType(), id, Valueify(value));
return cx->addTypePropertyId(obj->getType(), id, Valueify(value));
}
static JSBool
@ -3401,9 +3404,10 @@ DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namele
uintN flags, intN tinyid)
{
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
cx->addTypePropertyId(obj->getType(), ATOM_TO_JSID(atom), value);
return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
flags, tinyid);
if (!atom || !cx->addTypePropertyId(obj->getType(), ATOM_TO_JSID(atom), value))
return false;
return DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
flags, tinyid);
}
JS_PUBLIC_API(JSBool)
@ -3446,7 +3450,8 @@ JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp
if (!nobj)
return NULL;
cx->addTypeProperty(obj->getType(), name, ObjectValue(*nobj));
if (!cx->addTypeProperty(obj->getType(), name, ObjectValue(*nobj)))
return NULL;
nobj->syncSpecialEquality();
if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
@ -3463,11 +3468,12 @@ JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
CHECK_REQUEST(cx);
for (ok = JS_TRUE; cds->name; cds++) {
if (!cx->addTypeProperty(obj->getType(), cds->name, TYPE_DOUBLE))
return false;
Value value = DoubleValue(cds->dval);
attrs = cds->flags;
if (!attrs)
attrs = JSPROP_READONLY | JSPROP_PERMANENT;
cx->addTypeProperty(obj->getType(), cds->name, value);
ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
if (!ok)
break;
@ -3481,14 +3487,7 @@ JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
JSBool ok;
for (ok = true; ps->name; ps++) {
ok = DefineProperty(cx, obj, ps->name, UndefinedValue(),
Valueify(ps->getter), Valueify(ps->setter),
ps->flags, Shape::HAS_SHORTID, ps->tinyid);
if (!ok)
break;
#ifdef JS_TYPE_INFERENCE
if (ps->handler) {
if (cx->typeInferenceEnabled() && ps->handler) {
jstype type = 0;
if (ps->handler == JS_TypeHandlerBool)
type = TYPE_BOOLEAN;
@ -3500,9 +3499,16 @@ JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
type = TYPE_STRING;
JS_ASSERT(type);
cx->addTypeProperty(obj->getType(), ps->name, type);
ok = cx->addTypeProperty(obj->getType(), ps->name, type);
if (!ok)
break;
}
#endif
ok = DefineProperty(cx, obj, ps->name, UndefinedValue(),
Valueify(ps->getter), Valueify(ps->setter),
ps->flags, Shape::HAS_SHORTID, ps->tinyid);
if (!ok)
break;
}
return ok;
}
@ -3527,6 +3533,7 @@ JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *ali
js_ReportIsNotDefined(cx, name);
return JS_FALSE;
}
if (obj2 != obj || !obj->isNative()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
alias, name, obj2->getClass()->name);
@ -3536,6 +3543,10 @@ JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *ali
if (!aliasAtom) {
ok = JS_FALSE;
} else {
/* Alias the properties within the type information for the object. */
if (!cx->aliasTypeProperties(obj->getType(), ATOM_TO_JSID(nameAtom), ATOM_TO_JSID(aliasAtom)))
return JS_FALSE;
shape = (Shape *)prop;
ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(aliasAtom),
shape->getter(), shape->setter(), shape->slot,
@ -3544,9 +3555,6 @@ JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *ali
!= NULL);
}
/* Alias the properties within the type information for the object. */
cx->aliasTypeProperties(obj->getType(), ATOM_TO_JSID(nameAtom), ATOM_TO_JSID(aliasAtom));
return ok;
}
@ -3811,7 +3819,8 @@ JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
assertSameCompartment(cx, obj, id);
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
cx->addTypePropertyId(obj->getType(), id, Valueify(*vp));
if (!cx->addTypePropertyId(obj->getType(), id, Valueify(*vp)))
return false;
return obj->setProperty(cx, id, Valueify(vp), false);
}
@ -4315,7 +4324,8 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
Value v;
if (!obj->getProperty(cx, r.front().id, &v))
return NULL;
fun->script()->typeSetUpvar(cx, i, v);
if (!fun->script()->typeSetUpvar(cx, i, v))
return NULL;
clone->getFlatClosureUpvars()[i] = v;
}
@ -4330,80 +4340,67 @@ JS_TypeHandlerDynamic(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssi
JS_PUBLIC_API(void) JS_TypeHandlerVoid(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (site->returnTypes) {
if (site->isNew)
site->returnTypes->addType(cx, TYPE_UNKNOWN);
site->returnTypes->addType(cx, TYPE_UNDEFINED);
}
#endif
}
JS_PUBLIC_API(void) JS_TypeHandlerNull(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (site->returnTypes) {
if (site->isNew)
site->returnTypes->addType(cx, TYPE_UNKNOWN);
site->returnTypes->addType(cx, TYPE_NULL);
}
#endif
}
JS_PUBLIC_API(void) JS_TypeHandlerBool(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (site->returnTypes) {
if (site->isNew)
site->returnTypes->addType(cx, TYPE_UNKNOWN);
site->returnTypes->addType(cx, TYPE_BOOLEAN);
}
#endif
}
JS_PUBLIC_API(void) JS_TypeHandlerInt(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (site->returnTypes) {
if (site->isNew)
site->returnTypes->addType(cx, TYPE_UNKNOWN);
site->returnTypes->addType(cx, TYPE_INT32);
}
#endif
}
JS_PUBLIC_API(void) JS_TypeHandlerFloat(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (site->returnTypes) {
if (site->isNew)
site->returnTypes->addType(cx, TYPE_UNKNOWN);
site->returnTypes->addType(cx, TYPE_DOUBLE);
}
#endif
}
JS_PUBLIC_API(void) JS_TypeHandlerString(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (site->returnTypes) {
if (site->isNew)
site->returnTypes->addType(cx, TYPE_UNKNOWN);
site->returnTypes->addType(cx, TYPE_STRING);
}
#endif
}
JS_PUBLIC_API(void)
JS_TypeHandlerNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeFunction *fun = Valueify(jsfun);
TypeCallsite *site = Valueify(jssite);
@ -4412,14 +4409,14 @@ JS_TypeHandlerNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
TypeSet *prototypeTypes =
fun->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), true);
if (!prototypeTypes)
return;
prototypeTypes->addNewObject(cx, site->script, fun, site->returnTypes);
#endif
}
JS_PUBLIC_API(void)
JS_TypeHandlerThis(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (site->returnTypes) {
@ -4430,7 +4427,6 @@ JS_TypeHandlerThis(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
else
site->returnTypes->addType(cx, site->thisType);
}
#endif
}
JS_PUBLIC_API(JSObject *)
@ -4541,10 +4537,10 @@ JS_DefineFunctionsWithPrefix(JSContext *cx, JSObject *obj, JSFunctionSpec *fs,
if (!fun)
return JS_FALSE;
#ifdef JS_TYPE_INFERENCE
/* Mark the type handler for this function as generic. */
fun->getType()->asFunction()->isGeneric = true;
#endif
if (cx->typeInferenceEnabled()) {
/* Mark the type handler for this function as generic. */
fun->getType()->asFunction()->isGeneric = true;
}
/*
* As jsapi.h notes, fs must point to storage that lives as long

View File

@ -959,10 +959,12 @@ JS_StringToVersion(const char *string);
JS_BIT(16) /* Always whole-method JIT,
don't tune at run-time. */
#define JSOPTION_TYPE_INFERENCE JS_BIT(17) /* Perform type inference. */
/* Options which reflect compile-time properties of scripts. */
#define JSCOMPILEOPTION_MASK (JSOPTION_XML | JSOPTION_ANONFUNFIX)
#define JSRUNOPTION_MASK (JS_BITMASK(17) & ~JSCOMPILEOPTION_MASK)
#define JSRUNOPTION_MASK (JS_BITMASK(18) & ~JSCOMPILEOPTION_MASK)
#define JSALLOPTION_MASK (JSCOMPILEOPTION_MASK | JSRUNOPTION_MASK)
extern JS_PUBLIC_API(uint32)
@ -2246,10 +2248,10 @@ JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JS
/* Add properties to the type information for obj. */
extern JS_PUBLIC_API(void)
extern JS_PUBLIC_API(JSBool)
JS_AddTypeProperty(JSContext *cx, JSObject *obj, const char *name, jsval value);
extern JS_PUBLIC_API(void)
extern JS_PUBLIC_API(JSBool)
JS_AddTypePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value);
static JS_ALWAYS_INLINE JSBool

View File

@ -306,7 +306,7 @@ ArenaNew(JSArenaPool &pool)
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, sizeof(T));
return new (v) T();
return v ? new (v) T() : NULL;
}
template <typename T, typename A>
@ -315,7 +315,7 @@ ArenaNew(JSArenaPool &pool, const A &a)
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, sizeof(T));
return new (v) T(a);
return v ? new (v) T(a) : NULL;
}
template <typename T, typename A, typename B>
@ -324,7 +324,7 @@ ArenaNew(JSArenaPool &pool, const A &a, const B &b)
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, sizeof(T));
return new (v) T(a, b);
return v ? new (v) T(a, b) : NULL;
}
template <typename T, typename A, typename B, typename C>
@ -333,7 +333,7 @@ ArenaNew(JSArenaPool &pool, const A &a, const B &b, const C &c)
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, sizeof(T));
return new (v) T(a, b, c);
return v ? new (v) T(a, b, c) : NULL;
}
template <typename T, typename A, typename B, typename C, typename D>
@ -342,7 +342,7 @@ ArenaNew(JSArenaPool &pool, const A &a, const B &b, const C &c, const D &d)
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, sizeof(T));
return new (v) T(a, b, c, d);
return v ? new (v) T(a, b, c, d) : NULL;
}
template <typename T, typename A, typename B, typename C, typename D, typename E>
@ -351,7 +351,7 @@ ArenaNew(JSArenaPool &pool, const A &a, const B &b, const C &c, const D &d, cons
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, sizeof(T));
return new (v) T(a, b, c, d, e);
return v ? new (v) T(a, b, c, d, e) : NULL;
}
} /* namespace js */

View File

@ -466,7 +466,7 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, const Value &v)
if (result != JSObject::ED_OK)
break;
if (idx >= obj->getArrayLength())
obj->setArrayLength(cx, idx + 1);
obj->setDenseArrayLength(idx + 1);
obj->setDenseArrayElement(idx, v);
return true;
} while (false);
@ -505,7 +505,7 @@ js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i)
*/
obj->setDenseArrayElement(i, UndefinedValue());
if (u >= obj->getArrayLength())
obj->setArrayLength(cx, u + 1);
obj->setDenseArrayLength(u + 1);
/* Partially check the CallInfo's storeAccSet is correct. */
JS_ASSERT(obj->clasp == origObjClasp);
@ -537,8 +537,9 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, bool strict)
if (index <= jsuint(-1)) {
jsuint idx = jsuint(index);
if (idx < obj->getDenseArrayInitializedLength()) {
if (!obj->setDenseArrayNotPacked(cx))
return -1;
obj->setDenseArrayElement(idx, MagicValue(JS_ARRAY_HOLE));
obj->setDenseArrayNotPacked(cx);
if (!js_SuppressDeletedIndexProperties(cx, obj, idx, idx+1))
return -1;
}
@ -587,8 +588,8 @@ js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length)
* Arrays are already known to have lengths (if the length overflows, it will
* be caught by setArrayLength).
*/
if (!obj->isArray())
cx->addTypePropertyId(obj->getType(), id, v);
if (!obj->isArray() && !cx->addTypePropertyId(obj->getType(), id, v))
return false;
/* We don't support read-only array length yet. */
return obj->setProperty(cx, id, &v, false);
@ -651,10 +652,8 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value
return true;
vp->setNumber(newlen);
if (oldlen < newlen) {
obj->setArrayLength(cx, newlen);
return true;
}
if (oldlen < newlen)
return obj->setArrayLength(cx, newlen);
if (obj->isDenseArray()) {
/*
@ -669,21 +668,19 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value
jsuint oldinit = obj->getDenseArrayInitializedLength();
if (oldinit > newlen)
obj->setDenseArrayInitializedLength(newlen);
obj->setArrayLength(cx, newlen);
} else if (oldlen - newlen < (1 << 24)) {
do {
--oldlen;
if (!JS_CHECK_OPERATION_LIMIT(cx)) {
obj->setArrayLength(cx, oldlen + 1);
JS_ALWAYS_TRUE(obj->setArrayLength(cx, oldlen + 1));
return false;
}
int deletion = DeleteArrayElement(cx, obj, oldlen, strict);
if (deletion <= 0) {
obj->setArrayLength(cx, oldlen + 1);
JS_ALWAYS_TRUE(obj->setArrayLength(cx, oldlen + 1));
return deletion >= 0;
}
} while (oldlen != newlen);
obj->setArrayLength(cx, newlen);
} else {
/*
* We are going to remove a lot of indexes in a presumably sparse
@ -710,10 +707,9 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value
return false;
}
}
obj->setArrayLength(cx, newlen);
}
return true;
return obj->setArrayLength(cx, newlen);
}
/*
@ -823,8 +819,8 @@ slowarray_addProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
if (!js_IdIsIndex(id, &index))
return JS_TRUE;
length = obj->getArrayLength();
if (index >= length)
obj->setArrayLength(cx, index + 1);
if (index >= length && !obj->setArrayLength(cx, index + 1))
return false;
return JS_TRUE;
}
@ -860,7 +856,7 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool stric
}
if (i >= obj->getArrayLength())
obj->setArrayLength(cx, i + 1);
obj->setDenseArrayLength(i + 1);
obj->setDenseArrayElement(i, *vp);
return true;
} while (false);
@ -917,7 +913,7 @@ array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
}
if (i >= obj->getArrayLength())
obj->setArrayLength(cx, i + 1);
obj->setDenseArrayLength(i + 1);
obj->setDenseArrayElement(i, *value);
return true;
} while (false);
@ -957,8 +953,9 @@ array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool
}
if (js_IdIsIndex(id, &i) && i < obj->getDenseArrayInitializedLength()) {
if (!obj->setDenseArrayNotPacked(cx))
return false;
obj->setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE));
obj->setDenseArrayNotPacked(cx);
}
if (!js_SuppressDeletedProperty(cx, obj, id))
@ -1064,8 +1061,9 @@ JSObject::makeDenseArraySlow(JSContext *cx)
{
JS_ASSERT(isDenseArray());
cx->markTypeArrayNotPacked(getType(), true);
setDenseArrayNotPacked(cx);
if (!cx->markTypeArrayNotPacked(getType(), true))
return false;
JS_ALWAYS_TRUE(setDenseArrayNotPacked(cx));
/*
* Save old map now, before calling InitScopeForObject. We'll have to undo
@ -1431,7 +1429,7 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, Valu
}
jsuint newlen = start + count;
if (newlen > obj->getArrayLength())
obj->setArrayLength(cx, newlen);
obj->setDenseArrayLength(newlen);
JS_ASSERT(count < uint32(-1) / sizeof(Value));
memcpy(obj->getDenseArrayElements() + start, vector, sizeof(jsval) * count);
@ -1476,7 +1474,8 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector
JS_ASSERT(obj->isArray());
JS_ASSERT(obj->isDenseArray());
obj->setArrayLength(cx, length);
if (!obj->setArrayLength(cx, length))
return false;
if (!vector || !length)
return true;
@ -1484,11 +1483,13 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector
if (!obj->ensureSlots(cx, length))
return false;
obj->setDenseArrayInitializedLength(length);
bool hole = false;
for (jsuint i = 0; i < length; i++) {
obj->setDenseArrayElement(i, vector[i]);
if (vector[i].isMagic(JS_ARRAY_HOLE))
obj->setDenseArrayNotPacked(cx);
hole |= vector[i].isMagic(JS_ARRAY_HOLE);
}
if (hole && !obj->setDenseArrayNotPacked(cx))
return false;
return true;
}
@ -1555,8 +1556,9 @@ array_reverse(JSContext *cx, uintN argc, Value *vp)
/* Fill out the array's initialized length to its proper length. */
jsuint initlen = obj->getDenseArrayInitializedLength();
if (len > initlen) {
if (!obj->setDenseArrayNotPacked(cx))
return false;
ClearValueRange(obj->getDenseArrayElements() + initlen, len - initlen, true);
obj->setDenseArrayNotPacked(cx);
obj->setDenseArrayInitializedLength(len);
}
@ -2078,8 +2080,8 @@ array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *
rval->setNumber(newlength);
/* watch for length overflowing to a double. */
if (!rval->isInt32())
cx->markTypeCallerOverflow();
if (!rval->isInt32() && !cx->markTypeCallerOverflow())
return false;
return js_SetLengthProperty(cx, obj, newlength);
}
@ -2097,7 +2099,7 @@ array_push1_dense(JSContext* cx, JSObject* obj, const Value &v, Value *rval)
break;
}
obj->setArrayLength(cx, length + 1);
obj->setDenseArrayLength(length + 1);
obj->setDenseArrayElement(length, v);
rval->setNumber(obj->getArrayLength());
return true;
@ -2137,7 +2139,7 @@ ArrayCompPushImpl(JSContext *cx, JSObject *obj, const Value &v)
if (!obj->ensureSlots(cx, length + 1))
return false;
}
obj->setArrayLength(cx, length + 1);
obj->setDenseArrayLength(length + 1);
obj->setDenseArrayInitializedLength(length + 1);
obj->setDenseArrayElement(length, v);
return true;
@ -2173,8 +2175,8 @@ array_push(JSContext *cx, uintN argc, Value *vp)
if (!obj)
return false;
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(obj->getType());
if (cx->isTypeCallerMonitored() && !cx->markTypeObjectUnknownProperties(obj->getType()))
return false;
/* Insist on one argument and obj of the expected class. */
if (argc != 1 || !obj->isDenseArray())
@ -2221,7 +2223,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, Value *vp)
return JS_FALSE;
if (!hole && DeleteArrayElement(cx, obj, index, true) < 0)
return JS_FALSE;
obj->setArrayLength(cx, index);
obj->setDenseArrayLength(index);
if (index == obj->getDenseArrayInitializedLength() - 1)
obj->setDenseArrayInitializedLength(index);
return JS_TRUE;
@ -2266,7 +2268,7 @@ array_shift(JSContext *cx, uintN argc, Value *vp)
} else {
vp->setUndefined();
}
obj->setArrayLength(cx, length);
JS_ALWAYS_TRUE(obj->setArrayLength(cx, length));
if (!js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(length)))
return JS_FALSE;
return JS_TRUE;
@ -2309,8 +2311,8 @@ array_unshift(JSContext *cx, uintN argc, Value *vp)
if (!js_GetLengthProperty(cx, obj, &length))
return JS_FALSE;
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(obj->getType());
if (cx->isTypeCallerMonitored() && !cx->markTypeObjectUnknownProperties(obj->getType()))
return false;
newlen = length;
if (argc > 0) {
@ -2364,8 +2366,8 @@ array_unshift(JSContext *cx, uintN argc, Value *vp)
vp->setNumber(newlen);
/* watch for length overflowing to a double. */
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return JS_TRUE;
}
@ -2395,13 +2397,12 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
* result of the call so mark it at the callsite.
*/
type = cx->getTypeNewObject(JSProto_Array);
if (!type)
return JS_FALSE;
cx->markTypeCallerUnexpected((jstype) type);
if (!type || !cx->markTypeCallerUnexpected((jstype) type))
return false;
}
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(type);
if (cx->isTypeCallerMonitored() && !cx->markTypeObjectUnknownProperties(type))
return false;
/* Create a new array value to return. */
JSObject *obj2 = NewDenseEmptyArray(cx);
@ -2506,7 +2507,8 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
for (Value *src = srcbeg, *dst = dstbeg; src > srcend; --src, --dst)
*dst = *src;
obj->setArrayLength(cx, obj->getArrayLength() + delta);
if (!obj->setArrayLength(cx, obj->getArrayLength() + delta))
return false;
optimized = true;
} while (false);
@ -2567,9 +2569,9 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
/* Get the type object to use for the result. */
TypeObject *ntype = cx->getTypeCallerInitObject(true);
if (!ntype)
return JS_FALSE;
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(ntype);
return false;
if (cx->isTypeCallerMonitored() && !cx->markTypeObjectUnknownProperties(ntype))
return false;
/* Create a new Array object and root it using *vp. */
JSObject *aobj = ToObject(cx, &vp[1]);
@ -2584,8 +2586,9 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
nobj = NewDenseCopiedArray(cx, initlen, aobj->getDenseArrayElements());
if (!nobj)
return JS_FALSE;
nobj->setArrayLength(cx, length);
nobj->setType(ntype);
if (!nobj->setArrayLength(cx, length))
return JS_FALSE;
vp->setObject(*nobj);
if (argc == 0)
return JS_TRUE;
@ -2600,8 +2603,8 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
length = 0;
}
if (aobj->isDenseArray() && !aobj->isPackedDenseArray())
nobj->setDenseArrayNotPacked(cx);
if (aobj->isDenseArray() && !aobj->isPackedDenseArray() && !nobj->setDenseArrayNotPacked(cx))
return false;
AutoValueRooter tvr(cx);
@ -2645,7 +2648,8 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
* The type handler for Array.concat only handles array arguments.
* Inform type inference of any non-array arguments passed in.
*/
cx->addTypePropertyId(ntype, JSID_VOID, v);
if (!cx->addTypePropertyId(ntype, JSID_VOID, v))
return false;
if (!SetArrayElement(cx, nobj, length, v))
return false;
@ -2717,13 +2721,12 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
* result of the call so mark it at the callsite.
*/
type = cx->getTypeNewObject(JSProto_Array);
if (!type)
return JS_FALSE;
cx->markTypeCallerUnexpected((jstype) type);
if (!type || !cx->markTypeCallerUnexpected((jstype) type))
return false;
}
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(type);
if (cx->isTypeCallerMonitored() && !cx->markTypeObjectUnknownProperties(type))
return false;
if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
!js_PrototypeHasIndexedProperties(cx, obj)) {
@ -2731,8 +2734,8 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
if (!nobj)
return JS_FALSE;
nobj->setType(type);
if (!obj->isPackedDenseArray())
nobj->setDenseArrayNotPacked(cx);
if (!obj->isPackedDenseArray() && !nobj->setDenseArrayNotPacked(cx))
return JS_FALSE;
vp->setObject(*nobj);
return JS_TRUE;
}
@ -2822,8 +2825,8 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp)
return JS_FALSE;
if (equal) {
vp->setNumber(i);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return JS_TRUE;
}
}
@ -2958,8 +2961,10 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
* If the callsite is being monitored for type inference, and we are modifying
* the output array, monitor any reads on the array in the future.
*/
if (cx->isTypeCallerMonitored() && (mode == MAP || mode == FILTER))
cx->markTypeObjectUnknownProperties(newtype);
if (cx->isTypeCallerMonitored() && (mode == MAP || mode == FILTER) &&
!cx->markTypeObjectUnknownProperties(newtype)) {
return false;
}
/*
* For all but REDUCE, we call with 3 args (value, index, array). REDUCE
@ -3019,7 +3024,9 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
*vp = rval;
break;
case MAP:
cx->addTypePropertyId(newarr->getType(), JSID_VOID, rval);
ok = cx->addTypePropertyId(newarr->getType(), JSID_VOID, rval);
if (!ok)
goto out;
ok = SetArrayElement(cx, newarr, i, rval);
if (!ok)
goto out;
@ -3028,7 +3035,9 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
if (!cond)
break;
/* The element passed the filter, so push it onto our result. */
cx->addTypePropertyId(newarr->getType(), JSID_VOID, tvr.value());
ok = cx->addTypePropertyId(newarr->getType(), JSID_VOID, tvr.value());
if (!ok)
goto out;
ok = SetArrayElement(cx, newarr, newlen++, tvr.value());
if (!ok)
goto out;
@ -3103,24 +3112,24 @@ array_every(JSContext *cx, uintN argc, Value *vp)
* on arrays are both handled by write barriers within the natives.
*/
static void array_TypeSort(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
static void
array_TypeSort(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
site->forceThisTypes(cx);
if (!site->forceThisTypes(cx))
return;
if (site->returnTypes) {
if (site->isNew)
site->returnTypes->addType(cx, TYPE_UNKNOWN);
site->thisTypes->addSubset(cx, site->script, site->returnTypes);
}
#endif
}
static void array_TypeInsert(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
static void
array_TypeInsert(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (site->returnTypes) {
@ -3130,18 +3139,18 @@ static void array_TypeInsert(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
site->returnTypes->addType(cx, TYPE_INT32);
}
site->forceThisTypes(cx);
if (!site->forceThisTypes(cx))
return;
for (size_t ind = 0; ind < site->argumentCount; ind++) {
site->thisTypes->addSetProperty(cx, site->script, site->pc,
site->argumentTypes[ind], JSID_VOID);
}
#endif
}
static void array_TypeRemove(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
static void
array_TypeRemove(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (!site->returnTypes)
@ -3150,18 +3159,19 @@ static void array_TypeRemove(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
if (site->isNew)
site->returnTypes->addType(cx, TYPE_UNKNOWN);
site->forceThisTypes(cx);
if (!site->forceThisTypes(cx))
return;
site->thisTypes->addGetProperty(cx, site->script, site->pc, site->returnTypes, JSID_VOID);
site->returnTypes->addType(cx, TYPE_UNDEFINED);
#endif
}
static void array_TypeSplice(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
static void
array_TypeSplice(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
site->forceThisTypes(cx);
if (!site->forceThisTypes(cx))
return;
if (site->returnTypes) {
/* Treat the returned array the same as the 'this' array. */
@ -3175,12 +3185,11 @@ static void array_TypeSplice(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
site->thisTypes->addSetProperty(cx, site->script, site->pc,
site->argumentTypes[ind], JSID_VOID);
}
#endif
}
static void array_TypeConcat(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
static void
array_TypeConcat(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (!site->compileAndGo()) {
@ -3191,8 +3200,11 @@ static void array_TypeConcat(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
/* Treat the returned array as a new allocation site. */
TypeObject *object = site->getInitObject(cx, true);
if (!object)
return;
site->forceThisTypes(cx);
if (!site->forceThisTypes(cx))
return;
if (site->returnTypes) {
if (site->isNew)
@ -3202,6 +3214,8 @@ static void array_TypeConcat(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
/* Propagate elements of the 'this' array to the result. */
TypeSet *indexTypes = object->getProperty(cx, JSID_VOID, false);
if (!indexTypes)
return;
site->thisTypes->addGetProperty(cx, site->script, site->pc, indexTypes, JSID_VOID);
/* Ditto for all arguments to the call. */
@ -3209,14 +3223,13 @@ static void array_TypeConcat(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
site->argumentTypes[ind]->addGetProperty(cx, site->script, site->pc,
indexTypes, JSID_VOID);
}
#endif
}
/* Handler for all higher order array builtins. */
static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite,
ArrayExtraMode mode)
static void
array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite,
ArrayExtraMode mode)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (!site->returnTypes)
@ -3240,6 +3253,8 @@ static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
if (site->compileAndGo()) {
/* Makes a new array whose element type will be filled in as the code runs. */
TypeObject *object = site->getInitObject(cx, true);
if (!object)
return;
site->returnTypes->addType(cx, (jstype) object);
} else {
site->returnTypes->addType(cx, TYPE_UNKNOWN);
@ -3253,30 +3268,34 @@ static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
default:
JS_NOT_REACHED("Unexpected ArrayExtraMode");
}
#endif
}
static void array_TypeExtraForEach(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
static void
array_TypeExtraForEach(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
array_TypeExtra(cx, jsfun, jssite, FOREACH);
}
static void array_TypeExtraMap(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
static void
array_TypeExtraMap(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
array_TypeExtra(cx, jsfun, jssite, MAP);
}
static void array_TypeExtraReduce(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
static void
array_TypeExtraReduce(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
array_TypeExtra(cx, jsfun, jssite, REDUCE);
}
static void array_TypeExtraFilter(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
static void
array_TypeExtraFilter(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
array_TypeExtra(cx, jsfun, jssite, FILTER);
}
static void array_TypeExtraSome(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
static void
array_TypeExtraSome(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
array_TypeExtra(cx, jsfun, jssite, SOME);
}
@ -3350,7 +3369,8 @@ js_Array(JSContext *cx, uintN argc, Value *vp)
obj = NewDenseCopiedArray(cx, argc, vp + 2);
} else if (!vp[2].isNumber()) {
/* Unexpected case for type inference. */
cx->addTypeProperty(type, NULL, vp[2]);
if (!cx->addTypeProperty(type, NULL, vp[2]))
return false;
obj = NewDenseCopiedArray(cx, 1, vp + 2);
} else {
@ -3364,22 +3384,24 @@ js_Array(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
obj->setType(type);
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(type);
if (cx->isTypeCallerMonitored() && !cx->markTypeObjectUnknownProperties(type))
return false;
/* If the length calculation overflowed, make sure that is marked for the new type. */
if (obj->getArrayLength() > INT32_MAX)
obj->setArrayLength(cx, obj->getArrayLength());
if (obj->getArrayLength() > INT32_MAX && !obj->setArrayLength(cx, obj->getArrayLength()))
return false;
vp->setObject(*obj);
return JS_TRUE;
}
// specialized handler for Array() that propagates arguments into indexes
// of the resulting array.
static void array_TypeNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
/*
* Specialized handler for Array() that propagates arguments into indexes of
* the resulting array.
*/
static void
array_TypeNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (!site->compileAndGo()) {
@ -3389,19 +3411,24 @@ static void array_TypeNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *
}
TypeObject *object = site->getInitObject(cx, true);
if (!object)
return;
if (site->returnTypes)
site->returnTypes->addType(cx, (jstype) object);
TypeSet *indexTypes = object->getProperty(cx, JSID_VOID, true);
if (!indexTypes)
return;
// ignore the case where the call is passed a single argument. this is
// expected to be the array length, but if it isn't we will catch it
// in the Array native itself.
/*
* Ignore the case where the call is passed a single argument. This is
* expected to be the array length, but if it isn't we will catch it in the
* Array native itself.
*/
if (site->argumentCount > 1) {
for (size_t ind = 0; ind < site->argumentCount; ind++)
site->argumentTypes[ind]->addSubset(cx, site->script, indexTypes);
}
#endif
}
JSObject *
@ -3412,11 +3439,14 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
if (!proto)
return NULL;
JS_AddTypeProperty(cx, proto, "length", INT_TO_JSVAL(0));
proto->setArrayLength(cx, 0);
if (!JS_AddTypeProperty(cx, proto, "length", INT_TO_JSVAL(0)))
return NULL;
JS_ALWAYS_TRUE(proto->setArrayLength(cx, 0));
/* The default 'new' object for Array.prototype has unknown properties. */
cx->markTypeObjectUnknownProperties(proto->getNewType(cx));
TypeObject *newType = proto->getNewType(cx);
if (!newType || !cx->markTypeObjectUnknownProperties(newType))
return NULL;
return proto;
}
@ -3437,7 +3467,8 @@ NewArray(JSContext *cx, jsuint length, JSObject *proto)
if (!obj)
return NULL;
obj->setArrayLength(cx, length);
if (!obj->setArrayLength(cx, length))
return NULL;
if (allocateCapacity && !obj->ensureSlots(cx, length))
return NULL;
@ -3464,7 +3495,8 @@ NewDenseAllocatedEmptyArray(JSContext *cx, uint length, JSObject *proto)
if (!obj)
return NULL;
obj->setDenseArrayInitializedLength(length);
obj->setDenseArrayNotPacked(cx);
if (!obj->setDenseArrayNotPacked(cx))
return NULL;
ClearValueRange(obj->getSlots(), length, true);
return obj;
}
@ -3514,7 +3546,7 @@ NewSlowEmptyArray(JSContext *cx)
if (!obj || !AddLengthProperty(cx, obj))
return NULL;
obj->setArrayLength(cx, 0);
JS_ALWAYS_TRUE(obj->setArrayLength(cx, 0));
return obj;
}
@ -3672,10 +3704,9 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
if (!*clone)
return JS_FALSE;
if (!obj->isPackedDenseArray())
(*clone)->setDenseArrayNotPacked(cx);
if (!obj->isPackedDenseArray() && !(*clone)->setDenseArrayNotPacked(cx))
return JS_FALSE;
/* The length will be set to the initlen, above, but length might be larger. */
(*clone)->setArrayLength(cx, length);
return JS_TRUE;
return (*clone)->setArrayLength(cx, length);
}

View File

@ -74,14 +74,15 @@ JSObject::isPackedDenseArray()
return flags & PACKED_ARRAY;
}
inline void
inline bool
JSObject::setDenseArrayNotPacked(JSContext *cx)
{
JS_ASSERT(isDenseArray());
if (flags & PACKED_ARRAY) {
flags ^= PACKED_ARRAY;
cx->markTypeArrayNotPacked(getType(), false);
return cx->markTypeArrayNotPacked(getType(), false);
}
return true;
}
inline JSObject::EnsureDenseResult
@ -98,8 +99,9 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
return ED_OK;
if (index < currentCapacity) {
if (index > initLength) {
if (!setDenseArrayNotPacked(cx))
return ED_FAILED;
ClearValueRange(getSlots() + initLength, index - initLength, true);
setDenseArrayNotPacked(cx);
}
setDenseArrayInitializedLength(index + 1);
return ED_OK;
@ -120,7 +122,8 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
if (requiredCapacity <= currentCapacity) {
if (index > initLength) {
ClearValueRange(getSlots() + initLength, index - initLength, true);
setDenseArrayNotPacked(cx);
if (!setDenseArrayNotPacked(cx))
return ED_FAILED;
}
setDenseArrayInitializedLength(requiredCapacity);
return ED_OK;
@ -139,8 +142,9 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
return ED_FAILED;
if (index > initLength) {
if (!setDenseArrayNotPacked(cx))
return ED_FAILED;
ClearValueRange(getSlots() + initLength, index - initLength, true);
setDenseArrayNotPacked(cx);
}
setDenseArrayInitializedLength(requiredCapacity);

View File

@ -151,12 +151,10 @@ Boolean(JSContext *cx, uintN argc, Value *vp)
static void type_NewBoolean(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
if (Valueify(jssite)->isNew)
JS_TypeHandlerNew(cx, jsfun, jssite);
else
JS_TypeHandlerBool(cx, jsfun, jssite);
#endif
}
JSObject *

View File

@ -1042,21 +1042,17 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
JS_BeginRequest(cx);
#endif
#ifdef JS_TYPE_INFERENCE
{
/*
* Dump remaining type inference results first. This printing
* depends on atoms still existing.
*/
AutoLockGC lock(rt);
JSCompartment **compartment = rt->compartments.begin();
JSCompartment **end = rt->compartments.end();
while (compartment < end) {
(*compartment)->types.finish(cx, *compartment);
compartment++;
}
/*
* Dump remaining type inference results first. This printing
* depends on atoms still existing.
*/
AutoLockGC lock(rt);
JSCompartment **compartment = rt->compartments.begin();
JSCompartment **end = rt->compartments.end();
while (compartment < end) {
(*compartment)->types.finish(cx, *compartment);
compartment++;
}
#endif
js_FinishRuntimeNumberState(cx);
@ -2295,16 +2291,15 @@ IsJITBrokenHere()
void
JSContext::updateJITEnabled()
{
/* :FIXME: Don't enable the trace JIT if inference is on, they are not compatible yet. */
#ifndef JS_TYPE_INFERENCE
#ifdef JS_TRACER
traceJitEnabled = ((runOptions & JSOPTION_JIT) &&
!IsJITBrokenHere() &&
/* :FIXME: bug 637856 allow traceJit if inference is enabled */
!(runOptions & JSOPTION_TYPE_INFERENCE) &&
(debugHooks == &js_NullDebugHooks ||
(debugHooks == &runtime->globalDebugHooks &&
!runtime->debuggerInhibitsJIT())));
#endif
#endif
#ifdef JS_METHODJIT
methodJitEnabled = (runOptions & JSOPTION_METHODJIT) &&
!IsJITBrokenHere()

View File

@ -2134,6 +2134,8 @@ struct JSContext
public:
inline bool typeInferenceEnabled();
/* Make a type function or object with the specified name. */
js::types::TypeFunction *newTypeFunction(const char *name, JSObject *proto);
js::types::TypeObject *newTypeObject(const char *name, JSObject *proto);
@ -2161,37 +2163,36 @@ public:
inline bool isTypeCallerMonitored();
/* Mark the immediate allocation site as having produced an unexpected value. */
inline void markTypeCallerUnexpected(js::types::jstype type);
inline void markTypeCallerUnexpected(const js::Value &value);
inline void markTypeCallerOverflow();
inline bool markTypeCallerUnexpected(js::types::jstype type);
inline bool markTypeCallerUnexpected(const js::Value &value);
inline bool markTypeCallerOverflow();
/*
* Monitor a javascript call, either on entry to the interpreter or made
* from within the interpreter.
*/
inline void typeMonitorCall(JSScript *caller, const jsbytecode *callerpc,
const js::CallArgs &args, bool constructing, bool force);
inline void typeMonitorEntry(JSScript *script);
inline void typeMonitorEntry(JSScript *script, const js::Value &thisv);
inline bool typeMonitorCall(const js::CallArgs &args, bool constructing);
/* Monitor an assignment made to a property by a script. */
inline bool typeMonitorAssign(JSObject *obj, jsid id, const js::Value &value);
/* Add a possible value for the named property of obj. */
inline void addTypeProperty(js::types::TypeObject *obj, const char *name, js::types::jstype type);
inline void addTypeProperty(js::types::TypeObject *obj, const char *name, const js::Value &value);
inline void addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::jstype type);
inline void addTypePropertyId(js::types::TypeObject *obj, jsid id, const js::Value &value);
inline void markTypePropertyUnknown(js::types::TypeObject *obj, jsid id);
inline bool addTypeProperty(js::types::TypeObject *obj, const char *name, js::types::jstype type);
inline bool addTypeProperty(js::types::TypeObject *obj, const char *name, const js::Value &value);
inline bool addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::jstype type);
inline bool addTypePropertyId(js::types::TypeObject *obj, jsid id, const js::Value &value);
/* Get the type to add for properties which can be scripted getters/setters. */
inline js::types::TypeObject *getTypeGetSet();
/* Alias two properties in the type information for obj. */
inline void aliasTypeProperties(js::types::TypeObject *obj, jsid first, jsid second);
inline bool aliasTypeProperties(js::types::TypeObject *obj, jsid first, jsid second);
/* Mark an array type as being not packed and, possibly, not dense. */
inline void markTypeArrayNotPacked(js::types::TypeObject *obj, bool notDense, bool dynamic = true);
inline bool markTypeArrayNotPacked(js::types::TypeObject *obj, bool notDense);
/* Monitor all properties of a type object as unknown. */
inline void markTypeObjectUnknownProperties(js::types::TypeObject *obj);
inline bool markTypeObjectUnknownProperties(js::types::TypeObject *obj);
}; /* struct JSContext */
#ifdef JS_THREADSAFE

View File

@ -115,7 +115,7 @@ JSCompartment::~JSCompartment()
}
bool
JSCompartment::init()
JSCompartment::init(JSContext *cx)
{
chunk = NULL;
for (unsigned i = 0; i < FINALIZE_LIMIT; i++)
@ -125,7 +125,7 @@ JSCompartment::init()
#ifdef JS_GCMETER
memset(&compartmentStats, 0, sizeof(JSGCArenaStats) * FINALIZE_LIMIT);
#endif
types.init();
types.init(cx);
if (!crossCompartmentWrappers.init())
return false;
@ -523,27 +523,34 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
#endif
if (!types.inferenceDepth) {
#ifdef JS_TYPE_INFERENCE
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
JSScript *script = reinterpret_cast<JSScript *>(cursor);
script->condenseTypes(cx);
}
if (types.inferenceEnabled) {
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
JSScript *script = reinterpret_cast<JSScript *>(cursor);
script->condenseTypes(cx);
}
types::CondenseTypeObjectList(cx, types.objects);
types::CondenseTypeObjectList(cx, &types, types.objects);
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
JSScript *script = reinterpret_cast<JSScript *>(cursor);
script->sweepTypes(cx);
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
JSScript *script = reinterpret_cast<JSScript *>(cursor);
script->sweepTypes(cx);
}
}
#endif
types::SweepTypeObjectList(cx, types.objects);
/* Reset the inference pool, releasing all intermediate type data. */
JS_FinishArenaPool(&types.pool);
/*
* Destroy eval'ed scripts, now that any type inference information referring
* to eval scripts has been removed.
*/
js_DestroyScriptsToGC(cx, this);
/* Nuke types if there was an OOM while condensing type information. */
if (types.pendingNukeTypes)
types.nukeTypes(cx);
}
#if defined JS_METHODJIT && defined JS_MONOIC

View File

@ -450,7 +450,7 @@ struct JS_FRIEND_API(JSCompartment) {
JSCompartment(JSRuntime *rt);
~JSCompartment();
bool init();
bool init(JSContext *cx);
/* Mark cross-compartment wrappers. */
void markCrossCompartment(JSTracer *trc);

View File

@ -1444,8 +1444,8 @@ date_getYear(JSContext *cx, uintN argc, Value *vp)
vp->setInt32(year);
} else {
*vp = yearVal;
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
}
return true;
@ -1462,8 +1462,8 @@ date_getFullYear(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return JS_TRUE;
}
@ -1476,8 +1476,8 @@ date_getUTCFullYear(JSContext *cx, uintN argc, Value *vp)
if (JSDOUBLE_IS_FINITE(result))
result = YearFromTime(result);
else
cx->markTypeCallerOverflow();
else if (!cx->markTypeCallerOverflow())
return false;
vp->setNumber(result);
return true;
@ -1494,8 +1494,8 @@ date_getMonth(JSContext *cx, uintN argc, Value *vp)
return false;
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return true;
}
@ -1508,8 +1508,8 @@ date_getUTCMonth(JSContext *cx, uintN argc, Value *vp)
if (JSDOUBLE_IS_FINITE(result))
result = MonthFromTime(result);
else
cx->markTypeCallerOverflow();
else if (!cx->markTypeCallerOverflow())
return false;
vp->setNumber(result);
return true;
@ -1526,8 +1526,8 @@ date_getDate(JSContext *cx, uintN argc, Value *vp)
return false;
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return true;
}
@ -1540,8 +1540,8 @@ date_getUTCDate(JSContext *cx, uintN argc, Value *vp)
if (JSDOUBLE_IS_FINITE(result))
result = DateFromTime(result);
else
cx->markTypeCallerOverflow();
else if (!cx->markTypeCallerOverflow())
return false;
vp->setNumber(result);
return true;
@ -1558,8 +1558,8 @@ date_getDay(JSContext *cx, uintN argc, Value *vp)
return false;
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return true;
}
@ -1572,8 +1572,8 @@ date_getUTCDay(JSContext *cx, uintN argc, Value *vp)
if (JSDOUBLE_IS_FINITE(result))
result = WeekDay(result);
else
cx->markTypeCallerOverflow();
else if (!cx->markTypeCallerOverflow())
return false;
vp->setNumber(result);
return true;
@ -1590,8 +1590,8 @@ date_getHours(JSContext *cx, uintN argc, Value *vp)
return false;
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return true;
}
@ -1604,8 +1604,8 @@ date_getUTCHours(JSContext *cx, uintN argc, Value *vp)
if (JSDOUBLE_IS_FINITE(result))
result = HourFromTime(result);
else
cx->markTypeCallerOverflow();
else if (!cx->markTypeCallerOverflow())
return false;
vp->setNumber(result);
return JS_TRUE;
@ -1622,8 +1622,8 @@ date_getMinutes(JSContext *cx, uintN argc, Value *vp)
return false;
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return true;
}
@ -1636,8 +1636,8 @@ date_getUTCMinutes(JSContext *cx, uintN argc, Value *vp)
if (JSDOUBLE_IS_FINITE(result))
result = MinFromTime(result);
else
cx->markTypeCallerOverflow();
else if (!cx->markTypeCallerOverflow())
return false;
vp->setNumber(result);
return true;
@ -1656,8 +1656,8 @@ date_getUTCSeconds(JSContext *cx, uintN argc, Value *vp)
return false;
*vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return true;
}
@ -1672,8 +1672,8 @@ date_getUTCMilliseconds(JSContext *cx, uintN argc, Value *vp)
if (JSDOUBLE_IS_FINITE(result))
result = msFromTime(result);
else
cx->markTypeCallerOverflow();
else if (!cx->markTypeCallerOverflow())
return false;
vp->setNumber(result);
return true;
@ -1700,8 +1700,8 @@ date_getTimezoneOffset(JSContext *cx, uintN argc, Value *vp)
* daylight savings time.
*/
jsdouble result = (utctime - localtime) / msPerMinute;
if (!JSDOUBLE_IS_FINITE(result))
cx->markTypeCallerOverflow();
if (!JSDOUBLE_IS_FINITE(result) && !cx->markTypeCallerOverflow())
return false;
vp->setNumber(result);
return true;
@ -2610,12 +2610,10 @@ js_Date(JSContext *cx, uintN argc, Value *vp)
static void type_NewDate(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
if (Valueify(jssite)->isNew)
JS_TypeHandlerNew(cx, jsfun, jssite);
else
JS_TypeHandlerString(cx, jsfun, jssite);
#endif
}
JSObject *
@ -2643,11 +2641,11 @@ js_InitDateClass(JSContext *cx, JSObject *obj)
jsid toUTCStringId = ATOM_TO_JSID(cx->runtime->atomState.toUTCStringAtom);
jsid toGMTStringId = ATOM_TO_JSID(cx->runtime->atomState.toGMTStringAtom);
if (!js_GetProperty(cx, proto, toUTCStringId, toUTCStringFun.addr()) ||
!cx->addTypePropertyId(proto->getType(), toGMTStringId, toUTCStringFun.value()) ||
!js_DefineProperty(cx, proto, toGMTStringId, toUTCStringFun.addr(),
PropertyStub, StrictPropertyStub, 0)) {
return NULL;
}
cx->addTypePropertyId(proto->getType(), toGMTStringId, toUTCStringFun.value());
return proto;
}

View File

@ -573,8 +573,8 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
if (fp) {
JSScript *script = fp->functionScript();
if (script->usesArguments) {
if (arg < fp->numFormalArgs())
script->typeSetArgument(cx, arg, *vp);
if (arg < fp->numFormalArgs() && !script->typeSetArgument(cx, arg, *vp))
return false;
fp->canonicalActualArg(arg) = *vp;
}
return true;
@ -1230,19 +1230,9 @@ SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
else
argp = &obj->callObjArg(i);
#ifdef JS_TYPE_INFERENCE
JSFunction *fun = obj->getCallObjCalleeFunction();
JSScript *script = fun->script();
if (script->types) {
jstype type = GetValueType(cx, *vp);
TypeSet *types = script->argTypes(i);
if (types && !types->hasType(type)) {
InferSpew(ISpewDynamic, "AddCallProperty: #%u arg%u: %s",
script->id(), i, TypeString(type));
cx->compartment->types.addDynamicType(cx, types, type);
}
}
#endif
JSScript *script = obj->getCallObjCalleeFunction()->script();
if (!script->typeSetArgument(cx, i, *vp))
return false;
GC_POKE(cx, *argp);
*argp = *vp;
@ -1324,19 +1314,9 @@ SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
else
varp = &obj->callObjVar(i);
#ifdef JS_TYPE_INFERENCE
JSFunction *fun = obj->getCallObjCalleeFunction();
JSScript *script = fun->script();
if (script->types) {
jstype type = GetValueType(cx, *vp);
TypeSet *types = script->localTypes(i);
if (types && !types->hasType(type)) {
InferSpew(ISpewDynamic, "AddCallProperty: #%u local%u: %s",
script->id(), i, TypeString(type));
cx->compartment->types.addDynamicType(cx, types, type);
}
}
#endif
JSScript *script = obj->getCallObjCalleeFunction()->script();
if (!script->typeSetLocal(cx, i, *vp))
return false;
GC_POKE(cx, *varp);
*varp = *vp;
@ -1691,9 +1671,7 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
}
jsid nameid = atom ? ATOM_TO_JSID(atom) : JSID_VOID;
cx->addTypePropertyId(obj->getType(), nameid, *vp);
return true;
return cx->addTypePropertyId(obj->getType(), nameid, *vp);
}
struct LazyFunctionDataProp {
@ -1838,8 +1816,8 @@ fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
JS_ASSERT(!IsInternalFunctionObject(obj));
cx->addTypePropertyId(obj->getType(), id, types::TYPE_INT32);
if (!js_DefineNativeProperty(cx, obj, id, Int32Value(fun->nargs),
if (!cx->addTypePropertyId(obj->getType(), id, types::TYPE_INT32) ||
!js_DefineNativeProperty(cx, obj, id, Int32Value(fun->nargs),
PropertyStub, StrictPropertyStub,
JSPROP_PERMANENT | JSPROP_READONLY, 0, 0, NULL)) {
return false;
@ -2843,6 +2821,16 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
JS_ASSERT(parent);
JS_ASSERT(proto);
/*
* In COMPILE_N_GO code the existing prototype will be correct, so we can
* reuse the type. In non-COMPILE_N_GO code the proto is NULL, but since
* we don't run type inference on such code we can use the default new
* Function type.
*/
TypeObject *type = (fun->getProto() == proto) ? fun->getType() : proto->getNewType(cx);
if (!type)
return NULL;
JSObject *clone;
if (cx->compartment == fun->compartment()) {
/*
@ -2853,17 +2841,7 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
if (!clone)
return NULL;
clone->setPrivate(fun);
/*
* In COMPILE_N_GO code the existing prototype will be correct, so we can
* reuse the type. In non-COMPILE_N_GO code the proto is NULL, but since
* we don't run type inference on such code we can use the default new
* Function type.
*/
if (fun->getProto() == proto)
clone->setType(fun->getType());
else
clone->setType(proto->getNewType(cx));
clone->setType(type);
} else {
/*
* Across compartments we have to deep copy JSFunction and clone the
@ -2872,11 +2850,7 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
clone = NewFunction(cx, parent);
if (!clone)
return NULL;
if (fun->getProto() == proto)
clone->setType(fun->getType());
else
clone->setType(proto->getNewType(cx));
clone->setType(type);
JSFunction *cfun = (JSFunction *) clone;
cfun->nargs = fun->nargs;
@ -2963,10 +2937,13 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen)
uintN level = fun->u.i.script->staticLevel;
JSUpvarArray *uva = fun->script()->upvars();
bool ok = true;
for (uint32 i = 0, n = uva->length; i < n; i++) {
upvars[i] = GetUpvar(cx, level, uva->vector[i]);
fun->script()->typeSetUpvar(cx, i, upvars[i]);
ok &= fun->script()->typeSetUpvar(cx, i, upvars[i]);
}
if (!ok)
return NULL;
return closure;
}
@ -3065,10 +3042,12 @@ js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
if (!wasDelegate && obj->isDelegate())
obj->clearDelegate();
if (!cx->addTypePropertyId(obj->getType(), id, ObjectValue(*fun)))
return NULL;
if (!obj->defineProperty(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK))
return NULL;
cx->addTypePropertyId(obj->getType(), id, ObjectValue(*fun));
return fun;
}

View File

@ -2885,7 +2885,7 @@ NewCompartment(JSContext *cx, JSPrincipals *principals)
{
JSRuntime *rt = cx->runtime;
JSCompartment *compartment = js_new<JSCompartment>(rt);
if (!compartment || !compartment->init()) {
if (!compartment || !compartment->init(cx)) {
js_delete(compartment);
JS_ReportOutOfMemory(cx);
return NULL;

File diff suppressed because it is too large Load Diff

View File

@ -51,9 +51,9 @@
#include <sys/time.h>
#endif
/* Define to get detailed output of inference actions. */
namespace js { namespace analyze {
namespace js {
struct CallArgs;
namespace analyze {
struct Bytecode;
class Script;
} }
@ -89,23 +89,6 @@ const jstype TYPE_STRING = 6;
*/
const jstype TYPE_UNKNOWN = 7;
/* Coarse flags for the type of a value. */
enum {
TYPE_FLAG_UNDEFINED = 1 << TYPE_UNDEFINED,
TYPE_FLAG_NULL = 1 << TYPE_NULL,
TYPE_FLAG_BOOLEAN = 1 << TYPE_BOOLEAN,
TYPE_FLAG_INT32 = 1 << TYPE_INT32,
TYPE_FLAG_DOUBLE = 1 << TYPE_DOUBLE,
TYPE_FLAG_STRING = 1 << TYPE_STRING,
TYPE_FLAG_UNKNOWN = 1 << TYPE_UNKNOWN,
TYPE_FLAG_OBJECT = 0x1000
};
/* Vector of the above flags. */
typedef uint32 TypeFlags;
/*
* Test whether a type is an primitive or an object. Object types can be
* cast into a TypeObject*.
@ -235,13 +218,31 @@ enum ObjectKind {
OBJECT_NATIVE_FUNCTION
};
/* Coarse flags for the contents of a type set. */
enum {
TYPE_FLAG_UNDEFINED = 1 << TYPE_UNDEFINED,
TYPE_FLAG_NULL = 1 << TYPE_NULL,
TYPE_FLAG_BOOLEAN = 1 << TYPE_BOOLEAN,
TYPE_FLAG_INT32 = 1 << TYPE_INT32,
TYPE_FLAG_DOUBLE = 1 << TYPE_DOUBLE,
TYPE_FLAG_STRING = 1 << TYPE_STRING,
TYPE_FLAG_UNKNOWN = 1 << TYPE_UNKNOWN,
/* Flag for type sets which are cleared on GC. */
TYPE_FLAG_INTERMEDIATE_SET = 0x1000
};
/* Vector of the above flags. */
typedef uint32 TypeFlags;
/* Information about the set of types associated with an lvalue. */
struct TypeSet
{
/* Flags for the possible coarse types in this set. */
TypeFlags typeFlags;
/* If TYPE_FLAG_OBJECT, the possible objects this this type can represent. */
/* Possible objects this type set can represent. */
TypeObject **objectSet;
unsigned objectCount;
@ -254,6 +255,10 @@ struct TypeSet
void print(JSContext *cx);
void setIntermediate() { typeFlags |= TYPE_FLAG_INTERMEDIATE_SET; }
inline void destroy(JSContext *cx);
/* Whether this set contains a specific type. */
inline bool hasType(jstype type);
@ -292,7 +297,7 @@ struct TypeSet
* Make an intermediate type set with the specified debugging name,
* not embedded in another structure.
*/
static inline TypeSet* make(JSContext *cx, JSArenaPool &pool, const char *name);
static inline TypeSet* make(JSContext *cx, const char *name);
/* Methods for JIT compilation. */
@ -425,8 +430,9 @@ struct TypeObject
/* Helpers */
bool addProperty(JSContext *cx, jsid id, Property **pprop);
void addPrototype(JSContext *cx, TypeObject *proto);
void addProperty(JSContext *cx, jsid id, Property *&prop);
void markNotPacked(JSContext *cx, bool notDense);
void markUnknown(JSContext *cx);
void storeToInstances(JSContext *cx, Property *base);
void getFromPrototypes(JSContext *cx, Property *base);
@ -484,12 +490,11 @@ struct TypeCallsite
/* Type set receiving the return value of this call. */
TypeSet *returnTypes;
inline TypeCallsite(JSScript *script, const jsbytecode *pc,
inline TypeCallsite(JSContext *cx, JSScript *script, const jsbytecode *pc,
bool isNew, unsigned argumentCount);
/* Force creation of thisTypes or returnTypes. */
inline void forceThisTypes(JSContext *cx);
inline void forceReturnTypes(JSContext *cx);
/* Force creation of thisTypes. */
inline bool forceThisTypes(JSContext *cx);
/* Get the new object at this callsite. */
inline TypeObject* getInitObject(JSContext *cx, bool isArray);
@ -524,12 +529,6 @@ struct TypeScript
JSScript *script;
#endif
/*
* Pool into which intermediate type sets and all type constraints are allocated
* during analysis of the script.
*/
JSArenaPool pool;
/*
* Stack values pushed by all bytecodes in the script. Low bit is set for
* bytecodes which are monitored (side effects were not determined statically).
@ -560,21 +559,38 @@ struct TypeCompartment
/* List of objects not associated with a script. */
TypeObject *objects;
/* Number of active instances of AutoEnterTypeInference. */
/* Whether type inference is enabled in this compartment. */
bool inferenceEnabled;
/* Whether type inference is active, see AutoEnterTypeInference. */
unsigned inferenceDepth;
uint64_t inferenceStartTime;
/* Pool for all intermediate type information in this compartment. Cleared on every GC. */
JSArenaPool pool;
/* Number of scripts in this compartment. */
unsigned scriptCount;
/* Whether the interpreter is currently active (we are not inferring types). */
bool interpreting;
/* Object to use throughout the compartment as the default type of objects with no prototype. */
TypeObject emptyObject;
/* Dummy object added to properties which can have scripted getters/setters. */
TypeObject *typeGetSet;
/*
* Bit set if all current types must be marked as unknown, and all scripts
* recompiled. Caused by OOM failure within inference operations.
*/
bool pendingNukeTypes;
/*
* Whether type sets have been nuked, and all future type sets should be as well.
* This is not strictly necessary to do, but avoids thrashing from repeated
* redundant type nuking.
*/
bool typesNuked;
/* Pending recompilations to perform before execution of JIT code can resume. */
Vector<JSScript*> *pendingRecompiles;
@ -615,7 +631,7 @@ struct TypeCompartment
/* Number of recompilations triggered. */
unsigned recompilations;
void init();
void init(JSContext *cx);
uint64 currentTime()
{
@ -643,29 +659,34 @@ struct TypeCompartment
TypeObject *newTypeObject(JSContext *cx, JSScript *script,
const char *name, bool isFunction, JSObject *proto);
#ifdef JS_TYPE_INFERENCE
/* Make an initializer object. */
TypeObject *newInitializerTypeObject(JSContext *cx, JSScript *script,
uint32 offset, bool isArray);
#endif
/*
* Add the specified type to the specified set, do any necessary reanalysis
* stemming from the change and recompile any affected scripts.
*/
void addDynamicType(JSContext *cx, TypeSet *types, jstype type);
void addDynamicPush(JSContext *cx, JSScript *script, uint32 offset, jstype type);
void dynamicAssign(JSContext *cx, JSObject *obj, jsid id, const Value &rval);
bool dynamicPush(JSContext *cx, JSScript *script, uint32 offset, jstype type);
bool dynamicAssign(JSContext *cx, JSObject *obj, jsid id, const Value &rval);
bool dynamicCall(JSContext *cx, JSObject *callee, const CallArgs &args, bool constructing);
inline bool hasPendingRecompiles() { return pendingRecompiles != NULL; }
void processPendingRecompiles(JSContext *cx);
inline bool checkPendingRecompiles(JSContext *cx);
bool nukeTypes(JSContext *cx);
bool processPendingRecompiles(JSContext *cx);
/* Mark all types as needing destruction once inference has 'finished'. */
void setPendingNukeTypes(JSContext *cx);
/* Mark a script as needing recompilation once inference has finished. */
void addPendingRecompile(JSContext *cx, JSScript *script);
/* Monitor future effects on a bytecode. */
void monitorBytecode(JSContext *cx, JSScript *script, uint32 offset);
};
void CondenseTypeObjectList(JSContext *cx, TypeObject *objects);
void CondenseTypeObjectList(JSContext *cx, TypeCompartment *compartment, TypeObject *objects);
void SweepTypeObjectList(JSContext *cx, TypeObject *&objects);
enum SpewChannel {

File diff suppressed because it is too large Load Diff

View File

@ -554,6 +554,9 @@ js_OnUnknownMethod(JSContext *cx, Value *vp)
AutoValueRooter tvr(cx);
if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr()))
return false;
if (!cx->fp()->script()->typeMonitorUnknown(cx, cx->regs->pc))
return false;
if (tvr.value().isPrimitive()) {
vp[0] = tvr.value();
} else {
@ -583,7 +586,6 @@ js_OnUnknownMethod(JSContext *cx, Value *vp)
obj->setSlot(JSSLOT_SAVED_ID, vp[0]);
vp[0].setObject(*obj);
}
cx->fp()->script()->typeMonitorUnknown(cx, cx->regs->pc);
return true;
}
@ -709,7 +711,8 @@ Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags)
return true;
}
cx->typeMonitorCall(NULL, NULL, args, flags & JSFRAME_CONSTRUCTING, true);
if (!cx->typeMonitorCall(args, flags & JSFRAME_CONSTRUCTING))
return false;
/* Get pointer to new frame/slots, prepare arguments. */
InvokeFrameGuard frame;
@ -777,30 +780,26 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this
uint32 flags = 0;
if (!stack.getInvokeFrame(cx, args_, fun, script_, &flags, &frame_))
return false;
JSStackFrame *fp = frame_.fp();
fp->initCallFrame(cx, calleev.toObject(), fun, argc, flags);
stack.pushInvokeFrame(cx, args_, &frame_);
#ifdef JS_TYPE_INFERENCE
cx->typeMonitorEntry(script_);
/* Mark the shared 'this' type. */
jstype type = GetValueType(cx, thisv);
if (!script_->thisTypes()->hasType(type)) {
InferSpew(ISpewDynamic, "AddThis: #%u: %s",
script_->id(), TypeString(type));
cx->compartment->types.addDynamicType(cx, script_->thisTypes(), type);
}
/* Mark all formal arguments as unknown. */
for (unsigned arg = 0; arg < fun->nargs; arg++) {
TypeSet *types = script_->argTypes(arg);
if (!types->unknown()) {
InferSpew(ISpewDynamic, "AddArgUnknown: #%u %u", script_->id(), arg);
cx->compartment->types.addDynamicType(cx, types, TYPE_UNKNOWN);
JS_ASSERT(!(flags & JSFRAME_CONSTRUCTING));
if (cx->typeInferenceEnabled()) {
/*
* Set the 'this' type according to the value given, but mark the types
* of all arguments as unknown. We don't want to keep track of the
* possible values the InvokeSession's client could pass in.
*/
jstype type = GetValueType(cx, thisv);
if (!script_->typeSetThis(cx, type))
return false;
for (unsigned i = 0; i < fun->nargs; i++) {
if (!script_->typeSetArgument(cx, i, TYPE_UNKNOWN))
return false;
}
}
#endif
#ifdef JS_METHODJIT
/* Hoist dynamic checks from RunScript. */
@ -1032,7 +1031,11 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
Probes::startExecution(cx, script);
cx->typeMonitorEntry(script, frame.fp()->thisValue());
if (cx->typeInferenceEnabled()) {
jstype type = GetValueType(cx, frame.fp()->thisValue());
if (!script->typeSetThis(cx, type))
return false;
}
/* Run script until JSOP_STOP or error. */
AutoPreserveEnumerators preserve(cx);
@ -2215,9 +2218,12 @@ ScriptPrologue(JSContext *cx, JSStackFrame *fp)
static inline void
TypeCheckNextBytecode(JSContext *cx, JSScript *script, unsigned n, const JSFrameRegs &regs)
{
#if defined JS_TYPE_INFERENCE && DEBUG
if (*regs.pc != JSOP_TRAP && n == analyze::GetBytecodeLength(regs.pc))
#ifdef DEBUG
if (cx->typeInferenceEnabled() &&
*regs.pc != JSOP_TRAP &&
n == analyze::GetBytecodeLength(regs.pc)) {
script->typeCheckBytecode(cx, regs.pc, regs.sp);
}
#endif
}
@ -2697,12 +2703,6 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
advance_pc:
regs.pc += len;
op = (JSOp) *regs.pc;
#ifdef JS_TYPE_INFERENCE
// record types seen by every opcode.
script->typeScript->checkByteCode(regs.pc, regs.sp);
#endif
do_op:
CHECK_RECORDER();
LOG_OPCODE(op);
@ -3228,7 +3228,8 @@ BEGIN_CASE(JSOP_FORGNAME)
JS_ASSERT(regs.sp[-1].isObject());
if (!IteratorNext(cx, &regs.sp[-1].toObject(), tvr.addr()))
goto error;
script->typeMonitorAssign(cx, regs.pc, obj, id, tvr.value());
if (!cx->typeMonitorAssign(obj, id, tvr.value()))
goto error;
if (!obj->setProperty(cx, id, tvr.addr(), script->strictModeCode))
goto error;
}
@ -3248,7 +3249,8 @@ BEGIN_CASE(JSOP_FORPROP)
JS_ASSERT(regs.sp[-2].isObject());
if (!IteratorNext(cx, &regs.sp[-2].toObject(), tvr.addr()))
goto error;
script->typeMonitorAssign(cx, regs.pc, obj, id, tvr.value());
if (!cx->typeMonitorAssign(obj, id, tvr.value()))
goto error;
if (!obj->setProperty(cx, id, tvr.addr(), script->strictModeCode))
goto error;
}
@ -3375,7 +3377,8 @@ BEGIN_CASE(JSOP_SETCONST)
JSObject &obj = regs.fp->varobj(cx);
const Value &ref = regs.sp[-1];
script->typeMonitorAssign(cx, regs.pc, &obj, ATOM_TO_JSID(atom), ref);
if (!cx->typeMonitorAssign(&obj, ATOM_TO_JSID(atom), ref))
goto error;
if (!obj.defineProperty(cx, ATOM_TO_JSID(atom), ref,
PropertyStub, StrictPropertyStub,
@ -3707,8 +3710,8 @@ BEGIN_CASE(JSOP_URSH)
u >>= (j & 31);
regs.sp--;
if (!regs.sp[-1].setNumber(uint32(u)))
script->typeMonitorOverflow(cx, regs.pc);
if (!regs.sp[-1].setNumber(uint32(u)) && !script->typeMonitorOverflow(cx, regs.pc))
goto error;
}
END_CASE(JSOP_URSH)
@ -3723,7 +3726,8 @@ BEGIN_CASE(JSOP_ADD)
regs.sp--;
if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
regs.sp[-1].setDouble(double(l) + double(r));
script->typeMonitorOverflow(cx, regs.pc);
if (!script->typeMonitorOverflow(cx, regs.pc))
goto error;
} else {
regs.sp[-1].setInt32(sum);
}
@ -3771,8 +3775,11 @@ BEGIN_CASE(JSOP_ADD)
goto error;
l += r;
regs.sp--;
if (!regs.sp[-1].setNumber(l) && !(lval.isDouble() || rval.isDouble()))
script->typeMonitorOverflow(cx, regs.pc);
if (!regs.sp[-1].setNumber(l) &&
!(lval.isDouble() || rval.isDouble()) &&
!script->typeMonitorOverflow(cx, regs.pc)) {
goto error;
}
}
}
}
@ -3790,8 +3797,9 @@ END_CASE(JSOP_ADD)
double d = d1 OP d2; \
regs.sp--; \
if (!regs.sp[-1].setNumber(d) && \
!(lval.isDouble() || rval.isDouble())) { \
script->typeMonitorOverflow(cx, regs.pc); \
!(lval.isDouble() || rval.isDouble()) && \
!script->typeMonitorOverflow(cx, regs.pc)) { \
goto error; \
} \
JS_END_MACRO
@ -3830,11 +3838,15 @@ BEGIN_CASE(JSOP_DIV)
else
vp = &rt->positiveInfinityValue;
regs.sp[-1] = *vp;
script->typeMonitorOverflow(cx, regs.pc);
if (!script->typeMonitorOverflow(cx, regs.pc))
goto error;
} else {
d1 /= d2;
if (!regs.sp[-1].setNumber(d1) && !(lval.isDouble() || rval.isDouble()))
script->typeMonitorOverflow(cx, regs.pc);
if (!regs.sp[-1].setNumber(d1) &&
!(lval.isDouble() || rval.isDouble()) &&
!script->typeMonitorOverflow(cx, regs.pc)) {
goto error;
}
}
}
END_CASE(JSOP_DIV)
@ -3862,7 +3874,8 @@ BEGIN_CASE(JSOP_MOD)
d1 = js_fmod(d1, d2);
regs.sp[-1].setDouble(d1);
}
script->typeMonitorOverflow(cx, regs.pc);
if (!script->typeMonitorOverflow(cx, regs.pc))
goto error;
}
}
END_CASE(JSOP_MOD)
@ -3903,8 +3916,10 @@ BEGIN_CASE(JSOP_NEG)
if (!ValueToNumber(cx, regs.sp[-1], &d))
goto error;
d = -d;
if (!regs.sp[-1].setNumber(d) && !ref.isDouble())
script->typeMonitorOverflow(cx, regs.pc);
if (!regs.sp[-1].setNumber(d) && !ref.isDouble() &&
!script->typeMonitorOverflow(cx, regs.pc)) {
goto error;
}
}
}
END_CASE(JSOP_NEG)
@ -3912,8 +3927,8 @@ END_CASE(JSOP_NEG)
BEGIN_CASE(JSOP_POS)
if (!ValueToNumber(cx, &regs.sp[-1]))
goto error;
if (!regs.sp[-1].isInt32())
script->typeMonitorOverflow(cx, regs.pc);
if (!regs.sp[-1].isInt32() && !script->typeMonitorOverflow(cx, regs.pc))
goto error;
END_CASE(JSOP_POS)
BEGIN_CASE(JSOP_DELNAME)
@ -4102,9 +4117,10 @@ do_incop:
PUSH_NULL();
if (!js_DoIncDec(cx, cs, &regs.sp[-2], &regs.sp[-1]))
goto error;
if (!cx->typeMonitorAssign(obj, id, regs.sp[-1]))
goto error;
regs.fp->setAssigning();
JSBool ok = obj->setProperty(cx, id, &regs.sp[-1], script->strictModeCode);
script->typeMonitorAssign(cx, regs.pc, obj, id, regs.sp[-1], !regs.sp[-1].isInt32());
regs.fp->clearAssigning();
if (!ok)
goto error;
@ -4175,8 +4191,8 @@ BEGIN_CASE(JSOP_LOCALINC)
PUSH_COPY(*vp);
if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-1], vp))
goto error;
if (!vp->isInt32())
script->typeMonitorOverflow(cx, regs.pc);
if (!vp->isInt32() && !script->typeMonitorOverflow(cx, regs.pc))
goto error;
}
len = JSOP_INCARG_LENGTH;
JS_ASSERT(len == js_CodeSpec[op].length);
@ -4286,8 +4302,8 @@ BEGIN_CASE(JSOP_GETXPROP)
}
} while (0);
if (rval.isUndefined())
script->typeMonitorUndefined(cx, regs.pc);
if (rval.isUndefined() && !script->typeMonitorUndefined(cx, regs.pc))
goto error;
regs.sp[-1] = rval;
assertSameCompartment(cx, regs.sp[-1]);
@ -4409,8 +4425,8 @@ BEGIN_CASE(JSOP_CALLPROP)
goto error;
}
#endif
if (rval.isUndefined())
script->typeMonitorUndefined(cx, regs.pc);
if (rval.isUndefined() && !script->typeMonitorUndefined(cx, regs.pc))
goto error;
}
END_CASE(JSOP_CALLPROP)
@ -4434,7 +4450,8 @@ BEGIN_CASE(JSOP_SETMETHOD)
JS_ASSERT_IF(op == JSOP_SETGNAME, obj == regs.fp->scopeChain().getGlobal());
jsid id = ATOM_TO_JSID(atoms[GET_INDEX(regs.pc)]);
script->typeMonitorAssign(cx, regs.pc, obj, id, rval);
if (!cx->typeMonitorAssign(obj, id, rval))
goto error;
do {
PropertyCache *cache = &JS_PROPERTY_CACHE(cx);
@ -4647,10 +4664,12 @@ BEGIN_CASE(JSOP_GETELEM)
regs.sp[-1] = *copyFrom;
assertSameCompartment(cx, regs.sp[-1]);
if (!rref.isInt32()) {
script->typeMonitorUnknown(cx, regs.pc);
if (!script->typeMonitorUnknown(cx, regs.pc))
goto error;
} else if (copyFrom->isUndefined()) {
cx->addTypeProperty(obj->getType(), NULL, TYPE_UNDEFINED);
script->typeMonitorUndefined(cx, regs.pc);
if (!script->typeMonitorUndefined(cx, regs.pc))
goto error;
}
}
END_CASE(JSOP_GETELEM)
@ -4684,8 +4703,10 @@ BEGIN_CASE(JSOP_CALLELEM)
regs.sp[-1] = thisv;
}
if (regs.sp[-2].isUndefined() || !JSID_IS_INT(id))
script->typeMonitorUnknown(cx, regs.pc);
if ((regs.sp[-2].isUndefined() || !JSID_IS_INT(id)) &&
!script->typeMonitorUnknown(cx, regs.pc)) {
goto error;
}
}
END_CASE(JSOP_CALLELEM)
@ -4696,7 +4717,8 @@ BEGIN_CASE(JSOP_SETELEM)
jsid id;
FETCH_ELEMENT_ID(obj, -2, id);
Value rval;
script->typeMonitorAssign(cx, regs.pc, obj, id, regs.sp[-1], !JSID_IS_INT(id));
if (!cx->typeMonitorAssign(obj, id, regs.sp[-1]))
goto error;
do {
if (obj->isDenseArray() && JSID_IS_INT(id)) {
jsuint length = obj->getDenseArrayInitializedLength();
@ -4705,8 +4727,8 @@ BEGIN_CASE(JSOP_SETELEM)
if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
if (js_PrototypeHasIndexedProperties(cx, obj))
break;
if ((jsuint)i >= obj->getArrayLength())
obj->setArrayLength(cx, i + 1);
if ((jsuint)i >= obj->getArrayLength() && !obj->setArrayLength(cx, i + 1))
goto error;
}
obj->setDenseArrayElement(i, regs.sp[-1]);
goto end_setelem;
@ -4728,7 +4750,8 @@ BEGIN_CASE(JSOP_ENUMELEM)
jsid id;
FETCH_ELEMENT_ID(obj, -1, id);
Value rval = regs.sp[-3];
script->typeMonitorAssign(cx, regs.pc, obj, id, rval);
if (!cx->typeMonitorAssign(obj, id, rval))
goto error;
if (!obj->setProperty(cx, id, &rval, script->strictModeCode))
goto error;
regs.sp -= 3;
@ -4825,8 +4848,8 @@ BEGIN_CASE(JSOP_FUNCALL)
goto error;
}
cx->typeMonitorCall(script, regs.pc, CallArgs(vp + 2, argc),
flags & JSFRAME_CONSTRUCTING, false);
if (!cx->typeMonitorCall(CallArgs(vp + 2, argc), flags & JSFRAME_CONSTRUCTING))
goto error;
/* Get pointer to new frame/slots, prepare arguments. */
StackSpace &stack = cx->stack();
@ -4990,8 +5013,8 @@ BEGIN_CASE(JSOP_CALLNAME)
}
PUSH_COPY(rval);
if (rval.isUndefined())
script->typeMonitorUndefined(cx, regs.pc);
if (rval.isUndefined() && !script->typeMonitorUndefined(cx, regs.pc))
goto error;
/* obj must be on the scope chain, thus not a function. */
if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME)
@ -5416,8 +5439,8 @@ BEGIN_CASE(JSOP_CALLGLOBAL)
JSObject *obj = regs.fp->scopeChain().getGlobal();
JS_ASSERT(obj->containsSlot(slot));
PUSH_COPY(obj->getSlot(slot));
if (regs.sp[-1].isUndefined())
script->typeMonitorUndefined(cx, regs.pc);
if (regs.sp[-1].isUndefined() && !script->typeMonitorUndefined(cx, regs.pc))
goto error;
if (op == JSOP_CALLGLOBAL)
PUSH_UNDEFINED();
}
@ -5537,7 +5560,8 @@ BEGIN_CASE(JSOP_DEFFUN)
Value rval = ObjectValue(*obj);
script->typeMonitorAssign(cx, regs.pc, parent, id, rval);
if (!cx->typeMonitorAssign(parent, id, rval))
goto error;
do {
/* Steps 5d, 5f. */
@ -5605,13 +5629,14 @@ BEGIN_CASE(JSOP_DEFFUN_DBGFC)
if (!CheckRedeclaration(cx, &parent, id, attrs))
goto error;
if (!cx->typeMonitorAssign(&parent, id, rval))
goto error;
if ((attrs == JSPROP_ENUMERATE)
? !parent.setProperty(cx, id, &rval, script->strictModeCode)
: !parent.defineProperty(cx, id, rval, PropertyStub, StrictPropertyStub, attrs)) {
goto error;
}
script->typeMonitorAssign(cx, regs.pc, &parent, id, rval);
}
END_CASE(JSOP_DEFFUN_FC)
@ -6015,8 +6040,10 @@ BEGIN_CASE(JSOP_NEWOBJECT)
LOAD_OBJECT(0, baseobj);
TypeObject *type = script->getTypeInitObject(cx, regs.pc, false);
JSObject *obj = CopyInitializerObject(cx, baseobj, type);
if (!type)
goto error;
JSObject *obj = CopyInitializerObject(cx, baseobj, type);
if (!obj)
goto error;
@ -6070,13 +6097,14 @@ BEGIN_CASE(JSOP_INITMETHOD)
JS_ASSERT(slot == shape->slot);
}
if (!cx->typeMonitorAssign(obj, shape->id, rval))
goto error;
/* A new object, or one we just extended in a recent initprop op. */
JS_ASSERT(!obj->lastProperty() ||
obj->shape() == obj->lastProperty()->shape);
obj->extend(cx, shape);
script->typeMonitorAssign(cx, regs.pc, obj, shape->id, rval);
/*
* No method change check here because here we are adding a new
* property, not updating an existing slot's value that might
@ -6092,7 +6120,8 @@ BEGIN_CASE(JSOP_INITMETHOD)
LOAD_ATOM(0, atom);
jsid id = ATOM_TO_JSID(atom);
script->typeMonitorAssign(cx, regs.pc, obj, id, rval);
if (!cx->typeMonitorAssign(obj, id, rval))
goto error;
uintN defineHow = (op == JSOP_INITMETHOD)
? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD
@ -6140,6 +6169,8 @@ BEGIN_CASE(JSOP_INITELEM)
goto error;
}
} else {
if (!cx->typeMonitorAssign(obj, id, rref))
goto error;
if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
goto error;
}
@ -6499,7 +6530,8 @@ BEGIN_CASE(JSOP_SETXMLNAME)
Value rval = regs.sp[-1];
jsid id;
FETCH_ELEMENT_ID(obj, -2, id);
script->typeMonitorAssign(cx, regs.pc, obj, id, rval);
if (!cx->typeMonitorAssign(obj, id, rval))
goto error;
if (!obj->setProperty(cx, id, &rval, script->strictModeCode))
goto error;
rval = regs.sp[-1];
@ -6788,7 +6820,8 @@ BEGIN_CASE(JSOP_ARRAYPUSH)
JS_ASSERT(script->nfixed <= slot);
JS_ASSERT(slot < script->nslots);
JSObject *obj = &regs.fp->slots()[slot].toObject();
script->typeMonitorAssign(cx, regs.pc, obj, JSID_VOID, regs.sp[-1]);
if (!cx->typeMonitorAssign(obj, JSID_VOID, regs.sp[-1]))
goto error;
if (!js_ArrayCompPush(cx, obj, regs.sp[-1]))
goto error;
regs.sp--;

View File

@ -375,6 +375,21 @@ GetCustomIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
return true;
}
/*
* Notify type inference of the custom iterator. This only needs to be done
* if this is coming from a 'for in' loop, not a call to Iterator itself.
* If an Iterator object is used in a for loop then the values fetched in
* that loop are unknown, whether there is a custom __iterator__ or not.
*/
if (!(flags & JSITER_OWNONLY)) {
JS_ASSERT(JSOp(*cx->regs->pc) == JSOP_ITER);
TypeObject *getset = cx->getTypeGetSet();
if (!getset)
return false;
if (!cx->fp()->script()->typeMonitorResult(cx, cx->regs->pc, (jstype) getset))
return false;
}
/* Otherwise call it and return that object. */
LeaveTrace(cx);
Value arg = BooleanValue((flags & JSITER_FOREACH) == 0);
@ -392,16 +407,7 @@ GetCustomIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
-1, ObjectValue(*obj), NULL, bytes.ptr());
return false;
}
/*
* Notify type inference of the custom iterator. This only needs to be done
* if this is coming from a 'for in' loop, not a call to Iterator itself.
* If an Iterator object is used in a for loop then the values fetched in
* that loop are unknown, whether there is a custom __iterator__ or not.
*/
if (!(flags & JSITER_OWNONLY)) {
JS_ASSERT(JSOp(*cx->regs->pc) == JSOP_ITER);
cx->fp()->script()->typeMonitorResult(cx, cx->regs->pc, (jstype) cx->getTypeGetSet());
}
return true;
}
@ -1241,17 +1247,19 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
case JSGENOP_NEXT:
case JSGENOP_SEND:
if (gen->state == JSGEN_OPEN) {
JSScript *script = gen->floatingFrame()->script();
jsbytecode *yieldpc = gen->regs.pc - JSOP_YIELD_LENGTH;
JS_ASSERT(JSOp(*yieldpc) == JSOP_YIELD);
if (!script->typeMonitorUnknown(cx, yieldpc))
return JS_FALSE;
/*
* Store the argument to send as the result of the yield
* expression.
*/
gen->regs.sp[-1] = arg;
jsbytecode *yieldpc = gen->regs.pc - JSOP_YIELD_LENGTH;
JS_ASSERT(JSOp(*yieldpc) == JSOP_YIELD);
JSScript *script = gen->floatingFrame()->script();
script->typeMonitorUnknown(cx, yieldpc);
}
gen->state = JSGEN_RUNNING;
break;
@ -1486,7 +1494,8 @@ js_InitIteratorClasses(JSContext *cx, JSObject *obj)
if (!proto)
return NULL;
cx->addTypeProperty(obj->getType(), js_StopIteration_str, ObjectValue(*proto));
if (!cx->addTypeProperty(obj->getType(), js_StopIteration_str, ObjectValue(*proto)))
return NULL;
return proto;
}

View File

@ -126,15 +126,14 @@ js_math_abs(JSContext *cx, uintN argc, Value *vp)
if (argc == 0) {
vp->setDouble(js_NaN);
cx->markTypeCallerOverflow();
return JS_TRUE;
return cx->markTypeCallerOverflow();
}
if (!ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fabs(x);
vp->setNumber(z);
if (!vp[2].isDouble() && vp->isDouble())
cx->markTypeCallerOverflow();
if (!vp[2].isDouble() && vp->isDouble() && !cx->markTypeCallerOverflow())
return false;
return JS_TRUE;
}
@ -272,15 +271,14 @@ js_math_ceil(JSContext *cx, uintN argc, Value *vp)
if (argc == 0) {
vp->setDouble(js_NaN);
cx->markTypeCallerOverflow();
return JS_TRUE;
return cx->markTypeCallerOverflow();
}
if (!ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = js_math_ceil_impl(x);
vp->setNumber(z);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return JS_TRUE;
}
@ -349,15 +347,14 @@ js_math_floor(JSContext *cx, uintN argc, Value *vp)
if (argc == 0) {
vp->setDouble(js_NaN);
cx->markTypeCallerOverflow();
return JS_TRUE;
return cx->markTypeCallerOverflow();
}
if (!ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = js_math_floor_impl(x);
vp->setNumber(z);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return JS_TRUE;
}
@ -395,8 +392,7 @@ js_math_max(JSContext *cx, uintN argc, Value *vp)
if (argc == 0) {
vp->setDouble(js_NegativeInfinity);
cx->markTypeCallerOverflow();
return JS_TRUE;
return cx->markTypeCallerOverflow();
}
argv = vp + 2;
for (i = 0; i < argc; i++) {
@ -404,8 +400,7 @@ js_math_max(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
if (JSDOUBLE_IS_NaN(x)) {
vp->setDouble(js_NaN);
cx->markTypeCallerOverflow();
return JS_TRUE;
return cx->markTypeCallerOverflow();
}
if (x == 0 && x == z) {
if (js_copysign(1.0, z) == -1)
@ -427,8 +422,7 @@ js_math_min(JSContext *cx, uintN argc, Value *vp)
if (argc == 0) {
vp->setDouble(js_PositiveInfinity);
cx->markTypeCallerOverflow();
return JS_TRUE;
return cx->markTypeCallerOverflow();
}
argv = vp + 2;
for (i = 0; i < argc; i++) {
@ -436,8 +430,7 @@ js_math_min(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
if (JSDOUBLE_IS_NaN(x)) {
vp->setDouble(js_NaN);
cx->markTypeCallerOverflow();
return JS_TRUE;
return cx->markTypeCallerOverflow();
}
if (x == 0 && x == z) {
if (js_copysign(1.0, x) == -1)
@ -485,8 +478,7 @@ math_pow(JSContext *cx, uintN argc, Value *vp)
if (argc <= 1) {
vp->setDouble(js_NaN);
cx->markTypeCallerOverflow();
return JS_TRUE;
return cx->markTypeCallerOverflow();
}
if (!ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
@ -526,8 +518,8 @@ math_pow(JSContext *cx, uintN argc, Value *vp)
z = pow(x, y);
vp->setNumber(z);
if (vp->isDouble() && !(vp[2].isDouble() || vp[3].isDouble()))
cx->markTypeCallerOverflow();
if (vp->isDouble() && !(vp[2].isDouble() || vp[3].isDouble()) && !cx->markTypeCallerOverflow())
return false;
return JS_TRUE;
}
@ -613,15 +605,14 @@ js_math_round(JSContext *cx, uintN argc, Value *vp)
if (argc == 0) {
vp->setDouble(js_NaN);
cx->markTypeCallerOverflow();
return JS_TRUE;
return cx->markTypeCallerOverflow();
}
if (!ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = js_copysign(floor(x + 0.5), x);
vp->setNumber(z);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return JS_TRUE;
}
@ -854,7 +845,6 @@ JS_DEFINE_TRCINFO_1(js_math_ceil,
static void math_TypeArith(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
types::TypeCallsite *site = Valueify(jssite);
if (!site->returnTypes)
@ -863,10 +853,9 @@ static void math_TypeArith(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
if (site->isNew)
site->returnTypes->addType(cx, types::TYPE_UNKNOWN);
// the zero-argument case will be handled as an overflow in the actual natives.
/* The zero-argument case will be handled as an overflow in the actual natives. */
for (size_t ind = 0; ind < site->argumentCount; ind++)
site->argumentTypes[ind]->addArith(cx, site->script, site->returnTypes);
#endif
}
static JSFunctionSpec math_static_methods[] = {

View File

@ -424,8 +424,7 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
/* Fast paths and exceptional cases. */
if (argc == 0) {
vp->setDouble(js_NaN);
cx->markTypeCallerOverflow();
return true;
return cx->markTypeCallerOverflow();
}
if (argc == 1 || (vp[3].isInt32() && (vp[3].toInt32() == 0 || vp[3].toInt32() == 10))) {
@ -435,8 +434,8 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
}
if (vp[2].isDouble()) {
vp->setNumber(ParseIntDoubleHelper(vp[2].toDouble()));
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return true;
}
}
@ -456,8 +455,7 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
if (radix != 0) {
if (radix < 2 || radix > 36) {
vp->setDouble(js_NaN);
cx->markTypeCallerOverflow();
return true;
return cx->markTypeCallerOverflow();
}
if (radix != 16)
stripPrefix = false;
@ -476,8 +474,8 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
/* Step 15. */
vp->setNumber(number);
if (!vp->isInt32())
cx->markTypeCallerOverflow();
if (!vp->isInt32() && !cx->markTypeCallerOverflow())
return false;
return true;
}

View File

@ -1633,9 +1633,8 @@ js_obj_defineGetter(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
TypeObject *type = cx->getTypeGetSet();
if (!type)
if (!type || !cx->addTypePropertyId(obj->getType(), id, (jstype) type))
return JS_FALSE;
cx->addTypePropertyId(obj->getType(), id, (jstype) type);
vp->setUndefined();
return obj->defineProperty(cx, id, UndefinedValue(), getter, StrictPropertyStub,
@ -1672,9 +1671,8 @@ js_obj_defineSetter(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
TypeObject *type = cx->getTypeGetSet();
if (!type)
if (!type || !cx->addTypePropertyId(obj->getType(), id, (jstype) type))
return JS_FALSE;
cx->addTypePropertyId(obj->getType(), id, (jstype) type);
vp->setUndefined();
return obj->defineProperty(cx, id, UndefinedValue(), PropertyStub, setter,
@ -2451,7 +2449,8 @@ DefinePropertyOnArray(JSContext *cx, JSObject *obj, const PropDesc &desc,
if (index >= oldLen) {
JS_ASSERT(index != UINT32_MAX);
obj->setArrayLength(cx, index + 1);
if (!obj->setArrayLength(cx, index + 1))
return JS_FALSE;
}
*rval = true;
@ -2465,9 +2464,8 @@ static JSBool
DefineProperty(JSContext *cx, JSObject *obj, const PropDesc &desc, bool throwError,
bool *rval)
{
/* Add this to the type information for the object.
* TODO: handle getters and setters. */
cx->addTypePropertyId(obj->getType(), desc.id, desc.value);
if (!cx->addTypePropertyId(obj->getType(), desc.id, desc.value))
return false;
if (obj->isArray())
return DefinePropertyOnArray(cx, obj, desc, throwError, rval);
@ -2614,7 +2612,8 @@ obj_create(JSContext *cx, uintN argc, Value *vp)
vp->setObject(*obj); /* Root and prepare for eventual return. */
/* Don't track types or array-ness for objects created here. */
cx->markTypeObjectUnknownProperties(obj->getType());
if (!cx->markTypeObjectUnknownProperties(obj->getType()))
return false;
/* 15.2.3.5 step 4. */
if (argc > 1 && !vp[3].isUndefined()) {
@ -2946,7 +2945,8 @@ js_CreateThis(JSContext *cx, JSObject *callee)
JSObject *obj = NewObject<WithProto::Class>(cx, newclasp, proto, parent, kind);
if (obj) {
obj->syncSpecialEquality();
cx->markTypeArrayNotPacked(obj->getType(), true, true);
if (!cx->markTypeArrayNotPacked(obj->getType(), true))
return NULL;
}
return obj;
}
@ -2972,9 +2972,8 @@ js_CreateThisForFunction(JSContext *cx, JSObject *callee)
if (protov.isObject()) {
proto = &protov.toObject();
TypeObject *type = proto->getNewType(cx);
if (!type)
if (!type || !cx->markTypeArrayNotPacked(type, true))
return NULL;
cx->markTypeArrayNotPacked(type, true, true);
} else {
proto = NULL;
}
@ -3022,8 +3021,10 @@ js_InitializerObject(JSContext* cx, JSObject *proto, JSObject *baseobj)
return NewObjectWithClassProto(cx, &js_ObjectClass, proto, kind);
}
/* :FIXME: new Objects do not have the right type when created on trace. */
/* :FIXME: bug 637856 new Objects do not have the right type when created on trace. */
TypeObject *type = proto->getNewType(cx);
if (!type)
return NULL;
return CopyInitializerObject(cx, baseobj, type);
}
@ -3063,9 +3064,8 @@ js_CreateThisFromTrace(JSContext *cx, JSObject *ctor, uintN protoSlot)
if (protov.isObject()) {
proto = &protov.toObject();
TypeObject *type = proto->getNewType(cx);
if (!type)
if (!type || !cx->markTypeArrayNotPacked(type, true))
return NULL;
cx->markTypeArrayNotPacked(type, true, true);
} else {
/*
* GetInterpretedFunctionPrototype found that ctor.prototype is
@ -3832,11 +3832,12 @@ Class js_BlockClass = {
static void object_TypeNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (site->argumentCount == 0) {
TypeObject *object = site->getInitObject(cx, false);
if (!object)
return;
if (site->returnTypes)
site->returnTypes->addType(cx, (jstype) object);
} else {
@ -3844,7 +3845,6 @@ static void object_TypeNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
if (site->returnTypes)
site->returnTypes->addType(cx, TYPE_UNKNOWN);
}
#endif
}
JSObject *
@ -3862,7 +3862,9 @@ js_InitObjectClass(JSContext *cx, JSObject *obj)
return NULL;
/* The default 'new' object for Object.prototype has unknown properties. */
cx->markTypeObjectUnknownProperties(proto->getNewType(cx));
TypeObject *newType = proto->getNewType(cx);
if (!newType || !cx->markTypeObjectUnknownProperties(newType))
return NULL;
return proto;
}
@ -3978,10 +3980,8 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt
JSFunction *fun = js_NewFunction(cx, NULL, constructor, nargs, JSFUN_CONSTRUCTOR, obj, atom,
ctorHandler, clasp->name);
if (!fun)
return NULL;
cx->addTypePropertyId(obj->getType(), ATOM_TO_JSID(atom), ObjectValue(*fun));
if (!fun || !cx->addTypePropertyId(obj->getType(), ATOM_TO_JSID(atom), ObjectValue(*fun)))
goto bad;
AutoValueRooter tvr2(cx, ObjectValue(*fun));
if (!DefineStandardSlot(cx, obj, key, atom, tvr2.value(), 0, named))
@ -4290,8 +4290,10 @@ SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles)
* Setting __proto__ on an object that has escaped and may be referenced by
* other heap objects can only be done if the properties of both objects are unknown.
*/
cx->markTypeObjectUnknownProperties(obj->getType());
cx->markTypeObjectUnknownProperties(type);
if (!cx->markTypeObjectUnknownProperties(obj->getType()) ||
!cx->markTypeObjectUnknownProperties(type)) {
return false;
}
if (!proto || !checkForCycles) {
obj->setType(type);
@ -4480,7 +4482,8 @@ js_ConstructObject(JSContext *cx, Class *clasp, JSObject *proto, JSObject *paren
return NULL;
obj->syncSpecialEquality();
cx->markTypeObjectUnknownProperties(obj->getType());
if (!cx->markTypeObjectUnknownProperties(obj->getType()))
return NULL;
Value rval;
if (!InvokeConstructorWithGivenThis(cx, obj, cval, argc, argv, &rval))
@ -6345,8 +6348,10 @@ js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
JSBool
js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, uintN attrs)
{
cx->addTypePropertyId(ctor->getType(), ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
ObjectOrNullValue(proto));
if (!cx->addTypePropertyId(ctor->getType(), ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
ObjectOrNullValue(proto))) {
return JS_FALSE;
}
/*
* Use the given attributes for the prototype property of the constructor,

View File

@ -796,10 +796,11 @@ struct JSObject : js::gc::Cell {
*/
inline uint32 getArrayLength() const;
inline void setArrayLength(JSContext *cx, uint32 length);
inline bool setArrayLength(JSContext *cx, uint32 length);
inline uint32 getDenseArrayCapacity();
inline uint32 getDenseArrayInitializedLength();
inline void setDenseArrayLength(uint32 length);
inline void setDenseArrayInitializedLength(uint32 length);
inline js::Value* getDenseArrayElements();
inline const js::Value &getDenseArrayElement(uintN idx);
@ -808,7 +809,7 @@ struct JSObject : js::gc::Cell {
inline void shrinkDenseArrayElements(JSContext *cx, uintN cap);
inline bool isPackedDenseArray();
inline void setDenseArrayNotPacked(JSContext *cx);
inline bool setDenseArrayNotPacked(JSContext *cx);
/*
* ensureDenseArrayElements ensures that the dense array can hold at least
@ -1644,8 +1645,8 @@ js_DefineNativePropertyWithType(JSContext *cx, JSObject *obj, jsid id, const js:
uintN flags, intN shortid, JSProperty **propp,
uintN defineHow = 0)
{
JS_AddTypePropertyById(cx, obj, id, Jsvalify(value));
return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
return JS_AddTypePropertyById(cx, obj, id, Jsvalify(value)) &&
js_DefineNativeProperty(cx, obj, id, value, getter, setter,
attrs, flags, shortid, propp, defineHow);
}

View File

@ -311,16 +311,28 @@ JSObject::getArrayLength() const
return (uint32)(size_t) getPrivate();
}
inline void
inline bool
JSObject::setArrayLength(JSContext *cx, uint32 length)
{
JS_ASSERT(isArray());
setPrivate((void*) length);
if (length > INT32_MAX) {
cx->addTypePropertyId(getType(), ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
js::types::TYPE_DOUBLE);
if (length > INT32_MAX &&
!cx->addTypePropertyId(getType(), ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
js::types::TYPE_DOUBLE)) {
return false;
}
setPrivate((void*) length);
return true;
}
inline void
JSObject::setDenseArrayLength(uint32 length)
{
/* Variant of setArrayLength for use on dense arrays where the length cannot overflow int32. */
JS_ASSERT(isDenseArray());
JS_ASSERT(length <= INT32_MAX);
setPrivate((void*) length);
}
inline uint32

View File

@ -1182,7 +1182,8 @@ Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *scrip
* optimizations only take place if the property is not defined.
*/
rval.setObject(*fun);
cx->addTypePropertyId(globalObj->getType(), id, rval);
if (!cx->addTypePropertyId(globalObj->getType(), id, rval))
return false;
} else {
rval.setUndefined();
}

View File

@ -1158,7 +1158,8 @@ NewProxyObject(JSContext *cx, JSProxyHandler *handler, const Value &priv, JSObje
}
/* Don't track types of properties of proxies. */
cx->markTypeObjectUnknownProperties(obj->getType());
if (!cx->markTypeObjectUnknownProperties(obj->getType()))
return NULL;
return obj;
}

View File

@ -928,14 +928,17 @@ js_InitRegExpClass(JSContext *cx, JSObject *obj)
}
TypeObject *regexpType = proto->getNewType(cx);
JS_ASSERT(regexpType);
if (!regexpType)
return NULL;
cx->addTypeProperty(regexpType, "source", TYPE_STRING);
cx->addTypeProperty(regexpType, "global", TYPE_BOOLEAN);
cx->addTypeProperty(regexpType, "ignoreCase", TYPE_BOOLEAN);
cx->addTypeProperty(regexpType, "multiline", TYPE_BOOLEAN);
cx->addTypeProperty(regexpType, "sticky", TYPE_BOOLEAN);
cx->addTypeProperty(regexpType, "lastIndex", TYPE_INT32);
if (!cx->addTypeProperty(regexpType, "source", TYPE_STRING) ||
!cx->addTypeProperty(regexpType, "global", TYPE_BOOLEAN) ||
!cx->addTypeProperty(regexpType, "ignoreCase", TYPE_BOOLEAN) ||
!cx->addTypeProperty(regexpType, "multiline", TYPE_BOOLEAN) ||
!cx->addTypeProperty(regexpType, "sticky", TYPE_BOOLEAN) ||
!cx->addTypeProperty(regexpType, "lastIndex", TYPE_INT32)) {
return NULL;
}
return proto;
}

View File

@ -278,10 +278,12 @@ GetRegExpMatchType(JSContext *cx)
if (!type)
return NULL;
cx->addTypeProperty(type, NULL, types::TYPE_STRING);
cx->addTypeProperty(type, "index", types::TYPE_INT32);
cx->addTypeProperty(type, "input", types::TYPE_STRING);
cx->markTypeArrayNotPacked(type, true);
if (!cx->addTypeProperty(type, NULL, types::TYPE_STRING) ||
!cx->addTypeProperty(type, "index", types::TYPE_INT32) ||
!cx->addTypeProperty(type, "input", types::TYPE_STRING) ||
!cx->markTypeArrayNotPacked(type, true)) {
return NULL;
}
return type;
}
@ -301,7 +303,6 @@ RegExp::createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemC
if (!type)
return NULL;
array->setType(type);
cx->markTypeArrayNotPacked(type, true);
RegExpMatchBuilder builder(cx, array);
for (size_t i = 0; i < matchItemCount; i += 2) {

View File

@ -66,14 +66,11 @@
#endif
#include "methodjit/MethodJIT.h"
#include "jsinferinlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h"
#include "jsscriptinlines.h"
#ifdef JS_TYPE_INFERENCE
#include "jsinferinlines.h"
#endif
using namespace js;
using namespace js::gc;
@ -1383,7 +1380,7 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
script->owner = cx->thread;
#endif
#if defined JS_TYPE_INFERENCE && DEBUG
#ifdef DEBUG
script->id_ = ++cx->compartment->types.scriptCount;
#endif
@ -1483,7 +1480,6 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
cg->upvarMap.vector = NULL;
}
#ifdef JS_TYPE_INFERENCE
/* Set global for compileAndGo scripts. */
if (script->compileAndGo) {
GlobalScope *globalScope = cg->compiler()->globalScope;
@ -1493,7 +1489,6 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
script->global = cx->globalObject;
}
}
#endif
if (cg->globalUses.length()) {
memcpy(script->globals()->vector, &cg->globalUses[0],
@ -1527,22 +1522,25 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
#endif
fun->u.i.script = script;
#ifdef JS_TYPE_INFERENCE
char *name = NULL;
#ifdef DEBUG
name = (char *) alloca(10);
JS_snprintf(name, 10, "#%u", script->id());
#endif
types::TypeObject *type = cx->newTypeFunction(name, fun->getProto());
fun->setType(type);
cx->setTypeFunctionScript(fun, script);
#endif
#ifdef CHECK_SCRIPT_OWNER
script->owner = NULL;
#endif
if (cg->flags & TCF_FUN_HEAVYWEIGHT)
fun->flags |= JSFUN_HEAVYWEIGHT;
if (cx->typeInferenceEnabled()) {
char *name = NULL;
#ifdef DEBUG
name = (char *) alloca(10);
JS_snprintf(name, 10, "#%u", script->id());
#endif
types::TypeObject *type = cx->newTypeFunction(name, fun->getProto());
if (!type)
goto bad;
fun->setType(type);
cx->setTypeFunctionScript(fun, script);
}
}
/* Tell the debugger about this compiled script. */
@ -1660,7 +1658,6 @@ DestroyScript(JSContext *cx, JSScript *script)
PurgeScriptFragments(&script->compartment->traceMonitor, script);
#endif
#ifdef JS_TYPE_INFERENCE
JS_ASSERT(!script->types);
/* Migrate any type objects associated with this script to the compartment. */
@ -1678,7 +1675,6 @@ DestroyScript(JSContext *cx, JSScript *script)
cx->free(result);
result = next;
}
#endif
#if defined(JS_METHODJIT)
mjit::ReleaseScriptCode(cx, script);
@ -1757,7 +1753,10 @@ js_TraceScript(JSTracer *trc, JSScript *script)
script->bindings.trace(trc);
#ifdef JS_TYPE_INFERENCE
/*
* Trace all type objects associated with the script, these can be freely
* referenced from JIT code without needing to be pinned against GC.
*/
types::TypeObject *obj = script->typeObjects;
while (obj) {
if (!obj->marked)
@ -1769,7 +1768,6 @@ js_TraceScript(JSTracer *trc, JSScript *script)
JS_SET_TRACING_NAME(trc, "script_fun");
Mark(trc, script->fun);
}
#endif
}
JSBool

View File

@ -406,9 +406,7 @@ struct JSScript {
bool hasSingletons:1; /* script has singleton objects */
bool isCachedEval:1; /* script came from eval() */
bool isUncachedEval:1; /* script came from EvaluateScript */
#ifdef JS_TYPE_INFERENCE
bool analyzed:1; /* script has previously been analyzed */
#endif
bool analyzed:1; /* script has been analyzed by type inference */
#ifdef JS_METHODJIT
bool debugMode:1; /* script was compiled in debug mode */
bool singleStepMode:1; /* compile script in single-step mode */
@ -455,7 +453,6 @@ struct JSScript {
public:
#ifdef JS_TYPE_INFERENCE
#ifdef DEBUG
/* Unique identifier within the compartment for this script. */
unsigned id_;
@ -506,7 +503,6 @@ struct JSScript {
/* Get the default 'new' object for a given standard class, per the script's global. */
inline js::types::TypeObject *getTypeNewObject(JSContext *cx, JSProtoKey key);
#endif
void condenseTypes(JSContext *cx);
void sweepTypes(JSContext *cx);
@ -516,21 +512,18 @@ struct JSScript {
getTypeInitObject(JSContext *cx, const jsbytecode *pc, bool isArray);
/* Monitor a bytecode pushing an unexpected value. */
inline void typeMonitorResult(JSContext *cx, const jsbytecode *pc, js::types::jstype type);
inline void typeMonitorResult(JSContext *cx, const jsbytecode *pc, const js::Value &val);
inline void typeMonitorUndefined(JSContext *cx, const jsbytecode *pc);
inline void typeMonitorOverflow(JSContext *cx, const jsbytecode *pc);
inline void typeMonitorUnknown(JSContext *cx, const jsbytecode *pc);
inline bool typeMonitorResult(JSContext *cx, const jsbytecode *pc, js::types::jstype type);
inline bool typeMonitorResult(JSContext *cx, const jsbytecode *pc, const js::Value &val);
inline bool typeMonitorUndefined(JSContext *cx, const jsbytecode *pc);
inline bool typeMonitorOverflow(JSContext *cx, const jsbytecode *pc);
inline bool typeMonitorUnknown(JSContext *cx, const jsbytecode *pc);
/* Monitor a bytecode assigning to an object's property, if necessary. */
inline void typeMonitorAssign(JSContext *cx, const jsbytecode *pc,
JSObject *obj, jsid id, const js::Value &rval, bool force = false);
/* Override the value of an argument to this script by assigning to arguments[...]. */
inline void typeSetArgument(JSContext *cx, unsigned arg, const js::Value &value);
/* Mark the value of a flat closure upvar in this script. */
inline void typeSetUpvar(JSContext *cx, unsigned upvar, const js::Value &value);
/* Add a type for a variable in this script. */
inline bool typeSetThis(JSContext *cx, js::types::jstype type);
inline bool typeSetLocal(JSContext *cx, unsigned local, const js::Value &value);
inline bool typeSetArgument(JSContext *cx, unsigned arg, js::types::jstype type);
inline bool typeSetArgument(JSContext *cx, unsigned arg, const js::Value &value);
inline bool typeSetUpvar(JSContext *cx, unsigned upvar, const js::Value &value);
#ifdef JS_METHODJIT
// Fast-cached pointers to make calls faster. These are also used to

View File

@ -1102,9 +1102,8 @@ js_str_charCodeAt(JSContext *cx, uintN argc, Value *vp)
return true;
out_of_range:
cx->markTypeCallerOverflow();
vp->setDouble(js_NaN);
return true;
return cx->markTypeCallerOverflow();
}
jsint
@ -1828,7 +1827,6 @@ BuildFlatMatchArray(JSContext *cx, JSString *textstr, const FlatMatch &fm, Value
if (!type)
return false;
obj->setType(type);
cx->markTypeArrayNotPacked(type, true);
vp->setObject(*obj);
@ -2661,9 +2659,8 @@ str_split(JSContext *cx, uintN argc, Value *vp)
return false;
TypeObject *type = cx->getTypeCallerInitObject(true);
if (!type)
if (!type || !cx->addTypeProperty(type, NULL, types::TYPE_STRING))
return false;
cx->addTypeProperty(type, NULL, types::TYPE_STRING);
if (argc == 0) {
Value v = StringValue(str);
@ -3087,7 +3084,6 @@ JS_DEFINE_TRCINFO_1(str_concat,
static void type_StringMatch(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (!site->returnTypes)
@ -3102,18 +3098,15 @@ static void type_StringMatch(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
site->returnTypes->addType(cx, TYPE_UNKNOWN);
TypeObject *type = site->getInitObject(cx, true);
cx->addTypeProperty(type, NULL, TYPE_STRING);
cx->addTypeProperty(type, "index", TYPE_INT32);
cx->addTypeProperty(type, "input", TYPE_STRING);
if (!type)
return;
site->returnTypes->addType(cx, TYPE_NULL);
site->returnTypes->addType(cx, (jstype) type);
#endif
}
static void type_StringSplit(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
TypeCallsite *site = Valueify(jssite);
if (!site->returnTypes)
@ -3128,10 +3121,10 @@ static void type_StringSplit(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
site->returnTypes->addType(cx, TYPE_UNKNOWN);
TypeObject *type = site->getInitObject(cx, true);
cx->addTypeProperty(type, NULL, TYPE_STRING);
if (!type)
return;
site->returnTypes->addType(cx, (jstype) type);
#endif
}
static JSFunctionSpec string_methods[] = {
@ -3453,12 +3446,10 @@ static JSFunctionSpec string_static_methods[] = {
static void type_NewString(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
#ifdef JS_TYPE_INFERENCE
if (Valueify(jssite)->isNew)
JS_TypeHandlerNew(cx, jsfun, jssite);
else
JS_TypeHandlerString(cx, jsfun, jssite);
#endif
}
JSObject *
@ -3485,8 +3476,12 @@ js_InitStringClass(JSContext *cx, JSObject *obj)
return JS_FALSE;
}
cx->addTypePropertyId(proto->getType(), lengthId, TYPE_INT32);
cx->addTypeProperty(proto->getNewType(cx), NULL, TYPE_STRING);
if (!cx->addTypePropertyId(proto->getType(), lengthId, TYPE_INT32))
return NULL;
TypeObject *objectType = proto->getNewType(cx);
if (!objectType || !cx->addTypeProperty(objectType, NULL, TYPE_STRING))
return NULL;
return proto;
}

View File

@ -1567,11 +1567,16 @@ do { \
NULL, NULL); \
if (!proto) \
return NULL; \
cx->addTypeProperty(proto->getType(), NULL, types::TYPE_INT32); \
if (_typedArray::ArrayElementTypeMayBeDouble()) \
cx->addTypeProperty(proto->getType(), NULL, types::TYPE_DOUBLE); \
cx->addTypeProperty(proto->getType(), "buffer", \
(types::jstype) bufferType); \
if (!cx->addTypeProperty(proto->getType(), NULL, types::TYPE_INT32)) \
return NULL; \
if (_typedArray::ArrayElementTypeMayBeDouble() && \
!cx->addTypeProperty(proto->getType(), NULL, types::TYPE_DOUBLE)) { \
return NULL; \
} \
if (!cx->addTypeProperty(proto->getType(), "buffer", \
(types::jstype) bufferType)) { \
return NULL; \
} \
JSObject *ctor = JS_GetConstructor(cx, proto); \
if (!ctor || \
!JS_DefinePropertyWithType(cx, ctor, "BYTES_PER_ELEMENT", \
@ -1641,6 +1646,8 @@ js_InitTypedArrayClasses(JSContext *cx, JSObject *obj)
return NULL;
TypeObject *bufferType = proto->getNewType(cx);
if (!bufferType)
return NULL;
INIT_TYPED_ARRAY_CLASS(Int8Array,TYPE_INT8);
INIT_TYPED_ARRAY_CLASS(Uint8Array,TYPE_UINT8);

View File

@ -220,7 +220,8 @@ bool
JSWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool strict,
Value *vp)
{
cx->addTypePropertyId(wrappedObject(wrapper)->getType(), id, *vp);
if (!cx->addTypePropertyId(wrappedObject(wrapper)->getType(), id, *vp))
return false;
// FIXME (bug 596351): Need deal with strict mode.
SET(wrappedObject(wrapper)->setProperty(cx, id, vp, false));

View File

@ -6826,9 +6826,8 @@ CopyXMLSettings(JSContext *cx, JSObject *from, JSObject *to)
if (!JSVAL_IS_BOOLEAN(v))
continue;
}
if (!JS_SetProperty(cx, to, name, &v))
if (!JS_AddTypeProperty(cx, to, name, v) || !JS_SetProperty(cx, to, name, &v))
return false;
JS_AddTypeProperty(cx, to, name, v);
}
return true;
@ -7141,9 +7140,8 @@ js_InitXMLClass(JSContext *cx, JSObject *obj)
/* Properties of XML objects are not modeled by type inference. */
TypeObject *type = proto->getNewType(cx);
if (!type)
if (!type || !cx->markTypeObjectUnknownProperties(type))
return NULL;
cx->markTypeObjectUnknownProperties(type);
xml = js_NewXML(cx, JSXML_CLASS_TEXT);
if (!xml)

View File

@ -121,12 +121,10 @@ mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp)
addTraceHints(false),
#endif
recompiling(false),
#if defined JS_TYPE_INFERENCE
hasThisType(false),
thisType(JSVAL_TYPE_UNKNOWN),
argumentTypes(ContextAllocPolicy(cx)),
localTypes(ContextAllocPolicy(cx)),
#endif
oomInVector(false),
applyTricks(NoApplyTricks)
{
@ -165,6 +163,8 @@ mjit::Compiler::compile(const Vector<JSStackFrame*> *frames)
if (status_ != Compile_Okay) { \
if (oomInVector || masm.oom() || stubcc.masm.oom()) \
js_ReportOutOfMemory(cx); \
if (!cx->compartment->types.checkPendingRecompiles(cx)) \
return Compile_Error; \
return status_; \
} \
JS_END_MACRO
@ -193,8 +193,108 @@ mjit::Compiler::performCompilation(JITScript **jitp, const Vector<JSStackFrame*>
return Compile_Error;
}
#ifdef JS_TYPE_INFERENCE
types::AutoEnterTypeInference enter(cx);
#ifdef JS_METHODJIT_SPEW
if (IsJaegerSpewChannelActive(JSpew_Regalloc)) {
for (unsigned i = 0; i < script->nfixed; i++) {
if (!analysis->localEscapes(i)) {
JaegerSpew(JSpew_Regalloc, "Local %u:", i);
liveness.dumpLocal(i);
}
}
for (unsigned i = 0; fun && i < fun->nargs; i++) {
if (!analysis->argEscapes(i)) {
JaegerSpew(JSpew_Regalloc, "Argument %u:", i);
liveness.dumpArg(i);
}
}
}
#endif
if (!frame.init()) {
js_ReportOutOfMemory(cx);
return Compile_Error;
}
jumpMap = (Label *)cx->malloc(sizeof(Label) * script->length);
if (!jumpMap) {
js_ReportOutOfMemory(cx);
return Compile_Error;
}
#ifdef DEBUG
for (uint32 i = 0; i < script->length; i++)
jumpMap[i] = Label();
#endif
#ifdef JS_METHODJIT_SPEW
Profiler prof;
prof.start();
#endif
/* Initialize PC early so stub calls in the prologue can be fallible. */
PC = script->code;
#ifdef JS_METHODJIT
script->debugMode = debugMode();
#endif
for (uint32 i = 0; i < script->nClosedVars; i++)
frame.setClosedVar(script->getClosedVar(i));
for (uint32 i = 0; i < script->nClosedArgs; i++)
frame.setClosedArg(script->getClosedArg(i));
types::AutoEnterTypeInference enter(cx, true);
if (cx->typeInferenceEnabled()) {
CompileStatus status = prepareInferenceTypes(frames);
if (status != Compile_Okay) {
if (!cx->compartment->types.checkPendingRecompiles(cx))
return Compile_Error;
return status;
}
}
CHECK_STATUS(generatePrologue());
CHECK_STATUS(generateMethod());
CHECK_STATUS(generateEpilogue());
CHECK_STATUS(finishThisUp(jitp));
#ifdef JS_METHODJIT_SPEW
prof.stop();
JaegerSpew(JSpew_Prof, "compilation took %d us\n", prof.time_us());
#endif
JaegerSpew(JSpew_Scripts, "successfully compiled (code \"%p\") (size \"%ld\")\n",
(*jitp)->code.m_code.executableAddress(), (*jitp)->code.m_size);
if (!cx->compartment->types.checkPendingRecompiles(cx))
return Compile_Error;
if (!*jitp)
return Compile_Abort;
return Compile_Okay;
}
#undef CHECK_STATUS
mjit::Compiler::~Compiler()
{
cx->free(jumpMap);
cx->free(savedTraps);
}
CompileStatus
mjit::Compiler::prepareInferenceTypes(const Vector<JSStackFrame*> *frames)
{
/* Analyze the script if we have not already done so. */
if (!script->types) {
/* Uncached eval scripts are not analyzed or compiled. */
if (script->isUncachedEval)
return Compile_Abort;
types::AnalyzeScriptTypes(cx, script);
if (!script->types)
return Compile_Error;
}
/*
* Fill in known types of arguments and locals, and patch up doubles for
@ -203,14 +303,6 @@ mjit::Compiler::performCompilation(JITScript **jitp, const Vector<JSStackFrame*>
* frames. We handle this by patching up all hold stack frames to ensure that
* arguments, locals, and stack values we treat as doubles actually are doubles.
*/
if (!script->types) {
/* Uncached eval scripts are never analyzed or compiled. */
if (script->isUncachedEval)
return Compile_Abort;
types::AnalyzeScriptTypes(cx, script);
if (!script->types)
return Compile_Error;
}
uint32 nargs = fun ? fun->nargs : 0;
if (!argumentTypes.reserve(nargs))
@ -283,81 +375,10 @@ mjit::Compiler::performCompilation(JITScript **jitp, const Vector<JSStackFrame*>
break;
}
}
#endif
#ifdef JS_METHODJIT_SPEW
if (IsJaegerSpewChannelActive(JSpew_Regalloc)) {
for (unsigned i = 0; i < script->nfixed; i++) {
if (!analysis->localEscapes(i)) {
JaegerSpew(JSpew_Regalloc, "Local %u:", i);
liveness.dumpLocal(i);
}
}
for (unsigned i = 0; fun && i < fun->nargs; i++) {
if (!analysis->argEscapes(i)) {
JaegerSpew(JSpew_Regalloc, "Argument %u:", i);
liveness.dumpArg(i);
}
}
}
#endif
if (!frame.init()) {
js_ReportOutOfMemory(cx);
return Compile_Error;
}
jumpMap = (Label *)cx->malloc(sizeof(Label) * script->length);
if (!jumpMap) {
js_ReportOutOfMemory(cx);
return Compile_Error;
}
#ifdef DEBUG
for (uint32 i = 0; i < script->length; i++)
jumpMap[i] = Label();
#endif
#ifdef JS_METHODJIT_SPEW
Profiler prof;
prof.start();
#endif
/* Initialize PC early so stub calls in the prologue can be fallible. */
PC = script->code;
#ifdef JS_METHODJIT
script->debugMode = debugMode();
#endif
for (uint32 i = 0; i < script->nClosedVars; i++)
frame.setClosedVar(script->getClosedVar(i));
for (uint32 i = 0; i < script->nClosedArgs; i++)
frame.setClosedArg(script->getClosedArg(i));
CHECK_STATUS(generatePrologue());
CHECK_STATUS(generateMethod());
CHECK_STATUS(generateEpilogue());
CHECK_STATUS(finishThisUp(jitp));
#ifdef JS_METHODJIT_SPEW
prof.stop();
JaegerSpew(JSpew_Prof, "compilation took %d us\n", prof.time_us());
#endif
JaegerSpew(JSpew_Scripts, "successfully compiled (code \"%p\") (size \"%ld\")\n",
(*jitp)->code.m_code.executableAddress(), (*jitp)->code.m_size);
return Compile_Okay;
}
#undef CHECK_STATUS
mjit::Compiler::~Compiler()
{
cx->free(jumpMap);
cx->free(savedTraps);
}
CompileStatus JS_NEVER_INLINE
mjit::TryCompile(JSContext *cx, JSStackFrame *fp)
{
@ -1388,28 +1409,28 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_ADD)
if (!jsop_binary(op, stubs::Add, knownPushedType(0))) {
markPushedOverflow(0);
markPushedOverflow();
return Compile_Overflow;
}
END_CASE(JSOP_ADD)
BEGIN_CASE(JSOP_SUB)
if (!jsop_binary(op, stubs::Sub, knownPushedType(0))) {
markPushedOverflow(0);
markPushedOverflow();
return Compile_Overflow;
}
END_CASE(JSOP_SUB)
BEGIN_CASE(JSOP_MUL)
if (!jsop_binary(op, stubs::Mul, knownPushedType(0))) {
markPushedOverflow(0);
markPushedOverflow();
return Compile_Overflow;
}
END_CASE(JSOP_MUL)
BEGIN_CASE(JSOP_DIV)
if (!jsop_binary(op, stubs::Div, knownPushedType(0))) {
markPushedOverflow(0);
markPushedOverflow();
return Compile_Overflow;
}
END_CASE(JSOP_DIV)
@ -1450,7 +1471,7 @@ mjit::Compiler::generateMethod()
/* Watch for overflow in constant propagation. */
if (!v.isInt32() && knownPushedType(0) == JSVAL_TYPE_INT32) {
JaegerSpew(JSpew_Abort, "overflow in negation (%u)\n", PC - script->code);
markPushedOverflow(0);
markPushedOverflow();
return Compile_Overflow;
}
@ -1863,15 +1884,18 @@ mjit::Compiler::generateMethod()
END_CASE(JSOP_UINT16)
BEGIN_CASE(JSOP_NEWINIT)
jsop_newinit();
if (!jsop_newinit())
return Compile_Error;
END_CASE(JSOP_NEWINIT)
BEGIN_CASE(JSOP_NEWARRAY)
jsop_newinit();
if (!jsop_newinit())
return Compile_Error;
END_CASE(JSOP_NEWARRAY)
BEGIN_CASE(JSOP_NEWOBJECT)
jsop_newinit();
if (!jsop_newinit())
return Compile_Error;
END_CASE(JSOP_NEWOBJECT)
BEGIN_CASE(JSOP_ENDINIT)
@ -2677,11 +2701,6 @@ mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew)
static bool
IsLowerableFunCallOrApply(jsbytecode *pc)
{
#ifdef JS_TYPE_INFERENCE
/* :FIXME: see canUseApplyTricks */
return false;
#endif
#ifdef JS_MONOIC
return (*pc == JSOP_FUNCALL && GET_ARGC(pc) >= 1) ||
(*pc == JSOP_FUNAPPLY && GET_ARGC(pc) == 2);
@ -2779,17 +2798,19 @@ mjit::Compiler::checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedA
bool
mjit::Compiler::canUseApplyTricks()
{
#ifdef JS_TYPE_INFERENCE
/*
* :FIXME: Inference currently assumes that arguments passed via call and apply
* are monitored, and that short circuiting these doesn't happen.
*/
return false;
#endif
if (cx->typeInferenceEnabled()) {
/*
* :FIXME: bug 619428 inference currently assumes that arguments passed
* via call and apply are monitored, and that short circuiting these
* doesn't happen.
*/
return false;
}
JS_ASSERT(*PC == JSOP_ARGUMENTS);
jsbytecode *nextpc = PC + JSOP_ARGUMENTS_LENGTH;
return *nextpc == JSOP_FUNAPPLY &&
!cx->typeInferenceEnabled() /* :FIXME: bug 619428 */ &&
IsLowerableFunCallOrApply(nextpc) &&
!analysis->jumpTarget(nextpc) &&
!debugMode();
@ -2824,7 +2845,7 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
* the callIC cache and call 'this' directly. However, if it turns out that
* we are not actually calling js_fun_call, the callIC must act as normal.
*/
bool lowerFunCallOrApply = IsLowerableFunCallOrApply(PC);
bool lowerFunCallOrApply = !cx->typeInferenceEnabled() /* :FIXME: bug 619428 */ && IsLowerableFunCallOrApply(PC);
/*
* Currently, constant values are not functions, so don't even try to
@ -4941,7 +4962,7 @@ mjit::Compiler::jsop_arguments()
INLINE_STUBCALL(stubs::Arguments);
}
void
bool
mjit::Compiler::jsop_newinit()
{
bool isArray;
@ -4961,15 +4982,18 @@ mjit::Compiler::jsop_newinit()
break;
default:
JS_NOT_REACHED("Bad op");
return;
return false;
}
prepareStubCall(Uses(0));
/* Don't bake in types for non-compileAndGo scripts. */
types::TypeObject *type = NULL;
if (script->compileAndGo)
if (script->compileAndGo) {
type = script->getTypeInitObject(cx, PC, isArray);
if (!type)
return false;
}
masm.storePtr(ImmPtr(type), FrameAddress(offsetof(VMFrame, scratch)));
if (isArray) {
@ -4981,6 +5005,8 @@ mjit::Compiler::jsop_newinit()
}
frame.takeReg(Registers::ReturnReg);
frame.pushInitializerObject(Registers::ReturnReg, *PC == JSOP_NEWARRAY, baseobj);
return true;
}
bool
@ -5029,8 +5055,6 @@ mjit::Compiler::finishLoop(jsbytecode *head)
bool
mjit::Compiler::jumpAndTrace(Jump j, jsbytecode *target, Jump *slow, bool *trampoline)
{
bool consistent = frame.consistentRegisters(target);
if (trampoline)
*trampoline = false;
@ -5043,9 +5067,10 @@ mjit::Compiler::jumpAndTrace(Jump j, jsbytecode *target, Jump *slow, bool *tramp
lvtarget = ArenaNew<RegisterAllocation>(liveness.pool, false);
if (!lvtarget)
return false;
JS_ASSERT(consistent);
}
bool consistent = frame.consistentRegisters(target);
if (!addTraceHints || target >= PC ||
(JSOp(*target) != JSOP_TRACE && JSOp(*target) != JSOP_NOTRACE)
#ifdef JS_MONOIC
@ -5437,7 +5462,9 @@ mjit::Compiler::jsop_forgname(JSAtom *atom)
void
mjit::Compiler::fixDoubleTypes(Uses uses)
{
#ifdef JS_TYPE_INFERENCE
if (!cx->typeInferenceEnabled())
return;
for (uint32 i = 0; fun && i < fun->nargs; i++) {
JSValueType type = knownArgumentType(i);
if (type == JSVAL_TYPE_DOUBLE) {
@ -5455,13 +5482,14 @@ mjit::Compiler::fixDoubleTypes(Uses uses)
frame.ensureDouble(fe);
}
}
#endif
}
void
mjit::Compiler::restoreAnalysisTypes(uint32 stackDepth)
{
#ifdef JS_TYPE_INFERENCE
if (!cx->typeInferenceEnabled())
return;
/* Restore known types of locals/args, for join points or after forgetting everything. */
for (uint32 i = 0; i < script->nfixed; i++) {
JSValueType type = knownLocalType(i);
@ -5479,79 +5507,63 @@ mjit::Compiler::restoreAnalysisTypes(uint32 stackDepth)
frame.learnType(fe, type, false);
}
}
#endif
}
JSValueType
mjit::Compiler::knownThisType()
{
#ifdef JS_TYPE_INFERENCE
if (!cx->typeInferenceEnabled())
return JSVAL_TYPE_UNKNOWN;
if (hasThisType)
return thisType;
hasThisType = true;
thisType = script->thisTypes()->getKnownTypeTag(cx, script);
return thisType;
#endif
return JSVAL_TYPE_UNKNOWN;
}
JSValueType
mjit::Compiler::knownArgumentType(uint32 arg)
{
#ifdef JS_TYPE_INFERENCE
if (!cx->typeInferenceEnabled())
return JSVAL_TYPE_UNKNOWN;
JS_ASSERT(fun && arg < fun->nargs);
return argumentTypes[arg];
#endif
return JSVAL_TYPE_UNKNOWN;
}
void
mjit::Compiler::markArgumentOverflow(uint32 arg)
{
#ifdef JS_TYPE_INFERENCE
types::TypeSet *types = script->argTypes(arg);
JS_ASSERT(!types->hasType(types::TYPE_DOUBLE));
types::InferSpew(types::ISpewDynamic, "StaticOverflow: #%u", script->id());
cx->compartment->types.addDynamicType(cx, types, types::TYPE_DOUBLE);
#endif
script->typeSetArgument(cx, arg, DoubleValue(0.0));
}
JSValueType
mjit::Compiler::knownLocalType(uint32 local)
{
#ifdef JS_TYPE_INFERENCE
if (local >= script->nfixed)
if (!cx->typeInferenceEnabled() || local >= script->nfixed)
return JSVAL_TYPE_UNKNOWN;
return localTypes[local];
#endif
return JSVAL_TYPE_UNKNOWN;
}
void
mjit::Compiler::markLocalOverflow(uint32 local)
{
#ifdef JS_TYPE_INFERENCE
types::TypeSet *types = script->localTypes(local);
JS_ASSERT(!types->hasType(types::TYPE_DOUBLE));
types::InferSpew(types::ISpewDynamic, "StaticOverflow: #%u", script->id());
cx->compartment->types.addDynamicType(cx, types, types::TYPE_DOUBLE);
#endif
script->typeSetLocal(cx, local, DoubleValue(0.0));
}
JSValueType
mjit::Compiler::knownPushedType(uint32 pushed)
{
#ifdef JS_TYPE_INFERENCE
if (!cx->typeInferenceEnabled())
return JSVAL_TYPE_UNKNOWN;
types::TypeSet *types = script->types->pushed(PC - script->code, pushed);
return types->getKnownTypeTag(cx, script);
#endif
return JSVAL_TYPE_UNKNOWN;
}
bool
mjit::Compiler::mayPushUndefined(uint32 pushed)
{
#ifdef JS_TYPE_INFERENCE
JS_ASSERT(cx->typeInferenceEnabled());
/*
* This should only be used when the compiler is checking if it is OK to push
* undefined without going to a stub that can trigger recompilation.
@ -5560,48 +5572,32 @@ mjit::Compiler::mayPushUndefined(uint32 pushed)
*/
types::TypeSet *types = script->types->pushed(PC - script->code, pushed);
return types->hasType(types::TYPE_UNDEFINED);
#else
JS_NOT_REACHED("mayPushUndefined without JS_TYPE_INFERENCE");
return false;
#endif
}
types::TypeSet *
mjit::Compiler::argTypeSet(uint32 arg)
{
#ifdef JS_TYPE_INFERENCE
return script->argTypes(arg);
#endif
return NULL;
return cx->typeInferenceEnabled() ? script->argTypes(arg) : NULL;
}
types::TypeSet *
mjit::Compiler::localTypeSet(uint32 local)
{
#ifdef JS_TYPE_INFERENCE
if (local >= script->nfixed)
if (!cx->typeInferenceEnabled() || local >= script->nfixed)
return NULL;
return script->localTypes(local);
#endif
return NULL;
}
types::TypeSet *
mjit::Compiler::pushedTypeSet(uint32 pushed)
{
#ifdef JS_TYPE_INFERENCE
return script->types->pushed(PC - script->code, pushed);
#endif
return NULL;
return cx->typeInferenceEnabled() ? script->types->pushed(PC - script->code, pushed) : NULL;
}
bool
mjit::Compiler::monitored(jsbytecode *pc)
{
#ifdef JS_TYPE_INFERENCE
return script->types->monitored(pc - script->code);
#endif
return false;
return cx->typeInferenceEnabled() && script->types->monitored(pc - script->code);
}
void
@ -5611,20 +5607,18 @@ mjit::Compiler::pushSyncedEntry(uint32 pushed)
}
void
mjit::Compiler::markPushedOverflow(uint32 pushed)
mjit::Compiler::markPushedOverflow()
{
#ifdef JS_TYPE_INFERENCE
types::TypeSet *types = script->types->pushed(PC - script->code, pushed);
JS_ASSERT(!types->hasType(types::TYPE_DOUBLE));
types::InferSpew(types::ISpewDynamic, "StaticOverflow: #%u", script->id());
cx->compartment->types.addDynamicType(cx, types, types::TYPE_DOUBLE);
#endif
/* OK to ignore failure here, we aren't performing the operation itself. */
script->typeMonitorResult(cx, PC, types::TYPE_DOUBLE);
}
bool
mjit::Compiler::arrayPrototypeHasIndexedProperty()
{
#ifdef JS_TYPE_INFERENCE
if (!cx->typeInferenceEnabled())
return true;
/*
* Get the types of Array.prototype and Object.prototype to use. :XXX: This is broken
* in the presence of multiple global objects, we should figure out the possible
@ -5637,6 +5631,4 @@ mjit::Compiler::arrayPrototypeHasIndexedProperty()
types::TypeSet *objectTypes = proto->getProto()->getType()->getProperty(cx, JSID_VOID, false);
return arrayTypes->knownNonEmpty(cx, script)
|| objectTypes->knownNonEmpty(cx, script);
#endif
return true;
}

View File

@ -367,12 +367,10 @@ class Compiler : public BaseCompiler
bool debugMode_;
bool addTraceHints;
bool recompiling;
#ifdef JS_TYPE_INFERENCE
bool hasThisType;
JSValueType thisType;
js::Vector<JSValueType, 16> argumentTypes;
js::Vector<JSValueType, 16> localTypes;
#endif
bool oomInVector; // True if we have OOM'd appending to a vector.
enum { NoApplyTricks, LazyArgsObj } applyTricks;
@ -408,6 +406,7 @@ class Compiler : public BaseCompiler
CompileStatus finishThisUp(JITScript **jitp);
/* Analysis helpers. */
CompileStatus prepareInferenceTypes(const Vector<JSStackFrame*> *frames);
void fixDoubleTypes(Uses uses);
void restoreAnalysisTypes(uint32 stackDepth);
JSValueType knownThisType();
@ -420,7 +419,7 @@ class Compiler : public BaseCompiler
types::TypeSet *localTypeSet(uint32 local);
types::TypeSet *pushedTypeSet(uint32 pushed);
bool monitored(jsbytecode *pc);
void markPushedOverflow(uint32 pushed);
void markPushedOverflow();
void markLocalOverflow(uint32 local);
void markArgumentOverflow(uint32 arg);
@ -566,7 +565,7 @@ class Compiler : public BaseCompiler
bool jsop_andor(JSOp op, jsbytecode *target);
bool jsop_arginc(JSOp op, uint32 slot, bool popped);
bool jsop_localinc(JSOp op, uint32 slot, bool popped);
void jsop_newinit();
bool jsop_newinit();
void jsop_initmethod();
void jsop_initprop();
void jsop_initelem();

View File

@ -883,7 +883,7 @@ mjit::Compiler::jsop_mod()
if (tryBinaryConstantFold(cx, frame, JSOP_MOD, lhs, rhs, &v)) {
if (type == JSVAL_TYPE_INT32 && !v.isInt32()) {
JaegerSpew(JSpew_Abort, "overflow in mod (%u)\n", PC - script->code);
markPushedOverflow(0);
markPushedOverflow();
return false;
}
frame.popn(2);

View File

@ -1204,18 +1204,18 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
return true;
}
#ifdef JS_TYPE_INFERENCE
types::TypeSet *types = obj->getTypeSet();
types::ObjectKind kind = types ? types->getKnownObjectKind(cx, script) : types::OBJECT_UNKNOWN;
if (id->mightBeType(JSVAL_TYPE_INT32) &&
(kind == types::OBJECT_DENSE_ARRAY || kind == types::OBJECT_PACKED_ARRAY) &&
!arrayPrototypeHasIndexedProperty()) {
// this is definitely a dense array, generate code directly without
// using an inline cache.
jsop_setelem_dense();
return true;
if (cx->typeInferenceEnabled()) {
types::TypeSet *types = obj->getTypeSet();
types::ObjectKind kind = types ? types->getKnownObjectKind(cx, script) : types::OBJECT_UNKNOWN;
if (id->mightBeType(JSVAL_TYPE_INT32) &&
(kind == types::OBJECT_DENSE_ARRAY || kind == types::OBJECT_PACKED_ARRAY) &&
!arrayPrototypeHasIndexedProperty()) {
// This is definitely a dense array, generate code directly without
// using an inline cache.
jsop_setelem_dense();
return true;
}
}
#endif
SetElementICInfo ic = SetElementICInfo(JSOp(*PC));
@ -1516,19 +1516,19 @@ mjit::Compiler::jsop_getelem(bool isCall)
return true;
}
#ifdef JS_TYPE_INFERENCE
types::TypeSet *types = obj->getTypeSet();
types::ObjectKind kind = types ? types->getKnownObjectKind(cx, script) : types::OBJECT_UNKNOWN;
if (cx->typeInferenceEnabled()) {
types::TypeSet *types = obj->getTypeSet();
types::ObjectKind kind = types ? types->getKnownObjectKind(cx, script) : types::OBJECT_UNKNOWN;
if (!isCall && id->mightBeType(JSVAL_TYPE_INT32) &&
(kind == types::OBJECT_DENSE_ARRAY || kind == types::OBJECT_PACKED_ARRAY) &&
!arrayPrototypeHasIndexedProperty()) {
// this is definitely a dense array, generate code directly without
// using an inline cache.
jsop_getelem_dense(kind == types::OBJECT_PACKED_ARRAY);
return true;
if (!isCall && id->mightBeType(JSVAL_TYPE_INT32) &&
(kind == types::OBJECT_DENSE_ARRAY || kind == types::OBJECT_PACKED_ARRAY) &&
!arrayPrototypeHasIndexedProperty()) {
// this is definitely a dense array, generate code directly without
// using an inline cache.
jsop_getelem_dense(kind == types::OBJECT_PACKED_ARRAY);
return true;
}
}
#endif
GetElementICInfo ic = GetElementICInfo(JSOp(*PC));

View File

@ -762,10 +762,7 @@ FrameState::consistentRegisters(jsbytecode *target)
* been synced, and no stores will need to be issued by prepareForJump.
*/
RegisterAllocation *alloc = liveness.getCode(target).allocation;
if (!alloc) {
alloc = ArenaNew<RegisterAllocation>(liveness.pool, false); /* :XXX: set OOM on failure */
return true;
}
JS_ASSERT(alloc);
Registers regs(Registers::AvailAnyRegs);
while (!regs.empty()) {

View File

@ -352,7 +352,8 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint
JSScript *newscript = newfun->script();
CallArgs args(vp + 2, argc);
cx->typeMonitorCall(NULL, NULL, args, flags & JSFRAME_CONSTRUCTING, true);
if (!cx->typeMonitorCall(args, flags & JSFRAME_CONSTRUCTING))
return false;
/* Get pointer to new frame/slots, prepare arguments. */
StackSpace &stack = cx->stack();

View File

@ -900,19 +900,19 @@ class CallCompiler : public BaseCompiler
masm.storeValue(v, Address(vpReg, sizeof(Value)));
}
#ifdef JS_TYPE_INFERENCE
/*
* Look under the ABI abstraction and NULL out the slot used for the
* return address in a FASTCALL. This is seriously nasty but we need it
* to distinguish fast calls from native calls should we trigger a
* recompilation inside the native.
*/
if (cx->typeInferenceEnabled()) {
/*
* Look under the ABI abstraction and NULL out the slot used for the
* return address in a FASTCALL. This is seriously nasty but we need it
* to distinguish fast calls from native calls should we trigger a
* recompilation inside the native.
*/
#if defined(JS_CPU_X86) && !defined(JS_NO_FASTCALL)
masm.storePtr(ImmPtr(NULL), FrameAddress(-4));
masm.storePtr(ImmPtr(NULL), FrameAddress(-4));
#else
JS_NOT_REACHED("FIXME");
#endif
JS_NOT_REACHED("FIXME");
#endif
}
masm.setupABICall(Registers::NormalCall, 3);
masm.storeArg(2, vpReg);

View File

@ -1702,8 +1702,8 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
* :FIXME: looking under the usePropCache abstraction, which is only unset for
* reads of the prototype.
*/
if (v.isUndefined() && usePropCache)
f.script()->typeMonitorUndefined(f.cx, f.regs.pc);
if (v.isUndefined() && usePropCache && !f.script()->typeMonitorUndefined(f.cx, f.regs.pc))
THROW();
f.regs.sp[-1] = v;
}
@ -1857,8 +1857,8 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
}
#endif
if (regs.sp[-2].isUndefined())
f.script()->typeMonitorUndefined(cx, regs.pc);
if (regs.sp[-2].isUndefined() && !f.script()->typeMonitorUndefined(cx, regs.pc))
THROW();
if (f.jit()->recompilations != recompilations)
return;
@ -1910,8 +1910,8 @@ ic::XName(VMFrame &f, ic::PICInfo *pic)
THROW();
f.regs.sp[-1] = rval;
if (rval.isUndefined())
script->typeMonitorUndefined(f.cx, f.regs.pc);
if (rval.isUndefined() && !script->typeMonitorUndefined(f.cx, f.regs.pc))
THROW();
}
void JS_FASTCALL
@ -1930,8 +1930,8 @@ ic::Name(VMFrame &f, ic::PICInfo *pic)
THROW();
f.regs.sp[0] = rval;
if (rval.isUndefined())
script->typeMonitorUndefined(f.cx, f.regs.pc);
if (rval.isUndefined() && !script->typeMonitorUndefined(f.cx, f.regs.pc))
THROW();
}
static void JS_FASTCALL
@ -2411,8 +2411,8 @@ ic::CallElement(VMFrame &f, ic::GetElementIC *ic)
{
f.regs.sp[-1] = thisv;
}
if (f.regs.sp[-2].isUndefined())
f.script()->typeMonitorUndefined(cx, f.regs.pc);
if (f.regs.sp[-2].isUndefined() && !f.script()->typeMonitorUndefined(cx, f.regs.pc))
THROW();
}
void JS_FASTCALL
@ -2461,7 +2461,8 @@ ic::GetElement(VMFrame &f, ic::GetElementIC *ic)
if (f.regs.sp[-2].isUndefined()) {
if (idval.isInt32())
cx->addTypeProperty(obj->getType(), NULL, types::TYPE_UNDEFINED);
f.script()->typeMonitorUndefined(cx, f.regs.pc);
if (!f.script()->typeMonitorUndefined(cx, f.regs.pc))
THROW();
}
}

View File

@ -128,7 +128,8 @@ stubs::SetName(VMFrame &f, JSAtom *origAtom)
if (!obj)
THROW();
f.script()->typeMonitorAssign(cx, f.regs.pc, obj, ATOM_TO_JSID(origAtom), rval);
if (!cx->typeMonitorAssign(obj, ATOM_TO_JSID(origAtom), rval))
THROW();
do {
PropertyCache *cache = &JS_PROPERTY_CACHE(cx);
@ -284,7 +285,8 @@ stubs::SetPropNoCache(VMFrame &f, JSAtom *atom)
THROW();
Value rval = f.regs.sp[-1];
f.script()->typeMonitorAssign(f.cx, f.regs.pc, obj, ATOM_TO_JSID(atom), rval);
if (!f.cx->typeMonitorAssign(obj, ATOM_TO_JSID(atom), rval))
THROW();
if (!obj->setProperty(f.cx, ATOM_TO_JSID(atom), &f.regs.sp[-1], strict))
THROW();
@ -307,7 +309,8 @@ stubs::SetGlobalNameNoCache(VMFrame &f, JSAtom *atom)
THROW();
jsid id = ATOM_TO_JSID(atom);
f.script()->typeMonitorAssign(cx, f.regs.pc, obj, id, rval);
if (!cx->typeMonitorAssign(obj, id, rval))
THROW();
if (!obj->setProperty(cx, id, &rval, strict))
THROW();
@ -407,8 +410,8 @@ NameOp(VMFrame &f, JSObject *obj, bool callname = false)
f.regs.sp++;
f.regs.sp[-1] = rval;
if (rval.isUndefined())
f.script()->typeMonitorUndefined(cx, f.regs.pc);
if (rval.isUndefined() && !f.script()->typeMonitorUndefined(cx, f.regs.pc))
return NULL;
if (callname) {
Class *clasp;
@ -518,10 +521,12 @@ stubs::GetElem(VMFrame &f)
f.regs.sp[-2] = *copyFrom;
if (!rref.isInt32()) {
f.script()->typeMonitorUnknown(cx, regs.pc);
if (!f.script()->typeMonitorUnknown(cx, regs.pc))
THROW();
} else if (copyFrom->isUndefined()) {
cx->addTypeProperty(obj->getType(), NULL, TYPE_UNDEFINED);
f.script()->typeMonitorUndefined(cx, regs.pc);
if (!f.script()->typeMonitorUndefined(cx, regs.pc))
THROW();
}
}
@ -568,8 +573,10 @@ stubs::CallElem(VMFrame &f)
{
regs.sp[-1] = thisv;
}
if (regs.sp[-2].isUndefined() || !JSID_IS_INT(id))
f.script()->typeMonitorUnknown(cx, regs.pc);
if ((regs.sp[-2].isUndefined() || !JSID_IS_INT(id)) &&
!f.script()->typeMonitorUnknown(cx, regs.pc)) {
THROW();
}
}
template<JSBool strict>
@ -593,7 +600,8 @@ stubs::SetElem(VMFrame &f)
if (!FetchElementId(f, obj, idval, id, &regs.sp[-2]))
THROW();
f.script()->typeMonitorAssign(cx, regs.pc, obj, id, rval, !JSID_IS_INT(id));
if (!cx->typeMonitorAssign(obj, id, rval))
THROW();
do {
if (obj->isDenseArray() && JSID_IS_INT(id)) {
@ -603,8 +611,8 @@ stubs::SetElem(VMFrame &f)
if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
if (js_PrototypeHasIndexedProperties(cx, obj))
break;
if ((jsuint)i >= obj->getArrayLength())
obj->setArrayLength(cx, i + 1);
if ((jsuint)i >= obj->getArrayLength() && !obj->setArrayLength(cx, i + 1))
THROW();
}
obj->setDenseArrayElement(i, rval);
goto end_setelem;
@ -718,8 +726,8 @@ stubs::Ursh(VMFrame &f)
u >>= (j & 31);
if (!f.regs.sp[-2].setNumber(uint32(u)))
f.script()->typeMonitorOverflow(f.cx, f.regs.pc);
if (!f.regs.sp[-2].setNumber(uint32(u)) && !f.script()->typeMonitorOverflow(f.cx, f.regs.pc))
THROW();
}
template<JSBool strict>
@ -793,6 +801,9 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
Value rval = ObjectValue(*obj);
if (!cx->typeMonitorAssign(parent, id, rval))
THROW();
do {
/* Steps 5d, 5f. */
if (!prop || pobj != parent) {
@ -831,8 +842,6 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
/* Step 5f. */
if (!parent->setProperty(cx, id, &rval, strict))
THROW();
f.script()->typeMonitorAssign(cx, f.regs.pc, parent, id, rval);
} while (false);
}
@ -1042,13 +1051,14 @@ DefaultValue(VMFrame &f, JSType hint, Value &v, int n)
return true;
}
static inline void
static inline bool
MonitorArithmeticOverflow(VMFrame &f, const Value &v)
{
JSContext *cx = f.cx;
JS_ASSERT(v.isDouble());
f.script()->typeMonitorOverflow(cx, f.regs.pc);
if (!f.script()->typeMonitorOverflow(cx, f.regs.pc))
return false;
/*
* Monitoring the overflow is not enough for fused INC operations on NAME/PROP,
@ -1077,12 +1087,12 @@ MonitorArithmeticOverflow(VMFrame &f, const Value &v)
break;
default:
return;
return true;
}
JSObject *obj = ValueToObject(cx, &ov);
if (!obj)
return;
return true;
JSAtom *atom;
GET_ATOM_FROM_BYTECODE(f.script(), f.regs.pc, 0, atom);
cx->addTypePropertyId(obj->getType(), ATOM_TO_JSID(atom), TYPE_DOUBLE);
@ -1093,6 +1103,8 @@ MonitorArithmeticOverflow(VMFrame &f, const Value &v)
*/
Value nv = v;
obj->setProperty(cx, ATOM_TO_JSID(atom), &nv, f.script()->strictModeCode);
return true;
}
void JS_FASTCALL
@ -1152,8 +1164,8 @@ stubs::Add(VMFrame &f)
if (!ValueToNumber(cx, lval, &l) || !ValueToNumber(cx, rval, &r))
THROW();
l += r;
if (!regs.sp[-2].setNumber(l))
MonitorArithmeticOverflow(f, regs.sp[-2]);
if (!regs.sp[-2].setNumber(l) && !MonitorArithmeticOverflow(f, regs.sp[-2]))
THROW();
}
}
return;
@ -1178,8 +1190,8 @@ stubs::Sub(VMFrame &f)
THROW();
}
double d = d1 - d2;
if (!regs.sp[-2].setNumber(d))
MonitorArithmeticOverflow(f, regs.sp[-2]);
if (!regs.sp[-2].setNumber(d) && !MonitorArithmeticOverflow(f, regs.sp[-2]))
THROW();
}
void JS_FASTCALL
@ -1193,8 +1205,8 @@ stubs::Mul(VMFrame &f)
THROW();
}
double d = d1 * d2;
if (!regs.sp[-2].setNumber(d))
f.script()->typeMonitorOverflow(cx, f.regs.pc);
if (!regs.sp[-2].setNumber(d) && !f.script()->typeMonitorOverflow(cx, f.regs.pc))
THROW();
}
void JS_FASTCALL
@ -1224,11 +1236,12 @@ stubs::Div(VMFrame &f)
else
vp = &rt->positiveInfinityValue;
regs.sp[-2] = *vp;
f.script()->typeMonitorOverflow(cx, f.regs.pc);
if (!f.script()->typeMonitorOverflow(cx, f.regs.pc))
THROW();
} else {
d1 /= d2;
if (!regs.sp[-2].setNumber(d1))
f.script()->typeMonitorOverflow(cx, f.regs.pc);
if (!regs.sp[-2].setNumber(d1) && !f.script()->typeMonitorOverflow(cx, f.regs.pc))
THROW();
}
}
@ -1257,7 +1270,8 @@ stubs::Mod(VMFrame &f)
d1 = js_fmod(d1, d2);
regs.sp[-2].setDouble(d1);
}
f.script()->typeMonitorOverflow(cx, f.regs.pc);
if (!f.script()->typeMonitorOverflow(cx, f.regs.pc))
THROW();
}
}
@ -1369,8 +1383,8 @@ stubs::Neg(VMFrame &f)
if (!ValueToNumber(f.cx, f.regs.sp[-1], &d))
THROW();
d = -d;
if (!f.regs.sp[-1].setNumber(d))
f.script()->typeMonitorOverflow(f.cx, f.regs.pc);
if (!f.regs.sp[-1].setNumber(d) && !f.script()->typeMonitorOverflow(f.cx, f.regs.pc))
THROW();
}
JSObject * JS_FASTCALL
@ -1384,7 +1398,7 @@ stubs::NewInitArray(VMFrame &f, uint32 count)
if (type)
obj->setType(type);
obj->setArrayLength(f.cx, count);
JS_ALWAYS_TRUE(obj->setArrayLength(f.cx, count));
return obj;
}
@ -1459,8 +1473,8 @@ stubs::GetUpvar(VMFrame &f, uint32 ck)
cookie.fromInteger(ck);
f.regs.sp[0] = GetUpvar(f.cx, staticLevel, cookie);
if (f.regs.sp[0].isUndefined())
f.script()->typeMonitorUndefined(f.cx, f.regs.pc);
if (f.regs.sp[0].isUndefined() && !f.script()->typeMonitorUndefined(f.cx, f.regs.pc))
THROW();
}
JSObject * JS_FASTCALL
@ -1674,10 +1688,13 @@ ObjIncOp(VMFrame &f, JSObject *obj, jsid id)
ref.setNumber(d);
}
if (!v.setNumber(d)) {
f.script()->typeMonitorOverflow(cx, f.regs.pc);
cx->addTypePropertyId(obj->getType(), id, TYPE_DOUBLE);
if (!f.script()->typeMonitorOverflow(cx, f.regs.pc) ||
!cx->addTypePropertyId(obj->getType(), id, TYPE_DOUBLE)) {
return false;
}
}
f.script()->typeMonitorAssign(cx, f.regs.pc, obj, id, v);
if (!cx->typeMonitorAssign(obj, id, v))
return false;
fp->setAssigning();
JSBool ok = obj->setProperty(cx, id, &v, strict);
fp->clearAssigning();
@ -2006,8 +2023,8 @@ InlineGetProp(VMFrame &f)
}
} while(0);
if (rval.isUndefined())
f.script()->typeMonitorUndefined(cx, regs.pc);
if (rval.isUndefined() && !f.script()->typeMonitorUndefined(cx, regs.pc))
return false;
regs.sp[-1] = rval;
return true;
@ -2127,8 +2144,8 @@ stubs::CallProp(VMFrame &f, JSAtom *origAtom)
THROW();
}
#endif
if (rval.isUndefined())
f.script()->typeMonitorUndefined(cx, regs.pc);
if (rval.isUndefined() && !f.script()->typeMonitorUndefined(cx, regs.pc))
THROW();
}
void JS_FASTCALL
@ -2182,7 +2199,8 @@ InitPropOrMethod(VMFrame &f, JSAtom *atom, JSOp op)
JSObject *obj = &regs.sp[-2].toObject();
JS_ASSERT(obj->isNative());
f.script()->typeMonitorAssign(cx, regs.pc, obj, ATOM_TO_JSID(atom), rval);
if (!cx->typeMonitorAssign(obj, ATOM_TO_JSID(atom), rval))
THROW();
/*
* Probe the property cache.
@ -2608,8 +2626,8 @@ stubs::Pos(VMFrame &f)
{
if (!ValueToNumber(f.cx, &f.regs.sp[-1]))
THROW();
if (!f.regs.sp[-1].isInt32())
f.script()->typeMonitorOverflow(f.cx, f.regs.pc);
if (!f.regs.sp[-1].isInt32() && !f.script()->typeMonitorOverflow(f.cx, f.regs.pc))
THROW();
}
void JS_FASTCALL
@ -2772,14 +2790,16 @@ template void JS_FASTCALL stubs::DelElem<false>(VMFrame &f);
void JS_FASTCALL
stubs::UndefinedHelper(VMFrame &f)
{
f.script()->typeMonitorUndefined(f.cx, f.regs.pc);
if (!f.script()->typeMonitorUndefined(f.cx, f.regs.pc))
THROW();
f.regs.sp[-1].setUndefined();
}
void JS_FASTCALL
stubs::NegZeroHelper(VMFrame &f)
{
f.script()->typeMonitorOverflow(f.cx, f.regs.pc);
if (!f.script()->typeMonitorOverflow(f.cx, f.regs.pc))
THROW();
f.regs.sp[-1].setDouble(-0.0);
}

View File

@ -154,6 +154,7 @@ static volatile bool gCanceled = false;
static bool enableTraceJit = false;
static bool enableMethodJit = false;
static bool enableProfiling = false;
static bool enableTypeInference = false;
static bool printTiming = false;
@ -600,6 +601,7 @@ usage(void)
" methodjit: JSOPTION_METHODJIT\n"
" relimit: JSOPTION_RELIMIT\n"
" strict: JSOPTION_STRICT\n"
" typeinfer: JSOPTION_TYPE_INFERENCE\n"
" werror: JSOPTION_WERROR\n"
" xml: JSOPTION_XML\n"
" -v <version> Set the JavaScript language version\n"
@ -643,6 +645,7 @@ static const struct {
{"methodjit_always",JSOPTION_METHODJIT_ALWAYS},
{"relimit", JSOPTION_RELIMIT},
{"strict", JSOPTION_STRICT},
{"typeinfer", JSOPTION_TYPE_INFERENCE},
{"werror", JSOPTION_WERROR},
{"xml", JSOPTION_XML},
};
@ -820,6 +823,10 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
enableProfiling = !enableProfiling;
JS_ToggleOptions(cx, JSOPTION_PROFILING);
break;
case 'n':
/* Inference argument already handled. */
break;
case 'o':
{
@ -3127,7 +3134,7 @@ split_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **obj
{
ComplexObject *cpx;
cx->markTypePropertyUnknown(obj->getType(), id);
cx->addTypePropertyId(obj->getType(), id, types::TYPE_UNKNOWN);
if (JSID_IS_ATOM(id) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "isInner")) {
*objp = obj;
@ -5548,6 +5555,8 @@ NewContext(JSRuntime *rt)
JS_ToggleOptions(cx, JSOPTION_JIT);
if (enableMethodJit)
JS_ToggleOptions(cx, JSOPTION_METHODJIT);
if (enableTypeInference)
JS_ToggleOptions(cx, JSOPTION_TYPE_INFERENCE);
return cx;
}
@ -5611,6 +5620,37 @@ Shell(JSContext *cx, int argc, char **argv, char **envp)
{
JSAutoRequest ar(cx);
/*
* First check to see if type inference is enabled. This flag must be set
* on the compartment when it is constructed.
*/
for (int i = 0; i < argc; i++) {
switch (argv[i][1]) {
case 'c':
case 'f':
case 'e':
case 'v':
case 'S':
case 't':
#ifdef JS_GC_ZEAL
case 'Z':
#endif
#ifdef MOZ_TRACEVIS
case 'T':
#endif
case 'g':
++i;
break;
case 'n':
enableTypeInference = !enableTypeInference;
JS_ToggleOptions(cx, JSOPTION_TYPE_INFERENCE);
break;
default:;
}
}
JSObject *glob = NewGlobalObject(cx);
if (!glob)
return 1;

View File

@ -11,7 +11,7 @@ script regress-322135-02.js
skip script regress-322135-03.js # slow
skip script regress-322135-04.js # slow
script regress-387501.js
skip script regress-390598.js # :FIXME: bug 599159
script regress-390598.js
script regress-421325.js
script regress-430717.js
script regress-488989.js

View File

@ -61,10 +61,19 @@ var actualvalues = [];
var expect= '';
var expectedvalues = [];
var f = Function("x","y","\
function h() { return h_peer(); } \
function h_peer() { return (x + cnCOMMA + y); } \
return h");
function f(x,y)
{
function h()
{
return h_peer();
}
function h_peer()
{
return (x + cnCOMMA + y);
}
return h;
}
if (typeof clone == 'function')
{

View File

@ -59,7 +59,7 @@ function test()
else {
expect = 'PASSED';
f = Function("a", "return (function () { return a * a;});")();
f = eval("(function (a) {return (function () { return a * a;}); })()");
g = clone(f, {a: 3});
f = null;
gc();

View File

@ -10,5 +10,5 @@ script regress-352742-01.js
script regress-352742-02.js
script regress-386030.js
script regress-415451.js
skip script regress-415540.js # :FIXME: bug 599159
script regress-415540.js
script regress-566651.js

View File

@ -1325,6 +1325,9 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
case 'p':
JS_ToggleOptions(cx, JSOPTION_PROFILING);
break;
case 'n':
JS_ToggleOptions(cx, JSOPTION_TYPE_INFERENCE);
break;
default:
return usage();
}

View File

@ -605,6 +605,7 @@ pref("javascript.options.methodjit.chrome", false);
pref("javascript.options.jitprofiling.content", true);
pref("javascript.options.jitprofiling.chrome", false);
pref("javascript.options.methodjit_always", false);
pref("javascript.options.typeinference", false);
// This preference limits the memory usage of javascript.
// If you want to change these values for your device,
// please find Bug 417052 comment 17 and Bug 456721