Unreviewed, rolling out r243672.
[WebKit-https.git] / Source / JavaScriptCore / API / JSValue.mm
index d0824c9..86e10cf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "config.h"
-//#import "JSValue.h"
 
 #import "APICast.h"
-#import "APIShims.h"
 #import "DateInstance.h"
 #import "Error.h"
+#import "Exception.h"
 #import "JavaScriptCore.h"
 #import "JSContextInternal.h"
+#import "JSObjectRefPrivate.h"
 #import "JSVirtualMachineInternal.h"
 #import "JSValueInternal.h"
+#import "JSValuePrivate.h"
 #import "JSWrapperMap.h"
 #import "ObjcRuntimeExtras.h"
-#import "Operations.h"
+#import "JSCInlines.h"
 #import "JSCJSValue.h"
+#import "Strong.h"
+#import "StrongInlines.h"
+#import <wtf/Expected.h>
 #import <wtf/HashMap.h>
 #import <wtf/HashSet.h>
+#import <wtf/Lock.h>
+#import <wtf/ObjCRuntimeExtras.h>
 #import <wtf/Vector.h>
-#import <wtf/TCSpinLock.h>
 #import <wtf/text/WTFString.h>
 #import <wtf/text/StringHash.h>
 
-#if JS_OBJC_API_ENABLED
+#if ENABLE(REMOTE_INSPECTOR)
+#import "CallFrame.h"
+#import "JSGlobalObject.h"
+#import "JSGlobalObjectInspectorController.h"
+#endif
+
+#if JSC_OBJC_API_ENABLED
 
 NSString * const JSPropertyDescriptorWritableKey = @"writable";
 NSString * const JSPropertyDescriptorEnumerableKey = @"enumerable";
@@ -58,69 +69,132 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
     JSValueRef m_value;
 }
 
+- (void)dealloc
+{
+    JSValueUnprotect([_context JSGlobalContextRef], m_value);
+    [_context release];
+    _context = nil;
+    [super dealloc];
+}
+
+- (NSString *)description
+{
+    if (id wrapped = tryUnwrapObjcObject([_context JSGlobalContextRef], m_value))
+        return [wrapped description];
+    return [self toString];
+}
+
+- (JSValueRef)JSValueRef
+{
+    return m_value;
+}
+
 + (JSValue *)valueWithObject:(id)value inContext:(JSContext *)context
 {
-    return [JSValue valueWithValue:objectToValue(context, value) inContext:context];
+    return [JSValue valueWithJSValueRef:objectToValue(context, value) inContext:context];
 }
 
 + (JSValue *)valueWithBool:(BOOL)value inContext:(JSContext *)context
 {
-    return [JSValue valueWithValue:JSValueMakeBoolean(contextInternalContext(context), value) inContext:context];
+    return [JSValue valueWithJSValueRef:JSValueMakeBoolean([context JSGlobalContextRef], value) inContext:context];
 }
 
 + (JSValue *)valueWithDouble:(double)value inContext:(JSContext *)context
 {
-    return [JSValue valueWithValue:JSValueMakeNumber(contextInternalContext(context), value) inContext:context];
+    return [JSValue valueWithJSValueRef:JSValueMakeNumber([context JSGlobalContextRef], value) inContext:context];
 }
 
 + (JSValue *)valueWithInt32:(int32_t)value inContext:(JSContext *)context
 {
-    return [JSValue valueWithValue:JSValueMakeNumber(contextInternalContext(context), value) inContext:context];
+    return [JSValue valueWithJSValueRef:JSValueMakeNumber([context JSGlobalContextRef], value) inContext:context];
 }
 
 + (JSValue *)valueWithUInt32:(uint32_t)value inContext:(JSContext *)context
 {
-    return [JSValue valueWithValue:JSValueMakeNumber(contextInternalContext(context), value) inContext:context];
+    return [JSValue valueWithJSValueRef:JSValueMakeNumber([context JSGlobalContextRef], value) inContext:context];
 }
 
 + (JSValue *)valueWithNewObjectInContext:(JSContext *)context
 {
-    return [JSValue valueWithValue:JSObjectMake(contextInternalContext(context), 0, 0) inContext:context];
+    return [JSValue valueWithJSValueRef:JSObjectMake([context JSGlobalContextRef], 0, 0) inContext:context];
 }
 
 + (JSValue *)valueWithNewArrayInContext:(JSContext *)context
 {
-    return [JSValue valueWithValue:JSObjectMakeArray(contextInternalContext(context), 0, NULL, 0) inContext:context];
+    return [JSValue valueWithJSValueRef:JSObjectMakeArray([context JSGlobalContextRef], 0, NULL, 0) inContext:context];
 }
 
 + (JSValue *)valueWithNewRegularExpressionFromPattern:(NSString *)pattern flags:(NSString *)flags inContext:(JSContext *)context
 {
-    JSStringRef patternString = JSStringCreateWithCFString((CFStringRef)pattern);
-    JSStringRef flagsString = JSStringCreateWithCFString((CFStringRef)flags);
-    JSValueRef arguments[2] = { JSValueMakeString(contextInternalContext(context), patternString), JSValueMakeString(contextInternalContext(context), flagsString) };
-    JSStringRelease(patternString);
-    JSStringRelease(flagsString);
-
-    return [JSValue valueWithValue:JSObjectMakeRegExp(contextInternalContext(context), 2, arguments, 0) inContext:context];
+    auto patternString = OpaqueJSString::tryCreate(pattern);
+    auto flagsString = OpaqueJSString::tryCreate(flags);
+    JSValueRef arguments[2] = { JSValueMakeString([context JSGlobalContextRef], patternString.get()), JSValueMakeString([context JSGlobalContextRef], flagsString.get()) };
+    return [JSValue valueWithJSValueRef:JSObjectMakeRegExp([context JSGlobalContextRef], 2, arguments, 0) inContext:context];
 }
 
 + (JSValue *)valueWithNewErrorFromMessage:(NSString *)message inContext:(JSContext *)context
 {
-    JSStringRef string = JSStringCreateWithCFString((CFStringRef)message);
-    JSValueRef argument = JSValueMakeString(contextInternalContext(context), string);
-    JSStringRelease(string);
-
-    return [JSValue valueWithValue:JSObjectMakeError(contextInternalContext(context), 1, &argument, 0) inContext:context];
+    auto string = OpaqueJSString::tryCreate(message);
+    JSValueRef argument = JSValueMakeString([context JSGlobalContextRef], string.get());
+    return [JSValue valueWithJSValueRef:JSObjectMakeError([context JSGlobalContextRef], 1, &argument, 0) inContext:context];
 }
 
 + (JSValue *)valueWithNullInContext:(JSContext *)context
 {
-    return [JSValue valueWithValue:JSValueMakeNull(contextInternalContext(context)) inContext:context];
+    return [JSValue valueWithJSValueRef:JSValueMakeNull([context JSGlobalContextRef]) inContext:context];
 }
 
 + (JSValue *)valueWithUndefinedInContext:(JSContext *)context
 {
-    return [JSValue valueWithValue:JSValueMakeUndefined(contextInternalContext(context)) inContext:context];
+    return [JSValue valueWithJSValueRef:JSValueMakeUndefined([context JSGlobalContextRef]) inContext:context];
+}
+
++ (JSValue *)valueWithNewSymbolFromDescription:(NSString *)description inContext:(JSContext *)context
+{
+    auto string = OpaqueJSString::tryCreate(description);
+    return [JSValue valueWithJSValueRef:JSValueMakeSymbol([context JSGlobalContextRef], string.get()) inContext:context];
+}
+
++ (JSValue *)valueWithNewPromiseInContext:(JSContext *)context fromExecutor:(void (^)(JSValue *, JSValue *))executor
+{
+    JSObjectRef resolve;
+    JSObjectRef reject;
+    JSValueRef exception = nullptr;
+    JSObjectRef promise = JSObjectMakeDeferredPromise([context JSGlobalContextRef], &resolve, &reject, &exception);
+    if (exception) {
+        [context notifyException:exception];
+        return [JSValue valueWithUndefinedInContext:context];
+    }
+
+    JSValue *result = [JSValue valueWithJSValueRef:promise inContext:context];
+    JSValue *rejection = [JSValue valueWithJSValueRef:reject inContext:context];
+    CallbackData callbackData;
+    const size_t argumentCount = 2;
+    JSValueRef arguments[argumentCount];
+    arguments[0] = resolve;
+    arguments[1] = reject;
+
+    [context beginCallbackWithData:&callbackData calleeValue:nullptr thisValue:promise argumentCount:argumentCount arguments:arguments];
+    executor([JSValue valueWithJSValueRef:resolve inContext:context], rejection);
+    if (context.exception)
+        [rejection callWithArguments:@[context.exception]];
+    [context endCallbackWithData:&callbackData];
+
+    return result;
+}
+
++ (JSValue *)valueWithNewPromiseResolvedWithResult:(id)result inContext:(JSContext *)context
+{
+    return [JSValue valueWithNewPromiseInContext:context fromExecutor:^(JSValue *resolve, JSValue *) {
+        [resolve callWithArguments:@[result]];
+    }];
+}
+
++ (JSValue *)valueWithNewPromiseRejectedWithReason:(id)reason inContext:(JSContext *)context
+{
+    return [JSValue valueWithNewPromiseInContext:context fromExecutor:^(JSValue *, JSValue *reject) {
+        [reject callWithArguments:@[reason]];
+    }];
 }
 
 - (id)toObject
