Unreviewed, rolling out r243672.
[WebKit-https.git] / Source / JavaScriptCore / API / JSContext.mm
1 /*
2  * Copyright (C) 2013-2019 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
28 #import "APICast.h"
29 #import "Completion.h"
30 #import "JSBaseInternal.h"
31 #import "JSCInlines.h"
32 #import "JSContextInternal.h"
33 #import "JSContextPrivate.h"
34 #import "JSContextRefInternal.h"
35 #import "JSGlobalObject.h"
36 #import "JSInternalPromise.h"
37 #import "JSModuleLoader.h"
38 #import "JSValueInternal.h"
39 #import "JSVirtualMachineInternal.h"
40 #import "JSWrapperMap.h"
41 #import "JavaScriptCore.h"
42 #import "ObjcRuntimeExtras.h"
43 #import "StrongInlines.h"
44
45 #import <wtf/WeakObjCPtr.h>
46
47 #if JSC_OBJC_API_ENABLED
48
49 @implementation JSContext {
50     JSVirtualMachine *m_virtualMachine;
51     JSGlobalContextRef m_context;
52     JSC::Strong<JSC::JSObject> m_exception;
53     WeakObjCPtr<id <JSModuleLoaderDelegate>> m_moduleLoaderDelegate;
54 }
55
56 - (JSGlobalContextRef)JSGlobalContextRef
57 {
58     return m_context;
59 }
60
61 - (void)ensureWrapperMap
62 {
63     if (!toJS([self JSGlobalContextRef])->lexicalGlobalObject()->wrapperMap()) {
64         // The map will be retained by the GlobalObject in initialization.
65         [[[JSWrapperMap alloc] initWithGlobalContextRef:[self JSGlobalContextRef]] release];
66     }
67 }
68
69 - (instancetype)init
70 {
71     return [self initWithVirtualMachine:[[[JSVirtualMachine alloc] init] autorelease]];
72 }
73
74 - (instancetype)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine
75 {
76     self = [super init];
77     if (!self)
78         return nil;
79
80     m_virtualMachine = [virtualMachine retain];
81     m_context = JSGlobalContextCreateInGroup(getGroupFromVirtualMachine(virtualMachine), 0);
82
83     self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
84         context.exception = exceptionValue;
85     };
86
87     [self ensureWrapperMap];
88
89     toJSGlobalObject(m_context)->setAPIWrapper((__bridge void*)self);
90
91     return self;
92 }
93
94 - (void)dealloc
95 {
96     toJSGlobalObject(m_context)->setAPIWrapper((__bridge void*)nil);
97     m_exception.clear();
98     JSGlobalContextRelease(m_context);
99     [m_virtualMachine release];
100     [_exceptionHandler release];
101     [super dealloc];
102 }
103
104 - (JSValue *)evaluateScript:(NSString *)script
105 {
106     return [self evaluateScript:script withSourceURL:nil];
107 }
108
109 - (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL
110 {
111     JSValueRef exceptionValue = nullptr;
112     auto scriptJS = OpaqueJSString::tryCreate(script);
113     auto sourceURLJS = OpaqueJSString::tryCreate([sourceURL absoluteString]);
114     JSValueRef result = JSEvaluateScript(m_context, scriptJS.get(), nullptr, sourceURLJS.get(), 0, &exceptionValue);
115
116     if (exceptionValue)
117         return [self valueFromNotifyException:exceptionValue];
118     return [JSValue valueWithJSValueRef:result inContext:self];
119 }
120
121 - (JSValue *)evaluateJSScript:(JSScript *)script
122 {
123     JSC::ExecState* exec = toJS(m_context);
124     JSC::VM& vm = exec->vm();
125     JSC::JSLockHolder locker(vm);
126
127     if (script.type == kJSScriptTypeProgram) {
128         JSValueRef exceptionValue = nullptr;
129         JSC::SourceCode sourceCode = [script sourceCode];
130         JSValueRef result = JSEvaluateScriptInternal(locker, exec, m_context, nullptr, sourceCode, &exceptionValue);
131
132         if (exceptionValue)
133             return [self valueFromNotifyException:exceptionValue];
134         return [JSValue valueWithJSValueRef:result inContext:self];
135     }
136
137     auto* globalObject = JSC::jsDynamicCast<JSC::JSAPIGlobalObject*>(vm, exec->lexicalGlobalObject());
138     if (!globalObject)
139         return [JSValue valueWithNewPromiseRejectedWithReason:[JSValue valueWithNewErrorFromMessage:@"Context does not support module loading" inContext:self] inContext:self];
140
141     auto scope = DECLARE_CATCH_SCOPE(vm);
142     JSC::JSValue result = globalObject->loadAndEvaluateJSScriptModule(locker, script);
143     if (scope.exception()) {
144         JSValueRef exceptionValue = toRef(exec, scope.exception()->value());
145         scope.clearException();
146         return [JSValue valueWithNewPromiseRejectedWithReason:[JSValue valueWithJSValueRef:exceptionValue inContext:self] inContext:self];
147     }
148     return [JSValue valueWithJSValueRef:toRef(vm, result) inContext:self];
149 }
150
151 - (void)setException:(JSValue *)value
152 {
153     JSC::ExecState* exec = toJS(m_context);
154     JSC::VM& vm = exec->vm();
155     JSC::JSLockHolder locker(vm);
156     if (value)
157         m_exception.set(vm, toJS(JSValueToObject(m_context, valueInternalValue(value), 0)));
158     else
159         m_exception.clear();
160 }
161
162 - (JSValue *)exception
163 {
164     if (!m_exception)
165         return nil;
166     return [JSValue valueWithJSValueRef:toRef(m_exception.get()) inContext:self];
167 }
168
169 - (JSValue *)globalObject
170 {
171     return [JSValue valueWithJSValueRef:JSContextGetGlobalObject(m_context) inContext:self];
172 }
173
174 + (JSContext *)currentContext
175 {
176     Thread& thread = Thread::current();
177     CallbackData *entry = (CallbackData *)thread.m_apiData;
178     return entry ? entry->context : nil;
179 }
180
181 + (JSValue *)currentThis
182 {
183     Thread& thread = Thread::current();
184     CallbackData *entry = (CallbackData *)thread.m_apiData;
185     if (!entry)
186         return nil;
187     return [JSValue valueWithJSValueRef:entry->thisValue inContext:[JSContext currentContext]];
188 }
189
190 + (JSValue *)currentCallee
191 {
192     Thread& thread = Thread::current();
193     CallbackData *entry = (CallbackData *)thread.m_apiData;
194     // calleeValue may be null if we are initializing a promise.
195     if (!entry || !entry->calleeValue)
196         return nil;
197     return [JSValue valueWithJSValueRef:entry->calleeValue inContext:[JSContext currentContext]];
198 }
199
200 + (NSArray *)currentArguments
201 {
202     Thread& thread = Thread::current();
203     CallbackData *entry = (CallbackData *)thread.m_apiData;
204
205     if (!entry)
206         return nil;
207
208     if (!entry->currentArguments) {
209         JSContext *context = [JSContext currentContext];
210         size_t count = entry->argumentCount;
211         JSValue * argumentArray[count];
212         for (size_t i =0; i < count; ++i)
213             argumentArray[i] = [JSValue valueWithJSValueRef:entry->arguments[i] inContext:context];
214         entry->currentArguments = [[NSArray alloc] initWithObjects:argumentArray count:count];
215     }
216
217     return entry->currentArguments;
218 }
219
220 - (JSVirtualMachine *)virtualMachine
221 {
222     return m_virtualMachine;
223 }
224
225 - (NSString *)name
226 {
227     JSStringRef name = JSGlobalContextCopyName(m_context);
228     if (!name)
229         return nil;
230
231     return CFBridgingRelease(JSStringCopyCFString(kCFAllocatorDefault, name));
232 }
233
234 - (void)setName:(NSString *)name
235 {
236     JSGlobalContextSetName(m_context, OpaqueJSString::tryCreate(name).get());
237 }
238
239 - (BOOL)_remoteInspectionEnabled
240 {
241     return JSGlobalContextGetRemoteInspectionEnabled(m_context);
242 }
243
244 - (void)_setRemoteInspectionEnabled:(BOOL)enabled
245 {
246     JSGlobalContextSetRemoteInspectionEnabled(m_context, enabled);
247 }
248
249 - (BOOL)_includesNativeCallStackWhenReportingExceptions
250 {
251     return JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(m_context);
252 }
253
254 - (void)_setIncludesNativeCallStackWhenReportingExceptions:(BOOL)includeNativeCallStack
255 {
256     JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(m_context, includeNativeCallStack);
257 }
258
259 - (CFRunLoopRef)_debuggerRunLoop
260 {
261     return JSGlobalContextGetDebuggerRunLoop(m_context);
262 }
263
264 - (void)_setDebuggerRunLoop:(CFRunLoopRef)runLoop
265 {
266     JSGlobalContextSetDebuggerRunLoop(m_context, runLoop);
267 }
268
269 - (id<JSModuleLoaderDelegate>)moduleLoaderDelegate
270 {
271     return m_moduleLoaderDelegate.getAutoreleased();
272 }
273
274 - (void)setModuleLoaderDelegate:(id<JSModuleLoaderDelegate>)moduleLoaderDelegate
275 {
276     m_moduleLoaderDelegate = moduleLoaderDelegate;
277 }
278
279 @end
280
281 @implementation JSContext(SubscriptSupport)
282
283 - (JSValue *)objectForKeyedSubscript:(id)key
284 {
285     return [self globalObject][key];
286 }
287
288 - (void)setObject:(id)object forKeyedSubscript:(NSObject <NSCopying> *)key
289 {
290     [self globalObject][key] = object;
291 }
292
293 @end
294
295 @implementation JSContext (Internal)
296
297 - (instancetype)initWithGlobalContextRef:(JSGlobalContextRef)context
298 {
299     self = [super init];
300     if (!self)
301         return nil;
302
303     JSC::JSGlobalObject* globalObject = toJS(context)->lexicalGlobalObject();
304     m_virtualMachine = [[JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&globalObject->vm())] retain];
305     ASSERT(m_virtualMachine);
306     m_context = JSGlobalContextRetain(context);
307     [self ensureWrapperMap];
308
309     self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
310         context.exception = exceptionValue;
311     };
312
313     toJSGlobalObject(m_context)->setAPIWrapper((__bridge void*)self);
314
315     return self;
316 }
317
318 - (void)notifyException:(JSValueRef)exceptionValue
319 {
320     self.exceptionHandler(self, [JSValue valueWithJSValueRef:exceptionValue inContext:self]);
321 }
322
323 - (JSValue *)valueFromNotifyException:(JSValueRef)exceptionValue
324 {
325     [self notifyException:exceptionValue];
326     return [JSValue valueWithUndefinedInContext:self];
327 }
328
329 - (BOOL)boolFromNotifyException:(JSValueRef)exceptionValue
330 {
331     [self notifyException:exceptionValue];
332     return NO;
333 }
334
335 - (void)beginCallbackWithData:(CallbackData *)callbackData calleeValue:(JSValueRef)calleeValue thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments
336 {
337     Thread& thread = Thread::current();
338     [self retain];
339     CallbackData *prevStack = (CallbackData *)thread.m_apiData;
340     *callbackData = (CallbackData){ prevStack, self, [self.exception retain], calleeValue, thisValue, argumentCount, arguments, nil };
341     thread.m_apiData = callbackData;
342     self.exception = nil;
343 }
344
345 - (void)endCallbackWithData:(CallbackData *)callbackData
346 {
347     Thread& thread = Thread::current();
348     self.exception = callbackData->preservedException;
349     [callbackData->preservedException release];
350     [callbackData->currentArguments release];
351     thread.m_apiData = callbackData->next;
352     [self release];
353 }
354
355 - (JSValue *)wrapperForObjCObject:(id)object
356 {
357     JSC::JSLockHolder locker(toJS(m_context));
358     return [[self wrapperMap] jsWrapperForObject:object inContext:self];
359 }
360
361 - (JSWrapperMap *)wrapperMap
362 {
363     return toJSGlobalObject(m_context)->wrapperMap();
364 }
365
366 - (JSValue *)wrapperForJSObject:(JSValueRef)value
367 {
368     JSC::JSLockHolder locker(toJS(m_context));
369     return [[self wrapperMap] objcWrapperForJSValueRef:value inContext:self];
370 }
371
372 + (JSContext *)contextWithJSGlobalContextRef:(JSGlobalContextRef)globalContext
373 {
374     JSContext *context = (__bridge JSContext *)toJSGlobalObject(globalContext)->apiWrapper();
375     if (!context)
376         context = [[[JSContext alloc] initWithGlobalContextRef:globalContext] autorelease];
377     return context;
378 }
379
380 @end
381
382 #endif