/* * 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 #include #include /** * SECTION: JSCVirtualMachine * @short_description: JavaScript Virtual Machine * @title: JSCVirtualMachine * @see_also: JSCContext * * JSCVirtualMachine represents a group of JSCContexts. It allows * concurrent JavaScript execution by creating a different instance of * JSCVirtualMachine in each thread. * * To create a group of JSCContexts pass the same JSCVirtualMachine * instance to every JSCContext constructor. */ struct _JSCVirtualMachinePrivate { JSContextGroupRef jsContextGroup; HashMap contextCache; }; WEBKIT_DEFINE_TYPE(JSCVirtualMachine, jsc_virtual_machine, G_TYPE_OBJECT) static Lock wrapperCacheMutex; static HashMap& wrapperMap() { static LazyNeverDestroyed> shared; static std::once_flag onceKey; std::call_once(onceKey, [&] { shared.construct(); }); return shared; } static void addWrapper(JSContextGroupRef group, JSCVirtualMachine* vm) { auto locker = holdLock(wrapperCacheMutex); ASSERT(!wrapperMap().contains(group)); wrapperMap().set(group, vm); } static void removeWrapper(JSContextGroupRef group) { auto locker = holdLock(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 jscVirtualMachineGetOrCreate(JSContextGroupRef jsContextGroup) { GRefPtr 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)); }