2011-05-12 20:07:23 -07:00
|
|
|
//* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */
|
2010-10-29 08:05:55 -07:00
|
|
|
/* vim: set ts=40 sw=4 et tw=99: */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is the Mozilla SpiderMonkey bytecode type inference
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Mozilla Foundation
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Brian Hackett <bhackett@mozilla.com>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
/* Definitions related to javascript type inference. */
|
|
|
|
|
|
|
|
#ifndef jsinfer_h___
|
|
|
|
#define jsinfer_h___
|
|
|
|
|
2011-07-01 16:24:32 -07:00
|
|
|
#include "jsalloc.h"
|
2010-10-29 08:05:55 -07:00
|
|
|
#include "jsarena.h"
|
2011-07-21 07:28:01 -07:00
|
|
|
#include "jscell.h"
|
2010-10-29 08:05:55 -07:00
|
|
|
#include "jstl.h"
|
|
|
|
#include "jsprvtd.h"
|
2010-12-19 12:21:15 -08:00
|
|
|
#include "jsvalue.h"
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-03-03 14:07:48 -08:00
|
|
|
namespace js {
|
2011-05-09 10:00:29 -07:00
|
|
|
class CallArgs;
|
2011-04-22 07:59:45 -07:00
|
|
|
}
|
2010-10-29 08:05:55 -07:00
|
|
|
|
|
|
|
namespace js {
|
|
|
|
namespace types {
|
|
|
|
|
|
|
|
/* Forward declarations. */
|
2011-04-12 07:04:45 -07:00
|
|
|
class TypeSet;
|
2010-10-29 08:05:55 -07:00
|
|
|
struct TypeCallsite;
|
|
|
|
struct TypeObject;
|
|
|
|
struct TypeCompartment;
|
2011-07-15 10:14:07 -07:00
|
|
|
|
|
|
|
/* Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. */
|
|
|
|
struct TypeObjectKey {
|
|
|
|
static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }
|
|
|
|
static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; }
|
|
|
|
};
|
2010-10-29 08:05:55 -07:00
|
|
|
|
|
|
|
/*
|
2011-07-21 07:28:01 -07:00
|
|
|
* Information about a single concrete type. We pack this into a single word,
|
|
|
|
* where small values are particular primitive or other singleton types, and
|
|
|
|
* larger values are either specific JS objects or type objects.
|
2010-10-29 08:05:55 -07:00
|
|
|
*/
|
2011-07-15 10:14:07 -07:00
|
|
|
class Type
|
|
|
|
{
|
|
|
|
jsuword data;
|
|
|
|
Type(jsuword data) : data(data) {}
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
public:
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
jsuword raw() const { return data; }
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
bool isPrimitive() const {
|
|
|
|
return data < JSVAL_TYPE_OBJECT;
|
|
|
|
}
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
bool isPrimitive(JSValueType type) const {
|
|
|
|
JS_ASSERT(type < JSVAL_TYPE_OBJECT);
|
|
|
|
return type == (JSValueType) data;
|
|
|
|
}
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
JSValueType primitive() const {
|
|
|
|
JS_ASSERT(isPrimitive());
|
|
|
|
return (JSValueType) data;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isAnyObject() const {
|
|
|
|
return data == JSVAL_TYPE_OBJECT;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isUnknown() const {
|
|
|
|
return data == JSVAL_TYPE_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Accessors for types that are either JSObject or TypeObject. */
|
|
|
|
|
|
|
|
bool isObject() const {
|
|
|
|
JS_ASSERT(!isAnyObject() && !isUnknown());
|
|
|
|
return data > JSVAL_TYPE_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeObjectKey *objectKey() const {
|
|
|
|
JS_ASSERT(isObject());
|
|
|
|
return (TypeObjectKey *) data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Accessors for JSObject types */
|
|
|
|
|
|
|
|
bool isSingleObject() const {
|
|
|
|
return isObject() && !!(data & 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject *singleObject() const {
|
|
|
|
JS_ASSERT(isSingleObject());
|
|
|
|
return (JSObject *) (data ^ 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Accessors for TypeObject types */
|
|
|
|
|
|
|
|
bool isTypeObject() const {
|
|
|
|
return isObject() && !(data & 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeObject *typeObject() const {
|
|
|
|
JS_ASSERT(isTypeObject());
|
|
|
|
return (TypeObject *) data;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator == (Type o) const { return data == o.data; }
|
|
|
|
bool operator != (Type o) const { return data != o.data; }
|
|
|
|
|
|
|
|
static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
|
|
|
|
static inline Type NullType() { return Type(JSVAL_TYPE_NULL); }
|
|
|
|
static inline Type BooleanType() { return Type(JSVAL_TYPE_BOOLEAN); }
|
|
|
|
static inline Type Int32Type() { return Type(JSVAL_TYPE_INT32); }
|
|
|
|
static inline Type DoubleType() { return Type(JSVAL_TYPE_DOUBLE); }
|
|
|
|
static inline Type StringType() { return Type(JSVAL_TYPE_STRING); }
|
|
|
|
static inline Type LazyArgsType() { return Type(JSVAL_TYPE_MAGIC); }
|
|
|
|
static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
|
|
|
|
static inline Type UnknownType() { return Type(JSVAL_TYPE_UNKNOWN); }
|
|
|
|
|
|
|
|
static inline Type PrimitiveType(JSValueType type) {
|
|
|
|
JS_ASSERT(type < JSVAL_TYPE_UNKNOWN);
|
|
|
|
return Type(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Type ObjectType(JSObject *obj);
|
|
|
|
static inline Type ObjectType(TypeObject *obj);
|
|
|
|
static inline Type ObjectType(TypeObjectKey *obj);
|
|
|
|
};
|
2010-10-29 08:05:55 -07:00
|
|
|
|
|
|
|
/* Get the type of a jsval, or zero for an unknown special value. */
|
2011-07-15 10:14:07 -07:00
|
|
|
inline Type GetValueType(JSContext *cx, const Value &val);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-03-01 13:10:05 -08:00
|
|
|
/*
|
|
|
|
* Type inference memory management overview.
|
|
|
|
*
|
|
|
|
* Inference constructs a global web of constraints relating the contents of
|
2011-05-12 20:07:23 -07:00
|
|
|
* type sets particular to various scripts and type objects within a
|
2011-07-15 10:14:07 -07:00
|
|
|
* compartment. These constraints can consume a significant amount of memory,
|
|
|
|
* and to avoid this building up we clear out (almost, see 1.) all the
|
|
|
|
* constraints and most other type inference data on (almost, see 2.) every GC.
|
|
|
|
* JIT code which depends on this type information and is sensitive to
|
|
|
|
* subsequent changes is cleared at the same time.
|
2011-03-01 13:10:05 -08:00
|
|
|
*
|
2011-07-15 10:14:07 -07:00
|
|
|
* Type constraints may be either transient --- destroyed along with the type
|
|
|
|
* constraints --- or persistent. Persistent constraints describe properties
|
|
|
|
* of type objects, locals, args, and observed types in scripts, and may or
|
|
|
|
* may not survive GCs.
|
2011-03-01 13:10:05 -08:00
|
|
|
*
|
2011-07-15 10:14:07 -07:00
|
|
|
* Notes:
|
2011-05-17 20:29:41 -07:00
|
|
|
*
|
2011-07-15 10:14:07 -07:00
|
|
|
* 1. Some type constraints are persistent, and relate type objects to each
|
|
|
|
* other. These survive GCs as long as some target type object is live.
|
2011-03-01 13:10:05 -08:00
|
|
|
*
|
2011-07-15 10:14:07 -07:00
|
|
|
* 2. If a GC happens while we are in the middle of or working with analysis
|
2011-05-17 20:29:41 -07:00
|
|
|
* information (both type information and other transient information stored in
|
2011-07-15 10:14:07 -07:00
|
|
|
* ScriptAnalysis), we do not destroy analysis information or collect
|
2011-05-17 20:29:41 -07:00
|
|
|
* TypeObjects or JSScripts. This is controlled with AutoEnterAnalysis and
|
2011-05-12 20:07:23 -07:00
|
|
|
* AutoEnterTypeInference.
|
2011-03-01 13:10:05 -08:00
|
|
|
*/
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/*
|
|
|
|
* A constraint which listens to additions to a type set and propagates those
|
|
|
|
* changes to other type sets.
|
|
|
|
*/
|
|
|
|
class TypeConstraint
|
|
|
|
{
|
|
|
|
public:
|
2010-11-18 15:18:23 -08:00
|
|
|
#ifdef DEBUG
|
|
|
|
const char *kind_;
|
|
|
|
const char *kind() const { return kind_; }
|
|
|
|
#else
|
|
|
|
const char *kind() const { return NULL; }
|
2010-10-29 08:05:55 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Next constraint listening to the same type set. */
|
|
|
|
TypeConstraint *next;
|
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
TypeConstraint(const char *kind)
|
|
|
|
: next(NULL)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2010-11-18 15:18:23 -08:00
|
|
|
#ifdef DEBUG
|
|
|
|
this->kind_ = kind;
|
2010-10-29 08:05:55 -07:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Register a new type for the set this constraint is listening to. */
|
2011-07-15 10:14:07 -07:00
|
|
|
virtual void newType(JSContext *cx, TypeSet *source, Type type) = 0;
|
2010-11-05 07:37:09 -07:00
|
|
|
|
2011-04-11 20:10:46 -07:00
|
|
|
/*
|
|
|
|
* For constraints attached to an object property's type set, mark the
|
|
|
|
* property as having been configured or received an own property.
|
|
|
|
*/
|
|
|
|
virtual void newPropertyState(JSContext *cx, TypeSet *source) {}
|
|
|
|
|
2010-11-05 07:37:09 -07:00
|
|
|
/*
|
2011-07-21 07:28:01 -07:00
|
|
|
* For constraints attached to the JSID_EMPTY type set on an object, mark a
|
|
|
|
* change in one of the object's dynamic property flags. If force is set,
|
|
|
|
* recompilation is always triggered.
|
2010-11-05 07:37:09 -07:00
|
|
|
*/
|
2011-05-19 13:56:11 -07:00
|
|
|
virtual void newObjectState(JSContext *cx, TypeObject *object, bool force) {}
|
2010-11-05 07:37:09 -07:00
|
|
|
};
|
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
/* Flags and other state stored in TypeSet::flags */
|
2011-03-03 14:07:48 -08:00
|
|
|
enum {
|
2011-07-15 10:14:07 -07:00
|
|
|
TYPE_FLAG_UNDEFINED = 0x1,
|
|
|
|
TYPE_FLAG_NULL = 0x2,
|
|
|
|
TYPE_FLAG_BOOLEAN = 0x4,
|
|
|
|
TYPE_FLAG_INT32 = 0x8,
|
|
|
|
TYPE_FLAG_DOUBLE = 0x10,
|
|
|
|
TYPE_FLAG_STRING = 0x20,
|
|
|
|
TYPE_FLAG_LAZYARGS = 0x40,
|
|
|
|
TYPE_FLAG_ANYOBJECT = 0x80,
|
2011-03-03 14:07:48 -08:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
/* Mask/shift for the number of objects in objectSet */
|
|
|
|
TYPE_FLAG_OBJECT_COUNT_MASK = 0xff00,
|
|
|
|
TYPE_FLAG_OBJECT_COUNT_SHIFT = 8,
|
|
|
|
TYPE_FLAG_OBJECT_COUNT_LIMIT =
|
|
|
|
TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
|
|
|
|
|
|
|
|
/* Whether the contents of this type set are totally unknown. */
|
|
|
|
TYPE_FLAG_UNKNOWN = 0x00010000,
|
|
|
|
|
|
|
|
/* Mask of normal type flags on a type set. */
|
|
|
|
TYPE_FLAG_BASE_MASK = 0x000100ff,
|
2011-03-03 14:07:48 -08:00
|
|
|
|
|
|
|
/* Flag for type sets which are cleared on GC. */
|
2011-07-21 07:28:01 -07:00
|
|
|
TYPE_FLAG_INTERMEDIATE_SET = 0x00020000,
|
2011-04-11 20:10:46 -07:00
|
|
|
|
2011-04-12 20:39:16 -07:00
|
|
|
/* Flags for type sets which are on object properties. */
|
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
/*
|
|
|
|
* Whether there are subset constraints propagating the possible types
|
|
|
|
* for this property inherited from the object's prototypes. Reset on GC.
|
|
|
|
*/
|
|
|
|
TYPE_FLAG_PROPAGATED_PROPERTY = 0x00040000,
|
|
|
|
|
2011-04-12 20:39:16 -07:00
|
|
|
/* Whether this property has ever been directly written. */
|
2011-07-21 07:28:01 -07:00
|
|
|
TYPE_FLAG_OWN_PROPERTY = 0x00080000,
|
2011-04-12 20:39:16 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Whether the property has ever been deleted or reconfigured to behave
|
|
|
|
* differently from a normal native property (e.g. made non-writable or
|
|
|
|
* given a scripted getter or setter).
|
|
|
|
*/
|
2011-07-21 07:28:01 -07:00
|
|
|
TYPE_FLAG_CONFIGURED_PROPERTY = 0x00100000,
|
2011-07-15 10:14:07 -07:00
|
|
|
|
2011-04-11 20:10:46 -07:00
|
|
|
/*
|
2011-04-12 20:39:16 -07:00
|
|
|
* Whether the property is definitely in a particular inline slot on all
|
|
|
|
* objects from which it has not been deleted or reconfigured. Implies
|
|
|
|
* OWN_PROPERTY and unlike OWN/CONFIGURED property, this cannot change.
|
2011-04-11 20:10:46 -07:00
|
|
|
*/
|
2011-07-21 07:28:01 -07:00
|
|
|
TYPE_FLAG_DEFINITE_PROPERTY = 0x00200000,
|
2011-04-12 20:39:16 -07:00
|
|
|
|
|
|
|
/* If the property is definite, mask and shift storing the slot. */
|
2011-07-21 07:28:01 -07:00
|
|
|
TYPE_FLAG_DEFINITE_MASK = 0x0f000000,
|
2011-07-21 20:27:34 -07:00
|
|
|
TYPE_FLAG_DEFINITE_SHIFT = 24
|
2011-03-03 14:07:48 -08:00
|
|
|
};
|
|
|
|
typedef uint32 TypeFlags;
|
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
/* Flags and other state stored in TypeObject::flags */
|
2011-05-10 23:33:30 -07:00
|
|
|
enum {
|
2011-07-21 07:28:01 -07:00
|
|
|
/* Objects with this type are functions. */
|
|
|
|
OBJECT_FLAG_FUNCTION = 0x1,
|
|
|
|
|
|
|
|
/* If set, newScript information should not be installed on this object. */
|
|
|
|
OBJECT_FLAG_NEW_SCRIPT_CLEARED = 0x2,
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If set, type constraints covering the correctness of the newScript
|
|
|
|
* definite properties need to be regenerated before compiling any jitcode
|
|
|
|
* which depends on this information.
|
|
|
|
*/
|
|
|
|
OBJECT_FLAG_NEW_SCRIPT_REGENERATE = 0x4,
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Whether we have ensured all type sets in the compartment contain
|
|
|
|
* ANYOBJECT instead of this object.
|
|
|
|
*/
|
|
|
|
OBJECT_FLAG_SETS_MARKED_UNKNOWN = 0x8,
|
|
|
|
|
|
|
|
/* Mask/shift for the number of properties in propertySet */
|
|
|
|
OBJECT_FLAG_PROPERTY_COUNT_MASK = 0xfff0,
|
|
|
|
OBJECT_FLAG_PROPERTY_COUNT_SHIFT = 4,
|
|
|
|
OBJECT_FLAG_PROPERTY_COUNT_LIMIT =
|
|
|
|
OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT,
|
|
|
|
|
2011-05-10 23:33:30 -07:00
|
|
|
/*
|
|
|
|
* Whether any objects this represents are not dense arrays. This also
|
|
|
|
* includes dense arrays whose length property does not fit in an int32.
|
|
|
|
*/
|
2011-07-21 07:28:01 -07:00
|
|
|
OBJECT_FLAG_NON_DENSE_ARRAY = 0x010000,
|
2011-05-10 23:33:30 -07:00
|
|
|
|
|
|
|
/* Whether any objects this represents are not packed arrays. */
|
2011-07-21 07:28:01 -07:00
|
|
|
OBJECT_FLAG_NON_PACKED_ARRAY = 0x020000,
|
2011-05-10 23:33:30 -07:00
|
|
|
|
2011-06-15 11:26:12 -07:00
|
|
|
/* Whether any objects this represents are not typed arrays. */
|
2011-07-21 07:28:01 -07:00
|
|
|
OBJECT_FLAG_NON_TYPED_ARRAY = 0x040000,
|
2011-06-15 11:26:12 -07:00
|
|
|
|
2011-05-26 12:28:19 -07:00
|
|
|
/* Whether any represented script has had arguments objects created. */
|
2011-07-21 07:28:01 -07:00
|
|
|
OBJECT_FLAG_CREATED_ARGUMENTS = 0x080000,
|
2011-05-10 23:33:30 -07:00
|
|
|
|
2011-05-26 12:28:19 -07:00
|
|
|
/* Whether any represented script is considered uninlineable. */
|
2011-07-21 07:28:01 -07:00
|
|
|
OBJECT_FLAG_UNINLINEABLE = 0x100000,
|
2011-05-10 23:33:30 -07:00
|
|
|
|
2011-05-26 12:28:19 -07:00
|
|
|
/* Whether any objects have an equality hook. */
|
2011-07-21 07:28:01 -07:00
|
|
|
OBJECT_FLAG_SPECIAL_EQUALITY = 0x200000,
|
2011-05-26 12:28:19 -07:00
|
|
|
|
|
|
|
/* Whether any objects have been iterated over. */
|
2011-07-21 07:28:01 -07:00
|
|
|
OBJECT_FLAG_ITERATED = 0x400000,
|
|
|
|
|
|
|
|
/* Flags which indicate dynamic properties of represented objects. */
|
|
|
|
OBJECT_FLAG_DYNAMIC_MASK = 0x7f0000,
|
2011-07-15 10:14:07 -07:00
|
|
|
|
|
|
|
/*
|
2011-07-21 07:28:01 -07:00
|
|
|
* Whether all properties of this object are considered unknown.
|
|
|
|
* If set, all flags in DYNAMIC_MASK will also be set.
|
2011-07-15 10:14:07 -07:00
|
|
|
*/
|
2011-07-21 07:28:01 -07:00
|
|
|
OBJECT_FLAG_UNKNOWN_PROPERTIES = 0x800000,
|
|
|
|
|
|
|
|
/* Mask for objects created with unknown properties. */
|
|
|
|
OBJECT_FLAG_UNKNOWN_MASK =
|
|
|
|
OBJECT_FLAG_DYNAMIC_MASK
|
|
|
|
| OBJECT_FLAG_UNKNOWN_PROPERTIES
|
|
|
|
| OBJECT_FLAG_SETS_MARKED_UNKNOWN
|
2011-05-10 23:33:30 -07:00
|
|
|
};
|
|
|
|
typedef uint32 TypeObjectFlags;
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/* Information about the set of types associated with an lvalue. */
|
2011-04-05 18:12:03 -07:00
|
|
|
class TypeSet
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2011-07-21 07:28:01 -07:00
|
|
|
/* Flags for this type set. */
|
|
|
|
TypeFlags flags;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-03-03 14:07:48 -08:00
|
|
|
/* Possible objects this type set can represent. */
|
2011-07-15 10:14:07 -07:00
|
|
|
TypeObjectKey **objectSet;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-04-05 18:12:03 -07:00
|
|
|
public:
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/* Chain of constraints which propagate changes out from this type set. */
|
|
|
|
TypeConstraint *constraintList;
|
|
|
|
|
2011-03-01 13:10:05 -08:00
|
|
|
TypeSet()
|
2011-07-21 07:28:01 -07:00
|
|
|
: flags(0), objectSet(NULL), constraintList(NULL)
|
2011-03-01 13:10:05 -08:00
|
|
|
{}
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2010-11-18 15:18:23 -08:00
|
|
|
void print(JSContext *cx);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
inline void sweep(JSContext *cx, JSCompartment *compartment);
|
2011-07-07 20:04:47 -07:00
|
|
|
size_t dynamicSize();
|
2011-03-03 14:07:48 -08:00
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/* Whether this set contains a specific type. */
|
2011-07-15 10:14:07 -07:00
|
|
|
inline bool hasType(Type type);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
TypeFlags baseFlags() { return flags & TYPE_FLAG_BASE_MASK; }
|
|
|
|
bool unknown() { return !!(flags & TYPE_FLAG_UNKNOWN); }
|
|
|
|
bool unknownObject() { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
|
|
|
|
|
|
|
|
bool hasAnyFlag(TypeFlags flags) {
|
|
|
|
JS_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags);
|
|
|
|
return !!(baseFlags() & flags);
|
|
|
|
}
|
2010-12-21 07:32:21 -08:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
bool isOwnProperty(bool configurable) {
|
|
|
|
return flags & (configurable ? TYPE_FLAG_CONFIGURED_PROPERTY : TYPE_FLAG_OWN_PROPERTY);
|
|
|
|
}
|
|
|
|
bool isDefiniteProperty() { return flags & TYPE_FLAG_DEFINITE_PROPERTY; }
|
2011-04-12 20:39:16 -07:00
|
|
|
unsigned definiteSlot() {
|
|
|
|
JS_ASSERT(isDefiniteProperty());
|
2011-07-21 07:28:01 -07:00
|
|
|
return flags >> TYPE_FLAG_DEFINITE_SHIFT;
|
2011-04-12 20:39:16 -07:00
|
|
|
}
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/*
|
|
|
|
* Add a type to this set, calling any constraint handlers if this is a new
|
|
|
|
* possible type.
|
|
|
|
*/
|
2011-07-15 10:14:07 -07:00
|
|
|
inline void addType(JSContext *cx, Type type);
|
2011-03-15 23:50:44 -07:00
|
|
|
|
2011-04-11 20:10:46 -07:00
|
|
|
/* Mark this type set as representing an own property or configured property. */
|
|
|
|
inline void setOwnProperty(JSContext *cx, bool configured);
|
|
|
|
|
2011-04-05 18:12:03 -07:00
|
|
|
/*
|
|
|
|
* Iterate through the objects in this set. getObjectCount overapproximates
|
|
|
|
* in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
|
|
|
|
* may return NULL.
|
|
|
|
*/
|
|
|
|
inline unsigned getObjectCount();
|
2011-07-15 10:14:07 -07:00
|
|
|
inline TypeObjectKey *getObject(unsigned i);
|
|
|
|
inline JSObject *getSingleObject(unsigned i);
|
|
|
|
inline TypeObject *getTypeObject(unsigned i);
|
2011-05-12 20:07:23 -07:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
bool intermediate() { return !!(flags & TYPE_FLAG_INTERMEDIATE_SET); }
|
|
|
|
void setIntermediate() { JS_ASSERT(!flags); flags = TYPE_FLAG_INTERMEDIATE_SET; }
|
2011-04-12 20:39:16 -07:00
|
|
|
void setOwnProperty(bool configurable) {
|
2011-07-21 07:28:01 -07:00
|
|
|
flags |= TYPE_FLAG_OWN_PROPERTY;
|
2011-04-12 20:39:16 -07:00
|
|
|
if (configurable)
|
2011-07-21 07:28:01 -07:00
|
|
|
flags |= TYPE_FLAG_CONFIGURED_PROPERTY;
|
2011-04-12 20:39:16 -07:00
|
|
|
}
|
|
|
|
void setDefinite(unsigned slot) {
|
|
|
|
JS_ASSERT(slot <= (TYPE_FLAG_DEFINITE_MASK >> TYPE_FLAG_DEFINITE_SHIFT));
|
2011-07-21 07:28:01 -07:00
|
|
|
flags |= TYPE_FLAG_DEFINITE_PROPERTY | (slot << TYPE_FLAG_DEFINITE_SHIFT);
|
2011-04-12 20:39:16 -07:00
|
|
|
}
|
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
bool hasPropagatedProperty() { return !!(flags & TYPE_FLAG_PROPAGATED_PROPERTY); }
|
|
|
|
void setPropagatedProperty() { flags |= TYPE_FLAG_PROPAGATED_PROPERTY; }
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/* Add specific kinds of constraints to this set. */
|
2010-11-05 07:37:09 -07:00
|
|
|
inline void add(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
|
2011-07-15 10:14:07 -07:00
|
|
|
void addSubset(JSContext *cx, TypeSet *target);
|
2011-05-20 19:33:06 -07:00
|
|
|
void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
|
2010-12-28 11:53:50 -08:00
|
|
|
TypeSet *target, jsid id);
|
2011-05-20 19:33:06 -07:00
|
|
|
void addSetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
|
2010-12-28 11:53:50 -08:00
|
|
|
TypeSet *target, jsid id);
|
2011-05-27 14:21:37 -07:00
|
|
|
void addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id);
|
2010-10-29 08:05:55 -07:00
|
|
|
void addCall(JSContext *cx, TypeCallsite *site);
|
2011-07-15 10:14:07 -07:00
|
|
|
void addArith(JSContext *cx, TypeSet *target, TypeSet *other = NULL);
|
2010-12-28 11:53:50 -08:00
|
|
|
void addTransformThis(JSContext *cx, JSScript *script, TypeSet *target);
|
2011-07-15 10:14:07 -07:00
|
|
|
void addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc, Type type);
|
|
|
|
void addFilterPrimitives(JSContext *cx, TypeSet *target, bool onlyNullVoid);
|
2011-05-20 19:33:06 -07:00
|
|
|
void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
|
2011-07-15 10:14:07 -07:00
|
|
|
void addLazyArguments(JSContext *cx, TypeSet *target);
|
2011-03-01 13:10:05 -08:00
|
|
|
|
2010-11-05 07:37:09 -07:00
|
|
|
/*
|
|
|
|
* Make an intermediate type set with the specified debugging name,
|
|
|
|
* not embedded in another structure.
|
|
|
|
*/
|
2011-06-10 19:03:57 -07:00
|
|
|
static TypeSet *make(JSContext *cx, const char *name);
|
2010-11-05 07:37:09 -07:00
|
|
|
|
2010-11-03 15:07:49 -07:00
|
|
|
/*
|
2011-03-30 14:10:16 -07:00
|
|
|
* Methods for JIT compilation. If a script is currently being compiled
|
|
|
|
* (see AutoEnterCompilation) these will add constraints ensuring that if
|
|
|
|
* the return value change in the future due to new type information, the
|
|
|
|
* currently compiled script will be marked for recompilation.
|
2010-11-03 15:07:49 -07:00
|
|
|
*/
|
2011-03-11 16:29:38 -08:00
|
|
|
|
2011-03-27 18:25:05 -07:00
|
|
|
/* Completely freeze the contents of this type set. */
|
2011-03-30 14:10:16 -07:00
|
|
|
void addFreeze(JSContext *cx);
|
2011-03-27 18:25:05 -07:00
|
|
|
|
2011-03-11 16:29:38 -08:00
|
|
|
/* Get any type tag which all values in this set must have. */
|
2011-03-30 14:10:16 -07:00
|
|
|
JSValueType getKnownTypeTag(JSContext *cx);
|
2010-11-01 20:03:46 -07:00
|
|
|
|
2011-05-26 12:28:19 -07:00
|
|
|
bool isLazyArguments(JSContext *cx) { return getKnownTypeTag(cx) == JSVAL_TYPE_MAGIC; }
|
|
|
|
|
2011-05-10 23:33:30 -07:00
|
|
|
/* Whether the type set or a particular object has any of a set of flags. */
|
|
|
|
bool hasObjectFlags(JSContext *cx, TypeObjectFlags flags);
|
|
|
|
static bool HasObjectFlags(JSContext *cx, TypeObject *object, TypeObjectFlags flags);
|
2011-04-05 18:12:03 -07:00
|
|
|
|
2011-04-11 20:10:46 -07:00
|
|
|
/* Watch for slot reallocations on a particular object. */
|
|
|
|
static void WatchObjectReallocation(JSContext *cx, JSObject *object);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For type sets on a property, return true if the property has any 'own'
|
|
|
|
* values assigned. If configurable is set, return 'true' if the property
|
|
|
|
* has additionally been reconfigured as non-configurable, non-enumerable
|
|
|
|
* or non-writable (this only applies to properties that have changed after
|
|
|
|
* having been created, not to e.g. properties non-writable on creation).
|
|
|
|
*/
|
2011-07-21 07:28:01 -07:00
|
|
|
bool isOwnProperty(JSContext *cx, TypeObject *object, bool configurable);
|
2011-04-11 20:10:46 -07:00
|
|
|
|
2010-12-15 18:21:45 -08:00
|
|
|
/* Get whether this type set is non-empty. */
|
2011-03-30 14:10:16 -07:00
|
|
|
bool knownNonEmpty(JSContext *cx);
|
2011-03-09 11:04:36 -08:00
|
|
|
|
2011-07-14 07:42:37 -07:00
|
|
|
/*
|
|
|
|
* Get the typed array type of all objects in this set. Returns
|
|
|
|
* TypedArray::TYPE_MAX if the set contains different array types.
|
|
|
|
*/
|
|
|
|
int getTypedArrayType(JSContext *cx);
|
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
/* Get the single value which can appear in this type set, otherwise NULL. */
|
|
|
|
JSObject *getSingleton(JSContext *cx, bool freeze = true);
|
2011-05-12 09:49:04 -07:00
|
|
|
|
2011-05-18 12:34:17 -07:00
|
|
|
static bool
|
2011-07-15 10:14:07 -07:00
|
|
|
SweepTypeSet(JSContext *cx, JSCompartment *compartment, TypeSet *types);
|
2011-04-05 18:12:03 -07:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
inline void clearObjects();
|
|
|
|
|
2011-03-09 11:04:36 -08:00
|
|
|
private:
|
2011-07-21 07:28:01 -07:00
|
|
|
inline uint32 baseObjectCount() const;
|
|
|
|
inline void setBaseObjectCount(uint32 count);
|
2011-03-15 23:50:44 -07:00
|
|
|
};
|
|
|
|
|
2011-05-12 20:07:23 -07:00
|
|
|
/*
|
2011-07-21 07:28:01 -07:00
|
|
|
* Handler which persists information about dynamic types pushed within a
|
|
|
|
* script which can affect its behavior and are not covered by JOF_TYPESET ops,
|
|
|
|
* such as integer operations which overflow to a double. These persist across
|
|
|
|
* GCs and are regenerated when the script is reanalyzed.
|
2011-05-12 20:07:23 -07:00
|
|
|
*/
|
2011-07-21 07:28:01 -07:00
|
|
|
struct TypeResult
|
2011-05-12 20:07:23 -07:00
|
|
|
{
|
2011-07-21 07:28:01 -07:00
|
|
|
uint32 offset;
|
|
|
|
Type type;
|
|
|
|
TypeResult *next;
|
2011-07-07 20:04:47 -07:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
TypeResult(uint32 offset, Type type)
|
|
|
|
: offset(offset), type(type), next(NULL)
|
|
|
|
{}
|
2011-05-12 20:07:23 -07:00
|
|
|
};
|
|
|
|
|
2011-06-07 09:14:52 -07:00
|
|
|
/*
|
|
|
|
* Type barriers overview.
|
|
|
|
*
|
|
|
|
* Type barriers are a technique for using dynamic type information to improve
|
|
|
|
* the inferred types within scripts. At certain opcodes --- those with the
|
|
|
|
* JOF_TYPESET format --- we will construct a type set storing the set of types
|
|
|
|
* which we have observed to be pushed at that opcode, and will only use those
|
|
|
|
* observed types when doing propagation downstream from the bytecode. For
|
|
|
|
* example, in the following script:
|
|
|
|
*
|
|
|
|
* function foo(x) {
|
|
|
|
* return x.f + 10;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* Suppose we know the type of 'x' and that the type of its 'f' property is
|
|
|
|
* either an int or float. To account for all possible behaviors statically,
|
|
|
|
* we would mark the result of the 'x.f' access as an int or float, as well
|
|
|
|
* as the result of the addition and the return value of foo (and everywhere
|
|
|
|
* the result of 'foo' is used). When dealing with polymorphic code, this is
|
|
|
|
* undesirable behavior --- the type imprecision surrounding the polymorphism
|
|
|
|
* will tend to leak to many places in the program.
|
|
|
|
*
|
|
|
|
* Instead, we will keep track of the types that have been dynamically observed
|
|
|
|
* to have been produced by the 'x.f', and only use those observed types
|
|
|
|
* downstream from the access. If the 'x.f' has only ever produced integers,
|
|
|
|
* we will treat its result as an integer and mark the result of foo as an
|
|
|
|
* integer.
|
|
|
|
*
|
|
|
|
* The set of observed types will be a subset of the set of possible types,
|
|
|
|
* and if the two sets are different, a type barriers will be added at the
|
|
|
|
* bytecode which checks the dynamic result every time the bytecode executes
|
|
|
|
* and makes sure it is in the set of observed types. If it is not, that
|
|
|
|
* observed set is updated, and the new type information is automatically
|
|
|
|
* propagated along the already-generated type constraints to the places
|
|
|
|
* where the result of the bytecode is used.
|
|
|
|
*
|
|
|
|
* Observing new types at a bytecode removes type barriers at the bytecode
|
|
|
|
* (this removal happens lazily, see ScriptAnalysis::pruneTypeBarriers), and if
|
|
|
|
* all type barriers at a bytecode are removed --- the set of observed types
|
|
|
|
* grows to match the set of possible types --- then the result of the bytecode
|
|
|
|
* no longer needs to be dynamically checked (unless the set of possible types
|
|
|
|
* grows, triggering the generation of new type barriers).
|
|
|
|
*/
|
|
|
|
|
2011-05-14 05:45:13 -07:00
|
|
|
/*
|
|
|
|
* Barrier introduced at some bytecode. These are added when, during inference,
|
|
|
|
* we block a type from being propagated as would normally be done for a subset
|
|
|
|
* constraint. The propagation is technically possible, but we suspect it will
|
|
|
|
* not happen dynamically and this type needs to be watched for. These are only
|
|
|
|
* added at reads of properties and at scripted call sites.
|
|
|
|
*/
|
|
|
|
struct TypeBarrier
|
|
|
|
{
|
|
|
|
/* Next barrier on the same bytecode. */
|
|
|
|
TypeBarrier *next;
|
|
|
|
|
|
|
|
/* Target type set into which propagation was blocked. */
|
|
|
|
TypeSet *target;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Type which was not added to the target. If target ends up containing the
|
|
|
|
* type somehow, this barrier can be removed.
|
|
|
|
*/
|
2011-07-15 10:14:07 -07:00
|
|
|
Type type;
|
|
|
|
|
|
|
|
TypeBarrier(TypeSet *target, Type type)
|
|
|
|
: next(NULL), target(target), type(type)
|
|
|
|
{}
|
2011-05-14 05:45:13 -07:00
|
|
|
};
|
|
|
|
|
2010-11-24 17:41:52 -08:00
|
|
|
/* Type information about a property. */
|
|
|
|
struct Property
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2010-11-24 17:41:52 -08:00
|
|
|
/* Identifier for this property, JSID_VOID for the aggregate integer index property. */
|
|
|
|
jsid id;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2010-11-24 17:41:52 -08:00
|
|
|
/* Possible types for this property, including types inherited from prototypes. */
|
|
|
|
TypeSet types;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-03-01 13:10:05 -08:00
|
|
|
Property(jsid id)
|
|
|
|
: id(id)
|
2010-11-24 17:41:52 -08:00
|
|
|
{}
|
2010-11-20 15:45:52 -08:00
|
|
|
|
2010-11-24 17:41:52 -08:00
|
|
|
static uint32 keyBits(jsid id) { return (uint32) JSID_BITS(id); }
|
|
|
|
static jsid getKey(Property *p) { return p->id; }
|
2010-10-29 08:05:55 -07:00
|
|
|
};
|
|
|
|
|
2011-05-12 20:07:23 -07:00
|
|
|
/*
|
|
|
|
* Information attached to a TypeObject if it is always constructed using 'new'
|
2011-07-21 07:28:01 -07:00
|
|
|
* on a particular script. This is used to manage state related to the definite
|
|
|
|
* properties on the type object: these definite properties depend on type
|
|
|
|
* information which could change as the script executes (e.g. a scripted
|
|
|
|
* setter is added to a prototype object), and we need to ensure both that the
|
|
|
|
* appropriate type constraints are in place when necessary, and that we can
|
|
|
|
* remove the definite property information and repair the JS stack if the
|
|
|
|
* constraints are violated.
|
2011-05-12 20:07:23 -07:00
|
|
|
*/
|
|
|
|
struct TypeNewScript
|
|
|
|
{
|
|
|
|
JSScript *script;
|
|
|
|
|
|
|
|
/* Finalize kind to use for newly constructed objects. */
|
|
|
|
/* gc::FinalizeKind */ unsigned finalizeKind;
|
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
/*
|
|
|
|
* Shape to use for newly constructed objects. Reflects all definite
|
|
|
|
* properties the object will have.
|
|
|
|
*/
|
2011-05-12 20:07:23 -07:00
|
|
|
const Shape *shape;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Order in which properties become initialized. We need this in case a
|
2011-07-21 07:28:01 -07:00
|
|
|
* scripted setter is added to one of the object's prototypes while it is
|
|
|
|
* in the middle of being initialized, so we can walk the stack and fixup
|
|
|
|
* any objects which look for in-progress objects which were prematurely
|
|
|
|
* set with their final shape. Initialization can traverse stack frames,
|
2011-05-12 20:07:23 -07:00
|
|
|
* in which case FRAME_PUSH/FRAME_POP are used.
|
|
|
|
*/
|
|
|
|
struct Initializer {
|
|
|
|
enum Kind {
|
|
|
|
SETPROP,
|
|
|
|
FRAME_PUSH,
|
|
|
|
FRAME_POP,
|
|
|
|
DONE
|
|
|
|
} kind;
|
|
|
|
uint32 offset;
|
|
|
|
Initializer(Kind kind, uint32 offset)
|
|
|
|
: kind(kind), offset(offset)
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
Initializer *initializerList;
|
|
|
|
};
|
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
/*
|
|
|
|
* Lazy type objects overview.
|
|
|
|
*
|
|
|
|
* Type objects which represent at most one JS object are constructed lazily.
|
|
|
|
* These include types for native functions, standard classes, scripted
|
|
|
|
* functions defined at the top level of global/eval scripts, and in some
|
|
|
|
* other cases. Typical web workloads often create many windows (and many
|
|
|
|
* copies of standard natives) and many scripts, with comparatively few
|
|
|
|
* non-singleton types.
|
|
|
|
*
|
|
|
|
* We can recover the type information for the object from examining it
|
|
|
|
* (with exceptions for certain object flags, see OBJECT_FLAG_DETERMINED_MASK),
|
|
|
|
* so don't need to track type information when updating the object. The type
|
|
|
|
* object is only constructed when we need to put constraints on any of its
|
|
|
|
* properties, in which case we fully instantiate the type's properties.
|
|
|
|
*
|
|
|
|
* If all outgoing constraints on the type are removed constraints by a GC,
|
|
|
|
* the type object and its properties are destroyed and the JS object reverts
|
|
|
|
* to having a lazy type.
|
|
|
|
*/
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/* Type information about an object accessed by a script. */
|
2011-07-21 07:28:01 -07:00
|
|
|
struct TypeObject : gc::Cell
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2010-12-18 20:44:51 -08:00
|
|
|
#ifdef DEBUG
|
|
|
|
/* Name of this object. */
|
|
|
|
jsid name_;
|
2011-07-21 07:28:01 -07:00
|
|
|
#if JS_BITS_PER_WORD == 32
|
|
|
|
void *padding;
|
|
|
|
#endif
|
2010-12-18 20:44:51 -08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Prototype shared by objects using this type. */
|
|
|
|
JSObject *proto;
|
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
/*
|
|
|
|
* Whether there is a singleton JS object with this type. That JS object
|
|
|
|
* must appear in type sets instead of this; we include the back reference
|
|
|
|
* here to allow reverting the JS object to a lazy type.
|
|
|
|
*/
|
|
|
|
JSObject *singleton;
|
|
|
|
|
2010-12-18 20:44:51 -08:00
|
|
|
/* Lazily filled array of empty shapes for each size of objects with this type. */
|
|
|
|
js::EmptyShape **emptyShapes;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
/* Flags for this object. */
|
2011-04-05 18:12:03 -07:00
|
|
|
TypeObjectFlags flags;
|
|
|
|
|
2011-04-12 20:39:16 -07:00
|
|
|
/*
|
|
|
|
* If non-NULL, objects of this type have always been constructed using
|
2011-05-12 20:07:23 -07:00
|
|
|
* 'new' on the specified script, which adds some number of properties to
|
|
|
|
* the object in a definite order before the object escapes.
|
2011-04-12 20:39:16 -07:00
|
|
|
*/
|
2011-05-12 20:07:23 -07:00
|
|
|
TypeNewScript *newScript;
|
2011-04-12 20:39:16 -07:00
|
|
|
|
2011-03-09 11:04:36 -08:00
|
|
|
/*
|
|
|
|
* Estimate of the contribution of this object to the type sets it appears in.
|
|
|
|
* This is the sum of the sizes of those sets at the point when the object
|
|
|
|
* was added.
|
|
|
|
*
|
|
|
|
* When the contribution exceeds the CONTRIBUTION_LIMIT, any type sets the
|
|
|
|
* object is added to are instead marked as unknown. If we get to this point
|
|
|
|
* we are probably not adding types which will let us do meaningful optimization
|
|
|
|
* later, and we want to ensure in such cases that our time/space complexity
|
|
|
|
* is linear, not worst-case cubic as it would otherwise be.
|
|
|
|
*/
|
|
|
|
uint32 contribution;
|
2011-06-11 09:46:48 -07:00
|
|
|
static const uint32 CONTRIBUTION_LIMIT = 2000;
|
2011-03-09 11:04:36 -08:00
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/*
|
2011-05-16 16:15:37 -07:00
|
|
|
* Properties of this object. This may contain JSID_VOID, representing the
|
2011-07-21 07:28:01 -07:00
|
|
|
* types of all integer indexes of the object, and/or JSID_EMPTY, holding
|
|
|
|
* constraints listening to changes to the object's state. Correspondence
|
|
|
|
* between the properties of a TypeObject and the properties of
|
|
|
|
* script-visible JSObjects (not Call, Block, etc.) which have that type is
|
|
|
|
* as follows:
|
2011-05-16 16:15:37 -07:00
|
|
|
*
|
|
|
|
* - If the type has unknownProperties(), the possible properties and value
|
|
|
|
* types for associated JSObjects are unknown.
|
|
|
|
*
|
|
|
|
* - Otherwise, for any JSObject obj with TypeObject type, and any jsid id,
|
|
|
|
* after obj->getProperty(id) the property in type for id must reflect
|
|
|
|
* the result of the getProperty. The result is additionally allowed to
|
|
|
|
* be undefined for ids which are not in obj or its prototypes, and for
|
|
|
|
* properties of global objects defined with 'var' but not yet written.
|
|
|
|
*
|
|
|
|
* - Additionally, if id is a normal owned native property within obj, then
|
|
|
|
* after the setProperty or defineProperty which wrote its value, the
|
|
|
|
* property in type for id must reflect that type.
|
|
|
|
*
|
|
|
|
* We establish these by using write barriers on calls to setProperty and
|
|
|
|
* defineProperty which are on native properties, and read barriers on
|
|
|
|
* getProperty that go through a class hook or special PropertyOp.
|
2010-10-29 08:05:55 -07:00
|
|
|
*/
|
2010-11-24 17:41:52 -08:00
|
|
|
Property **propertySet;
|
|
|
|
|
2011-06-10 19:03:57 -07:00
|
|
|
/* If this is an interpreted function, the corresponding script. */
|
|
|
|
JSScript *functionScript;
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/* Make an object with the specified name. */
|
2011-07-21 07:28:01 -07:00
|
|
|
inline TypeObject(jsid id, JSObject *proto, bool isFunction, bool unknown);
|
|
|
|
|
|
|
|
bool isFunction() { return !!(flags & OBJECT_FLAG_FUNCTION); }
|
|
|
|
|
|
|
|
bool hasAnyFlags(TypeObjectFlags flags) {
|
|
|
|
JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
|
|
|
|
return !!(this->flags & flags);
|
|
|
|
}
|
|
|
|
bool hasAllFlags(TypeObjectFlags flags) {
|
|
|
|
JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
|
|
|
|
return (this->flags & flags) == flags;
|
|
|
|
}
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
bool unknownProperties() {
|
|
|
|
JS_ASSERT_IF(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES,
|
|
|
|
hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK));
|
|
|
|
return !!(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES);
|
|
|
|
}
|
2011-04-05 18:12:03 -07:00
|
|
|
|
2010-12-18 20:44:51 -08:00
|
|
|
/*
|
|
|
|
* Return an immutable, shareable, empty shape with the same clasp as this
|
|
|
|
* and the same slotSpan as this had when empty.
|
|
|
|
*
|
|
|
|
* If |this| is the scope of an object |proto|, the resulting scope can be
|
|
|
|
* used as the scope of a new object whose prototype is |proto|.
|
|
|
|
*/
|
|
|
|
inline bool canProvideEmptyShape(js::Class *clasp);
|
|
|
|
inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp,
|
|
|
|
/* gc::FinalizeKind */ unsigned kind);
|
|
|
|
|
2010-11-24 17:41:52 -08:00
|
|
|
/*
|
|
|
|
* Get or create a property of this object. Only call this for properties which
|
|
|
|
* a script accesses explicitly. 'assign' indicates whether this is for an
|
|
|
|
* assignment, and the own types of the property will be used instead of
|
|
|
|
* aggregate types.
|
|
|
|
*/
|
|
|
|
inline TypeSet *getProperty(JSContext *cx, jsid id, bool assign);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
/* Get a property only if it already exists. */
|
|
|
|
inline TypeSet *maybeGetProperty(JSContext *cx, jsid id);
|
2010-12-18 20:44:51 -08:00
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
inline const char * name();
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-04-05 18:12:03 -07:00
|
|
|
inline unsigned getPropertyCount();
|
|
|
|
inline Property *getProperty(unsigned i);
|
|
|
|
|
2011-06-15 11:26:12 -07:00
|
|
|
/* Set flags on this object which are implied by the specified key. */
|
2011-07-21 07:28:01 -07:00
|
|
|
inline void setFlagsFromKey(JSContext *cx, JSProtoKey kind);
|
2011-06-15 11:26:12 -07:00
|
|
|
|
2010-11-24 17:41:52 -08:00
|
|
|
/* Helpers */
|
2010-11-20 15:45:52 -08:00
|
|
|
|
2011-03-03 14:07:48 -08:00
|
|
|
bool addProperty(JSContext *cx, jsid id, Property **pprop);
|
2011-05-12 20:07:23 -07:00
|
|
|
bool addDefiniteProperties(JSContext *cx, JSObject *obj);
|
2011-07-21 07:28:01 -07:00
|
|
|
bool matchDefiniteProperties(JSObject *obj);
|
2010-11-24 17:41:52 -08:00
|
|
|
void addPrototype(JSContext *cx, TypeObject *proto);
|
2011-07-15 10:14:07 -07:00
|
|
|
void addPropertyType(JSContext *cx, jsid id, Type type);
|
2011-06-02 10:40:27 -07:00
|
|
|
void addPropertyType(JSContext *cx, jsid id, const Value &value);
|
2011-07-15 10:14:07 -07:00
|
|
|
void addPropertyType(JSContext *cx, const char *name, Type type);
|
2011-06-02 10:40:27 -07:00
|
|
|
void addPropertyType(JSContext *cx, const char *name, const Value &value);
|
|
|
|
void markPropertyConfigured(JSContext *cx, jsid id);
|
|
|
|
void markSlotReallocation(JSContext *cx);
|
2011-04-05 18:12:03 -07:00
|
|
|
void setFlags(JSContext *cx, TypeObjectFlags flags);
|
2010-11-24 17:41:52 -08:00
|
|
|
void markUnknown(JSContext *cx);
|
2011-04-12 20:39:16 -07:00
|
|
|
void clearNewScript(JSContext *cx);
|
2011-07-21 07:28:01 -07:00
|
|
|
void getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force = false);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2010-11-18 15:18:23 -08:00
|
|
|
void print(JSContext *cx);
|
2011-07-21 07:28:01 -07:00
|
|
|
void trace(JSTracer *trc, bool weak = false);
|
|
|
|
|
|
|
|
inline void clearProperties();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Type objects don't have explicit finalizers. Memory owned by a type
|
|
|
|
* object pending deletion is released when weak references are sweeped
|
|
|
|
* from all the compartment's type objects.
|
|
|
|
*/
|
|
|
|
void finalize(JSContext *cx) {}
|
|
|
|
|
|
|
|
private:
|
|
|
|
inline uint32 basePropertyCount() const;
|
|
|
|
inline void setBasePropertyCount(uint32 count);
|
2010-10-29 08:05:55 -07:00
|
|
|
};
|
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
/* Global singleton for the generic type of objects with no prototype. */
|
|
|
|
extern TypeObject emptyTypeObject;
|
2011-06-03 20:48:16 -07:00
|
|
|
|
|
|
|
/*
|
2011-07-21 07:28:01 -07:00
|
|
|
* Call to mark a script's arguments as having been created, recompile any
|
|
|
|
* dependencies and walk the stack if necessary to fix any lazy arguments.
|
2011-06-03 20:48:16 -07:00
|
|
|
*/
|
2011-07-21 07:28:01 -07:00
|
|
|
extern void
|
|
|
|
MarkArgumentsCreated(JSContext *cx, JSScript *script);
|
|
|
|
|
|
|
|
/* Whether to use a new type object when calling 'new' at script/pc. */
|
|
|
|
bool
|
|
|
|
UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc);
|
2011-06-03 20:48:16 -07:00
|
|
|
|
2010-12-28 11:53:50 -08:00
|
|
|
/*
|
|
|
|
* Type information about a callsite. this is separated from the bytecode
|
|
|
|
* information itself so we can handle higher order functions not called
|
|
|
|
* directly via a bytecode.
|
|
|
|
*/
|
|
|
|
struct TypeCallsite
|
|
|
|
{
|
|
|
|
JSScript *script;
|
2011-05-20 19:33:06 -07:00
|
|
|
jsbytecode *pc;
|
2010-12-28 11:53:50 -08:00
|
|
|
|
|
|
|
/* Whether this is a 'NEW' call. */
|
|
|
|
bool isNew;
|
|
|
|
|
|
|
|
/* Types of each argument to the call. */
|
|
|
|
TypeSet **argumentTypes;
|
|
|
|
unsigned argumentCount;
|
|
|
|
|
|
|
|
/* Types of the this variable. */
|
|
|
|
TypeSet *thisTypes;
|
|
|
|
|
|
|
|
/* Type set receiving the return value of this call. */
|
|
|
|
TypeSet *returnTypes;
|
|
|
|
|
2011-05-20 19:33:06 -07:00
|
|
|
inline TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
|
2010-12-28 11:53:50 -08:00
|
|
|
bool isNew, unsigned argumentCount);
|
2011-06-06 08:32:41 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Persistent type information for a script, retained across GCs. */
|
|
|
|
struct TypeScript
|
|
|
|
{
|
|
|
|
inline JSScript *script();
|
|
|
|
|
|
|
|
/* Lazily constructed types of variables and JOF_TYPESET ops in this script. */
|
|
|
|
TypeSet *typeArray;
|
|
|
|
inline unsigned numTypeSets();
|
|
|
|
|
|
|
|
/* Any type objects associated with this script, including initializer objects. */
|
|
|
|
TypeObject *typeObjects;
|
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
/* Dynamic types generated at points within this script. */
|
|
|
|
TypeResult *dynamicList;
|
2011-06-06 08:32:41 -07:00
|
|
|
|
|
|
|
/* Make sure there the type array has been constructed. */
|
|
|
|
inline bool ensureTypeArray(JSContext *cx);
|
|
|
|
|
|
|
|
inline TypeSet *bytecodeTypes(const jsbytecode *pc);
|
|
|
|
inline TypeSet *returnTypes();
|
|
|
|
inline TypeSet *thisTypes();
|
|
|
|
inline TypeSet *argTypes(unsigned i);
|
|
|
|
inline TypeSet *localTypes(unsigned i);
|
|
|
|
inline TypeSet *upvarTypes(unsigned i);
|
2010-12-28 11:53:50 -08:00
|
|
|
|
2011-06-06 08:32:41 -07:00
|
|
|
/* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
|
|
|
|
inline TypeSet *slotTypes(unsigned slot);
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool makeTypeArray(JSContext *cx);
|
|
|
|
public:
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
/* Check that correct types were inferred for the values pushed by this bytecode. */
|
|
|
|
void checkBytecode(JSContext *cx, jsbytecode *pc, const js::Value *sp);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Get the default 'new' object for a given standard class, per the script's global. */
|
2011-07-21 07:28:01 -07:00
|
|
|
inline TypeObject *standardType(JSContext *cx, JSProtoKey kind);
|
2011-06-06 08:32:41 -07:00
|
|
|
|
|
|
|
/* Get a type object for an allocation site in this script. */
|
2011-07-21 07:28:01 -07:00
|
|
|
inline TypeObject *initObject(JSContext *cx, const jsbytecode *pc, JSProtoKey kind);
|
2011-06-06 08:32:41 -07:00
|
|
|
|
2011-06-07 09:14:52 -07:00
|
|
|
/*
|
|
|
|
* Monitor a bytecode pushing a value which is not accounted for by the
|
|
|
|
* inference type constraints, such as integer overflow.
|
|
|
|
*/
|
2011-06-06 08:32:41 -07:00
|
|
|
inline void monitorOverflow(JSContext *cx, jsbytecode *pc);
|
|
|
|
inline void monitorString(JSContext *cx, jsbytecode *pc);
|
|
|
|
inline void monitorUnknown(JSContext *cx, jsbytecode *pc);
|
|
|
|
|
2011-06-07 09:14:52 -07:00
|
|
|
/*
|
|
|
|
* Monitor a bytecode pushing any value. This must be called for any opcode
|
|
|
|
* which is JOF_TYPESET, and where either the script has not been analyzed
|
|
|
|
* by type inference or where the pc has type barriers. For simplicity, we
|
|
|
|
* always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
|
|
|
|
* and only look at barriers when generating JIT code for the script.
|
|
|
|
*/
|
2011-06-06 08:32:41 -07:00
|
|
|
inline void monitor(JSContext *cx, jsbytecode *pc, const js::Value &val);
|
|
|
|
|
|
|
|
/* Monitor an assignment at a SETELEM on a non-integer identifier. */
|
|
|
|
inline void monitorAssign(JSContext *cx, jsbytecode *pc,
|
|
|
|
JSObject *obj, jsid id, const js::Value &val);
|
|
|
|
|
|
|
|
/* Add a type for a variable in this script. */
|
2011-07-15 10:14:07 -07:00
|
|
|
inline void setThis(JSContext *cx, Type type);
|
2011-06-06 08:32:41 -07:00
|
|
|
inline void setThis(JSContext *cx, const js::Value &value);
|
2011-07-15 10:14:07 -07:00
|
|
|
inline void setLocal(JSContext *cx, unsigned local, Type type);
|
2011-06-06 08:32:41 -07:00
|
|
|
inline void setLocal(JSContext *cx, unsigned local, const js::Value &value);
|
2011-07-15 10:14:07 -07:00
|
|
|
inline void setArgument(JSContext *cx, unsigned arg, Type type);
|
2011-06-06 08:32:41 -07:00
|
|
|
inline void setArgument(JSContext *cx, unsigned arg, const js::Value &value);
|
|
|
|
inline void setUpvar(JSContext *cx, unsigned upvar, const js::Value &value);
|
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
void sweep(JSContext *cx);
|
|
|
|
void destroy();
|
2010-12-28 11:53:50 -08:00
|
|
|
};
|
|
|
|
|
2011-03-10 16:17:39 -08:00
|
|
|
struct ArrayTableKey;
|
2011-03-10 19:25:49 -08:00
|
|
|
typedef HashMap<ArrayTableKey,TypeObject*,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable;
|
2011-03-10 16:17:39 -08:00
|
|
|
|
|
|
|
struct ObjectTableKey;
|
|
|
|
struct ObjectTableEntry;
|
2011-03-10 19:25:49 -08:00
|
|
|
typedef HashMap<ObjectTableKey,ObjectTableEntry,ObjectTableKey,SystemAllocPolicy> ObjectTypeTable;
|
2011-03-10 16:17:39 -08:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
struct AllocationSiteKey;
|
|
|
|
typedef HashMap<AllocationSiteKey,TypeObject*,AllocationSiteKey,SystemAllocPolicy> AllocationSiteTable;
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/* Type information for a compartment. */
|
|
|
|
struct TypeCompartment
|
|
|
|
{
|
2011-03-03 14:07:48 -08:00
|
|
|
/* Whether type inference is enabled in this compartment. */
|
|
|
|
bool inferenceEnabled;
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/* Number of scripts in this compartment. */
|
|
|
|
unsigned scriptCount;
|
|
|
|
|
2011-03-03 14:07:48 -08:00
|
|
|
/*
|
|
|
|
* Bit set if all current types must be marked as unknown, and all scripts
|
|
|
|
* recompiled. Caused by OOM failure within inference operations.
|
|
|
|
*/
|
|
|
|
bool pendingNukeTypes;
|
|
|
|
|
2010-11-18 08:28:05 -08:00
|
|
|
/* Pending recompilations to perform before execution of JIT code can resume. */
|
|
|
|
Vector<JSScript*> *pendingRecompiles;
|
|
|
|
|
2011-03-29 18:51:15 -07:00
|
|
|
/*
|
|
|
|
* Number of recompilation events and inline frame expansions that have
|
|
|
|
* occurred in this compartment. If these change, code should not count on
|
|
|
|
* compiled code or the current stack being intact.
|
|
|
|
*/
|
|
|
|
unsigned recompilations;
|
|
|
|
unsigned frameExpansions;
|
|
|
|
|
2011-03-30 14:10:16 -07:00
|
|
|
/*
|
|
|
|
* Script currently being compiled. All constraints which look for type
|
|
|
|
* changes inducing recompilation are keyed to this script. Note: script
|
|
|
|
* compilation is not reentrant.
|
|
|
|
*/
|
|
|
|
JSScript *compiledScript;
|
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
/* Table for referencing types of objects keyed to an allocation site. */
|
|
|
|
AllocationSiteTable *allocationSiteTable;
|
|
|
|
|
2011-03-10 16:17:39 -08:00
|
|
|
/* Tables for determining types of singleton/JSON objects. */
|
|
|
|
|
|
|
|
ArrayTypeTable *arrayTypeTable;
|
|
|
|
ObjectTypeTable *objectTypeTable;
|
|
|
|
|
2011-05-09 07:12:47 -07:00
|
|
|
void fixArrayType(JSContext *cx, JSObject *obj);
|
|
|
|
void fixObjectType(JSContext *cx, JSObject *obj);
|
2011-03-10 16:17:39 -08:00
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/* Constraint solving worklist structures. */
|
|
|
|
|
2011-04-07 16:12:37 -07:00
|
|
|
/*
|
|
|
|
* Worklist of types which need to be propagated to constraints. We use a
|
|
|
|
* worklist to avoid blowing the native stack.
|
|
|
|
*/
|
2010-10-29 08:05:55 -07:00
|
|
|
struct PendingWork
|
|
|
|
{
|
|
|
|
TypeConstraint *constraint;
|
|
|
|
TypeSet *source;
|
2011-07-15 10:14:07 -07:00
|
|
|
Type type;
|
2010-10-29 08:05:55 -07:00
|
|
|
};
|
|
|
|
PendingWork *pendingArray;
|
|
|
|
unsigned pendingCount;
|
|
|
|
unsigned pendingCapacity;
|
|
|
|
|
|
|
|
/* Whether we are currently resolving the pending worklist. */
|
|
|
|
bool resolving;
|
|
|
|
|
|
|
|
/* Logging fields */
|
|
|
|
|
|
|
|
/* Counts of stack type sets with some number of possible operand types. */
|
|
|
|
static const unsigned TYPE_COUNT_LIMIT = 4;
|
|
|
|
unsigned typeCounts[TYPE_COUNT_LIMIT];
|
|
|
|
unsigned typeCountOver;
|
|
|
|
|
2011-03-03 14:07:48 -08:00
|
|
|
void init(JSContext *cx);
|
2011-03-10 16:17:39 -08:00
|
|
|
~TypeCompartment();
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
inline JSCompartment *compartment();
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/* Add a type to register with a list of constraints. */
|
2011-07-15 10:14:07 -07:00
|
|
|
inline void addPending(JSContext *cx, TypeConstraint *constraint, TypeSet *source, Type type);
|
2011-03-01 13:10:05 -08:00
|
|
|
void growPendingArray(JSContext *cx);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
|
|
|
/* Resolve pending type registrations, excluding delayed ones. */
|
|
|
|
inline void resolvePending(JSContext *cx);
|
|
|
|
|
2010-11-18 15:18:23 -08:00
|
|
|
/* Prints results of this compartment if spew is enabled, checks for warnings. */
|
2011-07-21 07:28:01 -07:00
|
|
|
void print(JSContext *cx);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-06-15 11:26:12 -07:00
|
|
|
/*
|
|
|
|
* Make a function or non-function object associated with an optional
|
|
|
|
* script. The 'key' parameter here may be an array, typed array, function
|
|
|
|
* or JSProto_Object to indicate a type whose class is unknown (not just
|
|
|
|
* js_ObjectClass).
|
|
|
|
*/
|
2011-03-01 13:10:05 -08:00
|
|
|
TypeObject *newTypeObject(JSContext *cx, JSScript *script,
|
2011-05-19 09:15:12 -07:00
|
|
|
const char *base, const char *postfix,
|
2011-07-21 07:28:01 -07:00
|
|
|
JSProtoKey kind, JSObject *proto, bool unknown = false);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
/* Make an object for an allocation site. */
|
|
|
|
TypeObject *newAllocationSiteTypeObject(JSContext *cx, const AllocationSiteKey &key);
|
2010-12-28 11:53:50 -08:00
|
|
|
|
2011-05-09 07:12:47 -07:00
|
|
|
void nukeTypes(JSContext *cx);
|
|
|
|
void processPendingRecompiles(JSContext *cx);
|
2011-03-03 14:07:48 -08:00
|
|
|
|
|
|
|
/* Mark all types as needing destruction once inference has 'finished'. */
|
|
|
|
void setPendingNukeTypes(JSContext *cx);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-03-03 14:07:48 -08:00
|
|
|
/* Mark a script as needing recompilation once inference has finished. */
|
2010-11-18 08:28:05 -08:00
|
|
|
void addPendingRecompile(JSContext *cx, JSScript *script);
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/* Monitor future effects on a bytecode. */
|
2011-06-10 19:03:57 -07:00
|
|
|
void monitorBytecode(JSContext *cx, JSScript *script, uint32 offset,
|
|
|
|
bool returnOnly = false);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
/* Mark any type set containing obj as having a generic object type. */
|
|
|
|
void markSetsUnknown(JSContext *cx, TypeObject *obj);
|
|
|
|
|
2011-03-09 09:58:49 -08:00
|
|
|
void sweep(JSContext *cx);
|
2011-07-15 10:14:07 -07:00
|
|
|
void finalizeObjects();
|
2011-03-09 09:58:49 -08:00
|
|
|
};
|
2011-03-01 13:10:05 -08:00
|
|
|
|
2010-11-18 15:18:23 -08:00
|
|
|
enum SpewChannel {
|
|
|
|
ISpewOps, /* ops: New constraints and types. */
|
|
|
|
ISpewResult, /* result: Final type sets. */
|
|
|
|
SPEW_COUNT
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
2011-06-22 17:28:19 -07:00
|
|
|
const char * InferSpewColorReset();
|
2011-06-15 19:22:27 -07:00
|
|
|
const char * InferSpewColor(TypeConstraint *constraint);
|
|
|
|
const char * InferSpewColor(TypeSet *types);
|
|
|
|
|
2010-11-18 15:18:23 -08:00
|
|
|
void InferSpew(SpewChannel which, const char *fmt, ...);
|
2011-07-15 10:14:07 -07:00
|
|
|
const char * TypeString(Type type);
|
2011-05-26 12:28:19 -07:00
|
|
|
|
2011-03-06 15:35:09 -08:00
|
|
|
/* Check that the type property for id in obj contains value. */
|
|
|
|
bool TypeHasProperty(JSContext *cx, TypeObject *obj, jsid id, const Value &value);
|
|
|
|
|
2010-11-18 15:18:23 -08:00
|
|
|
#else
|
|
|
|
|
2011-06-15 19:22:27 -07:00
|
|
|
inline const char * InferSpewColorReset() { return NULL; }
|
|
|
|
inline const char * InferSpewColor(TypeConstraint *constraint) { return NULL; }
|
|
|
|
inline const char * InferSpewColor(TypeSet *types) { return NULL; }
|
2010-11-18 15:18:23 -08:00
|
|
|
inline void InferSpew(SpewChannel which, const char *fmt, ...) {}
|
2011-07-15 10:14:07 -07:00
|
|
|
inline const char * TypeString(Type type) { return NULL; }
|
2010-11-18 15:18:23 -08:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2010-11-20 15:45:52 -08:00
|
|
|
/* Print a warning, dump state and abort the program. */
|
|
|
|
void TypeFailure(JSContext *cx, const char *fmt, ...);
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
} /* namespace types */
|
|
|
|
} /* namespace js */
|
|
|
|
|
|
|
|
#endif // jsinfer_h___
|