| /* -*- 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 vm_ScopeObject_inl_h |
| #define vm_ScopeObject_inl_h |
| |
| #include "ScopeObject.h" |
| |
| #include "jsinferinlines.h" |
| #include "jsobjinlines.h" |
| #include "jsscriptinlines.h" |
| |
| template<> |
| inline bool |
| JSObject::is<js::ClonedBlockObject>() const |
| { |
| return is<js::BlockObject>() && !!getProto(); |
| } |
| |
| template<> |
| inline bool |
| JSObject::is<js::StaticBlockObject>() const |
| { |
| return is<js::BlockObject>() && !getProto(); |
| } |
| |
| inline JSObject * |
| JSObject::enclosingScope() |
| { |
| return is<js::ScopeObject>() |
| ? &as<js::ScopeObject>().enclosingScope() |
| : is<js::DebugScopeObject>() |
| ? &as<js::DebugScopeObject>().enclosingScope() |
| : getParent(); |
| } |
| |
| namespace js { |
| |
| inline |
| ScopeCoordinate::ScopeCoordinate(jsbytecode *pc) |
| : hops(GET_UINT16(pc)), slot(GET_UINT16(pc + 2)) |
| { |
| JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD); |
| } |
| |
| inline void |
| ScopeObject::setEnclosingScope(HandleObject obj) |
| { |
| JS_ASSERT_IF(obj->is<CallObject>() || obj->is<DeclEnvObject>() || obj->is<BlockObject>(), |
| obj->isDelegate()); |
| setFixedSlot(SCOPE_CHAIN_SLOT, ObjectValue(*obj)); |
| } |
| |
| inline const Value & |
| ScopeObject::aliasedVar(ScopeCoordinate sc) |
| { |
| JS_ASSERT(is<CallObject>() || is<ClonedBlockObject>()); |
| return getSlot(sc.slot); |
| } |
| |
| inline void |
| ScopeObject::setAliasedVar(JSContext *cx, ScopeCoordinate sc, PropertyName *name, const Value &v) |
| { |
| JS_ASSERT(is<CallObject>() || is<ClonedBlockObject>()); |
| JS_STATIC_ASSERT(CallObject::RESERVED_SLOTS == BlockObject::RESERVED_SLOTS); |
| |
| // name may be null for non-singletons, whose types do not need to be tracked. |
| JS_ASSERT_IF(hasSingletonType(), name); |
| |
| setSlot(sc.slot, v); |
| if (hasSingletonType()) |
| types::AddTypePropertyId(cx, this, NameToId(name), v); |
| } |
| |
| /*static*/ inline size_t |
| ScopeObject::offsetOfEnclosingScope() |
| { |
| return getFixedSlotOffset(SCOPE_CHAIN_SLOT); |
| } |
| |
| inline bool |
| CallObject::isForEval() const |
| { |
| JS_ASSERT(getReservedSlot(CALLEE_SLOT).isObjectOrNull()); |
| JS_ASSERT_IF(getReservedSlot(CALLEE_SLOT).isObject(), |
| getReservedSlot(CALLEE_SLOT).toObject().is<JSFunction>()); |
| return getReservedSlot(CALLEE_SLOT).isNull(); |
| } |
| |
| inline JSFunction & |
| CallObject::callee() const |
| { |
| return getReservedSlot(CALLEE_SLOT).toObject().as<JSFunction>(); |
| } |
| |
| inline const Value & |
| CallObject::aliasedVar(AliasedFormalIter fi) |
| { |
| return getSlot(fi.scopeSlot()); |
| } |
| |
| inline void |
| CallObject::setAliasedVar(JSContext *cx, AliasedFormalIter fi, PropertyName *name, const Value &v) |
| { |
| JS_ASSERT(name == fi->name()); |
| setSlot(fi.scopeSlot(), v); |
| if (hasSingletonType()) |
| types::AddTypePropertyId(cx, this, NameToId(name), v); |
| } |
| |
| /*static*/ inline size_t |
| CallObject::offsetOfCallee() |
| { |
| return getFixedSlotOffset(CALLEE_SLOT); |
| } |
| |
| inline uint32_t |
| NestedScopeObject::stackDepth() const |
| { |
| return getReservedSlot(DEPTH_SLOT).toPrivateUint32(); |
| } |
| |
| inline JSObject & |
| WithObject::withThis() const |
| { |
| return getReservedSlot(THIS_SLOT).toObject(); |
| } |
| |
| inline JSObject & |
| WithObject::object() const |
| { |
| return *JSObject::getProto(); |
| } |
| |
| inline uint32_t |
| BlockObject::slotCount() const |
| { |
| return propertyCount(); |
| } |
| |
| inline unsigned |
| BlockObject::slotToLocalIndex(const Bindings &bindings, unsigned slot) |
| { |
| JS_ASSERT(slot < RESERVED_SLOTS + slotCount()); |
| return bindings.numVars() + stackDepth() + (slot - RESERVED_SLOTS); |
| } |
| |
| inline unsigned |
| BlockObject::localIndexToSlot(const Bindings &bindings, unsigned i) |
| { |
| return RESERVED_SLOTS + (i - (bindings.numVars() + stackDepth())); |
| } |
| |
| inline const Value & |
| BlockObject::slotValue(unsigned i) |
| { |
| return getSlotRef(RESERVED_SLOTS + i); |
| } |
| |
| inline void |
| BlockObject::setSlotValue(unsigned i, const Value &v) |
| { |
| setSlot(RESERVED_SLOTS + i, v); |
| } |
| |
| inline void |
| StaticBlockObject::initPrevBlockChainFromParser(StaticBlockObject *prev) |
| { |
| setReservedSlot(SCOPE_CHAIN_SLOT, ObjectOrNullValue(prev)); |
| } |
| |
| inline void |
| StaticBlockObject::resetPrevBlockChainFromParser() |
| { |
| setReservedSlot(SCOPE_CHAIN_SLOT, UndefinedValue()); |
| } |
| |
| inline void |
| StaticBlockObject::initEnclosingStaticScope(JSObject *obj) |
| { |
| JS_ASSERT(getReservedSlot(SCOPE_CHAIN_SLOT).isUndefined()); |
| setReservedSlot(SCOPE_CHAIN_SLOT, ObjectOrNullValue(obj)); |
| } |
| |
| inline StaticBlockObject * |
| StaticBlockObject::enclosingBlock() const |
| { |
| JSObject *obj = getReservedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull(); |
| return obj && obj->is<StaticBlockObject>() ? &obj->as<StaticBlockObject>() : NULL; |
| } |
| |
| inline JSObject * |
| StaticBlockObject::enclosingStaticScope() const |
| { |
| return getReservedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull(); |
| } |
| |
| inline void |
| StaticBlockObject::setStackDepth(uint32_t depth) |
| { |
| JS_ASSERT(getReservedSlot(DEPTH_SLOT).isUndefined()); |
| initReservedSlot(DEPTH_SLOT, PrivateUint32Value(depth)); |
| } |
| |
| inline void |
| StaticBlockObject::setDefinitionParseNode(unsigned i, frontend::Definition *def) |
| { |
| JS_ASSERT(slotValue(i).isUndefined()); |
| setSlotValue(i, PrivateValue(def)); |
| } |
| |
| inline frontend::Definition * |
| StaticBlockObject::maybeDefinitionParseNode(unsigned i) |
| { |
| Value v = slotValue(i); |
| return v.isUndefined() ? NULL : reinterpret_cast<frontend::Definition *>(v.toPrivate()); |
| } |
| |
| inline void |
| StaticBlockObject::setAliased(unsigned i, bool aliased) |
| { |
| JS_ASSERT_IF(i > 0, slotValue(i-1).isBoolean()); |
| setSlotValue(i, BooleanValue(aliased)); |
| if (aliased && !needsClone()) { |
| setSlotValue(0, MagicValue(JS_BLOCK_NEEDS_CLONE)); |
| JS_ASSERT(needsClone()); |
| } |
| } |
| |
| inline bool |
| StaticBlockObject::isAliased(unsigned i) |
| { |
| return slotValue(i).isTrue(); |
| } |
| |
| inline bool |
| StaticBlockObject::needsClone() |
| { |
| return !slotValue(0).isFalse(); |
| } |
| |
| inline bool |
| StaticBlockObject::containsVarAtDepth(uint32_t depth) |
| { |
| return depth >= stackDepth() && depth < stackDepth() + slotCount(); |
| } |
| |
| inline StaticBlockObject & |
| ClonedBlockObject::staticBlock() const |
| { |
| return getProto()->as<StaticBlockObject>(); |
| } |
| |
| inline const Value & |
| ClonedBlockObject::var(unsigned i, MaybeCheckAliasing checkAliasing) |
| { |
| JS_ASSERT_IF(checkAliasing, staticBlock().isAliased(i)); |
| return slotValue(i); |
| } |
| |
| inline void |
| ClonedBlockObject::setVar(unsigned i, const Value &v, MaybeCheckAliasing checkAliasing) |
| { |
| JS_ASSERT_IF(checkAliasing, staticBlock().isAliased(i)); |
| setSlotValue(i, v); |
| } |
| |
| } /* namespace js */ |
| |
| #endif /* vm_ScopeObject_inl_h */ |