[maglev] Fix StringFromCharCode inlined builtin

- Fixes the operand index for the first argument of the builtin.
- Adds fast paths for constant code point.

Bug: v8:7700
Change-Id: I0bf398a7b6410f900b602218c79558af73f42e66
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3976509
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83905}
This commit is contained in:
Victor Gomes 2022-10-25 13:36:47 +02:00 committed by V8 LUCI CQ
parent 05bd7d9cd6
commit 84cc145f98
4 changed files with 87 additions and 45 deletions

View File

@ -2476,12 +2476,14 @@ void MaglevGraphBuilder::BuildCallFromRegisterList(
SetAccumulator(AddNode(call));
}
bool MaglevGraphBuilder::TryInlineBuiltin(int argc_count, Builtin builtin) {
bool MaglevGraphBuilder::TryInlineBuiltin(base::Optional<int> receiver_index,
int first_arg_index, int argc_count,
Builtin builtin) {
switch (builtin) {
case Builtin::kStringFromCharCode:
if (argc_count != 1) return false;
SetAccumulator(
AddNewNode<InlinedBuiltinStringFromCharCode>({LoadRegisterInt32(0)}));
SetAccumulator(AddNewNode<InlinedBuiltinStringFromCharCode>(
{LoadRegisterInt32(first_arg_index)}));
return true;
default:
// TODO(v8:7700): Inline more builtins.
@ -2547,7 +2549,19 @@ void MaglevGraphBuilder::BuildCallFromRegisters(
compiler::SharedFunctionInfoRef shared = target.AsJSFunction().shared();
if (shared.HasBuiltinId()) {
if (TryInlineBuiltin(argc_count, shared.builtin_id())) return;
base::Optional<int> receiver_index;
int first_arg_index;
if (receiver_mode != ConvertReceiverMode::kNullOrUndefined) {
receiver_index = 1;
first_arg_index = 2;
} else {
receiver_index = {};
first_arg_index = 1;
}
if (TryInlineBuiltin(receiver_index, first_arg_index, argc_count,
shared.builtin_id())) {
return;
}
}
break;

View File

@ -938,7 +938,8 @@ class MaglevGraphBuilder {
}
}
bool TryInlineBuiltin(int argc_count, Builtin builtin);
bool TryInlineBuiltin(base::Optional<int> receiver_index, int first_arg_index,
int argc_count, Builtin builtin);
void InlineCallFromRegisters(int argc_count,
ConvertReceiverMode receiver_mode,

View File

@ -1689,51 +1689,74 @@ void InlinedBuiltinStringFromCharCode::AllocateVreg(
DefineAsRegister(vreg_state, this);
set_temporaries_needed(1);
}
void InlinedBuiltinStringFromCharCode::AllocateTwoByteString(
MaglevAssembler* masm, Register result_string,
RegisterSnapshot save_registers) {
AllocateRaw(masm, save_registers, result_string,
SeqTwoByteString::SizeFor(1));
__ LoadRoot(kScratchRegister, RootIndex::kStringMap);
__ StoreTaggedField(FieldOperand(result_string, HeapObject::kMapOffset),
kScratchRegister);
__ StoreTaggedField(FieldOperand(result_string, Name::kRawHashFieldOffset),
Immediate(Name::kEmptyHashField));
__ StoreTaggedField(FieldOperand(result_string, String::kLengthOffset),
Immediate(1));
}
void InlinedBuiltinStringFromCharCode::GenerateCode(
MaglevAssembler* masm, const ProcessingState& state) {
Register code_point = ToRegister(code_input());
Register tmp = general_temporaries().PopFirst();
Register result_string = ToRegister(result());
Register scratch = general_temporaries().PopFirst();
ZoneLabelRef done(masm);
__ andl(code_point, Immediate(0xFFFF));
__ cmpl(code_point, Immediate(String::kMaxOneByteCharCode));
if (Int32Constant* constant = code_input().node()->TryCast<Int32Constant>()) {
int32_t char_code = constant->value();
if (char_code < String::kMaxOneByteCharCode) {
Register table = scratch;
__ LoadRoot(table, RootIndex::kSingleCharacterStringTable);
__ DecompressAnyTagged(ToRegister(result()),
FieldOperand(table, FixedArray::kHeaderSize +
char_code * kTaggedSize));
} else {
AllocateTwoByteString(masm, result_string, register_snapshot());
__ movw(FieldOperand(result_string, SeqTwoByteString::kHeaderSize),
Immediate(char_code & 0xFFFF));
}
} else {
Register char_code = ToRegister(code_input());
// Create two byte string in deferred code.
__ JumpToDeferredIf(
greater,
[](MaglevAssembler* masm, ZoneLabelRef done, Register code_point,
Register tmp, InlinedBuiltinStringFromCharCode* node) {
Register result_string = ToRegister(node->result());
RegisterSnapshot save_registers = node->register_snapshot();
// If {code_point} alias with {result_string}, use the tmp register.
if (code_point == result_string) {
DCHECK_NE(tmp, code_point);
__ Move(tmp, code_point);
code_point = tmp;
}
save_registers.live_registers.set(code_point);
AllocateRaw(masm, save_registers, result_string,
SeqTwoByteString::SizeFor(1));
__ LoadRoot(kScratchRegister, RootIndex::kStringMap);
__ StoreTaggedField(FieldOperand(result_string, HeapObject::kMapOffset),
kScratchRegister);
__ StoreTaggedField(
FieldOperand(result_string, Name::kRawHashFieldOffset),
Immediate(Name::kEmptyHashField));
__ StoreTaggedField(FieldOperand(result_string, String::kLengthOffset),
Immediate(1));
__ movw(FieldOperand(result_string, SeqTwoByteString::kHeaderSize),
code_point);
__ jmp(*done);
},
done, code_point, tmp, this);
ZoneLabelRef done(masm);
__ cmpl(char_code, Immediate(String::kMaxOneByteCharCode));
Register table = tmp;
__ LoadRoot(table, RootIndex::kSingleCharacterStringTable);
__ DecompressAnyTagged(ToRegister(result()),
FieldOperand(table, code_point, times_tagged_size,
FixedArray::kHeaderSize));
__ bind(*done);
// Create two byte string in deferred code.
__ JumpToDeferredIf(
greater,
[](MaglevAssembler* masm, ZoneLabelRef done, Register char_code,
Register scratch, InlinedBuiltinStringFromCharCode* node) {
Register result_string = ToRegister(node->result());
RegisterSnapshot save_registers = node->register_snapshot();
// If {char_code} alias with result register, use the scratch
// register.
if (char_code == result_string) {
DCHECK_NE(scratch, char_code);
__ Move(scratch, char_code);
char_code = scratch;
}
save_registers.live_registers.set(char_code);
node->AllocateTwoByteString(masm, result_string, save_registers);
__ Move(scratch, char_code);
__ andl(scratch, Immediate(0xFFFF));
__ movw(FieldOperand(result_string, SeqTwoByteString::kHeaderSize),
scratch);
__ jmp(*done);
},
done, char_code, scratch, this);
Register table = scratch;
__ LoadRoot(table, RootIndex::kSingleCharacterStringTable);
__ DecompressAnyTagged(ToRegister(result()),
FieldOperand(table, char_code, times_tagged_size,
FixedArray::kHeaderSize));
__ bind(*done);
}
}
void LoadTaggedField::AllocateVreg(MaglevVregAllocationState* vreg_state) {

View File

@ -3069,6 +3069,10 @@ class InlinedBuiltinStringFromCharCode
void AllocateVreg(MaglevVregAllocationState*);
void GenerateCode(MaglevAssembler*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
private:
void AllocateTwoByteString(MaglevAssembler* masm, Register result_string,
RegisterSnapshot save_registers);
};
class LoadTaggedField : public FixedInputValueNodeT<1, LoadTaggedField> {