PageRenderTime 41ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsscope.h

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
C++ Header | 419 lines | 152 code | 46 blank | 221 comment | 9 complexity | 9129c167eed088cd5976e1864437901c MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=8 sw=4 et tw=78:
  3. *
  4. * ***** BEGIN LICENSE BLOCK *****
  5. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6. *
  7. * The contents of this file are subject to the Mozilla Public License Version
  8. * 1.1 (the "License"); you may not use this file except in compliance with
  9. * the License. You may obtain a copy of the License at
  10. * http://www.mozilla.org/MPL/
  11. *
  12. * Software distributed under the License is distributed on an "AS IS" basis,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. * for the specific language governing rights and limitations under the
  15. * License.
  16. *
  17. * The Original Code is Mozilla Communicator client code, released
  18. * March 31, 1998.
  19. *
  20. * The Initial Developer of the Original Code is
  21. * Netscape Communications Corporation.
  22. * Portions created by the Initial Developer are Copyright (C) 1998
  23. * the Initial Developer. All Rights Reserved.
  24. *
  25. * Contributor(s):
  26. *
  27. * Alternatively, the contents of this file may be used under the terms of
  28. * either of the GNU General Public License Version 2 or later (the "GPL"),
  29. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  30. * in which case the provisions of the GPL or the LGPL are applicable instead
  31. * of those above. If you wish to allow use of your version of this file only
  32. * under the terms of either the GPL or the LGPL, and not to allow others to
  33. * use your version of this file under the terms of the MPL, indicate your
  34. * decision by deleting the provisions above and replace them with the notice
  35. * and other provisions required by the GPL or the LGPL. If you do not delete
  36. * the provisions above, a recipient may use your version of this file under
  37. * the terms of any one of the MPL, the GPL or the LGPL.
  38. *
  39. * ***** END LICENSE BLOCK ***** */
  40. #ifndef jsscope_h___
  41. #define jsscope_h___
  42. /*
  43. * JS symbol tables.
  44. */
  45. #include "jstypes.h"
  46. #include "jslock.h"
  47. #include "jsobj.h"
  48. #include "jsprvtd.h"
  49. #include "jspubtd.h"
  50. JS_BEGIN_EXTERN_C
  51. /*
  52. * Given P independent, non-unique properties each of size S words mapped by
  53. * all scopes in a runtime, construct a property tree of N nodes each of size
  54. * S+L words (L for tree linkage). A nominal L value is 2 for leftmost-child
  55. * and right-sibling links. We hope that the N < P by enough that the space
  56. * overhead of L, and the overhead of scope entries pointing at property tree
  57. * nodes, is worth it.
  58. *
  59. * The tree construction goes as follows. If any empty scope in the runtime
  60. * has a property X added to it, find or create a node under the tree root
  61. * labeled X, and set scope->lastProp to point at that node. If any non-empty
  62. * scope whose most recently added property is labeled Y has another property
  63. * labeled Z added, find or create a node for Z under the node that was added
  64. * for Y, and set scope->lastProp to point at that node.
  65. *
  66. * A property is labeled by its members' values: id, getter, setter, slot,
  67. * attributes, tiny or short id, and a field telling for..in order. Note that
  68. * labels are not unique in the tree, but they are unique among a node's kids
  69. * (barring rare and benign multi-threaded race condition outcomes, see below)
  70. * and along any ancestor line from the tree root to a given leaf node (except
  71. * for the hard case of duplicate formal parameters to a function).
  72. *
  73. * Thus the root of the tree represents all empty scopes, and the first ply
  74. * of the tree represents all scopes containing one property, etc. Each node
  75. * in the tree can stand for any number of scopes having the same ordered set
  76. * of properties, where that node was the last added to the scope. (We need
  77. * not store the root of the tree as a node, and do not -- all we need are
  78. * links to its kids.)
  79. *
  80. * Sidebar on for..in loop order: ECMA requires no particular order, but this
  81. * implementation has promised and delivered property definition order, and
  82. * compatibility is king. We could use an order number per property, which
  83. * would require a sort in js_Enumerate, and an entry order generation number
  84. * per scope. An order number beats a list, which should be doubly-linked for
  85. * O(1) delete. An even better scheme is to use a parent link in the property
  86. * tree, so that the ancestor line can be iterated from scope->lastProp when
  87. * filling in a JSIdArray from back to front. This parent link also helps the
  88. * GC to sweep properties iteratively.
  89. *
  90. * What if a property Y is deleted from a scope? If Y is the last property in
  91. * the scope, we simply adjust the scope's lastProp member after we remove the
  92. * scope's hash-table entry pointing at that property node. The parent link
  93. * mentioned in the for..in sidebar above makes this adjustment O(1). But if
  94. * Y comes between X and Z in the scope, then we might have to "fork" the tree
  95. * at X, leaving X->Y->Z in case other scopes have those properties added in
  96. * that order; and to finish the fork, we'd add a node labeled Z with the path
  97. * X->Z, if it doesn't exist. This could lead to lots of extra nodes, and to
  98. * O(n^2) growth when deleting lots of properties.
  99. *
  100. * Rather, for O(1) growth all around, we should share the path X->Y->Z among
  101. * scopes having those three properties added in that order, and among scopes
  102. * having only X->Z where Y was deleted. All such scopes have a lastProp that
  103. * points to the Z child of Y. But a scope in which Y was deleted does not
  104. * have a table entry for Y, and when iterating that scope by traversing the
  105. * ancestor line from Z, we will have to test for a table entry for each node,
  106. * skipping nodes that lack entries.
  107. *
  108. * What if we add Y again? X->Y->Z->Y is wrong and we'll enumerate Y twice.
  109. * Therefore we must fork in such a case, if not earlier. Because delete is
  110. * "bursty", we should not fork eagerly. Delaying a fork till we are at risk
  111. * of adding Y after it was deleted already requires a flag in the JSScope, to
  112. * wit, SCOPE_MIDDLE_DELETE.
  113. *
  114. * What about thread safety? If the property tree operations done by requests
  115. * are find-node and insert-node, then the only hazard is duplicate insertion.
  116. * This is harmless except for minor bloat. When all requests have ended or
  117. * been suspended, the GC is free to sweep the tree after marking all nodes
  118. * reachable from scopes, performing remove-node operations as needed.
  119. *
  120. * Is the property tree worth it compared to property storage in each table's
  121. * entries? To decide, we must find the relation <> between the words used
  122. * with a property tree and the words required without a tree.
  123. *
  124. * Model all scopes as one super-scope of capacity T entries (T a power of 2).
  125. * Let alpha be the load factor of this double hash-table. With the property
  126. * tree, each entry in the table is a word-sized pointer to a node that can be
  127. * shared by many scopes. But all such pointers are overhead compared to the
  128. * situation without the property tree, where the table stores property nodes
  129. * directly, as entries each of size S words. With the property tree, we need
  130. * L=2 extra words per node for siblings and kids pointers. Without the tree,
  131. * (1-alpha)*S*T words are wasted on free or removed sentinel-entries required
  132. * by double hashing.
  133. *
  134. * Therefore,
  135. *
  136. * (property tree) <> (no property tree)
  137. * N*(S+L) + T <> S*T
  138. * N*(S+L) + T <> P*S + (1-alpha)*S*T
  139. * N*(S+L) + alpha*T + (1-alpha)*T <> P*S + (1-alpha)*S*T
  140. *
  141. * Note that P is alpha*T by definition, so
  142. *
  143. * N*(S+L) + P + (1-alpha)*T <> P*S + (1-alpha)*S*T
  144. * N*(S+L) <> P*S - P + (1-alpha)*S*T - (1-alpha)*T
  145. * N*(S+L) <> (P + (1-alpha)*T) * (S-1)
  146. * N*(S+L) <> (P + (1-alpha)*P/alpha) * (S-1)
  147. * N*(S+L) <> P * (1/alpha) * (S-1)
  148. *
  149. * Let N = P*beta for a compression ratio beta, beta <= 1:
  150. *
  151. * P*beta*(S+L) <> P * (1/alpha) * (S-1)
  152. * beta*(S+L) <> (S-1)/alpha
  153. * beta <> (S-1)/((S+L)*alpha)
  154. *
  155. * For S = 6 (32-bit architectures) and L = 2, the property tree wins iff
  156. *
  157. * beta < 5/(8*alpha)
  158. *
  159. * We ensure that alpha <= .75, so the property tree wins if beta < .83_. An
  160. * average beta from recent Mozilla browser startups was around .6.
  161. *
  162. * Can we reduce L? Observe that the property tree degenerates into a list of
  163. * lists if at most one property Y follows X in all scopes. In or near such a
  164. * case, we waste a word on the right-sibling link outside of the root ply of
  165. * the tree. Note also that the root ply tends to be large, so O(n^2) growth
  166. * searching it is likely, indicating the need for hashing (but with increased
  167. * thread safety costs).
  168. *
  169. * If only K out of N nodes in the property tree have more than one child, we
  170. * could eliminate the sibling link and overlay a children list or hash-table
  171. * pointer on the leftmost-child link (which would then be either null or an
  172. * only-child link; the overlay could be tagged in the low bit of the pointer,
  173. * or flagged elsewhere in the property tree node, although such a flag must
  174. * not be considered when comparing node labels during tree search).
  175. *
  176. * For such a system, L = 1 + (K * averageChildrenTableSize) / N instead of 2.
  177. * If K << N, L approaches 1 and the property tree wins if beta < .95.
  178. *
  179. * We observe that fan-out below the root ply of the property tree appears to
  180. * have extremely low degree (see the MeterPropertyTree code that histograms
  181. * child-counts in jsscope.c), so instead of a hash-table we use a linked list
  182. * of child node pointer arrays ("kid chunks"). The details are isolated in
  183. * jsscope.c; others must treat JSScopeProperty.kids as opaque. We leave it
  184. * strongly typed for debug-ability of the common (null or one-kid) cases.
  185. *
  186. * One final twist (can you stand it?): the mean number of entries per scope
  187. * in Mozilla is < 5, with a large standard deviation (~8). Instead of always
  188. * allocating scope->table, we leave it null while initializing all the other
  189. * scope members as if it were non-null and minimal-length. Until a property
  190. * is added that crosses the threshold of 6 or more entries for hashing, or
  191. * until a "middle delete" occurs, we use linear search from scope->lastProp
  192. * to find a given id, and save on the space overhead of a hash table.
  193. */
  194. struct JSScope {
  195. JSObjectMap map; /* base class state */
  196. #ifdef JS_THREADSAFE
  197. JSTitle title; /* lock state */
  198. #endif
  199. JSObject *object; /* object that owns this scope */
  200. uint32 shape; /* property cache shape identifier */
  201. uint8 flags; /* flags, see below */
  202. int8 hashShift; /* multiplicative hash shift */
  203. uint16 spare; /* reserved */
  204. uint32 entryCount; /* number of entries in table */
  205. uint32 removedCount; /* removed entry sentinels in table */
  206. JSScopeProperty **table; /* table of ptrs to shared tree nodes */
  207. JSScopeProperty *lastProp; /* pointer to last property added */
  208. };
  209. #ifdef JS_THREADSAFE
  210. JS_STATIC_ASSERT(offsetof(JSScope, title) == sizeof(JSObjectMap));
  211. #endif
  212. #define JS_IS_SCOPE_LOCKED(cx, scope) JS_IS_TITLE_LOCKED(cx, &(scope)->title)
  213. #define OBJ_SCOPE(obj) ((JSScope *)(obj)->map)
  214. #define OBJ_SHAPE(obj) (OBJ_SCOPE(obj)->shape)
  215. #define SCOPE_MAKE_UNIQUE_SHAPE(cx,scope) \
  216. ((scope)->shape = js_GenerateShape((cx), JS_FALSE, NULL))
  217. #define SCOPE_EXTEND_SHAPE(cx,scope,sprop) \
  218. JS_BEGIN_MACRO \
  219. if (!(scope)->lastProp || \
  220. (scope)->shape == (scope)->lastProp->shape) { \
  221. (scope)->shape = (sprop)->shape; \
  222. } else { \
  223. (scope)->shape = js_GenerateShape((cx), JS_FALSE, sprop); \
  224. } \
  225. JS_END_MACRO
  226. /* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */
  227. #define SCOPE_CAPACITY(scope) JS_BIT(JS_DHASH_BITS-(scope)->hashShift)
  228. /* Scope flags and some macros to hide them from other files than jsscope.c. */
  229. #define SCOPE_MIDDLE_DELETE 0x0001
  230. #define SCOPE_SEALED 0x0002
  231. #define SCOPE_BRANDED 0x0004
  232. #define SCOPE_HAD_MIDDLE_DELETE(scope) ((scope)->flags & SCOPE_MIDDLE_DELETE)
  233. #define SCOPE_SET_MIDDLE_DELETE(scope) ((scope)->flags |= SCOPE_MIDDLE_DELETE)
  234. #define SCOPE_CLR_MIDDLE_DELETE(scope) ((scope)->flags &= ~SCOPE_MIDDLE_DELETE)
  235. #define SCOPE_IS_SEALED(scope) ((scope)->flags & SCOPE_SEALED)
  236. #define SCOPE_SET_SEALED(scope) ((scope)->flags |= SCOPE_SEALED)
  237. #if 0
  238. /*
  239. * Don't define this, it can't be done safely because JS_LOCK_OBJ will avoid
  240. * taking the lock if the object owns its scope and the scope is sealed.
  241. */
  242. #undef SCOPE_CLR_SEALED(scope) ((scope)->flags &= ~SCOPE_SEALED)
  243. #endif
  244. /*
  245. * A branded scope's object contains plain old methods (function-valued
  246. * properties without magic getters and setters), and its scope->shape
  247. * evolves whenever a function value changes.
  248. */
  249. #define SCOPE_IS_BRANDED(scope) ((scope)->flags & SCOPE_BRANDED)
  250. #define SCOPE_SET_BRANDED(scope) ((scope)->flags |= SCOPE_BRANDED)
  251. #define SCOPE_CLR_BRANDED(scope) ((scope)->flags &= ~SCOPE_BRANDED)
  252. /*
  253. * A little information hiding for scope->lastProp, in case it ever becomes
  254. * a tagged pointer again.
  255. */
  256. #define SCOPE_LAST_PROP(scope) ((scope)->lastProp)
  257. #define SCOPE_REMOVE_LAST_PROP(scope) ((scope)->lastProp = \
  258. (scope)->lastProp->parent)
  259. struct JSScopeProperty {
  260. jsid id; /* int-tagged jsval/untagged JSAtom* */
  261. JSPropertyOp getter; /* getter and setter hooks or objects */
  262. JSPropertyOp setter;
  263. uint32 slot; /* abstract index in object slots */
  264. uint8 attrs; /* attributes, see jsapi.h JSPROP_* */
  265. uint8 flags; /* flags, see below for defines */
  266. int16 shortid; /* tinyid, or local arg/var index */
  267. JSScopeProperty *parent; /* parent node, reverse for..in order */
  268. JSScopeProperty *kids; /* null, single child, or a tagged ptr
  269. to many-kids data structure */
  270. uint32 shape; /* property cache shape identifier */
  271. };
  272. /* JSScopeProperty pointer tag bit indicating a collision. */
  273. #define SPROP_COLLISION ((jsuword)1)
  274. #define SPROP_REMOVED ((JSScopeProperty *) SPROP_COLLISION)
  275. /* Macros to get and set sprop pointer values and collision flags. */
  276. #define SPROP_IS_FREE(sprop) ((sprop) == NULL)
  277. #define SPROP_IS_REMOVED(sprop) ((sprop) == SPROP_REMOVED)
  278. #define SPROP_IS_LIVE(sprop) ((sprop) > SPROP_REMOVED)
  279. #define SPROP_FLAG_COLLISION(spp,sprop) (*(spp) = (JSScopeProperty *) \
  280. ((jsuword)(sprop) | SPROP_COLLISION))
  281. #define SPROP_HAD_COLLISION(sprop) ((jsuword)(sprop) & SPROP_COLLISION)
  282. #define SPROP_FETCH(spp) SPROP_CLEAR_COLLISION(*(spp))
  283. #define SPROP_CLEAR_COLLISION(sprop) \
  284. ((JSScopeProperty *) ((jsuword)(sprop) & ~SPROP_COLLISION))
  285. #define SPROP_STORE_PRESERVING_COLLISION(spp, sprop) \
  286. (*(spp) = (JSScopeProperty *) ((jsuword)(sprop) \
  287. | SPROP_HAD_COLLISION(*(spp))))
  288. /* Bits stored in sprop->flags. */
  289. #define SPROP_MARK 0x01
  290. #define SPROP_IS_ALIAS 0x02
  291. #define SPROP_HAS_SHORTID 0x04
  292. #define SPROP_FLAG_SHAPE_REGEN 0x08
  293. /*
  294. * If SPROP_HAS_SHORTID is set in sprop->flags, we use sprop->shortid rather
  295. * than id when calling sprop's getter or setter.
  296. */
  297. #define SPROP_USERID(sprop) \
  298. (((sprop)->flags & SPROP_HAS_SHORTID) ? INT_TO_JSVAL((sprop)->shortid) \
  299. : ID_TO_VALUE((sprop)->id))
  300. #define SPROP_INVALID_SLOT 0xffffffff
  301. #define SLOT_IN_SCOPE(slot,scope) ((slot) < (scope)->map.freeslot)
  302. #define SPROP_HAS_VALID_SLOT(sprop,scope) SLOT_IN_SCOPE((sprop)->slot, scope)
  303. #define SPROP_HAS_STUB_GETTER(sprop) (!(sprop)->getter)
  304. #define SPROP_HAS_STUB_SETTER(sprop) (!(sprop)->setter)
  305. /*
  306. * NB: SPROP_GET must not be called if SPROP_HAS_STUB_GETTER(sprop).
  307. */
  308. #define SPROP_GET(cx,sprop,obj,obj2,vp) \
  309. (((sprop)->attrs & JSPROP_GETTER) \
  310. ? js_InternalGetOrSet(cx, obj, (sprop)->id, \
  311. OBJECT_TO_JSVAL((sprop)->getter), JSACC_READ, \
  312. 0, 0, vp) \
  313. : (sprop)->getter(cx, OBJ_THIS_OBJECT(cx,obj), SPROP_USERID(sprop), vp))
  314. /*
  315. * NB: SPROP_SET must not be called if (SPROP_HAS_STUB_SETTER(sprop) &&
  316. * !(sprop->attrs & JSPROP_GETTER)).
  317. */
  318. #define SPROP_SET(cx,sprop,obj,obj2,vp) \
  319. (((sprop)->attrs & JSPROP_SETTER) \
  320. ? js_InternalGetOrSet(cx, obj, (sprop)->id, \
  321. OBJECT_TO_JSVAL((sprop)->setter), JSACC_WRITE, \
  322. 1, vp, vp) \
  323. : ((sprop)->attrs & JSPROP_GETTER) \
  324. ? (JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, \
  325. JSMSG_GETTER_ONLY, NULL), JS_FALSE) \
  326. : (sprop)->setter(cx, OBJ_THIS_OBJECT(cx,obj), SPROP_USERID(sprop), vp))
  327. /* Macro for common expression to test for shared permanent attributes. */
  328. #define SPROP_IS_SHARED_PERMANENT(sprop) \
  329. ((~(sprop)->attrs & (JSPROP_SHARED | JSPROP_PERMANENT)) == 0)
  330. extern JSScope *
  331. js_GetMutableScope(JSContext *cx, JSObject *obj);
  332. extern JSScope *
  333. js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
  334. JSObject *obj);
  335. extern void
  336. js_DestroyScope(JSContext *cx, JSScope *scope);
  337. extern JS_FRIEND_API(JSScopeProperty **)
  338. js_SearchScope(JSScope *scope, jsid id, JSBool adding);
  339. #define SCOPE_GET_PROPERTY(scope, id) \
  340. SPROP_FETCH(js_SearchScope(scope, id, JS_FALSE))
  341. #define SCOPE_HAS_PROPERTY(scope, sprop) \
  342. (SCOPE_GET_PROPERTY(scope, (sprop)->id) == (sprop))
  343. extern JSScopeProperty *
  344. js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
  345. JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
  346. uintN attrs, uintN flags, intN shortid);
  347. extern JSScopeProperty *
  348. js_ChangeScopePropertyAttrs(JSContext *cx, JSScope *scope,
  349. JSScopeProperty *sprop, uintN attrs, uintN mask,
  350. JSPropertyOp getter, JSPropertyOp setter);
  351. extern JSBool
  352. js_RemoveScopeProperty(JSContext *cx, JSScope *scope, jsid id);
  353. extern void
  354. js_ClearScope(JSContext *cx, JSScope *scope);
  355. /*
  356. * These macros used to inline short code sequences, but they grew over time.
  357. * We retain them for internal backward compatibility, and in case one or both
  358. * ever shrink to inline-able size.
  359. */
  360. #define TRACE_ID(trc, id) js_TraceId(trc, id)
  361. #define TRACE_SCOPE_PROPERTY(trc, sprop) js_TraceScopeProperty(trc, sprop)
  362. extern void
  363. js_TraceId(JSTracer *trc, jsid id);
  364. extern void
  365. js_TraceScopeProperty(JSTracer *trc, JSScopeProperty *sprop);
  366. extern void
  367. js_SweepScopeProperties(JSContext *cx);
  368. extern JSBool
  369. js_InitPropertyTree(JSRuntime *rt);
  370. extern void
  371. js_FinishPropertyTree(JSRuntime *rt);
  372. JS_END_EXTERN_C
  373. #endif /* jsscope_h___ */