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/. */
6 
7 #ifndef vm_UnboxedObject_inl_h
8 #define vm_UnboxedObject_inl_h
9 
10 #include "vm/UnboxedObject.h"
11 
12 #include "gc/StoreBuffer-inl.h"
13 #include "vm/ArrayObject-inl.h"
14 #include "vm/NativeObject-inl.h"
15 
16 namespace js {
17 
GetUnboxedValue(uint8_t * p,JSValueType type,bool maybeUninitialized)18 static inline Value GetUnboxedValue(uint8_t* p, JSValueType type,
19                                     bool maybeUninitialized) {
20   switch (type) {
21     case JSVAL_TYPE_BOOLEAN:
22       return BooleanValue(*p != 0);
23 
24     case JSVAL_TYPE_INT32:
25       return Int32Value(*reinterpret_cast<int32_t*>(p));
26 
27     case JSVAL_TYPE_DOUBLE: {
28       // During unboxed plain object creation, non-GC thing properties are
29       // left uninitialized. This is normally fine, since the properties will
30       // be filled in shortly, but if they are read before that happens we
31       // need to make sure that doubles are canonical.
32       double d = *reinterpret_cast<double*>(p);
33       if (maybeUninitialized) return DoubleValue(JS::CanonicalizeNaN(d));
34       return DoubleValue(d);
35     }
36 
37     case JSVAL_TYPE_STRING:
38       return StringValue(*reinterpret_cast<JSString**>(p));
39 
40     case JSVAL_TYPE_OBJECT:
41       return ObjectOrNullValue(*reinterpret_cast<JSObject**>(p));
42 
43     default:
44       MOZ_CRASH("Invalid type for unboxed value");
45   }
46 }
47 
SetUnboxedValueNoTypeChange(JSObject * unboxedObject,uint8_t * p,JSValueType type,const Value & v,bool preBarrier)48 static inline void SetUnboxedValueNoTypeChange(JSObject* unboxedObject,
49                                                uint8_t* p, JSValueType type,
50                                                const Value& v,
51                                                bool preBarrier) {
52   switch (type) {
53     case JSVAL_TYPE_BOOLEAN:
54       *p = v.toBoolean();
55       return;
56 
57     case JSVAL_TYPE_INT32:
58       *reinterpret_cast<int32_t*>(p) = v.toInt32();
59       return;
60 
61     case JSVAL_TYPE_DOUBLE:
62       *reinterpret_cast<double*>(p) = v.toNumber();
63       return;
64 
65     case JSVAL_TYPE_STRING: {
66       MOZ_ASSERT(!IsInsideNursery(v.toString()));
67       JSString** np = reinterpret_cast<JSString**>(p);
68       if (preBarrier) JSString::writeBarrierPre(*np);
69       *np = v.toString();
70       return;
71     }
72 
73     case JSVAL_TYPE_OBJECT: {
74       JSObject** np = reinterpret_cast<JSObject**>(p);
75 
76       // Manually trigger post barriers on the whole object. If we treat
77       // the pointer as a HeapPtrObject we will get confused later if the
78       // object is converted to its native representation.
79       JSObject* obj = v.toObjectOrNull();
80       if (IsInsideNursery(obj) && !IsInsideNursery(unboxedObject))
81         unboxedObject->zone()->group()->storeBuffer().putWholeCell(
82             unboxedObject);
83 
84       if (preBarrier) JSObject::writeBarrierPre(*np);
85       *np = obj;
86       return;
87     }
88 
89     default:
90       MOZ_CRASH("Invalid type for unboxed value");
91   }
92 }
93 
SetUnboxedValue(JSContext * cx,JSObject * unboxedObject,jsid id,uint8_t * p,JSValueType type,const Value & v,bool preBarrier)94 static inline bool SetUnboxedValue(JSContext* cx, JSObject* unboxedObject,
95                                    jsid id, uint8_t* p, JSValueType type,
96                                    const Value& v, bool preBarrier) {
97   switch (type) {
98     case JSVAL_TYPE_BOOLEAN:
99       if (v.isBoolean()) {
100         *p = v.toBoolean();
101         return true;
102       }
103       return false;
104 
105     case JSVAL_TYPE_INT32:
106       if (v.isInt32()) {
107         *reinterpret_cast<int32_t*>(p) = v.toInt32();
108         return true;
109       }
110       return false;
111 
112     case JSVAL_TYPE_DOUBLE:
113       if (v.isNumber()) {
114         *reinterpret_cast<double*>(p) = v.toNumber();
115         return true;
116       }
117       return false;
118 
119     case JSVAL_TYPE_STRING:
120       if (v.isString()) {
121         JSString** np = reinterpret_cast<JSString**>(p);
122         if (IsInsideNursery(v.toString()) && !IsInsideNursery(unboxedObject))
123           unboxedObject->zone()->group()->storeBuffer().putWholeCell(
124               unboxedObject);
125 
126         if (preBarrier) JSString::writeBarrierPre(*np);
127         *np = v.toString();
128         return true;
129       }
130       return false;
131 
132     case JSVAL_TYPE_OBJECT:
133       if (v.isObjectOrNull()) {
134         JSObject** np = reinterpret_cast<JSObject**>(p);
135 
136         // Update property types when writing object properties. Types for
137         // other properties were captured when the unboxed layout was
138         // created.
139         AddTypePropertyId(cx, unboxedObject, id, v);
140 
141         // As above, trigger post barriers on the whole object.
142         JSObject* obj = v.toObjectOrNull();
143         if (IsInsideNursery(v.toObjectOrNull()) &&
144             !IsInsideNursery(unboxedObject))
145           unboxedObject->zone()->group()->storeBuffer().putWholeCell(
146               unboxedObject);
147 
148         if (preBarrier) JSObject::writeBarrierPre(*np);
149         *np = obj;
150         return true;
151       }
152       return false;
153 
154     default:
155       MOZ_CRASH("Invalid type for unboxed value");
156   }
157 }
158 
159 /////////////////////////////////////////////////////////////////////
160 // UnboxedPlainObject
161 /////////////////////////////////////////////////////////////////////
162 
layout()163 inline const UnboxedLayout& UnboxedPlainObject::layout() const {
164   return group()->unboxedLayout();
165 }
166 
167 /////////////////////////////////////////////////////////////////////
168 // UnboxedLayout
169 /////////////////////////////////////////////////////////////////////
170 
getAllocKind()171 gc::AllocKind js::UnboxedLayout::getAllocKind() const {
172   MOZ_ASSERT(size());
173   return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() +
174                                      size());
175 }
176 
177 }  // namespace js
178 
179 #endif  // vm_UnboxedObject_inl_h
180