- Revision
- 240951
- Author
- [email protected]
- Date
- 2019-02-04 17:09:57 -0800 (Mon, 04 Feb 2019)
Log Message
[JSC] ExecutableToCodeBlockEdge should be smaller
https://bugs.webkit.org/show_bug.cgi?id=194244
Reviewed by Michael Saboff.
ExecutableToCodeBlockEdge is allocated so many times. However its memory layout is not efficient.
sizeof(ExecutableToCodeBlockEdge) is 24bytes, but it discards 7bytes due to one bool m_isActive flag.
Because our size classes are rounded by 16bytes, ExecutableToCodeBlockEdge takes 32bytes. So, half of
it is wasted. We should fit it into 16bytes so that we can efficiently allocate it.
In this patch, we leverages TypeInfoMayBePrototype bit in JSTypeInfo. It is a bit special TypeInfo bit
since this is per-cell bit. We rename this to TypeInfoPerCellBit, and use it as a `m_isActive` mark in
ExecutableToCodeBlockEdge. In JSObject subclasses, we use it as MayBePrototype flag.
Since this flag is not changed in CAS style, we must not change this in concurrent threads. This is OK
for ExecutableToCodeBlockEdge's m_isActive flag since this is touched on the main thread (ScriptExecutable::installCode
does not touch it if it is called in non-main threads).
* bytecode/ExecutableToCodeBlockEdge.cpp:
(JSC::ExecutableToCodeBlockEdge::finishCreation):
(JSC::ExecutableToCodeBlockEdge::visitChildren):
(JSC::ExecutableToCodeBlockEdge::activate):
(JSC::ExecutableToCodeBlockEdge::deactivate):
(JSC::ExecutableToCodeBlockEdge::isActive const):
* bytecode/ExecutableToCodeBlockEdge.h:
* runtime/JSCell.h:
* runtime/JSCellInlines.h:
(JSC::JSCell::perCellBit const):
(JSC::JSCell::setPerCellBit):
(JSC::JSCell::mayBePrototype const): Deleted.
(JSC::JSCell::didBecomePrototype): Deleted.
* runtime/JSObject.cpp:
(JSC::JSObject::setPrototypeDirect):
* runtime/JSObject.h:
* runtime/JSObjectInlines.h:
(JSC::JSObject::mayBePrototype const):
(JSC::JSObject::didBecomePrototype):
* runtime/JSTypeInfo.h:
(JSC::TypeInfo::perCellBit):
(JSC::TypeInfo::mergeInlineTypeFlags):
(JSC::TypeInfo::mayBePrototype): Deleted.
Modified Paths
Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (240950 => 240951)
--- trunk/Source/_javascript_Core/ChangeLog 2019-02-05 01:08:40 UTC (rev 240950)
+++ trunk/Source/_javascript_Core/ChangeLog 2019-02-05 01:09:57 UTC (rev 240951)
@@ -1,5 +1,49 @@
2019-02-04 Yusuke Suzuki <[email protected]>
+ [JSC] ExecutableToCodeBlockEdge should be smaller
+ https://bugs.webkit.org/show_bug.cgi?id=194244
+
+ Reviewed by Michael Saboff.
+
+ ExecutableToCodeBlockEdge is allocated so many times. However its memory layout is not efficient.
+ sizeof(ExecutableToCodeBlockEdge) is 24bytes, but it discards 7bytes due to one bool m_isActive flag.
+ Because our size classes are rounded by 16bytes, ExecutableToCodeBlockEdge takes 32bytes. So, half of
+ it is wasted. We should fit it into 16bytes so that we can efficiently allocate it.
+
+ In this patch, we leverages TypeInfoMayBePrototype bit in JSTypeInfo. It is a bit special TypeInfo bit
+ since this is per-cell bit. We rename this to TypeInfoPerCellBit, and use it as a `m_isActive` mark in
+ ExecutableToCodeBlockEdge. In JSObject subclasses, we use it as MayBePrototype flag.
+
+ Since this flag is not changed in CAS style, we must not change this in concurrent threads. This is OK
+ for ExecutableToCodeBlockEdge's m_isActive flag since this is touched on the main thread (ScriptExecutable::installCode
+ does not touch it if it is called in non-main threads).
+
+ * bytecode/ExecutableToCodeBlockEdge.cpp:
+ (JSC::ExecutableToCodeBlockEdge::finishCreation):
+ (JSC::ExecutableToCodeBlockEdge::visitChildren):
+ (JSC::ExecutableToCodeBlockEdge::activate):
+ (JSC::ExecutableToCodeBlockEdge::deactivate):
+ (JSC::ExecutableToCodeBlockEdge::isActive const):
+ * bytecode/ExecutableToCodeBlockEdge.h:
+ * runtime/JSCell.h:
+ * runtime/JSCellInlines.h:
+ (JSC::JSCell::perCellBit const):
+ (JSC::JSCell::setPerCellBit):
+ (JSC::JSCell::mayBePrototype const): Deleted.
+ (JSC::JSCell::didBecomePrototype): Deleted.
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::setPrototypeDirect):
+ * runtime/JSObject.h:
+ * runtime/JSObjectInlines.h:
+ (JSC::JSObject::mayBePrototype const):
+ (JSC::JSObject::didBecomePrototype):
+ * runtime/JSTypeInfo.h:
+ (JSC::TypeInfo::perCellBit):
+ (JSC::TypeInfo::mergeInlineTypeFlags):
+ (JSC::TypeInfo::mayBePrototype): Deleted.
+
+2019-02-04 Yusuke Suzuki <[email protected]>
+
[JSC] Shrink size of FunctionExecutable
https://bugs.webkit.org/show_bug.cgi?id=194191
Modified: trunk/Source/_javascript_Core/bytecode/ExecutableToCodeBlockEdge.cpp (240950 => 240951)
--- trunk/Source/_javascript_Core/bytecode/ExecutableToCodeBlockEdge.cpp 2019-02-05 01:08:40 UTC (rev 240950)
+++ trunk/Source/_javascript_Core/bytecode/ExecutableToCodeBlockEdge.cpp 2019-02-05 01:09:57 UTC (rev 240951)
@@ -44,6 +44,12 @@
return result;
}
+void ExecutableToCodeBlockEdge::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(!isActive());
+}
+
void ExecutableToCodeBlockEdge::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
VM& vm = visitor.vm();
@@ -59,7 +65,7 @@
if (!codeBlock)
return;
- if (!edge->m_isActive) {
+ if (!edge->isActive()) {
visitor.appendUnbarriered(codeBlock);
return;
}
@@ -131,16 +137,21 @@
vm.executableToCodeBlockEdgesWithConstraints.remove(this);
}
-void ExecutableToCodeBlockEdge::activate()
+inline void ExecutableToCodeBlockEdge::activate()
{
- m_isActive = true;
+ setPerCellBit(true);
}
-void ExecutableToCodeBlockEdge::deactivate()
+inline void ExecutableToCodeBlockEdge::deactivate()
{
- m_isActive = false;
+ setPerCellBit(false);
}
+inline bool ExecutableToCodeBlockEdge::isActive() const
+{
+ return perCellBit();
+}
+
CodeBlock* ExecutableToCodeBlockEdge::deactivateAndUnwrap(ExecutableToCodeBlockEdge* edge)
{
if (!edge)
Modified: trunk/Source/_javascript_Core/bytecode/ExecutableToCodeBlockEdge.h (240950 => 240951)
--- trunk/Source/_javascript_Core/bytecode/ExecutableToCodeBlockEdge.h 2019-02-05 01:08:40 UTC (rev 240950)
+++ trunk/Source/_javascript_Core/bytecode/ExecutableToCodeBlockEdge.h 2019-02-05 01:09:57 UTC (rev 240951)
@@ -58,9 +58,6 @@
static void visitOutputConstraints(JSCell*, SlotVisitor&);
void finalizeUnconditionally(VM&);
- void activate();
- void deactivate();
-
static CodeBlock* unwrap(ExecutableToCodeBlockEdge* edge)
{
if (!edge)
@@ -78,11 +75,16 @@
friend class LLIntOffsetsExtractor;
ExecutableToCodeBlockEdge(VM&, CodeBlock*);
+
+ void finishCreation(VM&);
+
+ void activate();
+ void deactivate();
+ bool isActive() const;
void runConstraint(const ConcurrentJSLocker&, VM&, SlotVisitor&);
WriteBarrier<CodeBlock> m_codeBlock;
- bool m_isActive { false };
};
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/JSCell.h (240950 => 240951)
--- trunk/Source/_javascript_Core/runtime/JSCell.h 2019-02-05 01:08:40 UTC (rev 240950)
+++ trunk/Source/_javascript_Core/runtime/JSCell.h 2019-02-05 01:09:57 UTC (rev 240951)
@@ -139,9 +139,6 @@
TypeInfo::InlineTypeFlags inlineTypeFlags() const { return m_flags; }
- bool mayBePrototype() const;
- void didBecomePrototype();
-
const char* className(VM&) const;
// Extracting the value.
@@ -239,6 +236,9 @@
}
static const TypedArrayType TypedArrayStorageType = NotTypedArray;
+
+ void setPerCellBit(bool);
+ bool perCellBit() const;
protected:
void finishCreation(VM&);
Modified: trunk/Source/_javascript_Core/runtime/JSCellInlines.h (240950 => 240951)
--- trunk/Source/_javascript_Core/runtime/JSCellInlines.h 2019-02-05 01:08:40 UTC (rev 240950)
+++ trunk/Source/_javascript_Core/runtime/JSCellInlines.h 2019-02-05 01:09:57 UTC (rev 240951)
@@ -382,16 +382,20 @@
return IndexingTypeLockAlgorithm::isLocked(*lock);
}
-inline bool JSCell::mayBePrototype() const
+inline bool JSCell::perCellBit() const
{
- return TypeInfo::mayBePrototype(inlineTypeFlags());
+ return TypeInfo::perCellBit(inlineTypeFlags());
}
-inline void JSCell::didBecomePrototype()
+inline void JSCell::setPerCellBit(bool value)
{
- if (mayBePrototype())
+ if (value == perCellBit())
return;
- m_flags |= static_cast<TypeInfo::InlineTypeFlags>(TypeInfoMayBePrototype);
+
+ if (value)
+ m_flags |= static_cast<TypeInfo::InlineTypeFlags>(TypeInfoPerCellBit);
+ else
+ m_flags &= ~static_cast<TypeInfo::InlineTypeFlags>(TypeInfoPerCellBit);
}
inline JSObject* JSCell::toObject(ExecState* exec, JSGlobalObject* globalObject) const
Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (240950 => 240951)
--- trunk/Source/_javascript_Core/runtime/JSObject.cpp 2019-02-05 01:08:40 UTC (rev 240950)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp 2019-02-05 01:09:57 UTC (rev 240951)
@@ -1742,7 +1742,7 @@
{
ASSERT(prototype);
if (prototype.isObject())
- prototype.asCell()->didBecomePrototype();
+ asObject(prototype)->didBecomePrototype();
if (structure(vm)->hasMonoProto()) {
DeferredStructureTransitionWatchpointFire deferred(vm, structure(vm));
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (240950 => 240951)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2019-02-05 01:08:40 UTC (rev 240950)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2019-02-05 01:09:57 UTC (rev 240951)
@@ -879,6 +879,9 @@
bool canPerformFastPutInline(VM&, PropertyName);
bool canPerformFastPutInlineExcludingProto(VM&);
+ bool mayBePrototype() const;
+ void didBecomePrototype();
+
DECLARE_EXPORT_INFO;
protected:
Modified: trunk/Source/_javascript_Core/runtime/JSObjectInlines.h (240950 => 240951)
--- trunk/Source/_javascript_Core/runtime/JSObjectInlines.h 2019-02-05 01:08:40 UTC (rev 240950)
+++ trunk/Source/_javascript_Core/runtime/JSObjectInlines.h 2019-02-05 01:09:57 UTC (rev 240951)
@@ -384,4 +384,14 @@
return true;
}
+inline bool JSObject::mayBePrototype() const
+{
+ return perCellBit();
+}
+
+inline void JSObject::didBecomePrototype()
+{
+ setPerCellBit(true);
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/JSTypeInfo.h (240950 => 240951)
--- trunk/Source/_javascript_Core/runtime/JSTypeInfo.h 2019-02-05 01:08:40 UTC (rev 240950)
+++ trunk/Source/_javascript_Core/runtime/JSTypeInfo.h 2019-02-05 01:09:57 UTC (rev 240951)
@@ -43,7 +43,7 @@
static const unsigned OverridesGetOwnPropertySlot = 1 << 3;
static const unsigned OverridesToThis = 1 << 4; // If this is false then this returns something other than 'this'. Non-object cells that are visible to JS have this set as do some exotic objects.
static const unsigned HasStaticPropertyTable = 1 << 5;
-static const unsigned TypeInfoMayBePrototype = 1 << 7; // Unlike other inline flags, this will only be set on the cell itself and will not be set on the Structure.
+static const unsigned TypeInfoPerCellBit = 1 << 7; // Unlike other inline flags, this will only be set on the cell itself and will not be set on the Structure.
// Out of line flags.
@@ -89,7 +89,7 @@
bool overridesGetOwnPropertySlot() const { return overridesGetOwnPropertySlot(inlineTypeFlags()); }
static bool overridesGetOwnPropertySlot(InlineTypeFlags flags) { return flags & OverridesGetOwnPropertySlot; }
static bool hasStaticPropertyTable(InlineTypeFlags flags) { return flags & HasStaticPropertyTable; }
- static bool mayBePrototype(InlineTypeFlags flags) { return flags & TypeInfoMayBePrototype; }
+ static bool perCellBit(InlineTypeFlags flags) { return flags & TypeInfoPerCellBit; }
bool overridesToThis() const { return isSetOnFlags1(OverridesToThis); }
bool structureIsImmortal() const { return isSetOnFlags2(StructureIsImmortal); }
bool overridesGetPropertyNames() const { return isSetOnFlags2(OverridesGetPropertyNames); }
@@ -117,10 +117,10 @@
return OBJECT_OFFSETOF(TypeInfo, m_type);
}
- // Since the Structure doesn't track TypeInfoMayBePrototype, we need to make sure we copy it.
+ // Since the Structure doesn't track TypeInfoPerCellBit, we need to make sure we copy it.
static InlineTypeFlags mergeInlineTypeFlags(InlineTypeFlags structureFlags, InlineTypeFlags oldCellFlags)
{
- return structureFlags | (oldCellFlags & static_cast<InlineTypeFlags>(TypeInfoMayBePrototype));
+ return structureFlags | (oldCellFlags & static_cast<InlineTypeFlags>(TypeInfoPerCellBit));
}
InlineTypeFlags inlineTypeFlags() const { return m_flags; }