michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef vm_Shape_inl_h michael@0: #define vm_Shape_inl_h michael@0: michael@0: #include "vm/Shape.h" michael@0: michael@0: #include "mozilla/TypeTraits.h" michael@0: michael@0: #include "jsobj.h" michael@0: michael@0: #include "vm/Interpreter.h" michael@0: #include "vm/ScopeObject.h" michael@0: #include "vm/TypedArrayObject.h" michael@0: michael@0: #include "jsatominlines.h" michael@0: #include "jscntxtinlines.h" michael@0: #include "jsgcinlines.h" michael@0: michael@0: namespace js { michael@0: michael@0: inline michael@0: StackBaseShape::StackBaseShape(ThreadSafeContext *cx, const Class *clasp, michael@0: JSObject *parent, JSObject *metadata, uint32_t objectFlags) michael@0: : flags(objectFlags), michael@0: clasp(clasp), michael@0: parent(parent), michael@0: metadata(metadata), michael@0: rawGetter(nullptr), michael@0: rawSetter(nullptr), michael@0: compartment(cx->compartment_) michael@0: {} michael@0: michael@0: inline bool michael@0: Shape::get(JSContext* cx, HandleObject receiver, JSObject* obj, JSObject *pobj, michael@0: MutableHandleValue vp) michael@0: { michael@0: JS_ASSERT(!hasDefaultGetter()); michael@0: michael@0: if (hasGetterValue()) { michael@0: Value fval = getterValue(); michael@0: return InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp); michael@0: } michael@0: michael@0: RootedId id(cx, propid()); michael@0: return CallJSPropertyOp(cx, getterOp(), receiver, id, vp); michael@0: } michael@0: michael@0: inline Shape * michael@0: Shape::search(ExclusiveContext *cx, jsid id) michael@0: { michael@0: Shape **_; michael@0: return search(cx, this, id, &_); michael@0: } michael@0: michael@0: inline Shape * michael@0: Shape::searchThreadLocal(ThreadSafeContext *cx, Shape *start, jsid id, michael@0: Shape ***pspp, bool adding) michael@0: { michael@0: /* michael@0: * Note that adding is a best-effort attempt to claim an entry in a shape michael@0: * table. In the sequential case, this can be done either when the object michael@0: * is in dictionary mode, or when it has been hashified. michael@0: * michael@0: * In parallel, an object that is in dictionary mode may be thread michael@0: * local. That is, it was converted to a dictionary in the current thread, michael@0: * with all its shapes cloned into the current thread, and its shape table michael@0: * allocated thread locally. In that case, we may add to the michael@0: * table. Otherwise it is not allowed. michael@0: */ michael@0: JS_ASSERT_IF(adding, cx->isThreadLocal(start) && start->inDictionary()); michael@0: michael@0: if (start->inDictionary()) { michael@0: *pspp = start->table().search(id, adding); michael@0: return SHAPE_FETCH(*pspp); michael@0: } michael@0: michael@0: *pspp = nullptr; michael@0: michael@0: return searchNoHashify(start, id); michael@0: } michael@0: michael@0: inline bool michael@0: Shape::set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict, michael@0: MutableHandleValue vp) michael@0: { michael@0: JS_ASSERT_IF(hasDefaultSetter(), hasGetterValue()); michael@0: michael@0: if (attrs & JSPROP_SETTER) { michael@0: Value fval = setterValue(); michael@0: return InvokeGetterOrSetter(cx, receiver, fval, 1, vp.address(), vp); michael@0: } michael@0: michael@0: if (attrs & JSPROP_GETTER) michael@0: return js_ReportGetterOnlyAssignment(cx, strict); michael@0: michael@0: RootedId id(cx, propid()); michael@0: michael@0: /* michael@0: * |with (it) color='red';| ends up here. michael@0: * Avoid exposing the With object to native setters. michael@0: */ michael@0: if (obj->is()) { michael@0: RootedObject nobj(cx, &obj->as().object()); michael@0: return CallJSPropertyOpSetter(cx, setterOp(), nobj, id, strict, vp); michael@0: } michael@0: michael@0: return CallJSPropertyOpSetter(cx, setterOp(), obj, id, strict, vp); michael@0: } michael@0: michael@0: /* static */ inline Shape * michael@0: Shape::search(ExclusiveContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding) michael@0: { michael@0: if (start->inDictionary()) { michael@0: *pspp = start->table().search(id, adding); michael@0: return SHAPE_FETCH(*pspp); michael@0: } michael@0: michael@0: *pspp = nullptr; michael@0: michael@0: if (start->hasTable()) { michael@0: Shape **spp = start->table().search(id, adding); michael@0: return SHAPE_FETCH(spp); michael@0: } michael@0: michael@0: if (start->numLinearSearches() == LINEAR_SEARCHES_MAX) { michael@0: if (start->isBigEnoughForAShapeTable()) { michael@0: if (Shape::hashify(cx, start)) { michael@0: Shape **spp = start->table().search(id, adding); michael@0: return SHAPE_FETCH(spp); michael@0: } else { michael@0: cx->recoverFromOutOfMemory(); michael@0: } michael@0: } michael@0: /* michael@0: * No table built -- there weren't enough entries, or OOM occurred. michael@0: * Don't increment numLinearSearches, to keep hasTable() false. michael@0: */ michael@0: JS_ASSERT(!start->hasTable()); michael@0: } else { michael@0: start->incrementNumLinearSearches(); michael@0: } michael@0: michael@0: for (Shape *shape = start; shape; shape = shape->parent) { michael@0: if (shape->propidRef() == id) michael@0: return shape; michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: template michael@0: /* static */ inline bool michael@0: EmptyShape::ensureInitialCustomShape(ExclusiveContext *cx, Handle obj) michael@0: { michael@0: static_assert(mozilla::IsBaseOf::value, michael@0: "ObjectSubclass must be a subclass of JSObject"); michael@0: michael@0: // If the provided object has a non-empty shape, it was given the cached michael@0: // initial shape when created: nothing to do. michael@0: if (!obj->nativeEmpty()) michael@0: return true; michael@0: michael@0: // If no initial shape was assigned, do so. michael@0: RootedShape shape(cx, ObjectSubclass::assignInitialShape(cx, obj)); michael@0: if (!shape) michael@0: return false; michael@0: MOZ_ASSERT(!obj->nativeEmpty()); michael@0: michael@0: // If the object is a standard prototype -- |RegExp.prototype|, michael@0: // |String.prototype|, |RangeError.prototype|, &c. -- GlobalObject.cpp's michael@0: // |CreateBlankProto| marked it as a delegate. These are the only objects michael@0: // of this class that won't use the standard prototype, and there's no michael@0: // reason to pollute the initial shape cache with entries for them. michael@0: if (obj->isDelegate()) michael@0: return true; michael@0: michael@0: // Cache the initial shape for non-prototype objects, however, so that michael@0: // future instances will begin life with that shape. michael@0: RootedObject proto(cx, obj->getProto()); michael@0: EmptyShape::insertInitialShape(cx, shape, proto); michael@0: return true; michael@0: } michael@0: michael@0: inline michael@0: AutoRooterGetterSetter::Inner::Inner(ThreadSafeContext *cx, uint8_t attrs, michael@0: PropertyOp *pgetter_, StrictPropertyOp *psetter_) michael@0: : CustomAutoRooter(cx), attrs(attrs), michael@0: pgetter(pgetter_), psetter(psetter_) michael@0: { michael@0: JS_ASSERT_IF(attrs & JSPROP_GETTER, !IsPoisonedPtr(*pgetter)); michael@0: JS_ASSERT_IF(attrs & JSPROP_SETTER, !IsPoisonedPtr(*psetter)); michael@0: } michael@0: michael@0: inline michael@0: AutoRooterGetterSetter::AutoRooterGetterSetter(ThreadSafeContext *cx, uint8_t attrs, michael@0: PropertyOp *pgetter, StrictPropertyOp *psetter michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) michael@0: { michael@0: if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) michael@0: inner.construct(cx, attrs, pgetter, psetter); michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: static inline uint8_t michael@0: GetShapeAttributes(JSObject *obj, Shape *shape) michael@0: { michael@0: JS_ASSERT(obj->isNative()); michael@0: michael@0: if (IsImplicitDenseOrTypedArrayElement(shape)) { michael@0: if (obj->is()) michael@0: return JSPROP_ENUMERATE | JSPROP_PERMANENT; michael@0: return JSPROP_ENUMERATE; michael@0: } michael@0: michael@0: return shape->attributes(); michael@0: } michael@0: michael@0: } /* namespace js */ michael@0: michael@0: #endif /* vm_Shape_inl_h */