4b38cb60dfa0c9730a928ce5d921123026275965
[WebKit.git] / Source / WebCore / bridge / objc / WebScriptObject.mm
1 /*
2  * Copyright (C) 2004-2017 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 #import "config.h"
27 #import "WebScriptObjectPrivate.h"
28
29 #import "BridgeJSC.h"
30 #import "Frame.h"
31 #import "JSDOMBindingSecurity.h"
32 #import "JSDOMWindow.h"
33 #import "JSDOMWindowCustom.h"
34 #import "JSHTMLElement.h"
35 #import "JSMainThreadExecState.h"
36 #import "JSPluginElementFunctions.h"
37 #import "ObjCRuntimeObject.h"
38 #import "WebCoreObjCExtras.h"
39 #import "objc_instance.h"
40 #import "runtime_object.h"
41 #import "runtime_root.h"
42 #import <JavaScriptCore/APICast.h>
43 #import <JavaScriptCore/CallFrame.h>
44 #import <JavaScriptCore/CatchScope.h>
45 #import <JavaScriptCore/Completion.h>
46 #import <JavaScriptCore/InitializeThreading.h>
47 #import <JavaScriptCore/JSContextInternal.h>
48 #import <JavaScriptCore/JSGlobalObject.h>
49 #import <JavaScriptCore/JSLock.h>
50 #import <JavaScriptCore/JSValueInternal.h>
51 #import <wtf/HashMap.h>
52 #import <wtf/Lock.h>
53 #import <wtf/NeverDestroyed.h>
54 #import <wtf/Threading.h>
55 #import <wtf/text/WTFString.h>
56
57 using namespace JSC::Bindings;
58 using namespace WebCore;
59
60 using JSC::CallData;
61 using JSC::CallType;
62 using JSC::ExecState;
63 using JSC::Identifier;
64 using JSC::JSLockHolder;
65 using JSC::JSObject;
66 using JSC::MarkedArgumentBuffer;
67 using JSC::PutPropertySlot;
68 using JSC::jsCast;
69 using JSC::jsUndefined;
70 using JSC::makeSource;
71
72 namespace WebCore {
73
74 static StaticLock spinLock;
75 static CreateWrapperFunction createDOMWrapperFunction;
76 static DisconnectWindowWrapperFunction disconnectWindowWrapperFunction;
77
78 static HashMap<JSObject*, NSObject *>& wrapperCache()
79 {
80     static NeverDestroyed<HashMap<JSObject*, NSObject *>> map;
81     return map;
82 }
83
84 NSObject *getJSWrapper(JSObject* impl)
85 {
86     ASSERT(isMainThread());
87     LockHolder holder(&spinLock);
88
89     NSObject* wrapper = wrapperCache().get(impl);
90     return wrapper ? [[wrapper retain] autorelease] : nil;
91 }
92
93 void addJSWrapper(NSObject *wrapper, JSObject* impl)
94 {
95     ASSERT(isMainThread());
96     LockHolder holder(&spinLock);
97
98     wrapperCache().set(impl, wrapper);
99 }
100
101 void removeJSWrapper(JSObject* impl)
102 {
103     LockHolder holder(&spinLock);
104
105     wrapperCache().remove(impl);
106 }
107
108 static void removeJSWrapperIfRetainCountOne(NSObject* wrapper, JSObject* impl)
109 {
110     LockHolder holder(&spinLock);
111
112     if ([wrapper retainCount] == 1)
113         wrapperCache().remove(impl);
114 }
115
116 id createJSWrapper(JSC::JSObject* object, RefPtr<JSC::Bindings::RootObject>&& origin, RefPtr<JSC::Bindings::RootObject>&& root)
117 {
118     if (id wrapper = getJSWrapper(object))
119         return wrapper;
120     return [[[WebScriptObject alloc] _initWithJSObject:object originRootObject:WTFMove(origin) rootObject:WTFMove(root)] autorelease];
121 }
122
123 static void addExceptionToConsole(ExecState* exec, JSC::Exception* exception)
124 {
125     JSDOMWindow* window = asJSDOMWindow(exec->vmEntryGlobalObject());
126     if (!window || !exception)
127         return;
128     reportException(exec, exception);
129 }
130
131 static void addExceptionToConsole(ExecState* exec)
132 {
133     JSC::VM& vm = exec->vm();
134     auto scope = DECLARE_CATCH_SCOPE(vm);
135     JSC::Exception* exception = scope.exception();
136     scope.clearException();
137     addExceptionToConsole(exec, exception);
138 }
139
140 void initializeDOMWrapperHooks(CreateWrapperFunction createFunction, DisconnectWindowWrapperFunction disconnectFunction)
141 {
142     ASSERT(createFunction);
143     ASSERT(disconnectFunction);
144     ASSERT(!createDOMWrapperFunction);
145     ASSERT(!disconnectWindowWrapperFunction);
146     createDOMWrapperFunction = createFunction;
147     disconnectWindowWrapperFunction = disconnectFunction;
148 }
149
150 void disconnectWindowWrapper(WebScriptObject *windowWrapper)
151 {
152     ASSERT(windowWrapper);
153     ASSERT(disconnectWindowWrapperFunction);
154     disconnectWindowWrapperFunction(windowWrapper);
155 }
156
157 } // namespace WebCore
158
159 @implementation WebScriptObjectPrivate
160
161 @end
162
163 @implementation WebScriptObject
164
165 + (void)initialize
166 {
167 #if !USE(WEB_THREAD)
168     JSC::initializeThreading();
169     WTF::initializeMainThreadToProcessMainThread();
170 #endif
171 }
172
173 + (id)scriptObjectForJSObject:(JSObjectRef)jsObject originRootObject:(RootObject*)originRootObject rootObject:(RootObject*)rootObject
174 {
175     ASSERT(jsObject);
176     auto& wrapped = *toJS(jsObject);
177
178     if (WebCore::createDOMWrapperFunction) {
179         if (auto wrapper = WebCore::createDOMWrapperFunction(wrapped)) {
180             if (![wrapper _hasImp]) // new wrapper, not from cache
181                 [wrapper _setImp:&wrapped originRootObject:originRootObject rootObject:rootObject];
182             return wrapper;
183         }
184     }
185
186     return WebCore::createJSWrapper(&wrapped, originRootObject, rootObject);
187 }
188
189 - (void)_setImp:(JSObject*)imp originRootObject:(RefPtr<RootObject>&&)originRootObject rootObject:(RefPtr<RootObject>&&)rootObject
190 {
191     // This function should only be called once, as a (possibly lazy) initializer.
192     ASSERT(!_private->imp);
193     ASSERT(!_private->rootObject);
194     ASSERT(!_private->originRootObject);
195     ASSERT(imp);
196
197     _private->imp = imp;
198     _private->rootObject = rootObject.leakRef();
199     _private->originRootObject = originRootObject.leakRef();
200
201     WebCore::addJSWrapper(self, imp);
202
203     if (_private->rootObject)
204         _private->rootObject->gcProtect(imp);
205 }
206
207 - (void)_setOriginRootObject:(RefPtr<RootObject>&&)originRootObject andRootObject:(RefPtr<RootObject>&&)rootObject
208 {
209     ASSERT(_private->imp);
210
211     if (rootObject)
212         rootObject->gcProtect(_private->imp);
213
214     if (_private->rootObject && _private->rootObject->isValid())
215         _private->rootObject->gcUnprotect(_private->imp);
216
217     if (_private->rootObject)
218         _private->rootObject->deref();
219
220     if (_private->originRootObject)
221         _private->originRootObject->deref();
222
223     _private->rootObject = rootObject.leakRef();
224     _private->originRootObject = originRootObject.leakRef();
225 }
226
227 - (id)_initWithJSObject:(JSC::JSObject*)imp originRootObject:(RefPtr<JSC::Bindings::RootObject>&&)originRootObject rootObject:(RefPtr<JSC::Bindings::RootObject>&&)rootObject
228 {
229     ASSERT(imp);
230
231     self = [super init];
232     _private = [[WebScriptObjectPrivate alloc] init];
233     [self _setImp:imp originRootObject:WTFMove(originRootObject) rootObject:WTFMove(rootObject)];
234     
235     return self;
236 }
237
238 - (JSObject*)_imp
239 {
240     // Associate the WebScriptObject with the JS wrapper for the ObjC DOM wrapper.
241     // This is done on lazily, on demand.
242     if (!_private->imp && _private->isCreatedByDOMWrapper)
243         [self _initializeScriptDOMNodeImp];
244     return [self _rootObject] ? _private->imp : 0;
245 }
246
247 - (BOOL)_hasImp
248 {
249     return _private->imp != nil;
250 }
251
252 // Node that DOMNode overrides this method. So you should almost always
253 // use this method call instead of _private->rootObject directly.
254 - (RootObject*)_rootObject
255 {
256     return _private->rootObject && _private->rootObject->isValid() ? _private->rootObject : 0;
257 }
258
259 - (RootObject *)_originRootObject
260 {
261     return _private->originRootObject && _private->originRootObject->isValid() ? _private->originRootObject : 0;
262 }
263
264 - (BOOL)_isSafeScript
265 {
266     RootObject *root = [self _rootObject];
267     if (!root)
268         return false;
269
270     if (!_private->originRootObject)
271         return true;
272
273     if (!_private->originRootObject->isValid())
274         return false;
275
276     // It's not actually correct to call shouldAllowAccessToFrame in this way because
277     // JSDOMWindowBase* isn't the right object to represent the currently executing
278     // JavaScript. Instead, we should use ExecState, like we do elsewhere.
279     JSDOMWindowBase* target = jsCast<JSDOMWindowBase*>(root->globalObject());
280     return BindingSecurity::shouldAllowAccessToDOMWindow(_private->originRootObject->globalObject()->globalExec(), target->wrapped());
281 }
282
283 - (JSGlobalContextRef)_globalContextRef
284 {
285     if (![self _isSafeScript])
286         return nil;
287     return toGlobalRef([self _rootObject]->globalObject()->globalExec());
288 }
289
290 - (oneway void)release
291 {
292     // If we're releasing the last reference to this object, remove if from the map.
293     if (_private->imp)
294         WebCore::removeJSWrapperIfRetainCountOne(self, _private->imp);
295
296     [super release];
297 }
298
299 - (void)dealloc
300 {
301     if (WebCoreObjCScheduleDeallocateOnMainThread([WebScriptObject class], self))
302         return;
303
304     if (_private->rootObject && _private->rootObject->isValid())
305         _private->rootObject->gcUnprotect(_private->imp);
306
307     if (_private->rootObject)
308         _private->rootObject->deref();
309
310     if (_private->originRootObject)
311         _private->originRootObject->deref();
312
313     [_private release];
314
315     [super dealloc];
316 }
317
318 + (BOOL)throwException:(NSString *)exceptionMessage
319 {
320     ObjcInstance::setGlobalException(exceptionMessage);
321     return YES;
322 }
323
324 static void getListFromNSArray(ExecState *exec, NSArray *array, RootObject* rootObject, MarkedArgumentBuffer& aList)
325 {
326     int i, numObjects = array ? [array count] : 0;
327     
328     for (i = 0; i < numObjects; i++) {
329         id anObject = [array objectAtIndex:i];
330         aList.append(convertObjcValueToValue(exec, &anObject, ObjcObjectType, rootObject));
331     }
332 }
333
334 - (id)callWebScriptMethod:(NSString *)name withArguments:(NSArray *)args
335 {
336     if (![self _isSafeScript])
337         return nil;
338
339     // Look up the function object.
340     auto globalObject = [self _rootObject]->globalObject();
341     auto& vm = globalObject->vm();
342     JSLockHolder lock(vm);
343     auto scope = DECLARE_CATCH_SCOPE(vm);
344     ExecState* exec = globalObject->globalExec();
345     UNUSED_PARAM(scope);
346
347     JSC::JSValue function = [self _imp]->get(exec, Identifier::fromString(exec, String(name)));
348     CallData callData;
349     CallType callType = getCallData(function, callData);
350     if (callType == CallType::None)
351         return nil;
352
353     MarkedArgumentBuffer argList;
354     ASSERT(!argList.hasOverflowed());
355     getListFromNSArray(exec, args, [self _rootObject], argList);
356
357     if (![self _isSafeScript])
358         return nil;
359
360     NakedPtr<JSC::Exception> exception;
361     JSC::JSValue result = JSMainThreadExecState::profiledCall(exec, JSC::ProfilingReason::Other, function, callType, callData, [self _imp], argList, exception);
362
363     if (exception) {
364         addExceptionToConsole(exec, exception);
365         result = jsUndefined();
366     }
367
368     // Convert and return the result of the function call.
369     id resultObj = [WebScriptObject _convertValueToObjcValue:result originRootObject:[self _originRootObject] rootObject:[self _rootObject]];
370
371     return resultObj;
372 }
373
374 - (id)evaluateWebScript:(NSString *)script
375 {
376     if (![self _isSafeScript])
377         return nil;
378     
379     auto globalObject = [self _rootObject]->globalObject();
380     auto& vm = globalObject->vm();
381     JSLockHolder lock(vm);
382     auto scope = DECLARE_CATCH_SCOPE(vm);
383     ExecState* exec = globalObject->globalExec();
384     UNUSED_PARAM(scope);
385     
386     JSC::JSValue returnValue = JSMainThreadExecState::profiledEvaluate(exec, JSC::ProfilingReason::Other, makeSource(String(script), { }), JSC::JSValue());
387
388     id resultObj = [WebScriptObject _convertValueToObjcValue:returnValue originRootObject:[self _originRootObject] rootObject:[self _rootObject]];
389     
390     return resultObj;
391 }
392
393 - (void)setValue:(id)value forKey:(NSString *)key
394 {
395     if (![self _isSafeScript])
396         return;
397
398     auto globalObject = [self _rootObject]->globalObject();
399     auto& vm = globalObject->vm();
400     JSLockHolder lock(vm);
401     auto scope = DECLARE_CATCH_SCOPE(vm);
402     ExecState* exec = globalObject->globalExec();
403
404     JSObject* object = JSC::jsDynamicCast<JSObject*>(vm, [self _imp]);
405     PutPropertySlot slot(object);
406     object->methodTable(vm)->put(object, exec, Identifier::fromString(exec, String(key)), convertObjcValueToValue(exec, &value, ObjcObjectType, [self _rootObject]), slot);
407
408     if (UNLIKELY(scope.exception())) {
409         addExceptionToConsole(exec);
410         scope.clearException();
411     }
412 }
413
414 - (id)valueForKey:(NSString *)key
415 {
416     if (![self _isSafeScript])
417         return nil;
418
419     id resultObj;
420     {
421         auto globalObject = [self _rootObject]->globalObject();
422         auto& vm = globalObject->vm();
423
424         // Need to scope this lock to ensure that we release the lock before calling
425         // [super valueForKey:key] which might throw an exception and bypass the JSLock destructor,
426         // leaving the lock permanently held
427         JSLockHolder lock(vm);
428
429         auto scope = DECLARE_CATCH_SCOPE(vm);
430         ExecState* exec = globalObject->globalExec();
431
432         JSC::JSValue result = [self _imp]->get(exec, Identifier::fromString(exec, String(key)));
433         
434         if (UNLIKELY(scope.exception())) {
435             addExceptionToConsole(exec);
436             result = jsUndefined();
437             scope.clearException();
438         }
439
440         resultObj = [WebScriptObject _convertValueToObjcValue:result originRootObject:[self _originRootObject] rootObject:[self _rootObject]];
441     }
442     
443     if ([resultObj isKindOfClass:[WebUndefined class]])
444         resultObj = [super valueForKey:key];    // defaults to throwing an exception
445
446     return resultObj;
447 }
448
449 - (void)removeWebScriptKey:(NSString *)key
450 {
451     if (![self _isSafeScript])
452         return;
453
454     auto globalObject = [self _rootObject]->globalObject();
455     auto& vm = globalObject->vm();
456     JSLockHolder lock(vm);
457     auto scope = DECLARE_CATCH_SCOPE(vm);
458     ExecState* exec = globalObject->globalExec();
459
460     [self _imp]->methodTable(vm)->deleteProperty([self _imp], exec, Identifier::fromString(exec, String(key)));
461
462     if (UNLIKELY(scope.exception())) {
463         addExceptionToConsole(exec);
464         scope.clearException();
465     }
466 }
467
468 - (BOOL)hasWebScriptKey:(NSString *)key
469 {
470     if (![self _isSafeScript])
471         return NO;
472
473     auto globalObject = [self _rootObject]->globalObject();
474     auto& vm = globalObject->vm();
475     JSLockHolder lock(vm);
476     auto scope = DECLARE_CATCH_SCOPE(vm);
477     ExecState* exec = globalObject->globalExec();
478
479     BOOL result = [self _imp]->hasProperty(exec, Identifier::fromString(exec, String(key)));
480
481     if (UNLIKELY(scope.exception())) {
482         addExceptionToConsole(exec);
483         scope.clearException();
484     }
485
486     return result;
487 }
488
489 - (NSString *)stringRepresentation
490 {
491     if (![self _isSafeScript]) {
492         // This is a workaround for a gcc 3.3 internal compiler error.
493         return @"Undefined";
494     }
495
496     ExecState* exec = [self _rootObject]->globalObject()->globalExec();
497     JSLockHolder lock(exec);
498
499     id result = convertValueToObjcValue(exec, [self _imp], ObjcObjectType).objectValue;
500
501     NSString *description = [result description];
502
503     return description;
504 }
505
506 - (id)webScriptValueAtIndex:(unsigned)index
507 {
508     if (![self _isSafeScript])
509         return nil;
510
511     auto globalObject = [self _rootObject]->globalObject();
512     auto& vm = globalObject->vm();
513     JSLockHolder lock(vm);
514     auto scope = DECLARE_CATCH_SCOPE(vm);
515     ExecState* exec = globalObject->globalExec();
516
517     JSC::JSValue result = [self _imp]->get(exec, index);
518
519     if (UNLIKELY(scope.exception())) {
520         addExceptionToConsole(exec);
521         result = jsUndefined();
522         scope.clearException();
523     }
524
525     id resultObj = [WebScriptObject _convertValueToObjcValue:result originRootObject:[self _originRootObject] rootObject:[self _rootObject]];
526
527     return resultObj;
528 }
529
530 - (void)setWebScriptValueAtIndex:(unsigned)index value:(id)value
531 {
532     if (![self _isSafeScript])
533         return;
534
535     auto globalObject = [self _rootObject]->globalObject();
536     auto& vm = globalObject->vm();
537     JSLockHolder lock(vm);
538     auto scope = DECLARE_CATCH_SCOPE(vm);
539     ExecState* exec = globalObject->globalExec();
540
541     [self _imp]->methodTable(vm)->putByIndex([self _imp], exec, index, convertObjcValueToValue(exec, &value, ObjcObjectType, [self _rootObject]), false);
542
543     if (UNLIKELY(scope.exception())) {
544         addExceptionToConsole(exec);
545         scope.clearException();
546     }
547 }
548
549 - (void)setException:(NSString *)description
550 {
551     if (![self _rootObject])
552         return;
553     ObjcInstance::setGlobalException(description, [self _rootObject]->globalObject());
554 }
555
556 - (JSObjectRef)JSObject
557 {
558     if (![self _isSafeScript])
559         return 0;
560     ExecState* exec = [self _rootObject]->globalObject()->globalExec();
561
562     JSLockHolder lock(exec);
563     return toRef([self _imp]);
564 }
565
566 + (id)_convertValueToObjcValue:(JSC::JSValue)value originRootObject:(RootObject*)originRootObject rootObject:(RootObject*)rootObject
567 {
568     if (value.isObject()) {
569         JSObject* object = asObject(value);
570         JSC::VM& vm = rootObject->globalObject()->vm();
571         JSLockHolder lock(vm);
572
573         if (object->inherits<JSHTMLElement>(vm)) {
574             // Plugin elements cache the instance internally.
575             if (ObjcInstance* instance = static_cast<ObjcInstance*>(pluginInstance(jsCast<JSHTMLElement*>(object)->wrapped())))
576                 return instance->getObject();
577         } else if (object->inherits<ObjCRuntimeObject>(vm)) {
578             ObjCRuntimeObject* runtimeObject = static_cast<ObjCRuntimeObject*>(object);
579             ObjcInstance* instance = runtimeObject->getInternalObjCInstance();
580             if (instance)
581                 return instance->getObject();
582             return nil;
583         }
584
585         return [WebScriptObject scriptObjectForJSObject:toRef(object) originRootObject:originRootObject rootObject:rootObject];
586     }
587
588     if (value.isString())
589         return asString(value)->value(rootObject->globalObject()->globalExec());
590
591     if (value.isNumber())
592         return [NSNumber numberWithDouble:value.asNumber()];
593
594     if (value.isBoolean())
595         return [NSNumber numberWithBool:value.asBoolean()];
596
597     if (value.isUndefined())
598         return [WebUndefined undefined];
599
600     // jsNull is not returned as NSNull because existing applications do not expect
601     // that return value. Return as nil for compatibility. <rdar://problem/4651318> <rdar://problem/4701626>
602     // Other types (e.g., UnspecifiedType) also return as nil.
603     return nil;
604 }
605
606
607 #if JSC_OBJC_API_ENABLED
608 - (JSValue *)JSValue
609 {
610     if (![self _isSafeScript])
611         return 0;
612
613     return [JSValue valueWithJSValueRef:[self JSObject]
614                     inContext:[JSContext contextWithJSGlobalContextRef:[self _globalContextRef]]];
615 }
616 #endif
617
618 @end
619
620 @interface WebScriptObject (WebKitCocoaBindings)
621
622 - (id)objectAtIndex:(unsigned)index;
623
624 @end
625
626 @implementation WebScriptObject (WebKitCocoaBindings)
627
628 #if 0
629
630 // FIXME: We'd like to add this, but we can't do that until this issue is resolved:
631 // http://bugs.webkit.org/show_bug.cgi?id=13129: presence of 'count' method on
632 // WebScriptObject breaks Democracy player.
633
634 - (unsigned)count
635 {
636     id length = [self valueForKey:@"length"];
637     if (![length respondsToSelector:@selector(intValue)])
638         return 0;
639     return [length intValue];
640 }
641
642 #endif
643
644 - (id)objectAtIndex:(unsigned)index
645 {
646     return [self webScriptValueAtIndex:index];
647 }
648
649 @end
650
651 @implementation WebUndefined
652
653 + (id)allocWithZone:(NSZone *)unusedZone
654 {
655     UNUSED_PARAM(unusedZone);
656
657     static WebUndefined *sharedUndefined = 0;
658     if (!sharedUndefined)
659         sharedUndefined = [super allocWithZone:NULL];
660     return sharedUndefined;
661 }
662
663 - (NSString *)description
664 {
665     return @"undefined";
666 }
667
668 - (id)initWithCoder:(NSCoder *)unusedCoder
669 {
670     UNUSED_PARAM(unusedCoder);
671
672     return self;
673 }
674
675 - (void)encodeWithCoder:(NSCoder *)unusedCoder
676 {
677     UNUSED_PARAM(unusedCoder);
678 }
679
680 - (id)copyWithZone:(NSZone *)unusedZone
681 {
682     UNUSED_PARAM(unusedZone);
683
684     return self;
685 }
686
687 - (id)retain
688 {
689     return self;
690 }
691
692 - (oneway void)release
693 {
694 }
695
696 - (NSUInteger)retainCount
697 {
698     return NSUIntegerMax;
699 }
700
701 - (id)autorelease
702 {
703     return self;
704 }
705
706 #pragma clang diagnostic push
707 #pragma clang diagnostic ignored "-Wobjc-missing-super-calls"
708 - (void)dealloc
709 {
710     return;
711 }
712 #pragma clang diagnostic pop
713
714 + (WebUndefined *)undefined
715 {
716     return [WebUndefined allocWithZone:NULL];
717 }
718
719 @end