1/*
2 * Copyright (C) 1999-2001 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2003-2019 Apple Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include "config.h"
24#include "JSCell.h"
25
26#include "ArrayBufferView.h"
27#include "JSCInlines.h"
28#include "JSCast.h"
29#include "JSFunction.h"
30#include "JSString.h"
31#include "JSObject.h"
32#include "NumberObject.h"
33#include "WebAssemblyToJSCallee.h"
34#include <wtf/LockAlgorithmInlines.h>
35#include <wtf/MathExtras.h>
36
37namespace JSC {
38
39COMPILE_ASSERT(sizeof(JSCell) == sizeof(uint64_t), jscell_is_eight_bytes);
40STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSCell);
41
42void JSCell::destroy(JSCell* cell)
43{
44 cell->JSCell::~JSCell();
45}
46
47void JSCell::dump(PrintStream& out) const
48{
49 methodTable(vm())->dumpToStream(this, out);
50}
51
52void JSCell::dumpToStream(const JSCell* cell, PrintStream& out)
53{
54 out.printf("<%p, %s>", cell, cell->className(cell->vm()));
55}
56
57size_t JSCell::estimatedSizeInBytes(VM& vm) const
58{
59 return methodTable(vm)->estimatedSize(const_cast<JSCell*>(this), vm);
60}
61
62size_t JSCell::estimatedSize(JSCell* cell, VM&)
63{
64 return cell->cellSize();
65}
66
67void JSCell::analyzeHeap(JSCell*, HeapAnalyzer&)
68{
69}
70
71bool JSCell::getString(JSGlobalObject* globalObject, String& stringValue) const
72{
73 if (!isString())
74 return false;
75 stringValue = static_cast<const JSString*>(this)->value(globalObject);
76 return true;
77}
78
79String JSCell::getString(JSGlobalObject* globalObject) const
80{
81 return isString() ? static_cast<const JSString*>(this)->value(globalObject) : String();
82}
83
84JSObject* JSCell::getObject()
85{
86 return isObject() ? asObject(this) : 0;
87}
88
89const JSObject* JSCell::getObject() const
90{
91 return isObject() ? static_cast<const JSObject*>(this) : 0;
92}
93
94CallType JSCell::getCallData(JSCell*, CallData& callData)
95{
96 callData.js.functionExecutable = nullptr;
97 callData.js.scope = nullptr;
98 callData.native.function = nullptr;
99 return CallType::None;
100}
101
102ConstructType JSCell::getConstructData(JSCell*, ConstructData& constructData)
103{
104 constructData.js.functionExecutable = nullptr;
105 constructData.js.scope = nullptr;
106 constructData.native.function = nullptr;
107 return ConstructType::None;
108}
109
110bool JSCell::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName identifier, JSValue value, PutPropertySlot& slot)
111{
112 if (cell->isString() || cell->isSymbol() || cell->isBigInt())
113 return JSValue(cell).putToPrimitive(globalObject, identifier, value, slot);
114
115 JSObject* thisObject = cell->toObject(globalObject);
116 return thisObject->methodTable(globalObject->vm())->put(thisObject, globalObject, identifier, value, slot);
117}
118
119bool JSCell::putByIndex(JSCell* cell, JSGlobalObject* globalObject, unsigned identifier, JSValue value, bool shouldThrow)
120{
121 VM& vm = globalObject->vm();
122 if (cell->isString() || cell->isSymbol() || cell->isBigInt()) {
123 PutPropertySlot slot(cell, shouldThrow);
124 return JSValue(cell).putToPrimitive(globalObject, Identifier::from(vm, identifier), value, slot);
125 }
126 JSObject* thisObject = cell->toObject(globalObject);
127 return thisObject->methodTable(vm)->putByIndex(thisObject, globalObject, identifier, value, shouldThrow);
128}
129
130bool JSCell::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName identifier)
131{
132 JSObject* thisObject = cell->toObject(globalObject);
133 return thisObject->methodTable(globalObject->vm())->deleteProperty(thisObject, globalObject, identifier);
134}
135
136bool JSCell::deletePropertyByIndex(JSCell* cell, JSGlobalObject* globalObject, unsigned identifier)
137{
138 JSObject* thisObject = cell->toObject(globalObject);
139 return thisObject->methodTable(globalObject->vm())->deletePropertyByIndex(thisObject, globalObject, identifier);
140}
141
142JSValue JSCell::toThis(JSCell* cell, JSGlobalObject* globalObject, ECMAMode ecmaMode)
143{
144 if (ecmaMode == StrictMode)
145 return cell;
146 return cell->toObject(globalObject);
147}
148
149JSValue JSCell::toPrimitive(JSGlobalObject* globalObject, PreferredPrimitiveType preferredType) const
150{
151 if (isString())
152 return static_cast<const JSString*>(this)->toPrimitive(globalObject, preferredType);
153 if (isSymbol())
154 return static_cast<const Symbol*>(this)->toPrimitive(globalObject, preferredType);
155 if (isBigInt())
156 return static_cast<const JSBigInt*>(this)->toPrimitive(globalObject, preferredType);
157 return static_cast<const JSObject*>(this)->toPrimitive(globalObject, preferredType);
158}
159
160bool JSCell::getPrimitiveNumber(JSGlobalObject* globalObject, double& number, JSValue& value) const
161{
162 if (isString())
163 return static_cast<const JSString*>(this)->getPrimitiveNumber(globalObject, number, value);
164 if (isSymbol())
165 return static_cast<const Symbol*>(this)->getPrimitiveNumber(globalObject, number, value);
166 if (isBigInt())
167 return static_cast<const JSBigInt*>(this)->getPrimitiveNumber(globalObject, number, value);
168 return static_cast<const JSObject*>(this)->getPrimitiveNumber(globalObject, number, value);
169}
170
171double JSCell::toNumber(JSGlobalObject* globalObject) const
172{
173 if (isString())
174 return static_cast<const JSString*>(this)->toNumber(globalObject);
175 if (isSymbol())
176 return static_cast<const Symbol*>(this)->toNumber(globalObject);
177 if (isBigInt())
178 return static_cast<const JSBigInt*>(this)->toNumber(globalObject);
179 return static_cast<const JSObject*>(this)->toNumber(globalObject);
180}
181
182JSObject* JSCell::toObjectSlow(JSGlobalObject* globalObject) const
183{
184 ASSERT(!isObject());
185 if (isString())
186 return static_cast<const JSString*>(this)->toObject(globalObject);
187 if (isBigInt())
188 return static_cast<const JSBigInt*>(this)->toObject(globalObject);
189 ASSERT(isSymbol());
190 return static_cast<const Symbol*>(this)->toObject(globalObject);
191}
192
193void slowValidateCell(JSCell* cell)
194{
195 ASSERT_GC_OBJECT_LOOKS_VALID(cell);
196}
197
198JSValue JSCell::defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType)
199{
200 RELEASE_ASSERT_NOT_REACHED();
201 return jsUndefined();
202}
203
204bool JSCell::getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&)
205{
206 RELEASE_ASSERT_NOT_REACHED();
207 return false;
208}
209
210bool JSCell::getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned, PropertySlot&)
211{
212 RELEASE_ASSERT_NOT_REACHED();
213 return false;
214}
215
216void JSCell::doPutPropertySecurityCheck(JSObject*, JSGlobalObject*, PropertyName, PutPropertySlot&)
217{
218 RELEASE_ASSERT_NOT_REACHED();
219}
220
221void JSCell::getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode)
222{
223 RELEASE_ASSERT_NOT_REACHED();
224}
225
226void JSCell::getOwnNonIndexPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode)
227{
228 RELEASE_ASSERT_NOT_REACHED();
229}
230
231String JSCell::className(const JSObject*, VM&)
232{
233 RELEASE_ASSERT_NOT_REACHED();
234 return String();
235}
236
237String JSCell::toStringName(const JSObject*, JSGlobalObject*)
238{
239 RELEASE_ASSERT_NOT_REACHED();
240 return String();
241}
242
243const char* JSCell::className(VM& vm) const
244{
245 return classInfo(vm)->className;
246}
247
248void JSCell::getPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode)
249{
250 RELEASE_ASSERT_NOT_REACHED();
251}
252
253bool JSCell::customHasInstance(JSObject*, JSGlobalObject*, JSValue)
254{
255 RELEASE_ASSERT_NOT_REACHED();
256 return false;
257}
258
259bool JSCell::defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool)
260{
261 RELEASE_ASSERT_NOT_REACHED();
262 return false;
263}
264
265uint32_t JSCell::getEnumerableLength(JSGlobalObject*, JSObject*)
266{
267 RELEASE_ASSERT_NOT_REACHED();
268 return 0;
269}
270
271void JSCell::getStructurePropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode)
272{
273 RELEASE_ASSERT_NOT_REACHED();
274}
275
276void JSCell::getGenericPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode)
277{
278 RELEASE_ASSERT_NOT_REACHED();
279}
280
281bool JSCell::preventExtensions(JSObject*, JSGlobalObject*)
282{
283 RELEASE_ASSERT_NOT_REACHED();
284}
285
286bool JSCell::isExtensible(JSObject*, JSGlobalObject*)
287{
288 RELEASE_ASSERT_NOT_REACHED();
289}
290
291bool JSCell::setPrototype(JSObject*, JSGlobalObject*, JSValue, bool)
292{
293 RELEASE_ASSERT_NOT_REACHED();
294}
295
296JSValue JSCell::getPrototype(JSObject*, JSGlobalObject*)
297{
298 RELEASE_ASSERT_NOT_REACHED();
299}
300
301void JSCellLock::lockSlow()
302{
303 Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc);
304 IndexingTypeLockAlgorithm::lockSlow(*lock);
305}
306
307void JSCellLock::unlockSlow()
308{
309 Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc);
310 IndexingTypeLockAlgorithm::unlockSlow(*lock);
311}
312
313} // namespace JSC
314