https://bugs.webkit.org/show_bug.cgi?id=186877
Reviewed by Filip Pizlo.
Here’s an example of the results that this fix may yield:
1. The workload: load cnn.com, wait for it to fully load, scroll down and up.
2. Statistics on memory touched and memory freed by VM::deleteAllCode():
Visiting Executables:
Old New
Number of objects visited: 70897 14264
Number of objects with deletable code: 14264 (20.1%) 14264 (100%)
Number of memory pages visited: 3224 1602
Number of memory pages with deletable code: 1602 (49.7%) 1602 (100%)
Visitng UnlinkedFunctionExecutables:
Old New
Number of objects visited: 105454 17231
Number of objects with deletable code: 42319 (20.1%) 17231 (100%) **
Number of memory pages visited: 4796 1349
Number of memory pages with deletable code: 4013 (83.7%) 1349 (100%)
** The number of objects differ because the old code only visit unlinked
executables indirectly via linked executables, whereas the new behavior visit
all unlinked executables with deletable code directly. This means:
a. we used to not visit unlinked executables that have not been linked yet
i.e. deleteAllCode() may not delete all code (especially code that is not
used).
b. we had to visit all linked executables to check if they of type
FunctionExecutable, before going on to visit their unlinked executable, and
this includes the ones that do not have deletable code. This means that we
would touch more memory in the process.
Both of these these issues are now fixed with the new code.
This code was tested with manually inserted instrumentation to track the above
statistics. It is not feasible to write an automated test for this without
leaving a lot of invasive instrumentation in the code.
* bytecode/UnlinkedFunctionExecutable.cpp:
(JSC::UnlinkedFunctionExecutable::unlinkedCodeBlockFor):
* bytecode/UnlinkedFunctionExecutable.h:
* heap/CodeBlockSetInlines.h:
(JSC::CodeBlockSet::iterateViaSubspaces):
* heap/Heap.cpp:
(JSC::Heap::deleteAllCodeBlocks):
(JSC::Heap::deleteAllUnlinkedCodeBlocks):
(JSC::Heap::deleteUnmarkedCompiledCode):
(JSC::Heap::clearUnmarkedExecutables): Deleted.
(JSC::Heap::addExecutable): Deleted.
* heap/Heap.h:
* runtime/DirectEvalExecutable.h:
* runtime/ExecutableBase.cpp:
(JSC::ExecutableBase::hasClearableCode const):
- this is written based on the implementation of ExecutableBase::clearCode().
* runtime/ExecutableBase.h:
* runtime/FunctionExecutable.h:
* runtime/IndirectEvalExecutable.h:
* runtime/ModuleProgramExecutable.h:
* runtime/ProgramExecutable.h:
* runtime/ScriptExecutable.cpp:
(JSC::ScriptExecutable::clearCode):
(JSC::ScriptExecutable::installCode):
* runtime/ScriptExecutable.h:
(JSC::ScriptExecutable::finishCreation):
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
(JSC::VM::ScriptExecutableSpaceAndSet::ScriptExecutableSpaceAndSet):
(JSC::VM::ScriptExecutableSpaceAndSet::clearableCodeSetFor):
(JSC::VM::forEachScriptExecutableSpace):
(JSC::VM::UnlinkedFunctionExecutableSpaceAndSet::UnlinkedFunctionExecutableSpaceAndSet):
(JSC::VM::UnlinkedFunctionExecutableSpaceAndSet::clearableCodeSetFor):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@233039
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2018-06-21 Mark Lam <mark.lam@apple.com>
+
+ Use IsoCellSets to track Executables with clearable code.
+ https://bugs.webkit.org/show_bug.cgi?id=186877
+
+ Reviewed by Filip Pizlo.
+
+ Here’s an example of the results that this fix may yield:
+ 1. The workload: load cnn.com, wait for it to fully load, scroll down and up.
+ 2. Statistics on memory touched and memory freed by VM::deleteAllCode():
+
+ Visiting Executables:
+ Old New
+ Number of objects visited: 70897 14264
+ Number of objects with deletable code: 14264 (20.1%) 14264 (100%)
+ Number of memory pages visited: 3224 1602
+ Number of memory pages with deletable code: 1602 (49.7%) 1602 (100%)
+
+ Visitng UnlinkedFunctionExecutables:
+ Old New
+ Number of objects visited: 105454 17231
+ Number of objects with deletable code: 42319 (20.1%) 17231 (100%) **
+ Number of memory pages visited: 4796 1349
+ Number of memory pages with deletable code: 4013 (83.7%) 1349 (100%)
+
+ ** The number of objects differ because the old code only visit unlinked
+ executables indirectly via linked executables, whereas the new behavior visit
+ all unlinked executables with deletable code directly. This means:
+
+ a. we used to not visit unlinked executables that have not been linked yet
+ i.e. deleteAllCode() may not delete all code (especially code that is not
+ used).
+ b. we had to visit all linked executables to check if they of type
+ FunctionExecutable, before going on to visit their unlinked executable, and
+ this includes the ones that do not have deletable code. This means that we
+ would touch more memory in the process.
+
+ Both of these these issues are now fixed with the new code.
+
+ This code was tested with manually inserted instrumentation to track the above
+ statistics. It is not feasible to write an automated test for this without
+ leaving a lot of invasive instrumentation in the code.
+
+ * bytecode/UnlinkedFunctionExecutable.cpp:
+ (JSC::UnlinkedFunctionExecutable::unlinkedCodeBlockFor):
+ * bytecode/UnlinkedFunctionExecutable.h:
+ * heap/CodeBlockSetInlines.h:
+ (JSC::CodeBlockSet::iterateViaSubspaces):
+ * heap/Heap.cpp:
+ (JSC::Heap::deleteAllCodeBlocks):
+ (JSC::Heap::deleteAllUnlinkedCodeBlocks):
+ (JSC::Heap::deleteUnmarkedCompiledCode):
+ (JSC::Heap::clearUnmarkedExecutables): Deleted.
+ (JSC::Heap::addExecutable): Deleted.
+ * heap/Heap.h:
+ * runtime/DirectEvalExecutable.h:
+
+ * runtime/ExecutableBase.cpp:
+ (JSC::ExecutableBase::hasClearableCode const):
+ - this is written based on the implementation of ExecutableBase::clearCode().
+
+ * runtime/ExecutableBase.h:
+ * runtime/FunctionExecutable.h:
+ * runtime/IndirectEvalExecutable.h:
+ * runtime/ModuleProgramExecutable.h:
+ * runtime/ProgramExecutable.h:
+ * runtime/ScriptExecutable.cpp:
+ (JSC::ScriptExecutable::clearCode):
+ (JSC::ScriptExecutable::installCode):
+ * runtime/ScriptExecutable.h:
+ (JSC::ScriptExecutable::finishCreation):
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ * runtime/VM.h:
+ (JSC::VM::ScriptExecutableSpaceAndSet::ScriptExecutableSpaceAndSet):
+ (JSC::VM::ScriptExecutableSpaceAndSet::clearableCodeSetFor):
+ (JSC::VM::forEachScriptExecutableSpace):
+ (JSC::VM::UnlinkedFunctionExecutableSpaceAndSet::UnlinkedFunctionExecutableSpaceAndSet):
+ (JSC::VM::UnlinkedFunctionExecutableSpaceAndSet::clearableCodeSetFor):
+
2018-06-21 Zan Dobersek <zdobersek@igalia.com>
[GTK] WebDriver: allow applying host-specific TLS certificates for automated sessions
#include "Debugger.h"
#include "ExecutableInfo.h"
#include "FunctionOverrides.h"
+#include "IsoCellSetInlines.h"
#include "JSCInlines.h"
#include "Parser.h"
#include "SourceProvider.h"
m_unlinkedCodeBlockForConstruct.set(vm, this, result);
break;
}
+ vm.unlinkedFunctionExecutableSpace.clearableCodeSet.add(this);
return result;
}
typedef JSCell Base;
static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+ template<typename CellType>
+ static IsoSubspace* subspaceFor(VM& vm)
+ {
+ return &vm.unlinkedFunctionExecutableSpace.space;
+ }
+
static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, VariableEnvironment& parentScopeTDZVariables, DerivedContextType derivedContextType, bool isBuiltinDefaultClassConstructor = false)
{
UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm->heap))
JS_EXPORT_PRIVATE FunctionExecutable* link(VM&, const SourceCode& parentSource, std::optional<int> overrideLineNumber = std::nullopt, Intrinsic = NoIntrinsic);
- void clearCode()
+ void clearCode(VM& vm)
{
m_unlinkedCodeBlockForCall.clear();
m_unlinkedCodeBlockForConstruct.clear();
+ vm.unlinkedFunctionExecutableSpace.clearableCodeSet.remove(this);
}
void recordParse(CodeFeatures features, bool hasCapturedVariables)
/*
- * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-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
void CodeBlockSet::iterateViaSubspaces(VM& vm, const Functor& functor)
{
vm.forEachCodeBlockSpace(
- [&] (IsoSubspace& space) {
- space.forEachLiveCell(
+ [&] (auto& spaceAndSet) {
+ spaceAndSet.space.forEachLiveCell(
[&] (HeapCell* cell, HeapCell::Kind) {
functor(jsCast<CodeBlock*>(static_cast<JSCell*>(cell)));
});
{
if (m_collectionScope && effort == DeleteAllCodeIfNotCollecting)
return;
-
+
+ VM& vm = *m_vm;
PreventCollectionScope preventCollectionScope(*this);
// If JavaScript is running, it's not safe to delete all JavaScript code, since
// we'll end up returning to deleted code.
- RELEASE_ASSERT(!m_vm->entryScope);
+ RELEASE_ASSERT(!vm.entryScope);
RELEASE_ASSERT(!m_collectionScope);
completeAllJITPlans();
- for (ExecutableBase* executable : m_executables)
- executable->clearCode();
+ vm.forEachScriptExecutableSpace(
+ [&] (auto& spaceAndSet) {
+ HeapIterationScope heapIterationScope(*this);
+ auto& clearableCodeSet = spaceAndSet.clearableCodeSet;
+ clearableCodeSet.forEachLiveCell(
+ [&] (HeapCell* cell, HeapCell::Kind) {
+ ScriptExecutable* executable = static_cast<ScriptExecutable*>(cell);
+ executable->clearCode(clearableCodeSet);
+ });
+ });
#if ENABLE(WEBASSEMBLY)
{
// points into a CodeBlock that could be dead. The IC will still succeed because
// it uses a callee check, but then it will call into dead code.
HeapIterationScope heapIterationScope(*this);
- m_vm->webAssemblyCodeBlockSpace.forEachLiveCell([&] (HeapCell* cell, HeapCell::Kind kind) {
+ vm.webAssemblyCodeBlockSpace.forEachLiveCell([&] (HeapCell* cell, HeapCell::Kind kind) {
ASSERT_UNUSED(kind, kind == HeapCell::Kind::JSCell);
JSWebAssemblyCodeBlock* codeBlock = static_cast<JSWebAssemblyCodeBlock*>(cell);
- codeBlock->clearJSCallICs(*m_vm);
+ codeBlock->clearJSCallICs(vm);
});
}
#endif
{
if (m_collectionScope && effort == DeleteAllCodeIfNotCollecting)
return;
-
+
+ VM& vm = *m_vm;
PreventCollectionScope preventCollectionScope(*this);
RELEASE_ASSERT(!m_collectionScope);
-
- for (ExecutableBase* current : m_executables) {
- if (!current->isFunctionExecutable())
- continue;
- static_cast<FunctionExecutable*>(current)->unlinkedExecutable()->clearCode();
- }
-}
-void Heap::clearUnmarkedExecutables()
-{
- for (unsigned i = m_executables.size(); i--;) {
- ExecutableBase* current = m_executables[i];
- if (isMarked(current))
- continue;
-
- // Eagerly dereference the Executable's JITCode in order to run watchpoint
- // destructors. Otherwise, watchpoints might fire for deleted CodeBlocks.
- current->clearCode();
- std::swap(m_executables[i], m_executables.last());
- m_executables.removeLast();
- }
-
- m_executables.shrinkToFit();
+ HeapIterationScope heapIterationScope(*this);
+ vm.unlinkedFunctionExecutableSpace.clearableCodeSet.forEachLiveCell(
+ [&] (HeapCell* cell, HeapCell::Kind) {
+ UnlinkedFunctionExecutable* executable = static_cast<UnlinkedFunctionExecutable*>(cell);
+ executable->clearCode(vm);
+ });
}
void Heap::deleteUnmarkedCompiledCode()
{
- clearUnmarkedExecutables();
+ vm()->forEachScriptExecutableSpace([] (auto& space) { space.space.sweep(); });
vm()->forEachCodeBlockSpace([] (auto& space) { space.space.sweep(); }); // Sweeping must occur before deleting stubs, otherwise the stubs might still think they're alive as they get deleted.
m_jitStubRoutines->deleteUnmarkedJettisonedStubRoutines();
}
WeakSet::deallocate(WeakImpl::asWeakImpl(slot));
}
-void Heap::addExecutable(ExecutableBase* executable)
-{
- m_executables.append(executable);
-}
-
void Heap::collectNowFullIfNotDoneRecently(Synchronousness synchronousness)
{
if (!m_fullActivityCallback) {
class ConservativeRoots;
class GCDeferralContext;
class EdenGCActivityCallback;
-class ExecutableBase;
class FullGCActivityCallback;
class GCActivityCallback;
class GCAwareJITStubRoutine;
typedef void (*Finalizer)(JSCell*);
JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer);
- void addExecutable(ExecutableBase*);
void notifyIsSafeToCollect();
bool isSafeToCollect() const { return m_isSafeToCollect; }
void finalizeMarkedUnconditionalFinalizers(CellSet&);
void finalizeUnconditionalFinalizers();
-
- void clearUnmarkedExecutables();
+
void deleteUnmarkedCompiledCode();
JS_EXPORT_PRIVATE void addToRememberedSet(const JSCell*);
void updateAllocationLimits();
Seconds m_lastFullGCLength;
Seconds m_lastEdenGCLength;
- Vector<ExecutableBase*> m_executables;
-
Vector<WeakBlock*> m_logicallyEmptyWeakBlocks;
size_t m_indexOfNextLogicallyEmptyWeakBlockToSweep { WTF::notFound };
/*
- * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-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
template<typename CellType>
static IsoSubspace* subspaceFor(VM& vm)
{
- return &vm.directEvalExecutableSpace;
+ return &vm.directEvalExecutableSpace.space;
}
static DirectEvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, DerivedContextType, bool isArrowFunctionContext, EvalContextType, const VariableEnvironment*);
static_cast<ExecutableBase*>(cell)->ExecutableBase::~ExecutableBase();
}
+bool ExecutableBase::hasClearableCode() const
+{
+ VM& vm = *this->vm();
+
+#if ENABLE(JIT)
+ if (m_jitCodeForCall
+ || m_jitCodeForConstruct
+ || m_jitCodeForCallWithArityCheck
+ || m_jitCodeForConstructWithArityCheck)
+ return true;
+#endif
+
+ if (structure(vm)->classInfo() == FunctionExecutable::info()) {
+ auto* executable = static_cast<const FunctionExecutable*>(this);
+ if (executable->m_codeBlockForCall || executable->m_codeBlockForConstruct)
+ return true;
+
+ } else if (structure(vm)->classInfo() == EvalExecutable::info()) {
+ auto* executable = static_cast<const EvalExecutable*>(this);
+ if (executable->m_evalCodeBlock || executable->m_unlinkedEvalCodeBlock)
+ return true;
+
+ } else if (structure(vm)->classInfo() == ProgramExecutable::info()) {
+ auto* executable = static_cast<const ProgramExecutable*>(this);
+ if (executable->m_programCodeBlock || executable->m_unlinkedProgramCodeBlock)
+ return true;
+
+ } else if (structure(vm)->classInfo() == ModuleProgramExecutable::info()) {
+ auto* executable = static_cast<const ModuleProgramExecutable*>(this);
+ if (executable->m_moduleProgramCodeBlock
+ || executable->m_unlinkedModuleProgramCodeBlock
+ || executable->m_moduleEnvironmentSymbolTable)
+ return true;
+ }
+ return false;
+}
+
void ExecutableBase::clearCode()
{
#if ENABLE(JIT)
}
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); }
-
+
+ bool hasClearableCode() const;
void clearCode();
DECLARE_EXPORT_INFO;
template<typename CellType>
static IsoSubspace* subspaceFor(VM& vm)
{
- return &vm.functionExecutableSpace;
+ return &vm.functionExecutableSpace.space;
}
static FunctionExecutable* create(
/*
- * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-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
template<typename CellType>
static IsoSubspace* subspaceFor(VM& vm)
{
- return &vm.indirectEvalExecutableSpace;
+ return &vm.indirectEvalExecutableSpace.space;
}
static IndirectEvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, DerivedContextType, bool isArrowFunctionContext, EvalContextType);
/*
- * Copyright (C) 2009-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2009-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
template<typename CellType>
static IsoSubspace* subspaceFor(VM& vm)
{
- return &vm.moduleProgramExecutableSpace;
+ return &vm.moduleProgramExecutableSpace.space;
}
static ModuleProgramExecutable* create(ExecState*, const SourceCode&);
/*
- * Copyright (C) 2009-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2009-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
template<typename CellType>
static IsoSubspace* subspaceFor(VM& vm)
{
- return &vm.programExecutableSpace;
+ return &vm.programExecutableSpace.space;
}
static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
#include "Debugger.h"
#include "EvalCodeBlock.h"
#include "FunctionCodeBlock.h"
+#include "IsoCellSetInlines.h"
#include "JIT.h"
#include "JSCInlines.h"
#include "LLIntEntrypoint.h"
static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable();
}
+void ScriptExecutable::clearCode(IsoCellSet& clearableCodeSet)
+{
+ Base::clearCode();
+ ASSERT(&VM::ScriptExecutableSpaceAndSet::clearableCodeSetFor(*subspace()) == &clearableCodeSet);
+ clearableCodeSet.remove(this);
+}
+
void ScriptExecutable::installCode(CodeBlock* codeBlock)
{
installCode(*codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind());
break;
}
+ auto& clearableCodeSet = VM::ScriptExecutableSpaceAndSet::clearableCodeSetFor(*subspace());
+ if (hasClearableCode())
+ clearableCodeSet.add(this);
+ else
+ clearableCodeSet.remove(this);
+
if (genericCodeBlock) {
RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this);
RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType()));
/*
- * Copyright (C) 2009, 2010, 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2009-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
namespace JSC {
+class IsoCellSet;
+
class ScriptExecutable : public ExecutableBase {
public:
typedef ExecutableBase Base;
CodeBlock* newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, JSObject*& exception);
CodeBlock* newReplacementCodeBlockFor(CodeSpecializationKind);
+ void clearCode(IsoCellSet&);
+
// This function has an interesting GC story. Callers of this function are asking us to create a CodeBlock
// that is not jettisoned before this function returns. Callers are essentially asking for a strong reference
// to the CodeBlock. Because the Executable may be allocating the CodeBlock, we require callers to pass in
void finishCreation(VM& vm)
{
Base::finishCreation(vm);
- vm.heap.addExecutable(this); // Balanced by Heap::deleteUnmarkedCompiledCode().
#if ENABLE(CODEBLOCK_SAMPLING)
if (SamplingTool* sampler = vm.interpreter->sampler())
, boundFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSBoundFunction)
, callbackFunctionSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), JSCallbackFunction)
, customGetterSetterFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSCustomGetterSetterFunction)
- , directEvalExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), DirectEvalExecutable)
, errorConstructorSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), ErrorConstructor)
, executableToCodeBlockEdgeSpace ISO_SUBSPACE_INIT(heap, cellDangerousBitsHeapCellType.get(), ExecutableToCodeBlockEdge)
- , functionExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), FunctionExecutable)
, functionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSFunction)
, generatorFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSGeneratorFunction)
- , indirectEvalExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), IndirectEvalExecutable)
, inferredTypeSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), InferredType)
, inferredValueSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), InferredValue)
, internalFunctionSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), InternalFunction)
, intlNumberFormatConstructorSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), IntlNumberFormatConstructor)
, intlPluralRulesConstructorSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), IntlPluralRulesConstructor)
#endif
- , moduleProgramExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), ModuleProgramExecutable)
, nativeErrorConstructorSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), NativeErrorConstructor)
, nativeExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), NativeExecutable)
, nativeStdFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSNativeStdFunction)
#if JSC_OBJC_API_ENABLED
, objCCallbackFunctionSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), ObjCCallbackFunction)
#endif
- , programExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), ProgramExecutable)
, propertyTableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), PropertyTable)
, proxyRevokeSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), ProxyRevoke)
, regExpConstructorSpace ISO_SUBSPACE_INIT(heap, destructibleObjectHeapCellType.get(), RegExpConstructor)
, functionCodeBlockSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), FunctionCodeBlock)
, moduleProgramCodeBlockSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), ModuleProgramCodeBlock)
, programCodeBlockSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), ProgramCodeBlock)
+ , directEvalExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), DirectEvalExecutable)
+ , functionExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), FunctionExecutable)
+ , indirectEvalExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), IndirectEvalExecutable)
+ , moduleProgramExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), ModuleProgramExecutable)
+ , programExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), ProgramExecutable)
+ , unlinkedFunctionExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), UnlinkedFunctionExecutable)
, vmType(vmType)
, clientData(0)
, topEntryFrame(nullptr)
IsoSubspace boundFunctionSpace;
IsoSubspace callbackFunctionSpace;
IsoSubspace customGetterSetterFunctionSpace;
- IsoSubspace directEvalExecutableSpace;
IsoSubspace errorConstructorSpace;
IsoSubspace executableToCodeBlockEdgeSpace;
- IsoSubspace functionExecutableSpace;
IsoSubspace functionSpace;
IsoSubspace generatorFunctionSpace;
- IsoSubspace indirectEvalExecutableSpace;
IsoSubspace inferredTypeSpace;
IsoSubspace inferredValueSpace;
IsoSubspace internalFunctionSpace;
IsoSubspace intlNumberFormatConstructorSpace;
IsoSubspace intlPluralRulesConstructorSpace;
#endif
- IsoSubspace moduleProgramExecutableSpace;
IsoSubspace nativeErrorConstructorSpace;
IsoSubspace nativeExecutableSpace;
IsoSubspace nativeStdFunctionSpace;
#if JSC_OBJC_API_ENABLED
IsoSubspace objCCallbackFunctionSpace;
#endif
- IsoSubspace programExecutableSpace;
IsoSubspace propertyTableSpace;
IsoSubspace proxyRevokeSpace;
IsoSubspace regExpConstructorSpace;
func(moduleProgramCodeBlockSpace);
func(programCodeBlockSpace);
}
-
+
+ struct ScriptExecutableSpaceAndSet {
+ IsoSubspace space;
+ IsoCellSet clearableCodeSet;
+
+ template<typename... Arguments>
+ ScriptExecutableSpaceAndSet(Arguments&&... arguments)
+ : space(std::forward<Arguments>(arguments)...)
+ , clearableCodeSet(space)
+ { }
+
+ static IsoCellSet& clearableCodeSetFor(Subspace& space)
+ {
+ return *bitwise_cast<IsoCellSet*>(
+ bitwise_cast<char*>(&space) -
+ OBJECT_OFFSETOF(ScriptExecutableSpaceAndSet, space) +
+ OBJECT_OFFSETOF(ScriptExecutableSpaceAndSet, clearableCodeSet));
+ }
+ };
+
+ ScriptExecutableSpaceAndSet directEvalExecutableSpace;
+ ScriptExecutableSpaceAndSet functionExecutableSpace;
+ ScriptExecutableSpaceAndSet indirectEvalExecutableSpace;
+ ScriptExecutableSpaceAndSet moduleProgramExecutableSpace;
+ ScriptExecutableSpaceAndSet programExecutableSpace;
+
+ template<typename Func>
+ void forEachScriptExecutableSpace(const Func& func)
+ {
+ func(directEvalExecutableSpace);
+ func(functionExecutableSpace);
+ func(indirectEvalExecutableSpace);
+ func(moduleProgramExecutableSpace);
+ func(programExecutableSpace);
+ }
+
+ struct UnlinkedFunctionExecutableSpaceAndSet {
+ IsoSubspace space;
+ IsoCellSet clearableCodeSet;
+
+ template<typename... Arguments>
+ UnlinkedFunctionExecutableSpaceAndSet(Arguments&&... arguments)
+ : space(std::forward<Arguments>(arguments)...)
+ , clearableCodeSet(space)
+ { }
+
+ static IsoCellSet& clearableCodeSetFor(Subspace& space)
+ {
+ return *bitwise_cast<IsoCellSet*>(
+ bitwise_cast<char*>(&space) -
+ OBJECT_OFFSETOF(UnlinkedFunctionExecutableSpaceAndSet, space) +
+ OBJECT_OFFSETOF(UnlinkedFunctionExecutableSpaceAndSet, clearableCodeSet));
+ }
+ };
+
+ UnlinkedFunctionExecutableSpaceAndSet unlinkedFunctionExecutableSpace;
+
VMType vmType;
ClientData* clientData;
EntryFrame* topEntryFrame;