Files
sdk/runtime/vm/compiler/frontend/multiple_entrypoints_test.cc
T
Martin Kustermann e34f6e4405 [vm/compiler] Ensure parameters for multiple entrypoints get Phi nodes with AssertAssignable/Redefinition as inputs
Our compiler uses data dependencies to represent certain control
dependencies. In particular code that uses a SSA definition after an
AssertAssignable should use the AssertAssignable instead of it's input.

Issue https://github.com/dart-lang/sdk/issues/43534

Change-Id: I495b793a68a99385483c62e3cbc6a7e12b2527ab
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/165562
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Tess Strickland <sstrickl@google.com>
2020-10-01 11:24:22 +00:00

107 lines
3.3 KiB
C++

// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/compiler/backend/il_test_helper.h"
#include "vm/compiler/compiler_pass.h"
#include "vm/object.h"
#include "vm/unit_test.h"
namespace dart {
#if defined(DART_PRECOMPILER)
ISOLATE_UNIT_TEST_CASE(IRTest_MultilpeEntryPoints_Regress43534) {
const char* kScript =
R"(
import 'dart:typed_data';
@pragma('vm:never-inline')
void callWith<T>(void Function(T arg) fun, T arg) {
fun(arg);
}
@pragma('vm:never-inline')
void use(dynamic arg) {}
void test() {
callWith<Uint8List>((Uint8List list) {
use(list);
}, Uint8List(10));
}
)";
const auto& root_library = Library::Handle(LoadTestScript(kScript));
Invoke(root_library, "test");
const auto& test_function =
Function::Handle(GetFunction(root_library, "test"));
const auto& closures = GrowableObjectArray::Handle(
Isolate::Current()->object_store()->closure_functions());
auto& function = Function::Handle();
for (intptr_t i = closures.Length() - 1; 0 <= i; ++i) {
function ^= closures.At(i);
if (function.parent_function() == test_function.raw()) {
break;
}
function = Function::null();
}
RELEASE_ASSERT(!function.IsNull());
TestPipeline pipeline(function, CompilerPass::kAOT);
FlowGraph* flow_graph = pipeline.RunPasses({CompilerPass::kComputeSSA});
auto entry = flow_graph->graph_entry()->normal_entry();
EXPECT(entry != nullptr);
auto unchecked_entry = flow_graph->graph_entry()->unchecked_entry();
EXPECT(unchecked_entry != nullptr);
AssertAssignableInstr* assert_assignable = nullptr;
StaticCallInstr* static_call = nullptr;
// Normal entry
ILMatcher cursor(flow_graph, entry, /*trace=*/true);
RELEASE_ASSERT(cursor.TryMatch(
{
kMatchAndMoveGoto,
kMatchAndMoveBranchFalse,
{kMatchAndMoveAssertAssignable, &assert_assignable},
kMatchAndMoveGoto,
{kMatchAndMoveStaticCall, &static_call},
kMatchReturn,
},
kMoveGlob));
RedefinitionInstr* redefinition = nullptr;
StaticCallInstr* static_call2 = nullptr;
// Unchecked entry
ILMatcher cursor2(flow_graph, entry, /*trace=*/true);
RELEASE_ASSERT(cursor2.TryMatch(
{
kMatchAndMoveGoto,
kMatchAndMoveBranchTrue,
{kMatchAndMoveRedefinition, &redefinition},
kMatchAndMoveGoto,
{kMatchAndMoveStaticCall, &static_call2},
kMatchReturn,
},
kMoveGlob));
// Ensure the value the static call uses is a Phi node with 2 inputs:
// a) Normal entry: AssertAssignable
// b) Unchecked entry: Redefinition
RELEASE_ASSERT(static_call->ArgumentAt(0)->IsPhi());
auto phi = static_call->ArgumentAt(0)->AsPhi();
auto input_a = phi->InputAt(0)->definition();
auto input_b = phi->InputAt(1)->definition();
RELEASE_ASSERT(input_a->IsRedefinition());
RELEASE_ASSERT(input_b->IsAssertAssignable());
RELEASE_ASSERT(input_a == redefinition);
RELEASE_ASSERT(input_b == assert_assignable);
RELEASE_ASSERT(static_call == static_call2);
}
#endif // defined(DART_PRECOMPILER)
} // namespace dart