9f124d3567bd407bad8362a622372d2f58bf8712
[WebKit-https.git] / Source / JavaScriptCore / runtime / ProxyObject.cpp
1 /*
2  * Copyright (C) 2016 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "ProxyObject.h"
28
29 #include "Error.h"
30 #include "IdentifierInlines.h"
31 #include "JSCJSValueInlines.h"
32 #include "JSCellInlines.h"
33 #include "ObjectConstructor.h"
34 #include "SlotVisitorInlines.h"
35 #include "StructureInlines.h"
36
37 namespace JSC {
38
39 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ProxyObject);
40
41 const ClassInfo ProxyObject::s_info = { "ProxyObject", &Base::s_info, 0, CREATE_METHOD_TABLE(ProxyObject) };
42
43 ProxyObject::ProxyObject(VM& vm, Structure* structure)
44     : Base(vm, structure)
45 {
46 }
47
48 Structure* ProxyObject::structureForTarget(JSGlobalObject* globalObject, JSValue target)
49 {
50     if (!target.isObject())
51         return globalObject->proxyObjectStructure();
52
53     JSObject* targetAsObject = jsCast<JSObject*>(target);
54     CallData ignoredCallData;
55     bool isCallable = targetAsObject->methodTable()->getCallData(targetAsObject, ignoredCallData) != CallType::None;
56     return isCallable ? globalObject->callableProxyObjectStructure() : globalObject->proxyObjectStructure();
57 }
58
59 void ProxyObject::finishCreation(VM& vm, ExecState* exec, JSValue target, JSValue handler)
60 {
61     Base::finishCreation(vm);
62     if (!target.isObject()) {
63         throwTypeError(exec, ASCIILiteral("A Proxy's 'target' should be an Object"));
64         return;
65     }
66     if (ProxyObject* targetAsProxy = jsDynamicCast<ProxyObject*>(target)) {
67         if (targetAsProxy->handler().isNull()) {
68             throwTypeError(exec, ASCIILiteral("If a Proxy's handler is another Proxy object, the other Proxy should not have been revoked"));
69             return;
70         }
71     }
72     if (!handler.isObject()) {
73         throwTypeError(exec, ASCIILiteral("A Proxy's 'handler' should be an Object"));
74         return;
75     }
76
77     JSObject* targetAsObject = jsCast<JSObject*>(target);
78
79     CallData ignoredCallData;
80     m_isCallable = targetAsObject->methodTable(vm)->getCallData(targetAsObject, ignoredCallData) != CallType::None;
81     if (m_isCallable) {
82         TypeInfo info = structure(vm)->typeInfo();
83         RELEASE_ASSERT(info.implementsHasInstance() && info.implementsDefaultHasInstance());
84     }
85
86     ConstructData ignoredConstructData;
87     m_isConstructible = jsCast<JSObject*>(target)->methodTable(vm)->getConstructData(jsCast<JSObject*>(target), ignoredConstructData) != ConstructType::None;
88
89     m_target.set(vm, this, targetAsObject);
90     m_handler.set(vm, this, handler);
91 }
92
93 static const char* s_proxyAlreadyRevokedErrorMessage = "Proxy has already been revoked. No more operations are allowed to be performed on it";
94
95 static EncodedJSValue performProxyGet(ExecState* exec, EncodedJSValue thisValue, PropertyName propertyName)
96 {
97     VM& vm = exec->vm();
98     if (!vm.isSafeToRecurse()) {
99         throwStackOverflowError(exec);
100         return JSValue::encode(JSValue());
101     }
102
103     JSObject* thisObject = jsCast<JSObject*>(JSValue::decode(thisValue)); // This might be a value where somewhere in __proto__ chain lives a ProxyObject.
104     JSObject* proxyObjectAsObject = thisObject;
105     // FIXME: make it so that custom getters take both the |this| value and the slotBase (property holder).
106     // https://bugs.webkit.org/show_bug.cgi?id=154320
107     while (true) {
108         if (LIKELY(proxyObjectAsObject->type() == ProxyObjectType))
109             break;
110
111         JSValue prototype = proxyObjectAsObject->getPrototypeDirect();
112         RELEASE_ASSERT(prototype.isObject());
113         proxyObjectAsObject = asObject(prototype);
114     }
115
116     ProxyObject* proxyObject = jsCast<ProxyObject*>(proxyObjectAsObject);
117     JSObject* target = proxyObject->target();
118
119     if (propertyName == vm.propertyNames->underscoreProto)
120         return JSValue::encode(proxyObject->performGetPrototype(exec));
121
122     auto performDefaultGet = [&] {
123         return JSValue::encode(target->get(exec, propertyName));
124     };
125
126     if (vm.propertyNames->isPrivateName(Identifier::fromUid(&vm, propertyName.uid())))
127         return performDefaultGet();
128
129     JSValue handlerValue = proxyObject->handler();
130     if (handlerValue.isNull())
131         return throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
132
133     JSObject* handler = jsCast<JSObject*>(handlerValue);
134     CallData callData;
135     CallType callType;
136     JSValue getHandler = handler->getMethod(exec, callData, callType, vm.propertyNames->get, ASCIILiteral("'get' property of a Proxy's handler object should be callable"));
137     if (exec->hadException())
138         return JSValue::encode(jsUndefined());
139
140     if (getHandler.isUndefined())
141         return performDefaultGet();
142
143     MarkedArgumentBuffer arguments;
144     arguments.append(target);
145     arguments.append(identifierToSafePublicJSValue(vm, Identifier::fromUid(&vm, propertyName.uid())));
146     arguments.append(thisObject);
147     JSValue trapResult = call(exec, getHandler, callType, callData, handler, arguments);
148     if (exec->hadException())
149         return JSValue::encode(jsUndefined());
150
151     PropertyDescriptor descriptor;
152     if (target->getOwnPropertyDescriptor(exec, propertyName, descriptor)) {
153         if (descriptor.isDataDescriptor() && !descriptor.configurable() && !descriptor.writable()) {
154             if (!sameValue(exec, descriptor.value(), trapResult))
155                 return throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'get' result of a non-configurable and non-writable property should be the same value as the target's property"));
156         } else if (descriptor.isAccessorDescriptor() && !descriptor.configurable() && descriptor.getter().isUndefined()) {
157             if (!trapResult.isUndefined())
158                 return throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'get' result of a non-configurable accessor property without a getter should be undefined"));
159         }
160     }
161
162     if (exec->hadException())
163         return JSValue::encode(jsUndefined());
164
165     return JSValue::encode(trapResult);
166 }
167
168 bool ProxyObject::performInternalMethodGetOwnProperty(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
169 {
170     VM& vm = exec->vm();
171     JSObject* target = this->target();
172
173     auto performDefaultGetOwnProperty = [&] {
174         return target->methodTable(vm)->getOwnPropertySlot(target, exec, propertyName, slot);
175     };
176
177     if (vm.propertyNames->isPrivateName(Identifier::fromUid(&vm, propertyName.uid())))
178         return performDefaultGetOwnProperty();
179
180     JSValue handlerValue = this->handler();
181     if (handlerValue.isNull()) {
182         throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
183         return false;
184     }
185
186     JSObject* handler = jsCast<JSObject*>(handlerValue);
187     CallData callData;
188     CallType callType;
189     JSValue getOwnPropertyDescriptorMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "getOwnPropertyDescriptor"), ASCIILiteral("'getOwnPropertyDescriptor' property of a Proxy's handler should be callable"));
190     if (exec->hadException())
191         return false;
192     if (getOwnPropertyDescriptorMethod.isUndefined())
193         return performDefaultGetOwnProperty();
194
195     MarkedArgumentBuffer arguments;
196     arguments.append(target);
197     arguments.append(identifierToSafePublicJSValue(vm, Identifier::fromUid(&vm, propertyName.uid())));
198     JSValue trapResult = call(exec, getOwnPropertyDescriptorMethod, callType, callData, handler, arguments);
199     if (exec->hadException())
200         return false;
201
202     if (!trapResult.isUndefined() && !trapResult.isObject()) {
203         throwVMTypeError(exec, ASCIILiteral("result of 'getOwnPropertyDescriptor' call should either be an Object or undefined"));
204         return false;
205     }
206
207     PropertyDescriptor targetPropertyDescriptor;
208     bool isTargetPropertyDescriptorDefined = target->getOwnPropertyDescriptor(exec, propertyName, targetPropertyDescriptor);
209     if (exec->hadException())
210         return false;
211
212     if (trapResult.isUndefined()) {
213         if (!isTargetPropertyDescriptorDefined)
214             return false;
215         if (!targetPropertyDescriptor.configurable()) {
216             throwVMTypeError(exec, ASCIILiteral("When the result of 'getOwnPropertyDescriptor' is undefined the target must be configurable"));
217             return false;
218         }
219         // FIXME: this doesn't work if 'target' is another Proxy. We don't have isExtensible implemented in a way that fits w/ Proxys.
220         // https://bugs.webkit.org/show_bug.cgi?id=154375
221         bool isExtensible = target->isExtensible(exec);
222         if (exec->hadException())
223             return false;
224         if (!isExtensible) {
225             // FIXME: Come up with a test for this error. I'm not sure how to because
226             // Object.seal(o) will make all fields [[Configurable]] false.
227             // https://bugs.webkit.org/show_bug.cgi?id=154376
228             throwVMTypeError(exec, ASCIILiteral("When 'getOwnPropertyDescriptor' returns undefined, the 'target' of a Proxy should be extensible"));
229             return false;
230         }
231
232         return false;
233     }
234
235     bool isExtensible = target->isExtensible(exec);
236     if (exec->hadException())
237         return false;
238     PropertyDescriptor trapResultAsDescriptor;
239     toPropertyDescriptor(exec, trapResult, trapResultAsDescriptor);
240     if (exec->hadException())
241         return false;
242     bool throwException = false;
243     bool valid = validateAndApplyPropertyDescriptor(exec, nullptr, propertyName, isExtensible,
244         trapResultAsDescriptor, isTargetPropertyDescriptorDefined, targetPropertyDescriptor, throwException);
245     if (!valid) {
246         throwVMTypeError(exec, ASCIILiteral("Result from 'getOwnPropertyDescriptor' fails the IsCompatiblePropertyDescriptor test"));
247         return false;
248     }
249
250     if (!trapResultAsDescriptor.configurable()) {
251         if (!isTargetPropertyDescriptorDefined || targetPropertyDescriptor.configurable()) {
252             throwVMTypeError(exec, ASCIILiteral("Result from 'getOwnPropertyDescriptor' can't be non-configurable when the 'target' doesn't have it as an own property or if it is a configurable own property on 'target'"));
253             return false;
254         }
255     }
256
257     if (trapResultAsDescriptor.isAccessorDescriptor()) {
258         GetterSetter* getterSetter = trapResultAsDescriptor.slowGetterSetter(exec);
259         if (exec->hadException())
260             return false;
261         slot.setGetterSlot(this, trapResultAsDescriptor.attributes(), getterSetter);
262     } else if (trapResultAsDescriptor.isDataDescriptor())
263         slot.setValue(this, trapResultAsDescriptor.attributes(), trapResultAsDescriptor.value());
264     else
265         slot.setValue(this, trapResultAsDescriptor.attributes(), jsUndefined()); // We use undefined because it's the default value in object properties.
266
267     return true;
268 }
269
270 bool ProxyObject::performHasProperty(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
271 {
272     VM& vm = exec->vm();
273     JSObject* target = this->target();
274     slot.setValue(this, None, jsUndefined()); // Nobody should rely on our value, but be safe and protect against any bad actors reading our value.
275
276     auto performDefaultHasProperty = [&] {
277         return target->methodTable(vm)->getOwnPropertySlot(target, exec, propertyName, slot);
278     };
279
280     if (vm.propertyNames->isPrivateName(Identifier::fromUid(&vm, propertyName.uid())))
281         return performDefaultHasProperty();
282
283     JSValue handlerValue = this->handler();
284     if (handlerValue.isNull()) {
285         throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
286         return false;
287     }
288
289     JSObject* handler = jsCast<JSObject*>(handlerValue);
290     CallData callData;
291     CallType callType;
292     JSValue hasMethod = handler->getMethod(exec, callData, callType, vm.propertyNames->has, ASCIILiteral("'has' property of a Proxy's handler should be callable"));
293     if (exec->hadException())
294         return false;
295     if (hasMethod.isUndefined())
296         return performDefaultHasProperty();
297
298     MarkedArgumentBuffer arguments;
299     arguments.append(target);
300     arguments.append(identifierToSafePublicJSValue(vm, Identifier::fromUid(&vm, propertyName.uid())));
301     JSValue trapResult = call(exec, hasMethod, callType, callData, handler, arguments);
302     if (exec->hadException())
303         return false;
304
305     bool trapResultAsBool = trapResult.toBoolean(exec);
306     if (exec->hadException())
307         return false;
308
309     if (!trapResultAsBool) {
310         PropertyDescriptor descriptor;
311         bool isPropertyDescriptorDefined = target->getOwnPropertyDescriptor(exec, propertyName, descriptor); 
312         if (exec->hadException())
313             return false;
314         if (isPropertyDescriptorDefined) {
315             if (!descriptor.configurable()) {
316                 throwVMTypeError(exec, ASCIILiteral("Proxy 'has' must return 'true' for non-configurable properties"));
317                 return false;
318             }
319             bool isExtensible = target->isExtensible(exec);
320             if (exec->hadException())
321                 return false;
322             if (!isExtensible) {
323                 throwVMTypeError(exec, ASCIILiteral("Proxy 'has' must return 'true' for a non-extensible 'target' object with a configurable property"));
324                 return false;
325             }
326         }
327     }
328
329     return trapResultAsBool;
330 }
331
332 bool ProxyObject::getOwnPropertySlotCommon(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
333 {
334     slot.disableCaching();
335     if (slot.internalMethodType() != PropertySlot::InternalMethodType::VMInquiry)
336         slot.setIsTaintedByProxy();
337     switch (slot.internalMethodType()) {
338     case PropertySlot::InternalMethodType::Get:
339         slot.setCustom(this, CustomAccessor, performProxyGet);
340         return true;
341     case PropertySlot::InternalMethodType::GetOwnProperty:
342         return performInternalMethodGetOwnProperty(exec, propertyName, slot);
343     case PropertySlot::InternalMethodType::HasProperty:
344         return performHasProperty(exec, propertyName, slot);
345     default:
346         return false;
347     }
348
349     RELEASE_ASSERT_NOT_REACHED();
350     return false;
351 }
352
353 bool ProxyObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
354 {
355     ProxyObject* thisObject = jsCast<ProxyObject*>(object);
356     return thisObject->getOwnPropertySlotCommon(exec, propertyName, slot);
357 }
358
359 bool ProxyObject::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot)
360 {
361     ProxyObject* thisObject = jsCast<ProxyObject*>(object);
362     Identifier ident = Identifier::from(exec, propertyName); 
363     return thisObject->getOwnPropertySlotCommon(exec, ident.impl(), slot);
364 }
365
366 template <typename PerformDefaultPutFunction>
367 bool ProxyObject::performPut(ExecState* exec, JSValue putValue, JSValue thisValue, PropertyName propertyName, PerformDefaultPutFunction performDefaultPut)
368 {
369     VM& vm = exec->vm();
370     if (!vm.isSafeToRecurse()) {
371         throwStackOverflowError(exec);
372         return false;
373     }
374
375     if (vm.propertyNames->isPrivateName(Identifier::fromUid(&vm, propertyName.uid())))
376         return performDefaultPut();
377
378     JSValue handlerValue = this->handler();
379     if (handlerValue.isNull()) {
380         throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
381         return false;
382     }
383
384     JSObject* handler = jsCast<JSObject*>(handlerValue);
385     CallData callData;
386     CallType callType;
387     JSValue setMethod = handler->getMethod(exec, callData, callType, vm.propertyNames->set, ASCIILiteral("'set' property of a Proxy's handler should be callable"));
388     if (exec->hadException())
389         return false;
390     JSObject* target = this->target();
391     if (setMethod.isUndefined())
392         return performDefaultPut();
393
394     MarkedArgumentBuffer arguments;
395     arguments.append(target);
396     arguments.append(identifierToSafePublicJSValue(vm, Identifier::fromUid(&vm, propertyName.uid())));
397     arguments.append(putValue);
398     arguments.append(thisValue);
399     JSValue trapResult = call(exec, setMethod, callType, callData, handler, arguments);
400     if (exec->hadException())
401         return false;
402     bool trapResultAsBool = trapResult.toBoolean(exec);
403     if (exec->hadException())
404         return false;
405     if (!trapResultAsBool)
406         return false;
407
408     PropertyDescriptor descriptor;
409     if (target->getOwnPropertyDescriptor(exec, propertyName, descriptor)) {
410         if (descriptor.isDataDescriptor() && !descriptor.configurable() && !descriptor.writable()) {
411             if (!sameValue(exec, descriptor.value(), putValue)) {
412                 throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'set' on a non-configurable and non-writable property on 'target' should either return false or be the same value already on the 'target'"));
413                 return false;
414             }
415         } else if (descriptor.isAccessorDescriptor() && !descriptor.configurable() && descriptor.setter().isUndefined()) {
416             throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'set' method on a non-configurable accessor property without a setter should return false"));
417             return false;
418         }
419     }
420     return true;
421 }
422
423 bool ProxyObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
424 {
425     VM& vm = exec->vm();
426     slot.disableCaching();
427     if (propertyName == vm.propertyNames->underscoreProto)
428         return Base::put(cell, exec, propertyName, value, slot);
429
430     ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
431     auto performDefaultPut = [&] () {
432         JSObject* target = jsCast<JSObject*>(thisObject->target());
433         return target->methodTable(vm)->put(target, exec, propertyName, value, slot);
434     };
435     return thisObject->performPut(exec, value, slot.thisValue(), propertyName, performDefaultPut);
436 }
437
438 bool ProxyObject::putByIndexCommon(ExecState* exec, JSValue thisValue, unsigned propertyName, JSValue putValue, bool shouldThrow)
439 {
440     VM& vm = exec->vm();
441     Identifier ident = Identifier::from(exec, propertyName); 
442     if (exec->hadException())
443         return false;
444     auto performDefaultPut = [&] () {
445         JSObject* target = this->target();
446         bool isStrictMode = shouldThrow;
447         PutPropertySlot slot(thisValue, isStrictMode); // We must preserve the "this" target of the putByIndex.
448         return target->methodTable(vm)->put(target, exec, ident.impl(), putValue, slot);
449     };
450     return performPut(exec, putValue, thisValue, ident.impl(), performDefaultPut);
451 }
452
453 bool ProxyObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
454 {
455     ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
456     return thisObject->putByIndexCommon(exec, thisObject, propertyName, value, shouldThrow);
457 }
458
459 static EncodedJSValue JSC_HOST_CALL performProxyCall(ExecState* exec)
460 {
461     VM& vm = exec->vm();
462     ProxyObject* proxy = jsCast<ProxyObject*>(exec->callee());
463     JSValue handlerValue = proxy->handler();
464     if (handlerValue.isNull())
465         return throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
466
467     JSObject* handler = jsCast<JSObject*>(handlerValue);
468     CallData callData;
469     CallType callType;
470     JSValue applyMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "apply"), ASCIILiteral("'apply' property of a Proxy's handler should be callable"));
471     if (exec->hadException())
472         return JSValue::encode(jsUndefined());
473     JSObject* target = proxy->target();
474     if (applyMethod.isUndefined()) {
475         CallData callData;
476         CallType callType = target->methodTable(vm)->getCallData(target, callData);
477         RELEASE_ASSERT(callType != CallType::None);
478         return JSValue::encode(call(exec, target, callType, callData, exec->thisValue(), ArgList(exec)));
479     }
480
481     JSArray* argArray = constructArray(exec, static_cast<ArrayAllocationProfile*>(nullptr), ArgList(exec));
482     if (exec->hadException())
483         return JSValue::encode(jsUndefined());
484     MarkedArgumentBuffer arguments;
485     arguments.append(target);
486     arguments.append(exec->thisValue());
487     arguments.append(argArray);
488     return JSValue::encode(call(exec, applyMethod, callType, callData, handler, arguments));
489 }
490
491 CallType ProxyObject::getCallData(JSCell* cell, CallData& callData)
492 {
493     ProxyObject* proxy = jsCast<ProxyObject*>(cell);
494     if (!proxy->m_isCallable) {
495         callData.js.functionExecutable = nullptr;
496         callData.js.scope = nullptr;
497         return CallType::None;
498     }
499
500     callData.native.function = performProxyCall;
501     return CallType::Host;
502 }
503
504 static EncodedJSValue JSC_HOST_CALL performProxyConstruct(ExecState* exec)
505 {
506     VM& vm = exec->vm();
507     ProxyObject* proxy = jsCast<ProxyObject*>(exec->callee());
508     JSValue handlerValue = proxy->handler();
509     if (handlerValue.isNull())
510         return throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
511
512     JSObject* handler = jsCast<JSObject*>(handlerValue);
513     CallData callData;
514     CallType callType;
515     JSValue constructMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "construct"), ASCIILiteral("'construct' property of a Proxy's handler should be constructible"));
516     if (exec->hadException())
517         return JSValue::encode(jsUndefined());
518     JSObject* target = proxy->target();
519     if (constructMethod.isUndefined()) {
520         ConstructData constructData;
521         ConstructType constructType = target->methodTable(vm)->getConstructData(target, constructData);
522         RELEASE_ASSERT(constructType != ConstructType::None);
523         return JSValue::encode(construct(exec, target, constructType, constructData, ArgList(exec), exec->newTarget()));
524     }
525
526     JSArray* argArray = constructArray(exec, static_cast<ArrayAllocationProfile*>(nullptr), ArgList(exec));
527     if (exec->hadException())
528         return JSValue::encode(jsUndefined());
529     MarkedArgumentBuffer arguments;
530     arguments.append(target);
531     arguments.append(argArray);
532     arguments.append(exec->newTarget());
533     JSValue result = call(exec, constructMethod, callType, callData, handler, arguments);
534     if (exec->hadException())
535         return JSValue::encode(jsUndefined());
536     if (!result.isObject())
537         return throwVMTypeError(exec, ASCIILiteral("Result from Proxy handler's 'construct' method should be an object"));
538     return JSValue::encode(result);
539 }
540
541 ConstructType ProxyObject::getConstructData(JSCell* cell, ConstructData& constructData)
542 {
543     ProxyObject* proxy = jsCast<ProxyObject*>(cell);
544     if (!proxy->m_isConstructible) {
545         constructData.js.functionExecutable = nullptr;
546         constructData.js.scope = nullptr;
547         return ConstructType::None;
548     }
549
550     constructData.native.function = performProxyConstruct;
551     return ConstructType::Host;
552 }
553
554 template <typename DefaultDeleteFunction>
555 bool ProxyObject::performDelete(ExecState* exec, PropertyName propertyName, DefaultDeleteFunction performDefaultDelete)
556 {
557     VM& vm = exec->vm();
558
559     if (vm.propertyNames->isPrivateName(Identifier::fromUid(&vm, propertyName.uid())))
560         return performDefaultDelete();
561
562     JSValue handlerValue = this->handler();
563     if (handlerValue.isNull()) {
564         throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
565         return false;
566     }
567
568     JSObject* handler = jsCast<JSObject*>(handlerValue);
569     CallData callData;
570     CallType callType;
571     JSValue deletePropertyMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "deleteProperty"), ASCIILiteral("'deleteProperty' property of a Proxy's handler should be callable"));
572     if (exec->hadException())
573         return false;
574     JSObject* target = this->target();
575     if (deletePropertyMethod.isUndefined())
576         return performDefaultDelete();
577
578     MarkedArgumentBuffer arguments;
579     arguments.append(target);
580     arguments.append(identifierToSafePublicJSValue(vm, Identifier::fromUid(&vm, propertyName.uid())));
581     JSValue trapResult = call(exec, deletePropertyMethod, callType, callData, handler, arguments);
582     if (exec->hadException())
583         return false;
584
585     bool trapResultAsBool = trapResult.toBoolean(exec);
586     if (exec->hadException())
587         return false;
588
589     if (!trapResultAsBool)
590         return false;
591
592     PropertyDescriptor descriptor;
593     if (target->getOwnPropertyDescriptor(exec, propertyName, descriptor)) {
594         if (!descriptor.configurable()) {
595             throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'deleteProperty' method should return false when the target's property is not configurable"));
596             return false;
597         }
598     }
599
600     if (exec->hadException())
601         return false;
602
603     return true;
604 }
605
606 bool ProxyObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
607 {
608     ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
609     auto performDefaultDelete = [&] () -> bool {
610         JSObject* target = thisObject->target();
611         return target->methodTable(exec->vm())->deleteProperty(target, exec, propertyName);
612     };
613     return thisObject->performDelete(exec, propertyName, performDefaultDelete);
614 }
615
616 bool ProxyObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
617 {
618     ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
619     Identifier ident = Identifier::from(exec, propertyName); 
620     auto performDefaultDelete = [&] () -> bool {
621         JSObject* target = thisObject->target();
622         return target->methodTable(exec->vm())->deletePropertyByIndex(target, exec, propertyName);
623     };
624     return thisObject->performDelete(exec, ident.impl(), performDefaultDelete);
625 }
626
627 bool ProxyObject::performPreventExtensions(ExecState* exec)
628 {
629     VM& vm = exec->vm();
630
631     JSValue handlerValue = this->handler();
632     if (handlerValue.isNull()) {
633         throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
634         return false;
635     }
636
637     JSObject* handler = jsCast<JSObject*>(handlerValue);
638     CallData callData;
639     CallType callType;
640     JSValue preventExtensionsMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "preventExtensions"), ASCIILiteral("'preventExtensions' property of a Proxy's handler should be callable"));
641     if (exec->hadException())
642         return false;
643     JSObject* target = this->target();
644     if (preventExtensionsMethod.isUndefined())
645         return target->methodTable(vm)->preventExtensions(target, exec);
646
647     MarkedArgumentBuffer arguments;
648     arguments.append(target);
649     JSValue trapResult = call(exec, preventExtensionsMethod, callType, callData, handler, arguments);
650     if (exec->hadException())
651         return false;
652
653     bool trapResultAsBool = trapResult.toBoolean(exec);
654     if (exec->hadException())
655         return false;
656
657     if (trapResultAsBool) {
658         bool targetIsExtensible = target->isExtensible(exec);
659         if (exec->hadException())
660             return false;
661         if (targetIsExtensible) {
662             throwVMTypeError(exec, ASCIILiteral("Proxy's 'preventExtensions' trap returned true even though its target is extensible. It should have returned false"));
663             return false;
664         }
665     }
666
667     return trapResultAsBool;
668 }
669
670 bool ProxyObject::preventExtensions(JSObject* object, ExecState* exec)
671 {
672     return jsCast<ProxyObject*>(object)->performPreventExtensions(exec);
673 }
674
675 bool ProxyObject::performIsExtensible(ExecState* exec)
676 {
677     VM& vm = exec->vm();
678
679     JSValue handlerValue = this->handler();
680     if (handlerValue.isNull()) {
681         throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
682         return false;
683     }
684
685     JSObject* handler = jsCast<JSObject*>(handlerValue);
686     CallData callData;
687     CallType callType;
688     JSValue isExtensibleMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "isExtensible"), ASCIILiteral("'isExtensible' property of a Proxy's handler should be callable"));
689     if (exec->hadException())
690         return false;
691
692     JSObject* target = this->target();
693     if (isExtensibleMethod.isUndefined())
694         return target->isExtensible(exec);
695
696     MarkedArgumentBuffer arguments;
697     arguments.append(target);
698     JSValue trapResult = call(exec, isExtensibleMethod, callType, callData, handler, arguments);
699     if (exec->hadException())
700         return false;
701
702     bool trapResultAsBool = trapResult.toBoolean(exec);
703     if (exec->hadException())
704         return false;
705
706     bool isTargetExtensible = target->isExtensible(exec);
707     if (exec->hadException())
708         return false;
709
710     if (trapResultAsBool != isTargetExtensible) {
711         if (isTargetExtensible) {
712             ASSERT(!trapResultAsBool);
713             throwVMTypeError(exec, ASCIILiteral("Proxy object's 'isExtensible' trap returned false when the target is extensible. It should have returned true"));
714         } else {
715             ASSERT(!isTargetExtensible);
716             ASSERT(trapResultAsBool);
717             throwVMTypeError(exec, ASCIILiteral("Proxy object's 'isExtensible' trap returned true when the target is non-extensible. It should have returned false"));
718         }
719     }
720     
721     return trapResultAsBool;
722 }
723
724 bool ProxyObject::isExtensible(JSObject* object, ExecState* exec)
725 {
726     return jsCast<ProxyObject*>(object)->performIsExtensible(exec);
727 }
728
729 bool ProxyObject::performDefineOwnProperty(ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
730 {
731     VM& vm = exec->vm();
732
733     JSObject* target = this->target();
734     auto performDefaultDefineOwnProperty = [&] {
735         return target->methodTable(vm)->defineOwnProperty(target, exec, propertyName, descriptor, shouldThrow);
736     };
737
738     if (vm.propertyNames->isPrivateName(Identifier::fromUid(&vm, propertyName.uid())))
739         return performDefaultDefineOwnProperty();
740
741     JSValue handlerValue = this->handler();
742     if (handlerValue.isNull()) {
743         throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
744         return false;
745     }
746
747     JSObject* handler = jsCast<JSObject*>(handlerValue);
748     CallData callData;
749     CallType callType;
750     JSValue definePropertyMethod = handler->getMethod(exec, callData, callType, vm.propertyNames->defineProperty, ASCIILiteral("'defineProperty' property of a Proxy's handler should be callable"));
751     if (vm.exception())
752         return false;
753
754     if (definePropertyMethod.isUndefined())
755         return performDefaultDefineOwnProperty();
756
757     JSObject* descriptorObject = constructObjectFromPropertyDescriptor(exec, descriptor);
758     if (vm.exception())
759         return false;
760
761     MarkedArgumentBuffer arguments;
762     arguments.append(target);
763     arguments.append(identifierToSafePublicJSValue(vm, Identifier::fromUid(&vm, propertyName.uid())));
764     arguments.append(descriptorObject);
765     JSValue trapResult = call(exec, definePropertyMethod, callType, callData, handler, arguments);
766     if (vm.exception())
767         return false;
768
769     bool trapResultAsBool = trapResult.toBoolean(exec);
770     if (vm.exception())
771         return false;
772
773     if (!trapResultAsBool)
774         return false;
775
776     PropertyDescriptor targetDescriptor;
777     bool isTargetDescriptorDefined = target->getOwnPropertyDescriptor(exec, propertyName, targetDescriptor);
778     if (vm.exception())
779         return false;
780
781     bool targetIsExtensible = target->isExtensible(exec);
782     if (vm.exception())
783         return false;
784     bool settingConfigurableToFalse = descriptor.configurablePresent() && !descriptor.configurable();
785
786     if (!isTargetDescriptorDefined) {
787         if (!targetIsExtensible) {
788             throwVMTypeError(exec, ASCIILiteral("Proxy's 'defineProperty' trap returned true even though getOwnPropertyDescriptor of the Proxy's target returned undefined and the target is non-extensible"));
789             return false;
790         }
791         if (settingConfigurableToFalse) {
792             throwVMTypeError(exec, ASCIILiteral("Proxy's 'defineProperty' trap returned true for a non-configurable field even though getOwnPropertyDescriptor of the Proxy's target returned undefined"));
793             return false;
794         }
795
796         return true;
797     } 
798
799     ASSERT(isTargetDescriptorDefined);
800     bool isCurrentDefined = isTargetDescriptorDefined;
801     const PropertyDescriptor& current = targetDescriptor;
802     bool throwException = false;
803     bool isCompatibleDescriptor = validateAndApplyPropertyDescriptor(exec, nullptr, propertyName, targetIsExtensible, descriptor, isCurrentDefined, current, throwException);
804     if (!isCompatibleDescriptor) {
805         throwVMTypeError(exec, ASCIILiteral("Proxy's 'defineProperty' trap did not define a property on its target that is compatible with the trap's input descriptor"));
806         return false;
807     }
808     if (settingConfigurableToFalse && targetDescriptor.configurable()) {
809         throwVMTypeError(exec, ASCIILiteral("Proxy's 'defineProperty' trap did not define a non-configurable property on its target even though the input descriptor to the trap said it must do so"));
810         return false;
811     }
812     
813     return true;
814 }
815
816 bool ProxyObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
817 {
818     ProxyObject* thisObject = jsCast<ProxyObject*>(object);
819     return thisObject->performDefineOwnProperty(exec, propertyName, descriptor, shouldThrow);
820 }
821
822 void ProxyObject::performGetOwnPropertyNames(ExecState* exec, PropertyNameArray& trapResult, EnumerationMode enumerationMode)
823 {
824     VM& vm = exec->vm();
825     JSValue handlerValue = this->handler();
826     if (handlerValue.isNull()) {
827         throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
828         return;
829     }
830
831     JSObject* handler = jsCast<JSObject*>(handlerValue);
832     CallData callData;
833     CallType callType;
834     JSValue ownKeysMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "ownKeys"), ASCIILiteral("'ownKeys' property of a Proxy's handler should be callable"));
835     if (exec->hadException())
836         return;
837     JSObject* target = this->target();
838     if (ownKeysMethod.isUndefined()) {
839         target->methodTable(exec->vm())->getOwnPropertyNames(target, exec, trapResult, enumerationMode);
840         return;
841     }
842
843     MarkedArgumentBuffer arguments;
844     arguments.append(target);
845     JSValue arrayLikeObject = call(exec, ownKeysMethod, callType, callData, handler, arguments);
846     if (exec->hadException())
847         return;
848
849     PropertyNameMode propertyNameMode = trapResult.mode();
850     RuntimeTypeMask resultFilter = 0;
851     switch (propertyNameMode) {
852     case PropertyNameMode::Symbols:
853         resultFilter = TypeSymbol;
854         break;
855     case PropertyNameMode::Strings:
856         resultFilter = TypeString;
857         break;
858     case PropertyNameMode::StringsAndSymbols:
859         resultFilter = TypeSymbol | TypeString;
860         break;
861     }
862     ASSERT(resultFilter);
863     RuntimeTypeMask dontThrowAnExceptionTypeFilter = TypeString | TypeSymbol;
864     HashMap<UniquedStringImpl*, unsigned> uncheckedResultKeys;
865     unsigned totalSize = 0;
866
867     auto addPropName = [&] (JSValue value, RuntimeType type) -> bool {
868         static const bool doExitEarly = true;
869         static const bool dontExitEarly = false;
870
871         if (!(type & resultFilter))
872             return dontExitEarly;
873
874         Identifier ident = value.toPropertyKey(exec);
875         if (exec->hadException())
876             return doExitEarly;
877
878         ++uncheckedResultKeys.add(ident.impl(), 0).iterator->value;
879         ++totalSize;
880
881         trapResult.addUnchecked(ident.impl());
882
883         return dontExitEarly;
884     };
885
886     createListFromArrayLike(exec, arrayLikeObject, dontThrowAnExceptionTypeFilter, ASCIILiteral("Proxy handler's 'ownKeys' method must return an array-like object containing only Strings and Symbols"), addPropName);
887     if (exec->hadException())
888         return;
889
890     bool targetIsExensible = target->isExtensible(exec);
891
892     PropertyNameArray targetKeys(&vm, propertyNameMode);
893     target->methodTable(vm)->getOwnPropertyNames(target, exec, targetKeys, enumerationMode);
894     if (exec->hadException())
895         return;
896     Vector<UniquedStringImpl*> targetConfigurableKeys;
897     Vector<UniquedStringImpl*> targetNonConfigurableKeys;
898     for (const Identifier& ident : targetKeys) {
899         PropertyDescriptor descriptor;
900         bool isPropertyDefined = target->getOwnPropertyDescriptor(exec, ident.impl(), descriptor); 
901         if (exec->hadException())
902             return;
903         if (isPropertyDefined && !descriptor.configurable())
904             targetNonConfigurableKeys.append(ident.impl());
905         else
906             targetConfigurableKeys.append(ident.impl());
907     }
908
909     auto removeIfContainedInUncheckedResultKeys = [&] (UniquedStringImpl* impl) -> bool {
910         static const bool isContainedIn = true;
911         static const bool isNotContainedIn = false;
912
913         auto iter = uncheckedResultKeys.find(impl);
914         if (iter == uncheckedResultKeys.end())
915             return isNotContainedIn;
916
917         unsigned& count = iter->value;
918         if (count == 0)
919             return isNotContainedIn;
920
921         --count;
922         --totalSize;
923         return isContainedIn;
924     };
925
926     for (UniquedStringImpl* impl : targetNonConfigurableKeys) {
927         bool contains = removeIfContainedInUncheckedResultKeys(impl);
928         if (!contains) {
929             throwVMTypeError(exec, makeString("Proxy object's 'target' has the non-configurable property '", String(impl), "' that was not in the result from the 'ownKeys' trap"));
930             return;
931         }
932     }
933
934     if (targetIsExensible)
935         return;
936
937     for (UniquedStringImpl* impl : targetConfigurableKeys) {
938         bool contains = removeIfContainedInUncheckedResultKeys(impl);
939         if (!contains) {
940             throwVMTypeError(exec, makeString("Proxy object's non-extensible 'target' has configurable property '", String(impl), "' that was not in the result from the 'ownKeys' trap"));
941             return;
942         }
943     }
944
945 #ifndef NDEBUG
946     unsigned sum = 0;
947     for (unsigned keyCount : uncheckedResultKeys.values())
948         sum += keyCount;
949     ASSERT(sum == totalSize);
950 #endif
951
952     if (totalSize) {
953         throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'ownKeys' method returned a key that was not present in its target or it returned duplicate keys"));
954         return;
955     }
956 }
957
958 void ProxyObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNameArray, EnumerationMode enumerationMode)
959 {
960     ProxyObject* thisObject = jsCast<ProxyObject*>(object);
961     thisObject->performGetOwnPropertyNames(exec, propertyNameArray, enumerationMode);
962 }
963
964 void ProxyObject::getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
965 {
966     RELEASE_ASSERT_NOT_REACHED();
967 }
968
969 void ProxyObject::getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
970 {
971     // We should always go down the getOwnPropertyNames path.
972     RELEASE_ASSERT_NOT_REACHED();
973 }
974
975 void ProxyObject::getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
976 {
977     RELEASE_ASSERT_NOT_REACHED();
978 }
979
980 bool ProxyObject::performSetPrototype(ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
981 {
982     ASSERT(prototype.isObject() || prototype.isNull());
983
984     VM& vm = exec->vm();
985
986     JSValue handlerValue = this->handler();
987     if (handlerValue.isNull()) {
988         throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
989         return false;
990     }
991
992     JSObject* handler = jsCast<JSObject*>(handlerValue);
993     CallData callData;
994     CallType callType;
995     JSValue setPrototypeOfMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "setPrototypeOf"), ASCIILiteral("'setPrototypeOf' property of a Proxy's handler should be callable"));
996     if (vm.exception())
997         return false;
998
999     JSObject* target = this->target();
1000     if (setPrototypeOfMethod.isUndefined())
1001         return target->setPrototype(vm, exec, prototype, shouldThrowIfCantSet);
1002
1003     MarkedArgumentBuffer arguments;
1004     arguments.append(target);
1005     arguments.append(prototype);
1006     JSValue trapResult = call(exec, setPrototypeOfMethod, callType, callData, handler, arguments);
1007     if (vm.exception())
1008         return false;
1009
1010     bool trapResultAsBool = trapResult.toBoolean(exec);
1011     if (vm.exception())
1012         return false;
1013     
1014     if (!trapResultAsBool) {
1015         if (shouldThrowIfCantSet)
1016             throwVMTypeError(exec, ASCIILiteral("Proxy 'setPrototypeOf' returned false indicating it could not set the prototype value. The operation was expected to succeed"));
1017         return false;
1018     }
1019
1020     bool targetIsExtensible = target->isExtensible(exec);
1021     if (vm.exception())
1022         return false;
1023     if (targetIsExtensible)
1024         return true;
1025
1026     JSValue targetPrototype = target->getPrototype(vm, exec);
1027     if (vm.exception())
1028         return false;
1029     if (!sameValue(exec, prototype, targetPrototype)) {
1030         throwVMTypeError(exec, ASCIILiteral("Proxy 'setPrototypeOf' trap returned true when its target is non-extensible and the new prototype value is not the same as the current prototype value. It should have returned false"));
1031         return false;
1032     }
1033
1034     return true;
1035 }
1036
1037 bool ProxyObject::setPrototype(JSObject* object, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
1038 {
1039     return jsCast<ProxyObject*>(object)->performSetPrototype(exec, prototype, shouldThrowIfCantSet);
1040 }
1041
1042 JSValue ProxyObject::performGetPrototype(ExecState* exec)
1043 {
1044     VM& vm = exec->vm();
1045
1046     JSValue handlerValue = this->handler();
1047     if (handlerValue.isNull()) {
1048         throwVMTypeError(exec, ASCIILiteral(s_proxyAlreadyRevokedErrorMessage));
1049         return JSValue();
1050     }
1051
1052     JSObject* handler = jsCast<JSObject*>(handlerValue);
1053     CallData callData;
1054     CallType callType;
1055     JSValue getPrototypeOfMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "getPrototypeOf"), ASCIILiteral("'getPrototypeOf' property of a Proxy's handler should be callable"));
1056     if (vm.exception())
1057         return JSValue();
1058
1059     JSObject* target = this->target();
1060     if (getPrototypeOfMethod.isUndefined())
1061         return target->getPrototype(vm, exec);
1062
1063     MarkedArgumentBuffer arguments;
1064     arguments.append(target);
1065     JSValue trapResult = call(exec, getPrototypeOfMethod, callType, callData, handler, arguments);
1066     if (vm.exception())
1067         return JSValue();
1068
1069     if (!trapResult.isObject() && !trapResult.isNull()) {
1070         throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'getPrototypeOf' trap should either return an object or null"));
1071         return JSValue();
1072     }
1073
1074     bool targetIsExtensible = target->isExtensible(exec);
1075     if (vm.exception())
1076         return JSValue();
1077     if (targetIsExtensible)
1078         return trapResult;
1079
1080     JSValue targetPrototype = target->getPrototype(vm, exec);
1081     if (vm.exception())
1082         return JSValue();
1083     if (!sameValue(exec, targetPrototype, trapResult)) {
1084         throwVMTypeError(exec, ASCIILiteral("Proxy's 'getPrototypeOf' trap for a non-extensible target should return the same value as the target's prototype"));
1085         return JSValue();
1086     }
1087
1088     return trapResult;
1089 }
1090
1091 JSValue ProxyObject::getPrototype(JSObject* object, ExecState* exec)
1092 {
1093     return jsCast<ProxyObject*>(object)->performGetPrototype(exec);
1094 }
1095
1096 void ProxyObject::revoke(VM& vm)
1097
1098     // This should only ever be called once and we should strictly transition from Object to null.
1099     RELEASE_ASSERT(!m_handler.get().isNull() && m_handler.get().isObject());
1100     m_handler.set(vm, this, jsNull());
1101 }
1102
1103 bool ProxyObject::isRevoked() const
1104 {
1105     return handler().isNull();
1106 }
1107
1108 void ProxyObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
1109 {
1110     ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
1111     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
1112     Base::visitChildren(thisObject, visitor);
1113
1114     visitor.append(&thisObject->m_target);
1115     visitor.append(&thisObject->m_handler);
1116 }
1117
1118 } // namespace JSC