@@ -136,13 +210,13 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 
 - (BOOL)toBool
 {
-    return JSValueToBoolean(contextInternalContext(_context), m_value);
+    return JSValueToBoolean([_context JSGlobalContextRef], m_value);
 }
 
 - (double)toDouble
 {
     JSValueRef exception = 0;
-    double result = JSValueToNumber(contextInternalContext(_context), m_value, &exception);
+    double result = JSValueToNumber([_context JSGlobalContextRef], m_value, &exception);
     if (exception) {
         [_context notifyException:exception];
         return std::numeric_limits<double>::quiet_NaN();
@@ -164,7 +238,7 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 - (NSNumber *)toNumber
 {
     JSValueRef exception = 0;
-    id result = valueToNumber(contextInternalContext(_context), m_value, &exception);
+    id result = valueToNumber([_context JSGlobalContextRef], m_value, &exception);
     if (exception)
         [_context notifyException:exception];
     return result;
@@ -173,7 +247,7 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 - (NSString *)toString
 {
     JSValueRef exception = 0;
-    id result = valueToString(contextInternalContext(_context), m_value, &exception);
+    id result = valueToString([_context JSGlobalContextRef], m_value, &exception);
     if (exception)
         [_context notifyException:exception];
     return result;
@@ -182,7 +256,7 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 - (NSDate *)toDate
 {
     JSValueRef exception = 0;
-    id result = valueToDate(contextInternalContext(_context), m_value, &exception);
+    id result = valueToDate([_context JSGlobalContextRef], m_value, &exception);
     if (exception)
         [_context notifyException:exception];
     return result;
@@ -191,7 +265,7 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 - (NSArray *)toArray
 {
     JSValueRef exception = 0;
-    id result = valueToArray(contextInternalContext(_context), m_value, &exception);
+    id result = valueToArray([_context JSGlobalContextRef], m_value, &exception);
     if (exception)
         [_context notifyException:exception];
     return result;
@@ -200,78 +274,86 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 - (NSDictionary *)toDictionary
 {
     JSValueRef exception = 0;
-    id result = valueToDictionary(contextInternalContext(_context), m_value, &exception);
+    id result = valueToDictionary([_context JSGlobalContextRef], m_value, &exception);
     if (exception)
         [_context notifyException:exception];
     return result;
 }
 
-- (JSValue *)valueForProperty:(NSString *)propertyName
+template<typename Result, typename NSStringFunction, typename JSValueFunction, typename... Types>
+inline Expected<Result, JSValueRef> performPropertyOperation(NSStringFunction stringFunction, JSValueFunction jsFunction, JSValue* value, id propertyKey, Types... arguments)
 {
-    JSValueRef exception = 0;
-    JSObjectRef object = JSValueToObject(contextInternalContext(_context), m_value, &exception);
+    JSContext* context = [value context];
+    JSValueRef exception = nullptr;
+    JSObjectRef object = JSValueToObject([context JSGlobalContextRef], [value JSValueRef], &exception);
     if (exception)
-        return [_context valueFromNotifyException:exception];
+        return Unexpected<JSValueRef>(exception);
 
-    JSStringRef name = JSStringCreateWithCFString((CFStringRef)propertyName);
-    JSValueRef result = JSObjectGetProperty(contextInternalContext(_context), object, name, &exception);
-    JSStringRelease(name);
-    if (exception)
-        return [_context valueFromNotifyException:exception];
+    Result result;
+    // If it's a NSString already, reduce indirection and just pass the NSString.
+    if ([propertyKey isKindOfClass:[NSString class]]) {
+        auto name = OpaqueJSString::tryCreate((NSString *)propertyKey);
+        result = stringFunction([context JSGlobalContextRef], object, name.get(), arguments..., &exception);
+    } else
+        result = jsFunction([context JSGlobalContextRef], object, [[JSValue valueWithObject:propertyKey inContext:context] JSValueRef], arguments..., &exception);
+    return Expected<Result, JSValueRef>(result);
+}
+
+- (JSValue *)valueForProperty:(id)key
+{
+    auto result = performPropertyOperation<JSValueRef>(JSObjectGetProperty, JSObjectGetPropertyForKey, self, key);
+    if (!result)
+        return [_context valueFromNotifyException:result.error()];
 
-    return [JSValue valueWithValue:result inContext:_context];
+    return [JSValue valueWithJSValueRef:result.value() inContext:_context];
 }
 
-- (void)setValue:(id)value forProperty:(NSString *)propertyName
+
+- (void)setValue:(id)value forProperty:(JSValueProperty)key
 {
-    JSValueRef exception = 0;
-    JSObjectRef object = JSValueToObject(contextInternalContext(_context), m_value, &exception);
-    if (exception) {
-        [_context notifyException:exception];
-        return;
-    }
+    // We need Unit business because void can't be assigned to in performPropertyOperation and I don't want to duplicate the code...
+    using Unit = std::tuple<>;
+    auto stringSetProperty = [] (auto... args) -> Unit {
+        JSObjectSetProperty(args...);
+        return { };
+    };
 
-    JSStringRef name = JSStringCreateWithCFString((CFStringRef)propertyName);
-    JSObjectSetProperty(contextInternalContext(_context), object, name, objectToValue(_context, value), 0, &exception);
-    JSStringRelease(name);
-    if (exception) {
-        [_context notifyException:exception];
+    auto jsValueSetProperty = [] (auto... args) -> Unit {
+        JSObjectSetPropertyForKey(args...);
+        return { };
+    };
+
+    auto result = performPropertyOperation<Unit>(stringSetProperty, jsValueSetProperty, self, key, objectToValue(_context, value), kJSPropertyAttributeNone);
+    if (!result) {
+        [_context notifyException:result.error()];
         return;
     }
 }
 
-- (BOOL)deleteProperty:(NSString *)propertyName
+- (BOOL)deleteProperty:(JSValueProperty)key
 {
-    JSValueRef exception = 0;
-    JSObjectRef object = JSValueToObject(contextInternalContext(_context), m_value, &exception);
-    if (exception)
-        return [_context boolFromNotifyException:exception];
-
-    JSStringRef name = JSStringCreateWithCFString((CFStringRef)propertyName);
-    BOOL result = JSObjectDeleteProperty(contextInternalContext(_context), object, name, &exception);
-    JSStringRelease(name);
-    if (exception)
-        return [_context boolFromNotifyException:exception];
-
-    return result;
+    Expected<BOOL, JSValueRef> result = performPropertyOperation<BOOL>(JSObjectDeleteProperty, JSObjectDeletePropertyForKey, self, key);
+    if (!result)
+        return [_context boolFromNotifyException:result.error()];
+    return result.value();
 }
 
-- (BOOL)hasProperty:(NSString *)propertyName
+- (BOOL)hasProperty:(JSValueProperty)key
 {
-    JSValueRef exception = 0;
-    JSObjectRef object = JSValueToObject(contextInternalContext(_context), m_value, &exception);
-    if (exception)
-        return [_context boolFromNotifyException:exception];
+    // The C-api doesn't return an exception value for the string version of has property.
+    auto stringHasProperty = [] (JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef*) -> BOOL {
+        return JSObjectHasProperty(ctx, object, propertyName);
+    };
 
-    JSStringRef name = JSStringCreateWithCFString((CFStringRef)propertyName);
-    BOOL result = JSObjectHasProperty(contextInternalContext(_context), object, name);
-    JSStringRelease(name);
-    return result;
+    Expected<BOOL, JSValueRef> result = performPropertyOperation<BOOL>(stringHasProperty, JSObjectHasPropertyForKey, self, key);
+    if (!result)
+        return [_context boolFromNotifyException:result.error()];
+    return result.value();
 }
 
-- (void)defineProperty:(NSString *)property descriptor:(id)descriptor
+- (void)defineProperty:(JSValueProperty)key descriptor:(id)descriptor
 {
-    [[_context globalObject][@"Object"] invokeMethod:@"defineProperty" withArguments:@[ self, property, descriptor ]];
+    [[_context globalObject][@"Object"] invokeMethod:@"defineProperty" withArguments:@[ self, key, descriptor ]];
 }
 
 - (JSValue *)valueAtIndex:(NSUInteger)index
@@ -282,15 +364,15 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
         return [self valueForProperty:[[JSValue valueWithDouble:index inContext:_context] toString]];
 
     JSValueRef exception = 0;
-    JSObjectRef object = JSValueToObject(contextInternalContext(_context), m_value, &exception);
+    JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception);
     if (exception)
         return [_context valueFromNotifyException:exception];
 
-    JSValueRef result = JSObjectGetPropertyAtIndex(contextInternalContext(_context), object, (unsigned)index, &exception);
+    JSValueRef result = JSObjectGetPropertyAtIndex([_context JSGlobalContextRef], object, (unsigned)index, &exception);
     if (exception)
         return [_context valueFromNotifyException:exception];
 
-    return [JSValue valueWithValue:result inContext:_context];
+    return [JSValue valueWithJSValueRef:result inContext:_context];
 }
 
 - (void)setValue:(id)value atIndex:(NSUInteger)index
@@ -301,13 +383,13 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
         return [self setValue:value forProperty:[[JSValue valueWithDouble:index inContext:_context] toString]];
 
     JSValueRef exception = 0;
-    JSObjectRef object = JSValueToObject(contextInternalContext(_context), m_value, &exception);
+    JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception);
     if (exception) {
         [_context notifyException:exception];
         return;
     }
 
-    JSObjectSetPropertyAtIndex(contextInternalContext(_context), object, (unsigned)index, objectToValue(_context, value), &exception);
+    JSObjectSetPropertyAtIndex([_context JSGlobalContextRef], object, (unsigned)index, objectToValue(_context, value), &exception);
     if (exception) {
         [_context notifyException:exception];
         return;
@@ -316,43 +398,58 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 
 - (BOOL)isUndefined
 {
-    return JSValueIsUndefined(contextInternalContext(_context), m_value);
+    return JSValueIsUndefined([_context JSGlobalContextRef], m_value);
 }
 
 - (BOOL)isNull
 {
-    return JSValueIsNull(contextInternalContext(_context), m_value);
+    return JSValueIsNull([_context JSGlobalContextRef], m_value);
 }
 
 - (BOOL)isBoolean
 {
-    return JSValueIsBoolean(contextInternalContext(_context), m_value);
+    return JSValueIsBoolean([_context JSGlobalContextRef], m_value);
 }
 
 - (BOOL)isNumber
 {
-    return JSValueIsNumber(contextInternalContext(_context), m_value);
+    return JSValueIsNumber([_context JSGlobalContextRef], m_value);
 }
 
 - (BOOL)isString
 {
-    return JSValueIsString(contextInternalContext(_context), m_value);
+    return JSValueIsString([_context JSGlobalContextRef], m_value);
 }
 
 - (BOOL)isObject
 {
-    return JSValueIsObject(contextInternalContext(_context), m_value);
+    return JSValueIsObject([_context JSGlobalContextRef], m_value);
+}
+
+- (BOOL)isSymbol
+{
+    return JSValueIsSymbol([_context JSGlobalContextRef], m_value);
+}
+
+- (BOOL)isArray
+{
+    return JSValueIsArray([_context JSGlobalContextRef], m_value);
+}
+
+- (BOOL)isDate
+{
+    return JSValueIsDate([_context JSGlobalContextRef], m_value);
 }
 
 - (BOOL)isEqualToObject:(id)value
 {
-    return JSValueIsStrictEqual(contextInternalContext(_context), m_value, objectToValue(_context, value));
+    return JSValueIsStrictEqual([_context JSGlobalContextRef], m_value, objectToValue(_context, value));
 }
 
 - (BOOL)isEqualWithTypeCoercionToObject:(id)value
 {
     JSValueRef exception = 0;
-    BOOL result = JSValueIsEqual(contextInternalContext(_context), m_value, objectToValue(_context, value), &exception);
+    BOOL result = JSValueIsEqual([_context JSGlobalContextRef], m_value, objectToValue(_context, value), &exception);
     if (exception)
         return [_context boolFromNotifyException:exception];
 
@@ -362,11 +459,11 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 - (BOOL)isInstanceOf:(id)value
 {
     JSValueRef exception = 0;
-    JSObjectRef constructor = JSValueToObject(contextInternalContext(_context), objectToValue(_context, value), &exception);
+    JSObjectRef constructor = JSValueToObject([_context JSGlobalContextRef], objectToValue(_context, value), &exception);
     if (exception)
         return [_context boolFromNotifyException:exception];
 
-    BOOL result = JSValueIsInstanceOfConstructor(contextInternalContext(_context), m_value, constructor, &exception);
+    BOOL result = JSValueIsInstanceOfConstructor([_context JSGlobalContextRef], m_value, constructor, &exception);
     if (exception)
         return [_context boolFromNotifyException:exception];
 
@@ -381,15 +478,15 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
         arguments[i] = objectToValue(_context, [argumentArray objectAtIndex:i]);
 
     JSValueRef exception = 0;
-    JSObjectRef object = JSValueToObject(contextInternalContext(_context), m_value, &exception);
+    JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception);
     if (exception)
         return [_context valueFromNotifyException:exception];
 
-    JSValueRef result = JSObjectCallAsFunction(contextInternalContext(_context), object, 0, argumentCount, arguments, &exception);
+    JSValueRef result = JSObjectCallAsFunction([_context JSGlobalContextRef], object, 0, argumentCount, arguments, &exception);
     if (exception)
         return [_context valueFromNotifyException:exception];
 
-    return [JSValue valueWithValue:result inContext:_context];
+    return [JSValue valueWithJSValueRef:result inContext:_context];
 }
 
 - (JSValue *)constructWithArguments:(NSArray *)argumentArray
@@ -400,15 +497,15 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
         arguments[i] = objectToValue(_context, [argumentArray objectAtIndex:i]);
 
     JSValueRef exception = 0;
-    JSObjectRef object = JSValueToObject(contextInternalContext(_context), m_value, &exception);
+    JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception);
     if (exception)
         return [_context valueFromNotifyException:exception];
 
-    JSObjectRef result = JSObjectCallAsConstructor(contextInternalContext(_context), object, argumentCount, arguments, &exception);
+    JSObjectRef result = JSObjectCallAsConstructor([_context JSGlobalContextRef], object, argumentCount, arguments, &exception);
     if (exception)
         return [_context valueFromNotifyException:exception];
 
-    return [JSValue valueWithValue:result inContext:_context];
+    return [JSValue valueWithJSValueRef:result inContext:_context];
 }
 
 - (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments
@@ -419,25 +516,24 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
         argumentArray[i] = objectToValue(_context, [arguments objectAtIndex:i]);
 
     JSValueRef exception = 0;
-    JSObjectRef thisObject = JSValueToObject(contextInternalContext(_context), m_value, &exception);
+    JSObjectRef thisObject = JSValueToObject([_context JSGlobalContextRef], m_value, &exception);
     if (exception)
         return [_context valueFromNotifyException:exception];
 
-    JSStringRef name = JSStringCreateWithCFString((CFStringRef)method);
-    JSValueRef function = JSObjectGetProperty(contextInternalContext(_context), thisObject, name, &exception);
-    JSStringRelease(name);
+    auto name = OpaqueJSString::tryCreate(method);
+    JSValueRef function = JSObjectGetProperty([_context JSGlobalContextRef], thisObject, name.get(), &exception);
     if (exception)
         return [_context valueFromNotifyException:exception];
 
-    JSObjectRef object = JSValueToObject(contextInternalContext(_context), function, &exception);
+    JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], function, &exception);
     if (exception)
         return [_context valueFromNotifyException:exception];
 
-    JSValueRef result = JSObjectCallAsFunction(contextInternalContext(_context), object, thisObject, argumentCount, argumentArray, &exception);
+    JSValueRef result = JSObjectCallAsFunction([_context JSGlobalContextRef], object, thisObject, argumentCount, argumentArray, &exception);
     if (exception)
         return [_context valueFromNotifyException:exception];
 
-    return [JSValue valueWithValue:result inContext:_context];
+    return [JSValue valueWithJSValueRef:result inContext:_context];
 }
 
 @end
@@ -447,8 +543,8 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 - (CGPoint)toPoint
 {
     return (CGPoint){
-        [self[@"x"] toDouble],
-        [self[@"y"] toDouble]
+        static_cast<CGFloat>([self[@"x"] toDouble]),
+        static_cast<CGFloat>([self[@"y"] toDouble])
     };
 }
 
@@ -471,8 +567,8 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 - (CGSize)toSize
 {
     return (CGSize){
-        [self[@"width"] toDouble],
-        [self[@"height"] toDouble]
+        static_cast<CGFloat>([self[@"width"] toDouble]),
+        static_cast<CGFloat>([self[@"height"] toDouble])
     };
 }
 
@@ -516,13 +612,7 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 
 - (JSValue *)objectForKeyedSubscript:(id)key
 {
-    if (![key isKindOfClass:[NSString class]]) {
-        key = [[JSValue valueWithObject:key inContext:_context] toString];
-        if (!key)
-            return [JSValue valueWithUndefinedInContext:_context];
-    }
-
-    return [self valueForProperty:(NSString *)key];
+    return [self valueForProperty:key];
 }
 
 - (JSValue *)objectAtIndexedSubscript:(NSUInteger)index
@@ -530,15 +620,9 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
     return [self valueAtIndex:index];
 }
 
