PageRenderTime 55ms CodeModel.GetById 35ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

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