summaryrefslogtreecommitdiffstats
path: root/js/src/vm/Shape-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/Shape-inl.h')
-rw-r--r--js/src/vm/Shape-inl.h210
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 */