/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * 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" #include "jsgcinlines.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 /* 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(id, keep); *pshape = (*pentry)->shape(); return true; } *pentry = nullptr; *pshape = Shape::search(cx, start, id); return true; } template /* 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(id, nogc); return entry.shape(); } } else { // Just do a linear search. cx->recoverFromOutOfMemory(); } return start->searchLinear(id); } inline Shape* Shape::new_(ExclusiveContext* cx, Handle other, uint32_t nfixed) { Shape* shape = other.isAccessorShape() ? js::Allocate(cx) : js::Allocate(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_; if (IsForwarded(base)) base_.unsafeSet(Forwarded(base)); } template /* static */ inline bool EmptyShape::ensureInitialCustomShape(ExclusiveContext* cx, Handle obj) { static_assert(mozilla::IsBaseOf::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(pgetter), reinterpret_cast(psetter)); } MOZ_GUARD_OBJECT_NOTIFIER_INIT; } static inline uint8_t GetPropertyAttributes(JSObject* obj, PropertyResult prop) { MOZ_ASSERT(obj->isNative()); if (prop.isDenseOrTypedArrayElement()) { if (obj->is()) return JSPROP_ENUMERATE | JSPROP_PERMANENT; return obj->as().getElementsHeader()->elementAttributes(); } return prop.shape()->attributes(); } } /* namespace js */ #endif /* vm_Shape_inl_h */