Reviewed by Darin.
authorggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 2 Apr 2006 08:55:58 +0000 (08:55 +0000)
committerggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 2 Apr 2006 08:55:58 +0000 (08:55 +0000)
        - Fixed <rdar://problem/4430836> JavaScript patch crashing Quartz
        Composer

        JSValueWrappers used to hold on to the ExecState that pertained at
        the time of their creation. Since ExecStates are transient, that
        design was totally bogus, and it would crash once the ExecState had
        been deallocated.

        Unfortunately, there's no clean solution to this problem, since
        the JSGlue API has no notion of state. The solution here is to use
        a shared, global ExecState for the purpose of JSGlue calls. Given
        the pre-existing limitations in the JSGlue API, this design
        shouldn't actually introduce any new limitations (see comments in
        JSValueWrapper.cpp).

        I tested with Quartz Composer and PAC files, neither of which are
        layout-testable.

        * JSUtils.cpp:
        (KJSValueToJSObject):
        * JSValueWrapper.cpp:
        (JSValueWrapper::JSValueWrapper):
        (JSValueWrapper::GetValue):
        (getProcessGlobalExecState):
        (JSValueWrapper::JSObjectCopyPropertyNames):
        (JSValueWrapper::JSObjectCopyProperty):
        (JSValueWrapper::JSObjectSetProperty):
        (JSValueWrapper::JSObjectCallFunction):
        (JSValueWrapper::JSObjectCopyCFValue):
        * JSValueWrapper.h:

        Also added a test harness file. It was helpful while I was testing,
        and may come in handy in the future:

        * JavaScriptGlue.xcodeproj/project.pbxproj:
        testjsglue.cpp: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@13635 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptGlue/ChangeLog
JavaScriptGlue/JSUtils.cpp
JavaScriptGlue/JSValueWrapper.cpp
JavaScriptGlue/JSValueWrapper.h
JavaScriptGlue/JavaScriptGlue.xcodeproj/project.pbxproj
JavaScriptGlue/testjsglue.cpp [new file with mode: 0644]

index 1b25c8d43db222369b0e1e828d0185fe62bd1f26..979a732f53287306c8eb9599b59f4100bdc78fac 100644 (file)
@@ -1,3 +1,44 @@
+2006-03-31  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Darin.
+
+        - Fixed <rdar://problem/4430836> JavaScript patch crashing Quartz
+        Composer
+
+        JSValueWrappers used to hold on to the ExecState that pertained at
+        the time of their creation. Since ExecStates are transient, that
+        design was totally bogus, and it would crash once the ExecState had
+        been deallocated.
+
+        Unfortunately, there's no clean solution to this problem, since
+        the JSGlue API has no notion of state. The solution here is to use
+        a shared, global ExecState for the purpose of JSGlue calls. Given
+        the pre-existing limitations in the JSGlue API, this design
+        shouldn't actually introduce any new limitations (see comments in
+        JSValueWrapper.cpp).
+
+        I tested with Quartz Composer and PAC files, neither of which are
+        layout-testable.
+        
+        * JSUtils.cpp:
+        (KJSValueToJSObject):
+        * JSValueWrapper.cpp:
+        (JSValueWrapper::JSValueWrapper):
+        (JSValueWrapper::GetValue):
+        (getProcessGlobalExecState):
+        (JSValueWrapper::JSObjectCopyPropertyNames):
+        (JSValueWrapper::JSObjectCopyProperty):
+        (JSValueWrapper::JSObjectSetProperty):
+        (JSValueWrapper::JSObjectCallFunction):
+        (JSValueWrapper::JSObjectCopyCFValue):
+        * JSValueWrapper.h:
+
+        Also added a test harness file. It was helpful while I was testing,
+        and may come in handy in the future:
+        
+        * JavaScriptGlue.xcodeproj/project.pbxproj:
+        testjsglue.cpp: Added.
+
 2006-03-28  Darin Adler  <darin@apple.com>
 
         Reviewed by Geoff.