-- (void)setObject:(id)object forKeyedSubscript:(NSObject <NSCopying> *)key
+- (void)setObject:(id)object forKeyedSubscript:(id)key
 {
-    if (![key isKindOfClass:[NSString class]]) {
-        key = [[JSValue valueWithObject:key inContext:_context] toString];
-        if (!key)
-            return;
-    }
-
-    [self setValue:object forProperty:(NSString *)key];
+    [self setValue:object forProperty:key];
 }
 
 - (void)setObject:(id)object atIndexedSubscript:(NSUInteger)index
@@ -548,16 +632,16 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 
 @end
 
-inline bool isDate(JSObjectRef object, JSGlobalContextRef context)
+inline bool isDate(JSC::VM& vm, JSObjectRef object, JSGlobalContextRef context)
 {
-    JSC::APIEntryShim entryShim(toJS(context));
-    return toJS(object)->inherits(&JSC::DateInstance::s_info);
+    JSC::JSLockHolder locker(toJS(context));
+    return toJS(object)->inherits<JSC::DateInstance>(vm);
 }
 
-inline bool isArray(JSObjectRef object, JSGlobalContextRef context)
+inline bool isArray(JSC::VM& vm, JSObjectRef object, JSGlobalContextRef context)
 {
-    JSC::APIEntryShim entryShim(toJS(context));
-    return toJS(object)->inherits(&JSC::JSArray::s_info);
+    JSC::JSLockHolder locker(toJS(context));
+    return toJS(object)->inherits<JSC::JSArray>(vm);
 }
 
 @implementation JSValue(Internal)
