Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Unified Diff: runtime/vm/kernel_to_il.cc

Issue 2659363003: VM: [Kernel] Partial support for checked mode. (Closed)
Patch Set: Renamed Maybe* -> *InCheckedMode Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/kernel_to_il.h ('k') | tests/language/language_kernel.status » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/kernel_to_il.cc
diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc
index 11a84e2ffe6f9bbc55a57a82685f8b6ff037a375..8c8e581ce165677984c3a30c506dd5f2ad8a70de 100644
--- a/runtime/vm/kernel_to_il.cc
+++ b/runtime/vm/kernel_to_il.cc
@@ -1769,8 +1769,7 @@ void ConstantEvaluator::VisitStringConcatenation(StringConcatenation* node) {
void ConstantEvaluator::VisitConditionalExpression(
ConditionalExpression* node) {
- EvaluateExpression(node->condition());
- if (Bool::Cast(result_).value()) {
+ if (EvaluateBooleanExpression(node->condition())) {
EvaluateExpression(node->then());
} else {
EvaluateExpression(node->otherwise());
@@ -1780,25 +1779,20 @@ void ConstantEvaluator::VisitConditionalExpression(
void ConstantEvaluator::VisitLogicalExpression(LogicalExpression* node) {
if (node->op() == LogicalExpression::kAnd) {
- EvaluateExpression(node->left());
- if (Bool::Cast(result_).value()) {
- EvaluateExpression(node->right());
+ if (EvaluateBooleanExpression(node->left())) {
+ EvaluateBooleanExpression(node->right());
}
} else {
ASSERT(node->op() == LogicalExpression::kOr);
- EvaluateExpression(node->left());
- if (!Bool::Cast(result_).value()) {
- EvaluateExpression(node->right());
+ if (!EvaluateBooleanExpression(node->left())) {
+ EvaluateBooleanExpression(node->right());
}
}
}
void ConstantEvaluator::VisitNot(Not* node) {
- EvaluateExpression(node->expression());
- ASSERT(result_.IsBool());
- result_ =
- Bool::Cast(result_).value() ? Bool::False().raw() : Bool::True().raw();
+ result_ ^= Bool::Get(!EvaluateBooleanExpression(node->expression())).raw();
}
@@ -2533,12 +2527,19 @@ Fragment FlowGraphBuilder::PushArgument() {
Fragment FlowGraphBuilder::Return(TokenPosition position) {
+ Fragment instructions;
+
+ instructions += CheckReturnTypeInCheckedMode();
+
Value* value = Pop();
ASSERT(stack_ == NULL);
- ReturnInstr* return_instr =
- new (Z) ReturnInstr(TokenPosition::kNoSource, value);
+
+ ReturnInstr* return_instr = new (Z) ReturnInstr(position, value);
if (exit_collector_ != NULL) exit_collector_->AddExit(return_instr);
- return Fragment(return_instr).closed();
+
+ instructions <<= return_instr;
+
+ return instructions.closed();
}
@@ -2609,15 +2610,24 @@ Fragment FlowGraphBuilder::StoreInstanceField(
const dart::Field& field,
bool is_initialization_store,
StoreBarrierType emit_store_barrier) {
+ Fragment instructions;
+
+ const AbstractType& dst_type = AbstractType::ZoneHandle(Z, field.type());
+ instructions += CheckAssignableInCheckedMode(
+ dst_type, dart::String::ZoneHandle(Z, field.name()));
+
Value* value = Pop();
if (value->BindsToConstant()) {
emit_store_barrier = kNoStoreBarrier;
}
+
StoreInstanceFieldInstr* store = new (Z)
StoreInstanceFieldInstr(MayCloneField(Z, field), Pop(), value,
emit_store_barrier, TokenPosition::kNoSource);
store->set_is_initialization(is_initialization_store);
- return Fragment(store);
+ instructions <<= store;
+
+ return instructions;
}
@@ -3093,6 +3103,26 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFunction(FunctionNode* function,
body = Fragment(body.entry, non_null_entry);
}
+ // If we run in checked mode, we have to check the type of the passed
+ // arguments.
+ if (I->type_checks()) {
+ List<VariableDeclaration>& positional = function->positional_parameters();
+ List<VariableDeclaration>& named = function->named_parameters();
+
+ for (intptr_t i = 0; i < positional.length(); i++) {
+ VariableDeclaration* variable = positional[i];
+ body += LoadLocal(LookupVariable(variable));
+ body += CheckVariableTypeInCheckedMode(variable);
+ body += Drop();
+ }
+ for (intptr_t i = 0; i < named.length(); i++) {
+ VariableDeclaration* variable = named[i];
+ body += LoadLocal(LookupVariable(variable));
+ body += CheckVariableTypeInCheckedMode(variable);
+ body += Drop();
+ }
+ }
+
if (dart_function.is_native()) {
body += NativeFunctionBody(function, dart_function);
} else if (function->body() != NULL) {
@@ -3465,6 +3495,97 @@ Fragment FlowGraphBuilder::GuardFieldClass(const dart::Field& field,
}
+Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode(
+ VariableDeclaration* variable) {
+ if (I->type_checks()) {
+ const AbstractType& dst_type = T.TranslateType(variable->type());
+ if (dst_type.IsMalformed()) {
+ return ThrowTypeError();
+ }
+ return CheckAssignableInCheckedMode(dst_type,
+ H.DartSymbol(variable->name()));
+ }
+ return Fragment();
+}
+
+
+Fragment FlowGraphBuilder::EvaluateAssertion() {
+ const dart::Class& klass = dart::Class::ZoneHandle(
+ Z, dart::Library::LookupCoreClass(Symbols::AssertionError()));
+ ASSERT(!klass.IsNull());
+ const dart::Function& target =
+ dart::Function::ZoneHandle(Z, klass.LookupStaticFunctionAllowPrivate(
+ H.DartSymbol("_evaluateAssertion")));
+ ASSERT(!target.IsNull());
+ return StaticCall(TokenPosition::kNoSource, target, 1);
+}
+
+
+Fragment FlowGraphBuilder::CheckReturnTypeInCheckedMode() {
+ if (I->type_checks()) {
+ const AbstractType& return_type =
+ AbstractType::Handle(Z, parsed_function_->function().result_type());
+ return CheckAssignableInCheckedMode(return_type, Symbols::FunctionResult());
+ }
+ return Fragment();
+}
+
+
+Fragment FlowGraphBuilder::CheckBooleanInCheckedMode() {
+ Fragment instructions;
+ if (I->type_checks()) {
+ LocalVariable* top_of_stack = MakeTemporary();
+ instructions += LoadLocal(top_of_stack);
+ instructions += AssertBool();
+ instructions += Drop();
+ }
+ return instructions;
+}
+
+
+Fragment FlowGraphBuilder::CheckAssignableInCheckedMode(
+ const dart::AbstractType& dst_type,
+ const dart::String& dst_name) {
+ Fragment instructions;
+ if (I->type_checks() && !dst_type.IsDynamicType() &&
+ !dst_type.IsObjectType()) {
+ LocalVariable* top_of_stack = MakeTemporary();
+ instructions += LoadLocal(top_of_stack);
+ instructions += AssertAssignable(dst_type, dst_name);
+ instructions += Drop();
+ }
+ return instructions;
+}
+
+
+Fragment FlowGraphBuilder::AssertBool() {
+ Value* value = Pop();
+ AssertBooleanInstr* instr =
+ new (Z) AssertBooleanInstr(TokenPosition::kNoSource, value);
+ Push(instr);
+ return Fragment(instr);
+}
+
+
+Fragment FlowGraphBuilder::AssertAssignable(const dart::AbstractType& dst_type,
+ const dart::String& dst_name) {
+ Fragment instructions;
+ Value* value = Pop();
+
+ instructions += LoadInstantiatorTypeArguments();
+ Value* type_args = Pop();
+
+ AssertAssignableInstr* instr = new (Z)
+ AssertAssignableInstr(TokenPosition::kNoSource, value, type_args,
+ dst_type, dst_name, H.thread()->GetNextDeoptId());
+ Push(instr);
+
+ instructions += Fragment(instr);
+
+ return instructions;
+}
+
+
FlowGraph* FlowGraphBuilder::BuildGraphOfMethodExtractor(
const Function& method) {
// A method extractor is the implicit getter for a method.
@@ -3906,10 +4027,14 @@ Fragment FlowGraphBuilder::TranslateStatement(Statement* statement) {
Fragment FlowGraphBuilder::TranslateCondition(Expression* expression,
bool* negate) {
*negate = expression->IsNot();
+ Fragment instructions;
if (*negate) {
- return TranslateExpression(Not::Cast(expression)->expression());
+ instructions += TranslateExpression(Not::Cast(expression)->expression());
+ } else {
+ instructions += TranslateExpression(expression);
}
- return TranslateExpression(expression);
+ instructions += CheckBooleanInCheckedMode();
+ return instructions;
}
@@ -4300,6 +4425,7 @@ void FlowGraphBuilder::VisitVariableGet(VariableGet* node) {
void FlowGraphBuilder::VisitVariableSet(VariableSet* node) {
Fragment instructions = TranslateExpression(node->expression());
+ instructions += CheckVariableTypeInCheckedMode(node->variable());
instructions +=
StoreLocal(node->position(), LookupVariable(node->variable()));
fragment_ = instructions;
@@ -4349,7 +4475,10 @@ void FlowGraphBuilder::VisitStaticSet(StaticSet* node) {
Field* kernel_field = Field::Cast(target);
const dart::Field& field =
dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(kernel_field));
+ const AbstractType& dst_type = AbstractType::ZoneHandle(Z, field.type());
Fragment instructions = TranslateExpression(node->expression());
+ instructions += CheckAssignableInCheckedMode(
+ dst_type, dart::String::ZoneHandle(Z, field.name()));
LocalVariable* variable = MakeTemporary();
instructions += LoadLocal(variable);
fragment_ = instructions + StoreStaticField(field);
@@ -4620,6 +4749,41 @@ void FlowGraphBuilder::VisitConstructorInvocation(ConstructorInvocation* node) {
dart::Class::ZoneHandle(Z, H.LookupClassByKernelClass(kernel_class));
Fragment instructions;
+
+ // Check for malbounded-ness of type.
+ if (I->type_checks()) {
+ List<DartType>& kernel_type_arguments = node->arguments()->types();
+ const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments(
+ klass, kernel_type_arguments.raw_array(),
+ kernel_type_arguments.length());
+
+ AbstractType& type = AbstractType::Handle(
+ Z, Type::New(klass, type_arguments, TokenPosition::kNoSource));
+ type = ClassFinalizer::FinalizeType(klass, type,
+ ClassFinalizer::kCanonicalize);
+
+ if (type.IsMalbounded()) {
+ // Evaluate expressions for correctness.
+ List<Expression>& positional = node->arguments()->positional();
+ List<NamedExpression>& named = node->arguments()->named();
+ for (intptr_t i = 0; i < positional.length(); ++i) {
+ instructions += TranslateExpression(positional[i]);
+ instructions += Drop();
+ }
+ for (intptr_t i = 0; i < named.length(); ++i) {
+ instructions += TranslateExpression(named[i]->expression());
+ instructions += Drop();
+ }
+
+ // Throw an error & keep the [Value] on the stack.
+ instructions += ThrowTypeError();
+
+ // Bail out early.
+ fragment_ = instructions;
+ return;
+ }
+ }
+
if (klass.NumTypeArguments() > 0) {
List<DartType>& kernel_type_arguments = node->arguments()->types();
const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments(
@@ -4824,7 +4988,9 @@ void FlowGraphBuilder::VisitLogicalExpression(LogicalExpression* node) {
void FlowGraphBuilder::VisitNot(Not* node) {
Fragment instructions = TranslateExpression(node->expression());
- fragment_ = instructions + BooleanNegate();
+ instructions += CheckBooleanInCheckedMode();
+ instructions += BooleanNegate();
+ fragment_ = instructions;
}
@@ -5084,6 +5250,7 @@ void FlowGraphBuilder::VisitVariableDeclaration(VariableDeclaration* node) {
instructions += Constant(constant_value);
} else {
instructions += TranslateExpression(initializer);
+ instructions += CheckVariableTypeInCheckedMode(node);
}
}
instructions += StoreLocal(variable->token_pos(), variable);
@@ -5548,10 +5715,20 @@ void FlowGraphBuilder::VisitAssertStatement(AssertStatement* node) {
TargetEntryInstr* then;
TargetEntryInstr* otherwise;
- bool negate;
Fragment instructions;
- instructions += TranslateCondition(node->condition(), &negate);
- instructions += BranchIfTrue(&then, &otherwise, negate);
+ // 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 += TranslateExpression(node->condition());
+ instructions += PushArgument();
+ instructions += EvaluateAssertion();
+ instructions += CheckBooleanInCheckedMode();
+ instructions += Constant(Bool::True());
+ instructions += BranchIfEqual(&then, &otherwise, false);
const dart::Class& klass = dart::Class::ZoneHandle(
Z, dart::Library::LookupCoreClass(Symbols::AssertionError()));
@@ -5574,10 +5751,7 @@ void FlowGraphBuilder::VisitAssertStatement(AssertStatement* node) {
otherwise_fragment += LoadLocal(instance);
otherwise_fragment += PushArgument(); // this
- otherwise_fragment +=
- node->message() != NULL
- ? TranslateExpression(node->message())
- : Constant(H.DartString("<no message>", Heap::kOld));
+ otherwise_fragment += Constant(H.DartString("<no message>", Heap::kOld));
otherwise_fragment += PushArgument(); // failedAssertion
otherwise_fragment += Constant(url);
@@ -5589,7 +5763,10 @@ void FlowGraphBuilder::VisitAssertStatement(AssertStatement* node) {
otherwise_fragment += IntConstant(0);
otherwise_fragment += PushArgument(); // column
- otherwise_fragment += Constant(H.DartString("<no message>", Heap::kOld));
+ otherwise_fragment +=
+ node->message() != NULL
+ ? TranslateExpression(node->message())
+ : Constant(H.DartString("<no message>", Heap::kOld));
otherwise_fragment += PushArgument(); // message
otherwise_fragment += StaticCall(TokenPosition::kNoSource, constructor, 6);
« no previous file with comments | « runtime/vm/kernel_to_il.h ('k') | tests/language/language_kernel.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698