Reland "[ia32] Remove arguments adaptor frame"
This is a reland of 403390ec60
Original change's description:
> [ia32] Remove arguments adaptor frame
>
> Change-Id: Id66d2c57fc92c00b033bc53231313f477cceca75
> Bug: v8:10201
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2448463
> Reviewed-by: Georg Neis <neis@chromium.org>
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Commit-Queue: Victor Gomes <victorgomes@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#70652}
Bug: v8:10201
Change-Id: I2c50b22fbe565e8ad6a510c02bfbd79c145d284e
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2485225
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70663}
This commit is contained in:
parent
1d83f52ca9
commit
958d8e9f32
3
BUILD.gn
3
BUILD.gn
@ -110,7 +110,8 @@ declare_args() {
|
|||||||
v8_enable_31bit_smis_on_64bit_arch = false
|
v8_enable_31bit_smis_on_64bit_arch = false
|
||||||
|
|
||||||
# Disable arguments adaptor frame (sets -dV8_NO_ARGUMENTS_ADAPTOR).
|
# Disable arguments adaptor frame (sets -dV8_NO_ARGUMENTS_ADAPTOR).
|
||||||
v8_disable_arguments_adaptor = v8_current_cpu == "x64"
|
v8_disable_arguments_adaptor =
|
||||||
|
v8_current_cpu == "x86" || v8_current_cpu == "x64"
|
||||||
|
|
||||||
# Sets -dOBJECT_PRINT.
|
# Sets -dOBJECT_PRINT.
|
||||||
v8_enable_object_print = ""
|
v8_enable_object_print = ""
|
||||||
|
@ -136,6 +136,11 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
|
|||||||
__ push(eax);
|
__ push(eax);
|
||||||
__ SmiUntag(eax);
|
__ SmiUntag(eax);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
// Set up pointer to first argument (skip receiver).
|
// Set up pointer to first argument (skip receiver).
|
||||||
__ lea(esi, Operand(ebp, StandardFrameConstants::kCallerSPOffset +
|
__ lea(esi, Operand(ebp, StandardFrameConstants::kCallerSPOffset +
|
||||||
kSystemPointerSize));
|
kSystemPointerSize));
|
||||||
@ -275,6 +280,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(edi, eax, ecx);
|
__ PushArray(edi, eax, ecx);
|
||||||
|
|
||||||
@ -739,22 +749,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).
|
||||||
|
__ mov(params_size,
|
||||||
// Get the arguments + receiver count.
|
|
||||||
__ mov(args_count,
|
|
||||||
Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp));
|
Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp));
|
||||||
__ mov(args_count,
|
__ mov(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).
|
||||||
|
__ mov(actual_params_size, Operand(ebp, StandardFrameConstants::kArgCOffset));
|
||||||
|
__ lea(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;
|
||||||
|
__ cmp(params_size, actual_params_size);
|
||||||
|
__ j(greater_equal, &corrected_args_count, Label::kNear);
|
||||||
|
__ mov(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.
|
||||||
__ pop(return_pc);
|
Register return_pc = scratch2;
|
||||||
__ add(esp, args_count);
|
__ PopReturnAddressTo(return_pc);
|
||||||
__ push(return_pc);
|
__ add(esp, params_size);
|
||||||
|
__ PushReturnAddressFrom(return_pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tail-call |function_id| if |smi_entry| == |marker|
|
// Tail-call |function_id| if |smi_entry| == |marker|
|
||||||
@ -779,8 +805,8 @@ static void TailCallOptimizedCodeSlot(MacroAssembler* masm,
|
|||||||
DCHECK(!AreAliased(edx, edi, optimized_code_entry));
|
DCHECK(!AreAliased(edx, edi, optimized_code_entry));
|
||||||
|
|
||||||
Register closure = edi;
|
Register closure = edi;
|
||||||
|
__ movd(xmm0, eax);
|
||||||
__ push(edx);
|
__ movd(xmm1, edx);
|
||||||
|
|
||||||
// Check if the optimized code is marked for deopt. If it is, bailout to a
|
// Check if the optimized code is marked for deopt. If it is, bailout to a
|
||||||
// given label.
|
// given label.
|
||||||
@ -797,13 +823,15 @@ static void TailCallOptimizedCodeSlot(MacroAssembler* masm,
|
|||||||
eax);
|
eax);
|
||||||
static_assert(kJavaScriptCallCodeStartRegister == ecx, "ABI mismatch");
|
static_assert(kJavaScriptCallCodeStartRegister == ecx, "ABI mismatch");
|
||||||
__ LoadCodeObjectEntry(ecx, optimized_code_entry);
|
__ LoadCodeObjectEntry(ecx, optimized_code_entry);
|
||||||
__ pop(edx);
|
__ movd(edx, xmm1);
|
||||||
|
__ movd(eax, xmm0);
|
||||||
__ jmp(ecx);
|
__ jmp(ecx);
|
||||||
|
|
||||||
// Optimized code slot contains deoptimized code, evict it and re-enter
|
// Optimized code slot contains deoptimized code, evict it and re-enter
|
||||||
// the closure's code.
|
// the closure's code.
|
||||||
__ bind(&found_deoptimized_code);
|
__ bind(&found_deoptimized_code);
|
||||||
__ pop(edx);
|
__ movd(edx, xmm1);
|
||||||
|
__ movd(eax, xmm0);
|
||||||
GenerateTailCallToReturnedCode(masm, Runtime::kEvictOptimizedCodeSlot);
|
GenerateTailCallToReturnedCode(masm, Runtime::kEvictOptimizedCodeSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2051,6 +2079,12 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
|
|||||||
|
|
||||||
__ movd(xmm1, edx); // Preserve new.target (in case of [[Construct]]).
|
__ movd(xmm1, edx); // Preserve new.target (in case of [[Construct]]).
|
||||||
|
|
||||||
|
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||||
|
// TODO(victorgomes): Remove this copy when all the arguments adaptor frame
|
||||||
|
// code is erased.
|
||||||
|
__ mov(scratch, ebp);
|
||||||
|
__ mov(edx, Operand(ebp, StandardFrameConstants::kArgCOffset));
|
||||||
|
#else
|
||||||
// Check if we have an arguments adaptor frame below the function frame.
|
// Check if we have an arguments adaptor frame below the function frame.
|
||||||
Label arguments_adaptor, arguments_done;
|
Label arguments_adaptor, arguments_done;
|
||||||
__ mov(scratch, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
__ mov(scratch, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
||||||
@ -2073,6 +2107,7 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
|
|||||||
__ SmiUntag(edx);
|
__ SmiUntag(edx);
|
||||||
}
|
}
|
||||||
__ bind(&arguments_done);
|
__ bind(&arguments_done);
|
||||||
|
#endif
|
||||||
|
|
||||||
Label stack_done, stack_overflow;
|
Label stack_done, stack_overflow;
|
||||||
__ sub(edx, ecx);
|
__ sub(edx, ecx);
|
||||||
|
@ -1113,12 +1113,68 @@ void TurboAssembler::PrepareForTailCall(
|
|||||||
void MacroAssembler::InvokePrologue(Register expected_parameter_count,
|
void MacroAssembler::InvokePrologue(Register expected_parameter_count,
|
||||||
Register actual_parameter_count,
|
Register actual_parameter_count,
|
||||||
Label* done, InvokeFlag flag) {
|
Label* done, InvokeFlag flag) {
|
||||||
DCHECK_EQ(actual_parameter_count, eax);
|
|
||||||
|
|
||||||
if (expected_parameter_count != actual_parameter_count) {
|
if (expected_parameter_count != actual_parameter_count) {
|
||||||
|
DCHECK_EQ(actual_parameter_count, eax);
|
||||||
DCHECK_EQ(expected_parameter_count, ecx);
|
DCHECK_EQ(expected_parameter_count, ecx);
|
||||||
|
|
||||||
Label regular_invoke;
|
Label regular_invoke;
|
||||||
|
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||||
|
// Skip if adaptor sentinel.
|
||||||
|
cmp(expected_parameter_count, Immediate(kDontAdaptArgumentsSentinel));
|
||||||
|
j(equal, ®ular_invoke, Label::kNear);
|
||||||
|
|
||||||
|
// Skip if overapplication or if expected number of arguments.
|
||||||
|
sub(expected_parameter_count, actual_parameter_count);
|
||||||
|
j(less_equal, ®ular_invoke, Label::kNear);
|
||||||
|
|
||||||
|
// We need to preserve edx, edi, esi and ebx.
|
||||||
|
movd(xmm0, edx);
|
||||||
|
movd(xmm1, edi);
|
||||||
|
movd(xmm2, esi);
|
||||||
|
movd(xmm3, ebx);
|
||||||
|
|
||||||
|
Register scratch = esi;
|
||||||
|
|
||||||
|
// Underapplication. Move the arguments already in the stack, including the
|
||||||
|
// receiver and the return address.
|
||||||
|
{
|
||||||
|
Label copy, check;
|
||||||
|
Register src = edx, dest = esp, num = edi, current = ebx;
|
||||||
|
mov(src, esp);
|
||||||
|
lea(scratch,
|
||||||
|
Operand(expected_parameter_count, times_system_pointer_size, 0));
|
||||||
|
AllocateStackSpace(scratch);
|
||||||
|
// Extra words are the receiver and the return address (if a jump).
|
||||||
|
int extra_words = flag == CALL_FUNCTION ? 1 : 2;
|
||||||
|
lea(num, Operand(eax, 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(©);
|
||||||
|
mov(scratch, Operand(src, current, times_system_pointer_size, 0));
|
||||||
|
mov(Operand(dest, current, times_system_pointer_size, 0), scratch);
|
||||||
|
inc(current);
|
||||||
|
bind(&check);
|
||||||
|
cmp(current, num);
|
||||||
|
j(less, ©);
|
||||||
|
lea(edx, Operand(esp, num, times_system_pointer_size, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill remaining expected arguments with undefined values.
|
||||||
|
movd(ebx, xmm3); // Restore root.
|
||||||
|
LoadRoot(scratch, RootIndex::kUndefinedValue);
|
||||||
|
{
|
||||||
|
Label loop;
|
||||||
|
bind(&loop);
|
||||||
|
dec(expected_parameter_count);
|
||||||
|
mov(Operand(edx, expected_parameter_count, times_system_pointer_size, 0),
|
||||||
|
scratch);
|
||||||
|
j(greater, &loop, Label::kNear);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore remaining registers.
|
||||||
|
movd(esi, xmm2);
|
||||||
|
movd(edi, xmm1);
|
||||||
|
movd(edx, xmm0);
|
||||||
|
#else
|
||||||
cmp(expected_parameter_count, actual_parameter_count);
|
cmp(expected_parameter_count, actual_parameter_count);
|
||||||
j(equal, ®ular_invoke);
|
j(equal, ®ular_invoke);
|
||||||
Handle<Code> adaptor = BUILTIN_CODE(isolate(), ArgumentsAdaptorTrampoline);
|
Handle<Code> adaptor = BUILTIN_CODE(isolate(), ArgumentsAdaptorTrampoline);
|
||||||
@ -1128,6 +1184,7 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1182,7 +1239,7 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
|
|||||||
push(eax);
|
push(eax);
|
||||||
cmpb(ExternalReferenceAsOperand(debug_hook_active, eax), Immediate(0));
|
cmpb(ExternalReferenceAsOperand(debug_hook_active, eax), Immediate(0));
|
||||||
pop(eax);
|
pop(eax);
|
||||||
j(not_equal, &debug_hook, Label::kNear);
|
j(not_equal, &debug_hook);
|
||||||
}
|
}
|
||||||
bind(&continue_after_hook);
|
bind(&continue_after_hook);
|
||||||
|
|
||||||
@ -1210,7 +1267,7 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
|
|||||||
bind(&debug_hook);
|
bind(&debug_hook);
|
||||||
CallDebugOnFunctionCall(function, new_target, expected_parameter_count,
|
CallDebugOnFunctionCall(function, new_target, expected_parameter_count,
|
||||||
actual_parameter_count);
|
actual_parameter_count);
|
||||||
jmp(&continue_after_hook, Label::kNear);
|
jmp(&continue_after_hook);
|
||||||
|
|
||||||
bind(&done);
|
bind(&done);
|
||||||
}
|
}
|
||||||
|
@ -4784,7 +4784,7 @@ void CodeGenerator::AssembleConstructFrame() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
|
void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) {
|
||||||
auto call_descriptor = linkage()->GetIncomingDescriptor();
|
auto call_descriptor = linkage()->GetIncomingDescriptor();
|
||||||
|
|
||||||
const RegList saves = call_descriptor->CalleeSavedRegisters();
|
const RegList saves = call_descriptor->CalleeSavedRegisters();
|
||||||
@ -4800,37 +4800,86 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Might need ecx for scratch if pop_size is too big or if there is a variable
|
// We might need ecx and edx for scratch.
|
||||||
// pop count.
|
DCHECK_EQ(0u, call_descriptor->CalleeSavedRegisters() & edx.bit());
|
||||||
DCHECK_EQ(0u, call_descriptor->CalleeSavedRegisters() & ecx.bit());
|
DCHECK_EQ(0u, call_descriptor->CalleeSavedRegisters() & ecx.bit());
|
||||||
size_t pop_size = call_descriptor->StackParameterCount() * kSystemPointerSize;
|
|
||||||
IA32OperandConverter g(this, nullptr);
|
IA32OperandConverter g(this, nullptr);
|
||||||
|
int parameter_count =
|
||||||
|
static_cast<int>(call_descriptor->StackParameterCount());
|
||||||
|
|
||||||
|
// {aditional_pop_count} is only greater than zero if {parameter_count = 0}.
|
||||||
|
// Check RawMachineAssembler::PopAndReturn.
|
||||||
|
if (parameter_count != 0) {
|
||||||
|
if (additional_pop_count->IsImmediate()) {
|
||||||
|
DCHECK_EQ(g.ToConstant(additional_pop_count).ToInt32(), 0);
|
||||||
|
} else if (__ emit_debug_code()) {
|
||||||
|
__ cmp(g.ToRegister(additional_pop_count), Immediate(0));
|
||||||
|
__ Assert(equal, AbortReason::kUnexpectedAdditionalPopValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Register argc_reg = ecx;
|
||||||
|
#ifdef V8_NO_ARGUMENTS_ADAPTOR
|
||||||
|
// Functions with JS linkage have at least one parameter (the receiver).
|
||||||
|
// If {parameter_count} == 0, it means it is a builtin with
|
||||||
|
// kDontAdaptArgumentsSentinel, which takes care of JS arguments popping
|
||||||
|
// itself.
|
||||||
|
const bool drop_jsargs = frame_access_state()->has_frame() &&
|
||||||
|
call_descriptor->IsJSFunctionCall() &&
|
||||||
|
parameter_count != 0;
|
||||||
|
#else
|
||||||
|
const bool drop_jsargs = false;
|
||||||
|
#endif
|
||||||
if (call_descriptor->IsCFunctionCall()) {
|
if (call_descriptor->IsCFunctionCall()) {
|
||||||
AssembleDeconstructFrame();
|
AssembleDeconstructFrame();
|
||||||
} else if (frame_access_state()->has_frame()) {
|
} else if (frame_access_state()->has_frame()) {
|
||||||
// Canonicalize JSFunction return sites for now if they always have the same
|
// Canonicalize JSFunction return sites for now if they always have the same
|
||||||
// number of return args.
|
// number of return args.
|
||||||
if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
|
if (additional_pop_count->IsImmediate() &&
|
||||||
|
g.ToConstant(additional_pop_count).ToInt32() == 0) {
|
||||||
if (return_label_.is_bound()) {
|
if (return_label_.is_bound()) {
|
||||||
__ jmp(&return_label_);
|
__ jmp(&return_label_);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
__ bind(&return_label_);
|
__ bind(&return_label_);
|
||||||
AssembleDeconstructFrame();
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
AssembleDeconstructFrame();
|
|
||||||
}
|
}
|
||||||
|
if (drop_jsargs) {
|
||||||
|
// Get the actual argument count.
|
||||||
|
__ mov(argc_reg, Operand(ebp, StandardFrameConstants::kArgCOffset));
|
||||||
|
}
|
||||||
|
AssembleDeconstructFrame();
|
||||||
}
|
}
|
||||||
DCHECK_EQ(0u, call_descriptor->CalleeSavedRegisters() & edx.bit());
|
|
||||||
DCHECK_EQ(0u, call_descriptor->CalleeSavedRegisters() & ecx.bit());
|
if (drop_jsargs) {
|
||||||
if (pop->IsImmediate()) {
|
// We must pop all arguments from the stack (including the receiver). This
|
||||||
DCHECK_EQ(Constant::kInt32, g.ToConstant(pop).type());
|
// number of arguments is given by max(1 + argc_reg, parameter_count).
|
||||||
pop_size += g.ToConstant(pop).ToInt32() * kSystemPointerSize;
|
int parameter_count_without_receiver =
|
||||||
__ Ret(static_cast<int>(pop_size), ecx);
|
parameter_count - 1; // Exclude the receiver to simplify the
|
||||||
|
// computation. We'll account for it at the end.
|
||||||
|
Label mismatch_return;
|
||||||
|
Register scratch_reg = edx;
|
||||||
|
DCHECK_NE(argc_reg, scratch_reg);
|
||||||
|
__ cmp(argc_reg, Immediate(parameter_count_without_receiver));
|
||||||
|
__ j(greater, &mismatch_return, Label::kNear);
|
||||||
|
__ Ret(parameter_count * kSystemPointerSize, scratch_reg);
|
||||||
|
__ bind(&mismatch_return);
|
||||||
|
__ PopReturnAddressTo(scratch_reg);
|
||||||
|
__ lea(esp, Operand(esp, argc_reg, times_system_pointer_size,
|
||||||
|
kSystemPointerSize)); // Also pop the receiver.
|
||||||
|
// We use a return instead of a jump for better return address prediction.
|
||||||
|
__ PushReturnAddressFrom(scratch_reg);
|
||||||
|
__ Ret();
|
||||||
|
} else if (additional_pop_count->IsImmediate()) {
|
||||||
|
Register scratch_reg = ecx;
|
||||||
|
int additional_count = g.ToConstant(additional_pop_count).ToInt32();
|
||||||
|
size_t pop_size = (parameter_count + additional_count) * kSystemPointerSize;
|
||||||
|
CHECK_LE(pop_size, static_cast<size_t>(std::numeric_limits<int>::max()));
|
||||||
|
__ Ret(static_cast<int>(pop_size), scratch_reg);
|
||||||
} else {
|
} else {
|
||||||
Register pop_reg = g.ToRegister(pop);
|
Register pop_reg = g.ToRegister(additional_pop_count);
|
||||||
Register scratch_reg = pop_reg == ecx ? edx : ecx;
|
Register scratch_reg = pop_reg == ecx ? edx : ecx;
|
||||||
|
int pop_size = static_cast<int>(parameter_count * kSystemPointerSize);
|
||||||
__ PopReturnAddressTo(scratch_reg);
|
__ PopReturnAddressTo(scratch_reg);
|
||||||
__ lea(esp, Operand(esp, pop_reg, times_system_pointer_size,
|
__ lea(esp, Operand(esp, pop_reg, times_system_pointer_size,
|
||||||
static_cast<int>(pop_size)));
|
static_cast<int>(pop_size)));
|
||||||
|
Loading…
Reference in New Issue
Block a user