1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/Shape-inl.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,225 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef vm_Shape_inl_h 1.11 +#define vm_Shape_inl_h 1.12 + 1.13 +#include "vm/Shape.h" 1.14 + 1.15 +#include "mozilla/TypeTraits.h" 1.16 + 1.17 +#include "jsobj.h" 1.18 + 1.19 +#include "vm/Interpreter.h" 1.20 +#include "vm/ScopeObject.h" 1.21 +#include "vm/TypedArrayObject.h" 1.22 + 1.23 +#include "jsatominlines.h" 1.24 +#include "jscntxtinlines.h" 1.25 +#include "jsgcinlines.h" 1.26 + 1.27 +namespace js { 1.28 + 1.29 +inline 1.30 +StackBaseShape::StackBaseShape(ThreadSafeContext *cx, const Class *clasp, 1.31 + JSObject *parent, JSObject *metadata, uint32_t objectFlags) 1.32 + : flags(objectFlags), 1.33 + clasp(clasp), 1.34 + parent(parent), 1.35 + metadata(metadata), 1.36 + rawGetter(nullptr), 1.37 + rawSetter(nullptr), 1.38 + compartment(cx->compartment_) 1.39 +{} 1.40 + 1.41 +inline bool 1.42 +Shape::get(JSContext* cx, HandleObject receiver, JSObject* obj, JSObject *pobj, 1.43 + MutableHandleValue vp) 1.44 +{ 1.45 + JS_ASSERT(!hasDefaultGetter()); 1.46 + 1.47 + if (hasGetterValue()) { 1.48 + Value fval = getterValue(); 1.49 + return InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp); 1.50 + } 1.51 + 1.52 + RootedId id(cx, propid()); 1.53 + return CallJSPropertyOp(cx, getterOp(), receiver, id, vp); 1.54 +} 1.55 + 1.56 +inline Shape * 1.57 +Shape::search(ExclusiveContext *cx, jsid id) 1.58 +{ 1.59 + Shape **_; 1.60 + return search(cx, this, id, &_); 1.61 +} 1.62 + 1.63 +inline Shape * 1.64 +Shape::searchThreadLocal(ThreadSafeContext *cx, Shape *start, jsid id, 1.65 + Shape ***pspp, bool adding) 1.66 +{ 1.67 + /* 1.68 + * Note that adding is a best-effort attempt to claim an entry in a shape 1.69 + * table. In the sequential case, this can be done either when the object 1.70 + * is in dictionary mode, or when it has been hashified. 1.71 + * 1.72 + * In parallel, an object that is in dictionary mode may be thread 1.73 + * local. That is, it was converted to a dictionary in the current thread, 1.74 + * with all its shapes cloned into the current thread, and its shape table 1.75 + * allocated thread locally. In that case, we may add to the 1.76 + * table. Otherwise it is not allowed. 1.77 + */ 1.78 + JS_ASSERT_IF(adding, cx->isThreadLocal(start) && start->inDictionary()); 1.79 + 1.80 + if (start->inDictionary()) { 1.81 + *pspp = start->table().search(id, adding); 1.82 + return SHAPE_FETCH(*pspp); 1.83 + } 1.84 + 1.85 + *pspp = nullptr; 1.86 + 1.87 + return searchNoHashify(start, id); 1.88 +} 1.89 + 1.90 +inline bool 1.91 +Shape::set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict, 1.92 + MutableHandleValue vp) 1.93 +{ 1.94 + JS_ASSERT_IF(hasDefaultSetter(), hasGetterValue()); 1.95 + 1.96 + if (attrs & JSPROP_SETTER) { 1.97 + Value fval = setterValue(); 1.98 + return InvokeGetterOrSetter(cx, receiver, fval, 1, vp.address(), vp); 1.99 + } 1.100 + 1.101 + if (attrs & JSPROP_GETTER) 1.102 + return js_ReportGetterOnlyAssignment(cx, strict); 1.103 + 1.104 + RootedId id(cx, propid()); 1.105 + 1.106 + /* 1.107 + * |with (it) color='red';| ends up here. 1.108 + * Avoid exposing the With object to native setters. 1.109 + */ 1.110 + if (obj->is<DynamicWithObject>()) { 1.111 + RootedObject nobj(cx, &obj->as<DynamicWithObject>().object()); 1.112 + return CallJSPropertyOpSetter(cx, setterOp(), nobj, id, strict, vp); 1.113 + } 1.114 + 1.115 + return CallJSPropertyOpSetter(cx, setterOp(), obj, id, strict, vp); 1.116 +} 1.117 + 1.118 +/* static */ inline Shape * 1.119 +Shape::search(ExclusiveContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding) 1.120 +{ 1.121 + if (start->inDictionary()) { 1.122 + *pspp = start->table().search(id, adding); 1.123 + return SHAPE_FETCH(*pspp); 1.124 + } 1.125 + 1.126 + *pspp = nullptr; 1.127 + 1.128 + if (start->hasTable()) { 1.129 + Shape **spp = start->table().search(id, adding); 1.130 + return SHAPE_FETCH(spp); 1.131 + } 1.132 + 1.133 + if (start->numLinearSearches() == LINEAR_SEARCHES_MAX) { 1.134 + if (start->isBigEnoughForAShapeTable()) { 1.135 + if (Shape::hashify(cx, start)) { 1.136 + Shape **spp = start->table().search(id, adding); 1.137 + return SHAPE_FETCH(spp); 1.138 + } else { 1.139 + cx->recoverFromOutOfMemory(); 1.140 + } 1.141 + } 1.142 + /* 1.143 + * No table built -- there weren't enough entries, or OOM occurred. 1.144 + * Don't increment numLinearSearches, to keep hasTable() false. 1.145 + */ 1.146 + JS_ASSERT(!start->hasTable()); 1.147 + } else { 1.148 + start->incrementNumLinearSearches(); 1.149 + } 1.150 + 1.151 + for (Shape *shape = start; shape; shape = shape->parent) { 1.152 + if (shape->propidRef() == id) 1.153 + return shape; 1.154 + } 1.155 + 1.156 + return nullptr; 1.157 +} 1.158 + 1.159 +template<class ObjectSubclass> 1.160 +/* static */ inline bool 1.161 +EmptyShape::ensureInitialCustomShape(ExclusiveContext *cx, Handle<ObjectSubclass*> obj) 1.162 +{ 1.163 + static_assert(mozilla::IsBaseOf<JSObject, ObjectSubclass>::value, 1.164 + "ObjectSubclass must be a subclass of JSObject"); 1.165 + 1.166 + // If the provided object has a non-empty shape, it was given the cached 1.167 + // initial shape when created: nothing to do. 1.168 + if (!obj->nativeEmpty()) 1.169 + return true; 1.170 + 1.171 + // If no initial shape was assigned, do so. 1.172 + RootedShape shape(cx, ObjectSubclass::assignInitialShape(cx, obj)); 1.173 + if (!shape) 1.174 + return false; 1.175 + MOZ_ASSERT(!obj->nativeEmpty()); 1.176 + 1.177 + // If the object is a standard prototype -- |RegExp.prototype|, 1.178 + // |String.prototype|, |RangeError.prototype|, &c. -- GlobalObject.cpp's 1.179 + // |CreateBlankProto| marked it as a delegate. These are the only objects 1.180 + // of this class that won't use the standard prototype, and there's no 1.181 + // reason to pollute the initial shape cache with entries for them. 1.182 + if (obj->isDelegate()) 1.183 + return true; 1.184 + 1.185 + // Cache the initial shape for non-prototype objects, however, so that 1.186 + // future instances will begin life with that shape. 1.187 + RootedObject proto(cx, obj->getProto()); 1.188 + EmptyShape::insertInitialShape(cx, shape, proto); 1.189 + return true; 1.190 +} 1.191 + 1.192 +inline 1.193 +AutoRooterGetterSetter::Inner::Inner(ThreadSafeContext *cx, uint8_t attrs, 1.194 + PropertyOp *pgetter_, StrictPropertyOp *psetter_) 1.195 + : CustomAutoRooter(cx), attrs(attrs), 1.196 + pgetter(pgetter_), psetter(psetter_) 1.197 +{ 1.198 + JS_ASSERT_IF(attrs & JSPROP_GETTER, !IsPoisonedPtr(*pgetter)); 1.199 + JS_ASSERT_IF(attrs & JSPROP_SETTER, !IsPoisonedPtr(*psetter)); 1.200 +} 1.201 + 1.202 +inline 1.203 +AutoRooterGetterSetter::AutoRooterGetterSetter(ThreadSafeContext *cx, uint8_t attrs, 1.204 + PropertyOp *pgetter, StrictPropertyOp *psetter 1.205 + MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) 1.206 +{ 1.207 + if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) 1.208 + inner.construct(cx, attrs, pgetter, psetter); 1.209 + MOZ_GUARD_OBJECT_NOTIFIER_INIT; 1.210 +} 1.211 + 1.212 +static inline uint8_t 1.213 +GetShapeAttributes(JSObject *obj, Shape *shape) 1.214 +{ 1.215 + JS_ASSERT(obj->isNative()); 1.216 + 1.217 + if (IsImplicitDenseOrTypedArrayElement(shape)) { 1.218 + if (obj->is<TypedArrayObject>()) 1.219 + return JSPROP_ENUMERATE | JSPROP_PERMANENT; 1.220 + return JSPROP_ENUMERATE; 1.221 + } 1.222 + 1.223 + return shape->attributes(); 1.224 +} 1.225 + 1.226 +} /* namespace js */ 1.227 + 1.228 +#endif /* vm_Shape_inl_h */