Reland "[vm] Replace array GetIndexed graph intrinsics with flow graph builder implementation"

This is a reland of commit d24b5d1f5e

On top of the original change, the following is fixed and improved:

1) Flow graph builder (FGB) body is now also applied to
   dynamic invocation forwarders (similarly to graph
   intrinsics).

2) Frame can be omitted for functions which have a
   call on a shared slow path. This is needed to make
   FGB implementation of GetIndexed frameless, as it has
   GenericCheckBound which calls on shared slow path.
   (Graph intrinsics are frameless).

3) Range analysis is enabled for force-optimized functions,
   so more efficient code can be generated for boxing
   instructions. Range analysis is fixed to avoid crashes
   and correctly intersect ranges with constant boundaries
   (needed for some force-optimized FFI functions).

4) EliminateStackOverflowChecks pass is enabled for
   force-optimized functions so CheckStackOverflow can be
   eliminated.

Original change's description:
> [vm] Replace array GetIndexed graph intrinsics with flow graph builder implementation
>
> _Array, _GrowableList, internal and external typed data 'operator []'
> are now implemented in the flow graph builder.
>
> Unlike graph intrinsics, flow graph created in the flow graph builder
> can be used by the inliner. Corresponding graph intrinsics and native
> methods are removed.
>
> Also, this change adds missing external typed data indexing operations.
>
> TEST=ci
>
> Change-Id: Ic19784481feadf54c096a587413e67b4e18353dc
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/359940
> Reviewed-by: Ryan Macnak <rmacnak@google.com>
> Commit-Queue: Alexander Markov <alexmarkov@google.com>

TEST=ci

Change-Id: I04ef008a04238d432683d7543cd047e35bad17c3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/360560
Reviewed-by: Tess Strickland <sstrickl@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2024-04-02 20:41:19 +00:00 committed by Commit Queue
parent df1361dded
commit 0af6dde79d
20 changed files with 519 additions and 355 deletions

View file

