Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (201667 => 201668)
--- trunk/Source/_javascript_Core/ChangeLog 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-06-03 23:06:39 UTC (rev 201668)
@@ -1,3 +1,44 @@
+2016-06-03 Keith Miller <[email protected]>
+
+ Add argument_count bytecode for concat
+ https://bugs.webkit.org/show_bug.cgi?id=158358
+
+ Reviewed by Geoffrey Garen.
+
+ This patch adds a new argument count bytecode. Normally, we would
+ just make sure that the argument.length bytecode was fast enough
+ that we shouldn't need such an bytecode. However, for the case of
+ Array.prototype.concat the overhead of the arguments object
+ allocation in the LLInt was too high and caused regressions.
+
+ * bytecode/BytecodeIntrinsicRegistry.h:
+ * bytecode/BytecodeList.json:
+ * bytecode/BytecodeUseDef.h:
+ (JSC::computeUsesForBytecodeOffset):
+ (JSC::computeDefsForBytecodeOffset):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dumpBytecode):
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::BytecodeIntrinsicNode::emit_intrinsic_argumentCount):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::getArgumentCount):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::capabilityLevel):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ * jit/JIT.h:
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_op_argument_count):
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+ * tests/stress/argument-count-bytecode.js: Added.
+ (inlineCount):
+ (inlineCount1):
+ (inlineCount2):
+ (inlineCountVarArgs):
+ (assert):
+
2016-06-03 Geoffrey Garen <[email protected]>
Clients of PolymorphicAccess::addCases shouldn't have to malloc
Modified: trunk/Source/_javascript_Core/bytecode/BytecodeIntrinsicRegistry.h (201667 => 201668)
--- trunk/Source/_javascript_Core/bytecode/BytecodeIntrinsicRegistry.h 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeIntrinsicRegistry.h 2016-06-03 23:06:39 UTC (rev 201668)
@@ -40,6 +40,7 @@
class Identifier;
#define JSC_COMMON_BYTECODE_INTRINSIC_FUNCTIONS_EACH_NAME(macro) \
+ macro(argumentCount) \
macro(assert) \
macro(isObject) \
macro(tryGetById) \
Modified: trunk/Source/_javascript_Core/bytecode/BytecodeList.json (201667 => 201668)
--- trunk/Source/_javascript_Core/bytecode/BytecodeList.json 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeList.json 2016-06-03 23:06:39 UTC (rev 201668)
@@ -9,6 +9,7 @@
{ "name" : "op_create_scoped_arguments", "length" : 3 },
{ "name" : "op_create_cloned_arguments", "length" : 2 },
{ "name" : "op_create_this", "length" : 5 },
+ { "name" : "op_argument_count", "length" : 2 },
{ "name" : "op_to_this", "length" : 4 },
{ "name" : "op_check_tdz", "length" : 2 },
{ "name" : "op_new_object", "length" : 4 },
Modified: trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h (201667 => 201668)
--- trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h 2016-06-03 23:06:39 UTC (rev 201668)
@@ -53,6 +53,7 @@
case op_jmp:
case op_new_object:
case op_enter:
+ case op_argument_count:
case op_catch:
case op_profile_control_flow:
case op_create_direct_arguments:
@@ -362,6 +363,7 @@
#undef LLINT_HELPER_OPCODES
return;
// These all have a single destination for the first argument.
+ case op_argument_count:
case op_to_index_string:
case op_get_enumerable_length:
case op_has_indexed_property:
Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -818,6 +818,11 @@
out.printf("%s", registerName(r0).data());
break;
}
+ case op_argument_count: {
+ int r0 = (++it)->u.operand;
+ printLocationOpAndRegisterOperand(out, exec, location, it, "argument_count", r0);
+ break;
+ }
case op_copy_rest: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -854,6 +854,13 @@
return (this->*m_emitter)(generator, dst);
}
+RegisterID* BytecodeIntrinsicNode::emit_intrinsic_argumentCount(BytecodeGenerator& generator, RegisterID* dst)
+{
+ ASSERT(!m_args->m_listNode);
+
+ return generator.emitUnaryNoDstOp(op_argument_count, generator.finalDestination(dst));
+}
+
RegisterID* BytecodeIntrinsicNode::emit_intrinsic_assert(BytecodeGenerator& generator, RegisterID* dst)
{
#ifndef NDEBUG
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-06-03 23:06:39 UTC (rev 201668)
@@ -1973,7 +1973,7 @@
forNode(node).setType(m_graph, SpecFunction);
break;
- case GetArgumentCount:
+ case GetArgumentCountIncludingThis:
forNode(node).setType(SpecInt32Only);
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGArgumentsUtilities.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGArgumentsUtilities.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGArgumentsUtilities.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -76,7 +76,7 @@
Node* argumentCount;
if (!inlineCallFrame)
- argumentCount = insertionSet.insertNode(nodeIndex, SpecInt32Only, GetArgumentCount, origin);
+ argumentCount = insertionSet.insertNode(nodeIndex, SpecInt32Only, GetArgumentCountIncludingThis, origin);
else {
VirtualRegister argumentCountRegister(inlineCallFrame->stackOffset + JSStack::ArgumentCount);
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -196,6 +196,7 @@
Terminality handleVarargsCall(Instruction* pc, NodeType op, CallMode);
void emitFunctionChecks(CallVariant, Node* callTarget, VirtualRegister thisArgumnt);
void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis);
+ Node* getArgumentCount();
unsigned inliningCost(CallVariant, int argumentCountIncludingThis, CallMode); // Return UINT_MAX if it's not an inlining candidate. By convention, intrinsics have a cost of 1.
// Handle inlining. Return true if it succeeded, false if we need to plant a call.
bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, VirtualRegister thisArgument, VirtualRegister argumentsArgument, unsigned argumentsOffset, int argumentCountIncludingThis, unsigned nextOffset, NodeType callOp, InlineCallFrame::Kind, SpeculatedType prediction);
@@ -1322,6 +1323,19 @@
addToGraph(CheckCell, OpInfo(m_graph.freeze(calleeCell)), callTargetForCheck, thisArgument);
}
+Node* ByteCodeParser::getArgumentCount()
+{
+ Node* argumentCount;
+ if (m_inlineStackTop->m_inlineCallFrame) {
+ if (m_inlineStackTop->m_inlineCallFrame->isVarargs())
+ argumentCount = get(VirtualRegister(JSStack::ArgumentCount));
+ else
+ argumentCount = jsConstant(m_graph.freeze(jsNumber(m_inlineStackTop->m_inlineCallFrame->arguments.size()))->value());
+ } else
+ argumentCount = addToGraph(GetArgumentCountIncludingThis, OpInfo(0), OpInfo(SpecInt32Only));
+ return argumentCount;
+}
+
void ByteCodeParser::emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis)
{
for (int i = 0; i < argumentCountIncludingThis; ++i)
@@ -4886,7 +4900,14 @@
set(VirtualRegister(currentInstruction[1].u.operand), result);
NEXT_OPCODE(op_get_scope);
}
-
+
+ case op_argument_count: {
+ Node* sub = addToGraph(ArithSub, OpInfo(Arith::Unchecked), OpInfo(SpecInt32Only), getArgumentCount(), addToGraph(JSConstant, OpInfo(m_constantOne)));
+
+ set(VirtualRegister(currentInstruction[1].u.operand), sub);
+ NEXT_OPCODE(op_argument_count);
+ }
+
case op_create_direct_arguments: {
noticeArgumentsUse();
Node* createArguments = addToGraph(CreateDirectArguments);
Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -106,6 +106,7 @@
switch (opcodeID) {
case op_enter:
case op_to_this:
+ case op_argument_count:
case op_check_tdz:
case op_create_this:
case op_bitand:
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2016-06-03 23:06:39 UTC (rev 201668)
@@ -502,7 +502,7 @@
def(HeapLocation(StackLoc, AbstractHeap(Stack, JSStack::Callee)), LazyNode(node));
return;
- case GetArgumentCount:
+ case GetArgumentCountIncludingThis:
read(AbstractHeap(Stack, JSStack::ArgumentCount));
def(HeapLocation(StackPayloadLoc, AbstractHeap(Stack, JSStack::ArgumentCount)), LazyNode(node));
return;
Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -50,7 +50,7 @@
case LazyJSConstant:
case Identity:
case GetCallee:
- case GetArgumentCount:
+ case GetArgumentCountIncludingThis:
case GetRestLength:
case GetLocal:
case SetLocal:
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -1508,7 +1508,7 @@
case DoubleConstant:
case GetLocal:
case GetCallee:
- case GetArgumentCount:
+ case GetArgumentCountIncludingThis:
case GetRestLength:
case Flush:
case PhantomLocal:
Modified: trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -71,7 +71,7 @@
case KillStack:
case GetStack:
case GetCallee:
- case GetArgumentCount:
+ case GetArgumentCountIncludingThis:
case GetRestLength:
case GetScope:
case PhantomLocal:
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2016-06-03 23:06:39 UTC (rev 201668)
@@ -53,7 +53,7 @@
macro(ToThis, NodeResultJS) \
macro(CreateThis, NodeResultJS) /* Note this is not MustGenerate since we're returning it anyway. */ \
macro(GetCallee, NodeResultJS) \
- macro(GetArgumentCount, NodeResultInt32) \
+ macro(GetArgumentCountIncludingThis, NodeResultInt32) \
\
/* Nodes for local variable access. These nodes are linked together using Phi nodes. */\
/* Any two nodes that are part of the same Phi graph will share the same */\
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -737,7 +737,7 @@
break;
}
- case GetArgumentCount: {
+ case GetArgumentCountIncludingThis: {
setPrediction(SpecInt32Only);
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2016-06-03 23:06:39 UTC (rev 201668)
@@ -142,7 +142,7 @@
case ToThis:
case CreateThis:
case GetCallee:
- case GetArgumentCount:
+ case GetArgumentCountIncludingThis:
case GetRestLength:
case GetLocal:
case SetLocal:
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -4070,7 +4070,7 @@
break;
}
- case GetArgumentCount: {
+ case GetArgumentCountIncludingThis: {
GPRTemporary result(this);
m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), result.gpr());
int32Result(result.gpr(), node);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -4007,7 +4007,7 @@
break;
}
- case GetArgumentCount: {
+ case GetArgumentCountIncludingThis: {
GPRTemporary result(this);
m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), result.gpr());
int32Result(result.gpr(), node);
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -160,7 +160,7 @@
case GetExecutable:
case GetScope:
case GetCallee:
- case GetArgumentCount:
+ case GetArgumentCountIncludingThis:
case ToString:
case CallStringConstructor:
case MakeRope:
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -776,8 +776,8 @@
case GetCallee:
compileGetCallee();
break;
- case GetArgumentCount:
- compileGetArgumentCount();
+ case GetArgumentCountIncludingThis:
+ compileGetArgumentCountIncludingThis();
break;
case GetScope:
compileGetScope();
@@ -4670,7 +4670,7 @@
setJSValue(m_out.loadPtr(addressFor(JSStack::Callee)));
}
- void compileGetArgumentCount()
+ void compileGetArgumentCountIncludingThis()
{
setInt32(m_out.load32(payloadFor(JSStack::ArgumentCount)));
}
Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/jit/JIT.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -223,6 +223,7 @@
DEFINE_OP(op_create_direct_arguments)
DEFINE_OP(op_create_scoped_arguments)
DEFINE_OP(op_create_cloned_arguments)
+ DEFINE_OP(op_argument_count)
DEFINE_OP(op_copy_rest)
DEFINE_OP(op_get_rest_length)
DEFINE_OP(op_check_tdz)
Modified: trunk/Source/_javascript_Core/jit/JIT.h (201667 => 201668)
--- trunk/Source/_javascript_Core/jit/JIT.h 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/jit/JIT.h 2016-06-03 23:06:39 UTC (rev 201668)
@@ -491,6 +491,7 @@
void emit_op_create_direct_arguments(Instruction*);
void emit_op_create_scoped_arguments(Instruction*);
void emit_op_create_cloned_arguments(Instruction*);
+ void emit_op_argument_count(Instruction*);
void emit_op_copy_rest(Instruction*);
void emit_op_get_rest_length(Instruction*);
void emit_op_check_tdz(Instruction*);
Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (201667 => 201668)
--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp 2016-06-03 23:06:39 UTC (rev 201668)
@@ -1419,6 +1419,16 @@
slowPathCall.call();
}
+void JIT::emit_op_argument_count(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ load32(payloadFor(JSStack::ArgumentCount), regT0);
+ sub32(TrustedImm32(1), regT0);
+ JSValueRegs result = JSValueRegs::withTwoAvailableRegs(regT0, regT1);
+ boxInt32(regT0, result);
+ emitPutVirtualRegister(dst, result);
+}
+
void JIT::emit_op_copy_rest(Instruction* currentInstruction)
{
JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_copy_rest);
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (201667 => 201668)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2016-06-03 23:06:39 UTC (rev 201668)
@@ -677,6 +677,17 @@
dispatch(1)
+_llint_op_argument_count:
+ traceExecution()
+ loadisFromInstruction(1, t2)
+ loadi PayloadOffset + ArgumentCount[cfr], t0
+ subi 1, t0
+ move Int32Tag, t1
+ storei t1, TagOffset[cfr, t2, 8]
+ storei t0, PayloadOffset[cfr, t2, 8]
+ dispatch(2)
+
+
_llint_op_get_scope:
traceExecution()
loadi Callee + PayloadOffset[cfr], t0
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (201667 => 201668)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2016-06-03 23:01:49 UTC (rev 201667)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2016-06-03 23:06:39 UTC (rev 201668)
@@ -584,6 +584,16 @@
dispatch(1)
+_llint_op_argument_count:
+ traceExecution()
+ loadisFromInstruction(1, t1)
+ loadi PayloadOffset + ArgumentCount[cfr], t0
+ subi 1, t0
+ orq TagTypeNumber, t0
+ storeq t0, [cfr, t1, 8]
+ dispatch(2)
+
+
_llint_op_get_scope:
traceExecution()
loadp Callee[cfr], t0
Added: trunk/Source/_javascript_Core/tests/stress/argument-count-bytecode.js (0 => 201668)
--- trunk/Source/_javascript_Core/tests/stress/argument-count-bytecode.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/argument-count-bytecode.js 2016-06-03 23:06:39 UTC (rev 201668)
@@ -0,0 +1,38 @@
+count = createBuiltin("(function () { return @argumentCount(); })");
+countNoInline = createBuiltin("(function () { return @argumentCount(); })");
+noInline(countNoInline);
+
+
+function inlineCount() { return count(); }
+noInline(inlineCount);
+
+function inlineCount1() { return count(1); }
+noInline(inlineCount1);
+
+function inlineCount2() { return count(1,2); }
+noInline(inlineCount2);
+
+function inlineCountVarArgs(list) { return count(...list); }
+noInline(inlineCountVarArgs);
+
+function assert(condition, message) {
+ if (!condition)
+ throw new Error(message);
+}
+
+for (i = 0; i < 1000000; i++) {
+ assert(count(1,1,2) === 3, i);
+ assert(count() === 0, i);
+ assert(count(1) === 1, i);
+ assert(count(...[1,2,3,4,5]) === 5, i);
+ assert(count(...[]) === 0, i);
+ assert(inlineCount() === 0, i);
+ assert(inlineCount1() === 1, i);
+ assert(inlineCount2() === 2, i);
+ assert(inlineCountVarArgs([1,2,3,4]) === 4, i);
+ assert(inlineCountVarArgs([]) === 0, i);
+ // Insert extra junk so that inlineCountVarArgs.arguments.length !== count.arguments.length
+ assert(inlineCountVarArgs([1], 2, 4) === 1, i);
+ assert(countNoInline(4) === 1, i)
+ assert(countNoInline() === 0, i);
+}