1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef vm_Shape_inl_h
8 #define vm_Shape_inl_h
9 
10 #include "vm/Shape.h"
11 
12 #include "gc/Allocator.h"
13 #include "vm/Interpreter.h"
14 #include "vm/JSObject.h"
15 #include "vm/TypedArrayObject.h"
16 
17 #include "gc/FreeOp-inl.h"
18 #include "gc/Marking-inl.h"
19 #include "vm/JSAtom-inl.h"
20 #include "vm/JSContext-inl.h"
21 #include "vm/PropMap-inl.h"
22 
23 namespace js {
24 
25 template <class ObjectSubclass>
ensureInitialCustomShape(JSContext * cx,Handle<ObjectSubclass * > obj)26 /* static */ inline bool SharedShape::ensureInitialCustomShape(
27     JSContext* cx, Handle<ObjectSubclass*> obj) {
28   static_assert(std::is_base_of_v<JSObject, ObjectSubclass>,
29                 "ObjectSubclass must be a subclass of JSObject");
30 
31   // If the provided object has a non-empty shape, it was given the cached
32   // initial shape when created: nothing to do.
33   if (!obj->empty()) {
34     return true;
35   }
36 
37   // Ensure the initial shape isn't collected under assignInitialShape, to
38   // simplify insertInitialShape.
39   RootedShape emptyShape(cx, obj->shape());
40 
41   // If no initial shape was assigned, do so.
42   RootedShape shape(cx, ObjectSubclass::assignInitialShape(cx, obj));
43   if (!shape) {
44     return false;
45   }
46   MOZ_ASSERT(!obj->empty());
47 
48   // Cache the initial shape, so that future instances will begin life with that
49   // shape.
50   SharedShape::insertInitialShape(cx, shape);
51   return true;
52 }
53 
lookup(JSContext * cx,PropertyKey key,uint32_t * index)54 MOZ_ALWAYS_INLINE PropMap* Shape::lookup(JSContext* cx, PropertyKey key,
55                                          uint32_t* index) {
56   uint32_t len = propMapLength();
57   return len > 0 ? propMap_->lookup(cx, len, key, index) : nullptr;
58 }
59 
lookupPure(PropertyKey key,uint32_t * index)60 MOZ_ALWAYS_INLINE PropMap* Shape::lookupPure(PropertyKey key, uint32_t* index) {
61   uint32_t len = propMapLength();
62   return len > 0 ? propMap_->lookupPure(len, key, index) : nullptr;
63 }
64 
purgeCache(JSFreeOp * fop)65 inline void Shape::purgeCache(JSFreeOp* fop) {
66   if (cache_.isShapeSetForAdd()) {
67     fop->delete_(this, cache_.toShapeSetForAdd(), MemoryUse::ShapeSetForAdd);
68   }
69   cache_.setNone();
70 }
71 
finalize(JSFreeOp * fop)72 inline void Shape::finalize(JSFreeOp* fop) {
73   if (!cache_.isNone()) {
74     purgeCache(fop);
75   }
76 }
77 
GetPropertyAttributes(JSObject * obj,PropertyResult prop)78 static inline JS::PropertyAttributes GetPropertyAttributes(
79     JSObject* obj, PropertyResult prop) {
80   MOZ_ASSERT(obj->is<NativeObject>());
81 
82   if (prop.isDenseElement()) {
83     return obj->as<NativeObject>().getElementsHeader()->elementAttributes();
84   }
85   if (prop.isTypedArrayElement()) {
86     return {JS::PropertyAttribute::Configurable,
87             JS::PropertyAttribute::Enumerable, JS::PropertyAttribute::Writable};
88   }
89 
90   return prop.propertyInfo().propAttributes();
91 }
92 
93 } /* namespace js */
94 
95 #endif /* vm_Shape_inl_h */
96