2 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
28 #import "JSManagedValue.h"
30 #if JSC_OBJC_API_ENABLED
34 #import "JSCJSValueInlines.h"
35 #import "JSContextInternal.h"
36 #import "JSValueInternal.h"
38 #import "WeakHandleOwner.h"
39 #import "ObjcRuntimeExtras.h"
41 class JSManagedValueHandleOwner : public JSC::WeakHandleOwner {
43 virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
44 virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
47 static JSManagedValueHandleOwner* managedValueHandleOwner()
49 DEFINE_STATIC_LOCAL(JSManagedValueHandleOwner, jsManagedValueHandleOwner, ());
50 return &jsManagedValueHandleOwner;
71 u.m_primitive = JSC::JSValue();
80 RELEASE_ASSERT_NOT_REACHED();
89 return !u.m_primitive;
95 RELEASE_ASSERT_NOT_REACHED();
98 bool isSet() const { return m_tag != NotSet; }
99 bool isPrimitive() const { return m_tag == Primitive; }
100 bool isObject() const { return m_tag == Object; }
101 bool isString() const { return m_tag == String; }
103 void setPrimitive(JSC::JSValue primitive)
106 ASSERT(!u.m_primitive);
107 ASSERT(primitive.isPrimitive());
109 u.m_primitive = primitive;
112 void setObject(JSC::JSObject* object, void* context)
117 JSC::Weak<JSC::JSObject> weak(object, managedValueHandleOwner(), context);
118 u.m_object.swap(weak);
121 void setString(JSC::JSString* string, void* context)
126 JSC::Weak<JSC::JSString> weak(string, managedValueHandleOwner(), context);
127 u.m_string.swap(weak);
130 JSC::JSObject* object()
133 return u.m_object.get();
136 JSC::JSValue primitive()
138 ASSERT(isPrimitive());
139 return u.m_primitive;
142 JSC::JSString* string()
145 return u.m_string.get();
149 enum WeakTypeTag { NotSet, Primitive, Object, String };
151 union WeakValueUnion {
154 : m_primitive(JSC::JSValue())
160 ASSERT(!m_primitive);
163 JSC::JSValue m_primitive;
164 JSC::Weak<JSC::JSObject> m_object;
165 JSC::Weak<JSC::JSString> m_string;
169 @implementation JSManagedValue {
170 JSC::Weak<JSC::JSGlobalObject> m_globalObject;
171 WeakValueRef m_weakValue;
174 + (JSManagedValue *)managedValueWithValue:(JSValue *)value
176 return [[[self alloc] initWithValue:value] autorelease];
181 return [self initWithValue:nil];
184 - (id)initWithValue:(JSValue *)value
193 JSC::ExecState* exec = toJS([value.context JSGlobalContextRef]);
194 JSC::JSGlobalObject* globalObject = exec->lexicalGlobalObject();
195 JSC::Weak<JSC::JSGlobalObject> weak(globalObject, managedValueHandleOwner(), self);
196 m_globalObject.swap(weak);
198 JSC::JSValue jsValue = toJS(exec, [value JSValueRef]);
199 if (jsValue.isObject())
200 m_weakValue.setObject(JSC::jsCast<JSC::JSObject*>(jsValue.asCell()), self);
201 else if (jsValue.isString())
202 m_weakValue.setString(JSC::jsCast<JSC::JSString*>(jsValue.asCell()), self);
204 m_weakValue.setPrimitive(jsValue);
212 if (m_weakValue.isClear())
214 JSC::ExecState* exec = m_globalObject->globalExec();
215 JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(exec)];
217 if (m_weakValue.isPrimitive())
218 value = m_weakValue.primitive();
219 else if (m_weakValue.isString())
220 value = m_weakValue.string();
222 value = m_weakValue.object();
223 return [JSValue valueWithJSValueRef:toRef(exec, value) inContext:context];
226 - (void)disconnectValue
228 m_globalObject.clear();
234 @interface JSManagedValue (PrivateMethods)
235 - (void)disconnectValue;
238 bool JSManagedValueHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor& visitor)
240 JSManagedValue *managedValue = static_cast<JSManagedValue *>(context);
241 return visitor.containsOpaqueRoot(managedValue);
244 void JSManagedValueHandleOwner::finalize(JSC::Handle<JSC::Unknown>, void* context)
246 JSManagedValue *managedValue = static_cast<JSManagedValue *>(context);
247 [managedValue disconnectValue];
250 #endif // JSC_OBJC_API_ENABLED