index 2c00c9866a86e4ecadf4a78fbe16976adc999002..36fdaedaf59061f48d94a1a140d70953d57b1940 100644 (file)
@@ -111,7 +111,7 @@ JSUserObject* KJSValueToJSObject(JSValue *inValue, ExecState *exec)
         if (result)
             result->Retain();
     } else {
-        JSValueWrapper* wrapperValue = new JSValueWrapper(inValue, exec);
+        JSValueWrapper* wrapperValue = new JSValueWrapper(inValue);
         if (wrapperValue) {
             JSObjectCallBacks callBacks;
             JSValueWrapper::GetJSObectCallBacks(callBacks);
index 231b2483401319fc154c7fc06a34d216152d1aea..401355da6bc31840a178a6f4312179e22195d1f4 100644 (file)
 #include "config.h"
 #include "JSValueWrapper.h"
 #include "JavaScriptCore/reference_list.h"
+#include <pthread.h>
 
-JSValueWrapper::JSValueWrapper(JSValue *inValue, ExecState *inExec)
-    : fValue(inValue), fExec(inExec)
+JSValueWrapper::JSValueWrapper(JSValue *inValue)
+    : fValue(inValue)
 {
 }
 
@@ -43,11 +44,50 @@ JSValue *JSValueWrapper::GetValue()
 {
     return fValue;
 }
-ExecState* JSValueWrapper::GetExecState() const
+
+/*
+ * This is a slight hack. The JSGlue API has no concept of execution state.
+ * However, execution state is an inherent part of JS, and JSCore requires it.
+ * So, we keep a single execution state for the whole thread and supply it
+ * where necessary.
+
+ * The execution state holds two things: (1) exceptions; (2) the global object. 
+ * JSGlue has no API for accessing exceptions, so we just discard them. As for
+ * the global object, JSGlue includes no calls that depend on it. Its property
+ * getters and setters are per-object; they don't walk up the enclosing scope. 
+ * Functions called by JSObjectCallFunction may reference values in the enclosing 
+ * scope, but they do so through an internally stored scope chain, so we don't 
+ * need to supply the global scope.
+ */      
+
+pthread_key_t interpreterKey;
+pthread_once_t interpreterKeyOnce = PTHREAD_ONCE_INIT;
+
+static void destroyInterpreter(void* data) 
+{
+    delete static_cast<Interpreter*>(data);
+}
+
+static void initializeInterpreterKey()
 {
-    return fExec;
+    pthread_key_create(&interpreterKey, destroyInterpreter);
 }
 
+static ExecState* getThreadGlobalExecState()
+{
+    pthread_once(&interpreterKeyOnce, initializeInterpreterKey);
+    Interpreter* interpreter = static_cast<Interpreter*>(pthread_getspecific(interpreterKey));
+    if (!interpreter) {
+        interpreter = new Interpreter();
+        pthread_setspecific(interpreterKey, interpreter);
+    }
+
+    // Discard exceptions -- otherwise an exception would forestall JS 
+    // evaluation throughout the thread
+    interpreter->globalExec()->clearException();
+
+    return interpreter->globalExec();
+}
 
 void JSValueWrapper::GetJSObectCallBacks(JSObjectCallBacks& callBacks)
 {
@@ -75,7 +115,7 @@ CFArrayRef JSValueWrapper::JSObjectCopyPropertyNames(void *data)
     JSValueWrapper* ptr = (JSValueWrapper*)data;
     if (ptr)
     {
-        ExecState* exec = ptr->GetExecState();
+        ExecState* exec = getThreadGlobalExecState();
         JSObject *object = ptr->GetValue()->toObject(exec);
         ReferenceList list = object->propList(exec);
         ReferenceListIterator iterator = list.begin();
@@ -109,9 +149,9 @@ JSObjectRef JSValueWrapper::JSObjectCopyProperty(void *data, CFStringRef propert
     JSValueWrapper* ptr = (JSValueWrapper*)data;
     if (ptr)
     {
-        ExecState* exec = ptr->GetExecState();
+        ExecState* exec = getThreadGlobalExecState();
         JSValue *propValue = ptr->GetValue()->toObject(exec)->get(exec, CFStringToIdentifier(propertyName));
-        JSValueWrapper* wrapperValue = new JSValueWrapper(propValue, exec);
+        JSValueWrapper* wrapperValue = new JSValueWrapper(propValue);
 
         JSObjectCallBacks callBacks;
         GetJSObectCallBacks(callBacks);
@@ -132,7 +172,7 @@ void JSValueWrapper::JSObjectSetProperty(void *data, CFStringRef propertyName, J
     JSValueWrapper* ptr = (JSValueWrapper*)data;
     if (ptr)
     {
-        ExecState* exec = ptr->GetExecState();
+        ExecState* exec = getThreadGlobalExecState();
         JSValue *value = JSObjectKJSValue((JSUserObject*)jsValue);
         JSObject *objValue = ptr->GetValue()->toObject(exec);
         objValue->put(exec, CFStringToIdentifier(propertyName), value);
@@ -147,7 +187,7 @@ JSObjectRef JSValueWrapper::JSObjectCallFunction(void *data, JSObjectRef thisObj
     JSValueWrapper* ptr = (JSValueWrapper*)data;
     if (ptr)
     {
-        ExecState* exec = ptr->GetExecState();
+        ExecState* exec = getThreadGlobalExecState();
 
         JSValue *value = JSObjectKJSValue((JSUserObject*)thisObj);
         JSObject *ksjThisObj = value->toObject(exec);
@@ -163,7 +203,7 @@ JSObjectRef JSValueWrapper::JSObjectCallFunction(void *data, JSObjectRef thisObj
         }
 
         JSValue *resultValue = objValue->call(exec, ksjThisObj, listArgs);
-        JSValueWrapper* wrapperValue = new JSValueWrapper(resultValue, ptr->GetExecState());
+        JSValueWrapper* wrapperValue = new JSValueWrapper(resultValue);
         JSObjectCallBacks callBacks;
         GetJSObectCallBacks(callBacks);
         result = JSObjectCreate(wrapperValue, &callBacks);
@@ -183,7 +223,7 @@ CFTypeRef JSValueWrapper::JSObjectCopyCFValue(void *data)
     JSValueWrapper* ptr = (JSValueWrapper*)data;
     if (ptr)
     {
-        result = KJSValueToCFType(ptr->fValue, ptr->fExec);
+        result = KJSValueToCFType(ptr->GetValue(), getThreadGlobalExecState());
     }
     return result;
 }
index 9c6bc4e47cc0622bfb3024afb0e9f9cc40c0e452..5c3329755eea36ff4c7d77ff074712979325239b 100644 (file)
 
 class JSValueWrapper {
 public:
-    JSValueWrapper(JSValue *inValue, ExecState *inExec);
+    JSValueWrapper(JSValue *inValue);
     virtual ~JSValueWrapper();
 
-    JSValue *GetValue();
-    ExecState *GetExecState() const;
-
-    ProtectedPtr<JSValue> fValue;
-    ExecState *fExec;
-
     static void GetJSObectCallBacks(JSObjectCallBacks& callBacks);
 
+    JSValue *GetValue();
+
 private:
+    ProtectedPtr<JSValue> fValue;
+    
     static void JSObjectDispose(void *data);
     static CFArrayRef JSObjectCopyPropertyNames(void *data);
     static JSObjectRef JSObjectCopyProperty(void *data, CFStringRef propertyName);
index d05899b90e25b71ed3b125ec3fadb53713b3a410..1bf4dba36f8826b1d6c8c409749fa0f59ca29e27 100644 (file)
@@ -6,7 +6,27 @@
        objectVersion = 42;
        objects = {
 
+/* Begin PBXAggregateTarget section */
+               1422E8C409DE3EA600749B87 /* All */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = 1422E8DD09DE3EF500749B87 /* Build configuration list for PBXAggregateTarget "All" */;
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               PRODUCT_NAME = All;
+                       };
+                       dependencies = (
+                               1422E8CA09DE3EB100749B87 /* PBXTargetDependency */,
+                               1422E8C809DE3EAD00749B87 /* PBXTargetDependency */,
+                       );
+                       name = All;
+                       productName = All;
+               };
+/* End PBXAggregateTarget section */
+
 /* Begin PBXBuildFile section */
+               1422E87B09DE3BF000749B87 /* testjsglue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1422E86709DE3BCE00749B87 /* testjsglue.cpp */; };
+               1422E88209DE3C0400749B87 /* JavaScriptGlue.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD66F3D608F73ED700C75FD7 /* JavaScriptGlue.framework */; };
                DD66F3BB08F73ED700C75FD7 /* JavaScriptGlue.h in Headers */ = {isa = PBXBuildFile; fileRef = F11798B30262465703CA149D /* JavaScriptGlue.h */; settings = {ATTRIBUTES = (Public, ); }; };
                DD66F3BC08F73ED700C75FD7 /* JSBase.h in Headers */ = {isa = PBXBuildFile; fileRef = F11798B9026246FD03CA149D /* JSBase.h */; };
                DD66F3BD08F73ED700C75FD7 /* JSUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = F11798B7026246FD03CA149D /* JSUtils.h */; };
                };
 /* End PBXBuildStyle section */
 
+/* Begin PBXContainerItemProxy section */
+               1422E8C709DE3EAD00749B87 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 1422E87609DE3BE800749B87;
+                       remoteInfo = testjsglue;
+               };
+               1422E8C909DE3EB100749B87 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = DD66F3B908F73ED700C75FD7;
+                       remoteInfo = JavaScriptGlue;
+               };
+/* End PBXContainerItemProxy section */
+
 /* Begin PBXFileReference section */
                0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
                0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
                089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; indentWidth = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
+               1422E86709DE3BCE00749B87 /* testjsglue.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = testjsglue.cpp; sourceTree = "<group>"; };
+               1422E87709DE3BE800749B87 /* testjsglue */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testjsglue; sourceTree = BUILT_PRODUCTS_DIR; };
                DD66F3D508F73ED700C75FD7 /* Info.plist */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xml; path = Info.plist; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                DD66F3D608F73ED700C75FD7 /* JavaScriptGlue.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JavaScriptGlue.framework; sourceTree = BUILT_PRODUCTS_DIR; };
                DD66F3F508F7401B00C75FD7 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = JavaScriptCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
+               1422E87509DE3BE800749B87 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               1422E88209DE3C0400749B87 /* JavaScriptGlue.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                DD66F3CD08F73ED700C75FD7 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        isa = PBXGroup;
                        children = (
                                DD66F3D608F73ED700C75FD7 /* JavaScriptGlue.framework */,
+                               1422E87709DE3BE800749B87 /* testjsglue */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                0867D691FE84028FC02AAC07 /* JavaScriptGlue */ = {
                        isa = PBXGroup;
                        children = (
+                               1422E86709DE3BCE00749B87 /* testjsglue.cpp */,
                                08FB77AEFE84172EC02AAC07 /* Classes */,
                                089C1665FE841158C02AAC07 /* Resources */,
                                0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
 /* End PBXHeadersBuildPhase section */
 
 /* Begin PBXNativeTarget section */
+               1422E87609DE3BE800749B87 /* testjsglue */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 1422E88609DE3C2200749B87 /* Build configuration list for PBXNativeTarget "testjsglue" */;
+                       buildPhases = (
+                               1422E87409DE3BE800749B87 /* Sources */,
+                               1422E87509DE3BE800749B87 /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = testjsglue;
+                               ZERO_LINK = YES;
+                       };
+                       dependencies = (
+                       );
+                       name = testjsglue;
+                       productName = testjsglue;
+                       productReference = 1422E87709DE3BE800749B87 /* testjsglue */;
+                       productType = "com.apple.product-type.tool";
+               };
                DD66F3B908F73ED700C75FD7 /* JavaScriptGlue */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = DD66F3D108F73ED700C75FD7 /* Build configuration list for PBXNativeTarget "JavaScriptGlue" */;
                        projectDirPath = "";
                        targets = (
                                DD66F3B908F73ED700C75FD7 /* JavaScriptGlue */,
+                               1422E87609DE3BE800749B87 /* testjsglue */,
+                               1422E8C409DE3EA600749B87 /* All */,
                        );
                };
 /* End PBXProject section */
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
+               1422E87409DE3BE800749B87 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               1422E87B09DE3BF000749B87 /* testjsglue.cpp in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                DD66F3C408F73ED700C75FD7 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                };
 /* End PBXSourcesBuildPhase section */
 
+/* Begin PBXTargetDependency section */
+               1422E8C809DE3EAD00749B87 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 1422E87609DE3BE800749B87 /* testjsglue */;
+                       targetProxy = 1422E8C709DE3EAD00749B87 /* PBXContainerItemProxy */;
+               };
+               1422E8CA09DE3EB100749B87 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = DD66F3B908F73ED700C75FD7 /* JavaScriptGlue */;
+                       targetProxy = 1422E8C909DE3EB100749B87 /* PBXContainerItemProxy */;
+               };
+/* End PBXTargetDependency section */
+
 /* Begin PBXVariantGroup section */
                089C1666FE841158C02AAC07 /* InfoPlist.strings */ = {
                        isa = PBXVariantGroup;
 /* End PBXVariantGroup section */
 
 /* Begin XCBuildConfiguration section */
+               1422E88709DE3C2200749B87 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = testjsglue;
+                               ZERO_LINK = YES;
+                       };
+                       name = Debug;
+               };
+               1422E88809DE3C2200749B87 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = testjsglue;
+                               ZERO_LINK = NO;
+                       };
+                       name = Release;
+               };
+               1422E88909DE3C2200749B87 /* Production */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = testjsglue;
+                               ZERO_LINK = YES;
+                       };
+                       name = Production;
+               };
+               1422E8DE09DE3EF500749B87 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               PRODUCT_NAME = All;
+                       };
+                       name = Debug;
+               };
+               1422E8DF09DE3EF500749B87 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               PRODUCT_NAME = All;
+                               ZERO_LINK = NO;
+                       };
+                       name = Release;
+               };
+               1422E8E009DE3EF500749B87 /* Production */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PRODUCT_NAME = All;
+                       };
+                       name = Production;
+               };
                14AC662C08CE7791006915A8 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
