[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:
Victor Gomes 2020-09-11 17:47:58 +02:00 committed by Commit Bot
parent b4ecc0e2d0
commit e6f654016b
11 changed files with 179 additions and 29 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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
}; };
}
} }

View File

@ -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

View File

@ -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);
} }

View File

@ -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,

View File

@ -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, &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 // 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(&regular_invoke); bind(&regular_invoke);
} else { } else {
Move(rax, actual_parameter_count); Move(rax, actual_parameter_count);

View File

@ -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();

View File

@ -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.

View File

@ -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(