Skip to content

Commit faee973

Browse files
anonrigtargos
authored andcommitted
deps: V8: cherry-pick bc831f8ba33b
Original commit message: [fastcall] Implement support for onebyte string arguments This CL adds one byte string specialization support for fast API call arguments. It introduces a kOneByteString variant to CTypeInfo. We see a ~6x improvement in Deno's TextEncoder#encode microbenchmark. Rendered results: https://divy-v8-patches.deno.dev/ Bug: chromium:1052746 Change-Id: I47c3a9e101cd18ddc6ad58f627db3a34231b60f7 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4036884 Reviewed-by: Toon Verwaest <[email protected]> Reviewed-by: Maya Lekova <[email protected]> Commit-Queue: Maya Lekova <[email protected]> Cr-Commit-Position: refs/heads/main@{#84552} Refs: v8/v8@bc831f8 PR-URL: #45788 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Jiawen Geng <[email protected]> Reviewed-By: Daeyeon Jeong <[email protected]>
1 parent 7bd6a2c commit faee973

File tree

8 files changed

+200
-2
lines changed

8 files changed

+200
-2
lines changed

common.gypi

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
# Reset this number to 0 on major V8 upgrades.
3838
# Increment by one for each non-official patch applied to deps/v8.
39-
'v8_embedder_string': '-node.9',
39+
'v8_embedder_string': '-node.10',
4040

4141
##### V8 defaults for Node.js #####
4242

deps/v8/include/v8-fast-api-calls.h

+20-1
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ class CTypeInfo {
248248
kFloat32,
249249
kFloat64,
250250
kV8Value,
251+
kSeqOneByteString,
251252
kApiObject, // This will be deprecated once all users have
252253
// migrated from v8::ApiObject to v8::Local<v8::Value>.
253254
kAny, // This is added to enable untyped representation of fast
@@ -379,6 +380,11 @@ struct FastApiArrayBuffer {
379380
size_t byte_length;
380381
};
381382

383+
struct FastOneByteString {
384+
const char* data;
385+
uint32_t length;
386+
};
387+
382388
class V8_EXPORT CFunctionInfo {
383389
public:
384390
// Construct a struct to hold a CFunction's type information.
@@ -438,6 +444,7 @@ struct AnyCType {
438444
const FastApiTypedArray<uint64_t>* uint64_ta_value;
439445
const FastApiTypedArray<float>* float_ta_value;
440446
const FastApiTypedArray<double>* double_ta_value;
447+
const FastOneByteString* string_value;
441448
FastApiCallbackOptions* options_value;
442449
};
443450
};
@@ -614,7 +621,7 @@ class CFunctionInfoImpl : public CFunctionInfo {
614621
kReturnType == CTypeInfo::Type::kFloat32 ||
615622
kReturnType == CTypeInfo::Type::kFloat64 ||
616623
kReturnType == CTypeInfo::Type::kAny,
617-
"64-bit int and api object values are not currently "
624+
"64-bit int, string and api object values are not currently "
618625
"supported return types.");
619626
}
620627

@@ -735,6 +742,18 @@ struct TypeInfoHelper<FastApiCallbackOptions&> {
735742
}
736743
};
737744

745+
template <>
746+
struct TypeInfoHelper<const FastOneByteString&> {
747+
static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; }
748+
749+
static constexpr CTypeInfo::Type Type() {
750+
return CTypeInfo::Type::kSeqOneByteString;
751+
}
752+
static constexpr CTypeInfo::SequenceType SequenceType() {
753+
return CTypeInfo::SequenceType::kScalar;
754+
}
755+
};
756+
738757
#define STATIC_ASSERT_IMPLIES(COND, ASSERTION, MSG) \
739758
static_assert(((COND) == 0) || (ASSERTION), MSG)
740759

deps/v8/src/codegen/machine-type.h

+1
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ class MachineType {
315315
case CTypeInfo::Type::kFloat64:
316316
return MachineType::Float64();
317317
case CTypeInfo::Type::kV8Value:
318+
case CTypeInfo::Type::kSeqOneByteString:
318319
case CTypeInfo::Type::kApiObject:
319320
return MachineType::AnyTagged();
320321
}

deps/v8/src/compiler/effect-control-linearizer.cc

