e34f6e4405
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>
107 lines
3.3 KiB
C++
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
|