Analysis and recompilation tuning for SS, bug 608746.

This commit is contained in:
Brian Hackett 2010-11-20 15:45:52 -08:00
parent ee3f068ff9
commit 36efb56b2b
13 changed files with 607 additions and 332 deletions

View File

@ -469,7 +469,7 @@ Script::analyze(JSContext *cx)
code->pushedArray[i].setInnerStack(stack);
stack = &code->pushedArray[i];
types::InferSpew(types::ISpewOps, "pushed #%u:%05u %u T%u\n",
types::InferSpew(types::ISpewOps, "pushed #%u:%05u %u T%u",
id, offset, i, stack->types.id());
}
@ -759,10 +759,13 @@ Script::analyze(JSContext *cx)
#ifdef JS_TYPE_INFERENCE
/* Generate type constraints for the script. */
AnalyzeState state;
state.init(cx, script);
offset = 0;
TypeState state;
while (offset < script->length) {
analyze::Bytecode *code = maybeCode(offset);
Bytecode *code = maybeCode(offset);
jsbytecode *pc = script->code + offset;
UntrapOpcode untrap(cx, script, pc);
@ -772,6 +775,8 @@ Script::analyze(JSContext *cx)
if (code && code->analyzed)
analyzeTypes(cx, code, state);
}
state.destroy(cx);
#endif
}

View File

