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 * Copyright (C) 2007 Eric Seidel ([email protected])
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#pragma once
25
26#include "AuxiliaryBarrierInlines.h"
27#include "ButterflyInlines.h"
28#include "Error.h"
29#include "JSObject.h"
30#include "JSTypedArrays.h"
31#include "Lookup.h"
32#include "StructureInlines.h"
33#include "TypedArrayType.h"
34
35namespace JSC {
36
37// Section 7.3.17 of the spec.
38template <typename AddFunction> // Add function should have a type like: (JSValue, RuntimeType) -> bool
39void createListFromArrayLike(JSGlobalObject* globalObject, JSValue arrayLikeValue, RuntimeTypeMask legalTypesFilter, const String& notAnObjectErroMessage, const String& illegalTypeErrorMessage, AddFunction addFunction)
40{
41 VM& vm = getVM(globalObject);
42 auto scope = DECLARE_THROW_SCOPE(vm);
43
44 if (!arrayLikeValue.isObject()) {
45 throwTypeError(globalObject, scope, notAnObjectErroMessage);
46 return;
47 }
48
49 Vector<JSValue> result;
50 JSValue lengthProperty = arrayLikeValue.get(globalObject, vm.propertyNames->length);
51 RETURN_IF_EXCEPTION(scope, void());
52 double lengthAsDouble = lengthProperty.toLength(globalObject);
53 RETURN_IF_EXCEPTION(scope, void());
54 RELEASE_ASSERT(lengthAsDouble >= 0.0 && lengthAsDouble == std::trunc(lengthAsDouble));
55 uint64_t length = static_cast<uint64_t>(lengthAsDouble);
56 for (uint64_t index = 0; index < length; index++) {
57 JSValue next = arrayLikeValue.get(globalObject, index);
58 RETURN_IF_EXCEPTION(scope, void());
59
60 RuntimeType type = runtimeTypeForValue(vm, next);
61 if (!(type & legalTypesFilter)) {
62 throwTypeError(globalObject, scope, illegalTypeErrorMessage);
63 return;
64 }
65
66 bool exitEarly = addFunction(next, type);
67 if (exitEarly)
68 return;
69 }
70}
71
72ALWAYS_INLINE bool JSObject::canPerformFastPutInlineExcludingProto(VM& vm)
73{
74 // Check if there are any setters or getters in the prototype chain
75 JSValue prototype;
76 JSObject* obj = this;
77 while (true) {
78 MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
79 if (obj->structure(vm)->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || obj->methodTable(vm)->getPrototype != defaultGetPrototype)
80 return false;
81
82 prototype = obj->getPrototypeDirect(vm);
83 if (prototype.isNull())
84 return true;
85
86 obj = asObject(prototype);
87 }
88
89 ASSERT_NOT_REACHED();
90}
91
92ALWAYS_INLINE bool JSObject::canPerformFastPutInline(VM& vm, PropertyName propertyName)
93{
94 if (UNLIKELY(propertyName == vm.propertyNames->underscoreProto))
95 return false;
96 return canPerformFastPutInlineExcludingProto(vm);
97}
98
99template<typename CallbackWhenNoException>
100ALWAYS_INLINE typename std::result_of<CallbackWhenNoException(bool, PropertySlot&)>::type JSObject::getPropertySlot(JSGlobalObject* globalObject, PropertyName propertyName, CallbackWhenNoException callback) const
101{
102 PropertySlot slot(this, PropertySlot::InternalMethodType::Get);
103 return getPropertySlot(globalObject, propertyName, slot, callback);
104}
105
106template<typename CallbackWhenNoException>
107ALWAYS_INLINE typename std::result_of<CallbackWhenNoException(bool, PropertySlot&)>::type JSObject::getPropertySlot(JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot, CallbackWhenNoException callback) const
108{
109 VM& vm = getVM(globalObject);
110 auto scope = DECLARE_THROW_SCOPE(vm);
111 bool found = const_cast<JSObject*>(this)->getPropertySlot(globalObject, propertyName, slot);
112 RETURN_IF_EXCEPTION(scope, { });
113 RELEASE_AND_RETURN(scope, callback(found, slot));
114}
115
116ALWAYS_INLINE bool JSObject::getPropertySlot(JSGlobalObject* globalObject, unsigned propertyName, PropertySlot& slot)
117{
118 VM& vm = getVM(globalObject);
119 auto scope = DECLARE_THROW_SCOPE(vm);
120 auto& structureIDTable = vm.heap.structureIDTable();
121 JSObject* object = this;
122 MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
123 while (true) {
124 Structure* structure = structureIDTable.get(object->structureID());
125 bool hasSlot = structure->classInfo()->methodTable.getOwnPropertySlotByIndex(object, globalObject, propertyName, slot);
126 RETURN_IF_EXCEPTION(scope, false);
127 if (hasSlot)
128 return true;
129 if (object->type() == ProxyObjectType && slot.internalMethodType() == PropertySlot::InternalMethodType::HasProperty)
130 return false;
131 JSValue prototype;
132 if (LIKELY(structure->classInfo()->methodTable.getPrototype == defaultGetPrototype || slot.internalMethodType() == PropertySlot::InternalMethodType::VMInquiry))
133 prototype = object->getPrototypeDirect(vm);
134 else {
135 prototype = object->getPrototype(vm, globalObject);
136 RETURN_IF_EXCEPTION(scope, false);
137 }
138 if (!prototype.isObject())
139 return false;
140 object = asObject(prototype);
141 }
142}
143
144ALWAYS_INLINE bool JSObject::getNonIndexPropertySlot(JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot)
145{
146 // This method only supports non-index PropertyNames.
147 ASSERT(!parseIndex(propertyName));
148
149 VM& vm = getVM(globalObject);
150 auto scope = DECLARE_THROW_SCOPE(vm);
151 auto& structureIDTable = vm.heap.structureIDTable();
152 JSObject* object = this;
153 MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
154 while (true) {
155 Structure* structure = structureIDTable.get(object->structureID());
156 if (LIKELY(!TypeInfo::overridesGetOwnPropertySlot(object->inlineTypeFlags()))) {
157 if (object->getOwnNonIndexPropertySlot(vm, structure, propertyName, slot))
158 return true;
159 } else {
160 bool hasSlot = structure->classInfo()->methodTable.getOwnPropertySlot(object, globalObject, propertyName, slot);
161 RETURN_IF_EXCEPTION(scope, false);
162 if (hasSlot)
163 return true;
164 if (object->type() == ProxyObjectType && slot.internalMethodType() == PropertySlot::InternalMethodType::HasProperty)
165 return false;
166 }
167 JSValue prototype;
168 if (LIKELY(structure->classInfo()->methodTable.getPrototype == defaultGetPrototype || slot.internalMethodType() == PropertySlot::InternalMethodType::VMInquiry))
169 prototype = object->getPrototypeDirect(vm);
170 else {
171 prototype = object->getPrototype(vm, globalObject);
172 RETURN_IF_EXCEPTION(scope, false);
173 }
174 if (!prototype.isObject())
175 return false;
176 object = asObject(prototype);
177 }
178}
179
180inline bool JSObject::getOwnPropertySlotInline(JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot)
181{
182 VM& vm = getVM(globalObject);
183 if (UNLIKELY(TypeInfo::overridesGetOwnPropertySlot(inlineTypeFlags())))
184 return methodTable(vm)->getOwnPropertySlot(this, globalObject, propertyName, slot);
185 return JSObject::getOwnPropertySlot(this, globalObject, propertyName, slot);
186}
187
188inline bool JSObject::mayInterceptIndexedAccesses(VM& vm)
189{
190 return structure(vm)->mayInterceptIndexedAccesses();
191}
192
193inline void JSObject::putDirectWithoutTransition(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
194{
195 ASSERT(!value.isGetterSetter() && !(attributes & PropertyAttribute::Accessor));
196 ASSERT(!value.isCustomGetterSetter());
197 StructureID structureID = this->structureID();
198 Structure* structure = vm.heap.structureIDTable().get(structureID);
199 PropertyOffset offset = prepareToPutDirectWithoutTransition(vm, propertyName, attributes, structureID, structure);
200 putDirect(vm, offset, value);
201 if (attributes & PropertyAttribute::ReadOnly)
202 structure->setContainsReadOnlyProperties();
203}
204
205ALWAYS_INLINE PropertyOffset JSObject::prepareToPutDirectWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes, StructureID structureID, Structure* structure)
206{
207 unsigned oldOutOfLineCapacity = structure->outOfLineCapacity();
208 PropertyOffset result;
209 structure->addPropertyWithoutTransition(
210 vm, propertyName, attributes,
211 [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newLastOffset) {
212 unsigned newOutOfLineCapacity = Structure::outOfLineCapacity(newLastOffset);
213 if (newOutOfLineCapacity != oldOutOfLineCapacity) {
214 Butterfly* butterfly = allocateMoreOutOfLineStorage(vm, oldOutOfLineCapacity, newOutOfLineCapacity);
215 nukeStructureAndSetButterfly(vm, structureID, butterfly);
216 structure->setLastOffset(newLastOffset);
217 WTF::storeStoreFence();
218 setStructureIDDirectly(structureID);
219 } else
220 structure->setLastOffset(newLastOffset);
221
222 // This assertion verifies that the concurrent GC won't read garbage if the concurrentGC
223 // is running at the same time we put without transitioning.
224 ASSERT(!getDirect(offset) || !JSValue::encode(getDirect(offset)));
225 result = offset;
226 });
227 return result;
228}
229
230// ECMA 8.6.2.2
231ALWAYS_INLINE bool JSObject::putInlineForJSObject(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
232{
233 VM& vm = getVM(globalObject);
234 auto scope = DECLARE_THROW_SCOPE(vm);
235
236 JSObject* thisObject = jsCast<JSObject*>(cell);
237 ASSERT(value);
238 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
239
240 if (UNLIKELY(isThisValueAltered(slot, thisObject)))
241 RELEASE_AND_RETURN(scope, ordinarySetSlow(globalObject, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode()));
242
243 // Try indexed put first. This is required for correctness, since loads on property names that appear like
244 // valid indices will never look in the named property storage.
245 if (Optional<uint32_t> index = parseIndex(propertyName))
246 RELEASE_AND_RETURN(scope, putByIndex(thisObject, globalObject, index.value(), value, slot.isStrictMode()));
247
248 if (thisObject->canPerformFastPutInline(vm, propertyName)) {
249 ASSERT(!thisObject->prototypeChainMayInterceptStoreTo(vm, propertyName));
250 if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot))
251 return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
252 return true;
253 }
254
255 RELEASE_AND_RETURN(scope, thisObject->putInlineSlow(globalObject, propertyName, value, slot));
256}
257
258// HasOwnProperty(O, P) from section 7.3.11 in the spec.
259// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasownproperty
260ALWAYS_INLINE bool JSObject::hasOwnProperty(JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) const
261{
262 VM& vm = getVM(globalObject);
263 ASSERT(slot.internalMethodType() == PropertySlot::InternalMethodType::GetOwnProperty);
264 if (LIKELY(const_cast<JSObject*>(this)->methodTable(vm)->getOwnPropertySlot == JSObject::getOwnPropertySlot))
265 return JSObject::getOwnPropertySlot(const_cast<JSObject*>(this), globalObject, propertyName, slot);
266 return const_cast<JSObject*>(this)->methodTable(vm)->getOwnPropertySlot(const_cast<JSObject*>(this), globalObject, propertyName, slot);
267}
268
269ALWAYS_INLINE bool JSObject::hasOwnProperty(JSGlobalObject* globalObject, PropertyName propertyName) const
270{
271 PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
272 return hasOwnProperty(globalObject, propertyName, slot);
273}
274
275ALWAYS_INLINE bool JSObject::hasOwnProperty(JSGlobalObject* globalObject, unsigned propertyName) const
276{
277 PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
278 return const_cast<JSObject*>(this)->methodTable(getVM(globalObject))->getOwnPropertySlotByIndex(const_cast<JSObject*>(this), globalObject, propertyName, slot);
279}
280
281template<JSObject::PutMode mode>
282ALWAYS_INLINE bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
283{
284 ASSERT(value);
285 ASSERT(value.isGetterSetter() == !!(attributes & PropertyAttribute::Accessor));
286 ASSERT(value.isCustomGetterSetter() == !!(attributes & PropertyAttribute::CustomAccessorOrValue));
287 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
288 ASSERT(!parseIndex(propertyName));
289
290 StructureID structureID = this->structureID();
291 Structure* structure = vm.heap.structureIDTable().get(structureID);
292 if (structure->isDictionary()) {
293 ASSERT(!isCopyOnWrite(indexingMode()));
294
295 unsigned currentAttributes;
296 PropertyOffset offset = structure->get(vm, propertyName, currentAttributes);
297 if (offset != invalidOffset) {
298 if ((mode == PutModePut) && currentAttributes & PropertyAttribute::ReadOnly)
299 return false;
300
301 putDirect(vm, offset, value);
302 structure->didReplaceProperty(offset);
303
304 if ((attributes & PropertyAttribute::Accessor) != (currentAttributes & PropertyAttribute::Accessor) || (attributes & PropertyAttribute::CustomAccessorOrValue) != (currentAttributes & PropertyAttribute::CustomAccessorOrValue)) {
305 ASSERT(!(attributes & PropertyAttribute::ReadOnly));
306 setStructure(vm, Structure::attributeChangeTransition(vm, structure, propertyName, attributes));
307 } else
308 slot.setExistingProperty(this, offset);
309
310 return true;
311 }
312
313 if ((mode == PutModePut) && !isStructureExtensible(vm))
314 return false;
315
316 offset = prepareToPutDirectWithoutTransition(vm, propertyName, attributes, structureID, structure);
317 validateOffset(offset);
318 putDirect(vm, offset, value);
319 slot.setNewProperty(this, offset);
320 if (attributes & PropertyAttribute::ReadOnly)
321 this->structure(vm)->setContainsReadOnlyProperties();
322 return true;
323 }
324
325 PropertyOffset offset;
326 size_t currentCapacity = this->structure(vm)->outOfLineCapacity();
327 Structure* newStructure = Structure::addPropertyTransitionToExistingStructure(
328 structure, propertyName, attributes, offset);
329 if (newStructure) {
330 Butterfly* newButterfly = butterfly();
331 if (currentCapacity != newStructure->outOfLineCapacity()) {
332 ASSERT(newStructure != this->structure(vm));
333 newButterfly = allocateMoreOutOfLineStorage(vm, currentCapacity, newStructure->outOfLineCapacity());
334 nukeStructureAndSetButterfly(vm, structureID, newButterfly);
335 }
336
337 validateOffset(offset);
338 ASSERT(newStructure->isValidOffset(offset));
339
340 // This assertion verifies that the concurrent GC won't read garbage if the concurrentGC
341 // is running at the same time we put without transitioning.
342 ASSERT(!getDirect(offset) || !JSValue::encode(getDirect(offset)));
343 putDirect(vm, offset, value);
344 setStructure(vm, newStructure);
345 slot.setNewProperty(this, offset);
346 return true;
347 }
348
349 unsigned currentAttributes;
350 offset = structure->get(vm, propertyName, currentAttributes);
351 if (offset != invalidOffset) {
352 if ((mode == PutModePut) && currentAttributes & PropertyAttribute::ReadOnly)
353 return false;
354
355 structure->didReplaceProperty(offset);
356 putDirect(vm, offset, value);
357
358 if ((attributes & PropertyAttribute::Accessor) != (currentAttributes & PropertyAttribute::Accessor) || (attributes & PropertyAttribute::CustomAccessorOrValue) != (currentAttributes & PropertyAttribute::CustomAccessorOrValue)) {
359 ASSERT(!(attributes & PropertyAttribute::ReadOnly));
360 setStructure(vm, Structure::attributeChangeTransition(vm, structure, propertyName, attributes));
361 } else
362 slot.setExistingProperty(this, offset);
363
364 return true;
365 }
366
367 if ((mode == PutModePut) && !isStructureExtensible(vm))
368 return false;
369
370 // We want the structure transition watchpoint to fire after this object has switched
371 // structure. This allows adaptive watchpoints to observe if the new structure is the one
372 // we want.
373 DeferredStructureTransitionWatchpointFire deferredWatchpointFire(vm, structure);
374
375 newStructure = Structure::addNewPropertyTransition(
376 vm, structure, propertyName, attributes, offset, slot.context(), &deferredWatchpointFire);
377
378 validateOffset(offset);
379 ASSERT(newStructure->isValidOffset(offset));
380 size_t oldCapacity = structure->outOfLineCapacity();
381 size_t newCapacity = newStructure->outOfLineCapacity();
382 ASSERT(oldCapacity <= newCapacity);
383 if (oldCapacity != newCapacity) {
384 Butterfly* newButterfly = allocateMoreOutOfLineStorage(vm, oldCapacity, newCapacity);
385 nukeStructureAndSetButterfly(vm, structureID, newButterfly);
386 }
387
388 // This assertion verifies that the concurrent GC won't read garbage if the concurrentGC
389 // is running at the same time we put without transitioning.
390 ASSERT(!getDirect(offset) || !JSValue::encode(getDirect(offset)));
391 putDirect(vm, offset, value);
392 setStructure(vm, newStructure);
393 slot.setNewProperty(this, offset);
394 if (attributes & PropertyAttribute::ReadOnly)
395 newStructure->setContainsReadOnlyProperties();
396 return true;
397}
398
399inline bool JSObject::mayBePrototype() const
400{
401 return perCellBit();
402}
403
404inline void JSObject::didBecomePrototype()
405{
406 setPerCellBit(true);
407}
408
409inline bool JSObject::canGetIndexQuicklyForTypedArray(unsigned i) const
410{
411 switch (type()) {
412#define CASE_TYPED_ARRAY_TYPE(name) \
413 case name ## ArrayType :\
414 return jsCast<const JS ## name ## Array *>(this)->canGetIndexQuickly(i);
415 FOR_EACH_TYPED_ARRAY_TYPE_EXCLUDING_DATA_VIEW(CASE_TYPED_ARRAY_TYPE)
416#undef CASE_TYPED_ARRAY_TYPE
417 default:
418 return false;
419 }
420}
421
422inline bool JSObject::canSetIndexQuicklyForTypedArray(unsigned i, JSValue value) const
423{
424 switch (type()) {
425#define CASE_TYPED_ARRAY_TYPE(name) \
426 case name ## ArrayType :\
427 return jsCast<const JS ## name ## Array *>(this)->canSetIndexQuickly(i, value);
428 FOR_EACH_TYPED_ARRAY_TYPE_EXCLUDING_DATA_VIEW(CASE_TYPED_ARRAY_TYPE)
429#undef CASE_TYPED_ARRAY_TYPE
430 default:
431 return false;
432 }
433}
434
435inline JSValue JSObject::getIndexQuicklyForTypedArray(unsigned i) const
436{
437 switch (type()) {
438#define CASE_TYPED_ARRAY_TYPE(name) \
439 case name ## ArrayType : {\
440 auto* typedArray = jsCast<const JS ## name ## Array *>(this);\
441 RELEASE_ASSERT(typedArray->canGetIndexQuickly(i));\
442 return typedArray->getIndexQuickly(i);\
443 }
444 FOR_EACH_TYPED_ARRAY_TYPE_EXCLUDING_DATA_VIEW(CASE_TYPED_ARRAY_TYPE)
445#undef CASE_TYPED_ARRAY_TYPE
446 default:
447 RELEASE_ASSERT_NOT_REACHED();
448 return JSValue();
449 }
450}
451
452inline void JSObject::setIndexQuicklyForTypedArray(unsigned i, JSValue value)
453{
454 switch (type()) {
455#define CASE_TYPED_ARRAY_TYPE(name) \
456 case name ## ArrayType : {\
457 auto* typedArray = jsCast<JS ## name ## Array *>(this);\
458 RELEASE_ASSERT(typedArray->canSetIndexQuickly(i, value));\
459 typedArray->setIndexQuickly(i, value);\
460 break;\
461 }
462 FOR_EACH_TYPED_ARRAY_TYPE_EXCLUDING_DATA_VIEW(CASE_TYPED_ARRAY_TYPE)
463#undef CASE_TYPED_ARRAY_TYPE
464 default:
465 RELEASE_ASSERT_NOT_REACHED();
466 return;
467 }
468}
469
470inline void JSObject::validatePutOwnDataProperty(VM& vm, PropertyName propertyName, JSValue value)
471{
472#if !ASSERT_DISABLED
473 ASSERT(value);
474 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
475 unsigned attributes;
476 PropertyOffset offset = structure(vm)->get(vm, propertyName, attributes);
477 if (isValidOffset(offset))
478 ASSERT(!(attributes & (PropertyAttribute::Accessor | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly)));
479 else if (TypeInfo::hasStaticPropertyTable(inlineTypeFlags())) {
480 if (auto entry = findPropertyHashEntry(vm, propertyName))
481 ASSERT(!(entry->value->attributes() & (PropertyAttribute::Accessor | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly)));
482 }
483#else
484 UNUSED_PARAM(vm);
485 UNUSED_PARAM(propertyName);
486 UNUSED_PARAM(value);
487#endif
488}
489
490inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
491{
492 validatePutOwnDataProperty(vm, propertyName, value);
493 return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot);
494}
495
496inline bool JSObject::putOwnDataPropertyMayBeIndex(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
497{
498 VM& vm = getVM(globalObject);
499 validatePutOwnDataProperty(vm, propertyName, value);
500 if (Optional<uint32_t> index = parseIndex(propertyName))
501 return putDirectIndex(globalObject, index.value(), value, 0, PutDirectIndexLikePutDirect);
502
503 return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot);
504}
505
506} // namespace JSC
507