+               1422E88609DE3C2200749B87 /* Build configuration list for PBXNativeTarget "testjsglue" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1422E88709DE3C2200749B87 /* Debug */,
+                               1422E88809DE3C2200749B87 /* Release */,
+                               1422E88909DE3C2200749B87 /* Production */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Production;
+               };
+               1422E8DD09DE3EF500749B87 /* Build configuration list for PBXAggregateTarget "All" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1422E8DE09DE3EF500749B87 /* Debug */,
+                               1422E8DF09DE3EF500749B87 /* Release */,
+                               1422E8E009DE3EF500749B87 /* Production */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Production;
+               };
                14AC662B08CE7791006915A8 /* Build configuration list for PBXProject "JavaScriptGlue" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
diff --git a/JavaScriptGlue/testjsglue.cpp b/JavaScriptGlue/testjsglue.cpp
new file mode 100644 (file)
index 0000000..bc5f664
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR 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.
+ */
+
+#include "CoreFoundation/CoreFoundation.h"
+#include "JavaScriptGlue.h"
+
+CFStringRef script = 
+CFSTR("\
+x = 1; \n\
+function getX() \n\
+{ \n\
+    return x; \n\
+} \n\
+");
+
+int main(int argc, char* argv[])
+{
+    JSRunRef jsRun = JSRunCreate(script, kJSFlagNone);
+    if (!JSRunCheckSyntax(jsRun)) {
+        return -1;
+    }
+    JSObjectRef globalObject = JSRunCopyGlobalObject(jsRun);
+    JSRunEvaluate(jsRun);
+    JSObjectRef getX = JSObjectCopyProperty(globalObject, CFSTR("getX"));
+    JSObjectRef jsResult = JSObjectCallFunction(getX, globalObject, 0);
+
+    if (jsResult) {
+        CFTypeRef cfResult = JSObjectCopyCFValue(jsResult);
+        CFShow(cfResult);
+        
+        CFRelease(cfResult);
+        JSRelease(jsResult);
+    }
+    
+    JSRelease(jsRun);
+    
+    return 0;
+}