/js/src/jsfuninlines.h

http://github.com/zpao/v8monkey · C Header · 410 lines · 271 code · 54 blank · 85 comment · 36 complexity · 976b8e5a23eef702c1e2f45ec8501a19 MD5 · raw file

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=8 sw=4 et tw=99:
  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 SpiderMonkey.
  18. *
  19. * The Initial Developer of the Original Code is
  20. * the Mozilla Foundation.
  21. * Portions created by the Initial Developer are Copyright (C) 2010
  22. * the Initial Developer. All Rights Reserved.
  23. *
  24. * Contributor(s):
  25. *
  26. * Alternatively, the contents of this file may be used under the terms of
  27. * either the GNU General Public License Version 2 or later (the "GPL"), or
  28. * 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. #ifndef jsfuninlines_h___
  40. #define jsfuninlines_h___
  41. #include "jsfun.h"
  42. #include "jsscript.h"
  43. #include "vm/GlobalObject.h"
  44. #include "vm/ScopeObject-inl.h"
  45. inline bool
  46. JSFunction::inStrictMode() const
  47. {
  48. return script()->strictModeCode;
  49. }
  50. inline JSObject *
  51. JSFunction::environment() const
  52. {
  53. JS_ASSERT(isInterpreted());
  54. return u.i.env_;
  55. }
  56. inline void
  57. JSFunction::setEnvironment(JSObject *obj)
  58. {
  59. JS_ASSERT(isInterpreted());
  60. *(js::HeapPtrObject *)&u.i.env_ = obj;
  61. }
  62. inline void
  63. JSFunction::initEnvironment(JSObject *obj)
  64. {
  65. JS_ASSERT(isInterpreted());
  66. ((js::HeapPtrObject *)&u.i.env_)->init(obj);
  67. }
  68. inline void
  69. JSFunction::initializeExtended()
  70. {
  71. JS_ASSERT(isExtended());
  72. JS_ASSERT(js::ArrayLength(toExtended()->extendedSlots) == 2);
  73. toExtended()->extendedSlots[0].init(js::UndefinedValue());
  74. toExtended()->extendedSlots[1].init(js::UndefinedValue());
  75. }
  76. inline void
  77. JSFunction::setJoinable()
  78. {
  79. JS_ASSERT(isInterpreted());
  80. flags |= JSFUN_JOINABLE;
  81. }
  82. inline bool
  83. JSFunction::isClonedMethod() const
  84. {
  85. return joinable() && isExtended() && getExtendedSlot(METHOD_OBJECT_SLOT).isObject();
  86. }
  87. inline JSAtom *
  88. JSFunction::methodAtom() const
  89. {
  90. return (joinable() && isExtended() && getExtendedSlot(METHOD_PROPERTY_SLOT).isString())
  91. ? (JSAtom *) getExtendedSlot(METHOD_PROPERTY_SLOT).toString()
  92. : NULL;
  93. }
  94. inline void
  95. JSFunction::setMethodAtom(JSAtom *atom)
  96. {
  97. JS_ASSERT(joinable());
  98. setExtendedSlot(METHOD_PROPERTY_SLOT, js::StringValue(atom));
  99. }
  100. inline JSObject *
  101. JSFunction::methodObj() const
  102. {
  103. JS_ASSERT(joinable());
  104. return isClonedMethod() ? &getExtendedSlot(METHOD_OBJECT_SLOT).toObject() : NULL;
  105. }
  106. inline void
  107. JSFunction::setMethodObj(JSObject& obj)
  108. {
  109. JS_ASSERT(joinable());
  110. setExtendedSlot(METHOD_OBJECT_SLOT, js::ObjectValue(obj));
  111. }
  112. inline void
  113. JSFunction::setExtendedSlot(size_t which, const js::Value &val)
  114. {
  115. JS_ASSERT(which < js::ArrayLength(toExtended()->extendedSlots));
  116. toExtended()->extendedSlots[which] = val;
  117. }
  118. inline const js::Value &
  119. JSFunction::getExtendedSlot(size_t which) const
  120. {
  121. JS_ASSERT(which < js::ArrayLength(toExtended()->extendedSlots));
  122. return toExtended()->extendedSlots[which];
  123. }
  124. inline bool
  125. JSFunction::hasFlatClosureUpvars() const
  126. {
  127. JS_ASSERT(isFlatClosure());
  128. return isExtended() && !getExtendedSlot(FLAT_CLOSURE_UPVARS_SLOT).isUndefined();
  129. }
  130. inline js::HeapValue *
  131. JSFunction::getFlatClosureUpvars() const
  132. {
  133. JS_ASSERT(hasFlatClosureUpvars());
  134. return (js::HeapValue *) getExtendedSlot(FLAT_CLOSURE_UPVARS_SLOT).toPrivate();
  135. }
  136. inline void
  137. JSFunction::finalizeUpvars()
  138. {
  139. /*
  140. * Cloned function objects may be flat closures with upvars to free.
  141. *
  142. * We must not access JSScript here that is stored in JSFunction. The
  143. * script can be finalized before the function or closure instances. So we
  144. * just check if JSSLOT_FLAT_CLOSURE_UPVARS holds a private value encoded
  145. * as a double. We must also ignore newborn closures that do not have the
  146. * private pointer set.
  147. *
  148. * FIXME bug 648320 - allocate upvars on the GC heap to avoid doing it
  149. * here explicitly.
  150. */
  151. if (hasFlatClosureUpvars()) {
  152. js::HeapValue *upvars = getFlatClosureUpvars();
  153. js::Foreground::free_(upvars);
  154. }
  155. }
  156. inline js::Value
  157. JSFunction::getFlatClosureUpvar(uint32_t i) const
  158. {
  159. JS_ASSERT(hasFlatClosureUpvars());
  160. JS_ASSERT(script()->bindings.countUpvars() == script()->upvars()->length);
  161. JS_ASSERT(i < script()->bindings.countUpvars());
  162. return getFlatClosureUpvars()[i];
  163. }
  164. inline void
  165. JSFunction::setFlatClosureUpvar(uint32_t i, const js::Value &v)
  166. {
  167. JS_ASSERT(isFlatClosure());
  168. JS_ASSERT(script()->bindings.countUpvars() == script()->upvars()->length);
  169. JS_ASSERT(i < script()->bindings.countUpvars());
  170. getFlatClosureUpvars()[i] = v;
  171. }
  172. inline void
  173. JSFunction::initFlatClosureUpvar(uint32_t i, const js::Value &v)
  174. {
  175. JS_ASSERT(isFlatClosure());
  176. JS_ASSERT(script()->bindings.countUpvars() == script()->upvars()->length);
  177. JS_ASSERT(i < script()->bindings.countUpvars());
  178. getFlatClosureUpvars()[i].init(v);
  179. }
  180. /* static */ inline size_t
  181. JSFunction::getFlatClosureUpvarsOffset()
  182. {
  183. return offsetof(js::FunctionExtended, extendedSlots[FLAT_CLOSURE_UPVARS_SLOT]);
  184. }
  185. namespace js {
  186. static JS_ALWAYS_INLINE bool
  187. IsFunctionObject(const js::Value &v)
  188. {
  189. return v.isObject() && v.toObject().isFunction();
  190. }
  191. static JS_ALWAYS_INLINE bool
  192. IsFunctionObject(const js::Value &v, JSFunction **fun)
  193. {
  194. if (v.isObject() && v.toObject().isFunction()) {
  195. *fun = v.toObject().toFunction();
  196. return true;
  197. }
  198. return false;
  199. }
  200. static JS_ALWAYS_INLINE bool
  201. IsNativeFunction(const js::Value &v)
  202. {
  203. JSFunction *fun;
  204. return IsFunctionObject(v, &fun) && fun->isNative();
  205. }
  206. static JS_ALWAYS_INLINE bool
  207. IsNativeFunction(const js::Value &v, JSFunction **fun)
  208. {
  209. return IsFunctionObject(v, fun) && (*fun)->isNative();
  210. }
  211. static JS_ALWAYS_INLINE bool
  212. IsNativeFunction(const js::Value &v, JSNative native)
  213. {
  214. JSFunction *fun;
  215. return IsFunctionObject(v, &fun) && fun->maybeNative() == native;
  216. }
  217. /*
  218. * When we have an object of a builtin class, we don't quite know what its
  219. * valueOf/toString methods are, since these methods may have been overwritten
  220. * or shadowed. However, we can still do better than the general case by
  221. * hard-coding the necessary properties for us to find the native we expect.
  222. *
  223. * TODO: a per-thread shape-based cache would be faster and simpler.
  224. */
  225. static JS_ALWAYS_INLINE bool
  226. ClassMethodIsNative(JSContext *cx, JSObject *obj, Class *clasp, jsid methodid, JSNative native)
  227. {
  228. JS_ASSERT(obj->getClass() == clasp);
  229. Value v;
  230. if (!HasDataProperty(cx, obj, methodid, &v)) {
  231. JSObject *proto = obj->getProto();
  232. if (!proto || proto->getClass() != clasp || !HasDataProperty(cx, proto, methodid, &v))
  233. return false;
  234. }
  235. return js::IsNativeFunction(v, native);
  236. }
  237. extern JS_ALWAYS_INLINE bool
  238. SameTraceType(const Value &lhs, const Value &rhs)
  239. {
  240. return SameType(lhs, rhs) &&
  241. (lhs.isPrimitive() ||
  242. lhs.toObject().isFunction() == rhs.toObject().isFunction());
  243. }
  244. /* Valueified JS_IsConstructing. */
  245. static JS_ALWAYS_INLINE bool
  246. IsConstructing(const Value *vp)
  247. {
  248. #ifdef DEBUG
  249. JSObject *callee = &JS_CALLEE(cx, vp).toObject();
  250. if (callee->isFunction()) {
  251. JSFunction *fun = callee->toFunction();
  252. JS_ASSERT((fun->flags & JSFUN_CONSTRUCTOR) != 0);
  253. } else {
  254. JS_ASSERT(callee->getClass()->construct != NULL);
  255. }
  256. #endif
  257. return vp[1].isMagic();
  258. }
  259. inline bool
  260. IsConstructing(CallReceiver call)
  261. {
  262. return IsConstructing(call.base());
  263. }
  264. inline const char *
  265. GetFunctionNameBytes(JSContext *cx, JSFunction *fun, JSAutoByteString *bytes)
  266. {
  267. if (fun->atom)
  268. return bytes->encode(cx, fun->atom);
  269. return js_anonymous_str;
  270. }
  271. extern JSFunctionSpec function_methods[];
  272. extern JSBool
  273. Function(JSContext *cx, uintN argc, Value *vp);
  274. extern bool
  275. IsBuiltinFunctionConstructor(JSFunction *fun);
  276. /*
  277. * Preconditions: funobj->isInterpreted() && !funobj->isFunctionPrototype() &&
  278. * !funobj->isBoundFunction(). This is sufficient to establish that funobj has
  279. * a non-configurable non-method .prototype data property, thought it might not
  280. * have been resolved yet, and its value could be anything.
  281. *
  282. * Return the shape of the .prototype property of funobj, resolving it if
  283. * needed. On error, return NULL.
  284. *
  285. * This is not safe to call on trace because it defines properties, which can
  286. * trigger lookups that could reenter.
  287. */
  288. const Shape *
  289. LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj);
  290. static inline JSObject *
  291. SkipScopeParent(JSObject *parent)
  292. {
  293. if (!parent)
  294. return NULL;
  295. while (parent->isScope())
  296. parent = &parent->asScope().enclosingScope();
  297. return parent;
  298. }
  299. inline JSFunction *
  300. CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
  301. gc::AllocKind kind = JSFunction::FinalizeKind)
  302. {
  303. JS_ASSERT(parent);
  304. JSObject *proto = parent->global().getOrCreateFunctionPrototype(cx);
  305. if (!proto)
  306. return NULL;
  307. return js_CloneFunctionObject(cx, fun, parent, proto, kind);
  308. }
  309. inline JSFunction *
  310. CloneFunctionObjectIfNotSingleton(JSContext *cx, JSFunction *fun, JSObject *parent)
  311. {
  312. /*
  313. * For attempts to clone functions at a function definition opcode or from
  314. * a method barrier, don't perform the clone if the function has singleton
  315. * type. This was called pessimistically, and we need to preserve the
  316. * type's property that if it is singleton there is only a single object
  317. * with its type in existence.
  318. */
  319. if (fun->hasSingletonType()) {
  320. if (!fun->setParent(cx, SkipScopeParent(parent)))
  321. return NULL;
  322. fun->setEnvironment(parent);
  323. return fun;
  324. }
  325. return CloneFunctionObject(cx, fun, parent);
  326. }
  327. inline JSFunction *
  328. CloneFunctionObject(JSContext *cx, JSFunction *fun)
  329. {
  330. /*
  331. * Variant which makes an exact clone of fun, preserving parent and proto.
  332. * Calling the above version CloneFunctionObject(cx, fun, fun->getParent())
  333. * is not equivalent: API clients, including XPConnect, can reparent
  334. * objects so that fun->global() != fun->getProto()->global().
  335. * See ReparentWrapperIfFound.
  336. */
  337. JS_ASSERT(fun->getParent() && fun->getProto());
  338. if (fun->hasSingletonType())
  339. return fun;
  340. return js_CloneFunctionObject(cx, fun, fun->environment(), fun->getProto(),
  341. JSFunction::ExtendedFinalizeKind);
  342. }
  343. } /* namespace js */
  344. inline void
  345. JSFunction::setScript(JSScript *script_)
  346. {
  347. JS_ASSERT(isInterpreted());
  348. script() = script_;
  349. }
  350. inline void
  351. JSFunction::initScript(JSScript *script_)
  352. {
  353. JS_ASSERT(isInterpreted());
  354. script().init(script_);
  355. }
  356. #endif /* jsfuninlines_h___ */