diff options
Diffstat (limited to 'js/src/vm/Shape-inl.h')
-rw-r--r-- | js/src/vm/Shape-inl.h | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h new file mode 100644 index 000000000..b8c48780e --- /dev/null +++ b/js/src/vm/Shape-inl.h @@ -0,0 +1,210 @@ +/* -*- 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_Shape_inl_h +#define vm_Shape_inl_h + +#include "vm/Shape.h" + +#include "mozilla/TypeTraits.h" + +#include "jsobj.h" + +#include "gc/Allocator.h" +#include "vm/Interpreter.h" +#include "vm/TypedArrayCommon.h" + +#include "jsatominlines.h" +#include "jscntxtinlines.h" + +namespace js { + +inline +AutoKeepShapeTables::AutoKeepShapeTables(ExclusiveContext* cx) + : cx_(cx), + prev_(cx->zone()->keepShapeTables()) +{ + cx->zone()->setKeepShapeTables(true); +} + +inline +AutoKeepShapeTables::~AutoKeepShapeTables() +{ + cx_->zone()->setKeepShapeTables(prev_); +} + +inline +StackBaseShape::StackBaseShape(ExclusiveContext* cx, const Class* clasp, uint32_t objectFlags) + : flags(objectFlags), + clasp(clasp) +{} + +inline Shape* +Shape::search(ExclusiveContext* cx, jsid id) +{ + return search(cx, this, id); +} + +MOZ_ALWAYS_INLINE bool +Shape::maybeCreateTableForLookup(ExclusiveContext* cx) +{ + if (hasTable()) + return true; + + if (!inDictionary() && numLinearSearches() < LINEAR_SEARCHES_MAX) { + incrementNumLinearSearches(); + return true; + } + + if (!isBigEnoughForAShapeTable()) + return true; + + return Shape::hashify(cx, this); +} + +template<MaybeAdding Adding> +/* static */ inline bool +Shape::search(ExclusiveContext* cx, Shape* start, jsid id, const AutoKeepShapeTables& keep, + Shape** pshape, ShapeTable::Entry** pentry) +{ + if (start->inDictionary()) { + ShapeTable* table = start->ensureTableForDictionary(cx, keep); + if (!table) + return false; + *pentry = &table->search<Adding>(id, keep); + *pshape = (*pentry)->shape(); + return true; + } + + *pentry = nullptr; + *pshape = Shape::search<Adding>(cx, start, id); + return true; +} + +template<MaybeAdding Adding> +/* static */ inline Shape* +Shape::search(ExclusiveContext* cx, Shape* start, jsid id) +{ + if (start->maybeCreateTableForLookup(cx)) { + JS::AutoCheckCannotGC nogc; + if (ShapeTable* table = start->maybeTable(nogc)) { + ShapeTable::Entry& entry = table->search<Adding>(id, nogc); + return entry.shape(); + } + } else { + // Just do a linear search. + cx->recoverFromOutOfMemory(); + } + + return start->searchLinear(id); +} + +inline Shape* +Shape::new_(ExclusiveContext* cx, Handle<StackShape> other, uint32_t nfixed) +{ + Shape* shape = other.isAccessorShape() + ? js::Allocate<AccessorShape>(cx) + : js::Allocate<Shape>(cx); + if (!shape) { + ReportOutOfMemory(cx); + return nullptr; + } + + if (other.isAccessorShape()) + new (shape) AccessorShape(other, nfixed); + else + new (shape) Shape(other, nfixed); + + return shape; +} + +inline void +Shape::updateBaseShapeAfterMovingGC() +{ + BaseShape* base = base_.unbarrieredGet(); + if (IsForwarded(base)) + base_.unsafeSet(Forwarded(base)); +} + +template<class ObjectSubclass> +/* static */ inline bool +EmptyShape::ensureInitialCustomShape(ExclusiveContext* cx, Handle<ObjectSubclass*> obj) +{ + static_assert(mozilla::IsBaseOf<JSObject, ObjectSubclass>::value, + "ObjectSubclass must be a subclass of JSObject"); + + // If the provided object has a non-empty shape, it was given the cached + // initial shape when created: nothing to do. + if (!obj->empty()) + return true; + + // If no initial shape was assigned, do so. + RootedShape shape(cx, ObjectSubclass::assignInitialShape(cx, obj)); + if (!shape) + return false; + MOZ_ASSERT(!obj->empty()); + + // If the object is a standard prototype -- |RegExp.prototype|, + // |String.prototype|, |RangeError.prototype|, &c. -- GlobalObject.cpp's + // |CreateBlankProto| marked it as a delegate. These are the only objects + // of this class that won't use the standard prototype, and there's no + // reason to pollute the initial shape cache with entries for them. + if (obj->isDelegate()) + return true; + + // Cache the initial shape for non-prototype objects, however, so that + // future instances will begin life with that shape. + RootedObject proto(cx, obj->staticPrototype()); + EmptyShape::insertInitialShape(cx, shape, proto); + return true; +} + +inline +AutoRooterGetterSetter::Inner::Inner(ExclusiveContext* cx, uint8_t attrs, + GetterOp* pgetter_, SetterOp* psetter_) + : CustomAutoRooter(cx), attrs(attrs), + pgetter(pgetter_), psetter(psetter_) +{} + +inline +AutoRooterGetterSetter::AutoRooterGetterSetter(ExclusiveContext* cx, uint8_t attrs, + GetterOp* pgetter, SetterOp* psetter + MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) +{ + if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) + inner.emplace(cx, attrs, pgetter, psetter); + MOZ_GUARD_OBJECT_NOTIFIER_INIT; +} + +inline +AutoRooterGetterSetter::AutoRooterGetterSetter(ExclusiveContext* cx, uint8_t attrs, + JSNative* pgetter, JSNative* psetter + MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) +{ + if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { + inner.emplace(cx, attrs, reinterpret_cast<GetterOp*>(pgetter), + reinterpret_cast<SetterOp*>(psetter)); + } + MOZ_GUARD_OBJECT_NOTIFIER_INIT; +} + +static inline uint8_t +GetShapeAttributes(JSObject* obj, Shape* shape) +{ + MOZ_ASSERT(obj->isNative()); + + if (IsImplicitDenseOrTypedArrayElement(shape)) { + if (obj->is<TypedArrayObject>()) + return JSPROP_ENUMERATE | JSPROP_PERMANENT; + return obj->as<NativeObject>().getElementsHeader()->elementAttributes(); + } + + return shape->attributes(); +} + +} /* namespace js */ + +#endif /* vm_Shape_inl_h */ |