@ -139,12 +139,6 @@ struct Bytecode
*/
bool hasIncDecOverflow : 1;
/*
* For logging, whether we've generated warnings due to a mismatch between the
* actual and inferred types at this bytecode.
*/
bool missingTypes : 1;
/* Pool which constraints on this instruction should use. */
inline JSArenaPool &pool();
@ -163,7 +157,9 @@ struct Bytecode
*/
inline types::TypeObject* getInitObject(JSContext *cx, bool isArray);
#ifdef DEBUG
void print(JSContext *cx);
#endif
#endif /* JS_TYPE_INFERENCE */
@ -349,37 +345,115 @@ class Script
/* Bytecode where this script is nested. */
inline Bytecode *parentCode();
void print(JSContext *cx);
/* Gather statistics off this script and print it if necessary. */
void finish(JSContext *cx);
/* Helpers */
/* Temporary state for handling opcodes with fused behavior. */
struct TypeState {
/* Inference state destroyed after the initial pass through the function. */
struct AnalyzeStateStack {
/* Whether this node is the iterator for a 'for each' loop. */
bool isForEach;
/* Variable set for any scope name binding pushed on this stack node. */
types::VariableSet *scopeVars;
/* Any value pushed by a JSOP_DOUBLE. */
bool hasDouble;
double doubleValue;
/* Whether this is or could be the constant zero. */
bool isZero;
/* Whether this is another constant. */
bool isConstant;
};
struct AnalyzeState {
AnalyzeStateStack *stack;
/* Current stack depth. */
unsigned stackDepth;
/* Last opcode was JSOP_GETTER or JSOP_SETTER. */
bool hasGetSet;
/* Last opcode was JSOP_HOLE. */
bool hasHole;
TypeState()
: hasGetSet(false), hasHole(false)
/* Locals thought to be zero/constants. */
bool zeroLocals[4];
uint32 constLocals[4];
unsigned numConstLocals;
AnalyzeState()
: stack(NULL), stackDepth(0), hasGetSet(false), hasHole(false), numConstLocals(0)
{}
bool init(JSContext *cx, JSScript *script)
{
if (script->nslots) {
stack = (AnalyzeStateStack *)
cx->calloc(script->nslots * sizeof(AnalyzeStateStack));
return (stack != NULL);
}
return true;
}
void destroy(JSContext *cx)
{
cx->free(stack);
}
AnalyzeStateStack &popped(unsigned i) {
JS_ASSERT(i < stackDepth);
return stack[stackDepth - 1 - i];
}
const AnalyzeStateStack &popped(unsigned i) const {
JS_ASSERT(i < stackDepth);
return stack[stackDepth - 1 - i];
}
void addConstLocal(uint32 local, bool zero) {
if (numConstLocals == JS_ARRAY_LENGTH(constLocals))
return;
if (maybeLocalConst(local, false))
return;
zeroLocals[numConstLocals] = zero;
constLocals[numConstLocals++] = local;
}
bool maybeLocalConst(uint32 local, bool zero) {
for (unsigned i = 0; i < numConstLocals; i++) {
if (constLocals[i] == local)
return !zero || zeroLocals[i];
}
return false;
}
void clearLocal(uint32 local) {
for (unsigned i = 0; i < numConstLocals; i++) {
if (constLocals[i] == local) {
constLocals[i] = constLocals[--numConstLocals];
return;
}
}
}
};
/* Analyzes a bytecode, generating type constraints describing its behavior. */
void analyzeTypes(JSContext *cx, Bytecode *codeType, TypeState &state);
void analyzeTypes(JSContext *cx, Bytecode *code, AnalyzeState &state);
/*
* Get the name to use for the local with specified index. Stack indicates the
* point of the access, for looking up let variables.
*/
inline jsid getLocalId(unsigned index, types::TypeStack *stack);
/* Get the name to use for the local with specified index. */
inline jsid getLocalId(unsigned index, Bytecode *code);
/* Get the name to use for the argument with the specified index. */
inline jsid getArgumentId(unsigned index);
/* Get the type set to use for a stack slot at a fixed stack depth. */
inline types::TypeSet *getStackTypes(unsigned index, types::TypeStack *stack);
inline types::TypeSet *getStackTypes(unsigned index, Bytecode *code);
/* Get any known type tag for an argument or local variable. */
inline JSValueType knownArgumentTypeTag(JSContext *cx, JSScript *script, unsigned arg);

View File

@ -4303,9 +4303,8 @@ JS_TypeHandlerMissing(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssi
TypeCallsite *site = Valueify(jssite);
/* Don't mark the return type as anything, and add a warning. */
cx->compartment->types.warnings = true;
InferSpew(ISpewDynamic, "warning: Call to unimplemented handler at #%u:%05u: %s\n",
site->code->script->id, site->code->offset, TypeIdString(cx, fun->name));
TypeFailure(cx, "Call to unimplemented handler at #%u:%05u: %s",
site->code->script->id, site->code->offset, TypeIdString(fun->name));
#endif
}
@ -4876,7 +4875,7 @@ JS_MakeTypeObject(JSContext *cx, const char *name, JSBool monitorNeeded, JSBool
proto->addPropagate(cx, type);
if (monitorNeeded)
cx->monitorTypeObject(type);
cx->markTypeObjectUnknownProperties(type);
return (JSTypeObject*) type;
#endif

View File

@ -2135,7 +2135,7 @@ array_push(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
if (cx->isTypeCallerMonitored())
cx->monitorTypeObject(obj->getTypeObject());
cx->markTypeObjectUnknownProperties(obj->getTypeObject());
if (argc != 1 || !obj->isDenseArray())
return array_push_slowly(cx, obj, argc, vp + 2, vp);
@ -2263,7 +2263,7 @@ array_unshift(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
if (cx->isTypeCallerMonitored())
cx->monitorTypeObject(obj->getTypeObject());
cx->markTypeObjectUnknownProperties(obj->getTypeObject());
newlen = length;
if (argc > 0) {
@ -2325,13 +2325,13 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
* result of the call so mark it at the callsite.
*/
objType = cx->getTypeCallerInitObject(true);
cx->monitorTypeObject(objType);
cx->markTypeObjectUnknownProperties(objType);
cx->markTypeCallerUnexpected((jstype) objType);
}
#endif
if (cx->isTypeCallerMonitored())
cx->monitorTypeObject(objType);
cx->markTypeObjectUnknownProperties(objType);
/*
* Create a new array value to return. Our ECMA v2 proposal specs
@ -2487,7 +2487,7 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
TypeObject *ntype = cx->getTypeCallerInitObject(true);
if (cx->isTypeCallerMonitored())
cx->monitorTypeObject(ntype);
cx->markTypeObjectUnknownProperties(ntype);
/* Create a new Array object and root it using *vp. */
JSObject *aobj = ComputeThisFromVp(cx, vp);
@ -2623,13 +2623,13 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
* result of the call so mark it at the callsite.
*/
objType = cx->getTypeCallerInitObject(true);
cx->monitorTypeObject(objType);
cx->markTypeObjectUnknownProperties(objType);
cx->markTypeCallerUnexpected((jstype) objType);
}
#endif
if (cx->isTypeCallerMonitored())
cx->monitorTypeObject(objType);
cx->markTypeObjectUnknownProperties(objType);
if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
!js_PrototypeHasIndexedProperties(cx, obj)) {
@ -2848,7 +2848,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
* the output array, monitor any reads on the array in the future.
*/
if (cx->isTypeCallerMonitored() && (mode == MAP || mode == FILTER))
cx->monitorTypeObject(newtype);
cx->markTypeObjectUnknownProperties(newtype);
/*
* For all but REDUCE, we call with 3 args (value, index, array). REDUCE
@ -3307,7 +3307,7 @@ js_Array(JSContext *cx, uintN argc, Value *vp)
}
if (cx->isTypeCallerMonitored() && vector)
cx->monitorTypeObject(type);
cx->markTypeObjectUnknownProperties(type);
/* Whether called with 'new' or not, use a new Array object. */
JSObject *obj = NewDenseArrayObject(cx, type, length);
@ -3381,6 +3381,7 @@ static void array_TypeNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *
if (site->argumentCount > 1) {
for (size_t ind = 0; ind < site->argumentCount; ind++)
site->argumentTypes[ind]->addSubset(cx, site->pool(), indexTypes);
object->possiblePackedArray = true;
}
#endif
}

View File

@ -2455,13 +2455,10 @@ public:
inline void 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);
inline void markTypeArrayNotPacked(js::types::TypeObject *obj, bool notDense, bool dynamic = true);
/*
* Monitor future reads from the a type object. Instances may have properties
* the inference does not know about.
*/
inline void monitorTypeObject(js::types::TypeObject *obj);
/* Monitor all properties of a type object as unknown. */
inline void markTypeObjectUnknownProperties(js::types::TypeObject *obj);
private:
/* To silence MSVC warning about using 'this' in a member initializer. */

File diff suppressed because it is too large Load Diff

View File

@ -290,38 +290,30 @@ struct TypeStack
*/
TypeStack *mergedGroup;
/* Identifier for this class within the script. filled in during printing. */
int id;
/* Number of nodes beneath this one in the stack. */
unsigned stackDepth;
/* Equivalence class for the node beneath this one in the stack. */
TypeStack *innerStack;
/* Possible types for values at this stack node. */
TypeSet types;
/* Whether any other stack nodes have been merged into this one. */
bool hasMerged;
/* Whether the values at this node are bound by a 'with'. */
/*
* Any let variable associated with this stack node, and whether the values
* at this node are bound by a 'with'. For resolving ambiguous cross-script
* local variable lookups. :TODO: remove.
*/
jsid letVariable;
bool boundWith;
/* Whether this node is the iterator for a 'for each' or 'for in' loop. */
bool isForEach;
/*
* Whether to ignore the type tag of this stack entry downstream; it may not
* represent the actual values in this slot.
*/
bool ignoreTypeTag;
/* The name of any 'let' variable stored by this node. */
jsid letVariable;
/* Variable set for any scope name binding pushed on this stack node. */
VariableSet *scopeVars;
#ifdef DEBUG
/* Identifier for this class within the script. filled in during printing. */
int id;
#endif
/* Get the representative node for the equivalence class of this node. */
inline TypeStack* group();
@ -419,8 +411,11 @@ struct VariableSet
JSArenaPool *pool;
/* Whether the variables in this set are unknown. */
bool unknown;
VariableSet(JSArenaPool *pool)
: variables(NULL), propagateSet(NULL), propagateCount(NULL), pool(pool)
: variables(NULL), propagateSet(NULL), propagateCount(NULL), pool(pool), unknown(false)
{
JS_ASSERT(pool);
}
@ -436,6 +431,9 @@ struct VariableSet
*/
bool addPropagate(JSContext *cx, VariableSet *target, bool excludePrototype);
/* Mark all existing and future properties of this set as unknown. */
void markUnknown(JSContext *cx);
void print(JSContext *cx);
};
@ -452,12 +450,6 @@ struct TypeObject
/* Whether this is a function object, and may be cast into TypeFunction. */
bool isFunction;
/*
* Whether all reads from this object need to be monitored. This includes
* all property and element accesses, and for functions all calls to the function.
*/
bool monitored;
/*
* Properties of this object. This is filled in lazily for function objects
* to avoid unnecessary property and prototype object creation. Don't access
@ -489,6 +481,13 @@ struct TypeObject
/* Whether all objects this represents are packed arrays (implies isDenseArray). */
bool isPackedArray;
/*
* Whether this object is thought to be a possible packed array: either it came
* from a [a,b,c] initializer, an Array(a,b,c) call, or is another array for
* which we've seen what looks like initialization code. This is pure heuristic.
*/
bool possiblePackedArray;
/* Make an object with the specified name. */
TypeObject(JSContext *cx, JSArenaPool *pool, jsid id, bool isArray);
@ -507,6 +506,9 @@ struct TypeObject
/* Get the properties of this object, filled in lazily. */
inline VariableSet& properties(JSContext *cx);
/* Whether the properties of this object are unknown. */
bool unknownProperties() { return propertySet.unknown; }
/* Get the type set for all integer index properties of this object. */
inline TypeSet* indexTypes(JSContext *cx);
@ -745,18 +747,6 @@ struct TypeCompartment
/* Logging fields */
/*
* Whether any warnings were emitted. These are nonfatal but (generally)
* indicate unhandled constructs leading to analysis unsoundness.
*/
bool warnings;
/*
* Whether to ignore generated warnings. For handling regressions with
* shell functions we don't model.
*/
bool ignoreWarnings;
/*
* The total time (in microseconds) spent generating inference structures
* and performing analysis.
@ -768,6 +758,9 @@ struct TypeCompartment
unsigned typeCounts[TYPE_COUNT_LIMIT];
unsigned typeCountOver;
/* Number of recompilations triggered. */
unsigned recompilations;
void init();
~TypeCompartment();
@ -826,17 +819,19 @@ enum SpewChannel {
#ifdef DEBUG
/* Spew with INFERFLAGS = full or base */
void InferSpew(SpewChannel which, const char *fmt, ...);
void InferSpewType(SpewChannel which, JSContext *cx, jstype type, const char *fmt, ...);
const char * TypeString(jstype type);
#else
inline void InferSpew(SpewChannel which, const char *fmt, ...) {}
inline void InferSpewType(SpewChannel which, JSContext *cx, jstype type, const char *fmt, ...) {}
inline const char * TypeString(jstype type) { return NULL; }
#endif
/* Print a warning, dump state and abort the program. */
void TypeFailure(JSContext *cx, const char *fmt, ...);
} /* namespace types */
} /* namespace js */

