https://bugs.webkit.org/show_bug.cgi?id=194191
Reviewed by Michael Saboff.
This patch reduces the size of FunctionExecutable. Since it is allocated in IsoSubspace, reducing the size directly
improves the allocation efficiency.
1. ScriptExecutable (base class of FunctionExecutable) has several members, but it is meaningful only in FunctionExecutable.
We remove this from ScriptExecutable, and move it to FunctionExecutable.
2. FunctionExecutable has several data which are rarely used. One for FunctionOverrides functionality, which is typically
used for JSC debugging purpose, and another is TypeSet and offsets for type profiler. We move them to RareData and reduce
the size of FunctionExecutable in the common case.
This patch changes the size of FunctionExecutable from 176 to 144.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpSource):
(JSC::CodeBlock::finishCreation):
* dfg/DFGNode.h:
(JSC::DFG::Node::OpInfoWrapper::as const):
* interpreter/StackVisitor.cpp:
(JSC::StackVisitor::Frame::computeLineAndColumn const):
* runtime/ExecutableBase.h:
* runtime/FunctionExecutable.cpp:
(JSC::FunctionExecutable::FunctionExecutable):
(JSC::FunctionExecutable::ensureRareDataSlow):
* runtime/FunctionExecutable.h:
* runtime/Intrinsic.h:
* runtime/ModuleProgramExecutable.cpp:
(JSC::ModuleProgramExecutable::ModuleProgramExecutable):
* runtime/ProgramExecutable.cpp:
(JSC::ProgramExecutable::ProgramExecutable):
* runtime/ScriptExecutable.cpp:
(JSC::ScriptExecutable::ScriptExecutable):
(JSC::ScriptExecutable::overrideLineNumber const):
(JSC::ScriptExecutable::typeProfilingStartOffset const):
(JSC::ScriptExecutable::typeProfilingEndOffset const):
* runtime/ScriptExecutable.h:
(JSC::ScriptExecutable::firstLine const):
(JSC::ScriptExecutable::setOverrideLineNumber): Deleted.
(JSC::ScriptExecutable::hasOverrideLineNumber const): Deleted.
(JSC::ScriptExecutable::overrideLineNumber const): Deleted.
(JSC::ScriptExecutable::typeProfilingStartOffset const): Deleted.
(JSC::ScriptExecutable::typeProfilingEndOffset const): Deleted.
* runtime/StackFrame.cpp:
(JSC::StackFrame::computeLineAndColumn const):
* tools/JSDollarVM.cpp:
(JSC::functionReturnTypeFor):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@240938
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2019-02-04 Yusuke Suzuki <ysuzuki@apple.com>
+
+ [JSC] Shrink size of FunctionExecutable
+ https://bugs.webkit.org/show_bug.cgi?id=194191
+
+ Reviewed by Michael Saboff.
+
+ This patch reduces the size of FunctionExecutable. Since it is allocated in IsoSubspace, reducing the size directly
+ improves the allocation efficiency.
+
+ 1. ScriptExecutable (base class of FunctionExecutable) has several members, but it is meaningful only in FunctionExecutable.
+ We remove this from ScriptExecutable, and move it to FunctionExecutable.
+
+ 2. FunctionExecutable has several data which are rarely used. One for FunctionOverrides functionality, which is typically
+ used for JSC debugging purpose, and another is TypeSet and offsets for type profiler. We move them to RareData and reduce
+ the size of FunctionExecutable in the common case.
+
+ This patch changes the size of FunctionExecutable from 176 to 144.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dumpSource):
+ (JSC::CodeBlock::finishCreation):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::OpInfoWrapper::as const):
+ * interpreter/StackVisitor.cpp:
+ (JSC::StackVisitor::Frame::computeLineAndColumn const):
+ * runtime/ExecutableBase.h:
+ * runtime/FunctionExecutable.cpp:
+ (JSC::FunctionExecutable::FunctionExecutable):
+ (JSC::FunctionExecutable::ensureRareDataSlow):
+ * runtime/FunctionExecutable.h:
+ * runtime/Intrinsic.h:
+ * runtime/ModuleProgramExecutable.cpp:
+ (JSC::ModuleProgramExecutable::ModuleProgramExecutable):
+ * runtime/ProgramExecutable.cpp:
+ (JSC::ProgramExecutable::ProgramExecutable):
+ * runtime/ScriptExecutable.cpp:
+ (JSC::ScriptExecutable::ScriptExecutable):
+ (JSC::ScriptExecutable::overrideLineNumber const):
+ (JSC::ScriptExecutable::typeProfilingStartOffset const):
+ (JSC::ScriptExecutable::typeProfilingEndOffset const):
+ * runtime/ScriptExecutable.h:
+ (JSC::ScriptExecutable::firstLine const):
+ (JSC::ScriptExecutable::setOverrideLineNumber): Deleted.
+ (JSC::ScriptExecutable::hasOverrideLineNumber const): Deleted.
+ (JSC::ScriptExecutable::overrideLineNumber const): Deleted.
+ (JSC::ScriptExecutable::typeProfilingStartOffset const): Deleted.
+ (JSC::ScriptExecutable::typeProfilingEndOffset const): Deleted.
+ * runtime/StackFrame.cpp:
+ (JSC::StackFrame::computeLineAndColumn const):
+ * tools/JSDollarVM.cpp:
+ (JSC::functionReturnTypeFor):
+
2019-02-04 Mark Lam <mark.lam@apple.com>
DFG's doesGC() is incorrect about the SameValue node's behavior.
FunctionExecutable* functionExecutable = reinterpret_cast<FunctionExecutable*>(executable);
StringView source = functionExecutable->source().provider()->getRange(
functionExecutable->parametersStartOffset(),
- functionExecutable->typeProfilingEndOffset() + 1); // Type profiling end offset is the character before the '}'.
+ functionExecutable->typeProfilingEndOffset(*vm()) + 1); // Type profiling end offset is the character before the '}'.
out.print("function ", inferredName(), source);
return;
auto throwScope = DECLARE_THROW_SCOPE(vm);
if (vm.typeProfiler() || vm.controlFlowProfiler())
- vm.functionHasExecutedCache()->removeUnexecutedRange(ownerExecutable->sourceID(), ownerExecutable->typeProfilingStartOffset(), ownerExecutable->typeProfilingEndOffset());
+ vm.functionHasExecutedCache()->removeUnexecutedRange(ownerExecutable->sourceID(), ownerExecutable->typeProfilingStartOffset(vm), ownerExecutable->typeProfilingEndOffset(vm));
setConstantRegisters(unlinkedCodeBlock->constantRegisters(), unlinkedCodeBlock->constantsSourceCodeRepresentation());
RETURN_IF_EXCEPTION(throwScope, false);
// the user's program, give the type profiler some range to identify these return statements.
// Currently, the text offset that is used as identification is "f" in the function keyword
// and is stored on TypeLocation's m_divotForFunctionOffsetIfReturnStatement member variable.
- divotStart = divotEnd = ownerExecutable->typeProfilingStartOffset();
+ divotStart = divotEnd = ownerExecutable->typeProfilingStartOffset(vm);
shouldAnalyze = true;
}
break;
bool isNewLocation = locationPair.second;
if (bytecode.m_flag == ProfileTypeBytecodeFunctionReturnStatement)
- location->m_divotForFunctionOffsetIfReturnStatement = ownerExecutable->typeProfilingStartOffset();
+ location->m_divotForFunctionOffsetIfReturnStatement = ownerExecutable->typeProfilingStartOffset(vm);
if (shouldAnalyze && isNewLocation)
vm.typeProfiler()->insertNewLocation(location);
return static_cast<T>(u.constPointer);
}
template <typename T>
- ALWAYS_INLINE auto as() const -> typename std::enable_if<(std::is_integral<T>::value || std::is_enum<T>::value) && sizeof(T) == 4, T>::type
+ ALWAYS_INLINE auto as() const -> typename std::enable_if<(std::is_integral<T>::value || std::is_enum<T>::value) && sizeof(T) <= 4, T>::type
{
return static_cast<T>(u.int32);
}
line = divotLine + codeBlock->ownerScriptExecutable()->firstLine();
column = divotColumn + (divotLine ? 1 : codeBlock->firstLineColumnOffset());
- if (codeBlock->ownerScriptExecutable()->hasOverrideLineNumber())
- line = codeBlock->ownerScriptExecutable()->overrideLineNumber();
+ if (Optional<int> overrideLineNumber = codeBlock->ownerScriptExecutable()->overrideLineNumber(*codeBlock->vm()))
+ line = overrideLineNumber.value();
}
void StackVisitor::Frame::retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) const
void dump(PrintStream&) const;
protected:
- Intrinsic m_intrinsic;
RefPtr<JITCode> m_jitCodeForCall;
RefPtr<JITCode> m_jitCodeForConstruct;
MacroAssemblerCodePtr<JSEntryPtrTag> m_jitCodeForCallWithArityCheck;
MacroAssemblerCodePtr<JSEntryPtrTag> m_jitCodeForConstructWithArityCheck;
+ Intrinsic m_intrinsic;
};
} // namespace JSC
m_lastLine = lastLine;
ASSERT(endColumn != UINT_MAX);
m_endColumn = endColumn;
- m_parametersStartOffset = unlinkedExecutable->parametersStartOffset();
- m_typeProfilingStartOffset = unlinkedExecutable->typeProfilingStartOffset();
- m_typeProfilingEndOffset = unlinkedExecutable->typeProfilingEndOffset();
if (VM::canUseJIT())
new (&m_singletonFunction) WriteBarrier<InferredValue>();
else
return unlinkedExecutable->link(exec.vm(), source, overrideLineNumber);
}
+FunctionExecutable::RareData& FunctionExecutable::ensureRareDataSlow()
+{
+ ASSERT(!m_rareData);
+ m_rareData = std::make_unique<RareData>();
+ m_rareData->m_parametersStartOffset = m_unlinkedExecutable->parametersStartOffset();
+ m_rareData->m_typeProfilingStartOffset = m_unlinkedExecutable->typeProfilingStartOffset();
+ m_rareData->m_typeProfilingEndOffset = m_unlinkedExecutable->typeProfilingEndOffset();
+ return *m_rareData;
+}
+
} // namespace JSC
#include "ScriptExecutable.h"
#include "SourceCode.h"
#include <wtf/Box.h>
+#include <wtf/Markable.h>
namespace JSC {
RefPtr<TypeSet> returnStatementTypeSet()
{
- if (!m_returnStatementTypeSet)
- m_returnStatementTypeSet = TypeSet::create();
-
- return m_returnStatementTypeSet;
+ RareData& rareData = ensureRareData();
+ if (!rareData.m_returnStatementTypeSet)
+ rareData.m_returnStatementTypeSet = TypeSet::create();
+ return rareData.m_returnStatementTypeSet;
}
FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); }
return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), info());
}
- unsigned parametersStartOffset() const { return m_parametersStartOffset; }
+ void setOverrideLineNumber(int overrideLineNumber)
+ {
+ if (overrideLineNumber == -1) {
+ if (UNLIKELY(m_rareData))
+ m_rareData->m_overrideLineNumber = WTF::nullopt;
+ return;
+ }
+ ensureRareData().m_overrideLineNumber = overrideLineNumber;
+ }
+
+ Optional<int> overrideLineNumber() const
+ {
+ if (UNLIKELY(m_rareData))
+ return m_rareData->m_overrideLineNumber;
+ return WTF::nullopt;
+ }
+
+ unsigned typeProfilingStartOffset(VM&) const
+ {
+ if (UNLIKELY(m_rareData))
+ return m_rareData->m_typeProfilingStartOffset;
+ return m_unlinkedExecutable->typeProfilingStartOffset();
+ }
+
+ unsigned typeProfilingEndOffset(VM&) const
+ {
+ if (UNLIKELY(m_rareData))
+ return m_rareData->m_typeProfilingEndOffset;
+ return m_unlinkedExecutable->typeProfilingEndOffset();
+ }
+
+ unsigned parametersStartOffset() const
+ {
+ if (UNLIKELY(m_rareData))
+ return m_rareData->m_parametersStartOffset;
+ return m_unlinkedExecutable->parametersStartOffset();
+ }
void overrideParameterAndTypeProfilingStartEndOffsets(unsigned parametersStartOffset, unsigned typeProfilingStartOffset, unsigned typeProfilingEndOffset)
{
- m_parametersStartOffset = parametersStartOffset;
- m_typeProfilingStartOffset = typeProfilingStartOffset;
- m_typeProfilingEndOffset = typeProfilingEndOffset;
+ auto& rareData = ensureRareData();
+ rareData.m_parametersStartOffset = parametersStartOffset;
+ rareData.m_typeProfilingStartOffset = typeProfilingStartOffset;
+ rareData.m_typeProfilingEndOffset = typeProfilingEndOffset;
}
DECLARE_INFO;
void finishCreation(VM&);
friend class ScriptExecutable;
-
- unsigned m_parametersStartOffset;
+
+ struct RareData {
+ WTF_MAKE_STRUCT_FAST_ALLOCATED;
+ Markable<int, IntegralMarkableTraits<int, -1>> m_overrideLineNumber;
+ unsigned m_parametersStartOffset { 0 };
+ unsigned m_typeProfilingStartOffset { UINT_MAX };
+ unsigned m_typeProfilingEndOffset { UINT_MAX };
+ RefPtr<TypeSet> m_returnStatementTypeSet;
+ };
+
+ RareData& ensureRareData()
+ {
+ if (LIKELY(m_rareData))
+ return *m_rareData;
+ return ensureRareDataSlow();
+ }
+ RareData& ensureRareDataSlow();
+
+ std::unique_ptr<RareData> m_rareData;
WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForCall;
WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForConstruct;
- RefPtr<TypeSet> m_returnStatementTypeSet;
union {
WriteBarrier<InferredValue> m_singletonFunction;
WatchpointState m_singletonFunctionState;
namespace JSC {
-enum Intrinsic {
+enum Intrinsic : uint8_t {
// Call intrinsics.
NoIntrinsic,
AbsIntrinsic,
: ScriptExecutable(exec->vm().moduleProgramExecutableStructure.get(), exec->vm(), source, false, DerivedContextType::None, false, EvalContextType::None, NoIntrinsic)
{
ASSERT(source.provider()->sourceType() == SourceProviderSourceType::Module);
- m_typeProfilingStartOffset = 0;
- m_typeProfilingEndOffset = source.length() - 1;
- if (exec->vm().typeProfiler() || exec->vm().controlFlowProfiler())
- exec->vm().functionHasExecutedCache()->insertUnexecutedRange(sourceID(), m_typeProfilingStartOffset, m_typeProfilingEndOffset);
+ VM& vm = exec->vm();
+ if (vm.typeProfiler() || vm.controlFlowProfiler())
+ vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(), typeProfilingStartOffset(vm), typeProfilingEndOffset(vm));
}
ModuleProgramExecutable* ModuleProgramExecutable::create(ExecState* exec, const SourceCode& source)
: ScriptExecutable(exec->vm().programExecutableStructure.get(), exec->vm(), source, false, DerivedContextType::None, false, EvalContextType::None, NoIntrinsic)
{
ASSERT(source.provider()->sourceType() == SourceProviderSourceType::Program);
- m_typeProfilingStartOffset = 0;
- m_typeProfilingEndOffset = source.length() - 1;
- if (exec->vm().typeProfiler() || exec->vm().controlFlowProfiler())
- exec->vm().functionHasExecutedCache()->insertUnexecutedRange(sourceID(), m_typeProfilingStartOffset, m_typeProfilingEndOffset);
+ VM& vm = exec->vm();
+ if (vm.typeProfiler() || vm.controlFlowProfiler())
+ vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(), typeProfilingStartOffset(vm), typeProfilingEndOffset(vm));
}
void ProgramExecutable::destroy(JSCell* cell)
ScriptExecutable::ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext, DerivedContextType derivedContextType, bool isInArrowFunctionContext, EvalContextType evalContextType, Intrinsic intrinsic)
: ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED, intrinsic)
, m_features(isInStrictContext ? StrictModeFeature : 0)
- , m_didTryToEnterInLoop(false)
, m_hasCapturedVariables(false)
, m_neverInline(false)
, m_neverOptimize(false)
, m_canUseOSRExitFuzzing(true)
, m_derivedContextType(static_cast<unsigned>(derivedContextType))
, m_evalContextType(static_cast<unsigned>(evalContextType))
- , m_overrideLineNumber(-1)
- , m_lastLine(-1)
- , m_endColumn(UINT_MAX)
- , m_typeProfilingStartOffset(UINT_MAX)
- , m_typeProfilingEndOffset(UINT_MAX)
, m_source(source)
{
}
return CodeBlockHash(source(), kind);
}
+Optional<int> ScriptExecutable::overrideLineNumber(VM& vm) const
+{
+ if (inherits<FunctionExecutable>(vm))
+ return jsCast<const FunctionExecutable*>(this)->overrideLineNumber();
+ return WTF::nullopt;
+}
+
+unsigned ScriptExecutable::typeProfilingStartOffset(VM& vm) const
+{
+ if (inherits<FunctionExecutable>(vm))
+ return jsCast<const FunctionExecutable*>(this)->typeProfilingStartOffset(vm);
+ if (inherits<EvalExecutable>(vm))
+ return UINT_MAX;
+ return 0;
+}
+
+unsigned ScriptExecutable::typeProfilingEndOffset(VM& vm) const
+{
+ if (inherits<FunctionExecutable>(vm))
+ return jsCast<const FunctionExecutable*>(this)->typeProfilingEndOffset(vm);
+ if (inherits<EvalExecutable>(vm))
+ return UINT_MAX;
+ return m_source.length() - 1;
+}
+
} // namespace JSC
const SourceOrigin& sourceOrigin() const { return m_source.provider()->sourceOrigin(); }
const String& sourceURL() const { return m_source.provider()->url(); }
int firstLine() const { return m_source.firstLine().oneBasedInt(); }
- void setOverrideLineNumber(int overrideLineNumber) { m_overrideLineNumber = overrideLineNumber; }
- bool hasOverrideLineNumber() const { return m_overrideLineNumber != -1; }
- int overrideLineNumber() const { return m_overrideLineNumber; }
int lastLine() const { return m_lastLine; }
unsigned startColumn() const { return m_source.startColumn().oneBasedInt(); }
unsigned endColumn() const { return m_endColumn; }
- unsigned typeProfilingStartOffset() const { return m_typeProfilingStartOffset; }
- unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; }
+
+ Optional<int> overrideLineNumber(VM&) const;
+ unsigned typeProfilingStartOffset(VM&) const;
+ unsigned typeProfilingEndOffset(VM&) const;
bool usesEval() const { return m_features & EvalFeature; }
bool usesArguments() const { return m_features & ArgumentsFeature; }
#endif
}
+ bool m_didTryToEnterInLoop { false };
CodeFeatures m_features;
- bool m_didTryToEnterInLoop;
bool m_hasCapturedVariables : 1;
bool m_neverInline : 1;
bool m_neverOptimize : 1;
unsigned m_derivedContextType : 2; // DerivedContextType
unsigned m_evalContextType : 2; // EvalContextType
- int m_overrideLineNumber;
- int m_lastLine;
- unsigned m_endColumn;
- unsigned m_typeProfilingStartOffset;
- unsigned m_typeProfilingEndOffset;
+ int m_lastLine { -1 };
+ unsigned m_endColumn { UINT_MAX };
SourceCode m_source;
};
m_codeBlock->expressionRangeForBytecodeOffset(m_bytecodeOffset, divot, unusedStartOffset, unusedEndOffset, line, column);
ScriptExecutable* executable = m_codeBlock->ownerScriptExecutable();
- if (executable->hasOverrideLineNumber())
- line = executable->overrideLineNumber();
+ if (Optional<int> overrideLineNumber = executable->overrideLineNumber(*m_codeBlock->vm()))
+ line = overrideLineNumber.value();
}
String StackFrame::toString(VM& vm) const
RELEASE_ASSERT(functionValue.isFunction(vm));
FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable();
- unsigned offset = executable->typeProfilingStartOffset();
+ unsigned offset = executable->typeProfilingStartOffset(vm);
String jsonString = vm.typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorFunctionReturn, offset, executable->sourceID(), vm);
return JSValue::encode(JSONParse(exec, jsonString));
}