JavaScriptCore-7608.4.9.1.3

This commit is contained in:
Ariel Abreu 2020-08-29 09:27:11 -04:00
parent 5ea63805e6
commit ffed2428ed
No known key found for this signature in database
GPG Key ID: ECF8C2B9E8AD3E6B
2357 changed files with 387815 additions and 412341 deletions

View File

@ -30,6 +30,7 @@
#include "JSCJSValue.h"
#include "JSCJSValueInlines.h"
#include "JSGlobalObject.h"
#include "HeapCellInlines.h"
namespace JSC {
class ExecState;
@ -68,7 +69,7 @@ inline JSC::JSGlobalObject* toJSGlobalObject(JSGlobalContextRef context)
inline JSC::JSValue toJS(JSC::ExecState* exec, JSValueRef v)
{
ASSERT_UNUSED(exec, exec);
#if USE(JSVALUE32_64)
#if !CPU(ADDRESS64)
JSC::JSCell* jsCell = reinterpret_cast<JSC::JSCell*>(const_cast<OpaqueJSValue*>(v));
if (!jsCell)
return JSC::jsNull();
@ -78,28 +79,28 @@ inline JSC::JSValue toJS(JSC::ExecState* exec, JSValueRef v)
else
result = jsCell;
#else
JSC::JSValue result = JSC::JSValue::decode(reinterpret_cast<JSC::EncodedJSValue>(const_cast<OpaqueJSValue*>(v)));
JSC::JSValue result = bitwise_cast<JSC::JSValue>(v);
#endif
if (!result)
return JSC::jsNull();
if (result.isCell())
RELEASE_ASSERT(result.asCell()->methodTable());
RELEASE_ASSERT(result.asCell()->methodTable(exec->vm()));
return result;
}
inline JSC::JSValue toJSForGC(JSC::ExecState* exec, JSValueRef v)
{
ASSERT_UNUSED(exec, exec);
#if USE(JSVALUE32_64)
#if !CPU(ADDRESS64)
JSC::JSCell* jsCell = reinterpret_cast<JSC::JSCell*>(const_cast<OpaqueJSValue*>(v));
if (!jsCell)
return JSC::JSValue();
JSC::JSValue result = jsCell;
#else
JSC::JSValue result = JSC::JSValue::decode(reinterpret_cast<JSC::EncodedJSValue>(const_cast<OpaqueJSValue*>(v)));
JSC::JSValue result = bitwise_cast<JSC::JSValue>(v);
#endif
if (result && result.isCell())
RELEASE_ASSERT(result.asCell()->methodTable());
RELEASE_ASSERT(result.asCell()->methodTable(exec->vm()));
return result;
}
@ -113,7 +114,7 @@ inline JSC::JSObject* toJS(JSObjectRef o)
{
JSC::JSObject* object = uncheckedToJS(o);
if (object)
RELEASE_ASSERT(object->methodTable());
RELEASE_ASSERT(object->methodTable(*object->vm()));
return object;
}
@ -127,21 +128,26 @@ inline JSC::VM* toJS(JSContextGroupRef g)
return reinterpret_cast<JSC::VM*>(const_cast<OpaqueJSContextGroup*>(g));
}
inline JSValueRef toRef(JSC::ExecState* exec, JSC::JSValue v)
inline JSValueRef toRef(JSC::VM& vm, JSC::JSValue v)
{
ASSERT(exec->vm().currentThreadIsHoldingAPILock());
#if USE(JSVALUE32_64)
ASSERT(vm.currentThreadIsHoldingAPILock());
#if !CPU(ADDRESS64)
if (!v)
return 0;
if (!v.isCell())
return reinterpret_cast<JSValueRef>(JSC::jsAPIValueWrapper(exec, v).asCell());
return reinterpret_cast<JSValueRef>(JSC::JSAPIValueWrapper::create(vm, v));
return reinterpret_cast<JSValueRef>(v.asCell());
#else
UNUSED_PARAM(exec);
return reinterpret_cast<JSValueRef>(JSC::JSValue::encode(v));
UNUSED_PARAM(vm);
return bitwise_cast<JSValueRef>(v);
#endif
}
inline JSValueRef toRef(JSC::ExecState* exec, JSC::JSValue v)
{
return toRef(exec->vm(), v);
}
inline JSObjectRef toRef(JSC::JSObject* o)
{
return reinterpret_cast<JSObjectRef>(o);

View File

@ -37,17 +37,15 @@ enum class ExceptionStatus {
DidNotThrow
};
inline ExceptionStatus handleExceptionIfNeeded(JSC::ExecState* exec, JSValueRef* returnedExceptionRef)
inline ExceptionStatus handleExceptionIfNeeded(JSC::CatchScope& scope, JSC::ExecState* exec, JSValueRef* returnedExceptionRef)
{
JSC::VM& vm = exec->vm();
auto scope = DECLARE_CATCH_SCOPE(vm);
if (UNLIKELY(scope.exception())) {
JSC::Exception* exception = scope.exception();
if (returnedExceptionRef)
*returnedExceptionRef = toRef(exec, exception->value());
scope.clearException();
#if ENABLE(REMOTE_INSPECTOR)
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception);
scope.vm().vmEntryGlobalObject(exec)->inspectorController().reportAPIException(exec, exception);
#endif
return ExceptionStatus::DidThrow;
}
@ -59,7 +57,8 @@ inline void setException(JSC::ExecState* exec, JSValueRef* returnedExceptionRef,
if (returnedExceptionRef)
*returnedExceptionRef = toRef(exec, exception);
#if ENABLE(REMOTE_INSPECTOR)
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, JSC::Exception::create(exec->vm(), exception));
JSC::VM& vm = exec->vm();
vm.vmEntryGlobalObject(exec)->inspectorController().reportAPIException(exec, JSC::Exception::create(vm, exception));
#endif
}

54
API/JSAPIGlobalObject.cpp Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2019 Apple 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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 "config.h"
#include "JSAPIGlobalObject.h"
#if !JSC_OBJC_API_ENABLED
namespace JSC {
const ClassInfo JSAPIGlobalObject::s_info = { "GlobalObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSAPIGlobalObject) };
const GlobalObjectMethodTable JSAPIGlobalObject::s_globalObjectMethodTable = {
&supportsRichSourceInfo,
&shouldInterruptScript,
&javaScriptRuntimeFlags,
nullptr, // queueTaskToEventLoop
&shouldInterruptScriptBeforeTimeout,
nullptr, // moduleLoaderImportModule
nullptr, // moduleLoaderResolve
nullptr, // moduleLoaderFetch
nullptr, // moduleLoaderCreateImportMetaProperties
nullptr, // moduleLoaderEvaluate
nullptr, // promiseRejectionTracker
nullptr, // defaultLanguage
nullptr, // compileStreaming
nullptr, // instantiateStreaming
};
}
#endif

69
API/JSAPIGlobalObject.h Normal file
View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2019 Apple 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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.
*/
#pragma once
#include "JSGlobalObject.h"
OBJC_CLASS JSScript;
namespace JSC {
class JSAPIGlobalObject : public JSGlobalObject {
public:
using Base = JSGlobalObject;
DECLARE_EXPORT_INFO;
static const GlobalObjectMethodTable s_globalObjectMethodTable;
static JSAPIGlobalObject* create(VM& vm, Structure* structure)
{
auto* object = new (NotNull, allocateCell<JSAPIGlobalObject>(vm.heap)) JSAPIGlobalObject(vm, structure);
object->finishCreation(vm);
return object;
}
static Structure* createStructure(VM& vm, JSValue prototype)
{
auto* result = Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
result->setTransitionWatchpointIsLikelyToBeFired(true);
return result;
}
static JSInternalPromise* moduleLoaderImportModule(JSGlobalObject*, ExecState*, JSModuleLoader*, JSString* moduleNameValue, JSValue parameters, const SourceOrigin&);
static Identifier moduleLoaderResolve(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue keyValue, JSValue referrerValue, JSValue);
static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue, JSValue);
static JSObject* moduleLoaderCreateImportMetaProperties(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSModuleRecord*, JSValue);
static JSValue moduleLoaderEvaluate(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue, JSValue);
JSValue loadAndEvaluateJSScriptModule(const JSLockHolder&, JSScript *);
private:
JSAPIGlobalObject(VM& vm, Structure* structure)
: Base(vm, structure, &s_globalObjectMethodTable)
{ }
};
}

288
API/JSAPIGlobalObject.mm Normal file
View File

@ -0,0 +1,288 @@
/*
* Copyright (C) 2019 Apple 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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.
*/
#import "config.h"
#import "JSAPIGlobalObject.h"
#if JSC_OBJC_API_ENABLED
#import "APICast.h"
#import "CatchScope.h"
#import "Completion.h"
#import "Error.h"
#import "Exception.h"
#import "JSContextInternal.h"
#import "JSInternalPromise.h"
#import "JSInternalPromiseDeferred.h"
#import "JSModuleLoader.h"
#import "JSNativeStdFunction.h"
#import "JSPromiseDeferred.h"
#import "JSScriptInternal.h"
#import "JSSourceCode.h"
#import "JSValueInternal.h"
#import "JSVirtualMachineInternal.h"
#import "JavaScriptCore.h"
#import "ObjectConstructor.h"
#import "SourceOrigin.h"
#import <wtf/URL.h>
namespace JSC {
const ClassInfo JSAPIGlobalObject::s_info = { "GlobalObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSAPIGlobalObject) };
const GlobalObjectMethodTable JSAPIGlobalObject::s_globalObjectMethodTable = {
&supportsRichSourceInfo,
&shouldInterruptScript,
&javaScriptRuntimeFlags,
nullptr, // queueTaskToEventLoop
&shouldInterruptScriptBeforeTimeout,
&moduleLoaderImportModule, // moduleLoaderImportModule
&moduleLoaderResolve, // moduleLoaderResolve
&moduleLoaderFetch, // moduleLoaderFetch
&moduleLoaderCreateImportMetaProperties, // moduleLoaderCreateImportMetaProperties
moduleLoaderEvaluate, // moduleLoaderEvaluate
nullptr, // promiseRejectionTracker
nullptr, // defaultLanguage
nullptr, // compileStreaming
nullptr, // instantiateStreaming
};
static Expected<URL, String> computeValidImportSpecifier(const URL& base, const String& specifier)
{
URL absoluteURL(URL(), specifier);
if (absoluteURL.isValid())
return absoluteURL;
if (!specifier.startsWith('/') && !specifier.startsWith("./") && !specifier.startsWith("../"))
return makeUnexpected(makeString("Module specifier: "_s, specifier, " does not start with \"/\", \"./\", or \"../\"."_s));
if (specifier.startsWith('/')) {
absoluteURL = URL(URL({ }, "file://"), specifier);
if (absoluteURL.isValid())
return absoluteURL;
}
if (base == URL())
return makeUnexpected("Could not determine the base URL for loading."_s);
if (!base.isValid())
return makeUnexpected(makeString("Referrering script's url is not valid: "_s, base.string()));
absoluteURL = URL(base, specifier);
if (absoluteURL.isValid())
return absoluteURL;
return makeUnexpected(makeString("Could not form valid URL from identifier and base. Tried:"_s, absoluteURL.string()));
}
Identifier JSAPIGlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue key, JSValue referrer, JSValue)
{
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
ASSERT_UNUSED(globalObject, globalObject == exec->lexicalGlobalObject());
ASSERT(key.isString() || key.isSymbol());
String name = key.toWTFString(exec);
RETURN_IF_EXCEPTION(scope, { });
URL base;
if (JSString* referrerString = jsDynamicCast<JSString*>(vm, referrer)) {
String value = referrerString->value(exec);
RETURN_IF_EXCEPTION(scope, { });
URL referrerURL({ }, value);
RELEASE_ASSERT(referrerURL.isValid());
base = WTFMove(referrerURL);
}
auto result = computeValidImportSpecifier(base, name);
if (result)
return Identifier::fromString(&vm, result.value());
throwVMError(exec, scope, createError(exec, result.error()));
return { };
}
JSInternalPromise* JSAPIGlobalObject::moduleLoaderImportModule(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSString* specifierValue, JSValue, const SourceOrigin& sourceOrigin)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_CATCH_SCOPE(vm);
auto reject = [&] (JSValue exception) -> JSInternalPromise* {
scope.clearException();
auto* promise = JSInternalPromiseDeferred::tryCreate(exec, globalObject);
scope.clearException();
return promise->reject(exec, exception);
};
auto import = [&] (URL& url) {
auto result = importModule(exec, Identifier::fromString(&vm, url), jsUndefined(), jsUndefined());
if (UNLIKELY(scope.exception()))
return reject(scope.exception());
return result;
};
auto specifier = specifierValue->value(exec);
if (UNLIKELY(scope.exception())) {
JSValue exception = scope.exception();
scope.clearException();
return reject(exception);
}
String referrer = !sourceOrigin.isNull() ? sourceOrigin.string() : String();
URL baseURL(URL(), referrer);
auto result = computeValidImportSpecifier(baseURL, specifier);
if (result)
return import(result.value());
return reject(createError(exec, result.error()));
}
JSInternalPromise* JSAPIGlobalObject::moduleLoaderFetch(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue key, JSValue, JSValue)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_CATCH_SCOPE(vm);
ASSERT(globalObject == exec->lexicalGlobalObject());
JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(globalObject->globalExec())];
JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::tryCreate(exec, globalObject);
RETURN_IF_EXCEPTION(scope, nullptr);
Identifier moduleKey = key.toPropertyKey(exec);
if (UNLIKELY(scope.exception())) {
JSValue exception = scope.exception();
scope.clearException();
return deferred->reject(exec, exception);
}
if (UNLIKELY(![context moduleLoaderDelegate]))
return deferred->reject(exec, createError(exec, "No module loader provided."));
auto deferredPromise = Strong<JSInternalPromiseDeferred>(vm, deferred);
auto* resolve = JSNativeStdFunction::create(vm, globalObject, 1, "resolve", [=] (ExecState* exec) {
// This captures the globalObject but that's ok because our structure keeps it alive anyway.
VM& vm = exec->vm();
JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(globalObject->globalExec())];
id script = valueToObject(context, toRef(exec, exec->argument(0)));
MarkedArgumentBuffer args;
auto rejectPromise = [&] (String message) {
args.append(createTypeError(exec, message));
call(exec, deferredPromise->JSPromiseDeferred::reject(), args, "This should never be seen...");
return encodedJSUndefined();
};
if (UNLIKELY(![script isKindOfClass:[JSScript class]]))
return rejectPromise("First argument of resolution callback is not a JSScript"_s);
JSScript* jsScript = static_cast<JSScript *>(script);
JSSourceCode* source = [jsScript jsSourceCode];
if (UNLIKELY([jsScript type] != kJSScriptTypeModule))
return rejectPromise("The JSScript that was provided did not have expected type of kJSScriptTypeModule."_s);
NSURL *sourceURL = [jsScript sourceURL];
String oldModuleKey { [sourceURL absoluteString] };
if (UNLIKELY(Identifier::fromString(&vm, oldModuleKey) != moduleKey))
return rejectPromise(makeString("The same JSScript was provided for two different identifiers, previously: ", oldModuleKey, " and now: ", moduleKey.string()));
args.append(source);
call(exec, deferredPromise->JSPromiseDeferred::resolve(), args, "This should never be seen...");
return encodedJSUndefined();
});
auto* reject = JSNativeStdFunction::create(vm, globalObject, 1, "reject", [=] (ExecState* exec) {
MarkedArgumentBuffer args;
args.append(exec->argument(0));
call(exec, deferredPromise->JSPromiseDeferred::reject(), args, "This should never be seen...");
return encodedJSUndefined();
});
[[context moduleLoaderDelegate] context:context fetchModuleForIdentifier:[::JSValue valueWithJSValueRef:toRef(exec, key) inContext:context] withResolveHandler:[::JSValue valueWithJSValueRef:toRef(exec, resolve) inContext:context] andRejectHandler:[::JSValue valueWithJSValueRef:toRef(exec, reject) inContext:context]];
if (context.exception) {
deferred->reject(exec, toJS(exec, [context.exception JSValueRef]));
context.exception = nil;
}
return deferred->promise();
}
JSObject* JSAPIGlobalObject::moduleLoaderCreateImportMetaProperties(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue key, JSModuleRecord*, JSValue)
{
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSObject* metaProperties = constructEmptyObject(exec, globalObject->nullPrototypeObjectStructure());
RETURN_IF_EXCEPTION(scope, nullptr);
metaProperties->putDirect(vm, Identifier::fromString(&vm, "filename"), key);
RETURN_IF_EXCEPTION(scope, nullptr);
return metaProperties;
}
JSValue JSAPIGlobalObject::moduleLoaderEvaluate(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader* moduleLoader, JSValue key, JSValue moduleRecordValue, JSValue scriptFetcher)
{
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(globalObject->globalExec())];
id <JSModuleLoaderDelegate> moduleLoaderDelegate = [context moduleLoaderDelegate];
NSURL *url = nil;
if ([moduleLoaderDelegate respondsToSelector:@selector(willEvaluateModule:)] || [moduleLoaderDelegate respondsToSelector:@selector(didEvaluateModule:)]) {
String moduleKey = key.toWTFString(exec);
RETURN_IF_EXCEPTION(scope, { });
url = [NSURL URLWithString:static_cast<NSString *>(moduleKey)];
}
if ([moduleLoaderDelegate respondsToSelector:@selector(willEvaluateModule:)])
[moduleLoaderDelegate willEvaluateModule:url];
scope.release();
JSValue result = moduleLoader->evaluateNonVirtual(exec, key, moduleRecordValue, scriptFetcher);
if ([moduleLoaderDelegate respondsToSelector:@selector(didEvaluateModule:)])
[moduleLoaderDelegate didEvaluateModule:url];
return result;
}
JSValue JSAPIGlobalObject::loadAndEvaluateJSScriptModule(const JSLockHolder&, JSScript *script)
{
ASSERT(script.type == kJSScriptTypeModule);
VM& vm = this->vm();
ExecState* exec = globalExec();
auto scope = DECLARE_THROW_SCOPE(vm);
Identifier key = Identifier::fromString(exec, String { [[script sourceURL] absoluteString] });
JSInternalPromise* promise = importModule(exec, key, jsUndefined(), jsUndefined());
RETURN_IF_EXCEPTION(scope, { });
auto result = JSPromiseDeferred::tryCreate(exec, this);
RETURN_IF_EXCEPTION(scope, { });
result->resolve(exec, promise);
return result->promise();
}
}
#endif // JSC_OBJC_API_ENABLED

View File

@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2004, 2005, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2003-2019 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -22,14 +22,14 @@
#pragma once
#include "JSCJSValue.h"
#include "JSCell.h"
#include "CallFrame.h"
#include "JSCJSValue.h"
#include "JSCast.h"
#include "Structure.h"
namespace JSC {
class JSAPIValueWrapper : public JSCell {
class JSAPIValueWrapper final : public JSCell {
friend JSValue jsAPIValueWrapper(ExecState*, JSValue);
public:
typedef JSCell Base;
@ -44,10 +44,9 @@ public:
DECLARE_EXPORT_INFO;
static JSAPIValueWrapper* create(ExecState* exec, JSValue value)
static JSAPIValueWrapper* create(VM& vm, JSValue value)
{
VM& vm = exec->vm();
JSAPIValueWrapper* wrapper = new (NotNull, allocateCell<JSAPIValueWrapper>(vm.heap)) JSAPIValueWrapper(exec);
JSAPIValueWrapper* wrapper = new (NotNull, allocateCell<JSAPIValueWrapper>(vm.heap)) JSAPIValueWrapper(vm);
wrapper->finishCreation(vm, value);
return wrapper;
}
@ -61,17 +60,12 @@ protected:
}
private:
JSAPIValueWrapper(ExecState* exec)
: JSCell(exec->vm(), exec->vm().apiWrapperStructure.get())
JSAPIValueWrapper(VM& vm)
: JSCell(vm, vm.apiWrapperStructure.get())
{
}
WriteBarrier<Unknown> m_value;
};
inline JSValue jsAPIValueWrapper(ExecState* exec, JSValue value)
{
return JSAPIValueWrapper::create(exec, value);
}
} // namespace JSC

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
* Copyright (C) 2013-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -28,9 +28,8 @@
#include "JSBase.h"
#include "JSDestructibleObject.h"
#include "WeakReferenceHarvester.h"
#if JSC_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED || defined(JSC_GLIB_API_ENABLED)
namespace JSC {
@ -48,11 +47,11 @@ protected:
JSAPIWrapperObject(VM&, Structure*);
private:
void* m_wrappedObject;
void* m_wrappedObject { nullptr };
};
} // namespace JSC
#endif // JSC_OBJC_API_ENABLED
#endif // JSC_OBJC_API_ENABLED || defined(JSC_GLIB_API_ENABLED)
#endif // JSAPIWrapperObject_h

View 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
@ -37,7 +37,7 @@
class JSAPIWrapperObjectHandleOwner : public JSC::WeakHandleOwner {
public:
void finalize(JSC::Handle<JSC::Unknown>, void*) override;
bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&) override;
bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**) override;
};
static JSAPIWrapperObjectHandleOwner* jsAPIWrapperObjectHandleOwner()
@ -56,14 +56,14 @@ void JSAPIWrapperObjectHandleOwner::finalize(JSC::Handle<JSC::Unknown> handle, v
JSC::WeakSet::deallocate(JSC::WeakImpl::asWeakImpl(handle.slot()));
}
bool JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor)
bool JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor, const char**)
{
JSC::JSAPIWrapperObject* wrapperObject = JSC::jsCast<JSC::JSAPIWrapperObject*>(handle.get().asCell());
// We use the JSGlobalObject when processing weak handles to prevent the situation where using
// the same Objective-C object in multiple global objects keeps all of the global objects alive.
if (!wrapperObject->wrappedObject())
return false;
return JSC::Heap::isMarked(wrapperObject->structure()->globalObject()) && visitor.containsOpaqueRoot(wrapperObject->wrappedObject());
return visitor.vm().heap.isMarked(wrapperObject->structure()->globalObject()) && visitor.containsOpaqueRoot(wrapperObject->wrappedObject());
}
namespace JSC {
@ -80,7 +80,6 @@ Structure* JSCallbackObject<JSAPIWrapperObject>::createStructure(VM& vm, JSGloba
JSAPIWrapperObject::JSAPIWrapperObject(VM& vm, Structure* structure)
: Base(vm, structure)
, m_wrappedObject(0)
{
}

View File

@ -25,6 +25,7 @@
#include "config.h"
#include "JSBase.h"
#include "JSBaseInternal.h"
#include "JSBasePrivate.h"
#include "APICast.h"
@ -47,24 +48,15 @@
using namespace JSC;
JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef thisObject, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
JSValueRef JSEvaluateScriptInternal(const JSLockHolder&, ExecState* exec, JSContextRef ctx, JSObjectRef thisObject, const SourceCode& source, JSValueRef* exception)
{
if (!ctx) {
ASSERT_NOT_REACHED();
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
UNUSED_PARAM(ctx);
JSObject* jsThisObject = toJS(thisObject);
startingLineNumber = std::max(1, startingLineNumber);
// evaluate sets "this" to the global object if it is NULL
JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
auto sourceURLString = sourceURL ? sourceURL->string() : String();
SourceCode source = makeSource(script->string(), SourceOrigin { sourceURLString }, sourceURLString, TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber()));
VM& vm = exec->vm();
JSGlobalObject* globalObject = vm.vmEntryGlobalObject(exec);
NakedPtr<Exception> evaluationException;
JSValue returnValue = profiledEvaluate(globalObject->globalExec(), ProfilingReason::API, source, jsThisObject, evaluationException);
@ -79,7 +71,7 @@ JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef th
// We could stash it in the inspector in case an inspector is ever opened.
globalObject->inspectorController().reportAPIException(exec, evaluationException);
#endif
return 0;
return nullptr;
}
if (returnValue)
@ -89,6 +81,24 @@ JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef th
return toRef(exec, jsUndefined());
}
JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef thisObject, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
{
if (!ctx) {
ASSERT_NOT_REACHED();
return nullptr;
}
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(vm);
startingLineNumber = std::max(1, startingLineNumber);
auto sourceURLString = sourceURL ? sourceURL->string() : String();
SourceCode source = makeSource(script->string(), SourceOrigin { sourceURLString }, URL({ }, sourceURLString), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber()));
return JSEvaluateScriptInternal(locker, exec, ctx, thisObject, source, exception);
}
bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
{
if (!ctx) {
@ -96,22 +106,23 @@ bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStringRef sourc
return false;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
startingLineNumber = std::max(1, startingLineNumber);
auto sourceURLString = sourceURL ? sourceURL->string() : String();
SourceCode source = makeSource(script->string(), SourceOrigin { sourceURLString }, sourceURLString, TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber()));
SourceCode source = makeSource(script->string(), SourceOrigin { sourceURLString }, URL({ }, sourceURLString), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber()));
JSValue syntaxException;
bool isValidSyntax = checkSyntax(exec->vmEntryGlobalObject()->globalExec(), source, &syntaxException);
bool isValidSyntax = checkSyntax(vm.vmEntryGlobalObject(exec)->globalExec(), source, &syntaxException);
if (!isValidSyntax) {
if (exception)
*exception = toRef(exec, syntaxException);
#if ENABLE(REMOTE_INSPECTOR)
Exception* exception = Exception::create(exec->vm(), syntaxException);
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception);
Exception* exception = Exception::create(vm, syntaxException);
vm.vmEntryGlobalObject(exec)->inspectorController().reportAPIException(exec, exception);
#endif
return false;
}
@ -130,9 +141,10 @@ void JSGarbageCollect(JSContextRef ctx)
return;
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
exec->vm().heap.reportAbandonedObjectGraph();
vm.heap.reportAbandonedObjectGraph();
}
void JSReportExtraMemoryCost(JSContextRef ctx, size_t size)
@ -142,9 +154,10 @@ void JSReportExtraMemoryCost(JSContextRef ctx, size_t size)
return;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
exec->vm().heap.deprecatedReportExtraMemory(size);
vm.heap.deprecatedReportExtraMemory(size);
}
extern "C" JS_EXPORT void JSSynchronousGarbageCollectForDebugging(JSContextRef);
@ -156,8 +169,9 @@ void JSSynchronousGarbageCollectForDebugging(JSContextRef ctx)
return;
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
exec->vm().heap.collectNow(Sync, CollectionScope::Full);
VM& vm = exec->vm();
JSLockHolder locker(vm);
vm.heap.collectNow(Sync, CollectionScope::Full);
}
void JSSynchronousEdenCollectForDebugging(JSContextRef ctx)
@ -166,8 +180,9 @@ void JSSynchronousEdenCollectForDebugging(JSContextRef ctx)
return;
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
exec->vm().heap.collectSync(CollectionScope::Eden);
VM& vm = exec->vm();
JSLockHolder locker(vm);
vm.heap.collectSync(CollectionScope::Eden);
}
void JSDisableGCTimer(void)
@ -175,7 +190,7 @@ void JSDisableGCTimer(void)
GCActivityCallback::s_shouldCreateGCTimer = false;
}
#if PLATFORM(IOS)
#if PLATFORM(IOS_FAMILY) && TARGET_OS_IOS
// FIXME: Expose symbols to tell dyld where to find JavaScriptCore on older versions of
// iOS (< 7.0). We should remove these symbols once we no longer need to support such
// versions of iOS. See <rdar://problem/13696872> for more details.

View File

@ -68,20 +68,27 @@ typedef const struct OpaqueJSValue* JSValueRef;
/*! @typedef JSObjectRef A JavaScript object. A JSObject is a JSValue. */
typedef struct OpaqueJSValue* JSObjectRef;
/* Clang's __has_declspec_attribute emulation */
/* https://clang.llvm.org/docs/LanguageExtensions.html#has-declspec-attribute */
#ifndef __has_declspec_attribute
#define __has_declspec_attribute(x) 0
#endif
/* JavaScript symbol exports */
/* These rules should stay the same as in WebKit2/Shared/API/c/WKBase.h */
/* These rules should stay the same as in WebKit/Shared/API/c/WKDeclarationSpecifiers.h */
#undef JS_EXPORT
#if defined(JS_NO_EXPORT)
#define JS_EXPORT
#elif defined(__GNUC__) && !defined(__CC_ARM) && !defined(__ARMCC__)
#define JS_EXPORT __attribute__((visibility("default")))
#elif defined(WIN32) || defined(_WIN32) || defined(_WIN32_WCE) || defined(__CC_ARM) || defined(__ARMCC__)
#elif defined(WIN32) || defined(_WIN32) || defined(__CC_ARM) || defined(__ARMCC__) || (__has_declspec_attribute(dllimport) && __has_declspec_attribute(dllexport))
#if defined(BUILDING_JavaScriptCore) || defined(STATICALLY_LINKED_WITH_JavaScriptCore)
#define JS_EXPORT __declspec(dllexport)
#else
#define JS_EXPORT __declspec(dllimport)
#endif
#elif defined(__GNUC__)
#define JS_EXPORT __attribute__((visibility("default")))
#else /* !defined(JS_NO_EXPORT) */
#define JS_EXPORT
#endif /* defined(JS_NO_EXPORT) */
@ -136,7 +143,7 @@ JS_EXPORT void JSGarbageCollect(JSContextRef ctx);
}
#endif
/* Enable the Objective-C API for platforms with a modern runtime. */
/* Enable the Objective-C API for platforms with a modern runtime. NOTE: This is duplicated in VM.h. */
#if !defined(JSC_OBJC_API_ENABLED)
#if (defined(__clang__) && defined(__APPLE__) && ((defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && !defined(__i386__)) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)))
#define JSC_OBJC_API_ENABLED 1

View File

@ -1,6 +1,5 @@
/*
* Copyright (C) 2006 Apple Inc. All rights reserved.
* Copyright (C) 2008 Alp Toker <alp@atoker.com>
* Copyright (C) 2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -24,14 +23,15 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JavaScript_h
#define JavaScript_h
#pragma once
#include <JavaScriptCore/JSBase.h>
#include <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSStringRef.h>
#include <JavaScriptCore/JSObjectRef.h>
#include <JavaScriptCore/JSTypedArray.h>
#include <JavaScriptCore/JSValueRef.h>
#include <JavaScriptCore/WebKitAvailability.h>
#endif /* JavaScript_h */
namespace JSC {
class JSLockHolder;
class ExecState;
class SourceCode;
}
extern "C" JSValueRef JSEvaluateScriptInternal(const JSC::JSLockHolder&, JSC::ExecState*, JSContextRef, JSObjectRef thisObject, const JSC::SourceCode&, JSValueRef* exception);

View File

@ -43,7 +43,7 @@ owns a large non-GC memory region. Calling this function will encourage the
garbage collector to collect soon, hoping to reclaim that large non-GC memory
region.
*/
JS_EXPORT void JSReportExtraMemoryCost(JSContextRef ctx, size_t size) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT void JSReportExtraMemoryCost(JSContextRef ctx, size_t size) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
JS_EXPORT void JSDisableGCTimer(void);

View File

@ -26,19 +26,20 @@
#ifndef JSCallbackConstructor_h
#define JSCallbackConstructor_h
#include "JSDestructibleObject.h"
#include "JSObjectRef.h"
#include "runtime/JSDestructibleObject.h"
namespace JSC {
class JSCallbackConstructor : public JSDestructibleObject {
class JSCallbackConstructor final : public JSDestructibleObject {
public:
typedef JSDestructibleObject Base;
static const unsigned StructureFlags = Base::StructureFlags | ImplementsHasInstance | ImplementsDefaultHasInstance;
static JSCallbackConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, JSObjectCallAsConstructorCallback callback)
{
JSCallbackConstructor* constructor = new (NotNull, allocateCell<JSCallbackConstructor>(*exec->heap())) JSCallbackConstructor(globalObject, structure, classRef, callback);
VM& vm = exec->vm();
JSCallbackConstructor* constructor = new (NotNull, allocateCell<JSCallbackConstructor>(vm.heap)) JSCallbackConstructor(globalObject, structure, classRef, callback);
constructor->finishCreation(globalObject, classRef);
return constructor;
}

View File

@ -44,7 +44,7 @@ STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSCallbackFunction);
const ClassInfo JSCallbackFunction::s_info = { "CallbackFunction", &InternalFunction::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCallbackFunction) };
JSCallbackFunction::JSCallbackFunction(VM& vm, Structure* structure, JSObjectCallAsFunctionCallback callback)
: InternalFunction(vm, structure)
: InternalFunction(vm, structure, APICallbackFunction::call<JSCallbackFunction>, nullptr)
, m_callback(callback)
{
}
@ -63,10 +63,4 @@ JSCallbackFunction* JSCallbackFunction::create(VM& vm, JSGlobalObject* globalObj
return function;
}
CallType JSCallbackFunction::getCallData(JSCell*, CallData& callData)
{
callData.native.function = APICallbackFunction::call<JSCallbackFunction>;
return CallType::Host;
}
} // namespace JSC

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2006-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -31,11 +31,17 @@
namespace JSC {
class JSCallbackFunction : public InternalFunction {
class JSCallbackFunction final : public InternalFunction {
friend struct APICallbackFunction;
public:
typedef InternalFunction Base;
template<typename CellType, SubspaceAccess mode>
static IsoSubspace* subspaceFor(VM& vm)
{
return vm.callbackFunctionSpace<mode>();
}
static JSCallbackFunction* create(VM&, JSGlobalObject*, JSObjectCallAsFunctionCallback, const String& name);
DECLARE_INFO;
@ -44,18 +50,16 @@ public:
// refactor the code so this override isn't necessary
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
{
return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info());
return Structure::create(vm, globalObject, proto, TypeInfo(InternalFunctionType, StructureFlags), info());
}
private:
JSCallbackFunction(VM&, Structure*, JSObjectCallAsFunctionCallback);
void finishCreation(VM&, const String& name);
static CallType getCallData(JSCell*, CallData&);
JSObjectCallAsFunctionCallback functionCallback() { return m_callback; }
JSObjectCallAsFunctionCallback m_callback;
JSObjectCallAsFunctionCallback m_callback { nullptr };
};
} // namespace JSC

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2016 Apple Inc. All rights reserved.
* Copyright (C) 2006-2019 Apple Inc. All rights reserved.
* Copyright (C) 2007 Eric Seidel <eric@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
@ -122,7 +122,7 @@ public:
template <class Parent>
class JSCallbackObject : public Parent {
class JSCallbackObject final : public Parent {
protected:
JSCallbackObject(ExecState*, Structure*, JSClassRef, void* data);
JSCallbackObject(VM&, JSClassRef, Structure*);
@ -132,14 +132,16 @@ protected:
public:
typedef Parent Base;
static const unsigned StructureFlags = Base::StructureFlags | ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesGetPropertyNames | TypeOfShouldCallGetCallData;
static const unsigned StructureFlags = Base::StructureFlags | ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesGetPropertyNames | OverridesGetCallData;
static_assert(!(StructureFlags & ImplementsDefaultHasInstance), "using customHasInstance");
~JSCallbackObject();
static JSCallbackObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, void* data)
{
VM& vm = exec->vm();
ASSERT_UNUSED(globalObject, !structure->globalObject() || structure->globalObject() == globalObject);
JSCallbackObject* callbackObject = new (NotNull, allocateCell<JSCallbackObject>(*exec->heap())) JSCallbackObject(exec, structure, classRef, data);
JSCallbackObject* callbackObject = new (NotNull, allocateCell<JSCallbackObject>(vm.heap)) JSCallbackObject(exec, structure, classRef, data);
callbackObject->finishCreation(exec);
return callbackObject;
}
@ -155,18 +157,9 @@ public:
void* getPrivate();
// FIXME: We should fix the warnings for extern-template in JSObject template classes: https://bugs.webkit.org/show_bug.cgi?id=161979
#if COMPILER(CLANG)
#if __has_warning("-Wundefined-var-template")
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundefined-var-template"
#endif
#endif
IGNORE_CLANG_WARNINGS_BEGIN("undefined-var-template")
DECLARE_INFO;
#if COMPILER(CLANG)
#if __has_warning("-Wundefined-var-template")
#pragma clang diagnostic pop
#endif
#endif
IGNORE_CLANG_WARNINGS_END
JSClassRef classRef() const { return m_callbackObjectData->jsClass; }
bool inherits(JSClassRef) const;
@ -191,7 +184,8 @@ public:
using Parent::methodTable;
private:
static String className(const JSObject*);
static String className(const JSObject*, VM&);
static String toStringName(const JSObject*, ExecState*);
static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
@ -232,7 +226,7 @@ private:
static EncodedJSValue callbackGetter(ExecState*, EncodedJSValue, PropertyName);
std::unique_ptr<JSCallbackObjectData> m_callbackObjectData;
const ClassInfo* m_classInfo;
const ClassInfo* m_classInfo { nullptr };
};
} // namespace JSC

View File

@ -34,7 +34,6 @@
#include "JSLock.h"
#include "JSObjectRef.h"
#include "JSString.h"
#include "JSStringRef.h"
#include "OpaqueJSString.h"
#include "PropertyNameArray.h"
#include <wtf/Vector.h>
@ -130,14 +129,23 @@ void JSCallbackObject<Parent>::init(ExecState* exec)
}
template <class Parent>
String JSCallbackObject<Parent>::className(const JSObject* object)
String JSCallbackObject<Parent>::className(const JSObject* object, VM& vm)
{
const JSCallbackObject* thisObject = jsCast<const JSCallbackObject*>(object);
String thisClassName = thisObject->classRef()->className();
if (!thisClassName.isEmpty())
return thisClassName;
return Parent::className(object);
return Parent::className(object, vm);
}
template <class Parent>
String JSCallbackObject<Parent>::toStringName(const JSObject* object, ExecState* exec)
{
VM& vm = exec->vm();
const ClassInfo* info = object->classInfo(vm);
ASSERT(info);
return info->methodTable.className(object, vm);
}
template <class Parent>
@ -156,15 +164,15 @@ bool JSCallbackObject<Parent>::getOwnPropertySlot(JSObject* object, ExecState* e
// optional optimization to bypass getProperty in cases when we only need to know if the property exists
if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) {
if (!propertyNameRef)
propertyNameRef = OpaqueJSString::create(name);
propertyNameRef = OpaqueJSString::tryCreate(name);
JSLock::DropAllLocks dropAllLocks(exec);
if (hasProperty(ctx, thisRef, propertyNameRef.get())) {
slot.setCustom(thisObject, ReadOnly | DontEnum, callbackGetter);
slot.setCustom(thisObject, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, callbackGetter);
return true;
}
} else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) {
if (!propertyNameRef)
propertyNameRef = OpaqueJSString::create(name);
propertyNameRef = OpaqueJSString::tryCreate(name);
JSValueRef exception = 0;
JSValueRef value;
{
@ -173,11 +181,11 @@ bool JSCallbackObject<Parent>::getOwnPropertySlot(JSObject* object, ExecState* e
}
if (exception) {
throwException(exec, scope, toJS(exec, exception));
slot.setValue(thisObject, ReadOnly | DontEnum, jsUndefined());
slot.setValue(thisObject, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, jsUndefined());
return true;
}
if (value) {
slot.setValue(thisObject, ReadOnly | DontEnum, toJS(exec, value));
slot.setValue(thisObject, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, toJS(exec, value));
return true;
}
}
@ -186,7 +194,7 @@ bool JSCallbackObject<Parent>::getOwnPropertySlot(JSObject* object, ExecState* e
if (staticValues->contains(name)) {
JSValue value = thisObject->getStaticValue(exec, propertyName);
if (value) {
slot.setValue(thisObject, ReadOnly | DontEnum, value);
slot.setValue(thisObject, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, value);
return true;
}
}
@ -194,7 +202,7 @@ bool JSCallbackObject<Parent>::getOwnPropertySlot(JSObject* object, ExecState* e
if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) {
if (staticFunctions->contains(name)) {
slot.setCustom(thisObject, ReadOnly | DontEnum, staticFunctionGetter);
slot.setCustom(thisObject, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, staticFunctionGetter);
return true;
}
}
@ -207,7 +215,7 @@ bool JSCallbackObject<Parent>::getOwnPropertySlot(JSObject* object, ExecState* e
template <class Parent>
bool JSCallbackObject<Parent>::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot)
{
return object->methodTable()->getOwnPropertySlot(object, exec, Identifier::from(exec, propertyName), slot);
return object->methodTable(exec->vm())->getOwnPropertySlot(object, exec, Identifier::from(exec, propertyName), slot);
}
template <class Parent>
@ -253,7 +261,7 @@ bool JSCallbackObject<Parent>::put(JSCell* cell, ExecState* exec, PropertyName p
for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) {
if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) {
if (!propertyNameRef)
propertyNameRef = OpaqueJSString::create(name);
propertyNameRef = OpaqueJSString::tryCreate(name);
JSValueRef exception = 0;
bool result;
{
@ -317,7 +325,7 @@ bool JSCallbackObject<Parent>::putByIndex(JSCell* cell, ExecState* exec, unsigne
for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) {
if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) {
if (!propertyNameRef)
propertyNameRef = OpaqueJSString::create(propertyName.impl());
propertyNameRef = OpaqueJSString::tryCreate(propertyName.impl());
JSValueRef exception = 0;
bool result;
{
@ -376,7 +384,7 @@ bool JSCallbackObject<Parent>::deleteProperty(JSCell* cell, ExecState* exec, Pro
for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) {
if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) {
if (!propertyNameRef)
propertyNameRef = OpaqueJSString::create(name);
propertyNameRef = OpaqueJSString::tryCreate(name);
JSValueRef exception = 0;
bool result;
{
@ -414,7 +422,7 @@ template <class Parent>
bool JSCallbackObject<Parent>::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
{
JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell);
return thisObject->methodTable()->deleteProperty(thisObject, exec, Identifier::from(exec, propertyName));
return thisObject->methodTable(exec->vm())->deleteProperty(thisObject, exec, Identifier::from(exec, propertyName));
}
template <class Parent>
@ -653,7 +661,7 @@ EncodedJSValue JSCallbackObject<Parent>::staticFunctionGetter(ExecState* exec, E
if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) {
if (StaticFunctionEntry* entry = staticFunctions->get(name)) {
if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) {
JSObject* o = JSCallbackFunction::create(vm, thisObj->globalObject(), callAsFunction, name);
JSObject* o = JSCallbackFunction::create(vm, thisObj->globalObject(vm), callAsFunction, name);
thisObj->putDirect(vm, propertyName, o, entry->attributes);
return JSValue::encode(o);
}
@ -662,7 +670,7 @@ EncodedJSValue JSCallbackObject<Parent>::staticFunctionGetter(ExecState* exec, E
}
}
return JSValue::encode(throwException(exec, scope, createReferenceError(exec, ASCIILiteral("Static function property defined with NULL callAsFunction callback."))));
return JSValue::encode(throwException(exec, scope, createReferenceError(exec, "Static function property defined with NULL callAsFunction callback."_s)));
}
template <class Parent>
@ -680,7 +688,7 @@ EncodedJSValue JSCallbackObject<Parent>::callbackGetter(ExecState* exec, Encoded
for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) {
if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) {
if (!propertyNameRef)
propertyNameRef = OpaqueJSString::create(name);
propertyNameRef = OpaqueJSString::tryCreate(name);
JSValueRef exception = 0;
JSValueRef value;
{
@ -697,7 +705,7 @@ EncodedJSValue JSCallbackObject<Parent>::callbackGetter(ExecState* exec, Encoded
}
}
return JSValue::encode(throwException(exec, scope, createReferenceError(exec, ASCIILiteral("hasProperty callback returned true for a property that doesn't exist."))));
return JSValue::encode(throwException(exec, scope, createReferenceError(exec, "hasProperty callback returned true for a property that doesn't exist."_s)));
}
} // namespace JSC

View File

@ -35,11 +35,8 @@
#include "ObjectPrototype.h"
#include "JSCInlines.h"
#include <wtf/text/StringHash.h>
#include <wtf/unicode/UTF8.h>
using namespace std;
using namespace JSC;
using namespace WTF::Unicode;
const JSClassDefinition kJSClassDefinitionEmpty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
@ -88,19 +85,19 @@ OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass*
OpaqueJSClass::~OpaqueJSClass()
{
// The empty string is shared across threads & is an identifier, in all other cases we should have done a deep copy in className(), below.
ASSERT(!m_className.length() || !m_className.impl()->isAtomic());
ASSERT(!m_className.length() || !m_className.impl()->isAtom());
#ifndef NDEBUG
if (m_staticValues) {
OpaqueJSClassStaticValuesTable::const_iterator end = m_staticValues->end();
for (OpaqueJSClassStaticValuesTable::const_iterator it = m_staticValues->begin(); it != end; ++it)
ASSERT(!it->key->isAtomic());
ASSERT(!it->key->isAtom());
}
if (m_staticFunctions) {
OpaqueJSClassStaticFunctionsTable::const_iterator end = m_staticFunctions->end();
for (OpaqueJSClassStaticFunctionsTable::const_iterator it = m_staticFunctions->begin(); it != end; ++it)
ASSERT(!it->key->isAtomic());
ASSERT(!it->key->isAtom());
}
#endif
@ -119,7 +116,7 @@ Ref<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* clientDefiniti
JSClassDefinition protoDefinition = kJSClassDefinitionEmpty;
protoDefinition.finalize = 0;
swap(definition.staticFunctions, protoDefinition.staticFunctions); // Move static functions to the prototype.
std::swap(definition.staticFunctions, protoDefinition.staticFunctions); // Move static functions to the prototype.
// We are supposed to use JSClassRetain/Release but since we know that we currently have
// the only reference to this class object we cheat and use a RefPtr instead.
@ -134,7 +131,7 @@ OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::VM&, OpaqueJSClass* jsCl
staticValues = std::make_unique<OpaqueJSClassStaticValuesTable>();
OpaqueJSClassStaticValuesTable::const_iterator end = jsClass->m_staticValues->end();
for (OpaqueJSClassStaticValuesTable::const_iterator it = jsClass->m_staticValues->begin(); it != end; ++it) {
ASSERT(!it->key->isAtomic());
ASSERT(!it->key->isAtom());
String valueName = it->key->isolatedCopy();
staticValues->add(valueName.impl(), std::make_unique<StaticValueEntry>(it->value->getProperty, it->value->setProperty, it->value->attributes, valueName));
}
@ -144,7 +141,7 @@ OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::VM&, OpaqueJSClass* jsCl
staticFunctions = std::make_unique<OpaqueJSClassStaticFunctionsTable>();
OpaqueJSClassStaticFunctionsTable::const_iterator end = jsClass->m_staticFunctions->end();
for (OpaqueJSClassStaticFunctionsTable::const_iterator it = jsClass->m_staticFunctions->begin(); it != end; ++it) {
ASSERT(!it->key->isAtomic());
ASSERT(!it->key->isAtom());
staticFunctions->add(it->key->isolatedCopy(), std::make_unique<StaticFunctionEntry>(it->value->callAsFunction, it->value->attributes));
}
}
@ -160,7 +157,7 @@ OpaqueJSClassContextData& OpaqueJSClass::contextData(ExecState* exec)
String OpaqueJSClass::className()
{
// Make a deep copy, so that the caller has no chance to put the original into AtomicStringTable.
// Make a deep copy, so that the caller has no chance to put the original into AtomStringTable.
return m_className.isolatedCopy();
}

View File

@ -37,7 +37,10 @@ struct StaticValueEntry {
WTF_MAKE_FAST_ALLOCATED;
public:
StaticValueEntry(JSObjectGetPropertyCallback _getProperty, JSObjectSetPropertyCallback _setProperty, JSPropertyAttributes _attributes, String& propertyName)
: getProperty(_getProperty), setProperty(_setProperty), attributes(_attributes), propertyNameRef(OpaqueJSString::create(propertyName))
: getProperty(_getProperty)
, setProperty(_setProperty)
, attributes(_attributes)
, propertyNameRef(OpaqueJSString::tryCreate(propertyName))
{
}
@ -118,7 +121,7 @@ private:
OpaqueJSClassContextData& contextData(JSC::ExecState*);
// Strings in these data members should not be put into any AtomicStringTable.
// Strings in these data members should not be put into any AtomStringTable.
String m_className;
std::unique_ptr<OpaqueJSClassStaticValuesTable> m_staticValues;
std::unique_ptr<OpaqueJSClassStaticFunctionsTable> m_staticFunctions;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
* Copyright (C) 2013-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -31,7 +31,7 @@
#if JSC_OBJC_API_ENABLED
@class JSVirtualMachine, JSValue;
@class JSScript, JSVirtualMachine, JSValue, JSContext;
/*!
@interface
@ -39,7 +39,7 @@
JavaScript execution takes place within a context, and all JavaScript values
are tied to a context.
*/
NS_CLASS_AVAILABLE(10_9, 7_0)
JSC_CLASS_AVAILABLE(macos(10.9), ios(7.0))
@interface JSContext : NSObject
/*!
@ -78,7 +78,7 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
@param sourceURL A URL for the script's source file. Used by debuggers and when reporting exceptions. This parameter is informative only: it does not change the behavior of the script.
@result The last value generated by the script.
*/
- (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL NS_AVAILABLE(10_10, 8_0);
- (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL JSC_API_AVAILABLE(macos(10.10), ios(8.0));
/*!
@methodgroup Callback Accessors
@ -101,7 +101,7 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
a callback from JavaScript this method will return nil.
@result The currently executing JavaScript function or nil if there isn't one.
*/
+ (JSValue *)currentCallee NS_AVAILABLE(10_10, 8_0);
+ (JSValue *)currentCallee JSC_API_AVAILABLE(macos(10.10), ios(8.0));
/*!
@method
@ -176,8 +176,7 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
@property
@discussion Name of the JSContext. Exposed when remote debugging the context.
*/
@property (copy) NSString *name NS_AVAILABLE(10_10, 8_0);
@property (copy) NSString *name JSC_API_AVAILABLE(macos(10.10), ios(8.0));
@end
/*!
@ -231,6 +230,7 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
@result The C API equivalent of this JSContext.
*/
@property (readonly) JSGlobalContextRef JSGlobalContextRef;
@end
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
* Copyright (C) 2013-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -26,11 +26,15 @@
#include "config.h"
#import "APICast.h"
#import "Completion.h"
#import "JSBaseInternal.h"
#import "JSCInlines.h"
#import "JSContextInternal.h"
#import "JSContextPrivate.h"
#import "JSContextRefInternal.h"
#import "JSGlobalObject.h"
#import "JSInternalPromise.h"
#import "JSModuleLoader.h"
#import "JSValueInternal.h"
#import "JSVirtualMachineInternal.h"
#import "JSWrapperMap.h"
@ -38,12 +42,15 @@
#import "ObjcRuntimeExtras.h"
#import "StrongInlines.h"
#import <wtf/WeakObjCPtr.h>
#if JSC_OBJC_API_ENABLED
@implementation JSContext {
JSVirtualMachine *m_virtualMachine;
JSGlobalContextRef m_context;
JSC::Strong<JSC::JSObject> m_exception;
WeakObjCPtr<id <JSModuleLoaderDelegate>> m_moduleLoaderDelegate;
}
- (JSGlobalContextRef)JSGlobalContextRef
@ -100,24 +107,78 @@
- (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL
{
JSValueRef exceptionValue = nullptr;
JSStringRef scriptJS = JSStringCreateWithCFString((CFStringRef)script);
JSStringRef sourceURLJS = sourceURL ? JSStringCreateWithCFString((CFStringRef)[sourceURL absoluteString]) : nullptr;
JSValueRef result = JSEvaluateScript(m_context, scriptJS, nullptr, sourceURLJS, 0, &exceptionValue);
if (sourceURLJS)
JSStringRelease(sourceURLJS);
JSStringRelease(scriptJS);
auto scriptJS = OpaqueJSString::tryCreate(script);
auto sourceURLJS = OpaqueJSString::tryCreate([sourceURL absoluteString]);
JSValueRef result = JSEvaluateScript(m_context, scriptJS.get(), nullptr, sourceURLJS.get(), 0, &exceptionValue);
if (exceptionValue)
return [self valueFromNotifyException:exceptionValue];
return [JSValue valueWithJSValueRef:result inContext:self];
}
- (JSValue *)evaluateJSScript:(JSScript *)script
{
JSC::ExecState* exec = toJS(m_context);
JSC::VM& vm = exec->vm();
JSC::JSLockHolder locker(vm);
if (script.type == kJSScriptTypeProgram) {
JSValueRef exceptionValue = nullptr;
JSC::SourceCode sourceCode = [script sourceCode];
JSValueRef result = JSEvaluateScriptInternal(locker, exec, m_context, nullptr, sourceCode, &exceptionValue);
if (exceptionValue)
return [self valueFromNotifyException:exceptionValue];
return [JSValue valueWithJSValueRef:result inContext:self];
}
auto* globalObject = JSC::jsDynamicCast<JSC::JSAPIGlobalObject*>(vm, exec->lexicalGlobalObject());
if (!globalObject)
return [JSValue valueWithNewPromiseRejectedWithReason:[JSValue valueWithNewErrorFromMessage:@"Context does not support module loading" inContext:self] inContext:self];
auto scope = DECLARE_CATCH_SCOPE(vm);
JSC::JSValue result = globalObject->loadAndEvaluateJSScriptModule(locker, script);
if (scope.exception()) {
JSValueRef exceptionValue = toRef(exec, scope.exception()->value());
scope.clearException();
return [JSValue valueWithNewPromiseRejectedWithReason:[JSValue valueWithJSValueRef:exceptionValue inContext:self] inContext:self];
}
return [JSValue valueWithJSValueRef:toRef(vm, result) inContext:self];
}
- (JSValue *)dependencyIdentifiersForModuleJSScript:(JSScript *)script
{
JSC::ExecState* exec = toJS(m_context);
JSC::VM& vm = exec->vm();
JSC::JSLockHolder locker(vm);
if (script.type != kJSScriptTypeModule) {
self.exceptionHandler(self, [JSValue valueWithNewErrorFromMessage:@"script is not a module" inContext:self]);
return [JSValue valueWithUndefinedInContext:self];
}
auto scope = DECLARE_CATCH_SCOPE(vm);
JSC::JSArray* result = exec->lexicalGlobalObject()->moduleLoader()->dependencyKeysIfEvaluated(exec, JSC::jsString(&vm, [[script sourceURL] absoluteString]));
if (scope.exception()) {
JSValueRef exceptionValue = toRef(exec, scope.exception()->value());
scope.clearException();
return [self valueFromNotifyException:exceptionValue];
}
if (!result) {
self.exceptionHandler(self, [JSValue valueWithNewErrorFromMessage:@"script has not run in context or was not evaluated successfully" inContext:self]);
return [JSValue valueWithUndefinedInContext:self];
}
return [JSValue valueWithJSValueRef:toRef(vm, result) inContext:self];
}
- (void)setException:(JSValue *)value
{
JSC::JSLockHolder locker(toJS(m_context));
JSC::ExecState* exec = toJS(m_context);
JSC::VM& vm = exec->vm();
JSC::JSLockHolder locker(vm);
if (value)
m_exception.set(toJS(m_context)->vm(), toJS(JSValueToObject(m_context, valueInternalValue(value), 0)));
m_exception.set(vm, toJS(JSValueToObject(m_context, valueInternalValue(value), 0)));
else
m_exception.clear();
}
@ -129,11 +190,6 @@
return [JSValue valueWithJSValueRef:toRef(m_exception.get()) inContext:self];
}
- (JSWrapperMap *)wrapperMap
{
return toJS(m_context)->lexicalGlobalObject()->wrapperMap();
}
- (JSValue *)globalObject
{
return [JSValue valueWithJSValueRef:JSContextGetGlobalObject(m_context) inContext:self];
@ -141,15 +197,15 @@
+ (JSContext *)currentContext
{
WTFThreadData& threadData = wtfThreadData();
CallbackData *entry = (CallbackData *)threadData.m_apiData;
Thread& thread = Thread::current();
CallbackData *entry = (CallbackData *)thread.m_apiData;
return entry ? entry->context : nil;
}
+ (JSValue *)currentThis
{
WTFThreadData& threadData = wtfThreadData();
CallbackData *entry = (CallbackData *)threadData.m_apiData;
Thread& thread = Thread::current();
CallbackData *entry = (CallbackData *)thread.m_apiData;
if (!entry)
return nil;
return [JSValue valueWithJSValueRef:entry->thisValue inContext:[JSContext currentContext]];
@ -157,17 +213,18 @@
+ (JSValue *)currentCallee
{
WTFThreadData& threadData = wtfThreadData();
CallbackData *entry = (CallbackData *)threadData.m_apiData;
if (!entry)
Thread& thread = Thread::current();
CallbackData *entry = (CallbackData *)thread.m_apiData;
// calleeValue may be null if we are initializing a promise.
if (!entry || !entry->calleeValue)
return nil;
return [JSValue valueWithJSValueRef:entry->calleeValue inContext:[JSContext currentContext]];
}
+ (NSArray *)currentArguments
{
WTFThreadData& threadData = wtfThreadData();
CallbackData *entry = (CallbackData *)threadData.m_apiData;
Thread& thread = Thread::current();
CallbackData *entry = (CallbackData *)thread.m_apiData;
if (!entry)
return nil;
@ -195,15 +252,12 @@
if (!name)
return nil;
return (NSString *)adoptCF(JSStringCopyCFString(kCFAllocatorDefault, name)).autorelease();
return CFBridgingRelease(JSStringCopyCFString(kCFAllocatorDefault, name));
}
- (void)setName:(NSString *)name
{
JSStringRef nameJS = name ? JSStringCreateWithCFString((CFStringRef)[[name copy] autorelease]) : nullptr;
JSGlobalContextSetName(m_context, nameJS);
if (nameJS)
JSStringRelease(nameJS);
JSGlobalContextSetName(m_context, OpaqueJSString::tryCreate(name).get());
}
- (BOOL)_remoteInspectionEnabled
@ -236,6 +290,16 @@
JSGlobalContextSetDebuggerRunLoop(m_context, runLoop);
}
- (id<JSModuleLoaderDelegate>)moduleLoaderDelegate
{
return m_moduleLoaderDelegate.getAutoreleased();
}
- (void)setModuleLoaderDelegate:(id<JSModuleLoaderDelegate>)moduleLoaderDelegate
{
m_moduleLoaderDelegate = moduleLoaderDelegate;
}
@end
@implementation JSContext(SubscriptSupport)
@ -294,21 +358,21 @@
- (void)beginCallbackWithData:(CallbackData *)callbackData calleeValue:(JSValueRef)calleeValue thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments
{
WTFThreadData& threadData = wtfThreadData();
Thread& thread = Thread::current();
[self retain];
CallbackData *prevStack = (CallbackData *)threadData.m_apiData;
CallbackData *prevStack = (CallbackData *)thread.m_apiData;
*callbackData = (CallbackData){ prevStack, self, [self.exception retain], calleeValue, thisValue, argumentCount, arguments, nil };
threadData.m_apiData = callbackData;
thread.m_apiData = callbackData;
self.exception = nil;
}
- (void)endCallbackWithData:(CallbackData *)callbackData
{
WTFThreadData& threadData = wtfThreadData();
Thread& thread = Thread::current();
self.exception = callbackData->preservedException;
[callbackData->preservedException release];
[callbackData->currentArguments release];
threadData.m_apiData = callbackData->next;
thread.m_apiData = callbackData->next;
[self release];
}
@ -318,6 +382,11 @@
return [[self wrapperMap] jsWrapperForObject:object inContext:self];
}
- (JSWrapperMap *)wrapperMap
{
return toJS(m_context)->lexicalGlobalObject()->wrapperMap();
}
- (JSValue *)wrapperForJSObject:(JSValueRef)value
{
JSC::JSLockHolder locker(toJS(m_context));
@ -335,24 +404,4 @@
@end
WeakContextRef::WeakContextRef(JSContext *context)
{
objc_initWeak(&m_weakContext, context);
}
WeakContextRef::~WeakContextRef()
{
objc_destroyWeak(&m_weakContext);
}
JSContext * WeakContextRef::get()
{
return objc_loadWeak(&m_weakContext);
}
void WeakContextRef::set(JSContext *context)
{
objc_storeWeak(&m_weakContext, context);
}
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
* Copyright (C) 2013-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -23,17 +23,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JSContextInternal_h
#define JSContextInternal_h
#import <JavaScriptCore/JavaScriptCore.h>
#if JSC_OBJC_API_ENABLED
#import <JavaScriptCore/JSContext.h>
#import <JavaScriptCore/JSContextPrivate.h>
struct CallbackData {
CallbackData *next;
CallbackData* next;
JSContext *context;
JSValue *preservedException;
JSValueRef calleeValue;
@ -43,24 +40,10 @@ struct CallbackData {
NSArray *currentArguments;
};
class WeakContextRef {
public:
WeakContextRef(JSContext * = nil);
~WeakContextRef();
JSContext * get();
void set(JSContext *);
private:
JSContext *m_weakContext;
};
@class JSWrapperMap;
@interface JSContext(Internal)
- (instancetype)initWithGlobalContextRef:(JSGlobalContextRef)context;
- (void)notifyException:(JSValueRef)exception;
- (JSValue *)valueFromNotifyException:(JSValueRef)exception;
- (BOOL)boolFromNotifyException:(JSValueRef)exception;
@ -68,13 +51,10 @@ private:
- (void)beginCallbackWithData:(CallbackData *)callbackData calleeValue:(JSValueRef)calleeValue thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments;
- (void)endCallbackWithData:(CallbackData *)callbackData;
- (JSWrapperMap *)wrapperMap;
- (JSValue *)wrapperForObjCObject:(id)object;
- (JSValue *)wrapperForJSObject:(JSValueRef)value;
@property (readonly, retain) JSWrapperMap *wrapperMap;
@end
#endif
#endif // JSContextInternal_h

View File

@ -30,25 +30,81 @@
#import <JavaScriptCore/JSContext.h>
@protocol JSModuleLoaderDelegate <NSObject>
@required
/*! @abstract Provides source code for any JS module that is actively imported.
@param context The context for which the module is being requested.
@param identifier The resolved identifier for the requested module.
@param resolve A JS function to call with the desired script for identifier.
@param reject A JS function to call when identifier cannot be fetched.
@discussion Currently, identifier will always be an absolute file URL computed from specifier of the requested module relative to the URL of the requesting script. If the requesting script does not have a URL and the module specifier is not an absolute path the module loader will fail to load the module.
The first argument to resolve sholud always be a JSScript, otherwise the module loader will reject the module.
Once an identifier has been resolved or rejected in a given context it will never be requested again. If a script is successfully evaluated it will not be re-evaluated on any subsequent import.
The VM will retain all evaluated modules for the lifetime of the context.
*/
- (void)context:(JSContext *)context fetchModuleForIdentifier:(JSValue *)identifier withResolveHandler:(JSValue *)resolve andRejectHandler:(JSValue *)reject;
@optional
/*! @abstract This is called before the module with "key" is evaluated.
@param key The module key for the module that is about to be evaluated.
*/
- (void)willEvaluateModule:(NSURL *)key;
/*! @abstract This is called after the module with "key" is evaluated.
@param key The module key for the module that was just evaluated.
*/
- (void)didEvaluateModule:(NSURL *)key;
@end
@interface JSContext(Private)
/*!
@property
@discussion Remote inspection setting of the JSContext. Default value is YES.
*/
@property (setter=_setRemoteInspectionEnabled:) BOOL _remoteInspectionEnabled NS_AVAILABLE(10_10, 8_0);
@property (setter=_setRemoteInspectionEnabled:) BOOL _remoteInspectionEnabled JSC_API_AVAILABLE(macos(10.10), ios(8.0));
/*!
@property
@discussion Set whether or not the native call stack is included when reporting exceptions. Default value is YES.
*/
@property (setter=_setIncludesNativeCallStackWhenReportingExceptions:) BOOL _includesNativeCallStackWhenReportingExceptions NS_AVAILABLE(10_10, 8_0);
@property (setter=_setIncludesNativeCallStackWhenReportingExceptions:) BOOL _includesNativeCallStackWhenReportingExceptions JSC_API_AVAILABLE(macos(10.10), ios(8.0));
/*!
@property
@discussion Set the run loop the Web Inspector debugger should use when evaluating JavaScript in the JSContext.
*/
@property (setter=_setDebuggerRunLoop:) CFRunLoopRef _debuggerRunLoop NS_AVAILABLE(10_10, 8_0);
@property (setter=_setDebuggerRunLoop:) CFRunLoopRef _debuggerRunLoop JSC_API_AVAILABLE(macos(10.10), ios(8.0));
/*! @abstract The delegate the context will use when trying to load a module. Note, this delegate will be ignored for contexts returned by UIWebView. */
@property (nonatomic, weak) id <JSModuleLoaderDelegate> moduleLoaderDelegate JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@method
@abstract Run a JSScript.
@param script the JSScript to evaluate.
@discussion If the provided JSScript was created with kJSScriptTypeProgram, the script will run synchronously and return the result of evaluation.
Otherwise, if the script was created with kJSScriptTypeModule, the module will be run asynchronously and will return a promise resolved when the module and any transitive dependencies are loaded. The module loader will treat the script as if it had been returned from a delegate call to moduleLoaderDelegate. This mirrors the JavaScript dynamic import operation.
*/
// FIXME: Before making this public need to fix: https://bugs.webkit.org/show_bug.cgi?id=199714
- (JSValue *)evaluateJSScript:(JSScript *)script JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@method
@abstract Get the identifiers of the modules a JSScript depends on in this context.
@param script the JSScript to determine the dependencies of.
@result An Array containing all the identifiers of modules script depends on.
@discussion If the provided JSScript was not created with kJSScriptTypeModule, an exception will be thrown. Also, if the script has not already been evaluated in this context an error will be throw.
*/
- (JSValue *)dependencyIdentifiersForModuleJSScript:(JSScript *)script JSC_API_AVAILABLE(macos(10.15), ios(13.0));
@end

View File

@ -30,9 +30,9 @@
#include "APICast.h"
#include "CallFrame.h"
#include "InitializeThreading.h"
#include "JSAPIGlobalObject.h"
#include "JSCallbackObject.h"
#include "JSClassRef.h"
#include "JSGlobalObject.h"
#include "JSObject.h"
#include "JSCInlines.h"
#include "SourceProvider.h"
@ -99,9 +99,9 @@ void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit,
Watchdog& watchdog = vm.ensureWatchdog();
if (callback) {
void* callbackPtr = reinterpret_cast<void*>(callback);
watchdog.setTimeLimit(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(limit)), internalScriptTimeoutCallback, callbackPtr, callbackData);
watchdog.setTimeLimit(Seconds { limit }, internalScriptTimeoutCallback, callbackPtr, callbackData);
} else
watchdog.setTimeLimit(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(limit)));
watchdog.setTimeLimit(Seconds { limit });
}
void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group)
@ -138,7 +138,7 @@ JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClass
JSLockHolder locker(vm.ptr());
if (!globalObjectClass) {
JSGlobalObject* globalObject = JSGlobalObject::create(vm.get(), JSGlobalObject::createStructure(vm.get(), jsNull()));
JSGlobalObject* globalObject = JSAPIGlobalObject::create(vm.get(), JSAPIGlobalObject::createStructure(vm.get(), jsNull()));
#if ENABLE(REMOTE_INSPECTOR)
if (JSRemoteInspectorGetInspectionEnabledByDefault())
globalObject->setRemoteDebuggingEnabled(true);
@ -162,10 +162,10 @@ JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClass
JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx)
{
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
gcProtect(exec->vmEntryGlobalObject());
JSLockHolder locker(vm);
gcProtect(vm.vmEntryGlobalObject(exec));
vm.ref();
return ctx;
}
@ -173,10 +173,10 @@ JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx)
void JSGlobalContextRelease(JSGlobalContextRef ctx)
{
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
bool protectCountIsZero = Heap::heap(exec->vmEntryGlobalObject())->unprotect(exec->vmEntryGlobalObject());
JSLockHolder locker(vm);
bool protectCountIsZero = vm.heap.unprotect(vm.vmEntryGlobalObject(exec));
if (protectCountIsZero)
vm.heap.reportAbandonedObjectGraph();
vm.deref();
@ -189,9 +189,10 @@ JSObjectRef JSContextGetGlobalObject(JSContextRef ctx)
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
return toRef(jsCast<JSObject*>(exec->lexicalGlobalObject()->methodTable()->toThis(exec->lexicalGlobalObject(), exec, NotStrictMode)));
return toRef(jsCast<JSObject*>(exec->lexicalGlobalObject()->methodTable(vm)->toThis(exec->lexicalGlobalObject(), exec, NotStrictMode)));
}
JSContextGroupRef JSContextGetGroup(JSContextRef ctx)
@ -224,13 +225,14 @@ JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx)
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
String name = exec->vmEntryGlobalObject()->name();
String name = vm.vmEntryGlobalObject(exec)->name();
if (name.isNull())
return 0;
return OpaqueJSString::create(name).leakRef();
return OpaqueJSString::tryCreate(name).leakRef();
}
void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name)
@ -241,9 +243,10 @@ void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name)
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
exec->vmEntryGlobalObject()->setName(name ? name->string() : String());
vm.vmEntryGlobalObject(exec)->setName(name ? name->string() : String());
}
@ -304,15 +307,16 @@ JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder lock(exec);
VM& vm = exec->vm();
JSLockHolder lock(vm);
StringBuilder builder;
CallFrame* frame = exec->vm().topCallFrame;
CallFrame* frame = vm.topCallFrame;
ASSERT(maxStackSize);
BacktraceFunctor functor(builder, maxStackSize);
frame->iterate(functor);
return OpaqueJSString::create(builder.toString()).leakRef();
return OpaqueJSString::tryCreate(builder.toString()).leakRef();
}
bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx)
@ -323,9 +327,10 @@ bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx)
}
ExecState* exec = toJS(ctx);
JSLockHolder lock(exec);
VM& vm = exec->vm();
JSLockHolder lock(vm);
return exec->vmEntryGlobalObject()->remoteDebuggingEnabled();
return vm.vmEntryGlobalObject(exec)->remoteDebuggingEnabled();
}
void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx, bool enabled)
@ -336,9 +341,10 @@ void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx, bool enab
}
ExecState* exec = toJS(ctx);
JSLockHolder lock(exec);
VM& vm = exec->vm();
JSLockHolder lock(vm);
exec->vmEntryGlobalObject()->setRemoteDebuggingEnabled(enabled);
vm.vmEntryGlobalObject(exec)->setRemoteDebuggingEnabled(enabled);
}
bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx)
@ -350,9 +356,10 @@ bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalCo
}
ExecState* exec = toJS(ctx);
JSLockHolder lock(exec);
VM& vm = exec->vm();
JSLockHolder lock(vm);
JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
JSGlobalObject* globalObject = vm.vmEntryGlobalObject(exec);
return globalObject->inspectorController().includesNativeCallStackWhenReportingExceptions();
#else
UNUSED_PARAM(ctx);
@ -369,9 +376,10 @@ void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalCo
}
ExecState* exec = toJS(ctx);
JSLockHolder lock(exec);
VM& vm = exec->vm();
JSLockHolder lock(vm);
JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
JSGlobalObject* globalObject = vm.vmEntryGlobalObject(exec);
globalObject->inspectorController().setIncludesNativeCallStackWhenReportingExceptions(includesNativeCallStack);
#else
UNUSED_PARAM(ctx);
@ -389,9 +397,10 @@ CFRunLoopRef JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx)
}
ExecState* exec = toJS(ctx);
JSLockHolder lock(exec);
VM& vm = exec->vm();
JSLockHolder lock(vm);
return exec->vmEntryGlobalObject()->inspectorDebuggable().targetRunLoop();
return vm.vmEntryGlobalObject(exec)->inspectorDebuggable().targetRunLoop();
#else
UNUSED_PARAM(ctx);
return nullptr;
@ -407,9 +416,10 @@ void JSGlobalContextSetDebuggerRunLoop(JSGlobalContextRef ctx, CFRunLoopRef runL
}
ExecState* exec = toJS(ctx);
JSLockHolder lock(exec);
VM& vm = exec->vm();
JSLockHolder lock(vm);
exec->vmEntryGlobalObject()->inspectorDebuggable().setTargetRunLoop(runLoop);
vm.vmEntryGlobalObject(exec)->inspectorDebuggable().setTargetRunLoop(runLoop);
#else
UNUSED_PARAM(ctx);
UNUSED_PARAM(runLoop);
@ -426,8 +436,9 @@ Inspector::AugmentableInspectorController* JSGlobalContextGetAugmentableInspecto
}
ExecState* exec = toJS(ctx);
JSLockHolder lock(exec);
VM& vm = exec->vm();
JSLockHolder lock(vm);
return &exec->vmEntryGlobalObject()->inspectorController();
return &vm.vmEntryGlobalObject(exec)->inspectorController();
}
#endif

View File

@ -46,9 +46,14 @@ extern "C" {
JavaScript objects between contexts in different groups will produce undefined behavior.
When objects from the same context group are used in multiple threads, explicit
synchronization is required.
A JSContextGroup may need to run deferred tasks on a run loop, such as garbage collection
or resolving WebAssembly compilations. By default, calling JSContextGroupCreate will use
the run loop of the thread it was called on. Currently, there is no API to change a
JSContextGroup's run loop once it has been created.
@result The created JSContextGroup.
*/
JS_EXPORT JSContextGroupRef JSContextGroupCreate(void) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT JSContextGroupRef JSContextGroupCreate(void) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
/*!
@function
@ -56,14 +61,14 @@ JS_EXPORT JSContextGroupRef JSContextGroupCreate(void) CF_AVAILABLE(10_6, 7_0);
@param group The JSContextGroup to retain.
@result A JSContextGroup that is the same as group.
*/
JS_EXPORT JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
/*!
@function
@abstract Releases a JavaScript context group.
@param group The JSContextGroup to release.
*/
JS_EXPORT void JSContextGroupRelease(JSContextGroupRef group) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT void JSContextGroupRelease(JSContextGroupRef group) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
/*!
@function
@ -78,7 +83,7 @@ JS_EXPORT void JSContextGroupRelease(JSContextGroupRef group) CF_AVAILABLE(10_6,
NULL to use the default object class.
@result A JSGlobalContext with a global object of class globalObjectClass.
*/
JS_EXPORT JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass) CF_AVAILABLE(10_5, 7_0);
JS_EXPORT JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass) JSC_API_AVAILABLE(macos(10.5), ios(7.0));
/*!
@function
@ -92,7 +97,7 @@ JS_EXPORT JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass)
@result A JSGlobalContext with a global object of class globalObjectClass and a context
group equal to group.
*/
JS_EXPORT JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
/*!
@function
@ -123,7 +128,7 @@ JS_EXPORT JSObjectRef JSContextGetGlobalObject(JSContextRef ctx);
@param ctx The JSContext whose group you want to get.
@result ctx's group.
*/
JS_EXPORT JSContextGroupRef JSContextGetGroup(JSContextRef ctx) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT JSContextGroupRef JSContextGetGroup(JSContextRef ctx) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
/*!
@function
@ -131,7 +136,7 @@ JS_EXPORT JSContextGroupRef JSContextGetGroup(JSContextRef ctx) CF_AVAILABLE(10_
@param ctx The JSContext whose global context you want to get.
@result ctx's global context.
*/
JS_EXPORT JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx) CF_AVAILABLE(10_7, 7_0);
JS_EXPORT JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx) JSC_API_AVAILABLE(macos(10.7), ios(7.0));
/*!
@function
@ -141,7 +146,7 @@ JS_EXPORT JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx) CF_AVAI
@discussion A JSGlobalContext's name is exposed for remote debugging to make it
easier to identify the context you would like to attach to.
*/
JS_EXPORT JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx) CF_AVAILABLE(10_10, 8_0);
JS_EXPORT JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx) JSC_API_AVAILABLE(macos(10.10), ios(8.0));
/*!
@function
@ -149,7 +154,7 @@ JS_EXPORT JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx) CF_AVAILAB
@param ctx The JSGlobalContext that you want to name.
@param name The remote debugging name to set on ctx.
*/
JS_EXPORT void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name) CF_AVAILABLE(10_10, 8_0);
JS_EXPORT void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name) JSC_API_AVAILABLE(macos(10.10), ios(8.0));
#ifdef __cplusplus
}

View File

@ -42,7 +42,7 @@ extern "C" {
@abstract Gets the run loop used by the Web Inspector debugger when evaluating JavaScript in this context.
@param ctx The JSGlobalContext whose setting you want to get.
*/
JS_EXPORT CFRunLoopRef JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx) CF_AVAILABLE(10_10, 8_0);
JS_EXPORT CFRunLoopRef JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx) JSC_API_AVAILABLE(macos(10.10), ios(8.0));
/*!
@function
@ -50,7 +50,7 @@ JS_EXPORT CFRunLoopRef JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx)
@param ctx The JSGlobalContext that you want to change.
@param runLoop The new value of the setting for the context.
*/
JS_EXPORT void JSGlobalContextSetDebuggerRunLoop(JSGlobalContextRef ctx, CFRunLoopRef runLoop) CF_AVAILABLE(10_10, 8_0);
JS_EXPORT void JSGlobalContextSetDebuggerRunLoop(JSGlobalContextRef ctx, CFRunLoopRef runLoop) JSC_API_AVAILABLE(macos(10.10), ios(8.0));
#endif
#ifdef __cplusplus

View File

@ -44,7 +44,7 @@ extern "C" {
@param ctx The JSContext whose backtrace you want to get
@result A string containing the backtrace
*/
JS_EXPORT JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
/*!
@ -85,14 +85,14 @@ typedef bool
need to call JSContextGroupSetExecutionTimeLimit before you start executing
any scripts.
*/
JS_EXPORT void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* context) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* context) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
/*!
@function
@abstract Clears the script execution time limit.
@param group The JavaScript context group that the time limit is cleared on.
*/
JS_EXPORT void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
/*!
@function
@ -101,7 +101,7 @@ JS_EXPORT void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group) CF
@result The value of the setting, true if remote inspection is enabled, otherwise false.
@discussion Remote inspection is true by default.
*/
JS_EXPORT bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx) CF_AVAILABLE(10_10, 8_0);
JS_EXPORT bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx) JSC_API_AVAILABLE(macos(10.10), ios(8.0));
/*!
@function
@ -109,7 +109,7 @@ JS_EXPORT bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx)
@param ctx The JSGlobalContext that you want to change.
@param enabled The new remote inspection enabled setting for the context.
*/
JS_EXPORT void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx, bool enabled) CF_AVAILABLE(10_10, 8_0);
JS_EXPORT void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx, bool enabled) JSC_API_AVAILABLE(macos(10.10), ios(8.0));
/*!
@function
@ -118,7 +118,7 @@ JS_EXPORT void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx,
@result The value of the setting, true if remote inspection is enabled, otherwise false.
@discussion This setting is true by default.
*/
JS_EXPORT bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx) CF_AVAILABLE(10_10, 8_0);
JS_EXPORT bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx) JSC_API_AVAILABLE(macos(10.10), ios(8.0));
/*!
@function
@ -126,7 +126,7 @@ JS_EXPORT bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(
@param ctx The JSGlobalContext that you want to change.
@param includesNativeCallStack The new value of the setting for the context.
*/
JS_EXPORT void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack) CF_AVAILABLE(10_10, 8_0);
JS_EXPORT void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack) JSC_API_AVAILABLE(macos(10.10), ios(8.0));
#ifdef __cplusplus
}

View File

@ -124,7 +124,7 @@
- Any lowercase letter that had followed a colon will be capitalized.
Under the default conversion a selector <code>doFoo:withBar:</code> will be exported as
<code>doFooWithBar</code>. The default conversion may be overriden using the JSExportAs
<code>doFooWithBar</code>. The default conversion may be overridden using the JSExportAs
macro, for example to export a method <code>doFoo:withBar:</code> as <code>doFoo</code>:
<pre>

View File

@ -57,7 +57,7 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
@result The new JSManagedValue.
*/
+ (JSManagedValue *)managedValueWithValue:(JSValue *)value;
+ (JSManagedValue *)managedValueWithValue:(JSValue *)value andOwner:(id)owner NS_AVAILABLE(10_10, 8_0);
+ (JSManagedValue *)managedValueWithValue:(JSValue *)value andOwner:(id)owner JSC_API_AVAILABLE(macos(10.10), ios(8.0));
/*!
@method

View File

@ -33,145 +33,28 @@
#import "Heap.h"
#import "JSContextInternal.h"
#import "JSValueInternal.h"
#import "Weak.h"
#import "JSWeakValue.h"
#import "WeakHandleOwner.h"
#import "ObjcRuntimeExtras.h"
#import "JSCInlines.h"
#import <wtf/NeverDestroyed.h>
#import <wtf/spi/cocoa/NSMapTableSPI.h>
class JSManagedValueHandleOwner : public JSC::WeakHandleOwner {
public:
void finalize(JSC::Handle<JSC::Unknown>, void* context) override;
bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&) override;
bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**) override;
};
static JSManagedValueHandleOwner* managedValueHandleOwner()
static JSManagedValueHandleOwner& managedValueHandleOwner()
{
static NeverDestroyed<JSManagedValueHandleOwner> jsManagedValueHandleOwner;
return &jsManagedValueHandleOwner.get();
return jsManagedValueHandleOwner;
}
class WeakValueRef {
public:
WeakValueRef()
: m_tag(NotSet)
{
}
~WeakValueRef()
{
clear();
}
void clear()
{
switch (m_tag) {
case NotSet:
return;
case Primitive:
u.m_primitive = JSC::JSValue();
return;
case Object:
u.m_object.clear();
return;
case String:
u.m_string.clear();
return;
}
RELEASE_ASSERT_NOT_REACHED();
}
bool isClear() const
{
switch (m_tag) {
case NotSet:
return true;
case Primitive:
return !u.m_primitive;
case Object:
return !u.m_object;
case String:
return !u.m_string;
}
RELEASE_ASSERT_NOT_REACHED();
}
bool isSet() const { return m_tag != NotSet; }
bool isPrimitive() const { return m_tag == Primitive; }
bool isObject() const { return m_tag == Object; }
bool isString() const { return m_tag == String; }
void setPrimitive(JSC::JSValue primitive)
{
ASSERT(!isSet());
ASSERT(!u.m_primitive);
ASSERT(primitive.isPrimitive());
m_tag = Primitive;
u.m_primitive = primitive;
}
void setObject(JSC::JSObject* object, void* context)
{
ASSERT(!isSet());
ASSERT(!u.m_object);
m_tag = Object;
JSC::Weak<JSC::JSObject> weak(object, managedValueHandleOwner(), context);
u.m_object.swap(weak);
}
void setString(JSC::JSString* string, void* context)
{
ASSERT(!isSet());
ASSERT(!u.m_object);
m_tag = String;
JSC::Weak<JSC::JSString> weak(string, managedValueHandleOwner(), context);
u.m_string.swap(weak);
}
JSC::JSObject* object()
{
ASSERT(isObject());
return u.m_object.get();
}
JSC::JSValue primitive()
{
ASSERT(isPrimitive());
return u.m_primitive;
}
JSC::JSString* string()
{
ASSERT(isString());
return u.m_string.get();
}
private:
enum WeakTypeTag { NotSet, Primitive, Object, String };
WeakTypeTag m_tag;
union WeakValueUnion {
public:
WeakValueUnion ()
: m_primitive(JSC::JSValue())
{
}
~WeakValueUnion()
{
ASSERT(!m_primitive);
}
JSC::JSValue m_primitive;
JSC::Weak<JSC::JSObject> m_object;
JSC::Weak<JSC::JSString> m_string;
} u;
};
@implementation JSManagedValue {
JSC::Weak<JSC::JSGlobalObject> m_globalObject;
RefPtr<JSC::JSLock> m_lock;
WeakValueRef m_weakValue;
JSC::JSWeakValue m_weakValue;
NSMapTable *m_owners;
}
@ -203,7 +86,8 @@ private:
JSC::ExecState* exec = toJS([value.context JSGlobalContextRef]);
JSC::JSGlobalObject* globalObject = exec->lexicalGlobalObject();
JSC::Weak<JSC::JSGlobalObject> weak(globalObject, managedValueHandleOwner(), self);
auto& owner = managedValueHandleOwner();
JSC::Weak<JSC::JSGlobalObject> weak(globalObject, &owner, (__bridge void*)self);
m_globalObject.swap(weak);
m_lock = &exec->vm().apiLock();
@ -214,9 +98,9 @@ private:
JSC::JSValue jsValue = toJS(exec, [value JSValueRef]);
if (jsValue.isObject())
m_weakValue.setObject(JSC::jsCast<JSC::JSObject*>(jsValue.asCell()), self);
m_weakValue.setObject(JSC::jsCast<JSC::JSObject*>(jsValue.asCell()), owner, (__bridge void*)self);
else if (jsValue.isString())
m_weakValue.setString(JSC::jsCast<JSC::JSString*>(jsValue.asCell()), self);
m_weakValue.setString(JSC::jsCast<JSC::JSString*>(jsValue.asCell()), owner, (__bridge void*)self);
else
m_weakValue.setPrimitive(jsValue);
return self;
@ -228,7 +112,7 @@ private:
if (virtualMachine) {
NSMapTable *copy = [m_owners copy];
for (id owner in [copy keyEnumerator]) {
size_t count = reinterpret_cast<size_t>(NSMapGet(m_owners, owner));
size_t count = reinterpret_cast<size_t>(NSMapGet(m_owners, (__bridge void*)owner));
while (count--)
[virtualMachine removeManagedReference:self withOwner:owner];
}
@ -242,32 +126,33 @@ private:
- (void)didAddOwner:(id)owner
{
size_t count = reinterpret_cast<size_t>(NSMapGet(m_owners, owner));
NSMapInsert(m_owners, owner, reinterpret_cast<void*>(count + 1));
size_t count = reinterpret_cast<size_t>(NSMapGet(m_owners, (__bridge void*)owner));
NSMapInsert(m_owners, (__bridge void*)owner, reinterpret_cast<void*>(count + 1));
}
- (void)didRemoveOwner:(id)owner
{
size_t count = reinterpret_cast<size_t>(NSMapGet(m_owners, owner));
size_t count = reinterpret_cast<size_t>(NSMapGet(m_owners, (__bridge void*)owner));
if (!count)
return;
if (count == 1) {
NSMapRemove(m_owners, owner);
NSMapRemove(m_owners, (__bridge void*)owner);
return;
}
NSMapInsert(m_owners, owner, reinterpret_cast<void*>(count - 1));
NSMapInsert(m_owners, (__bridge void*)owner, reinterpret_cast<void*>(count - 1));
}
- (JSValue *)value
{
WTF::Locker<JSC::JSLock> locker(m_lock.get());
if (!m_lock->vm())
JSC::VM* vm = m_lock->vm();
if (!vm)
return nil;
JSC::JSLockHolder apiLocker(m_lock->vm());
JSC::JSLockHolder apiLocker(vm);
if (!m_globalObject)
return nil;
if (m_weakValue.isClear())
@ -296,15 +181,17 @@ private:
- (void)disconnectValue;
@end
bool JSManagedValueHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor& visitor)
bool JSManagedValueHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor& visitor, const char** reason)
{
JSManagedValue *managedValue = static_cast<JSManagedValue *>(context);
return visitor.containsOpaqueRoot(managedValue);
if (UNLIKELY(reason))
*reason = "JSManagedValue is opaque root";
JSManagedValue *managedValue = (__bridge JSManagedValue *)context;
return visitor.containsOpaqueRoot((__bridge void*)managedValue);
}
void JSManagedValueHandleOwner::finalize(JSC::Handle<JSC::Unknown>, void* context)
{
JSManagedValue *managedValue = static_cast<JSManagedValue *>(context);
JSManagedValue *managedValue = (__bridge JSManagedValue *)context;
[managedValue disconnectValue];
}

View File

@ -28,8 +28,7 @@
#include "APICast.h"
#include "JSCInlines.h"
#include "MarkingConstraint.h"
#include "VisitingTimeout.h"
#include "SimpleMarkingConstraint.h"
using namespace JSC;
@ -41,12 +40,12 @@ struct Marker : JSMarker {
SlotVisitor* visitor;
};
bool isMarked(JSMarkerRef, JSObjectRef objectRef)
bool isMarked(JSMarkerRef markerRef, JSObjectRef objectRef)
{
if (!objectRef)
return true; // Null is an immortal object.
return Heap::isMarked(toJS(objectRef));
return static_cast<Marker*>(markerRef)->visitor->vm().heap.isMarked(toJS(objectRef));
}
void mark(JSMarkerRef markerRef, JSObjectRef objectRef)
@ -72,11 +71,11 @@ void JSContextGroupAddMarkingConstraint(JSContextGroupRef group, JSMarkingConstr
// else gets marked.
ConstraintVolatility volatility = ConstraintVolatility::GreyedByMarking;
auto constraint = std::make_unique<MarkingConstraint>(
auto constraint = std::make_unique<SimpleMarkingConstraint>(
toCString("Amc", constraintIndex, "(", RawPointer(bitwise_cast<void*>(constraintCallback)), ")"),
toCString("API Marking Constraint #", constraintIndex, " (", RawPointer(bitwise_cast<void*>(constraintCallback)), ", ", RawPointer(userData), ")"),
[constraintCallback, userData]
(SlotVisitor& slotVisitor, const VisitingTimeout&) {
(SlotVisitor& slotVisitor) {
Marker marker;
marker.IsMarked = isMarked;
marker.Mark = mark;
@ -84,7 +83,8 @@ void JSContextGroupAddMarkingConstraint(JSContextGroupRef group, JSMarkingConstr
constraintCallback(&marker, userData);
},
volatility);
volatility,
ConstraintConcurrency::Sequential);
vm.heap.addMarkingConstraint(WTFMove(constraint));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2017 Apple Inc. All rights reserved.
* Copyright (C) 2006-2019 Apple Inc. All rights reserved.
* Copyright (C) 2008 Kelvin W Sherlock (ksherlock@gmail.com)
*
* Redistribution and use in source and binary forms, with or without
@ -46,6 +46,8 @@
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "JSObject.h"
#include "JSPromise.h"
#include "JSPromiseDeferred.h"
#include "JSRetainPtr.h"
#include "JSString.h"
#include "JSValueRef.h"
@ -89,14 +91,15 @@ JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data)
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
if (!jsClass)
return toRef(constructEmptyObject(exec));
JSCallbackObject<JSDestructibleObject>* object = JSCallbackObject<JSDestructibleObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data);
if (JSObject* prototype = jsClass->prototype(exec))
object->setPrototypeDirect(exec->vm(), prototype);
object->setPrototypeDirect(vm, prototype);
return toRef(object);
}
@ -108,8 +111,9 @@ JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name,
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
return toRef(JSCallbackFunction::create(exec->vm(), exec->lexicalGlobalObject(), callAsFunction, name ? name->string() : ASCIILiteral("anonymous")));
VM& vm = exec->vm();
JSLockHolder locker(vm);
return toRef(JSCallbackFunction::create(vm, exec->lexicalGlobalObject(), callAsFunction, name ? name->string() : "anonymous"_s));
}
JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor)
@ -119,14 +123,15 @@ JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObje
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
JSValue jsPrototype = jsClass ? jsClass->prototype(exec) : 0;
if (!jsPrototype)
jsPrototype = exec->lexicalGlobalObject()->objectPrototype();
JSCallbackConstructor* constructor = JSCallbackConstructor::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackConstructorStructure(), jsClass, callAsConstructor);
constructor->putDirect(exec->vm(), exec->propertyNames().prototype, jsPrototype, DontEnum | DontDelete | ReadOnly);
constructor->putDirect(vm, vm.propertyNames->prototype, jsPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
return toRef(constructor);
}
@ -137,19 +142,27 @@ JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned pa
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
startingLineNumber = std::max(1, startingLineNumber);
Identifier nameID = name ? name->identifier(&exec->vm()) : Identifier::fromString(exec, "anonymous");
Identifier nameID = name ? name->identifier(&vm) : Identifier::fromString(exec, "anonymous");
MarkedArgumentBuffer args;
for (unsigned i = 0; i < parameterCount; i++)
args.append(jsString(exec, parameterNames[i]->string()));
args.append(jsString(exec, body->string()));
if (UNLIKELY(args.hasOverflowed())) {
auto throwScope = DECLARE_THROW_SCOPE(vm);
throwOutOfMemoryError(exec, throwScope);
handleExceptionIfNeeded(scope, exec, exception);
return 0;
}
auto sourceURLString = sourceURL ? sourceURL->string() : String();
JSObject* result = constructFunction(exec, exec->lexicalGlobalObject(), args, nameID, SourceOrigin { sourceURLString }, sourceURLString, TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber()));
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
result = 0;
return toRef(result);
}
@ -161,19 +174,27 @@ JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSVa
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSObject* result;
if (argumentCount) {
MarkedArgumentBuffer argList;
for (size_t i = 0; i < argumentCount; ++i)
argList.append(toJS(exec, arguments[i]));
if (UNLIKELY(argList.hasOverflowed())) {
auto throwScope = DECLARE_THROW_SCOPE(vm);
throwOutOfMemoryError(exec, throwScope);
handleExceptionIfNeeded(scope, exec, exception);
return 0;
}
result = constructArray(exec, static_cast<ArrayAllocationProfile*>(0), argList);
} else
result = constructEmptyArray(exec, 0);
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
result = 0;
return toRef(result);
@ -186,14 +207,22 @@ JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSVal
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
MarkedArgumentBuffer argList;
for (size_t i = 0; i < argumentCount; ++i)
argList.append(toJS(exec, arguments[i]));
if (UNLIKELY(argList.hasOverflowed())) {
auto throwScope = DECLARE_THROW_SCOPE(vm);
throwOutOfMemoryError(exec, throwScope);
handleExceptionIfNeeded(scope, exec, exception);
return 0;
}
JSObject* result = constructDate(exec, exec->lexicalGlobalObject(), JSValue(), argList);
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
result = 0;
return toRef(result);
@ -206,13 +235,15 @@ JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSVa
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSValue message = argumentCount ? toJS(exec, arguments[0]) : jsUndefined();
Structure* errorStructure = exec->lexicalGlobalObject()->errorStructure();
JSObject* result = ErrorInstance::create(exec, errorStructure, message);
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
result = 0;
return toRef(result);
@ -225,19 +256,51 @@ JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSV
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
MarkedArgumentBuffer argList;
for (size_t i = 0; i < argumentCount; ++i)
argList.append(toJS(exec, arguments[i]));
if (UNLIKELY(argList.hasOverflowed())) {
auto throwScope = DECLARE_THROW_SCOPE(vm);
throwOutOfMemoryError(exec, throwScope);
handleExceptionIfNeeded(scope, exec, exception);
return 0;
}
JSObject* result = constructRegExp(exec, exec->lexicalGlobalObject(), argList);
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
result = 0;
return toRef(result);
}
JSObjectRef JSObjectMakeDeferredPromise(JSContextRef ctx, JSObjectRef* resolve, JSObjectRef* reject, JSValueRef* exception)
{
if (!ctx) {
ASSERT_NOT_REACHED();
return nullptr;
}
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(exec);
auto scope = DECLARE_CATCH_SCOPE(vm);
auto* globalObject = exec->lexicalGlobalObject();
JSPromiseDeferred::DeferredData data = JSPromiseDeferred::createDeferredData(exec, globalObject, globalObject->promiseConstructor());
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
return nullptr;
if (resolve)
*resolve = toRef(data.resolve);
if (reject)
*reject = toRef(data.reject);
return toRef(data.promise);
}
JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object)
{
if (!ctx) {
@ -248,7 +311,7 @@ JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object)
JSLockHolder locker(exec);
JSObject* jsObject = toJS(object);
return toRef(exec, jsObject->getPrototypeDirect());
return toRef(exec, jsObject->getPrototypeDirect(exec->vm()));
}
void JSObjectSetPrototype(JSContextRef ctx, JSObjectRef object, JSValueRef value)
@ -259,20 +322,13 @@ void JSObjectSetPrototype(JSContextRef ctx, JSObjectRef object, JSValueRef value
}
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(exec);
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSObject* jsObject = toJS(object);
JSValue jsValue = toJS(exec, value);
if (JSProxy* proxy = jsDynamicCast<JSProxy*>(vm, jsObject)) {
if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(vm, proxy->target())) {
globalObject->resetPrototype(exec->vm(), jsValue.isObject() ? jsValue : jsNull());
return;
}
// Someday we might use proxies for something other than JSGlobalObjects, but today is not that day.
RELEASE_ASSERT_NOT_REACHED();
}
jsObject->setPrototype(exec->vm(), exec, jsValue.isObject() ? jsValue : jsNull());
jsObject->setPrototype(vm, exec, jsValue.isObject() ? jsValue : jsNull());
handleExceptionIfNeeded(scope, exec, nullptr);
}
bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
@ -282,11 +338,12 @@ bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope
return false;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
JSObject* jsObject = toJS(object);
return jsObject->hasProperty(exec, propertyName->identifier(&exec->vm()));
return jsObject->hasProperty(exec, propertyName->identifier(&vm));
}
JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
@ -296,12 +353,14 @@ JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSObject* jsObject = toJS(object);
JSValue jsValue = jsObject->get(exec, propertyName->identifier(&exec->vm()));
handleExceptionIfNeeded(exec, exception);
JSValue jsValue = jsObject->get(exec, propertyName->identifier(&vm));
handleExceptionIfNeeded(scope, exec, exception);
return toRef(exec, jsValue);
}
@ -317,20 +376,114 @@ void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope
auto scope = DECLARE_CATCH_SCOPE(vm);
JSObject* jsObject = toJS(object);
Identifier name(propertyName->identifier(&exec->vm()));
Identifier name(propertyName->identifier(&vm));
JSValue jsValue = toJS(exec, value);
bool doesNotHaveProperty = attributes && !jsObject->hasProperty(exec, name);
if (LIKELY(!scope.exception())) {
if (doesNotHaveProperty) {
PropertyDescriptor desc(jsValue, attributes);
jsObject->methodTable()->defineOwnProperty(jsObject, exec, name, desc, false);
jsObject->methodTable(vm)->defineOwnProperty(jsObject, exec, name, desc, false);
} else {
PutPropertySlot slot(jsObject);
jsObject->methodTable()->put(jsObject, exec, name, jsValue, slot);
jsObject->methodTable(vm)->put(jsObject, exec, name, jsValue, slot);
}
}
handleExceptionIfNeeded(exec, exception);
handleExceptionIfNeeded(scope, exec, exception);
}
bool JSObjectHasPropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef* exception)
{
if (!ctx) {
ASSERT_NOT_REACHED();
return false;
}
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSObject* jsObject = toJS(object);
Identifier ident = toJS(exec, key).toPropertyKey(exec);
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
return false;
bool result = jsObject->hasProperty(exec, ident);
handleExceptionIfNeeded(scope, exec, exception);
return result;
}
JSValueRef JSObjectGetPropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef* exception)
{
if (!ctx) {
ASSERT_NOT_REACHED();
return nullptr;
}
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSObject* jsObject = toJS(object);
Identifier ident = toJS(exec, key).toPropertyKey(exec);
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
return nullptr;
JSValue jsValue = jsObject->get(exec, ident);
handleExceptionIfNeeded(scope, exec, exception);
return toRef(exec, jsValue);
}
void JSObjectSetPropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception)
{
if (!ctx) {
ASSERT_NOT_REACHED();
return;
}
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSObject* jsObject = toJS(object);
JSValue jsValue = toJS(exec, value);
Identifier ident = toJS(exec, key).toPropertyKey(exec);
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
return;
bool doesNotHaveProperty = attributes && !jsObject->hasProperty(exec, ident);
if (LIKELY(!scope.exception())) {
if (doesNotHaveProperty) {
PropertyDescriptor desc(jsValue, attributes);
jsObject->methodTable(vm)->defineOwnProperty(jsObject, exec, ident, desc, false);
} else {
PutPropertySlot slot(jsObject);
jsObject->methodTable(vm)->put(jsObject, exec, ident, jsValue, slot);
}
}
handleExceptionIfNeeded(scope, exec, exception);
}
bool JSObjectDeletePropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef* exception)
{
if (!ctx) {
ASSERT_NOT_REACHED();
return false;
}
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSObject* jsObject = toJS(object);
Identifier ident = toJS(exec, key).toPropertyKey(exec);
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
return false;
bool result = jsObject->methodTable(vm)->deleteProperty(jsObject, exec, ident);
handleExceptionIfNeeded(scope, exec, exception);
return result;
}
JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception)
@ -340,12 +493,14 @@ JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsi
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSObject* jsObject = toJS(object);
JSValue jsValue = jsObject->get(exec, propertyIndex);
handleExceptionIfNeeded(exec, exception);
handleExceptionIfNeeded(scope, exec, exception);
return toRef(exec, jsValue);
}
@ -357,13 +512,15 @@ void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned p
return;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSObject* jsObject = toJS(object);
JSValue jsValue = toJS(exec, value);
jsObject->methodTable()->putByIndex(jsObject, exec, propertyIndex, jsValue, false);
handleExceptionIfNeeded(exec, exception);
jsObject->methodTable(vm)->putByIndex(jsObject, exec, propertyIndex, jsValue, false);
handleExceptionIfNeeded(scope, exec, exception);
}
bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
@ -373,12 +530,14 @@ bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef pr
return false;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSObject* jsObject = toJS(object);
bool result = jsObject->methodTable()->deleteProperty(jsObject, exec, propertyName->identifier(&exec->vm()));
handleExceptionIfNeeded(exec, exception);
bool result = jsObject->methodTable(vm)->deleteProperty(jsObject, exec, propertyName->identifier(&vm));
handleExceptionIfNeeded(scope, exec, exception);
return result;
}
@ -455,22 +614,22 @@ JSValueRef JSObjectGetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSSt
{
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(exec);
JSLockHolder locker(vm);
JSObject* jsObject = toJS(object);
JSValue result;
Identifier name(propertyName->identifier(&exec->vm()));
Identifier name(propertyName->identifier(&vm));
// Get wrapped object if proxied
if (jsObject->inherits(vm, JSProxy::info()))
if (jsObject->inherits<JSProxy>(vm))
jsObject = jsCast<JSProxy*>(jsObject)->target();
if (jsObject->inherits(vm, JSCallbackObject<JSGlobalObject>::info()))
if (jsObject->inherits<JSCallbackObject<JSGlobalObject>>(vm))
result = jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivateProperty(name);
else if (jsObject->inherits(vm, JSCallbackObject<JSDestructibleObject>::info()))
else if (jsObject->inherits<JSCallbackObject<JSDestructibleObject>>(vm))
result = jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivateProperty(name);
#if JSC_OBJC_API_ENABLED
else if (jsObject->inherits(vm, JSCallbackObject<JSAPIWrapperObject>::info()))
else if (jsObject->inherits<JSCallbackObject<JSAPIWrapperObject>>(vm))
result = jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->getPrivateProperty(name);
#endif
return toRef(exec, result);
@ -480,26 +639,26 @@ bool JSObjectSetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRe
{
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(exec);
JSLockHolder locker(vm);
JSObject* jsObject = toJS(object);
JSValue jsValue = value ? toJS(exec, value) : JSValue();
Identifier name(propertyName->identifier(&exec->vm()));
Identifier name(propertyName->identifier(&vm));
// Get wrapped object if proxied
if (jsObject->inherits(vm, JSProxy::info()))
if (jsObject->inherits<JSProxy>(vm))
jsObject = jsCast<JSProxy*>(jsObject)->target();
if (jsObject->inherits(vm, JSCallbackObject<JSGlobalObject>::info())) {
jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue);
if (jsObject->inherits<JSCallbackObject<JSGlobalObject>>(vm)) {
jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivateProperty(vm, name, jsValue);
return true;
}
if (jsObject->inherits(vm, JSCallbackObject<JSDestructibleObject>::info())) {
jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue);
if (jsObject->inherits<JSCallbackObject<JSDestructibleObject>>(vm)) {
jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivateProperty(vm, name, jsValue);
return true;
}
#if JSC_OBJC_API_ENABLED
if (jsObject->inherits(vm, JSCallbackObject<JSAPIWrapperObject>::info())) {
jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue);
if (jsObject->inherits<JSCallbackObject<JSAPIWrapperObject>>(vm)) {
jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->setPrivateProperty(vm, name, jsValue);
return true;
}
#endif
@ -510,24 +669,24 @@ bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef object, JSStrin
{
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(exec);
JSLockHolder locker(vm);
JSObject* jsObject = toJS(object);
Identifier name(propertyName->identifier(&exec->vm()));
Identifier name(propertyName->identifier(&vm));
// Get wrapped object if proxied
if (jsObject->inherits(vm, JSProxy::info()))
if (jsObject->inherits<JSProxy>(vm))
jsObject = jsCast<JSProxy*>(jsObject)->target();
if (jsObject->inherits(vm, JSCallbackObject<JSGlobalObject>::info())) {
if (jsObject->inherits<JSCallbackObject<JSGlobalObject>>(vm)) {
jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->deletePrivateProperty(name);
return true;
}
if (jsObject->inherits(vm, JSCallbackObject<JSDestructibleObject>::info())) {
if (jsObject->inherits<JSCallbackObject<JSDestructibleObject>>(vm)) {
jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->deletePrivateProperty(name);
return true;
}
#if JSC_OBJC_API_ENABLED
if (jsObject->inherits(vm, JSCallbackObject<JSAPIWrapperObject>::info())) {
if (jsObject->inherits<JSCallbackObject<JSAPIWrapperObject>>(vm)) {
jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->deletePrivateProperty(name);
return true;
}
@ -539,16 +698,20 @@ bool JSObjectIsFunction(JSContextRef ctx, JSObjectRef object)
{
if (!object)
return false;
JSLockHolder locker(toJS(ctx));
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(vm);
CallData callData;
JSCell* cell = toJS(object);
return cell->methodTable()->getCallData(cell, callData) != CallType::None;
return cell->methodTable(vm)->getCallData(cell, callData) != CallType::None;
}
JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
if (!object)
return 0;
@ -562,31 +725,40 @@ JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObject
MarkedArgumentBuffer argList;
for (size_t i = 0; i < argumentCount; i++)
argList.append(toJS(exec, arguments[i]));
if (UNLIKELY(argList.hasOverflowed())) {
auto throwScope = DECLARE_THROW_SCOPE(vm);
throwOutOfMemoryError(exec, throwScope);
handleExceptionIfNeeded(scope, exec, exception);
return 0;
}
CallData callData;
CallType callType = jsObject->methodTable()->getCallData(jsObject, callData);
CallType callType = jsObject->methodTable(vm)->getCallData(jsObject, callData);
if (callType == CallType::None)
return 0;
JSValueRef result = toRef(exec, profiledCall(exec, ProfilingReason::API, jsObject, callType, callData, jsThisObject, argList));
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
result = 0;
return result;
}
bool JSObjectIsConstructor(JSContextRef, JSObjectRef object)
bool JSObjectIsConstructor(JSContextRef ctx, JSObjectRef object)
{
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(vm);
if (!object)
return false;
JSObject* jsObject = toJS(object);
ConstructData constructData;
return jsObject->methodTable()->getConstructData(jsObject, constructData) != ConstructType::None;
return toJS(object)->isConstructor(vm);
}
JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
if (!object)
return 0;
@ -594,16 +766,22 @@ JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size
JSObject* jsObject = toJS(object);
ConstructData constructData;
ConstructType constructType = jsObject->methodTable()->getConstructData(jsObject, constructData);
ConstructType constructType = jsObject->methodTable(vm)->getConstructData(jsObject, constructData);
if (constructType == ConstructType::None)
return 0;
MarkedArgumentBuffer argList;
for (size_t i = 0; i < argumentCount; i++)
argList.append(toJS(exec, arguments[i]));
if (UNLIKELY(argList.hasOverflowed())) {
auto throwScope = DECLARE_THROW_SCOPE(vm);
throwOutOfMemoryError(exec, throwScope);
handleExceptionIfNeeded(scope, exec, exception);
return 0;
}
JSObjectRef result = toRef(profiledConstruct(exec, ProfilingReason::API, jsObject, constructType, constructData, argList));
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
result = 0;
return result;
}
@ -611,6 +789,7 @@ JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size
struct OpaqueJSPropertyNameArray {
WTF_MAKE_FAST_ALLOCATED;
public:
// FIXME: Why not inherit from RefCounted?
OpaqueJSPropertyNameArray(VM* vm)
: refCount(0)
, vm(vm)
@ -619,7 +798,7 @@ public:
unsigned refCount;
VM* vm;
Vector<JSRetainPtr<JSStringRef>> array;
Vector<Ref<OpaqueJSString>> array;
};
JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object)
@ -635,13 +814,13 @@ JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef o
JSObject* jsObject = toJS(object);
JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(vm);
PropertyNameArray array(vm, PropertyNameMode::Strings);
jsObject->methodTable()->getPropertyNames(jsObject, exec, array, EnumerationMode());
PropertyNameArray array(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
jsObject->methodTable(*vm)->getPropertyNames(jsObject, exec, array, EnumerationMode());
size_t size = array.size();
propertyNames->array.reserveInitialCapacity(size);
for (size_t i = 0; i < size; ++i)
propertyNames->array.uncheckedAppend(JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create(array[i].string()).leakRef()));
propertyNames->array.uncheckedAppend(OpaqueJSString::tryCreate(array[i].string()).releaseNonNull());
return JSPropertyNameArrayRetain(propertyNames);
}
@ -667,14 +846,15 @@ size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array)
JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size_t index)
{
return array->array[static_cast<unsigned>(index)].get();
return array->array[static_cast<unsigned>(index)].ptr();
}
void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array, JSStringRef propertyName)
{
PropertyNameArray* propertyNames = toJS(array);
JSLockHolder locker(propertyNames->vm());
propertyNames->add(propertyName->identifier(propertyNames->vm()));
VM* vm = propertyNames->vm();
JSLockHolder locker(vm);
propertyNames->add(propertyName->identifier(vm));
}
JSObjectRef JSObjectGetProxyTarget(JSObjectRef objectRef)
@ -691,3 +871,12 @@ JSObjectRef JSObjectGetProxyTarget(JSObjectRef objectRef)
result = proxy->target();
return toRef(result);
}
JSGlobalContextRef JSObjectGetGlobalContext(JSObjectRef objectRef)
{
JSObject* object = toJS(objectRef);
if (!object)
return nullptr;
return reinterpret_cast<JSGlobalContextRef>(object->globalObject()->globalExec());
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2006-2019 Apple Inc. All rights reserved.
* Copyright (C) 2008 Kelvin W Sherlock (ksherlock@gmail.com)
*
* Redistribution and use in source and binary forms, with or without
@ -441,7 +441,7 @@ JS_EXPORT JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsCla
@discussion The behavior of this function does not exactly match the behavior of the built-in Array constructor. Specifically, if one argument
is supplied, this function returns an array with one element.
*/
JS_EXPORT JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
/*!
@function
@ -452,7 +452,7 @@ JS_EXPORT JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount,
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result A JSObject that is a Date.
*/
JS_EXPORT JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
/*!
@function
@ -463,7 +463,7 @@ JS_EXPORT JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, c
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result A JSObject that is a Error.
*/
JS_EXPORT JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
/*!
@function
@ -474,7 +474,18 @@ JS_EXPORT JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount,
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result A JSObject that is a RegExp.
*/
JS_EXPORT JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0);
JS_EXPORT JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) JSC_API_AVAILABLE(macos(10.6), ios(7.0));
/*!
@function
@abstract Creates a JavaScript promise object by invoking the provided executor.
@param ctx The execution context to use.
@param resolve A pointer to a JSObjectRef in which to store the resolve function for the new promise. Pass NULL if you do not care to store the resolve callback.
@param reject A pointer to a JSObjectRef in which to store the reject function for the new promise. Pass NULL if you do not care to store the reject callback.
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result A JSObject that is a promise or NULL if an exception occurred.
*/
JS_EXPORT JSObjectRef JSObjectMakeDeferredPromise(JSContextRef ctx, JSObjectRef* resolve, JSObjectRef* reject, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@function
@ -536,9 +547,9 @@ JS_EXPORT JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, J
@param ctx The execution context to use.
@param object The JSObject whose property you want to set.
@param propertyName A JSString containing the property's name.
@param value A JSValue to use as the property's value.
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@param value A JSValueRef to use as the property's value.
@param attributes A logically ORed set of JSPropertyAttributes to give to the property.
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
*/
JS_EXPORT void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception);
@ -553,6 +564,54 @@ JS_EXPORT void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStrin
*/
JS_EXPORT bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception);
/*!
@function
@abstract Tests whether an object has a given property using a JSValueRef as the property key.
@param object The JSObject to test.
@param propertyKey A JSValueRef containing the property key to use when looking up the property.
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result true if the object has a property whose name matches propertyKey, otherwise false.
@discussion This function is the same as performing "propertyKey in object" from JavaScript.
*/
JS_EXPORT bool JSObjectHasPropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef propertyKey, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@function
@abstract Gets a property from an object using a JSValueRef as the property key.
@param ctx The execution context to use.
@param object The JSObject whose property you want to get.
@param propertyKey A JSValueRef containing the property key to use when looking up the property.
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result The property's value if object has the property key, otherwise the undefined value.
@discussion This function is the same as performing "object[propertyKey]" from JavaScript.
*/
JS_EXPORT JSValueRef JSObjectGetPropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef propertyKey, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@function
@abstract Sets a property on an object using a JSValueRef as the property key.
@param ctx The execution context to use.
@param object The JSObject whose property you want to set.
@param propertyKey A JSValueRef containing the property key to use when looking up the property.
@param value A JSValueRef to use as the property's value.
@param attributes A logically ORed set of JSPropertyAttributes to give to the property.
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@discussion This function is the same as performing "object[propertyKey] = value" from JavaScript.
*/
JS_EXPORT void JSObjectSetPropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef propertyKey, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@function
@abstract Deletes a property from an object using a JSValueRef as the property key.
@param ctx The execution context to use.
@param object The JSObject whose property you want to delete.
@param propertyKey A JSValueRef containing the property key to use when looking up the property.
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result true if the delete operation succeeds, otherwise false (for example, if the property has the kJSPropertyAttributeDontDelete attribute set).
@discussion This function is the same as performing "delete object[propertyKey]" from JavaScript.
*/
JS_EXPORT bool JSObjectDeletePropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef propertyKey, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@function
@abstract Gets a property from an object by numeric index.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Apple Inc. All rights reserved.
* Copyright (C) 2010-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -69,6 +69,8 @@ JS_EXPORT bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef objec
JS_EXPORT JSObjectRef JSObjectGetProxyTarget(JSObjectRef);
JS_EXPORT JSGlobalContextRef JSObjectGetGlobalContext(JSObjectRef object);
#ifdef __cplusplus
}
#endif

View File

@ -27,6 +27,7 @@
#include "JSRemoteInspector.h"
#include "JSGlobalObjectConsoleClient.h"
#include <wtf/ProcessID.h>
#if ENABLE(REMOTE_INSPECTOR)
#include "RemoteInspector.h"
@ -50,7 +51,7 @@ void JSRemoteInspectorStart(void)
#endif
}
void JSRemoteInspectorSetParentProcessInformation(pid_t pid, const uint8_t* auditData, size_t auditLength)
void JSRemoteInspectorSetParentProcessInformation(ProcessID pid, const uint8_t* auditData, size_t auditLength)
{
#if ENABLE(REMOTE_INSPECTOR) && PLATFORM(COCOA)
RetainPtr<CFDataRef> auditDataRef = adoptCF(CFDataCreate(kCFAllocatorDefault, auditData, auditLength));

View File

@ -29,20 +29,25 @@
#include <JavaScriptCore/JSBase.h>
#include <JavaScriptCore/WebKitAvailability.h>
#if defined(WIN32) || defined(_WIN32)
typedef int JSProcessID;
#else
#include <unistd.h>
typedef pid_t JSProcessID;
#endif
#ifdef __cplusplus
extern "C" {
#endif
JS_EXPORT void JSRemoteInspectorDisableAutoStart(void) CF_AVAILABLE(10_11, 9_0);
JS_EXPORT void JSRemoteInspectorStart(void) CF_AVAILABLE(10_11, 9_0);
JS_EXPORT void JSRemoteInspectorSetParentProcessInformation(pid_t, const uint8_t* auditData, size_t auditLength) CF_AVAILABLE(10_11, 9_0);
JS_EXPORT void JSRemoteInspectorDisableAutoStart(void) JSC_API_AVAILABLE(macos(10.11), ios(9.0));
JS_EXPORT void JSRemoteInspectorStart(void) JSC_API_AVAILABLE(macos(10.11), ios(9.0));
JS_EXPORT void JSRemoteInspectorSetParentProcessInformation(JSProcessID, const uint8_t* auditData, size_t auditLength) JSC_API_AVAILABLE(macos(10.11), ios(9.0));
JS_EXPORT void JSRemoteInspectorSetLogToSystemConsole(bool) CF_AVAILABLE(10_11, 9_0);
JS_EXPORT void JSRemoteInspectorSetLogToSystemConsole(bool) JSC_API_AVAILABLE(macos(10.11), ios(9.0));
JS_EXPORT bool JSRemoteInspectorGetInspectionEnabledByDefault(void) CF_AVAILABLE(10_11, 9_0);
JS_EXPORT void JSRemoteInspectorSetInspectionEnabledByDefault(bool) CF_AVAILABLE(10_11, 9_0);
JS_EXPORT bool JSRemoteInspectorGetInspectionEnabledByDefault(void) JSC_API_AVAILABLE(macos(10.11), ios(9.0));
JS_EXPORT void JSRemoteInspectorSetInspectionEnabledByDefault(bool) JSC_API_AVAILABLE(macos(10.11), ios(9.0));
#ifdef __cplusplus
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2005-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
@ -26,8 +26,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JSRetainPtr_h
#define JSRetainPtr_h
#pragma once
#include <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSStringRef.h>
@ -42,17 +41,16 @@ enum AdoptTag { Adopt };
template<typename T> class JSRetainPtr {
public:
JSRetainPtr() : m_ptr(0) { }
JSRetainPtr() = default;
JSRetainPtr(T ptr) : m_ptr(ptr) { if (ptr) JSRetain(ptr); }
JSRetainPtr(AdoptTag, T ptr) : m_ptr(ptr) { }
JSRetainPtr(const JSRetainPtr&);
template<typename U> JSRetainPtr(const JSRetainPtr<U>&);
JSRetainPtr(JSRetainPtr&&);
~JSRetainPtr();
T get() const { return m_ptr; }
void clear();
T leakRef();
T leakRef() WARN_UNUSED_RETURN;
T operator->() const { return m_ptr; }
@ -60,18 +58,30 @@ public:
explicit operator bool() const { return m_ptr; }
JSRetainPtr& operator=(const JSRetainPtr&);
template<typename U> JSRetainPtr& operator=(const JSRetainPtr<U>&);
JSRetainPtr& operator=(JSRetainPtr&&);
JSRetainPtr& operator=(T);
template<typename U> JSRetainPtr& operator=(U*);
void adopt(T);
void swap(JSRetainPtr&);
friend JSRetainPtr<JSStringRef> adopt(JSStringRef);
friend JSRetainPtr<JSGlobalContextRef> adopt(JSGlobalContextRef);
// FIXME: Make this private once Apple's internal code is updated to not rely on it.
// https://bugs.webkit.org/show_bug.cgi?id=189644
JSRetainPtr(AdoptTag, T);
private:
T m_ptr;
T m_ptr { nullptr };
};
JSRetainPtr<JSStringRef> adopt(JSStringRef);
JSRetainPtr<JSGlobalContextRef> adopt(JSGlobalContextRef);
template<typename T> inline JSRetainPtr<T>::JSRetainPtr(AdoptTag, T ptr)
: m_ptr(ptr)
{
}
inline JSRetainPtr<JSStringRef> adopt(JSStringRef o)
{
return JSRetainPtr<JSStringRef>(Adopt, o);
@ -89,11 +99,9 @@ template<typename T> inline JSRetainPtr<T>::JSRetainPtr(const JSRetainPtr& o)
JSRetain(m_ptr);
}
template<typename T> template<typename U> inline JSRetainPtr<T>::JSRetainPtr(const JSRetainPtr<U>& o)
: m_ptr(o.get())
template<typename T> inline JSRetainPtr<T>::JSRetainPtr(JSRetainPtr&& o)
: m_ptr(o.leakRef())
{
if (m_ptr)
JSRetain(m_ptr);
}
template<typename T> inline JSRetainPtr<T>::~JSRetainPtr()
@ -104,39 +112,23 @@ template<typename T> inline JSRetainPtr<T>::~JSRetainPtr()
template<typename T> inline void JSRetainPtr<T>::clear()
{
if (T ptr = m_ptr) {
m_ptr = 0;
if (T ptr = leakRef())
JSRelease(ptr);
}
}
template<typename T> inline T JSRetainPtr<T>::leakRef()
{
T ptr = m_ptr;
m_ptr = 0;
return ptr;
return std::exchange(m_ptr, nullptr);
}
template<typename T> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(const JSRetainPtr<T>& o)
{
T optr = o.get();
if (optr)
JSRetain(optr);
T ptr = m_ptr;
m_ptr = optr;
if (ptr)
JSRelease(ptr);
return *this;
return operator=(o.get());
}
template<typename T> template<typename U> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(const JSRetainPtr<U>& o)
template<typename T> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(JSRetainPtr&& o)
{
T optr = o.get();
if (optr)
JSRetain(optr);
T ptr = m_ptr;
m_ptr = optr;
if (ptr)
if (T ptr = std::exchange(m_ptr, o.leakRef()))
JSRelease(ptr);
return *this;
}
@ -145,28 +137,7 @@ template<typename T> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(T optr)
{
if (optr)
JSRetain(optr);
T ptr = m_ptr;
m_ptr = optr;
if (ptr)
JSRelease(ptr);
return *this;
}
template<typename T> inline void JSRetainPtr<T>::adopt(T optr)
{
T ptr = m_ptr;
m_ptr = optr;
if (ptr)
JSRelease(ptr);
}
template<typename T> template<typename U> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(U* optr)
{
if (optr)
JSRetain(optr);
T ptr = m_ptr;
m_ptr = optr;
if (ptr)
if (T ptr = std::exchange(m_ptr, optr))
JSRelease(ptr);
return *this;
}
@ -210,6 +181,3 @@ template<typename T, typename U> inline bool operator!=(T* a, const JSRetainPtr<
{
return a != b.get();
}
#endif // JSRetainPtr_h

108
API/JSScript.h Normal file
View File

@ -0,0 +1,108 @@
/*
* Copyright (C) 2019 Apple 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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.
*/
#import <JavaScriptCore/JSValue.h>
#if JSC_OBJC_API_ENABLED
NS_ASSUME_NONNULL_BEGIN
@class JSVirtualMachine;
/*!
@enum JSScriptType
@abstract A constant identifying the execution type of a JSScript.
@constant kJSScriptTypeProgram The type of a normal JavaScript program.
@constant kJSScriptTypeModule The type of a module JavaScript program.
*/
typedef NS_ENUM(NSInteger, JSScriptType) {
kJSScriptTypeProgram,
kJSScriptTypeModule,
};
JSC_CLASS_AVAILABLE(macos(10.15), ios(13.0))
@interface JSScript : NSObject
/*!
@method
@abstract Create a JSScript for the specified virtual machine.
@param type The type of JavaScript source.
@param source The source code to use when the script is evaluated by the JS vm.
@param sourceURL The source URL to associate with this script. For modules, this is the module identifier.
@param cachePath A URL containing the path where the VM should cache for future execution. On creation, we use this path to load the cached bytecode off disk. If the cached bytecode at this location is stale, you should delete that file before calling this constructor.
@param vm The JSVirtualMachine the script can be evaluated in.
@param error A description of why the script could not be created if the result is nil.
@result The new script.
@discussion The file at cachePath should not be externally modified for the lifecycle of vm.
*/
+ (nullable instancetype)scriptOfType:(JSScriptType)type withSource:(NSString *)source andSourceURL:(NSURL *)sourceURL andBytecodeCache:(nullable NSURL *)cachePath inVirtualMachine:(JSVirtualMachine *)vm error:(out NSError * _Nullable * _Nullable)error;
/*!
@method
@abstract Create a JSScript for the specified virtual machine with a path to a codesigning and bytecode caching.
@param type The type of JavaScript source.
@param filePath A URL containing the path to a JS source code file on disk.
@param sourceURL The source URL to associate with this script. For modules, this is the module identifier.
@param cachePath A URL containing the path where the VM should cache for future execution. On creation, we use this path to load the cached bytecode off disk. If the cached bytecode at this location is stale, you should delete that file before calling this constructor.
@param vm The JSVirtualMachine the script can be evaluated in.
@param error A description of why the script could not be created if the result is nil.
@result The new script.
@discussion The files at filePath and cachePath should not be externally modified for the lifecycle of vm. This method will file back the memory for the source.
If the file at filePath is not ascii this method will return nil.
*/
+ (nullable instancetype)scriptOfType:(JSScriptType)type memoryMappedFromASCIIFile:(NSURL *)filePath withSourceURL:(NSURL *)sourceURL andBytecodeCache:(nullable NSURL *)cachePath inVirtualMachine:(JSVirtualMachine *)vm error:(out NSError * _Nullable * _Nullable)error;
/*!
@method
@abstract Cache the bytecode for this JSScript to disk at the path passed in during creation.
@param error A description of why the script could not be cached if the result is FALSE.
*/
- (BOOL)cacheBytecodeWithError:(out NSError * _Nullable * _Nullable)error;
/*!
@method
@abstract Returns true when evaluating this JSScript will use the bytecode cache. Returns false otherwise.
*/
- (BOOL)isUsingBytecodeCache;
/*!
@method
@abstract Returns the JSScriptType of this JSScript.
*/
- (JSScriptType)type;
/*!
@method
@abstract Returns the sourceURL of this JSScript.
*/
- (NSURL *)sourceURL;
@end
NS_ASSUME_NONNULL_END
#endif // JSC_OBJC_API_ENABLED

304
API/JSScript.mm Normal file
View File

@ -0,0 +1,304 @@
/*
* Copyright (C) 2019 Apple 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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.
*/
#import "config.h"
#import "JSScriptInternal.h"
#import "APICast.h"
#import "BytecodeCacheError.h"
#import "CachedTypes.h"
#import "CodeCache.h"
#import "Identifier.h"
#import "JSContextInternal.h"
#import "JSScriptSourceProvider.h"
#import "JSSourceCode.h"
#import "JSValuePrivate.h"
#import "JSVirtualMachineInternal.h"
#import "Symbol.h"
#import <sys/stat.h>
#import <wtf/FileMetadata.h>
#import <wtf/FileSystem.h>
#import <wtf/Scope.h>
#import <wtf/WeakObjCPtr.h>
#import <wtf/spi/darwin/DataVaultSPI.h>
#if JSC_OBJC_API_ENABLED
@implementation JSScript {
WeakObjCPtr<JSVirtualMachine> m_virtualMachine;
JSScriptType m_type;
FileSystem::MappedFileData m_mappedSource;
String m_source;
RetainPtr<NSURL> m_sourceURL;
RetainPtr<NSURL> m_cachePath;
RefPtr<JSC::CachedBytecode> m_cachedBytecode;
}
static JSScript *createError(NSString *message, NSError** error)
{
if (error)
*error = [NSError errorWithDomain:@"JSScriptErrorDomain" code:1 userInfo:@{ @"message": message }];
return nil;
}
static bool validateBytecodeCachePath(NSURL* cachePath, NSError** error)
{
if (!cachePath)
return true;
URL cachePathURL([cachePath absoluteURL]);
if (!cachePathURL.isLocalFile()) {
createError([NSString stringWithFormat:@"Cache path `%@` is not a local file", static_cast<NSString *>(cachePathURL)], error);
return false;
}
String systemPath = cachePathURL.fileSystemPath();
if (auto metadata = FileSystem::fileMetadata(systemPath)) {
if (metadata->type != FileMetadata::Type::File) {
createError([NSString stringWithFormat:@"Cache path `%@` already exists and is not a file", static_cast<NSString *>(systemPath)], error);
return false;
}
}
String directory = FileSystem::directoryName(systemPath);
if (directory.isNull()) {
createError([NSString stringWithFormat:@"Cache path `%@` does not contain in a valid directory", static_cast<NSString *>(systemPath)], error);
return false;
}
if (!FileSystem::fileIsDirectory(directory, FileSystem::ShouldFollowSymbolicLinks::No)) {
createError([NSString stringWithFormat:@"Cache directory `%@` is not a directory or does not exist", static_cast<NSString *>(directory)], error);
return false;
}
#if USE(APPLE_INTERNAL_SDK)
if (rootless_check_datavault_flag(FileSystem::fileSystemRepresentation(directory).data(), nullptr)) {
createError([NSString stringWithFormat:@"Cache directory `%@` is not a data vault", static_cast<NSString *>(directory)], error);
return false;
}
#endif
return true;
}
+ (instancetype)scriptOfType:(JSScriptType)type withSource:(NSString *)source andSourceURL:(NSURL *)sourceURL andBytecodeCache:(NSURL *)cachePath inVirtualMachine:(JSVirtualMachine *)vm error:(out NSError **)error
{
if (!validateBytecodeCachePath(cachePath, error))
return nil;
JSScript *result = [[[JSScript alloc] init] autorelease];
result->m_virtualMachine = vm;
result->m_type = type;
result->m_source = source;
result->m_sourceURL = sourceURL;
result->m_cachePath = cachePath;
[result readCache];
return result;
}
+ (instancetype)scriptOfType:(JSScriptType)type memoryMappedFromASCIIFile:(NSURL *)filePath withSourceURL:(NSURL *)sourceURL andBytecodeCache:(NSURL *)cachePath inVirtualMachine:(JSVirtualMachine *)vm error:(out NSError **)error
{
if (!validateBytecodeCachePath(cachePath, error))
return nil;
URL filePathURL([filePath absoluteURL]);
if (!filePathURL.isLocalFile())
return createError([NSString stringWithFormat:@"File path %@ is not a local file", static_cast<NSString *>(filePathURL)], error);
bool success = false;
String systemPath = filePathURL.fileSystemPath();
FileSystem::MappedFileData fileData(systemPath, success);
if (!success)
return createError([NSString stringWithFormat:@"File at path %@ could not be mapped.", static_cast<NSString *>(systemPath)], error);
if (!charactersAreAllASCII(reinterpret_cast<const LChar*>(fileData.data()), fileData.size()))
return createError([NSString stringWithFormat:@"Not all characters in file at %@ are ASCII.", static_cast<NSString *>(systemPath)], error);
JSScript *result = [[[JSScript alloc] init] autorelease];
result->m_virtualMachine = vm;
result->m_type = type;
result->m_source = String(StringImpl::createWithoutCopying(bitwise_cast<const LChar*>(fileData.data()), fileData.size()));
result->m_mappedSource = WTFMove(fileData);
result->m_sourceURL = sourceURL;
result->m_cachePath = cachePath;
[result readCache];
return result;
}
- (void)readCache
{
if (!m_cachePath)
return;
int fd = open([m_cachePath path].UTF8String, O_RDONLY | O_EXLOCK | O_NONBLOCK, 0666);
if (fd == -1)
return;
auto closeFD = makeScopeExit([&] {
close(fd);
});
struct stat sb;
int res = fstat(fd, &sb);
size_t size = static_cast<size_t>(sb.st_size);
if (res || !size)
return;
void* buffer = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
Ref<JSC::CachedBytecode> cachedBytecode = JSC::CachedBytecode::create(buffer, size);
JSC::VM& vm = [m_virtualMachine vm];
JSC::SourceCode sourceCode = [self sourceCode];
JSC::SourceCodeKey key = m_type == kJSScriptTypeProgram ? sourceCodeKeyForSerializedProgram(vm, sourceCode) : sourceCodeKeyForSerializedModule(vm, sourceCode);
if (isCachedBytecodeStillValid(vm, cachedBytecode.copyRef(), key, m_type == kJSScriptTypeProgram ? JSC::SourceCodeType::ProgramType : JSC::SourceCodeType::ModuleType))
m_cachedBytecode = WTFMove(cachedBytecode);
else
ftruncate(fd, 0);
}
- (BOOL)cacheBytecodeWithError:(NSError **)error
{
String errorString { };
[self writeCache:errorString];
if (!errorString.isNull()) {
createError(errorString, error);
return NO;
}
return YES;
}
- (BOOL)isUsingBytecodeCache
{
return !!m_cachedBytecode->size();
}
- (NSURL *)sourceURL
{
return m_sourceURL.get();
}
- (JSScriptType)type
{
return m_type;
}
@end
@implementation JSScript(Internal)
- (instancetype)init
{
self = [super init];
if (!self)
return nil;
self->m_cachedBytecode = JSC::CachedBytecode::create();
return self;
}
- (unsigned)hash
{
return m_source.hash();
}
- (const String&)source
{
return m_source;
}
- (RefPtr<JSC::CachedBytecode>)cachedBytecode
{
return m_cachedBytecode;
}
- (JSC::SourceCode)sourceCode
{
JSC::VM& vm = [m_virtualMachine vm];
JSC::JSLockHolder locker(vm);
TextPosition startPosition { };
String url = String { [[self sourceURL] absoluteString] };
auto type = m_type == kJSScriptTypeModule ? JSC::SourceProviderSourceType::Module : JSC::SourceProviderSourceType::Program;
Ref<JSScriptSourceProvider> sourceProvider = JSScriptSourceProvider::create(self, JSC::SourceOrigin(url), URL({ }, url), startPosition, type);
JSC::SourceCode sourceCode(WTFMove(sourceProvider), startPosition.m_line.oneBasedInt(), startPosition.m_column.oneBasedInt());
return sourceCode;
}
- (JSC::JSSourceCode*)jsSourceCode
{
JSC::VM& vm = [m_virtualMachine vm];
JSC::JSLockHolder locker(vm);
JSC::JSSourceCode* jsSourceCode = JSC::JSSourceCode::create(vm, [self sourceCode]);
return jsSourceCode;
}
- (BOOL)writeCache:(String&)error
{
if (self.isUsingBytecodeCache) {
error = "Cache for JSScript is already non-empty. Can not override it."_s;
return NO;
}
if (!m_cachePath) {
error = "No cache path was provided during construction of this JSScript."_s;
return NO;
}
int fd = open([m_cachePath path].UTF8String, O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK, 0666);
if (fd == -1) {
error = makeString("Could not open or lock the bytecode cache file. It's likely another VM or process is already using it. Error: ", strerror(errno));
return NO;
}
auto closeFD = makeScopeExit([&] {
close(fd);
});
JSC::BytecodeCacheError cacheError;
JSC::SourceCode sourceCode = [self sourceCode];
switch (m_type) {
case kJSScriptTypeModule:
m_cachedBytecode = JSC::generateModuleBytecode([m_virtualMachine vm], sourceCode, fd, cacheError);
break;
case kJSScriptTypeProgram:
m_cachedBytecode = JSC::generateProgramBytecode([m_virtualMachine vm], sourceCode, fd, cacheError);
break;
}
if (cacheError.isValid()) {
m_cachedBytecode = JSC::CachedBytecode::create();
ftruncate(fd, 0);
error = makeString("Unable to generate bytecode for this JSScript because: ", cacheError.message());
return NO;
}
return YES;
}
@end
#endif

60
API/JSScriptInternal.h Normal file
View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2019 Apple 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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.
*/
#pragma once
#import "JSScript.h"
#import "SourceCode.h"
#import <wtf/RefPtr.h>
#if JSC_OBJC_API_ENABLED
NS_ASSUME_NONNULL_BEGIN
namespace JSC {
class CachedBytecode;
class Identifier;
class JSSourceCode;
};
namespace WTF {
class String;
};
@interface JSScript(Internal)
- (instancetype)init;
- (unsigned)hash;
- (const WTF::String&)source;
- (RefPtr<JSC::CachedBytecode>)cachedBytecode;
- (JSC::JSSourceCode*)jsSourceCode;
- (JSC::SourceCode)sourceCode;
- (BOOL)writeCache:(String&)error;
@end
NS_ASSUME_NONNULL_END
#endif // JSC_OBJC_API_ENABLED

View File

@ -41,9 +41,9 @@ using namespace JSC;
struct OpaqueJSScript : public SourceProvider {
public:
static WTF::Ref<OpaqueJSScript> create(VM& vm, const SourceOrigin& sourceOrigin, const String& url, int startingLineNumber, const String& source)
static WTF::Ref<OpaqueJSScript> create(VM& vm, const SourceOrigin& sourceOrigin, URL&& url, int startingLineNumber, const String& source)
{
return WTF::adoptRef(*new OpaqueJSScript(vm, sourceOrigin, url, startingLineNumber, source));
return WTF::adoptRef(*new OpaqueJSScript(vm, sourceOrigin, WTFMove(url), startingLineNumber, source));
}
unsigned hash() const override
@ -59,8 +59,8 @@ public:
VM& vm() const { return m_vm; }
private:
OpaqueJSScript(VM& vm, const SourceOrigin& sourceOrigin, const String& url, int startingLineNumber, const String& source)
: SourceProvider(sourceOrigin, url, TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber()), SourceProviderSourceType::Program)
OpaqueJSScript(VM& vm, const SourceOrigin& sourceOrigin, URL&& url, int startingLineNumber, const String& source)
: SourceProvider(sourceOrigin, WTFMove(url), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber()), SourceProviderSourceType::Program)
, m_vm(vm)
, m_source(source.isNull() ? *StringImpl::empty() : *source.impl())
{
@ -94,12 +94,12 @@ JSScriptRef JSScriptCreateReferencingImmortalASCIIText(JSContextGroupRef context
startingLineNumber = std::max(1, startingLineNumber);
auto sourceURLString = url ? url->string() : String();
auto result = OpaqueJSScript::create(vm, SourceOrigin { sourceURLString }, sourceURLString, startingLineNumber, String(StringImpl::createFromLiteral(source, length)));
auto result = OpaqueJSScript::create(vm, SourceOrigin { sourceURLString }, URL({ }, sourceURLString), startingLineNumber, String(StringImpl::createFromLiteral(source, length)));
ParserError error;
if (!parseScript(vm, SourceCode(result.copyRef()), error)) {
if (errorMessage)
*errorMessage = OpaqueJSString::create(error.message()).leakRef();
*errorMessage = OpaqueJSString::tryCreate(error.message()).leakRef();
if (errorLine)
*errorLine = error.line();
return nullptr;
@ -116,12 +116,12 @@ JSScriptRef JSScriptCreateFromString(JSContextGroupRef contextGroup, JSStringRef
startingLineNumber = std::max(1, startingLineNumber);
auto sourceURLString = url ? url->string() : String();
auto result = OpaqueJSScript::create(vm, SourceOrigin { sourceURLString }, sourceURLString, startingLineNumber, source->string());
auto result = OpaqueJSScript::create(vm, SourceOrigin { sourceURLString }, URL({ }, sourceURLString), startingLineNumber, source->string());
ParserError error;
if (!parseScript(vm, SourceCode(result.copyRef()), error)) {
if (errorMessage)
*errorMessage = OpaqueJSString::create(error.message()).leakRef();
*errorMessage = OpaqueJSString::tryCreate(error.message()).leakRef();
if (errorLine)
*errorLine = error.line();
return nullptr;
@ -145,8 +145,9 @@ void JSScriptRelease(JSScriptRef script)
JSValueRef JSScriptEvaluate(JSContextRef context, JSScriptRef script, JSValueRef thisValueRef, JSValueRef* exception)
{
ExecState* exec = toJS(context);
JSLockHolder locker(exec);
if (&script->vm() != &exec->vm()) {
VM& vm = exec->vm();
JSLockHolder locker(vm);
if (&script->vm() != &vm) {
RELEASE_ASSERT_NOT_REACHED();
return 0;
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2019 Apple 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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.
*/
#if JSC_OBJC_API_ENABLED
#import "SourceProvider.h"
@class JSScript;
class JSScriptSourceProvider : public JSC::SourceProvider {
public:
template<typename... Args>
static Ref<JSScriptSourceProvider> create(JSScript *script, Args&&... args)
{
return adoptRef(*new JSScriptSourceProvider(script, std::forward<Args>(args)...));
}
unsigned hash() const override;
StringView source() const override;
RefPtr<JSC::CachedBytecode> cachedBytecode() const override;
private:
template<typename... Args>
JSScriptSourceProvider(JSScript *script, Args&&... args)
: SourceProvider(std::forward<Args>(args)...)
, m_script(script)
{ }
RetainPtr<JSScript> m_script;
};
#endif // JSC_OBJC_API_ENABLED

View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2019 Apple 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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.
*/
#import "config.h"
#import "JSScriptSourceProvider.h"
#if JSC_OBJC_API_ENABLED
#import "JSScriptInternal.h"
unsigned JSScriptSourceProvider::hash() const
{
return [m_script.get() hash];
}
StringView JSScriptSourceProvider::source() const
{
return [m_script.get() source];
}
RefPtr<JSC::CachedBytecode> JSScriptSourceProvider::cachedBytecode() const
{
return [m_script.get() cachedBytecode];
}
#endif // JSC_OBJC_API_ENABLED

View File

@ -29,7 +29,7 @@
#include "InitializeThreading.h"
#include "OpaqueJSString.h"
#include <wtf/unicode/UTF8.h>
#include <wtf/unicode/UTF8Conversion.h>
using namespace JSC;
using namespace WTF::Unicode;
@ -49,7 +49,7 @@ JSStringRef JSStringCreateWithUTF8CString(const char* string)
UChar* p = buffer.data();
bool sourceIsAllASCII;
const LChar* stringStart = reinterpret_cast<const LChar*>(string);
if (conversionOK == convertUTF8ToUTF16(&string, string + length, &p, p + length, &sourceIsAllASCII)) {
if (convertUTF8ToUTF16(string, string + length, &p, p + length, &sourceIsAllASCII)) {
if (sourceIsAllASCII)
return &OpaqueJSString::create(stringStart, length).leakRef();
return &OpaqueJSString::create(buffer.data(), p - buffer.data()).leakRef();
@ -62,7 +62,7 @@ JSStringRef JSStringCreateWithUTF8CString(const char* string)
JSStringRef JSStringCreateWithCharactersNoCopy(const JSChar* chars, size_t numChars)
{
initializeThreading();
return OpaqueJSString::create(StringImpl::createWithoutCopying(reinterpret_cast<const UChar*>(chars), numChars)).leakRef();
return OpaqueJSString::tryCreate(StringImpl::createWithoutCopying(reinterpret_cast<const UChar*>(chars), numChars)).leakRef();
}
JSStringRef JSStringRetain(JSStringRef string)
@ -102,20 +102,18 @@ size_t JSStringGetUTF8CString(JSStringRef string, char* buffer, size_t bufferSiz
return 0;
char* destination = buffer;
ConversionResult result;
bool failed = false;
if (string->is8Bit()) {
const LChar* source = string->characters8();
result = convertLatin1ToUTF8(&source, source + string->length(), &destination, destination + bufferSize - 1);
convertLatin1ToUTF8(&source, source + string->length(), &destination, destination + bufferSize - 1);
} else {
const UChar* source = string->characters16();
result = convertUTF16ToUTF8(&source, source + string->length(), &destination, destination + bufferSize - 1, true);
auto result = convertUTF16ToUTF8(&source, source + string->length(), &destination, destination + bufferSize - 1);
failed = result != ConversionOK && result != TargetExhausted;
}
*destination++ = '\0';
if (result != conversionOK && result != targetExhausted)
return 0;
return destination - buffer;
return failed ? 0 : destination - buffer;
}
bool JSStringIsEqual(JSStringRef a, JSStringRef b)
@ -125,9 +123,5 @@ bool JSStringIsEqual(JSStringRef a, JSStringRef b)
bool JSStringIsEqualToUTF8CString(JSStringRef a, const char* b)
{
JSStringRef bBuf = JSStringCreateWithUTF8CString(b);
bool result = JSStringIsEqual(a, bBuf);
JSStringRelease(bBuf);
return result;
return JSStringIsEqual(a, adoptRef(JSStringCreateWithUTF8CString(b)).get());
}

View File

@ -49,10 +49,10 @@ JSStringRef JSStringCreateWithCFString(CFStringRef string)
if (static_cast<size_t>(convertedSize) == length && static_cast<size_t>(usedBufferLength) == length)
return &OpaqueJSString::create(lcharBuffer.data(), length).leakRef();
auto buffer = std::make_unique<UniChar[]>(length);
CFStringGetCharacters(string, CFRangeMake(0, length), buffer.get());
Vector<UniChar> buffer(length);
CFStringGetCharacters(string, CFRangeMake(0, length), buffer.data());
static_assert(sizeof(UniChar) == sizeof(UChar), "UniChar and UChar must be same size");
return &OpaqueJSString::create(reinterpret_cast<UChar*>(buffer.get()), length).leakRef();
return &OpaqueJSString::create(reinterpret_cast<UChar*>(buffer.data()), length).leakRef();
}
CFStringRef JSStringCopyCFString(CFAllocatorRef allocator, JSStringRef string)

View File

@ -141,7 +141,7 @@ JSTypedArrayType JSValueGetTypedArrayType(JSContextRef ctx, JSValueRef valueRef,
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(exec);
JSLockHolder locker(vm);
JSValue value = toJS(exec, valueRef);
if (!value.isObject())
@ -157,7 +157,9 @@ JSTypedArrayType JSValueGetTypedArrayType(JSContextRef ctx, JSValueRef valueRef,
JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType arrayType, size_t length, JSValueRef* exception)
{
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
if (arrayType == kJSTypedArrayTypeNone || arrayType == kJSTypedArrayTypeArrayBuffer)
return nullptr;
@ -166,7 +168,7 @@ JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType arrayType,
auto buffer = ArrayBuffer::tryCreate(length, elementByteSize);
JSObject* result = createTypedArray(exec, arrayType, WTFMove(buffer), 0, length);
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
return nullptr;
return toRef(result);
}
@ -174,19 +176,21 @@ JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType arrayType,
JSObjectRef JSObjectMakeTypedArrayWithBytesNoCopy(JSContextRef ctx, JSTypedArrayType arrayType, void* bytes, size_t length, JSTypedArrayBytesDeallocator destructor, void* destructorContext, JSValueRef* exception)
{
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
if (arrayType == kJSTypedArrayTypeNone || arrayType == kJSTypedArrayTypeArrayBuffer)
return nullptr;
unsigned elementByteSize = elementSize(toTypedArrayType(arrayType));
RefPtr<ArrayBuffer> buffer = ArrayBuffer::createFromBytes(bytes, length, [=](void* p) {
auto buffer = ArrayBuffer::createFromBytes(bytes, length, [=](void* p) {
if (destructor)
destructor(p, destructorContext);
});
JSObject* result = createTypedArray(exec, arrayType, WTFMove(buffer), 0, length / elementByteSize);
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
return nullptr;
return toRef(result);
}
@ -195,7 +199,8 @@ JSObjectRef JSObjectMakeTypedArrayWithArrayBuffer(JSContextRef ctx, JSTypedArray
{
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(exec);
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
if (arrayType == kJSTypedArrayTypeNone || arrayType == kJSTypedArrayTypeArrayBuffer)
return nullptr;
@ -210,7 +215,7 @@ JSObjectRef JSObjectMakeTypedArrayWithArrayBuffer(JSContextRef ctx, JSTypedArray
unsigned elementByteSize = elementSize(toTypedArrayType(arrayType));
JSObject* result = createTypedArray(exec, arrayType, WTFMove(buffer), 0, buffer->byteLength() / elementByteSize);
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
return nullptr;
return toRef(result);
}
@ -219,7 +224,8 @@ JSObjectRef JSObjectMakeTypedArrayWithArrayBufferAndOffset(JSContextRef ctx, JST
{
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(exec);
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
if (arrayType == kJSTypedArrayTypeNone || arrayType == kJSTypedArrayTypeArrayBuffer)
return nullptr;
@ -231,7 +237,7 @@ JSObjectRef JSObjectMakeTypedArrayWithArrayBufferAndOffset(JSContextRef ctx, JST
}
JSObject* result = createTypedArray(exec, arrayType, jsBuffer->impl(), offset, length);
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
return nullptr;
return toRef(result);
}
@ -240,7 +246,7 @@ void* JSObjectGetTypedArrayBytesPtr(JSContextRef ctx, JSObjectRef objectRef, JSV
{
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(exec);
JSLockHolder locker(vm);
JSObject* object = toJS(objectRef);
if (JSArrayBufferView* typedArray = jsDynamicCast<JSArrayBufferView*>(vm, object)) {
@ -291,11 +297,11 @@ JSObjectRef JSObjectGetTypedArrayBuffer(JSContextRef ctx, JSObjectRef objectRef,
{
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(exec);
JSLockHolder locker(vm);
JSObject* object = toJS(objectRef);
if (JSArrayBufferView* typedArray = jsDynamicCast<JSArrayBufferView*>(vm, object))
return toRef(exec->vm().m_typedArrayController->toJS(exec, typedArray->globalObject(), typedArray->possiblySharedBuffer()));
return toRef(vm.m_typedArrayController->toJS(exec, typedArray->globalObject(vm), typedArray->possiblySharedBuffer()));
return nullptr;
}
@ -303,15 +309,17 @@ JSObjectRef JSObjectGetTypedArrayBuffer(JSContextRef ctx, JSObjectRef objectRef,
JSObjectRef JSObjectMakeArrayBufferWithBytesNoCopy(JSContextRef ctx, void* bytes, size_t byteLength, JSTypedArrayBytesDeallocator bytesDeallocator, void* deallocatorContext, JSValueRef* exception)
{
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
auto buffer = ArrayBuffer::createFromBytes(bytes, byteLength, [=](void* p) {
if (bytesDeallocator)
bytesDeallocator(p, deallocatorContext);
});
JSArrayBuffer* jsBuffer = JSArrayBuffer::create(exec->vm(), exec->lexicalGlobalObject()->arrayBufferStructure(ArrayBufferSharingMode::Default), WTFMove(buffer));
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
JSArrayBuffer* jsBuffer = JSArrayBuffer::create(vm, exec->lexicalGlobalObject()->arrayBufferStructure(ArrayBufferSharingMode::Default), WTFMove(buffer));
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
return nullptr;
return toRef(jsBuffer);
@ -321,13 +329,13 @@ void* JSObjectGetArrayBufferBytesPtr(JSContextRef ctx, JSObjectRef objectRef, JS
{
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(exec);
JSLockHolder locker(vm);
JSObject* object = toJS(objectRef);
if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(vm, object)) {
ArrayBuffer* buffer = jsBuffer->impl();
if (buffer->isWasmMemory()) {
setException(exec, exception, createTypeError(exec, ASCIILiteral("Cannot get the backing buffer for a WebAssembly.Memory")));
setException(exec, exception, createTypeError(exec, "Cannot get the backing buffer for a WebAssembly.Memory"_s));
return nullptr;
}

View File

@ -45,7 +45,7 @@ extern "C" {
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result A JSObjectRef that is a Typed Array with all elements set to zero or NULL if there was an error.
*/
JS_EXPORT JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType arrayType, size_t length, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType arrayType, size_t length, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
/*!
@function
@ -60,7 +60,7 @@ JS_EXPORT JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType
@result A JSObjectRef Typed Array whose backing store is the same as the one pointed to by bytes or NULL if there was an error.
@discussion If an exception is thrown during this function the bytesDeallocator will always be called.
*/
JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithBytesNoCopy(JSContextRef ctx, JSTypedArrayType arrayType, void* bytes, size_t byteLength, JSTypedArrayBytesDeallocator bytesDeallocator, void* deallocatorContext, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithBytesNoCopy(JSContextRef ctx, JSTypedArrayType arrayType, void* bytes, size_t byteLength, JSTypedArrayBytesDeallocator bytesDeallocator, void* deallocatorContext, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
/*!
@function
@ -71,7 +71,7 @@ JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithBytesNoCopy(JSContextRef ctx, JS
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result A JSObjectRef that is a Typed Array or NULL if there was an error. The backing store of the Typed Array will be buffer.
*/
JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBuffer(JSContextRef ctx, JSTypedArrayType arrayType, JSObjectRef buffer, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBuffer(JSContextRef ctx, JSTypedArrayType arrayType, JSObjectRef buffer, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
/*!
@function
@ -84,7 +84,7 @@ JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBuffer(JSContextRef ctx, JS
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result A JSObjectRef that is a Typed Array or NULL if there was an error. The backing store of the Typed Array will be buffer.
*/
JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBufferAndOffset(JSContextRef ctx, JSTypedArrayType arrayType, JSObjectRef buffer, size_t byteOffset, size_t length, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBufferAndOffset(JSContextRef ctx, JSTypedArrayType arrayType, JSObjectRef buffer, size_t byteOffset, size_t length, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
/*!
@function
@ -95,7 +95,7 @@ JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBufferAndOffset(JSContextRe
@result A pointer to the raw data buffer that serves as object's backing store or NULL if object is not a Typed Array object.
@discussion The pointer returned by this function is temporary and is not guaranteed to remain valid across JavaScriptCore API calls.
*/
JS_EXPORT void* JSObjectGetTypedArrayBytesPtr(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT void* JSObjectGetTypedArrayBytesPtr(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
/*!
@function
@ -105,7 +105,7 @@ JS_EXPORT void* JSObjectGetTypedArrayBytesPtr(JSContextRef ctx, JSObjectRef obje
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result The length of the Typed Array object or 0 if the object is not a Typed Array object.
*/
JS_EXPORT size_t JSObjectGetTypedArrayLength(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT size_t JSObjectGetTypedArrayLength(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
/*!
@function
@ -115,7 +115,7 @@ JS_EXPORT size_t JSObjectGetTypedArrayLength(JSContextRef ctx, JSObjectRef objec
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result The byte length of the Typed Array object or 0 if the object is not a Typed Array object.
*/
JS_EXPORT size_t JSObjectGetTypedArrayByteLength(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT size_t JSObjectGetTypedArrayByteLength(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
/*!
@function
@ -125,7 +125,7 @@ JS_EXPORT size_t JSObjectGetTypedArrayByteLength(JSContextRef ctx, JSObjectRef o
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result The byte offset of the Typed Array object or 0 if the object is not a Typed Array object.
*/
JS_EXPORT size_t JSObjectGetTypedArrayByteOffset(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT size_t JSObjectGetTypedArrayByteOffset(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
/*!
@function
@ -135,7 +135,7 @@ JS_EXPORT size_t JSObjectGetTypedArrayByteOffset(JSContextRef ctx, JSObjectRef o
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result A JSObjectRef with a JSTypedArrayType of kJSTypedArrayTypeArrayBuffer or NULL if object is not a Typed Array.
*/
JS_EXPORT JSObjectRef JSObjectGetTypedArrayBuffer(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT JSObjectRef JSObjectGetTypedArrayBuffer(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
// ------------- Array Buffer functions -------------
@ -151,7 +151,7 @@ JS_EXPORT JSObjectRef JSObjectGetTypedArrayBuffer(JSContextRef ctx, JSObjectRef
@result A JSObjectRef Array Buffer whose backing store is the same as the one pointed to by bytes or NULL if there was an error.
@discussion If an exception is thrown during this function the bytesDeallocator will always be called.
*/
JS_EXPORT JSObjectRef JSObjectMakeArrayBufferWithBytesNoCopy(JSContextRef ctx, void* bytes, size_t byteLength, JSTypedArrayBytesDeallocator bytesDeallocator, void* deallocatorContext, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT JSObjectRef JSObjectMakeArrayBufferWithBytesNoCopy(JSContextRef ctx, void* bytes, size_t byteLength, JSTypedArrayBytesDeallocator bytesDeallocator, void* deallocatorContext, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
/*!
@function
@ -161,7 +161,7 @@ JS_EXPORT JSObjectRef JSObjectMakeArrayBufferWithBytesNoCopy(JSContextRef ctx, v
@result A pointer to the raw data buffer that serves as object's backing store or NULL if object is not an Array Buffer object.
@discussion The pointer returned by this function is temporary and is not guaranteed to remain valid across JavaScriptCore API calls.
*/
JS_EXPORT void* JSObjectGetArrayBufferBytesPtr(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT void* JSObjectGetArrayBufferBytesPtr(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
/*!
@function
@ -171,7 +171,7 @@ JS_EXPORT void* JSObjectGetArrayBufferBytesPtr(JSContextRef ctx, JSObjectRef obj
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result The number of bytes stored in the data object.
*/
JS_EXPORT size_t JSObjectGetArrayBufferByteLength(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT size_t JSObjectGetArrayBufferByteLength(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
#ifdef __cplusplus
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
* Copyright (C) 2013-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -132,6 +132,45 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
*/
+ (JSValue *)valueWithNewErrorFromMessage:(NSString *)message inContext:(JSContext *)context;
/*!
@method
@abstract Create a new promise object using the provided executor callback.
@param callback A callback block invoked while the promise object is being initialized. The resolve and reject parameters are functions that can be called to notify any pending reactions about the state of the new promise object.
@param context The JSContext to which the resulting JSValue belongs.
@result The JSValue representing a new promise JavaScript object.
@discussion This method is equivalent to calling the Promise constructor in JavaScript. the resolve and reject callbacks each normally take a single value, which they forward to all relevent pending reactions. While inside the executor callback context will act as if it were in any other callback, except calleeFunction will be <code>nil</code>. This also means means the new promise object may be accessed via <code>[context thisValue]</code>.
*/
+ (JSValue *)valueWithNewPromiseInContext:(JSContext *)context fromExecutor:(void (^)(JSValue *resolve, JSValue *reject))callback JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@method
@abstract Create a new resolved promise object with the provided value.
@param result The result value to be passed to any reactions.
@param context The JSContext to which the resulting JSValue belongs.
@result The JSValue representing a new promise JavaScript object.
@discussion This method is equivalent to calling <code>[JSValue valueWithNewPromiseFromExecutor:^(JSValue *resolve, JSValue *reject) { [resolve callWithArguments:@[result]]; } inContext:context]</code>
*/
+ (JSValue *)valueWithNewPromiseResolvedWithResult:(id)result inContext:(JSContext *)context JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@method
@abstract Create a new rejected promise object with the provided value.
@param reason The result value to be passed to any reactions.
@param context The JSContext to which the resulting JSValue belongs.
@result The JSValue representing a new promise JavaScript object.
@discussion This method is equivalent to calling <code>[JSValue valueWithNewPromiseFromExecutor:^(JSValue *resolve, JSValue *reject) { [reject callWithArguments:@[reason]]; } inContext:context]</code>
*/
+ (JSValue *)valueWithNewPromiseRejectedWithReason:(id)reason inContext:(JSContext *)context JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@method
@abstract Create a new, unique, symbol object.
@param description The description of the symbol object being created.
@param context The JSContext to which the resulting JSValue belongs.
@result The JSValue representing a unique JavaScript value with type symbol.
*/
+ (JSValue *)valueWithNewSymbolFromDescription:(NSString *)description inContext:(JSContext *)context JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@method
@abstract Create the JavaScript value <code>null</code>.
@ -302,63 +341,6 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
*/
- (NSDictionary *)toDictionary;
/*!
@methodgroup Accessing Properties
*/
/*!
@method
@abstract Access a property of a JSValue.
@result The JSValue for the requested property or the JSValue <code>undefined</code>
if the property does not exist.
*/
- (JSValue *)valueForProperty:(NSString *)property;
/*!
@method
@abstract Set a property on a JSValue.
*/
- (void)setValue:(id)value forProperty:(NSString *)property;
/*!
@method
@abstract Delete a property from a JSValue.
@result YES if deletion is successful, NO otherwise.
*/
- (BOOL)deleteProperty:(NSString *)property;
/*!
@method
@abstract Check if a JSValue has a property.
@discussion This method has the same function as the JavaScript operator <code>in</code>.
@result Returns YES if property is present on the value.
*/
- (BOOL)hasProperty:(NSString *)property;
/*!
@method
@abstract Define properties with custom descriptors on JSValues.
@discussion This method may be used to create a data or accessor property on an object.
This method operates in accordance with the Object.defineProperty method in the
JavaScript language.
*/
- (void)defineProperty:(NSString *)property descriptor:(id)descriptor;
/*!
@method
@abstract Access an indexed (numerical) property on a JSValue.
@result The JSValue for the property at the specified index.
Returns the JavaScript value <code>undefined</code> if no property exists at that index.
*/
- (JSValue *)valueAtIndex:(NSUInteger)index;
/*!
@method
@abstract Set an indexed (numerical) property on a JSValue.
@discussion For JSValues that are JavaScript arrays, indices greater than
UINT_MAX - 1 will not affect the length of the array.
*/
- (void)setValue:(id)value atIndex:(NSUInteger)index;
/*!
@functiongroup Checking JavaScript Types
*/
@ -406,13 +388,19 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
@property
@abstract Check if a JSValue is an array.
*/
@property (readonly) BOOL isArray NS_AVAILABLE(10_11, 9_0);
@property (readonly) BOOL isArray JSC_API_AVAILABLE(macos(10.11), ios(9.0));
/*!
@property
@abstract Check if a JSValue is a date.
*/
@property (readonly) BOOL isDate NS_AVAILABLE(10_11, 9_0);
@property (readonly) BOOL isDate JSC_API_AVAILABLE(macos(10.11), ios(9.0));
/*!
@property
@abstract Check if a JSValue is a symbol.
*/
@property (readonly) BOOL isSymbol JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@method
@ -555,6 +543,77 @@ Create a JSValue from a CGRect.
@end
/*!
@category
@discussion These methods enable querying properties on a JSValue.
*/
@interface JSValue (PropertyAccess)
#if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500) || (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000)
typedef NSString *JSValueProperty;
#else
typedef id JSValueProperty;
#endif
/*!
@method
@abstract Access a property of a JSValue.
@result The JSValue for the requested property or the JSValue <code>undefined</code>
if the property does not exist.
@discussion Corresponds to the JavaScript operation <code>object[property]</code>. Starting with macOS 10.15 and iOS 13, 'property' can be any 'id' and will be converted to a JSValue using the conversion rules of <code>valueWithObject:inContext:</code>. Prior to macOS 10.15 and iOS 13, 'property' was expected to be an NSString *.
*/
- (JSValue *)valueForProperty:(JSValueProperty)property;
/*!
@method
@abstract Set a property on a JSValue.
@discussion Corresponds to the JavaScript operation <code>object[property] = value</code>. Starting with macOS 10.15 and iOS 13, 'property' can be any 'id' and will be converted to a JSValue using the conversion rules of <code>valueWithObject:inContext:</code>. Prior to macOS 10.15 and iOS 13, 'property' was expected to be an NSString *.
*/
- (void)setValue:(id)value forProperty:(JSValueProperty)property;
/*!
@method
@abstract Delete a property from a JSValue.
@result YES if deletion is successful, NO otherwise.
@discussion Corresponds to the JavaScript operation <code>delete object[property]</code>. Starting with macOS 10.15 and iOS 13, 'property' can be any 'id' and will be converted to a JSValue using the conversion rules of <code>valueWithObject:inContext:</code>. Prior to macOS 10.15 and iOS 13, 'property' was expected to be an NSString *.
*/
- (BOOL)deleteProperty:(JSValueProperty)property;
/*!
@method
@abstract Check if a JSValue has a property.
@discussion This method has the same function as the JavaScript operator <code>in</code>.
@result Returns YES if property is present on the value.
@discussion Corresponds to the JavaScript operation <code>property in object</code>. Starting with macOS 10.15 and iOS 13, 'property' can be any 'id' and will be converted to a JSValue using the conversion rules of <code>valueWithObject:inContext:</code>. Prior to macOS 10.15 and iOS 13, 'property' was expected to be an NSString *.
*/
- (BOOL)hasProperty:(JSValueProperty)property;
/*!
@method
@abstract Define properties with custom descriptors on JSValues.
@discussion This method may be used to create a data or accessor property on an object.
This method operates in accordance with the Object.defineProperty method in the JavaScript language. Starting with macOS 10.15 and iOS 13, 'property' can be any 'id' and will be converted to a JSValue using the conversion rules of <code>valueWithObject:inContext:</code>. Prior to macOS 10.15 and iOS 13, 'property' was expected to be an NSString *.
*/
- (void)defineProperty:(JSValueProperty)property descriptor:(id)descriptor;
/*!
@method
@abstract Access an indexed (numerical) property on a JSValue.
@result The JSValue for the property at the specified index.
Returns the JavaScript value <code>undefined</code> if no property exists at that index.
*/
- (JSValue *)valueAtIndex:(NSUInteger)index;
/*!
@method
@abstract Set an indexed (numerical) property on a JSValue.
@discussion For JSValues that are JavaScript arrays, indices greater than
UINT_MAX - 1 will not affect the length of the array.
*/
- (void)setValue:(id)value atIndex:(NSUInteger)index;
@end
/*!
@category
@discussion Instances of JSValue implement the following methods in order to enable
@ -569,13 +628,16 @@ Create a JSValue from a CGRect.
@/textblock
An object key passed as a subscript will be converted to a JavaScript value,
and then the value converted to a string used as a property name.
and then the value using the same rules as <code>valueWithObject:inContext:</code>. In macOS
10.14 and iOS 12 and below, the <code>key</code> argument of
<code>setObject:object forKeyedSubscript:key</code> was restricted to an
<code>NSObject <NSCopying> *</code> but that restriction was never used internally.
*/
@interface JSValue (SubscriptSupport)
- (JSValue *)objectForKeyedSubscript:(id)key;
- (JSValue *)objectAtIndexedSubscript:(NSUInteger)index;
- (void)setObject:(id)object forKeyedSubscript:(NSObject <NSCopying> *)key;
- (void)setObject:(id)object forKeyedSubscript:(id)key;
- (void)setObject:(id)object atIndexedSubscript:(NSUInteger)index;
@end

View 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
@ -31,18 +31,21 @@
#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 "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/ObjCRuntimeExtras.h>
#import <wtf/Vector.h>
#import <wtf/text/WTFString.h>
#import <wtf/text/StringHash.h>
@ -66,6 +69,21 @@ 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;
@ -108,21 +126,16 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
+ (JSValue *)valueWithNewRegularExpressionFromPattern:(NSString *)pattern flags:(NSString *)flags inContext:(JSContext *)context
{
JSStringRef patternString = JSStringCreateWithCFString((CFStringRef)pattern);
JSStringRef flagsString = JSStringCreateWithCFString((CFStringRef)flags);
JSValueRef arguments[2] = { JSValueMakeString([context JSGlobalContextRef], patternString), JSValueMakeString([context JSGlobalContextRef], flagsString) };
JSStringRelease(patternString);
JSStringRelease(flagsString);
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([context JSGlobalContextRef], string);
JSStringRelease(string);
auto string = OpaqueJSString::tryCreate(message);
JSValueRef argument = JSValueMakeString([context JSGlobalContextRef], string.get());
return [JSValue valueWithJSValueRef:JSObjectMakeError([context JSGlobalContextRef], 1, &argument, 0) inContext:context];
}
@ -136,6 +149,54 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
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
{
return valueToObject(_context, m_value);
@ -219,72 +280,80 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
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([_context JSGlobalContextRef], 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([_context JSGlobalContextRef], object, name, &exception);
JSStringRelease(name);
if (exception)
return [_context valueFromNotifyException:exception];
return [JSValue valueWithJSValueRef:result inContext:_context];
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);
}
- (void)setValue:(id)value forProperty:(NSString *)propertyName
- (JSValue *)valueForProperty:(id)key
{
JSValueRef exception = 0;
JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception);
if (exception) {
[_context notifyException:exception];
return;
}
auto result = performPropertyOperation<JSValueRef>(JSObjectGetProperty, JSObjectGetPropertyForKey, self, key);
if (!result)
return [_context valueFromNotifyException:result.error()];
JSStringRef name = JSStringCreateWithCFString((CFStringRef)propertyName);
JSObjectSetProperty([_context JSGlobalContextRef], object, name, objectToValue(_context, value), 0, &exception);
JSStringRelease(name);
if (exception) {
[_context notifyException:exception];
return [JSValue valueWithJSValueRef:result.value() inContext:_context];
}
- (void)setValue:(id)value forProperty:(JSValueProperty)key
{
// 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 { };
};
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([_context JSGlobalContextRef], m_value, &exception);
if (exception)
return [_context boolFromNotifyException:exception];
JSStringRef name = JSStringCreateWithCFString((CFStringRef)propertyName);
BOOL result = JSObjectDeleteProperty([_context JSGlobalContextRef], 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([_context JSGlobalContextRef], 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([_context JSGlobalContextRef], 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
@ -357,6 +426,11 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
return JSValueIsObject([_context JSGlobalContextRef], m_value);
}
- (BOOL)isSymbol
{
return JSValueIsSymbol([_context JSGlobalContextRef], m_value);
}
- (BOOL)isArray
{
return JSValueIsArray([_context JSGlobalContextRef], m_value);
@ -446,9 +520,8 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
if (exception)
return [_context valueFromNotifyException:exception];
JSStringRef name = JSStringCreateWithCFString((CFStringRef)method);
JSValueRef function = JSObjectGetProperty([_context JSGlobalContextRef], 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];
@ -539,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
@ -553,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
@ -574,13 +635,13 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
inline bool isDate(JSC::VM& vm, JSObjectRef object, JSGlobalContextRef context)
{
JSC::JSLockHolder locker(toJS(context));
return toJS(object)->inherits(vm, JSC::DateInstance::info());
return toJS(object)->inherits<JSC::DateInstance>(vm);
}
inline bool isArray(JSC::VM& vm, JSObjectRef object, JSGlobalContextRef context)
{
JSC::JSLockHolder locker(toJS(context));
return toJS(object)->inherits(vm, JSC::JSArray::info());
return toJS(object)->inherits<JSC::JSArray>(vm);
}
@implementation JSValue(Internal)
@ -611,14 +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;
@ -649,8 +710,9 @@ JSContainerConvertor::Task JSContainerConvertor::take()
static void reportExceptionToInspector(JSGlobalContextRef context, JSC::JSValue exceptionValue)
{
JSC::ExecState* exec = toJS(context);
JSC::Exception* exception = JSC::Exception::create(exec->vm(), exceptionValue);
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception);
JSC::VM& vm = exec->vm();
JSC::Exception* exception = JSC::Exception::create(vm, exceptionValue);
vm.vmEntryGlobalObject(exec)->inspectorController().reportAPIException(exec, exception);
}
#endif
@ -670,31 +732,29 @@ 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(vm, object, context))
return (JSContainerConvertor::Task){ object, [NSDate dateWithTimeIntervalSince1970:JSValueToNumber(context, object, 0) / 1000.0], ContainerNone };
return { object, [NSDate dateWithTimeIntervalSince1970:JSValueToNumber(context, object, 0) / 1000.0], ContainerNone };
if (isArray(vm, object, context))
return (JSContainerConvertor::Task){ object, [NSMutableArray array], ContainerArray };
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)
@ -714,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));
@ -734,7 +793,7 @@ static id containerValueToObject(JSGlobalContextRef context, JSContainerConverto
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);
@ -776,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;
}
RetainPtr<CFStringRef> stringCF = adoptCF(JSStringCopyCFString(kCFAllocatorDefault, jsstring));
JSStringRelease(jsstring);
return (NSString *)stringCF.autorelease();
return CFBridgingRelease(JSStringCopyCFString(kCFAllocatorDefault, jsstring.get()));
}
id valueToDate(JSGlobalContextRef context, JSValueRef value, JSValueRef* exception)
@ -808,11 +865,11 @@ id valueToArray(JSGlobalContextRef context, JSValueRef value, JSValueRef* except
}
if (JSValueIsObject(context, value))
return containerValueToObject(context, (JSContainerConvertor::Task){ value, [NSMutableArray array], ContainerArray});
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), ASCIILiteral("Cannot convert primitive to NSArray"));
JSC::JSObject* exceptionObject = JSC::createTypeError(toJS(context), "Cannot convert primitive to NSArray"_s);
*exception = toRef(exceptionObject);
#if ENABLE(REMOTE_INSPECTOR)
reportExceptionToInspector(context, exceptionObject);
@ -830,11 +887,11 @@ id valueToDictionary(JSGlobalContextRef context, JSValueRef value, JSValueRef* e
}
if (JSValueIsObject(context, value))
return containerValueToObject(context, (JSContainerConvertor::Task){ value, [NSMutableDictionary dictionary], ContainerDictionary});
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), ASCIILiteral("Cannot convert primitive to NSDictionary"));
JSC::JSObject* exceptionObject = JSC::createTypeError(toJS(context), "Cannot convert primitive to NSDictionary"_s);
*exception = toRef(exceptionObject);
#if ENABLE(REMOTE_INSPECTOR)
reportExceptionToInspector(context, exceptionObject);
@ -863,7 +920,7 @@ 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;
};
@ -911,49 +968,47 @@ static ObjcContainerConvertor::Task objectToValueWithoutCopy(JSContext *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] * 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 (ObjcContainerConvertor::Task) { object, JSValueMakeUndefined(contextRef), ContainerNone };
return (ObjcContainerConvertor::Task){ object, value->m_value, ContainerNone };
return { object, JSValueMakeUndefined(contextRef), ContainerNone };
return { object, value->m_value, ContainerNone };
}
}
return (ObjcContainerConvertor::Task){ object, valueInternalValue([context wrapperForObjCObject:object]), ContainerNone };
return { object, valueInternalValue([context wrapperForObjCObject:object]), ContainerNone };
}
JSValueRef objectToValue(JSContext *context, id object)
@ -986,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;
@ -1054,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);
{
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.
@ -1081,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;
@ -1117,7 +1168,7 @@ static StructHandlers* createStructHandlerMap()
static StructTagHandler* handerForStructTag(const char* encodedType)
{
static StaticLock handerForStructTagLock;
static Lock handerForStructTagLock;
LockHolder lockHolder(&handerForStructTagLock);
static StructHandlers* structHandlers = createStructHandlerMap();
@ -1140,21 +1191,6 @@ static StructTagHandler* handerForStructTag(const char* encodedType)
return handler ? handler->valueToTypeSEL : nil;
}
- (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];
}
NSInvocation *typeToValueInvocationFor(const char* encodedType)
{
SEL selector = [JSValue selectorForStructToValue:encodedType];

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
* Copyright (C) 2013-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -26,8 +26,7 @@
#ifndef JSValueInternal_h
#define JSValueInternal_h
#import <JavaScriptCore/JavaScriptCore.h>
#import <JavaScriptCore/JSValue.h>
#import <JavaScriptCore/JSValuePrivate.h>
#if JSC_OBJC_API_ENABLED

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2018-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -23,20 +23,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JavaScriptCore_h
#define JavaScriptCore_h
#if JSC_OBJC_API_ENABLED
#include <JavaScriptCore/JavaScript.h>
#include <JavaScriptCore/JSStringRefCF.h>
#import <JavaScriptCore/JavaScriptCore.h>
#if defined(__OBJC__) && JSC_OBJC_API_ENABLED
@interface JSValue(JSPrivate)
#import "JSContext.h"
#import "JSValue.h"
#import "JSManagedValue.h"
#import "JSVirtualMachine.h"
#import "JSExport.h"
// Currently empty. May be used again in the future.
#endif
@end
#endif /* JavaScriptCore_h */
#endif // JSC_OBJC_API_ENABLED

View File

@ -36,6 +36,7 @@
#include "JSCallbackObject.h"
#include "JSGlobalObject.h"
#include "JSONObject.h"
#include "JSObjectRefPrivate.h"
#include "JSString.h"
#include "LiteralParser.h"
#include "Protect.h"
@ -54,17 +55,6 @@
using namespace JSC;
#if PLATFORM(MAC)
static bool evernoteHackNeeded()
{
static const int32_t webkitLastVersionWithEvernoteHack = 35133959;
static bool hackNeeded = CFEqual(CFBundleGetIdentifier(CFBundleGetMainBundle()), CFSTR("com.evernote.Evernote"))
&& NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitLastVersionWithEvernoteHack;
return hackNeeded;
}
#endif
::JSType JSValueGetType(JSContextRef ctx, JSValueRef value)
{
if (!ctx) {
@ -86,6 +76,8 @@ static bool evernoteHackNeeded()
return kJSTypeNumber;
if (jsValue.isString())
return kJSTypeString;
if (jsValue.isSymbol())
return kJSTypeSymbol;
ASSERT(jsValue.isObject());
return kJSTypeObject;
}
@ -162,6 +154,18 @@ bool JSValueIsObject(JSContextRef ctx, JSValueRef value)
return toJS(exec, value).isObject();
}
bool JSValueIsSymbol(JSContextRef ctx, JSValueRef value)
{
if (!ctx) {
ASSERT_NOT_REACHED();
return false;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
return toJS(exec, value).isSymbol();
}
bool JSValueIsArray(JSContextRef ctx, JSValueRef value)
{
if (!ctx) {
@ -172,7 +176,7 @@ bool JSValueIsArray(JSContextRef ctx, JSValueRef value)
VM& vm = exec->vm();
JSLockHolder locker(exec);
return toJS(exec, value).inherits(vm, JSArray::info());
return toJS(exec, value).inherits<JSArray>(vm);
}
bool JSValueIsDate(JSContextRef ctx, JSValueRef value)
@ -185,7 +189,7 @@ bool JSValueIsDate(JSContextRef ctx, JSValueRef value)
VM& vm = exec->vm();
JSLockHolder locker(exec);
return toJS(exec, value).inherits(vm, DateInstance::info());
return toJS(exec, value).inherits<DateInstance>(vm);
}
bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass)
@ -201,15 +205,15 @@ bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsCla
JSValue jsValue = toJS(exec, value);
if (JSObject* o = jsValue.getObject()) {
if (o->inherits(vm, JSProxy::info()))
if (o->inherits<JSProxy>(vm))
o = jsCast<JSProxy*>(o)->target();
if (o->inherits(vm, JSCallbackObject<JSGlobalObject>::info()))
if (o->inherits<JSCallbackObject<JSGlobalObject>>(vm))
return jsCast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass);
if (o->inherits(vm, JSCallbackObject<JSDestructibleObject>::info()))
if (o->inherits<JSCallbackObject<JSDestructibleObject>>(vm))
return jsCast<JSCallbackObject<JSDestructibleObject>*>(o)->inherits(jsClass);
#if JSC_OBJC_API_ENABLED
if (o->inherits(vm, JSCallbackObject<JSAPIWrapperObject>::info()))
if (o->inherits<JSCallbackObject<JSAPIWrapperObject>>(vm))
return jsCast<JSCallbackObject<JSAPIWrapperObject>*>(o)->inherits(jsClass);
#endif
}
@ -223,13 +227,15 @@ bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* ex
return false;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSValue jsA = toJS(exec, a);
JSValue jsB = toJS(exec, b);
bool result = JSValue::equal(exec, jsA, jsB); // false if an exception is thrown
handleExceptionIfNeeded(exec, exception);
handleExceptionIfNeeded(scope, exec, exception);
return result;
}
@ -256,15 +262,17 @@ bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObject
return false;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSValue jsValue = toJS(exec, value);
JSObject* jsConstructor = toJS(constructor);
if (!jsConstructor->structure()->typeInfo().implementsHasInstance())
if (!jsConstructor->structure(vm)->typeInfo().implementsHasInstance())
return false;
bool result = jsConstructor->hasInstance(exec, jsValue); // false if an exception is thrown
handleExceptionIfNeeded(exec, exception);
handleExceptionIfNeeded(scope, exec, exception);
return result;
}
@ -316,6 +324,21 @@ JSValueRef JSValueMakeNumber(JSContextRef ctx, double value)
return toRef(exec, jsNumber(purifyNaN(value)));
}
JSValueRef JSValueMakeSymbol(JSContextRef ctx, JSStringRef description)
{
if (!ctx) {
ASSERT_NOT_REACHED();
return nullptr;
}
ExecState* exec = toJS(ctx);
VM& vm = exec->vm();
JSLockHolder locker(exec);
if (!description)
return toRef(exec, Symbol::create(vm));
return toRef(exec, Symbol::createWithDescription(vm, description->string()));
}
JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string)
{
if (!ctx) {
@ -353,14 +376,17 @@ JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef apiValue, unsig
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSValue value = toJS(exec, apiValue);
String result = JSONStringify(exec, value, indent);
if (exception)
*exception = 0;
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
return 0;
return OpaqueJSString::create(result).leakRef();
return OpaqueJSString::tryCreate(result).leakRef();
}
bool JSValueToBoolean(JSContextRef ctx, JSValueRef value)
@ -383,12 +409,14 @@ double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception
return PNaN;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSValue jsValue = toJS(exec, value);
double number = jsValue.toNumber(exec);
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
number = PNaN;
return number;
}
@ -400,12 +428,14 @@ JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef*
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSValue jsValue = toJS(exec, value);
auto stringRef(OpaqueJSString::create(jsValue.toWTFString(exec)));
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
auto stringRef(OpaqueJSString::tryCreate(jsValue.toWTFString(exec)));
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
stringRef = nullptr;
return stringRef.leakRef();
}
@ -417,12 +447,14 @@ JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exce
return 0;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSValue jsValue = toJS(exec, value);
JSObjectRef objectRef = toRef(jsValue.toObject(exec));
if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
objectRef = 0;
return objectRef;
}
@ -442,11 +474,6 @@ void JSValueProtect(JSContextRef ctx, JSValueRef value)
void JSValueUnprotect(JSContextRef ctx, JSValueRef value)
{
#if PLATFORM(MAC)
if ((!value || !ctx) && evernoteHackNeeded())
return;
#endif
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006 Apple Inc. All rights reserved.
* Copyright (C) 2006-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -42,6 +42,7 @@
@constant kJSTypeNumber A primitive number value.
@constant kJSTypeString A primitive string value.
@constant kJSTypeObject An object value (meaning that this JSValueRef is a JSObjectRef).
@constant kJSTypeSymbol A primitive symbol value.
*/
typedef enum {
kJSTypeUndefined,
@ -49,7 +50,8 @@ typedef enum {
kJSTypeBoolean,
kJSTypeNumber,
kJSTypeString,
kJSTypeObject
kJSTypeObject,
kJSTypeSymbol JSC_API_AVAILABLE(macos(10.15), ios(13.0))
} JSType;
/*!
@ -80,7 +82,7 @@ typedef enum {
kJSTypedArrayTypeFloat64Array,
kJSTypedArrayTypeArrayBuffer,
kJSTypedArrayTypeNone,
} JSTypedArrayType CF_ENUM_AVAILABLE(10_12, 10_0);
} JSTypedArrayType JSC_API_AVAILABLE(macos(10.12), ios(10.0));
#ifdef __cplusplus
extern "C" {
@ -140,6 +142,15 @@ JS_EXPORT bool JSValueIsNumber(JSContextRef ctx, JSValueRef value);
*/
JS_EXPORT bool JSValueIsString(JSContextRef ctx, JSValueRef value);
/*!
@function
@abstract Tests whether a JavaScript value's type is the symbol type.
@param ctx The execution context to use.
@param value The JSValue to test.
@result true if value's type is the symbol type, otherwise false.
*/
JS_EXPORT bool JSValueIsSymbol(JSContextRef ctx, JSValueRef value) JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/*!
@function
@abstract Tests whether a JavaScript value's type is the object type.
@ -149,6 +160,7 @@ JS_EXPORT bool JSValueIsString(JSContextRef ctx, JSValueRef value);
*/
JS_EXPORT bool JSValueIsObject(JSContextRef ctx, JSValueRef value);
/*!
@function
@abstract Tests whether a JavaScript value is an object with a given class in its class chain.
@ -166,7 +178,7 @@ JS_EXPORT bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClas
@param value The JSValue to test.
@result true if value is an array, otherwise false.
*/
JS_EXPORT bool JSValueIsArray(JSContextRef ctx, JSValueRef value) CF_AVAILABLE(10_11, 9_0);
JS_EXPORT bool JSValueIsArray(JSContextRef ctx, JSValueRef value) JSC_API_AVAILABLE(macos(10.11), ios(9.0));
/*!
@function
@ -175,7 +187,7 @@ JS_EXPORT bool JSValueIsArray(JSContextRef ctx, JSValueRef value) CF_AVAILABLE(1
@param value The JSValue to test.
@result true if value is a date, otherwise false.
*/
JS_EXPORT bool JSValueIsDate(JSContextRef ctx, JSValueRef value) CF_AVAILABLE(10_11, 9_0);
JS_EXPORT bool JSValueIsDate(JSContextRef ctx, JSValueRef value) JSC_API_AVAILABLE(macos(10.11), ios(9.0));
/*!
@function
@ -185,7 +197,7 @@ JS_EXPORT bool JSValueIsDate(JSContextRef ctx, JSValueRef value) CF_AVAILABLE(10
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result A value of type JSTypedArrayType that identifies value's Typed Array type, or kJSTypedArrayTypeNone if the value is not a Typed Array object.
*/
JS_EXPORT JSTypedArrayType JSValueGetTypedArrayType(JSContextRef ctx, JSValueRef value, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
JS_EXPORT JSTypedArrayType JSValueGetTypedArrayType(JSContextRef ctx, JSValueRef value, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0));
/* Comparing values */
@ -267,6 +279,15 @@ JS_EXPORT JSValueRef JSValueMakeNumber(JSContextRef ctx, double number);
*/
JS_EXPORT JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string);
/*!
@function
@abstract Creates a JavaScript value of the symbol type.
@param ctx The execution context to use.
@param description A description of the newly created symbol value.
@result A unique JSValue of the symbol type, whose description matches the one provided.
*/
JS_EXPORT JSValueRef JSValueMakeSymbol(JSContextRef ctx, JSStringRef description) JSC_API_AVAILABLE(macos(10.15), ios(13.0));
/* Converting to and from JSON formatted strings */
/*!
@ -276,7 +297,7 @@ JS_EXPORT JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string);
@param string The JSString containing the JSON string to be parsed.
@result A JSValue containing the parsed value, or NULL if the input is invalid.
*/
JS_EXPORT JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) CF_AVAILABLE(10_7, 7_0);
JS_EXPORT JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) JSC_API_AVAILABLE(macos(10.7), ios(7.0));
/*!
@function
@ -287,7 +308,7 @@ JS_EXPORT JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef str
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
@result A JSString with the result of serialization, or NULL if an exception is thrown.
*/
JS_EXPORT JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef value, unsigned indent, JSValueRef* exception) CF_AVAILABLE(10_7, 7_0);
JS_EXPORT JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef value, unsigned indent, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.7), ios(7.0));
/* Converting to primitive values */

View File

@ -33,6 +33,11 @@
or set of execution resources. Thread safety is supported by locking the
virtual machine, with concurrent JavaScript execution supported by allocating
separate instances of JSVirtualMachine.
A virtual machine may need to run deferred tasks on a run loop, such as garbage collection
or resolving WebAssembly compilations. By default, a virtual machine will use the run loop
of the thread it was initialized on. Currently, there is no API to change a
JSVirtualMachine's run loop once it has been initialized.
*/
NS_CLASS_AVAILABLE(10_9, 7_0)
@interface JSVirtualMachine : NSObject

View File

@ -30,19 +30,20 @@
#if JSC_OBJC_API_ENABLED
#import "APICast.h"
#import "DFGWorklist.h"
#import "JSManagedValueInternal.h"
#import "JSVirtualMachine.h"
#import "JSVirtualMachineInternal.h"
#import "JSVirtualMachinePrivate.h"
#import "JSWrapperMap.h"
#import "SigillCrashAnalyzer.h"
#import "SlotVisitorInlines.h"
#import <mutex>
#import <wtf/BlockPtr.h>
#import <wtf/Lock.h>
#import <wtf/spi/cocoa/NSMapTableSPI.h>
static NSMapTable *globalWrapperCache = 0;
static StaticLock wrapperCacheMutex;
static Lock wrapperCacheMutex;
static void initWrapperCache()
{
@ -68,14 +69,14 @@ static NSMapTable *wrapperCache()
+ (void)addWrapper:(JSVirtualMachine *)wrapper forJSContextGroupRef:(JSContextGroupRef)group
{
std::lock_guard<StaticLock> lock(wrapperCacheMutex);
NSMapInsert(wrapperCache(), group, wrapper);
std::lock_guard<Lock> lock(wrapperCacheMutex);
NSMapInsert(wrapperCache(), group, (__bridge void*)wrapper);
}
+ (JSVirtualMachine *)wrapperForJSContextGroupRef:(JSContextGroupRef)group
{
std::lock_guard<StaticLock> lock(wrapperCacheMutex);
return static_cast<JSVirtualMachine *>(NSMapGet(wrapperCache(), group));
std::lock_guard<Lock> lock(wrapperCacheMutex);
return (__bridge JSVirtualMachine *)NSMapGet(wrapperCache(), group);
}
@end
@ -153,7 +154,7 @@ static id getInternalObjcObject(id object)
- (bool)isOldExternalObject:(id)object
{
JSC::VM* vm = toJS(m_group);
return vm->heap.collectorSlotVisitor().containsOpaqueRoot(object);
return vm->heap.collectorSlotVisitor().containsOpaqueRoot((__bridge void*)object);
}
- (void)addExternalRememberedObject:(id)object
@ -186,11 +187,10 @@ static id getInternalObjcObject(id object)
ownedObjects = [[NSMapTable alloc] initWithKeyOptions:weakIDOptions valueOptions:integerOptions capacity:1];
[m_externalObjectGraph setObject:ownedObjects forKey:owner];
[ownedObjects release];
}
size_t count = reinterpret_cast<size_t>(NSMapGet(ownedObjects, object));
NSMapInsert(ownedObjects, object, reinterpret_cast<void*>(count + 1));
size_t count = reinterpret_cast<size_t>(NSMapGet(ownedObjects, (__bridge void*)object));
NSMapInsert(ownedObjects, (__bridge void*)object, reinterpret_cast<void*>(count + 1));
}
- (void)removeManagedReference:(id)object withOwner:(id)owner
@ -211,14 +211,14 @@ static id getInternalObjcObject(id object)
if (!ownedObjects)
return;
size_t count = reinterpret_cast<size_t>(NSMapGet(ownedObjects, object));
size_t count = reinterpret_cast<size_t>(NSMapGet(ownedObjects, (__bridge void*)object));
if (count > 1) {
NSMapInsert(ownedObjects, object, reinterpret_cast<void*>(count - 1));
NSMapInsert(ownedObjects, (__bridge void*)object, reinterpret_cast<void*>(count - 1));
return;
}
if (count == 1)
NSMapRemove(ownedObjects, object);
NSMapRemove(ownedObjects, (__bridge void*)object);
if (![ownedObjects count]) {
[m_externalObjectGraph removeObjectForKey:owner];
@ -245,12 +245,12 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine)
- (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext
{
return static_cast<JSContext *>(NSMapGet(m_contextCache, globalContext));
return (__bridge JSContext *)NSMapGet(m_contextCache, globalContext);
}
- (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext
{
NSMapInsert(m_contextCache, globalContext, wrapper);
NSMapInsert(m_contextCache, globalContext, (__bridge void*)wrapper);
}
- (Lock&)externalDataMutex
@ -268,6 +268,50 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine)
return m_externalRememberedSet;
}
- (void)shrinkFootprintWhenIdle
{
JSC::VM* vm = toJS(m_group);
JSC::JSLockHolder locker(vm);
vm->shrinkFootprintWhenIdle();
}
#if ENABLE(DFG_JIT)
+ (NSUInteger)setNumberOfDFGCompilerThreads:(NSUInteger)numberOfThreads
{
JSC::DFG::Worklist* worklist = JSC::DFG::existingGlobalDFGWorklistOrNull();
if (worklist)
return worklist->setNumberOfThreads(numberOfThreads, JSC::Options::priorityDeltaOfDFGCompilerThreads());
else
return JSC::DFG::setNumberOfDFGCompilerThreads(numberOfThreads);
}
+ (NSUInteger)setNumberOfFTLCompilerThreads:(NSUInteger)numberOfThreads
{
JSC::DFG::Worklist* worklist = JSC::DFG::existingGlobalFTLWorklistOrNull();
if (worklist)
return worklist->setNumberOfThreads(numberOfThreads, JSC::Options::priorityDeltaOfFTLCompilerThreads());
else
return JSC::DFG::setNumberOfFTLCompilerThreads(numberOfThreads);
}
#endif // ENABLE(DFG_JIT)
- (JSC::VM&)vm
{
return *toJS(m_group);
}
- (BOOL)isWebThreadAware
{
return [self vm].apiLock().isWebThreadAware();
}
+ (void)setCrashOnVMCreation:(BOOL)shouldCrash
{
JSC::VM::setCrashOnVMCreation(shouldCrash);
}
@end
static void scanExternalObjectGraph(JSC::VM& vm, JSC::SlotVisitor& visitor, void* root, bool lockAcquired)
@ -283,14 +327,13 @@ static void scanExternalObjectGraph(JSC::VM& vm, JSC::SlotVisitor& visitor, void
while (!stack.isEmpty()) {
void* nextRoot = stack.last();
stack.removeLast();
if (visitor.containsOpaqueRootTriState(nextRoot) == TrueTriState)
if (!visitor.addOpaqueRoot(nextRoot))
continue;
visitor.addOpaqueRoot(nextRoot);
auto appendOwnedObjects = [&] {
NSMapTable *ownedObjects = [externalObjectGraph objectForKey:static_cast<id>(nextRoot)];
NSMapTable *ownedObjects = [externalObjectGraph objectForKey:(__bridge id)nextRoot];
for (id ownedObject in ownedObjects)
stack.append(static_cast<void*>(ownedObject));
stack.append((__bridge void*)ownedObject);
};
if (lockAcquired)
@ -323,12 +366,10 @@ void scanExternalRememberedSet(JSC::VM& vm, JSC::SlotVisitor& visitor)
NSMapTable *ownedObjects = [externalObjectGraph objectForKey:key];
bool lockAcquired = true;
for (id ownedObject in ownedObjects)
scanExternalObjectGraph(vm, visitor, ownedObject, lockAcquired);
scanExternalObjectGraph(vm, visitor, (__bridge void*)ownedObject, lockAcquired);
}
[externalRememberedSet removeAllObjects];
}
visitor.mergeIfNecessary();
}
#endif // JSC_OBJC_API_ENABLED

View File

@ -46,8 +46,12 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *);
- (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext;
- (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext;
- (JSC::VM&)vm;
- (BOOL)isWebThreadAware;
@end
#endif // defined(__OBJC__)
void scanExternalObjectGraph(JSC::VM&, JSC::SlotVisitor&, void* root);

View File

@ -0,0 +1,87 @@
/*
* Copyright (C) 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
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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 "JSExportMacros.h"
#include <JavaScriptCore/JavaScript.h>
#if JSC_OBJC_API_ENABLED
#import <JavaScriptCore/JSVirtualMachine.h>
@interface JSVirtualMachine(JSPrivate)
/*!
@method
@discussion Shrinks the memory footprint of the VM by deleting various internal caches,
running synchronous garbage collection, and releasing memory back to the OS. Note: this
API waits until no JavaScript is running on the stack before it frees any memory. It's
best to call this API when no JavaScript is running on the stack for this reason. However, if
you do call this API when JavaScript is running on the stack, the API will wait until all JavaScript
on the stack finishes running to free memory back to the OS. Therefore, calling this
API may not synchronously free memory.
*/
- (void)shrinkFootprintWhenIdle JSC_API_AVAILABLE(macos(10.14), ios(12.0));
#if ENABLE(DFG_JIT)
/*!
@method
@abstract Set the number of threads to be used by the DFG JIT compiler.
@discussion If called after the VM has been initialized, it will terminate
threads until it meets the new limit or create new threads accordingly if the
new limit is higher than the previous limit. If called before initialization,
the Options value for the number of DFG threads will be updated to ensure the
DFG compiler already starts with the up-to-date limit.
@param numberOfThreads The number of threads the DFG compiler should use going forward
@result The previous number of threads being used by the DFG compiler
*/
+ (NSUInteger)setNumberOfDFGCompilerThreads:(NSUInteger)numberOfThreads JSC_API_AVAILABLE(macos(10.14), ios(12.0));
/*!
@method
@abstract Set the number of threads to be used by the FTL JIT compiler.
@discussion If called after the VM has been initialized, it will terminate
threads until it meets the new limit or create new threads accordingly if the
new limit is higher than the previous limit. If called before initialization,
the Options value for the number of FTL threads will be updated to ensure the
FTL compiler already starts with the up-to-date limit.
@param numberOfThreads The number of threads the FTL compiler should use going forward
@result The previous number of threads being used by the FTL compiler
*/
+ (NSUInteger)setNumberOfFTLCompilerThreads:(NSUInteger)numberOfThreads JSC_API_AVAILABLE(macos(10.14), ios(12.0));
/*!
@method
@abstract Allows embedders of JSC to specify that JSC should crash the process if a VM is created when unexpected.
@param shouldCrash Sets process-wide state that indicates whether VM creation should crash or not.
*/
+ (void)setCrashOnVMCreation:(BOOL)shouldCrash;
#endif // ENABLE(DFG_JIT)
@end
#endif // JSC_OBJC_API_ENABLED

View File

@ -34,7 +34,6 @@
#include "Weak.h"
#include "WeakGCMapInlines.h"
using namespace WTF;
using namespace JSC;
#ifdef __cplusplus
@ -44,10 +43,11 @@ extern "C" {
JSWeakObjectMapRef JSWeakObjectMapCreate(JSContextRef context, void* privateData, JSWeakMapDestroyedCallback callback)
{
ExecState* exec = toJS(context);
JSLockHolder locker(exec);
RefPtr<OpaqueJSWeakObjectMap> map = OpaqueJSWeakObjectMap::create(exec->vm(), privateData, callback);
exec->lexicalGlobalObject()->registerWeakMap(map.get());
return map.get();
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto map = OpaqueJSWeakObjectMap::create(vm, privateData, callback);
exec->lexicalGlobalObject()->registerWeakMap(map.ptr());
return map.ptr();
}
void JSWeakObjectMapSet(JSContextRef ctx, JSWeakObjectMapRef map, void* key, JSObjectRef object)
@ -57,13 +57,14 @@ void JSWeakObjectMapSet(JSContextRef ctx, JSWeakObjectMapRef map, void* key, JSO
return;
}
ExecState* exec = toJS(ctx);
JSLockHolder locker(exec);
VM& vm = exec->vm();
JSLockHolder locker(vm);
JSObject* obj = toJS(object);
if (!obj)
return;
ASSERT(obj->inherits(exec->vm(), JSProxy::info())
|| obj->inherits(exec->vm(), JSCallbackObject<JSGlobalObject>::info())
|| obj->inherits(exec->vm(), JSCallbackObject<JSDestructibleObject>::info()));
ASSERT(obj->inherits<JSProxy>(vm)
|| obj->inherits<JSCallbackObject<JSGlobalObject>>(vm)
|| obj->inherits<JSCallbackObject<JSDestructibleObject>>(vm));
map->map().set(key, obj);
}

100
API/JSWeakValue.cpp Normal file
View File

@ -0,0 +1,100 @@
/*
* Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2018 Igalia S.L.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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 "config.h"
#include "JSWeakValue.h"
#include "JSCInlines.h"
#include "WeakHandleOwner.h"
namespace JSC {
JSWeakValue::~JSWeakValue()
{
clear();
}
void JSWeakValue::clear()
{
switch (m_tag) {
case WeakTypeTag::NotSet:
return;
case WeakTypeTag::Primitive:
m_value.primitive = JSValue();
return;
case WeakTypeTag::Object:
m_value.object.clear();
return;
case WeakTypeTag::String:
m_value.string.clear();
return;
}
RELEASE_ASSERT_NOT_REACHED();
}
bool JSWeakValue::isClear() const
{
switch (m_tag) {
case WeakTypeTag::NotSet:
return true;
case WeakTypeTag::Primitive:
return !m_value.primitive;
case WeakTypeTag::Object:
return !m_value.object;
case WeakTypeTag::String:
return !m_value.string;
}
RELEASE_ASSERT_NOT_REACHED();
}
void JSWeakValue::setPrimitive(JSValue primitive)
{
ASSERT(!isSet());
ASSERT(!m_value.primitive);
ASSERT(primitive.isPrimitive());
m_tag = WeakTypeTag::Primitive;
m_value.primitive = primitive;
}
void JSWeakValue::setObject(JSObject* object, WeakHandleOwner& owner, void* context)
{
ASSERT(!isSet());
ASSERT(!m_value.object);
m_tag = WeakTypeTag::Object;
Weak<JSObject> weak(object, &owner, context);
m_value.object.swap(weak);
}
void JSWeakValue::setString(JSString* string, WeakHandleOwner& owner, void* context)
{
ASSERT(!isSet());
ASSERT(!m_value.string);
m_tag = WeakTypeTag::String;
Weak<JSString> weak(string, &owner, context);
m_value.string.swap(weak);
}
} // namespace JSC

95
API/JSWeakValue.h Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2018 Igalia S.L.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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.
*/
#pragma once
#include "JSCJSValue.h"
#include "Weak.h"
namespace JSC {
class JSObject;
class JSString;
class WeakHandleOwner;
class JSWeakValue {
public:
JSWeakValue() = default;
~JSWeakValue();
void clear();
bool isClear() const;
bool isSet() const { return m_tag != WeakTypeTag::NotSet; }
bool isPrimitive() const { return m_tag == WeakTypeTag::Primitive; }
bool isObject() const { return m_tag == WeakTypeTag::Object; }
bool isString() const { return m_tag == WeakTypeTag::String; }
void setPrimitive(JSValue);
void setObject(JSObject*, WeakHandleOwner&, void* context);
void setString(JSString*, WeakHandleOwner&, void* context);
JSObject* object() const
{
ASSERT(isObject());
return m_value.object.get();
}
JSValue primitive() const
{
ASSERT(isPrimitive());
return m_value.primitive;
}
JSString* string() const
{
ASSERT(isString());
return m_value.string.get();
}
private:
enum class WeakTypeTag { NotSet, Primitive, Object, String };
WeakTypeTag m_tag { WeakTypeTag::NotSet };
union WeakValueUnion {
WeakValueUnion()
: primitive(JSValue())
{
}
~WeakValueUnion()
{
ASSERT(!primitive);
}
JSValue primitive;
Weak<JSObject> object;
Weak<JSString> string;
} m_value;
};
} // namespace JSC

View File

@ -28,6 +28,7 @@
#if JSC_OBJC_API_ENABLED
#import "APICast.h"
#import "APIUtils.h"
#import "JSAPIWrapperObject.h"
#import "JSCInlines.h"
#import "JSCallbackObject.h"
@ -39,7 +40,6 @@
#import "WeakGCMap.h"
#import "WeakGCMapInlines.h"
#import <wtf/Vector.h>
#import <wtf/spi/cocoa/NSMapTableSPI.h>
#import <wtf/spi/darwin/dyldSPI.h>
#include <mach-o/dyld.h>
@ -47,7 +47,7 @@
#if PLATFORM(APPLETV)
#else
static const int32_t firstJavaScriptCoreVersionWithInitConstructorSupport = 0x21A0400; // 538.4.0
#if PLATFORM(IOS)
#if PLATFORM(IOS_FAMILY)
static const uint32_t firstSDKVersionWithInitConstructorSupport = DYLD_IOS_VERSION_10_0;
#elif PLATFORM(MAC)
static const uint32_t firstSDKVersionWithInitConstructorSupport = 0xA0A00; // OSX 10.10.0
@ -62,6 +62,8 @@ static const uint32_t firstSDKVersionWithInitConstructorSupport = 0xA0A00; // OS
@end
static const constexpr unsigned InitialBufferSize { 256 };
// Default conversion of selectors to property names.
// All semicolons are removed, lowercase letters following a semicolon are capitalized.
static NSString *selectorToPropertyName(const char* start)
@ -75,10 +77,10 @@ static NSString *selectorToPropertyName(const char* start)
size_t header = firstColon - start;
// The new string needs to be long enough to hold 'header', plus the remainder of the string, excluding
// at least one ':', but including a '\0'. (This is conservative if there are more than one ':').
char* buffer = static_cast<char*>(malloc(header + strlen(firstColon + 1) + 1));
Vector<char, InitialBufferSize> buffer(header + strlen(firstColon + 1) + 1);
// Copy 'header' characters, set output to point to the end of this & input to point past the first ':'.
memcpy(buffer, start, header);
char* output = buffer + header;
memcpy(buffer.data(), start, header);
char* output = buffer.data() + header;
const char* input = start + header + 1;
// On entry to the loop, we have already skipped over a ':' from the input.
@ -89,7 +91,7 @@ static NSString *selectorToPropertyName(const char* start)
while ((c = *(input++)) == ':');
// Copy the character, converting to upper case if necessary.
// If the character we copy is '\0', then we're done!
if (!(*(output++) = toupper(c)))
if (!(*(output++) = toASCIIUpper(c)))
goto done;
// Loop over characters other than ':'.
while ((c = *(input++)) != ':') {
@ -101,31 +103,31 @@ static NSString *selectorToPropertyName(const char* start)
// If we get here, we've consumed a ':' - wash, rinse, repeat.
}
done:
NSString *result = [NSString stringWithUTF8String:buffer];
free(buffer);
return result;
return [NSString stringWithUTF8String:buffer.data()];
}
static bool constructorHasInstance(JSContextRef ctx, JSObjectRef constructorRef, JSValueRef possibleInstance, JSValueRef*)
{
JSC::ExecState* exec = toJS(ctx);
JSC::JSLockHolder locker(exec);
JSC::VM& vm = exec->vm();
JSC::JSLockHolder locker(vm);
JSC::JSObject* constructor = toJS(constructorRef);
JSC::JSValue instance = toJS(exec, possibleInstance);
return JSC::JSObject::defaultHasInstance(exec, instance, constructor->get(exec, exec->propertyNames().prototype));
return JSC::JSObject::defaultHasInstance(exec, instance, constructor->get(exec, vm.propertyNames->prototype));
}
static JSC::JSObject* makeWrapper(JSContextRef ctx, JSClassRef jsClass, id wrappedObject)
{
JSC::ExecState* exec = toJS(ctx);
JSC::JSLockHolder locker(exec);
JSC::VM& vm = exec->vm();
JSC::JSLockHolder locker(vm);
ASSERT(jsClass);
JSC::JSCallbackObject<JSC::JSAPIWrapperObject>* object = JSC::JSCallbackObject<JSC::JSAPIWrapperObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->objcWrapperObjectStructure(), jsClass, 0);
object->setWrappedObject(wrappedObject);
object->setWrappedObject((__bridge void*)wrappedObject);
if (JSC::JSObject* prototype = jsClass->prototype(exec))
object->setPrototypeDirect(exec->vm(), prototype);
object->setPrototypeDirect(vm, prototype);
return object;
}
@ -177,14 +179,31 @@ static NSMutableDictionary *createRenameMap(Protocol *protocol, BOOL isInstanceM
return renameMap;
}
inline void putNonEnumerable(JSValue *base, NSString *propertyName, JSValue *value)
inline void putNonEnumerable(JSContext *context, JSValue *base, NSString *propertyName, JSValue *value)
{
[base defineProperty:propertyName descriptor:@{
JSPropertyDescriptorValueKey: value,
JSPropertyDescriptorWritableKey: @YES,
JSPropertyDescriptorEnumerableKey: @NO,
JSPropertyDescriptorConfigurableKey: @YES
}];
if (![base isObject])
return;
JSC::ExecState* exec = toJS([context JSGlobalContextRef]);
JSC::VM& vm = exec->vm();
JSC::JSLockHolder locker(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);
JSC::JSObject* baseObject = JSC::asObject(toJS(exec, [base JSValueRef]));
auto name = OpaqueJSString::tryCreate(propertyName);
if (!name)
return;
JSC::PropertyDescriptor descriptor;
descriptor.setValue(toJS(exec, [value JSValueRef]));
descriptor.setEnumerable(false);
descriptor.setConfigurable(true);
descriptor.setWritable(true);
bool shouldThrow = false;
baseObject->methodTable(vm)->defineOwnProperty(baseObject, exec, name->identifier(&vm), descriptor, shouldThrow);
JSValueRef exception = 0;
if (handleExceptionIfNeeded(scope, exec, &exception) == ExceptionStatus::DidThrow)
[context valueFromNotifyException:exception];
}
static bool isInitFamilyMethod(NSString *name)
@ -249,30 +268,45 @@ static void copyMethodsToObject(JSContext *context, Class objcClass, Protocol *p
name = renameMap[name];
if (!name)
name = selectorToPropertyName(nameCStr);
if ([object hasProperty:name])
auto exec = toJS([context JSGlobalContextRef]);
JSValue *existingMethod = object[name];
// ObjCCallbackFunction does a dynamic lookup for the
// selector before calling the method. In order to save
// memory we only put one callback object in any givin
// prototype chain. However, to handle the client trying
// to override normal builtins e.g. "toString" we check if
// the existing value on the prototype chain is an ObjC
// callback already.
if ([existingMethod isObject] && JSC::jsDynamicCast<JSC::ObjCCallbackFunction*>(exec->vm(), toJS(exec, [existingMethod JSValueRef])))
return;
JSObjectRef method = objCCallbackFunctionForMethod(context, objcClass, protocol, isInstanceMethod, sel, types);
if (method)
putNonEnumerable(object, name, [JSValue valueWithJSValueRef:method inContext:context]);
putNonEnumerable(context, object, name, [JSValue valueWithJSValueRef:method inContext:context]);
}
});
[renameMap release];
}
static bool parsePropertyAttributes(objc_property_t property, char*& getterName, char*& setterName)
struct Property {
const char* name;
RetainPtr<NSString> getterName;
RetainPtr<NSString> setterName;
};
static bool parsePropertyAttributes(objc_property_t objcProperty, Property& property)
{
bool readonly = false;
unsigned attributeCount;
objc_property_attribute_t* attributes = property_copyAttributeList(property, &attributeCount);
auto attributes = adoptSystem<objc_property_attribute_t[]>(property_copyAttributeList(objcProperty, &attributeCount));
if (attributeCount) {
for (unsigned i = 0; i < attributeCount; ++i) {
switch (*(attributes[i].name)) {
case 'G':
getterName = strdup(attributes[i].value);
property.getterName = @(attributes[i].value);
break;
case 'S':
setterName = strdup(attributes[i].value);
property.setterName = @(attributes[i].value);
break;
case 'R':
readonly = true;
@ -281,33 +315,28 @@ static bool parsePropertyAttributes(objc_property_t property, char*& getterName,
break;
}
}
free(attributes);
}
return readonly;
}
static char* makeSetterName(const char* name)
static RetainPtr<NSString> makeSetterName(const char* name)
{
size_t nameLength = strlen(name);
char* setterName = (char*)malloc(nameLength + 5); // "set" Name ":\0"
setterName[0] = 's';
setterName[1] = 'e';
setterName[2] = 't';
setterName[3] = toupper(*name);
memcpy(setterName + 4, name + 1, nameLength - 1);
setterName[nameLength + 3] = ':';
setterName[nameLength + 4] = '\0';
return setterName;
// "set" Name ":\0" => nameLength + 5.
Vector<char, 128> buffer(nameLength + 5);
buffer[0] = 's';
buffer[1] = 'e';
buffer[2] = 't';
buffer[3] = toASCIIUpper(*name);
memcpy(buffer.data() + 4, name + 1, nameLength - 1);
buffer[nameLength + 3] = ':';
buffer[nameLength + 4] = '\0';
return @(buffer.data());
}
static void copyPrototypeProperties(JSContext *context, Class objcClass, Protocol *protocol, JSValue *prototypeValue)
{
// First gather propreties into this list, then handle the methods (capturing the accessor methods).
struct Property {
const char* name;
char* getterName;
char* setterName;
};
__block Vector<Property> propertyList;
// Map recording the methods used as getters/setters.
@ -316,41 +345,36 @@ static void copyPrototypeProperties(JSContext *context, Class objcClass, Protoco
// Useful value.
JSValue *undefined = [JSValue valueWithUndefinedInContext:context];
forEachPropertyInProtocol(protocol, ^(objc_property_t property){
char* getterName = 0;
char* setterName = 0;
bool readonly = parsePropertyAttributes(property, getterName, setterName);
const char* name = property_getName(property);
forEachPropertyInProtocol(protocol, ^(objc_property_t objcProperty) {
const char* name = property_getName(objcProperty);
Property property { name, nullptr, nullptr };
bool readonly = parsePropertyAttributes(objcProperty, property);
// Add the names of the getter & setter methods to
if (!getterName)
getterName = strdup(name);
accessorMethods[@(getterName)] = undefined;
if (!property.getterName)
property.getterName = @(name);
accessorMethods[property.getterName.get()] = undefined;
if (!readonly) {
if (!setterName)
setterName = makeSetterName(name);
accessorMethods[@(setterName)] = undefined;
if (!property.setterName)
property.setterName = makeSetterName(name);
accessorMethods[property.setterName.get()] = undefined;
}
// Add the properties to a list.
propertyList.append((Property){ name, getterName, setterName });
propertyList.append(WTFMove(property));
});
// Copy methods to the prototype, capturing accessors in the accessorMethods map.
copyMethodsToObject(context, objcClass, protocol, YES, prototypeValue, accessorMethods);
// Iterate the propertyList & generate accessor properties.
for (size_t i = 0; i < propertyList.size(); ++i) {
Property& property = propertyList[i];
JSValue *getter = accessorMethods[@(property.getterName)];
free(property.getterName);
for (auto& property : propertyList) {
JSValue* getter = accessorMethods[property.getterName.get()];
ASSERT(![getter isUndefined]);
JSValue *setter = undefined;
JSValue* setter = undefined;
if (property.setterName) {
setter = accessorMethods[@(property.setterName)];
free(property.setterName);
setter = accessorMethods[property.setterName.get()];
ASSERT(![setter isUndefined]);
}
@ -369,6 +393,7 @@ static void copyPrototypeProperties(JSContext *context, Class objcClass, Protoco
JSClassRef m_classRef;
JSC::Weak<JSC::JSObject> m_prototype;
JSC::Weak<JSC::JSObject> m_constructor;
JSC::Weak<JSC::Structure> m_structure;
}
- (instancetype)initForClass:(Class)cls;
@ -409,7 +434,7 @@ static JSC::JSObject* allocateConstructorForCustomClass(JSContext *context, cons
return constructorWithCustomBrand(context, [NSString stringWithFormat:@"%sConstructor", className], cls);
// For each protocol that the class implements, gather all of the init family methods into a hash table.
__block HashMap<String, Protocol *> initTable;
__block HashMap<String, CFTypeRef> initTable;
Protocol *exportProtocol = getJSExportProtocol();
for (Class currentClass = cls; currentClass; currentClass = class_getSuperclass(currentClass)) {
forEachProtocolImplementingProtocol(currentClass, exportProtocol, ^(Protocol *protocol, bool&) {
@ -417,7 +442,7 @@ static JSC::JSObject* allocateConstructorForCustomClass(JSContext *context, cons
const char* name = sel_getName(selector);
if (!isInitFamilyMethod(@(name)))
return;
initTable.set(name, protocol);
initTable.set(name, (__bridge CFTypeRef)protocol);
});
});
}
@ -437,7 +462,7 @@ static JSC::JSObject* allocateConstructorForCustomClass(JSContext *context, cons
numberOfInitsFound++;
initMethod = selector;
initProtocol = iter->value;
initProtocol = (__bridge Protocol *)iter->value;
types = method_getTypeEncoding(method);
});
@ -486,8 +511,9 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair;
JSValue* prototype = [JSValue valueWithJSValueRef:toRef(jsPrototype) inContext:context];
JSValue* constructor = [JSValue valueWithJSValueRef:toRef(jsConstructor) inContext:context];
putNonEnumerable(prototype, @"constructor", constructor);
putNonEnumerable(constructor, @"prototype", prototype);
putNonEnumerable(context, prototype, @"constructor", constructor);
putNonEnumerable(context, constructor, @"prototype", prototype);
Protocol *exportProtocol = getJSExportProtocol();
forEachProtocolImplementingProtocol(m_class, exportProtocol, ^(Protocol *protocol, bool&){
@ -513,16 +539,20 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair;
if (JSObjectRef method = objCCallbackFunctionForBlock(context, object)) {
JSValue *constructor = [JSValue valueWithJSValueRef:method inContext:context];
JSValue *prototype = [JSValue valueWithNewObjectInContext:context];
putNonEnumerable(constructor, @"prototype", prototype);
putNonEnumerable(prototype, @"constructor", constructor);
putNonEnumerable(context, constructor, @"prototype", prototype);
putNonEnumerable(context, prototype, @"constructor", constructor);
return toJS(method);
}
}
JSC::JSObject* prototype = [self prototypeInContext:context];
JSC::Structure* structure = [self structureInContext:context];
JSC::JSObject* wrapper = makeWrapper([context JSGlobalContextRef], m_classRef, object);
JSObjectSetPrototype([context JSGlobalContextRef], toRef(wrapper), toRef(prototype));
JSC::ExecState* exec = toJS([context JSGlobalContextRef]);
JSC::VM& vm = exec->vm();
JSC::JSLockHolder locker(vm);
auto wrapper = JSC::JSCallbackObject<JSC::JSAPIWrapperObject>::create(exec, exec->lexicalGlobalObject(), structure, m_classRef, 0);
wrapper->setWrappedObject((__bridge void*)object);
return wrapper;
}
@ -544,11 +574,25 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair;
return prototype;
}
- (JSC::Structure*)structureInContext:(JSContext *)context
{
JSC::Structure* structure = m_structure.get();
if (structure)
return structure;
JSC::ExecState* exec = toJS([context JSGlobalContextRef]);
JSC::JSGlobalObject* globalObject = toJSGlobalObject([context JSGlobalContextRef]);
JSC::JSObject* prototype = [self prototypeInContext:context];
m_structure = JSC::JSCallbackObject<JSC::JSAPIWrapperObject>::createStructure(exec->vm(), globalObject, prototype);
return m_structure.get();
}
@end
@implementation JSWrapperMap {
NSMutableDictionary *m_classMap;
std::unique_ptr<JSC::WeakGCMap<id, JSC::JSObject>> m_cachedJSWrappers;
std::unique_ptr<JSC::WeakGCMap<__unsafe_unretained id, JSC::JSObject>> m_cachedJSWrappers;
NSMapTable *m_cachedObjCWrappers;
}
@ -562,7 +606,7 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair;
NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
m_cachedObjCWrappers = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
m_cachedJSWrappers = std::make_unique<JSC::WeakGCMap<id, JSC::JSObject>>(toJS(context)->vm());
m_cachedJSWrappers = std::make_unique<JSC::WeakGCMap<__unsafe_unretained id, JSC::JSObject>>(toJS(context)->vm());
ASSERT(!toJSGlobalObject(context)->wrapperMap());
toJSGlobalObject(context)->setWrapperMap(self);
@ -595,10 +639,10 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair;
});
if (!conformsToExportProtocol)
return m_classMap[(id<NSCopying>)cls] = [self classInfoForClass:class_getSuperclass(cls)];
return m_classMap[cls] = [self classInfoForClass:class_getSuperclass(cls)];
}
return m_classMap[(id<NSCopying>)cls] = [[[JSObjCClassInfo alloc] initForClass:cls] autorelease];
return m_classMap[cls] = [[[JSObjCClassInfo alloc] initForClass:cls] autorelease];
}
- (JSValue *)jsWrapperForObject:(id)object inContext:(JSContext *)context
@ -627,10 +671,10 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair;
- (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value inContext:context
{
ASSERT(toJSGlobalObject([context JSGlobalContextRef])->wrapperMap() == self);
JSValue *wrapper = static_cast<JSValue *>(NSMapGet(m_cachedObjCWrappers, value));
JSValue *wrapper = (__bridge JSValue *)NSMapGet(m_cachedObjCWrappers, value);
if (!wrapper) {
wrapper = [[[JSValue alloc] initWithValue:value inContext:context] autorelease];
NSMapInsert(m_cachedObjCWrappers, value, wrapper);
NSMapInsert(m_cachedObjCWrappers, value, (__bridge void*)wrapper);
}
return wrapper;
}
@ -646,8 +690,8 @@ id tryUnwrapObjcObject(JSGlobalContextRef context, JSValueRef value)
ASSERT(!exception);
JSC::JSLockHolder locker(toJS(context));
JSC::VM& vm = toJS(context)->vm();
if (toJS(object)->inherits(vm, JSC::JSCallbackObject<JSC::JSAPIWrapperObject>::info()))
return (id)JSC::jsCast<JSC::JSAPIWrapperObject*>(toJS(object))->wrappedObject();
if (toJS(object)->inherits<JSC::JSCallbackObject<JSC::JSAPIWrapperObject>>(vm))
return (__bridge id)JSC::jsCast<JSC::JSAPIWrapperObject*>(toJS(object))->wrappedObject();
if (id target = tryUnwrapConstructor(&vm, object))
return target;
return nil;

View File

@ -1 +0,0 @@
.

View File

@ -48,13 +48,19 @@ class ObjCCallbackFunction : public InternalFunction {
public:
typedef InternalFunction Base;
template<typename CellType, SubspaceAccess mode>
static IsoSubspace* subspaceFor(VM& vm)
{
return vm.objCCallbackFunctionSpace<mode>();
}
static ObjCCallbackFunction* create(VM&, JSGlobalObject*, const String& name, std::unique_ptr<ObjCCallbackFunctionImpl>);
static void destroy(JSCell*);
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
ASSERT(globalObject);
return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info());
}
DECLARE_EXPORT_INFO;
@ -65,9 +71,6 @@ protected:
ObjCCallbackFunction(VM&, Structure*, JSObjectCallAsFunctionCallback, JSObjectCallAsConstructorCallback, std::unique_ptr<ObjCCallbackFunctionImpl>);
private:
static CallType getCallData(JSCell*, CallData&);
static ConstructType getConstructData(JSCell*, ConstructData&);
JSObjectCallAsFunctionCallback functionCallback() { return m_functionCallback; }
JSObjectCallAsConstructorCallback constructCallback() { return m_constructCallback; }

View File

@ -121,7 +121,7 @@ private:
return;
}
*exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("Argument does not match Objective-C Class")));
*exception = toRef(JSC::createTypeError(toJS(contextRef), "Argument does not match Objective-C Class"_s));
}
RetainPtr<Class> m_class;
@ -458,7 +458,7 @@ static JSValueRef objCCallbackFunctionCallAsFunction(JSContextRef callerContext,
if (impl->type() == CallbackInitMethod) {
JSGlobalContextRef contextRef = [context JSGlobalContextRef];
*exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("Cannot call a class constructor without |new|")));
*exception = toRef(JSC::createTypeError(toJS(contextRef), "Cannot call a class constructor without |new|"_s));
return JSValueMakeUndefined(contextRef);
}
@ -497,16 +497,16 @@ static JSObjectRef objCCallbackFunctionCallAsConstructor(JSContextRef callerCont
return nullptr;
if (!JSValueIsObject(contextRef, result)) {
*exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("Objective-C blocks called as constructors must return an object.")));
*exception = toRef(JSC::createTypeError(toJS(contextRef), "Objective-C blocks called as constructors must return an object."_s));
return nullptr;
}
return (JSObjectRef)result;
return const_cast<JSObjectRef>(result);
}
const JSC::ClassInfo ObjCCallbackFunction::s_info = { "CallbackFunction", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ObjCCallbackFunction) };
ObjCCallbackFunction::ObjCCallbackFunction(JSC::VM& vm, JSC::Structure* structure, JSObjectCallAsFunctionCallback functionCallback, JSObjectCallAsConstructorCallback constructCallback, std::unique_ptr<ObjCCallbackFunctionImpl> impl)
: Base(vm, structure)
: Base(vm, structure, APICallbackFunction::call<ObjCCallbackFunction>, impl->isConstructible() ? APICallbackFunction::construct<ObjCCallbackFunction> : nullptr)
, m_functionCallback(functionCallback)
, m_constructCallback(constructCallback)
, m_impl(WTFMove(impl))
@ -528,22 +528,6 @@ void ObjCCallbackFunction::destroy(JSCell* cell)
function.~ObjCCallbackFunction();
}
CallType ObjCCallbackFunction::getCallData(JSCell*, CallData& callData)
{
callData.native.function = APICallbackFunction::call<ObjCCallbackFunction>;
return CallType::Host;
}
ConstructType ObjCCallbackFunction::getConstructData(JSCell* cell, ConstructData& constructData)
{
ObjCCallbackFunction* callback = jsCast<ObjCCallbackFunction*>(cell);
if (!callback->impl()->isConstructible())
return Base::getConstructData(cell, constructData);
constructData.native.function = APICallbackFunction::construct<ObjCCallbackFunction>;
return ConstructType::Host;
}
String ObjCCallbackFunctionImpl::name()
{
if (m_type == CallbackInitMethod)
@ -564,7 +548,7 @@ JSValueRef ObjCCallbackFunctionImpl::call(JSContext *context, JSObjectRef thisOb
RELEASE_ASSERT(!thisObject);
target = [m_instanceClass alloc];
if (!target || ![target isKindOfClass:m_instanceClass.get()]) {
*exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("self type check failed for Objective-C instance method")));
*exception = toRef(JSC::createTypeError(toJS(contextRef), "self type check failed for Objective-C instance method"_s));
return JSValueMakeUndefined(contextRef);
}
[m_invocation setTarget:target];
@ -574,7 +558,7 @@ JSValueRef ObjCCallbackFunctionImpl::call(JSContext *context, JSObjectRef thisOb
case CallbackInstanceMethod: {
target = tryUnwrapObjcObject(contextRef, thisObject);
if (!target || ![target isKindOfClass:m_instanceClass.get()]) {
*exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("self type check failed for Objective-C instance method")));
*exception = toRef(JSC::createTypeError(toJS(contextRef), "self type check failed for Objective-C instance method"_s));
return JSValueMakeUndefined(contextRef);
}
[m_invocation setTarget:target];
@ -619,7 +603,7 @@ static bool blockSignatureContainsClass()
{
static bool containsClass = ^{
id block = ^(NSString *string){ return string; };
return _Block_has_signature(block) && strstr(_Block_signature(block), "NSString");
return _Block_has_signature((__bridge void*)block) && strstr(_Block_signature((__bridge void*)block), "NSString");
}();
return containsClass;
}
@ -675,10 +659,11 @@ static JSObjectRef objCCallbackFunctionForInvocation(JSContext *context, NSInvoc
}
JSC::ExecState* exec = toJS([context JSGlobalContextRef]);
JSC::JSLockHolder locker(exec);
JSC::VM& vm = exec->vm();
JSC::JSLockHolder locker(vm);
auto impl = std::make_unique<JSC::ObjCCallbackFunctionImpl>(invocation, type, instanceClass, WTFMove(arguments), WTFMove(result));
const String& name = impl->name();
return toRef(JSC::ObjCCallbackFunction::create(exec->vm(), exec->lexicalGlobalObject(), name, WTFMove(impl)));
return toRef(JSC::ObjCCallbackFunction::create(vm, exec->lexicalGlobalObject(), name, WTFMove(impl)));
}
JSObjectRef objCCallbackFunctionForInit(JSContext *context, Class cls, Protocol *protocol, SEL sel, const char* types)
@ -692,18 +677,20 @@ JSObjectRef objCCallbackFunctionForMethod(JSContext *context, Class cls, Protoco
{
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:types]];
[invocation setSelector:sel];
if (!isInstanceMethod) {
[invocation setTarget:cls];
// We need to retain the target Class because m_invocation doesn't retain it by default (and we don't want it to).
// FIXME: What releases it?
if (!isInstanceMethod)
[invocation setTarget:[cls retain]];
CFRetain((__bridge CFTypeRef)cls);
}
return objCCallbackFunctionForInvocation(context, invocation, isInstanceMethod ? CallbackInstanceMethod : CallbackClassMethod, isInstanceMethod ? cls : nil, _protocol_getMethodTypeEncoding(protocol, sel, YES, isInstanceMethod));
}
JSObjectRef objCCallbackFunctionForBlock(JSContext *context, id target)
{
if (!_Block_has_signature(target))
if (!_Block_has_signature((__bridge void*)target))
return nullptr;
const char* signature = _Block_signature(target);
const char* signature = _Block_signature((__bridge void*)target);
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:signature]];
// We don't want to use -retainArguments because that leaks memory. Arguments
@ -717,7 +704,7 @@ JSObjectRef objCCallbackFunctionForBlock(JSContext *context, id target)
id tryUnwrapConstructor(JSC::VM* vm, JSObjectRef object)
{
if (!toJS(object)->inherits(*vm, JSC::ObjCCallbackFunction::info()))
if (!toJS(object)->inherits<JSC::ObjCCallbackFunction>(*vm))
return nil;
JSC::ObjCCallbackFunctionImpl* impl = static_cast<JSC::ObjCCallbackFunction*>(toJS(object))->impl();
if (!impl->isConstructible())

View File

@ -23,22 +23,28 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <memory>
#import <objc/Protocol.h>
#import <objc/runtime.h>
#import <wtf/HashSet.h>
#import <wtf/SystemFree.h>
#import <wtf/Vector.h>
#import <wtf/text/CString.h>
template<typename T, typename U>
inline std::unique_ptr<T, WTF::SystemFree<T>> adoptSystem(U value)
{
return std::unique_ptr<T, WTF::SystemFree<T>>(value);
}
inline bool protocolImplementsProtocol(Protocol *candidate, Protocol *target)
{
unsigned protocolProtocolsCount;
Protocol ** protocolProtocols = protocol_copyProtocolList(candidate, &protocolProtocolsCount);
auto protocolProtocols = adoptSystem<__unsafe_unretained Protocol*[]>(protocol_copyProtocolList(candidate, &protocolProtocolsCount));
for (unsigned i = 0; i < protocolProtocolsCount; ++i) {
if (protocol_isEqual(protocolProtocols[i], target)) {
free(protocolProtocols);
if (protocol_isEqual(protocolProtocols[i], target))
return true;
}
}
free(protocolProtocols);
return false;
}
@ -47,14 +53,15 @@ inline void forEachProtocolImplementingProtocol(Class cls, Protocol *target, voi
ASSERT(cls);
ASSERT(target);
Vector<Protocol *> worklist;
Vector<Protocol*> worklist;
HashSet<void*> visited;
// Initially fill the worklist with the Class's protocols.
{
unsigned protocolsCount;
Protocol ** protocols = class_copyProtocolList(cls, &protocolsCount);
worklist.append(protocols, protocolsCount);
free(protocols);
auto protocols = adoptSystem<__unsafe_unretained Protocol*[]>(class_copyProtocolList(cls, &protocolsCount));
worklist.append(protocols.get(), protocolsCount);
}
bool stop = false;
while (!worklist.isEmpty()) {
@ -62,7 +69,7 @@ inline void forEachProtocolImplementingProtocol(Class cls, Protocol *target, voi
worklist.removeLast();
// Are we encountering this Protocol for the first time?
if (!visited.add(protocol).isNewEntry)
if (!visited.add((__bridge void*)protocol).isNewEntry)
continue;
// If it implements the protocol, make the callback.
@ -73,37 +80,36 @@ inline void forEachProtocolImplementingProtocol(Class cls, Protocol *target, voi
}
// Add incorporated protocols to the worklist.
protocols = protocol_copyProtocolList(protocol, &protocolsCount);
worklist.append(protocols, protocolsCount);
free(protocols);
{
unsigned protocolsCount;
auto protocols = adoptSystem<__unsafe_unretained Protocol*[]>(protocol_copyProtocolList(protocol, &protocolsCount));
worklist.append(protocols.get(), protocolsCount);
}
}
}
inline void forEachMethodInClass(Class cls, void (^callback)(Method))
{
unsigned count;
Method* methods = class_copyMethodList(cls, &count);
auto methods = adoptSystem<Method[]>(class_copyMethodList(cls, &count));
for (unsigned i = 0; i < count; ++i)
callback(methods[i]);
free(methods);
}
inline void forEachMethodInProtocol(Protocol *protocol, BOOL isRequiredMethod, BOOL isInstanceMethod, void (^callback)(SEL, const char*))
{
unsigned count;
struct objc_method_description* methods = protocol_copyMethodDescriptionList(protocol, isRequiredMethod, isInstanceMethod, &count);
auto methods = adoptSystem<objc_method_description[]>(protocol_copyMethodDescriptionList(protocol, isRequiredMethod, isInstanceMethod, &count));
for (unsigned i = 0; i < count; ++i)
callback(methods[i].name, methods[i].types);
free(methods);
}
inline void forEachPropertyInProtocol(Protocol *protocol, void (^callback)(objc_property_t))
{
unsigned count;
objc_property_t* properties = protocol_copyPropertyList(protocol, &count);
auto properties = adoptSystem<objc_property_t[]>(protocol_copyPropertyList(protocol, &count));
for (unsigned i = 0; i < count; ++i)
callback(properties[i]);
free(properties);
}
template<char open, char close>
@ -124,13 +130,14 @@ void skipPair(const char*& position)
class StringRange {
WTF_MAKE_NONCOPYABLE(StringRange);
public:
StringRange(const char* begin, const char* end) : m_ptr(strndup(begin, end - begin)) { }
~StringRange() { free(m_ptr); }
operator const char*() const { return m_ptr; }
const char* get() const { return m_ptr; }
StringRange(const char* begin, const char* end)
: m_string(begin, end - begin)
{ }
operator const char*() const { return m_string.data(); }
const char* get() const { return m_string.data(); }
private:
char* m_ptr;
CString m_string;
};
class StructBuffer {
@ -140,16 +147,13 @@ public:
{
NSUInteger size, alignment;
NSGetSizeAndAlignment(encodedType, &size, &alignment);
--alignment;
m_allocation = static_cast<char*>(malloc(size + alignment));
m_buffer = reinterpret_cast<char*>((reinterpret_cast<intptr_t>(m_allocation) + alignment) & ~alignment);
m_buffer = fastAlignedMalloc(alignment, size);
}
~StructBuffer() { free(m_allocation); }
~StructBuffer() { fastAlignedFree(m_buffer); }
operator void*() const { return m_buffer; }
private:
void* m_allocation;
void* m_buffer;
};

View File

@ -34,7 +34,7 @@
using namespace JSC;
RefPtr<OpaqueJSString> OpaqueJSString::create(const String& string)
RefPtr<OpaqueJSString> OpaqueJSString::tryCreate(const String& string)
{
if (string.isNull())
return nullptr;
@ -42,6 +42,14 @@ RefPtr<OpaqueJSString> OpaqueJSString::create(const String& string)
return adoptRef(new OpaqueJSString(string));
}
RefPtr<OpaqueJSString> OpaqueJSString::tryCreate(String&& string)
{
if (string.isNull())
return nullptr;
return adoptRef(new OpaqueJSString(WTFMove(string)));
}
OpaqueJSString::~OpaqueJSString()
{
// m_characters is put in a local here to avoid an extra atomic load.

View File

@ -51,7 +51,8 @@ struct OpaqueJSString : public ThreadSafeRefCounted<OpaqueJSString> {
return adoptRef(*new OpaqueJSString(characters, length));
}
JS_EXPORT_PRIVATE static RefPtr<OpaqueJSString> create(const String&);
JS_EXPORT_PRIVATE static RefPtr<OpaqueJSString> tryCreate(const String&);
JS_EXPORT_PRIVATE static RefPtr<OpaqueJSString> tryCreate(String&&);
JS_EXPORT_PRIVATE ~OpaqueJSString();
@ -81,6 +82,12 @@ private:
{
}
explicit OpaqueJSString(String&& string)
: m_string(WTFMove(string))
, m_characters(m_string.impl() && m_string.is8Bit() ? nullptr : const_cast<UChar*>(m_string.characters16()))
{
}
OpaqueJSString(const LChar* characters, unsigned length)
: m_string(characters, length)
, m_characters(nullptr)

View File

@ -69,15 +69,12 @@
#endif /* !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED < 101100 */
#if defined(BUILDING_GTK__)
#undef CF_AVAILABLE
#define CF_AVAILABLE(_mac, _ios)
#undef CF_ENUM_AVAILABLE
#define CF_ENUM_AVAILABLE(_mac, _ios)
#undef JSC_API_AVAILABLE
#define JSC_API_AVAILABLE(...)
#endif
#else
#define CF_AVAILABLE(_mac, _ios)
#define CF_ENUM_AVAILABLE(_mac, _ios)
#define JSC_API_AVAILABLE(...)
#endif
#endif /* __WebKitAvailability__ */

View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "config.h"
#include "JSAPIWrapperGlobalObject.h"
#include "JSCInlines.h"
#include "JSCallbackObject.h"
#include "Structure.h"
#include <wtf/NeverDestroyed.h>
class JSAPIWrapperGlobalObjectHandleOwner : public JSC::WeakHandleOwner {
public:
void finalize(JSC::Handle<JSC::Unknown>, void*) override;
};
static JSAPIWrapperGlobalObjectHandleOwner* jsAPIWrapperGlobalObjectHandleOwner()
{
static NeverDestroyed<JSAPIWrapperGlobalObjectHandleOwner> jsWrapperGlobalObjectHandleOwner;
return &jsWrapperGlobalObjectHandleOwner.get();
}
void JSAPIWrapperGlobalObjectHandleOwner::finalize(JSC::Handle<JSC::Unknown> handle, void*)
{
auto* wrapperObject = static_cast<JSC::JSAPIWrapperGlobalObject*>(handle.get().asCell());
if (!wrapperObject->wrappedObject())
return;
JSC::Heap::heap(wrapperObject)->releaseSoon(std::unique_ptr<JSC::JSCGLibWrapperObject>(wrapperObject->wrappedObject()));
JSC::WeakSet::deallocate(JSC::WeakImpl::asWeakImpl(handle.slot()));
}
namespace JSC {
template <> const ClassInfo JSCallbackObject<JSAPIWrapperGlobalObject>::s_info = { "JSAPIWrapperGlobalObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCallbackObject) };
template<> const bool JSCallbackObject<JSAPIWrapperGlobalObject>::needsDestruction = false;
template <>
Structure* JSCallbackObject<JSAPIWrapperGlobalObject>::createStructure(VM& vm, JSGlobalObject*, JSValue proto)
{
return Structure::create(vm, nullptr, proto, TypeInfo(GlobalObjectType, StructureFlags), &s_info);
}
template<>
JSCallbackObject<JSAPIWrapperGlobalObject>* JSCallbackObject<JSAPIWrapperGlobalObject>::create(VM& vm, JSClassRef classRef, Structure* structure)
{
JSCallbackObject<JSAPIWrapperGlobalObject>* callbackObject = new (NotNull, allocateCell<JSCallbackObject<JSAPIWrapperGlobalObject>>(vm.heap)) JSCallbackObject(vm, classRef, structure);
callbackObject->finishCreation(vm);
return callbackObject;
}
JSAPIWrapperGlobalObject::JSAPIWrapperGlobalObject(VM& vm, Structure* structure)
: Base(vm, structure)
{
}
void JSAPIWrapperGlobalObject::finishCreation(VM& vm)
{
Base::finishCreation(vm);
WeakSet::allocate(this, jsAPIWrapperGlobalObjectHandleOwner(), 0); // Balanced in JSAPIWrapperGlobalObjectHandleOwner::finalize.
}
void JSAPIWrapperGlobalObject::visitChildren(JSCell* cell, JSC::SlotVisitor& visitor)
{
Base::visitChildren(cell, visitor);
}
} // namespace JSC

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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.
*/
#pragma once
#include "JSBase.h"
#include "JSCGLibWrapperObject.h"
#include "JSGlobalObject.h"
namespace JSC {
class JSAPIWrapperGlobalObject : public JSGlobalObject {
public:
typedef JSGlobalObject Base;
void finishCreation(VM&);
static void visitChildren(JSCell*, JSC::SlotVisitor&);
JSCGLibWrapperObject* wrappedObject() const { return m_wrappedObject; }
void setWrappedObject(JSCGLibWrapperObject* wrappedObject) { m_wrappedObject = wrappedObject; }
protected:
JSAPIWrapperGlobalObject(VM&, Structure*);
private:
JSCGLibWrapperObject* m_wrappedObject;
};
} // namespace JSC

View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2018 Igalia S.L.
* 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
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "config.h"
#include "JSAPIWrapperObject.h"
#include "JSCGLibWrapperObject.h"
#include "JSCInlines.h"
#include "JSCallbackObject.h"
#include "Structure.h"
#include <wtf/NeverDestroyed.h>
class JSAPIWrapperObjectHandleOwner : public JSC::WeakHandleOwner {
public:
void finalize(JSC::Handle<JSC::Unknown>, void*) override;
bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**) override;
};
static JSAPIWrapperObjectHandleOwner* jsAPIWrapperObjectHandleOwner()
{
static NeverDestroyed<JSAPIWrapperObjectHandleOwner> jsWrapperObjectHandleOwner;
return &jsWrapperObjectHandleOwner.get();
}
void JSAPIWrapperObjectHandleOwner::finalize(JSC::Handle<JSC::Unknown> handle, void*)
{
auto* wrapperObject = static_cast<JSC::JSAPIWrapperObject*>(handle.get().asCell());
if (!wrapperObject->wrappedObject())
return;
JSC::Heap::heap(wrapperObject)->releaseSoon(std::unique_ptr<JSC::JSCGLibWrapperObject>(static_cast<JSC::JSCGLibWrapperObject*>(wrapperObject->wrappedObject())));
JSC::WeakSet::deallocate(JSC::WeakImpl::asWeakImpl(handle.slot()));
}
bool JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor, const char**)
{
JSC::JSAPIWrapperObject* wrapperObject = JSC::jsCast<JSC::JSAPIWrapperObject*>(handle.get().asCell());
// We use the JSGlobalObject when processing weak handles to prevent the situation where using
// the same wrapped object in multiple global objects keeps all of the global objects alive.
if (!wrapperObject->wrappedObject())
return false;
return visitor.vm().heap.isMarked(wrapperObject->structure()->globalObject()) && visitor.containsOpaqueRoot(wrapperObject->wrappedObject());
}
namespace JSC {
template <> const ClassInfo JSCallbackObject<JSAPIWrapperObject>::s_info = { "JSAPIWrapperObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCallbackObject) };
template<> const bool JSCallbackObject<JSAPIWrapperObject>::needsDestruction = true;
template <>
Structure* JSCallbackObject<JSAPIWrapperObject>::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
{
return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info);
}
JSAPIWrapperObject::JSAPIWrapperObject(VM& vm, Structure* structure)
: Base(vm, structure)
{
}
void JSAPIWrapperObject::finishCreation(VM& vm)
{
Base::finishCreation(vm);
WeakSet::allocate(this, jsAPIWrapperObjectHandleOwner(), 0); // Balanced in JSAPIWrapperObjectHandleOwner::finalize.
}
void JSAPIWrapperObject::setWrappedObject(void* wrappedObject)
{
ASSERT(!m_wrappedObject);
m_wrappedObject = wrappedObject;
}
void JSAPIWrapperObject::visitChildren(JSCell* cell, JSC::SlotVisitor& visitor)
{
Base::visitChildren(cell, visitor);
}
} // namespace JSC

View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION) && !defined(WEBKIT2_COMPILATION)
#error "Only <jsc/jsc.h> can be included directly."
#endif
#ifndef JSCAutoPtr_h
#define JSCAutoPtr_h
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
#ifndef __GI_SCANNER__
G_DEFINE_AUTOPTR_CLEANUP_FUNC (JSCClass, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (JSCContext, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (JSCException, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (JSCValue, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (JSCVirtualMachine, g_object_unref)
#endif /* __GI_SCANNER__ */
#endif /* G_DEFINE_AUTOPTR_CLEANUP_FUNC */
#endif /* JSCAutoPtr_h */

View File

@ -0,0 +1,232 @@
/*
* Copyright (C) 2018 Igalia S.L.
* Copyright (C) 2006-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
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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 "config.h"
#include "JSCCallbackFunction.h"
#include "APICallbackFunction.h"
#include "APICast.h"
#include "IsoSubspacePerVM.h"
#include "JSCClassPrivate.h"
#include "JSCContextPrivate.h"
#include "JSDestructibleObjectHeapCellType.h"
#include "JSCExceptionPrivate.h"
#include "JSCInlines.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "JSLock.h"
namespace JSC {
static JSValueRef callAsFunction(JSContextRef callerContext, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
return static_cast<JSCCallbackFunction*>(toJS(function))->call(callerContext, thisObject, argumentCount, arguments, exception);
}
static JSObjectRef callAsConstructor(JSContextRef callerContext, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
return static_cast<JSCCallbackFunction*>(toJS(constructor))->construct(callerContext, argumentCount, arguments, exception);
}
const ClassInfo JSCCallbackFunction::s_info = { "CallbackFunction", &InternalFunction::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCCallbackFunction) };
JSCCallbackFunction* JSCCallbackFunction::create(VM& vm, JSGlobalObject* globalObject, const String& name, Type type, JSCClass* jscClass, GRefPtr<GClosure>&& closure, GType returnType, Optional<Vector<GType>>&& parameters)
{
Structure* structure = globalObject->glibCallbackFunctionStructure();
JSCCallbackFunction* function = new (NotNull, allocateCell<JSCCallbackFunction>(vm.heap)) JSCCallbackFunction(vm, structure, type, jscClass, WTFMove(closure), returnType, WTFMove(parameters));
function->finishCreation(vm, name);
return function;
}
JSCCallbackFunction::JSCCallbackFunction(VM& vm, Structure* structure, Type type, JSCClass* jscClass, GRefPtr<GClosure>&& closure, GType returnType, Optional<Vector<GType>>&& parameters)
: InternalFunction(vm, structure, APICallbackFunction::call<JSCCallbackFunction>, type == Type::Constructor ? APICallbackFunction::construct<JSCCallbackFunction> : nullptr)
, m_functionCallback(callAsFunction)
, m_constructCallback(callAsConstructor)
, m_type(type)
, m_class(jscClass)
, m_closure(WTFMove(closure))
, m_returnType(returnType)
, m_parameters(WTFMove(parameters))
{
ASSERT(type != Type::Constructor || jscClass);
if (G_CLOSURE_NEEDS_MARSHAL(m_closure.get()))
g_closure_set_marshal(m_closure.get(), g_cclosure_marshal_generic);
}
JSValueRef JSCCallbackFunction::call(JSContextRef callerContext, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
JSLockHolder locker(toJS(callerContext));
auto context = jscContextGetOrCreate(toGlobalRef(globalObject()->globalExec()));
auto* jsContext = jscContextGetJSContext(context.get());
if (m_type == Type::Constructor) {
*exception = toRef(JSC::createTypeError(toJS(jsContext), "cannot call a class constructor without |new|"_s));
return JSValueMakeUndefined(jsContext);
}
gpointer instance = nullptr;
if (m_type == Type::Method) {
instance = jscContextWrappedObject(context.get(), thisObject);
if (!instance) {
*exception = toRef(JSC::createTypeError(toJS(jsContext), "invalid instance type in method"_s));
return JSValueMakeUndefined(jsContext);
}
}
auto callbackData = jscContextPushCallback(context.get(), toRef(this), thisObject, argumentCount, arguments);
// GClosure always expect to have at least the instance parameter.
bool addInstance = instance || (m_parameters && m_parameters->isEmpty());
auto parameterCount = m_parameters ? std::min(m_parameters->size(), argumentCount) : 1;
if (addInstance)
parameterCount++;
auto* values = static_cast<GValue*>(g_alloca(sizeof(GValue) * parameterCount));
memset(values, 0, sizeof(GValue) * parameterCount);
size_t firstParameter = 0;
if (addInstance) {
g_value_init(&values[0], G_TYPE_POINTER);
g_value_set_pointer(&values[0], instance);
firstParameter = 1;
}
if (m_parameters) {
for (size_t i = firstParameter; i < parameterCount && !*exception; ++i)
jscContextJSValueToGValue(context.get(), arguments[i - firstParameter], m_parameters.value()[i - firstParameter], &values[i], exception);
} else {
auto* parameters = g_ptr_array_new_full(argumentCount, g_object_unref);
for (size_t i = 0; i < argumentCount; ++i)
g_ptr_array_add(parameters, jscContextGetOrCreateValue(context.get(), arguments[i]).leakRef());
g_value_init(&values[firstParameter], G_TYPE_PTR_ARRAY);
g_value_take_boxed(&values[firstParameter], parameters);
}
GValue returnValue = G_VALUE_INIT;
if (m_returnType != G_TYPE_NONE)
g_value_init(&returnValue, m_returnType);
if (!*exception)
g_closure_invoke(m_closure.get(), m_returnType != G_TYPE_NONE ? &returnValue : nullptr, parameterCount, values, nullptr);
for (size_t i = 0; i < parameterCount; ++i)
g_value_unset(&values[i]);
if (auto* jscException = jsc_context_get_exception(context.get()))
*exception = jscExceptionGetJSValue(jscException);
jscContextPopCallback(context.get(), WTFMove(callbackData));
if (m_returnType == G_TYPE_NONE)
return JSValueMakeUndefined(jsContext);
auto* retval = *exception ? JSValueMakeUndefined(jsContext) : jscContextGValueToJSValue(context.get(), &returnValue, exception);
g_value_unset(&returnValue);
return retval;
}
JSObjectRef JSCCallbackFunction::construct(JSContextRef callerContext, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
JSLockHolder locker(toJS(callerContext));
auto context = jscContextGetOrCreate(toGlobalRef(globalObject()->globalExec()));
auto* jsContext = jscContextGetJSContext(context.get());
if (m_returnType == G_TYPE_NONE) {
*exception = toRef(JSC::createTypeError(toJS(jsContext), "constructors cannot be void"_s));
return nullptr;
}
auto callbackData = jscContextPushCallback(context.get(), toRef(this), nullptr, argumentCount, arguments);
GValue returnValue = G_VALUE_INIT;
g_value_init(&returnValue, m_returnType);
if (m_parameters && m_parameters->isEmpty()) {
// GClosure always expect to have at least the instance parameter.
GValue dummyValue = G_VALUE_INIT;
g_value_init(&dummyValue, G_TYPE_POINTER);
g_closure_invoke(m_closure.get(), &returnValue, 1, &dummyValue, nullptr);
g_value_unset(&dummyValue);
} else {
auto parameterCount = m_parameters ? std::min(m_parameters->size(), argumentCount) : 1;
auto* values = static_cast<GValue*>(g_alloca(sizeof(GValue) * parameterCount));
memset(values, 0, sizeof(GValue) * parameterCount);
if (m_parameters) {
for (size_t i = 0; i < parameterCount && !*exception; ++i)
jscContextJSValueToGValue(context.get(), arguments[i], m_parameters.value()[i], &values[i], exception);
} else {
auto* parameters = g_ptr_array_new_full(argumentCount, g_object_unref);
for (size_t i = 0; i < argumentCount; ++i)
g_ptr_array_add(parameters, jscContextGetOrCreateValue(context.get(), arguments[i]).leakRef());
g_value_init(&values[0], G_TYPE_PTR_ARRAY);
g_value_take_boxed(&values[0], parameters);
}
if (!*exception)
g_closure_invoke(m_closure.get(), &returnValue, parameterCount, values, nullptr);
for (size_t i = 0; i < parameterCount; ++i)
g_value_unset(&values[i]);
}
if (auto* jscException = jsc_context_get_exception(context.get()))
*exception = jscExceptionGetJSValue(jscException);
jscContextPopCallback(context.get(), WTFMove(callbackData));
if (*exception) {
g_value_unset(&returnValue);
return nullptr;
}
switch (g_type_fundamental(G_VALUE_TYPE(&returnValue))) {
case G_TYPE_POINTER:
case G_TYPE_BOXED:
case G_TYPE_OBJECT:
if (auto* ptr = returnValue.data[0].v_pointer)
return toRef(jscClassGetOrCreateJSWrapper(m_class.get(), context.get(), ptr));
*exception = toRef(JSC::createTypeError(toJS(jsContext), "constructor returned null"_s));
break;
default:
*exception = toRef(JSC::createTypeError(toJS(jsContext), makeString("invalid type ", g_type_name(G_VALUE_TYPE(&returnValue)), " returned by constructor")));
break;
}
g_value_unset(&returnValue);
return nullptr;
}
void JSCCallbackFunction::destroy(JSCell* cell)
{
static_cast<JSCCallbackFunction*>(cell)->JSCCallbackFunction::~JSCCallbackFunction();
}
IsoSubspace* JSCCallbackFunction::subspaceForImpl(VM& vm)
{
NeverDestroyed<IsoSubspacePerVM> perVM([] (VM& vm) -> IsoSubspacePerVM::SubspaceParameters { return ISO_SUBSPACE_PARAMETERS(vm.destructibleObjectHeapCellType.get(), JSCCallbackFunction); });
return &perVM.get().forVM(vm);
}
} // namespace JSC

View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2018 Igalia S.L.
* Copyright (C) 2006-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
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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.
*/
#pragma once
#include "InternalFunction.h"
#include "JSObjectRef.h"
#include <glib-object.h>
#include <wtf/glib/GRefPtr.h>
typedef struct _JSCClass JSCClass;
namespace JSC {
class JSCCallbackFunction : public InternalFunction {
friend struct APICallbackFunction;
public:
typedef InternalFunction Base;
template<typename CellType, SubspaceAccess>
static IsoSubspace* subspaceFor(VM& vm)
{
return subspaceForImpl(vm);
}
enum class Type {
Function,
Method,
Constructor
};
static JSCCallbackFunction* create(VM&, JSGlobalObject*, const String& name, Type, JSCClass*, GRefPtr<GClosure>&&, GType, Optional<Vector<GType>>&&);
static void destroy(JSCell*);
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
ASSERT(globalObject);
return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info());
}
DECLARE_INFO;
JSValueRef call(JSContextRef, JSObjectRef, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
JSObjectRef construct(JSContextRef, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
private:
static IsoSubspace* subspaceForImpl(VM&);
JSCCallbackFunction(VM&, Structure*, Type, JSCClass*, GRefPtr<GClosure>&&, GType, Optional<Vector<GType>>&&);
JSObjectCallAsFunctionCallback functionCallback() { return m_functionCallback; }
JSObjectCallAsConstructorCallback constructCallback() { return m_constructCallback; }
JSObjectCallAsFunctionCallback m_functionCallback;
JSObjectCallAsConstructorCallback m_constructCallback;
Type m_type;
GRefPtr<JSCClass> m_class;
GRefPtr<GClosure> m_closure;
GType m_returnType;
Optional<Vector<GType>> m_parameters;
};
} // namespace JSC

865
API/glib/JSCClass.cpp Normal file
View File

@ -0,0 +1,865 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "JSCClass.h"
#include "APICast.h"
#include "JSAPIWrapperGlobalObject.h"
#include "JSAPIWrapperObject.h"
#include "JSCCallbackFunction.h"
#include "JSCClassPrivate.h"
#include "JSCContextPrivate.h"
#include "JSCExceptionPrivate.h"
#include "JSCInlines.h"
#include "JSCValuePrivate.h"
#include "JSCallbackObject.h"
#include "JSRetainPtr.h"
#include <wtf/glib/GUniquePtr.h>
#include <wtf/glib/WTFGType.h>
/**
* SECTION: JSCClass
* @short_description: JavaScript custom class
* @title: JSCClass
* @see_also: JSCContext
*
* A JSSClass represents a custom JavaScript class registered by the user in a #JSCContext.
* It allows to create new JavaScripts objects whose instances are created by the user using
* this API.
* It's possible to add constructors, properties and methods for a JSSClass by providing
* #GCallback<!-- -->s to implement them.
*/
enum {
PROP_0,
PROP_CONTEXT,
PROP_NAME,
PROP_PARENT
};
typedef struct _JSCClassPrivate {
JSGlobalContextRef context;
CString name;
JSClassRef jsClass;
JSCClassVTable* vtable;
GDestroyNotify destroyFunction;
JSCClass* parentClass;
JSC::Weak<JSC::JSObject> prototype;
} JSCClassPrivate;
struct _JSCClass {
GObject parent;
JSCClassPrivate* priv;
};
struct _JSCClassClass {
GObjectClass parent_class;
};
WEBKIT_DEFINE_TYPE(JSCClass, jsc_class, G_TYPE_OBJECT)
class VTableExceptionHandler {
public:
VTableExceptionHandler(JSCContext* context, JSValueRef* exception)
: m_context(context)
, m_exception(exception)
, m_savedException(exception ? jsc_context_get_exception(m_context) : nullptr)
{
}
~VTableExceptionHandler()
{
if (!m_exception)
return;
auto* exception = jsc_context_get_exception(m_context);
if (m_savedException.get() == exception)
return;
*m_exception = jscExceptionGetJSValue(exception);
if (m_savedException)
jsc_context_throw_exception(m_context, m_savedException.get());
else
jsc_context_clear_exception(m_context);
}
private:
JSCContext* m_context { nullptr };
JSValueRef* m_exception { nullptr };
GRefPtr<JSCException> m_savedException;
};
static bool isWrappedObject(JSC::JSObject* jsObject)
{
JSC::ExecState* exec = jsObject->globalObject()->globalExec();
if (jsObject->isGlobalObject())
return jsObject->inherits<JSC::JSCallbackObject<JSC::JSAPIWrapperGlobalObject>>(exec->vm());
return jsObject->inherits<JSC::JSCallbackObject<JSC::JSAPIWrapperObject>>(exec->vm());
}
static JSClassRef wrappedObjectClass(JSC::JSObject* jsObject)
{
ASSERT(isWrappedObject(jsObject));
if (jsObject->isGlobalObject())
return JSC::jsCast<JSC::JSCallbackObject<JSC::JSAPIWrapperGlobalObject>*>(jsObject)->classRef();
return JSC::jsCast<JSC::JSCallbackObject<JSC::JSAPIWrapperObject>*>(jsObject)->classRef();
}
static GRefPtr<JSCContext> jscContextForObject(JSC::JSObject* jsObject)
{
ASSERT(isWrappedObject(jsObject));
JSC::JSGlobalObject* globalObject = jsObject->globalObject();
JSC::ExecState* exec = globalObject->globalExec();
if (jsObject->isGlobalObject()) {
JSC::VM& vm = globalObject->vm();
if (auto* globalScopeExtension = vm.vmEntryGlobalObject(exec)->globalScopeExtension())
exec = JSC::JSScope::objectAtScope(globalScopeExtension)->globalObject()->globalExec();
}
return jscContextGetOrCreate(toGlobalRef(exec));
}
static JSValueRef getProperty(JSContextRef callerContext, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
{
JSC::JSLockHolder locker(toJS(callerContext));
auto* jsObject = toJS(object);
if (!isWrappedObject(jsObject))
return nullptr;
auto context = jscContextForObject(jsObject);
gpointer instance = jscContextWrappedObject(context.get(), object);
if (!instance)
return nullptr;
VTableExceptionHandler exceptionHandler(context.get(), exception);
JSClassRef jsClass = wrappedObjectClass(jsObject);
for (auto* jscClass = jscContextGetRegisteredClass(context.get(), jsClass); jscClass; jscClass = jscClass->priv->parentClass) {
if (!jscClass->priv->vtable)
continue;
if (auto* getPropertyFunction = jscClass->priv->vtable->get_property) {
if (GRefPtr<JSCValue> value = adoptGRef(getPropertyFunction(jscClass, context.get(), instance, propertyName->string().utf8().data())))
return jscValueGetJSValue(value.get());
}
}
return nullptr;
}
static bool setProperty(JSContextRef callerContext, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
{
JSC::JSLockHolder locker(toJS(callerContext));
auto* jsObject = toJS(object);
if (!isWrappedObject(jsObject))
return false;
auto context = jscContextForObject(jsObject);
gpointer instance = jscContextWrappedObject(context.get(), object);
if (!instance)
return false;
VTableExceptionHandler exceptionHandler(context.get(), exception);
GRefPtr<JSCValue> propertyValue;
JSClassRef jsClass = wrappedObjectClass(jsObject);
for (auto* jscClass = jscContextGetRegisteredClass(context.get(), jsClass); jscClass; jscClass = jscClass->priv->parentClass) {
if (!jscClass->priv->vtable)
continue;
if (auto* setPropertyFunction = jscClass->priv->vtable->set_property) {
if (!propertyValue)
propertyValue = jscContextGetOrCreateValue(context.get(), value);
if (setPropertyFunction(jscClass, context.get(), instance, propertyName->string().utf8().data(), propertyValue.get()))
return true;
}
}
return false;
}
static bool hasProperty(JSContextRef callerContext, JSObjectRef object, JSStringRef propertyName)
{
JSC::JSLockHolder locker(toJS(callerContext));
auto* jsObject = toJS(object);
if (!isWrappedObject(jsObject))
return false;
auto context = jscContextForObject(jsObject);
gpointer instance = jscContextWrappedObject(context.get(), object);
if (!instance)
return false;
JSClassRef jsClass = wrappedObjectClass(jsObject);
for (auto* jscClass = jscContextGetRegisteredClass(context.get(), jsClass); jscClass; jscClass = jscClass->priv->parentClass) {
if (!jscClass->priv->vtable)
continue;
if (auto* hasPropertyFunction = jscClass->priv->vtable->has_property) {
if (hasPropertyFunction(jscClass, context.get(), instance, propertyName->string().utf8().data()))
return true;
}
}
return false;
}
static bool deleteProperty(JSContextRef callerContext, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
{
JSC::JSLockHolder locker(toJS(callerContext));
auto* jsObject = toJS(object);
if (!isWrappedObject(jsObject))
return false;
auto context = jscContextForObject(jsObject);
gpointer instance = jscContextWrappedObject(context.get(), object);
if (!instance)
return false;
VTableExceptionHandler exceptionHandler(context.get(), exception);
JSClassRef jsClass = wrappedObjectClass(jsObject);
for (auto* jscClass = jscContextGetRegisteredClass(context.get(), jsClass); jscClass; jscClass = jscClass->priv->parentClass) {
if (!jscClass->priv->vtable)
continue;
if (auto* deletePropertyFunction = jscClass->priv->vtable->delete_property) {
if (deletePropertyFunction(jscClass, context.get(), instance, propertyName->string().utf8().data()))
return true;
}
}
return false;
}
static void getPropertyNames(JSContextRef callerContext, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
{
JSC::JSLockHolder locker(toJS(callerContext));
auto* jsObject = toJS(object);
if (!isWrappedObject(jsObject))
return;
auto context = jscContextForObject(jsObject);
gpointer instance = jscContextWrappedObject(context.get(), object);
if (!instance)
return;
JSClassRef jsClass = wrappedObjectClass(jsObject);
for (auto* jscClass = jscContextGetRegisteredClass(context.get(), jsClass); jscClass; jscClass = jscClass->priv->parentClass) {
if (!jscClass->priv->vtable)
continue;
if (auto* enumeratePropertiesFunction = jscClass->priv->vtable->enumerate_properties) {
GUniquePtr<char*> properties(enumeratePropertiesFunction(jscClass, context.get(), instance));
if (properties) {
unsigned i = 0;
while (const auto* name = properties.get()[i++]) {
JSRetainPtr<JSStringRef> propertyName(Adopt, JSStringCreateWithUTF8CString(name));
JSPropertyNameAccumulatorAddName(propertyNames, propertyName.get());
}
}
}
}
}
static void jscClassGetProperty(GObject* object, guint propID, GValue* value, GParamSpec* paramSpec)
{
JSCClass* jscClass = JSC_CLASS(object);
switch (propID) {
case PROP_NAME:
g_value_set_string(value, jscClass->priv->name.data());
break;
case PROP_PARENT:
g_value_set_object(value, jscClass->priv->parentClass);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
}
}
static void jscClassSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* paramSpec)
{
JSCClass* jscClass = JSC_CLASS(object);
switch (propID) {
case PROP_CONTEXT:
jscClass->priv->context = jscContextGetJSContext(JSC_CONTEXT(g_value_get_object(value)));
break;
case PROP_NAME:
jscClass->priv->name = g_value_get_string(value);
break;
case PROP_PARENT:
if (auto* parent = g_value_get_object(value))
jscClass->priv->parentClass = JSC_CLASS(parent);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
}
}
static void jscClassDispose(GObject* object)
{
JSCClass* jscClass = JSC_CLASS(object);
if (jscClass->priv->jsClass) {
JSClassRelease(jscClass->priv->jsClass);
jscClass->priv->jsClass = nullptr;
}
G_OBJECT_CLASS(jsc_class_parent_class)->dispose(object);
}
static void jsc_class_class_init(JSCClassClass* klass)
{
GObjectClass* objClass = G_OBJECT_CLASS(klass);
objClass->dispose = jscClassDispose;
objClass->get_property = jscClassGetProperty;
objClass->set_property = jscClassSetProperty;
/**
* JSCClass:context:
*
* The #JSCContext in which the class was registered.
*/
g_object_class_install_property(objClass,
PROP_CONTEXT,
g_param_spec_object(
"context",
"JSCContext",
"JSC Context",
JSC_TYPE_CONTEXT,
static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
/**
* JSCClass:name:
*
* The name of the class.
*/
g_object_class_install_property(objClass,
PROP_NAME,
g_param_spec_string(
"name",
"Name",
"The class name",
nullptr,
static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
/**
* JSCClass:parent:
*
* The parent class or %NULL in case of final classes.
*/
g_object_class_install_property(objClass,
PROP_PARENT,
g_param_spec_object(
"parent",
"Partent",
"The parent class",
JSC_TYPE_CLASS,
static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
}
/**
* JSCClassGetPropertyFunction:
* @jsc_class: a #JSCClass
* @context: a #JSCContext
* @instance: the @jsc_class instance
* @name: the property name
*
* The type of get_property in #JSCClassVTable. This is only required when you need to handle
* external properties not added to the prototype.
*
* Returns: (transfer full) (nullable): a #JSCValue or %NULL to forward the request to
* the parent class or prototype chain
*/
/**
* JSCClassSetPropertyFunction:
* @jsc_class: a #JSCClass
* @context: a #JSCContext
* @instance: the @jsc_class instance
* @name: the property name
* @value: the #JSCValue to set
*
* The type of set_property in #JSCClassVTable. This is only required when you need to handle
* external properties not added to the prototype.
*
* Returns: %TRUE if handled or %FALSE to forward the request to the parent class or prototype chain.
*/
/**
* JSCClassHasPropertyFunction:
* @jsc_class: a #JSCClass
* @context: a #JSCContext
* @instance: the @jsc_class instance
* @name: the property name
*
* The type of has_property in #JSCClassVTable. This is only required when you need to handle
* external properties not added to the prototype.
*
* Returns: %TRUE if @instance has a property with @name or %FALSE to forward the request
* to the parent class or prototype chain.
*/
/**
* JSCClassDeletePropertyFunction:
* @jsc_class: a #JSCClass
* @context: a #JSCContext
* @instance: the @jsc_class instance
* @name: the property name
*
* The type of delete_property in #JSCClassVTable. This is only required when you need to handle
* external properties not added to the prototype.
*
* Returns: %TRUE if handled or %FALSE to to forward the request to the parent class or prototype chain.
*/
/**
* JSCClassEnumeratePropertiesFunction:
* @jsc_class: a #JSCClass
* @context: a #JSCContext
* @instance: the @jsc_class instance
*
* The type of enumerate_properties in #JSCClassVTable. This is only required when you need to handle
* external properties not added to the prototype.
*
* Returns: (array zero-terminated=1) (transfer full) (nullable): a %NULL-terminated array of strings
* containing the property names, or %NULL if @instance doesn't have enumerable properties.
*/
/**
* JSCClassVTable:
* @get_property: a #JSCClassGetPropertyFunction for getting a property.
* @set_property: a #JSCClassSetPropertyFunction for setting a property.
* @has_property: a #JSCClassHasPropertyFunction for querying a property.
* @delete_property: a #JSCClassDeletePropertyFunction for deleting a property.
* @enumerate_properties: a #JSCClassEnumeratePropertiesFunction for enumerating properties.
*
* Virtual table for a JSCClass. This can be optionally used when registering a #JSCClass in a #JSCContext
* to provide a custom implementation for the class. All virtual functions are optional and can be set to
* %NULL to fallback to the default implementation.
*/
GRefPtr<JSCClass> jscClassCreate(JSCContext* context, const char* name, JSCClass* parentClass, JSCClassVTable* vtable, GDestroyNotify destroyFunction)
{
GRefPtr<JSCClass> jscClass = adoptGRef(JSC_CLASS(g_object_new(JSC_TYPE_CLASS, "context", context, "name", name, "parent", parentClass, nullptr)));
JSCClassPrivate* priv = jscClass->priv;
priv->vtable = vtable;
priv->destroyFunction = destroyFunction;
JSClassDefinition definition = kJSClassDefinitionEmpty;
definition.className = priv->name.data();
#define SET_IMPL_IF_NEEDED(definitionFunc, vtableFunc) \
for (auto* klass = jscClass.get(); klass; klass = klass->priv->parentClass) { \
if (klass->priv->vtable && klass->priv->vtable->vtableFunc) { \
definition.definitionFunc = definitionFunc; \
break; \
} \
}
SET_IMPL_IF_NEEDED(getProperty, get_property);
SET_IMPL_IF_NEEDED(setProperty, set_property);
SET_IMPL_IF_NEEDED(hasProperty, has_property);
SET_IMPL_IF_NEEDED(deleteProperty, delete_property);
SET_IMPL_IF_NEEDED(getPropertyNames, enumerate_properties);
#undef SET_IMPL_IF_NEEDED
priv->jsClass = JSClassCreate(&definition);
GUniquePtr<char> prototypeName(g_strdup_printf("%sPrototype", priv->name.data()));
JSClassDefinition prototypeDefinition = kJSClassDefinitionEmpty;
prototypeDefinition.className = prototypeName.get();
JSClassRef prototypeClass = JSClassCreate(&prototypeDefinition);
priv->prototype = jscContextGetOrCreateJSWrapper(context, prototypeClass);
JSClassRelease(prototypeClass);
if (priv->parentClass)
JSObjectSetPrototype(jscContextGetJSContext(context), toRef(priv->prototype.get()), toRef(priv->parentClass->priv->prototype.get()));
return jscClass;
}
JSClassRef jscClassGetJSClass(JSCClass* jscClass)
{
return jscClass->priv->jsClass;
}
JSC::JSObject* jscClassGetOrCreateJSWrapper(JSCClass* jscClass, JSCContext* context, gpointer wrappedObject)
{
JSCClassPrivate* priv = jscClass->priv;
return jscContextGetOrCreateJSWrapper(context, priv->jsClass, toRef(priv->prototype.get()), wrappedObject, priv->destroyFunction);
}
JSGlobalContextRef jscClassCreateContextWithJSWrapper(JSCClass* jscClass, JSCContext* context, gpointer wrappedObject)
{
JSCClassPrivate* priv = jscClass->priv;
return jscContextCreateContextWithJSWrapper(context, priv->jsClass, toRef(priv->prototype.get()), wrappedObject, priv->destroyFunction);
}
void jscClassInvalidate(JSCClass* jscClass)
{
jscClass->priv->context = nullptr;
}
/**
* jsc_class_get_name:
* @jsc_class: a @JSCClass
*
* Get the class name of @jsc_class
*
* Returns: (transfer none): the name of @jsc_class
*/
const char* jsc_class_get_name(JSCClass* jscClass)
{
g_return_val_if_fail(JSC_IS_CLASS(jscClass), nullptr);
return jscClass->priv->name.data();
}
/**
* jsc_class_get_parent:
* @jsc_class: a @JSCClass
*
* Get the parent class of @jsc_class
*
* Returns: (transfer none): the parent class of @jsc_class
*/
JSCClass* jsc_class_get_parent(JSCClass* jscClass)
{
g_return_val_if_fail(JSC_IS_CLASS(jscClass), nullptr);
return jscClass->priv->parentClass;
}
static GRefPtr<JSCValue> jscClassCreateConstructor(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, Optional<Vector<GType>>&& parameters)
{
// If the constructor doesn't have arguments, we need to swap the fake instance and user data to ensure
// user data is the first parameter and fake instance ignored.
GRefPtr<GClosure> closure;
if (parameters && parameters->isEmpty() && userData)
closure = adoptGRef(g_cclosure_new_swap(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
else
closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
JSCClassPrivate* priv = jscClass->priv;
JSC::ExecState* exec = toJS(priv->context);
JSC::VM& vm = exec->vm();
JSC::JSLockHolder locker(vm);
auto* functionObject = JSC::JSCCallbackFunction::create(vm, exec->lexicalGlobalObject(), String::fromUTF8(name),
JSC::JSCCallbackFunction::Type::Constructor, jscClass, WTFMove(closure), returnType, WTFMove(parameters));
auto context = jscContextGetOrCreate(priv->context);
auto constructor = jscContextGetOrCreateValue(context.get(), toRef(functionObject));
GRefPtr<JSCValue> prototype = jscContextGetOrCreateValue(context.get(), toRef(priv->prototype.get()));
auto nonEnumerable = static_cast<JSCValuePropertyFlags>(JSC_VALUE_PROPERTY_CONFIGURABLE | JSC_VALUE_PROPERTY_WRITABLE);
jsc_value_object_define_property_data(constructor.get(), "prototype", nonEnumerable, prototype.get());
jsc_value_object_define_property_data(prototype.get(), "constructor", nonEnumerable, constructor.get());
return constructor;
}
/**
* jsc_class_add_constructor: (skip)
* @jsc_class: a #JSCClass
* @name: (nullable): the constructor name or %NULL
* @callback: (scope async): a #GCallback to be called to create an instance of @jsc_class
* @user_data: (closure): user data to pass to @callback
* @destroy_notify: (nullable): destroy notifier for @user_data
* @return_type: the #GType of the constructor return value
* @n_params: the number of parameter types to follow or 0 if constructor doesn't receive parameters.
* @...: a list of #GType<!-- -->s, one for each parameter.
*
* Add a constructor to @jsc_class. If @name is %NULL, the class name will be used. When <function>new</function>
* is used with the constructor or jsc_value_constructor_call() is called, @callback is invoked receiving the
* parameters and @user_data as the last parameter. When the constructor object is cleared in the #JSCClass context,
* @destroy_notify is called with @user_data as parameter.
*
* This function creates the constructor, which needs to be added to an object as a property to be able to use it. Use
* jsc_context_set_value() to make the constructor available in the global object.
*
* Note that the value returned by @callback is adopted by @jsc_class, and the #GDestroyNotify passed to
* jsc_context_register_class() is responsible for disposing of it.
*
* Returns: (transfer full): a #JSCValue representing the class constructor.
*/
JSCValue* jsc_class_add_constructor(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned paramCount, ...)
{
g_return_val_if_fail(JSC_IS_CLASS(jscClass), nullptr);
g_return_val_if_fail(callback, nullptr);
JSCClassPrivate* priv = jscClass->priv;
g_return_val_if_fail(priv->context, nullptr);
if (!name)
name = priv->name.data();
va_list args;
va_start(args, paramCount);
Vector<GType> parameters;
if (paramCount) {
parameters.reserveInitialCapacity(paramCount);
for (unsigned i = 0; i < paramCount; ++i)
parameters.uncheckedAppend(va_arg(args, GType));
}
va_end(args);
return jscClassCreateConstructor(jscClass, name ? name : priv->name.data(), callback, userData, destroyNotify, returnType, WTFMove(parameters)).leakRef();
}
/**
* jsc_class_add_constructorv: (rename-to jsc_class_add_constructor)
* @jsc_class: a #JSCClass
* @name: (nullable): the constructor name or %NULL
* @callback: (scope async): a #GCallback to be called to create an instance of @jsc_class
* @user_data: (closure): user data to pass to @callback
* @destroy_notify: (nullable): destroy notifier for @user_data
* @return_type: the #GType of the constructor return value
* @n_parameters: the number of parameters
* @parameter_types: (nullable) (array length=n_parameters) (element-type GType): a list of #GType<!-- -->s, one for each parameter, or %NULL
*
* Add a constructor to @jsc_class. If @name is %NULL, the class name will be used. When <function>new</function>
* is used with the constructor or jsc_value_constructor_call() is called, @callback is invoked receiving the
* parameters and @user_data as the last parameter. When the constructor object is cleared in the #JSCClass context,
* @destroy_notify is called with @user_data as parameter.
*
* This function creates the constructor, which needs to be added to an object as a property to be able to use it. Use
* jsc_context_set_value() to make the constructor available in the global object.
*
* Note that the value returned by @callback is adopted by @jsc_class, and the #GDestroyNotify passed to
* jsc_context_register_class() is responsible for disposing of it.
*
* Returns: (transfer full): a #JSCValue representing the class constructor.
*/
JSCValue* jsc_class_add_constructorv(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned parametersCount, GType* parameterTypes)
{
g_return_val_if_fail(JSC_IS_CLASS(jscClass), nullptr);
g_return_val_if_fail(callback, nullptr);
g_return_val_if_fail(!parametersCount || parameterTypes, nullptr);
JSCClassPrivate* priv = jscClass->priv;
g_return_val_if_fail(priv->context, nullptr);
if (!name)
name = priv->name.data();
Vector<GType> parameters;
if (parametersCount) {
parameters.reserveInitialCapacity(parametersCount);
for (unsigned i = 0; i < parametersCount; ++i)
parameters.uncheckedAppend(parameterTypes[i]);
}
return jscClassCreateConstructor(jscClass, name ? name : priv->name.data(), callback, userData, destroyNotify, returnType, WTFMove(parameters)).leakRef();
}
/**
* jsc_class_add_constructor_variadic:
* @jsc_class: a #JSCClass
* @name: (nullable): the constructor name or %NULL
* @callback: (scope async): a #GCallback to be called to create an instance of @jsc_class
* @user_data: (closure): user data to pass to @callback
* @destroy_notify: (nullable): destroy notifier for @user_data
* @return_type: the #GType of the constructor return value
*
* Add a constructor to @jsc_class. If @name is %NULL, the class name will be used. When <function>new</function>
* is used with the constructor or jsc_value_constructor_call() is called, @callback is invoked receiving
* a #GPtrArray of #JSCValue<!-- -->s as arguments and @user_data as the last parameter. When the constructor object
* is cleared in the #JSCClass context, @destroy_notify is called with @user_data as parameter.
*
* This function creates the constructor, which needs to be added to an object as a property to be able to use it. Use
* jsc_context_set_value() to make the constructor available in the global object.
*
* Note that the value returned by @callback is adopted by @jsc_class, and the #GDestroyNotify passed to
* jsc_context_register_class() is responsible for disposing of it.
*
* Returns: (transfer full): a #JSCValue representing the class constructor.
*/
JSCValue* jsc_class_add_constructor_variadic(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType)
{
g_return_val_if_fail(JSC_IS_CLASS(jscClass), nullptr);
g_return_val_if_fail(callback, nullptr);
JSCClassPrivate* priv = jscClass->priv;
g_return_val_if_fail(jscClass->priv->context, nullptr);
if (!name)
name = priv->name.data();
return jscClassCreateConstructor(jscClass, name ? name : priv->name.data(), callback, userData, destroyNotify, returnType, WTF::nullopt).leakRef();
}
static void jscClassAddMethod(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, Optional<Vector<GType>>&& parameters)
{
JSCClassPrivate* priv = jscClass->priv;
GRefPtr<GClosure> closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
JSC::ExecState* exec = toJS(priv->context);
JSC::VM& vm = exec->vm();
JSC::JSLockHolder locker(vm);
auto* functionObject = toRef(JSC::JSCCallbackFunction::create(vm, exec->lexicalGlobalObject(), String::fromUTF8(name),
JSC::JSCCallbackFunction::Type::Method, jscClass, WTFMove(closure), returnType, WTFMove(parameters)));
auto context = jscContextGetOrCreate(priv->context);
auto method = jscContextGetOrCreateValue(context.get(), functionObject);
GRefPtr<JSCValue> prototype = jscContextGetOrCreateValue(context.get(), toRef(priv->prototype.get()));
auto nonEnumerable = static_cast<JSCValuePropertyFlags>(JSC_VALUE_PROPERTY_CONFIGURABLE | JSC_VALUE_PROPERTY_WRITABLE);
jsc_value_object_define_property_data(prototype.get(), name, nonEnumerable, method.get());
}
/**
* jsc_class_add_method: (skip)
* @jsc_class: a #JSCClass
* @name: the method name
* @callback: (scope async): a #GCallback to be called to invoke method @name of @jsc_class
* @user_data: (closure): user data to pass to @callback
* @destroy_notify: (nullable): destroy notifier for @user_data
* @return_type: the #GType of the method return value, or %G_TYPE_NONE if the method is void.
* @n_params: the number of parameter types to follow or 0 if the method doesn't receive parameters.
* @...: a list of #GType<!-- -->s, one for each parameter.
*
* Add method with @name to @jsc_class. When the method is called by JavaScript or jsc_value_object_invoke_method(),
* @callback is called receiving the class instance as first parameter, followed by the method parameters and then
* @user_data as last parameter. When the method is cleared in the #JSCClass context, @destroy_notify is called with
* @user_data as parameter.
*
* Note that the value returned by @callback must be transfer full. In case of non-refcounted boxed types, you should use
* %G_TYPE_POINTER instead of the actual boxed #GType to ensure that the instance owned by #JSCClass is used.
* If you really want to return a new copy of the boxed type, use #JSC_TYPE_VALUE and return a #JSCValue created
* with jsc_value_new_object() that receives the copy as the instance parameter.
*/
void jsc_class_add_method(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned paramCount, ...)
{
g_return_if_fail(JSC_IS_CLASS(jscClass));
g_return_if_fail(name);
g_return_if_fail(callback);
g_return_if_fail(jscClass->priv->context);
va_list args;
va_start(args, paramCount);
Vector<GType> parameters;
if (paramCount) {
parameters.reserveInitialCapacity(paramCount);
for (unsigned i = 0; i < paramCount; ++i)
parameters.uncheckedAppend(va_arg(args, GType));
}
va_end(args);
jscClassAddMethod(jscClass, name, callback, userData, destroyNotify, returnType, WTFMove(parameters));
}
/**
* jsc_class_add_methodv: (rename-to jsc_class_add_method)
* @jsc_class: a #JSCClass
* @name: the method name
* @callback: (scope async): a #GCallback to be called to invoke method @name of @jsc_class
* @user_data: (closure): user data to pass to @callback
* @destroy_notify: (nullable): destroy notifier for @user_data
* @return_type: the #GType of the method return value, or %G_TYPE_NONE if the method is void.
* @n_parameters: the number of parameter types to follow or 0 if the method doesn't receive parameters.
* @parameter_types: (nullable) (array length=n_parameters) (element-type GType): a list of #GType<!-- -->s, one for each parameter, or %NULL
*
* Add method with @name to @jsc_class. When the method is called by JavaScript or jsc_value_object_invoke_method(),
* @callback is called receiving the class instance as first parameter, followed by the method parameters and then
* @user_data as last parameter. When the method is cleared in the #JSCClass context, @destroy_notify is called with
* @user_data as parameter.
*
* Note that the value returned by @callback must be transfer full. In case of non-refcounted boxed types, you should use
* %G_TYPE_POINTER instead of the actual boxed #GType to ensure that the instance owned by #JSCClass is used.
* If you really want to return a new copy of the boxed type, use #JSC_TYPE_VALUE and return a #JSCValue created
* with jsc_value_new_object() that receives the copy as the instance parameter.
*/
void jsc_class_add_methodv(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned parametersCount, GType *parameterTypes)
{
g_return_if_fail(JSC_IS_CLASS(jscClass));
g_return_if_fail(name);
g_return_if_fail(callback);
g_return_if_fail(!parametersCount || parameterTypes);
g_return_if_fail(jscClass->priv->context);
Vector<GType> parameters;
if (parametersCount) {
parameters.reserveInitialCapacity(parametersCount);
for (unsigned i = 0; i < parametersCount; ++i)
parameters.uncheckedAppend(parameterTypes[i]);
}
jscClassAddMethod(jscClass, name, callback, userData, destroyNotify, returnType, WTFMove(parameters));
}
/**
* jsc_class_add_method_variadic:
* @jsc_class: a #JSCClass
* @name: the method name
* @callback: (scope async): a #GCallback to be called to invoke method @name of @jsc_class
* @user_data: (closure): user data to pass to @callback
* @destroy_notify: (nullable): destroy notifier for @user_data
* @return_type: the #GType of the method return value, or %G_TYPE_NONE if the method is void.
*
* Add method with @name to @jsc_class. When the method is called by JavaScript or jsc_value_object_invoke_method(),
* @callback is called receiving the class instance as first parameter, followed by a #GPtrArray of #JSCValue<!-- -->s
* with the method arguments and then @user_data as last parameter. When the method is cleared in the #JSCClass context,
* @destroy_notify is called with @user_data as parameter.
*
* Note that the value returned by @callback must be transfer full. In case of non-refcounted boxed types, you should use
* %G_TYPE_POINTER instead of the actual boxed #GType to ensure that the instance owned by #JSCClass is used.
* If you really want to return a new copy of the boxed type, use #JSC_TYPE_VALUE and return a #JSCValue created
* with jsc_value_new_object() that receives the copy as the instance parameter.
*/
void jsc_class_add_method_variadic(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType)
{
g_return_if_fail(JSC_IS_CLASS(jscClass));
g_return_if_fail(name);
g_return_if_fail(callback);
g_return_if_fail(jscClass->priv->context);
jscClassAddMethod(jscClass, name, callback, userData, destroyNotify, returnType, WTF::nullopt);
}
/**
* jsc_class_add_property:
* @jsc_class: a #JSCClass
* @name: the property name
* @property_type: the #GType of the property value
* @getter: (scope async) (nullable): a #GCallback to be called to get the property value
* @setter: (scope async) (nullable): a #GCallback to be called to set the property value
* @user_data: (closure): user data to pass to @getter and @setter
* @destroy_notify: (nullable): destroy notifier for @user_data
*
* Add a property with @name to @jsc_class. When the property value needs to be getted, @getter is called
* receiving the the class instance as first parameter and @user_data as last parameter. When the property
* value needs to be set, @setter is called receiving the the class instance as first parameter, followed
* by the value to be set and then @user_data as the last parameter. When the property is cleared in the
* #JSCClass context, @destroy_notify is called with @user_data as parameter.
*
* Note that the value returned by @getter must be transfer full. In case of non-refcounted boxed types, you should use
* %G_TYPE_POINTER instead of the actual boxed #GType to ensure that the instance owned by #JSCClass is used.
* If you really want to return a new copy of the boxed type, use #JSC_TYPE_VALUE and return a #JSCValue created
* with jsc_value_new_object() that receives the copy as the instance parameter.
*/
void jsc_class_add_property(JSCClass* jscClass, const char* name, GType propertyType, GCallback getter, GCallback setter, gpointer userData, GDestroyNotify destroyNotify)
{
g_return_if_fail(JSC_IS_CLASS(jscClass));
g_return_if_fail(name);
g_return_if_fail(propertyType != G_TYPE_INVALID && propertyType != G_TYPE_NONE);
g_return_if_fail(getter || setter);
JSCClassPrivate* priv = jscClass->priv;
g_return_if_fail(priv->context);
auto context = jscContextGetOrCreate(priv->context);
GRefPtr<JSCValue> prototype = jscContextGetOrCreateValue(context.get(), toRef(priv->prototype.get()));
jsc_value_object_define_property_accessor(prototype.get(), name, JSC_VALUE_PROPERTY_CONFIGURABLE, propertyType, getter, setter, userData, destroyNotify);
}

154
API/glib/JSCClass.h Normal file
View File

@ -0,0 +1,154 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION) && !defined(WEBKIT2_COMPILATION)
#error "Only <jsc/jsc.h> can be included directly."
#endif
#ifndef JSCClass_h
#define JSCClass_h
#include <glib-object.h>
#include <jsc/JSCDefines.h>
#include <jsc/JSCValue.h>
G_BEGIN_DECLS
#define JSC_TYPE_CLASS (jsc_class_get_type())
#define JSC_CLASS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), JSC_TYPE_CLASS, JSCClass))
#define JSC_IS_CLASS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), JSC_TYPE_CLASS))
typedef struct _JSCClass JSCClass;
typedef struct _JSCClassClass JSCClassClass;
typedef struct _JSCContext JSCContext;
typedef JSCValue *(*JSCClassGetPropertyFunction) (JSCClass *jsc_class,
JSCContext *context,
gpointer instance,
const char *name);
typedef gboolean (*JSCClassSetPropertyFunction) (JSCClass *jsc_class,
JSCContext *context,
gpointer instance,
const char *name,
JSCValue *value);
typedef gboolean (*JSCClassHasPropertyFunction) (JSCClass *jsc_class,
JSCContext *context,
gpointer instance,
const char *name);
typedef gboolean (*JSCClassDeletePropertyFunction) (JSCClass *jsc_class,
JSCContext *context,
gpointer instance,
const char *name);
typedef gchar **(*JSCClassEnumeratePropertiesFunction) (JSCClass *jsc_class,
JSCContext *context,
gpointer instance);
typedef struct {
JSCClassGetPropertyFunction get_property;
JSCClassSetPropertyFunction set_property;
JSCClassHasPropertyFunction has_property;
JSCClassDeletePropertyFunction delete_property;
JSCClassEnumeratePropertiesFunction enumerate_properties;
/*< private >*/
void (*_jsc_reserved0) (void);
void (*_jsc_reserved1) (void);
void (*_jsc_reserved2) (void);
void (*_jsc_reserved3) (void);
} JSCClassVTable;
JSC_API GType
jsc_class_get_type (void);
JSC_API const char *
jsc_class_get_name (JSCClass *jsc_class);
JSC_API JSCClass *
jsc_class_get_parent (JSCClass *jsc_class);
JSC_API JSCValue *
jsc_class_add_constructor (JSCClass *jsc_class,
const char *name,
GCallback callback,
gpointer user_data,
GDestroyNotify destroy_notify,
GType return_type,
guint n_params,
...);
JSC_API JSCValue *
jsc_class_add_constructorv (JSCClass *jsc_class,
const char *name,
GCallback callback,
gpointer user_data,
GDestroyNotify destroy_notify,
GType return_type,
guint n_parameters,
GType *parameter_types);
JSC_API JSCValue *
jsc_class_add_constructor_variadic (JSCClass *jsc_class,
const char *name,
GCallback callback,
gpointer user_data,
GDestroyNotify destroy_notify,
GType return_type);
JSC_API void
jsc_class_add_method (JSCClass *jsc_class,
const char *name,
GCallback callback,
gpointer user_data,
GDestroyNotify destroy_notify,
GType return_type,
guint n_params,
...);
JSC_API void
jsc_class_add_methodv (JSCClass *jsc_class,
const char *name,
GCallback callback,
gpointer user_data,
GDestroyNotify destroy_notify,
GType return_type,
guint n_parameters,
GType *parameter_types);
JSC_API void
jsc_class_add_method_variadic (JSCClass *jsc_class,
const char *name,
GCallback callback,
gpointer user_data,
GDestroyNotify destroy_notify,
GType return_type);
JSC_API void
jsc_class_add_property (JSCClass *jsc_class,
const char *name,
GType property_type,
GCallback getter,
GCallback setter,
gpointer user_data,
GDestroyNotify destroy_notify);
G_END_DECLS
#endif /* JSCClass_h */

View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include "APICast.h"
#include "JSCClass.h"
#include "JSCContext.h"
#include "JSCValue.h"
#include <wtf/glib/GRefPtr.h>
GRefPtr<JSCClass> jscClassCreate(JSCContext*, const char*, JSCClass*, JSCClassVTable*, GDestroyNotify);
JSClassRef jscClassGetJSClass(JSCClass*);
JSC::JSObject* jscClassGetOrCreateJSWrapper(JSCClass*, JSCContext*, gpointer);
JSGlobalContextRef jscClassCreateContextWithJSWrapper(JSCClass*, JSCContext*, gpointer);
void jscClassInvalidate(JSCClass*);

1081
API/glib/JSCContext.cpp Normal file

File diff suppressed because it is too large Load Diff

187
API/glib/JSCContext.h Normal file
View File

@ -0,0 +1,187 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION) && !defined(WEBKIT2_COMPILATION)
#error "Only <jsc/jsc.h> can be included directly."
#endif
#ifndef JSCContext_h
#define JSCContext_h
#include <glib-object.h>
#include <jsc/JSCDefines.h>
#include <jsc/JSCException.h>
#include <jsc/JSCClass.h>
#include <jsc/JSCValue.h>
#include <jsc/JSCVirtualMachine.h>
G_BEGIN_DECLS
#define JSC_TYPE_CONTEXT (jsc_context_get_type())
#define JSC_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), JSC_TYPE_CONTEXT, JSCContext))
#define JSC_IS_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), JSC_TYPE_CONTEXT))
#define JSC_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), JSC_TYPE_CONTEXT, JSCContextClass))
#define JSC_IS_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JSC_TYPE_CONTEXT))
#define JSC_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), JSC_TYPE_CONTEXT, JSCContextClass))
typedef struct _JSCContext JSCContext;
typedef struct _JSCContextClass JSCContextClass;
typedef struct _JSCContextPrivate JSCContextPrivate;
typedef void (* JSCExceptionHandler) (JSCContext *context,
JSCException *exception,
gpointer user_data);
typedef enum {
JSC_CHECK_SYNTAX_MODE_SCRIPT,
JSC_CHECK_SYNTAX_MODE_MODULE
} JSCCheckSyntaxMode;
typedef enum {
JSC_CHECK_SYNTAX_RESULT_SUCCESS,
JSC_CHECK_SYNTAX_RESULT_RECOVERABLE_ERROR,
JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR,
JSC_CHECK_SYNTAX_RESULT_UNTERMINATED_LITERAL_ERROR,
JSC_CHECK_SYNTAX_RESULT_OUT_OF_MEMORY_ERROR,
JSC_CHECK_SYNTAX_RESULT_STACK_OVERFLOW_ERROR,
} JSCCheckSyntaxResult;
struct _JSCContext {
GObject parent;
/*< private >*/
JSCContextPrivate *priv;
};
struct _JSCContextClass {
GObjectClass parent_class;
void (*_jsc_reserved0) (void);
void (*_jsc_reserved1) (void);
void (*_jsc_reserved2) (void);
void (*_jsc_reserved3) (void);
};
JSC_API GType
jsc_context_get_type (void);
JSC_API JSCContext *
jsc_context_new (void);
JSC_API JSCContext *
jsc_context_new_with_virtual_machine (JSCVirtualMachine *vm);
JSC_API JSCVirtualMachine *
jsc_context_get_virtual_machine (JSCContext *context);
JSC_API JSCException *
jsc_context_get_exception (JSCContext *context);
JSC_API void
jsc_context_throw (JSCContext *context,
const char *error_message);
JSC_API void
jsc_context_throw_printf (JSCContext *context,
const char *format,
...) G_GNUC_PRINTF (2, 3);
JSC_API void
jsc_context_throw_with_name (JSCContext *context,
const char *error_name,
const char *error_message);
JSC_API void
jsc_context_throw_with_name_printf (JSCContext *context,
const char *error_name,
const char *format,
...) G_GNUC_PRINTF (3, 4);
JSC_API void
jsc_context_throw_exception (JSCContext *context,
JSCException *exception);
JSC_API void
jsc_context_clear_exception (JSCContext *context);
JSC_API void
jsc_context_push_exception_handler (JSCContext *context,
JSCExceptionHandler handler,
gpointer user_data,
GDestroyNotify destroy_notify);
JSC_API void
jsc_context_pop_exception_handler (JSCContext *context);
JSC_API JSCContext *
jsc_context_get_current (void);
JSC_API JSCValue *
jsc_context_evaluate (JSCContext *context,
const char *code,
gssize length) G_GNUC_WARN_UNUSED_RESULT;
JSC_API JSCValue *
jsc_context_evaluate_with_source_uri (JSCContext *context,
const char *code,
gssize length,
const char *uri,
guint line_number) G_GNUC_WARN_UNUSED_RESULT;
JSC_API JSCValue *
jsc_context_evaluate_in_object (JSCContext *context,
const char *code,
gssize length,
gpointer object_instance,
JSCClass *object_class,
const char *uri,
guint line_number,
JSCValue **object) G_GNUC_WARN_UNUSED_RESULT;
JSC_API JSCCheckSyntaxResult
jsc_context_check_syntax (JSCContext *context,
const char *code,
gssize length,
JSCCheckSyntaxMode mode,
const char *uri,
unsigned line_number,
JSCException **exception);
JSC_API JSCValue *
jsc_context_get_global_object (JSCContext *context);
JSC_API void
jsc_context_set_value (JSCContext *context,
const char *name,
JSCValue *value);
JSC_API JSCValue *
jsc_context_get_value (JSCContext *context,
const char *name);
JSC_API JSCClass *
jsc_context_register_class (JSCContext *context,
const char *name,
JSCClass *parent_class,
JSCClassVTable *vtable,
GDestroyNotify destroy_notify);
G_END_DECLS
#endif /* JSCContext_h */

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include "APICast.h"
#include "JSCContext.h"
#include "JSCValue.h"
#include "JSContextRef.h"
#include <wtf/glib/GRefPtr.h>
GRefPtr<JSCContext> jscContextGetOrCreate(JSGlobalContextRef);
JSGlobalContextRef jscContextGetJSContext(JSCContext*);
GRefPtr<JSCValue> jscContextGetOrCreateValue(JSCContext*, JSValueRef);
void jscContextValueDestroyed(JSCContext*, JSValueRef);
JSC::JSObject* jscContextGetJSWrapper(JSCContext*, gpointer);
JSC::JSObject* jscContextGetOrCreateJSWrapper(JSCContext*, JSClassRef, JSValueRef prototype = nullptr, gpointer = nullptr, GDestroyNotify = nullptr);
JSGlobalContextRef jscContextCreateContextWithJSWrapper(JSCContext*, JSClassRef, JSValueRef prototype = nullptr, gpointer = nullptr, GDestroyNotify = nullptr);
gpointer jscContextWrappedObject(JSCContext*, JSObjectRef);
JSCClass* jscContextGetRegisteredClass(JSCContext*, JSClassRef);
struct CallbackData {
GRefPtr<JSCContext> context;
GRefPtr<JSCException> preservedException;
JSValueRef calleeValue;
JSValueRef thisValue;
size_t argumentCount;
const JSValueRef* arguments;
CallbackData* next;
};
CallbackData jscContextPushCallback(JSCContext*, JSValueRef calleeValue, JSValueRef thisValue, size_t argumentCount, const JSValueRef* arguments);
void jscContextPopCallback(JSCContext*, CallbackData&&);
bool jscContextHandleExceptionIfNeeded(JSCContext*, JSValueRef);
JSValueRef jscContextGArrayToJSArray(JSCContext*, GPtrArray*, JSValueRef* exception);
JSValueRef jscContextGValueToJSValue(JSCContext*, const GValue*, JSValueRef* exception);
void jscContextJSValueToGValue(JSCContext*, JSValueRef, GType, GValue*, JSValueRef* exception);

48
API/glib/JSCDefines.h Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2011 Igalia S.L.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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.
*/
#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION)
#error "Only <jsc/jsc.h> can be included directly."
#endif
#ifndef JSCDefines_h
#define JSCDefines_h
#include <glib.h>
#ifdef G_OS_WIN32
# if defined(BUILDING_JavaScriptCore) || defined(STATICALLY_LINKED_WITH_JavaScriptCore)
# define JSC_API __declspec(dllexport)
# else
# define JSC_API __declspec(dllimport)
# endif
#else
# define JSC_API __attribute__((visibility("default")))
#endif
#define JSC_DEPRECATED JSC_API G_DEPRECATED
#define JSC_DEPRECATED_FOR(f) JSC_API G_DEPRECATED_FOR(f)
#endif /* JSCDefines_h */

423
API/glib/JSCException.cpp Normal file
View File

@ -0,0 +1,423 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "JSCException.h"
#include "APICast.h"
#include "JSCContextPrivate.h"
#include "JSCExceptionPrivate.h"
#include "JSCInlines.h"
#include "JSRetainPtr.h"
#include "StrongInlines.h"
#include <glib/gprintf.h>
#include <wtf/glib/GUniquePtr.h>
#include <wtf/glib/WTFGType.h>
/**
* SECTION: JSCException
* @short_description: JavaScript exception
* @title: JSCException
* @see_also: JSCContext
*
* JSCException represents a JavaScript exception.
*/
struct _JSCExceptionPrivate {
JSCContext* context;
JSC::Strong<JSC::JSObject> jsException;
bool cached;
GUniquePtr<char> errorName;
GUniquePtr<char> message;
unsigned lineNumber;
unsigned columnNumber;
GUniquePtr<char> sourceURI;
GUniquePtr<char> backtrace;
};
WEBKIT_DEFINE_TYPE(JSCException, jsc_exception, G_TYPE_OBJECT)
static void jscExceptionDispose(GObject* object)
{
JSCExceptionPrivate* priv = JSC_EXCEPTION(object)->priv;
if (priv->context) {
g_object_remove_weak_pointer(G_OBJECT(priv->context), reinterpret_cast<void**>(&priv->context));
priv->context = nullptr;
}
G_OBJECT_CLASS(jsc_exception_parent_class)->dispose(object);
}
static void jsc_exception_class_init(JSCExceptionClass* klass)
{
GObjectClass* objClass = G_OBJECT_CLASS(klass);
objClass->dispose = jscExceptionDispose;
}
GRefPtr<JSCException> jscExceptionCreate(JSCContext* context, JSValueRef jsException)
{
GRefPtr<JSCException> exception = adoptGRef(JSC_EXCEPTION(g_object_new(JSC_TYPE_EXCEPTION, nullptr)));
auto* jsContext = jscContextGetJSContext(context);
JSC::ExecState* exec = toJS(jsContext);
JSC::VM& vm = exec->vm();
JSC::JSLockHolder locker(vm);
exception->priv->jsException.set(vm, toJS(JSValueToObject(jsContext, jsException, nullptr)));
// The context has a strong reference to the exception, so we can't ref the context. We use a weak
// pointer instead to invalidate the exception if the context is destroyed before.
exception->priv->context = context;
g_object_add_weak_pointer(G_OBJECT(context), reinterpret_cast<void**>(&exception->priv->context));
return exception;
}
JSValueRef jscExceptionGetJSValue(JSCException* exception)
{
return toRef(exception->priv->jsException.get());
}
void jscExceptionEnsureProperties(JSCException* exception)
{
JSCExceptionPrivate* priv = exception->priv;
if (priv->cached)
return;
priv->cached = true;
auto value = jscContextGetOrCreateValue(priv->context, toRef(priv->jsException.get()));
auto propertyValue = adoptGRef(jsc_value_object_get_property(value.get(), "name"));
if (!jsc_value_is_undefined(propertyValue.get()))
priv->errorName.reset(jsc_value_to_string(propertyValue.get()));
propertyValue = adoptGRef(jsc_value_object_get_property(value.get(), "message"));
if (!jsc_value_is_undefined(propertyValue.get()))
priv->message.reset(jsc_value_to_string(propertyValue.get()));
propertyValue = adoptGRef(jsc_value_object_get_property(value.get(), "line"));
if (!jsc_value_is_undefined(propertyValue.get()))
priv->lineNumber = jsc_value_to_int32(propertyValue.get());
propertyValue = adoptGRef(jsc_value_object_get_property(value.get(), "column"));
if (!jsc_value_is_undefined(propertyValue.get()))
priv->columnNumber = jsc_value_to_int32(propertyValue.get());
propertyValue = adoptGRef(jsc_value_object_get_property(value.get(), "sourceURL"));
if (!jsc_value_is_undefined(propertyValue.get()))
priv->sourceURI.reset(jsc_value_to_string(propertyValue.get()));
propertyValue = adoptGRef(jsc_value_object_get_property(value.get(), "stack"));
if (!jsc_value_is_undefined(propertyValue.get()))
priv->backtrace.reset(jsc_value_to_string(propertyValue.get()));
}
/**
* jsc_exception_new:
* @context: a #JSCContext
* @message: the error message
*
* Create a new #JSCException in @context with @message.
*
* Returns: (transfer full): a new #JSCException.
*/
JSCException* jsc_exception_new(JSCContext* context, const char* message)
{
return jsc_exception_new_with_name(context, nullptr, message);
}
/**
* jsc_exception_new_printf:
* @context: a #JSCContext
* @format: the string format
* @...: the parameters to insert into the format string
*
* Create a new #JSCException in @context using a formatted string
* for the message.
*
* Returns: (transfer full): a new #JSCException.
*/
JSCException* jsc_exception_new_printf(JSCContext* context, const char* format, ...)
{
va_list args;
va_start(args, format);
auto* exception = jsc_exception_new_vprintf(context, format, args);
va_end(args);
return exception;
}
/**
* jsc_exception_new_vprintf:
* @context: a #JSCContext
* @format: the string format
* @args: the parameters to insert into the format string
*
* Create a new #JSCException in @context using a formatted string
* for the message. This is similar to jsc_exception_new_printf()
* except that the arguments to the format string are passed as a va_list.
*
* Returns: (transfer full): a new #JSCException.
*/
JSCException* jsc_exception_new_vprintf(JSCContext* context, const char* format, va_list args)
{
g_return_val_if_fail(JSC_IS_CONTEXT(context), nullptr);
GUniqueOutPtr<char> buffer;
g_vasprintf(&buffer.outPtr(), format, args);
return jsc_exception_new(context, buffer.get());
}
/**
* jsc_exception_new_with_name:
* @context: a #JSCContext
* @name: the error name
* @message: the error message
*
* Create a new #JSCException in @context with @name and @message.
*
* Returns: (transfer full): a new #JSCException.
*/
JSCException* jsc_exception_new_with_name(JSCContext* context, const char* name, const char* message)
{
g_return_val_if_fail(JSC_IS_CONTEXT(context), nullptr);
auto* jsContext = jscContextGetJSContext(context);
JSValueRef jsMessage = nullptr;
if (message) {
JSRetainPtr<JSStringRef> jsMessageString(Adopt, JSStringCreateWithUTF8CString(message));
jsMessage = JSValueMakeString(jsContext, jsMessageString.get());
}
auto exception = jscExceptionCreate(context, JSObjectMakeError(jsContext, jsMessage ? 1 : 0, &jsMessage, nullptr));
if (name) {
auto value = jscContextGetOrCreateValue(context, toRef(exception->priv->jsException.get()));
GRefPtr<JSCValue> nameValue = adoptGRef(jsc_value_new_string(context, name));
jsc_value_object_set_property(value.get(), "name", nameValue.get());
}
return exception.leakRef();
}
/**
* jsc_exception_new_with_name_printf:
* @context: a #JSCContext
* @name: the error name
* @format: the string format
* @...: the parameters to insert into the format string
*
* Create a new #JSCException in @context with @name and using a formatted string
* for the message.
*
* Returns: (transfer full): a new #JSCException.
*/
JSCException* jsc_exception_new_with_name_printf(JSCContext* context, const char* name, const char* format, ...)
{
va_list args;
va_start(args, format);
auto* exception = jsc_exception_new_with_name_vprintf(context, name, format, args);
va_end(args);
return exception;
}
/**
* jsc_exception_new_with_name_vprintf:
* @context: a #JSCContext
* @name: the error name
* @format: the string format
* @args: the parameters to insert into the format string
*
* Create a new #JSCException in @context with @name and using a formatted string
* for the message. This is similar to jsc_exception_new_with_name_printf()
* except that the arguments to the format string are passed as a va_list.
*
* Returns: (transfer full): a new #JSCException.
*/
JSCException* jsc_exception_new_with_name_vprintf(JSCContext* context, const char* name, const char* format, va_list args)
{
g_return_val_if_fail(JSC_IS_CONTEXT(context), nullptr);
GUniqueOutPtr<char> buffer;
g_vasprintf(&buffer.outPtr(), format, args);
return jsc_exception_new_with_name(context, name, buffer.get());
}
/**
* jsc_exception_get_name:
* @exception: a #JSCException
*
* Get the error name of @exception
*
* Returns: the @exception error name.
*/
const char* jsc_exception_get_name(JSCException* exception)
{
g_return_val_if_fail(JSC_IS_EXCEPTION(exception), nullptr);
JSCExceptionPrivate* priv = exception->priv;
g_return_val_if_fail(priv->context, nullptr);
jscExceptionEnsureProperties(exception);
return priv->errorName.get();
}
/**
* jsc_exception_get_message:
* @exception: a #JSCException
*
* Get the error message of @exception.
*
* Returns: the @exception error message.
*/
const char* jsc_exception_get_message(JSCException* exception)
{
g_return_val_if_fail(JSC_IS_EXCEPTION(exception), nullptr);
JSCExceptionPrivate* priv = exception->priv;
g_return_val_if_fail(priv->context, nullptr);
jscExceptionEnsureProperties(exception);
return priv->message.get();
}
/**
* jsc_exception_get_line_number:
* @exception: a #JSCException
*
* Get the line number at which @exception happened.
*
* Returns: the line number of @exception.
*/
guint jsc_exception_get_line_number(JSCException* exception)
{
g_return_val_if_fail(JSC_IS_EXCEPTION(exception), 0);
JSCExceptionPrivate* priv = exception->priv;
g_return_val_if_fail(priv->context, 0);
jscExceptionEnsureProperties(exception);
return priv->lineNumber;
}
/**
* jsc_exception_get_column_number:
* @exception: a #JSCException
*
* Get the column number at which @exception happened.
*
* Returns: the column number of @exception.
*/
guint jsc_exception_get_column_number(JSCException* exception)
{
g_return_val_if_fail(JSC_IS_EXCEPTION(exception), 0);
JSCExceptionPrivate* priv = exception->priv;
g_return_val_if_fail(priv->context, 0);
jscExceptionEnsureProperties(exception);
return priv->columnNumber;
}
/**
* jsc_exception_get_source_uri:
* @exception: a #JSCException
*
* Get the source URI of @exception.
*
* Returns: (nullable): the the source URI of @exception, or %NULL.
*/
const char* jsc_exception_get_source_uri(JSCException* exception)
{
g_return_val_if_fail(JSC_IS_EXCEPTION(exception), nullptr);
JSCExceptionPrivate* priv = exception->priv;
g_return_val_if_fail(priv->context, nullptr);
jscExceptionEnsureProperties(exception);
return priv->sourceURI.get();
}
/**
* jsc_exception_get_backtrace_string:
* @exception: a #JSCException
*
* Get a string with the exception backtrace.
*
* Returns: (nullable): the exception backtrace string or %NULL.
*/
const char* jsc_exception_get_backtrace_string(JSCException* exception)
{
g_return_val_if_fail(JSC_IS_EXCEPTION(exception), nullptr);
JSCExceptionPrivate* priv = exception->priv;
g_return_val_if_fail(priv->context, nullptr);
jscExceptionEnsureProperties(exception);
return priv->backtrace.get();
}
/**
* jsc_exception_to_string:
* @exception: a #JSCException
*
* Get the string representation of @exception error.
*
* Returns: (transfer full): the string representation of @exception.
*/
char* jsc_exception_to_string(JSCException* exception)
{
g_return_val_if_fail(JSC_IS_EXCEPTION(exception), nullptr);
JSCExceptionPrivate* priv = exception->priv;
g_return_val_if_fail(priv->context, nullptr);
auto value = jscContextGetOrCreateValue(priv->context, toRef(priv->jsException.get()));
return jsc_value_to_string(value.get());
}
/**
* jsc_exception_report:
* @exception: a #JSCException
*
* Return a report message of @exception, containing all the possible details such us
* source URI, line, column and backtrace, and formatted to be printed.
*
* Returns: (transfer full): a new string with the exception report
*/
char* jsc_exception_report(JSCException* exception)
{
g_return_val_if_fail(JSC_IS_EXCEPTION(exception), nullptr);
JSCExceptionPrivate* priv = exception->priv;
g_return_val_if_fail(priv->context, nullptr);
jscExceptionEnsureProperties(exception);
GString* report = g_string_new(nullptr);
if (priv->sourceURI)
report = g_string_append(report, priv->sourceURI.get());
if (priv->lineNumber)
g_string_append_printf(report, ":%d", priv->lineNumber);
if (priv->columnNumber)
g_string_append_printf(report, ":%d", priv->columnNumber);
report = g_string_append_c(report, ' ');
GUniquePtr<char> errorMessage(jsc_exception_to_string(exception));
if (errorMessage)
report = g_string_append(report, errorMessage.get());
report = g_string_append_c(report, '\n');
if (priv->backtrace) {
GUniquePtr<char*> lines(g_strsplit(priv->backtrace.get(), "\n", 0));
for (unsigned i = 0; lines.get()[i]; ++i)
g_string_append_printf(report, " %s\n", lines.get()[i]);
}
return g_string_free(report, FALSE);
}

121
API/glib/JSCException.h Normal file
View File

@ -0,0 +1,121 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION) && !defined(WEBKIT2_COMPILATION)
#error "Only <jsc/jsc.h> can be included directly."
#endif
#ifndef JSCException_h
#define JSCException_h
#include <glib-object.h>
#include <jsc/JSCDefines.h>
G_BEGIN_DECLS
#define JSC_TYPE_EXCEPTION (jsc_exception_get_type())
#define JSC_EXCEPTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), JSC_TYPE_EXCEPTION, JSCException))
#define JSC_IS_EXCEPTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), JSC_TYPE_EXCEPTION))
#define JSC_EXCEPTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), JSC_TYPE_EXCEPTION, JSCExceptionClass))
#define JSC_IS_EXCEPTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JSC_TYPE_EXCEPTION))
#define JSC_EXCEPTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), JSC_TYPE_EXCEPTION, JSCExceptionClass))
typedef struct _JSCException JSCException;
typedef struct _JSCExceptionClass JSCExceptionClass;
typedef struct _JSCExceptionPrivate JSCExceptionPrivate;
typedef struct _JSCContext JSCContext;
struct _JSCException {
GObject parent;
/*< private >*/
JSCExceptionPrivate *priv;
};
struct _JSCExceptionClass {
GObjectClass parent_class;
void (*_jsc_reserved0) (void);
void (*_jsc_reserved1) (void);
void (*_jsc_reserved2) (void);
void (*_jsc_reserved3) (void);
};
JSC_API GType
jsc_exception_get_type (void);
JSC_API JSCException *
jsc_exception_new (JSCContext *context,
const char *message);
JSC_API JSCException *
jsc_exception_new_printf (JSCContext *context,
const char *format,
...) G_GNUC_PRINTF (2, 3);
JSC_API JSCException *
jsc_exception_new_vprintf (JSCContext *context,
const char *format,
va_list args) G_GNUC_PRINTF(2, 0);
JSC_API JSCException *
jsc_exception_new_with_name (JSCContext *context,
const char *name,
const char *message);
JSC_API JSCException *
jsc_exception_new_with_name_printf (JSCContext *context,
const char *name,
const char *format,
...) G_GNUC_PRINTF (3, 4);
JSC_API JSCException *
jsc_exception_new_with_name_vprintf (JSCContext *context,
const char *name,
const char *format,
va_list args) G_GNUC_PRINTF (3, 0);
JSC_API const char *
jsc_exception_get_name (JSCException *exception);
JSC_API const char *
jsc_exception_get_message (JSCException *exception);
JSC_API guint
jsc_exception_get_line_number (JSCException *exception);
JSC_API guint
jsc_exception_get_column_number (JSCException *exception);
JSC_API const char *
jsc_exception_get_source_uri (JSCException *exception);
JSC_API const char *
jsc_exception_get_backtrace_string (JSCException *exception);
JSC_API char *
jsc_exception_to_string (JSCException *exception);
JSC_API char *
jsc_exception_report (JSCException *exception);
G_END_DECLS
#endif /* JSCException_h */

View File

@ -0,0 +1,27 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include "JSCContext.h"
#include "JSCException.h"
#include <wtf/glib/GRefPtr.h>
GRefPtr<JSCException> jscExceptionCreate(JSCContext*, JSValueRef);
JSValueRef jscExceptionGetJSValue(JSCException*);

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <glib.h>
#include <wtf/FastMalloc.h>
namespace JSC {
class JSCGLibWrapperObject {
WTF_MAKE_FAST_ALLOCATED;
public:
JSCGLibWrapperObject(gpointer object, GDestroyNotify destroyFunction)
: m_object(object)
, m_destroyFunction(destroyFunction)
{
}
~JSCGLibWrapperObject()
{
if (m_destroyFunction)
m_destroyFunction(m_object);
}
gpointer object() const { return m_object; }
private:
gpointer m_object { nullptr };
GDestroyNotify m_destroyFunction { nullptr };
};
} // namespace JSC

726
API/glib/JSCOptions.cpp Normal file
View File

@ -0,0 +1,726 @@
/*
* Copyright (C) 2019 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "JSCOptions.h"
#include "Options.h"
#include <glib/gi18n-lib.h>
#include <wtf/Vector.h>
#include <wtf/glib/GUniquePtr.h>
/**
* SECTION: JSCOptions
* @short_description: JavaScript options
* @title: JSCOptions
*
* JavaScript options allow changing the behavior of the JavaScript engine.
* They affect the way the engine works, so it's encouraged to set the options
* at the very beginning of the program execution, before any other JavaScript
* API call. Most of the options are only useful for testing and debugging.
* Only a few of them are documented; you can use the undocumented options at
* your own risk. (You can find the list of options in the WebKit source code).
*
* The API allows to set and get any option using the types defined in #JSCOptionType.
* You can also iterate all the available options using jsc_options_foreach() and
* passing a #JSCOptionsFunc callback. If your application uses #GOptionContext to handle
* command line arguments, you can easily integrate the JSCOptions by adding the
* #GOptionGroup returned by jsc_options_get_option_group().
*
* Since: 2.24
*/
using namespace JSC;
using int32 = int32_t;
using size = size_t;
static bool valueFromGValue(const GValue* gValue, bool& value)
{
value = g_value_get_boolean(gValue);
return true;
}
static void valueToGValue(bool value, GValue* gValue)
{
g_value_set_boolean(gValue, value);
}
static bool valueFromGValue(const GValue* gValue, int32_t& value)
{
value = g_value_get_int(gValue);
return true;
}
static void valueToGValue(int32_t value, GValue* gValue)
{
g_value_set_int(gValue, value);
}
#if CPU(ADDRESS64)
static bool valueFromGValue(const GValue* gValue, unsigned& value)
{
value = g_value_get_uint(gValue);
return true;
}
static void valueToGValue(unsigned value, GValue* gValue)
{
g_value_set_uint(gValue, value);
}
#endif
static bool valueFromGValue(const GValue* gValue, size_t& value)
{
value = GPOINTER_TO_SIZE(g_value_get_pointer(gValue));
return true;
}
static void valueToGValue(size_t value, GValue* gValue)
{
g_value_set_pointer(gValue, GSIZE_TO_POINTER(value));
}
static bool valueFromGValue(const GValue* gValue, const char*& value)
{
value = g_value_dup_string(gValue);
return true;
}
static void valueToGValue(const char* value, GValue* gValue)
{
g_value_set_string(gValue, value);
}
static bool valueFromGValue(const GValue* gValue, double& value)
{
value = g_value_get_double(gValue);
return true;
}
static void valueToGValue(double value, GValue* gValue)
{
g_value_set_double(gValue, value);
}
static bool valueFromGValue(const GValue* gValue, OptionRange& value)
{
return value.init(g_value_get_string(gValue) ? g_value_get_string(gValue) : "<null>");
}
static void valueToGValue(const OptionRange& value, GValue* gValue)
{
const char* rangeString = value.rangeString();
g_value_set_string(gValue, !g_strcmp0(rangeString, "<null>") ? nullptr : rangeString);
}
static bool valueFromGValue(const GValue* gValue, GCLogging::Level& value)
{
switch (g_value_get_uint(gValue)) {
case 0:
value = GCLogging::Level::None;
return true;
case 1:
value = GCLogging::Level::Basic;
return true;
case 2:
value = GCLogging::Level::Verbose;
return true;
default:
break;
}
return false;
}
static void valueToGValue(GCLogging::Level value, GValue* gValue)
{
switch (value) {
case GCLogging::Level::None:
g_value_set_uint(gValue, 0);
break;
case GCLogging::Level::Basic:
g_value_set_uint(gValue, 1);
break;
case GCLogging::Level::Verbose:
g_value_set_uint(gValue, 2);
break;
}
}
static gboolean jscOptionsSetValue(const char* option, const GValue* value)
{
#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
if (!g_strcmp0(#name_, option)) { \
type_ valueToSet; \
if (!valueFromGValue(value, valueToSet)) \
return FALSE; \
Options::name_() = valueToSet; \
return TRUE; \
}
Options::initialize();
JSC_OPTIONS(FOR_EACH_OPTION)
#undef FOR_EACH_OPTION
return FALSE;
}
static gboolean jscOptionsGetValue(const char* option, GValue* value)
{
#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
if (!g_strcmp0(#name_, option)) { \
type_ valueToGet = Options::name_(); \
valueToGValue(valueToGet, value); \
return TRUE; \
}
Options::initialize();
JSC_OPTIONS(FOR_EACH_OPTION)
#undef FOR_EACH_OPTION
return FALSE;
}
/**
* jsc_options_set_boolean:
* @option: the option identifier
* @value: the value to set
*
* Set @option as a #gboolean value.
*
* Returns: %TRUE if option was correctly set or %FALSE otherwise.
*
* Since: 2.24
*/
gboolean jsc_options_set_boolean(const char* option, gboolean value)
{
g_return_val_if_fail(option, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_BOOLEAN);
g_value_set_boolean(&gValue, value);
return jscOptionsSetValue(option, &gValue);
}
/**
* jsc_options_get_boolean:
* @option: the option identifier
* @value: (out): return location for the option value
*
* Get @option as a #gboolean value.
*
* Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
*
* Since: 2.24
*/
gboolean jsc_options_get_boolean(const char* option, gboolean* value)
{
g_return_val_if_fail(option, FALSE);
g_return_val_if_fail(value, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_BOOLEAN);
if (!jscOptionsGetValue(option, &gValue))
return FALSE;
*value = g_value_get_boolean(&gValue);
return TRUE;
}
/**
* jsc_options_set_int:
* @option: the option identifier
* @value: the value to set
*
* Set @option as a #gint value.
*
* Returns: %TRUE if option was correctly set or %FALSE otherwise.
*
* Since: 2.24
*/
gboolean jsc_options_set_int(const char* option, gint value)
{
g_return_val_if_fail(option, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_INT);
g_value_set_int(&gValue, value);
return jscOptionsSetValue(option, &gValue);
}
/**
* jsc_options_get_int:
* @option: the option identifier
* @value: (out): return location for the option value
*
* Get @option as a #gint value.
*
* Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
*
* Since: 2.24
*/
gboolean jsc_options_get_int(const char* option, gint* value)
{
g_return_val_if_fail(option, FALSE);
g_return_val_if_fail(value, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_INT);
if (!jscOptionsGetValue(option, &gValue))
return FALSE;
*value = g_value_get_int(&gValue);
return TRUE;
}
/**
* jsc_options_set_uint:
* @option: the option identifier
* @value: the value to set
*
* Set @option as a #guint value.
*
* Returns: %TRUE if option was correctly set or %FALSE otherwise.
*
* Since: 2.24
*/
gboolean jsc_options_set_uint(const char* option, guint value)
{
g_return_val_if_fail(option, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_UINT);
g_value_set_uint(&gValue, value);
return jscOptionsSetValue(option, &gValue);
}
/**
* jsc_options_get_uint:
* @option: the option identifier
* @value: (out): return location for the option value
*
* Get @option as a #guint value.
*
* Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
*
* Since: 2.24
*/
gboolean jsc_options_get_uint(const char* option, guint* value)
{
g_return_val_if_fail(option, FALSE);
g_return_val_if_fail(value, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_UINT);
if (!jscOptionsGetValue(option, &gValue))
return FALSE;
*value = g_value_get_uint(&gValue);
return TRUE;
}
/**
* jsc_options_set_size:
* @option: the option identifier
* @value: the value to set
*
* Set @option as a #gsize value.
*
* Returns: %TRUE if option was correctly set or %FALSE otherwise.
*
* Since: 2.24
*/
gboolean jsc_options_set_size(const char* option, gsize value)
{
g_return_val_if_fail(option, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_POINTER);
g_value_set_pointer(&gValue, GSIZE_TO_POINTER(value));
return jscOptionsSetValue(option, &gValue);
}
/**
* jsc_options_get_size:
* @option: the option identifier
* @value: (out): return location for the option value
*
* Get @option as a #gsize value.
*
* Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
*
* Since: 2.24
*/
gboolean jsc_options_get_size(const char* option, gsize* value)
{
g_return_val_if_fail(option, FALSE);
g_return_val_if_fail(value, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_POINTER);
if (!jscOptionsGetValue(option, &gValue))
return FALSE;
*value = GPOINTER_TO_SIZE(g_value_get_pointer(&gValue));
return TRUE;
}
/**
* jsc_options_set_double:
* @option: the option identifier
* @value: the value to set
*
* Set @option as a #gdouble value.
*
* Returns: %TRUE if option was correctly set or %FALSE otherwise.
*
* Since: 2.24
*/
gboolean jsc_options_set_double(const char* option, gdouble value)
{
g_return_val_if_fail(option, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_DOUBLE);
g_value_set_double(&gValue, value);
return jscOptionsSetValue(option, &gValue);
}
/**
* jsc_options_get_double:
* @option: the option identifier
* @value: (out): return location for the option value
*
* Get @option as a #gdouble value.
*
* Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
*
* Since: 2.24
*/
gboolean jsc_options_get_double(const char* option, gdouble* value)
{
g_return_val_if_fail(option, FALSE);
g_return_val_if_fail(value, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_DOUBLE);
if (!jscOptionsGetValue(option, &gValue))
return FALSE;
*value = g_value_get_double(&gValue);
return TRUE;
}
/**
* jsc_options_set_string:
* @option: the option identifier
* @value: the value to set
*
* Set @option as a string.
*
* Returns: %TRUE if option was correctly set or %FALSE otherwise.
*
* Since: 2.24
*/
gboolean jsc_options_set_string(const char* option, const char* value)
{
g_return_val_if_fail(option, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_STRING);
g_value_set_string(&gValue, value);
bool success = jscOptionsSetValue(option, &gValue);
g_value_unset(&gValue);
return success;
}
/**
* jsc_options_get_string:
* @option: the option identifier
* @value: (out): return location for the option value
*
* Get @option as a string.
*
* Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
*
* Since: 2.24
*/
gboolean jsc_options_get_string(const char* option, char** value)
{
g_return_val_if_fail(option, FALSE);
g_return_val_if_fail(value, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_STRING);
if (!jscOptionsGetValue(option, &gValue))
return FALSE;
*value = g_value_dup_string(&gValue);
g_value_unset(&gValue);
return TRUE;
}
/**
* jsc_options_set_range_string:
* @option: the option identifier
* @value: the value to set
*
* Set @option as a range string. The string must be in the
* format <emphasis>[!]&lt;low&gt;[:&lt;high&gt;]</emphasis> where low and high are #guint values.
* Values between low and high (both included) will be considered in
* the range, unless <emphasis>!</emphasis> is used to invert the range.
*
* Returns: %TRUE if option was correctly set or %FALSE otherwise.
*
* Since: 2.24
*/
gboolean jsc_options_set_range_string(const char* option, const char* value)
{
g_return_val_if_fail(option, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_STRING);
g_value_set_string(&gValue, value);
bool success = jscOptionsSetValue(option, &gValue);
g_value_unset(&gValue);
return success;
}
/**
* jsc_options_get_range_string:
* @option: the option identifier
* @value: (out): return location for the option value
*
* Get @option as a range string. The string must be in the
* format <emphasis>[!]&lt;low&gt;[:&lt;high&gt;]</emphasis> where low and high are #guint values.
* Values between low and high (both included) will be considered in
* the range, unless <emphasis>!</emphasis> is used to invert the range.
*
* Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
*
* Since: 2.24
*/
gboolean jsc_options_get_range_string(const char* option, char** value)
{
g_return_val_if_fail(option, FALSE);
g_return_val_if_fail(value, FALSE);
GValue gValue = G_VALUE_INIT;
g_value_init(&gValue, G_TYPE_STRING);
if (!jscOptionsGetValue(option, &gValue))
return FALSE;
*value = g_value_dup_string(&gValue);
g_value_unset(&gValue);
return TRUE;
}
static JSCOptionType jscOptionsType(bool)
{
return JSC_OPTION_BOOLEAN;
}
static JSCOptionType jscOptionsType(int)
{
return JSC_OPTION_INT;
}
#if CPU(ADDRESS64)
static JSCOptionType jscOptionsType(unsigned)
{
return JSC_OPTION_UINT;
}
#endif
static JSCOptionType jscOptionsType(size_t)
{
return JSC_OPTION_SIZE;
}
static JSCOptionType jscOptionsType(double)
{
return JSC_OPTION_DOUBLE;
}
static JSCOptionType jscOptionsType(const char*)
{
return JSC_OPTION_STRING;
}
static JSCOptionType jscOptionsType(const OptionRange&)
{
return JSC_OPTION_RANGE_STRING;
}
/**
* JSCOptionType:
* @JSC_OPTION_BOOLEAN: A #gboolean option type.
* @JSC_OPTION_INT: A #gint option type.
* @JSC_OPTION_UINT: A #guint option type.
* @JSC_OPTION_SIZE: A #gsize options type.
* @JSC_OPTION_DOUBLE: A #gdouble options type.
* @JSC_OPTION_STRING: A string option type.
* @JSC_OPTION_RANGE_STRING: A range string option type.
*
* Enum values for options types.
*
* Since: 2.24
*/
/**
* JSCOptionsFunc:
* @option: the option name
* @type: the option #JSCOptionType
* @description: (nullable): the option description, or %NULL
* @user_data: user data
*
* Function used to iterate options.
*
* Not that @description string is not localized.
*
* Returns: %TRUE to stop the iteration, or %FALSE otherwise
*
* Since: 2.24
*/
/**
* jsc_options_foreach:
* @function: (scope call): a #JSCOptionsFunc callback
* @user_data: callback user data
*
* Iterates all available options calling @function for each one. Iteration can
* stop early if @function returns %FALSE.
*
* Since: 2.24
*/
void jsc_options_foreach(JSCOptionsFunc function, gpointer userData)
{
g_return_if_fail(function);
#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
if (Options::Availability::availability_ == Options::Availability::Normal \
|| Options::isAvailable(Options::name_##ID, Options::Availability::availability_)) { \
type_ defaultValue { }; \
auto optionType = jscOptionsType(defaultValue); \
if (function (#name_, optionType, description_, userData)) \
return; \
}
Options::initialize();
JSC_OPTIONS(FOR_EACH_OPTION)
#undef FOR_EACH_OPTION
}
static gboolean setOptionEntry(const char* optionNameFull, const char* value, gpointer, GError** error)
{
const char* optionName = optionNameFull + 6; // Remove the --jsc- prefix.
GUniquePtr<char> option(g_strdup_printf("%s=%s", optionName, value));
if (!Options::setOption(option.get())) {
g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Failed parse value '%s' for %s", value, optionNameFull);
return FALSE;
}
return TRUE;
}
/**
* jsc_options_get_option_group:
*
* Create a #GOptionGroup to handle JSCOptions as command line arguments.
* The options will be exposed as command line arguments with the form
* <emphasis>--jsc-&lt;option&gt;=&lt;value&gt;</emphasis>.
* Each entry in the returned #GOptionGroup is configured to apply the
* corresponding option during command line parsing. Applications only need to
* pass the returned group to g_option_context_add_group(), and the rest will
* be taken care for automatically.
*
* Returns: (transfer full): a #GOptionGroup for the JSCOptions
*
* Since: 2.24
*/
GOptionGroup* jsc_options_get_option_group(void)
{
// GOptionEntry works with const strings, so we need to keep the option names around.
auto* names = new Vector<GUniquePtr<char>>;
GOptionGroup* group = g_option_group_new("jsc", _("JSC Options"), _("Show JSC Options"), names, [] (gpointer data) {
delete static_cast<Vector<GUniquePtr<char>>*>(data);
});
g_option_group_set_translation_domain(group, GETTEXT_PACKAGE);
GArray* entries = g_array_new(TRUE, TRUE, sizeof(GOptionEntry));
#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
if (Options::Availability::availability_ == Options::Availability::Normal \
|| Options::isAvailable(Options::name_##ID, Options::Availability::availability_)) { \
GUniquePtr<char> name(g_strdup_printf("jsc-%s", #name_)); \
entries = g_array_set_size(entries, entries->len + 1); \
GOptionEntry* entry = &g_array_index(entries, GOptionEntry, entries->len - 1); \
entry->long_name = name.get(); \
entry->arg = G_OPTION_ARG_CALLBACK; \
entry->arg_data = reinterpret_cast<gpointer>(setOptionEntry); \
entry->description = description_; \
names->append(WTFMove(name)); \
}
Options::initialize();
JSC_OPTIONS(FOR_EACH_OPTION)
#undef FOR_EACH_OPTION
g_option_group_add_entries(group, reinterpret_cast<GOptionEntry*>(entries->data));
return group;
}
/**
* JSC_OPTIONS_USE_JIT:
*
* Allows the executable pages to be allocated for JIT and thunks if %TRUE.
* Option type: %JSC_OPTION_BOOLEAN
* Default value: %TRUE.
*
* Since: 2.24
*/
/**
* JSC_OPTIONS_USE_DFG:
*
* Allows the DFG JIT to be used if %TRUE.
* Option type: %JSC_OPTION_BOOLEAN
* Default value: %TRUE.
*
* Since: 2.24
*/
/**
* JSC_OPTIONS_USE_FTL:
*
* Allows the FTL JIT to be used if %TRUE.
* Option type: %JSC_OPTION_BOOLEAN
* Default value: %TRUE.
*
* Since: 2.24
*/
/**
* JSC_OPTIONS_USE_LLINT:
*
* Allows the LLINT to be used if %TRUE.
* Option type: %JSC_OPTION_BOOLEAN
* Default value: %TRUE.
*
* Since: 2.24
*/

110
API/glib/JSCOptions.h Normal file
View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 2019 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION) && !defined(WEBKIT2_COMPILATION)
#error "Only <jsc/jsc.h> can be included directly."
#endif
#ifndef JSCOptions_h
#define JSCOptions_h
#include <glib-object.h>
#include <jsc/JSCDefines.h>
G_BEGIN_DECLS
#define JSC_OPTIONS_USE_JIT "useJIT"
#define JSC_OPTIONS_USE_DFG "useDFGJIT"
#define JSC_OPTIONS_USE_FTL "useFTLJIT"
#define JSC_OPTIONS_USE_LLINT "useLLInt"
JSC_API gboolean
jsc_options_set_boolean (const char *option,
gboolean value);
JSC_API gboolean
jsc_options_get_boolean (const char *option,
gboolean *value);
JSC_API gboolean
jsc_options_set_int (const char *option,
gint value);
JSC_API gboolean
jsc_options_get_int (const char *option,
gint *value);
JSC_API gboolean
jsc_options_set_uint (const char *option,
guint value);
JSC_API gboolean
jsc_options_get_uint (const char *option,
guint *value);
JSC_API gboolean
jsc_options_set_size (const char *option,
gsize value);
JSC_API gboolean
jsc_options_get_size (const char *option,
gsize *value);
JSC_API gboolean
jsc_options_set_double (const char *option,
gdouble value);
JSC_API gboolean
jsc_options_get_double (const char *option,
gdouble *value);
JSC_API gboolean
jsc_options_set_string (const char *option,
const char *value);
JSC_API gboolean
jsc_options_get_string (const char *option,
char **value);
JSC_API gboolean
jsc_options_set_range_string (const char *option,
const char *value);
JSC_API gboolean
jsc_options_get_range_string (const char *option,
char **value);
typedef enum {
JSC_OPTION_BOOLEAN,
JSC_OPTION_INT,
JSC_OPTION_UINT,
JSC_OPTION_SIZE,
JSC_OPTION_DOUBLE,
JSC_OPTION_STRING,
JSC_OPTION_RANGE_STRING
} JSCOptionType;
typedef gboolean (* JSCOptionsFunc) (const char *option,
JSCOptionType type,
const char *description,
gpointer user_data);
JSC_API void
jsc_options_foreach (JSCOptionsFunc function,
gpointer user_data);
JSC_API GOptionGroup *
jsc_options_get_option_group (void);
G_END_DECLS
#endif /* JSCOptions_h */

1443
API/glib/JSCValue.cpp Normal file

File diff suppressed because it is too large Load Diff

265
API/glib/JSCValue.h Normal file
View File

@ -0,0 +1,265 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION) && !defined(WEBKIT2_COMPILATION)
#error "Only <jsc/jsc.h> can be included directly."
#endif
#ifndef JSCValue_h
#define JSCValue_h
#include <glib-object.h>
#include <jsc/JSCDefines.h>
G_BEGIN_DECLS
#define JSC_TYPE_VALUE (jsc_value_get_type())
#define JSC_VALUE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), JSC_TYPE_VALUE, JSCValue))
#define JSC_IS_VALUE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), JSC_TYPE_VALUE))
#define JSC_VALUE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), JSC_TYPE_VALUE, JSCValueClass))
#define JSC_IS_VALUE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JSC_TYPE_VALUE))
#define JSC_VALUE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), JSC_TYPE_VALUE, JSCValueClass))
typedef struct _JSCValue JSCValue;
typedef struct _JSCValueClass JSCValueClass;
typedef struct _JSCValuePrivate JSCValuePrivate;
typedef struct _JSCClass JSCClass;
typedef struct _JSCContext JSCContext;
typedef enum {
JSC_VALUE_PROPERTY_CONFIGURABLE = 1 << 0,
JSC_VALUE_PROPERTY_ENUMERABLE = 1 << 1,
JSC_VALUE_PROPERTY_WRITABLE = 1 << 2
} JSCValuePropertyFlags;
struct _JSCValue {
GObject parent;
/*< private >*/
JSCValuePrivate *priv;
};
struct _JSCValueClass {
GObjectClass parent_class;
void (*_jsc_reserved0) (void);
void (*_jsc_reserved1) (void);
void (*_jsc_reserved2) (void);
void (*_jsc_reserved3) (void);
};
JSC_API GType
jsc_value_get_type (void);
JSC_API JSCContext *
jsc_value_get_context (JSCValue *value);
JSC_API JSCValue *
jsc_value_new_undefined (JSCContext *context);
JSC_API gboolean
jsc_value_is_undefined (JSCValue *value);
JSC_API JSCValue *
jsc_value_new_null (JSCContext *context);
JSC_API gboolean
jsc_value_is_null (JSCValue *value);
JSC_API JSCValue *
jsc_value_new_number (JSCContext *context,
double number);
JSC_API gboolean
jsc_value_is_number (JSCValue *value);
JSC_API double
jsc_value_to_double (JSCValue *value);
JSC_API gint32
jsc_value_to_int32 (JSCValue *value);
JSC_API JSCValue *
jsc_value_new_boolean (JSCContext *context,
gboolean value);
JSC_API gboolean
jsc_value_is_boolean (JSCValue *value);
JSC_API gboolean
jsc_value_to_boolean (JSCValue *value);
JSC_API JSCValue *
jsc_value_new_string (JSCContext *context,
const char *string);
JSC_API JSCValue *
jsc_value_new_string_from_bytes (JSCContext *context,
GBytes *bytes);
JSC_API gboolean
jsc_value_is_string (JSCValue *value);
JSC_API char *
jsc_value_to_string (JSCValue *value);
JSC_API GBytes *
jsc_value_to_string_as_bytes (JSCValue *value);
JSC_API JSCValue *
jsc_value_new_array (JSCContext *context,
GType first_item_type,
...);
JSC_API JSCValue *
jsc_value_new_array_from_garray (JSCContext *context,
GPtrArray *array);
JSC_API JSCValue *
jsc_value_new_array_from_strv (JSCContext *context,
const char *const *strv);
JSC_API gboolean
jsc_value_is_array (JSCValue *value);
JSC_API JSCValue *
jsc_value_new_object (JSCContext *context,
gpointer instance,
JSCClass *jsc_class);
JSC_API gboolean
jsc_value_is_object (JSCValue *value);
JSC_API gboolean
jsc_value_object_is_instance_of (JSCValue *value,
const char *name);
JSC_API void
jsc_value_object_set_property (JSCValue *value,
const char *name,
JSCValue *property);
JSC_API JSCValue *
jsc_value_object_get_property (JSCValue *value,
const char *name);
JSC_API void
jsc_value_object_set_property_at_index (JSCValue *value,
guint index,
JSCValue *property);
JSC_API JSCValue *
jsc_value_object_get_property_at_index (JSCValue *value,
guint index);
JSC_API gboolean
jsc_value_object_has_property (JSCValue *value,
const char *name);
JSC_API gboolean
jsc_value_object_delete_property (JSCValue *value,
const char *name);
JSC_API gchar **
jsc_value_object_enumerate_properties (JSCValue *value);
JSC_API JSCValue *
jsc_value_object_invoke_method (JSCValue *value,
const char *name,
GType first_parameter_type,
...) G_GNUC_WARN_UNUSED_RESULT;
JSC_API JSCValue *
jsc_value_object_invoke_methodv (JSCValue *value,
const char *name,
guint n_parameters,
JSCValue **parameters) G_GNUC_WARN_UNUSED_RESULT;
JSC_API void
jsc_value_object_define_property_data (JSCValue *value,
const char *property_name,
JSCValuePropertyFlags flags,
JSCValue *property_value);
JSC_API void
jsc_value_object_define_property_accessor (JSCValue *value,
const char *property_name,
JSCValuePropertyFlags flags,
GType property_type,
GCallback getter,
GCallback setter,
gpointer user_data,
GDestroyNotify destroy_notify);
JSC_API JSCValue *
jsc_value_new_function (JSCContext *context,
const char *name,
GCallback callback,
gpointer user_data,
GDestroyNotify destroy_notify,
GType return_type,
guint n_params,
...);
JSC_API JSCValue *
jsc_value_new_functionv (JSCContext *context,
const char *name,
GCallback callback,
gpointer user_data,
GDestroyNotify destroy_notify,
GType return_type,
guint n_parameters,
GType *parameter_types);
JSC_API JSCValue *
jsc_value_new_function_variadic (JSCContext *context,
const char *name,
GCallback callback,
gpointer user_data,
GDestroyNotify destroy_notify,
GType return_type);
JSC_API gboolean
jsc_value_is_function (JSCValue *value);
JSC_API JSCValue *
jsc_value_function_call (JSCValue *value,
GType first_parameter_type,
...) G_GNUC_WARN_UNUSED_RESULT;
JSC_API JSCValue *
jsc_value_function_callv (JSCValue *value,
guint n_parameters,
JSCValue **parameters) G_GNUC_WARN_UNUSED_RESULT;
JSC_API gboolean
jsc_value_is_constructor (JSCValue *value);
JSC_API JSCValue *
jsc_value_constructor_call (JSCValue *value,
GType first_parameter_type,
...);
JSC_API JSCValue *
jsc_value_constructor_callv (JSCValue *value,
guint n_parameters,
JSCValue **parameters);
G_END_DECLS
#endif /* JSCValue_h */

View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include "JSCValue.h"
JSValueRef jscValueGetJSValue(JSCValue*);
JSCValue* jscValueCreate(JSCContext*, JSValueRef);

89
API/glib/JSCVersion.cpp Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "JSCVersion.h"
/**
* SECTION: JSCVersion
* @Short_description: Provides the JavaScriptCore version
* @Title: JSCVersion
*
* Provides convenience functions returning JavaScriptCore's major, minor and
* micro versions of the JavaScriptCore library your code is running
* against. This is not necessarily the same as the
* #JSC_MAJOR_VERSION, #JSC_MINOR_VERSION or
* #JSC_MICRO_VERSION, which represent the version of the JavaScriptCore
* headers included when compiling the code.
*
*/
/**
* jsc_get_major_version:
*
* Returns the major version number of the JavaScriptCore library.
* (e.g. in JavaScriptCore version 1.8.3 this is 1.)
*
* This function is in the library, so it represents the JavaScriptCore library
* your code is running against. Contrast with the #JSC_MAJOR_VERSION
* macro, which represents the major version of the JavaScriptCore headers you
* have included when compiling your code.
*
* Returns: the major version number of the JavaScriptCore library
*/
guint jsc_get_major_version(void)
{
return JSC_MAJOR_VERSION;
}
/**
* jsc_get_minor_version:
*
* Returns the minor version number of the JavaScriptCore library.
* (e.g. in JavaScriptCore version 1.8.3 this is 8.)
*
* This function is in the library, so it represents the JavaScriptCore library
* your code is running against. Contrast with the #JSC_MINOR_VERSION
* macro, which represents the minor version of the JavaScriptCore headers you
* have included when compiling your code.
*
* Returns: the minor version number of the JavaScriptCore library
*/
guint jsc_get_minor_version(void)
{
return JSC_MINOR_VERSION;
}
/**
* jsc_get_micro_version:
*
* Returns the micro version number of the JavaScriptCore library.
* (e.g. in JavaScriptCore version 1.8.3 this is 3.)
*
* This function is in the library, so it represents the JavaScriptCore library
* your code is running against. Contrast with the #JSC_MICRO_VERSION
* macro, which represents the micro version of the JavaScriptCore headers you
* have included when compiling your code.
*
* Returns: the micro version number of the JavaScriptCore library
*/
guint jsc_get_micro_version(void)
{
return JSC_MICRO_VERSION;
}

84
API/glib/JSCVersion.h.in Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION) && !defined(WEBKIT2_COMPILATION)
#error "Only <jsc/jsc.h> can be included directly."
#endif
#ifndef JSCVersion_h
#define JSCVersion_h
#include <jsc/JSCDefines.h>
G_BEGIN_DECLS
/**
* JSC_MAJOR_VERSION:
*
* Like jsc_get_major_version(), but from the headers used at
* application compile time, rather than from the library linked
* against at application run time.
*/
#define JSC_MAJOR_VERSION (@PROJECT_VERSION_MAJOR@)
/**
* JSC_MINOR_VERSION:
*
* Like jsc_get_minor_version(), but from the headers used at
* application compile time, rather than from the library linked
* against at application run time.
*/
#define JSC_MINOR_VERSION (@PROJECT_VERSION_MINOR@)
/**
* JSC_MICRO_VERSION:
*
* Like jsc_get_micro_version(), but from the headers used at
* application compile time, rather than from the library linked
* against at application run time.
*/
#define JSC_MICRO_VERSION (@PROJECT_VERSION_MICRO@)
/**
* JSC_CHECK_VERSION:
* @major: major version (e.g. 1 for version 1.2.5)
* @minor: minor version (e.g. 2 for version 1.2.5)
* @micro: micro version (e.g. 5 for version 1.2.5)
*
* Returns: %TRUE if the version of the JavaScriptCore header files
* is the same as or newer than the passed-in version.
*/
#define JSC_CHECK_VERSION(major, minor, micro) \
(JSC_MAJOR_VERSION > (major) || \
(JSC_MAJOR_VERSION == (major) && JSC_MINOR_VERSION > (minor)) || \
(JSC_MAJOR_VERSION == (major) && JSC_MINOR_VERSION == (minor) && \
JSC_MICRO_VERSION >= (micro)))
JSC_API guint
jsc_get_major_version (void);
JSC_API guint
jsc_get_minor_version (void);
JSC_API guint
jsc_get_micro_version (void);
G_END_DECLS
#endif /* JSCVersion_h */

View File

@ -0,0 +1,159 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "JSCVirtualMachine.h"
#include "JSCContextPrivate.h"
#include "JSCVirtualMachinePrivate.h"
#include <wtf/HashMap.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/glib/WTFGType.h>
/**
* SECTION: JSCVirtualMachine
* @short_description: JavaScript Virtual Machine
* @title: JSCVirtualMachine
* @see_also: JSCContext
*
* JSCVirtualMachine represents a group of JSCContext<!-- -->s. It allows
* concurrent JavaScript exeution by creating a different instance of
* JSCVirtualMachine in each thread.
*
* To create a group of JSCContext<!-- -->s pass the same JSCVirtualMachine
* instance to every JSCContext constructor.
*/
struct _JSCVirtualMachinePrivate {
JSContextGroupRef jsContextGroup;
HashMap<JSGlobalContextRef, JSCContext*> contextCache;
};
WEBKIT_DEFINE_TYPE(JSCVirtualMachine, jsc_virtual_machine, G_TYPE_OBJECT)
static Lock wrapperCacheMutex;
static HashMap<JSContextGroupRef, JSCVirtualMachine*>& wrapperMap()
{
static NeverDestroyed<HashMap<JSContextGroupRef, JSCVirtualMachine*>> map;
return map;
}
static void addWrapper(JSContextGroupRef group, JSCVirtualMachine* vm)
{
std::lock_guard<Lock> lock(wrapperCacheMutex);
ASSERT(!wrapperMap().contains(group));
wrapperMap().set(group, vm);
}
static void removeWrapper(JSContextGroupRef group)
{
std::lock_guard<Lock> lock(wrapperCacheMutex);
ASSERT(wrapperMap().contains(group));
wrapperMap().remove(group);
}
static void jscVirtualMachineSetContextGroup(JSCVirtualMachine *vm, JSContextGroupRef group)
{
if (group) {
ASSERT(!vm->priv->jsContextGroup);
vm->priv->jsContextGroup = group;
JSContextGroupRetain(vm->priv->jsContextGroup);
addWrapper(vm->priv->jsContextGroup, vm);
} else if (vm->priv->jsContextGroup) {
removeWrapper(vm->priv->jsContextGroup);
JSContextGroupRelease(vm->priv->jsContextGroup);
vm->priv->jsContextGroup = nullptr;
}
}
static void jscVirtualMachineEnsureContextGroup(JSCVirtualMachine *vm)
{
if (vm->priv->jsContextGroup)
return;
auto* jsContextGroup = JSContextGroupCreate();
jscVirtualMachineSetContextGroup(vm, jsContextGroup);
JSContextGroupRelease(jsContextGroup);
}
static void jscVirtualMachineDispose(GObject* object)
{
JSCVirtualMachine* vm = JSC_VIRTUAL_MACHINE(object);
jscVirtualMachineSetContextGroup(vm, nullptr);
G_OBJECT_CLASS(jsc_virtual_machine_parent_class)->dispose(object);
}
static void jsc_virtual_machine_class_init(JSCVirtualMachineClass* klass)
{
GObjectClass* objClass = G_OBJECT_CLASS(klass);
objClass->dispose = jscVirtualMachineDispose;
}
GRefPtr<JSCVirtualMachine> jscVirtualMachineGetOrCreate(JSContextGroupRef jsContextGroup)
{
GRefPtr<JSCVirtualMachine> vm = wrapperMap().get(jsContextGroup);
if (!vm) {
vm = adoptGRef(jsc_virtual_machine_new());
jscVirtualMachineSetContextGroup(vm.get(), jsContextGroup);
}
return vm;
}
JSContextGroupRef jscVirtualMachineGetContextGroup(JSCVirtualMachine* vm)
{
jscVirtualMachineEnsureContextGroup(vm);
return vm->priv->jsContextGroup;
}
void jscVirtualMachineAddContext(JSCVirtualMachine* vm, JSCContext* context)
{
ASSERT(vm->priv->jsContextGroup);
auto jsContext = jscContextGetJSContext(context);
ASSERT(JSContextGetGroup(jsContext) == vm->priv->jsContextGroup);
ASSERT(!vm->priv->contextCache.contains(jsContext));
vm->priv->contextCache.set(jsContext, context);
}
void jscVirtualMachineRemoveContext(JSCVirtualMachine* vm, JSCContext* context)
{
ASSERT(vm->priv->jsContextGroup);
auto jsContext = jscContextGetJSContext(context);
ASSERT(JSContextGetGroup(jsContext) == vm->priv->jsContextGroup);
ASSERT(vm->priv->contextCache.contains(jsContext));
vm->priv->contextCache.remove(jsContext);
}
JSCContext* jscVirtualMachineGetContext(JSCVirtualMachine* vm, JSGlobalContextRef jsContext)
{
return vm->priv->contextCache.get(jsContext);
}
/**
* jsc_virtual_machine_new:
*
* Create a new #JSCVirtualMachine.
*
* Returns: (transfer full): the newly created #JSCVirtualMachine.
*/
JSCVirtualMachine* jsc_virtual_machine_new()
{
return JSC_VIRTUAL_MACHINE(g_object_new(JSC_TYPE_VIRTUAL_MACHINE, nullptr));
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION) && !defined(WEBKIT2_COMPILATION)
#error "Only <jsc/jsc.h> can be included directly."
#endif
#ifndef JSCVirtualMachine_h
#define JSCVirtualMachine_h
#include <glib-object.h>
#include <jsc/JSCDefines.h>
#include <jsc/JSCValue.h>
G_BEGIN_DECLS
#define JSC_TYPE_VIRTUAL_MACHINE (jsc_virtual_machine_get_type())
#define JSC_VIRTUAL_MACHINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), JSC_TYPE_VIRTUAL_MACHINE, JSCVirtualMachine))
#define JSC_IS_VIRTUAL_MACHINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), JSC_TYPE_VIRTUAL_MACHINE))
#define JSC_VIRTUAL_MACHINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), JSC_TYPE_VIRTUAL_MACHINE, JSCVirtualMachineClass))
#define JSC_IS_VIRTUAL_MACHINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JSC_TYPE_VIRTUAL_MACHINE))
#define JSC_VIRTUAL_MACHINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), JSC_TYPE_VIRTUAL_MACHINE, JSCVirtualMachineClass))
typedef struct _JSCVirtualMachine JSCVirtualMachine;
typedef struct _JSCVirtualMachineClass JSCVirtualMachineClass;
typedef struct _JSCVirtualMachinePrivate JSCVirtualMachinePrivate;
struct _JSCVirtualMachine {
GObject parent;
/*< private >*/
JSCVirtualMachinePrivate *priv;
};
struct _JSCVirtualMachineClass {
GObjectClass parent_class;
void (*_jsc_reserved0) (void);
void (*_jsc_reserved1) (void);
void (*_jsc_reserved2) (void);
void (*_jsc_reserved3) (void);
};
JSC_API GType
jsc_virtual_machine_get_type (void);
JSC_API JSCVirtualMachine *
jsc_virtual_machine_new (void);
G_END_DECLS
#endif /* JSCVirtualMachine_h */

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include "JSCContext.h"
#include "JSCVirtualMachine.h"
#include <wtf/glib/GRefPtr.h>
GRefPtr<JSCVirtualMachine> jscVirtualMachineGetOrCreate(JSContextGroupRef);
JSContextGroupRef jscVirtualMachineGetContextGroup(JSCVirtualMachine*);
void jscVirtualMachineAddContext(JSCVirtualMachine*, JSCContext*);
void jscVirtualMachineRemoveContext(JSCVirtualMachine*, JSCContext*);
JSCContext* jscVirtualMachineGetContext(JSCVirtualMachine*, JSGlobalContextRef);

212
API/glib/JSCWeakValue.cpp Normal file
View File

@ -0,0 +1,212 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "JSCWeakValue.h"
#include "APICast.h"
#include "JSCContextPrivate.h"
#include "JSCInlines.h"
#include "JSCValuePrivate.h"
#include "JSWeakValue.h"
#include "WeakHandleOwner.h"
#include <wtf/glib/GRefPtr.h>
#include <wtf/glib/GUniquePtr.h>
#include <wtf/glib/WTFGType.h>
/**
* SECTION: JSCWeakValue
* @short_description: JavaScript weak value
* @title: JSCWeakValue
* @see_also: JSCValue
*
* JSCWeakValue represents a weak reference to a value in a #JSCContext. It can be used
* to keep a reference to a JavaScript value without protecting it from being garbage
* collected and without referencing the #JSCContext either.
*/
enum {
PROP_0,
PROP_VALUE,
};
enum {
CLEARED,
LAST_SIGNAL
};
struct _JSCWeakValuePrivate {
JSC::Weak<JSC::JSGlobalObject> globalObject;
RefPtr<JSC::JSLock> lock;
JSC::JSWeakValue weakValueRef;
};
static guint signals[LAST_SIGNAL] = { 0, };
WEBKIT_DEFINE_TYPE(JSCWeakValue, jsc_weak_value, G_TYPE_OBJECT)
static void jscWeakValueClear(JSCWeakValue* weakValue)
{
JSCWeakValuePrivate* priv = weakValue->priv;
priv->globalObject.clear();
priv->weakValueRef.clear();
}
class JSCWeakValueHandleOwner : public JSC::WeakHandleOwner {
public:
void finalize(JSC::Handle<JSC::Unknown>, void* context) override
{
auto* weakValue = JSC_WEAK_VALUE(context);
jscWeakValueClear(weakValue);
g_signal_emit(weakValue, signals[CLEARED], 0, nullptr);
}
};
static JSCWeakValueHandleOwner& weakValueHandleOwner()
{
static NeverDestroyed<JSCWeakValueHandleOwner> jscWeakValueHandleOwner;
return jscWeakValueHandleOwner;
}
static void jscWeakValueInitialize(JSCWeakValue* weakValue, JSCValue* value)
{
JSCWeakValuePrivate* priv = weakValue->priv;
auto* jsContext = jscContextGetJSContext(jsc_value_get_context(value));
JSC::ExecState* exec = toJS(jsContext);
JSC::JSGlobalObject* globalObject = exec->lexicalGlobalObject();
auto& owner = weakValueHandleOwner();
JSC::Weak<JSC::JSGlobalObject> weak(globalObject, &owner, weakValue);
priv->globalObject.swap(weak);
priv->lock = &exec->vm().apiLock();
JSC::JSValue jsValue = toJS(exec, jscValueGetJSValue(value));
if (jsValue.isObject())
priv->weakValueRef.setObject(JSC::jsCast<JSC::JSObject*>(jsValue.asCell()), owner, weakValue);
else if (jsValue.isString())
priv->weakValueRef.setString(JSC::jsCast<JSC::JSString*>(jsValue.asCell()), owner, weakValue);
else
priv->weakValueRef.setPrimitive(jsValue);
}
static void jscWeakValueSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* paramSpec)
{
switch (propID) {
case PROP_VALUE:
jscWeakValueInitialize(JSC_WEAK_VALUE(object), JSC_VALUE(g_value_get_object(value)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
}
}
static void jscWeakValueDispose(GObject* object)
{
JSCWeakValue* weakValue = JSC_WEAK_VALUE(object);
jscWeakValueClear(weakValue);
G_OBJECT_CLASS(jsc_weak_value_parent_class)->dispose(object);
}
static void jsc_weak_value_class_init(JSCWeakValueClass* klass)
{
GObjectClass* objClass = G_OBJECT_CLASS(klass);
objClass->set_property = jscWeakValueSetProperty;
objClass->dispose = jscWeakValueDispose;
/**
* JSCWeakValue:value:
*
* The #JSCValue referencing the JavaScript value.
*/
g_object_class_install_property(objClass,
PROP_VALUE,
g_param_spec_object(
"value",
"JSCValue",
"JSC Value",
JSC_TYPE_VALUE,
static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
/**
* JSCWeakValue::cleared:
* @weak_value: the #JSCWeakValue
*
* This signal is emitted when the JavaScript value is destroyed.
*/
signals[CLEARED] = g_signal_new(
"cleared",
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST,
0, nullptr, nullptr,
g_cclosure_marshal_generic,
G_TYPE_NONE, 0,
G_TYPE_NONE);
}
/**
* jsc_weak_value_new:
* @value: a #JSCValue
*
* Create a new #JSCWeakValue for the JavaScript value referenced by @value.
*
* Returns: (transfer full): a new #JSCWeakValue
*/
JSCWeakValue* jsc_weak_value_new(JSCValue* value)
{
g_return_val_if_fail(JSC_IS_VALUE(value), nullptr);
return JSC_WEAK_VALUE(g_object_new(JSC_TYPE_WEAK_VALUE, "value", value, nullptr));
}
/**
* jsc_weak_value_get_value:
* @weak_value: a #JSCWeakValue
*
* Get a #JSCValue referencing the JavaScript value of @weak_value.
*
* Returns: (transfer full): a new #JSCValue or %NULL if @weak_value was cleared.
*/
JSCValue* jsc_weak_value_get_value(JSCWeakValue* weakValue)
{
g_return_val_if_fail(JSC_IS_WEAK_VALUE(weakValue), nullptr);
JSCWeakValuePrivate* priv = weakValue->priv;
WTF::Locker<JSC::JSLock> locker(priv->lock.get());
JSC::VM* vm = priv->lock->vm();
if (!vm)
return nullptr;
JSC::JSLockHolder apiLocker(vm);
if (!priv->globalObject || priv->weakValueRef.isClear())
return nullptr;
JSC::JSValue value;
if (priv->weakValueRef.isPrimitive())
value = priv->weakValueRef.primitive();
else if (priv->weakValueRef.isString())
value = priv->weakValueRef.string();
else
value = priv->weakValueRef.object();
JSC::ExecState* exec = priv->globalObject->globalExec();
GRefPtr<JSCContext> context = jscContextGetOrCreate(toGlobalRef(exec));
return jscContextGetOrCreateValue(context.get(), toRef(exec, value)).leakRef();
}

71
API/glib/JSCWeakValue.h Normal file
View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION) && !defined(WEBKIT2_COMPILATION)
#error "Only <jsc/jsc.h> can be included directly."
#endif
#ifndef JSCWeakValue_h
#define JSCWeakValue_h
#include <glib-object.h>
#include <jsc/JSCDefines.h>
#include <jsc/JSCValue.h>
G_BEGIN_DECLS
#define JSC_TYPE_WEAK_VALUE (jsc_weak_value_get_type())
#define JSC_WEAK_VALUE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), JSC_TYPE_WEAK_VALUE, JSCWeakValue))
#define JSC_IS_WEAK_VALUE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), JSC_TYPE_WEAK_VALUE))
#define JSC_WEAK_VALUE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), JSC_TYPE_WEAK_VALUE, JSCWeakValueClass))
#define JSC_IS_WEAK_VALUE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JSC_TYPE_WEAK_VALUE))
#define JSC_WEAK_VALUE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), JSC_TYPE_WEAK_VALUE, JSCWeakValueClass))
typedef struct _JSCWeakValue JSCWeakValue;
typedef struct _JSCWeakValueClass JSCWeakValueClass;
typedef struct _JSCWeakValuePrivate JSCWeakValuePrivate;
struct _JSCWeakValue {
GObject parent;
/*< private >*/
JSCWeakValuePrivate *priv;
};
struct _JSCWeakValueClass {
GObjectClass parent_class;
void (*_jsc_reserved0) (void);
void (*_jsc_reserved1) (void);
void (*_jsc_reserved2) (void);
void (*_jsc_reserved3) (void);
};
JSC_API GType
jsc_weak_value_get_type (void);
JSC_API JSCWeakValue *
jsc_weak_value_new (JSCValue *value);
JSC_API JSCValue *
jsc_weak_value_get_value (JSCWeakValue *weak_value);
G_END_DECLS
#endif /* JSCWeakValue_h */

139
API/glib/JSCWrapperMap.cpp Normal file
View File

@ -0,0 +1,139 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "JSCWrapperMap.h"
#include "APICast.h"
#include "JSAPIWrapperGlobalObject.h"
#include "JSAPIWrapperObject.h"
#include "JSCClassPrivate.h"
#include "JSCContextPrivate.h"
#include "JSCGLibWrapperObject.h"
#include "JSCInlines.h"
#include "JSCValuePrivate.h"
#include "JSCallbackObject.h"
namespace JSC {
WrapperMap::WrapperMap(JSGlobalContextRef jsContext)
: m_cachedJSWrappers(std::make_unique<JSC::WeakGCMap<gpointer, JSC::JSObject>>(toJS(jsContext)->vm()))
{
}
WrapperMap::~WrapperMap()
{
for (const auto& jscClass : m_classMap.values())
jscClassInvalidate(jscClass.get());
}
GRefPtr<JSCValue> WrapperMap::gobjectWrapper(JSCContext* jscContext, JSValueRef jsValue)
{
auto* jsContext = jscContextGetJSContext(jscContext);
JSC::JSLockHolder locker(toJS(jsContext));
ASSERT(toJSGlobalObject(jsContext)->wrapperMap() == this);
GRefPtr<JSCValue> value = m_cachedGObjectWrappers.get(jsValue);
if (!value) {
value = adoptGRef(jscValueCreate(jscContext, jsValue));
m_cachedGObjectWrappers.set(jsValue, value.get());
}
return value;
}
void WrapperMap::unwrap(JSValueRef jsValue)
{
ASSERT(m_cachedGObjectWrappers.contains(jsValue));
m_cachedGObjectWrappers.remove(jsValue);
}
void WrapperMap::registerClass(JSCClass* jscClass)
{
auto* jsClass = jscClassGetJSClass(jscClass);
ASSERT(!m_classMap.contains(jsClass));
m_classMap.set(jsClass, jscClass);
}
JSCClass* WrapperMap::registeredClass(JSClassRef jsClass) const
{
return m_classMap.get(jsClass);
}
JSObject* WrapperMap::createJSWrappper(JSGlobalContextRef jsContext, JSClassRef jsClass, JSValueRef prototype, gpointer wrappedObject, GDestroyNotify destroyFunction)
{
ASSERT(toJSGlobalObject(jsContext)->wrapperMap() == this);
ExecState* exec = toJS(jsContext);
VM& vm = exec->vm();
JSLockHolder locker(vm);
auto* object = JSC::JSCallbackObject<JSC::JSAPIWrapperObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->glibWrapperObjectStructure(), jsClass, nullptr);
if (wrappedObject) {
object->setWrappedObject(new JSC::JSCGLibWrapperObject(wrappedObject, destroyFunction));
m_cachedJSWrappers->set(wrappedObject, object);
}
if (prototype)
JSObjectSetPrototype(jsContext, toRef(object), prototype);
else if (auto* jsPrototype = jsClass->prototype(exec))
object->setPrototypeDirect(vm, jsPrototype);
return object;
}
JSGlobalContextRef WrapperMap::createContextWithJSWrappper(JSContextGroupRef jsGroup, JSClassRef jsClass, JSValueRef prototype, gpointer wrappedObject, GDestroyNotify destroyFunction)
{
Ref<VM> vm(*toJS(jsGroup));
JSLockHolder locker(vm.ptr());
auto* globalObject = JSCallbackObject<JSAPIWrapperGlobalObject>::create(vm.get(), jsClass, JSCallbackObject<JSAPIWrapperGlobalObject>::createStructure(vm.get(), nullptr, jsNull()));
if (wrappedObject) {
globalObject->setWrappedObject(new JSC::JSCGLibWrapperObject(wrappedObject, destroyFunction));
m_cachedJSWrappers->set(wrappedObject, globalObject);
}
ExecState* exec = globalObject->globalExec();
if (prototype)
globalObject->resetPrototype(vm.get(), toJS(exec, prototype));
else if (auto jsPrototype = jsClass->prototype(exec))
globalObject->resetPrototype(vm.get(), jsPrototype);
else
globalObject->resetPrototype(vm.get(), jsNull());
return JSGlobalContextRetain(toGlobalRef(exec));
}
JSObject* WrapperMap::jsWrapper(gpointer wrappedObject) const
{
if (!wrappedObject)
return nullptr;
return m_cachedJSWrappers->get(wrappedObject);
}
gpointer WrapperMap::wrappedObject(JSGlobalContextRef jsContext, JSObjectRef jsObject) const
{
ASSERT(toJSGlobalObject(jsContext)->wrapperMap() == this);
JSLockHolder locker(toJS(jsContext));
VM& vm = toJS(jsContext)->vm();
auto* object = toJS(jsObject);
if (object->inherits(vm, JSC::JSCallbackObject<JSC::JSAPIWrapperObject>::info())) {
if (auto* wrapper = JSC::jsCast<JSC::JSAPIWrapperObject*>(object)->wrappedObject())
return static_cast<JSC::JSCGLibWrapperObject*>(wrapper)->object();
}
if (object->inherits(vm, JSC::JSCallbackObject<JSC::JSAPIWrapperGlobalObject>::info())) {
if (auto* wrapper = JSC::jsCast<JSC::JSAPIWrapperGlobalObject*>(object)->wrappedObject())
return wrapper->object();
}
return nullptr;
}
} // namespace JSC

61
API/glib/JSCWrapperMap.h Normal file
View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include "JSBase.h"
#include "VM.h"
#include "WeakGCMap.h"
#include <glib.h>
#include <wtf/HashMap.h>
#include <wtf/glib/GRefPtr.h>
#include <wtf/text/CString.h>
typedef struct _JSCClass JSCClass;
typedef struct _JSCContext JSCContext;
typedef struct _JSCValue JSCValue;
namespace JSC {
class JSObject;
class WrapperMap {
WTF_MAKE_FAST_ALLOCATED;
public:
explicit WrapperMap(JSGlobalContextRef);
~WrapperMap();
GRefPtr<JSCValue> gobjectWrapper(JSCContext*, JSValueRef);
void unwrap(JSValueRef);
void registerClass(JSCClass*);
JSCClass* registeredClass(JSClassRef) const;
JSObject* createJSWrappper(JSGlobalContextRef, JSClassRef, JSValueRef prototype, gpointer, GDestroyNotify);
JSGlobalContextRef createContextWithJSWrappper(JSContextGroupRef, JSClassRef, JSValueRef prototype, gpointer, GDestroyNotify);
JSObject* jsWrapper(gpointer wrappedObject) const;
gpointer wrappedObject(JSGlobalContextRef, JSObjectRef) const;
private:
HashMap<JSValueRef, JSCValue*> m_cachedGObjectWrappers;
std::unique_ptr<JSC::WeakGCMap<gpointer, JSC::JSObject>> m_cachedJSWrappers;
HashMap<JSClassRef, GRefPtr<JSCClass>> m_classMap;
};
} // namespace JSC

Some files were not shown because too many files have changed in this diff Show More