Skip to content

Commit b94d3f7

Browse files
sstricklCommit Queue
authored and
Commit Queue
committed
[vm/compiler] Move setRange bounds checking entirely into Dart.
The bounds checking was implemented in Dart previously, but this removes _checkSetRangeArguments, inlining it into _TypedListBase.setRange, renames _checkBoundsAndMemcpyN to _memMoveN since it no longer performs bounds checking, and also removes the now unneeded bounds checking from the native function TypedData_setRange. TEST=co19{,_2}/LibTest/typed_data lib{,_2}/typed_data corelib{,_2}/list_test Issue: #42072 Cq-Include-Trybots: luci.dart.try:vm-aot-linux-debug-simarm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-aot-linux-release-simarm_x64-try,vm-aot-linux-release-x64-try,vm-aot-mac-release-arm64-try,vm-linux-release-x64-try,vm-mac-release-arm64-try,vm-kernel-precomp-linux-release-x64-try Change-Id: I85ec751708f603f68729f4109d7339dd8407ae77 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/324102 Reviewed-by: Alexander Markov <[email protected]> Commit-Queue: Tess Strickland <[email protected]>
1 parent 2a669c5 commit b94d3f7

File tree

7 files changed

+311
-262
lines changed

7 files changed

+311
-262
lines changed

runtime/lib/typed_data.cc

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,13 @@ static bool IsUint8(intptr_t cid) {
8989
}
9090

