mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
Reland "[VM] Inline ClassID.getID() eagerly, extend pattern matching logic to recognize it, use it to special case ascii decoding"
This change extends/fixes the exiting "pattern recognition" which tries to recognize the pattern v2 <- LoadClassIdInstr(v1) BranchIf v2 == IntegerConstant(cid) Furthermore we start inlining the recognized `ClassID.getID` method very early in the pipeline. This allows the VM to recognize the above pattern and insert redefinitions before the actual inlining pass. Furthermore we special-case two very hot methods in utf8 decoding by manually having two loops, one of which is guarded by a class-id check against the _Uint8ArrayView class, which is most common. (In the future we would like to unify the typed data layouts so we no longer need to use `ClassId.getID`, thereby also allowing non core library code to use this). This improves dart-aot by * 31%+ for a protobuf decoding benchmark we care about Issue https://github.com/dart-lang/sdk/issues/31954 Change-Id: I7181bbf096aabe303634fd3b2bff9cc96d69719c Reviewed-on: https://dart-review.googlesource.com/c/85443 Reviewed-by: Vyacheslav Egorov <vegorov@google.com> Commit-Queue: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
c9a8589ba6
commit
f5d1229081
|
@ -495,3 +495,13 @@ class Utf8Decoder {
|
|||
return null;
|
||||
}();
|
||||
}
|
||||
|
||||
@patch
|
||||
int _scanOneByteCharacters(List<int> units, int from, int endIndex) {
|
||||
final to = endIndex;
|
||||
for (var i = from; i < to; i++) {
|
||||
final unit = units[i];
|
||||
if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
|
||||
}
|
||||
return to - from;
|
||||
}
|
||||
|
|
|
@ -342,9 +342,7 @@ template("dart_io") {
|
|||
"..:dart_config",
|
||||
"..:dart_os_config",
|
||||
] + extra_configs
|
||||
public_configs = [
|
||||
"..:dart_public_config",
|
||||
]
|
||||
public_configs = [ "..:dart_public_config" ]
|
||||
if (is_fuchsia) {
|
||||
configs -= [ "//build/config:symbol_visibility_hidden" ]
|
||||
}
|
||||
|
|
|
@ -615,9 +615,9 @@ class ProcessStarter {
|
|||
char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
|
||||
uint32_t flags = FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC |
|
||||
FDIO_SPAWN_CLONE_NAMESPACE;
|
||||
status = fdio_spawn_vmo(ZX_HANDLE_INVALID, flags, vmo, program_arguments_,
|
||||
program_environment_, 4, actions, &process,
|
||||
err_msg);
|
||||
status =
|
||||
fdio_spawn_vmo(ZX_HANDLE_INVALID, flags, vmo, program_arguments_,
|
||||
program_environment_, 4, actions, &process, err_msg);
|
||||
|
||||
if (status != ZX_OK) {
|
||||
LOG_ERR("ProcessStarter: Start() fdio_spawn_vmo failed\n");
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
// part of "internal_patch.dart";
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
class ClassID {
|
||||
@pragma("vm:entry-point")
|
||||
@pragma("vm:exact-result-type", "dart:core#_Smi")
|
||||
static int getID(Object value) native "ClassID_getID";
|
||||
|
||||
|
|
|
@ -4,14 +4,24 @@
|
|||
|
||||
// part of "internal_patch.dart";
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
class ClassID {
|
||||
@pragma("vm:entry-point")
|
||||
@pragma("vm:exact-result-type", "dart:core#_Smi")
|
||||
static int getID(Object value) native "ClassID_getID";
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
static final int cidArray = 0;
|
||||
@pragma("vm:entry-point")
|
||||
static final int cidExternalOneByteString = 0;
|
||||
@pragma("vm:entry-point")
|
||||
static final int cidGrowableObjectArray = 0;
|
||||
@pragma("vm:entry-point")
|
||||
static final int cidImmutableArray = 0;
|
||||
@pragma("vm:entry-point")
|
||||
static final int cidOneByteString = 0;
|
||||
@pragma("vm:entry-point")
|
||||
static final int cidTwoByteString = 0;
|
||||
@pragma("vm:entry-point")
|
||||
static final int cidUint8ArrayView = 0;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
/// used by patches of that library. We plan to change this when we have a
|
||||
/// shared front end and simply use parts.
|
||||
|
||||
import "dart:_internal" show POWERS_OF_TEN, patch;
|
||||
import "dart:_internal" show POWERS_OF_TEN, patch, ClassID;
|
||||
|
||||
import "dart:typed_data" show Uint8List, Uint16List;
|
||||
|
||||
|
@ -1816,3 +1816,27 @@ class _JsonUtf8DecoderSink extends ByteConversionSinkBase {
|
|||
_sink.close();
|
||||
}
|
||||
}
|
||||
|
||||
@patch
|
||||
int _scanOneByteCharacters(List<int> units, int from, int endIndex) {
|
||||
final to = endIndex;
|
||||
|
||||
// Special case for _Uint8ArrayView.
|
||||
final cid = ClassID.getID(units);
|
||||
if (identical(cid, ClassID.cidUint8ArrayView)) {
|
||||
if (from >= 0 && to >= 0 && to <= units.length) {
|
||||
for (int i = from; i < to; i++) {
|
||||
final unit = units[i];
|
||||
if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
|
||||
}
|
||||
return to - from;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall through to normal case.
|
||||
for (var i = from; i < to; i++) {
|
||||
final unit = units[i];
|
||||
if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
|
||||
}
|
||||
return to - from;
|
||||
}
|
||||
|
|
|
@ -222,6 +222,19 @@ abstract class _StringBase implements String {
|
|||
static String _createOneByteString(List<int> charCodes, int start, int len) {
|
||||
// It's always faster to do this in Dart than to call into the runtime.
|
||||
var s = _OneByteString._allocate(len);
|
||||
|
||||
// Special case for _Uint8ArrayView.
|
||||
final cid = ClassID.getID(charCodes);
|
||||
if (identical(cid, ClassID.cidUint8ArrayView)) {
|
||||
if (start >= 0 && len >= 0) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
s._setAt(i, charCodes[start + i]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall through to normal case.
|
||||
for (int i = 0; i < len; i++) {
|
||||
s._setAt(i, charCodes[start + i]);
|
||||
}
|
||||
|
|
|
@ -2692,6 +2692,22 @@ static bool InlineGrowableArraySetter(FlowGraph* flow_graph,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool InlineLoadClassId(FlowGraph* flow_graph,
|
||||
Instruction* call,
|
||||
GraphEntryInstr* graph_entry,
|
||||
FunctionEntryInstr** entry,
|
||||
Instruction** last) {
|
||||
*entry =
|
||||
new (Z) FunctionEntryInstr(graph_entry, flow_graph->allocate_block_id(),
|
||||
call->GetBlock()->try_index(), DeoptId::kNone);
|
||||
(*entry)->InheritDeoptTarget(Z, call);
|
||||
auto load_cid = new (Z)
|
||||
LoadClassIdInstr(call->PushArgumentAt(0)->value()->CopyWithType(Z));
|
||||
flow_graph->InsertBefore(call, load_cid, nullptr, FlowGraph::kValue);
|
||||
*last = load_cid;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Adds an explicit bounds check for a typed getter/setter.
|
||||
static void PrepareInlineTypedArrayBoundsCheck(FlowGraph* flow_graph,
|
||||
Instruction* call,
|
||||
|
@ -3605,6 +3621,8 @@ bool FlowGraphInliner::TryInlineRecognizedMethod(
|
|||
}
|
||||
return InlineGetIndexed(flow_graph, kind, call, receiver, graph_entry,
|
||||
entry, last, can_speculate);
|
||||
case MethodRecognizer::kClassIDgetID:
|
||||
return InlineLoadClassId(flow_graph, call, graph_entry, entry, last);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -3707,6 +3707,18 @@ void Class::InjectCIDFields() const {
|
|||
|
||||
CLASS_LIST_WITH_NULL(ADD_SET_FIELD)
|
||||
#undef ADD_SET_FIELD
|
||||
|
||||
#define ADD_SET_FIELD(clazz) \
|
||||
field_name = Symbols::New(thread, "cid" #clazz "View"); \
|
||||
field = Field::New(field_name, true, false, true, false, *this, \
|
||||
Type::Handle(Type::IntType()), TokenPosition::kMinSource, \
|
||||
TokenPosition::kMinSource); \
|
||||
value = Smi::New(kTypedData##clazz##ViewCid); \
|
||||
field.SetStaticValue(value, true); \
|
||||
AddField(field);
|
||||
|
||||
CLASS_LIST_TYPED_DATA(ADD_SET_FIELD)
|
||||
#undef ADD_SET_FIELD
|
||||
#undef CLASS_LIST_WITH_NULL
|
||||
}
|
||||
|
||||
|
|
|
@ -412,6 +412,7 @@ class ObjectPointerVisitor;
|
|||
V(_UserTag, "_UserTag") \
|
||||
V(Default, "Default") \
|
||||
V(ClassID, "ClassID") \
|
||||
V(getID, "getID") \
|
||||
V(DartIsVM, "dart.isVM") \
|
||||
V(stack, ":stack") \
|
||||
V(stack_pointer, ":stack_pointer") \
|
||||
|
|
|
@ -496,3 +496,13 @@ class Utf8Decoder {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@patch
|
||||
int _scanOneByteCharacters(List<int> units, int from, int endIndex) {
|
||||
final to = endIndex;
|
||||
for (var i = from; i < to; i++) {
|
||||
final unit = units[i];
|
||||
if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
|
||||
}
|
||||
return to - from;
|
||||
}
|
||||
|
|
|
@ -412,16 +412,6 @@ class _Utf8Decoder {
|
|||
_expectedUnits = 0;
|
||||
_extraUnits = 0;
|
||||
|
||||
int scanOneByteCharacters(List<int> units, int from) {
|
||||
final to = endIndex;
|
||||
final mask = _ONE_BYTE_LIMIT;
|
||||
for (var i = from; i < to; i++) {
|
||||
final unit = units[i];
|
||||
if ((unit & mask) != unit) return i - from;
|
||||
}
|
||||
return to - from;
|
||||
}
|
||||
|
||||
void addSingleBytes(int from, int to) {
|
||||
assert(from >= startIndex && from <= endIndex);
|
||||
assert(to >= startIndex && to <= endIndex);
|
||||
|
@ -484,7 +474,7 @@ class _Utf8Decoder {
|
|||
}
|
||||
|
||||
while (i < endIndex) {
|
||||
var oneBytes = scanOneByteCharacters(codeUnits, i);
|
||||
var oneBytes = _scanOneByteCharacters(codeUnits, i, endIndex);
|
||||
if (oneBytes > 0) {
|
||||
_isFirstCharacter = false;
|
||||
addSingleBytes(i, i + oneBytes);
|
||||
|
@ -545,3 +535,10 @@ class _Utf8Decoder {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the number of bytes in [units] starting at offset [from] which have
|
||||
// the leftmost bit set to 0.
|
||||
//
|
||||
// To increase performance of this critical method we have a special variant of
|
||||
// it implemented in the VM's patch files, which is why we make it external.
|
||||
external int _scanOneByteCharacters(List<int> units, int from, int endIndex);
|
||||
|
|
Loading…
Reference in a new issue