@@ -588,13 +672,14 @@ public:
 
 private:
     JSGlobalContextRef m_context;
-    HashMap<JSValueRef, id> m_objectMap;
+    HashMap<JSValueRef, __unsafe_unretained id> m_objectMap;
     Vector<Task> m_worklist;
+    Vector<JSC::Strong<JSC::Unknown>> m_jsValues;
 };
 
 inline id JSContainerConvertor::convert(JSValueRef value)
 {
-    HashMap<JSValueRef, id>::iterator iter = m_objectMap.find(value);
+    auto iter = m_objectMap.find(value);
     if (iter != m_objectMap.end())
         return iter->value;
 
@@ -606,6 +691,8 @@ inline id JSContainerConvertor::convert(JSValueRef value)
 
 void JSContainerConvertor::add(Task task)
 {
+    JSC::ExecState* exec = toJS(m_context);
+    m_jsValues.append(JSC::Strong<JSC::Unknown>(exec->vm(), toJSForGC(exec, task.js)));
     m_objectMap.add(task.js, task.objc);
     if (task.type != ContainerNone)
         m_worklist.append(task);
@@ -619,8 +706,21 @@ JSContainerConvertor::Task JSContainerConvertor::take()
     return last;
 }
 
+#if ENABLE(REMOTE_INSPECTOR)
+static void reportExceptionToInspector(JSGlobalContextRef context, JSC::JSValue exceptionValue)
+{
+    JSC::ExecState* exec = toJS(context);
+    JSC::VM& vm = exec->vm();
+    JSC::Exception* exception = JSC::Exception::create(vm, exceptionValue);
+    vm.vmEntryGlobalObject(exec)->inspectorController().reportAPIException(exec, exception);
+}
+#endif
+
 static JSContainerConvertor::Task valueToObjectWithoutCopy(JSGlobalContextRef context, JSValueRef value)
 {
+    JSC::ExecState* exec = toJS(context);
+    JSC::VM& vm = exec->vm();
+
     if (!JSValueIsObject(context, value)) {
         id primitive;
         if (JSValueIsBoolean(context, value))
@@ -632,42 +732,41 @@ static JSContainerConvertor::Task valueToObjectWithoutCopy(JSGlobalContextRef co
             primitive = [NSNumber numberWithDouble:JSValueToNumber(context, value, 0)];
         } else if (JSValueIsString(context, value)) {
             // Would be nice to unique strings, too.
-            JSStringRef jsstring = JSValueToStringCopy(context, value, 0);
-            NSString * stringNS = (NSString *)JSStringCopyCFString(kCFAllocatorDefault, jsstring);
-            JSStringRelease(jsstring);
-            primitive = [stringNS autorelease];
+            auto jsstring = adoptRef(JSValueToStringCopy(context, value, 0));
+            primitive = CFBridgingRelease(JSStringCopyCFString(kCFAllocatorDefault, jsstring.get()));
         } else if (JSValueIsNull(context, value))
             primitive = [NSNull null];
         else {
             ASSERT(JSValueIsUndefined(context, value));
             primitive = nil;
         }
-        return (JSContainerConvertor::Task){ value, primitive, ContainerNone };
+        return { value, primitive, ContainerNone };
     }
 
     JSObjectRef object = JSValueToObject(context, value, 0);
 
     if (id wrapped = tryUnwrapObjcObject(context, object))
-        return (JSContainerConvertor::Task){ object, wrapped, ContainerNone };
+        return { object, wrapped, ContainerNone };
 
-    if (isDate(object, context))
-        return (JSContainerConvertor::Task){ object, [NSDate dateWithTimeIntervalSince1970:JSValueToNumber(context, object, 0)], ContainerNone };
+    if (isDate(vm, object, context))
+        return { object, [NSDate dateWithTimeIntervalSince1970:JSValueToNumber(context, object, 0) / 1000.0], ContainerNone };
 
-    if (isArray(object, context))
-        return (JSContainerConvertor::Task){ object, [NSMutableArray array], ContainerArray };
+    if (isArray(vm, object, context))
+        return { object, [NSMutableArray array], ContainerArray };
 
-    return (JSContainerConvertor::Task){ object, [NSMutableDictionary dictionary], ContainerDictionary };
+    return { object, [NSMutableDictionary dictionary], ContainerDictionary };
 }
 
 static id containerValueToObject(JSGlobalContextRef context, JSContainerConvertor::Task task)
 {
     ASSERT(task.type != ContainerNone);
+    JSC::JSLockHolder locker(toJS(context));
     JSContainerConvertor convertor(context);
     convertor.add(task);
     ASSERT(!convertor.isWorkListEmpty());
     
     do {
-        JSContainerConvertor::Task current = task = convertor.take();
+        JSContainerConvertor::Task current = convertor.take();
         ASSERT(JSValueIsObject(context, current.js));
         JSObjectRef js = JSValueToObject(context, current.js, 0);
 
@@ -675,9 +774,8 @@ static id containerValueToObject(JSGlobalContextRef context, JSContainerConverto
             ASSERT([current.objc isKindOfClass:[NSMutableArray class]]);
             NSMutableArray *array = (NSMutableArray *)current.objc;
         
-            JSStringRef lengthString = JSStringCreateWithUTF8CString("length");
-            unsigned length = JSC::toUInt32(JSValueToNumber(context, JSObjectGetProperty(context, js, lengthString, 0), 0));
-            JSStringRelease(lengthString);
+            auto lengthString = OpaqueJSString::tryCreate("length"_s);
+            unsigned length = JSC::toUInt32(JSValueToNumber(context, JSObjectGetProperty(context, js, lengthString.get(), 0), 0));
 
             for (unsigned i = 0; i < length; ++i) {
                 id objc = convertor.convert(JSObjectGetPropertyAtIndex(context, js, i, 0));
@@ -687,13 +785,15 @@ static id containerValueToObject(JSGlobalContextRef context, JSContainerConverto
             ASSERT([current.objc isKindOfClass:[NSMutableDictionary class]]);
             NSMutableDictionary *dictionary = (NSMutableDictionary *)current.objc;
 
+            JSC::JSLockHolder locker(toJS(context));
+
             JSPropertyNameArrayRef propertyNameArray = JSObjectCopyPropertyNames(context, js);
             size_t length = JSPropertyNameArrayGetCount(propertyNameArray);
 
             for (size_t i = 0; i < length; ++i) {
                 JSStringRef propertyName = JSPropertyNameArrayGetNameAtIndex(propertyNameArray, i);
                 if (id objc = convertor.convert(JSObjectGetProperty(context, js, propertyName, 0)))
-                    dictionary[[(NSString *)JSStringCopyCFString(kCFAllocatorDefault, propertyName) autorelease]] = objc;
+                    dictionary[(__bridge NSString *)adoptCF(JSStringCopyCFString(kCFAllocatorDefault, propertyName)).get()] = objc;
             }
 
             JSPropertyNameArrayRelease(propertyNameArray);
@@ -706,10 +806,10 @@ static id containerValueToObject(JSGlobalContextRef context, JSContainerConverto
 
 id valueToObject(JSContext *context, JSValueRef value)
 {
-    JSContainerConvertor::Task result = valueToObjectWithoutCopy(contextInternalContext(context), value);
+    JSContainerConvertor::Task result = valueToObjectWithoutCopy([context JSGlobalContextRef], value);
     if (result.type == ContainerNone)
         return result.objc;
-    return containerValueToObject(contextInternalContext(context), result);
+    return containerValueToObject([context JSGlobalContextRef], result);
 }
 
 id valueToNumber(JSGlobalContextRef context, JSValueRef value, JSValueRef* exception)
@@ -735,15 +835,13 @@ id valueToString(JSGlobalContextRef context, JSValueRef value, JSValueRef* excep
             return wrapped;
     }
 
-    JSStringRef jsstring = JSValueToStringCopy(context, value, exception);
+    auto jsstring = adoptRef(JSValueToStringCopy(context, value, exception));
     if (*exception) {
         ASSERT(!jsstring);
         return nil;
     }
 
-    NSString *stringNS = [(NSString *)JSStringCopyCFString(kCFAllocatorDefault, jsstring) autorelease];
-    JSStringRelease(jsstring);
-    return stringNS;
+    return CFBridgingRelease(JSStringCopyCFString(kCFAllocatorDefault, jsstring.get()));
 }
 
 id valueToDate(JSGlobalContextRef context, JSValueRef value, JSValueRef* exception)
@@ -754,7 +852,7 @@ id valueToDate(JSGlobalContextRef context, JSValueRef value, JSValueRef* excepti
             return wrapped;
     }
 
-    double result = JSValueToNumber(context, value, exception);
+    double result = JSValueToNumber(context, value, exception) / 1000.0;
     return *exception ? nil : [NSDate dateWithTimeIntervalSince1970:result];
 }
 
@@ -767,10 +865,16 @@ id valueToArray(JSGlobalContextRef context, JSValueRef value, JSValueRef* except
     }
 
     if (JSValueIsObject(context, value))
-        return containerValueToObject(context, (JSContainerConvertor::Task){ value, [NSMutableArray array], ContainerArray});
-
-    if (!(JSValueIsNull(context, value) || JSValueIsUndefined(context, value)))
-        *exception = toRef(JSC::createTypeError(toJS(context), "Cannot convert primitive to NSArray"));
+        return containerValueToObject(context, { value, [NSMutableArray array], ContainerArray});
+
+    JSC::JSLockHolder locker(toJS(context));
+    if (!(JSValueIsNull(context, value) || JSValueIsUndefined(context, value))) {
+        JSC::JSObject* exceptionObject = JSC::createTypeError(toJS(context), "Cannot convert primitive to NSArray"_s);
+        *exception = toRef(exceptionObject);
+#if ENABLE(REMOTE_INSPECTOR)
+        reportExceptionToInspector(context, exceptionObject);
+#endif
+    }
     return nil;
 }
 
@@ -783,10 +887,16 @@ id valueToDictionary(JSGlobalContextRef context, JSValueRef value, JSValueRef* e
     }
 
     if (JSValueIsObject(context, value))
-        return containerValueToObject(context, (JSContainerConvertor::Task){ value, [NSMutableDictionary dictionary], ContainerDictionary});
-
-    if (!(JSValueIsNull(context, value) || JSValueIsUndefined(context, value)))
-        *exception = toRef(JSC::createTypeError(toJS(context), "Cannot convert primitive to NSDictionary"));
+        return containerValueToObject(context, { value, [NSMutableDictionary dictionary], ContainerDictionary});
+
+    JSC::JSLockHolder locker(toJS(context));
+    if (!(JSValueIsNull(context, value) || JSValueIsUndefined(context, value))) {
+        JSC::JSObject* exceptionObject = JSC::createTypeError(toJS(context), "Cannot convert primitive to NSDictionary"_s);
+        *exception = toRef(exceptionObject);
+#if ENABLE(REMOTE_INSPECTOR)
+        reportExceptionToInspector(context, exceptionObject);
+#endif
+    }
     return nil;
 }
 
@@ -810,8 +920,9 @@ public:
 
 private:
     JSContext *m_context;
-    HashMap<id, JSValueRef> m_objectMap;
+    HashMap<__unsafe_unretained id, JSValueRef> m_objectMap;
     Vector<Task> m_worklist;
+    Vector<JSC::Strong<JSC::Unknown>> m_jsValues;
 };
 
 JSValueRef ObjcContainerConvertor::convert(id object)
@@ -829,6 +940,8 @@ JSValueRef ObjcContainerConvertor::convert(id object)
 
 void ObjcContainerConvertor::add(ObjcContainerConvertor::Task task)
 {
+    JSC::ExecState* exec = toJS(m_context.JSGlobalContextRef);
+    m_jsValues.append(JSC::Strong<JSC::Unknown>(exec->vm(), toJSForGC(exec, task.js)));
     m_objectMap.add(task.objc, task.js);
     if (task.type != ContainerNone)
         m_worklist.append(task);
@@ -852,55 +965,61 @@ inline bool isNSBoolean(id object)
 
 static ObjcContainerConvertor::Task objectToValueWithoutCopy(JSContext *context, id object)
 {
-    JSGlobalContextRef contextRef = contextInternalContext(context);
+    JSGlobalContextRef contextRef = [context JSGlobalContextRef];
 
     if (!object)
-        return (ObjcContainerConvertor::Task){ object, JSValueMakeUndefined(contextRef), ContainerNone };
+        return { object, JSValueMakeUndefined(contextRef), ContainerNone };
 
     if (!class_conformsToProtocol(object_getClass(object), getJSExportProtocol())) {
         if ([object isKindOfClass:[NSArray class]])
-            return (ObjcContainerConvertor::Task){ object, JSObjectMakeArray(contextRef, 0, NULL, 0), ContainerArray };
+            return { object, JSObjectMakeArray(contextRef, 0, NULL, 0), ContainerArray };
 
         if ([object isKindOfClass:[NSDictionary class]])
-            return (ObjcContainerConvertor::Task){ object, JSObjectMake(contextRef, 0, 0), ContainerDictionary };
+            return { object, JSObjectMake(contextRef, 0, 0), ContainerDictionary };
 
         if ([object isKindOfClass:[NSNull class]])
-            return (ObjcContainerConvertor::Task){ object, JSValueMakeNull(contextRef), ContainerNone };
+            return { object, JSValueMakeNull(contextRef), ContainerNone };
 
         if ([object isKindOfClass:[JSValue class]])
-            return (ObjcContainerConvertor::Task){ object, ((JSValue *)object)->m_value, ContainerNone };
+            return { object, ((JSValue *)object)->m_value, ContainerNone };
 
         if ([object isKindOfClass:[NSString class]]) {
-            JSStringRef string = JSStringCreateWithCFString((CFStringRef)object);
-            JSValueRef js = JSValueMakeString(contextRef, string);
-            JSStringRelease(string);
-            return (ObjcContainerConvertor::Task){ object, js, ContainerNone };
+            auto string = OpaqueJSString::tryCreate((NSString *)object);
+            return { object, JSValueMakeString(contextRef, string.get()), ContainerNone };
         }
 
         if ([object isKindOfClass:[NSNumber class]]) {
             if (isNSBoolean(object))
-                return (ObjcContainerConvertor::Task){ object, JSValueMakeBoolean(contextRef, [object boolValue]), ContainerNone };
-            return (ObjcContainerConvertor::Task){ object, JSValueMakeNumber(contextRef, [object doubleValue]), ContainerNone };
+                return { object, JSValueMakeBoolean(contextRef, [object boolValue]), ContainerNone };
+            return { object, JSValueMakeNumber(contextRef, [object doubleValue]), ContainerNone };
         }
 
         if ([object isKindOfClass:[NSDate class]]) {
-            JSValueRef argument = JSValueMakeNumber(contextRef, [object timeIntervalSince1970]);
+            JSValueRef argument = JSValueMakeNumber(contextRef, [object timeIntervalSince1970] * 1000.0);
             JSObjectRef result = JSObjectMakeDate(contextRef, 1, &argument, 0);
-            return (ObjcContainerConvertor::Task){ object, result, ContainerNone };
+            return { object, result, ContainerNone };
+        }
+
+        if ([object isKindOfClass:[JSManagedValue class]]) {
+            JSValue *value = [static_cast<JSManagedValue *>(object) value];
+            if (!value)
+                return  { object, JSValueMakeUndefined(contextRef), ContainerNone };
+            return { object, value->m_value, ContainerNone };
         }
     }
 
-    return (ObjcContainerConvertor::Task){ object, valueInternalValue([context wrapperForObject:object]), ContainerNone };
+    return { object, valueInternalValue([context wrapperForObjCObject:object]), ContainerNone };
 }
 
 JSValueRef objectToValue(JSContext *context, id object)
 {
-    JSGlobalContextRef contextRef = contextInternalContext(context);
+    JSGlobalContextRef contextRef = [context JSGlobalContextRef];
 
     ObjcContainerConvertor::Task task = objectToValueWithoutCopy(context, object);
     if (task.type == ContainerNone)
         return task.js;
 
+    JSC::JSLockHolder locker(toJS(contextRef));
     ObjcContainerConvertor convertor(context);
     convertor.add(task);
     ASSERT(!convertor.isWorkListEmpty());
@@ -922,13 +1041,11 @@ JSValueRef objectToValue(JSContext *context, id object)
             NSDictionary *dictionary = (NSDictionary *)current.objc;
             for (id key in [dictionary keyEnumerator]) {
                 if ([key isKindOfClass:[NSString class]]) {
-                    JSStringRef propertyName = JSStringCreateWithCFString((CFStringRef)key);
-                    JSObjectSetProperty(contextRef, js, propertyName, convertor.convert([dictionary objectForKey:key]), 0, 0);
-                    JSStringRelease(propertyName);
+                    auto propertyName = OpaqueJSString::tryCreate((NSString *)key);
+                    JSObjectSetProperty(contextRef, js, propertyName.get(), convertor.convert([dictionary objectForKey:key]), 0, 0);
                 }
             }
         }
-        
     } while (!convertor.isWorkListEmpty());
 
     return task.js;
@@ -939,21 +1056,28 @@ JSValueRef valueInternalValue(JSValue * value)
     return value->m_value;
 }
 
-+ (JSValue *)valueWithValue:(JSValueRef)value inContext:(JSContext *)context
++ (JSValue *)valueWithJSValueRef:(JSValueRef)value inContext:(JSContext *)context
 {
-    return [[[JSValue alloc] initWithValue:value inContext:context] autorelease];
+    return [context wrapperForJSObject:value];
+}
+
+- (JSValue *)init
+{
+    return nil;
 }
 
 - (JSValue *)initWithValue:(JSValueRef)value inContext:(JSContext *)context
 {
+    if (!value || !context)
+        return nil;
+
     self = [super init];
     if (!self)
         return nil;
 
-    ASSERT(value);
     _context = [context retain];
     m_value = value;
-    JSValueProtect(contextInternalContext(_context), m_value);
+    JSValueProtect([_context JSGlobalContextRef], m_value);
     return self;
 }
 
@@ -983,19 +1107,19 @@ static StructHandlers* createStructHandlerMap()
             return;
         char idType[3];
         // Check 2nd argument type is "@"
-        char* secondType = method_copyArgumentType(method, 3);
-        if (strcmp(secondType, "@") != 0) {
-            free(secondType);
-            return;
+        {
+            auto secondType = adoptSystem<char[]>(method_copyArgumentType(method, 3));
+            if (strcmp(secondType.get(), "@") != 0)
+                return;
         }
-        free(secondType);
         // Check result type is also "@"
         method_getReturnType(method, idType, 3);
         if (strcmp(idType, "@") != 0)
             return;
-        char* type = method_copyArgumentType(method, 2);
-        structHandlers->add(StringImpl::create(type), (StructTagHandler){ selector, 0 });
-        free(type);
+        {
+            auto type = adoptSystem<char[]>(method_copyArgumentType(method, 2));
+            structHandlers->add(StringImpl::create(type.get()), (StructTagHandler) { selector, 0 });
+        }
     });
 
     // Step 2: find all to<Foo> instance methods in JSValue.
