[vm/bytecode] Add a compile-time error if there are too many arguments.
Issue: https://github.com/dart-lang/sdk/issues/37305
Change-Id: I9dac7c1b7b49fca8531ca2bf83b1c309d8217969
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106984
Reviewed-by: Aart Bik <ajcbik@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/front_end/lib/src/api_unstable/vm.dart b/pkg/front_end/lib/src/api_unstable/vm.dart
index 77ea7b9..649e318 100644
--- a/pkg/front_end/lib/src/api_unstable/vm.dart
+++ b/pkg/front_end/lib/src/api_unstable/vm.dart
@@ -34,6 +34,8 @@
export '../fasta/fasta_codes.dart'
show
LocatedMessage,
+ messageBytecodeLimitExceededTooManyArguments,
+ noLength,
templateFfiFieldAnnotation,
templateFfiStructAnnotation,
templateFfiNotStatic,
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index b25813b..de913de 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -461,6 +461,15 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeBytecodeLimitExceededTooManyArguments =
+ messageBytecodeLimitExceededTooManyArguments;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageBytecodeLimitExceededTooManyArguments =
+ const MessageCode("BytecodeLimitExceededTooManyArguments",
+ message: r"""Dart bytecode limit exceeded: too many arguments.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeCandidateFound = messageCandidateFound;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 8f99626..0ea1a63 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -28,6 +28,8 @@
BadTypeVariableInSupertype/analyzerCode: Fail
BuiltInIdentifierAsType/example: Fail
BuiltInIdentifierInDeclaration/example: Fail
+BytecodeLimitExceededTooManyArguments/analyzerCode: Fail
+BytecodeLimitExceededTooManyArguments/example: Fail
CannotAssignToParenthesizedExpression/example: Fail
CannotAssignToSuper/example: Fail
CannotReadPackagesFile/analyzerCode: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index d2b0dac..d94388d 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -3566,3 +3566,6 @@
script: >
class Base<T> {}
class Derived<T> extends Base<Derived<Derived<T>>> {}
+
+BytecodeLimitExceededTooManyArguments:
+ template: "Dart bytecode limit exceeded: too many arguments."
diff --git a/pkg/vm/lib/bytecode/dbc.dart b/pkg/vm/lib/bytecode/dbc.dart
index 2c9f9c1..45afa97 100644
--- a/pkg/vm/lib/bytecode/dbc.dart
+++ b/pkg/vm/lib/bytecode/dbc.dart
@@ -645,6 +645,9 @@
// Context IDs are referenced using 8-bit unsigned operands.
const int contextIdLimit = 1 << 8;
+// Number of arguments is encoded as 8-bit unsigned operand.
+const int argumentsLimit = 1 << 8;
+
// Base class for exceptions thrown when certain limit of bytecode
// format is exceeded.
abstract class BytecodeLimitExceededException {}
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 343915a..74f7ded 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -9,7 +9,12 @@
import 'package:front_end/src/api_prototype/constant_evaluator.dart'
show ConstantEvaluator, EvaluationEnvironment, ErrorReporter;
import 'package:front_end/src/api_unstable/vm.dart'
- show CompilerContext, Severity, templateIllegalRecursiveType;
+ show
+ CompilerContext,
+ Severity,
+ messageBytecodeLimitExceededTooManyArguments,
+ noLength,
+ templateIllegalRecursiveType;
import 'package:kernel/ast.dart' hide MapEntry, Component, FunctionDeclaration;
import 'package:kernel/ast.dart' as ast show Component, FunctionDeclaration;
@@ -691,9 +696,11 @@
throw 'Unexpected member ${node.runtimeType} $node';
}
end(node, hasCode);
- } on BytecodeLimitExceededException {
- // Do not generate bytecode and fall back to using kernel AST.
- // TODO(alexmarkov): issue compile-time error
+ } on TooManyArgumentsException catch (e) {
+ CompilerContext.current.options.report(
+ messageBytecodeLimitExceededTooManyArguments.withLocation(
+ node.fileUri, e.fileOffset, noLength),
+ Severity.error);
hasErrors = true;
end(node, false);
}
@@ -970,18 +977,21 @@
}
void _genDirectCall(Member target, ObjectHandle argDesc, int totalArgCount,
- {bool isGet: false, bool isSet: false}) {
+ {bool isGet: false, bool isSet: false, TreeNode context}) {
assert(!isGet || !isSet);
final kind = isGet
? InvocationKind.getter
: (isSet ? InvocationKind.setter : InvocationKind.method);
final cpIndex = cp.addDirectCall(kind, target, argDesc);
+ if (totalArgCount >= argumentsLimit) {
+ throw new TooManyArgumentsException(context.fileOffset);
+ }
asm.emitDirectCall(cpIndex, totalArgCount);
}
void _genDirectCallWithArgs(Member target, Arguments args,
- {bool hasReceiver: false, bool isFactory: false}) {
+ {bool hasReceiver: false, bool isFactory: false, TreeNode context}) {
final argDesc = objectTable.getArgDescHandleByArguments(args,
hasReceiver: hasReceiver, isFactory: isFactory);
@@ -995,7 +1005,7 @@
totalArgCount++;
}
- _genDirectCall(target, argDesc, totalArgCount);
+ _genDirectCall(target, argDesc, totalArgCount, context: context);
}
void _genTypeArguments(List<DartType> typeArgs, {Class instantiatingClass}) {
@@ -2359,7 +2369,7 @@
new Arguments(node.arguments.positional, named: node.arguments.named)
..parent = node;
_genArguments(null, args);
- _genDirectCallWithArgs(node.target, args, hasReceiver: true);
+ _genDirectCallWithArgs(node.target, args, hasReceiver: true, context: node);
asm.emitDrop1();
}
@@ -2369,7 +2379,7 @@
_genArguments(node.receiver, args);
final target = node.target;
if (target is Procedure && !target.isGetter && !target.isSetter) {
- _genDirectCallWithArgs(target, args, hasReceiver: true);
+ _genDirectCallWithArgs(target, args, hasReceiver: true, context: node);
} else {
throw new UnsupportedOperationError(
'Unsupported DirectMethodInvocation with target ${target.runtimeType} $target');
@@ -2624,7 +2634,11 @@
}
void _genInstanceCall(
- int totalArgCount, int callCpIndex, bool isDynamic, bool isUnchecked) {
+ int totalArgCount, int callCpIndex, bool isDynamic, bool isUnchecked,
+ [TreeNode context]) {
+ if (totalArgCount >= argumentsLimit) {
+ throw new TooManyArgumentsException(context.fileOffset);
+ }
if (isDynamic) {
assert(!isUnchecked);
asm.emitDynamicCall(callCpIndex, totalArgCount);
@@ -2662,7 +2676,7 @@
args.named.length +
1 /* receiver */ +
(args.types.isNotEmpty ? 1 : 0) /* type arguments */;
- _genInstanceCall(totalArgCount, callCpIndex, isDynamic, isUnchecked);
+ _genInstanceCall(totalArgCount, callCpIndex, isDynamic, isUnchecked, node);
}
@override
@@ -2719,7 +2733,7 @@
return;
}
_genArguments(new ThisExpression(), args);
- _genDirectCallWithArgs(target, args, hasReceiver: true);
+ _genDirectCallWithArgs(target, args, hasReceiver: true, context: node);
}
@override
@@ -2872,7 +2886,8 @@
..parent = node;
}
_genArguments(null, args);
- _genDirectCallWithArgs(target, args, isFactory: target.isFactory);
+ _genDirectCallWithArgs(target, args,
+ isFactory: target.isFactory, context: node);
}
@override
@@ -3700,7 +3715,7 @@
final args = node.arguments;
assert(args.types.isEmpty);
_genArguments(new ThisExpression(), args);
- _genDirectCallWithArgs(node.target, args, hasReceiver: true);
+ _genDirectCallWithArgs(node.target, args, hasReceiver: true, context: node);
asm.emitDrop1();
}
@@ -3718,7 +3733,7 @@
}
}
assert(target != null);
- _genDirectCallWithArgs(target, args, hasReceiver: true);
+ _genDirectCallWithArgs(target, args, hasReceiver: true, context: node);
asm.emitDrop1();
}
@@ -3746,6 +3761,11 @@
String toString() => message;
}
+class TooManyArgumentsException extends BytecodeLimitExceededException {
+ final int fileOffset;
+ TooManyArgumentsException(this.fileOffset);
+}
+
typedef void GenerateContinuation();
class FinallyBlock {