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