[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>
This commit is contained in:
Alexander Markov 2019-06-24 16:02:05 +00:00 committed by commit-bot@chromium.org
parent 714234525b
commit 37a25d9100
6 changed files with 54 additions and 15 deletions

View file

@ -34,6 +34,8 @@ export '../fasta/compiler_context.dart' show CompilerContext;
export '../fasta/fasta_codes.dart'
show
LocatedMessage,
messageBytecodeLimitExceededTooManyArguments,
noLength,
templateFfiFieldAnnotation,
templateFfiStructAnnotation,
templateFfiNotStatic,

View file

@ -460,6 +460,15 @@ Message _withArgumentsBuiltInIdentifierInDeclaration(Token token) {
arguments: {'token': token});
}
// 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;

View file

@ -28,6 +28,8 @@ AwaitNotAsync/example: Fail
BadTypeVariableInSupertype/analyzerCode: Fail
BuiltInIdentifierAsType/example: Fail
BuiltInIdentifierInDeclaration/example: Fail
BytecodeLimitExceededTooManyArguments/analyzerCode: Fail
BytecodeLimitExceededTooManyArguments/example: Fail
CannotAssignToParenthesizedExpression/example: Fail
CannotAssignToSuper/example: Fail
CannotReadPackagesFile/analyzerCode: Fail

View file

@ -3566,3 +3566,6 @@ IllegalRecursiveType:
script: >
class Base<T> {}
class Derived<T> extends Base<Derived<Derived<T>>> {}
BytecodeLimitExceededTooManyArguments:
template: "Dart bytecode limit exceeded: too many arguments."

View file

@ -645,6 +645,9 @@ const int capturedVariableIndexLimit = 1 << 32;
// 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 {}

View file

@ -9,7 +9,12 @@ library vm.bytecode.gen_bytecode;
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 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
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 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
}
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 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
totalArgCount++;
}
_genDirectCall(target, argDesc, totalArgCount);
_genDirectCall(target, argDesc, totalArgCount, context: context);
}
void _genTypeArguments(List<DartType> typeArgs, {Class instantiatingClass}) {
@ -2359,7 +2369,7 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
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 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
_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 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
}
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 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
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 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
return;
}
_genArguments(new ThisExpression(), args);
_genDirectCallWithArgs(target, args, hasReceiver: true);
_genDirectCallWithArgs(target, args, hasReceiver: true, context: node);
}
@override
@ -2872,7 +2886,8 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
..parent = node;
}
_genArguments(null, args);
_genDirectCallWithArgs(target, args, isFactory: target.isFactory);
_genDirectCallWithArgs(target, args,
isFactory: target.isFactory, context: node);
}
@override
@ -3700,7 +3715,7 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
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 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
}
}
assert(target != null);
_genDirectCallWithArgs(target, args, hasReceiver: true);
_genDirectCallWithArgs(target, args, hasReceiver: true, context: node);
asm.emitDrop1();
}
@ -3746,6 +3761,11 @@ class UnsupportedOperationError {
String toString() => message;
}
class TooManyArgumentsException extends BytecodeLimitExceededException {
final int fileOffset;
TooManyArgumentsException(this.fileOffset);
}
typedef void GenerateContinuation();
class FinallyBlock {