[vm] Remove FallThroughError code in the VM

Since Dart 2.0 we can never have FallThroughErrors.

The CFE does not synthesize breaks unterminated cases which never
reach the end of the block. For example:
* Call to something that returns never.
* Nested complete switch which returns from every branch.

In these cases we need to construct a correct control flow in the VM,
even though it is dead code. Because the CFE does not make the outer
switch a labelled statement, we cannot find a jump target in the VM.

Therefore, throw something (just not a FallThroughError). This should
never be hit at runtime, because it's dead code.

When the CFE emits synthetic breaks, we can remove this workaround.

TEST=build SDK and run default suites.

Bug: https://github.com/dart-lang/sdk/issues/50595
Change-Id: I595dd3baf7253b0ac4931445bd5b6da49e84cae4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/273740
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Tess Strickland <sstrickl@google.com>
This commit is contained in:
Daco Harkes 2022-12-08 11:51:31 +00:00 committed by Commit Queue
parent 636232628b
commit d86c043cbb
4 changed files with 9 additions and 38 deletions

View file

@ -4957,42 +4957,14 @@ Fragment StreamingFlowGraphBuilder::BuildSwitchCase(SwitchHelper* helper,
body_fragment += Drop();
}
// The Dart language specification mandates fall-throughs in [SwitchCase]es
// to be runtime errors.
// TODO(http://dartbug.com/50595): The CFE does not insert breaks for
// unterminated cases which never reach the end of their control flow.
// If the CFE inserts synthesized breaks, we can add an assert here instead.
if (!is_default && body_fragment.is_open() &&
(case_index < (helper->case_count() - 1))) {
const Class& klass = Class::ZoneHandle(
Z, Library::LookupCoreClass(Symbols::FallThroughError()));
ASSERT(!klass.IsNull());
const auto& error = klass.EnsureIsFinalized(thread());
ASSERT(error == Error::null());
GrowableHandlePtrArray<const String> pieces(Z, 3);
pieces.Add(Symbols::FallThroughError());
pieces.Add(Symbols::Dot());
pieces.Add(H.DartSymbolObfuscate("_create"));
const Function& constructor = Function::ZoneHandle(
Z, klass.LookupConstructorAllowPrivate(String::ZoneHandle(
Z, Symbols::FromConcatAll(H.thread(), pieces))));
ASSERT(!constructor.IsNull());
const String& url = H.DartSymbolPlain(
parsed_function()->function().ToLibNamePrefixedQualifiedCString());
// Create instance of _FallThroughError
body_fragment += AllocateObject(TokenPosition::kNoSource, klass, 0);
LocalVariable* instance = MakeTemporary();
// Call _FallThroughError._create constructor.
body_fragment += LoadLocal(instance); // this
body_fragment += Constant(url); // url
body_fragment += NullConstant(); // line
body_fragment +=
StaticCall(TokenPosition::kNoSource, constructor, 3, ICData::kStatic);
body_fragment += Drop();
// Throw the exception
const auto& error =
String::ZoneHandle(Z, Symbols::New(thread(), "Unreachable code."));
body_fragment += Constant(error);
body_fragment += ThrowException(TokenPosition::kNoSource);
body_fragment += Drop();
}

View file

@ -687,7 +687,7 @@ Fragment FlowGraphBuilder::ThrowTypeError() {
Fragment instructions;
// Create instance of _FallThroughError
// Create instance of _TypeError
instructions += AllocateObject(TokenPosition::kNoSource, klass, 0);
LocalVariable* instance = MakeTemporary();

View file

@ -7420,7 +7420,7 @@ static void CheckConcatAll(const String* data[], intptr_t n) {
ISOLATE_UNIT_TEST_CASE(Symbols_FromConcatAll) {
{
const String* data[3] = {&Symbols::FallThroughError(), &Symbols::Dot(),
const String* data[3] = {&Symbols::NullThrownError(), &Symbols::Dot(),
&Symbols::isPaused()};
CheckConcatAll(data, 3);
}
@ -7475,7 +7475,7 @@ ISOLATE_UNIT_TEST_CASE(Symbols_FromConcatAll) {
{
const String& empty = String::Handle(String::New(""));
const String* data[3] = {&Symbols::FallThroughError(), &empty,
const String* data[3] = {&Symbols::NullThrownError(), &empty,
&Symbols::isPaused()};
CheckConcatAll(data, 3);
}

View file

@ -99,7 +99,6 @@ class ObjectPointerVisitor;
V(ExprTemp, ":expr_temp") \
V(ExternalOneByteString, "_ExternalOneByteString") \
V(ExternalTwoByteString, "_ExternalTwoByteString") \
V(FallThroughError, "FallThroughError") \
V(FfiAbiSpecificMapping, "_FfiAbiSpecificMapping") \
V(FfiBool, "Bool") \
V(FfiCallback, "_FfiCallback") \