js/src/jsinferinlines.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jsinferinlines.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1286 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* Inline members for javascript type inference. */
    1.11 +
    1.12 +#ifndef jsinferinlines_h
    1.13 +#define jsinferinlines_h
    1.14 +
    1.15 +#include "jsinfer.h"
    1.16 +
    1.17 +#include "mozilla/PodOperations.h"
    1.18 +
    1.19 +#include "jsanalyze.h"
    1.20 +
    1.21 +#include "vm/ArrayObject.h"
    1.22 +#include "vm/BooleanObject.h"
    1.23 +#include "vm/NumberObject.h"
    1.24 +#include "vm/SharedArrayObject.h"
    1.25 +#include "vm/StringObject.h"
    1.26 +#include "vm/TypedArrayObject.h"
    1.27 +
    1.28 +#include "jscntxtinlines.h"
    1.29 +
    1.30 +#include "jit/ExecutionMode-inl.h"
    1.31 +
    1.32 +namespace js {
    1.33 +namespace types {
    1.34 +
    1.35 +/////////////////////////////////////////////////////////////////////
    1.36 +// CompilerOutput & RecompileInfo
    1.37 +/////////////////////////////////////////////////////////////////////
    1.38 +
    1.39 +inline jit::IonScript *
    1.40 +CompilerOutput::ion() const
    1.41 +{
    1.42 +#ifdef JS_ION
    1.43 +    // Note: If type constraints are generated before compilation has finished
    1.44 +    // (i.e. after IonBuilder but before CodeGenerator::link) then a valid
    1.45 +    // CompilerOutput may not yet have an associated IonScript.
    1.46 +    JS_ASSERT(isValid());
    1.47 +    jit::IonScript *ion = jit::GetIonScript(script(), mode());
    1.48 +    JS_ASSERT(ion != ION_COMPILING_SCRIPT);
    1.49 +    return ion;
    1.50 +#endif
    1.51 +    MOZ_ASSUME_UNREACHABLE("Invalid kind of CompilerOutput");
    1.52 +}
    1.53 +
    1.54 +inline CompilerOutput*
    1.55 +RecompileInfo::compilerOutput(TypeZone &types) const
    1.56 +{
    1.57 +    if (!types.compilerOutputs || outputIndex >= types.compilerOutputs->length())
    1.58 +        return nullptr;
    1.59 +    return &(*types.compilerOutputs)[outputIndex];
    1.60 +}
    1.61 +
    1.62 +inline CompilerOutput*
    1.63 +RecompileInfo::compilerOutput(JSContext *cx) const
    1.64 +{
    1.65 +    return compilerOutput(cx->zone()->types);
    1.66 +}
    1.67 +
    1.68 +inline bool
    1.69 +RecompileInfo::shouldSweep(TypeZone &types)
    1.70 +{
    1.71 +    CompilerOutput *output = compilerOutput(types);
    1.72 +    if (!output || !output->isValid())
    1.73 +        return true;
    1.74 +
    1.75 +    // Update this info for the output's new index in the zone's compiler outputs.
    1.76 +    outputIndex = output->sweepIndex();
    1.77 +    return false;
    1.78 +}
    1.79 +
    1.80 +/////////////////////////////////////////////////////////////////////
    1.81 +// Types
    1.82 +/////////////////////////////////////////////////////////////////////
    1.83 +
    1.84 +/* static */ inline Type
    1.85 +Type::ObjectType(JSObject *obj)
    1.86 +{
    1.87 +    if (obj->hasSingletonType())
    1.88 +        return Type(uintptr_t(obj) | 1);
    1.89 +    return Type(uintptr_t(obj->type()));
    1.90 +}
    1.91 +
    1.92 +/* static */ inline Type
    1.93 +Type::ObjectType(TypeObject *obj)
    1.94 +{
    1.95 +    if (obj->singleton())
    1.96 +        return Type(uintptr_t(obj->singleton()) | 1);
    1.97 +    return Type(uintptr_t(obj));
    1.98 +}
    1.99 +
   1.100 +/* static */ inline Type
   1.101 +Type::ObjectType(TypeObjectKey *obj)
   1.102 +{
   1.103 +    return Type(uintptr_t(obj));
   1.104 +}
   1.105 +
   1.106 +inline Type
   1.107 +GetValueType(const Value &val)
   1.108 +{
   1.109 +    if (val.isDouble())
   1.110 +        return Type::DoubleType();
   1.111 +    if (val.isObject())
   1.112 +        return Type::ObjectType(&val.toObject());
   1.113 +    return Type::PrimitiveType(val.extractNonDoubleType());
   1.114 +}
   1.115 +
   1.116 +inline Type
   1.117 +GetMaybeOptimizedOutValueType(const Value &val)
   1.118 +{
   1.119 +    if (val.isMagic() && val.whyMagic() == JS_OPTIMIZED_OUT)
   1.120 +        return Type::UnknownType();
   1.121 +    return GetValueType(val);
   1.122 +}
   1.123 +
   1.124 +inline TypeFlags
   1.125 +PrimitiveTypeFlag(JSValueType type)
   1.126 +{
   1.127 +    switch (type) {
   1.128 +      case JSVAL_TYPE_UNDEFINED:
   1.129 +        return TYPE_FLAG_UNDEFINED;
   1.130 +      case JSVAL_TYPE_NULL:
   1.131 +        return TYPE_FLAG_NULL;
   1.132 +      case JSVAL_TYPE_BOOLEAN:
   1.133 +        return TYPE_FLAG_BOOLEAN;
   1.134 +      case JSVAL_TYPE_INT32:
   1.135 +        return TYPE_FLAG_INT32;
   1.136 +      case JSVAL_TYPE_DOUBLE:
   1.137 +        return TYPE_FLAG_DOUBLE;
   1.138 +      case JSVAL_TYPE_STRING:
   1.139 +        return TYPE_FLAG_STRING;
   1.140 +      case JSVAL_TYPE_MAGIC:
   1.141 +        return TYPE_FLAG_LAZYARGS;
   1.142 +      default:
   1.143 +        MOZ_ASSUME_UNREACHABLE("Bad type");
   1.144 +    }
   1.145 +}
   1.146 +
   1.147 +inline JSValueType
   1.148 +TypeFlagPrimitive(TypeFlags flags)
   1.149 +{
   1.150 +    switch (flags) {
   1.151 +      case TYPE_FLAG_UNDEFINED:
   1.152 +        return JSVAL_TYPE_UNDEFINED;
   1.153 +      case TYPE_FLAG_NULL:
   1.154 +        return JSVAL_TYPE_NULL;
   1.155 +      case TYPE_FLAG_BOOLEAN:
   1.156 +        return JSVAL_TYPE_BOOLEAN;
   1.157 +      case TYPE_FLAG_INT32:
   1.158 +        return JSVAL_TYPE_INT32;
   1.159 +      case TYPE_FLAG_DOUBLE:
   1.160 +        return JSVAL_TYPE_DOUBLE;
   1.161 +      case TYPE_FLAG_STRING:
   1.162 +        return JSVAL_TYPE_STRING;
   1.163 +      case TYPE_FLAG_LAZYARGS:
   1.164 +        return JSVAL_TYPE_MAGIC;
   1.165 +      default:
   1.166 +        MOZ_ASSUME_UNREACHABLE("Bad type");
   1.167 +    }
   1.168 +}
   1.169 +
   1.170 +/*
   1.171 + * Get the canonical representation of an id to use when doing inference.  This
   1.172 + * maintains the constraint that if two different jsids map to the same property
   1.173 + * in JS (e.g. 3 and "3"), they have the same type representation.
   1.174 + */
   1.175 +inline jsid
   1.176 +IdToTypeId(jsid id)
   1.177 +{
   1.178 +    JS_ASSERT(!JSID_IS_EMPTY(id));
   1.179 +
   1.180 +    /*
   1.181 +     * All integers must map to the aggregate property for index types, including
   1.182 +     * negative integers.
   1.183 +     */
   1.184 +    if (JSID_IS_INT(id))
   1.185 +        return JSID_VOID;
   1.186 +
   1.187 +    /*
   1.188 +     * Check for numeric strings, as in js_StringIsIndex, but allow negative
   1.189 +     * and overflowing integers.
   1.190 +     */
   1.191 +    if (JSID_IS_STRING(id)) {
   1.192 +        JSAtom *atom = JSID_TO_ATOM(id);
   1.193 +        JS::TwoByteChars cp = atom->range();
   1.194 +        if (cp.length() > 0 && (JS7_ISDEC(cp[0]) || cp[0] == '-')) {
   1.195 +            for (size_t i = 1; i < cp.length(); ++i) {
   1.196 +                if (!JS7_ISDEC(cp[i]))
   1.197 +                    return id;
   1.198 +            }
   1.199 +            return JSID_VOID;
   1.200 +        }
   1.201 +        return id;
   1.202 +    }
   1.203 +
   1.204 +    return JSID_VOID;
   1.205 +}
   1.206 +
   1.207 +const char * TypeIdStringImpl(jsid id);
   1.208 +
   1.209 +/* Convert an id for printing during debug. */
   1.210 +static inline const char *
   1.211 +TypeIdString(jsid id)
   1.212 +{
   1.213 +#ifdef DEBUG
   1.214 +    return TypeIdStringImpl(id);
   1.215 +#else
   1.216 +    return "(missing)";
   1.217 +#endif
   1.218 +}
   1.219 +
   1.220 +/*
   1.221 + * Structure for type inference entry point functions. All functions which can
   1.222 + * change type information must use this, and functions which depend on
   1.223 + * intermediate types (i.e. JITs) can use this to ensure that intermediate
   1.224 + * information is not collected and does not change.
   1.225 + *
   1.226 + * Pins inference results so that intermediate type information, TypeObjects
   1.227 + * and JSScripts won't be collected during GC. Does additional sanity checking
   1.228 + * that inference is not reentrant and that recompilations occur properly.
   1.229 + */
   1.230 +struct AutoEnterAnalysis
   1.231 +{
   1.232 +    /* Prevent GC activity in the middle of analysis. */
   1.233 +    gc::AutoSuppressGC suppressGC;
   1.234 +
   1.235 +    FreeOp *freeOp;
   1.236 +    JSCompartment *compartment;
   1.237 +    bool oldActiveAnalysis;
   1.238 +
   1.239 +    AutoEnterAnalysis(ExclusiveContext *cx)
   1.240 +      : suppressGC(cx)
   1.241 +    {
   1.242 +        init(cx->defaultFreeOp(), cx->compartment());
   1.243 +    }
   1.244 +
   1.245 +    AutoEnterAnalysis(FreeOp *fop, JSCompartment *comp)
   1.246 +      : suppressGC(comp)
   1.247 +    {
   1.248 +        init(fop, comp);
   1.249 +    }
   1.250 +
   1.251 +    ~AutoEnterAnalysis()
   1.252 +    {
   1.253 +        compartment->activeAnalysis = oldActiveAnalysis;
   1.254 +
   1.255 +        /*
   1.256 +         * If there are no more type inference activations on the stack,
   1.257 +         * process any triggered recompilations. Note that we should not be
   1.258 +         * invoking any scripted code while type inference is running.
   1.259 +         */
   1.260 +        if (!compartment->activeAnalysis) {
   1.261 +            TypeZone &types = compartment->zone()->types;
   1.262 +            if (types.pendingRecompiles)
   1.263 +                types.processPendingRecompiles(freeOp);
   1.264 +        }
   1.265 +    }
   1.266 +
   1.267 +  private:
   1.268 +    void init(FreeOp *fop, JSCompartment *comp) {
   1.269 +        freeOp = fop;
   1.270 +        compartment = comp;
   1.271 +        oldActiveAnalysis = compartment->activeAnalysis;
   1.272 +        compartment->activeAnalysis = true;
   1.273 +    }
   1.274 +};
   1.275 +
   1.276 +/////////////////////////////////////////////////////////////////////
   1.277 +// Interface functions
   1.278 +/////////////////////////////////////////////////////////////////////
   1.279 +
   1.280 +inline const Class *
   1.281 +GetClassForProtoKey(JSProtoKey key)
   1.282 +{
   1.283 +    switch (key) {
   1.284 +      case JSProto_Object:
   1.285 +        return &JSObject::class_;
   1.286 +      case JSProto_Array:
   1.287 +        return &ArrayObject::class_;
   1.288 +
   1.289 +      case JSProto_Number:
   1.290 +        return &NumberObject::class_;
   1.291 +      case JSProto_Boolean:
   1.292 +        return &BooleanObject::class_;
   1.293 +      case JSProto_String:
   1.294 +        return &StringObject::class_;
   1.295 +      case JSProto_RegExp:
   1.296 +        return &RegExpObject::class_;
   1.297 +
   1.298 +      case JSProto_Int8Array:
   1.299 +      case JSProto_Uint8Array:
   1.300 +      case JSProto_Int16Array:
   1.301 +      case JSProto_Uint16Array:
   1.302 +      case JSProto_Int32Array:
   1.303 +      case JSProto_Uint32Array:
   1.304 +      case JSProto_Float32Array:
   1.305 +      case JSProto_Float64Array:
   1.306 +      case JSProto_Uint8ClampedArray:
   1.307 +        return &TypedArrayObject::classes[key - JSProto_Int8Array];
   1.308 +
   1.309 +      case JSProto_ArrayBuffer:
   1.310 +        return &ArrayBufferObject::class_;
   1.311 +
   1.312 +      case JSProto_SharedArrayBuffer:
   1.313 +        return &SharedArrayBufferObject::class_;
   1.314 +
   1.315 +      case JSProto_DataView:
   1.316 +        return &DataViewObject::class_;
   1.317 +
   1.318 +      default:
   1.319 +        MOZ_ASSUME_UNREACHABLE("Bad proto key");
   1.320 +    }
   1.321 +}
   1.322 +
   1.323 +/*
   1.324 + * Get the default 'new' object for a given standard class, per the currently
   1.325 + * active global.
   1.326 + */
   1.327 +inline TypeObject *
   1.328 +GetTypeNewObject(JSContext *cx, JSProtoKey key)
   1.329 +{
   1.330 +    RootedObject proto(cx);
   1.331 +    if (!GetBuiltinPrototype(cx, key, &proto))
   1.332 +        return nullptr;
   1.333 +    return cx->getNewType(GetClassForProtoKey(key), proto.get());
   1.334 +}
   1.335 +
   1.336 +/* Get a type object for the immediate allocation site within a native. */
   1.337 +inline TypeObject *
   1.338 +GetTypeCallerInitObject(JSContext *cx, JSProtoKey key)
   1.339 +{
   1.340 +    jsbytecode *pc;
   1.341 +    RootedScript script(cx, cx->currentScript(&pc));
   1.342 +    if (script)
   1.343 +        return TypeScript::InitObject(cx, script, pc, key);
   1.344 +    return GetTypeNewObject(cx, key);
   1.345 +}
   1.346 +
   1.347 +void MarkIteratorUnknownSlow(JSContext *cx);
   1.348 +
   1.349 +void TypeMonitorCallSlow(JSContext *cx, JSObject *callee, const CallArgs &args,
   1.350 +                         bool constructing);
   1.351 +
   1.352 +/*
   1.353 + * Monitor a javascript call, either on entry to the interpreter or made
   1.354 + * from within the interpreter.
   1.355 + */
   1.356 +inline void
   1.357 +TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing)
   1.358 +{
   1.359 +    if (args.callee().is<JSFunction>()) {
   1.360 +        JSFunction *fun = &args.callee().as<JSFunction>();
   1.361 +        if (fun->isInterpreted() && fun->nonLazyScript()->types)
   1.362 +            TypeMonitorCallSlow(cx, &args.callee(), args, constructing);
   1.363 +    }
   1.364 +}
   1.365 +
   1.366 +inline bool
   1.367 +TrackPropertyTypes(ExclusiveContext *cx, JSObject *obj, jsid id)
   1.368 +{
   1.369 +    if (obj->hasLazyType() || obj->type()->unknownProperties())
   1.370 +        return false;
   1.371 +
   1.372 +    if (obj->hasSingletonType() && !obj->type()->maybeGetProperty(id))
   1.373 +        return false;
   1.374 +
   1.375 +    return true;
   1.376 +}
   1.377 +
   1.378 +inline void
   1.379 +EnsureTrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
   1.380 +{
   1.381 +    id = IdToTypeId(id);
   1.382 +
   1.383 +    if (obj->hasSingletonType()) {
   1.384 +        AutoEnterAnalysis enter(cx);
   1.385 +        if (obj->hasLazyType() && !obj->getType(cx)) {
   1.386 +            CrashAtUnhandlableOOM("Could not allocate TypeObject in EnsureTrackPropertyTypes");
   1.387 +            return;
   1.388 +        }
   1.389 +        if (!obj->type()->unknownProperties() && !obj->type()->getProperty(cx, id)) {
   1.390 +            MOZ_ASSERT(obj->type()->unknownProperties());
   1.391 +            return;
   1.392 +        }
   1.393 +    }
   1.394 +
   1.395 +    JS_ASSERT(obj->type()->unknownProperties() || TrackPropertyTypes(cx, obj, id));
   1.396 +}
   1.397 +
   1.398 +inline bool
   1.399 +CanHaveEmptyPropertyTypesForOwnProperty(JSObject *obj)
   1.400 +{
   1.401 +    // Per the comment on TypeSet::propertySet, property type sets for global
   1.402 +    // objects may be empty for 'own' properties if the global property still
   1.403 +    // has its initial undefined value.
   1.404 +    return obj->is<GlobalObject>();
   1.405 +}
   1.406 +
   1.407 +inline bool
   1.408 +HasTypePropertyId(JSObject *obj, jsid id, Type type)
   1.409 +{
   1.410 +    if (obj->hasLazyType())
   1.411 +        return true;
   1.412 +
   1.413 +    if (obj->type()->unknownProperties())
   1.414 +        return true;
   1.415 +
   1.416 +    if (HeapTypeSet *types = obj->type()->maybeGetProperty(IdToTypeId(id)))
   1.417 +        return types->hasType(type);
   1.418 +
   1.419 +    return false;
   1.420 +}
   1.421 +
   1.422 +inline bool
   1.423 +HasTypePropertyId(JSObject *obj, jsid id, const Value &value)
   1.424 +{
   1.425 +    return HasTypePropertyId(obj, id, GetValueType(value));
   1.426 +}
   1.427 +
   1.428 +/* Add a possible type for a property of obj. */
   1.429 +inline void
   1.430 +AddTypePropertyId(ExclusiveContext *cx, JSObject *obj, jsid id, Type type)
   1.431 +{
   1.432 +    id = IdToTypeId(id);
   1.433 +    if (TrackPropertyTypes(cx, obj, id))
   1.434 +        obj->type()->addPropertyType(cx, id, type);
   1.435 +}
   1.436 +
   1.437 +inline void
   1.438 +AddTypePropertyId(ExclusiveContext *cx, JSObject *obj, jsid id, const Value &value)
   1.439 +{
   1.440 +    id = IdToTypeId(id);
   1.441 +    if (TrackPropertyTypes(cx, obj, id))
   1.442 +        obj->type()->addPropertyType(cx, id, value);
   1.443 +}
   1.444 +
   1.445 +inline void
   1.446 +AddTypePropertyId(ExclusiveContext *cx, TypeObject *obj, jsid id, Type type)
   1.447 +{
   1.448 +    if (!obj->unknownProperties())
   1.449 +        obj->addPropertyType(cx, id, type);
   1.450 +}
   1.451 +
   1.452 +inline void
   1.453 +AddTypePropertyId(ExclusiveContext *cx, TypeObject *obj, jsid id, const Value &value)
   1.454 +{
   1.455 +    if (!obj->unknownProperties())
   1.456 +        obj->addPropertyType(cx, id, value);
   1.457 +}
   1.458 +
   1.459 +/* Set one or more dynamic flags on a type object. */
   1.460 +inline void
   1.461 +MarkTypeObjectFlags(ExclusiveContext *cx, JSObject *obj, TypeObjectFlags flags)
   1.462 +{
   1.463 +    if (!obj->hasLazyType() && !obj->type()->hasAllFlags(flags))
   1.464 +        obj->type()->setFlags(cx, flags);
   1.465 +}
   1.466 +
   1.467 +/*
   1.468 + * Mark all properties of a type object as unknown. If markSetsUnknown is set,
   1.469 + * scan the entire compartment and mark all type sets containing it as having
   1.470 + * an unknown object. This is needed for correctness in dealing with mutable
   1.471 + * __proto__, which can change the type of an object dynamically.
   1.472 + */
   1.473 +inline void
   1.474 +MarkTypeObjectUnknownProperties(JSContext *cx, TypeObject *obj,
   1.475 +                                bool markSetsUnknown = false)
   1.476 +{
   1.477 +    if (!obj->unknownProperties())
   1.478 +        obj->markUnknown(cx);
   1.479 +    if (markSetsUnknown && !(obj->flags() & OBJECT_FLAG_SETS_MARKED_UNKNOWN))
   1.480 +        cx->compartment()->types.markSetsUnknown(cx, obj);
   1.481 +}
   1.482 +
   1.483 +inline void
   1.484 +MarkTypePropertyNonData(ExclusiveContext *cx, JSObject *obj, jsid id)
   1.485 +{
   1.486 +    id = IdToTypeId(id);
   1.487 +    if (TrackPropertyTypes(cx, obj, id))
   1.488 +        obj->type()->markPropertyNonData(cx, id);
   1.489 +}
   1.490 +
   1.491 +inline void
   1.492 +MarkTypePropertyNonWritable(ExclusiveContext *cx, JSObject *obj, jsid id)
   1.493 +{
   1.494 +    id = IdToTypeId(id);
   1.495 +    if (TrackPropertyTypes(cx, obj, id))
   1.496 +        obj->type()->markPropertyNonWritable(cx, id);
   1.497 +}
   1.498 +
   1.499 +inline bool
   1.500 +IsTypePropertyIdMarkedNonData(JSObject *obj, jsid id)
   1.501 +{
   1.502 +    return obj->type()->isPropertyNonData(id);
   1.503 +}
   1.504 +
   1.505 +inline bool
   1.506 +IsTypePropertyIdMarkedNonWritable(JSObject *obj, jsid id)
   1.507 +{
   1.508 +    return obj->type()->isPropertyNonWritable(id);
   1.509 +}
   1.510 +
   1.511 +/* Mark a state change on a particular object. */
   1.512 +inline void
   1.513 +MarkObjectStateChange(ExclusiveContext *cx, JSObject *obj)
   1.514 +{
   1.515 +    if (!obj->hasLazyType() && !obj->type()->unknownProperties())
   1.516 +        obj->type()->markStateChange(cx);
   1.517 +}
   1.518 +
   1.519 +/*
   1.520 + * For an array or object which has not yet escaped and been referenced elsewhere,
   1.521 + * pick a new type based on the object's current contents.
   1.522 + */
   1.523 +
   1.524 +inline void
   1.525 +FixArrayType(ExclusiveContext *cx, HandleObject obj)
   1.526 +{
   1.527 +    cx->compartment()->types.fixArrayType(cx, obj);
   1.528 +}
   1.529 +
   1.530 +inline void
   1.531 +FixObjectType(ExclusiveContext *cx, HandleObject obj)
   1.532 +{
   1.533 +    cx->compartment()->types.fixObjectType(cx, obj);
   1.534 +}
   1.535 +
   1.536 +/* Interface helpers for JSScript*. */
   1.537 +extern void TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc,
   1.538 +                              const js::Value &rval);
   1.539 +extern void TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc,
   1.540 +                              js::types::Type type);
   1.541 +
   1.542 +/////////////////////////////////////////////////////////////////////
   1.543 +// Script interface functions
   1.544 +/////////////////////////////////////////////////////////////////////
   1.545 +
   1.546 +/* static */ inline unsigned
   1.547 +TypeScript::NumTypeSets(JSScript *script)
   1.548 +{
   1.549 +    return script->nTypeSets() + analyze::LocalSlot(script, 0);
   1.550 +}
   1.551 +
   1.552 +/* static */ inline StackTypeSet *
   1.553 +TypeScript::ThisTypes(JSScript *script)
   1.554 +{
   1.555 +    return script->types->typeArray() + script->nTypeSets() + analyze::ThisSlot();
   1.556 +}
   1.557 +
   1.558 +/*
   1.559 + * Note: for non-escaping arguments and locals, argTypes/localTypes reflect
   1.560 + * only the initial type of the variable (e.g. passed values for argTypes,
   1.561 + * or undefined for localTypes) and not types from subsequent assignments.
   1.562 + */
   1.563 +
   1.564 +/* static */ inline StackTypeSet *
   1.565 +TypeScript::ArgTypes(JSScript *script, unsigned i)
   1.566 +{
   1.567 +    JS_ASSERT(i < script->functionNonDelazifying()->nargs());
   1.568 +    return script->types->typeArray() + script->nTypeSets() + analyze::ArgSlot(i);
   1.569 +}
   1.570 +
   1.571 +template <typename TYPESET>
   1.572 +/* static */ inline TYPESET *
   1.573 +TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *bytecodeMap,
   1.574 +                          uint32_t *hint, TYPESET *typeArray)
   1.575 +{
   1.576 +    JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);
   1.577 +    uint32_t offset = script->pcToOffset(pc);
   1.578 +
   1.579 +    // See if this pc is the next typeset opcode after the last one looked up.
   1.580 +    if ((*hint + 1) < script->nTypeSets() && bytecodeMap[*hint + 1] == offset) {
   1.581 +        (*hint)++;
   1.582 +        return typeArray + *hint;
   1.583 +    }
   1.584 +
   1.585 +    // See if this pc is the same as the last one looked up.
   1.586 +    if (bytecodeMap[*hint] == offset)
   1.587 +        return typeArray + *hint;
   1.588 +
   1.589 +    // Fall back to a binary search.
   1.590 +    size_t bottom = 0;
   1.591 +    size_t top = script->nTypeSets() - 1;
   1.592 +    size_t mid = bottom + (top - bottom) / 2;
   1.593 +    while (mid < top) {
   1.594 +        if (bytecodeMap[mid] < offset)
   1.595 +            bottom = mid + 1;
   1.596 +        else if (bytecodeMap[mid] > offset)
   1.597 +            top = mid;
   1.598 +        else
   1.599 +            break;
   1.600 +        mid = bottom + (top - bottom) / 2;
   1.601 +    }
   1.602 +
   1.603 +    // We should have have zeroed in on either the exact offset, unless there
   1.604 +    // are more JOF_TYPESET opcodes than nTypeSets in the script (as can happen
   1.605 +    // if the script is very long).
   1.606 +    JS_ASSERT(bytecodeMap[mid] == offset || mid == top);
   1.607 +
   1.608 +    *hint = mid;
   1.609 +    return typeArray + *hint;
   1.610 +}
   1.611 +
   1.612 +/* static */ inline StackTypeSet *
   1.613 +TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc)
   1.614 +{
   1.615 +    JS_ASSERT(CurrentThreadCanAccessRuntime(script->runtimeFromMainThread()));
   1.616 +#ifdef JS_ION
   1.617 +    uint32_t *hint = script->baselineScript()->bytecodeTypeMap() + script->nTypeSets();
   1.618 +    return BytecodeTypes(script, pc, script->baselineScript()->bytecodeTypeMap(),
   1.619 +                         hint, script->types->typeArray());
   1.620 +#else
   1.621 +    MOZ_CRASH();
   1.622 +#endif
   1.623 +}
   1.624 +
   1.625 +struct AllocationSiteKey : public DefaultHasher<AllocationSiteKey> {
   1.626 +    JSScript *script;
   1.627 +
   1.628 +    uint32_t offset : 24;
   1.629 +    JSProtoKey kind : 8;
   1.630 +
   1.631 +    static const uint32_t OFFSET_LIMIT = (1 << 23);
   1.632 +
   1.633 +    AllocationSiteKey() { mozilla::PodZero(this); }
   1.634 +
   1.635 +    static inline uint32_t hash(AllocationSiteKey key) {
   1.636 +        return uint32_t(size_t(key.script->offsetToPC(key.offset)) ^ key.kind);
   1.637 +    }
   1.638 +
   1.639 +    static inline bool match(const AllocationSiteKey &a, const AllocationSiteKey &b) {
   1.640 +        return a.script == b.script && a.offset == b.offset && a.kind == b.kind;
   1.641 +    }
   1.642 +};
   1.643 +
   1.644 +/* Whether to use a new type object for an initializer opcode at script/pc. */
   1.645 +js::NewObjectKind
   1.646 +UseNewTypeForInitializer(JSScript *script, jsbytecode *pc, JSProtoKey key);
   1.647 +
   1.648 +js::NewObjectKind
   1.649 +UseNewTypeForInitializer(JSScript *script, jsbytecode *pc, const Class *clasp);
   1.650 +
   1.651 +/* static */ inline TypeObject *
   1.652 +TypeScript::InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey kind)
   1.653 +{
   1.654 +    JS_ASSERT(!UseNewTypeForInitializer(script, pc, kind));
   1.655 +
   1.656 +    /* :XXX: Limit script->length so we don't need to check the offset up front? */
   1.657 +    uint32_t offset = script->pcToOffset(pc);
   1.658 +
   1.659 +    if (!script->compileAndGo() || offset >= AllocationSiteKey::OFFSET_LIMIT)
   1.660 +        return GetTypeNewObject(cx, kind);
   1.661 +
   1.662 +    AllocationSiteKey key;
   1.663 +    key.script = script;
   1.664 +    key.offset = offset;
   1.665 +    key.kind = kind;
   1.666 +
   1.667 +    if (!cx->compartment()->types.allocationSiteTable)
   1.668 +        return cx->compartment()->types.addAllocationSiteTypeObject(cx, key);
   1.669 +
   1.670 +    AllocationSiteTable::Ptr p = cx->compartment()->types.allocationSiteTable->lookup(key);
   1.671 +
   1.672 +    if (p)
   1.673 +        return p->value();
   1.674 +    return cx->compartment()->types.addAllocationSiteTypeObject(cx, key);
   1.675 +}
   1.676 +
   1.677 +/* Set the type to use for obj according to the site it was allocated at. */
   1.678 +static inline bool
   1.679 +SetInitializerObjectType(JSContext *cx, HandleScript script, jsbytecode *pc, HandleObject obj, NewObjectKind kind)
   1.680 +{
   1.681 +    JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
   1.682 +    JS_ASSERT(key != JSProto_Null);
   1.683 +    JS_ASSERT(kind == UseNewTypeForInitializer(script, pc, key));
   1.684 +
   1.685 +    if (kind == SingletonObject) {
   1.686 +        JS_ASSERT(obj->hasSingletonType());
   1.687 +
   1.688 +        /*
   1.689 +         * Inference does not account for types of run-once initializer
   1.690 +         * objects, as these may not be created until after the script
   1.691 +         * has been analyzed.
   1.692 +         */
   1.693 +        TypeScript::Monitor(cx, script, pc, ObjectValue(*obj));
   1.694 +    } else {
   1.695 +        types::TypeObject *type = TypeScript::InitObject(cx, script, pc, key);
   1.696 +        if (!type)
   1.697 +            return false;
   1.698 +        obj->uninlinedSetType(type);
   1.699 +    }
   1.700 +
   1.701 +    return true;
   1.702 +}
   1.703 +
   1.704 +/* static */ inline void
   1.705 +TypeScript::Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
   1.706 +{
   1.707 +    TypeMonitorResult(cx, script, pc, rval);
   1.708 +}
   1.709 +
   1.710 +/* static */ inline void
   1.711 +TypeScript::Monitor(JSContext *cx, const js::Value &rval)
   1.712 +{
   1.713 +    jsbytecode *pc;
   1.714 +    RootedScript script(cx, cx->currentScript(&pc));
   1.715 +    Monitor(cx, script, pc, rval);
   1.716 +}
   1.717 +
   1.718 +/* static */ inline void
   1.719 +TypeScript::MonitorAssign(JSContext *cx, HandleObject obj, jsid id)
   1.720 +{
   1.721 +    if (!obj->hasSingletonType()) {
   1.722 +        /*
   1.723 +         * Mark as unknown any object which has had dynamic assignments to
   1.724 +         * non-integer properties at SETELEM opcodes. This avoids making large
   1.725 +         * numbers of type properties for hashmap-style objects. We don't need
   1.726 +         * to do this for objects with singleton type, because type properties
   1.727 +         * are only constructed for them when analyzed scripts depend on those
   1.728 +         * specific properties.
   1.729 +         */
   1.730 +        uint32_t i;
   1.731 +        if (js_IdIsIndex(id, &i))
   1.732 +            return;
   1.733 +
   1.734 +        // But if we don't have too many properties yet, don't do anything.  The
   1.735 +        // idea here is that normal object initialization should not trigger
   1.736 +        // deoptimization in most cases, while actual usage as a hashmap should.
   1.737 +        TypeObject* type = obj->type();
   1.738 +        if (type->getPropertyCount() < 8)
   1.739 +            return;
   1.740 +        MarkTypeObjectUnknownProperties(cx, type);
   1.741 +    }
   1.742 +}
   1.743 +
   1.744 +/* static */ inline void
   1.745 +TypeScript::SetThis(JSContext *cx, JSScript *script, Type type)
   1.746 +{
   1.747 +    if (!script->types)
   1.748 +        return;
   1.749 +
   1.750 +    if (!ThisTypes(script)->hasType(type)) {
   1.751 +        AutoEnterAnalysis enter(cx);
   1.752 +
   1.753 +        InferSpew(ISpewOps, "externalType: setThis #%u: %s",
   1.754 +                  script->id(), TypeString(type));
   1.755 +        ThisTypes(script)->addType(cx, type);
   1.756 +    }
   1.757 +}
   1.758 +
   1.759 +/* static */ inline void
   1.760 +TypeScript::SetThis(JSContext *cx, JSScript *script, const js::Value &value)
   1.761 +{
   1.762 +    SetThis(cx, script, GetValueType(value));
   1.763 +}
   1.764 +
   1.765 +/* static */ inline void
   1.766 +TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type)
   1.767 +{
   1.768 +    if (!script->types)
   1.769 +        return;
   1.770 +
   1.771 +    if (!ArgTypes(script, arg)->hasType(type)) {
   1.772 +        AutoEnterAnalysis enter(cx);
   1.773 +
   1.774 +        InferSpew(ISpewOps, "externalType: setArg #%u %u: %s",
   1.775 +                  script->id(), arg, TypeString(type));
   1.776 +        ArgTypes(script, arg)->addType(cx, type);
   1.777 +    }
   1.778 +}
   1.779 +
   1.780 +/* static */ inline void
   1.781 +TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value)
   1.782 +{
   1.783 +    Type type = GetValueType(value);
   1.784 +    SetArgument(cx, script, arg, type);
   1.785 +}
   1.786 +
   1.787 +/////////////////////////////////////////////////////////////////////
   1.788 +// TypeCompartment
   1.789 +/////////////////////////////////////////////////////////////////////
   1.790 +
   1.791 +inline JSCompartment *
   1.792 +TypeCompartment::compartment()
   1.793 +{
   1.794 +    return (JSCompartment *)((char *)this - offsetof(JSCompartment, types));
   1.795 +}
   1.796 +
   1.797 +/////////////////////////////////////////////////////////////////////
   1.798 +// TypeSet
   1.799 +/////////////////////////////////////////////////////////////////////
   1.800 +
   1.801 +/*
   1.802 + * The sets of objects and scripts in a type set grow monotonically, are usually
   1.803 + * empty, almost always small, and sometimes big.  For empty or singleton sets,
   1.804 + * the pointer refers directly to the value.  For sets fitting into SET_ARRAY_SIZE,
   1.805 + * an array of this length is used to store the elements.  For larger sets, a hash
   1.806 + * table filled to 25%-50% of capacity is used, with collisions resolved by linear
   1.807 + * probing.  TODO: replace these with jshashtables.
   1.808 + */
   1.809 +const unsigned SET_ARRAY_SIZE = 8;
   1.810 +const unsigned SET_CAPACITY_OVERFLOW = 1u << 30;
   1.811 +
   1.812 +/* Get the capacity of a set with the given element count. */
   1.813 +static inline unsigned
   1.814 +HashSetCapacity(unsigned count)
   1.815 +{
   1.816 +    JS_ASSERT(count >= 2);
   1.817 +    JS_ASSERT(count < SET_CAPACITY_OVERFLOW);
   1.818 +
   1.819 +    if (count <= SET_ARRAY_SIZE)
   1.820 +        return SET_ARRAY_SIZE;
   1.821 +
   1.822 +    return 1u << (mozilla::FloorLog2(count) + 2);
   1.823 +}
   1.824 +
   1.825 +/* Compute the FNV hash for the low 32 bits of v. */
   1.826 +template <class T, class KEY>
   1.827 +static inline uint32_t
   1.828 +HashKey(T v)
   1.829 +{
   1.830 +    uint32_t nv = KEY::keyBits(v);
   1.831 +
   1.832 +    uint32_t hash = 84696351 ^ (nv & 0xff);
   1.833 +    hash = (hash * 16777619) ^ ((nv >> 8) & 0xff);
   1.834 +    hash = (hash * 16777619) ^ ((nv >> 16) & 0xff);
   1.835 +    return (hash * 16777619) ^ ((nv >> 24) & 0xff);
   1.836 +}
   1.837 +
   1.838 +/*
   1.839 + * Insert space for an element into the specified set and grow its capacity if needed.
   1.840 + * returned value is an existing or new entry (nullptr if new).
   1.841 + */
   1.842 +template <class T, class U, class KEY>
   1.843 +static U **
   1.844 +HashSetInsertTry(LifoAlloc &alloc, U **&values, unsigned &count, T key)
   1.845 +{
   1.846 +    unsigned capacity = HashSetCapacity(count);
   1.847 +    unsigned insertpos = HashKey<T,KEY>(key) & (capacity - 1);
   1.848 +
   1.849 +    /* Whether we are converting from a fixed array to hashtable. */
   1.850 +    bool converting = (count == SET_ARRAY_SIZE);
   1.851 +
   1.852 +    if (!converting) {
   1.853 +        while (values[insertpos] != nullptr) {
   1.854 +            if (KEY::getKey(values[insertpos]) == key)
   1.855 +                return &values[insertpos];
   1.856 +            insertpos = (insertpos + 1) & (capacity - 1);
   1.857 +        }
   1.858 +    }
   1.859 +
   1.860 +    if (count >= SET_CAPACITY_OVERFLOW)
   1.861 +        return nullptr;
   1.862 +
   1.863 +    count++;
   1.864 +    unsigned newCapacity = HashSetCapacity(count);
   1.865 +
   1.866 +    if (newCapacity == capacity) {
   1.867 +        JS_ASSERT(!converting);
   1.868 +        return &values[insertpos];
   1.869 +    }
   1.870 +
   1.871 +    U **newValues = alloc.newArray<U*>(newCapacity);
   1.872 +    if (!newValues)
   1.873 +        return nullptr;
   1.874 +    mozilla::PodZero(newValues, newCapacity);
   1.875 +
   1.876 +    for (unsigned i = 0; i < capacity; i++) {
   1.877 +        if (values[i]) {
   1.878 +            unsigned pos = HashKey<T,KEY>(KEY::getKey(values[i])) & (newCapacity - 1);
   1.879 +            while (newValues[pos] != nullptr)
   1.880 +                pos = (pos + 1) & (newCapacity - 1);
   1.881 +            newValues[pos] = values[i];
   1.882 +        }
   1.883 +    }
   1.884 +
   1.885 +    values = newValues;
   1.886 +
   1.887 +    insertpos = HashKey<T,KEY>(key) & (newCapacity - 1);
   1.888 +    while (values[insertpos] != nullptr)
   1.889 +        insertpos = (insertpos + 1) & (newCapacity - 1);
   1.890 +    return &values[insertpos];
   1.891 +}
   1.892 +
   1.893 +/*
   1.894 + * Insert an element into the specified set if it is not already there, returning
   1.895 + * an entry which is nullptr if the element was not there.
   1.896 + */
   1.897 +template <class T, class U, class KEY>
   1.898 +static inline U **
   1.899 +HashSetInsert(LifoAlloc &alloc, U **&values, unsigned &count, T key)
   1.900 +{
   1.901 +    if (count == 0) {
   1.902 +        JS_ASSERT(values == nullptr);
   1.903 +        count++;
   1.904 +        return (U **) &values;
   1.905 +    }
   1.906 +
   1.907 +    if (count == 1) {
   1.908 +        U *oldData = (U*) values;
   1.909 +        if (KEY::getKey(oldData) == key)
   1.910 +            return (U **) &values;
   1.911 +
   1.912 +        values = alloc.newArray<U*>(SET_ARRAY_SIZE);
   1.913 +        if (!values) {
   1.914 +            values = (U **) oldData;
   1.915 +            return nullptr;
   1.916 +        }
   1.917 +        mozilla::PodZero(values, SET_ARRAY_SIZE);
   1.918 +        count++;
   1.919 +
   1.920 +        values[0] = oldData;
   1.921 +        return &values[1];
   1.922 +    }
   1.923 +
   1.924 +    if (count <= SET_ARRAY_SIZE) {
   1.925 +        for (unsigned i = 0; i < count; i++) {
   1.926 +            if (KEY::getKey(values[i]) == key)
   1.927 +                return &values[i];
   1.928 +        }
   1.929 +
   1.930 +        if (count < SET_ARRAY_SIZE) {
   1.931 +            count++;
   1.932 +            return &values[count - 1];
   1.933 +        }
   1.934 +    }
   1.935 +
   1.936 +    return HashSetInsertTry<T,U,KEY>(alloc, values, count, key);
   1.937 +}
   1.938 +
   1.939 +/* Lookup an entry in a hash set, return nullptr if it does not exist. */
   1.940 +template <class T, class U, class KEY>
   1.941 +static inline U *
   1.942 +HashSetLookup(U **values, unsigned count, T key)
   1.943 +{
   1.944 +    if (count == 0)
   1.945 +        return nullptr;
   1.946 +
   1.947 +    if (count == 1)
   1.948 +        return (KEY::getKey((U *) values) == key) ? (U *) values : nullptr;
   1.949 +
   1.950 +    if (count <= SET_ARRAY_SIZE) {
   1.951 +        for (unsigned i = 0; i < count; i++) {
   1.952 +            if (KEY::getKey(values[i]) == key)
   1.953 +                return values[i];
   1.954 +        }
   1.955 +        return nullptr;
   1.956 +    }
   1.957 +
   1.958 +    unsigned capacity = HashSetCapacity(count);
   1.959 +    unsigned pos = HashKey<T,KEY>(key) & (capacity - 1);
   1.960 +
   1.961 +    while (values[pos] != nullptr) {
   1.962 +        if (KEY::getKey(values[pos]) == key)
   1.963 +            return values[pos];
   1.964 +        pos = (pos + 1) & (capacity - 1);
   1.965 +    }
   1.966 +
   1.967 +    return nullptr;
   1.968 +}
   1.969 +
   1.970 +inline TypeObjectKey *
   1.971 +Type::objectKey() const
   1.972 +{
   1.973 +    JS_ASSERT(isObject());
   1.974 +    if (isTypeObject())
   1.975 +        TypeObject::readBarrier((TypeObject *) data);
   1.976 +    else
   1.977 +        JSObject::readBarrier((JSObject *) (data ^ 1));
   1.978 +    return (TypeObjectKey *) data;
   1.979 +}
   1.980 +
   1.981 +inline JSObject *
   1.982 +Type::singleObject() const
   1.983 +{
   1.984 +    JS_ASSERT(isSingleObject());
   1.985 +    JSObject::readBarrier((JSObject *) (data ^ 1));
   1.986 +    return (JSObject *) (data ^ 1);
   1.987 +}
   1.988 +
   1.989 +inline TypeObject *
   1.990 +Type::typeObject() const
   1.991 +{
   1.992 +    JS_ASSERT(isTypeObject());
   1.993 +    TypeObject::readBarrier((TypeObject *) data);
   1.994 +    return (TypeObject *) data;
   1.995 +}
   1.996 +
   1.997 +inline bool
   1.998 +TypeSet::hasType(Type type) const
   1.999 +{
  1.1000 +    if (unknown())
  1.1001 +        return true;
  1.1002 +
  1.1003 +    if (type.isUnknown()) {
  1.1004 +        return false;
  1.1005 +    } else if (type.isPrimitive()) {
  1.1006 +        return !!(flags & PrimitiveTypeFlag(type.primitive()));
  1.1007 +    } else if (type.isAnyObject()) {
  1.1008 +        return !!(flags & TYPE_FLAG_ANYOBJECT);
  1.1009 +    } else {
  1.1010 +        return !!(flags & TYPE_FLAG_ANYOBJECT) ||
  1.1011 +            HashSetLookup<TypeObjectKey*,TypeObjectKey,TypeObjectKey>
  1.1012 +            (objectSet, baseObjectCount(), type.objectKey()) != nullptr;
  1.1013 +    }
  1.1014 +}
  1.1015 +
  1.1016 +inline void
  1.1017 +TypeSet::setBaseObjectCount(uint32_t count)
  1.1018 +{
  1.1019 +    JS_ASSERT(count <= TYPE_FLAG_OBJECT_COUNT_LIMIT);
  1.1020 +    flags = (flags & ~TYPE_FLAG_OBJECT_COUNT_MASK)
  1.1021 +          | (count << TYPE_FLAG_OBJECT_COUNT_SHIFT);
  1.1022 +}
  1.1023 +
  1.1024 +inline void
  1.1025 +HeapTypeSet::newPropertyState(ExclusiveContext *cxArg)
  1.1026 +{
  1.1027 +    /* Propagate the change to all constraints. */
  1.1028 +    if (JSContext *cx = cxArg->maybeJSContext()) {
  1.1029 +        TypeConstraint *constraint = constraintList;
  1.1030 +        while (constraint) {
  1.1031 +            constraint->newPropertyState(cx, this);
  1.1032 +            constraint = constraint->next;
  1.1033 +        }
  1.1034 +    } else {
  1.1035 +        JS_ASSERT(!constraintList);
  1.1036 +    }
  1.1037 +}
  1.1038 +
  1.1039 +inline void
  1.1040 +HeapTypeSet::setNonDataPropertyIgnoringConstraints()
  1.1041 +{
  1.1042 +    flags |= TYPE_FLAG_NON_DATA_PROPERTY;
  1.1043 +}
  1.1044 +
  1.1045 +inline void
  1.1046 +HeapTypeSet::setNonDataProperty(ExclusiveContext *cx)
  1.1047 +{
  1.1048 +    if (flags & TYPE_FLAG_NON_DATA_PROPERTY)
  1.1049 +        return;
  1.1050 +
  1.1051 +    setNonDataPropertyIgnoringConstraints();
  1.1052 +    newPropertyState(cx);
  1.1053 +}
  1.1054 +
  1.1055 +inline void
  1.1056 +HeapTypeSet::setNonWritableProperty(ExclusiveContext *cx)
  1.1057 +{
  1.1058 +    if (flags & TYPE_FLAG_NON_WRITABLE_PROPERTY)
  1.1059 +        return;
  1.1060 +
  1.1061 +    flags |= TYPE_FLAG_NON_WRITABLE_PROPERTY;
  1.1062 +    newPropertyState(cx);
  1.1063 +}
  1.1064 +
  1.1065 +inline unsigned
  1.1066 +TypeSet::getObjectCount() const
  1.1067 +{
  1.1068 +    JS_ASSERT(!unknownObject());
  1.1069 +    uint32_t count = baseObjectCount();
  1.1070 +    if (count > SET_ARRAY_SIZE)
  1.1071 +        return HashSetCapacity(count);
  1.1072 +    return count;
  1.1073 +}
  1.1074 +
  1.1075 +inline TypeObjectKey *
  1.1076 +TypeSet::getObject(unsigned i) const
  1.1077 +{
  1.1078 +    JS_ASSERT(i < getObjectCount());
  1.1079 +    if (baseObjectCount() == 1) {
  1.1080 +        JS_ASSERT(i == 0);
  1.1081 +        return (TypeObjectKey *) objectSet;
  1.1082 +    }
  1.1083 +    return objectSet[i];
  1.1084 +}
  1.1085 +
  1.1086 +inline JSObject *
  1.1087 +TypeSet::getSingleObject(unsigned i) const
  1.1088 +{
  1.1089 +    TypeObjectKey *key = getObject(i);
  1.1090 +    return (key && key->isSingleObject()) ? key->asSingleObject() : nullptr;
  1.1091 +}
  1.1092 +
  1.1093 +inline TypeObject *
  1.1094 +TypeSet::getTypeObject(unsigned i) const
  1.1095 +{
  1.1096 +    TypeObjectKey *key = getObject(i);
  1.1097 +    return (key && key->isTypeObject()) ? key->asTypeObject() : nullptr;
  1.1098 +}
  1.1099 +
  1.1100 +inline const Class *
  1.1101 +TypeSet::getObjectClass(unsigned i) const
  1.1102 +{
  1.1103 +    if (JSObject *object = getSingleObject(i))
  1.1104 +        return object->getClass();
  1.1105 +    if (TypeObject *object = getTypeObject(i))
  1.1106 +        return object->clasp();
  1.1107 +    return nullptr;
  1.1108 +}
  1.1109 +
  1.1110 +/////////////////////////////////////////////////////////////////////
  1.1111 +// TypeObject
  1.1112 +/////////////////////////////////////////////////////////////////////
  1.1113 +
  1.1114 +inline TypeObject::TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags)
  1.1115 +{
  1.1116 +    mozilla::PodZero(this);
  1.1117 +
  1.1118 +    /* Inner objects may not appear on prototype chains. */
  1.1119 +    JS_ASSERT_IF(proto.isObject(), !proto.toObject()->getClass()->ext.outerObject);
  1.1120 +
  1.1121 +    this->clasp_ = clasp;
  1.1122 +    this->proto_ = proto.raw();
  1.1123 +    this->flags_ = initialFlags;
  1.1124 +
  1.1125 +    InferSpew(ISpewOps, "newObject: %s", TypeObjectString(this));
  1.1126 +}
  1.1127 +
  1.1128 +inline uint32_t
  1.1129 +TypeObject::basePropertyCount() const
  1.1130 +{
  1.1131 +    return (flags() & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
  1.1132 +}
  1.1133 +
  1.1134 +inline void
  1.1135 +TypeObject::setBasePropertyCount(uint32_t count)
  1.1136 +{
  1.1137 +    // Note: Callers must ensure they are performing threadsafe operations.
  1.1138 +    JS_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT);
  1.1139 +    flags_ = (flags() & ~OBJECT_FLAG_PROPERTY_COUNT_MASK)
  1.1140 +           | (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
  1.1141 +}
  1.1142 +
  1.1143 +inline HeapTypeSet *
  1.1144 +TypeObject::getProperty(ExclusiveContext *cx, jsid id)
  1.1145 +{
  1.1146 +    JS_ASSERT(cx->compartment()->activeAnalysis);
  1.1147 +
  1.1148 +    JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
  1.1149 +    JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
  1.1150 +    JS_ASSERT(!unknownProperties());
  1.1151 +
  1.1152 +    if (HeapTypeSet *types = maybeGetProperty(id))
  1.1153 +        return types;
  1.1154 +
  1.1155 +    Property *base = cx->typeLifoAlloc().new_<Property>(id);
  1.1156 +    if (!base) {
  1.1157 +        markUnknown(cx);
  1.1158 +        return nullptr;
  1.1159 +    }
  1.1160 +
  1.1161 +    uint32_t propertyCount = basePropertyCount();
  1.1162 +    Property **pprop = HashSetInsert<jsid,Property,Property>
  1.1163 +        (cx->typeLifoAlloc(), propertySet, propertyCount, id);
  1.1164 +    if (!pprop) {
  1.1165 +        markUnknown(cx);
  1.1166 +        return nullptr;
  1.1167 +    }
  1.1168 +
  1.1169 +    JS_ASSERT(!*pprop);
  1.1170 +
  1.1171 +    setBasePropertyCount(propertyCount);
  1.1172 +    *pprop = base;
  1.1173 +
  1.1174 +    updateNewPropertyTypes(cx, id, &base->types);
  1.1175 +
  1.1176 +    if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
  1.1177 +        // We hit the maximum number of properties the object can have, mark
  1.1178 +        // the object unknown so that new properties will not be added in the
  1.1179 +        // future.
  1.1180 +        markUnknown(cx);
  1.1181 +    }
  1.1182 +
  1.1183 +    return &base->types;
  1.1184 +}
  1.1185 +
  1.1186 +inline HeapTypeSet *
  1.1187 +TypeObject::maybeGetProperty(jsid id)
  1.1188 +{
  1.1189 +    JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
  1.1190 +    JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
  1.1191 +    JS_ASSERT(!unknownProperties());
  1.1192 +
  1.1193 +    Property *prop = HashSetLookup<jsid,Property,Property>
  1.1194 +        (propertySet, basePropertyCount(), id);
  1.1195 +
  1.1196 +    return prop ? &prop->types : nullptr;
  1.1197 +}
  1.1198 +
  1.1199 +inline unsigned
  1.1200 +TypeObject::getPropertyCount()
  1.1201 +{
  1.1202 +    uint32_t count = basePropertyCount();
  1.1203 +    if (count > SET_ARRAY_SIZE)
  1.1204 +        return HashSetCapacity(count);
  1.1205 +    return count;
  1.1206 +}
  1.1207 +
  1.1208 +inline Property *
  1.1209 +TypeObject::getProperty(unsigned i)
  1.1210 +{
  1.1211 +    JS_ASSERT(i < getPropertyCount());
  1.1212 +    if (basePropertyCount() == 1) {
  1.1213 +        JS_ASSERT(i == 0);
  1.1214 +        return (Property *) propertySet;
  1.1215 +    }
  1.1216 +    return propertySet[i];
  1.1217 +}
  1.1218 +
  1.1219 +inline void
  1.1220 +TypeObjectAddendum::writeBarrierPre(TypeObjectAddendum *type)
  1.1221 +{
  1.1222 +#ifdef JSGC_INCREMENTAL
  1.1223 +    if (!type)
  1.1224 +        return;
  1.1225 +
  1.1226 +    switch (type->kind) {
  1.1227 +      case NewScript:
  1.1228 +        return TypeNewScript::writeBarrierPre(type->asNewScript());
  1.1229 +
  1.1230 +      case TypedObject:
  1.1231 +        return TypeTypedObject::writeBarrierPre(type->asTypedObject());
  1.1232 +    }
  1.1233 +#endif
  1.1234 +}
  1.1235 +
  1.1236 +inline void
  1.1237 +TypeNewScript::writeBarrierPre(TypeNewScript *newScript)
  1.1238 +{
  1.1239 +#ifdef JSGC_INCREMENTAL
  1.1240 +    if (!newScript || !newScript->fun->runtimeFromAnyThread()->needsBarrier())
  1.1241 +        return;
  1.1242 +
  1.1243 +    JS::Zone *zone = newScript->fun->zoneFromAnyThread();
  1.1244 +    if (zone->needsBarrier()) {
  1.1245 +        MarkObject(zone->barrierTracer(), &newScript->fun, "write barrier");
  1.1246 +        MarkObject(zone->barrierTracer(), &newScript->templateObject, "write barrier");
  1.1247 +    }
  1.1248 +#endif
  1.1249 +}
  1.1250 +
  1.1251 +} } /* namespace js::types */
  1.1252 +
  1.1253 +inline bool
  1.1254 +JSScript::ensureHasTypes(JSContext *cx)
  1.1255 +{
  1.1256 +    return types || makeTypes(cx);
  1.1257 +}
  1.1258 +
  1.1259 +namespace js {
  1.1260 +
  1.1261 +template <>
  1.1262 +struct GCMethods<const types::Type>
  1.1263 +{
  1.1264 +    static types::Type initial() { return types::Type::UnknownType(); }
  1.1265 +    static ThingRootKind kind() { return THING_ROOT_TYPE; }
  1.1266 +    static bool poisoned(const types::Type &v) {
  1.1267 +        return (v.isTypeObject() && IsPoisonedPtr(v.typeObject()))
  1.1268 +            || (v.isSingleObject() && IsPoisonedPtr(v.singleObject()));
  1.1269 +    }
  1.1270 +};
  1.1271 +
  1.1272 +template <>
  1.1273 +struct GCMethods<types::Type>
  1.1274 +{
  1.1275 +    static types::Type initial() { return types::Type::UnknownType(); }
  1.1276 +    static ThingRootKind kind() { return THING_ROOT_TYPE; }
  1.1277 +    static bool poisoned(const types::Type &v) {
  1.1278 +        return (v.isTypeObject() && IsPoisonedPtr(v.typeObject()))
  1.1279 +            || (v.isSingleObject() && IsPoisonedPtr(v.singleObject()));
  1.1280 +    }
  1.1281 +};
  1.1282 +
  1.1283 +} // namespace js
  1.1284 +
  1.1285 +namespace JS {
  1.1286 +template<> class AnchorPermitted<js::types::TypeObject *> { };
  1.1287 +}  // namespace JS
  1.1288 +
  1.1289 +#endif /* jsinferinlines_h */

mercurial