Commit e6f65401 authored by Victor Gomes's avatar Victor Gomes Committed by Commit Bot

[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: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69851}
parent b4ecc0e2
......@@ -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, &regular_invoke, Label::kNear);
// Skip if overapplication or if expected number of arguments.
subq(expected_parameter_count, actual_parameter_count);
j(less_equal, &regular_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(&copy);
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, &copy);
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(&regular_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(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment