Beispiel #1
0
 JSObject JSObject::CallAsConstructor(const std::vector<JSValue>&  arguments) {
   HAL_JSOBJECT_LOCK_GUARD;
   
   if (!IsConstructor()) {
     detail::ThrowRuntimeError("JSObject", "This JavaScript object is not a constructor.");
   }
   
   JSValueRef exception { nullptr };
   JSObjectRef js_object_ref = nullptr;
   if (!arguments.empty()) {
     const auto arguments_array = detail::to_vector(arguments);
     js_object_ref = JSObjectCallAsConstructor(static_cast<JSContextRef>(js_context__), js_object_ref__, arguments_array.size(), &arguments_array[0], &exception);
   } else {
     js_object_ref = JSObjectCallAsConstructor(static_cast<JSContextRef>(js_context__), js_object_ref__, 0, nullptr, &exception);
   }
   
   if (exception) {
     // If this assert fails then we need to JSValueUnprotect
     // js_object_ref.
     assert(!js_object_ref);
     detail::ThrowRuntimeError("JSObject", JSValue(js_context__, exception));
   }
   
   // postcondition
   assert(js_object_ref);
   return JSObject(js_context__, js_object_ref);
 }
Beispiel #2
0
NATIVE(JSObject,jobject,callAsConstructor) (PARAMS, jlong ctx, jlong object, jlongArray args) {
	JSValueRef exception = NULL;

	int i, sum = 0;
	jsize len = env->GetArrayLength(args);
	jlong *values = env->GetLongArrayElements(args, 0);
	JSValueRef* elements = new JSValueRef[len];
	for (i=0; i<len; i++) {
		elements[i] = (JSValueRef) values[i];
	}
	env->ReleaseLongArrayElements(args, values, 0);

	jclass ret = env->FindClass("org/liquidplayer/webkit/javascriptcore/JNIReturnObject");
	jmethodID cid = env->GetMethodID(ret,"<init>","()V");
	jobject out = env->NewObject(ret, cid);

	jfieldID fid = env->GetFieldID(ret , "reference", "J");
	env->SetLongField( out, fid, (long) JSObjectCallAsConstructor((JSContextRef) ctx, (JSObjectRef)object,
			(size_t)len, (len==0)?NULL:elements, &exception));

	fid = env->GetFieldID(ret , "exception", "J");
	env->SetLongField( out, fid, (long) exception);

	delete elements;
	return out;
}
Beispiel #3
0
JS4D::ObjectRef JS4D::VTimeToObject( ContextRef inContext, const VTime& inTime, ExceptionRef *outException)
{
	if (inTime.IsNull())
		return NULL;	// can't return JSValueMakeNull as an object
	
	sWORD year, month, day, hour, minute, second, millisecond;
	
	inTime.GetLocalTime( year, month, day, hour, minute, second, millisecond);

	JSValueRef	args[6];
	args[0] = JSValueMakeNumber( inContext, year);
	args[1] = JSValueMakeNumber( inContext, month-1);
	args[2] = JSValueMakeNumber( inContext, day);
	args[3] = JSValueMakeNumber( inContext, hour);
	args[4] = JSValueMakeNumber( inContext, minute);
	args[5] = JSValueMakeNumber( inContext, second);

	#if NEW_WEBKIT
	JSObjectRef date = JSObjectMakeDate( inContext, 6, args, outException);
	#else
    JSStringRef jsClassName = JSStringCreateWithUTF8CString("Date");
    JSObjectRef constructor = JSValueToObject( inContext, JSObjectGetProperty( inContext, JSContextGetGlobalObject( inContext), jsClassName, NULL), NULL);
    JSStringRelease( jsClassName);
    JSObjectRef date = JSObjectCallAsConstructor( inContext, constructor, 6, args, outException);
	#endif

	return date;
}
void InspectorController::addScriptConsoleMessage(const ConsoleMessage* message)
{
    ASSERT_ARG(message, message);

    JSStringRef messageConstructorString = JSStringCreateWithUTF8CString("ConsoleMessage");
    JSObjectRef messageConstructor = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, messageConstructorString, 0), 0);
    JSStringRelease(messageConstructorString);

    JSStringRef addMessageString = JSStringCreateWithUTF8CString("addMessageToConsole");
    JSObjectRef addMessage = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, addMessageString, 0), 0);
    JSStringRelease(addMessageString);

    JSValueRef sourceValue = JSValueMakeNumber(m_scriptContext, message->source);
    JSValueRef levelValue = JSValueMakeNumber(m_scriptContext, message->level);
    JSStringRef messageString = JSStringCreateWithCharacters(message->message.characters(), message->message.length());
    JSValueRef messageValue = JSValueMakeString(m_scriptContext, messageString);
    JSValueRef lineValue = JSValueMakeNumber(m_scriptContext, message->line);
    JSStringRef urlString = JSStringCreateWithCharacters(message->url.characters(), message->url.length());
    JSValueRef urlValue = JSValueMakeString(m_scriptContext, urlString);

    JSValueRef args[] = { sourceValue, levelValue, messageValue, lineValue, urlValue };
    JSObjectRef messageObject = JSObjectCallAsConstructor(m_scriptContext, messageConstructor, 5, args, 0);
    JSStringRelease(messageString);
    JSStringRelease(urlString);

    JSObjectCallAsFunction(m_scriptContext, addMessage, m_scriptObject, 1, &messageObject, 0);
}
Beispiel #5
0
inline JSObjectRef jsc::Function::construct(JSContextRef ctx, const JSObjectRef &function, size_t argc, const JSValueRef arguments[]) {
    JSValueRef exception = nullptr;
    JSObjectRef result = JSObjectCallAsConstructor(ctx, function, argc, arguments, &exception);
    if (exception) {
        throw jsc::Exception(ctx, exception);
    }
    return result;
}
Beispiel #6
0
Object Object::callAsConstructor(std::initializer_list<JSValueRef> args) const {
  JSValueRef exn;
  JSObjectRef result = JSObjectCallAsConstructor(m_context, m_obj, args.size(), args.begin(), &exn);
  if (!result) {
    std::string exceptionText = Value(m_context, exn).toString().str();
    throwJSExecutionException("Exception calling object as constructor: %s", exceptionText.c_str());
  }
  return Object(m_context, result);
}
JSObjectRef InspectorController::addScriptResource(InspectorResource* resource)
{
    ASSERT_ARG(resource, resource);

    // This happens for pages loaded from the back/forward cache.
    if (resource->scriptObject)
        return resource->scriptObject;

    ASSERT(m_scriptContext);
    ASSERT(m_scriptObject);
    if (!m_scriptContext || !m_scriptObject)
        return 0;

    JSStringRef resourceString = JSStringCreateWithUTF8CString("Resource");
    JSObjectRef resourceConstructor = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, resourceString, 0), 0);
    JSStringRelease(resourceString);

    String urlString = resource->requestURL.url();
    JSStringRef url = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
    JSValueRef urlValue = JSValueMakeString(m_scriptContext, url);
    JSStringRelease(url);

    urlString = resource->requestURL.host();
    JSStringRef domain = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
    JSValueRef domainValue = JSValueMakeString(m_scriptContext, domain);
    JSStringRelease(domain);

    urlString = resource->requestURL.path();
    JSStringRef path = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
    JSValueRef pathValue = JSValueMakeString(m_scriptContext, path);
    JSStringRelease(path);

    urlString = resource->requestURL.lastPathComponent();
    JSStringRef lastPathComponent = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
    JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, lastPathComponent);
    JSStringRelease(lastPathComponent);

    JSValueRef identifier = JSValueMakeNumber(m_scriptContext, resource->identifier);
    JSValueRef mainResource = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
    JSValueRef cached = JSValueMakeBoolean(m_scriptContext, resource->cached);

    JSValueRef arguments[] = { scriptObjectForRequest(m_scriptContext, resource), urlValue, domainValue, pathValue, lastPathComponentValue, identifier, mainResource, cached };
    JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, resourceConstructor, 8, arguments, 0);

    resource->setScriptObject(m_scriptContext, result);

    ASSERT(result);

    JSStringRef addResourceString = JSStringCreateWithUTF8CString("addResource");
    JSObjectRef addResourceFunction = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, addResourceString, 0), 0);
    JSStringRelease(addResourceString);

    JSValueRef addArguments[] = { result };
    JSObjectCallAsFunction(m_scriptContext, addResourceFunction, m_scriptObject, 1, addArguments, 0);

    return result;
}
Beispiel #8
0
template<> std::string RJSAccessor::to_binary(JSContextRef ctx, JSValueRef &val) {
    static JSStringRef arrayBufferString = JSStringCreateWithUTF8CString("ArrayBuffer");
    static JSStringRef bufferString = JSStringCreateWithUTF8CString("buffer");
    static JSStringRef byteLengthString = JSStringCreateWithUTF8CString("byteLength");
    static JSStringRef byteOffsetString = JSStringCreateWithUTF8CString("byteOffset");
    static JSStringRef isViewString = JSStringCreateWithUTF8CString("isView");
    static JSStringRef uint8ArrayString = JSStringCreateWithUTF8CString("Uint8Array");

    JSObjectRef arrayBufferConstructor = RJSValidatedObjectProperty(ctx, JSContextGetGlobalObject(ctx), arrayBufferString);
    JSObjectRef uint8ArrayContructor = RJSValidatedObjectProperty(ctx, JSContextGetGlobalObject(ctx), uint8ArrayString);
    JSValueRef uint8ArrayArguments[3];
    size_t uint8ArrayArgumentsCount = 0;

    // Value should either be an ArrayBuffer or ArrayBufferView (i.e. TypedArray or DataView).
    if (JSValueIsInstanceOfConstructor(ctx, val, arrayBufferConstructor, NULL)) {
        uint8ArrayArguments[0] = val;
        uint8ArrayArgumentsCount = 1;
    }
    else if (JSObjectRef object = JSValueToObject(ctx, val, NULL)) {
        // Check if value is an ArrayBufferView by calling ArrayBuffer.isView(val).
        JSObjectRef isViewMethod = RJSValidatedObjectProperty(ctx, arrayBufferConstructor, isViewString);
        JSValueRef isView = JSObjectCallAsFunction(ctx, isViewMethod, arrayBufferConstructor, 1, &val, NULL);

        if (isView && JSValueToBoolean(ctx, isView)) {
            uint8ArrayArguments[0] = RJSValidatedObjectProperty(ctx, object, bufferString);
            uint8ArrayArguments[1] = RJSValidatedPropertyValue(ctx, object, byteOffsetString);
            uint8ArrayArguments[2] = RJSValidatedPropertyValue(ctx, object, byteLengthString);
            uint8ArrayArgumentsCount = 3;
        }
    }

    if (!uint8ArrayArgumentsCount) {
        throw std::runtime_error("Can only convert ArrayBuffer and TypedArray objects to binary");
    }

    JSValueRef exception = NULL;
    JSObjectRef uint8Array = JSObjectCallAsConstructor(ctx, uint8ArrayContructor, uint8ArrayArgumentsCount, uint8ArrayArguments, &exception);
    if (exception) {
        throw RJSException(ctx, exception);
    }

    size_t byteCount = RJSValidatedListLength(ctx, uint8Array);
    std::string bytes(byteCount, 0);

    for (size_t i = 0; i < byteCount; i++) {
        JSValueRef byteValue = JSObjectGetPropertyAtIndex(ctx, uint8Array, (unsigned)i, NULL);
        bytes[i] = JSValueToNumber(ctx, byteValue, NULL);
    }

    return bytes;
}
static JSValueRef search(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
{
    InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
    if (!controller)
        return JSValueMakeUndefined(ctx);

    if (argumentCount < 2 || !JSValueIsString(ctx, arguments[1]))
        return JSValueMakeUndefined(ctx);

    Node* node = toNode(toJS(arguments[0]));
    if (!node)
        return JSValueMakeUndefined(ctx);

    JSStringRef string = JSValueToStringCopy(ctx, arguments[1], 0);
    String target(JSStringGetCharactersPtr(string), JSStringGetLength(string));
    JSStringRelease(string);

    JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
    JSStringRef constructorString = JSStringCreateWithUTF8CString("Array");
    JSObjectRef arrayConstructor = JSValueToObject(ctx, JSObjectGetProperty(ctx, globalObject, constructorString, 0), 0);
    JSStringRelease(constructorString);
    JSObjectRef array = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, 0);

    JSStringRef pushString = JSStringCreateWithUTF8CString("push");
    JSValueRef pushValue = JSObjectGetProperty(ctx, array, pushString, 0);
    JSStringRelease(pushString);
    JSObjectRef push = JSValueToObject(ctx, pushValue, 0);

    RefPtr<Range> searchRange(rangeOfContents(node));

    int exception = 0;
    do {
        RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, false));
        if (resultRange->collapsed(exception))
            break;

        // A non-collapsed result range can in some funky whitespace cases still not
        // advance the range's start position (4509328). Break to avoid infinite loop.
        VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
        if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
            break;

        KJS::JSLock lock;
        JSValueRef arg0 = toRef(toJS(toJS(ctx), resultRange.get()));
        JSObjectCallAsFunction(ctx, push, array, 1, &arg0, 0);

        setStart(searchRange.get(), newStart);
    } while (true);

    return array;
}
Beispiel #10
0
bool VJSObject::CallAsConstructor (const std::vector<VJSValue> *inValues, VJSObject *outCreatedObject, JS4D::ExceptionRef *outException)
{
	xbox_assert(outCreatedObject != NULL);

	if (!JSObjectIsConstructor(GetContextRef(), GetObjectRef()))

		return false;

	uLONG		argumentCount	= inValues == NULL || inValues->empty() ? 0 : (uLONG) inValues->size();
	JSValueRef	*values			= argumentCount == 0 ? NULL : new JSValueRef[argumentCount];

	if (values != NULL) {

		std::vector<VJSValue>::const_iterator	i;
		uLONG									j;

		for (i = inValues->begin(), j = 0; i != inValues->end(); i++, j++)

			values[j] = i->GetValueRef();
		

	}

	JS4D::ExceptionRef	exception;
	JS4D::ObjectRef		createdObject;
	
	exception = NULL;
	createdObject = JSObjectCallAsConstructor(GetContextRef(), GetObjectRef(), argumentCount, values, &exception);
		
	if (values != NULL)

		delete[] values;

	if (outException != NULL)

		*outException = exception;

	outCreatedObject->SetContext(fContext);
	if (exception != NULL || createdObject == NULL) {
		
		outCreatedObject->SetUndefined();
		return false;

	} else {

		outCreatedObject->SetObjectRef(createdObject);
		return true;

	}
}
Beispiel #11
0
template<> JSValueRef RJSAccessor::from_binary(JSContextRef ctx, BinaryData data) {
    static JSStringRef bufferString = JSStringCreateWithUTF8CString("buffer");
    static JSStringRef uint8ArrayString = JSStringCreateWithUTF8CString("Uint8Array");

    size_t byteCount = data.size();
    JSValueRef byteCountValue = JSValueMakeNumber(ctx, byteCount);
    JSObjectRef uint8ArrayContructor = RJSValidatedObjectProperty(ctx, JSContextGetGlobalObject(ctx), uint8ArrayString);
    JSObjectRef uint8Array = JSObjectCallAsConstructor(ctx, uint8ArrayContructor, 1, &byteCountValue, NULL);

    for (size_t i = 0; i < byteCount; i++) {
        JSValueRef num = JSValueMakeNumber(ctx, data[i]);
        JSObjectSetPropertyAtIndex(ctx, uint8Array, (unsigned)i, num, NULL);
    }

    return RJSValidatedObjectProperty(ctx, uint8Array, bufferString);
}
static JSValueRef getChildren(JSContextRef ctx, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
    KJS::JSLock lock(false);

    if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
        return JSValueMakeUndefined(ctx);

    ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
    const Vector<RefPtr<ProfileNode> >& children = profileNode->children();

    JSObjectRef global = JSContextGetGlobalObject(ctx);

    JSRetainPtr<JSStringRef> arrayString(Adopt, JSStringCreateWithUTF8CString("Array"));

    JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, arrayString.get(), exception);
    if (exception && *exception)
        return JSValueMakeUndefined(ctx);

    JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception);
    if (exception && *exception)
        return JSValueMakeUndefined(ctx);

    JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception);
    if (exception && *exception)
        return JSValueMakeUndefined(ctx);

    JSRetainPtr<JSStringRef> pushString(Adopt, JSStringCreateWithUTF8CString("push"));
    
    JSValueRef pushProperty = JSObjectGetProperty(ctx, result, pushString.get(), exception);
    if (exception && *exception)
        return JSValueMakeUndefined(ctx);

    JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception);
    if (exception && *exception)
        return JSValueMakeUndefined(ctx);

    for (Vector<RefPtr<ProfileNode> >::const_iterator it = children.begin(); it != children.end(); ++it) {
        JSValueRef arg0 = toRef(toJS(toJS(ctx), (*it).get() ));
        JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception);
        if (exception && *exception)
            return JSValueMakeUndefined(ctx);
    }

    return result;
}
static PeasExtension *
peas_plugin_loader_seed_create_extension (PeasPluginLoader *loader,
                                          PeasPluginInfo   *info,
                                          GType             exten_type,
                                          guint             n_parameters,
                                          GParameter       *parameters)
{
  PeasPluginLoaderSeed *sloader = PEAS_PLUGIN_LOADER_SEED (loader);
  SeedInfo *sinfo;
  SeedValue extension_ctor, extension;
  guint i, j;
  SeedValue value;
  GValue gvalue = { 0 };
  GArray *interfaces;
  gchar **property_names;

  sinfo = (SeedInfo *) g_hash_table_lookup (sloader->loaded_plugins, info);

  /* FIXME: instantiate new object and pass the parameters */
  extension_ctor = seed_object_get_property (sinfo->context,
                                             sinfo->extensions,
                                             g_type_name (exten_type));
  if (!extension_ctor ||
      seed_value_is_undefined (sinfo->context, extension_ctor) ||
      seed_value_is_null (sinfo->context, extension_ctor))
    return NULL;

  if (!seed_value_is_object (sinfo->context, extension_ctor))
    {
      g_warning ("Extension '%s' in plugin '%s' is not a Seed object",
                 g_type_name (exten_type), peas_plugin_info_get_module_name (info));
      return NULL;
    }

  /* Instantiate the ctor object into a new specific object. */
  extension = JSObjectCallAsConstructor (sinfo->context, extension_ctor, 0, NULL, NULL);

  if (extension == NULL)
    {
#ifndef PEAS_DISABLE_DEPRECATED_FEATURES
      gchar **property_names;

      g_warning ("DEPRECATION WARNING: Extension '%s' in plugin '%s' is not a valid "
                 "constructor function. Support for extension initialization by array "
                 "copy will be dropped soon.",
                 g_type_name (exten_type), peas_plugin_info_get_module_name (info));

      extension = seed_make_object (sinfo->context, NULL, NULL);
      property_names = seed_object_copy_property_names (sinfo->context,
                                                        extension_ctor);
      for (i = 0; property_names[i] != NULL; i++)
        {
          SeedValue value;
          value = seed_object_get_property (sinfo->context,
                                            extension_ctor,
                                            property_names[i]);
          seed_object_set_property (sinfo->context,
                                    extension,
                                    property_names[i],
                                    value);
        }

        g_strfreev (property_names);
#else
      g_warning ("Extension '%s' in plugin '%s' is not a valid constructor",
                 g_type_name (exten_type), peas_plugin_info_get_module_name (info));
      return NULL;
#endif
    }

  /* Set the properties as well, cannot use
   * g_object_set_property() because it may be construct-only
   */
  for (i = 0; i < n_parameters; i++)
    {
      gchar *key;

      /* We want to normalize the property names to have a '_' instead of the
       * conventional '-', to make them accessible through this.property_name */
      key = g_strdup (parameters[i].name);
      for (j = 0; key[j] != '\0'; j++)
        {
          if (key[j] == '-')
            key[j] = '_';
        }

      value = seed_value_from_gvalue (sinfo->context,
                                      &parameters[i].value,
                                      NULL);
      seed_object_set_property (sinfo->context,
                                extension,
                                key,
                                value);

      g_free (key);
    }

  /* Set the plugin info as an attribute of the instance */
  g_value_init (&gvalue, PEAS_TYPE_PLUGIN_INFO);
  g_value_set_boxed (&gvalue, info);

  value = seed_value_from_gvalue (sinfo->context, &gvalue, NULL);
  seed_object_set_property (sinfo->context, extension, "plugin_info", value);

  g_value_unset (&gvalue);


  /* Do not add exten_type as it will be added below */
  interfaces = g_array_new (TRUE, FALSE, sizeof (GType));

  property_names = seed_object_copy_property_names (sinfo->context,
                                                    sinfo->extensions);

  for (i = 0; property_names[i] != NULL; ++i)
    {
      gchar *property_name = property_names[i];
      SeedValue *prop_extension_ctor;
      GType the_type;

      prop_extension_ctor = seed_object_get_property (sinfo->context,
                                                      sinfo->extensions,
                                                      property_name);

      if (prop_extension_ctor != extension_ctor)
        continue;

      if (!seed_value_is_object (sinfo->context, extension_ctor))
        {
          g_warning ("Extension '%s' in plugin '%s' is not a Seed object",
                     property_name, peas_plugin_info_get_module_name (info));
          continue;
        }

      the_type = peas_gi_get_type_from_name (property_name);

      if (the_type == G_TYPE_INVALID)
        {
          g_warning ("Could not find GType for '%s', "
                     "did you forget to import it?", property_name);
        }
      else
        {
          g_array_append_val (interfaces, the_type);
        }
    }

  g_array_sort (interfaces, (GCompareFunc) prerequisites_sort);

  g_strfreev (property_names);

  return peas_extension_seed_new (exten_type,
                                  (GType *) g_array_free (interfaces, FALSE),
                                  sinfo->context, extension);
}
Beispiel #14
0
int main(int argc, char* argv[])
{
    const char *scriptPath = "testapi.js";
    if (argc > 1) {
        scriptPath = argv[1];
    }
    
    // Test garbage collection with a fresh context
    context = JSGlobalContextCreateInGroup(NULL, NULL);
    TestInitializeFinalize = true;
    testInitializeFinalize();
    JSGlobalContextRelease(context);
    TestInitializeFinalize = false;

    ASSERT(Base_didFinalize);

    JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty;
    globalObjectClassDefinition.initialize = globalObject_initialize;
    globalObjectClassDefinition.staticValues = globalObject_staticValues;
    globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions;
    globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
    JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition);
    context = JSGlobalContextCreateInGroup(NULL, globalObjectClass);

    JSGlobalContextRetain(context);
    JSGlobalContextRelease(context);

    JSObjectRef globalObject = JSContextGetGlobalObject(context);
    ASSERT(JSValueIsObject(context, globalObject));
    
    JSValueRef jsUndefined = JSValueMakeUndefined(context);
    JSValueRef jsNull = JSValueMakeNull(context);
    JSValueRef jsTrue = JSValueMakeBoolean(context, true);
    JSValueRef jsFalse = JSValueMakeBoolean(context, false);
    JSValueRef jsZero = JSValueMakeNumber(context, 0);
    JSValueRef jsOne = JSValueMakeNumber(context, 1);
    JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0);
    JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, NULL);
    JSObjectSetPrototype(context, jsObjectNoProto, JSValueMakeNull(context));

    // FIXME: test funny utf8 characters
    JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString("");
    JSValueRef jsEmptyString = JSValueMakeString(context, jsEmptyIString);
    
    JSStringRef jsOneIString = JSStringCreateWithUTF8CString("1");
    JSValueRef jsOneString = JSValueMakeString(context, jsOneIString);

    UniChar singleUniChar = 65; // Capital A
    CFMutableStringRef cfString = 
        CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault,
                                                          &singleUniChar,
                                                          1,
                                                          1,
                                                          kCFAllocatorNull);

    JSStringRef jsCFIString = JSStringCreateWithCFString(cfString);
    JSValueRef jsCFString = JSValueMakeString(context, jsCFIString);
    
    CFStringRef cfEmptyString = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8);
    
    JSStringRef jsCFEmptyIString = JSStringCreateWithCFString(cfEmptyString);
    JSValueRef jsCFEmptyString = JSValueMakeString(context, jsCFEmptyIString);

    CFIndex cfStringLength = CFStringGetLength(cfString);
    UniChar* buffer = (UniChar*)malloc(cfStringLength * sizeof(UniChar));
    CFStringGetCharacters(cfString, 
                          CFRangeMake(0, cfStringLength), 
                          buffer);
    JSStringRef jsCFIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, cfStringLength);
    JSValueRef jsCFStringWithCharacters = JSValueMakeString(context, jsCFIStringWithCharacters);
    
    JSStringRef jsCFEmptyIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, CFStringGetLength(cfEmptyString));
    free(buffer);
    JSValueRef jsCFEmptyStringWithCharacters = JSValueMakeString(context, jsCFEmptyIStringWithCharacters);

    ASSERT(JSValueGetType(context, jsUndefined) == kJSTypeUndefined);
    ASSERT(JSValueGetType(context, jsNull) == kJSTypeNull);
    ASSERT(JSValueGetType(context, jsTrue) == kJSTypeBoolean);
    ASSERT(JSValueGetType(context, jsFalse) == kJSTypeBoolean);
    ASSERT(JSValueGetType(context, jsZero) == kJSTypeNumber);
    ASSERT(JSValueGetType(context, jsOne) == kJSTypeNumber);
    ASSERT(JSValueGetType(context, jsOneThird) == kJSTypeNumber);
    ASSERT(JSValueGetType(context, jsEmptyString) == kJSTypeString);
    ASSERT(JSValueGetType(context, jsOneString) == kJSTypeString);
    ASSERT(JSValueGetType(context, jsCFString) == kJSTypeString);
    ASSERT(JSValueGetType(context, jsCFStringWithCharacters) == kJSTypeString);
    ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString);
    ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString);

    JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
    JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
    JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
    JSStringRelease(myObjectIString);
    
    JSValueRef exception;

    // Conversions that throw exceptions
    exception = NULL;
    ASSERT(NULL == JSValueToObject(context, jsNull, &exception));
    ASSERT(exception);
    
    exception = NULL;
    // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
    // causing a build break with -Wshorten-64-to-32 enabled.  The issue is known by the appropriate team.
    // After that's resolved, we can remove these casts
    ASSERT(isnan((float)JSValueToNumber(context, jsObjectNoProto, &exception)));
    ASSERT(exception);

    exception = NULL;
    ASSERT(!JSValueToStringCopy(context, jsObjectNoProto, &exception));
    ASSERT(exception);
    
    ASSERT(JSValueToBoolean(context, myObject));
    
    exception = NULL;
    ASSERT(!JSValueIsEqual(context, jsObjectNoProto, JSValueMakeNumber(context, 1), &exception));
    ASSERT(exception);
    
    exception = NULL;
    JSObjectGetPropertyAtIndex(context, myObject, 0, &exception);
    ASSERT(1 == JSValueToNumber(context, exception, NULL));

    assertEqualsAsBoolean(jsUndefined, false);
    assertEqualsAsBoolean(jsNull, false);
    assertEqualsAsBoolean(jsTrue, true);
    assertEqualsAsBoolean(jsFalse, false);
    assertEqualsAsBoolean(jsZero, false);
    assertEqualsAsBoolean(jsOne, true);
    assertEqualsAsBoolean(jsOneThird, true);
    assertEqualsAsBoolean(jsEmptyString, false);
    assertEqualsAsBoolean(jsOneString, true);
    assertEqualsAsBoolean(jsCFString, true);
    assertEqualsAsBoolean(jsCFStringWithCharacters, true);
    assertEqualsAsBoolean(jsCFEmptyString, false);
    assertEqualsAsBoolean(jsCFEmptyStringWithCharacters, false);
    
    assertEqualsAsNumber(jsUndefined, nan(""));
    assertEqualsAsNumber(jsNull, 0);
    assertEqualsAsNumber(jsTrue, 1);
    assertEqualsAsNumber(jsFalse, 0);
    assertEqualsAsNumber(jsZero, 0);
    assertEqualsAsNumber(jsOne, 1);
    assertEqualsAsNumber(jsOneThird, 1.0 / 3.0);
    assertEqualsAsNumber(jsEmptyString, 0);
    assertEqualsAsNumber(jsOneString, 1);
    assertEqualsAsNumber(jsCFString, nan(""));
    assertEqualsAsNumber(jsCFStringWithCharacters, nan(""));
    assertEqualsAsNumber(jsCFEmptyString, 0);
    assertEqualsAsNumber(jsCFEmptyStringWithCharacters, 0);
    ASSERT(sizeof(JSChar) == sizeof(UniChar));
    
    assertEqualsAsCharactersPtr(jsUndefined, "undefined");
    assertEqualsAsCharactersPtr(jsNull, "null");
    assertEqualsAsCharactersPtr(jsTrue, "true");
    assertEqualsAsCharactersPtr(jsFalse, "false");
    assertEqualsAsCharactersPtr(jsZero, "0");
    assertEqualsAsCharactersPtr(jsOne, "1");
    assertEqualsAsCharactersPtr(jsOneThird, "0.3333333333333333");
    assertEqualsAsCharactersPtr(jsEmptyString, "");
    assertEqualsAsCharactersPtr(jsOneString, "1");
    assertEqualsAsCharactersPtr(jsCFString, "A");
    assertEqualsAsCharactersPtr(jsCFStringWithCharacters, "A");
    assertEqualsAsCharactersPtr(jsCFEmptyString, "");
    assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters, "");
    
    assertEqualsAsUTF8String(jsUndefined, "undefined");
    assertEqualsAsUTF8String(jsNull, "null");
    assertEqualsAsUTF8String(jsTrue, "true");
    assertEqualsAsUTF8String(jsFalse, "false");
    assertEqualsAsUTF8String(jsZero, "0");
    assertEqualsAsUTF8String(jsOne, "1");
    assertEqualsAsUTF8String(jsOneThird, "0.3333333333333333");
    assertEqualsAsUTF8String(jsEmptyString, "");
    assertEqualsAsUTF8String(jsOneString, "1");
    assertEqualsAsUTF8String(jsCFString, "A");
    assertEqualsAsUTF8String(jsCFStringWithCharacters, "A");
    assertEqualsAsUTF8String(jsCFEmptyString, "");
    assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters, "");
    
    ASSERT(JSValueIsStrictEqual(context, jsTrue, jsTrue));
    ASSERT(!JSValueIsStrictEqual(context, jsOne, jsOneString));

    ASSERT(JSValueIsEqual(context, jsOne, jsOneString, NULL));
    ASSERT(!JSValueIsEqual(context, jsTrue, jsFalse, NULL));
    
    CFStringRef cfJSString = JSStringCopyCFString(kCFAllocatorDefault, jsCFIString);
    CFStringRef cfJSEmptyString = JSStringCopyCFString(kCFAllocatorDefault, jsCFEmptyIString);
    ASSERT(CFEqual(cfJSString, cfString));
    ASSERT(CFEqual(cfJSEmptyString, cfEmptyString));
    CFRelease(cfJSString);
    CFRelease(cfJSEmptyString);

    CFRelease(cfString);
    CFRelease(cfEmptyString);
    
    jsGlobalValue = JSObjectMake(context, NULL, NULL);
    JSValueProtect(context, jsGlobalValue);
    JSGarbageCollect(context);
    ASSERT(JSValueIsObject(context, jsGlobalValue));
    JSValueUnprotect(context, jsGlobalValue);

    JSStringRef goodSyntax = JSStringCreateWithUTF8CString("x = 1;");
    JSStringRef badSyntax = JSStringCreateWithUTF8CString("x := 1;");
    ASSERT(JSCheckScriptSyntax(context, goodSyntax, NULL, 0, NULL));
    ASSERT(!JSCheckScriptSyntax(context, badSyntax, NULL, 0, NULL));

    JSValueRef result;
    JSValueRef v;
    JSObjectRef o;
    JSStringRef string;

    result = JSEvaluateScript(context, goodSyntax, NULL, NULL, 1, NULL);
    ASSERT(result);
    ASSERT(JSValueIsEqual(context, result, jsOne, NULL));

    exception = NULL;
    result = JSEvaluateScript(context, badSyntax, NULL, NULL, 1, &exception);
    ASSERT(!result);
    ASSERT(JSValueIsObject(context, exception));
    
    JSStringRef array = JSStringCreateWithUTF8CString("Array");
    JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
    JSStringRelease(array);
    result = JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, NULL);
    ASSERT(result);
    ASSERT(JSValueIsObject(context, result));
    ASSERT(JSValueIsInstanceOfConstructor(context, result, arrayConstructor, NULL));
    ASSERT(!JSValueIsInstanceOfConstructor(context, JSValueMakeNull(context), arrayConstructor, NULL));

    o = JSValueToObject(context, result, NULL);
    exception = NULL;
    ASSERT(JSValueIsUndefined(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception)));
    ASSERT(!exception);
    
    JSObjectSetPropertyAtIndex(context, o, 0, JSValueMakeNumber(context, 1), &exception);
    ASSERT(!exception);
    
    exception = NULL;
    ASSERT(1 == JSValueToNumber(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception), &exception));
    ASSERT(!exception);

    JSStringRef functionBody;
    JSObjectRef function;
    
    exception = NULL;
    functionBody = JSStringCreateWithUTF8CString("rreturn Array;");
    JSStringRef line = JSStringCreateWithUTF8CString("line");
    ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception));
    ASSERT(JSValueIsObject(context, exception));
    v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL);
    assertEqualsAsNumber(v, 1);
    JSStringRelease(functionBody);
    JSStringRelease(line);

    exception = NULL;
    functionBody = JSStringCreateWithUTF8CString("return Array;");
    function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception);
    JSStringRelease(functionBody);
    ASSERT(!exception);
    ASSERT(JSObjectIsFunction(context, function));
    v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
    ASSERT(v);
    ASSERT(JSValueIsEqual(context, v, arrayConstructor, NULL));
    
    exception = NULL;
    function = JSObjectMakeFunction(context, NULL, 0, NULL, jsEmptyIString, NULL, 0, &exception);
    ASSERT(!exception);
    v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, &exception);
    ASSERT(v && !exception);
    ASSERT(JSValueIsUndefined(context, v));
    
    exception = NULL;
    v = NULL;
    JSStringRef foo = JSStringCreateWithUTF8CString("foo");
    JSStringRef argumentNames[] = { foo };
    functionBody = JSStringCreateWithUTF8CString("return foo;");
    function = JSObjectMakeFunction(context, foo, 1, argumentNames, functionBody, NULL, 1, &exception);
    ASSERT(function && !exception);
    JSValueRef arguments[] = { JSValueMakeNumber(context, 2) };
    v = JSObjectCallAsFunction(context, function, NULL, 1, arguments, &exception);
    JSStringRelease(foo);
    JSStringRelease(functionBody);
    
    string = JSValueToStringCopy(context, function, NULL);
    assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) {return foo;}");
    JSStringRelease(string);

    JSStringRef print = JSStringCreateWithUTF8CString("print");
    JSObjectRef printFunction = JSObjectMakeFunctionWithCallback(context, print, print_callAsFunction);
    JSObjectSetProperty(context, globalObject, print, printFunction, kJSPropertyAttributeNone, NULL); 
    JSStringRelease(print);
    
    ASSERT(!JSObjectSetPrivate(printFunction, (void*)1));
    ASSERT(!JSObjectGetPrivate(printFunction));

    JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor");
    JSObjectRef myConstructor = JSObjectMakeConstructor(context, NULL, myConstructor_callAsConstructor);
    JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL);
    JSStringRelease(myConstructorIString);
    
    ASSERT(!JSObjectSetPrivate(myConstructor, (void*)1));
    ASSERT(!JSObjectGetPrivate(myConstructor));
    
    string = JSStringCreateWithUTF8CString("Derived");
    JSObjectRef derivedConstructor = JSObjectMakeConstructor(context, Derived_class(context), NULL);
    JSObjectSetProperty(context, globalObject, string, derivedConstructor, kJSPropertyAttributeNone, NULL);
    JSStringRelease(string);
    
    o = JSObjectMake(context, NULL, NULL);
    JSObjectSetProperty(context, o, jsOneIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeNone, NULL);
    JSObjectSetProperty(context, o, jsCFIString,  JSValueMakeNumber(context, 1), kJSPropertyAttributeDontEnum, NULL);
    JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, o);
    size_t expectedCount = JSPropertyNameArrayGetCount(nameArray);
    size_t count;
    for (count = 0; count < expectedCount; ++count)
        JSPropertyNameArrayGetNameAtIndex(nameArray, count);
    JSPropertyNameArrayRelease(nameArray);
    ASSERT(count == 1); // jsCFString should not be enumerated

    JSClassDefinition nullDefinition = kJSClassDefinitionEmpty;
    nullDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
    JSClassRef nullClass = JSClassCreate(&nullDefinition);
    JSClassRelease(nullClass);
    
    nullDefinition = kJSClassDefinitionEmpty;
    nullClass = JSClassCreate(&nullDefinition);
    JSClassRelease(nullClass);

    functionBody = JSStringCreateWithUTF8CString("return this;");
    function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
    JSStringRelease(functionBody);
    v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
    ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
    v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
    ASSERT(JSValueIsEqual(context, v, o, NULL));

    functionBody = JSStringCreateWithUTF8CString("return eval(\"this\");");
    function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
    JSStringRelease(functionBody);
    v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
    ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
    v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
    ASSERT(JSValueIsEqual(context, v, o, NULL));

    JSStringRef script = JSStringCreateWithUTF8CString("this;");
    v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
    ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
    v = JSEvaluateScript(context, script, o, NULL, 1, NULL);
    ASSERT(JSValueIsEqual(context, v, o, NULL));
    JSStringRelease(script);

    script = JSStringCreateWithUTF8CString("eval(this);");
    v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
    ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
    v = JSEvaluateScript(context, script, o, NULL, 1, NULL);
    ASSERT(JSValueIsEqual(context, v, o, NULL));
    JSStringRelease(script);

    char* scriptUTF8 = createStringWithContentsOfFile(scriptPath);
    if (!scriptUTF8)
        printf("FAIL: Test script could not be loaded.\n");
    else {
        script = JSStringCreateWithUTF8CString(scriptUTF8);
        result = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
        if (JSValueIsUndefined(context, result))
            printf("PASS: Test script executed successfully.\n");
        else {
            printf("FAIL: Test script returned unexpected value:\n");
            JSStringRef exceptionIString = JSValueToStringCopy(context, exception, NULL);
            CFStringRef exceptionCF = JSStringCopyCFString(kCFAllocatorDefault, exceptionIString);
            CFShow(exceptionCF);
            CFRelease(exceptionCF);
            JSStringRelease(exceptionIString);
        }
        JSStringRelease(script);
        free(scriptUTF8);
    }

    // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
    function = NULL;
    v = NULL;
    o = NULL;
    globalObject = NULL;

    JSStringRelease(jsEmptyIString);
    JSStringRelease(jsOneIString);
    JSStringRelease(jsCFIString);
    JSStringRelease(jsCFEmptyIString);
    JSStringRelease(jsCFIStringWithCharacters);
    JSStringRelease(jsCFEmptyIStringWithCharacters);
    JSStringRelease(goodSyntax);
    JSStringRelease(badSyntax);

    JSGlobalContextRelease(context);
    JSClassRelease(globalObjectClass);

    printf("PASS: Program exited normally.\n");
    return 0;
}