@ -16,15 +16,6 @@ DEFINE_NATIVE_ENTRY(List_allocate, 0, 2) {
return Object::null();
}
DEFINE_NATIVE_ENTRY(List_getIndexed, 0, 2) {
const Array& array = Array::CheckedHandle(zone, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Smi, index, arguments->NativeArgAt(1));
if ((index.Value() < 0) || (index.Value() >= array.Length())) {
Exceptions::ThrowRangeError("index", index, 0, array.Length() - 1);
}
return array.At(index.Value());
}
DEFINE_NATIVE_ENTRY(List_setIndexed, 0, 3) {
const Array& array = Array::CheckedHandle(zone, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Smi, index, arguments->NativeArgAt(1));

View file

@ -28,17 +28,6 @@ DEFINE_NATIVE_ENTRY(GrowableList_allocate, 0, 2) {
return new_array.ptr();
}
DEFINE_NATIVE_ENTRY(GrowableList_getIndexed, 0, 2) {
const GrowableObjectArray& array =
GrowableObjectArray::CheckedHandle(zone, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Smi, index, arguments->NativeArgAt(1));
if ((index.Value() < 0) || (index.Value() >= array.Length())) {
Exceptions::ThrowRangeError("index", index, 0, array.Length() - 1);
}
const Instance& obj = Instance::CheckedHandle(zone, array.At(index.Value()));
return obj.ptr();
}
DEFINE_NATIVE_ENTRY(GrowableList_setIndexed, 0, 3) {
const GrowableObjectArray& array =
GrowableObjectArray::CheckedHandle(zone, arguments->NativeArgAt(0));

View file

@ -119,7 +119,6 @@ namespace dart {
V(RegExp_ExecuteMatch, 3) \
V(RegExp_ExecuteMatchSticky, 3) \
V(List_allocate, 2) \
V(List_getIndexed, 2) \
V(List_setIndexed, 3) \
V(List_getLength, 1) \
V(List_slice, 4) \
@ -264,7 +263,6 @@ namespace dart {
V(Isolate_spawnFunction, 10) \
V(Isolate_spawnUri, 12) \
V(GrowableList_allocate, 2) \
V(GrowableList_getIndexed, 2) \
V(GrowableList_setIndexed, 3) \
V(GrowableList_getLength, 1) \
V(GrowableList_getCapacity, 1) \

View file

@ -3060,10 +3060,25 @@ void ThrowErrorSlowPathCode::EmitNativeCode(FlowGraphCompiler* compiler) {
__ Bind(entry_label());
EmitCodeAtSlowPathEntry(compiler);
LocationSummary* locs = instruction()->locs();
// Save registers as they are needed for lazy deopt / exception handling.
const bool has_frame = compiler->flow_graph().graph_entry()->NeedsFrame();
if (use_shared_stub) {
if (!has_frame) {
#if !defined(TARGET_ARCH_IA32)
ASSERT(__ constant_pool_allowed());
__ set_constant_pool_allowed(false);
#endif
__ EnterDartFrame(0);
}
EmitSharedStubCall(compiler, live_fpu_registers);
#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
if (!has_frame) {
// Undo EnterDartFrame for the code generated after this slow path.
RESTORES_LR_FROM_FRAME({});
}
#endif
} else {
ASSERT(has_frame);
// Save registers as they are needed for lazy deopt / exception handling.
compiler->SaveLiveRegisters(locs);
PushArgumentsForRuntimeCall(compiler);
__ CallRuntime(runtime_entry_, num_args);

View file

@ -3375,7 +3375,13 @@ class CheckStackOverflowSlowPath
compiler->SlowPathEnvironmentFor(instruction(), kNumSlowPathArgs);
compiler->pending_deoptimization_env_ = env;
const bool has_frame = compiler->flow_graph().graph_entry()->NeedsFrame();
if (using_shared_stub) {
if (!has_frame) {
ASSERT(__ constant_pool_allowed());
__ set_constant_pool_allowed(false);
__ EnterDartFrame(0);
}
const uword entry_point_offset = compiler::target::Thread::
stack_overflow_shared_stub_entry_point_offset(
instruction()->locs()->live_registers()->FpuRegisterCount() > 0);
@ -3385,7 +3391,12 @@ class CheckStackOverflowSlowPath
compiler->AddCurrentDescriptor(UntaggedPcDescriptors::kOther,
instruction()->deopt_id(),
instruction()->source());
if (!has_frame) {
__ LeaveDartFrame();
__ set_constant_pool_allowed(true);
}
} else {
ASSERT(has_frame);
__ CallRuntime(kInterruptOrStackOverflowRuntimeEntry, kNumSlowPathArgs);
compiler->EmitCallsiteMetadata(
instruction()->source(), instruction()->deopt_id(),
@ -3428,7 +3439,8 @@ void CheckStackOverflowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
? object_store->stack_overflow_stub_with_fpu_regs_stub()
: object_store->stack_overflow_stub_without_fpu_regs_stub());
const bool using_shared_stub = locs()->call_on_shared_slow_path();
if (using_shared_stub && compiler->CanPcRelativeCall(stub)) {
if (using_shared_stub && compiler->CanPcRelativeCall(stub) &&
compiler->flow_graph().graph_entry()->NeedsFrame()) {
__ GenerateUnRelocatedPcRelativeCall(LS);
compiler->AddPcRelativeCallStubTarget(stub);
@ -4540,6 +4552,12 @@ void BoxInt64Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
compiler->intrinsic_slow_path_label(),
compiler::Assembler::kNearJump, out_reg, tmp);
} else if (locs()->call_on_shared_slow_path()) {
const bool has_frame = compiler->flow_graph().graph_entry()->NeedsFrame();
if (!has_frame) {
ASSERT(__ constant_pool_allowed());
__ set_constant_pool_allowed(false);
__ EnterDartFrame(0);
}
auto object_store = compiler->isolate_group()->object_store();
const bool live_fpu_regs = locs()->live_registers()->FpuRegisterCount() > 0;
const auto& stub = Code::ZoneHandle(
@ -4552,6 +4570,10 @@ void BoxInt64Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
auto extended_env = compiler->SlowPathEnvironmentFor(this, 0);
compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
locs(), DeoptId::kNone, extended_env);
if (!has_frame) {
__ LeaveDartFrame();
__ set_constant_pool_allowed(true);
}
} else {
BoxAllocationSlowPath::Allocate(compiler, this, compiler->mint_class(),
out_reg, tmp);
@ -6290,7 +6312,8 @@ void CheckNullInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
NullErrorSlowPath::GetStub(compiler, exception_type(), live_fpu_regs));
const bool using_shared_stub = locs()->call_on_shared_slow_path();
if (using_shared_stub && compiler->CanPcRelativeCall(stub)) {
if (using_shared_stub && compiler->CanPcRelativeCall(stub) &&
compiler->flow_graph().graph_entry()->NeedsFrame()) {
__ GenerateUnRelocatedPcRelativeCall(EQUAL);
compiler->AddPcRelativeCallStubTarget(stub);

View file

@ -2935,7 +2935,13 @@ class CheckStackOverflowSlowPath
compiler->SlowPathEnvironmentFor(instruction(), kNumSlowPathArgs);
compiler->pending_deoptimization_env_ = env;
const bool has_frame = compiler->flow_graph().graph_entry()->NeedsFrame();
if (using_shared_stub) {
if (!has_frame) {
ASSERT(__ constant_pool_allowed());
__ set_constant_pool_allowed(false);
__ EnterDartFrame(0);
}
auto object_store = compiler->isolate_group()->object_store();
const bool live_fpu_regs = locs->live_registers()->FpuRegisterCount() > 0;
const auto& stub = Code::ZoneHandle(
@ -2944,7 +2950,7 @@ class CheckStackOverflowSlowPath
? object_store->stack_overflow_stub_with_fpu_regs_stub()
: object_store->stack_overflow_stub_without_fpu_regs_stub());
if (using_shared_stub && compiler->CanPcRelativeCall(stub)) {
if (compiler->CanPcRelativeCall(stub)) {
__ GenerateUnRelocatedPcRelativeCall();
compiler->AddPcRelativeCallStubTarget(stub);
} else {
@ -2958,7 +2964,12 @@ class CheckStackOverflowSlowPath
compiler->AddCurrentDescriptor(UntaggedPcDescriptors::kOther,
instruction()->deopt_id(),
instruction()->source());
if (!has_frame) {
__ LeaveDartFrame();
__ set_constant_pool_allowed(true);
}
} else {
ASSERT(has_frame);
__ CallRuntime(kInterruptOrStackOverflowRuntimeEntry, kNumSlowPathArgs);
compiler->EmitCallsiteMetadata(
instruction()->source(), instruction()->deopt_id(),
@ -3775,6 +3786,12 @@ void BoxInt64Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
compiler->intrinsic_slow_path_label(),
compiler::Assembler::kNearJump, out, temp);
} else if (locs()->call_on_shared_slow_path()) {
const bool has_frame = compiler->flow_graph().graph_entry()->NeedsFrame();
if (!has_frame) {
ASSERT(__ constant_pool_allowed());
__ set_constant_pool_allowed(false);
__ EnterDartFrame(0);
}
auto object_store = compiler->isolate_group()->object_store();
const bool live_fpu_regs = locs()->live_registers()->FpuRegisterCount() > 0;
const auto& stub = Code::ZoneHandle(
@ -3787,6 +3804,10 @@ void BoxInt64Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
auto extended_env = compiler->SlowPathEnvironmentFor(this, 0);
compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
locs(), DeoptId::kNone, extended_env);
if (!has_frame) {
__ LeaveDartFrame();
__ set_constant_pool_allowed(true);
}
} else {
BoxAllocationSlowPath::Allocate(compiler, this, compiler->mint_class(), out,
temp);

View file

@ -3182,7 +3182,13 @@ class CheckStackOverflowSlowPath
compiler->SlowPathEnvironmentFor(instruction(), kNumSlowPathArgs);
compiler->pending_deoptimization_env_ = env;
const bool has_frame = compiler->flow_graph().graph_entry()->NeedsFrame();
if (using_shared_stub) {
if (!has_frame) {
ASSERT(__ constant_pool_allowed());
__ set_constant_pool_allowed(false);
__ EnterDartFrame(0);
}
auto object_store = compiler->isolate_group()->object_store();
const bool live_fpu_regs = locs->live_registers()->FpuRegisterCount() > 0;
const auto& stub = Code::ZoneHandle(
@ -3191,7 +3197,7 @@ class CheckStackOverflowSlowPath
? object_store->stack_overflow_stub_with_fpu_regs_stub()
: object_store->stack_overflow_stub_without_fpu_regs_stub());
if (using_shared_stub && compiler->CanPcRelativeCall(stub)) {
if (compiler->CanPcRelativeCall(stub)) {
__ GenerateUnRelocatedPcRelativeCall();
compiler->AddPcRelativeCallStubTarget(stub);
} else {
@ -3205,7 +3211,12 @@ class CheckStackOverflowSlowPath
compiler->AddCurrentDescriptor(UntaggedPcDescriptors::kOther,
instruction()->deopt_id(),
instruction()->source());
if (!has_frame) {
__ LeaveDartFrame();
__ set_constant_pool_allowed(true);
}
} else {
ASSERT(has_frame);
__ CallRuntime(kInterruptOrStackOverflowRuntimeEntry, kNumSlowPathArgs);
compiler->EmitCallsiteMetadata(
instruction()->source(), instruction()->deopt_id(),
@ -4140,6 +4151,12 @@ void BoxInt64Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
compiler->intrinsic_slow_path_label(),
compiler::Assembler::kNearJump, out_reg, TMP);
} else if (locs()->call_on_shared_slow_path()) {
const bool has_frame = compiler->flow_graph().graph_entry()->NeedsFrame();
if (!has_frame) {
ASSERT(__ constant_pool_allowed());
__ set_constant_pool_allowed(false);
__ EnterDartFrame(0);
}
auto object_store = compiler->isolate_group()->object_store();
const bool live_fpu_regs = locs()->live_registers()->FpuRegisterCount() > 0;
const auto& stub = Code::ZoneHandle(
@ -4152,6 +4169,10 @@ void BoxInt64Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
auto extended_env = compiler->SlowPathEnvironmentFor(this, 0);
compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
locs(), DeoptId::kNone, extended_env);
if (!has_frame) {
__ LeaveDartFrame();
__ set_constant_pool_allowed(true);
}
} else {
BoxAllocationSlowPath::Allocate(compiler, this, compiler->mint_class(),
out_reg, TMP);

View file

@ -2964,7 +2964,13 @@ class CheckStackOverflowSlowPath
compiler->SlowPathEnvironmentFor(instruction(), kNumSlowPathArgs);
compiler->pending_deoptimization_env_ = env;
const bool has_frame = compiler->flow_graph().graph_entry()->NeedsFrame();
if (using_shared_stub) {
if (!has_frame) {
ASSERT(__ constant_pool_allowed());
__ set_constant_pool_allowed(false);
__ EnterDartFrame(0);
}
const uword entry_point_offset =
Thread::stack_overflow_shared_stub_entry_point_offset(
instruction()->locs()->live_registers()->FpuRegisterCount() > 0);
@ -2974,7 +2980,12 @@ class CheckStackOverflowSlowPath
compiler->AddCurrentDescriptor(UntaggedPcDescriptors::kOther,
instruction()->deopt_id(),
instruction()->source());
if (!has_frame) {
__ LeaveDartFrame();
__ set_constant_pool_allowed(true);
}
} else {
ASSERT(has_frame);
__ CallRuntime(kInterruptOrStackOverflowRuntimeEntry, kNumSlowPathArgs);
compiler->EmitCallsiteMetadata(
instruction()->source(), instruction()->deopt_id(),
@ -4103,6 +4114,12 @@ void BoxInt64Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
compiler->intrinsic_slow_path_label(),
compiler::Assembler::kNearJump, out, temp);
} else if (locs()->call_on_shared_slow_path()) {
const bool has_frame = compiler->flow_graph().graph_entry()->NeedsFrame();
if (!has_frame) {
ASSERT(__ constant_pool_allowed());
__ set_constant_pool_allowed(false);
__ EnterDartFrame(0);
}
auto object_store = compiler->isolate_group()->object_store();
const bool live_fpu_regs = locs()->live_registers()->FpuRegisterCount() > 0;
const auto& stub = Code::ZoneHandle(
@ -4115,6 +4132,10 @@ void BoxInt64Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
auto extended_env = compiler->SlowPathEnvironmentFor(this, 0);
compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
locs(), DeoptId::kNone, extended_env);
if (!has_frame) {
__ LeaveDartFrame();
__ set_constant_pool_allowed(true);
}
} else {
BoxAllocationSlowPath::Allocate(compiler, this, compiler->mint_class(), out,
temp);

View file

@ -3258,11 +3258,21 @@ void FlowGraphAllocator::RemoveFrameIfNotNeeded() {
#if defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_ARM)
bool has_write_barrier_call = false;
#endif
intptr_t num_calls_on_shared_slow_path = 0;
for (auto block : block_order_) {
for (auto instruction : block->instructions()) {
if (instruction->HasLocs() && instruction->locs()->can_call()) {
// Function contains a call and thus needs a frame.
return;
if (!instruction->locs()->call_on_shared_slow_path()) {
// Function contains a call and thus needs a frame.
return;
}
// For calls on shared slow paths the frame can be created on
// a slow path around the call. Only allow one call on a shared
// slow path to avoid extra code size.
++num_calls_on_shared_slow_path;
if (num_calls_on_shared_slow_path > 1) {
return;
}
}
// Some instructions contain write barriers inside, which can call

View file

@ -2054,6 +2054,10 @@ RangeBoundary RangeBoundary::IntersectionMin(RangeBoundary a, RangeBoundary b) {
return a;
}
if (a.IsConstant() && b.IsConstant()) {
return RangeBoundary(Utils::Maximum(a.ConstantValue(), b.ConstantValue()));
}
if (a.IsMinimumOrBelow(RangeBoundary::kRangeBoundarySmi)) {
return b;
} else if (b.IsMinimumOrBelow(RangeBoundary::kRangeBoundarySmi)) {
@ -2079,6 +2083,10 @@ RangeBoundary RangeBoundary::IntersectionMax(RangeBoundary a, RangeBoundary b) {
return a;
}
if (a.IsConstant() && b.IsConstant()) {
return RangeBoundary(Utils::Minimum(a.ConstantValue(), b.ConstantValue()));
}
if (a.IsMaximumOrAbove(RangeBoundary::kRangeBoundarySmi)) {
return b;
} else if (b.IsMaximumOrAbove(RangeBoundary::kRangeBoundarySmi)) {

View file

@ -320,6 +320,7 @@ FlowGraph* CompilerPass::RunForceOptimizedPipeline(
INVOKE_PASS(SelectRepresentations_Final);
INVOKE_PASS(CSE);
INVOKE_PASS(TypePropagation);
INVOKE_PASS(RangeAnalysis);
INVOKE_PASS(TryCatchOptimization);
INVOKE_PASS(EliminateEnvironments);
INVOKE_PASS(EliminateDeadPhis);
@ -328,6 +329,7 @@ FlowGraph* CompilerPass::RunForceOptimizedPipeline(
INVOKE_PASS(DCE);
INVOKE_PASS(Canonicalize);
INVOKE_PASS_AOT(DelayAllocations);
INVOKE_PASS(EliminateStackOverflowChecks);
INVOKE_PASS(EliminateWriteBarriers);
// This must be done after all other possible intra-block code motion.
INVOKE_PASS(LoweringAfterCodeMotionDisabled);

View file

@ -868,6 +868,39 @@ Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function,
return body;
}
static bool CanUnboxElements(classid_t cid) {
switch (RepresentationUtils::RepresentationOfArrayElement(cid)) {
case kUnboxedFloat:
case kUnboxedDouble:
return FlowGraphCompiler::SupportsUnboxedDoubles();
case kUnboxedInt32x4:
case kUnboxedFloat32x4:
case kUnboxedFloat64x2:
return FlowGraphCompiler::SupportsUnboxedSimd128();
default:
return true;
}
}
const Function& TypedListGetNativeFunction(Thread* thread, classid_t cid) {
auto& state = thread->compiler_state();
switch (RepresentationUtils::RepresentationOfArrayElement(cid)) {
case kUnboxedFloat:
return state.TypedListGetFloat32();
case kUnboxedDouble:
return state.TypedListGetFloat64();
case kUnboxedInt32x4:
return state.TypedListGetInt32x4();
case kUnboxedFloat32x4:
return state.TypedListGetFloat32x4();
case kUnboxedFloat64x2:
return state.TypedListGetFloat64x2();
default:
UNREACHABLE();
return Object::null_function();
}
}
#define LOAD_NATIVE_FIELD(V) \
V(ByteDataViewLength, TypedDataBase_length) \
V(ByteDataViewOffsetInBytes, TypedDataView_offset_in_bytes) \
@ -928,6 +961,36 @@ bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph(
const MethodRecognizer::Kind kind = function.recognized_kind();
switch (kind) {
case MethodRecognizer::kObjectArrayGetIndexed:
case MethodRecognizer::kGrowableArrayGetIndexed:
case MethodRecognizer::kInt8ArrayGetIndexed:
case MethodRecognizer::kExternalInt8ArrayGetIndexed:
case MethodRecognizer::kUint8ArrayGetIndexed:
case MethodRecognizer::kExternalUint8ArrayGetIndexed:
case MethodRecognizer::kUint8ClampedArrayGetIndexed:
case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
case MethodRecognizer::kInt16ArrayGetIndexed:
case MethodRecognizer::kExternalInt16ArrayGetIndexed:
case MethodRecognizer::kUint16ArrayGetIndexed:
case MethodRecognizer::kExternalUint16ArrayGetIndexed:
case MethodRecognizer::kInt32ArrayGetIndexed:
case MethodRecognizer::kExternalInt32ArrayGetIndexed:
case MethodRecognizer::kUint32ArrayGetIndexed:
case MethodRecognizer::kExternalUint32ArrayGetIndexed:
case MethodRecognizer::kInt64ArrayGetIndexed:
case MethodRecognizer::kExternalInt64ArrayGetIndexed:
case MethodRecognizer::kUint64ArrayGetIndexed:
case MethodRecognizer::kExternalUint64ArrayGetIndexed:
case MethodRecognizer::kFloat32ArrayGetIndexed:
case MethodRecognizer::kExternalFloat32ArrayGetIndexed:
case MethodRecognizer::kFloat64ArrayGetIndexed:
case MethodRecognizer::kExternalFloat64ArrayGetIndexed:
case MethodRecognizer::kFloat32x4ArrayGetIndexed:
case MethodRecognizer::kExternalFloat32x4ArrayGetIndexed:
case MethodRecognizer::kFloat64x2ArrayGetIndexed:
case MethodRecognizer::kExternalFloat64x2ArrayGetIndexed:
case MethodRecognizer::kInt32x4ArrayGetIndexed:
case MethodRecognizer::kExternalInt32x4ArrayGetIndexed:
case MethodRecognizer::kRecord_fieldAt:
case MethodRecognizer::kRecord_fieldNames:
case MethodRecognizer::kRecord_numFields:
@ -1143,8 +1206,88 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
Fragment body(instruction_cursor);
body += CheckStackOverflowInPrologue(function.token_pos());
if (function.IsDynamicInvocationForwarder()) {
body += BuildDefaultTypeHandling(function);
BuildTypeArgumentTypeChecks(
TypeChecksToBuild::kCheckNonCovariantTypeParameterBounds, &body);
BuildArgumentTypeChecks(&body, &body, nullptr);
}
const MethodRecognizer::Kind kind = function.recognized_kind();
switch (kind) {
case MethodRecognizer::kObjectArrayGetIndexed:
case MethodRecognizer::kGrowableArrayGetIndexed:
case MethodRecognizer::kInt8ArrayGetIndexed:
case MethodRecognizer::kExternalInt8ArrayGetIndexed:
case MethodRecognizer::kUint8ArrayGetIndexed:
case MethodRecognizer::kExternalUint8ArrayGetIndexed:
case MethodRecognizer::kUint8ClampedArrayGetIndexed:
case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
case MethodRecognizer::kInt16ArrayGetIndexed:
case MethodRecognizer::kExternalInt16ArrayGetIndexed:
case MethodRecognizer::kUint16ArrayGetIndexed:
case MethodRecognizer::kExternalUint16ArrayGetIndexed:
case MethodRecognizer::kInt32ArrayGetIndexed:
case MethodRecognizer::kExternalInt32ArrayGetIndexed:
case MethodRecognizer::kUint32ArrayGetIndexed:
case MethodRecognizer::kExternalUint32ArrayGetIndexed:
case MethodRecognizer::kInt64ArrayGetIndexed:
case MethodRecognizer::kExternalInt64ArrayGetIndexed:
case MethodRecognizer::kUint64ArrayGetIndexed:
case MethodRecognizer::kExternalUint64ArrayGetIndexed:
case MethodRecognizer::kFloat32ArrayGetIndexed:
case MethodRecognizer::kExternalFloat32ArrayGetIndexed:
case MethodRecognizer::kFloat64ArrayGetIndexed:
case MethodRecognizer::kExternalFloat64ArrayGetIndexed:
case MethodRecognizer::kFloat32x4ArrayGetIndexed:
case MethodRecognizer::kExternalFloat32x4ArrayGetIndexed:
case MethodRecognizer::kFloat64x2ArrayGetIndexed:
case MethodRecognizer::kExternalFloat64x2ArrayGetIndexed:
case MethodRecognizer::kInt32x4ArrayGetIndexed:
case MethodRecognizer::kExternalInt32x4ArrayGetIndexed: {
ASSERT_EQUAL(function.NumParameters(), 2);
intptr_t array_cid = MethodRecognizer::MethodKindToReceiverCid(kind);
const Representation elem_rep =
RepresentationUtils::RepresentationOfArrayElement(array_cid);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::GetLengthFieldForArrayCid(array_cid));
body += LoadLocal(parsed_function_->RawParameterVariable(1));
body += GenericCheckBound();
LocalVariable* safe_index = MakeTemporary();
body += LoadLocal(parsed_function_->RawParameterVariable(0));
if (IsTypedDataBaseClassId(array_cid) && !CanUnboxElements(array_cid)) {
const auto& native_function =
TypedListGetNativeFunction(thread_, array_cid);
body += LoadLocal(safe_index);
body += UnboxTruncate(kUnboxedIntPtr);
body += IntConstant(Utils::ShiftForPowerOfTwo(
RepresentationUtils::ValueSize(elem_rep)));
body += BinaryIntegerOp(Token::kSHL, kUnboxedIntPtr,
/*is_truncating=*/true);
body += StaticCall(TokenPosition::kNoSource, native_function, 2,
ICData::kNoRebind);
} else {
if (kind == MethodRecognizer::kGrowableArrayGetIndexed) {
body += LoadNativeField(Slot::GrowableObjectArray_data());
array_cid = kArrayCid;
} else if (IsExternalTypedDataClassId(array_cid)) {
body += LoadNativeField(Slot::PointerBase_data(),
InnerPointerAccess::kCannotBeInnerPointer);
}
body += LoadLocal(safe_index);
body +=
LoadIndexed(array_cid,
/*index_scale=*/
compiler::target::Instance::ElementSizeFor(array_cid),
/*index_unboxed=*/
GenericCheckBoundInstr::UseUnboxedRepresentation());
if (elem_rep == kUnboxedFloat) {
body += FloatToDouble();
}
}
body += DropTempsPreserveTop(1); // Drop [safe_index], keep result.
break;
}
case MethodRecognizer::kRecord_fieldAt:
ASSERT_EQUAL(function.NumParameters(), 2);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
@ -1959,40 +2102,6 @@ Fragment FlowGraphBuilder::BuildTypedDataViewFactoryConstructor(
return body;
}
static bool CanUnboxElements(classid_t cid) {
switch (RepresentationUtils::RepresentationOfArrayElement(cid)) {
case kUnboxedFloat:
case kUnboxedDouble:
return FlowGraphCompiler::SupportsUnboxedDoubles();
case kUnboxedInt32x4:
case kUnboxedFloat32x4:
case kUnboxedFloat64x2:
return FlowGraphCompiler::SupportsUnboxedSimd128();
default:
return true;
}
}
static const Function& TypedListGetNativeFunction(Thread* thread,
classid_t cid) {
auto& state = thread->compiler_state();
switch (RepresentationUtils::RepresentationOfArrayElement(cid)) {
case kUnboxedFloat:
return state.TypedListGetFloat32();
case kUnboxedDouble:
return state.TypedListGetFloat64();
case kUnboxedInt32x4:
return state.TypedListGetInt32x4();
case kUnboxedFloat32x4:
return state.TypedListGetFloat32x4();
case kUnboxedFloat64x2:
return state.TypedListGetFloat64x2();
default:
UNREACHABLE();
return Object::null_function();
}
}
Fragment FlowGraphBuilder::BuildTypedListGet(const Function& function,
classid_t cid) {
const intptr_t kNumParameters = 2;
@ -4380,6 +4489,9 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfDynamicInvocationForwarder(
if (target.IsMethodExtractor()) {
return BuildGraphOfMethodExtractor(target);
}
if (FlowGraphBuilder::IsRecognizedMethodForFlowGraph(function)) {
return BuildGraphOfRecognizedMethod(function);
}
graph_entry_ = new (Z) GraphEntryInstr(*parsed_function_, osr_id_);

View file

@ -361,6 +361,12 @@ ScopeBuildingResult* ScopeBuilder::BuildScopes() {
const auto& target = Function::ZoneHandle(Z, function.ForwardingTarget());
ASSERT(!target.IsNull());
if (FlowGraphBuilder::IsRecognizedMethodForFlowGraph(function) &&
FlowGraphBuilder::IsExpressionTempVarUsedInRecognizedMethodFlowGraph(
function)) {
needs_expr_temp_ = true;
}
if (helper_.PeekTag() == kField) {
// Create [this] variable.
const Class& klass = Class::Handle(Z, function.Owner());

View file

@ -215,55 +215,6 @@ static Definition* CreateUnboxedResultIfNeeded(BlockBuilder* builder,
}
}
static bool IntrinsifyArrayGetIndexed(FlowGraph* flow_graph,
intptr_t array_cid) {
GraphEntryInstr* graph_entry = flow_graph->graph_entry();
auto normal_entry = graph_entry->normal_entry();
BlockBuilder builder(flow_graph, normal_entry, /*with_frame=*/false);
Definition* array = builder.AddParameter(0);
Definition* index = builder.AddParameter(1);
VerifyParameterIsBoxed(&builder, 0);
index = CreateBoxedParameterIfNeeded(&builder, index, kUnboxedInt64, 1);
index = PrepareIndexedOp(flow_graph, &builder, array, index,
Slot::GetLengthFieldForArrayCid(array_cid));
if (IsExternalTypedDataClassId(array_cid)) {
array = builder.AddDefinition(new LoadFieldInstr(
new Value(array), Slot::PointerBase_data(),
InnerPointerAccess::kCannotBeInnerPointer, builder.Source()));
}
Definition* result = builder.AddDefinition(new LoadIndexedInstr(
new Value(array), new Value(index), /*index_unboxed=*/false,
/*index_scale=*/target::Instance::ElementSizeFor(array_cid), array_cid,
kAlignedAccess, DeoptId::kNone, builder.Source()));
// We don't perform [RangeAnalysis] for graph intrinsics. To inform the
// following boxing instruction about a more precise range we attach it here
// manually.
// http://dartbug.com/36632
auto const rep = RepresentationUtils::RepresentationOfArrayElement(array_cid);
if (RepresentationUtils::IsUnboxedInteger(rep)) {
result->set_range(Range::Full(rep));
}
const bool clear_environment =
RangeUtils::Fits(result->range(), RangeBoundary::kRangeBoundarySmi);
// Box and/or convert result if necessary.
if (RepresentationUtils::IsUnboxed(rep)) {
result = CreateBoxedResultIfNeeded(&builder, result, rep);
}
if (result->IsBoxInteger() && clear_environment) {
result->AsBoxInteger()->ClearEnv();
}
result = CreateUnboxedResultIfNeeded(&builder, result);
builder.AddReturn(new Value(result));
return true;
}
static bool IntrinsifyArraySetIndexed(FlowGraph* flow_graph,
intptr_t array_cid) {
GraphEntryInstr* graph_entry = flow_graph->graph_entry();
@ -326,14 +277,6 @@ static bool IntrinsifyArraySetIndexed(FlowGraph* flow_graph,
return true;
}
#define DEFINE_ARRAY_GETTER_INTRINSIC(enum_name) \
bool GraphIntrinsifier::Build_##enum_name##GetIndexed( \
FlowGraph* flow_graph) { \
return IntrinsifyArrayGetIndexed( \
flow_graph, MethodRecognizer::MethodKindToReceiverCid( \
MethodRecognizer::k##enum_name##GetIndexed)); \
}
#define DEFINE_ARRAY_SETTER_INTRINSIC(enum_name) \
bool GraphIntrinsifier::Build_##enum_name##SetIndexed( \
FlowGraph* flow_graph) { \
@ -342,39 +285,20 @@ static bool IntrinsifyArraySetIndexed(FlowGraph* flow_graph,
MethodRecognizer::k##enum_name##SetIndexed)); \
}
DEFINE_ARRAY_GETTER_INTRINSIC(ObjectArray)
DEFINE_ARRAY_SETTER_INTRINSIC(Int8Array)
DEFINE_ARRAY_SETTER_INTRINSIC(Uint8Array)
DEFINE_ARRAY_SETTER_INTRINSIC(ExternalUint8Array)
DEFINE_ARRAY_SETTER_INTRINSIC(Uint8ClampedArray)
DEFINE_ARRAY_SETTER_INTRINSIC(ExternalUint8ClampedArray)
DEFINE_ARRAY_SETTER_INTRINSIC(Int16Array)
DEFINE_ARRAY_SETTER_INTRINSIC(Uint16Array)
DEFINE_ARRAY_SETTER_INTRINSIC(Int32Array)
DEFINE_ARRAY_SETTER_INTRINSIC(Uint32Array)
DEFINE_ARRAY_SETTER_INTRINSIC(Int64Array)
DEFINE_ARRAY_SETTER_INTRINSIC(Uint64Array)
#define DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(enum_name) \
DEFINE_ARRAY_GETTER_INTRINSIC(enum_name) \
DEFINE_ARRAY_SETTER_INTRINSIC(enum_name)
DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int8Array)
DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint8Array)
DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(ExternalUint8Array)
DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint8ClampedArray)
DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(ExternalUint8ClampedArray)
DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int16Array)
DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint16Array)
DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int32Array)
DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint32Array)
DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int64Array)
DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint64Array)
#undef DEFINE_ARRAY_GETTER_SETTER_INTRINSICS
#undef DEFINE_ARRAY_GETTER_INTRINSIC
#undef DEFINE_ARRAY_SETTER_INTRINSIC
#define DEFINE_FLOAT_ARRAY_GETTER_INTRINSIC(enum_name) \
bool GraphIntrinsifier::Build_##enum_name##GetIndexed( \
FlowGraph* flow_graph) { \
if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { \
return false; \
} \
return IntrinsifyArrayGetIndexed( \
flow_graph, MethodRecognizer::MethodKindToReceiverCid( \
MethodRecognizer::k##enum_name##GetIndexed)); \
}
#define DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC(enum_name) \
bool GraphIntrinsifier::Build_##enum_name##SetIndexed( \
FlowGraph* flow_graph) { \
@ -386,28 +310,11 @@ DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint64Array)
MethodRecognizer::k##enum_name##SetIndexed)); \
}
#define DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(enum_name) \
DEFINE_FLOAT_ARRAY_GETTER_INTRINSIC(enum_name) \
DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC(enum_name)
DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC(Float64Array)
DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC(Float32Array)
DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(Float64Array)
DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(Float32Array)
#undef DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS
#undef DEFINE_FLOAT_ARRAY_GETTER_INTRINSIC
#undef DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC
#define DEFINE_SIMD_ARRAY_GETTER_INTRINSIC(enum_name) \
bool GraphIntrinsifier::Build_##enum_name##GetIndexed( \
FlowGraph* flow_graph) { \
if (!FlowGraphCompiler::SupportsUnboxedSimd128()) { \
return false; \
} \
return IntrinsifyArrayGetIndexed( \
flow_graph, MethodRecognizer::MethodKindToReceiverCid( \
MethodRecognizer::k##enum_name##GetIndexed)); \
}
#define DEFINE_SIMD_ARRAY_SETTER_INTRINSIC(enum_name) \
bool GraphIntrinsifier::Build_##enum_name##SetIndexed( \
FlowGraph* flow_graph) { \
@ -419,16 +326,10 @@ DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(Float32Array)
MethodRecognizer::k##enum_name##SetIndexed)); \
}
#define DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS(enum_name) \
DEFINE_SIMD_ARRAY_GETTER_INTRINSIC(enum_name) \
DEFINE_SIMD_ARRAY_SETTER_INTRINSIC(enum_name)
DEFINE_SIMD_ARRAY_SETTER_INTRINSIC(Float32x4Array)
DEFINE_SIMD_ARRAY_SETTER_INTRINSIC(Int32x4Array)
DEFINE_SIMD_ARRAY_SETTER_INTRINSIC(Float64x2Array)
DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS(Float32x4Array)
DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS(Int32x4Array)
DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS(Float64x2Array)
#undef DEFINE_SIMD_ARRAY_GETTER_SETTER_INTRINSICS
#undef DEFINE_SIMD_ARRAY_GETTER_INTRINSIC
#undef DEFINE_SIMD_ARRAY_SETTER_INTRINSIC
static bool BuildSimdOp(FlowGraph* flow_graph, intptr_t cid, Token::Kind kind) {
@ -596,32 +497,6 @@ bool GraphIntrinsifier::Build_GrowableArrayCapacity(FlowGraph* flow_graph) {
return true;
}
bool GraphIntrinsifier::Build_GrowableArrayGetIndexed(FlowGraph* flow_graph) {
GraphEntryInstr* graph_entry = flow_graph->graph_entry();
auto normal_entry = graph_entry->normal_entry();
BlockBuilder builder(flow_graph, normal_entry, /*with_frame=*/false);
Definition* growable_array = builder.AddParameter(0);
Definition* index = builder.AddParameter(1);
VerifyParameterIsBoxed(&builder, 0);
index = CreateBoxedParameterIfNeeded(&builder, index, kUnboxedInt64, 1);
index = PrepareIndexedOp(flow_graph, &builder, growable_array, index,
Slot::GrowableObjectArray_length());
Definition* backing_store = builder.AddDefinition(
new LoadFieldInstr(new Value(growable_array),
Slot::GrowableObjectArray_data(), builder.Source()));
Definition* result = builder.AddDefinition(new LoadIndexedInstr(
new Value(backing_store), new Value(index), /*index_unboxed=*/false,
/*index_scale=*/target::Instance::ElementSizeFor(kArrayCid), kArrayCid,
kAlignedAccess, DeoptId::kNone, builder.Source()));
result = CreateUnboxedResultIfNeeded(&builder, result);
builder.AddReturn(new Value(result));
return true;
}
bool GraphIntrinsifier::Build_ObjectArraySetIndexedUnchecked(
FlowGraph* flow_graph) {
GraphEntryInstr* graph_entry = flow_graph->graph_entry();

View file

@ -108,14 +108,23 @@ intptr_t MethodRecognizer::MethodKindToReceiverCid(Kind kind) {
case kFloat32ArraySetIndexed:
return kTypedDataFloat32ArrayCid;
case kExternalFloat32ArrayGetIndexed:
return kExternalTypedDataFloat32ArrayCid;
case kFloat64ArrayGetIndexed:
case kFloat64ArraySetIndexed:
return kTypedDataFloat64ArrayCid;
case kExternalFloat64ArrayGetIndexed:
return kExternalTypedDataFloat64ArrayCid;
case kInt8ArrayGetIndexed:
case kInt8ArraySetIndexed:
return kTypedDataInt8ArrayCid;
case kExternalInt8ArrayGetIndexed:
return kExternalTypedDataInt8ArrayCid;
case kUint8ArrayGetIndexed:
case kUint8ArraySetIndexed:
return kTypedDataUint8ArrayCid;
@ -136,38 +145,65 @@ intptr_t MethodRecognizer::MethodKindToReceiverCid(Kind kind) {
case kInt16ArraySetIndexed:
return kTypedDataInt16ArrayCid;
case kExternalInt16ArrayGetIndexed:
return kExternalTypedDataInt16ArrayCid;
case kUint16ArrayGetIndexed:
case kUint16ArraySetIndexed:
return kTypedDataUint16ArrayCid;
case kExternalUint16ArrayGetIndexed:
return kExternalTypedDataUint16ArrayCid;
case kInt32ArrayGetIndexed:
case kInt32ArraySetIndexed:
return kTypedDataInt32ArrayCid;
case kExternalInt32ArrayGetIndexed:
return kExternalTypedDataInt32ArrayCid;
case kUint32ArrayGetIndexed:
case kUint32ArraySetIndexed:
return kTypedDataUint32ArrayCid;
case kExternalUint32ArrayGetIndexed:
return kExternalTypedDataUint32ArrayCid;
case kInt64ArrayGetIndexed:
case kInt64ArraySetIndexed:
return kTypedDataInt64ArrayCid;
case kExternalInt64ArrayGetIndexed:
return kExternalTypedDataInt64ArrayCid;
case kUint64ArrayGetIndexed:
case kUint64ArraySetIndexed:
return kTypedDataUint64ArrayCid;
case kExternalUint64ArrayGetIndexed:
return kExternalTypedDataUint64ArrayCid;
case kFloat32x4ArrayGetIndexed:
case kFloat32x4ArraySetIndexed:
return kTypedDataFloat32x4ArrayCid;
case kExternalFloat32x4ArrayGetIndexed:
return kExternalTypedDataFloat32x4ArrayCid;
case kInt32x4ArrayGetIndexed:
case kInt32x4ArraySetIndexed:
return kTypedDataInt32x4ArrayCid;
case kExternalInt32x4ArrayGetIndexed:
return kExternalTypedDataInt32x4ArrayCid;
case kFloat64x2ArrayGetIndexed:
case kFloat64x2ArraySetIndexed:
return kTypedDataFloat64x2ArrayCid;
case kExternalFloat64x2ArrayGetIndexed:
return kExternalTypedDataFloat64x2ArrayCid;
default:
break;
}

View file

@ -15,6 +15,37 @@ namespace dart {
V(::, identical, ObjectIdentical, 0x0407f735) \
V(ClassID, getID, ClassIDgetID, 0xdc7cfcaa) \
V(Object, Object., ObjectConstructor, 0xab6d6cfa) \
V(_Array, [], ObjectArrayGetIndexed, 0x78e66c72) \
V(_GrowableList, [], GrowableArrayGetIndexed, 0x78e66c72) \
V(_Int8List, [], Int8ArrayGetIndexed, 0x2321c262) \
V(_ExternalInt8Array, [], ExternalInt8ArrayGetIndexed, 0x2321c262) \
V(_Uint8List, [], Uint8ArrayGetIndexed, 0x2321c262) \
V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 0x2321c262) \
V(_Uint8ClampedList, [], Uint8ClampedArrayGetIndexed, 0x2321c262) \
V(_ExternalUint8ClampedArray, [], ExternalUint8ClampedArrayGetIndexed, \
0x2321c262) \
V(_Int16List, [], Int16ArrayGetIndexed, 0x2321c262) \
V(_ExternalInt16Array, [], ExternalInt16ArrayGetIndexed, 0x2321c262) \
V(_Uint16List, [], Uint16ArrayGetIndexed, 0x2321c262) \
V(_ExternalUint16Array, [], ExternalUint16ArrayGetIndexed, 0x2321c262) \
V(_Int32List, [], Int32ArrayGetIndexed, 0x2321bea1) \
V(_ExternalInt32Array, [], ExternalInt32ArrayGetIndexed, 0x2321bea1) \
V(_Uint32List, [], Uint32ArrayGetIndexed, 0x2321bea1) \
V(_ExternalUint32Array, [], ExternalUint32ArrayGetIndexed, 0x2321bea1) \
V(_Int64List, [], Int64ArrayGetIndexed, 0x2321bea1) \
V(_ExternalInt64Array, [], ExternalInt64ArrayGetIndexed, 0x2321bea1) \
V(_Uint64List, [], Uint64ArrayGetIndexed, 0x2321bea1) \
V(_ExternalUint64Array, [], ExternalUint64ArrayGetIndexed, 0x2321bea1) \
V(_Float32List, [], Float32ArrayGetIndexed, 0x0784da3c) \
V(_ExternalFloat32Array, [], ExternalFloat32ArrayGetIndexed, 0x0784da3c) \
V(_Float64List, [], Float64ArrayGetIndexed, 0x0784da3c) \
V(_ExternalFloat64Array, [], ExternalFloat64ArrayGetIndexed, 0x0784da3c) \
V(_Float32x4List, [], Float32x4ArrayGetIndexed, 0xb0f79623) \
V(_ExternalFloat32x4Array, [], ExternalFloat32x4ArrayGetIndexed, 0xb0f79623) \
V(_Float64x2List, [], Float64x2ArrayGetIndexed, 0x5fd5df39) \
V(_ExternalFloat64x2Array, [], ExternalFloat64x2ArrayGetIndexed, 0x5fd5df39) \
V(_Int32x4List, [], Int32x4ArrayGetIndexed, 0x4967f00b) \
V(_ExternalInt32x4Array, [], ExternalInt32x4ArrayGetIndexed, 0x4967f00b) \
V(_List, ., ObjectArrayAllocate, 0x4c8eae02) \
V(_List, []=, ObjectArraySetIndexed, 0x3a3252da) \
V(_GrowableList, ._withData, GrowableArrayAllocateWithData, 0x19394cc1) \
@ -394,39 +425,22 @@ namespace dart {
V(_IntegerImplementation, <<, Integer_shl, 0x2d253e1b) \
#define GRAPH_TYPED_DATA_INTRINSICS_LIST(V) \
V(_Int8List, [], Int8ArrayGetIndexed, 0x7b31eba4) \
V(_Int8List, []=, Int8ArraySetIndexed, 0x02f7bc29) \
V(_Uint8List, [], Uint8ArrayGetIndexed, 0xe0aa6f64) \
V(_Uint8List, []=, Uint8ArraySetIndexed, 0xc8fdea5d) \
V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 0xe0aa6f64) \
V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 0xc8fdea5d) \
V(_Uint8ClampedList, [], Uint8ClampedArrayGetIndexed, 0xe0aa6f64) \
V(_Uint8ClampedList, []=, Uint8ClampedArraySetIndexed, 0x45020fa5) \
V(_ExternalUint8ClampedArray, [], ExternalUint8ClampedArrayGetIndexed, \
0xe0aa6f64) \
V(_ExternalUint8ClampedArray, []=, ExternalUint8ClampedArraySetIndexed, \
0x45020fa5) \
V(_Int16List, [], Int16ArrayGetIndexed, 0x97526723) \
V(_Int16List, []=, Int16ArraySetIndexed, 0x3c52d77c) \
V(_Uint16List, [], Uint16ArrayGetIndexed, 0x4cba19cf) \
V(_Uint16List, []=, Uint16ArraySetIndexed, 0x96e38a7c) \
V(_Int32List, [], Int32ArrayGetIndexed, 0x1113e36a) \
V(_Int32List, []=, Int32ArraySetIndexed, 0x7cf2875c) \
V(_Uint32List, [], Uint32ArrayGetIndexed, 0x97cbdf48) \
V(_Uint32List, []=, Uint32ArraySetIndexed, 0xe5065f1c) \
V(_Int64List, [], Int64ArrayGetIndexed, 0x03bd8740) \
V(_Int64List, []=, Int64ArraySetIndexed, 0x672a7e1c) \
V(_Uint64List, [], Uint64ArrayGetIndexed, 0xcc7e9c0c) \
V(_Uint64List, []=, Uint64ArraySetIndexed, 0x5e2325bc) \
V(_Float64List, [], Float64ArrayGetIndexed, 0x4cf25eb3) \
V(_Float64List, []=, Float64ArraySetIndexed, 0x84d73842) \
V(_Float32List, [], Float32ArrayGetIndexed, 0x289ee54d) \
V(_Float32List, []=, Float32ArraySetIndexed, 0x5e323082) \
V(_Float32x4List, [], Float32x4ArrayGetIndexed, 0x874fca98) \
V(_Float32x4List, []=, Float32x4ArraySetIndexed, 0xadc022db) \
V(_Int32x4List, [], Int32x4ArrayGetIndexed, 0xc9f525b4) \
V(_Int32x4List, []=, Int32x4ArraySetIndexed, 0xf38ac7d3) \
V(_Float64x2List, [], Float64x2ArrayGetIndexed, 0x7a32de78) \
V(_Float64x2List, []=, Float64x2ArraySetIndexed, 0xf316f725) \
V(_TypedListBase, get:length, TypedListBaseLength, 0x5842648b) \
V(_ByteDataView, get:length, ByteDataViewLength, 0x5842648b) \
@ -445,13 +459,11 @@ namespace dart {
#define GRAPH_CORE_INTRINSICS_LIST(V) \
V(_Array, get:length, ObjectArrayLength, 0x5842648b) \
V(_Array, [], ObjectArrayGetIndexed, 0x78e668b1) \
V(_List, _setIndexed, ObjectArraySetIndexedUnchecked, 0xe6212a10) \
V(_GrowableList, get:length, GrowableArrayLength, 0x5842648b) \
V(_GrowableList, get:_capacity, GrowableArrayCapacity, 0x7d911012) \
V(_GrowableList, _setData, GrowableArraySetData, 0xbdcbb43b) \
V(_GrowableList, _setLength, GrowableArraySetLength, 0xcc0d6dd6) \
V(_GrowableList, [], GrowableArrayGetIndexed, 0x78e668b1) \
V(_GrowableList, _setIndexed, GrowableArraySetIndexedUnchecked, 0x513c774f) \
V(_StringBase, get:length, StringBaseLength, 0x5842648b) \
V(_Smi, ~, Smi_bitNegate, 0x82466cfc) \

View file

@ -9193,6 +9193,36 @@ bool Function::RecognizedKindForceOptimize() const {
// Uses unboxed/untagged data not supported in unoptimized, or uses
// LoadIndexed/StoreIndexed/MemoryCopy instructions with typed data
// arrays, which requires optimization for payload extraction.
case MethodRecognizer::kObjectArrayGetIndexed:
case MethodRecognizer::kGrowableArrayGetIndexed:
case MethodRecognizer::kInt8ArrayGetIndexed:
case MethodRecognizer::kExternalInt8ArrayGetIndexed:
case MethodRecognizer::kUint8ArrayGetIndexed:
case MethodRecognizer::kExternalUint8ArrayGetIndexed:
case MethodRecognizer::kUint8ClampedArrayGetIndexed:
case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
case MethodRecognizer::kInt16ArrayGetIndexed:
case MethodRecognizer::kExternalInt16ArrayGetIndexed:
case MethodRecognizer::kUint16ArrayGetIndexed:
case MethodRecognizer::kExternalUint16ArrayGetIndexed:
case MethodRecognizer::kInt32ArrayGetIndexed:
case MethodRecognizer::kExternalInt32ArrayGetIndexed:
case MethodRecognizer::kUint32ArrayGetIndexed:
case MethodRecognizer::kExternalUint32ArrayGetIndexed:
case MethodRecognizer::kInt64ArrayGetIndexed:
case MethodRecognizer::kExternalInt64ArrayGetIndexed:
case MethodRecognizer::kUint64ArrayGetIndexed:
case MethodRecognizer::kExternalUint64ArrayGetIndexed:
case MethodRecognizer::kFloat32ArrayGetIndexed:
case MethodRecognizer::kExternalFloat32ArrayGetIndexed:
case MethodRecognizer::kFloat64ArrayGetIndexed:
case MethodRecognizer::kExternalFloat64ArrayGetIndexed:
case MethodRecognizer::kFloat32x4ArrayGetIndexed:
case MethodRecognizer::kExternalFloat32x4ArrayGetIndexed:
case MethodRecognizer::kFloat64x2ArrayGetIndexed:
case MethodRecognizer::kExternalFloat64x2ArrayGetIndexed:
case MethodRecognizer::kInt32x4ArrayGetIndexed:
case MethodRecognizer::kExternalInt32x4ArrayGetIndexed:
case MethodRecognizer::kCopyRangeFromUint8ListToOneByteString:
case MethodRecognizer::kFinalizerBase_getIsolateFinalizers:
case MethodRecognizer::kFinalizerBase_setIsolate:

View file

@ -5,8 +5,9 @@
part of "core_patch.dart";
abstract class _Array<E> extends FixedLengthListBase<E> {
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:external-name", "List_getIndexed")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
external E operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")

View file

@ -259,8 +259,9 @@ class _GrowableList<T> extends ListBase<T> {
@pragma("vm:external-name", "GrowableList_setData")
external void _setData(_List array);
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:external-name", "GrowableList_getIndexed")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
external T operator [](int index);
@pragma("vm:recognized", "other")

View file

@ -2264,12 +2264,11 @@ final class _Int8List extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Smi")
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getInt8(index);
}
external int operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, int value) {
@ -2320,12 +2319,11 @@ final class _Uint8List extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Smi")
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getUint8(index);
}
external int operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, int value) {
@ -2379,12 +2377,11 @@ final class _Uint8ClampedList extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Smi")
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getUint8(index);
}
external int operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, int value) {
@ -2441,12 +2438,11 @@ final class _Int16List extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Smi")
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getInt16(index * Int16List.bytesPerElement);
}
external int operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, int value) {
@ -2510,12 +2506,11 @@ final class _Uint16List extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Smi")
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getUint16(index * Uint16List.bytesPerElement);
}
external int operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, int value) {
@ -2579,11 +2574,10 @@ final class _Int32List extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getInt32(index * Int32List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
external int operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, int value) {
@ -2634,11 +2628,10 @@ final class _Uint32List extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getUint32(index * Uint32List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
external int operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, int value) {
@ -2689,11 +2682,10 @@ final class _Int64List extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getInt64(index * Int64List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
external int operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, int value) {
@ -2744,11 +2736,10 @@ final class _Uint64List extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getUint64(index * Uint64List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
external int operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, int value) {
@ -2799,12 +2790,11 @@ final class _Float32List extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Double")
double operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getFloat32(index * Float32List.bytesPerElement);
}
external double operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, double value) {
@ -2855,12 +2845,11 @@ final class _Float64List extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Double")
double operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getFloat64(index * Float64List.bytesPerElement);
}
external double operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, double value) {
@ -2910,12 +2899,11 @@ final class _Float32x4List extends _TypedList
throw "Unreachable";
}
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", _Float32x4)
Float32x4 operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getFloat32x4(index * Float32x4List.bytesPerElement);
}
external Float32x4 operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, Float32x4 value) {
@ -2965,12 +2953,11 @@ final class _Int32x4List extends _TypedList
throw "Unreachable";
}
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", _Int32x4)
Int32x4 operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getInt32x4(index * Int32x4List.bytesPerElement);
}
external Int32x4 operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, Int32x4 value) {
@ -3020,12 +3007,11 @@ final class _Float64x2List extends _TypedList
throw "Unreachable";
}
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", _Float64x2)
Float64x2 operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getFloat64x2(index * Float64x2List.bytesPerElement);
}
external Float64x2 operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, Float64x2 value) {
@ -3061,10 +3047,11 @@ final class _ExternalInt8Array extends _TypedList
}
// Method(s) implementing the List interface.
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getInt8(index);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Smi")
external int operator [](int index);
void operator []=(int index, int value) {
index = _typedDataIndexCheck(this, index, length);
@ -3099,12 +3086,11 @@ final class _ExternalUint8Array extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Smi")
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getUint8(index);
}
external int operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, int value) {
@ -3143,12 +3129,11 @@ final class _ExternalUint8ClampedArray extends _TypedList
}
// Method(s) implementing the List interface.
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Smi")
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getUint8(index);
}
external int operator [](int index);
@pragma("vm:recognized", "graph-intrinsic")
void operator []=(int index, int value) {
@ -3190,10 +3175,11 @@ final class _ExternalInt16Array extends _TypedList
}
// Method(s) implementing the List interface.
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getInt16(index * Int16List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Smi")
external int operator [](int index);
void operator []=(int index, int value) {
index = _typedDataIndexCheck(this, index, length);
@ -3228,10 +3214,11 @@ final class _ExternalUint16Array extends _TypedList
}
// Method(s) implementing the List interface.
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getUint16(index * Uint16List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Smi")
external int operator [](int index);
void operator []=(int index, int value) {
index = _typedDataIndexCheck(this, index, length);
@ -3266,10 +3253,10 @@ final class _ExternalInt32Array extends _TypedList
}
// Method(s) implementing the List interface.
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getInt32(index * Int32List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
external int operator [](int index);
void operator []=(int index, int value) {
index = _typedDataIndexCheck(this, index, length);
@ -3304,10 +3291,10 @@ final class _ExternalUint32Array extends _TypedList
}
// Method(s) implementing the List interface.
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getUint32(index * Uint32List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
external int operator [](int index);
void operator []=(int index, int value) {
index = _typedDataIndexCheck(this, index, length);
@ -3342,10 +3329,10 @@ final class _ExternalInt64Array extends _TypedList
}
// Method(s) implementing the List interface.
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getInt64(index * Int64List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
external int operator [](int index);
void operator []=(int index, int value) {
index = _typedDataIndexCheck(this, index, length);
@ -3380,10 +3367,10 @@ final class _ExternalUint64Array extends _TypedList
}
// Method(s) implementing the List interface.
int operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getUint64(index * Uint64List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
external int operator [](int index);
void operator []=(int index, int value) {
index = _typedDataIndexCheck(this, index, length);
@ -3418,10 +3405,11 @@ final class _ExternalFloat32Array extends _TypedList
}
// Method(s) implementing the List interface.
double operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getFloat32(index * Float32List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Double")
external double operator [](int index);
void operator []=(int index, double value) {
index = _typedDataIndexCheck(this, index, length);
@ -3456,10 +3444,11 @@ final class _ExternalFloat64Array extends _TypedList
}
// Method(s) implementing the List interface.
double operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getFloat64(index * Float64List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", "dart:core#_Double")
external double operator [](int index);
void operator []=(int index, double value) {
index = _typedDataIndexCheck(this, index, length);
@ -3494,10 +3483,11 @@ final class _ExternalFloat32x4Array extends _TypedList
}
// Method(s) implementing the List interface.
Float32x4 operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getFloat32x4(index * Float32x4List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", _Float32x4)
external Float32x4 operator [](int index);
void operator []=(int index, Float32x4 value) {
index = _typedDataIndexCheck(this, index, length);
@ -3532,10 +3522,11 @@ final class _ExternalInt32x4Array extends _TypedList
}
// Method(s) implementing the List interface.
Int32x4 operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getInt32x4(index * Int32x4List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", _Int32x4)
external Int32x4 operator [](int index);
void operator []=(int index, Int32x4 value) {
index = _typedDataIndexCheck(this, index, length);
@ -3570,10 +3561,11 @@ final class _ExternalFloat64x2Array extends _TypedList
}
// Method(s) implementing the List interface.
Float64x2 operator [](int index) {
index = _typedDataIndexCheck(this, index, length);
return _getFloat64x2(index * Float64x2List.bytesPerElement);
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
@pragma("vm:idempotent")
@pragma("vm:exact-result-type", _Float64x2)
external Float64x2 operator [](int index);
void operator []=(int index, Float64x2 value) {
index = _typedDataIndexCheck(this, index, length);