/js/src/jsinferinlines.h

http://github.com/zpao/v8monkey · C Header · 1444 lines · 1058 code · 210 blank · 176 comment · 220 complexity · 1c5c1d75de0a9d2c5a0af2941ae3caf9 MD5 · raw file

  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. /* Inline members for javascript type inference. */
  40. #include "jsarray.h"
  41. #include "jsanalyze.h"
  42. #include "jscompartment.h"
  43. #include "jsgcmark.h"
  44. #include "jsinfer.h"
  45. #include "jsprf.h"
  46. #include "vm/GlobalObject.h"
  47. #include "vm/Stack-inl.h"
  48. #ifndef jsinferinlines_h___
  49. #define jsinferinlines_h___
  50. /////////////////////////////////////////////////////////////////////
  51. // Types
  52. /////////////////////////////////////////////////////////////////////
  53. namespace js {
  54. namespace types {
  55. /* static */ inline Type
  56. Type::ObjectType(JSObject *obj)
  57. {
  58. if (obj->hasSingletonType())
  59. return Type(uintptr_t(obj) | 1);
  60. return Type(uintptr_t(obj->type()));
  61. }
  62. /* static */ inline Type
  63. Type::ObjectType(TypeObject *obj)
  64. {
  65. if (obj->singleton)
  66. return Type(uintptr_t(obj->singleton.get()) | 1);
  67. return Type(uintptr_t(obj));
  68. }
  69. /* static */ inline Type
  70. Type::ObjectType(TypeObjectKey *obj)
  71. {
  72. return Type(uintptr_t(obj));
  73. }
  74. inline Type
  75. GetValueType(JSContext *cx, const Value &val)
  76. {
  77. JS_ASSERT(cx->typeInferenceEnabled());
  78. if (val.isDouble())
  79. return Type::DoubleType();
  80. if (val.isObject())
  81. return Type::ObjectType(&val.toObject());
  82. return Type::PrimitiveType(val.extractNonDoubleType());
  83. }
  84. inline TypeFlags
  85. PrimitiveTypeFlag(JSValueType type)
  86. {
  87. switch (type) {
  88. case JSVAL_TYPE_UNDEFINED:
  89. return TYPE_FLAG_UNDEFINED;
  90. case JSVAL_TYPE_NULL:
  91. return TYPE_FLAG_NULL;
  92. case JSVAL_TYPE_BOOLEAN:
  93. return TYPE_FLAG_BOOLEAN;
  94. case JSVAL_TYPE_INT32:
  95. return TYPE_FLAG_INT32;
  96. case JSVAL_TYPE_DOUBLE:
  97. return TYPE_FLAG_DOUBLE;
  98. case JSVAL_TYPE_STRING:
  99. return TYPE_FLAG_STRING;
  100. case JSVAL_TYPE_MAGIC:
  101. return TYPE_FLAG_LAZYARGS;
  102. default:
  103. JS_NOT_REACHED("Bad type");
  104. return 0;
  105. }
  106. }
  107. inline JSValueType
  108. TypeFlagPrimitive(TypeFlags flags)
  109. {
  110. switch (flags) {
  111. case TYPE_FLAG_UNDEFINED:
  112. return JSVAL_TYPE_UNDEFINED;
  113. case TYPE_FLAG_NULL:
  114. return JSVAL_TYPE_NULL;
  115. case TYPE_FLAG_BOOLEAN:
  116. return JSVAL_TYPE_BOOLEAN;
  117. case TYPE_FLAG_INT32:
  118. return JSVAL_TYPE_INT32;
  119. case TYPE_FLAG_DOUBLE:
  120. return JSVAL_TYPE_DOUBLE;
  121. case TYPE_FLAG_STRING:
  122. return JSVAL_TYPE_STRING;
  123. case TYPE_FLAG_LAZYARGS:
  124. return JSVAL_TYPE_MAGIC;
  125. default:
  126. JS_NOT_REACHED("Bad type");
  127. return (JSValueType) 0;
  128. }
  129. }
  130. /*
  131. * Get the canonical representation of an id to use when doing inference. This
  132. * maintains the constraint that if two different jsids map to the same property
  133. * in JS (e.g. 3 and "3"), they have the same type representation.
  134. */
  135. inline jsid
  136. MakeTypeId(JSContext *cx, jsid id)
  137. {
  138. JS_ASSERT(!JSID_IS_EMPTY(id));
  139. /*
  140. * All integers must map to the aggregate property for index types, including
  141. * negative integers.
  142. */
  143. if (JSID_IS_INT(id))
  144. return JSID_VOID;
  145. /*
  146. * Check for numeric strings, as in js_StringIsIndex, but allow negative
  147. * and overflowing integers.
  148. */
  149. if (JSID_IS_STRING(id)) {
  150. JSFlatString *str = JSID_TO_FLAT_STRING(id);
  151. const jschar *cp = str->getCharsZ(cx);
  152. if (JS7_ISDEC(*cp) || *cp == '-') {
  153. cp++;
  154. while (JS7_ISDEC(*cp))
  155. cp++;
  156. if (*cp == 0)
  157. return JSID_VOID;
  158. }
  159. return id;
  160. }
  161. return JSID_VOID;
  162. }
  163. const char * TypeIdStringImpl(jsid id);
  164. /* Convert an id for printing during debug. */
  165. static inline const char *
  166. TypeIdString(jsid id)
  167. {
  168. #ifdef DEBUG
  169. return TypeIdStringImpl(id);
  170. #else
  171. return "(missing)";
  172. #endif
  173. }
  174. /*
  175. * Structure for type inference entry point functions. All functions which can
  176. * change type information must use this, and functions which depend on
  177. * intermediate types (i.e. JITs) can use this to ensure that intermediate
  178. * information is not collected and does not change.
  179. *
  180. * Pins inference results so that intermediate type information, TypeObjects
  181. * and JSScripts won't be collected during GC. Does additional sanity checking
  182. * that inference is not reentrant and that recompilations occur properly.
  183. */
  184. struct AutoEnterTypeInference
  185. {
  186. JSContext *cx;
  187. bool oldActiveAnalysis;
  188. bool oldActiveInference;
  189. AutoEnterTypeInference(JSContext *cx, bool compiling = false)
  190. : cx(cx), oldActiveAnalysis(cx->compartment->activeAnalysis),
  191. oldActiveInference(cx->compartment->activeInference)
  192. {
  193. JS_ASSERT_IF(!compiling, cx->compartment->types.inferenceEnabled);
  194. cx->compartment->activeAnalysis = true;
  195. cx->compartment->activeInference = true;
  196. }
  197. ~AutoEnterTypeInference()
  198. {
  199. cx->compartment->activeAnalysis = oldActiveAnalysis;
  200. cx->compartment->activeInference = oldActiveInference;
  201. /*
  202. * If there are no more type inference activations on the stack,
  203. * process any triggered recompilations. Note that we should not be
  204. * invoking any scripted code while type inference is running.
  205. * :TODO: assert this.
  206. */
  207. if (!cx->compartment->activeInference) {
  208. TypeCompartment *types = &cx->compartment->types;
  209. if (types->pendingNukeTypes)
  210. types->nukeTypes(cx);
  211. else if (types->pendingRecompiles)
  212. types->processPendingRecompiles(cx);
  213. }
  214. }
  215. };
  216. /*
  217. * Structure marking the currently compiled script, for constraints which can
  218. * trigger recompilation.
  219. */
  220. struct AutoEnterCompilation
  221. {
  222. RecompileInfo &info;
  223. AutoEnterCompilation(JSContext *cx, JSScript *script, bool constructing, unsigned chunkIndex)
  224. : info(cx->compartment->types.compiledInfo)
  225. {
  226. JS_ASSERT(!info.script);
  227. info.script = script;
  228. info.constructing = constructing;
  229. info.chunkIndex = chunkIndex;
  230. }
  231. ~AutoEnterCompilation()
  232. {
  233. JS_ASSERT(info.script);
  234. info.script = NULL;
  235. info.constructing = false;
  236. info.chunkIndex = 0;
  237. }
  238. };
  239. /////////////////////////////////////////////////////////////////////
  240. // Interface functions
  241. /////////////////////////////////////////////////////////////////////
  242. /*
  243. * These functions check whether inference is enabled before performing some
  244. * action on the type state. To avoid checking cx->typeInferenceEnabled()
  245. * everywhere, it is generally preferred to use one of these functions or
  246. * a type function on JSScript to perform inference operations.
  247. */
  248. /*
  249. * Get the default 'new' object for a given standard class, per the currently
  250. * active global.
  251. */
  252. inline TypeObject *
  253. GetTypeNewObject(JSContext *cx, JSProtoKey key)
  254. {
  255. JSObject *proto;
  256. if (!js_GetClassPrototype(cx, NULL, key, &proto, NULL))
  257. return NULL;
  258. return proto->getNewType(cx);
  259. }
  260. /* Get a type object for the immediate allocation site within a native. */
  261. inline TypeObject *
  262. GetTypeCallerInitObject(JSContext *cx, JSProtoKey key)
  263. {
  264. if (cx->typeInferenceEnabled()) {
  265. jsbytecode *pc;
  266. JSScript *script = cx->stack.currentScript(&pc);
  267. if (script)
  268. return TypeScript::InitObject(cx, script, pc, key);
  269. }
  270. return GetTypeNewObject(cx, key);
  271. }
  272. /*
  273. * When using a custom iterator within the initialization of a 'for in' loop,
  274. * mark the iterator values as unknown.
  275. */
  276. inline void
  277. MarkIteratorUnknown(JSContext *cx)
  278. {
  279. extern void MarkIteratorUnknownSlow(JSContext *cx);
  280. if (cx->typeInferenceEnabled())
  281. MarkIteratorUnknownSlow(cx);
  282. }
  283. /*
  284. * Monitor a javascript call, either on entry to the interpreter or made
  285. * from within the interpreter.
  286. */
  287. inline void
  288. TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing)
  289. {
  290. extern void TypeMonitorCallSlow(JSContext *cx, JSObject *callee,
  291. const CallArgs &args, bool constructing);
  292. JSObject *callee = &args.callee();
  293. if (callee->isFunction()) {
  294. JSFunction *fun = callee->toFunction();
  295. if (fun->isInterpreted()) {
  296. JSScript *script = fun->script();
  297. if (!script->ensureRanAnalysis(cx, fun->environment()))
  298. return;
  299. if (cx->typeInferenceEnabled())
  300. TypeMonitorCallSlow(cx, callee, args, constructing);
  301. }
  302. }
  303. }
  304. inline bool
  305. TrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
  306. {
  307. if (!cx->typeInferenceEnabled() || obj->hasLazyType() || obj->type()->unknownProperties())
  308. return false;
  309. if (obj->hasSingletonType() && !obj->type()->maybeGetProperty(cx, id))
  310. return false;
  311. return true;
  312. }
  313. /* Add a possible type for a property of obj. */
  314. inline void
  315. AddTypePropertyId(JSContext *cx, JSObject *obj, jsid id, Type type)
  316. {
  317. if (cx->typeInferenceEnabled())
  318. id = MakeTypeId(cx, id);
  319. if (TrackPropertyTypes(cx, obj, id))
  320. obj->type()->addPropertyType(cx, id, type);
  321. }
  322. inline void
  323. AddTypePropertyId(JSContext *cx, JSObject *obj, jsid id, const Value &value)
  324. {
  325. if (cx->typeInferenceEnabled())
  326. id = MakeTypeId(cx, id);
  327. if (TrackPropertyTypes(cx, obj, id))
  328. obj->type()->addPropertyType(cx, id, value);
  329. }
  330. inline void
  331. AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, Type type)
  332. {
  333. if (cx->typeInferenceEnabled() && !obj->unknownProperties())
  334. obj->addPropertyType(cx, name, type);
  335. }
  336. inline void
  337. AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, const Value &value)
  338. {
  339. if (cx->typeInferenceEnabled() && !obj->unknownProperties())
  340. obj->addPropertyType(cx, name, value);
  341. }
  342. /* Set one or more dynamic flags on a type object. */
  343. inline void
  344. MarkTypeObjectFlags(JSContext *cx, JSObject *obj, TypeObjectFlags flags)
  345. {
  346. if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->hasAllFlags(flags))
  347. obj->type()->setFlags(cx, flags);
  348. }
  349. /*
  350. * Mark all properties of a type object as unknown. If markSetsUnknown is set,
  351. * scan the entire compartment and mark all type sets containing it as having
  352. * an unknown object. This is needed for correctness in dealing with mutable
  353. * __proto__, which can change the type of an object dynamically.
  354. */
  355. inline void
  356. MarkTypeObjectUnknownProperties(JSContext *cx, TypeObject *obj,
  357. bool markSetsUnknown = false)
  358. {
  359. if (cx->typeInferenceEnabled()) {
  360. if (!obj->unknownProperties())
  361. obj->markUnknown(cx);
  362. if (markSetsUnknown && !(obj->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN))
  363. cx->compartment->types.markSetsUnknown(cx, obj);
  364. }
  365. }
  366. /*
  367. * Mark any property which has been deleted or configured to be non-writable or
  368. * have a getter/setter.
  369. */
  370. inline void
  371. MarkTypePropertyConfigured(JSContext *cx, JSObject *obj, jsid id)
  372. {
  373. if (cx->typeInferenceEnabled())
  374. id = MakeTypeId(cx, id);
  375. if (TrackPropertyTypes(cx, obj, id))
  376. obj->type()->markPropertyConfigured(cx, id);
  377. }
  378. /* Mark a state change on a particular object. */
  379. inline void
  380. MarkObjectStateChange(JSContext *cx, JSObject *obj)
  381. {
  382. if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->unknownProperties())
  383. obj->type()->markStateChange(cx);
  384. }
  385. /*
  386. * For an array or object which has not yet escaped and been referenced elsewhere,
  387. * pick a new type based on the object's current contents.
  388. */
  389. inline void
  390. FixArrayType(JSContext *cx, JSObject *obj)
  391. {
  392. if (cx->typeInferenceEnabled())
  393. cx->compartment->types.fixArrayType(cx, obj);
  394. }
  395. inline void
  396. FixObjectType(JSContext *cx, JSObject *obj)
  397. {
  398. if (cx->typeInferenceEnabled())
  399. cx->compartment->types.fixObjectType(cx, obj);
  400. }
  401. /* Interface helpers for JSScript */
  402. extern void TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval);
  403. extern void TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, js::types::Type type);
  404. inline bool
  405. UseNewTypeAtEntry(JSContext *cx, StackFrame *fp)
  406. {
  407. return fp->isConstructing() && cx->typeInferenceEnabled() &&
  408. fp->prev() && fp->prev()->isScriptFrame() &&
  409. UseNewType(cx, fp->prev()->script(), fp->prev()->pcQuadratic(cx->stack, fp));
  410. }
  411. /////////////////////////////////////////////////////////////////////
  412. // Script interface functions
  413. /////////////////////////////////////////////////////////////////////
  414. inline
  415. TypeScript::TypeScript()
  416. {
  417. this->global = (js::GlobalObject *) GLOBAL_MISSING_SCOPE;
  418. }
  419. /* static */ inline unsigned
  420. TypeScript::NumTypeSets(JSScript *script)
  421. {
  422. return script->nTypeSets + analyze::TotalSlots(script);
  423. }
  424. /* static */ inline TypeSet *
  425. TypeScript::ReturnTypes(JSScript *script)
  426. {
  427. return script->types->typeArray() + script->nTypeSets + js::analyze::CalleeSlot();
  428. }
  429. /* static */ inline TypeSet *
  430. TypeScript::ThisTypes(JSScript *script)
  431. {
  432. return script->types->typeArray() + script->nTypeSets + js::analyze::ThisSlot();
  433. }
  434. /*
  435. * Note: for non-escaping arguments and locals, argTypes/localTypes reflect
  436. * only the initial type of the variable (e.g. passed values for argTypes,
  437. * or undefined for localTypes) and not types from subsequent assignments.
  438. */
  439. /* static */ inline TypeSet *
  440. TypeScript::ArgTypes(JSScript *script, unsigned i)
  441. {
  442. JS_ASSERT(i < script->function()->nargs);
  443. return script->types->typeArray() + script->nTypeSets + js::analyze::ArgSlot(i);
  444. }
  445. /* static */ inline TypeSet *
  446. TypeScript::LocalTypes(JSScript *script, unsigned i)
  447. {
  448. JS_ASSERT(i < script->nfixed);
  449. return script->types->typeArray() + script->nTypeSets + js::analyze::LocalSlot(script, i);
  450. }
  451. /* static */ inline TypeSet *
  452. TypeScript::SlotTypes(JSScript *script, unsigned slot)
  453. {
  454. JS_ASSERT(slot < js::analyze::TotalSlots(script));
  455. return script->types->typeArray() + script->nTypeSets + slot;
  456. }
  457. /* static */ inline TypeObject *
  458. TypeScript::StandardType(JSContext *cx, JSScript *script, JSProtoKey key)
  459. {
  460. JSObject *proto;
  461. if (!js_GetClassPrototype(cx, script->global(), key, &proto, NULL))
  462. return NULL;
  463. return proto->getNewType(cx);
  464. }
  465. struct AllocationSiteKey {
  466. JSScript *script;
  467. uint32_t offset : 24;
  468. JSProtoKey kind : 8;
  469. static const uint32_t OFFSET_LIMIT = (1 << 23);
  470. AllocationSiteKey() { PodZero(this); }
  471. typedef AllocationSiteKey Lookup;
  472. static inline uint32_t hash(AllocationSiteKey key) {
  473. return uint32_t(size_t(key.script->code + key.offset)) ^ key.kind;
  474. }
  475. static inline bool match(const AllocationSiteKey &a, const AllocationSiteKey &b) {
  476. return a.script == b.script && a.offset == b.offset && a.kind == b.kind;
  477. }
  478. };
  479. /* static */ inline TypeObject *
  480. TypeScript::InitObject(JSContext *cx, JSScript *script, const jsbytecode *pc, JSProtoKey kind)
  481. {
  482. /* :XXX: Limit script->length so we don't need to check the offset up front? */
  483. uint32_t offset = pc - script->code;
  484. if (!cx->typeInferenceEnabled() || !script->hasGlobal() || offset >= AllocationSiteKey::OFFSET_LIMIT)
  485. return GetTypeNewObject(cx, kind);
  486. AllocationSiteKey key;
  487. key.script = script;
  488. key.offset = offset;
  489. key.kind = kind;
  490. if (!cx->compartment->types.allocationSiteTable)
  491. return cx->compartment->types.newAllocationSiteTypeObject(cx, key);
  492. AllocationSiteTable::Ptr p = cx->compartment->types.allocationSiteTable->lookup(key);
  493. if (p)
  494. return p->value;
  495. return cx->compartment->types.newAllocationSiteTypeObject(cx, key);
  496. }
  497. /* static */ inline void
  498. TypeScript::Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
  499. {
  500. if (cx->typeInferenceEnabled())
  501. TypeMonitorResult(cx, script, pc, rval);
  502. }
  503. /* static */ inline void
  504. TypeScript::MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc)
  505. {
  506. if (cx->typeInferenceEnabled())
  507. TypeDynamicResult(cx, script, pc, Type::DoubleType());
  508. }
  509. /* static */ inline void
  510. TypeScript::MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc)
  511. {
  512. if (cx->typeInferenceEnabled())
  513. TypeDynamicResult(cx, script, pc, Type::StringType());
  514. }
  515. /* static */ inline void
  516. TypeScript::MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc)
  517. {
  518. if (cx->typeInferenceEnabled())
  519. TypeDynamicResult(cx, script, pc, Type::UnknownType());
  520. }
  521. /* static */ inline void
  522. TypeScript::GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc)
  523. {
  524. *script = cx->fp()->script();
  525. *pc = cx->regs().pc;
  526. }
  527. /* static */ inline void
  528. TypeScript::MonitorOverflow(JSContext *cx)
  529. {
  530. JSScript *script;
  531. jsbytecode *pc;
  532. GetPcScript(cx, &script, &pc);
  533. MonitorOverflow(cx, script, pc);
  534. }
  535. /* static */ inline void
  536. TypeScript::MonitorString(JSContext *cx)
  537. {
  538. JSScript *script;
  539. jsbytecode *pc;
  540. GetPcScript(cx, &script, &pc);
  541. MonitorString(cx, script, pc);
  542. }
  543. /* static */ inline void
  544. TypeScript::MonitorUnknown(JSContext *cx)
  545. {
  546. JSScript *script;
  547. jsbytecode *pc;
  548. GetPcScript(cx, &script, &pc);
  549. MonitorUnknown(cx, script, pc);
  550. }
  551. /* static */ inline void
  552. TypeScript::Monitor(JSContext *cx, const js::Value &rval)
  553. {
  554. JSScript *script;
  555. jsbytecode *pc;
  556. GetPcScript(cx, &script, &pc);
  557. Monitor(cx, script, pc, rval);
  558. }
  559. /* static */ inline void
  560. TypeScript::MonitorAssign(JSContext *cx, JSScript *script, jsbytecode *pc,
  561. JSObject *obj, jsid id, const js::Value &rval)
  562. {
  563. if (cx->typeInferenceEnabled() && !obj->hasSingletonType()) {
  564. /*
  565. * Mark as unknown any object which has had dynamic assignments to
  566. * non-integer properties at SETELEM opcodes. This avoids making large
  567. * numbers of type properties for hashmap-style objects. We don't need
  568. * to do this for objects with singleton type, because type properties
  569. * are only constructed for them when analyzed scripts depend on those
  570. * specific properties.
  571. */
  572. uint32_t i;
  573. if (js_IdIsIndex(id, &i))
  574. return;
  575. MarkTypeObjectUnknownProperties(cx, obj->type());
  576. }
  577. }
  578. /* static */ inline void
  579. TypeScript::SetThis(JSContext *cx, JSScript *script, Type type)
  580. {
  581. if (!cx->typeInferenceEnabled())
  582. return;
  583. JS_ASSERT(script->types);
  584. /* Analyze the script regardless if -a was used. */
  585. bool analyze = cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS);
  586. if (!ThisTypes(script)->hasType(type) || analyze) {
  587. AutoEnterTypeInference enter(cx);
  588. InferSpew(ISpewOps, "externalType: setThis #%u: %s",
  589. script->id(), TypeString(type));
  590. ThisTypes(script)->addType(cx, type);
  591. if (analyze && script->types->hasScope())
  592. script->ensureRanInference(cx);
  593. }
  594. }
  595. /* static */ inline void
  596. TypeScript::SetThis(JSContext *cx, JSScript *script, const js::Value &value)
  597. {
  598. if (cx->typeInferenceEnabled())
  599. SetThis(cx, script, GetValueType(cx, value));
  600. }
  601. /* static */ inline void
  602. TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type)
  603. {
  604. if (!cx->typeInferenceEnabled())
  605. return;
  606. JS_ASSERT(script->types);
  607. if (!LocalTypes(script, local)->hasType(type)) {
  608. AutoEnterTypeInference enter(cx);
  609. InferSpew(ISpewOps, "externalType: setLocal #%u %u: %s",
  610. script->id(), local, TypeString(type));
  611. LocalTypes(script, local)->addType(cx, type);
  612. }
  613. }
  614. /* static */ inline void
  615. TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value)
  616. {
  617. if (cx->typeInferenceEnabled()) {
  618. Type type = GetValueType(cx, value);
  619. SetLocal(cx, script, local, type);
  620. }
  621. }
  622. /* static */ inline void
  623. TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type)
  624. {
  625. if (!cx->typeInferenceEnabled())
  626. return;
  627. JS_ASSERT(script->types);
  628. if (!ArgTypes(script, arg)->hasType(type)) {
  629. AutoEnterTypeInference enter(cx);
  630. InferSpew(ISpewOps, "externalType: setArg #%u %u: %s",
  631. script->id(), arg, TypeString(type));
  632. ArgTypes(script, arg)->addType(cx, type);
  633. }
  634. }
  635. /* static */ inline void
  636. TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value)
  637. {
  638. if (cx->typeInferenceEnabled()) {
  639. Type type = GetValueType(cx, value);
  640. SetArgument(cx, script, arg, type);
  641. }
  642. }
  643. void
  644. TypeScript::trace(JSTracer *trc)
  645. {
  646. if (hasScope() && global)
  647. gc::MarkObject(trc, global, "script_global");
  648. /* Note: nesting does not keep anything alive. */
  649. }
  650. /////////////////////////////////////////////////////////////////////
  651. // TypeCompartment
  652. /////////////////////////////////////////////////////////////////////
  653. inline JSCompartment *
  654. TypeCompartment::compartment()
  655. {
  656. return (JSCompartment *)((char *)this - offsetof(JSCompartment, types));
  657. }
  658. inline void
  659. TypeCompartment::addPending(JSContext *cx, TypeConstraint *constraint, TypeSet *source, Type type)
  660. {
  661. JS_ASSERT(this == &cx->compartment->types);
  662. JS_ASSERT(!cx->runtime->gcRunning);
  663. InferSpew(ISpewOps, "pending: %sC%p%s %s",
  664. InferSpewColor(constraint), constraint, InferSpewColorReset(),
  665. TypeString(type));
  666. if ((pendingCount == pendingCapacity) && !growPendingArray(cx))
  667. return;
  668. PendingWork &pending = pendingArray[pendingCount++];
  669. pending.constraint = constraint;
  670. pending.source = source;
  671. pending.type = type;
  672. }
  673. inline void
  674. TypeCompartment::resolvePending(JSContext *cx)
  675. {
  676. JS_ASSERT(this == &cx->compartment->types);
  677. if (resolving) {
  678. /* There is an active call further up resolving the worklist. */
  679. return;
  680. }
  681. resolving = true;
  682. /* Handle all pending type registrations. */
  683. while (pendingCount) {
  684. const PendingWork &pending = pendingArray[--pendingCount];
  685. InferSpew(ISpewOps, "resolve: %sC%p%s %s",
  686. InferSpewColor(pending.constraint), pending.constraint,
  687. InferSpewColorReset(), TypeString(pending.type));
  688. pending.constraint->newType(cx, pending.source, pending.type);
  689. }
  690. resolving = false;
  691. }
  692. /////////////////////////////////////////////////////////////////////
  693. // TypeSet
  694. /////////////////////////////////////////////////////////////////////
  695. /*
  696. * The sets of objects and scripts in a type set grow monotonically, are usually
  697. * empty, almost always small, and sometimes big. For empty or singleton sets,
  698. * the pointer refers directly to the value. For sets fitting into SET_ARRAY_SIZE,
  699. * an array of this length is used to store the elements. For larger sets, a hash
  700. * table filled to 25%-50% of capacity is used, with collisions resolved by linear
  701. * probing. TODO: replace these with jshashtables.
  702. */
  703. const unsigned SET_ARRAY_SIZE = 8;
  704. /* Get the capacity of a set with the given element count. */
  705. static inline unsigned
  706. HashSetCapacity(unsigned count)
  707. {
  708. JS_ASSERT(count >= 2);
  709. if (count <= SET_ARRAY_SIZE)
  710. return SET_ARRAY_SIZE;
  711. unsigned log2;
  712. JS_FLOOR_LOG2(log2, count);
  713. return 1 << (log2 + 2);
  714. }
  715. /* Compute the FNV hash for the low 32 bits of v. */
  716. template <class T, class KEY>
  717. static inline uint32_t
  718. HashKey(T v)
  719. {
  720. uint32_t nv = KEY::keyBits(v);
  721. uint32_t hash = 84696351 ^ (nv & 0xff);
  722. hash = (hash * 16777619) ^ ((nv >> 8) & 0xff);
  723. hash = (hash * 16777619) ^ ((nv >> 16) & 0xff);
  724. return (hash * 16777619) ^ ((nv >> 24) & 0xff);
  725. }
  726. /*
  727. * Insert space for an element into the specified set and grow its capacity if needed.
  728. * returned value is an existing or new entry (NULL if new).
  729. */
  730. template <class T, class U, class KEY>
  731. static U **
  732. HashSetInsertTry(JSCompartment *compartment, U **&values, unsigned &count, T key)
  733. {
  734. unsigned capacity = HashSetCapacity(count);
  735. unsigned insertpos = HashKey<T,KEY>(key) & (capacity - 1);
  736. /* Whether we are converting from a fixed array to hashtable. */
  737. bool converting = (count == SET_ARRAY_SIZE);
  738. if (!converting) {
  739. while (values[insertpos] != NULL) {
  740. if (KEY::getKey(values[insertpos]) == key)
  741. return &values[insertpos];
  742. insertpos = (insertpos + 1) & (capacity - 1);
  743. }
  744. }
  745. count++;
  746. unsigned newCapacity = HashSetCapacity(count);
  747. if (newCapacity == capacity) {
  748. JS_ASSERT(!converting);
  749. return &values[insertpos];
  750. }
  751. U **newValues = compartment->typeLifoAlloc.newArray<U*>(newCapacity);
  752. if (!newValues)
  753. return NULL;
  754. PodZero(newValues, newCapacity);
  755. for (unsigned i = 0; i < capacity; i++) {
  756. if (values[i]) {
  757. unsigned pos = HashKey<T,KEY>(KEY::getKey(values[i])) & (newCapacity - 1);
  758. while (newValues[pos] != NULL)
  759. pos = (pos + 1) & (newCapacity - 1);
  760. newValues[pos] = values[i];
  761. }
  762. }
  763. values = newValues;
  764. insertpos = HashKey<T,KEY>(key) & (newCapacity - 1);
  765. while (values[insertpos] != NULL)
  766. insertpos = (insertpos + 1) & (newCapacity - 1);
  767. return &values[insertpos];
  768. }
  769. /*
  770. * Insert an element into the specified set if it is not already there, returning
  771. * an entry which is NULL if the element was not there.
  772. */
  773. template <class T, class U, class KEY>
  774. static inline U **
  775. HashSetInsert(JSCompartment *compartment, U **&values, unsigned &count, T key)
  776. {
  777. if (count == 0) {
  778. JS_ASSERT(values == NULL);
  779. count++;
  780. return (U **) &values;
  781. }
  782. if (count == 1) {
  783. U *oldData = (U*) values;
  784. if (KEY::getKey(oldData) == key)
  785. return (U **) &values;
  786. values = compartment->typeLifoAlloc.newArray<U*>(SET_ARRAY_SIZE);
  787. if (!values) {
  788. values = (U **) oldData;
  789. return NULL;
  790. }
  791. PodZero(values, SET_ARRAY_SIZE);
  792. count++;
  793. values[0] = oldData;
  794. return &values[1];
  795. }
  796. if (count <= SET_ARRAY_SIZE) {
  797. for (unsigned i = 0; i < count; i++) {
  798. if (KEY::getKey(values[i]) == key)
  799. return &values[i];
  800. }
  801. if (count < SET_ARRAY_SIZE) {
  802. count++;
  803. return &values[count - 1];
  804. }
  805. }
  806. return HashSetInsertTry<T,U,KEY>(compartment, values, count, key);
  807. }
  808. /* Lookup an entry in a hash set, return NULL if it does not exist. */
  809. template <class T, class U, class KEY>
  810. static inline U *
  811. HashSetLookup(U **values, unsigned count, T key)
  812. {
  813. if (count == 0)
  814. return NULL;
  815. if (count == 1)
  816. return (KEY::getKey((U *) values) == key) ? (U *) values : NULL;
  817. if (count <= SET_ARRAY_SIZE) {
  818. for (unsigned i = 0; i < count; i++) {
  819. if (KEY::getKey(values[i]) == key)
  820. return values[i];
  821. }
  822. return NULL;
  823. }
  824. unsigned capacity = HashSetCapacity(count);
  825. unsigned pos = HashKey<T,KEY>(key) & (capacity - 1);
  826. while (values[pos] != NULL) {
  827. if (KEY::getKey(values[pos]) == key)
  828. return values[pos];
  829. pos = (pos + 1) & (capacity - 1);
  830. }
  831. return NULL;
  832. }
  833. inline bool
  834. TypeSet::hasType(Type type)
  835. {
  836. if (unknown())
  837. return true;
  838. if (type.isUnknown()) {
  839. return false;
  840. } else if (type.isPrimitive()) {
  841. return !!(flags & PrimitiveTypeFlag(type.primitive()));
  842. } else if (type.isAnyObject()) {
  843. return !!(flags & TYPE_FLAG_ANYOBJECT);
  844. } else {
  845. return !!(flags & TYPE_FLAG_ANYOBJECT) ||
  846. HashSetLookup<TypeObjectKey*,TypeObjectKey,TypeObjectKey>
  847. (objectSet, baseObjectCount(), type.objectKey()) != NULL;
  848. }
  849. }
  850. inline void
  851. TypeSet::setBaseObjectCount(uint32_t count)
  852. {
  853. JS_ASSERT(count <= TYPE_FLAG_OBJECT_COUNT_LIMIT);
  854. flags = (flags & ~TYPE_FLAG_OBJECT_COUNT_MASK)
  855. | (count << TYPE_FLAG_OBJECT_COUNT_SHIFT);
  856. }
  857. inline void
  858. TypeSet::clearObjects()
  859. {
  860. setBaseObjectCount(0);
  861. objectSet = NULL;
  862. }
  863. inline void
  864. TypeSet::addType(JSContext *cx, Type type)
  865. {
  866. JS_ASSERT(cx->compartment->activeInference);
  867. if (unknown())
  868. return;
  869. if (type.isUnknown()) {
  870. flags |= TYPE_FLAG_BASE_MASK;
  871. clearObjects();
  872. JS_ASSERT(unknown());
  873. } else if (type.isPrimitive()) {
  874. TypeFlags flag = PrimitiveTypeFlag(type.primitive());
  875. if (flags & flag)
  876. return;
  877. /* If we add float to a type set it is also considered to contain int. */
  878. if (flag == TYPE_FLAG_DOUBLE)
  879. flag |= TYPE_FLAG_INT32;
  880. flags |= flag;
  881. } else {
  882. if (flags & TYPE_FLAG_ANYOBJECT)
  883. return;
  884. if (type.isAnyObject())
  885. goto unknownObject;
  886. uint32_t objectCount = baseObjectCount();
  887. TypeObjectKey *object = type.objectKey();
  888. TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
  889. (cx->compartment, objectSet, objectCount, object);
  890. if (!pentry) {
  891. cx->compartment->types.setPendingNukeTypes(cx);
  892. return;
  893. }
  894. if (*pentry)
  895. return;
  896. *pentry = object;
  897. setBaseObjectCount(objectCount);
  898. if (objectCount == TYPE_FLAG_OBJECT_COUNT_LIMIT)
  899. goto unknownObject;
  900. if (type.isTypeObject()) {
  901. TypeObject *nobject = type.typeObject();
  902. JS_ASSERT(!nobject->singleton);
  903. if (nobject->unknownProperties())
  904. goto unknownObject;
  905. if (objectCount > 1) {
  906. nobject->contribution += (objectCount - 1) * (objectCount - 1);
  907. if (nobject->contribution >= TypeObject::CONTRIBUTION_LIMIT) {
  908. InferSpew(ISpewOps, "limitUnknown: %sT%p%s",
  909. InferSpewColor(this), this, InferSpewColorReset());
  910. goto unknownObject;
  911. }
  912. }
  913. }
  914. }
  915. if (false) {
  916. unknownObject:
  917. type = Type::AnyObjectType();
  918. flags |= TYPE_FLAG_ANYOBJECT;
  919. clearObjects();
  920. }
  921. InferSpew(ISpewOps, "addType: %sT%p%s %s",
  922. InferSpewColor(this), this, InferSpewColorReset(),
  923. TypeString(type));
  924. /* Propagate the type to all constraints. */
  925. TypeConstraint *constraint = constraintList;
  926. while (constraint) {
  927. cx->compartment->types.addPending(cx, constraint, this, type);
  928. constraint = constraint->next;
  929. }
  930. cx->compartment->types.resolvePending(cx);
  931. }
  932. inline void
  933. TypeSet::setOwnProperty(JSContext *cx, bool configured)
  934. {
  935. TypeFlags nflags = TYPE_FLAG_OWN_PROPERTY | (configured ? TYPE_FLAG_CONFIGURED_PROPERTY : 0);
  936. if ((flags & nflags) == nflags)
  937. return;
  938. flags |= nflags;
  939. /* Propagate the change to all constraints. */
  940. TypeConstraint *constraint = constraintList;
  941. while (constraint) {
  942. constraint->newPropertyState(cx, this);
  943. constraint = constraint->next;
  944. }
  945. }
  946. inline unsigned
  947. TypeSet::getObjectCount()
  948. {
  949. JS_ASSERT(!unknownObject());
  950. uint32_t count = baseObjectCount();
  951. if (count > SET_ARRAY_SIZE)
  952. return HashSetCapacity(count);
  953. return count;
  954. }
  955. inline TypeObjectKey *
  956. TypeSet::getObject(unsigned i)
  957. {
  958. JS_ASSERT(i < getObjectCount());
  959. if (baseObjectCount() == 1) {
  960. JS_ASSERT(i == 0);
  961. return (TypeObjectKey *) objectSet;
  962. }
  963. return objectSet[i];
  964. }
  965. inline JSObject *
  966. TypeSet::getSingleObject(unsigned i)
  967. {
  968. TypeObjectKey *key = getObject(i);
  969. return (uintptr_t(key) & 1) ? (JSObject *)(uintptr_t(key) ^ 1) : NULL;
  970. }
  971. inline TypeObject *
  972. TypeSet::getTypeObject(unsigned i)
  973. {
  974. TypeObjectKey *key = getObject(i);
  975. return (key && !(uintptr_t(key) & 1)) ? (TypeObject *) key : NULL;
  976. }
  977. /////////////////////////////////////////////////////////////////////
  978. // TypeCallsite
  979. /////////////////////////////////////////////////////////////////////
  980. inline
  981. TypeCallsite::TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
  982. bool isNew, unsigned argumentCount)
  983. : script(script), pc(pc), isNew(isNew), argumentCount(argumentCount),
  984. thisTypes(NULL), returnTypes(NULL)
  985. {
  986. /* Caller must check for failure. */
  987. argumentTypes = cx->typeLifoAlloc().newArray<TypeSet*>(argumentCount);
  988. }
  989. /////////////////////////////////////////////////////////////////////
  990. // TypeObject
  991. /////////////////////////////////////////////////////////////////////
  992. inline TypeObject::TypeObject(JSObject *proto, bool function, bool unknown)
  993. {
  994. PodZero(this);
  995. /* Inner objects may not appear on prototype chains. */
  996. JS_ASSERT_IF(proto, !proto->getClass()->ext.outerObject);
  997. this->proto = proto;
  998. if (function)
  999. flags |= OBJECT_FLAG_FUNCTION;
  1000. if (unknown)
  1001. flags |= OBJECT_FLAG_UNKNOWN_MASK;
  1002. InferSpew(ISpewOps, "newObject: %s", TypeObjectString(this));
  1003. }
  1004. inline uint32_t
  1005. TypeObject::basePropertyCount() const
  1006. {
  1007. return (flags & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
  1008. }
  1009. inline void
  1010. TypeObject::setBasePropertyCount(uint32_t count)
  1011. {
  1012. JS_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT);
  1013. flags = (flags & ~OBJECT_FLAG_PROPERTY_COUNT_MASK)
  1014. | (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
  1015. }
  1016. inline TypeSet *
  1017. TypeObject::getProperty(JSContext *cx, jsid id, bool assign)
  1018. {
  1019. JS_ASSERT(cx->compartment->activeInference);
  1020. JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
  1021. JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == MakeTypeId(cx, id));
  1022. JS_ASSERT(!unknownProperties());
  1023. uint32_t propertyCount = basePropertyCount();
  1024. Property **pprop = HashSetInsert<jsid,Property,Property>
  1025. (cx->compartment, propertySet, propertyCount, id);
  1026. if (!pprop) {
  1027. cx->compartment->types.setPendingNukeTypes(cx);
  1028. return NULL;
  1029. }
  1030. if (!*pprop) {
  1031. setBasePropertyCount(propertyCount);
  1032. if (!addProperty(cx, id, pprop))
  1033. return NULL;
  1034. if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
  1035. markUnknown(cx);
  1036. TypeSet *types = TypeSet::make(cx, "propertyOverflow");
  1037. types->addType(cx, Type::UnknownType());
  1038. return types;
  1039. }
  1040. }
  1041. TypeSet *types = &(*pprop)->types;
  1042. if (assign)
  1043. types->setOwnProperty(cx, false);
  1044. return types;
  1045. }
  1046. inline TypeSet *
  1047. TypeObject::maybeGetProperty(JSContext *cx, jsid id)
  1048. {
  1049. JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
  1050. JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == MakeTypeId(cx, id));
  1051. JS_ASSERT(!unknownProperties());
  1052. Property *prop = HashSetLookup<jsid,Property,Property>
  1053. (propertySet, basePropertyCount(), id);
  1054. return prop ? &prop->types : NULL;
  1055. }
  1056. inline unsigned
  1057. TypeObject::getPropertyCount()
  1058. {
  1059. uint32_t count = basePropertyCount();
  1060. if (count > SET_ARRAY_SIZE)
  1061. return HashSetCapacity(count);
  1062. return count;
  1063. }
  1064. inline Property *
  1065. TypeObject::getProperty(unsigned i)
  1066. {
  1067. JS_ASSERT(i < getPropertyCount());
  1068. if (basePropertyCount() == 1) {
  1069. JS_ASSERT(i == 0);
  1070. return (Property *) propertySet;
  1071. }
  1072. return propertySet[i];
  1073. }
  1074. inline void
  1075. TypeObject::setFlagsFromKey(JSContext *cx, JSProtoKey key)
  1076. {
  1077. TypeObjectFlags flags = 0;
  1078. switch (key) {
  1079. case JSProto_Function:
  1080. JS_ASSERT(isFunction());
  1081. /* FALLTHROUGH */
  1082. case JSProto_Object:
  1083. flags = OBJECT_FLAG_NON_DENSE_ARRAY
  1084. | OBJECT_FLAG_NON_PACKED_ARRAY
  1085. | OBJECT_FLAG_NON_TYPED_ARRAY;
  1086. break;
  1087. case JSProto_Array:
  1088. flags = OBJECT_FLAG_NON_TYPED_ARRAY;
  1089. break;
  1090. default:
  1091. /* :XXX: abstract */
  1092. JS_ASSERT(key == JSProto_Int8Array ||
  1093. key == JSProto_Uint8Array ||
  1094. key == JSProto_Int16Array ||
  1095. key == JSProto_Uint16Array ||
  1096. key == JSProto_Int32Array ||
  1097. key == JSProto_Uint32Array ||
  1098. key == JSProto_Float32Array ||
  1099. key == JSProto_Float64Array ||
  1100. key == JSProto_Uint8ClampedArray);
  1101. flags = OBJECT_FLAG_NON_DENSE_ARRAY
  1102. | OBJECT_FLAG_NON_PACKED_ARRAY;
  1103. break;
  1104. }
  1105. if (!hasAllFlags(flags))
  1106. setFlags(cx, flags);
  1107. }
  1108. inline JSObject *
  1109. TypeObject::getGlobal()
  1110. {
  1111. if (singleton)
  1112. return &singleton->global();
  1113. if (interpretedFunction && interpretedFunction->script()->compileAndGo)
  1114. return &interpretedFunction->global();
  1115. return NULL;
  1116. }
  1117. inline void
  1118. TypeObject::writeBarrierPre(TypeObject *type)
  1119. {
  1120. #ifdef JSGC_INCREMENTAL
  1121. if (!type)
  1122. return;
  1123. JSCompartment *comp = type->compartment();
  1124. if (comp->needsBarrier())
  1125. MarkTypeObjectUnbarriered(comp->barrierTracer(), type, "write barrier");
  1126. #endif
  1127. }
  1128. inline void
  1129. TypeObject::writeBarrierPost(TypeObject *type, void *addr)
  1130. {
  1131. }
  1132. inline void
  1133. TypeObject::readBarrier(TypeObject *type)
  1134. {
  1135. #ifdef JSGC_INCREMENTAL
  1136. JSCompartment *comp = type->compartment();
  1137. if (comp->needsBarrier())
  1138. MarkTypeObjectUnbarriered(comp->barrierTracer(), type, "read barrier");
  1139. #endif
  1140. }
  1141. inline void
  1142. TypeNewScript::writeBarrierPre(TypeNewScript *newScript)
  1143. {
  1144. #ifdef JSGC_INCREMENTAL
  1145. if (!newScript)
  1146. return;
  1147. JSCompartment *comp = newScript->fun->compartment();
  1148. if (comp->needsBarrier()) {
  1149. MarkObjectUnbarriered(comp->barrierTracer(), newScript->fun, "write barrier");
  1150. MarkShape(comp->barrierTracer(), newScript->shape, "write barrier");
  1151. }
  1152. #endif
  1153. }
  1154. inline void
  1155. TypeNewScript::writeBarrierPost(TypeNewScript *newScript, void *addr)
  1156. {
  1157. }
  1158. inline
  1159. Property::Property(jsid id)
  1160. : id(id)
  1161. {
  1162. }
  1163. inline
  1164. Property::Property(const Property &o)
  1165. : id(o.id.get()), types(o.types)
  1166. {
  1167. }
  1168. } } /* namespace js::types */
  1169. inline bool
  1170. JSScript::ensureHasTypes(JSContext *cx)
  1171. {
  1172. return types || makeTypes(cx);
  1173. }
  1174. inline bool
  1175. JSScript::ensureRanAnalysis(JSContext *cx, JSObject *scope)
  1176. {
  1177. JSScript *self = this;
  1178. if (!self->ensureHasTypes(cx))
  1179. return false;
  1180. if (!self->types->hasScope()) {
  1181. js::CheckRoot root(cx, &self);
  1182. js::RootObject objRoot(cx, &scope);
  1183. if (!js::types::TypeScript::SetScope(cx, self, scope))
  1184. return false;
  1185. }
  1186. if (!self->hasAnalysis() && !self->makeAnalysis(cx))
  1187. return false;
  1188. JS_ASSERT(self->analysis()->ranBytecode());
  1189. return true;
  1190. }
  1191. inline bool
  1192. JSScript::ensureRanInference(JSContext *cx)
  1193. {
  1194. if (!ensureRanAnalysis(cx, NULL))
  1195. return false;
  1196. if (!analysis()->ranInference()) {
  1197. js::types::AutoEnterTypeInference enter(cx);
  1198. analysis()->analyzeTypes(cx);
  1199. }
  1200. return !analysis()->OOM() &&
  1201. !cx->compartment->types.pendingNukeTypes;
  1202. }
  1203. inline bool
  1204. JSScript::hasAnalysis()
  1205. {
  1206. return types && types->analysis;
  1207. }
  1208. inline js::analyze::ScriptAnalysis *
  1209. JSScript::analysis()
  1210. {
  1211. JS_ASSERT(hasAnalysis());
  1212. return types->analysis;
  1213. }
  1214. inline void
  1215. JSScript::clearAnalysis()
  1216. {
  1217. if (types)
  1218. types->analysis = NULL;
  1219. }
  1220. inline void
  1221. js::analyze::ScriptAnalysis::addPushedType(JSContext *cx, uint32_t offset, uint32_t which,
  1222. js::types::Type type)
  1223. {
  1224. js::types::TypeSet *pushed = pushedTypes(offset, which);
  1225. pushed->addType(cx, type);
  1226. }
  1227. inline js::types::TypeObject *
  1228. JSCompartment::getEmptyType(JSContext *cx)
  1229. {
  1230. if (!emptyTypeObject)
  1231. emptyTypeObject = types.newTypeObject(cx, NULL, JSProto_Object, NULL, true);
  1232. return emptyTypeObject;
  1233. }
  1234. #endif // jsinferinlines_h___