9191
DEFINE_NATIVE_ENTRY(TypedDataBase_setRange, 0, 5) {
92+
// This is called after bounds checking, so the numeric inputs are
93+
// guaranteed to be Smis, and the length is guaranteed to be non-zero.
9294
const TypedDataBase& dst =
9395
TypedDataBase::CheckedHandle(zone, arguments->NativeArgAt(0));
9496
const Smi& dst_start_smi =
9597
Smi::CheckedHandle(zone, arguments->NativeArgAt(1));
96-
const Smi& dst_end_smi = Smi::CheckedHandle(zone, arguments->NativeArgAt(2));
98+
const Smi& length_smi = Smi::CheckedHandle(zone, arguments->NativeArgAt(2));
9799
const TypedDataBase& src =
98100
TypedDataBase::CheckedHandle(zone, arguments->NativeArgAt(3));
99101
const Smi& src_start_smi =
@@ -104,16 +106,29 @@ DEFINE_NATIVE_ENTRY(TypedDataBase_setRange, 0, 5) {
104106

105107
const intptr_t dst_start_in_bytes =
106108
dst_start_smi.Value() * element_size_in_bytes;
107-
const intptr_t dst_end_in_bytes = dst_end_smi.Value() * element_size_in_bytes;
109+
const intptr_t length_in_bytes = length_smi.Value() * element_size_in_bytes;
108110
const intptr_t src_start_in_bytes =
109111
src_start_smi.Value() * element_size_in_bytes;
110112

111-
const intptr_t length_in_bytes = dst_end_in_bytes - dst_start_in_bytes;
113+
#if defined(DEBUG)
114+
// Verify bounds checks weren't needed.
115+
ASSERT(dst_start_in_bytes >= 0);
116+
ASSERT(src_start_in_bytes >= 0);
117+
// The callers of this native function never call it for a zero-sized copy.
118+
ASSERT(length_in_bytes > 0);
119+
120+
const intptr_t dst_length_in_bytes = dst.LengthInBytes();
121+
// Since the length is non-zero, the start can't be the same as the end.
122+
ASSERT(dst_start_in_bytes < dst_length_in_bytes);
123+
ASSERT(length_in_bytes <= dst_length_in_bytes - dst_start_in_bytes);
124+
125+
const intptr_t src_length_in_bytes = src.LengthInBytes();
126+
// Since the length is non-zero, the start can't be the same as the end.
127+
ASSERT(src_start_in_bytes < src_length_in_bytes);
128+
ASSERT(length_in_bytes <= src_length_in_bytes - src_start_in_bytes);
129+
#endif
112130

113131
if (!IsClamped(dst.ptr()->GetClassId()) || IsUint8(src.ptr()->GetClassId())) {
114-
// We've already performed range checking in _boundsCheckAndMemcpyN prior
115-
// to the call to _nativeSetRange, so just perform the memmove.
116-
//
117132
// TODO(dartbug.com/42072): We do this when the copy length gets large
118133
// enough that a native call to invoke memmove is faster than the generated
119134
// code from MemoryCopy. Replace the static call to _nativeSetRange with
@@ -125,31 +140,19 @@ DEFINE_NATIVE_ENTRY(TypedDataBase_setRange, 0, 5) {
125140
return Object::null();
126141
}
127142

128-
// This is called on the fast path prior to bounds checking, so perform
129-
// the bounds check even if the length is 0.
130-
const intptr_t dst_length_in_bytes = dst.LengthInBytes();
131-
RangeCheck(dst_start_in_bytes, length_in_bytes, dst_length_in_bytes,
132-
element_size_in_bytes);
133-
134-
const intptr_t src_length_in_bytes = src.LengthInBytes();
135-
RangeCheck(src_start_in_bytes, length_in_bytes, src_length_in_bytes,
136-
element_size_in_bytes);
137-
138143
ASSERT_EQUAL(element_size_in_bytes, 1);
139144

140-
if (length_in_bytes > 0) {
141-
NoSafepointScope no_safepoint;
142-
uint8_t* dst_data =
143-
reinterpret_cast<uint8_t*>(dst.DataAddr(dst_start_in_bytes));
144-
int8_t* src_data =
145-
reinterpret_cast<int8_t*>(src.DataAddr(src_start_in_bytes));
146-
for (intptr_t ix = 0; ix < length_in_bytes; ix++) {
147-
int8_t v = *src_data;
148-
if (v < 0) v = 0;
149-
*dst_data = v;
150-
src_data++;
151-
dst_data++;
152-
}
145+
NoSafepointScope no_safepoint;
146+
uint8_t* dst_data =
147+
reinterpret_cast<uint8_t*>(dst.DataAddr(dst_start_in_bytes));
148+
int8_t* src_data =
149+
reinterpret_cast<int8_t*>(src.DataAddr(src_start_in_bytes));
150+
for (intptr_t ix = 0; ix < length_in_bytes; ix++) {
151+
int8_t v = *src_data;
152+
if (v < 0) v = 0;
153+
*dst_data = v;
154+
src_data++;
155+
dst_data++;
153156
}
154157

155158
return Object::null();

runtime/vm/compiler/backend/memory_copy_test.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,8 +420,8 @@ static void RunMemoryCopyInstrTest(intptr_t src_start,
420420
#define MEMORY_MOVE_TEST_BOXED(src_start, dest_start, length, elem_size) \
421421
ISOLATE_UNIT_TEST_CASE( \
422422
IRTest_MemoryMove_##src_start##_##dest_start##_##length##_##elem_size) { \
423-
RunMemoryCopyInstrTest(src_start, dest_start, length, elem_size, true, \
424-
false); \
423+
RunMemoryCopyInstrTest(src_start, dest_start, length, elem_size, false, \
424+
true); \
425425
}
426426

427427
#define MEMORY_MOVE_TEST_UNBOXED(src_start, dest_start, length, el_si) \

runtime/vm/compiler/frontend/kernel_to_il.cc

Lines changed: 23 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -925,11 +925,11 @@ bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph(
925925
case MethodRecognizer::kRecord_numFields:
926926
case MethodRecognizer::kSuspendState_clone:
927927
case MethodRecognizer::kSuspendState_resume:
928-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy1:
929-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy2:
930-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy4:
931-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy8:
932-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy16:
928+
case MethodRecognizer::kTypedData_memMove1:
929+
case MethodRecognizer::kTypedData_memMove2:
930+
case MethodRecognizer::kTypedData_memMove4:
931+
case MethodRecognizer::kTypedData_memMove8:
932+
case MethodRecognizer::kTypedData_memMove16:
933933
case MethodRecognizer::kTypedData_ByteDataView_factory:
934934
case MethodRecognizer::kTypedData_Int8ArrayView_factory:
935935
case MethodRecognizer::kTypedData_Uint8ArrayView_factory:
@@ -1138,26 +1138,21 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
11381138
body += TailCall(resume_stub);
11391139
break;
11401140
}
1141-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy1:
1141+
case MethodRecognizer::kTypedData_memMove1:
11421142
// Pick an appropriate typed data cid based on the element size.
1143-
body +=
1144-
BuildTypedDataCheckBoundsAndMemcpy(function, kTypedDataUint8ArrayCid);
1143+
body += BuildTypedDataMemMove(function, kTypedDataUint8ArrayCid);
11451144
break;
1146-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy2:
1147-
body += BuildTypedDataCheckBoundsAndMemcpy(function,
1148-
kTypedDataUint16ArrayCid);
1145+
case MethodRecognizer::kTypedData_memMove2:
1146+
body += BuildTypedDataMemMove(function, kTypedDataUint16ArrayCid);
11491147
break;
1150-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy4:
1151-
body += BuildTypedDataCheckBoundsAndMemcpy(function,
1152-
kTypedDataUint32ArrayCid);
1148+
case MethodRecognizer::kTypedData_memMove4:
1149+
body += BuildTypedDataMemMove(function, kTypedDataUint32ArrayCid);
11531150
break;
1154-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy8:
1155-
body += BuildTypedDataCheckBoundsAndMemcpy(function,
1156-
kTypedDataUint64ArrayCid);
1151+
case MethodRecognizer::kTypedData_memMove8:
1152+
body += BuildTypedDataMemMove(function, kTypedDataUint64ArrayCid);
11571153
break;
1158-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy16:
1159-
body += BuildTypedDataCheckBoundsAndMemcpy(function,
1160-
kTypedDataInt32x4ArrayCid);
1154+
case MethodRecognizer::kTypedData_memMove16:
1155+
body += BuildTypedDataMemMove(function, kTypedDataInt32x4ArrayCid);
11611156
break;
11621157
#define CASE(name) \
11631158
case MethodRecognizer::kTypedData_##name##_factory: \
@@ -1758,33 +1753,16 @@ Fragment FlowGraphBuilder::BuildTypedDataViewFactoryConstructor(
17581753
return body;
17591754
}
17601755

1761-
Fragment FlowGraphBuilder::BuildTypedDataCheckBoundsAndMemcpy(
1762-
const Function& function,
1763-
intptr_t cid) {
1756+
Fragment FlowGraphBuilder::BuildTypedDataMemMove(const Function& function,
1757+
intptr_t cid) {
17641758
ASSERT_EQUAL(parsed_function_->function().NumParameters(), 5);
17651759
LocalVariable* arg_to = parsed_function_->RawParameterVariable(0);
17661760
LocalVariable* arg_to_start = parsed_function_->RawParameterVariable(1);
1767-
LocalVariable* arg_to_end = parsed_function_->RawParameterVariable(2);
1761+
LocalVariable* arg_count = parsed_function_->RawParameterVariable(2);
17681762
LocalVariable* arg_from = parsed_function_->RawParameterVariable(3);
17691763
LocalVariable* arg_from_start = parsed_function_->RawParameterVariable(4);
17701764

1771-
const Library& lib = Library::Handle(Z, Library::TypedDataLibrary());
1772-
ASSERT(!lib.IsNull());
1773-
const Function& check_set_range_args = Function::ZoneHandle(
1774-
Z, lib.LookupFunctionAllowPrivate(Symbols::_checkSetRangeArguments()));
1775-
ASSERT(!check_set_range_args.IsNull());
1776-
17771765
Fragment body;
1778-
body += LoadLocal(arg_to);
1779-
body += LoadLocal(arg_to_start);
1780-
body += LoadLocal(arg_to_end);
1781-
body += LoadLocal(arg_from);
1782-
body += LoadLocal(arg_from_start);
1783-
body += StaticCall(TokenPosition::kNoSource, check_set_range_args, 5,
1784-
ICData::kStatic);
1785-
// The length is guaranteed to be a Smi if bounds checking is successful.
1786-
LocalVariable* length_to_copy = MakeTemporary("length");
1787-
17881766
// If we're copying at least this many elements, calling _nativeSetRange,
17891767
// which calls memmove via a native call, is faster than using the code
17901768
// currently emitted by the MemoryCopy instruction.
@@ -1806,7 +1784,7 @@ Fragment FlowGraphBuilder::BuildTypedDataCheckBoundsAndMemcpy(
18061784

18071785
JoinEntryInstr* done = BuildJoinEntry();
18081786
TargetEntryInstr *is_small_enough, *is_too_large;
1809-
body += LoadLocal(length_to_copy);
1787+
body += LoadLocal(arg_count);
18101788
body += IntConstant(kCopyLengthForNativeCall);
18111789
body += SmiRelationalOp(Token::kLT);
18121790
body += BranchIfTrue(&is_small_enough, &is_too_large);
@@ -1816,13 +1794,15 @@ Fragment FlowGraphBuilder::BuildTypedDataCheckBoundsAndMemcpy(
18161794
use_instruction += LoadLocal(arg_to);
18171795
use_instruction += LoadLocal(arg_from_start);
18181796
use_instruction += LoadLocal(arg_to_start);
1819-
use_instruction += LoadLocal(length_to_copy);
1797+
use_instruction += LoadLocal(arg_count);
18201798
use_instruction += MemoryCopy(cid, cid,
18211799
/*unboxed_inputs=*/false, /*can_overlap=*/true);
18221800
use_instruction += Goto(done);
18231801

18241802
// TODO(dartbug.com/42072): Instead of doing a static call to a native
18251803
// method, make a leaf runtime entry for memmove and use CCall.
1804+
const Library& lib = Library::Handle(Z, Library::TypedDataLibrary());
1805+
ASSERT(!lib.IsNull());
18261806
const Class& typed_list_base =
18271807
Class::Handle(Z, lib.LookupClassAllowPrivate(Symbols::_TypedListBase()));
18281808
ASSERT(!typed_list_base.IsNull());
@@ -1836,7 +1816,7 @@ Fragment FlowGraphBuilder::BuildTypedDataCheckBoundsAndMemcpy(
18361816
Fragment call_native(is_too_large);
18371817
call_native += LoadLocal(arg_to);
18381818
call_native += LoadLocal(arg_to_start);
1839-
call_native += LoadLocal(arg_to_end);
1819+
call_native += LoadLocal(arg_count);
18401820
call_native += LoadLocal(arg_from);
18411821
call_native += LoadLocal(arg_from_start);
18421822
call_native += StaticCall(TokenPosition::kNoSource, native_set_range, 5,
@@ -1845,7 +1825,6 @@ Fragment FlowGraphBuilder::BuildTypedDataCheckBoundsAndMemcpy(
18451825
call_native += Goto(done);
18461826

18471827
body.current = done;
1848-
body += DropTemporary(&length_to_copy);
18491828
body += NullConstant();
18501829

18511830
return body;

runtime/vm/compiler/frontend/kernel_to_il.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,7 @@ class FlowGraphBuilder : public BaseFlowGraphBuilder {
146146

147147
FlowGraph* BuildGraphOfRecognizedMethod(const Function& function);
148148

149-
Fragment BuildTypedDataCheckBoundsAndMemcpy(const Function& function,
150-
intptr_t cid);
149+
Fragment BuildTypedDataMemMove(const Function& function, intptr_t cid);
151150
Fragment BuildTypedDataViewFactoryConstructor(const Function& function,
152151
classid_t cid);
153152
Fragment BuildTypedDataFactoryConstructor(const Function& function,

runtime/vm/compiler/recognized_methods_list.h

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,11 @@ namespace dart {
114114
V(Float32x4List, ., TypedData_Float32x4Array_factory, 0x0a6eefa8) \
115115
V(Int32x4List, ., TypedData_Int32x4Array_factory, 0x5a09288e) \
116116
V(Float64x2List, ., TypedData_Float64x2Array_factory, 0xecbc738a) \
117-
V(_TypedListBase, _checkBoundsAndMemcpy1, \
118-
TypedData_checkBoundsAndMemcpy1, 0xf9d326bd) \
119-
V(_TypedListBase, _checkBoundsAndMemcpy2, \
120-
TypedData_checkBoundsAndMemcpy2, 0xf0756646) \
121-
V(_TypedListBase, _checkBoundsAndMemcpy4, \
122-
TypedData_checkBoundsAndMemcpy4, 0xe8cfd800) \
123-
V(_TypedListBase, _checkBoundsAndMemcpy8, \
124-
TypedData_checkBoundsAndMemcpy8, 0xe945188e) \
125-
V(_TypedListBase, _checkBoundsAndMemcpy16, \
126-
TypedData_checkBoundsAndMemcpy16, 0xebd06cb3) \
117+
V(_TypedListBase, _memMove1, TypedData_memMove1, 0xd2767fb0) \
118+
V(_TypedListBase, _memMove2, TypedData_memMove2, 0xed382bb6) \
119+
V(_TypedListBase, _memMove4, TypedData_memMove4, 0xcfe37726) \
120+
V(_TypedListBase, _memMove8, TypedData_memMove8, 0xd1d8e325) \
121+
V(_TypedListBase, _memMove16, TypedData_memMove16, 0x07861cd5) \
127122
V(::, _toClampedUint8, ConvertIntToClampedUint8, 0xd0e522d0) \
128123
V(::, copyRangeFromUint8ListToOneByteString, \
129124
CopyRangeFromUint8ListToOneByteString, 0xcc42cce1) \

runtime/vm/object.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9102,11 +9102,11 @@ bool Function::RecognizedKindForceOptimize() const {
91029102
case MethodRecognizer::kRecord_numFields:
91039103
case MethodRecognizer::kUtf8DecoderScan:
91049104
case MethodRecognizer::kDouble_hashCode:
9105-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy1:
9106-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy2:
9107-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy4:
9108-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy8:
9109-
case MethodRecognizer::kTypedData_checkBoundsAndMemcpy16:
9105+
case MethodRecognizer::kTypedData_memMove1:
9106+
case MethodRecognizer::kTypedData_memMove2:
9107+
case MethodRecognizer::kTypedData_memMove4:
9108+
case MethodRecognizer::kTypedData_memMove8:
9109+
case MethodRecognizer::kTypedData_memMove16:
91109110
// Prevent the GC from running so that the operation is atomic from
91119111
// a GC point of view. Always double check implementation in
91129112
// kernel_to_il.cc that no GC can happen in between the relevant IL

0 commit comments

Comments
 (0)