1 : /* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */
2 : /* vim: set ts=40 sw=4 et tw=99: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is the Mozilla SpiderMonkey bytecode type inference
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Mozilla Foundation
20 : * Portions created by the Initial Developer are Copyright (C) 2010
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Brian Hackett <bhackett@mozilla.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : /* Inline members for javascript type inference. */
41 :
42 : #include "jsarray.h"
43 : #include "jsanalyze.h"
44 : #include "jscompartment.h"
45 : #include "jsgcmark.h"
46 : #include "jsinfer.h"
47 : #include "jsprf.h"
48 : #include "vm/GlobalObject.h"
49 :
50 : #include "vm/Stack-inl.h"
51 :
52 : #ifndef jsinferinlines_h___
53 : #define jsinferinlines_h___
54 :
55 : /////////////////////////////////////////////////////////////////////
56 : // Types
57 : /////////////////////////////////////////////////////////////////////
58 :
59 : namespace js {
60 : namespace types {
61 :
62 : /* static */ inline Type
63 41228106 : Type::ObjectType(JSObject *obj)
64 : {
65 41228106 : if (obj->hasSingletonType())
66 10252859 : return Type(uintptr_t(obj) | 1);
67 30975247 : return Type(uintptr_t(obj->type()));
68 : }
69 :
70 : /* static */ inline Type
71 737572 : Type::ObjectType(TypeObject *obj)
72 : {
73 737572 : if (obj->singleton)
74 132880 : return Type(uintptr_t(obj->singleton.get()) | 1);
75 604692 : return Type(uintptr_t(obj));
76 : }
77 :
78 : /* static */ inline Type
79 583578 : Type::ObjectType(TypeObjectKey *obj)
80 : {
81 583578 : return Type(uintptr_t(obj));
82 : }
83 :
84 : inline Type
85 166902888 : GetValueType(JSContext *cx, const Value &val)
86 : {
87 166902888 : JS_ASSERT(cx->typeInferenceEnabled());
88 166902888 : if (val.isDouble())
89 11836001 : return Type::DoubleType();
90 155066887 : if (val.isObject())
91 40406626 : return Type::ObjectType(&val.toObject());
92 114660261 : return Type::PrimitiveType(val.extractNonDoubleType());
93 : }
94 :
95 : inline TypeFlags
96 117733860 : PrimitiveTypeFlag(JSValueType type)
97 : {
98 117733860 : switch (type) {
99 : case JSVAL_TYPE_UNDEFINED:
100 11228146 : return TYPE_FLAG_UNDEFINED;
101 : case JSVAL_TYPE_NULL:
102 3498205 : return TYPE_FLAG_NULL;
103 : case JSVAL_TYPE_BOOLEAN:
104 2219644 : return TYPE_FLAG_BOOLEAN;
105 : case JSVAL_TYPE_INT32:
106 79909397 : return TYPE_FLAG_INT32;
107 : case JSVAL_TYPE_DOUBLE:
108 12239144 : return TYPE_FLAG_DOUBLE;
109 : case JSVAL_TYPE_STRING:
110 8569890 : return TYPE_FLAG_STRING;
111 : case JSVAL_TYPE_MAGIC:
112 69434 : return TYPE_FLAG_LAZYARGS;
113 : default:
114 0 : JS_NOT_REACHED("Bad type");
115 : return 0;
116 : }
117 : }
118 :
119 : inline JSValueType
120 774498 : TypeFlagPrimitive(TypeFlags flags)
121 : {
122 774498 : switch (flags) {
123 : case TYPE_FLAG_UNDEFINED:
124 127742 : return JSVAL_TYPE_UNDEFINED;
125 : case TYPE_FLAG_NULL:
126 7297 : return JSVAL_TYPE_NULL;
127 : case TYPE_FLAG_BOOLEAN:
128 8896 : return JSVAL_TYPE_BOOLEAN;
129 : case TYPE_FLAG_INT32:
130 546520 : return JSVAL_TYPE_INT32;
131 : case TYPE_FLAG_DOUBLE:
132 13054 : return JSVAL_TYPE_DOUBLE;
133 : case TYPE_FLAG_STRING:
134 70560 : return JSVAL_TYPE_STRING;
135 : case TYPE_FLAG_LAZYARGS:
136 429 : return JSVAL_TYPE_MAGIC;
137 : default:
138 0 : JS_NOT_REACHED("Bad type");
139 : return (JSValueType) 0;
140 : }
141 : }
142 :
143 : /*
144 : * Get the canonical representation of an id to use when doing inference. This
145 : * maintains the constraint that if two different jsids map to the same property
146 : * in JS (e.g. 3 and "3"), they have the same type representation.
147 : */
148 : inline jsid
149 73674843 : MakeTypeId(JSContext *cx, jsid id)
150 : {
151 73674843 : JS_ASSERT(!JSID_IS_EMPTY(id));
152 :
153 : /*
154 : * All integers must map to the aggregate property for index types, including
155 : * negative integers.
156 : */
157 73674843 : if (JSID_IS_INT(id))
158 1475390 : return JSID_VOID;
159 :
160 : /*
161 : * Check for numeric strings, as in js_StringIsIndex, but allow negative
162 : * and overflowing integers.
163 : */
164 72199453 : if (JSID_IS_STRING(id)) {
165 41507281 : JSFlatString *str = JSID_TO_FLAT_STRING(id);
166 41507281 : const jschar *cp = str->getCharsZ(cx);
167 41507281 : if (JS7_ISDEC(*cp) || *cp == '-') {
168 25305 : cp++;
169 56280 : while (JS7_ISDEC(*cp))
170 5670 : cp++;
171 25305 : if (*cp == 0)
172 2905 : return JSID_VOID;
173 : }
174 41504376 : return id;
175 : }
176 :
177 30692172 : return JSID_VOID;
178 : }
179 :
180 : const char * TypeIdStringImpl(jsid id);
181 :
182 : /* Convert an id for printing during debug. */
183 : static inline const char *
184 194854 : TypeIdString(jsid id)
185 : {
186 : #ifdef DEBUG
187 194854 : return TypeIdStringImpl(id);
188 : #else
189 : return "(missing)";
190 : #endif
191 : }
192 :
193 : /*
194 : * Structure for type inference entry point functions. All functions which can
195 : * change type information must use this, and functions which depend on
196 : * intermediate types (i.e. JITs) can use this to ensure that intermediate
197 : * information is not collected and does not change.
198 : *
199 : * Pins inference results so that intermediate type information, TypeObjects
200 : * and JSScripts won't be collected during GC. Does additional sanity checking
201 : * that inference is not reentrant and that recompilations occur properly.
202 : */
203 : struct AutoEnterTypeInference
204 : {
205 : FreeOp *freeOp;
206 : JSCompartment *compartment;
207 : bool oldActiveAnalysis;
208 : bool oldActiveInference;
209 :
210 955923595 : AutoEnterTypeInference(JSContext *cx, bool compiling = false)
211 : {
212 955923595 : JS_ASSERT_IF(!compiling, cx->compartment->types.inferenceEnabled);
213 955923595 : init(cx->runtime->defaultFreeOp(), cx->compartment);
214 955923595 : }
215 :
216 34485 : AutoEnterTypeInference(FreeOp *fop, JSCompartment *comp)
217 : {
218 34485 : init(fop, comp);
219 34485 : }
220 :
221 955958080 : ~AutoEnterTypeInference()
222 : {
223 955958080 : compartment->activeAnalysis = oldActiveAnalysis;
224 955958080 : compartment->activeInference = oldActiveInference;
225 :
226 : /*
227 : * If there are no more type inference activations on the stack,
228 : * process any triggered recompilations. Note that we should not be
229 : * invoking any scripted code while type inference is running.
230 : * :TODO: assert this.
231 : */
232 955958080 : if (!compartment->activeInference) {
233 955797074 : TypeCompartment *types = &compartment->types;
234 955797074 : if (types->pendingNukeTypes)
235 0 : types->nukeTypes(freeOp);
236 955797074 : else if (types->pendingRecompiles)
237 32935 : types->processPendingRecompiles(freeOp);
238 : }
239 955958080 : }
240 :
241 : private:
242 955958080 : void init(FreeOp *fop, JSCompartment *comp) {
243 955958080 : freeOp = fop;
244 955958080 : compartment = comp;
245 955958080 : oldActiveAnalysis = compartment->activeAnalysis;
246 955958080 : oldActiveInference = compartment->activeInference;
247 955958080 : compartment->activeAnalysis = true;
248 955958080 : compartment->activeInference = true;
249 955958080 : }
250 : };
251 :
252 : /*
253 : * Structure marking the currently compiled script, for constraints which can
254 : * trigger recompilation.
255 : */
256 : struct AutoEnterCompilation
257 : {
258 : RecompileInfo &info;
259 :
260 95862 : AutoEnterCompilation(JSContext *cx, JSScript *script, bool constructing, unsigned chunkIndex)
261 95862 : : info(cx->compartment->types.compiledInfo)
262 : {
263 95862 : JS_ASSERT(!info.script);
264 95862 : info.script = script;
265 95862 : info.constructing = constructing;
266 95862 : info.chunkIndex = chunkIndex;
267 95862 : }
268 :
269 95862 : ~AutoEnterCompilation()
270 : {
271 95862 : JS_ASSERT(info.script);
272 95862 : info.script = NULL;
273 95862 : info.constructing = false;
274 95862 : info.chunkIndex = 0;
275 95862 : }
276 : };
277 :
278 : /////////////////////////////////////////////////////////////////////
279 : // Interface functions
280 : /////////////////////////////////////////////////////////////////////
281 :
282 : /*
283 : * These functions check whether inference is enabled before performing some
284 : * action on the type state. To avoid checking cx->typeInferenceEnabled()
285 : * everywhere, it is generally preferred to use one of these functions or
286 : * a type function on JSScript to perform inference operations.
287 : */
288 :
289 : /*
290 : * Get the default 'new' object for a given standard class, per the currently
291 : * active global.
292 : */
293 : inline TypeObject *
294 62852 : GetTypeNewObject(JSContext *cx, JSProtoKey key)
295 : {
296 : JSObject *proto;
297 62852 : if (!js_GetClassPrototype(cx, NULL, key, &proto, NULL))
298 0 : return NULL;
299 62852 : return proto->getNewType(cx);
300 : }
301 :
302 : /* Get a type object for the immediate allocation site within a native. */
303 : inline TypeObject *
304 108378 : GetTypeCallerInitObject(JSContext *cx, JSProtoKey key)
305 : {
306 108378 : if (cx->typeInferenceEnabled()) {
307 : jsbytecode *pc;
308 54379 : JSScript *script = cx->stack.currentScript(&pc);
309 54379 : if (script)
310 54254 : return TypeScript::InitObject(cx, script, pc, key);
311 : }
312 54124 : return GetTypeNewObject(cx, key);
313 : }
314 :
315 : /*
316 : * When using a custom iterator within the initialization of a 'for in' loop,
317 : * mark the iterator values as unknown.
318 : */
319 : inline void
320 4363 : MarkIteratorUnknown(JSContext *cx)
321 : {
322 : extern void MarkIteratorUnknownSlow(JSContext *cx);
323 :
324 4363 : if (cx->typeInferenceEnabled())
325 2396 : MarkIteratorUnknownSlow(cx);
326 4363 : }
327 :
328 : /*
329 : * Monitor a javascript call, either on entry to the interpreter or made
330 : * from within the interpreter.
331 : */
332 : inline void
333 21873273 : TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing)
334 : {
335 : extern void TypeMonitorCallSlow(JSContext *cx, JSObject *callee,
336 : const CallArgs &args, bool constructing);
337 :
338 21873273 : JSObject *callee = &args.callee();
339 21873273 : if (callee->isFunction()) {
340 21873273 : JSFunction *fun = callee->toFunction();
341 21873273 : if (fun->isInterpreted()) {
342 21873273 : JSScript *script = fun->script();
343 21873273 : if (!script->ensureRanAnalysis(cx, fun->environment()))
344 0 : return;
345 21873273 : if (cx->typeInferenceEnabled())
346 12965925 : TypeMonitorCallSlow(cx, callee, args, constructing);
347 : }
348 : }
349 : }
350 :
351 : inline bool
352 72113711 : TrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
353 : {
354 72113711 : if (!cx->typeInferenceEnabled() || obj->hasLazyType() || obj->type()->unknownProperties())
355 51458296 : return false;
356 :
357 20655415 : if (obj->hasSingletonType() && !obj->type()->maybeGetProperty(cx, id))
358 7090045 : return false;
359 :
360 13565370 : return true;
361 : }
362 :
363 : /* Add a possible type for a property of obj. */
364 : inline void
365 1242527 : AddTypePropertyId(JSContext *cx, JSObject *obj, jsid id, Type type)
366 : {
367 1242527 : if (cx->typeInferenceEnabled())
368 688815 : id = MakeTypeId(cx, id);
369 1242527 : if (TrackPropertyTypes(cx, obj, id))
370 272259 : obj->type()->addPropertyType(cx, id, type);
371 1242527 : }
372 :
373 : inline void
374 58164129 : AddTypePropertyId(JSContext *cx, JSObject *obj, jsid id, const Value &value)
375 : {
376 58164129 : if (cx->typeInferenceEnabled())
377 28141961 : id = MakeTypeId(cx, id);
378 58164129 : if (TrackPropertyTypes(cx, obj, id))
379 13018142 : obj->type()->addPropertyType(cx, id, value);
380 58164129 : }
381 :
382 : inline void
383 32848 : AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, Type type)
384 : {
385 32848 : if (cx->typeInferenceEnabled() && !obj->unknownProperties())
386 17870 : obj->addPropertyType(cx, name, type);
387 32848 : }
388 :
389 : inline void
390 0 : AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, const Value &value)
391 : {
392 0 : if (cx->typeInferenceEnabled() && !obj->unknownProperties())
393 0 : obj->addPropertyType(cx, name, value);
394 0 : }
395 :
396 : /* Set one or more dynamic flags on a type object. */
397 : inline void
398 3133320 : MarkTypeObjectFlags(JSContext *cx, JSObject *obj, TypeObjectFlags flags)
399 : {
400 3133320 : if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->hasAllFlags(flags))
401 5954 : obj->type()->setFlags(cx, flags);
402 3133320 : }
403 :
404 : /*
405 : * Mark all properties of a type object as unknown. If markSetsUnknown is set,
406 : * scan the entire compartment and mark all type sets containing it as having
407 : * an unknown object. This is needed for correctness in dealing with mutable
408 : * __proto__, which can change the type of an object dynamically.
409 : */
410 : inline void
411 3801202 : MarkTypeObjectUnknownProperties(JSContext *cx, TypeObject *obj,
412 : bool markSetsUnknown = false)
413 : {
414 3801202 : if (cx->typeInferenceEnabled()) {
415 2278024 : if (!obj->unknownProperties())
416 13710 : obj->markUnknown(cx);
417 2278024 : if (markSetsUnknown && !(obj->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN))
418 65 : cx->compartment->types.markSetsUnknown(cx, obj);
419 : }
420 3801202 : }
421 :
422 : /*
423 : * Mark any property which has been deleted or configured to be non-writable or
424 : * have a getter/setter.
425 : */
426 : inline void
427 12707055 : MarkTypePropertyConfigured(JSContext *cx, JSObject *obj, jsid id)
428 : {
429 12707055 : if (cx->typeInferenceEnabled())
430 7021114 : id = MakeTypeId(cx, id);
431 12707055 : if (TrackPropertyTypes(cx, obj, id))
432 274969 : obj->type()->markPropertyConfigured(cx, id);
433 12707055 : }
434 :
435 : /* Mark a state change on a particular object. */
436 : inline void
437 23700 : MarkObjectStateChange(JSContext *cx, JSObject *obj)
438 : {
439 23700 : if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->unknownProperties())
440 13065 : obj->type()->markStateChange(cx);
441 23700 : }
442 :
443 : /*
444 : * For an array or object which has not yet escaped and been referenced elsewhere,
445 : * pick a new type based on the object's current contents.
446 : */
447 :
448 : inline void
449 3258 : FixArrayType(JSContext *cx, JSObject *obj)
450 : {
451 3258 : if (cx->typeInferenceEnabled())
452 1810 : cx->compartment->types.fixArrayType(cx, obj);
453 3258 : }
454 :
455 : inline void
456 2569 : FixObjectType(JSContext *cx, JSObject *obj)
457 : {
458 2569 : if (cx->typeInferenceEnabled())
459 1425 : cx->compartment->types.fixObjectType(cx, obj);
460 2569 : }
461 :
462 : /* Interface helpers for JSScript */
463 : extern void TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval);
464 : extern void TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, js::types::Type type);
465 :
466 : inline bool
467 502154 : UseNewTypeAtEntry(JSContext *cx, StackFrame *fp)
468 : {
469 502484 : return fp->isConstructing() && cx->typeInferenceEnabled() &&
470 346 : fp->prev() && fp->prev()->isScriptFrame() &&
471 502830 : UseNewType(cx, fp->prev()->script(), fp->prev()->pcQuadratic(cx->stack, fp));
472 : }
473 :
474 : /////////////////////////////////////////////////////////////////////
475 : // Script interface functions
476 : /////////////////////////////////////////////////////////////////////
477 :
478 : inline
479 154005 : TypeScript::TypeScript()
480 : {
481 154005 : this->global = (js::GlobalObject *) GLOBAL_MISSING_SCOPE;
482 154005 : }
483 :
484 : /* static */ inline unsigned
485 203037 : TypeScript::NumTypeSets(JSScript *script)
486 : {
487 203037 : return script->nTypeSets + analyze::TotalSlots(script);
488 : }
489 :
490 : /* static */ inline TypeSet *
491 131193 : TypeScript::ReturnTypes(JSScript *script)
492 : {
493 131193 : return script->types->typeArray() + script->nTypeSets + js::analyze::CalleeSlot();
494 : }
495 :
496 : /* static */ inline TypeSet *
497 29343419 : TypeScript::ThisTypes(JSScript *script)
498 : {
499 29343419 : return script->types->typeArray() + script->nTypeSets + js::analyze::ThisSlot();
500 : }
501 :
502 : /*
503 : * Note: for non-escaping arguments and locals, argTypes/localTypes reflect
504 : * only the initial type of the variable (e.g. passed values for argTypes,
505 : * or undefined for localTypes) and not types from subsequent assignments.
506 : */
507 :
508 : /* static */ inline TypeSet *
509 45082852 : TypeScript::ArgTypes(JSScript *script, unsigned i)
510 : {
511 45082852 : JS_ASSERT(i < script->function()->nargs);
512 45082852 : return script->types->typeArray() + script->nTypeSets + js::analyze::ArgSlot(i);
513 : }
514 :
515 : /* static */ inline TypeSet *
516 109170 : TypeScript::LocalTypes(JSScript *script, unsigned i)
517 : {
518 109170 : JS_ASSERT(i < script->nfixed);
519 109170 : return script->types->typeArray() + script->nTypeSets + js::analyze::LocalSlot(script, i);
520 : }
521 :
522 : /* static */ inline TypeSet *
523 337376 : TypeScript::SlotTypes(JSScript *script, unsigned slot)
524 : {
525 337376 : JS_ASSERT(slot < js::analyze::TotalSlots(script));
526 337376 : return script->types->typeArray() + script->nTypeSets + slot;
527 : }
528 :
529 : /* static */ inline TypeObject *
530 8070 : TypeScript::StandardType(JSContext *cx, JSScript *script, JSProtoKey key)
531 : {
532 : JSObject *proto;
533 8070 : if (!js_GetClassPrototype(cx, script->global(), key, &proto, NULL))
534 0 : return NULL;
535 8070 : return proto->getNewType(cx);
536 : }
537 :
538 : struct AllocationSiteKey {
539 : JSScript *script;
540 :
541 : uint32_t offset : 24;
542 : JSProtoKey kind : 8;
543 :
544 : static const uint32_t OFFSET_LIMIT = (1 << 23);
545 :
546 1244003 : AllocationSiteKey() { PodZero(this); }
547 :
548 : typedef AllocationSiteKey Lookup;
549 :
550 1017262 : static inline uint32_t hash(AllocationSiteKey key) {
551 1017262 : return uint32_t(size_t(key.script->code + key.offset)) ^ key.kind;
552 : }
553 :
554 996425 : static inline bool match(const AllocationSiteKey &a, const AllocationSiteKey &b) {
555 996425 : return a.script == b.script && a.offset == b.offset && a.kind == b.kind;
556 : }
557 : };
558 :
559 : /* static */ inline TypeObject *
560 1017738 : TypeScript::InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey kind)
561 : {
562 1017738 : JS_ASSERT(!UseNewTypeForInitializer(cx, script, pc));
563 :
564 : /* :XXX: Limit script->length so we don't need to check the offset up front? */
565 1017738 : uint32_t offset = pc - script->code;
566 :
567 1017738 : if (!cx->typeInferenceEnabled() || !script->hasGlobal() || offset >= AllocationSiteKey::OFFSET_LIMIT)
568 8728 : return GetTypeNewObject(cx, kind);
569 :
570 1009010 : AllocationSiteKey key;
571 1009010 : key.script = script;
572 1009010 : key.offset = offset;
573 1009010 : key.kind = kind;
574 :
575 1009010 : if (!cx->compartment->types.allocationSiteTable)
576 4333 : return cx->compartment->types.newAllocationSiteTypeObject(cx, key);
577 :
578 1004677 : AllocationSiteTable::Ptr p = cx->compartment->types.allocationSiteTable->lookup(key);
579 :
580 1004677 : if (p)
581 996425 : return p->value;
582 8252 : return cx->compartment->types.newAllocationSiteTypeObject(cx, key);
583 : }
584 :
585 : /* Set the type to use for obj according to the site it was allocated at. */
586 : static inline bool
587 1870897 : SetInitializerObjectType(JSContext *cx, JSScript *script, jsbytecode *pc, JSObject *obj)
588 : {
589 1870897 : if (!cx->typeInferenceEnabled())
590 944359 : return true;
591 :
592 926538 : if (UseNewTypeForInitializer(cx, script, pc)) {
593 2660 : if (!obj->setSingletonType(cx))
594 0 : return false;
595 :
596 : /*
597 : * Inference does not account for types of run-once initializer
598 : * objects, as these may not be created until after the script
599 : * has been analyzed.
600 : */
601 2660 : TypeScript::Monitor(cx, script, pc, ObjectValue(*obj));
602 : } else {
603 923878 : JSProtoKey key = obj->isDenseArray() ? JSProto_Array : JSProto_Object;
604 923878 : types::TypeObject *type = TypeScript::InitObject(cx, script, pc, key);
605 923878 : if (!type)
606 0 : return false;
607 923878 : obj->setType(type);
608 : }
609 :
610 926538 : return true;
611 : }
612 :
613 : /* static */ inline void
614 149850692 : TypeScript::Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
615 : {
616 149850692 : if (cx->typeInferenceEnabled())
617 75873907 : TypeMonitorResult(cx, script, pc, rval);
618 149850692 : }
619 :
620 : /* static */ inline void
621 1398041 : TypeScript::MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc)
622 : {
623 1398041 : if (cx->typeInferenceEnabled())
624 530616 : TypeDynamicResult(cx, script, pc, Type::DoubleType());
625 1398041 : }
626 :
627 : /* static */ inline void
628 509356 : TypeScript::MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc)
629 : {
630 509356 : if (cx->typeInferenceEnabled())
631 282975 : TypeDynamicResult(cx, script, pc, Type::StringType());
632 509356 : }
633 :
634 : /* static */ inline void
635 2826 : TypeScript::MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc)
636 : {
637 2826 : if (cx->typeInferenceEnabled())
638 1570 : TypeDynamicResult(cx, script, pc, Type::UnknownType());
639 2826 : }
640 :
641 : /* static */ inline void
642 2619521 : TypeScript::GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc)
643 : {
644 2619521 : *script = cx->fp()->script();
645 2619521 : *pc = cx->regs().pc;
646 2619521 : }
647 :
648 : /* static */ inline void
649 999574 : TypeScript::MonitorOverflow(JSContext *cx)
650 : {
651 : JSScript *script;
652 : jsbytecode *pc;
653 999574 : GetPcScript(cx, &script, &pc);
654 999574 : MonitorOverflow(cx, script, pc);
655 999574 : }
656 :
657 : /* static */ inline void
658 118047 : TypeScript::MonitorString(JSContext *cx)
659 : {
660 : JSScript *script;
661 : jsbytecode *pc;
662 118047 : GetPcScript(cx, &script, &pc);
663 118047 : MonitorString(cx, script, pc);
664 118047 : }
665 :
666 : /* static */ inline void
667 874 : TypeScript::MonitorUnknown(JSContext *cx)
668 : {
669 : JSScript *script;
670 : jsbytecode *pc;
671 874 : GetPcScript(cx, &script, &pc);
672 874 : MonitorUnknown(cx, script, pc);
673 874 : }
674 :
675 : /* static */ inline void
676 : TypeScript::Monitor(JSContext *cx, const js::Value &rval)
677 : {
678 : JSScript *script;
679 : jsbytecode *pc;
680 : GetPcScript(cx, &script, &pc);
681 : Monitor(cx, script, pc, rval);
682 : }
683 :
684 : /* static */ inline void
685 13161666 : TypeScript::MonitorAssign(JSContext *cx, JSObject *obj, jsid id)
686 : {
687 13161666 : if (cx->typeInferenceEnabled() && !obj->hasSingletonType()) {
688 : /*
689 : * Mark as unknown any object which has had dynamic assignments to
690 : * non-integer properties at SETELEM opcodes. This avoids making large
691 : * numbers of type properties for hashmap-style objects. We don't need
692 : * to do this for objects with singleton type, because type properties
693 : * are only constructed for them when analyzed scripts depend on those
694 : * specific properties.
695 : */
696 : uint32_t i;
697 5995489 : if (js_IdIsIndex(id, &i))
698 5592969 : return;
699 402520 : MarkTypeObjectUnknownProperties(cx, obj->type());
700 : }
701 : }
702 :
703 : /* static */ inline void
704 12519334 : TypeScript::SetThis(JSContext *cx, JSScript *script, Type type)
705 : {
706 12519334 : if (!cx->typeInferenceEnabled())
707 0 : return;
708 12519334 : JS_ASSERT(script->types);
709 :
710 : /* Analyze the script regardless if -a was used. */
711 12519334 : bool analyze = cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS);
712 :
713 12519334 : if (!ThisTypes(script)->hasType(type) || analyze) {
714 8521978 : AutoEnterTypeInference enter(cx);
715 :
716 : InferSpew(ISpewOps, "externalType: setThis #%u: %s",
717 4260989 : script->id(), TypeString(type));
718 4260989 : ThisTypes(script)->addType(cx, type);
719 :
720 4260989 : if (analyze && script->types->hasScope())
721 4210936 : script->ensureRanInference(cx);
722 : }
723 : }
724 :
725 : /* static */ inline void
726 11806672 : TypeScript::SetThis(JSContext *cx, JSScript *script, const js::Value &value)
727 : {
728 11806672 : if (cx->typeInferenceEnabled())
729 11738645 : SetThis(cx, script, GetValueType(cx, value));
730 11806672 : }
731 :
732 : /* static */ inline void
733 10731 : TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type)
734 : {
735 10731 : if (!cx->typeInferenceEnabled())
736 0 : return;
737 10731 : JS_ASSERT(script->types);
738 :
739 10731 : if (!LocalTypes(script, local)->hasType(type)) {
740 908 : AutoEnterTypeInference enter(cx);
741 :
742 : InferSpew(ISpewOps, "externalType: setLocal #%u %u: %s",
743 454 : script->id(), local, TypeString(type));
744 454 : LocalTypes(script, local)->addType(cx, type);
745 : }
746 : }
747 :
748 : /* static */ inline void
749 18559 : TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value)
750 : {
751 18559 : if (cx->typeInferenceEnabled()) {
752 10731 : Type type = GetValueType(cx, value);
753 10731 : SetLocal(cx, script, local, type);
754 : }
755 18559 : }
756 :
757 : /* static */ inline void
758 20696700 : TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type)
759 : {
760 20696700 : if (!cx->typeInferenceEnabled())
761 0 : return;
762 20696700 : JS_ASSERT(script->types);
763 :
764 20696700 : if (!ArgTypes(script, arg)->hasType(type)) {
765 165882 : AutoEnterTypeInference enter(cx);
766 :
767 : InferSpew(ISpewOps, "externalType: setArg #%u %u: %s",
768 82941 : script->id(), arg, TypeString(type));
769 82941 : ArgTypes(script, arg)->addType(cx, type);
770 : }
771 : }
772 :
773 : /* static */ inline void
774 20697199 : TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value)
775 : {
776 20697199 : if (cx->typeInferenceEnabled()) {
777 20696700 : Type type = GetValueType(cx, value);
778 20696700 : SetArgument(cx, script, arg, type);
779 : }
780 20697199 : }
781 :
782 : void
783 70791 : TypeScript::trace(JSTracer *trc)
784 : {
785 70791 : if (hasScope() && global)
786 67363 : gc::MarkObject(trc, &global, "script_global");
787 :
788 : /* Note: nesting does not keep anything alive. */
789 70791 : }
790 :
791 : /////////////////////////////////////////////////////////////////////
792 : // TypeCompartment
793 : /////////////////////////////////////////////////////////////////////
794 :
795 : inline JSCompartment *
796 157873 : TypeCompartment::compartment()
797 : {
798 157873 : return (JSCompartment *)((char *)this - offsetof(JSCompartment, types));
799 : }
800 :
801 : inline void
802 3160284 : TypeCompartment::addPending(JSContext *cx, TypeConstraint *constraint, TypeSet *source, Type type)
803 : {
804 3160284 : JS_ASSERT(this == &cx->compartment->types);
805 3160284 : JS_ASSERT(!cx->runtime->gcRunning);
806 :
807 : InferSpew(ISpewOps, "pending: %sC%p%s %s",
808 : InferSpewColor(constraint), constraint, InferSpewColorReset(),
809 3160284 : TypeString(type));
810 :
811 3160284 : if ((pendingCount == pendingCapacity) && !growPendingArray(cx))
812 0 : return;
813 :
814 3160284 : PendingWork &pending = pendingArray[pendingCount++];
815 3160284 : pending.constraint = constraint;
816 3160284 : pending.source = source;
817 3160284 : pending.type = type;
818 : }
819 :
820 : inline void
821 4699928 : TypeCompartment::resolvePending(JSContext *cx)
822 : {
823 4699928 : JS_ASSERT(this == &cx->compartment->types);
824 :
825 4699928 : if (resolving) {
826 : /* There is an active call further up resolving the worklist. */
827 1222924 : return;
828 : }
829 :
830 3477004 : resolving = true;
831 :
832 : /* Handle all pending type registrations. */
833 10114292 : while (pendingCount) {
834 3160284 : const PendingWork &pending = pendingArray[--pendingCount];
835 : InferSpew(ISpewOps, "resolve: %sC%p%s %s",
836 : InferSpewColor(pending.constraint), pending.constraint,
837 3160284 : InferSpewColorReset(), TypeString(pending.type));
838 3160284 : pending.constraint->newType(cx, pending.source, pending.type);
839 : }
840 :
841 3477004 : resolving = false;
842 : }
843 :
844 : /////////////////////////////////////////////////////////////////////
845 : // TypeSet
846 : /////////////////////////////////////////////////////////////////////
847 :
848 : /*
849 : * The sets of objects and scripts in a type set grow monotonically, are usually
850 : * empty, almost always small, and sometimes big. For empty or singleton sets,
851 : * the pointer refers directly to the value. For sets fitting into SET_ARRAY_SIZE,
852 : * an array of this length is used to store the elements. For larger sets, a hash
853 : * table filled to 25%-50% of capacity is used, with collisions resolved by linear
854 : * probing. TODO: replace these with jshashtables.
855 : */
856 : const unsigned SET_ARRAY_SIZE = 8;
857 :
858 : /* Get the capacity of a set with the given element count. */
859 : static inline unsigned
860 4554030 : HashSetCapacity(unsigned count)
861 : {
862 4554030 : JS_ASSERT(count >= 2);
863 :
864 4554030 : if (count <= SET_ARRAY_SIZE)
865 19715 : return SET_ARRAY_SIZE;
866 :
867 : unsigned log2;
868 4534315 : JS_FLOOR_LOG2(log2, count);
869 4534315 : return 1 << (log2 + 2);
870 : }
871 :
872 : /* Compute the FNV hash for the low 32 bits of v. */
873 : template <class T, class KEY>
874 : static inline uint32_t
875 2882738 : HashKey(T v)
876 : {
877 2882738 : uint32_t nv = KEY::keyBits(v);
878 :
879 2882738 : uint32_t hash = 84696351 ^ (nv & 0xff);
880 2882738 : hash = (hash * 16777619) ^ ((nv >> 8) & 0xff);
881 2882738 : hash = (hash * 16777619) ^ ((nv >> 16) & 0xff);
882 2882738 : return (hash * 16777619) ^ ((nv >> 24) & 0xff);
883 : }
884 :
885 : /*
886 : * Insert space for an element into the specified set and grow its capacity if needed.
887 : * returned value is an existing or new entry (NULL if new).
888 : */
889 : template <class T, class U, class KEY>
890 : static U **
891 1007448 : HashSetInsertTry(JSCompartment *compartment, U **&values, unsigned &count, T key)
892 : {
893 1007448 : unsigned capacity = HashSetCapacity(count);
894 1007448 : unsigned insertpos = HashKey<T,KEY>(key) & (capacity - 1);
895 :
896 : /* Whether we are converting from a fixed array to hashtable. */
897 1007448 : bool converting = (count == SET_ARRAY_SIZE);
898 :
899 1007448 : if (!converting) {
900 2717699 : while (values[insertpos] != NULL) {
901 1211594 : if (KEY::getKey(values[insertpos]) == key)
902 487163 : return &values[insertpos];
903 724431 : insertpos = (insertpos + 1) & (capacity - 1);
904 : }
905 : }
906 :
907 520285 : count++;
908 520285 : unsigned newCapacity = HashSetCapacity(count);
909 :
910 520285 : if (newCapacity == capacity) {
911 493267 : JS_ASSERT(!converting);
912 493267 : return &values[insertpos];
913 : }
914 :
915 27018 : U **newValues = compartment->typeLifoAlloc.newArray<U*>(newCapacity);
916 27018 : if (!newValues)
917 0 : return NULL;
918 27018 : PodZero(newValues, newCapacity);
919 :
920 1542682 : for (unsigned i = 0; i < capacity; i++) {
921 1515664 : if (values[i]) {
922 784884 : unsigned pos = HashKey<T,KEY>(KEY::getKey(values[i])) & (newCapacity - 1);
923 1720917 : while (newValues[pos] != NULL)
924 151149 : pos = (pos + 1) & (newCapacity - 1);
925 784884 : newValues[pos] = values[i];
926 : }
927 : }
928 :
929 27018 : values = newValues;
930 :
931 27018 : insertpos = HashKey<T,KEY>(key) & (newCapacity - 1);
932 69989 : while (values[insertpos] != NULL)
933 15953 : insertpos = (insertpos + 1) & (newCapacity - 1);
934 27018 : return &values[insertpos];
935 : }
936 :
937 : /*
938 : * Insert an element into the specified set if it is not already there, returning
939 : * an entry which is NULL if the element was not there.
940 : */
941 : template <class T, class U, class KEY>
942 : static inline U **
943 16970315 : HashSetInsert(JSCompartment *compartment, U **&values, unsigned &count, T key)
944 : {
945 16970315 : if (count == 0) {
946 693877 : JS_ASSERT(values == NULL);
947 693877 : count++;
948 693877 : return (U **) &values;
949 : }
950 :
951 16276438 : if (count == 1) {
952 10969030 : U *oldData = (U*) values;
953 10969030 : if (KEY::getKey(oldData) == key)
954 10904536 : return (U **) &values;
955 :
956 64494 : values = compartment->typeLifoAlloc.newArray<U*>(SET_ARRAY_SIZE);
957 64494 : if (!values) {
958 0 : values = (U **) oldData;
959 0 : return NULL;
960 : }
961 64494 : PodZero(values, SET_ARRAY_SIZE);
962 64494 : count++;
963 :
964 64494 : values[0] = oldData;
965 64494 : return &values[1];
966 : }
967 :
968 5307408 : if (count <= SET_ARRAY_SIZE) {
969 11957622 : for (unsigned i = 0; i < count; i++) {
970 11831796 : if (KEY::getKey(values[i]) == key)
971 4184948 : return &values[i];
972 : }
973 :
974 125826 : if (count < SET_ARRAY_SIZE) {
975 115012 : count++;
976 115012 : return &values[count - 1];
977 : }
978 : }
979 :
980 1007448 : return HashSetInsertTry<T,U,KEY>(compartment, values, count, key);
981 : }
982 :
983 : /* Lookup an entry in a hash set, return NULL if it does not exist. */
984 : template <class T, class U, class KEY>
985 : static inline U *
986 48668577 : HashSetLookup(U **values, unsigned count, T key)
987 : {
988 48668577 : if (count == 0)
989 7901252 : return NULL;
990 :
991 40767325 : if (count == 1)
992 33114490 : return (KEY::getKey((U *) values) == key) ? (U *) values : NULL;
993 :
994 7652835 : if (count <= SET_ARRAY_SIZE) {
995 10998138 : for (unsigned i = 0; i < count; i++) {
996 10965497 : if (KEY::getKey(values[i]) == key)
997 6556806 : return values[i];
998 : }
999 32641 : return NULL;
1000 : }
1001 :
1002 1063388 : unsigned capacity = HashSetCapacity(count);
1003 1063388 : unsigned pos = HashKey<T,KEY>(key) & (capacity - 1);
1004 :
1005 2684437 : while (values[pos] != NULL) {
1006 1580709 : if (KEY::getKey(values[pos]) == key)
1007 1023048 : return values[pos];
1008 557661 : pos = (pos + 1) & (capacity - 1);
1009 : }
1010 :
1011 40340 : return NULL;
1012 : }
1013 :
1014 : inline bool
1015 171094302 : TypeSet::hasType(Type type)
1016 : {
1017 171094302 : if (unknown())
1018 13604222 : return true;
1019 :
1020 157490080 : if (type.isUnknown()) {
1021 53095 : return false;
1022 157436985 : } else if (type.isPrimitive()) {
1023 115909926 : return !!(flags & PrimitiveTypeFlag(type.primitive()));
1024 41527059 : } else if (type.isAnyObject()) {
1025 351038 : return !!(flags & TYPE_FLAG_ANYOBJECT);
1026 : } else {
1027 41176021 : return !!(flags & TYPE_FLAG_ANYOBJECT) ||
1028 : HashSetLookup<TypeObjectKey*,TypeObjectKey,TypeObjectKey>
1029 41176021 : (objectSet, baseObjectCount(), type.objectKey()) != NULL;
1030 : }
1031 : }
1032 :
1033 : inline void
1034 1337387 : TypeSet::setBaseObjectCount(uint32_t count)
1035 : {
1036 1337387 : JS_ASSERT(count <= TYPE_FLAG_OBJECT_COUNT_LIMIT);
1037 : flags = (flags & ~TYPE_FLAG_OBJECT_COUNT_MASK)
1038 1337387 : | (count << TYPE_FLAG_OBJECT_COUNT_SHIFT);
1039 1337387 : }
1040 :
1041 : inline void
1042 138771 : TypeSet::clearObjects()
1043 : {
1044 138771 : setBaseObjectCount(0);
1045 138771 : objectSet = NULL;
1046 138771 : }
1047 :
1048 : inline void
1049 6412854 : TypeSet::addType(JSContext *cx, Type type)
1050 : {
1051 6412854 : JS_ASSERT(cx->compartment->activeInference);
1052 :
1053 6412854 : if (unknown())
1054 2514689 : return;
1055 :
1056 3898165 : if (type.isUnknown()) {
1057 71420 : flags |= TYPE_FLAG_BASE_MASK;
1058 71420 : clearObjects();
1059 71420 : JS_ASSERT(unknown());
1060 3826745 : } else if (type.isPrimitive()) {
1061 1823934 : TypeFlags flag = PrimitiveTypeFlag(type.primitive());
1062 1823934 : if (flags & flag)
1063 764293 : return;
1064 :
1065 : /* If we add float to a type set it is also considered to contain int. */
1066 1059641 : if (flag == TYPE_FLAG_DOUBLE)
1067 49016 : flag |= TYPE_FLAG_INT32;
1068 :
1069 1059641 : flags |= flag;
1070 : } else {
1071 2002811 : if (flags & TYPE_FLAG_ANYOBJECT)
1072 5191 : return;
1073 1997620 : if (type.isAnyObject())
1074 28267 : goto unknownObject;
1075 1969353 : uint32_t objectCount = baseObjectCount();
1076 1969353 : TypeObjectKey *object = type.objectKey();
1077 : TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
1078 1969353 : (cx->compartment, objectSet, objectCount, object);
1079 1969353 : if (!pentry) {
1080 0 : cx->compartment->types.setPendingNukeTypes(cx);
1081 0 : return;
1082 : }
1083 1969353 : if (*pentry)
1084 1041954 : return;
1085 927399 : *pentry = object;
1086 :
1087 927399 : setBaseObjectCount(objectCount);
1088 :
1089 927399 : if (objectCount == TYPE_FLAG_OBJECT_COUNT_LIMIT)
1090 15 : goto unknownObject;
1091 :
1092 927384 : if (type.isTypeObject()) {
1093 277306 : TypeObject *nobject = type.typeObject();
1094 277306 : JS_ASSERT(!nobject->singleton);
1095 277306 : if (nobject->unknownProperties())
1096 28221 : goto unknownObject;
1097 249085 : if (objectCount > 1) {
1098 32350 : nobject->contribution += (objectCount - 1) * (objectCount - 1);
1099 32350 : if (nobject->contribution >= TypeObject::CONTRIBUTION_LIMIT) {
1100 : InferSpew(ISpewOps, "limitUnknown: %sT%p%s",
1101 422 : InferSpewColor(this), this, InferSpewColorReset());
1102 422 : goto unknownObject;
1103 : }
1104 : }
1105 : }
1106 : }
1107 :
1108 : if (false) {
1109 : unknownObject:
1110 56925 : type = Type::AnyObjectType();
1111 56925 : flags |= TYPE_FLAG_ANYOBJECT;
1112 56925 : clearObjects();
1113 : }
1114 :
1115 : InferSpew(ISpewOps, "addType: %sT%p%s %s",
1116 : InferSpewColor(this), this, InferSpewColorReset(),
1117 2086727 : TypeString(type));
1118 :
1119 : /* Propagate the type to all constraints. */
1120 2086727 : TypeConstraint *constraint = constraintList;
1121 5940879 : while (constraint) {
1122 1767425 : cx->compartment->types.addPending(cx, constraint, this, type);
1123 1767425 : constraint = constraint->next;
1124 : }
1125 :
1126 2086727 : cx->compartment->types.resolvePending(cx);
1127 : }
1128 :
1129 : inline void
1130 13999037 : TypeSet::setOwnProperty(JSContext *cx, bool configured)
1131 : {
1132 13999037 : TypeFlags nflags = TYPE_FLAG_OWN_PROPERTY | (configured ? TYPE_FLAG_CONFIGURED_PROPERTY : 0);
1133 :
1134 13999037 : if ((flags & nflags) == nflags)
1135 13909304 : return;
1136 :
1137 89733 : flags |= nflags;
1138 :
1139 : /* Propagate the change to all constraints. */
1140 89733 : TypeConstraint *constraint = constraintList;
1141 186401 : while (constraint) {
1142 6935 : constraint->newPropertyState(cx, this);
1143 6935 : constraint = constraint->next;
1144 : }
1145 : }
1146 :
1147 : inline unsigned
1148 6453355 : TypeSet::getObjectCount()
1149 : {
1150 6453355 : JS_ASSERT(!unknownObject());
1151 6453355 : uint32_t count = baseObjectCount();
1152 6453355 : if (count > SET_ARRAY_SIZE)
1153 1949391 : return HashSetCapacity(count);
1154 4503964 : return count;
1155 : }
1156 :
1157 : inline TypeObjectKey *
1158 2638378 : TypeSet::getObject(unsigned i)
1159 : {
1160 2638378 : JS_ASSERT(i < getObjectCount());
1161 2638378 : if (baseObjectCount() == 1) {
1162 860036 : JS_ASSERT(i == 0);
1163 860036 : return (TypeObjectKey *) objectSet;
1164 : }
1165 1778342 : return objectSet[i];
1166 : }
1167 :
1168 : inline JSObject *
1169 765341 : TypeSet::getSingleObject(unsigned i)
1170 : {
1171 765341 : TypeObjectKey *key = getObject(i);
1172 765341 : return (uintptr_t(key) & 1) ? (JSObject *)(uintptr_t(key) ^ 1) : NULL;
1173 : }
1174 :
1175 : inline TypeObject *
1176 840987 : TypeSet::getTypeObject(unsigned i)
1177 : {
1178 840987 : TypeObjectKey *key = getObject(i);
1179 840987 : return (key && !(uintptr_t(key) & 1)) ? (TypeObject *) key : NULL;
1180 : }
1181 :
1182 : /////////////////////////////////////////////////////////////////////
1183 : // TypeCallsite
1184 : /////////////////////////////////////////////////////////////////////
1185 :
1186 : inline
1187 57521 : TypeCallsite::TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
1188 : bool isNew, unsigned argumentCount)
1189 : : script(script), pc(pc), isNew(isNew), argumentCount(argumentCount),
1190 57521 : thisTypes(NULL), returnTypes(NULL)
1191 : {
1192 : /* Caller must check for failure. */
1193 57521 : argumentTypes = cx->typeLifoAlloc().newArray<TypeSet*>(argumentCount);
1194 57521 : }
1195 :
1196 : /////////////////////////////////////////////////////////////////////
1197 : // TypeObject
1198 : /////////////////////////////////////////////////////////////////////
1199 :
1200 346138 : inline TypeObject::TypeObject(JSObject *proto, bool function, bool unknown)
1201 : {
1202 346138 : PodZero(this);
1203 :
1204 : /* Inner objects may not appear on prototype chains. */
1205 346138 : JS_ASSERT_IF(proto, !proto->getClass()->ext.outerObject);
1206 :
1207 346138 : this->proto = proto;
1208 :
1209 346138 : if (function)
1210 14025 : flags |= OBJECT_FLAG_FUNCTION;
1211 346138 : if (unknown)
1212 182901 : flags |= OBJECT_FLAG_UNKNOWN_MASK;
1213 :
1214 346138 : InferSpew(ISpewOps, "newObject: %s", TypeObjectString(this));
1215 346138 : }
1216 :
1217 : inline uint32_t
1218 24524934 : TypeObject::basePropertyCount() const
1219 : {
1220 24524934 : return (flags & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
1221 : }
1222 :
1223 : inline void
1224 358522 : TypeObject::setBasePropertyCount(uint32_t count)
1225 : {
1226 358522 : JS_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT);
1227 : flags = (flags & ~OBJECT_FLAG_PROPERTY_COUNT_MASK)
1228 358522 : | (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
1229 358522 : }
1230 :
1231 : inline TypeSet *
1232 14686877 : TypeObject::getProperty(JSContext *cx, jsid id, bool assign)
1233 : {
1234 14686877 : JS_ASSERT(cx->compartment->activeInference);
1235 14686877 : JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
1236 14686877 : JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == MakeTypeId(cx, id));
1237 14686877 : JS_ASSERT(!unknownProperties());
1238 :
1239 14686877 : uint32_t propertyCount = basePropertyCount();
1240 : Property **pprop = HashSetInsert<jsid,Property,Property>
1241 14686877 : (cx->compartment, propertySet, propertyCount, id);
1242 14686877 : if (!pprop) {
1243 0 : cx->compartment->types.setPendingNukeTypes(cx);
1244 0 : return NULL;
1245 : }
1246 :
1247 14686877 : if (!*pprop) {
1248 152184 : setBasePropertyCount(propertyCount);
1249 152184 : if (!addProperty(cx, id, pprop))
1250 0 : return NULL;
1251 152184 : if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
1252 0 : markUnknown(cx);
1253 0 : TypeSet *types = TypeSet::make(cx, "propertyOverflow");
1254 0 : types->addType(cx, Type::UnknownType());
1255 0 : return types;
1256 : }
1257 : }
1258 :
1259 14686877 : TypeSet *types = &(*pprop)->types;
1260 :
1261 14686877 : if (assign)
1262 13667350 : types->setOwnProperty(cx, false);
1263 :
1264 14686877 : return types;
1265 : }
1266 :
1267 : inline TypeSet *
1268 8421831 : TypeObject::maybeGetProperty(JSContext *cx, jsid id)
1269 : {
1270 8421831 : JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
1271 8421831 : JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == MakeTypeId(cx, id));
1272 8421831 : JS_ASSERT(!unknownProperties());
1273 :
1274 : Property *prop = HashSetLookup<jsid,Property,Property>
1275 8421831 : (propertySet, basePropertyCount(), id);
1276 :
1277 8421831 : return prop ? &prop->types : NULL;
1278 : }
1279 :
1280 : inline unsigned
1281 452774 : TypeObject::getPropertyCount()
1282 : {
1283 452774 : uint32_t count = basePropertyCount();
1284 452774 : if (count > SET_ARRAY_SIZE)
1285 1316 : return HashSetCapacity(count);
1286 451458 : return count;
1287 : }
1288 :
1289 : inline Property *
1290 15947 : TypeObject::getProperty(unsigned i)
1291 : {
1292 15947 : JS_ASSERT(i < getPropertyCount());
1293 15947 : if (basePropertyCount() == 1) {
1294 4016 : JS_ASSERT(i == 0);
1295 4016 : return (Property *) propertySet;
1296 : }
1297 11931 : return propertySet[i];
1298 : }
1299 :
1300 : inline void
1301 246841 : TypeObject::setFlagsFromKey(JSContext *cx, JSProtoKey key)
1302 : {
1303 246841 : TypeObjectFlags flags = 0;
1304 :
1305 246841 : switch (key) {
1306 : case JSProto_Function:
1307 14025 : JS_ASSERT(isFunction());
1308 : /* FALLTHROUGH */
1309 :
1310 : case JSProto_Object:
1311 : flags = OBJECT_FLAG_NON_DENSE_ARRAY
1312 : | OBJECT_FLAG_NON_PACKED_ARRAY
1313 237595 : | OBJECT_FLAG_NON_TYPED_ARRAY;
1314 237595 : break;
1315 :
1316 : case JSProto_Array:
1317 8289 : flags = OBJECT_FLAG_NON_TYPED_ARRAY;
1318 8289 : break;
1319 :
1320 : default:
1321 : /* :XXX: abstract */
1322 0 : JS_ASSERT(key == JSProto_Int8Array ||
1323 : key == JSProto_Uint8Array ||
1324 : key == JSProto_Int16Array ||
1325 : key == JSProto_Uint16Array ||
1326 : key == JSProto_Int32Array ||
1327 : key == JSProto_Uint32Array ||
1328 : key == JSProto_Float32Array ||
1329 : key == JSProto_Float64Array ||
1330 957 : key == JSProto_Uint8ClampedArray);
1331 : flags = OBJECT_FLAG_NON_DENSE_ARRAY
1332 957 : | OBJECT_FLAG_NON_PACKED_ARRAY;
1333 957 : break;
1334 : }
1335 :
1336 246841 : if (!hasAllFlags(flags))
1337 150087 : setFlags(cx, flags);
1338 246841 : }
1339 :
1340 : inline JSObject *
1341 0 : TypeObject::getGlobal()
1342 : {
1343 0 : if (singleton)
1344 0 : return &singleton->global();
1345 0 : if (interpretedFunction && interpretedFunction->script()->compileAndGo)
1346 0 : return &interpretedFunction->global();
1347 0 : return NULL;
1348 : }
1349 :
1350 : inline void
1351 10645876 : TypeObject::writeBarrierPre(TypeObject *type)
1352 : {
1353 : #ifdef JSGC_INCREMENTAL
1354 10645876 : if (!type)
1355 1692685 : return;
1356 :
1357 8953191 : JSCompartment *comp = type->compartment();
1358 8953191 : if (comp->needsBarrier()) {
1359 1146 : TypeObject *tmp = type;
1360 1146 : MarkTypeObjectUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
1361 1146 : JS_ASSERT(tmp == type);
1362 : }
1363 : #endif
1364 : }
1365 :
1366 : inline void
1367 15734705 : TypeObject::writeBarrierPost(TypeObject *type, void *addr)
1368 : {
1369 15734705 : }
1370 :
1371 : inline void
1372 41838774 : TypeObject::readBarrier(TypeObject *type)
1373 : {
1374 : #ifdef JSGC_INCREMENTAL
1375 41838774 : JSCompartment *comp = type->compartment();
1376 41838774 : if (comp->needsBarrier()) {
1377 5754 : TypeObject *tmp = type;
1378 5754 : MarkTypeObjectUnbarriered(comp->barrierTracer(), &tmp, "read barrier");
1379 5754 : JS_ASSERT(tmp == type);
1380 : }
1381 : #endif
1382 41838774 : }
1383 :
1384 : inline void
1385 619 : TypeNewScript::writeBarrierPre(TypeNewScript *newScript)
1386 : {
1387 : #ifdef JSGC_INCREMENTAL
1388 619 : if (!newScript)
1389 579 : return;
1390 :
1391 40 : JSCompartment *comp = newScript->fun->compartment();
1392 40 : if (comp->needsBarrier()) {
1393 0 : MarkObject(comp->barrierTracer(), &newScript->fun, "write barrier");
1394 0 : MarkShape(comp->barrierTracer(), &newScript->shape, "write barrier");
1395 : }
1396 : #endif
1397 : }
1398 :
1399 : inline void
1400 619 : TypeNewScript::writeBarrierPost(TypeNewScript *newScript, void *addr)
1401 : {
1402 619 : }
1403 :
1404 : inline
1405 152184 : Property::Property(jsid id)
1406 152184 : : id(id)
1407 : {
1408 152184 : }
1409 :
1410 : inline
1411 21534 : Property::Property(const Property &o)
1412 21534 : : id(o.id.get()), types(o.types)
1413 : {
1414 21534 : }
1415 :
1416 : } } /* namespace js::types */
1417 :
1418 : inline bool
1419 102566654 : JSScript::ensureHasTypes(JSContext *cx)
1420 : {
1421 102566654 : return types || makeTypes(cx);
1422 : }
1423 :
1424 : inline bool
1425 102493944 : JSScript::ensureRanAnalysis(JSContext *cx, JSObject *scope)
1426 : {
1427 102493944 : JSScript *self = this;
1428 :
1429 102493944 : if (!self->ensureHasTypes(cx))
1430 0 : return false;
1431 102493944 : if (!self->types->hasScope()) {
1432 307890 : js::CheckRoot root(cx, &self);
1433 307890 : js::RootObject objRoot(cx, &scope);
1434 153945 : if (!js::types::TypeScript::SetScope(cx, self, scope))
1435 0 : return false;
1436 : }
1437 102493944 : if (!self->hasAnalysis() && !self->makeAnalysis(cx))
1438 0 : return false;
1439 102493944 : JS_ASSERT(self->analysis()->ranBytecode());
1440 102493944 : return true;
1441 : }
1442 :
1443 : inline bool
1444 4355484 : JSScript::ensureRanInference(JSContext *cx)
1445 : {
1446 4355484 : if (!ensureRanAnalysis(cx, NULL))
1447 0 : return false;
1448 4355484 : if (!analysis()->ranInference()) {
1449 77188 : js::types::AutoEnterTypeInference enter(cx);
1450 38594 : analysis()->analyzeTypes(cx);
1451 : }
1452 4355484 : return !analysis()->OOM() &&
1453 4355484 : !cx->compartment->types.pendingNukeTypes;
1454 : }
1455 :
1456 : inline bool
1457 2028248078 : JSScript::hasAnalysis()
1458 : {
1459 2028248078 : return types && types->analysis;
1460 : }
1461 :
1462 : inline js::analyze::ScriptAnalysis *
1463 1062778766 : JSScript::analysis()
1464 : {
1465 1062778766 : JS_ASSERT(hasAnalysis());
1466 1062778766 : return types->analysis;
1467 : }
1468 :
1469 : inline void
1470 428422 : JSScript::clearAnalysis()
1471 : {
1472 428422 : if (types)
1473 218213 : types->analysis = NULL;
1474 428422 : }
1475 :
1476 : inline void
1477 : js::analyze::ScriptAnalysis::addPushedType(JSContext *cx, uint32_t offset, uint32_t which,
1478 : js::types::Type type)
1479 : {
1480 : js::types::TypeSet *pushed = pushedTypes(offset, which);
1481 : pushed->addType(cx, type);
1482 : }
1483 :
1484 : inline js::types::TypeObject *
1485 1336772 : JSCompartment::getEmptyType(JSContext *cx)
1486 : {
1487 1336772 : if (!emptyTypeObject)
1488 22524 : emptyTypeObject = types.newTypeObject(cx, NULL, JSProto_Object, NULL, true);
1489 1336772 : return emptyTypeObject;
1490 : }
1491 :
1492 : #endif // jsinferinlines_h___
|