Skip to content

Commit ae1e21f

Browse files
committed
[JSC] Make CallArguments tight
https://bugs.webkit.org/show_bug.cgi?id=279207 rdar://135354950 Reviewed by Keith Miller. For large function, CallArguments is super frequently used. This patch makes code super tight for performance. We avoid Vector's movement and use std::span instead for adjustment. * Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h: (JSC::CallArguments::argumentCountIncludingThis): * Source/JavaScriptCore/bytecompiler/BytecodeGeneratorBase.h: * Source/JavaScriptCore/bytecompiler/BytecodeGeneratorBaseInlines.h: (JSC::BytecodeGeneratorBase<Traits>::newTemporaries): * Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp: (JSC::CallArguments::CallArguments): Canonical link: https://commits.webkit.org/283232@main
1 parent 55b569c commit ae1e21f

4 files changed

Lines changed: 37 additions & 19 deletions

File tree

‎Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,13 @@ namespace JSC {
8484
RegisterID* thisRegister() { return m_argv[0].get(); }
8585
RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); }
8686
unsigned stackOffset() { return -m_argv[0]->index() + CallFrame::headerSizeInRegisters; }
87-
unsigned argumentCountIncludingThis() { return m_argv.size() - m_padding; }
87+
unsigned argumentCountIncludingThis() { return m_argv.size(); }
8888
ArgumentsNode* argumentsNode() { return m_argumentsNode; }
8989

9090
private:
9191
ArgumentsNode* m_argumentsNode;
92-
Vector<RefPtr<RegisterID>, 8, UnsafeVectorOverflow> m_argv;
93-
unsigned m_padding;
92+
std::span<RefPtr<RegisterID>> m_argv;
93+
Vector<RefPtr<RegisterID>, 8, UnsafeVectorOverflow> m_allocatedRegisters;
9494
};
9595

9696
class Variable {

‎Source/JavaScriptCore/bytecompiler/BytecodeGeneratorBase.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ class BytecodeGeneratorBase {
6464
// register with a refcount of 0 is considered "available", meaning that
6565
// the next instruction may overwrite it.
6666
RegisterID* newTemporary();
67+
template<typename Functor>
68+
void newTemporaries(size_t count, const Functor&);
6769

6870
void emitLabel(GenericLabel<Traits>&);
6971
void recordOpcode(typename Traits::OpcodeID);

‎Source/JavaScriptCore/bytecompiler/BytecodeGeneratorBaseInlines.h‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,18 @@ RegisterID* BytecodeGeneratorBase<Traits>::newTemporary()
180180
return result;
181181
}
182182

183+
template<typename Traits>
184+
template<typename Functor>
185+
void BytecodeGeneratorBase<Traits>::newTemporaries(size_t count, const Functor& func)
186+
{
187+
reclaimFreeRegisters();
188+
for (size_t index = 0; index < count; ++index) {
189+
RegisterID* result = newRegister();
190+
result->setTemporary();
191+
func(result);
192+
}
193+
}
194+
183195
// Adds an anonymous local var slot. To give this slot a name, add it to symbolTable().
184196
template<typename Traits>
185197
RegisterID* BytecodeGeneratorBase<Traits>::addVar()

‎Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp‎

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,30 +1201,34 @@ RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID*
12011201

12021202
CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode, unsigned additionalArguments)
12031203
: m_argumentsNode(argumentsNode)
1204-
, m_padding(0)
12051204
{
12061205
size_t argumentCountIncludingThis = 1 + additionalArguments; // 'this' register.
12071206
if (argumentsNode) {
12081207
for (ArgumentListNode* node = argumentsNode->m_listNode; node; node = node->m_next)
12091208
++argumentCountIncludingThis;
12101209
}
12111210

1212-
m_argv.grow(argumentCountIncludingThis);
1213-
for (int i = argumentCountIncludingThis - 1; i >= 0; --i) {
1214-
m_argv[i] = generator.newTemporary();
1215-
ASSERT(static_cast<size_t>(i) == m_argv.size() - 1 || m_argv[i]->index() == m_argv[i + 1]->index() - 1);
1216-
}
1211+
static_assert(stackAlignmentRegisters() == 2);
1212+
size_t argvSize = argumentCountIncludingThis;
1213+
ASSERT(argvSize >= 1);
1214+
if ((CallFrame::headerSizeInRegisters + argvSize) % stackAlignmentRegisters())
1215+
++argvSize;
1216+
argvSize += 1; // For stackOffset adjustment case.
1217+
ASSERT(argvSize >= 2);
1218+
m_allocatedRegisters.grow(argvSize);
12171219

1218-
// We need to ensure that the frame size is stack-aligned
1219-
while ((CallFrame::headerSizeInRegisters + m_argv.size()) % stackAlignmentRegisters()) {
1220-
m_argv.insert(0, generator.newTemporary());
1221-
m_padding++;
1222-
}
1223-
1224-
while (stackOffset() % stackAlignmentRegisters()) {
1225-
m_argv.insert(0, generator.newTemporary());
1226-
m_padding++;
1227-
}
1220+
// Do not initialize index 0.
1221+
size_t index = m_allocatedRegisters.size();
1222+
generator.newTemporaries(m_allocatedRegisters.size() - 1, [&](RegisterID* slot) {
1223+
m_allocatedRegisters[--index] = slot;
1224+
});
1225+
1226+
// We initialize 0 based on offset. And adjust m_argv based on that.
1227+
if ((-m_allocatedRegisters[1]->index() + CallFrame::headerSizeInRegisters) % stackAlignmentRegisters()) {
1228+
m_allocatedRegisters[0] = generator.newTemporary();
1229+
m_argv = m_allocatedRegisters.mutableSpan().subspan(0, argumentCountIncludingThis);
1230+
} else
1231+
m_argv = m_allocatedRegisters.mutableSpan().subspan(1, argumentCountIncludingThis);
12281232
}
12291233

12301234
// ------------------------------ EvalFunctionCallNode ----------------------------------

0 commit comments

Comments
 (0)