[builtins] Separate Array.prototype.* CSA builtins into two parts

Previous to this CL, CSA-optimized Array builtins--like forEach, some, and
every--were written in a single, monolithic block of CSA code.

This CL teases the code for each of these builtins apart into two chunks, a main
body with optimizations for fast cases, and a "continuation" builtin that
performs a spec-compliant, but slower version of the main loop of the
builtin. The general idea is that when the "fast" main body builtin encounters
an unexpected condition that invalidates assumptions allowing fast-case code, it
tail calls to the slow, correct version of the loop that finishes the builtin
execution.

This separation currently doens't really provide any specific advantage over the
combined version. However, it paves the way to TF-optimized inlined Array
builtins. Inlined Array builtins may trigger deopts during the execution of the
builtin's loop, and those deopt must continue execution from the point at which
they failed. With some massaging of the deoptimizer, it will be possible to make
those deopt points create an extra frame on the top of the stack which resumes
execution in the slow-loop builtin created in this CL.

BUG=v8:1956
LOG=N

Review-Url: https://codereview.chromium.org/2753793002
Cr-Commit-Position: refs/heads/master@{#43867}
This commit is contained in:
danno 2017-03-16 08:34:01 -07:00 committed by Commit bot
parent 947a043766
commit 7de21c4d3b
6 changed files with 283 additions and 199 deletions

View File

@ -18,10 +18,16 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
typedef std::function<void(Node* a, Node* pK, Node* value)>
CallResultProcessor;
void GenerateArrayIteratingBuiltinBody(
const char* name, Node* receiver, Node* callbackfn, Node* this_arg,
Node* context, const BuiltinResultGenerator& generator,
const CallResultProcessor& processor) {
void GenerateIteratingArrayBuiltinBody(
const char* name, const BuiltinResultGenerator& generator,
const CallResultProcessor& processor,
const Callable& slow_case_continuation) {
Node* receiver = Parameter(IteratingArrayBuiltinDescriptor::kReceiver);
Node* callbackfn = Parameter(IteratingArrayBuiltinDescriptor::kCallback);
Node* this_arg = Parameter(IteratingArrayBuiltinDescriptor::kThisArg);
Node* context = Parameter(IteratingArrayBuiltinDescriptor::kContext);
Node* new_target = Parameter(IteratingArrayBuiltinDescriptor::kNewTarget);
Variable k(this, MachineRepresentation::kTagged, SmiConstant(0));
Label non_array(this), slow(this, &k), array_changes(this, &k);
@ -91,47 +97,89 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
// Already done above in initialization of the Variable k
Bind(&slow);
Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
MachineType::TaggedPointer());
TailCallStub(
slow_case_continuation, context, target, new_target,
Int32Constant(IteratingArrayBuiltinLoopContinuationDescriptor::kArity),
receiver, callbackfn, this_arg, a, o, k.value(), len);
}
void GenerateIteratingArrayBuiltinLoopContinuation(
const CallResultProcessor& processor) {
Node* callbackfn =
Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kCallback);
Node* this_arg =
Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kThisArg);
Node* a =
Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kArray);
Node* o =
Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kObject);
Node* initial_k =
Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kInitialK);
Node* len =
Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kLength);
Node* context =
Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kContext);
// 8. Repeat, while k < len
Variable k(this, MachineRepresentation::kTagged, initial_k);
Label loop(this, &k);
Label after_loop(this);
Goto(&loop);
Bind(&loop);
{
// 8. Repeat, while k < len
Label loop(this, &k);
Label after_loop(this);
GotoUnlessNumberLessThan(k.value(), len, &after_loop);
Label done_element(this);
// a. Let Pk be ToString(k).
Node* p_k = ToString(context, k.value());
// b. Let kPresent be HasProperty(O, Pk).
// c. ReturnIfAbrupt(kPresent).
Node* k_present = HasProperty(o, p_k, context);
// d. If kPresent is true, then
GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element);
// i. Let kValue be Get(O, Pk).
// ii. ReturnIfAbrupt(kValue).
Node* k_value = GetProperty(context, o, k.value());
// iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»).
// iv. ReturnIfAbrupt(funcResult).
Node* result = CallJS(CodeFactory::Call(isolate()), context, callbackfn,
this_arg, k_value, k.value(), o);
processor(a, p_k, result);
Goto(&done_element);
Bind(&done_element);
// e. Increase k by 1.
k.Bind(NumberInc(k.value()));
Goto(&loop);
Bind(&loop);
{
GotoUnlessNumberLessThan(k.value(), len, &after_loop);
Label done_element(this);
// a. Let Pk be ToString(k).
Node* p_k = ToString(context, k.value());
// b. Let kPresent be HasProperty(O, Pk).
// c. ReturnIfAbrupt(kPresent).
Node* k_present =
CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o);
// d. If kPresent is true, then
GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element);
// i. Let kValue be Get(O, Pk).
// ii. ReturnIfAbrupt(kValue).
Node* k_value = GetProperty(context, o, k.value());
// iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»).
// iv. ReturnIfAbrupt(funcResult).
Node* result = CallJS(CodeFactory::Call(isolate()), context, callbackfn,
this_arg, k_value, k.value(), o);
processor(a, p_k, result);
Goto(&done_element);
Bind(&done_element);
// e. Increase k by 1.
k.Bind(NumberInc(k.value()));
Goto(&loop);
}
Bind(&after_loop);
Return(a);
}
Bind(&after_loop);
Return(a);
}
void ForEachProcessor(Node* a, Node* p_k, Node* value) {}
void SomeProcessor(Node* a, Node* p_k, Node* value) {
Label false_continue(this), return_true(this);
BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
Bind(&return_true);
Return(TrueConstant());
Bind(&false_continue);
}
void EveryProcessor(Node* a, Node* p_k, Node* value) {
Label true_continue(this), return_false(this);
BranchIfToBooleanIsTrue(value, &true_continue, &return_false);
Bind(&return_false);
Return(FalseConstant());
Bind(&true_continue);
}
private:
@ -414,54 +462,53 @@ TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
}
}
TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) {
Node* receiver = Parameter(ForEachDescriptor::kReceiver);
Node* callbackfn = Parameter(ForEachDescriptor::kCallback);
Node* this_arg = Parameter(ForEachDescriptor::kThisArg);
Node* context = Parameter(ForEachDescriptor::kContext);
GenerateArrayIteratingBuiltinBody(
"Array.prototype.forEach", receiver, callbackfn, this_arg, context,
[=](Node*, Node*) { return UndefinedConstant(); },
[](Node* a, Node* p_k, Node* value) {});
TF_BUILTIN(ArrayForEachLoopContinuation, ArrayBuiltinCodeStubAssembler) {
GenerateIteratingArrayBuiltinLoopContinuation(
[this](Node* a, Node* p_k, Node* value) {
ForEachProcessor(a, p_k, value);
});
}
TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) {
Node* receiver = Parameter(ForEachDescriptor::kReceiver);
Node* callbackfn = Parameter(ForEachDescriptor::kCallback);
Node* this_arg = Parameter(ForEachDescriptor::kThisArg);
Node* context = Parameter(ForEachDescriptor::kContext);
TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) {
GenerateIteratingArrayBuiltinBody(
"Array.prototype.forEach",
[=](Node*, Node*) { return UndefinedConstant(); },
[this](Node* a, Node* p_k, Node* value) {
ForEachProcessor(a, p_k, value);
},
CodeFactory::ArrayForEachLoopContinuation(isolate()));
}
GenerateArrayIteratingBuiltinBody(
"Array.prototype.every", receiver, callbackfn, this_arg, context,
[=](Node*, Node*) { return TrueConstant(); },
[=](Node* a, Node* p_k, Node* value) {
Label true_continue(this), return_false(this);
BranchIfToBooleanIsTrue(value, &true_continue, &return_false);
Bind(&return_false);
Return(FalseConstant());
Bind(&true_continue);
TF_BUILTIN(ArraySomeLoopContinuation, ArrayBuiltinCodeStubAssembler) {
GenerateIteratingArrayBuiltinLoopContinuation(
[this](Node* a, Node* p_k, Node* value) {
SomeProcessor(a, p_k, value);
});
}
TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) {
Node* receiver = Parameter(ForEachDescriptor::kReceiver);
Node* callbackfn = Parameter(ForEachDescriptor::kCallback);
Node* this_arg = Parameter(ForEachDescriptor::kThisArg);
Node* context = Parameter(ForEachDescriptor::kContext);
GenerateIteratingArrayBuiltinBody(
"Array.prototype.some", [=](Node*, Node*) { return FalseConstant(); },
[this](Node* a, Node* p_k, Node* value) { SomeProcessor(a, p_k, value); },
CodeFactory::ArraySomeLoopContinuation(isolate()));
}
GenerateArrayIteratingBuiltinBody(
"Array.prototype.some", receiver, callbackfn, this_arg, context,
[=](Node*, Node*) { return FalseConstant(); },
[=](Node* a, Node* p_k, Node* value) {
Label false_continue(this), return_true(this);
BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
Bind(&return_true);
Return(TrueConstant());
Bind(&false_continue);
TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinCodeStubAssembler) {
GenerateIteratingArrayBuiltinLoopContinuation(
[this](Node* a, Node* p_k, Node* value) {
EveryProcessor(a, p_k, value);
});
}
TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) {
GenerateIteratingArrayBuiltinBody(
"Array.prototype.every", [=](Node*, Node*) { return TrueConstant(); },
[this](Node* a, Node* p_k, Node* value) {
EveryProcessor(a, p_k, value);
},
CodeFactory::ArrayEveryLoopContinuation(isolate()));
}
TF_BUILTIN(ArrayIsArray, CodeStubAssembler) {
Node* object = Parameter(1);
Node* context = Parameter(4);

View File

@ -277,6 +277,9 @@ class Isolate;
CPP(ArraySlice) \
CPP(ArraySplice) \
CPP(ArrayUnshift) \
TFJ(ArrayForEachLoopContinuation, 6) \
TFJ(ArrayEveryLoopContinuation, 6) \
TFJ(ArraySomeLoopContinuation, 6) \
TFJ(ArrayForEach, 2) \
TFJ(ArrayEvery, 2) \
TFJ(ArraySome, 2) \

View File

@ -508,6 +508,24 @@ Callable CodeFactory::ArrayPush(Isolate* isolate) {
return Callable(isolate->builtins()->ArrayPush(), BuiltinDescriptor(isolate));
}
// static
Callable CodeFactory::ArrayForEachLoopContinuation(Isolate* isolate) {
return Callable(isolate->builtins()->ArrayForEachLoopContinuation(),
IteratingArrayBuiltinLoopContinuationDescriptor(isolate));
}
// static
Callable CodeFactory::ArraySomeLoopContinuation(Isolate* isolate) {
return Callable(isolate->builtins()->ArraySomeLoopContinuation(),
IteratingArrayBuiltinLoopContinuationDescriptor(isolate));
}
// static
Callable CodeFactory::ArrayEveryLoopContinuation(Isolate* isolate) {
return Callable(isolate->builtins()->ArrayEveryLoopContinuation(),
IteratingArrayBuiltinLoopContinuationDescriptor(isolate));
}
// static
Callable CodeFactory::FunctionPrototypeBind(Isolate* isolate) {
return Callable(isolate->builtins()->FunctionPrototypeBind(),

View File

@ -180,6 +180,9 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable ArrayConstructor(Isolate* isolate);
static Callable ArrayPush(Isolate* isolate);
static Callable ArrayForEachLoopContinuation(Isolate* isolate);
static Callable ArraySomeLoopContinuation(Isolate* isolate);
static Callable ArrayEveryLoopContinuation(Isolate* isolate);
static Callable FunctionPrototypeBind(Isolate* isolate);
static Callable PromiseHandleReject(Isolate* isolate);
};

View File

@ -31,6 +31,9 @@
#define REPEAT_1_TO_7(V, T) REPEAT_1_TO_6(V, T) V(T, T, T, T, T, T, T)
#define REPEAT_1_TO_8(V, T) REPEAT_1_TO_7(V, T) V(T, T, T, T, T, T, T, T)
#define REPEAT_1_TO_9(V, T) REPEAT_1_TO_8(V, T) V(T, T, T, T, T, T, T, T, T)
#define REPEAT_1_TO_10(V, T) REPEAT_1_TO_9(V, T) V(T, T, T, T, T, T, T, T, T, T)
#define REPEAT_1_TO_11(V, T) \
REPEAT_1_TO_10(V, T) V(T, T, T, T, T, T, T, T, T, T, T)
namespace v8 {
namespace internal {
@ -532,7 +535,7 @@ Node* CodeAssembler::CallRuntime(Runtime::FunctionId function, Node* context,
return return_value;
}
// Instantiate CallRuntime() with up to 6 arguments.
// Instantiate CallRuntime() for argument counts used by CSA-generated code
#define INSTANTIATE(...) \
template V8_EXPORT_PRIVATE Node* CodeAssembler::CallRuntime( \
Runtime::FunctionId, __VA_ARGS__);
@ -558,7 +561,7 @@ Node* CodeAssembler::TailCallRuntime(Runtime::FunctionId function,
return raw_assembler()->TailCallN(desc, arraysize(nodes), nodes);
}
// Instantiate TailCallRuntime() with up to 6 arguments.
// Instantiate TailCallRuntime() for argument counts used by CSA-generated code
#define INSTANTIATE(...) \
template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallRuntime( \
Runtime::FunctionId, __VA_ARGS__);
@ -573,7 +576,7 @@ Node* CodeAssembler::CallStubR(const CallInterfaceDescriptor& descriptor,
return CallStubN(descriptor, result_size, arraysize(nodes), nodes);
}
// Instantiate CallStubR() with up to 6 arguments.
// Instantiate CallStubR() for argument counts used by CSA-generated code.
#define INSTANTIATE(...) \
template V8_EXPORT_PRIVATE Node* CodeAssembler::CallStubR( \
const CallInterfaceDescriptor& descriptor, size_t, Node*, __VA_ARGS__);
@ -612,15 +615,15 @@ Node* CodeAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor,
MachineType::AnyTagged(), result_size);
Node* nodes[] = {target, args..., context};
CHECK_EQ(descriptor.GetParameterCount() + 2, arraysize(nodes));
return raw_assembler()->TailCallN(desc, arraysize(nodes), nodes);
}
// Instantiate TailCallStub() with up to 6 arguments.
// Instantiate TailCallStub() for argument counts used by CSA-generated code
#define INSTANTIATE(...) \
template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallStub( \
const CallInterfaceDescriptor& descriptor, Node*, __VA_ARGS__);
REPEAT_1_TO_7(INSTANTIATE, Node*)
REPEAT_1_TO_11(INSTANTIATE, Node*)
#undef INSTANTIATE
template <class... TArgs>
@ -631,10 +634,12 @@ Node* CodeAssembler::TailCallBytecodeDispatch(
isolate(), zone(), descriptor, descriptor.GetStackParameterCount());
Node* nodes[] = {target, args...};
CHECK_EQ(descriptor.GetParameterCount() + 1, arraysize(nodes));
return raw_assembler()->TailCallN(desc, arraysize(nodes), nodes);
}
// Instantiate TailCallBytecodeDispatch() with 4 arguments.
// Instantiate TailCallBytecodeDispatch() for argument counts used by
// CSA-generated code
template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallBytecodeDispatch(
const CallInterfaceDescriptor& descriptor, Node* target, Node*, Node*,
Node*, Node*);

View File

@ -16,86 +16,87 @@ namespace internal {
class PlatformInterfaceDescriptor;
#define INTERFACE_DESCRIPTOR_LIST(V) \
V(Void) \
V(ContextOnly) \
V(Load) \
V(LoadWithVector) \
V(LoadField) \
V(LoadICProtoArray) \
V(LoadGlobal) \
V(LoadGlobalWithVector) \
V(Store) \
V(StoreWithVector) \
V(StoreNamedTransition) \
V(StoreTransition) \
V(VarArgFunction) \
V(FastNewClosure) \
V(FastNewFunctionContext) \
V(FastNewObject) \
V(FastNewArguments) \
V(TypeConversion) \
V(Typeof) \
V(FastCloneRegExp) \
V(FastCloneShallowArray) \
V(FastCloneShallowObject) \
V(CreateAllocationSite) \
V(CreateWeakCell) \
V(CallFunction) \
V(CallIC) \
V(CallICTrampoline) \
V(CallForwardVarargs) \
V(CallConstruct) \
V(CallTrampoline) \
V(ConstructStub) \
V(ConstructTrampoline) \
V(RegExpExec) \
V(RegExpReplace) \
V(RegExpSplit) \
V(CopyFastSmiOrObjectElements) \
V(TransitionElementsKind) \
V(AllocateHeapNumber) \
V(Builtin) \
V(ArrayConstructor) \
V(ForEach) \
V(ArrayNoArgumentConstructor) \
V(ArraySingleArgumentConstructor) \
V(ArrayNArgumentsConstructor) \
V(Compare) \
V(BinaryOp) \
V(BinaryOpWithAllocationSite) \
V(BinaryOpWithVector) \
V(CountOp) \
V(StringAdd) \
V(StringCharAt) \
V(StringCharCodeAt) \
V(StringCompare) \
V(StringIndexOf) \
V(SubString) \
V(Keyed) \
V(Named) \
V(CreateIterResultObject) \
V(HasProperty) \
V(ForInFilter) \
V(ForInNext) \
V(ForInPrepare) \
V(GetProperty) \
V(CallHandler) \
V(ArgumentAdaptor) \
V(ApiCallback) \
V(ApiGetter) \
V(MathPowTagged) \
V(MathPowInteger) \
V(GrowArrayElements) \
V(NewArgumentsElements) \
V(InterpreterDispatch) \
V(InterpreterPushArgsAndCall) \
V(InterpreterPushArgsAndConstruct) \
V(InterpreterPushArgsAndConstructArray) \
V(InterpreterCEntry) \
V(ResumeGenerator) \
V(FrameDropperTrampoline) \
V(PromiseHandleReject) \
#define INTERFACE_DESCRIPTOR_LIST(V) \
V(Void) \
V(ContextOnly) \
V(Load) \
V(LoadWithVector) \
V(LoadField) \
V(LoadICProtoArray) \
V(LoadGlobal) \
V(LoadGlobalWithVector) \
V(Store) \
V(StoreWithVector) \
V(StoreNamedTransition) \
V(StoreTransition) \
V(VarArgFunction) \
V(FastNewClosure) \
V(FastNewFunctionContext) \
V(FastNewObject) \
V(FastNewArguments) \
V(TypeConversion) \
V(Typeof) \
V(FastCloneRegExp) \
V(FastCloneShallowArray) \
V(FastCloneShallowObject) \
V(CreateAllocationSite) \
V(CreateWeakCell) \
V(CallFunction) \
V(CallIC) \
V(CallICTrampoline) \
V(CallForwardVarargs) \
V(CallConstruct) \
V(CallTrampoline) \
V(ConstructStub) \
V(ConstructTrampoline) \
V(RegExpExec) \
V(RegExpReplace) \
V(RegExpSplit) \
V(CopyFastSmiOrObjectElements) \
V(TransitionElementsKind) \
V(AllocateHeapNumber) \
V(Builtin) \
V(ArrayConstructor) \
V(IteratingArrayBuiltin) \
V(IteratingArrayBuiltinLoopContinuation) \
V(ArrayNoArgumentConstructor) \
V(ArraySingleArgumentConstructor) \
V(ArrayNArgumentsConstructor) \
V(Compare) \
V(BinaryOp) \
V(BinaryOpWithAllocationSite) \
V(BinaryOpWithVector) \
V(CountOp) \
V(StringAdd) \
V(StringCharAt) \
V(StringCharCodeAt) \
V(StringCompare) \
V(StringIndexOf) \
V(SubString) \
V(Keyed) \
V(Named) \
V(CreateIterResultObject) \
V(HasProperty) \
V(ForInFilter) \
V(ForInNext) \
V(ForInPrepare) \
V(GetProperty) \
V(CallHandler) \
V(ArgumentAdaptor) \
V(ApiCallback) \
V(ApiGetter) \
V(MathPowTagged) \
V(MathPowInteger) \
V(GrowArrayElements) \
V(NewArgumentsElements) \
V(InterpreterDispatch) \
V(InterpreterPushArgsAndCall) \
V(InterpreterPushArgsAndConstruct) \
V(InterpreterPushArgsAndConstructArray) \
V(InterpreterCEntry) \
V(ResumeGenerator) \
V(FrameDropperTrampoline) \
V(PromiseHandleReject) \
V(WasmRuntimeCall)
class V8_EXPORT_PRIVATE CallInterfaceDescriptorData {
@ -286,39 +287,38 @@ class V8_EXPORT_PRIVATE CallInterfaceDescriptor {
kContext = kParameterCount /* implicit parameter */ \
};
#define DECLARE_BUILTIN_DESCRIPTOR(name) \
DECLARE_DESCRIPTOR_WITH_BASE(name, BuiltinDescriptor) \
protected: \
void InitializePlatformIndependent(CallInterfaceDescriptorData* data) \
override { \
MachineType machine_types[] = {MachineType::AnyTagged(), \
MachineType::AnyTagged(), \
MachineType::Int32()}; \
int argc = kStackParameterCount + 1 - arraysize(machine_types); \
data->InitializePlatformIndependent(arraysize(machine_types), argc, \
machine_types); \
} \
void InitializePlatformSpecific(CallInterfaceDescriptorData* data) \
override { \
Register registers[] = {TargetRegister(), NewTargetRegister(), \
ArgumentsCountRegister()}; \
data->InitializePlatformSpecific(arraysize(registers), registers); \
} \
\
#define DECLARE_BUILTIN_DESCRIPTOR(name) \
DECLARE_DESCRIPTOR_WITH_BASE(name, BuiltinDescriptor) \
protected: \
void InitializePlatformIndependent(CallInterfaceDescriptorData* data) \
override { \
MachineType machine_types[] = {MachineType::AnyTagged(), \
MachineType::AnyTagged(), \
MachineType::Int32()}; \
data->InitializePlatformIndependent(arraysize(machine_types), \
kStackParameterCount, machine_types); \
} \
void InitializePlatformSpecific(CallInterfaceDescriptorData* data) \
override { \
Register registers[] = {TargetRegister(), NewTargetRegister(), \
ArgumentsCountRegister()}; \
data->InitializePlatformSpecific(arraysize(registers), registers); \
} \
\
public:
#define DEFINE_BUILTIN_PARAMETERS(...) \
enum ParameterIndices { \
kReceiver, \
kBeforeFirstStackParameter = kReceiver, \
__VA_ARGS__, \
kAfterLastStackParameter, \
kNewTarget = kAfterLastStackParameter, \
kArgumentsCount, \
kContext, /* implicit parameter */ \
kParameterCount = kContext, \
kStackParameterCount = \
kAfterLastStackParameter - kBeforeFirstStackParameter - 1, \
#define DEFINE_BUILTIN_PARAMETERS(...) \
enum ParameterIndices { \
kReceiver, \
kBeforeFirstStackParameter = kReceiver, \
__VA_ARGS__, \
kAfterLastStackParameter, \
kNewTarget = kAfterLastStackParameter, \
kArgumentsCount, \
kContext, /* implicit parameter */ \
kParameterCount = kContext, \
kArity = kAfterLastStackParameter - kBeforeFirstStackParameter - 1, \
kStackParameterCount = kArity + 1 \
};
class VoidDescriptor : public CallInterfaceDescriptor {
@ -702,10 +702,18 @@ class BuiltinDescriptor : public CallInterfaceDescriptor {
static const Register TargetRegister();
};
class ForEachDescriptor : public BuiltinDescriptor {
class IteratingArrayBuiltinDescriptor : public BuiltinDescriptor {
public:
DEFINE_BUILTIN_PARAMETERS(kCallback, kThisArg)
DECLARE_BUILTIN_DESCRIPTOR(ForEachDescriptor)
DECLARE_BUILTIN_DESCRIPTOR(IteratingArrayBuiltinDescriptor)
};
class IteratingArrayBuiltinLoopContinuationDescriptor
: public BuiltinDescriptor {
public:
DEFINE_BUILTIN_PARAMETERS(kCallback, kThisArg, kArray, kObject, kInitialK,
kLength)
DECLARE_BUILTIN_DESCRIPTOR(IteratingArrayBuiltinLoopContinuationDescriptor)
};
class ArrayConstructorDescriptor : public CallInterfaceDescriptor {