]>
Commit | Line | Data |
---|---|---|
93a37866 A |
1 | /* |
2 | * Copyright (C) 2013 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 | |
81345200 | 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
93a37866 A |
24 | */ |
25 | ||
26 | #include "config.h" | |
27 | ||
28 | #import "APICast.h" | |
81345200 | 29 | #import "JSCInlines.h" |
93a37866 | 30 | #import "JSContextInternal.h" |
81345200 A |
31 | #import "JSContextPrivate.h" |
32 | #import "JSContextRefInternal.h" | |
93a37866 A |
33 | #import "JSGlobalObject.h" |
34 | #import "JSValueInternal.h" | |
35 | #import "JSVirtualMachineInternal.h" | |
36 | #import "JSWrapperMap.h" | |
37 | #import "JavaScriptCore.h" | |
38 | #import "ObjcRuntimeExtras.h" | |
93a37866 A |
39 | #import "StrongInlines.h" |
40 | #import <wtf/HashSet.h> | |
41 | ||
42 | #if JSC_OBJC_API_ENABLED | |
43 | ||
44 | @implementation JSContext { | |
45 | JSVirtualMachine *m_virtualMachine; | |
46 | JSGlobalContextRef m_context; | |
47 | JSWrapperMap *m_wrapperMap; | |
48 | JSC::Strong<JSC::JSObject> m_exception; | |
49 | } | |
50 | ||
51 | @synthesize exceptionHandler; | |
52 | ||
53 | - (JSGlobalContextRef)JSGlobalContextRef | |
54 | { | |
55 | return m_context; | |
56 | } | |
57 | ||
81345200 | 58 | - (instancetype)init |
93a37866 A |
59 | { |
60 | return [self initWithVirtualMachine:[[[JSVirtualMachine alloc] init] autorelease]]; | |
61 | } | |
62 | ||
81345200 | 63 | - (instancetype)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine |
93a37866 A |
64 | { |
65 | self = [super init]; | |
66 | if (!self) | |
67 | return nil; | |
68 | ||
69 | m_virtualMachine = [virtualMachine retain]; | |
70 | m_context = JSGlobalContextCreateInGroup(getGroupFromVirtualMachine(virtualMachine), 0); | |
71 | m_wrapperMap = [[JSWrapperMap alloc] initWithContext:self]; | |
72 | ||
73 | self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { | |
74 | context.exception = exceptionValue; | |
75 | }; | |
76 | ||
77 | [m_virtualMachine addContext:self forGlobalContextRef:m_context]; | |
78 | ||
79 | return self; | |
80 | } | |
81 | ||
82 | - (void)dealloc | |
83 | { | |
81345200 | 84 | m_exception.clear(); |
93a37866 A |
85 | [m_wrapperMap release]; |
86 | JSGlobalContextRelease(m_context); | |
87 | [m_virtualMachine release]; | |
88 | [self.exceptionHandler release]; | |
89 | [super dealloc]; | |
90 | } | |
91 | ||
92 | - (JSValue *)evaluateScript:(NSString *)script | |
93 | { | |
81345200 A |
94 | return [self evaluateScript:script withSourceURL:nil]; |
95 | } | |
96 | ||
97 | - (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL | |
98 | { | |
99 | JSValueRef exceptionValue = nullptr; | |
93a37866 | 100 | JSStringRef scriptJS = JSStringCreateWithCFString((CFStringRef)script); |
81345200 A |
101 | JSStringRef sourceURLJS = sourceURL ? JSStringCreateWithCFString((CFStringRef)[sourceURL absoluteString]) : nullptr; |
102 | JSValueRef result = JSEvaluateScript(m_context, scriptJS, nullptr, sourceURLJS, 0, &exceptionValue); | |
103 | if (sourceURLJS) | |
104 | JSStringRelease(sourceURLJS); | |
93a37866 A |
105 | JSStringRelease(scriptJS); |
106 | ||
107 | if (exceptionValue) | |
108 | return [self valueFromNotifyException:exceptionValue]; | |
109 | ||
110 | return [JSValue valueWithJSValueRef:result inContext:self]; | |
111 | } | |
112 | ||
113 | - (void)setException:(JSValue *)value | |
114 | { | |
81345200 | 115 | JSC::JSLockHolder locker(toJS(m_context)); |
93a37866 A |
116 | if (value) |
117 | m_exception.set(toJS(m_context)->vm(), toJS(JSValueToObject(m_context, valueInternalValue(value), 0))); | |
118 | else | |
119 | m_exception.clear(); | |
120 | } | |
121 | ||
122 | - (JSValue *)exception | |
123 | { | |
124 | if (!m_exception) | |
125 | return nil; | |
126 | return [JSValue valueWithJSValueRef:toRef(m_exception.get()) inContext:self]; | |
127 | } | |
128 | ||
129 | - (JSWrapperMap *)wrapperMap | |
130 | { | |
131 | return m_wrapperMap; | |
132 | } | |
133 | ||
134 | - (JSValue *)globalObject | |
135 | { | |
136 | return [JSValue valueWithJSValueRef:JSContextGetGlobalObject(m_context) inContext:self]; | |
137 | } | |
138 | ||
139 | + (JSContext *)currentContext | |
140 | { | |
141 | WTFThreadData& threadData = wtfThreadData(); | |
142 | CallbackData *entry = (CallbackData *)threadData.m_apiData; | |
143 | return entry ? entry->context : nil; | |
144 | } | |
145 | ||
146 | + (JSValue *)currentThis | |
147 | { | |
148 | WTFThreadData& threadData = wtfThreadData(); | |
149 | CallbackData *entry = (CallbackData *)threadData.m_apiData; | |
81345200 A |
150 | if (!entry) |
151 | return nil; | |
152 | return [JSValue valueWithJSValueRef:entry->thisValue inContext:[JSContext currentContext]]; | |
153 | } | |
93a37866 | 154 | |
81345200 A |
155 | + (JSValue *)currentCallee |
156 | { | |
157 | WTFThreadData& threadData = wtfThreadData(); | |
158 | CallbackData *entry = (CallbackData *)threadData.m_apiData; | |
159 | if (!entry) | |
160 | return nil; | |
161 | return [JSValue valueWithJSValueRef:entry->calleeValue inContext:[JSContext currentContext]]; | |
93a37866 A |
162 | } |
163 | ||
164 | + (NSArray *)currentArguments | |
165 | { | |
166 | WTFThreadData& threadData = wtfThreadData(); | |
167 | CallbackData *entry = (CallbackData *)threadData.m_apiData; | |
168 | ||
81345200 A |
169 | if (!entry) |
170 | return nil; | |
171 | ||
93a37866 A |
172 | if (!entry->currentArguments) { |
173 | JSContext *context = [JSContext currentContext]; | |
174 | size_t count = entry->argumentCount; | |
175 | JSValue * argumentArray[count]; | |
176 | for (size_t i =0; i < count; ++i) | |
177 | argumentArray[i] = [JSValue valueWithJSValueRef:entry->arguments[i] inContext:context]; | |
178 | entry->currentArguments = [[NSArray alloc] initWithObjects:argumentArray count:count]; | |
179 | } | |
180 | ||
181 | return entry->currentArguments; | |
182 | } | |
183 | ||
184 | - (JSVirtualMachine *)virtualMachine | |
185 | { | |
186 | return m_virtualMachine; | |
187 | } | |
188 | ||
81345200 A |
189 | - (NSString *)name |
190 | { | |
191 | JSStringRef name = JSGlobalContextCopyName(m_context); | |
192 | if (!name) | |
193 | return nil; | |
194 | ||
ed1e77d3 | 195 | return (NSString *)adoptCF(JSStringCopyCFString(kCFAllocatorDefault, name)).autorelease(); |
81345200 A |
196 | } |
197 | ||
198 | - (void)setName:(NSString *)name | |
199 | { | |
200 | JSStringRef nameJS = name ? JSStringCreateWithCFString((CFStringRef)[[name copy] autorelease]) : nullptr; | |
201 | JSGlobalContextSetName(m_context, nameJS); | |
202 | if (nameJS) | |
203 | JSStringRelease(nameJS); | |
204 | } | |
205 | ||
206 | - (BOOL)_remoteInspectionEnabled | |
207 | { | |
208 | return JSGlobalContextGetRemoteInspectionEnabled(m_context); | |
209 | } | |
210 | ||
211 | - (void)_setRemoteInspectionEnabled:(BOOL)enabled | |
212 | { | |
213 | JSGlobalContextSetRemoteInspectionEnabled(m_context, enabled); | |
214 | } | |
215 | ||
216 | - (BOOL)_includesNativeCallStackWhenReportingExceptions | |
217 | { | |
218 | return JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(m_context); | |
219 | } | |
220 | ||
221 | - (void)_setIncludesNativeCallStackWhenReportingExceptions:(BOOL)includeNativeCallStack | |
222 | { | |
223 | JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(m_context, includeNativeCallStack); | |
224 | } | |
225 | ||
226 | - (CFRunLoopRef)_debuggerRunLoop | |
227 | { | |
228 | return JSGlobalContextGetDebuggerRunLoop(m_context); | |
229 | } | |
230 | ||
231 | - (void)_setDebuggerRunLoop:(CFRunLoopRef)runLoop | |
232 | { | |
233 | JSGlobalContextSetDebuggerRunLoop(m_context, runLoop); | |
234 | } | |
235 | ||
93a37866 A |
236 | @end |
237 | ||
238 | @implementation JSContext(SubscriptSupport) | |
239 | ||
240 | - (JSValue *)objectForKeyedSubscript:(id)key | |
241 | { | |
242 | return [self globalObject][key]; | |
243 | } | |
244 | ||
245 | - (void)setObject:(id)object forKeyedSubscript:(NSObject <NSCopying> *)key | |
246 | { | |
247 | [self globalObject][key] = object; | |
248 | } | |
249 | ||
250 | @end | |
251 | ||
81345200 | 252 | @implementation JSContext (Internal) |
93a37866 | 253 | |
81345200 | 254 | - (instancetype)initWithGlobalContextRef:(JSGlobalContextRef)context |
93a37866 A |
255 | { |
256 | self = [super init]; | |
257 | if (!self) | |
258 | return nil; | |
259 | ||
260 | JSC::JSGlobalObject* globalObject = toJS(context)->lexicalGlobalObject(); | |
261 | m_virtualMachine = [[JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&globalObject->vm())] retain]; | |
262 | ASSERT(m_virtualMachine); | |
263 | m_context = JSGlobalContextRetain(context); | |
264 | m_wrapperMap = [[JSWrapperMap alloc] initWithContext:self]; | |
265 | ||
266 | self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { | |
267 | context.exception = exceptionValue; | |
268 | }; | |
269 | ||
270 | [m_virtualMachine addContext:self forGlobalContextRef:m_context]; | |
271 | ||
272 | return self; | |
273 | } | |
274 | ||
275 | - (void)notifyException:(JSValueRef)exceptionValue | |
276 | { | |
277 | self.exceptionHandler(self, [JSValue valueWithJSValueRef:exceptionValue inContext:self]); | |
278 | } | |
279 | ||
280 | - (JSValue *)valueFromNotifyException:(JSValueRef)exceptionValue | |
281 | { | |
282 | [self notifyException:exceptionValue]; | |
283 | return [JSValue valueWithUndefinedInContext:self]; | |
284 | } | |
285 | ||
286 | - (BOOL)boolFromNotifyException:(JSValueRef)exceptionValue | |
287 | { | |
288 | [self notifyException:exceptionValue]; | |
289 | return NO; | |
290 | } | |
291 | ||
81345200 | 292 | - (void)beginCallbackWithData:(CallbackData *)callbackData calleeValue:(JSValueRef)calleeValue thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments |
93a37866 A |
293 | { |
294 | WTFThreadData& threadData = wtfThreadData(); | |
295 | [self retain]; | |
296 | CallbackData *prevStack = (CallbackData *)threadData.m_apiData; | |
81345200 | 297 | *callbackData = (CallbackData){ prevStack, self, [self.exception retain], calleeValue, thisValue, argumentCount, arguments, nil }; |
93a37866 A |
298 | threadData.m_apiData = callbackData; |
299 | self.exception = nil; | |
300 | } | |
301 | ||
302 | - (void)endCallbackWithData:(CallbackData *)callbackData | |
303 | { | |
304 | WTFThreadData& threadData = wtfThreadData(); | |
305 | self.exception = callbackData->preservedException; | |
306 | [callbackData->preservedException release]; | |
93a37866 A |
307 | [callbackData->currentArguments release]; |
308 | threadData.m_apiData = callbackData->next; | |
309 | [self release]; | |
310 | } | |
311 | ||
312 | - (JSValue *)wrapperForObjCObject:(id)object | |
313 | { | |
81345200 | 314 | JSC::JSLockHolder locker(toJS(m_context)); |
93a37866 A |
315 | return [m_wrapperMap jsWrapperForObject:object]; |
316 | } | |
317 | ||
318 | - (JSValue *)wrapperForJSObject:(JSValueRef)value | |
319 | { | |
81345200 | 320 | JSC::JSLockHolder locker(toJS(m_context)); |
93a37866 A |
321 | return [m_wrapperMap objcWrapperForJSValueRef:value]; |
322 | } | |
323 | ||
324 | + (JSContext *)contextWithJSGlobalContextRef:(JSGlobalContextRef)globalContext | |
325 | { | |
326 | JSVirtualMachine *virtualMachine = [JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&toJS(globalContext)->vm())]; | |
327 | JSContext *context = [virtualMachine contextForGlobalContextRef:globalContext]; | |
328 | if (!context) | |
329 | context = [[[JSContext alloc] initWithGlobalContextRef:globalContext] autorelease]; | |
330 | return context; | |
331 | } | |
332 | ||
333 | @end | |
334 | ||
335 | WeakContextRef::WeakContextRef(JSContext *context) | |
336 | { | |
337 | objc_initWeak(&m_weakContext, context); | |
338 | } | |
339 | ||
340 | WeakContextRef::~WeakContextRef() | |
341 | { | |
342 | objc_destroyWeak(&m_weakContext); | |
343 | } | |
344 | ||
345 | JSContext * WeakContextRef::get() | |
346 | { | |
347 | return objc_loadWeak(&m_weakContext); | |
348 | } | |
349 | ||
350 | void WeakContextRef::set(JSContext *context) | |
351 | { | |
352 | objc_storeWeak(&m_weakContext, context); | |
353 | } | |
354 | ||
355 | #endif |