mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[INFER] Fix OOM handling in type inference, convert inference to runtime option, bug 637674.
This commit is contained in:
parent
70aee16fea
commit
41091b1bb6
@ -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
|
||||
|
@ -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
|
||||
|
@ -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@
|
||||
|
@ -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 ========================================================
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 *
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
1049
js/src/jsinfer.cpp
1049
js/src/jsinfer.cpp
File diff suppressed because it is too large
Load Diff
113
js/src/jsinfer.h
113
js/src/jsinfer.h
@ -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
@ -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 ®s)
|
||||
{
|
||||
#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, ®s.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, ®s.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, ®s.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, ®s.sp[-2], ®s.sp[-1]))
|
||||
goto error;
|
||||
if (!cx->typeMonitorAssign(obj, id, regs.sp[-1]))
|
||||
goto error;
|
||||
regs.fp->setAssigning();
|
||||
JSBool ok = obj->setProperty(cx, id, ®s.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], ®s.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 = ®s.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--;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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[] = {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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, ®s.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 = ®s.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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user