Chromium Code Reviews| 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..601b6fa246415ddd79748b0b79543a209faecc4d 100644 |
| --- a/runtime/vm/kernel_to_il.cc |
| +++ b/runtime/vm/kernel_to_il.cc |
| @@ -1770,9 +1770,10 @@ void ConstantEvaluator::VisitStringConcatenation(StringConcatenation* node) { |
| void ConstantEvaluator::VisitConditionalExpression( |
| ConditionalExpression* node) { |
| EvaluateExpression(node->condition()); |
| - if (Bool::Cast(result_).value()) { |
| + if (result_.raw() == Bool::True().raw()) { |
| EvaluateExpression(node->then()); |
| } else { |
| + MaybeCheckBool(); |
| EvaluateExpression(node->otherwise()); |
| } |
| } |
| @@ -1781,14 +1782,18 @@ void ConstantEvaluator::VisitConditionalExpression( |
| void ConstantEvaluator::VisitLogicalExpression(LogicalExpression* node) { |
| if (node->op() == LogicalExpression::kAnd) { |
| EvaluateExpression(node->left()); |
| + MaybeCheckBool(); |
|
Vyacheslav Egorov (Google)
2017/01/30 18:30:28
Consider making a helper:
EvaluateBooleanExpres
kustermann
2017/01/31 10:39:45
Done.
|
| if (Bool::Cast(result_).value()) { |
| EvaluateExpression(node->right()); |
| + MaybeCheckBool(); |
| } |
| } else { |
| ASSERT(node->op() == LogicalExpression::kOr); |
| EvaluateExpression(node->left()); |
| + MaybeCheckBool(); |
| if (!Bool::Cast(result_).value()) { |
| EvaluateExpression(node->right()); |
| + MaybeCheckBool(); |
| } |
| } |
| } |
| @@ -1796,9 +1801,12 @@ void ConstantEvaluator::VisitLogicalExpression(LogicalExpression* node) { |
| void ConstantEvaluator::VisitNot(Not* node) { |
| EvaluateExpression(node->expression()); |
| - ASSERT(result_.IsBool()); |
| - result_ = |
| - Bool::Cast(result_).value() ? Bool::False().raw() : Bool::True().raw(); |
| + if (result_.raw() == Bool::True().raw()) { |
| + result_ = Bool::False().raw(); |
| + } else { |
| + MaybeCheckBool(); |
| + result_ = Bool::True().raw(); |
| + } |
| } |
| @@ -2533,12 +2541,19 @@ Fragment FlowGraphBuilder::PushArgument() { |
| Fragment FlowGraphBuilder::Return(TokenPosition position) { |
| + Fragment instructions; |
| + |
| + instructions += MaybeCheckReturnType(); |
|
Vyacheslav Egorov (Google)
2017/01/30 18:30:28
Maybe "maybe" is not a good prefix because it does
kustermann
2017/01/31 10:39:45
Done.
|
| + |
| 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 +2624,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 += |
| + MaybeCheckAssignable(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 +3117,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 += MaybeCheckVariableType(variable); |
| + body += Drop(); |
| + } |
| + for (intptr_t i = 0; i < named.length(); i++) { |
| + VariableDeclaration* variable = named[i]; |
| + body += LoadLocal(LookupVariable(variable)); |
| + body += MaybeCheckVariableType(variable); |
| + body += Drop(); |
| + } |
| + } |
| + |
| if (dart_function.is_native()) { |
| body += NativeFunctionBody(function, dart_function); |
| } else if (function->body() != NULL) { |
| @@ -3465,6 +3509,96 @@ Fragment FlowGraphBuilder::GuardFieldClass(const dart::Field& field, |
| } |
| +Fragment FlowGraphBuilder::MaybeCheckVariableType( |
| + VariableDeclaration* variable) { |
| + if (I->type_checks()) { |
| + const AbstractType& dst_type = T.TranslateType(variable->type()); |
| + if (dst_type.IsMalformed()) { |
| + return ThrowTypeError(); |
| + } |
| + return MaybeCheckAssignable(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::MaybeCheckReturnType() { |
| + if (I->type_checks()) { |
| + const AbstractType& return_type = |
| + AbstractType::Handle(Z, parsed_function_->function().result_type()); |
| + return MaybeCheckAssignable(return_type, Symbols::FunctionResult()); |
| + } |
| + return Fragment(); |
| +} |
| + |
| + |
| +Fragment FlowGraphBuilder::MaybeCheckBool() { |
| + Fragment instructions; |
| + if (I->type_checks()) { |
| + LocalVariable* top_of_stack = MakeTemporary(); |
| + instructions += LoadLocal(top_of_stack); |
| + instructions += AssertBool(); |
| + instructions += Drop(); |
| + } |
| + return instructions; |
| +} |
| + |
| + |
| +Fragment FlowGraphBuilder::MaybeCheckAssignable( |
| + 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 +4040,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 += MaybeCheckBool(); |
| + return instructions; |
| } |
| @@ -4300,6 +4438,7 @@ void FlowGraphBuilder::VisitVariableGet(VariableGet* node) { |
| void FlowGraphBuilder::VisitVariableSet(VariableSet* node) { |
| Fragment instructions = TranslateExpression(node->expression()); |
| + instructions += MaybeCheckVariableType(node->variable()); |
| instructions += |
| StoreLocal(node->position(), LookupVariable(node->variable())); |
| fragment_ = instructions; |
| @@ -4349,7 +4488,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 += MaybeCheckAssignable( |
| + dst_type, dart::String::ZoneHandle(Z, field.name())); |
| LocalVariable* variable = MakeTemporary(); |
| instructions += LoadLocal(variable); |
| fragment_ = instructions + StoreStaticField(field); |
| @@ -4620,6 +4762,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 +5001,9 @@ void FlowGraphBuilder::VisitLogicalExpression(LogicalExpression* node) { |
| void FlowGraphBuilder::VisitNot(Not* node) { |
| Fragment instructions = TranslateExpression(node->expression()); |
| - fragment_ = instructions + BooleanNegate(); |
| + instructions += MaybeCheckBool(); |
| + instructions += BooleanNegate(); |
| + fragment_ = instructions; |
| } |
| @@ -5078,12 +5257,14 @@ void FlowGraphBuilder::VisitVariableDeclaration(VariableDeclaration* node) { |
| instructions += NullConstant(); |
| } else { |
| if (node->IsConst()) { |
| + // FIXME(checked-mode) |
|
Vyacheslav Egorov (Google)
2017/01/30 18:30:28
Needs to be
// TODO(issue-number) some comment
kustermann
2017/01/31 10:39:45
I'll remove the TODO. The ConstantEvaluator has be
|
| const Instance& constant_value = |
| constant_evaluator_.EvaluateExpression(initializer); |
| variable->SetConstValue(constant_value); |
| instructions += Constant(constant_value); |
| } else { |
| instructions += TranslateExpression(initializer); |
| + instructions += MaybeCheckVariableType(node); |
| } |
| } |
| instructions += StoreLocal(variable->token_pos(), variable); |
| @@ -5548,10 +5729,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 += MaybeCheckBool(); |
| + instructions += Constant(Bool::True()); |
| + instructions += BranchIfEqual(&then, &otherwise, false); |
| const dart::Class& klass = dart::Class::ZoneHandle( |
| Z, dart::Library::LookupCoreClass(Symbols::AssertionError())); |
| @@ -5574,10 +5765,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 +5777,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); |