Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
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/. */
7 #ifndef vm_Shape_inl_h
8 #define vm_Shape_inl_h
10 #include "vm/Shape.h"
12 #include "mozilla/TypeTraits.h"
14 #include "jsobj.h"
16 #include "vm/Interpreter.h"
17 #include "vm/ScopeObject.h"
18 #include "vm/TypedArrayObject.h"
20 #include "jsatominlines.h"
21 #include "jscntxtinlines.h"
22 #include "jsgcinlines.h"
24 namespace js {
26 inline
27 StackBaseShape::StackBaseShape(ThreadSafeContext *cx, const Class *clasp,
28 JSObject *parent, JSObject *metadata, uint32_t objectFlags)
29 : flags(objectFlags),
30 clasp(clasp),
31 parent(parent),
32 metadata(metadata),
33 rawGetter(nullptr),
34 rawSetter(nullptr),
35 compartment(cx->compartment_)
36 {}
38 inline bool
39 Shape::get(JSContext* cx, HandleObject receiver, JSObject* obj, JSObject *pobj,
40 MutableHandleValue vp)
41 {
42 JS_ASSERT(!hasDefaultGetter());
44 if (hasGetterValue()) {
45 Value fval = getterValue();
46 return InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp);
47 }
49 RootedId id(cx, propid());
50 return CallJSPropertyOp(cx, getterOp(), receiver, id, vp);
51 }
53 inline Shape *
54 Shape::search(ExclusiveContext *cx, jsid id)
55 {
56 Shape **_;
57 return search(cx, this, id, &_);
58 }
60 inline Shape *
61 Shape::searchThreadLocal(ThreadSafeContext *cx, Shape *start, jsid id,
62 Shape ***pspp, bool adding)
63 {
64 /*
65 * Note that adding is a best-effort attempt to claim an entry in a shape
66 * table. In the sequential case, this can be done either when the object
67 * is in dictionary mode, or when it has been hashified.
68 *
69 * In parallel, an object that is in dictionary mode may be thread
70 * local. That is, it was converted to a dictionary in the current thread,
71 * with all its shapes cloned into the current thread, and its shape table
72 * allocated thread locally. In that case, we may add to the
73 * table. Otherwise it is not allowed.
74 */
75 JS_ASSERT_IF(adding, cx->isThreadLocal(start) && start->inDictionary());
77 if (start->inDictionary()) {
78 *pspp = start->table().search(id, adding);
79 return SHAPE_FETCH(*pspp);
80 }
82 *pspp = nullptr;
84 return searchNoHashify(start, id);
85 }
87 inline bool
88 Shape::set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict,
89 MutableHandleValue vp)
90 {
91 JS_ASSERT_IF(hasDefaultSetter(), hasGetterValue());
93 if (attrs & JSPROP_SETTER) {
94 Value fval = setterValue();
95 return InvokeGetterOrSetter(cx, receiver, fval, 1, vp.address(), vp);
96 }
98 if (attrs & JSPROP_GETTER)
99 return js_ReportGetterOnlyAssignment(cx, strict);
101 RootedId id(cx, propid());
103 /*
104 * |with (it) color='red';| ends up here.
105 * Avoid exposing the With object to native setters.
106 */
107 if (obj->is<DynamicWithObject>()) {
108 RootedObject nobj(cx, &obj->as<DynamicWithObject>().object());
109 return CallJSPropertyOpSetter(cx, setterOp(), nobj, id, strict, vp);
110 }
112 return CallJSPropertyOpSetter(cx, setterOp(), obj, id, strict, vp);
113 }
115 /* static */ inline Shape *
116 Shape::search(ExclusiveContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding)
117 {
118 if (start->inDictionary()) {
119 *pspp = start->table().search(id, adding);
120 return SHAPE_FETCH(*pspp);
121 }
123 *pspp = nullptr;
125 if (start->hasTable()) {
126 Shape **spp = start->table().search(id, adding);
127 return SHAPE_FETCH(spp);
128 }
130 if (start->numLinearSearches() == LINEAR_SEARCHES_MAX) {
131 if (start->isBigEnoughForAShapeTable()) {
132 if (Shape::hashify(cx, start)) {
133 Shape **spp = start->table().search(id, adding);
134 return SHAPE_FETCH(spp);
135 } else {
136 cx->recoverFromOutOfMemory();
137 }
138 }
139 /*
140 * No table built -- there weren't enough entries, or OOM occurred.
141 * Don't increment numLinearSearches, to keep hasTable() false.
142 */
143 JS_ASSERT(!start->hasTable());
144 } else {
145 start->incrementNumLinearSearches();
146 }
148 for (Shape *shape = start; shape; shape = shape->parent) {
149 if (shape->propidRef() == id)
150 return shape;
151 }
153 return nullptr;
154 }
156 template<class ObjectSubclass>
157 /* static */ inline bool
158 EmptyShape::ensureInitialCustomShape(ExclusiveContext *cx, Handle<ObjectSubclass*> obj)
159 {
160 static_assert(mozilla::IsBaseOf<JSObject, ObjectSubclass>::value,
161 "ObjectSubclass must be a subclass of JSObject");
163 // If the provided object has a non-empty shape, it was given the cached
164 // initial shape when created: nothing to do.
165 if (!obj->nativeEmpty())
166 return true;
168 // If no initial shape was assigned, do so.
169 RootedShape shape(cx, ObjectSubclass::assignInitialShape(cx, obj));
170 if (!shape)
171 return false;
172 MOZ_ASSERT(!obj->nativeEmpty());
174 // If the object is a standard prototype -- |RegExp.prototype|,
175 // |String.prototype|, |RangeError.prototype|, &c. -- GlobalObject.cpp's
176 // |CreateBlankProto| marked it as a delegate. These are the only objects
177 // of this class that won't use the standard prototype, and there's no
178 // reason to pollute the initial shape cache with entries for them.
179 if (obj->isDelegate())
180 return true;
182 // Cache the initial shape for non-prototype objects, however, so that
183 // future instances will begin life with that shape.
184 RootedObject proto(cx, obj->getProto());
185 EmptyShape::insertInitialShape(cx, shape, proto);
186 return true;
187 }
189 inline
190 AutoRooterGetterSetter::Inner::Inner(ThreadSafeContext *cx, uint8_t attrs,
191 PropertyOp *pgetter_, StrictPropertyOp *psetter_)
192 : CustomAutoRooter(cx), attrs(attrs),
193 pgetter(pgetter_), psetter(psetter_)
194 {
195 JS_ASSERT_IF(attrs & JSPROP_GETTER, !IsPoisonedPtr(*pgetter));
196 JS_ASSERT_IF(attrs & JSPROP_SETTER, !IsPoisonedPtr(*psetter));
197 }
199 inline
200 AutoRooterGetterSetter::AutoRooterGetterSetter(ThreadSafeContext *cx, uint8_t attrs,
201 PropertyOp *pgetter, StrictPropertyOp *psetter
202 MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
203 {
204 if (attrs & (JSPROP_GETTER | JSPROP_SETTER))
205 inner.construct(cx, attrs, pgetter, psetter);
206 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
207 }
209 static inline uint8_t
210 GetShapeAttributes(JSObject *obj, Shape *shape)
211 {
212 JS_ASSERT(obj->isNative());
214 if (IsImplicitDenseOrTypedArrayElement(shape)) {
215 if (obj->is<TypedArrayObject>())
216 return JSPROP_ENUMERATE | JSPROP_PERMANENT;
217 return JSPROP_ENUMERATE;
218 }
220 return shape->attributes();
221 }
223 } /* namespace js */
225 #endif /* vm_Shape_inl_h */