[vm] Simplify evaluation of asserts

Since Dart 2, assert statements only accept bool conditions,
so evaluation of the assert condition can be simplified in the VM.

TEST=existing

Change-Id: I0f54ad66b9d9aef707fef4eac192128a3994e7c9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425920
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov
2025-05-01 13:13:19 -07:00
committed by Commit Queue
parent c644933a82
commit 16909d8ccb
7 changed files with 8 additions and 52 deletions
+6 -10
View File
@@ -11,18 +11,10 @@
namespace dart {
#if !defined(DART_PRECOMPILED_RUNTIME)
// Scan the stack until we hit the first function in the _AssertionError
// class. We then return the next frame's script taking inlining into account.
static ScriptPtr FindScript(DartFrameIterator* iterator) {
#if defined(DART_PRECOMPILED_RUNTIME)
// The precompiled runtime faces two issues in recovering the correct
// assertion text. First, the precompiled runtime does not include
// the inlining meta-data so we cannot walk the inline-aware stack trace.
// Second, the script text itself is missing so whatever script is returned
// from here will be missing the assertion expression text.
iterator->NextFrame(); // Skip _AssertionError._evaluateAssertion frame
return Exceptions::GetCallerScript(iterator);
#else
StackFrame* stack_frame = iterator->NextFrame();
Code& code = Code::Handle();
Function& func = Function::Handle();
@@ -60,8 +52,8 @@ static ScriptPtr FindScript(DartFrameIterator* iterator) {
}
UNREACHABLE();
return Script::null();
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
// Allocate and throw a new AssertionError.
// Arg0: index of the first token of the failed assertion.
@@ -69,6 +61,9 @@ static ScriptPtr FindScript(DartFrameIterator* iterator) {
// Arg2: Message object or null.
// Return value: none, throws an exception.
DEFINE_NATIVE_ENTRY(AssertionError_throwNew, 0, 3) {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
#else
// No need to type check the arguments. This function can only be called
// internally from the VM.
const TokenPosition assertion_start = TokenPosition::Deserialize(
@@ -114,6 +109,7 @@ DEFINE_NATIVE_ENTRY(AssertionError_throwNew, 0, 3) {
Exceptions::ThrowByType(Exceptions::kAssertion, args);
UNREACHABLE();
return Object::null();
#endif
}
// Allocate and throw a new AssertionError.
@@ -1521,10 +1521,6 @@ Fragment StreamingFlowGraphBuilder::Return(TokenPosition position) {
/*omit_result_type_check=*/false);
}
Fragment StreamingFlowGraphBuilder::EvaluateAssertion() {
return flow_graph_builder_->EvaluateAssertion();
}
Fragment StreamingFlowGraphBuilder::RethrowException(TokenPosition position,
int catch_try_index) {
return flow_graph_builder_->RethrowException(position, catch_try_index);
@@ -4626,13 +4622,6 @@ Fragment StreamingFlowGraphBuilder::BuildAssertStatement(
TargetEntryInstr* otherwise;
Fragment instructions;
// Asserts can be of the following two kinds:
//
// * `assert(expr)`
// * `assert(() { ... })`
//
// The call to `_AssertionError._evaluateAssertion()` will take care of both
// and returns a boolean.
instructions += BuildExpression(position); // read condition.
const TokenPosition condition_start_offset =
@@ -4640,7 +4629,6 @@ Fragment StreamingFlowGraphBuilder::BuildAssertStatement(
const TokenPosition condition_end_offset =
ReadPosition(); // read condition end offset.
instructions += EvaluateAssertion();
instructions += RecordCoverage(condition_start_offset);
instructions += Constant(Bool::True());
instructions += BranchIfEqual(&then, &otherwise);
@@ -4648,6 +4636,8 @@ Fragment StreamingFlowGraphBuilder::BuildAssertStatement(
const Class& klass =
Class::ZoneHandle(Z, Library::LookupCoreClass(Symbols::AssertionError()));
ASSERT(!klass.IsNull());
const auto& error = klass.EnsureIsFinalized(thread());
ASSERT(error == Error::null());
Fragment otherwise_fragment(otherwise);
if (CompilerState::Current().is_aot()) {
@@ -158,7 +158,6 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
Fragment LoadLocal(LocalVariable* variable);
IndirectGotoInstr* IndirectGoto(intptr_t target_count);
Fragment Return(TokenPosition position);
Fragment EvaluateAssertion();
Fragment RethrowException(TokenPosition position, int catch_try_index);
Fragment ThrowNoSuchMethodError(TokenPosition position,
const Function& target,
@@ -2281,19 +2281,6 @@ bool FlowGraphBuilder::NeedsDebugStepCheck(Value* value,
return false;
}
Fragment FlowGraphBuilder::EvaluateAssertion() {
const Class& klass =
Class::ZoneHandle(Z, Library::LookupCoreClass(Symbols::AssertionError()));
ASSERT(!klass.IsNull());
const auto& error = klass.EnsureIsFinalized(H.thread());
ASSERT(error == Error::null());
const Function& target = Function::ZoneHandle(
Z, klass.LookupStaticFunctionAllowPrivate(Symbols::EvaluateAssertion()));
ASSERT(!target.IsNull());
return StaticCall(TokenPosition::kNoSource, target, /* argument_count = */ 1,
ICData::kStatic);
}
Fragment FlowGraphBuilder::CheckAssignable(const AbstractType& dst_type,
const String& dst_name,
AssertAssignableInstr::Kind kind,
@@ -277,7 +277,6 @@ class FlowGraphBuilder : public BaseFlowGraphBuilder {
Fragment BuildImplicitClosureCreation(TokenPosition position,
const Function& target);
Fragment EvaluateAssertion();
Fragment CheckVariableTypeInCheckedMode(const AbstractType& dst_type,
const String& name_symbol);
Fragment CheckAssignable(
-1
View File
@@ -100,7 +100,6 @@ class ObjectPointerVisitor;
V(EqualOperator, "==") \
V(Error, "Error") \
V(EvalSourceUri, "evaluate:source") \
V(EvaluateAssertion, "_evaluateAssertion") \
V(ExceptionHandlers, "ExceptionHandlers") \
V(ExceptionVar, ":exception_var") \
V(Expando, "Expando") \
@@ -66,20 +66,6 @@ class _AssertionError extends Error implements AssertionError {
Object? message,
);
@pragma("vm:entry-point", "call")
static bool _evaluateAssertion(condition) {
if (identical(condition, true) || identical(condition, false)) {
return condition;
}
if (condition is _Closure) {
return (condition as dynamic Function())();
}
if (condition is Function) {
condition = (condition as dynamic Function())();
}
return condition;
}
String get _messageString {
final msg = message;
if (msg == null) return "is not true.";