mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[INFER] Overhaul inference handling of new object computation, bug 619433.
This commit is contained in:
parent
6279a0e820
commit
a3042809bc
@ -2141,7 +2141,8 @@ public:
|
||||
js::types::TypeObject *newTypeObject(const char *name, JSObject *proto);
|
||||
|
||||
/* Make a type object whose name is that of base followed by postfix. */
|
||||
js::types::TypeObject *newTypeObject(const char *base, const char *postfix, JSObject *proto);
|
||||
js::types::TypeObject *newTypeObject(const char *base, const char *postfix,
|
||||
JSObject *proto, bool isFunction = false);
|
||||
|
||||
/*
|
||||
* Get the default 'new' object for a given standard class, per the currently
|
||||
|
@ -2764,6 +2764,8 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj)
|
||||
script->owner = NULL;
|
||||
#endif
|
||||
fun->u.i.script = script;
|
||||
fun->getType()->asFunction()->script = script;
|
||||
script->fun = fun;
|
||||
js_CallNewScriptHook(cx, script, fun);
|
||||
|
||||
if (obj->isGlobal()) {
|
||||
|
@ -974,8 +974,9 @@ TypeConstraintNewObject::newType(JSContext *cx, TypeSet *source, jstype type)
|
||||
}
|
||||
} else if (!fun->script) {
|
||||
/*
|
||||
* This constraint should only be used for native constructors with
|
||||
* immutable non-primitive prototypes. Disregard primitives here.
|
||||
* This constraint should only be used for scripted functions and for
|
||||
* native constructors with immutable non-primitive prototypes.
|
||||
* Disregard primitives here.
|
||||
*/
|
||||
} else if (!fun->script->compileAndGo) {
|
||||
target->addType(cx, TYPE_UNKNOWN);
|
||||
@ -1083,15 +1084,7 @@ TypeConstraintCall::newType(JSContext *cx, TypeSet *source, jstype type)
|
||||
|
||||
/* Add a binding for the receiver object of the call. */
|
||||
if (callsite->isNew) {
|
||||
/* The receiver object is the 'new' object for the function's prototype. */
|
||||
if (function->unknownProperties) {
|
||||
script->thisTypes()->addType(cx, TYPE_UNKNOWN);
|
||||
} else {
|
||||
TypeSet *prototypeTypes = function->getProperty(cx, id_prototype(cx), false);
|
||||
if (!prototypeTypes)
|
||||
return;
|
||||
prototypeTypes->addNewObject(cx, script, function, callee->thisTypes());
|
||||
}
|
||||
callee->typeSetNewCalled(cx);
|
||||
|
||||
/*
|
||||
* If the script does not return a value then the pushed value is the new
|
||||
@ -1687,25 +1680,14 @@ TypeCompartment::dynamicCall(JSContext *cx, JSObject *callee,
|
||||
unsigned nargs = callee->getFunctionPrivate()->nargs;
|
||||
JSScript *script = callee->getFunctionPrivate()->script();
|
||||
|
||||
jstype type;
|
||||
if (constructing) {
|
||||
Value protov;
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
|
||||
if (!callee->getProperty(cx, id, &protov))
|
||||
return false;
|
||||
TypeObject *otype = protov.isObject()
|
||||
? protov.toObject().getNewType(cx)
|
||||
: cx->getTypeNewObject(JSProto_Object);
|
||||
if (!otype)
|
||||
return false;
|
||||
type = (jstype) otype;
|
||||
script->typeSetNewCalled(cx);
|
||||
} else {
|
||||
type = GetValueType(cx, args.thisv());
|
||||
jstype type = GetValueType(cx, args.thisv());
|
||||
if (!script->typeSetThis(cx, type))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!script->typeSetThis(cx, type))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Add constraints going up to the minimum of the actual and formal count.
|
||||
* If there are more actuals than formals the later values can only be
|
||||
@ -3306,6 +3288,9 @@ AnalyzeScriptTypes(JSContext *cx, JSScript *script)
|
||||
cursor += sizeof(TypeScript);
|
||||
types->pushedArray = (TypeSet **) cursor;
|
||||
|
||||
if (script->calledWithNew)
|
||||
AnalyzeScriptNew(cx, script);
|
||||
|
||||
unsigned offset = 0;
|
||||
while (offset < script->length) {
|
||||
analyze::Bytecode *code = analysis.maybeCode(offset);
|
||||
@ -3335,11 +3320,23 @@ AnalyzeScriptTypes(JSContext *cx, JSScript *script)
|
||||
}
|
||||
|
||||
void
|
||||
DestroyScriptTypes(JSContext *cx, JSScript *script)
|
||||
AnalyzeScriptNew(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JS_ASSERT(script->types);
|
||||
cx->free(script->types);
|
||||
script->types = NULL;
|
||||
JS_ASSERT(script->calledWithNew && script->fun);
|
||||
|
||||
/*
|
||||
* Compute the 'this' type when called with 'new'. We do not distinguish regular
|
||||
* from 'new' calls to the function.
|
||||
*/
|
||||
TypeFunction *funType = script->fun->getType()->asFunction();
|
||||
if (funType->unknownProperties) {
|
||||
script->thisTypes()->addType(cx, TYPE_UNKNOWN);
|
||||
} else {
|
||||
TypeSet *prototypeTypes = funType->getProperty(cx, id_prototype(cx), false);
|
||||
if (!prototypeTypes)
|
||||
return;
|
||||
prototypeTypes->addNewObject(cx, script, funType, script->thisTypes());
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@ -3576,7 +3573,7 @@ JSContext::newTypeObject(const char *name, JSObject *proto)
|
||||
}
|
||||
|
||||
js::types::TypeObject *
|
||||
JSContext::newTypeObject(const char *base, const char *postfix, JSObject *proto)
|
||||
JSContext::newTypeObject(const char *base, const char *postfix, JSObject *proto, bool isFunction)
|
||||
{
|
||||
char *name = NULL;
|
||||
#ifdef DEBUG
|
||||
@ -3584,7 +3581,7 @@ JSContext::newTypeObject(const char *base, const char *postfix, JSObject *proto)
|
||||
name = (char *)alloca(len);
|
||||
JS_snprintf(name, len, "%s:%s", base, postfix);
|
||||
#endif
|
||||
return compartment->types.newTypeObject(this, NULL, name, false, proto);
|
||||
return compartment->types.newTypeObject(this, NULL, name, isFunction, proto);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@ -4117,6 +4114,8 @@ JSScript::sweepTypes(JSContext *cx)
|
||||
{
|
||||
SweepTypeObjectList(cx, typeObjects);
|
||||
|
||||
if (types && !compartment->types.inferenceDepth)
|
||||
js::types::DestroyScriptTypes(cx, this);
|
||||
if (types && !compartment->types.inferenceDepth) {
|
||||
cx->free(types);
|
||||
types = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -570,8 +570,8 @@ struct TypeScript
|
||||
/* Analyzes all types in script, constructing its TypeScript. */
|
||||
void AnalyzeScriptTypes(JSContext *cx, JSScript *script);
|
||||
|
||||
/* Destroy the TypeScript associated with a script. */
|
||||
void DestroyScriptTypes(JSContext *cx, JSScript *script);
|
||||
/* Analyze the effect of invoking 'new' on script. */
|
||||
void AnalyzeScriptNew(JSContext *cx, JSScript *script);
|
||||
|
||||
/* Type information for a compartment. */
|
||||
struct TypeCompartment
|
||||
|
@ -530,6 +530,30 @@ JSScript::typeSetThis(JSContext *cx, js::types::jstype type)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::typeSetNewCalled(JSContext *cx)
|
||||
{
|
||||
if (!cx->typeInferenceEnabled() || calledWithNew)
|
||||
return true;
|
||||
calledWithNew = true;
|
||||
|
||||
/*
|
||||
* Determining the 'this' type used when the script is invoked with 'new'
|
||||
* happens during the script's prologue, so we don't try to pick it up from
|
||||
* dynamic calls. Instead, generate constraints modeling the construction
|
||||
* of 'this' when the script is analyzed or reanalyzed after an invoke with 'new',
|
||||
* and if 'new' is first invoked after the script has already been analyzed.
|
||||
*/
|
||||
if (analyzed) {
|
||||
/* Regenerate types for the function. */
|
||||
js::types::AutoEnterTypeInference enter(cx);
|
||||
js::types::AnalyzeScriptNew(cx, this);
|
||||
if (!cx->compartment->types.checkPendingRecompiles(cx))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::typeSetLocal(JSContext *cx, unsigned local, const js::Value &value)
|
||||
{
|
||||
|
@ -3940,7 +3940,8 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt
|
||||
if (!proto)
|
||||
return NULL;
|
||||
|
||||
TypeObject *protoType = cx->newTypeObject(clasp->name, "prototype", proto->getProto());
|
||||
TypeObject *protoType = cx->newTypeObject(clasp->name, "prototype", proto->getProto(),
|
||||
clasp == &js_FunctionClass);
|
||||
if (!protoType)
|
||||
return NULL;
|
||||
proto->setType(protoType);
|
||||
|
@ -406,6 +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 */
|
||||
bool calledWithNew:1; /* script has been called using 'new' */
|
||||
bool analyzed:1; /* script has been analyzed by type inference */
|
||||
#ifdef JS_METHODJIT
|
||||
bool debugMode:1; /* script was compiled in debug mode */
|
||||
@ -522,6 +523,7 @@ struct JSScript {
|
||||
|
||||
/* Add a type for a variable in this script. */
|
||||
inline bool typeSetThis(JSContext *cx, js::types::jstype type);
|
||||
inline bool typeSetNewCalled(JSContext *cx);
|
||||
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);
|
||||
|
@ -7114,6 +7114,8 @@ js_InitQNameClass(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JSObject *proto = js_InitClass(cx, obj, NULL, &js_QNameClass, QName, 2, JS_TypeHandlerDynamic,
|
||||
qname_props, qname_methods, NULL, NULL);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
|
||||
/* Properties of QName objects are not modeled by type inference. */
|
||||
TypeObject *type = proto->getNewType(cx);
|
||||
@ -7305,6 +7307,10 @@ js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
|
||||
|
||||
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
||||
JSObject &varobj = fp->varobj(cx);
|
||||
|
||||
if (!cx->addTypePropertyId(varobj.getType(), JS_DEFAULT_XML_NAMESPACE_ID, types::TYPE_UNKNOWN))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!varobj.defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns),
|
||||
PropertyStub, StrictPropertyStub, JSPROP_PERMANENT)) {
|
||||
return JS_FALSE;
|
||||
|
Loading…
Reference in New Issue
Block a user