[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);
|
||||
}
|
||||
|
||||
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||
const int length = frame->GetActualArgumentCount();
|
||||
#else
|
||||
// Find the frame that holds the actual arguments passed to the function.
|
||||
if (it->frame()->has_adapted_arguments()) {
|
||||
it->AdvanceOneFrame();
|
||||
DCHECK(it->frame()->is_arguments_adaptor());
|
||||
}
|
||||
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();
|
||||
#endif
|
||||
|
||||
// Construct an arguments object mirror for the right frame and the underlying
|
||||
// function.
|
||||
Handle<JSFunction> function(frame->function(), isolate);
|
||||
Handle<JSObject> arguments =
|
||||
isolate->factory()->NewArgumentsObject(function, length);
|
||||
|
@ -636,6 +636,7 @@ extern transitioning runtime TransitionElementsKindWithKind(
|
||||
extern macro LoadBufferObject(RawPtr, constexpr int32): Object;
|
||||
extern macro LoadBufferPointer(RawPtr, constexpr int32): RawPtr;
|
||||
extern macro LoadBufferSmi(RawPtr, constexpr int32): Smi;
|
||||
extern macro LoadBufferIntptr(RawPtr, constexpr int32): intptr;
|
||||
|
||||
extern runtime StringEqual(Context, String, String): Oddball;
|
||||
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
|
||||
// instead of the callee, due to the way that [[Construct]] is defined for
|
||||
// ordinary functions).
|
||||
TNode<Context> context =
|
||||
CAST(LoadObjectField(target, JSFunction::kContextOffset));
|
||||
TNode<Context> context = LoadJSFunctionContext(target);
|
||||
|
||||
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
|
||||
// including the receiver and the extra arguments.
|
||||
TNode<Int32T> argc =
|
||||
UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
|
||||
argc = Int32Add(
|
||||
argc,
|
||||
TNode<Int32T> argc = Int32Add(
|
||||
pushed_argc.value(),
|
||||
Int32Constant(BuiltinExitFrameConstants::kNumExtraArgsWithReceiver));
|
||||
|
||||
const bool builtin_exit_frame = true;
|
||||
|
@ -11,6 +11,8 @@ struct Arguments {
|
||||
|
||||
extern operator '[]' macro GetArgumentValue(Arguments, intptr): JSAny;
|
||||
extern macro GetFrameArguments(FrameWithArguments, intptr): Arguments;
|
||||
const kNoArgumentsAdaptor:
|
||||
constexpr bool generates 'kNoArgumentsAdaptor';
|
||||
|
||||
struct ArgumentsIterator {
|
||||
macro Next(): Object labels NoMore {
|
||||
@ -47,18 +49,30 @@ macro GetFrameWithArgumentsInfo(implicit context: Context)():
|
||||
const shared: SharedFunctionInfo = f.shared_function_info;
|
||||
const formalParameterCount: bint =
|
||||
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)
|
||||
otherwise return FrameWithArgumentsInfo{
|
||||
frame,
|
||||
argument_count: argumentCount,
|
||||
formal_parameter_count: formalParameterCount
|
||||
};
|
||||
const adaptor = Cast<ArgumentsAdaptorFrame>(frame.caller)
|
||||
otherwise return FrameWithArgumentsInfo{
|
||||
frame,
|
||||
argument_count: argumentCount,
|
||||
formal_parameter_count: formalParameterCount
|
||||
};
|
||||
|
||||
return FrameWithArgumentsInfo{
|
||||
frame: adaptor,
|
||||
argument_count: Convert<bint>(adaptor.length),
|
||||
formal_parameter_count: formalParameterCount
|
||||
};
|
||||
return FrameWithArgumentsInfo{
|
||||
frame: adaptor,
|
||||
argument_count: Convert<bint>(adaptor.length),
|
||||
formal_parameter_count: formalParameterCount
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,9 @@ macro LoadPointerFromFrame(f: Frame, o: constexpr int32): RawPtr {
|
||||
macro LoadSmiFromFrame(f: Frame, o: constexpr int32): Smi {
|
||||
return LoadBufferSmi(f, o);
|
||||
}
|
||||
macro LoadIntptrFromFrame(f: Frame, o: constexpr int32): intptr {
|
||||
return LoadBufferIntptr(f, o);
|
||||
}
|
||||
|
||||
const kStandardFrameFunctionOffset: constexpr int31
|
||||
generates 'StandardFrameConstants::kFunctionOffset';
|
||||
@ -67,6 +70,12 @@ operator '.caller' macro LoadCallerFromFrame(f: Frame): Frame {
|
||||
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;
|
||||
Cast<ContextOrFrameType>(implicit context: Context)(o: Object):
|
||||
ContextOrFrameType
|
||||
|
@ -132,6 +132,11 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
|
||||
__ Push(rsi);
|
||||
__ 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
|
||||
// Set up pointer to first argument (skip receiver).
|
||||
__ leaq(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
|
||||
@ -288,6 +293,11 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
|
||||
|
||||
__ 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.
|
||||
__ PushArray(rbx, rax, rcx);
|
||||
|
||||
@ -913,21 +923,38 @@ static void ReplaceClosureCodeWithOptimizedCode(MacroAssembler* masm,
|
||||
|
||||
static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch1,
|
||||
Register scratch2) {
|
||||
Register args_count = scratch1;
|
||||
Register return_pc = scratch2;
|
||||
|
||||
// Get the arguments + receiver count.
|
||||
__ movq(args_count,
|
||||
Register params_size = scratch1;
|
||||
// Get the size of the formal parameters + receiver (in bytes).
|
||||
__ movq(params_size,
|
||||
Operand(rbp, InterpreterFrameConstants::kBytecodeArrayFromFp));
|
||||
__ movl(args_count,
|
||||
FieldOperand(args_count, BytecodeArray::kParameterSizeOffset));
|
||||
__ movl(params_size,
|
||||
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();
|
||||
|
||||
// Drop receiver + arguments.
|
||||
Register return_pc = scratch2;
|
||||
__ PopReturnAddressTo(return_pc);
|
||||
__ addq(rsp, args_count);
|
||||
__ addq(rsp, params_size);
|
||||
__ PushReturnAddressFrom(return_pc);
|
||||
}
|
||||
|
||||
|
@ -290,6 +290,13 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
||||
#define CSA_SLOW_ASSERT(csa, ...) ((void)0)
|
||||
#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
|
||||
// CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler,
|
||||
// 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) {
|
||||
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.
|
||||
template <class T, typename std::enable_if<
|
||||
std::is_convertible<TNode<T>, TNode<Object>>::value,
|
||||
|
@ -2365,6 +2365,51 @@ void MacroAssembler::InvokePrologue(Register expected_parameter_count,
|
||||
Label* done, InvokeFlag flag) {
|
||||
if (expected_parameter_count != actual_parameter_count) {
|
||||
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
|
||||
// is the case when we invoke functions using call and apply.
|
||||
cmpq(expected_parameter_count, actual_parameter_count);
|
||||
@ -2378,6 +2423,8 @@ void MacroAssembler::InvokePrologue(Register expected_parameter_count,
|
||||
} else {
|
||||
Jump(adaptor, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
#endif
|
||||
|
||||
bind(®ular_invoke);
|
||||
} else {
|
||||
Move(rax, actual_parameter_count);
|
||||
|
@ -1288,6 +1288,13 @@ int JavaScriptFrame::ComputeParametersCount() const {
|
||||
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 {
|
||||
if (V8_LIKELY(!FLAG_detailed_error_stack_trace)) {
|
||||
return isolate()->factory()->empty_fixed_array();
|
||||
|
@ -669,6 +669,9 @@ class JavaScriptFrame : public StandardFrame {
|
||||
inline Address GetParameterSlot(int index) const;
|
||||
Object GetParameter(int index) const override;
|
||||
int ComputeParametersCount() const override;
|
||||
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||
int GetActualArgumentCount() const;
|
||||
#endif
|
||||
Handle<FixedArray> GetParameters() const;
|
||||
|
||||
// Debugger access.
|
||||
|
@ -379,12 +379,16 @@ std::unique_ptr<Handle<Object>[]> GetCallerArguments(Isolate* isolate,
|
||||
|
||||
return param_data;
|
||||
} else {
|
||||
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||
int args_count = frame->GetActualArgumentCount();
|
||||
#else
|
||||
if (it.frame()->has_adapted_arguments()) {
|
||||
it.AdvanceOneFrame();
|
||||
DCHECK(it.frame()->is_arguments_adaptor());
|
||||
}
|
||||
frame = it.frame();
|
||||
int args_count = frame->ComputeParametersCount();
|
||||
#endif
|
||||
|
||||
*total_argc = args_count;
|
||||
std::unique_ptr<Handle<Object>[]> param_data(
|
||||
|
Loading…
Reference in New Issue
Block a user