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 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 "APIShims.h" 30#import "JSContextInternal.h" 31#import "JSGlobalObject.h" 32#import "JSValueInternal.h" 33#import "JSVirtualMachineInternal.h" 34#import "JSWrapperMap.h" 35#import "JavaScriptCore.h" 36#import "ObjcRuntimeExtras.h" 37#import "Operations.h" 38#import "StrongInlines.h" 39#import <wtf/HashSet.h> 40 41#if JSC_OBJC_API_ENABLED 42 43@implementation JSContext { 44 JSVirtualMachine *m_virtualMachine; 45 JSGlobalContextRef m_context; 46 JSWrapperMap *m_wrapperMap; 47 JSC::Strong<JSC::JSObject> m_exception; 48} 49 50@synthesize exceptionHandler; 51 52- (JSGlobalContextRef)JSGlobalContextRef 53{ 54 return m_context; 55} 56 57- (id)init 58{ 59 return [self initWithVirtualMachine:[[[JSVirtualMachine alloc] init] autorelease]]; 60} 61 62- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine 63{ 64 self = [super init]; 65 if (!self) 66 return nil; 67 68 m_virtualMachine = [virtualMachine retain]; 69 m_context = JSGlobalContextCreateInGroup(getGroupFromVirtualMachine(virtualMachine), 0); 70 m_wrapperMap = [[JSWrapperMap alloc] initWithContext:self]; 71 72 self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { 73 context.exception = exceptionValue; 74 }; 75 76 [m_virtualMachine addContext:self forGlobalContextRef:m_context]; 77 78 return self; 79} 80 81- (void)dealloc 82{ 83 [m_wrapperMap release]; 84 JSGlobalContextRelease(m_context); 85 [m_virtualMachine release]; 86 [self.exceptionHandler release]; 87 [super dealloc]; 88} 89 90- (JSValue *)evaluateScript:(NSString *)script 91{ 92 JSValueRef exceptionValue = 0; 93 JSStringRef scriptJS = JSStringCreateWithCFString((CFStringRef)script); 94 JSValueRef result = JSEvaluateScript(m_context, scriptJS, 0, 0, 0, &exceptionValue); 95 JSStringRelease(scriptJS); 96 97 if (exceptionValue) 98 return [self valueFromNotifyException:exceptionValue]; 99 100 return [JSValue valueWithJSValueRef:result inContext:self]; 101} 102 103- (void)setException:(JSValue *)value 104{ 105 if (value) 106 m_exception.set(toJS(m_context)->vm(), toJS(JSValueToObject(m_context, valueInternalValue(value), 0))); 107 else 108 m_exception.clear(); 109} 110 111- (JSValue *)exception 112{ 113 if (!m_exception) 114 return nil; 115 return [JSValue valueWithJSValueRef:toRef(m_exception.get()) inContext:self]; 116} 117 118- (JSWrapperMap *)wrapperMap 119{ 120 return m_wrapperMap; 121} 122 123- (JSValue *)globalObject 124{ 125 return [JSValue valueWithJSValueRef:JSContextGetGlobalObject(m_context) inContext:self]; 126} 127 128+ (JSContext *)currentContext 129{ 130 WTFThreadData& threadData = wtfThreadData(); 131 CallbackData *entry = (CallbackData *)threadData.m_apiData; 132 return entry ? entry->context : nil; 133} 134 135+ (JSValue *)currentThis 136{ 137 WTFThreadData& threadData = wtfThreadData(); 138 CallbackData *entry = (CallbackData *)threadData.m_apiData; 139 140 if (!entry->currentThis) 141 entry->currentThis = [[JSValue alloc] initWithValue:entry->thisValue inContext:[JSContext currentContext]]; 142 143 return entry->currentThis; 144} 145 146+ (NSArray *)currentArguments 147{ 148 WTFThreadData& threadData = wtfThreadData(); 149 CallbackData *entry = (CallbackData *)threadData.m_apiData; 150 151 if (!entry->currentArguments) { 152 JSContext *context = [JSContext currentContext]; 153 size_t count = entry->argumentCount; 154 JSValue * argumentArray[count]; 155 for (size_t i =0; i < count; ++i) 156 argumentArray[i] = [JSValue valueWithJSValueRef:entry->arguments[i] inContext:context]; 157 entry->currentArguments = [[NSArray alloc] initWithObjects:argumentArray count:count]; 158 } 159 160 return entry->currentArguments; 161} 162 163- (JSVirtualMachine *)virtualMachine 164{ 165 return m_virtualMachine; 166} 167 168@end 169 170@implementation JSContext(SubscriptSupport) 171 172- (JSValue *)objectForKeyedSubscript:(id)key 173{ 174 return [self globalObject][key]; 175} 176 177- (void)setObject:(id)object forKeyedSubscript:(NSObject <NSCopying> *)key 178{ 179 [self globalObject][key] = object; 180} 181 182@end 183 184@implementation JSContext(Internal) 185 186- (id)initWithGlobalContextRef:(JSGlobalContextRef)context 187{ 188 self = [super init]; 189 if (!self) 190 return nil; 191 192 JSC::JSGlobalObject* globalObject = toJS(context)->lexicalGlobalObject(); 193 m_virtualMachine = [[JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&globalObject->vm())] retain]; 194 ASSERT(m_virtualMachine); 195 m_context = JSGlobalContextRetain(context); 196 m_wrapperMap = [[JSWrapperMap alloc] initWithContext:self]; 197 198 self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { 199 context.exception = exceptionValue; 200 }; 201 202 [m_virtualMachine addContext:self forGlobalContextRef:m_context]; 203 204 return self; 205} 206 207- (void)notifyException:(JSValueRef)exceptionValue 208{ 209 self.exceptionHandler(self, [JSValue valueWithJSValueRef:exceptionValue inContext:self]); 210} 211 212- (JSValue *)valueFromNotifyException:(JSValueRef)exceptionValue 213{ 214 [self notifyException:exceptionValue]; 215 return [JSValue valueWithUndefinedInContext:self]; 216} 217 218- (BOOL)boolFromNotifyException:(JSValueRef)exceptionValue 219{ 220 [self notifyException:exceptionValue]; 221 return NO; 222} 223 224- (void)beginCallbackWithData:(CallbackData *)callbackData thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments 225{ 226 WTFThreadData& threadData = wtfThreadData(); 227 [self retain]; 228 CallbackData *prevStack = (CallbackData *)threadData.m_apiData; 229 *callbackData = (CallbackData){ prevStack, self, [self.exception retain], thisValue, nil, argumentCount, arguments, nil }; 230 threadData.m_apiData = callbackData; 231 self.exception = nil; 232} 233 234- (void)endCallbackWithData:(CallbackData *)callbackData 235{ 236 WTFThreadData& threadData = wtfThreadData(); 237 self.exception = callbackData->preservedException; 238 [callbackData->preservedException release]; 239 [callbackData->currentThis release]; 240 [callbackData->currentArguments release]; 241 threadData.m_apiData = callbackData->next; 242 [self release]; 243} 244 245- (JSValue *)wrapperForObjCObject:(id)object 246{ 247 // Lock access to m_wrapperMap 248 JSC::JSLockHolder lock(toJS(m_context)); 249 return [m_wrapperMap jsWrapperForObject:object]; 250} 251 252- (JSValue *)wrapperForJSObject:(JSValueRef)value 253{ 254 JSC::JSLockHolder lock(toJS(m_context)); 255 return [m_wrapperMap objcWrapperForJSValueRef:value]; 256} 257 258+ (JSContext *)contextWithJSGlobalContextRef:(JSGlobalContextRef)globalContext 259{ 260 JSVirtualMachine *virtualMachine = [JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&toJS(globalContext)->vm())]; 261 JSContext *context = [virtualMachine contextForGlobalContextRef:globalContext]; 262 if (!context) 263 context = [[[JSContext alloc] initWithGlobalContextRef:globalContext] autorelease]; 264 return context; 265} 266 267@end 268 269WeakContextRef::WeakContextRef(JSContext *context) 270{ 271 objc_initWeak(&m_weakContext, context); 272} 273 274WeakContextRef::~WeakContextRef() 275{ 276 objc_destroyWeak(&m_weakContext); 277} 278 279JSContext * WeakContextRef::get() 280{ 281 return objc_loadWeak(&m_weakContext); 282} 283 284void WeakContextRef::set(JSContext *context) 285{ 286 objc_storeWeak(&m_weakContext, context); 287} 288 289#endif 290