Commit 57f8e38e authored by danno's avatar danno Committed by Commit bot

[turbofan]: Convert StringFromCharCode to var-args style TF builtin

Review-Url: https://codereview.chromium.org/2448993002
Cr-Commit-Position: refs/heads/master@{#40814}
parent 7f801ff3
......@@ -1522,7 +1522,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
// Install the String.fromCharCode function.
SimpleInstallFunction(string_fun, "fromCharCode",
Builtins::kStringFromCharCode, 1, true);
Builtins::kStringFromCharCode, 1, false);
// Install the String.fromCodePoint function.
SimpleInstallFunction(string_fun, "fromCodePoint",
......
......@@ -424,181 +424,117 @@ void Builtins::Generate_StringFromCharCode(CodeStubAssembler* assembler) {
typedef compiler::Node Node;
typedef CodeStubAssembler::Variable Variable;
Node* code = assembler->Parameter(1);
Node* context = assembler->Parameter(4);
Node* argc = assembler->ChangeInt32ToIntPtr(
assembler->Parameter(BuiltinDescriptor::kArgumentsCount));
Node* context = assembler->Parameter(BuiltinDescriptor::kContext);
CodeStubArguments arguments(assembler, argc);
// Check if we have exactly one argument (plus the implicit receiver), i.e.
// if the parent frame is not an arguments adaptor frame.
Label if_oneargument(assembler), if_notoneargument(assembler);
Node* parent_frame_pointer = assembler->LoadParentFramePointer();
Node* parent_frame_type =
assembler->Load(MachineType::Pointer(), parent_frame_pointer,
assembler->IntPtrConstant(
CommonFrameConstants::kContextOrFrameTypeOffset));
assembler->Branch(
assembler->WordEqual(
parent_frame_type,
assembler->SmiConstant(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))),
&if_notoneargument, &if_oneargument);
assembler->Branch(assembler->WordEqual(argc, assembler->IntPtrConstant(1)),
&if_oneargument, &if_notoneargument);
assembler->Bind(&if_oneargument);
{
// Single argument case, perform fast single character string cache lookup
// for one-byte code units, or fall back to creating a single character
// string on the fly otherwise.
Node* code = arguments.AtIndex(0);
Node* code32 = assembler->TruncateTaggedToWord32(context, code);
Node* code16 = assembler->Word32And(
code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit));
Node* result = assembler->StringFromCharCode(code16);
assembler->Return(result);
arguments.PopAndReturn(result);
}
Node* code16 = nullptr;
assembler->Bind(&if_notoneargument);
{
// Determine the resulting string length.
Node* length = assembler->LoadAndUntagSmi(
parent_frame_pointer, ArgumentsAdaptorFrameConstants::kLengthOffset);
Label two_byte(assembler);
// Assume that the resulting string contains only one-byte characters.
Node* result = assembler->AllocateSeqOneByteString(context, length);
// Truncate all input parameters and append them to the resulting string.
Variable var_offset(assembler, MachineType::PointerRepresentation());
Label loop(assembler, &var_offset), done_loop(assembler);
var_offset.Bind(assembler->IntPtrConstant(0));
assembler->Goto(&loop);
assembler->Bind(&loop);
{
// Load the current {offset}.
Node* offset = var_offset.value();
// Check if we're done with the string.
assembler->GotoIf(assembler->WordEqual(offset, length), &done_loop);
// Load the next code point and truncate it to a 16-bit value.
Node* code = assembler->Load(
MachineType::AnyTagged(), parent_frame_pointer,
assembler->IntPtrAdd(
assembler->WordShl(assembler->IntPtrSub(length, offset),
assembler->IntPtrConstant(kPointerSizeLog2)),
assembler->IntPtrConstant(
CommonFrameConstants::kFixedFrameSizeAboveFp -
kPointerSize)));
Node* code32 = assembler->TruncateTaggedToWord32(context, code);
Node* code16 = assembler->Word32And(
Node* one_byte_result = assembler->AllocateSeqOneByteString(context, argc);
Variable max_index(assembler, MachineType::PointerRepresentation());
max_index.Bind(assembler->IntPtrConstant(0));
// Iterate over the incoming arguments, converting them to 8-bit character
// codes. Stop if any of the conversions generates a code that doesn't fit
// in 8 bits.
CodeStubAssembler::VariableList vars({&max_index}, assembler->zone());
arguments.ForEach(vars, [context, &two_byte, &max_index, &code16,
one_byte_result](CodeStubAssembler* assembler,
Node* arg) {
Node* code32 = assembler->TruncateTaggedToWord32(context, arg);
code16 = assembler->Word32And(
code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit));
// Check if {code16} fits into a one-byte string.
Label if_codeisonebyte(assembler), if_codeistwobyte(assembler);
assembler->Branch(
assembler->Int32LessThanOrEqual(
assembler->GotoIf(
assembler->Int32GreaterThan(
code16, assembler->Int32Constant(String::kMaxOneByteCharCode)),
&if_codeisonebyte, &if_codeistwobyte);
assembler->Bind(&if_codeisonebyte);
{
// The {code16} fits into the SeqOneByteString {result}.
assembler->StoreNoWriteBarrier(
MachineRepresentation::kWord8, result,
assembler->IntPtrAdd(
assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
kHeapObjectTag),
offset),
code16);
var_offset.Bind(
assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
assembler->Goto(&loop);
}
assembler->Bind(&if_codeistwobyte);
{
// Allocate a SeqTwoByteString to hold the resulting string.
Node* cresult = assembler->AllocateSeqTwoByteString(context, length);
// Copy all characters that were previously written to the
// SeqOneByteString in {result} over to the new {cresult}.
Variable var_coffset(assembler, MachineType::PointerRepresentation());
Label cloop(assembler, &var_coffset), done_cloop(assembler);
var_coffset.Bind(assembler->IntPtrConstant(0));
assembler->Goto(&cloop);
assembler->Bind(&cloop);
{
Node* coffset = var_coffset.value();
assembler->GotoIf(assembler->WordEqual(coffset, offset), &done_cloop);
Node* ccode = assembler->Load(
MachineType::Uint8(), result,
assembler->IntPtrAdd(
assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
kHeapObjectTag),
coffset));
assembler->StoreNoWriteBarrier(
MachineRepresentation::kWord16, cresult,
assembler->IntPtrAdd(
assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize -
kHeapObjectTag),
assembler->WordShl(coffset, 1)),
ccode);
var_coffset.Bind(
assembler->IntPtrAdd(coffset, assembler->IntPtrConstant(1)));
assembler->Goto(&cloop);
}
&two_byte);
// The {code16} fits into the SeqOneByteString {one_byte_result}.
Node* offset = assembler->ElementOffsetFromIndex(
max_index.value(), UINT8_ELEMENTS,
CodeStubAssembler::INTPTR_PARAMETERS,
SeqOneByteString::kHeaderSize - kHeapObjectTag);
assembler->StoreNoWriteBarrier(MachineRepresentation::kWord8,
one_byte_result, offset, code16);
max_index.Bind(assembler->IntPtrAdd(max_index.value(),
assembler->IntPtrConstant(1)));
});
arguments.PopAndReturn(one_byte_result);
assembler->Bind(&two_byte);
// At least one of the characters in the string requires a 16-bit
// representation. Allocate a SeqTwoByteString to hold the resulting
// string.
Node* two_byte_result = assembler->AllocateSeqTwoByteString(context, argc);
// Copy the characters that have already been put in the 8-bit string into
// their corresponding positions in the new 16-bit string.
Node* zero = assembler->IntPtrConstant(0);
assembler->CopyStringCharacters(
one_byte_result, two_byte_result, zero, zero, max_index.value(),
String::ONE_BYTE_ENCODING, String::TWO_BYTE_ENCODING,
CodeStubAssembler::INTPTR_PARAMETERS);
// Write the pending {code16} to {offset}.
assembler->Bind(&done_cloop);
assembler->StoreNoWriteBarrier(
MachineRepresentation::kWord16, cresult,
assembler->IntPtrAdd(
assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize -
kHeapObjectTag),
assembler->WordShl(offset, 1)),
code16);
// Copy the remaining parameters to the SeqTwoByteString {cresult}.
Label floop(assembler, &var_offset), done_floop(assembler);
assembler->Goto(&floop);
assembler->Bind(&floop);
{
// Compute the next {offset}.
Node* offset = assembler->IntPtrAdd(var_offset.value(),
assembler->IntPtrConstant(1));
// Check if we're done with the string.
assembler->GotoIf(assembler->WordEqual(offset, length), &done_floop);
// Load the next code point and truncate it to a 16-bit value.
Node* code = assembler->Load(
MachineType::AnyTagged(), parent_frame_pointer,
assembler->IntPtrAdd(
assembler->WordShl(
assembler->IntPtrSub(length, offset),
assembler->IntPtrConstant(kPointerSizeLog2)),
assembler->IntPtrConstant(
CommonFrameConstants::kFixedFrameSizeAboveFp -
kPointerSize)));
Node* code32 = assembler->TruncateTaggedToWord32(context, code);
// Write the character that caused the 8-bit to 16-bit fault.
Node* max_index_offset = assembler->ElementOffsetFromIndex(
max_index.value(), UINT16_ELEMENTS,
CodeStubAssembler::INTPTR_PARAMETERS,
SeqTwoByteString::kHeaderSize - kHeapObjectTag);
assembler->StoreNoWriteBarrier(MachineRepresentation::kWord16,
two_byte_result, max_index_offset, code16);
max_index.Bind(
assembler->IntPtrAdd(max_index.value(), assembler->IntPtrConstant(1)));
// Resume copying the passed-in arguments from the same place where the
// 8-bit copy stopped, but this time copying over all of the characters
// using a 16-bit representation.
arguments.ForEach(
vars,
[context, two_byte_result, &max_index](CodeStubAssembler* assembler,
Node* arg) {
Node* code32 = assembler->TruncateTaggedToWord32(context, arg);
Node* code16 = assembler->Word32And(
code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit));
// Store the truncated {code} point at the next offset.
assembler->StoreNoWriteBarrier(
MachineRepresentation::kWord16, cresult,
assembler->IntPtrAdd(
assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize -
kHeapObjectTag),
assembler->WordShl(offset, 1)),
code16);
var_offset.Bind(offset);
assembler->Goto(&floop);
}
// Return the SeqTwoByteString.
assembler->Bind(&done_floop);
assembler->Return(cresult);
}
}
assembler->Bind(&done_loop);
assembler->Return(result);
Node* offset = assembler->ElementOffsetFromIndex(
max_index.value(), UINT16_ELEMENTS,
CodeStubAssembler::INTPTR_PARAMETERS,
SeqTwoByteString::kHeaderSize - kHeapObjectTag);
assembler->StoreNoWriteBarrier(MachineRepresentation::kWord16,
two_byte_result, offset, code16);
max_index.Bind(assembler->IntPtrAdd(max_index.value(),
assembler->IntPtrConstant(1)));
},
max_index.value());
arguments.PopAndReturn(two_byte_result);
}
}
......
......@@ -84,7 +84,8 @@ Code* BuildWithCodeStubAssemblerJS(Isolate* isolate,
Code::Flags flags, const char* name) {
HandleScope scope(isolate);
Zone zone(isolate->allocator(), ZONE_NAME);
const int argc_with_recv = argc + 1;
const int argc_with_recv =
(argc == SharedFunctionInfo::kDontAdaptArgumentsSentinel) ? 0 : argc + 1;
CodeStubAssembler assembler(isolate, &zone, argc_with_recv, flags, name);
generator(&assembler);
Handle<Code> code = assembler.GenerateCode();
......
......@@ -620,7 +620,7 @@ namespace internal {
ASM(StringConstructor_ConstructStub) \
CPP(StringFromCodePoint) \
/* ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) */ \
TFJ(StringFromCharCode, 1) \
TFJ(StringFromCharCode, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 section 21.1.3.1 String.prototype.charAt ( pos ) */ \
TFJ(StringPrototypeCharAt, 1) \
/* ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) */ \
......
......@@ -203,6 +203,12 @@ Callable CodeFactory::RegExpExec(Isolate* isolate) {
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::StringFromCharCode(Isolate* isolate) {
Handle<Code> code(isolate->builtins()->StringFromCharCode());
return Callable(code, BuiltinDescriptor(isolate));
}
#define DECLARE_TFS(Name, Kind, Extra, InterfaceDescriptor) \
typedef InterfaceDescriptor##Descriptor Name##Descriptor;
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, DECLARE_TFS,
......
......@@ -65,6 +65,8 @@ class V8_EXPORT_PRIVATE CodeFactory final {
// code-stubs.h.
static Callable InstanceOf(Isolate* isolate);
static Callable StringFromCharCode(Isolate* isolate);
static Callable GetProperty(Isolate* isolate);
static Callable ToBoolean(Isolate* isolate);
......
......@@ -1112,6 +1112,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
// TypedArray/ArrayBuffer helpers
compiler::Node* IsDetachedBuffer(compiler::Node* buffer);
compiler::Node* ElementOffsetFromIndex(compiler::Node* index,
ElementsKind kind, ParameterMode mode,
int base_size = 0);
private:
friend class CodeStubArguments;
......@@ -1172,10 +1176,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Label* definitely_no_elements,
Label* possibly_elements);
compiler::Node* ElementOffsetFromIndex(compiler::Node* index,
ElementsKind kind, ParameterMode mode,
int base_size = 0);
compiler::Node* AllocateRawAligned(compiler::Node* size_in_bytes,
AllocationFlags flags,
compiler::Node* top_address,
......
......@@ -370,6 +370,27 @@ void CallFunctionWithFeedbackAndVectorDescriptor::InitializePlatformIndependent(
machine_types);
}
void BuiltinDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) {
MachineType machine_types[] = {MachineType::AnyTagged(),
MachineType::Int32()};
data->InitializePlatformIndependent(arraysize(machine_types), 0,
machine_types);
}
void BuiltinDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {NewTargetRegister(), ArgumentsCountRegister()};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
const Register BuiltinDescriptor::ArgumentsCountRegister() {
return kJavaScriptCallArgCountRegister;
}
const Register BuiltinDescriptor::NewTargetRegister() {
return kJavaScriptCallNewTargetRegister;
}
void ArrayNoArgumentConstructorDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) {
// kFunction, kAllocationSite, kActualArgumentsCount, kFunctionParameter
......
......@@ -62,6 +62,7 @@ class PlatformInterfaceDescriptor;
V(AllocateInt8x16) \
V(AllocateUint8x16) \
V(AllocateBool8x16) \
V(Builtin) \
V(ArrayNoArgumentConstructor) \
V(ArraySingleArgumentConstructor) \
V(ArrayNArgumentsConstructor) \
......@@ -597,6 +598,15 @@ class AllocateHeapNumberDescriptor : public CallInterfaceDescriptor {
SIMD128_TYPES(SIMD128_ALLOC_DESC)
#undef SIMD128_ALLOC_DESC
class BuiltinDescriptor : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kNewTarget, kArgumentsCount)
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(BuiltinDescriptor,
CallInterfaceDescriptor)
static const Register ArgumentsCountRegister();
static const Register NewTargetRegister();
};
class ArrayNoArgumentConstructorDescriptor : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kFunction, kAllocationSite, kActualArgumentsCount,
......
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