[x64] Remove arguments adaptor frame
Only for the interpreter. Change-Id: I2456a7d6b385b3b8ebcb3ff8782ea5586289bea6 Bug: v8:10201 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2400343 Commit-Queue: Victor Gomes <victorgomes@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Cr-Commit-Position: refs/heads/master@{#69851}
This commit is contained in:
parent
b4ecc0e2d0
commit
e6f654016b
@ -462,16 +462,20 @@ Handle<JSObject> GetFrameArguments(Isolate* isolate,
|
|||||||
return ArgumentsForInlinedFunction(frame, function_index);
|
return ArgumentsForInlinedFunction(frame, function_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||||
|
const int length = frame->GetActualArgumentCount();
|
||||||
|
#else
|
||||||
// Find the frame that holds the actual arguments passed to the function.
|
// Find the frame that holds the actual arguments passed to the function.
|
||||||
if (it->frame()->has_adapted_arguments()) {
|
if (it->frame()->has_adapted_arguments()) {
|
||||||
it->AdvanceOneFrame();
|
it->AdvanceOneFrame();
|
||||||
DCHECK(it->frame()->is_arguments_adaptor());
|
DCHECK(it->frame()->is_arguments_adaptor());
|
||||||
}
|
}
|
||||||
frame = it->frame();
|
frame = it->frame();
|
||||||
|
|
||||||
// Get the number of arguments and construct an arguments object
|
|
||||||
// mirror for the right frame and the underlying function.
|
|
||||||
const int length = frame->ComputeParametersCount();
|
const int length = frame->ComputeParametersCount();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Construct an arguments object mirror for the right frame and the underlying
|
||||||
|
// function.
|
||||||
Handle<JSFunction> function(frame->function(), isolate);
|
Handle<JSFunction> function(frame->function(), isolate);
|
||||||
Handle<JSObject> arguments =
|
Handle<JSObject> arguments =
|
||||||
isolate->factory()->NewArgumentsObject(function, length);
|
isolate->factory()->NewArgumentsObject(function, length);
|
||||||
|
@ -636,6 +636,7 @@ extern transitioning runtime TransitionElementsKindWithKind(
|
|||||||
extern macro LoadBufferObject(RawPtr, constexpr int32): Object;
|
extern macro LoadBufferObject(RawPtr, constexpr int32): Object;
|
||||||
extern macro LoadBufferPointer(RawPtr, constexpr int32): RawPtr;
|
extern macro LoadBufferPointer(RawPtr, constexpr int32): RawPtr;
|
||||||
extern macro LoadBufferSmi(RawPtr, constexpr int32): Smi;
|
extern macro LoadBufferSmi(RawPtr, constexpr int32): Smi;
|
||||||
|
extern macro LoadBufferIntptr(RawPtr, constexpr int32): intptr;
|
||||||
|
|
||||||
extern runtime StringEqual(Context, String, String): Oddball;
|
extern runtime StringEqual(Context, String, String): Oddball;
|
||||||
extern builtin StringLessThan(Context, String, String): Boolean;
|
extern builtin StringLessThan(Context, String, String): Boolean;
|
||||||
|
@ -738,15 +738,39 @@ TF_BUILTIN(AdaptorWithBuiltinExitFrame, CodeStubAssembler) {
|
|||||||
// ConstructStubs implemented in C++ will be run in the context of the caller
|
// ConstructStubs implemented in C++ will be run in the context of the caller
|
||||||
// instead of the callee, due to the way that [[Construct]] is defined for
|
// instead of the callee, due to the way that [[Construct]] is defined for
|
||||||
// ordinary functions).
|
// ordinary functions).
|
||||||
TNode<Context> context =
|
TNode<Context> context = LoadJSFunctionContext(target);
|
||||||
CAST(LoadObjectField(target, JSFunction::kContextOffset));
|
|
||||||
|
TNode<Int32T> actual_argc =
|
||||||
|
UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
|
||||||
|
|
||||||
|
TVARIABLE(Int32T, pushed_argc, actual_argc);
|
||||||
|
|
||||||
|
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||||
|
TNode<SharedFunctionInfo> shared = LoadJSFunctionSharedFunctionInfo(target);
|
||||||
|
|
||||||
|
TNode<Int32T> formal_count =
|
||||||
|
UncheckedCast<Int32T>(LoadSharedFunctionInfoFormalParameterCount(shared));
|
||||||
|
|
||||||
|
// The number of arguments pushed is the maximum of actual arguments count
|
||||||
|
// and formal parameters count. Except when the formal parameters count is
|
||||||
|
// the sentinel.
|
||||||
|
Label check_argc(this), update_argc(this), done_argc(this);
|
||||||
|
|
||||||
|
Branch(Word32Equal(formal_count, Int32Constant(kDontAdaptArgumentsSentinel)),
|
||||||
|
&done_argc, &check_argc);
|
||||||
|
BIND(&check_argc);
|
||||||
|
Branch(Int32GreaterThan(formal_count, pushed_argc.value()), &update_argc,
|
||||||
|
&done_argc);
|
||||||
|
BIND(&update_argc);
|
||||||
|
pushed_argc = formal_count;
|
||||||
|
Goto(&done_argc);
|
||||||
|
BIND(&done_argc);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Update arguments count for CEntry to contain the number of arguments
|
// Update arguments count for CEntry to contain the number of arguments
|
||||||
// including the receiver and the extra arguments.
|
// including the receiver and the extra arguments.
|
||||||
TNode<Int32T> argc =
|
TNode<Int32T> argc = Int32Add(
|
||||||
UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
|
pushed_argc.value(),
|
||||||
argc = Int32Add(
|
|
||||||
argc,
|
|
||||||
Int32Constant(BuiltinExitFrameConstants::kNumExtraArgsWithReceiver));
|
Int32Constant(BuiltinExitFrameConstants::kNumExtraArgsWithReceiver));
|
||||||
|
|
||||||
const bool builtin_exit_frame = true;
|
const bool builtin_exit_frame = true;
|
||||||
|
@ -11,6 +11,8 @@ struct Arguments {
|
|||||||
|
|
||||||
extern operator '[]' macro GetArgumentValue(Arguments, intptr): JSAny;
|
extern operator '[]' macro GetArgumentValue(Arguments, intptr): JSAny;
|
||||||
extern macro GetFrameArguments(FrameWithArguments, intptr): Arguments;
|
extern macro GetFrameArguments(FrameWithArguments, intptr): Arguments;
|
||||||
|
const kNoArgumentsAdaptor:
|
||||||
|
constexpr bool generates 'kNoArgumentsAdaptor';
|
||||||
|
|
||||||
struct ArgumentsIterator {
|
struct ArgumentsIterator {
|
||||||
macro Next(): Object labels NoMore {
|
macro Next(): Object labels NoMore {
|
||||||
@ -47,18 +49,30 @@ macro GetFrameWithArgumentsInfo(implicit context: Context)():
|
|||||||
const shared: SharedFunctionInfo = f.shared_function_info;
|
const shared: SharedFunctionInfo = f.shared_function_info;
|
||||||
const formalParameterCount: bint =
|
const formalParameterCount: bint =
|
||||||
Convert<bint>(Convert<int32>(shared.formal_parameter_count));
|
Convert<bint>(Convert<int32>(shared.formal_parameter_count));
|
||||||
const argumentCount: bint = formalParameterCount;
|
if constexpr (kNoArgumentsAdaptor) {
|
||||||
|
// TODO(victorgomes): When removing the v8_disable_arguments_adaptor flag,
|
||||||
|
// FrameWithArgumentsInfo can be simplified, since the frame field already
|
||||||
|
// contains the argument count.
|
||||||
|
const argumentCount: bint = Convert<bint>(frame.argument_count);
|
||||||
|
return FrameWithArgumentsInfo{
|
||||||
|
frame,
|
||||||
|
argument_count: argumentCount,
|
||||||
|
formal_parameter_count: formalParameterCount
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const argumentCount: bint = formalParameterCount;
|
||||||
|
|
||||||
const adaptor = Cast<ArgumentsAdaptorFrame>(frame.caller)
|
const adaptor = Cast<ArgumentsAdaptorFrame>(frame.caller)
|
||||||
otherwise return FrameWithArgumentsInfo{
|
otherwise return FrameWithArgumentsInfo{
|
||||||
frame,
|
frame,
|
||||||
argument_count: argumentCount,
|
argument_count: argumentCount,
|
||||||
formal_parameter_count: formalParameterCount
|
formal_parameter_count: formalParameterCount
|
||||||
};
|
};
|
||||||
|
|
||||||
return FrameWithArgumentsInfo{
|
return FrameWithArgumentsInfo{
|
||||||
frame: adaptor,
|
frame: adaptor,
|
||||||
argument_count: Convert<bint>(adaptor.length),
|
argument_count: Convert<bint>(adaptor.length),
|
||||||
formal_parameter_count: formalParameterCount
|
formal_parameter_count: formalParameterCount
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,9 @@ macro LoadPointerFromFrame(f: Frame, o: constexpr int32): RawPtr {
|
|||||||
macro LoadSmiFromFrame(f: Frame, o: constexpr int32): Smi {
|
macro LoadSmiFromFrame(f: Frame, o: constexpr int32): Smi {
|
||||||
return LoadBufferSmi(f, o);
|
return LoadBufferSmi(f, o);
|
||||||
}
|
}
|
||||||
|
macro LoadIntptrFromFrame(f: Frame, o: constexpr int32): intptr {
|
||||||
|
return LoadBufferIntptr(f, o);
|
||||||
|
}
|
||||||
|
|
||||||
const kStandardFrameFunctionOffset: constexpr int31
|
const kStandardFrameFunctionOffset: constexpr int31
|
||||||
generates 'StandardFrameConstants::kFunctionOffset';
|
generates 'StandardFrameConstants::kFunctionOffset';
|
||||||
@ -67,6 +70,12 @@ operator '.caller' macro LoadCallerFromFrame(f: Frame): Frame {
|
|||||||
return %RawDownCast<Frame>(result);
|
return %RawDownCast<Frame>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const kStandardFrameArgCOffset: constexpr int31
|
||||||
|
generates 'StandardFrameConstants::kArgCOffset';
|
||||||
|
operator '.argument_count' macro LoadArgCFromFrame(f: Frame): intptr {
|
||||||
|
return LoadIntptrFromFrame(f, kStandardFrameArgCOffset);
|
||||||
|
}
|
||||||
|
|
||||||
type ContextOrFrameType = Context|FrameType;
|
type ContextOrFrameType = Context|FrameType;
|
||||||
Cast<ContextOrFrameType>(implicit context: Context)(o: Object):
|
Cast<ContextOrFrameType>(implicit context: Context)(o: Object):
|
||||||
ContextOrFrameType
|
ContextOrFrameType
|
||||||
|
@ -132,6 +132,11 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
|
|||||||
__ Push(rsi);
|
__ Push(rsi);
|
||||||
__ Push(rcx);
|
__ Push(rcx);
|
||||||
|
|
||||||
|
// TODO(victorgomes): When the arguments adaptor is completely removed, we
|
||||||
|
// should get the formal parameter count and copy the arguments in its
|
||||||
|
// correct position (including any undefined), instead of delaying this to
|
||||||
|
// InvokeFunction.
|
||||||
|
|
||||||
#ifdef V8_REVERSE_JSARGS
|
#ifdef V8_REVERSE_JSARGS
|
||||||
// Set up pointer to first argument (skip receiver).
|
// Set up pointer to first argument (skip receiver).
|
||||||
__ leaq(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
|
__ leaq(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
|
||||||
@ -288,6 +293,11 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
|
|||||||
|
|
||||||
__ bind(&enough_stack_space);
|
__ bind(&enough_stack_space);
|
||||||
|
|
||||||
|
// TODO(victorgomes): When the arguments adaptor is completely removed, we
|
||||||
|
// should get the formal parameter count and copy the arguments in its
|
||||||
|
// correct position (including any undefined), instead of delaying this to
|
||||||
|
// InvokeFunction.
|
||||||
|
|
||||||
// Copy arguments to the expression stack.
|
// Copy arguments to the expression stack.
|
||||||
__ PushArray(rbx, rax, rcx);
|
__ PushArray(rbx, rax, rcx);
|
||||||
|
|
||||||
@ -913,21 +923,38 @@ static void ReplaceClosureCodeWithOptimizedCode(MacroAssembler* masm,
|
|||||||
|
|
||||||
static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch1,
|
static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch1,
|
||||||
Register scratch2) {
|
Register scratch2) {
|
||||||
Register args_count = scratch1;
|
Register params_size = scratch1;
|
||||||
Register return_pc = scratch2;
|
// Get the size of the formal parameters + receiver (in bytes).
|
||||||
|
__ movq(params_size,
|
||||||
// Get the arguments + receiver count.
|
|
||||||
__ movq(args_count,
|
|
||||||
Operand(rbp, InterpreterFrameConstants::kBytecodeArrayFromFp));
|
Operand(rbp, InterpreterFrameConstants::kBytecodeArrayFromFp));
|
||||||
__ movl(args_count,
|
__ movl(params_size,
|
||||||
FieldOperand(args_count, BytecodeArray::kParameterSizeOffset));
|
FieldOperand(params_size, BytecodeArray::kParameterSizeOffset));
|
||||||
|
|
||||||
|
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||||
|
Register actual_params_size = scratch2;
|
||||||
|
// Compute the size of the actual parameters + receiver (in bytes).
|
||||||
|
__ movq(actual_params_size,
|
||||||
|
Operand(rbp, StandardFrameConstants::kArgCOffset));
|
||||||
|
__ leaq(actual_params_size,
|
||||||
|
Operand(actual_params_size, times_system_pointer_size,
|
||||||
|
kSystemPointerSize));
|
||||||
|
|
||||||
|
// If actual is bigger than formal, then we should use it to free up the stack
|
||||||
|
// arguments.
|
||||||
|
Label corrected_args_count;
|
||||||
|
__ cmpq(params_size, actual_params_size);
|
||||||
|
__ j(greater_equal, &corrected_args_count, Label::kNear);
|
||||||
|
__ movq(params_size, actual_params_size);
|
||||||
|
__ bind(&corrected_args_count);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Leave the frame (also dropping the register file).
|
// Leave the frame (also dropping the register file).
|
||||||
__ leave();
|
__ leave();
|
||||||
|
|
||||||
// Drop receiver + arguments.
|
// Drop receiver + arguments.
|
||||||
|
Register return_pc = scratch2;
|
||||||
__ PopReturnAddressTo(return_pc);
|
__ PopReturnAddressTo(return_pc);
|
||||||
__ addq(rsp, args_count);
|
__ addq(rsp, params_size);
|
||||||
__ PushReturnAddressFrom(return_pc);
|
__ PushReturnAddressFrom(return_pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,6 +290,13 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
|||||||
#define CSA_SLOW_ASSERT(csa, ...) ((void)0)
|
#define CSA_SLOW_ASSERT(csa, ...) ((void)0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Provides a constexpr boolean to be used inside Torque.
|
||||||
|
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||||
|
constexpr bool kNoArgumentsAdaptor = true;
|
||||||
|
#else
|
||||||
|
constexpr bool kNoArgumentsAdaptor = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Provides JavaScript-specific "macro-assembler" functionality on top of the
|
// Provides JavaScript-specific "macro-assembler" functionality on top of the
|
||||||
// CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler,
|
// CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler,
|
||||||
// it's possible to add JavaScript-specific useful CodeAssembler "macros"
|
// it's possible to add JavaScript-specific useful CodeAssembler "macros"
|
||||||
@ -1003,6 +1010,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
|||||||
TNode<Smi> LoadBufferSmi(TNode<RawPtrT> buffer, int offset) {
|
TNode<Smi> LoadBufferSmi(TNode<RawPtrT> buffer, int offset) {
|
||||||
return CAST(LoadBufferObject(buffer, offset));
|
return CAST(LoadBufferObject(buffer, offset));
|
||||||
}
|
}
|
||||||
|
TNode<IntPtrT> LoadBufferIntptr(TNode<RawPtrT> buffer, int offset) {
|
||||||
|
return LoadBufferData<IntPtrT>(buffer, offset);
|
||||||
|
}
|
||||||
// Load a field from an object on the heap.
|
// Load a field from an object on the heap.
|
||||||
template <class T, typename std::enable_if<
|
template <class T, typename std::enable_if<
|
||||||
std::is_convertible<TNode<T>, TNode<Object>>::value,
|
std::is_convertible<TNode<T>, TNode<Object>>::value,
|
||||||
|
@ -2365,6 +2365,51 @@ void MacroAssembler::InvokePrologue(Register expected_parameter_count,
|
|||||||
Label* done, InvokeFlag flag) {
|
Label* done, InvokeFlag flag) {
|
||||||
if (expected_parameter_count != actual_parameter_count) {
|
if (expected_parameter_count != actual_parameter_count) {
|
||||||
Label regular_invoke;
|
Label regular_invoke;
|
||||||
|
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||||
|
// Skip if adaptor sentinel.
|
||||||
|
cmpl(expected_parameter_count, Immediate(kDontAdaptArgumentsSentinel));
|
||||||
|
j(equal, ®ular_invoke, Label::kNear);
|
||||||
|
|
||||||
|
// Skip if overapplication or if expected number of arguments.
|
||||||
|
subq(expected_parameter_count, actual_parameter_count);
|
||||||
|
j(less_equal, ®ular_invoke, Label::kNear);
|
||||||
|
|
||||||
|
// Underapplication. Move the arguments already in the stack, including the
|
||||||
|
// receiver and the return address.
|
||||||
|
{
|
||||||
|
Label copy, check;
|
||||||
|
Register src = r8, dest = rsp, num = r9, current = r11;
|
||||||
|
movq(src, rsp);
|
||||||
|
leaq(kScratchRegister,
|
||||||
|
Operand(expected_parameter_count, times_system_pointer_size, 0));
|
||||||
|
AllocateStackSpace(kScratchRegister);
|
||||||
|
// Extra words are the receiver and the return address (if a jump).
|
||||||
|
int extra_words = flag == CALL_FUNCTION ? 1 : 2;
|
||||||
|
leaq(num, Operand(rax, extra_words)); // Number of words to copy.
|
||||||
|
Set(current, 0);
|
||||||
|
// Fall-through to the loop body because there are non-zero words to copy.
|
||||||
|
bind(©);
|
||||||
|
movq(kScratchRegister,
|
||||||
|
Operand(src, current, times_system_pointer_size, 0));
|
||||||
|
movq(Operand(dest, current, times_system_pointer_size, 0),
|
||||||
|
kScratchRegister);
|
||||||
|
incq(current);
|
||||||
|
bind(&check);
|
||||||
|
cmpq(current, num);
|
||||||
|
j(less, ©);
|
||||||
|
leaq(r8, Operand(rsp, num, times_system_pointer_size, 0));
|
||||||
|
}
|
||||||
|
// Fill remaining expected arguments with undefined values.
|
||||||
|
LoadRoot(kScratchRegister, RootIndex::kUndefinedValue);
|
||||||
|
{
|
||||||
|
Label loop;
|
||||||
|
bind(&loop);
|
||||||
|
decq(expected_parameter_count);
|
||||||
|
movq(Operand(r8, expected_parameter_count, times_system_pointer_size, 0),
|
||||||
|
kScratchRegister);
|
||||||
|
j(greater, &loop, Label::kNear);
|
||||||
|
}
|
||||||
|
#else
|
||||||
// Both expected and actual are in (different) registers. This
|
// Both expected and actual are in (different) registers. This
|
||||||
// is the case when we invoke functions using call and apply.
|
// is the case when we invoke functions using call and apply.
|
||||||
cmpq(expected_parameter_count, actual_parameter_count);
|
cmpq(expected_parameter_count, actual_parameter_count);
|
||||||
@ -2378,6 +2423,8 @@ void MacroAssembler::InvokePrologue(Register expected_parameter_count,
|
|||||||
} else {
|
} else {
|
||||||
Jump(adaptor, RelocInfo::CODE_TARGET);
|
Jump(adaptor, RelocInfo::CODE_TARGET);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bind(®ular_invoke);
|
bind(®ular_invoke);
|
||||||
} else {
|
} else {
|
||||||
Move(rax, actual_parameter_count);
|
Move(rax, actual_parameter_count);
|
||||||
|
@ -1288,6 +1288,13 @@ int JavaScriptFrame::ComputeParametersCount() const {
|
|||||||
return function().shared().internal_formal_parameter_count();
|
return function().shared().internal_formal_parameter_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||||
|
int JavaScriptFrame::GetActualArgumentCount() const {
|
||||||
|
return static_cast<int>(
|
||||||
|
Memory<intptr_t>(fp() + StandardFrameConstants::kArgCOffset));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
Handle<FixedArray> JavaScriptFrame::GetParameters() const {
|
Handle<FixedArray> JavaScriptFrame::GetParameters() const {
|
||||||
if (V8_LIKELY(!FLAG_detailed_error_stack_trace)) {
|
if (V8_LIKELY(!FLAG_detailed_error_stack_trace)) {
|
||||||
return isolate()->factory()->empty_fixed_array();
|
return isolate()->factory()->empty_fixed_array();
|
||||||
|
@ -669,6 +669,9 @@ class JavaScriptFrame : public StandardFrame {
|
|||||||
inline Address GetParameterSlot(int index) const;
|
inline Address GetParameterSlot(int index) const;
|
||||||
Object GetParameter(int index) const override;
|
Object GetParameter(int index) const override;
|
||||||
int ComputeParametersCount() const override;
|
int ComputeParametersCount() const override;
|
||||||
|
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||||
|
int GetActualArgumentCount() const;
|
||||||
|
#endif
|
||||||
Handle<FixedArray> GetParameters() const;
|
Handle<FixedArray> GetParameters() const;
|
||||||
|
|
||||||
// Debugger access.
|
// Debugger access.
|
||||||
|
@ -379,12 +379,16 @@ std::unique_ptr<Handle<Object>[]> GetCallerArguments(Isolate* isolate,
|
|||||||
|
|
||||||
return param_data;
|
return param_data;
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||||
|
int args_count = frame->GetActualArgumentCount();
|
||||||
|
#else
|
||||||
if (it.frame()->has_adapted_arguments()) {
|
if (it.frame()->has_adapted_arguments()) {
|
||||||
it.AdvanceOneFrame();
|
it.AdvanceOneFrame();
|
||||||
DCHECK(it.frame()->is_arguments_adaptor());
|
DCHECK(it.frame()->is_arguments_adaptor());
|
||||||
}
|
}
|
||||||
frame = it.frame();
|
frame = it.frame();
|
||||||
int args_count = frame->ComputeParametersCount();
|
int args_count = frame->ComputeParametersCount();
|
||||||
|
#endif
|
||||||
|
|
||||||
*total_argc = args_count;
|
*total_argc = args_count;
|
||||||
std::unique_ptr<Handle<Object>[]> param_data(
|
std::unique_ptr<Handle<Object>[]> param_data(
|
||||||
|
Loading…
Reference in New Issue
Block a user