1/*
2 * Copyright (C) 1999-2001 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2003-2018 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::heapSnapshot(JSCell*, HeapSnapshotBuilder&)
68{
69}
70
71bool JSCell::getString(ExecState* exec, String& stringValue) const
72{
73 if (!isString())
74 return false;
75 stringValue = static_cast<const JSString*>(this)->value(exec);
76 return true;
77}
78
79String JSCell::getString(ExecState* exec) const
80{
81 return isString() ? static_cast<const JSString*>(this)->value(exec) : 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, ExecState* exec, PropertyName identifier, JSValue value, PutPropertySlot& slot)
111{
112 if (cell->isString() || cell->isSymbol() || cell->isBigInt())
113 return JSValue(cell).putToPrimitive(exec, identifier, value, slot);
114
115 JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject());
116 return thisObject->methodTable(exec->vm())->put(thisObject, exec, identifier, value, slot);
117}
118
119bool JSCell::putByIndex(JSCell* cell, ExecState* exec, unsigned identifier, JSValue value, bool shouldThrow)
120{
121 if (cell->isString() || cell->isSymbol() || cell->isBigInt()) {
122 PutPropertySlot slot(cell, shouldThrow);
123 return JSValue(cell).putToPrimitive(exec, Identifier::from(exec, identifier), value, slot);
124 }
125 JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject());
126 return thisObject->methodTable(exec->vm())->putByIndex(thisObject, exec, identifier, value, shouldThrow);
127}
128
129bool JSCell::deleteProperty(JSCell* cell, ExecState* exec, PropertyName identifier)
130{
131 JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject());
132 return thisObject->methodTable(exec->vm())->deleteProperty(thisObject, exec, identifier);
133}
134
135bool JSCell::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned identifier)
136{
137 JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject());
138 return thisObject->methodTable(exec->vm())->deletePropertyByIndex(thisObject, exec, identifier);
139}
140
141JSValue JSCell::toThis(JSCell* cell, ExecState* exec, ECMAMode ecmaMode)
142{
143 if (ecmaMode == StrictMode)
144 return cell;
145 return cell->toObject(exec, exec->lexicalGlobalObject());
146}
147
148JSValue JSCell::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
149{
150 if (isString())
151 return static_cast<const JSString*>(this)->toPrimitive(exec, preferredType);
152 if (isSymbol())
153 return static_cast<const Symbol*>(this)->toPrimitive(exec, preferredType);
154 if (isBigInt())
155 return static_cast<const JSBigInt*>(this)->toPrimitive(exec, preferredType);
156 return static_cast<const JSObject*>(this)->toPrimitive(exec, preferredType);
157}
158
159bool JSCell::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) const
160{
161 if (isString())
162 return static_cast<const JSString*>(this)->getPrimitiveNumber(exec, number, value);
163 if (isSymbol())
164 return static_cast<const Symbol*>(this)->getPrimitiveNumber(exec, number, value);
165 if (isBigInt())
166 return static_cast<const JSBigInt*>(this)->getPrimitiveNumber(exec, number, value);
167 return static_cast<const JSObject*>(this)->getPrimitiveNumber(exec, number, value);
168}
169
170double JSCell::toNumber(ExecState* exec) const
171{
172 if (isString())
173 return static_cast<const JSString*>(this)->toNumber(exec);
174 if (isSymbol())
175 return static_cast<const Symbol*>(this)->toNumber(exec);
176 if (isBigInt())
177 return static_cast<const JSBigInt*>(this)->toNumber(exec);
178 return static_cast<const JSObject*>(this)->toNumber(exec);
179}
180
181JSObject* JSCell::toObjectSlow(ExecState* exec, JSGlobalObject* globalObject) const
182{
183 ASSERT(!isObject());
184 if (isString())
185 return static_cast<const JSString*>(this)->toObject(exec, globalObject);
186 if (isBigInt())
187 return static_cast<const JSBigInt*>(this)->toObject(exec, globalObject);
188 ASSERT(isSymbol());
189 return static_cast<const Symbol*>(this)->toObject(exec, globalObject);
190}
191
192void slowValidateCell(JSCell* cell)
193{
194 ASSERT_GC_OBJECT_LOOKS_VALID(cell);
195}
196
197JSValue JSCell::defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType)
198{
199 RELEASE_ASSERT_NOT_REACHED();
200 return jsUndefined();
201}
202
203bool JSCell::getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&)
204{
205 RELEASE_ASSERT_NOT_REACHED();
206 return false;
207}
208
209bool JSCell::getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned, PropertySlot&)
210{
211 RELEASE_ASSERT_NOT_REACHED();
212 return false;
213}
214
215void JSCell::getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
216{
217 RELEASE_ASSERT_NOT_REACHED();
218}
219
220void JSCell::getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
221{
222 RELEASE_ASSERT_NOT_REACHED();
223}
224
225String JSCell::className(const JSObject*, VM&)
226{
227 RELEASE_ASSERT_NOT_REACHED();
228 return String();
229}
230
231String JSCell::toStringName(const JSObject*, ExecState*)
232{
233 RELEASE_ASSERT_NOT_REACHED();
234 return String();
235}
236
237const char* JSCell::className(VM& vm) const
238{
239 return classInfo(vm)->className;
240}
241
242void JSCell::getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
243{
244 RELEASE_ASSERT_NOT_REACHED();
245}
246
247bool JSCell::customHasInstance(JSObject*, ExecState*, JSValue)
248{
249 RELEASE_ASSERT_NOT_REACHED();
250 return false;
251}
252
253bool JSCell::defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool)
254{
255 RELEASE_ASSERT_NOT_REACHED();
256 return false;
257}
258
259uint32_t JSCell::getEnumerableLength(ExecState*, JSObject*)
260{
261 RELEASE_ASSERT_NOT_REACHED();
262 return 0;
263}
264
265void JSCell::getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
266{
267 RELEASE_ASSERT_NOT_REACHED();
268}
269
270void JSCell::getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
271{
272 RELEASE_ASSERT_NOT_REACHED();
273}
274
275bool JSCell::preventExtensions(JSObject*, ExecState*)
276{
277 RELEASE_ASSERT_NOT_REACHED();
278}
279
280bool JSCell::isExtensible(JSObject*, ExecState*)
281{
282 RELEASE_ASSERT_NOT_REACHED();
283}
284
285bool JSCell::setPrototype(JSObject*, ExecState*, JSValue, bool)
286{
287 RELEASE_ASSERT_NOT_REACHED();
288}
289
290JSValue JSCell::getPrototype(JSObject*, ExecState*)
291{
292 RELEASE_ASSERT_NOT_REACHED();
293}
294
295void JSCellLock::lockSlow()
296{
297 Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc);
298 IndexingTypeLockAlgorithm::lockSlow(*lock);
299}
300
301void JSCellLock::unlockSlow()
302{
303 Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc);
304 IndexingTypeLockAlgorithm::unlockSlow(*lock);
305}
306
307} // namespace JSC
308