blob: e1fe414a46ff0c70ae0efe037c40bb3737aac8c1 [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jsfuninlines_h
#define jsfuninlines_h
#include "jsfun.h"
#include "jsscript.h"
#include "vm/GlobalObject.h"
#include "vm/ScopeObject-inl.h"
#include "vm/String-inl.h"
inline bool
JSFunction::strict() const
{
return nonLazyScript()->strict;
}
inline void
JSFunction::initAtom(JSAtom *atom)
{
atom_.init(atom);
}
inline void
JSFunction::setGuessedAtom(JSAtom *atom)
{
JS_ASSERT(atom_ == NULL);
JS_ASSERT(atom != NULL);
JS_ASSERT(!hasGuessedAtom());
atom_ = atom;
flags |= HAS_GUESSED_ATOM;
}
inline JSObject *
JSFunction::environment() const
{
JS_ASSERT(isInterpreted());
return u.i.env_;
}
inline void
JSFunction::setEnvironment(JSObject *obj)
{
JS_ASSERT(isInterpreted());
*(js::HeapPtrObject *)&u.i.env_ = obj;
}
inline void
JSFunction::initEnvironment(JSObject *obj)
{
JS_ASSERT(isInterpreted());
((js::HeapPtrObject *)&u.i.env_)->init(obj);
}
inline void
JSFunction::initNative(js::Native native, const JSJitInfo *data)
{
JS_ASSERT(native);
u.n.native = native;
u.n.jitinfo = data;
}
inline const JSJitInfo *
JSFunction::jitInfo() const
{
JS_ASSERT(isNative());
return u.n.jitinfo;
}
inline void
JSFunction::setJitInfo(const JSJitInfo *data)
{
JS_ASSERT(isNative());
u.n.jitinfo = data;
}
inline void
JSFunction::initializeExtended()
{
JS_ASSERT(isExtended());
JS_ASSERT(mozilla::ArrayLength(toExtended()->extendedSlots) == 2);
toExtended()->extendedSlots[0].init(js::UndefinedValue());
toExtended()->extendedSlots[1].init(js::UndefinedValue());
}
inline void
JSFunction::initExtendedSlot(size_t which, const js::Value &val)
{
JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
toExtended()->extendedSlots[which].init(val);
}
inline void
JSFunction::setExtendedSlot(size_t which, const js::Value &val)
{
JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
toExtended()->extendedSlots[which] = val;
}
inline const js::Value &
JSFunction::getExtendedSlot(size_t which) const
{
JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
return toExtended()->extendedSlots[which];
}
namespace js {
extern JS_ALWAYS_INLINE bool
SameTraceType(const Value &lhs, const Value &rhs)
{
return SameType(lhs, rhs) &&
(lhs.isPrimitive() ||
lhs.toObject().is<JSFunction>() == rhs.toObject().is<JSFunction>());
}
/* Valueified JS_IsConstructing. */
static JS_ALWAYS_INLINE bool
IsConstructing(const Value *vp)
{
#ifdef DEBUG
JSObject *callee = &JS_CALLEE(cx, vp).toObject();
if (callee->is<JSFunction>()) {
JSFunction *fun = &callee->as<JSFunction>();
JS_ASSERT(fun->isNativeConstructor());
} else {
JS_ASSERT(callee->getClass()->construct != NULL);
}
#endif
return vp[1].isMagic();
}
inline bool
IsConstructing(CallReceiver call)
{
return IsConstructing(call.base());
}
inline const char *
GetFunctionNameBytes(JSContext *cx, JSFunction *fun, JSAutoByteString *bytes)
{
JSAtom *atom = fun->atom();
if (atom)
return bytes->encodeLatin1(cx, atom);
return js_anonymous_str;
}
extern JSBool
Function(JSContext *cx, unsigned argc, Value *vp);
extern bool
IsBuiltinFunctionConstructor(JSFunction *fun);
static inline JSObject *
SkipScopeParent(JSObject *parent)
{
if (!parent)
return NULL;
while (parent->is<ScopeObject>())
parent = &parent->as<ScopeObject>().enclosingScope();
return parent;
}
inline bool
CanReuseFunctionForClone(JSContext *cx, HandleFunction fun)
{
if (!fun->hasSingletonType())
return false;
if (fun->isInterpretedLazy()) {
LazyScript *lazy = fun->lazyScript();
if (lazy->hasBeenCloned())
return false;
lazy->setHasBeenCloned();
} else {
JSScript *script = fun->nonLazyScript();
if (script->hasBeenCloned)
return false;
script->hasBeenCloned = true;
}
return true;
}
inline JSFunction *
CloneFunctionObjectIfNotSingleton(JSContext *cx, HandleFunction fun, HandleObject parent,
NewObjectKind newKind = GenericObject)
{
/*
* For attempts to clone functions at a function definition opcode,
* try to avoid the the clone if the function has singleton type. This
* was called pessimistically, and we need to preserve the type's
* property that if it is singleton there is only a single object
* with its type in existence.
*
* For functions inner to run once lambda, it may be possible that
* the lambda runs multiple times and we repeatedly clone it. In these
* cases, fall through to CloneFunctionObject, which will deep clone
* the function's script.
*/
if (CanReuseFunctionForClone(cx, fun)) {
RootedObject obj(cx, SkipScopeParent(parent));
if (!JSObject::setParent(cx, fun, obj))
return NULL;
fun->setEnvironment(parent);
return fun;
}
// These intermediate variables are needed to avoid link errors on some
// platforms. Sigh.
gc::AllocKind finalizeKind = JSFunction::FinalizeKind;
gc::AllocKind extendedFinalizeKind = JSFunction::ExtendedFinalizeKind;
gc::AllocKind kind = fun->isExtended()
? extendedFinalizeKind
: finalizeKind;
return CloneFunctionObject(cx, fun, parent, kind, newKind);
}
} /* namespace js */
inline bool
JSFunction::isHeavyweight() const
{
JS_ASSERT(!isInterpretedLazy());
if (isNative())
return false;
// Note: this should be kept in sync with FunctionBox::isHeavyweight().
return nonLazyScript()->bindings.hasAnyAliasedBindings() ||
nonLazyScript()->funHasExtensibleScope ||
nonLazyScript()->funNeedsDeclEnvObject;
}
inline JSScript *
JSFunction::existingScript()
{
JS_ASSERT(isInterpreted());
if (isInterpretedLazy()) {
js::LazyScript *lazy = lazyScript();
JSScript *script = lazy->maybeScript();
JS_ASSERT(script);
if (zone()->needsBarrier())
js::LazyScript::writeBarrierPre(lazy);
flags &= ~INTERPRETED_LAZY;
flags |= INTERPRETED;
initScript(script);
}
JS_ASSERT(hasScript());
return u.i.s.script_;
}
inline JSScript*
JSFunction::existingScriptForInlinedFunction() {
JS_ASSERT(isInterpreted());
if (isInterpretedLazy()) {
// Get the script from the canonical function. Ion used the
// canonical function to inline the script and because it has
// Baseline code it has not been relazified. Note that we can't
// use lazyScript->script_ here as it may be null in some cases,
// see bug 976536.
js::LazyScript *lazy = lazyScript();
JSFunction* fun = lazy->function();
JS_ASSERT(fun);
JSScript *script = fun->nonLazyScript();
if (zone()->needsBarrier())
js::LazyScript::writeBarrierPre(lazy);
flags &= ~INTERPRETED_LAZY;
flags |= INTERPRETED;
initScript(script);
}
JS_ASSERT(hasScript());
JS_ASSERT(u.i.s.script_);
return u.i.s.script_;
}
inline void
JSFunction::setScript(JSScript *script_)
{
JS_ASSERT(isInterpreted());
mutableScript() = script_;
}
inline void
JSFunction::initScript(JSScript *script_)
{
JS_ASSERT(isInterpreted());
mutableScript().init(script_);
}
inline void
JSFunction::initLazyScript(js::LazyScript *lazy)
{
JS_ASSERT(isInterpreted());
flags &= ~INTERPRETED;
flags |= INTERPRETED_LAZY;
u.i.s.lazy_ = lazy;
}
inline JSObject *
JSFunction::getBoundFunctionTarget() const
{
JS_ASSERT(isBoundFunction());
/* Bound functions abuse |parent| to store their target function. */
return getParent();
}
inline bool
js::Class::isCallable() const
{
return this == &JSFunction::class_ || call;
}
#endif /* jsfuninlines_h */