@@ -1010,10 +1134,8 @@ static StructHandlers* createStructHandlerMap()
         if (method_getNumberOfArguments(method) != 2)
             return;
         // Try to find a matching valueWith<Foo>:context: method.
-        char* type = method_copyReturnType(method);
-
-        StructHandlers::iterator iter = structHandlers->find(type);
-        free(type);
+        auto type = adoptSystem<char[]>(method_copyReturnType(method));
+        StructHandlers::iterator iter = structHandlers->find(type.get());
         if (iter == structHandlers->end())
             return;
         StructTagHandler& handler = iter->value;
@@ -1046,8 +1168,8 @@ static StructHandlers* createStructHandlerMap()
 
 static StructTagHandler* handerForStructTag(const char* encodedType)
 {
-    static SpinLock handerForStructTagLock = SPINLOCK_INITIALIZER;
-    SpinLockHolder lockHolder(&handerForStructTagLock);
+    static Lock handerForStructTagLock;
+    LockHolder lockHolder(&handerForStructTagLock);
 
     static StructHandlers* structHandlers = createStructHandlerMap();
 
@@ -1069,21 +1191,6 @@ static StructTagHandler* handerForStructTag(const char* encodedType)
     return handler ? handler->valueToTypeSEL : nil;
 }
 
-- (void)dealloc
-{
-    JSValueUnprotect(contextInternalContext(_context), m_value);
-    [_context release];
-    _context = nil;
-    [super dealloc];
-}
-
-- (NSString *)description
-{
-    if (id wrapped = tryUnwrapObjcObject(contextInternalContext(_context), m_value))
-        return [wrapped description];
-    return [self toString];
-}
-
 NSInvocation *typeToValueInvocationFor(const char* encodedType)
 {
     SEL selector = [JSValue selectorForStructToValue:encodedType];