2013-04-16 13:47:10 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
2012-05-21 04:12:37 -07:00
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2010-11-01 20:03:46 -07:00
|
|
|
/* Inline members for javascript type inference. */
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2013-06-25 21:38:35 -07:00
|
|
|
#ifndef jsinferinlines_h
|
|
|
|
#define jsinferinlines_h
|
|
|
|
|
2013-07-23 17:34:18 -07:00
|
|
|
#include "jsinfer.h"
|
|
|
|
|
2013-04-01 22:43:19 -07:00
|
|
|
#include "mozilla/PodOperations.h"
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
#include "jsanalyze.h"
|
2012-05-01 14:30:18 -07:00
|
|
|
|
2013-10-03 20:44:13 -07:00
|
|
|
#include "jit/ExecutionModeInlines.h"
|
2013-06-18 23:55:38 -07:00
|
|
|
#include "vm/ArrayObject.h"
|
2013-06-17 03:18:55 -07:00
|
|
|
#include "vm/BooleanObject.h"
|
|
|
|
#include "vm/NumberObject.h"
|
2014-02-20 14:43:03 -08:00
|
|
|
#include "vm/SharedArrayObject.h"
|
2013-06-17 03:18:55 -07:00
|
|
|
#include "vm/StringObject.h"
|
2013-07-02 20:58:39 -07:00
|
|
|
#include "vm/TypedArrayObject.h"
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2013-06-25 21:38:35 -07:00
|
|
|
#include "jscntxtinlines.h"
|
2013-06-06 17:48:12 -07:00
|
|
|
|
2012-07-16 14:19:26 -07:00
|
|
|
namespace js {
|
|
|
|
namespace types {
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
2012-07-16 14:19:26 -07:00
|
|
|
// CompilerOutput & RecompileInfo
|
2010-10-29 08:05:55 -07:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
2013-08-27 03:50:16 -07:00
|
|
|
inline jit::IonScript *
|
2012-08-14 16:30:07 -07:00
|
|
|
CompilerOutput::ion() const
|
|
|
|
{
|
2012-11-06 10:50:19 -08:00
|
|
|
#ifdef JS_ION
|
2013-10-03 20:44:13 -07:00
|
|
|
// Note: If type constraints are generated before compilation has finished
|
|
|
|
// (i.e. after IonBuilder but before CodeGenerator::link) then a valid
|
|
|
|
// CompilerOutput may not yet have an associated IonScript.
|
2013-05-13 16:47:57 -07:00
|
|
|
JS_ASSERT(isValid());
|
2013-10-03 20:44:13 -07:00
|
|
|
jit::IonScript *ion = jit::GetIonScript(script(), mode());
|
|
|
|
JS_ASSERT(ion != ION_COMPILING_SCRIPT);
|
|
|
|
return ion;
|
2012-11-06 10:50:19 -08:00
|
|
|
#endif
|
2013-06-28 19:20:12 -07:00
|
|
|
MOZ_ASSUME_UNREACHABLE("Invalid kind of CompilerOutput");
|
2012-07-16 14:19:26 -07:00
|
|
|
}
|
|
|
|
|
2012-08-14 16:30:07 -07:00
|
|
|
inline CompilerOutput*
|
2013-12-12 13:10:54 -08:00
|
|
|
RecompileInfo::compilerOutput(TypeZone &types) const
|
2012-08-14 16:30:07 -07:00
|
|
|
{
|
2013-12-12 13:10:54 -08:00
|
|
|
if (!types.compilerOutputs || outputIndex >= types.compilerOutputs->length())
|
2013-10-07 09:43:32 -07:00
|
|
|
return nullptr;
|
2013-12-12 13:10:54 -08:00
|
|
|
return &(*types.compilerOutputs)[outputIndex];
|
2012-08-14 16:30:07 -07:00
|
|
|
}
|
|
|
|
|
2012-07-16 14:19:26 -07:00
|
|
|
inline CompilerOutput*
|
|
|
|
RecompileInfo::compilerOutput(JSContext *cx) const
|
|
|
|
{
|
2013-12-12 13:10:54 -08:00
|
|
|
return compilerOutput(cx->zone()->types);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
RecompileInfo::shouldSweep(TypeZone &types)
|
|
|
|
{
|
|
|
|
CompilerOutput *output = compilerOutput(types);
|
|
|
|
if (!output || !output->isValid())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Update this info for the output's new index in the zone's compiler outputs.
|
|
|
|
outputIndex = output->sweepIndex();
|
|
|
|
return false;
|
2012-07-16 14:19:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
// Types
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
/* static */ inline Type
|
2013-04-30 15:41:12 -07:00
|
|
|
Type::ObjectType(JSObject *obj)
|
2011-07-15 10:14:07 -07:00
|
|
|
{
|
|
|
|
if (obj->hasSingletonType())
|
2012-01-11 00:23:05 -08:00
|
|
|
return Type(uintptr_t(obj) | 1);
|
|
|
|
return Type(uintptr_t(obj->type()));
|
2011-07-15 10:14:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ inline Type
|
|
|
|
Type::ObjectType(TypeObject *obj)
|
|
|
|
{
|
2013-12-19 10:01:25 -08:00
|
|
|
if (obj->singleton())
|
|
|
|
return Type(uintptr_t(obj->singleton()) | 1);
|
2012-01-11 00:23:05 -08:00
|
|
|
return Type(uintptr_t(obj));
|
2011-07-15 10:14:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ inline Type
|
|
|
|
Type::ObjectType(TypeObjectKey *obj)
|
|
|
|
{
|
2012-01-11 00:23:05 -08:00
|
|
|
return Type(uintptr_t(obj));
|
2011-07-15 10:14:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline Type
|
2013-08-22 06:13:18 -07:00
|
|
|
GetValueType(const Value &val)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
|
|
|
if (val.isDouble())
|
2011-07-15 10:14:07 -07:00
|
|
|
return Type::DoubleType();
|
|
|
|
if (val.isObject())
|
|
|
|
return Type::ObjectType(&val.toObject());
|
|
|
|
return Type::PrimitiveType(val.extractNonDoubleType());
|
|
|
|
}
|
|
|
|
|
|
|
|
inline TypeFlags
|
|
|
|
PrimitiveTypeFlag(JSValueType type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
2010-10-29 08:05:55 -07:00
|
|
|
case JSVAL_TYPE_UNDEFINED:
|
2011-07-15 10:14:07 -07:00
|
|
|
return TYPE_FLAG_UNDEFINED;
|
|
|
|
case JSVAL_TYPE_NULL:
|
|
|
|
return TYPE_FLAG_NULL;
|
2010-10-29 08:05:55 -07:00
|
|
|
case JSVAL_TYPE_BOOLEAN:
|
2011-07-15 10:14:07 -07:00
|
|
|
return TYPE_FLAG_BOOLEAN;
|
|
|
|
case JSVAL_TYPE_INT32:
|
|
|
|
return TYPE_FLAG_INT32;
|
|
|
|
case JSVAL_TYPE_DOUBLE:
|
|
|
|
return TYPE_FLAG_DOUBLE;
|
2010-10-29 08:05:55 -07:00
|
|
|
case JSVAL_TYPE_STRING:
|
2011-07-15 10:14:07 -07:00
|
|
|
return TYPE_FLAG_STRING;
|
2011-05-26 12:28:19 -07:00
|
|
|
case JSVAL_TYPE_MAGIC:
|
2011-07-15 10:14:07 -07:00
|
|
|
return TYPE_FLAG_LAZYARGS;
|
2010-10-29 08:05:55 -07:00
|
|
|
default:
|
2013-06-28 19:20:12 -07:00
|
|
|
MOZ_ASSUME_UNREACHABLE("Bad type");
|
2011-07-15 10:14:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline JSValueType
|
|
|
|
TypeFlagPrimitive(TypeFlags flags)
|
|
|
|
{
|
|
|
|
switch (flags) {
|
|
|
|
case TYPE_FLAG_UNDEFINED:
|
|
|
|
return JSVAL_TYPE_UNDEFINED;
|
|
|
|
case TYPE_FLAG_NULL:
|
|
|
|
return JSVAL_TYPE_NULL;
|
|
|
|
case TYPE_FLAG_BOOLEAN:
|
|
|
|
return JSVAL_TYPE_BOOLEAN;
|
|
|
|
case TYPE_FLAG_INT32:
|
|
|
|
return JSVAL_TYPE_INT32;
|
|
|
|
case TYPE_FLAG_DOUBLE:
|
|
|
|
return JSVAL_TYPE_DOUBLE;
|
|
|
|
case TYPE_FLAG_STRING:
|
|
|
|
return JSVAL_TYPE_STRING;
|
|
|
|
case TYPE_FLAG_LAZYARGS:
|
|
|
|
return JSVAL_TYPE_MAGIC;
|
|
|
|
default:
|
2013-06-28 19:20:12 -07:00
|
|
|
MOZ_ASSUME_UNREACHABLE("Bad type");
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the canonical representation of an id to use when doing inference. This
|
|
|
|
* maintains the constraint that if two different jsids map to the same property
|
|
|
|
* in JS (e.g. 3 and "3"), they have the same type representation.
|
|
|
|
*/
|
2013-04-30 15:41:04 -07:00
|
|
|
inline jsid
|
|
|
|
IdToTypeId(jsid id)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2011-05-20 19:33:06 -07:00
|
|
|
JS_ASSERT(!JSID_IS_EMPTY(id));
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/*
|
|
|
|
* All integers must map to the aggregate property for index types, including
|
|
|
|
* negative integers.
|
|
|
|
*/
|
|
|
|
if (JSID_IS_INT(id))
|
2013-12-16 18:27:43 -08:00
|
|
|
return JSID_VOID;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for numeric strings, as in js_StringIsIndex, but allow negative
|
2010-12-18 20:44:51 -08:00
|
|
|
* and overflowing integers.
|
2010-10-29 08:05:55 -07:00
|
|
|
*/
|
|
|
|
if (JSID_IS_STRING(id)) {
|
2013-12-19 10:01:25 -08:00
|
|
|
JSAtom *atom = JSID_TO_ATOM(id);
|
|
|
|
JS::TwoByteChars cp = atom->range();
|
2013-12-09 15:07:31 -08:00
|
|
|
if (cp.length() > 0 && (JS7_ISDEC(cp[0]) || cp[0] == '-')) {
|
2012-11-09 09:45:25 -08:00
|
|
|
for (size_t i = 1; i < cp.length(); ++i) {
|
|
|
|
if (!JS7_ISDEC(cp[i]))
|
|
|
|
return id;
|
|
|
|
}
|
2013-12-16 18:27:43 -08:00
|
|
|
return JSID_VOID;
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
2011-03-03 14:07:48 -08:00
|
|
|
return id;
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2013-12-16 18:27:43 -08:00
|
|
|
return JSID_VOID;
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2010-12-19 08:09:45 -08:00
|
|
|
const char * TypeIdStringImpl(jsid id);
|
|
|
|
|
2010-11-18 15:18:23 -08:00
|
|
|
/* Convert an id for printing during debug. */
|
|
|
|
static inline const char *
|
2013-04-30 15:41:04 -07:00
|
|
|
TypeIdString(jsid id)
|
2010-11-18 15:18:23 -08:00
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
2010-12-07 17:11:37 -08:00
|
|
|
return TypeIdStringImpl(id);
|
2010-11-18 15:18:23 -08:00
|
|
|
#else
|
2010-11-24 17:41:52 -08:00
|
|
|
return "(missing)";
|
2010-11-18 15:18:23 -08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2011-03-03 14:07:48 -08:00
|
|
|
/*
|
|
|
|
* Structure for type inference entry point functions. All functions which can
|
|
|
|
* change type information must use this, and functions which depend on
|
|
|
|
* intermediate types (i.e. JITs) can use this to ensure that intermediate
|
|
|
|
* information is not collected and does not change.
|
|
|
|
*
|
|
|
|
* Pins inference results so that intermediate type information, TypeObjects
|
|
|
|
* and JSScripts won't be collected during GC. Does additional sanity checking
|
|
|
|
* that inference is not reentrant and that recompilations occur properly.
|
|
|
|
*/
|
2013-01-18 08:23:28 -08:00
|
|
|
struct AutoEnterAnalysis
|
2011-03-03 14:07:48 -08:00
|
|
|
{
|
2013-01-18 08:23:28 -08:00
|
|
|
/* Prevent GC activity in the middle of analysis. */
|
|
|
|
gc::AutoSuppressGC suppressGC;
|
|
|
|
|
2012-03-20 03:22:05 -07:00
|
|
|
FreeOp *freeOp;
|
|
|
|
JSCompartment *compartment;
|
2011-04-22 07:59:45 -07:00
|
|
|
bool oldActiveAnalysis;
|
2011-03-03 14:07:48 -08:00
|
|
|
|
2013-08-22 06:13:18 -07:00
|
|
|
AutoEnterAnalysis(ExclusiveContext *cx)
|
2013-01-18 08:23:28 -08:00
|
|
|
: suppressGC(cx)
|
2011-03-03 14:07:48 -08:00
|
|
|
{
|
2013-08-22 06:13:18 -07:00
|
|
|
init(cx->defaultFreeOp(), cx->compartment());
|
2012-03-20 03:22:05 -07:00
|
|
|
}
|
|
|
|
|
2013-01-18 08:23:28 -08:00
|
|
|
AutoEnterAnalysis(FreeOp *fop, JSCompartment *comp)
|
|
|
|
: suppressGC(comp)
|
2012-03-20 03:22:05 -07:00
|
|
|
{
|
|
|
|
init(fop, comp);
|
2011-03-03 14:07:48 -08:00
|
|
|
}
|
|
|
|
|
2013-01-18 08:23:28 -08:00
|
|
|
~AutoEnterAnalysis()
|
2011-03-03 14:07:48 -08:00
|
|
|
{
|
2012-03-20 03:22:05 -07:00
|
|
|
compartment->activeAnalysis = oldActiveAnalysis;
|
2011-03-03 14:07:48 -08:00
|
|
|
|
|
|
|
/*
|
2011-04-22 07:59:45 -07:00
|
|
|
* If there are no more type inference activations on the stack,
|
|
|
|
* process any triggered recompilations. Note that we should not be
|
|
|
|
* invoking any scripted code while type inference is running.
|
2011-03-03 14:07:48 -08:00
|
|
|
*/
|
2013-01-18 08:23:28 -08:00
|
|
|
if (!compartment->activeAnalysis) {
|
2013-12-12 13:10:54 -08:00
|
|
|
TypeZone &types = compartment->zone()->types;
|
2014-03-08 12:37:57 -08:00
|
|
|
if (types.pendingNukeTypes)
|
|
|
|
types.nukeTypes(freeOp);
|
|
|
|
else if (types.pendingRecompiles)
|
2013-12-12 13:10:54 -08:00
|
|
|
types.processPendingRecompiles(freeOp);
|
2011-04-22 07:59:45 -07:00
|
|
|
}
|
2011-03-03 14:07:48 -08:00
|
|
|
}
|
2012-03-20 03:22:05 -07:00
|
|
|
|
|
|
|
private:
|
|
|
|
void init(FreeOp *fop, JSCompartment *comp) {
|
|
|
|
freeOp = fop;
|
|
|
|
compartment = comp;
|
|
|
|
oldActiveAnalysis = compartment->activeAnalysis;
|
|
|
|
compartment->activeAnalysis = true;
|
|
|
|
}
|
2011-04-22 07:59:45 -07:00
|
|
|
};
|
2011-03-03 14:07:48 -08:00
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
2011-06-02 10:40:27 -07:00
|
|
|
// Interface functions
|
2010-10-29 08:05:55 -07:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
2011-06-02 10:40:27 -07:00
|
|
|
/*
|
|
|
|
* These functions check whether inference is enabled before performing some
|
|
|
|
* action on the type state. To avoid checking cx->typeInferenceEnabled()
|
|
|
|
* everywhere, it is generally preferred to use one of these functions or
|
|
|
|
* a type function on JSScript to perform inference operations.
|
|
|
|
*/
|
2011-03-03 14:07:48 -08:00
|
|
|
|
2013-09-11 05:49:05 -07:00
|
|
|
inline const Class *
|
2013-01-23 11:57:55 -08:00
|
|
|
GetClassForProtoKey(JSProtoKey key)
|
|
|
|
{
|
|
|
|
switch (key) {
|
|
|
|
case JSProto_Object:
|
2013-07-04 00:50:50 -07:00
|
|
|
return &JSObject::class_;
|
2013-01-23 11:57:55 -08:00
|
|
|
case JSProto_Array:
|
2013-06-18 23:55:38 -07:00
|
|
|
return &ArrayObject::class_;
|
2013-01-23 11:57:55 -08:00
|
|
|
|
|
|
|
case JSProto_Number:
|
2013-06-17 03:18:55 -07:00
|
|
|
return &NumberObject::class_;
|
2013-01-23 11:57:55 -08:00
|
|
|
case JSProto_Boolean:
|
2013-06-17 03:18:55 -07:00
|
|
|
return &BooleanObject::class_;
|
2013-01-23 11:57:55 -08:00
|
|
|
case JSProto_String:
|
2013-06-17 03:18:55 -07:00
|
|
|
return &StringObject::class_;
|
2013-01-23 11:57:55 -08:00
|
|
|
case JSProto_RegExp:
|
2013-06-16 17:39:43 -07:00
|
|
|
return &RegExpObject::class_;
|
2013-01-23 11:57:55 -08:00
|
|
|
|
|
|
|
case JSProto_Int8Array:
|
|
|
|
case JSProto_Uint8Array:
|
|
|
|
case JSProto_Int16Array:
|
|
|
|
case JSProto_Uint16Array:
|
|
|
|
case JSProto_Int32Array:
|
|
|
|
case JSProto_Uint32Array:
|
|
|
|
case JSProto_Float32Array:
|
|
|
|
case JSProto_Float64Array:
|
|
|
|
case JSProto_Uint8ClampedArray:
|
2013-07-02 12:48:35 -07:00
|
|
|
return &TypedArrayObject::classes[key - JSProto_Int8Array];
|
2013-01-23 11:57:55 -08:00
|
|
|
|
|
|
|
case JSProto_ArrayBuffer:
|
2013-06-16 17:07:35 -07:00
|
|
|
return &ArrayBufferObject::class_;
|
2013-01-23 11:57:55 -08:00
|
|
|
|
2014-02-20 14:43:03 -08:00
|
|
|
case JSProto_SharedArrayBuffer:
|
|
|
|
return &SharedArrayBufferObject::class_;
|
|
|
|
|
2013-01-23 11:57:55 -08:00
|
|
|
case JSProto_DataView:
|
2013-06-16 17:19:53 -07:00
|
|
|
return &DataViewObject::class_;
|
2013-01-23 11:57:55 -08:00
|
|
|
|
|
|
|
default:
|
2013-06-28 19:20:12 -07:00
|
|
|
MOZ_ASSUME_UNREACHABLE("Bad proto key");
|
2013-01-23 11:57:55 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-02 10:40:27 -07:00
|
|
|
/*
|
|
|
|
* Get the default 'new' object for a given standard class, per the currently
|
|
|
|
* active global.
|
|
|
|
*/
|
|
|
|
inline TypeObject *
|
|
|
|
GetTypeNewObject(JSContext *cx, JSProtoKey key)
|
2010-11-24 17:41:52 -08:00
|
|
|
{
|
2013-03-06 08:41:42 -08:00
|
|
|
RootedObject proto(cx);
|
2012-08-17 11:21:57 -07:00
|
|
|
if (!js_GetClassPrototype(cx, key, &proto))
|
2013-10-07 09:43:32 -07:00
|
|
|
return nullptr;
|
2013-07-10 08:29:52 -07:00
|
|
|
return cx->getNewType(GetClassForProtoKey(key), proto.get());
|
2010-11-24 17:41:52 -08:00
|
|
|
}
|
|
|
|
|
2011-06-02 10:40:27 -07:00
|
|
|
/* Get a type object for the immediate allocation site within a native. */
|
|
|
|
inline TypeObject *
|
2011-06-15 11:26:12 -07:00
|
|
|
GetTypeCallerInitObject(JSContext *cx, JSProtoKey key)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2011-06-02 10:40:27 -07:00
|
|
|
if (cx->typeInferenceEnabled()) {
|
2011-06-05 22:39:45 -07:00
|
|
|
jsbytecode *pc;
|
2013-06-20 23:28:06 -07:00
|
|
|
RootedScript script(cx, cx->currentScript(&pc));
|
2011-08-01 22:24:29 -07:00
|
|
|
if (script)
|
2011-07-28 09:16:53 -07:00
|
|
|
return TypeScript::InitObject(cx, script, pc, key);
|
2011-03-03 14:07:48 -08:00
|
|
|
}
|
2011-06-15 11:26:12 -07:00
|
|
|
return GetTypeNewObject(cx, key);
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2012-11-16 13:59:26 -08:00
|
|
|
void MarkIteratorUnknownSlow(JSContext *cx);
|
|
|
|
|
2013-01-26 06:42:20 -08:00
|
|
|
void TypeMonitorCallSlow(JSContext *cx, JSObject *callee, const CallArgs &args,
|
2012-11-16 13:59:26 -08:00
|
|
|
bool constructing);
|
|
|
|
|
2011-06-02 10:40:27 -07:00
|
|
|
/*
|
2011-10-27 08:11:26 -07:00
|
|
|
* Monitor a javascript call, either on entry to the interpreter or made
|
|
|
|
* from within the interpreter.
|
2011-06-02 10:40:27 -07:00
|
|
|
*/
|
2013-05-27 10:01:27 -07:00
|
|
|
inline void
|
2011-10-27 08:11:26 -07:00
|
|
|
TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing)
|
2011-06-02 10:40:27 -07:00
|
|
|
{
|
2013-06-17 23:53:49 -07:00
|
|
|
if (args.callee().is<JSFunction>()) {
|
|
|
|
JSFunction *fun = &args.callee().as<JSFunction>();
|
2013-05-27 10:01:27 -07:00
|
|
|
if (fun->isInterpreted() && fun->nonLazyScript()->types && cx->typeInferenceEnabled())
|
|
|
|
TypeMonitorCallSlow(cx, &args.callee(), args, constructing);
|
2011-03-03 14:07:48 -08:00
|
|
|
}
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
inline bool
|
2013-07-10 08:29:52 -07:00
|
|
|
TrackPropertyTypes(ExclusiveContext *cx, JSObject *obj, jsid id)
|
2011-07-15 10:14:07 -07:00
|
|
|
{
|
2011-07-21 07:28:01 -07:00
|
|
|
if (!cx->typeInferenceEnabled() || obj->hasLazyType() || obj->type()->unknownProperties())
|
|
|
|
return false;
|
|
|
|
|
2013-10-08 15:14:04 -07:00
|
|
|
if (obj->hasSingletonType() && !obj->type()->maybeGetProperty(id))
|
2011-07-21 07:28:01 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
2011-07-15 10:14:07 -07:00
|
|
|
}
|
|
|
|
|
2013-02-15 04:17:48 -08:00
|
|
|
inline void
|
2013-04-30 15:41:12 -07:00
|
|
|
EnsureTrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
|
2013-02-15 04:17:48 -08:00
|
|
|
{
|
2013-10-14 11:13:41 -07:00
|
|
|
if (!cx->typeInferenceEnabled())
|
2013-02-15 04:17:48 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
id = IdToTypeId(id);
|
|
|
|
|
|
|
|
if (obj->hasSingletonType()) {
|
|
|
|
AutoEnterAnalysis enter(cx);
|
2013-10-14 11:13:41 -07:00
|
|
|
if (obj->hasLazyType() && !obj->getType(cx)) {
|
2014-03-08 12:37:57 -08:00
|
|
|
cx->compartment()->types.setPendingNukeTypes(cx);
|
|
|
|
cx->clearPendingException();
|
2013-10-14 11:13:41 -07:00
|
|
|
return;
|
|
|
|
}
|
2014-01-22 03:26:25 -08:00
|
|
|
if (!obj->type()->unknownProperties() && !obj->type()->getProperty(cx, id)) {
|
2014-03-08 12:37:57 -08:00
|
|
|
cx->compartment()->types.setPendingNukeTypes(cx);
|
2014-01-22 03:26:25 -08:00
|
|
|
return;
|
|
|
|
}
|
2013-02-15 04:17:48 -08:00
|
|
|
}
|
|
|
|
|
2013-02-26 05:03:50 -08:00
|
|
|
JS_ASSERT(obj->type()->unknownProperties() || TrackPropertyTypes(cx, obj, id));
|
2013-02-15 04:17:48 -08:00
|
|
|
}
|
|
|
|
|
2013-10-29 15:10:59 -07:00
|
|
|
inline bool
|
|
|
|
CanHaveEmptyPropertyTypesForOwnProperty(JSObject *obj)
|
|
|
|
{
|
|
|
|
// Per the comment on TypeSet::propertySet, property type sets for global
|
|
|
|
// objects may be empty for 'own' properties if the global property still
|
|
|
|
// has its initial undefined value.
|
|
|
|
return obj->is<GlobalObject>();
|
|
|
|
}
|
|
|
|
|
2013-10-08 15:14:04 -07:00
|
|
|
inline bool
|
|
|
|
HasTypePropertyId(JSObject *obj, jsid id, Type type)
|
|
|
|
{
|
|
|
|
if (obj->hasLazyType())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (obj->type()->unknownProperties())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (HeapTypeSet *types = obj->type()->maybeGetProperty(IdToTypeId(id)))
|
|
|
|
return types->hasType(type);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
HasTypePropertyId(JSObject *obj, jsid id, const Value &value)
|
|
|
|
{
|
|
|
|
return HasTypePropertyId(obj, id, GetValueType(value));
|
|
|
|
}
|
|
|
|
|
2011-06-02 10:40:27 -07:00
|
|
|
/* Add a possible type for a property of obj. */
|
2011-05-09 07:12:47 -07:00
|
|
|
inline void
|
2013-07-10 08:29:52 -07:00
|
|
|
AddTypePropertyId(ExclusiveContext *cx, JSObject *obj, jsid id, Type type)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2013-07-10 08:29:52 -07:00
|
|
|
if (cx->typeInferenceEnabled()) {
|
2012-12-31 12:40:21 -08:00
|
|
|
id = IdToTypeId(id);
|
2013-07-10 08:29:52 -07:00
|
|
|
if (TrackPropertyTypes(cx, obj, id))
|
2013-08-22 06:13:18 -07:00
|
|
|
obj->type()->addPropertyType(cx, id, type);
|
2013-07-10 08:29:52 -07:00
|
|
|
}
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2011-05-09 07:12:47 -07:00
|
|
|
inline void
|
2013-07-10 08:29:52 -07:00
|
|
|
AddTypePropertyId(ExclusiveContext *cx, JSObject *obj, jsid id, const Value &value)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2013-07-10 08:29:52 -07:00
|
|
|
if (cx->typeInferenceEnabled()) {
|
2012-12-31 12:40:21 -08:00
|
|
|
id = IdToTypeId(id);
|
2013-07-10 08:29:52 -07:00
|
|
|
if (TrackPropertyTypes(cx, obj, id))
|
2013-08-22 06:13:18 -07:00
|
|
|
obj->type()->addPropertyType(cx, id, value);
|
2013-07-10 08:29:52 -07:00
|
|
|
}
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2011-05-09 07:12:47 -07:00
|
|
|
inline void
|
2014-03-08 12:37:57 -08:00
|
|
|
AddTypeProperty(ExclusiveContext *cx, TypeObject *obj, const char *name, Type type)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2011-06-02 10:40:27 -07:00
|
|
|
if (cx->typeInferenceEnabled() && !obj->unknownProperties())
|
2014-03-08 12:37:57 -08:00
|
|
|
obj->addPropertyType(cx, name, type);
|
2010-12-21 18:26:09 -08:00
|
|
|
}
|
|
|
|
|
2011-05-09 07:12:47 -07:00
|
|
|
inline void
|
2014-03-08 12:37:57 -08:00
|
|
|
AddTypeProperty(ExclusiveContext *cx, TypeObject *obj, const char *name, const Value &value)
|
2011-03-15 23:50:44 -07:00
|
|
|
{
|
2011-06-02 10:40:27 -07:00
|
|
|
if (cx->typeInferenceEnabled() && !obj->unknownProperties())
|
2014-03-08 12:37:57 -08:00
|
|
|
obj->addPropertyType(cx, name, value);
|
2011-03-15 23:50:44 -07:00
|
|
|
}
|
|
|
|
|
2011-06-02 10:40:27 -07:00
|
|
|
/* Set one or more dynamic flags on a type object. */
|
2011-05-09 07:12:47 -07:00
|
|
|
inline void
|
2013-07-10 08:29:52 -07:00
|
|
|
MarkTypeObjectFlags(ExclusiveContext *cx, JSObject *obj, TypeObjectFlags flags)
|
2011-04-11 20:10:46 -07:00
|
|
|
{
|
2011-07-25 07:13:02 -07:00
|
|
|
if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->hasAllFlags(flags))
|
2013-08-22 06:13:18 -07:00
|
|
|
obj->type()->setFlags(cx, flags);
|
2011-04-11 20:10:46 -07:00
|
|
|
}
|
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
/*
|
|
|
|
* Mark all properties of a type object as unknown. If markSetsUnknown is set,
|
|
|
|
* scan the entire compartment and mark all type sets containing it as having
|
|
|
|
* an unknown object. This is needed for correctness in dealing with mutable
|
|
|
|
* __proto__, which can change the type of an object dynamically.
|
|
|
|
*/
|
2011-05-09 07:12:47 -07:00
|
|
|
inline void
|
2011-07-15 10:14:07 -07:00
|
|
|
MarkTypeObjectUnknownProperties(JSContext *cx, TypeObject *obj,
|
|
|
|
bool markSetsUnknown = false)
|
2011-04-11 20:10:46 -07:00
|
|
|
{
|
2011-07-15 10:14:07 -07:00
|
|
|
if (cx->typeInferenceEnabled()) {
|
|
|
|
if (!obj->unknownProperties())
|
|
|
|
obj->markUnknown(cx);
|
2013-12-16 10:53:02 -08:00
|
|
|
if (markSetsUnknown && !(obj->flags() & OBJECT_FLAG_SETS_MARKED_UNKNOWN))
|
2013-06-10 14:22:18 -07:00
|
|
|
cx->compartment()->types.markSetsUnknown(cx, obj);
|
2011-07-15 10:14:07 -07:00
|
|
|
}
|
2011-04-11 20:10:46 -07:00
|
|
|
}
|
|
|
|
|
2011-05-09 07:12:47 -07:00
|
|
|
inline void
|
2014-01-06 10:02:28 -08:00
|
|
|
MarkTypePropertyNonData(ExclusiveContext *cx, JSObject *obj, jsid id)
|
2010-11-09 14:40:10 -08:00
|
|
|
{
|
2013-07-10 08:29:52 -07:00
|
|
|
if (cx->typeInferenceEnabled()) {
|
2012-12-31 12:40:21 -08:00
|
|
|
id = IdToTypeId(id);
|
2013-07-10 08:29:52 -07:00
|
|
|
if (TrackPropertyTypes(cx, obj, id))
|
2014-01-06 10:02:28 -08:00
|
|
|
obj->type()->markPropertyNonData(cx, id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
MarkTypePropertyNonWritable(ExclusiveContext *cx, JSObject *obj, jsid id)
|
|
|
|
{
|
|
|
|
if (cx->typeInferenceEnabled()) {
|
|
|
|
id = IdToTypeId(id);
|
|
|
|
if (TrackPropertyTypes(cx, obj, id))
|
|
|
|
obj->type()->markPropertyNonWritable(cx, id);
|
2013-07-10 08:29:52 -07:00
|
|
|
}
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2013-10-08 15:14:04 -07:00
|
|
|
inline bool
|
2014-01-06 10:02:28 -08:00
|
|
|
IsTypePropertyIdMarkedNonData(JSObject *obj, jsid id)
|
2013-10-08 15:14:04 -07:00
|
|
|
{
|
2014-01-06 10:02:28 -08:00
|
|
|
return obj->type()->isPropertyNonData(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
IsTypePropertyIdMarkedNonWritable(JSObject *obj, jsid id)
|
|
|
|
{
|
|
|
|
return obj->type()->isPropertyNonWritable(id);
|
2013-10-08 15:14:04 -07:00
|
|
|
}
|
|
|
|
|
2011-08-09 09:52:55 -07:00
|
|
|
/* Mark a state change on a particular object. */
|
2011-05-09 07:12:47 -07:00
|
|
|
inline void
|
2013-07-10 08:29:52 -07:00
|
|
|
MarkObjectStateChange(ExclusiveContext *cx, JSObject *obj)
|
2010-11-24 17:41:52 -08:00
|
|
|
{
|
2011-08-09 09:52:55 -07:00
|
|
|
if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->unknownProperties())
|
2013-08-22 06:13:18 -07:00
|
|
|
obj->type()->markStateChange(cx);
|
2010-11-24 17:41:52 -08:00
|
|
|
}
|
|
|
|
|
2011-06-02 10:40:27 -07:00
|
|
|
/*
|
|
|
|
* For an array or object which has not yet escaped and been referenced elsewhere,
|
|
|
|
* pick a new type based on the object's current contents.
|
|
|
|
*/
|
|
|
|
|
2011-05-09 07:12:47 -07:00
|
|
|
inline void
|
2013-08-22 06:13:18 -07:00
|
|
|
FixArrayType(ExclusiveContext *cx, HandleObject obj)
|
2011-03-10 16:17:39 -08:00
|
|
|
{
|
2013-08-22 06:13:18 -07:00
|
|
|
if (cx->typeInferenceEnabled())
|
|
|
|
cx->compartment()->types.fixArrayType(cx, obj);
|
2011-03-10 16:17:39 -08:00
|
|
|
}
|
|
|
|
|
2011-05-09 07:12:47 -07:00
|
|
|
inline void
|
2013-08-22 06:13:18 -07:00
|
|
|
FixObjectType(ExclusiveContext *cx, HandleObject obj)
|
2011-03-10 16:17:39 -08:00
|
|
|
{
|
2013-08-22 06:13:18 -07:00
|
|
|
if (cx->typeInferenceEnabled())
|
|
|
|
cx->compartment()->types.fixObjectType(cx, obj);
|
2011-03-10 16:17:39 -08:00
|
|
|
}
|
|
|
|
|
2013-04-30 15:40:40 -07:00
|
|
|
/* Interface helpers for JSScript*. */
|
2013-01-26 06:42:20 -08:00
|
|
|
extern void TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc,
|
2012-09-16 16:32:06 -07:00
|
|
|
const js::Value &rval);
|
2013-01-26 06:42:20 -08:00
|
|
|
extern void TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc,
|
2012-09-16 16:32:06 -07:00
|
|
|
js::types::Type type);
|
2011-06-02 10:40:27 -07:00
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
2011-06-02 10:40:27 -07:00
|
|
|
// Script interface functions
|
2010-10-29 08:05:55 -07:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
2011-07-28 09:16:53 -07:00
|
|
|
/* static */ inline unsigned
|
2013-04-30 15:40:40 -07:00
|
|
|
TypeScript::NumTypeSets(JSScript *script)
|
2011-06-06 08:32:41 -07:00
|
|
|
{
|
2013-12-09 11:26:09 -08:00
|
|
|
return script->nTypeSets() + analyze::LocalSlot(script, 0);
|
2011-03-01 13:10:05 -08:00
|
|
|
}
|
|
|
|
|
2012-08-22 11:28:34 -07:00
|
|
|
/* static */ inline StackTypeSet *
|
2013-04-30 15:40:40 -07:00
|
|
|
TypeScript::ThisTypes(JSScript *script)
|
2011-03-01 13:10:05 -08:00
|
|
|
{
|
2013-12-16 10:53:02 -08:00
|
|
|
return script->types->typeArray() + script->nTypeSets() + analyze::ThisSlot();
|
2011-03-01 13:10:05 -08:00
|
|
|
}
|
|
|
|
|
2011-04-22 07:59:45 -07:00
|
|
|
/*
|
|
|
|
* Note: for non-escaping arguments and locals, argTypes/localTypes reflect
|
|
|
|
* only the initial type of the variable (e.g. passed values for argTypes,
|
|
|
|
* or undefined for localTypes) and not types from subsequent assignments.
|
|
|
|
*/
|
|
|
|
|
2012-08-22 11:28:34 -07:00
|
|
|
/* static */ inline StackTypeSet *
|
2013-04-30 15:40:40 -07:00
|
|
|
TypeScript::ArgTypes(JSScript *script, unsigned i)
|
2011-03-01 13:10:05 -08:00
|
|
|
{
|
2014-01-09 08:13:25 -08:00
|
|
|
JS_ASSERT(i < script->functionNonDelazifying()->nargs());
|
2013-12-16 10:53:02 -08:00
|
|
|
return script->types->typeArray() + script->nTypeSets() + analyze::ArgSlot(i);
|
2010-12-28 11:53:50 -08:00
|
|
|
}
|
|
|
|
|
2013-10-17 09:21:05 -07:00
|
|
|
template <typename TYPESET>
|
|
|
|
/* static */ inline TYPESET *
|
|
|
|
TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *hint, TYPESET *typeArray)
|
2013-05-07 04:11:46 -07:00
|
|
|
{
|
|
|
|
JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);
|
2013-10-22 07:08:10 -07:00
|
|
|
#ifdef JS_ION
|
|
|
|
uint32_t *bytecodeMap = script->baselineScript()->bytecodeTypeMap();
|
|
|
|
#else
|
2013-10-28 07:06:30 -07:00
|
|
|
uint32_t *bytecodeMap = nullptr;
|
2013-10-22 07:08:10 -07:00
|
|
|
MOZ_CRASH();
|
|
|
|
#endif
|
2013-12-03 08:17:50 -08:00
|
|
|
uint32_t offset = script->pcToOffset(pc);
|
2013-05-07 04:11:46 -07:00
|
|
|
|
|
|
|
// See if this pc is the next typeset opcode after the last one looked up.
|
2014-02-05 02:34:15 -08:00
|
|
|
if ((*hint + 1) < script->nTypeSets() && bytecodeMap[*hint + 1] == offset) {
|
2013-05-07 04:11:46 -07:00
|
|
|
(*hint)++;
|
2013-10-17 09:21:05 -07:00
|
|
|
return typeArray + *hint;
|
2013-05-07 04:11:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// See if this pc is the same as the last one looked up.
|
|
|
|
if (bytecodeMap[*hint] == offset)
|
2013-10-17 09:21:05 -07:00
|
|
|
return typeArray + *hint;
|
2013-05-07 04:11:46 -07:00
|
|
|
|
|
|
|
// Fall back to a binary search.
|
|
|
|
size_t bottom = 0;
|
2013-12-09 11:26:09 -08:00
|
|
|
size_t top = script->nTypeSets() - 1;
|
2013-09-25 08:25:46 -07:00
|
|
|
size_t mid = bottom + (top - bottom) / 2;
|
2013-05-07 04:11:46 -07:00
|
|
|
while (mid < top) {
|
|
|
|
if (bytecodeMap[mid] < offset)
|
|
|
|
bottom = mid + 1;
|
|
|
|
else if (bytecodeMap[mid] > offset)
|
|
|
|
top = mid;
|
|
|
|
else
|
|
|
|
break;
|
2013-09-25 08:25:46 -07:00
|
|
|
mid = bottom + (top - bottom) / 2;
|
2013-05-07 04:11:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// We should have have zeroed in on either the exact offset, unless there
|
|
|
|
// are more JOF_TYPESET opcodes than nTypeSets in the script (as can happen
|
|
|
|
// if the script is very long).
|
|
|
|
JS_ASSERT(bytecodeMap[mid] == offset || mid == top);
|
|
|
|
|
|
|
|
*hint = mid;
|
2013-10-17 09:21:05 -07:00
|
|
|
return typeArray + *hint;
|
2013-05-07 04:11:46 -07:00
|
|
|
}
|
|
|
|
|
2013-10-17 09:21:05 -07:00
|
|
|
/* static */ inline StackTypeSet *
|
|
|
|
TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc)
|
2010-12-28 11:53:50 -08:00
|
|
|
{
|
2013-10-17 09:21:05 -07:00
|
|
|
JS_ASSERT(CurrentThreadCanAccessRuntime(script->runtimeFromMainThread()));
|
2013-10-22 07:08:10 -07:00
|
|
|
#ifdef JS_ION
|
2013-12-09 11:26:09 -08:00
|
|
|
uint32_t *hint = script->baselineScript()->bytecodeTypeMap() + script->nTypeSets();
|
2013-10-22 07:08:10 -07:00
|
|
|
#else
|
2013-10-28 07:06:30 -07:00
|
|
|
uint32_t *hint = nullptr;
|
2013-10-22 07:08:10 -07:00
|
|
|
MOZ_CRASH();
|
|
|
|
#endif
|
2013-10-17 09:21:05 -07:00
|
|
|
return BytecodeTypes(script, pc, hint, script->types->typeArray());
|
2010-12-28 11:53:50 -08:00
|
|
|
}
|
|
|
|
|
2013-02-15 09:59:19 -08:00
|
|
|
struct AllocationSiteKey : public DefaultHasher<AllocationSiteKey> {
|
2011-07-21 07:28:01 -07:00
|
|
|
JSScript *script;
|
2011-09-01 12:20:30 -07:00
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
uint32_t offset : 24;
|
2011-07-21 07:28:01 -07:00
|
|
|
JSProtoKey kind : 8;
|
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
static const uint32_t OFFSET_LIMIT = (1 << 23);
|
2011-07-21 07:28:01 -07:00
|
|
|
|
2013-04-01 22:43:19 -07:00
|
|
|
AllocationSiteKey() { mozilla::PodZero(this); }
|
2011-07-21 07:28:01 -07:00
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
static inline uint32_t hash(AllocationSiteKey key) {
|
2013-12-03 08:17:50 -08:00
|
|
|
return uint32_t(size_t(key.script->offsetToPC(key.offset)) ^ key.kind);
|
2011-07-21 07:28:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool match(const AllocationSiteKey &a, const AllocationSiteKey &b) {
|
|
|
|
return a.script == b.script && a.offset == b.offset && a.kind == b.kind;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-01-28 11:01:54 -08:00
|
|
|
/* Whether to use a new type object for an initializer opcode at script/pc. */
|
|
|
|
js::NewObjectKind
|
2013-09-30 10:43:20 -07:00
|
|
|
UseNewTypeForInitializer(JSScript *script, jsbytecode *pc, JSProtoKey key);
|
2013-01-28 11:01:54 -08:00
|
|
|
|
|
|
|
js::NewObjectKind
|
2013-09-30 10:43:20 -07:00
|
|
|
UseNewTypeForInitializer(JSScript *script, jsbytecode *pc, const Class *clasp);
|
2013-01-28 11:01:54 -08:00
|
|
|
|
2011-07-28 09:16:53 -07:00
|
|
|
/* static */ inline TypeObject *
|
2013-01-26 06:42:20 -08:00
|
|
|
TypeScript::InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey kind)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2013-09-30 10:43:20 -07:00
|
|
|
JS_ASSERT(!UseNewTypeForInitializer(script, pc, kind));
|
2012-03-21 06:37:43 -07:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
/* :XXX: Limit script->length so we don't need to check the offset up front? */
|
2013-12-03 08:17:50 -08:00
|
|
|
uint32_t offset = script->pcToOffset(pc);
|
2010-12-28 11:53:50 -08:00
|
|
|
|
2013-12-10 18:22:28 -08:00
|
|
|
if (!cx->typeInferenceEnabled() || !script->compileAndGo() || offset >= AllocationSiteKey::OFFSET_LIMIT)
|
2011-07-21 07:28:01 -07:00
|
|
|
return GetTypeNewObject(cx, kind);
|
|
|
|
|
|
|
|
AllocationSiteKey key;
|
2011-07-28 09:16:53 -07:00
|
|
|
key.script = script;
|
2011-07-21 07:28:01 -07:00
|
|
|
key.offset = offset;
|
|
|
|
key.kind = kind;
|
|
|
|
|
2013-06-10 14:22:18 -07:00
|
|
|
if (!cx->compartment()->types.allocationSiteTable)
|
|
|
|
return cx->compartment()->types.addAllocationSiteTypeObject(cx, key);
|
2011-07-21 07:28:01 -07:00
|
|
|
|
2013-06-10 14:22:18 -07:00
|
|
|
AllocationSiteTable::Ptr p = cx->compartment()->types.allocationSiteTable->lookup(key);
|
2011-07-21 07:28:01 -07:00
|
|
|
|
|
|
|
if (p)
|
2013-11-25 17:35:09 -08:00
|
|
|
return p->value();
|
2013-06-10 14:22:18 -07:00
|
|
|
return cx->compartment()->types.addAllocationSiteTypeObject(cx, key);
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2012-03-21 06:37:43 -07:00
|
|
|
/* Set the type to use for obj according to the site it was allocated at. */
|
|
|
|
static inline bool
|
2013-01-28 11:01:54 -08:00
|
|
|
SetInitializerObjectType(JSContext *cx, HandleScript script, jsbytecode *pc, HandleObject obj, NewObjectKind kind)
|
2012-03-21 06:37:43 -07:00
|
|
|
{
|
|
|
|
if (!cx->typeInferenceEnabled())
|
|
|
|
return true;
|
|
|
|
|
2012-06-27 07:10:50 -07:00
|
|
|
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
|
|
|
|
JS_ASSERT(key != JSProto_Null);
|
2013-09-30 10:43:20 -07:00
|
|
|
JS_ASSERT(kind == UseNewTypeForInitializer(script, pc, key));
|
2012-06-27 07:10:50 -07:00
|
|
|
|
2013-01-28 11:01:54 -08:00
|
|
|
if (kind == SingletonObject) {
|
|
|
|
JS_ASSERT(obj->hasSingletonType());
|
2012-03-21 06:37:43 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Inference does not account for types of run-once initializer
|
|
|
|
* objects, as these may not be created until after the script
|
|
|
|
* has been analyzed.
|
|
|
|
*/
|
|
|
|
TypeScript::Monitor(cx, script, pc, ObjectValue(*obj));
|
|
|
|
} else {
|
|
|
|
types::TypeObject *type = TypeScript::InitObject(cx, script, pc, key);
|
|
|
|
if (!type)
|
|
|
|
return false;
|
2013-06-25 21:38:35 -07:00
|
|
|
obj->uninlinedSetType(type);
|
2012-03-21 06:37:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-07-28 09:16:53 -07:00
|
|
|
/* static */ inline void
|
2013-01-26 06:42:20 -08:00
|
|
|
TypeScript::Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2011-06-02 10:40:27 -07:00
|
|
|
if (cx->typeInferenceEnabled())
|
2011-07-28 09:16:53 -07:00
|
|
|
TypeMonitorResult(cx, script, pc, rval);
|
2011-03-01 13:10:05 -08:00
|
|
|
}
|
|
|
|
|
2012-01-24 07:20:34 -08:00
|
|
|
/* static */ inline void
|
|
|
|
TypeScript::Monitor(JSContext *cx, const js::Value &rval)
|
|
|
|
{
|
|
|
|
jsbytecode *pc;
|
2013-09-28 02:45:21 -07:00
|
|
|
RootedScript script(cx, cx->currentScript(&pc));
|
2012-01-24 07:20:34 -08:00
|
|
|
Monitor(cx, script, pc, rval);
|
|
|
|
}
|
|
|
|
|
2011-07-28 09:16:53 -07:00
|
|
|
/* static */ inline void
|
2012-09-16 16:32:02 -07:00
|
|
|
TypeScript::MonitorAssign(JSContext *cx, HandleObject obj, jsid id)
|
2011-05-16 16:15:37 -07:00
|
|
|
{
|
2011-08-01 22:24:29 -07:00
|
|
|
if (cx->typeInferenceEnabled() && !obj->hasSingletonType()) {
|
2011-05-16 16:15:37 -07:00
|
|
|
/*
|
|
|
|
* Mark as unknown any object which has had dynamic assignments to
|
|
|
|
* non-integer properties at SETELEM opcodes. This avoids making large
|
2011-08-01 22:24:29 -07:00
|
|
|
* numbers of type properties for hashmap-style objects. We don't need
|
|
|
|
* to do this for objects with singleton type, because type properties
|
|
|
|
* are only constructed for them when analyzed scripts depend on those
|
|
|
|
* specific properties.
|
2011-05-16 16:15:37 -07:00
|
|
|
*/
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
uint32_t i;
|
2011-05-16 16:15:37 -07:00
|
|
|
if (js_IdIsIndex(id, &i))
|
|
|
|
return;
|
2013-07-15 22:32:18 -07:00
|
|
|
|
|
|
|
// But if we don't have too many properties yet, don't do anything. The
|
|
|
|
// idea here is that normal object initialization should not trigger
|
|
|
|
// deoptimization in most cases, while actual usage as a hashmap should.
|
|
|
|
TypeObject* type = obj->type();
|
2013-07-17 07:21:22 -07:00
|
|
|
if (type->getPropertyCount() < 8)
|
2013-07-15 22:32:18 -07:00
|
|
|
return;
|
|
|
|
MarkTypeObjectUnknownProperties(cx, type);
|
2011-05-16 16:15:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-28 09:16:53 -07:00
|
|
|
/* static */ inline void
|
2013-01-26 06:42:20 -08:00
|
|
|
TypeScript::SetThis(JSContext *cx, JSScript *script, Type type)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2013-05-27 10:01:27 -07:00
|
|
|
if (!cx->typeInferenceEnabled() || !script->types)
|
2011-05-09 07:12:47 -07:00
|
|
|
return;
|
2011-03-04 11:28:52 -08:00
|
|
|
|
2013-05-22 05:50:45 -07:00
|
|
|
if (!ThisTypes(script)->hasType(type)) {
|
2013-01-18 08:23:28 -08:00
|
|
|
AutoEnterAnalysis enter(cx);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-06-06 08:32:41 -07:00
|
|
|
InferSpew(ISpewOps, "externalType: setThis #%u: %s",
|
2011-07-28 09:16:53 -07:00
|
|
|
script->id(), TypeString(type));
|
|
|
|
ThisTypes(script)->addType(cx, type);
|
2011-03-03 14:07:48 -08:00
|
|
|
}
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2011-07-28 09:16:53 -07:00
|
|
|
/* static */ inline void
|
2013-01-26 06:42:20 -08:00
|
|
|
TypeScript::SetThis(JSContext *cx, JSScript *script, const js::Value &value)
|
2011-03-15 18:22:23 -07:00
|
|
|
{
|
|
|
|
if (cx->typeInferenceEnabled())
|
2013-08-22 06:13:18 -07:00
|
|
|
SetThis(cx, script, GetValueType(value));
|
2011-03-15 18:22:23 -07:00
|
|
|
}
|
|
|
|
|
2011-07-28 09:16:53 -07:00
|
|
|
/* static */ inline void
|
2013-01-26 06:42:20 -08:00
|
|
|
TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type)
|
2011-03-03 14:07:48 -08:00
|
|
|
{
|
2013-05-27 10:01:27 -07:00
|
|
|
if (!cx->typeInferenceEnabled() || !script->types)
|
2011-05-09 07:12:47 -07:00
|
|
|
return;
|
2011-09-01 12:20:30 -07:00
|
|
|
|
2011-07-28 09:16:53 -07:00
|
|
|
if (!ArgTypes(script, arg)->hasType(type)) {
|
2013-01-18 08:23:28 -08:00
|
|
|
AutoEnterAnalysis enter(cx);
|
2011-03-03 14:07:48 -08:00
|
|
|
|
2011-06-06 08:32:41 -07:00
|
|
|
InferSpew(ISpewOps, "externalType: setArg #%u %u: %s",
|
2011-07-28 09:16:53 -07:00
|
|
|
script->id(), arg, TypeString(type));
|
|
|
|
ArgTypes(script, arg)->addType(cx, type);
|
2011-03-01 13:10:05 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-28 09:16:53 -07:00
|
|
|
/* static */ inline void
|
2013-01-26 06:42:20 -08:00
|
|
|
TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value)
|
2011-03-03 14:07:48 -08:00
|
|
|
{
|
|
|
|
if (cx->typeInferenceEnabled()) {
|
2013-08-22 06:13:18 -07:00
|
|
|
Type type = GetValueType(value);
|
2011-07-28 09:16:53 -07:00
|
|
|
SetArgument(cx, script, arg, type);
|
2011-03-03 14:07:48 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
// TypeCompartment
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
inline JSCompartment *
|
|
|
|
TypeCompartment::compartment()
|
|
|
|
{
|
|
|
|
return (JSCompartment *)((char *)this - offsetof(JSCompartment, types));
|
|
|
|
}
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
// TypeSet
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The sets of objects and scripts in a type set grow monotonically, are usually
|
|
|
|
* empty, almost always small, and sometimes big. For empty or singleton sets,
|
|
|
|
* the pointer refers directly to the value. For sets fitting into SET_ARRAY_SIZE,
|
|
|
|
* an array of this length is used to store the elements. For larger sets, a hash
|
|
|
|
* table filled to 25%-50% of capacity is used, with collisions resolved by linear
|
|
|
|
* probing. TODO: replace these with jshashtables.
|
|
|
|
*/
|
|
|
|
const unsigned SET_ARRAY_SIZE = 8;
|
2013-12-23 06:09:05 -08:00
|
|
|
const unsigned SET_CAPACITY_OVERFLOW = 1u << 30;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
|
|
|
/* Get the capacity of a set with the given element count. */
|
|
|
|
static inline unsigned
|
|
|
|
HashSetCapacity(unsigned count)
|
|
|
|
{
|
|
|
|
JS_ASSERT(count >= 2);
|
2013-12-23 06:09:05 -08:00
|
|
|
JS_ASSERT(count < SET_CAPACITY_OVERFLOW);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
|
|
|
if (count <= SET_ARRAY_SIZE)
|
|
|
|
return SET_ARRAY_SIZE;
|
|
|
|
|
2013-12-23 06:09:05 -08:00
|
|
|
return 1u << (mozilla::FloorLog2(count) + 2);
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Compute the FNV hash for the low 32 bits of v. */
|
2010-11-24 17:41:52 -08:00
|
|
|
template <class T, class KEY>
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
static inline uint32_t
|
2010-11-24 17:41:52 -08:00
|
|
|
HashKey(T v)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
uint32_t nv = KEY::keyBits(v);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
uint32_t hash = 84696351 ^ (nv & 0xff);
|
2010-10-29 08:05:55 -07:00
|
|
|
hash = (hash * 16777619) ^ ((nv >> 8) & 0xff);
|
|
|
|
hash = (hash * 16777619) ^ ((nv >> 16) & 0xff);
|
|
|
|
return (hash * 16777619) ^ ((nv >> 24) & 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-11-24 17:41:52 -08:00
|
|
|
* Insert space for an element into the specified set and grow its capacity if needed.
|
2013-10-07 09:43:32 -07:00
|
|
|
* returned value is an existing or new entry (nullptr if new).
|
2010-10-29 08:05:55 -07:00
|
|
|
*/
|
2010-11-24 17:41:52 -08:00
|
|
|
template <class T, class U, class KEY>
|
2011-03-03 14:07:48 -08:00
|
|
|
static U **
|
2012-08-22 11:28:34 -07:00
|
|
|
HashSetInsertTry(LifoAlloc &alloc, U **&values, unsigned &count, T key)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
|
|
|
unsigned capacity = HashSetCapacity(count);
|
2010-11-24 17:41:52 -08:00
|
|
|
unsigned insertpos = HashKey<T,KEY>(key) & (capacity - 1);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2010-11-24 17:41:52 -08:00
|
|
|
/* Whether we are converting from a fixed array to hashtable. */
|
|
|
|
bool converting = (count == SET_ARRAY_SIZE);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2010-11-24 17:41:52 -08:00
|
|
|
if (!converting) {
|
2013-10-07 09:43:32 -07:00
|
|
|
while (values[insertpos] != nullptr) {
|
2010-11-24 17:41:52 -08:00
|
|
|
if (KEY::getKey(values[insertpos]) == key)
|
2011-03-03 14:07:48 -08:00
|
|
|
return &values[insertpos];
|
2010-11-24 17:41:52 -08:00
|
|
|
insertpos = (insertpos + 1) & (capacity - 1);
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-23 06:09:05 -08:00
|
|
|
if (count >= SET_CAPACITY_OVERFLOW)
|
|
|
|
return nullptr;
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
count++;
|
|
|
|
unsigned newCapacity = HashSetCapacity(count);
|
|
|
|
|
2010-11-24 17:41:52 -08:00
|
|
|
if (newCapacity == capacity) {
|
|
|
|
JS_ASSERT(!converting);
|
2011-03-03 14:07:48 -08:00
|
|
|
return &values[insertpos];
|
2010-11-24 17:41:52 -08:00
|
|
|
}
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2012-08-22 11:28:34 -07:00
|
|
|
U **newValues = alloc.newArray<U*>(newCapacity);
|
2011-08-17 06:48:14 -07:00
|
|
|
if (!newValues)
|
2013-10-07 09:43:32 -07:00
|
|
|
return nullptr;
|
2013-04-01 22:43:19 -07:00
|
|
|
mozilla::PodZero(newValues, newCapacity);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2010-11-24 17:41:52 -08:00
|
|
|
for (unsigned i = 0; i < capacity; i++) {
|
|
|
|
if (values[i]) {
|
|
|
|
unsigned pos = HashKey<T,KEY>(KEY::getKey(values[i])) & (newCapacity - 1);
|
2013-10-07 09:43:32 -07:00
|
|
|
while (newValues[pos] != nullptr)
|
2010-11-24 17:41:52 -08:00
|
|
|
pos = (pos + 1) & (newCapacity - 1);
|
|
|
|
newValues[pos] = values[i];
|
|
|
|
}
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2010-11-24 17:41:52 -08:00
|
|
|
values = newValues;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2010-11-24 17:41:52 -08:00
|
|
|
insertpos = HashKey<T,KEY>(key) & (newCapacity - 1);
|
2013-10-07 09:43:32 -07:00
|
|
|
while (values[insertpos] != nullptr)
|
2010-11-24 17:41:52 -08:00
|
|
|
insertpos = (insertpos + 1) & (newCapacity - 1);
|
2011-03-03 14:07:48 -08:00
|
|
|
return &values[insertpos];
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-11-24 17:41:52 -08:00
|
|
|
* Insert an element into the specified set if it is not already there, returning
|
2013-10-07 09:43:32 -07:00
|
|
|
* an entry which is nullptr if the element was not there.
|
2010-10-29 08:05:55 -07:00
|
|
|
*/
|
2010-11-24 17:41:52 -08:00
|
|
|
template <class T, class U, class KEY>
|
2011-03-03 14:07:48 -08:00
|
|
|
static inline U **
|
2012-08-22 11:28:34 -07:00
|
|
|
HashSetInsert(LifoAlloc &alloc, U **&values, unsigned &count, T key)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
|
|
|
if (count == 0) {
|
2013-10-07 09:43:32 -07:00
|
|
|
JS_ASSERT(values == nullptr);
|
2010-10-29 08:05:55 -07:00
|
|
|
count++;
|
2011-03-03 14:07:48 -08:00
|
|
|
return (U **) &values;
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (count == 1) {
|
2010-11-24 17:41:52 -08:00
|
|
|
U *oldData = (U*) values;
|
2011-03-03 14:07:48 -08:00
|
|
|
if (KEY::getKey(oldData) == key)
|
|
|
|
return (U **) &values;
|
|
|
|
|
2012-08-22 11:28:34 -07:00
|
|
|
values = alloc.newArray<U*>(SET_ARRAY_SIZE);
|
2011-03-03 14:07:48 -08:00
|
|
|
if (!values) {
|
|
|
|
values = (U **) oldData;
|
2013-10-07 09:43:32 -07:00
|
|
|
return nullptr;
|
2010-11-24 17:41:52 -08:00
|
|
|
}
|
2013-04-01 22:43:19 -07:00
|
|
|
mozilla::PodZero(values, SET_ARRAY_SIZE);
|
2010-11-24 17:41:52 -08:00
|
|
|
count++;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
|
|
|
values[0] = oldData;
|
2011-03-03 14:07:48 -08:00
|
|
|
return &values[1];
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (count <= SET_ARRAY_SIZE) {
|
|
|
|
for (unsigned i = 0; i < count; i++) {
|
2010-11-24 17:41:52 -08:00
|
|
|
if (KEY::getKey(values[i]) == key)
|
2011-03-03 14:07:48 -08:00
|
|
|
return &values[i];
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (count < SET_ARRAY_SIZE) {
|
2010-11-24 17:41:52 -08:00
|
|
|
count++;
|
2011-03-03 14:07:48 -08:00
|
|
|
return &values[count - 1];
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-22 11:28:34 -07:00
|
|
|
return HashSetInsertTry<T,U,KEY>(alloc, values, count, key);
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2013-10-07 09:43:32 -07:00
|
|
|
/* Lookup an entry in a hash set, return nullptr if it does not exist. */
|
2010-11-24 17:41:52 -08:00
|
|
|
template <class T, class U, class KEY>
|
|
|
|
static inline U *
|
|
|
|
HashSetLookup(U **values, unsigned count, T key)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
|
|
|
if (count == 0)
|
2013-10-07 09:43:32 -07:00
|
|
|
return nullptr;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
|
|
|
if (count == 1)
|
2013-10-07 09:43:32 -07:00
|
|
|
return (KEY::getKey((U *) values) == key) ? (U *) values : nullptr;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
|
|
|
if (count <= SET_ARRAY_SIZE) {
|
|
|
|
for (unsigned i = 0; i < count; i++) {
|
2010-11-24 17:41:52 -08:00
|
|
|
if (KEY::getKey(values[i]) == key)
|
|
|
|
return values[i];
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
2013-10-07 09:43:32 -07:00
|
|
|
return nullptr;
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned capacity = HashSetCapacity(count);
|
2010-11-24 17:41:52 -08:00
|
|
|
unsigned pos = HashKey<T,KEY>(key) & (capacity - 1);
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2013-10-07 09:43:32 -07:00
|
|
|
while (values[pos] != nullptr) {
|
2010-11-24 17:41:52 -08:00
|
|
|
if (KEY::getKey(values[pos]) == key)
|
|
|
|
return values[pos];
|
2010-10-29 08:05:55 -07:00
|
|
|
pos = (pos + 1) & (capacity - 1);
|
|
|
|
}
|
|
|
|
|
2013-10-07 09:43:32 -07:00
|
|
|
return nullptr;
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2012-05-07 10:12:52 -07:00
|
|
|
inline TypeObjectKey *
|
|
|
|
Type::objectKey() const
|
|
|
|
{
|
|
|
|
JS_ASSERT(isObject());
|
|
|
|
if (isTypeObject())
|
|
|
|
TypeObject::readBarrier((TypeObject *) data);
|
|
|
|
else
|
|
|
|
JSObject::readBarrier((JSObject *) (data ^ 1));
|
|
|
|
return (TypeObjectKey *) data;
|
|
|
|
}
|
|
|
|
|
2013-04-30 15:41:12 -07:00
|
|
|
inline JSObject *
|
2012-05-07 10:12:52 -07:00
|
|
|
Type::singleObject() const
|
|
|
|
{
|
|
|
|
JS_ASSERT(isSingleObject());
|
|
|
|
JSObject::readBarrier((JSObject *) (data ^ 1));
|
|
|
|
return (JSObject *) (data ^ 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline TypeObject *
|
|
|
|
Type::typeObject() const
|
|
|
|
{
|
|
|
|
JS_ASSERT(isTypeObject());
|
|
|
|
TypeObject::readBarrier((TypeObject *) data);
|
|
|
|
return (TypeObject *) data;
|
|
|
|
}
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
inline bool
|
2012-11-26 13:32:45 -08:00
|
|
|
TypeSet::hasType(Type type) const
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2010-12-21 07:32:21 -08:00
|
|
|
if (unknown())
|
2010-10-29 08:05:55 -07:00
|
|
|
return true;
|
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
if (type.isUnknown()) {
|
2011-03-01 13:10:05 -08:00
|
|
|
return false;
|
2011-07-15 10:14:07 -07:00
|
|
|
} else if (type.isPrimitive()) {
|
2011-07-21 07:28:01 -07:00
|
|
|
return !!(flags & PrimitiveTypeFlag(type.primitive()));
|
2011-07-15 10:14:07 -07:00
|
|
|
} else if (type.isAnyObject()) {
|
2011-07-21 07:28:01 -07:00
|
|
|
return !!(flags & TYPE_FLAG_ANYOBJECT);
|
2010-11-24 17:41:52 -08:00
|
|
|
} else {
|
2011-07-21 07:28:01 -07:00
|
|
|
return !!(flags & TYPE_FLAG_ANYOBJECT) ||
|
2011-07-15 10:14:07 -07:00
|
|
|
HashSetLookup<TypeObjectKey*,TypeObjectKey,TypeObjectKey>
|
2013-10-07 09:43:32 -07:00
|
|
|
(objectSet, baseObjectCount(), type.objectKey()) != nullptr;
|
2010-11-24 17:41:52 -08:00
|
|
|
}
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
inline void
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
TypeSet::setBaseObjectCount(uint32_t count)
|
2011-07-21 07:28:01 -07:00
|
|
|
{
|
|
|
|
JS_ASSERT(count <= TYPE_FLAG_OBJECT_COUNT_LIMIT);
|
|
|
|
flags = (flags & ~TYPE_FLAG_OBJECT_COUNT_MASK)
|
|
|
|
| (count << TYPE_FLAG_OBJECT_COUNT_SHIFT);
|
|
|
|
}
|
|
|
|
|
2011-03-09 11:04:36 -08:00
|
|
|
inline void
|
2011-07-15 10:14:07 -07:00
|
|
|
TypeSet::clearObjects()
|
2011-03-09 11:04:36 -08:00
|
|
|
{
|
2011-07-21 07:28:01 -07:00
|
|
|
setBaseObjectCount(0);
|
2013-10-07 09:43:32 -07:00
|
|
|
objectSet = nullptr;
|
2011-03-09 11:04:36 -08:00
|
|
|
}
|
|
|
|
|
2014-03-08 12:37:57 -08:00
|
|
|
bool
|
2013-12-16 10:53:02 -08:00
|
|
|
TypeSet::addType(Type type, LifoAlloc *alloc)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2010-12-21 07:32:21 -08:00
|
|
|
if (unknown())
|
2014-03-08 12:37:57 -08:00
|
|
|
return true;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
if (type.isUnknown()) {
|
2011-10-18 11:24:28 -07:00
|
|
|
flags |= TYPE_FLAG_BASE_MASK;
|
2011-07-15 10:14:07 -07:00
|
|
|
clearObjects();
|
2011-10-18 11:24:28 -07:00
|
|
|
JS_ASSERT(unknown());
|
2014-03-08 12:37:57 -08:00
|
|
|
return true;
|
2013-10-17 09:21:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (type.isPrimitive()) {
|
2011-07-15 10:14:07 -07:00
|
|
|
TypeFlags flag = PrimitiveTypeFlag(type.primitive());
|
2011-07-21 07:28:01 -07:00
|
|
|
if (flags & flag)
|
2014-03-08 12:37:57 -08:00
|
|
|
return true;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
|
|
|
/* If we add float to a type set it is also considered to contain int. */
|
|
|
|
if (flag == TYPE_FLAG_DOUBLE)
|
|
|
|
flag |= TYPE_FLAG_INT32;
|
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
flags |= flag;
|
2014-03-08 12:37:57 -08:00
|
|
|
return true;
|
2013-10-17 09:21:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & TYPE_FLAG_ANYOBJECT)
|
2014-03-08 12:37:57 -08:00
|
|
|
return true;
|
2013-10-17 09:21:05 -07:00
|
|
|
if (type.isAnyObject())
|
|
|
|
goto unknownObject;
|
2012-08-22 11:28:34 -07:00
|
|
|
|
2013-10-17 09:21:05 -07:00
|
|
|
{
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
uint32_t objectCount = baseObjectCount();
|
2011-07-15 10:14:07 -07:00
|
|
|
TypeObjectKey *object = type.objectKey();
|
|
|
|
TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
|
2013-10-17 09:21:05 -07:00
|
|
|
(*alloc, objectSet, objectCount, object);
|
|
|
|
if (!pentry)
|
2014-03-08 12:37:57 -08:00
|
|
|
return false;
|
2011-08-17 06:48:14 -07:00
|
|
|
if (*pentry)
|
2014-03-08 12:37:57 -08:00
|
|
|
return true;
|
2011-03-03 14:07:48 -08:00
|
|
|
*pentry = object;
|
2011-03-09 11:04:36 -08:00
|
|
|
|
2011-07-21 07:28:01 -07:00
|
|
|
setBaseObjectCount(objectCount);
|
|
|
|
|
2011-07-31 08:40:46 -07:00
|
|
|
if (objectCount == TYPE_FLAG_OBJECT_COUNT_LIMIT)
|
|
|
|
goto unknownObject;
|
2013-10-17 09:21:05 -07:00
|
|
|
}
|
2011-07-31 08:40:46 -07:00
|
|
|
|
2013-10-17 09:21:05 -07:00
|
|
|
if (type.isTypeObject()) {
|
|
|
|
TypeObject *nobject = type.typeObject();
|
2013-12-19 10:01:25 -08:00
|
|
|
JS_ASSERT(!nobject->singleton());
|
2013-10-17 09:21:05 -07:00
|
|
|
if (nobject->unknownProperties())
|
|
|
|
goto unknownObject;
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
if (false) {
|
|
|
|
unknownObject:
|
|
|
|
type = Type::AnyObjectType();
|
2011-07-21 07:28:01 -07:00
|
|
|
flags |= TYPE_FLAG_ANYOBJECT;
|
2011-07-15 10:14:07 -07:00
|
|
|
clearObjects();
|
|
|
|
}
|
2014-03-08 12:37:57 -08:00
|
|
|
|
|
|
|
return true;
|
2013-10-17 09:21:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2013-11-04 07:29:46 -08:00
|
|
|
ConstraintTypeSet::addType(ExclusiveContext *cxArg, Type type)
|
2013-10-17 09:21:05 -07:00
|
|
|
{
|
|
|
|
JS_ASSERT(cxArg->compartment()->activeAnalysis);
|
|
|
|
|
2013-12-16 10:53:02 -08:00
|
|
|
if (hasType(type))
|
2013-10-17 09:21:05 -07:00
|
|
|
return;
|
2013-12-16 10:53:02 -08:00
|
|
|
|
2014-03-08 12:37:57 -08:00
|
|
|
if (!TypeSet::addType(type, &cxArg->typeLifoAlloc())) {
|
|
|
|
cxArg->compartment()->types.setPendingNukeTypes(cxArg);
|
|
|
|
return;
|
|
|
|
}
|
2013-10-17 09:21:05 -07:00
|
|
|
|
2011-06-15 19:22:27 -07:00
|
|
|
InferSpew(ISpewOps, "addType: %sT%p%s %s",
|
|
|
|
InferSpewColor(this), this, InferSpewColorReset(),
|
|
|
|
TypeString(type));
|
2011-03-17 09:42:56 -07:00
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/* Propagate the type to all constraints. */
|
2013-08-22 06:13:18 -07:00
|
|
|
if (JSContext *cx = cxArg->maybeJSContext()) {
|
|
|
|
TypeConstraint *constraint = constraintList;
|
|
|
|
while (constraint) {
|
2013-12-12 13:10:54 -08:00
|
|
|
constraint->newType(cx, this, type);
|
2013-08-22 06:13:18 -07:00
|
|
|
constraint = constraint->next;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
JS_ASSERT(!constraintList);
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-11 20:10:46 -07:00
|
|
|
inline void
|
2014-01-06 10:02:28 -08:00
|
|
|
HeapTypeSet::newPropertyState(ExclusiveContext *cxArg)
|
2011-04-11 20:10:46 -07:00
|
|
|
{
|
|
|
|
/* Propagate the change to all constraints. */
|
2013-08-22 06:13:18 -07:00
|
|
|
if (JSContext *cx = cxArg->maybeJSContext()) {
|
|
|
|
TypeConstraint *constraint = constraintList;
|
|
|
|
while (constraint) {
|
|
|
|
constraint->newPropertyState(cx, this);
|
|
|
|
constraint = constraint->next;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
JS_ASSERT(!constraintList);
|
2011-04-11 20:10:46 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-06 10:02:28 -08:00
|
|
|
inline void
|
|
|
|
HeapTypeSet::setNonDataProperty(ExclusiveContext *cx)
|
|
|
|
{
|
|
|
|
if (flags & TYPE_FLAG_NON_DATA_PROPERTY)
|
|
|
|
return;
|
|
|
|
|
|
|
|
flags |= TYPE_FLAG_NON_DATA_PROPERTY;
|
|
|
|
newPropertyState(cx);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
HeapTypeSet::setNonWritableProperty(ExclusiveContext *cx)
|
|
|
|
{
|
|
|
|
if (flags & TYPE_FLAG_NON_WRITABLE_PROPERTY)
|
|
|
|
return;
|
|
|
|
|
|
|
|
flags |= TYPE_FLAG_NON_WRITABLE_PROPERTY;
|
|
|
|
newPropertyState(cx);
|
|
|
|
}
|
|
|
|
|
2011-04-05 18:12:03 -07:00
|
|
|
inline unsigned
|
2012-11-26 13:32:45 -08:00
|
|
|
TypeSet::getObjectCount() const
|
2011-04-05 18:12:03 -07:00
|
|
|
{
|
2011-07-15 10:14:07 -07:00
|
|
|
JS_ASSERT(!unknownObject());
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
uint32_t count = baseObjectCount();
|
2011-07-21 07:28:01 -07:00
|
|
|
if (count > SET_ARRAY_SIZE)
|
|
|
|
return HashSetCapacity(count);
|
|
|
|
return count;
|
2011-04-05 18:12:03 -07:00
|
|
|
}
|
|
|
|
|
2011-07-15 10:14:07 -07:00
|
|
|
inline TypeObjectKey *
|
2012-11-26 13:32:45 -08:00
|
|
|
TypeSet::getObject(unsigned i) const
|
2011-04-05 18:12:03 -07:00
|
|
|
{
|
2011-07-15 10:14:07 -07:00
|
|
|
JS_ASSERT(i < getObjectCount());
|
2011-07-21 07:28:01 -07:00
|
|
|
if (baseObjectCount() == 1) {
|
2011-04-05 18:12:03 -07:00
|
|
|
JS_ASSERT(i == 0);
|
2011-07-15 10:14:07 -07:00
|
|
|
return (TypeObjectKey *) objectSet;
|
2011-04-05 18:12:03 -07:00
|
|
|
}
|
|
|
|
return objectSet[i];
|
|
|
|
}
|
|
|
|
|
2013-04-30 15:41:12 -07:00
|
|
|
inline JSObject *
|
2012-11-26 13:32:45 -08:00
|
|
|
TypeSet::getSingleObject(unsigned i) const
|
2011-07-15 10:14:07 -07:00
|
|
|
{
|
|
|
|
TypeObjectKey *key = getObject(i);
|
2013-10-07 09:43:32 -07:00
|
|
|
return (key && key->isSingleObject()) ? key->asSingleObject() : nullptr;
|
2011-07-15 10:14:07 -07:00
|
|
|
}
|
|
|
|
|
2011-05-12 20:07:23 -07:00
|
|
|
inline TypeObject *
|
2012-11-26 13:32:45 -08:00
|
|
|
TypeSet::getTypeObject(unsigned i) const
|
2011-05-12 20:07:23 -07:00
|
|
|
{
|
2011-07-15 10:14:07 -07:00
|
|
|
TypeObjectKey *key = getObject(i);
|
2013-10-07 09:43:32 -07:00
|
|
|
return (key && key->isTypeObject()) ? key->asTypeObject() : nullptr;
|
2011-05-12 20:07:23 -07:00
|
|
|
}
|
|
|
|
|
2014-03-08 12:37:57 -08:00
|
|
|
inline bool
|
|
|
|
TypeSet::getTypeOrSingleObject(JSContext *cx, unsigned i, TypeObject **result) const
|
|
|
|
{
|
|
|
|
JS_ASSERT(result);
|
|
|
|
JS_ASSERT(cx->compartment()->activeAnalysis);
|
|
|
|
|
|
|
|
*result = nullptr;
|
|
|
|
|
|
|
|
TypeObject *type = getTypeObject(i);
|
|
|
|
if (!type) {
|
|
|
|
JSObject *singleton = getSingleObject(i);
|
|
|
|
if (!singleton)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
type = singleton->uninlinedGetType(cx);
|
|
|
|
if (!type) {
|
|
|
|
cx->compartment()->types.setPendingNukeTypes(cx);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*result = type;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-27 01:02:55 -07:00
|
|
|
inline const Class *
|
|
|
|
TypeSet::getObjectClass(unsigned i) const
|
|
|
|
{
|
|
|
|
if (JSObject *object = getSingleObject(i))
|
|
|
|
return object->getClass();
|
|
|
|
if (TypeObject *object = getTypeObject(i))
|
2013-12-16 10:53:02 -08:00
|
|
|
return object->clasp();
|
2013-10-07 09:43:32 -07:00
|
|
|
return nullptr;
|
2013-09-27 01:02:55 -07:00
|
|
|
}
|
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
2010-11-24 17:41:52 -08:00
|
|
|
// TypeObject
|
2010-10-29 08:05:55 -07:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
2013-12-16 10:53:02 -08:00
|
|
|
inline TypeObject::TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags)
|
2011-06-15 11:26:12 -07:00
|
|
|
{
|
2013-04-01 22:43:19 -07:00
|
|
|
mozilla::PodZero(this);
|
2011-07-15 10:14:07 -07:00
|
|
|
|
2012-01-27 12:16:27 -08:00
|
|
|
/* Inner objects may not appear on prototype chains. */
|
2012-09-26 09:49:20 -07:00
|
|
|
JS_ASSERT_IF(proto.isObject(), !proto.toObject()->getClass()->ext.outerObject);
|
2012-01-27 12:16:27 -08:00
|
|
|
|
2013-12-16 10:53:02 -08:00
|
|
|
this->clasp_ = clasp;
|
|
|
|
this->proto_ = proto.raw();
|
|
|
|
this->flags_ = initialFlags;
|
2011-07-15 10:14:07 -07:00
|
|
|
|
2011-08-26 08:55:00 -07:00
|
|
|
InferSpew(ISpewOps, "newObject: %s", TypeObjectString(this));
|
2011-06-15 11:26:12 -07:00
|
|
|
}
|
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
inline uint32_t
|
2011-07-21 07:28:01 -07:00
|
|
|
TypeObject::basePropertyCount() const
|
|
|
|
{
|
2013-12-16 10:53:02 -08:00
|
|
|
return (flags() & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
|
2011-07-21 07:28:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
TypeObject::setBasePropertyCount(uint32_t count)
|
2011-07-21 07:28:01 -07:00
|
|
|
{
|
2013-12-16 10:53:02 -08:00
|
|
|
// Note: Callers must ensure they are performing threadsafe operations.
|
2011-07-21 07:28:01 -07:00
|
|
|
JS_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT);
|
2013-12-16 10:53:02 -08:00
|
|
|
flags_ = (flags() & ~OBJECT_FLAG_PROPERTY_COUNT_MASK)
|
|
|
|
| (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
|
2011-07-21 07:28:01 -07:00
|
|
|
}
|
|
|
|
|
2012-08-22 11:28:34 -07:00
|
|
|
inline HeapTypeSet *
|
2013-09-27 10:29:35 -07:00
|
|
|
TypeObject::getProperty(ExclusiveContext *cx, jsid id)
|
2010-10-29 08:05:55 -07:00
|
|
|
{
|
2013-06-10 14:22:18 -07:00
|
|
|
JS_ASSERT(cx->compartment()->activeAnalysis);
|
2012-12-31 12:40:21 -08:00
|
|
|
|
2010-12-18 20:44:51 -08:00
|
|
|
JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
|
2012-12-31 12:40:21 -08:00
|
|
|
JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
|
2011-04-05 18:12:03 -07:00
|
|
|
JS_ASSERT(!unknownProperties());
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2013-12-16 10:53:02 -08:00
|
|
|
if (HeapTypeSet *types = maybeGetProperty(id))
|
|
|
|
return types;
|
|
|
|
|
2014-02-14 04:17:53 -08:00
|
|
|
uint32_t propertyCount = basePropertyCount();
|
|
|
|
Property **pprop = HashSetInsert<jsid,Property,Property>
|
|
|
|
(cx->typeLifoAlloc(), propertySet, propertyCount, id);
|
|
|
|
if (!pprop) {
|
2014-03-08 12:37:57 -08:00
|
|
|
cx->compartment()->types.setPendingNukeTypes(cx);
|
2014-02-14 04:17:53 -08:00
|
|
|
return nullptr;
|
|
|
|
}
|
2013-12-16 10:53:02 -08:00
|
|
|
|
2014-02-14 04:17:53 -08:00
|
|
|
JS_ASSERT(!*pprop);
|
2010-11-20 15:45:52 -08:00
|
|
|
|
2014-02-14 04:17:53 -08:00
|
|
|
setBasePropertyCount(propertyCount);
|
|
|
|
if (!addProperty(cx, id, pprop)) {
|
2014-03-08 12:37:57 -08:00
|
|
|
setBasePropertyCount(0);
|
|
|
|
propertySet = nullptr;
|
2014-02-14 04:17:53 -08:00
|
|
|
return nullptr;
|
2013-12-16 10:53:02 -08:00
|
|
|
}
|
2012-06-25 17:32:34 -07:00
|
|
|
|
2013-12-16 10:53:02 -08:00
|
|
|
if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
|
|
|
|
markUnknown(cx);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return an arbitrary property in the object, as all have unknown
|
2014-01-06 10:02:28 -08:00
|
|
|
* type and are treated as non-data properties.
|
2013-12-16 10:53:02 -08:00
|
|
|
*/
|
|
|
|
unsigned count = getPropertyCount();
|
|
|
|
for (unsigned i = 0; i < count; i++) {
|
|
|
|
if (Property *prop = getProperty(i))
|
|
|
|
return &prop->types;
|
2012-06-25 17:32:34 -07:00
|
|
|
}
|
2013-12-16 10:53:02 -08:00
|
|
|
|
|
|
|
MOZ_ASSUME_UNREACHABLE("Missing property");
|
2012-06-25 17:32:34 -07:00
|
|
|
}
|
2011-04-11 20:10:46 -07:00
|
|
|
|
2013-09-27 10:29:35 -07:00
|
|
|
return &(*pprop)->types;
|
2010-10-29 08:05:55 -07:00
|
|
|
}
|
|
|
|
|
2012-08-22 11:28:34 -07:00
|
|
|
inline HeapTypeSet *
|
2013-10-08 15:14:04 -07:00
|
|
|
TypeObject::maybeGetProperty(jsid id)
|
2011-07-15 10:14:07 -07:00
|
|
|
{
|
2011-07-21 07:28:01 -07:00
|
|
|
JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
|
2012-12-31 12:40:21 -08:00
|
|
|
JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
|
2011-07-15 10:14:07 -07:00
|
|
|
JS_ASSERT(!unknownProperties());
|
2013-12-19 10:01:25 -08:00
|
|
|
|
2013-04-30 15:41:04 -07:00
|
|
|
Property *prop = HashSetLookup<jsid,Property,Property>
|
2011-07-21 07:28:01 -07:00
|
|
|
(propertySet, basePropertyCount(), id);
|
|
|
|
|
2013-10-07 09:43:32 -07:00
|
|
|
return prop ? &prop->types : nullptr;
|
2011-07-15 10:14:07 -07:00
|
|
|
}
|
|
|
|
|
2011-04-05 18:12:03 -07:00
|
|
|
inline unsigned
|
|
|
|
TypeObject::getPropertyCount()
|
|
|
|
{
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
uint32_t count = basePropertyCount();
|
2011-07-21 07:28:01 -07:00
|
|
|
if (count > SET_ARRAY_SIZE)
|
|
|
|
return HashSetCapacity(count);
|
|
|
|
return count;
|
2011-04-05 18:12:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline Property *
|
|
|
|
TypeObject::getProperty(unsigned i)
|
|
|
|
{
|
2011-07-21 07:28:01 -07:00
|
|
|
JS_ASSERT(i < getPropertyCount());
|
|
|
|
if (basePropertyCount() == 1) {
|
2011-04-05 18:12:03 -07:00
|
|
|
JS_ASSERT(i == 0);
|
|
|
|
return (Property *) propertySet;
|
|
|
|
}
|
|
|
|
return propertySet[i];
|
|
|
|
}
|
|
|
|
|
2013-07-20 13:18:53 -07:00
|
|
|
inline void
|
2014-01-07 13:49:39 -08:00
|
|
|
TypeObjectAddendum::writeBarrierPre(TypeObjectAddendum *type)
|
|
|
|
{
|
|
|
|
#ifdef JSGC_INCREMENTAL
|
|
|
|
if (!type)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (type->kind) {
|
|
|
|
case NewScript:
|
|
|
|
return TypeNewScript::writeBarrierPre(type->asNewScript());
|
|
|
|
|
|
|
|
case TypedObject:
|
|
|
|
return TypeTypedObject::writeBarrierPre(type->asTypedObject());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
TypeNewScript::writeBarrierPre(TypeNewScript *newScript)
|
2011-10-25 16:07:42 -07:00
|
|
|
{
|
|
|
|
#ifdef JSGC_INCREMENTAL
|
2013-08-05 07:48:34 -07:00
|
|
|
if (!newScript || !newScript->fun->runtimeFromAnyThread()->needsBarrier())
|
2011-10-25 16:07:42 -07:00
|
|
|
return;
|
|
|
|
|
2013-10-08 15:14:03 -07:00
|
|
|
JS::Zone *zone = newScript->fun->zoneFromAnyThread();
|
2013-01-27 13:51:41 -08:00
|
|
|
if (zone->needsBarrier()) {
|
|
|
|
MarkObject(zone->barrierTracer(), &newScript->fun, "write barrier");
|
2013-10-17 12:50:26 -07:00
|
|
|
MarkObject(zone->barrierTracer(), &newScript->templateObject, "write barrier");
|
2011-10-25 16:07:42 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-12-18 20:44:51 -08:00
|
|
|
} } /* namespace js::types */
|
|
|
|
|
2011-06-06 08:32:41 -07:00
|
|
|
inline bool
|
2011-10-21 14:31:01 -07:00
|
|
|
JSScript::ensureHasTypes(JSContext *cx)
|
2011-07-28 09:16:53 -07:00
|
|
|
{
|
2011-10-21 14:31:01 -07:00
|
|
|
return types || makeTypes(cx);
|
2011-07-28 09:16:53 -07:00
|
|
|
}
|
|
|
|
|
2013-01-26 06:42:20 -08:00
|
|
|
inline bool
|
|
|
|
JSScript::ensureRanAnalysis(JSContext *cx)
|
2011-07-28 09:16:53 -07:00
|
|
|
{
|
2013-01-18 08:23:28 -08:00
|
|
|
js::types::AutoEnterAnalysis aea(cx);
|
2011-12-31 06:32:04 -08:00
|
|
|
|
2013-01-26 06:42:20 -08:00
|
|
|
if (!ensureHasTypes(cx))
|
2011-12-31 06:13:01 -08:00
|
|
|
return false;
|
2013-01-26 06:42:20 -08:00
|
|
|
if (!hasAnalysis() && !makeAnalysis(cx))
|
2011-07-28 09:16:53 -07:00
|
|
|
return false;
|
2014-01-21 05:21:26 -08:00
|
|
|
JS_ASSERT(hasAnalysis());
|
2011-07-28 09:16:53 -07:00
|
|
|
return true;
|
2011-06-06 08:32:41 -07:00
|
|
|
}
|
|
|
|
|
2011-07-28 09:16:53 -07:00
|
|
|
inline bool
|
|
|
|
JSScript::hasAnalysis()
|
|
|
|
{
|
|
|
|
return types && types->analysis;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline js::analyze::ScriptAnalysis *
|
|
|
|
JSScript::analysis()
|
|
|
|
{
|
|
|
|
JS_ASSERT(hasAnalysis());
|
|
|
|
return types->analysis;
|
2011-06-06 08:32:41 -07:00
|
|
|
}
|
|
|
|
|
2011-09-01 12:20:30 -07:00
|
|
|
inline void
|
|
|
|
JSScript::clearAnalysis()
|
|
|
|
{
|
2013-10-22 07:08:10 -07:00
|
|
|
if (types)
|
2013-10-07 09:43:32 -07:00
|
|
|
types->analysis = nullptr;
|
2011-09-01 12:20:30 -07:00
|
|
|
}
|
|
|
|
|
2012-09-24 18:08:22 -07:00
|
|
|
namespace js {
|
2012-07-02 09:25:09 -07:00
|
|
|
|
|
|
|
template <>
|
2013-06-19 03:32:26 -07:00
|
|
|
struct GCMethods<const types::Type>
|
2012-07-02 09:25:09 -07:00
|
|
|
{
|
2012-09-24 18:08:22 -07:00
|
|
|
static types::Type initial() { return types::Type::UnknownType(); }
|
2012-07-02 09:25:09 -07:00
|
|
|
static ThingRootKind kind() { return THING_ROOT_TYPE; }
|
2012-09-24 18:08:22 -07:00
|
|
|
static bool poisoned(const types::Type &v) {
|
2012-07-02 09:25:09 -07:00
|
|
|
return (v.isTypeObject() && IsPoisonedPtr(v.typeObject()))
|
|
|
|
|| (v.isSingleObject() && IsPoisonedPtr(v.singleObject()));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
2013-06-19 03:32:26 -07:00
|
|
|
struct GCMethods<types::Type>
|
2012-07-02 09:25:09 -07:00
|
|
|
{
|
2012-09-24 18:08:22 -07:00
|
|
|
static types::Type initial() { return types::Type::UnknownType(); }
|
2012-07-02 09:25:09 -07:00
|
|
|
static ThingRootKind kind() { return THING_ROOT_TYPE; }
|
2012-09-24 18:08:22 -07:00
|
|
|
static bool poisoned(const types::Type &v) {
|
2012-07-02 09:25:09 -07:00
|
|
|
return (v.isTypeObject() && IsPoisonedPtr(v.typeObject()))
|
|
|
|
|| (v.isSingleObject() && IsPoisonedPtr(v.singleObject()));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-09-24 18:08:22 -07:00
|
|
|
} // namespace js
|
|
|
|
|
|
|
|
namespace JS {
|
|
|
|
template<> class AnchorPermitted<js::types::TypeObject *> { };
|
2012-07-02 09:25:09 -07:00
|
|
|
} // namespace JS
|
|
|
|
|
2013-06-19 17:59:46 -07:00
|
|
|
#endif /* jsinferinlines_h */
|