+45
Original file line numberDiff line numberDiff line change
@@ -5246,6 +5246,50 @@ Node* EffectControlLinearizer::AdaptFastCallArgument(
52465246
case CTypeInfo::Type::kFloat32: {
52475247
return __ TruncateFloat64ToFloat32(node);
52485248
}
5249+
case CTypeInfo::Type::kSeqOneByteString: {
5250+
// Check that the value is a HeapObject.
5251+
Node* value_is_smi = ObjectIsSmi(node);
5252+
__ GotoIf(value_is_smi, if_error);
5253+
5254+
Node* map = __ LoadField(AccessBuilder::ForMap(), node);
5255+
Node* instance_type =
5256+
__ LoadField(AccessBuilder::ForMapInstanceType(), map);
5257+
5258+
Node* encoding = __ Word32And(
5259+
instance_type,
5260+
__ Int32Constant(kStringRepresentationAndEncodingMask));
5261+
5262+
Node* is_onebytestring = __ Word32Equal(
5263+
encoding, __ Int32Constant(kSeqOneByteStringTag));
5264+
__ GotoIfNot(is_onebytestring, if_error);
5265+
5266+
Node* length_in_bytes =
5267+
__ LoadField(AccessBuilder::ForStringLength(), node);
5268+
Node* data_ptr = __ IntPtrAdd(
5269+
node, __ IntPtrConstant(SeqOneByteString::kHeaderSize -
5270+
kHeapObjectTag));
5271+
5272+
constexpr int kAlign = alignof(FastOneByteString);
5273+
constexpr int kSize = sizeof(FastOneByteString);
5274+
static_assert(kSize == sizeof(uintptr_t) + sizeof(size_t),
5275+
"The size of "
5276+
"FastOneByteString isn't equal to the sum of its "
5277+
"expected members.");
5278+
Node* stack_slot = __ StackSlot(kSize, kAlign);
5279+
5280+
__ Store(StoreRepresentation(MachineType::PointerRepresentation(),
5281+
kNoWriteBarrier),
5282+
stack_slot, 0, data_ptr);
5283+
__ Store(StoreRepresentation(MachineRepresentation::kWord32,
5284+
kNoWriteBarrier),
5285+
stack_slot, sizeof(size_t), length_in_bytes);
5286+
5287+
static_assert(sizeof(uintptr_t) == sizeof(size_t),
5288+
"The string length can't "
5289+
"fit the PointerRepresentation used to store it.");
5290+
5291+
return stack_slot;
5292+
}
52495293
default: {
52505294
return node;
52515295
}
@@ -5451,6 +5495,7 @@ Node* EffectControlLinearizer::LowerFastApiCall(Node* node) {
54515495
case CTypeInfo::Type::kFloat64:
54525496
return ChangeFloat64ToTagged(
54535497
c_call_result, CheckForMinusZeroMode::kCheckForMinusZero);
5498+
case CTypeInfo::Type::kSeqOneByteString:
54545499
case CTypeInfo::Type::kV8Value:
54555500
case CTypeInfo::Type::kApiObject:
54565501
case CTypeInfo::Type::kUint8:

deps/v8/src/compiler/fast-api-calls.cc

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ ElementsKind GetTypedArrayElementsKind(CTypeInfo::Type type) {
2828
case CTypeInfo::Type::kFloat64:
2929
return FLOAT64_ELEMENTS;
3030
case CTypeInfo::Type::kVoid:
31+
case CTypeInfo::Type::kSeqOneByteString:
3132
case CTypeInfo::Type::kBool:
3233
case CTypeInfo::Type::kV8Value:
3334
case CTypeInfo::Type::kApiObject:

deps/v8/src/compiler/simplified-lowering.cc

+1
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,7 @@ class RepresentationSelector {
19241924
case CTypeInfo::Type::kFloat64:
19251925
return UseInfo::CheckedNumberAsFloat64(kDistinguishZeros, feedback);
19261926
case CTypeInfo::Type::kV8Value:
1927+
case CTypeInfo::Type::kSeqOneByteString:
19271928
case CTypeInfo::Type::kApiObject:
19281929
return UseInfo::AnyTagged();
19291930
}

deps/v8/src/d8/d8-test.cc

+47
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,43 @@ class FastCApiObject {
4242
public:
4343
static FastCApiObject& instance();
4444

45+
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
46+
static AnyCType CopyStringFastCallbackPatch(AnyCType receiver,
47+
AnyCType should_fallback,
48+
AnyCType source, AnyCType out,
49+
AnyCType options) {
50+
AnyCType ret;
51+
CopyStringFastCallback(receiver.object_value, should_fallback.bool_value,
52+
*source.string_value, *out.uint8_ta_value,
53+
*options.options_value);
54+
return ret;
55+
}
56+
57+
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
58+
static void CopyStringFastCallback(Local<Object> receiver,
59+
bool should_fallback,
60+
const FastOneByteString& source,
61+
const FastApiTypedArray<uint8_t>& out,
62+
FastApiCallbackOptions& options) {
63+
FastCApiObject* self = UnwrapObject(receiver);
64+
self->fast_call_count_++;
65+
66+
if (should_fallback) {
67+
options.fallback = true;
68+
} else {
69+
options.fallback = false;
70+
}
71+
72+
uint8_t* memory = nullptr;
73+
CHECK(out.getStorageIfAligned(&memory));
74+
memcpy(memory, source.data, source.length);
75+
}
76+
77+
static void CopyStringSlowCallback(const FunctionCallbackInfo<Value>& args) {
78+
FastCApiObject* self = UnwrapObject(args.This());
79+
CHECK_SELF_OR_THROW();
80+
self->slow_call_count_++;
81+
}
4582
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
4683
static AnyCType AddAllFastCallbackPatch(AnyCType receiver,
4784
AnyCType should_fallback,
@@ -1072,6 +1109,16 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
10721109
PerIsolateData::Get(isolate)->SetTestApiObjectCtor(api_obj_ctor);
10731110
Local<Signature> signature = Signature::New(isolate, api_obj_ctor);
10741111
{
1112+
CFunction copy_str_func = CFunction::Make(
1113+
FastCApiObject::CopyStringFastCallback V8_IF_USE_SIMULATOR(
1114+
FastCApiObject::CopyStringFastCallbackPatch));
1115+
api_obj_ctor->PrototypeTemplate()->Set(
1116+
isolate, "copy_string",
1117+
FunctionTemplate::New(isolate, FastCApiObject::CopyStringSlowCallback,
1118+
Local<Value>(), signature, 1,
1119+
ConstructorBehavior::kThrow,
1120+
SideEffectType::kHasSideEffect, &copy_str_func));
1121+
10751122
CFunction add_all_c_func =
10761123
CFunction::Make(FastCApiObject::AddAllFastCallback V8_IF_USE_SIMULATOR(
10771124
FastCApiObject::AddAllFastCallbackPatch));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright 2022 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// This file excercises one byte string support for fast API calls.
6+
7+
// Flags: --turbo-fast-api-calls --expose-fast-api --allow-natives-syntax --turbofan
8+
// --always-turbofan is disabled because we rely on particular feedback for
9+
// optimizing to the fastest path.
10+
// Flags: --no-always-turbofan
11+
// The test relies on optimizing/deoptimizing at predictable moments, so
12+
// it's not suitable for deoptimization fuzzing.
13+
// Flags: --deopt-every-n-times=0
14+
15+
assertThrows(() => d8.test.FastCAPI());
16+
const fast_c_api = new d8.test.FastCAPI();
17+
18+
function assertSlowCall(input) {
19+
assertEquals(new Uint8Array(input.length), copy_string(false, input));
20+
}
21+
22+
function assertFastCall(input) {
23+
const bytes = Uint8Array.from(input, c => c.charCodeAt(0));
24+
assertEquals(bytes, copy_string(false, input));
25+
}
26+
27+
function copy_string(should_fallback = false, input) {
28+
const buffer = new Uint8Array(input.length);
29+
fast_c_api.copy_string(should_fallback, input, buffer);
30+
return buffer;
31+
}
32+
33+
%PrepareFunctionForOptimization(copy_string);
34+
assertSlowCall('Hello');
35+
%OptimizeFunctionOnNextCall(copy_string);
36+
37+
fast_c_api.reset_counts();
38+
assertFastCall('Hello');
39+
assertFastCall('');
40+
assertFastCall(['Hello', 'World'].join(''));
41+
assertOptimized(copy_string);
42+
assertEquals(3, fast_c_api.fast_call_count());
43+
assertEquals(0, fast_c_api.slow_call_count());
44+
45+
// Fall back for twobyte strings.
46+
fast_c_api.reset_counts();
47+
assertSlowCall('Hello\u{10000}');
48+
assertSlowCall('नमस्ते');
49+
assertSlowCall(['नमस्ते', 'World'].join(''));
50+
assertOptimized(copy_string);
51+
assertEquals(0, fast_c_api.fast_call_count());
52+
assertEquals(3, fast_c_api.slow_call_count());
53+
54+
// Fall back for cons strings.
55+
function getTwoByteString() {
56+
return '\u1234t';
57+
}
58+
function getCons() {
59+
return 'hello' + getTwoByteString()
60+
}
61+
62+
fast_c_api.reset_counts();
63+
assertSlowCall(getCons());
64+
assertOptimized(copy_string);
65+
assertEquals(0, fast_c_api.fast_call_count());
66+
assertEquals(1, fast_c_api.slow_call_count());
67+
68+
// Fall back for sliced strings.
69+
fast_c_api.reset_counts();
70+
function getSliced() {
71+
return getCons().slice(1);
72+
}
73+
assertSlowCall(getSliced());
74+
assertOptimized(copy_string);
75+
assertEquals(0, fast_c_api.fast_call_count());
76+
assertEquals(1, fast_c_api.slow_call_count());
77+
78+
// Fall back for SMI and non-string inputs.
79+
fast_c_api.reset_counts();
80+
assertSlowCall(1);
81+
assertSlowCall({});
82+
assertSlowCall(new Uint8Array(1));
83+
assertEquals(0, fast_c_api.fast_call_count());
84+
assertEquals(3, fast_c_api.slow_call_count());

0 commit comments

Comments
 (0)