View File

@ -131,7 +131,7 @@ MakeTypeId(jsid id)
/* Convert an id for printing during debug. */
static inline const char *
TypeIdString(JSContext *cx, jsid id)
TypeIdString(jsid id)
{
#ifdef DEBUG
if (JSID_IS_VOID(id))
@ -339,9 +339,10 @@ JSContext::addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::jst
return;
if (compartment->types.interpreting) {
js::types::InferSpewType(js::types::ISpewDynamic, this, type, "AddBuiltin: %s %s:",
js::types::TypeIdString(this, obj->name),
js::types::TypeIdString(this, id));
js::types::InferSpew(js::types::ISpewDynamic, "AddBuiltin: %s %s: %s",
js::types::TypeIdString(obj->name),
js::types::TypeIdString(id),
js::types::TypeString(type));
compartment->types.addDynamicType(this, types, type);
} else {
types->addType(this, type);
@ -373,7 +374,7 @@ JSContext::aliasTypeProperties(js::types::TypeObject *obj, jsid first, jsid seco
}
inline void
JSContext::markTypeArrayNotPacked(js::types::TypeObject *obj, bool notDense)
JSContext::markTypeArrayNotPacked(js::types::TypeObject *obj, bool notDense, bool dynamic)
{
#ifdef JS_TYPE_INFERENCE
if (notDense) {
@ -385,6 +386,12 @@ JSContext::markTypeArrayNotPacked(js::types::TypeObject *obj, bool notDense)
}
obj->isPackedArray = false;
if (dynamic) {
js::types::InferSpew(js::types::ISpewDynamic, "%s: %s",
notDense ? "NonDenseArray" : "NonPackedArray",
js::types::TypeIdString(obj->name));
}
/* All constraints listening to changes in packed/dense status are on the element types. */
js::types::TypeSet *elementTypes = obj->properties(this).getVariable(this, JSID_VOID);
js::types::TypeConstraint *constraint = elementTypes->constraintList;
@ -393,34 +400,19 @@ JSContext::markTypeArrayNotPacked(js::types::TypeObject *obj, bool notDense)
constraint = constraint->next;
}
if (compartment->types.hasPendingRecompiles())
if (dynamic && compartment->types.hasPendingRecompiles())
compartment->types.processPendingRecompiles(this);
#endif
}
void
JSContext::monitorTypeObject(js::types::TypeObject *obj)
JSContext::markTypeObjectUnknownProperties(js::types::TypeObject *obj)
{
#ifdef JS_TYPE_INFERENCE
if (obj->monitored)
if (obj->unknownProperties())
return;
/*
* Existing property constraints may have already been added to this object,
* which we need to do the right thing for. We can't ensure that we will
* mark all monitored objects before they have been accessed, as the __proto__
* of a non-monitored object could be dynamically set to a monitored object.
* Adding unknown for any properties accessed already accounts for possible
* values read from them.
*/
js::types::Variable *var = obj->properties(this).variables;
while (var) {
var->types.addType(this, js::types::TYPE_UNKNOWN);
var = var->next;
}
obj->monitored = true;
obj->properties(this).markUnknown(this);
#endif
}
@ -463,8 +455,8 @@ JSContext::typeMonitorCall(JSScript *caller, const jsbytecode *callerpc,
if (!JSID_IS_VOID(id)) {
js::types::TypeSet *types = script->localTypes.getVariable(this, id);
if (!types->hasType(type)) {
js::types::InferSpewType(js::types::ISpewDynamic, this, type,
"AddArg: #%u %u:", script->id, arg);
js::types::InferSpew(js::types::ISpewDynamic, "AddArg: #%u %u: %s",
script->id, arg, js::types::TypeString(type));
compartment->types.addDynamicType(this, types, type);
}
} else {
@ -506,8 +498,8 @@ JSContext::typeMonitorEntry(JSScript *script, const js::Value &thisv,
else
type = js::types::GetValueType(this, thisv);
if (!analysis->thisTypes.hasType(type)) {
js::types::InferSpewType(js::types::ISpewDynamic, this, type,
"AddThis: #%u:", analysis->id);
js::types::InferSpew(js::types::ISpewDynamic, "AddThis: #%u: %s",
analysis->id, js::types::TypeString(type));
compartment->types.addDynamicType(this, &analysis->thisTypes, type);
}
}
@ -516,6 +508,8 @@ JSContext::typeMonitorEntry(JSScript *script, const js::Value &thisv,
compartment->types.interpreting = false;
uint64_t startTime = compartment->types.currentTime();
js::types::InferSpew(js::types::ISpewDynamic, "EntryPoint: #%lu", analysis->id);
analysis->analyze(this);
uint64_t endTime = compartment->types.currentTime();
@ -606,7 +600,10 @@ JSScript::typeMonitorAssign(JSContext *cx, const jsbytecode *pc,
return;
}
cx->compartment->types.dynamicAssign(cx, obj, id, rval);
if (!obj->getTypeObject()->unknownProperties() ||
id == ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom)) {
cx->compartment->types.dynamicAssign(cx, obj, id, rval);
}
#endif
}
@ -619,8 +616,9 @@ JSScript::typeSetArgument(JSContext *cx, unsigned arg, const js::Value &value)
js::types::TypeSet *argTypes = analysis->localTypes.getVariable(cx, id);
js::types::jstype type = js::types::GetValueType(cx, value);
if (!argTypes->hasType(type)) {
js::types::InferSpewType(js::types::ISpewDynamic, cx, type, "SetArgument: #%u %s:",
analysis->id, js::types::TypeIdString(cx, id));
js::types::InferSpew(js::types::ISpewDynamic, "SetArgument: #%u %s: %s",
analysis->id, js::types::TypeIdString(id),
js::types::TypeString(type));
cx->compartment->types.addDynamicType(cx, argTypes, type);
}
}
@ -727,19 +725,18 @@ Bytecode::getInitObject(JSContext *cx, bool isArray)
/////////////////////////////////////////////////////////////////////
inline jsid
Script::getLocalId(unsigned index, types::TypeStack *stack)
Script::getLocalId(unsigned index, Bytecode *code)
{
if (index >= script->nfixed) {
/*
* This is an access on a let variable, we need the stack to figure out
* the name of the accessed variable. If multiple let variables have
* the same name, we flatten their types together.
*/
stack = stack ? stack->group() : NULL;
while (stack && (stack->stackDepth != index - script->nfixed)) {
stack = stack->innerStack;
stack = stack ? stack->group() : NULL;
}
if (!code)
return JSID_VOID;
JS_ASSERT(index - script->nfixed < code->stackDepth);
unsigned diff = code->stackDepth - (index - script->nfixed);
types::TypeStack *stack = code->inStack;
for (unsigned i = 1; i < diff; i++)
stack = stack->group()->innerStack;
JS_ASSERT(stack);
if (stack && JSID_TO_STRING(stack->letVariable) != NULL)
return stack->letVariable;
@ -774,19 +771,16 @@ Script::getArgumentId(unsigned index)
}
inline types::TypeSet*
Script::getStackTypes(unsigned index, types::TypeStack *stack)
Script::getStackTypes(unsigned index, Bytecode *code)
{
JS_ASSERT(index >= script->nfixed);
JS_ASSERT(index - script->nfixed < code->stackDepth);
stack = stack->group();
while (stack && (stack->stackDepth != index - script->nfixed)) {
stack = stack->innerStack;
stack = stack ? stack->group() : NULL;
}
/* This should not be used for accessing a let variable's stack slot. */
JS_ASSERT(stack && !JSID_IS_VOID(stack->letVariable));
return &stack->types;
types::TypeStack *stack = code->inStack;
unsigned diff = code->stackDepth - (index - script->nfixed) - 1;
for (unsigned i = 0; i < diff; i++)
stack = stack->group()->innerStack;
return &stack->group()->types;
}
inline JSValueType
@ -826,7 +820,7 @@ TypeCompartment::addPending(JSContext *cx, TypeConstraint *constraint, TypeSet *
JS_ASSERT(this == &cx->compartment->types);
JS_ASSERT(type);
InferSpewType(ISpewOps, cx, type, "pending: C%u", constraint->id());
InferSpew(ISpewOps, "pending: C%u %s", constraint->id(), TypeString(type));
if (pendingCount == pendingCapacity)
growPendingArray();
@ -852,7 +846,8 @@ TypeCompartment::resolvePending(JSContext *cx)
/* Handle all pending type registrations. */
while (pendingCount) {
const PendingWork &pending = pendingArray[--pendingCount];
InferSpewType(ISpewOps, cx, pending.type, "resolve: C%u ", pending.constraint->id());
InferSpew(ISpewOps, "resolve: C%u %s",
pending.constraint->id(), TypeString(pending.type));
pending.constraint->newType(cx, pending.source, pending.type);
}
@ -1061,7 +1056,7 @@ TypeSet::addType(JSContext *cx, jstype type)
{
JS_ASSERT(type);
JS_ASSERT_IF(typeFlags & TYPE_FLAG_UNKNOWN, typeFlags == TYPE_FLAG_UNKNOWN);
InferSpewType(ISpewOps, cx, type, "addType: T%u ", id());
InferSpew(ISpewOps, "addType: T%u %s", id(), TypeString(type));
if (typeFlags & TYPE_FLAG_UNKNOWN)
return;
@ -1124,7 +1119,7 @@ inline TypeSet *
TypeSet::make(JSContext *cx, JSArenaPool &pool, const char *name)
{
TypeSet *res = ArenaNew<TypeSet>(pool, &pool);
InferSpew(ISpewOps, "intermediate %s T%u\n", name, res->id());
InferSpew(ISpewOps, "intermediate %s T%u", name, res->id());
return res;
}
@ -1149,7 +1144,6 @@ TypeStack::setInnerStack(TypeStack *inner)
{
JS_ASSERT(!mergedGroup);
innerStack = inner;
stackDepth = inner ? (inner->group()->stackDepth + 1) : 0;
}
/////////////////////////////////////////////////////////////////////
@ -1215,8 +1209,17 @@ VariableSet::getVariable(JSContext *cx, jsid id)
res->next = variables;
variables = res;
InferSpew(ISpewOps, "addVariable: %s %s T%u\n",
TypeIdString(cx, name()), TypeIdString(cx, id), res->types.id());
InferSpew(ISpewOps, "addVariable: %s %s T%u",
TypeIdString(name()), TypeIdString(id), res->types.id());
if (unknown) {
/*
* Immediately mark the variable as unknown. Ideally we won't be doing this
* too often, but we don't assert !unknown to avoid extra complexity in
* other code accessing variable sets.
*/
res->types.addType(cx, TYPE_UNKNOWN);
}
/* Propagate the variable to any other sets receiving our variables. */
if (propagateCount >= 2) {

View File

@ -482,6 +482,7 @@ math_pow(JSContext *cx, uintN argc, Value *vp)
if (argc <= 1) {
vp->setDouble(js_NaN);
cx->markTypeCallerOverflow();
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
@ -522,6 +523,9 @@ math_pow(JSContext *cx, uintN argc, Value *vp)
z = pow(x, y);
vp->setNumber(z);
if (vp->isDouble() && vp[2].isInt32() && vp[3].isInt32())
cx->markTypeCallerOverflow();
return JS_TRUE;
}
@ -875,7 +879,7 @@ static JSFunctionSpec math_static_methods[] = {
JS_TN("log", math_log, 1, 0, &math_log_trcinfo, JS_TypeHandlerFloat),
JS_TN("max", js_math_max, 2, 0, &js_math_max_trcinfo, math_TypeArith),
JS_TN("min", js_math_min, 2, 0, &js_math_min_trcinfo, math_TypeArith),
JS_TN("pow", math_pow, 2, 0, &math_pow_trcinfo, JS_TypeHandlerFloat),
JS_TN("pow", math_pow, 2, 0, &math_pow_trcinfo, math_TypeArith),
JS_TN("random", math_random, 0, 0, &math_random_trcinfo, JS_TypeHandlerFloat),
JS_TN("round", js_math_round, 1, 0, &js_math_round_trcinfo, JS_TypeHandlerInt),
JS_TN("sin", math_sin, 1, 0, &math_sin_trcinfo, JS_TypeHandlerFloat),

View File

@ -1824,7 +1824,7 @@ JSScript::makeAnalysis(JSContext *cx)
char name[40];
JS_snprintf(name, sizeof(name), "#%u:locals", analysis->id);
analysis->localTypes.name_ = ATOM_TO_JSID(js_Atomize(cx, name, strlen(name), 0));
types::InferSpew(types::ISpewOps, "newScript: %s\n", name);
types::InferSpew(types::ISpewOps, "newScript: %s", name);
#endif
#endif /* JS_TYPE_INFERENCE */

View File

@ -2469,6 +2469,12 @@ mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew)
stubcc.linkExitDirect(notCompiled, stubcc.masm.label());
stubcc.rejoin(Changes(1));
callPatches.append(callPatch);
if (recompiling) {
/* In case we recompiled this call to an uncached call. */
OOL_STUBCALL(JS_FUNC_TO_DATA_PTR(void *, callingNew ? ic::New : ic::Call));
stubcc.rejoin(Changes(1));
}
}
static bool
@ -5068,8 +5074,7 @@ mjit::Compiler::fixDoubleTypes(Uses uses)
}
analyze::Bytecode &opinfo = analysis->getCode(PC);
for (uint32 i = 0; i < opinfo.stackDepth - uses.nuses; i++) {
types::TypeStack *stack = opinfo.inStack;
types::TypeSet *types = analysis->getStackTypes(script->nfixed + i, stack);
types::TypeSet *types = analysis->getStackTypes(script->nfixed + i, &opinfo);
JSValueType type = types->getKnownTypeTag(cx, script);
if (type == JSVAL_TYPE_DOUBLE) {
FrameEntry *fe = frame.getLocal(script->nfixed + i);

View File

@ -125,6 +125,8 @@ Recompiler::stealNative(JITScript *jit, jsbytecode *pc)
/* Already stole this stub. */
PatchableNative native;
native.pc = NULL;
native.guardedNative = NULL;
native.pool = NULL;
return native;
}

View File

@ -4208,13 +4208,6 @@ Deserialize(JSContext *cx, uintN argc, jsval *vp)
return true;
}
static void type_Bailout(JSContext *cx, JSTypeFunction *fun, JSTypeCallsite *site)
{
#ifdef JS_TYPE_INFERENCE
cx->compartment->types.ignoreWarnings = true;
#endif
}
/* We use a mix of JS_FS and JS_FN to test both kinds of natives. */
static JSFunctionSpec shell_functions[] = {
JS_FN_TYPE("version", Version, 0,0, JS_TypeHandlerInt),
@ -4267,12 +4260,12 @@ static JSFunctionSpec shell_functions[] = {
JS_FN_TYPE("build", BuildDate, 0,0, JS_TypeHandlerVoid),
JS_FN_TYPE("clear", Clear, 0,0, JS_TypeHandlerVoid),
JS_FN_TYPE("intern", Intern, 1,0, JS_TypeHandlerVoid),
JS_FN_TYPE("clone", Clone, 1,0, type_Bailout),
JS_FN_TYPE("getpda", GetPDA, 1,0, JS_TypeHandlerMissing),
JS_FN_TYPE("clone", Clone, 1,0, JS_TypeHandlerDynamic),
JS_FN_TYPE("getpda", GetPDA, 1,0, JS_TypeHandlerDynamic),
JS_FN_TYPE("getslx", GetSLX, 1,0, JS_TypeHandlerInt),
JS_FN_TYPE("toint32", ToInt32, 1,0, JS_TypeHandlerInt),
JS_FN_TYPE("evalcx", EvalInContext, 1,0, type_Bailout),
JS_FN_TYPE("evalInFrame", EvalInFrame, 2,0, type_Bailout),
JS_FN_TYPE("evalcx", EvalInContext, 1,0, JS_TypeHandlerDynamic),
JS_FN_TYPE("evalInFrame", EvalInFrame, 2,0, JS_TypeHandlerDynamic),
JS_FN_TYPE("shapeOf", ShapeOf, 1,0, JS_TypeHandlerInt),
#ifdef MOZ_SHARK
JS_FN_TYPE("startShark", js_StartShark, 0,0, JS_TypeHandlerVoid),
@ -4661,7 +4654,7 @@ its_bindMethod(JSContext *cx, uintN argc, jsval *vp)
}
static JSFunctionSpec its_methods[] = {
{"bindMethod", its_bindMethod, 2,0, type_Bailout},
{"bindMethod", its_bindMethod, 2,0, JS_TypeHandlerMissing},
{NULL,NULL,0,0}
};