OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #include <map> |
| 6 #include <set> |
| 7 #include <string> |
| 8 |
| 9 #include "vm/dil_to_il.h" |
| 10 |
| 11 #include "vm/compiler.h" |
| 12 #include "vm/dil_reader.h" |
| 13 #include "vm/intermediate_language.h" |
| 14 #include "vm/longjump.h" |
| 15 #include "vm/method_recognizer.h" |
| 16 #include "vm/object_store.h" |
| 17 #include "vm/report.h" |
| 18 #include "vm/resolver.h" |
| 19 #include "vm/stack_frame.h" |
| 20 |
| 21 namespace dart { |
| 22 |
| 23 DECLARE_FLAG(bool, support_externalizable_strings); |
| 24 |
| 25 namespace dil { |
| 26 |
| 27 #define Z (zone_) |
| 28 #define H (translation_helper_) |
| 29 #define T (type_translator_) |
| 30 #define I Isolate::Current() |
| 31 |
| 32 |
| 33 void ScopeBuilder::EnterScope(TreeNode* node) { |
| 34 scope_ = new (Z) LocalScope(scope_, depth_.function_, depth_.loop_); |
| 35 result_->scopes.Insert(node, scope_); |
| 36 } |
| 37 |
| 38 |
| 39 void ScopeBuilder::ExitScope() { scope_ = scope_->parent(); } |
| 40 |
| 41 |
| 42 LocalVariable* ScopeBuilder::MakeVariable(const dart::String& name) { |
| 43 return new (Z) |
| 44 LocalVariable(TokenPosition::kNoSource, name, Object::dynamic_type()); |
| 45 } |
| 46 |
| 47 |
| 48 LocalVariable* ScopeBuilder::MakeVariable(const dart::String& name, |
| 49 const Type& type) { |
| 50 return new (Z) LocalVariable(TokenPosition::kNoSource, name, type); |
| 51 } |
| 52 |
| 53 |
| 54 void ScopeBuilder::AddParameters(FunctionNode* function, intptr_t pos) { |
| 55 List<VariableDeclaration>& positional = function->positional_parameters(); |
| 56 for (intptr_t i = 0; i < positional.length(); ++i) { |
| 57 AddParameter(positional[i], pos++); |
| 58 } |
| 59 List<VariableDeclaration>& named = function->named_parameters(); |
| 60 for (intptr_t i = 0; i < named.length(); ++i) { |
| 61 AddParameter(named[i], pos++); |
| 62 } |
| 63 } |
| 64 |
| 65 |
| 66 void ScopeBuilder::AddParameter(VariableDeclaration* declaration, |
| 67 intptr_t pos) { |
| 68 // TODO(kmillikin): Handle final. |
| 69 LocalVariable* variable = MakeVariable(H.DartSymbol(declaration->name())); |
| 70 scope_->InsertParameterAt(pos, variable); |
| 71 result_->locals.Insert(declaration, variable); |
| 72 |
| 73 // The default value may contain 'let' bindings for which the constant |
| 74 // evaluator needs scope bindings. |
| 75 Expression* defaultValue = declaration->initializer(); |
| 76 if (defaultValue != NULL) { |
| 77 defaultValue->AcceptExpressionVisitor(this); |
| 78 } |
| 79 } |
| 80 |
| 81 |
| 82 void ScopeBuilder::AddExceptionVariable( |
| 83 GrowableArray<LocalVariable*>* variables, const char* prefix, |
| 84 intptr_t nesting_depth) { |
| 85 LocalVariable* v = NULL; |
| 86 |
| 87 // If we are inside a function with yield points then Kernel transformer |
| 88 // could have lifted some of the auxiliary exception variables into the |
| 89 // context to preserve them across yield points because they might |
| 90 // be needed for rethrow. |
| 91 // Check if it did and capture such variables instead of introducing |
| 92 // new local ones. |
| 93 // Note: function that wrap kSyncYielding function does not contain |
| 94 // its own try/catches. |
| 95 if (current_function_node_->async_marker() == FunctionNode::kSyncYielding) { |
| 96 ASSERT(current_function_scope_->parent() != NULL); |
| 97 v = current_function_scope_->parent()->LocalLookupVariable( |
| 98 GenerateName(prefix, nesting_depth - 1)); |
| 99 if (v != NULL) { |
| 100 scope_->CaptureVariable(v); |
| 101 } |
| 102 } |
| 103 |
| 104 // No need to create variables for try/catch-statements inside |
| 105 // nested functions. |
| 106 if (depth_.function_ > 0) return; |
| 107 if (variables->length() >= nesting_depth) return; |
| 108 |
| 109 // If variable was not lifted by the transformer introduce a new |
| 110 // one into the current function scope. |
| 111 if (v == NULL) { |
| 112 v = MakeVariable(GenerateName(prefix, nesting_depth - 1)); |
| 113 |
| 114 // If transformer did not lift the variable then there is no need |
| 115 // to lift it into the context when we encouter a YieldStatement. |
| 116 v->set_is_forced_stack(); |
| 117 current_function_scope_->AddVariable(v); |
| 118 } |
| 119 |
| 120 variables->Add(v); |
| 121 } |
| 122 |
| 123 |
| 124 void ScopeBuilder::AddTryVariables() { |
| 125 AddExceptionVariable(&result_->catch_context_variables, |
| 126 ":saved_try_context_var", depth_.try_); |
| 127 } |
| 128 |
| 129 |
| 130 void ScopeBuilder::AddCatchVariables() { |
| 131 AddExceptionVariable(&result_->exception_variables, ":exception", |
| 132 depth_.catch_); |
| 133 AddExceptionVariable(&result_->stack_trace_variables, ":stack_trace", |
| 134 depth_.catch_); |
| 135 } |
| 136 |
| 137 |
| 138 void ScopeBuilder::AddIteratorVariable() { |
| 139 if (depth_.function_ > 0) return; |
| 140 if (result_->iterator_variables.length() >= depth_.for_in_) return; |
| 141 |
| 142 ASSERT(result_->iterator_variables.length() == depth_.for_in_ - 1); |
| 143 LocalVariable* iterator = |
| 144 MakeVariable(GenerateName(":iterator", depth_.for_in_ - 1)); |
| 145 current_function_scope_->AddVariable(iterator); |
| 146 result_->iterator_variables.Add(iterator); |
| 147 } |
| 148 |
| 149 |
| 150 void ScopeBuilder::LookupVariable(VariableDeclaration* declaration) { |
| 151 LocalVariable* variable = result_->locals.Lookup(declaration); |
| 152 if (variable == NULL) { |
| 153 // We have not seen a declaration of the variable, so it must be the |
| 154 // case that we are compiling a nested function and the variable is |
| 155 // declared in an outer scope. In that case, look it up in the scope by |
| 156 // name and add it to the variable map to simplify later lookup. |
| 157 ASSERT(current_function_scope_->parent() != NULL); |
| 158 const dart::String& name = H.DartSymbol(declaration->name()); |
| 159 variable = current_function_scope_->parent()->LookupVariable(name, true); |
| 160 ASSERT(variable != NULL); |
| 161 result_->locals.Insert(declaration, variable); |
| 162 } |
| 163 if (variable->owner()->function_level() < scope_->function_level()) { |
| 164 // We call `LocalScope->CaptureVariable(variable)` in two scenarios for two |
| 165 // different reasons: |
| 166 // Scenario 1: |
| 167 // We need to know which variables defined in this function |
| 168 // are closed over by nested closures in order to ensure we will |
| 169 // create a [Context] object of appropriate size and store captured |
| 170 // variables there instead of the stack. |
| 171 // Scenario 2: |
| 172 // We need to find out which variables defined in enclosing functions |
| 173 // are closed over by this function/closure or nested closures. This |
| 174 // is necessary in order to build a fat flattened [ContextScope] |
| 175 // object. |
| 176 scope_->CaptureVariable(variable); |
| 177 } else { |
| 178 ASSERT(variable->owner()->function_level() == scope_->function_level()); |
| 179 } |
| 180 } |
| 181 |
| 182 |
| 183 void ScopeBuilder::LookupCapturedVariableByName(LocalVariable** variable, |
| 184 const dart::String& name) { |
| 185 if (*variable == NULL) { |
| 186 *variable = scope_->LookupVariable(name, true); |
| 187 ASSERT(*variable != NULL); |
| 188 scope_->CaptureVariable(*variable); |
| 189 } |
| 190 } |
| 191 |
| 192 |
| 193 const dart::String& ScopeBuilder::GenerateName(const char* prefix, |
| 194 intptr_t suffix) { |
| 195 char name[64]; |
| 196 OS::SNPrint(name, 64, "%s%" Pd "", prefix, suffix); |
| 197 return H.DartSymbol(name); |
| 198 } |
| 199 |
| 200 |
| 201 void ScopeBuilder::AddVariable(VariableDeclaration* declaration) { |
| 202 // TODO(kmillikin): Handle final and const, including function declarations. |
| 203 const dart::String& name = declaration->name()->is_empty() |
| 204 ? GenerateName(":var", name_index_++) |
| 205 : H.DartSymbol(declaration->name()); |
| 206 LocalVariable* variable = MakeVariable(name); |
| 207 scope_->AddVariable(variable); |
| 208 result_->locals.Insert(declaration, variable); |
| 209 } |
| 210 |
| 211 |
| 212 static bool IsStaticInitializer(const Function& function, Zone* zone) { |
| 213 return (function.kind() == RawFunction::kImplicitStaticFinalGetter) && |
| 214 dart::String::Handle(zone, function.name()) |
| 215 .StartsWith(Symbols::InitPrefix()); |
| 216 } |
| 217 |
| 218 |
| 219 ScopeBuildingResult* ScopeBuilder::BuildScopes() { |
| 220 if (result_ != NULL) return result_; |
| 221 |
| 222 ASSERT(scope_ == NULL && depth_.loop_ == 0 && depth_.function_ == 0); |
| 223 result_ = new (Z) ScopeBuildingResult(); |
| 224 |
| 225 ParsedFunction* parsed_function = parsed_function_; |
| 226 const dart::Function& function = parsed_function->function(); |
| 227 |
| 228 LocalScope* enclosing_scope = NULL; |
| 229 if (function.IsLocalFunction()) { |
| 230 enclosing_scope = LocalScope::RestoreOuterScope( |
| 231 ContextScope::Handle(Z, function.context_scope())); |
| 232 } |
| 233 current_function_scope_ = scope_ = new (Z) LocalScope(enclosing_scope, 0, 0); |
| 234 scope_->AddVariable(parsed_function->EnsureExpressionTemp()); |
| 235 scope_->AddVariable(parsed_function->current_context_var()); |
| 236 parsed_function->SetNodeSequence( |
| 237 new SequenceNode(TokenPosition::kNoSource, scope_)); |
| 238 |
| 239 switch (function.kind()) { |
| 240 case RawFunction::kClosureFunction: |
| 241 case RawFunction::kRegularFunction: |
| 242 case RawFunction::kGetterFunction: |
| 243 case RawFunction::kSetterFunction: |
| 244 case RawFunction::kConstructor: { |
| 245 FunctionNode* node; |
| 246 if (node_->IsProcedure()) { |
| 247 node = Procedure::Cast(node_)->function(); |
| 248 } else if (node_->IsConstructor()) { |
| 249 node = Constructor::Cast(node_)->function(); |
| 250 } else { |
| 251 node = FunctionNode::Cast(node_); |
| 252 } |
| 253 current_function_node_ = node; |
| 254 |
| 255 intptr_t pos = 0; |
| 256 if (function.IsClosureFunction()) { |
| 257 LocalVariable* variable = MakeVariable(Symbols::ClosureParameter()); |
| 258 scope_->InsertParameterAt(pos++, variable); |
| 259 } else if (!function.is_static()) { |
| 260 // We use [is_static] instead of [IsStaticFunction] because the latter |
| 261 // returns `false` for constructors. |
| 262 dart::Class& klass = dart::Class::Handle(Z, function.Owner()); |
| 263 Type& klass_type = H.GetCanonicalType(klass); |
| 264 LocalVariable* variable = MakeVariable(Symbols::This(), klass_type); |
| 265 scope_->InsertParameterAt(pos++, variable); |
| 266 result_->this_variable = variable; |
| 267 |
| 268 // We visit instance field initializers because they might contain |
| 269 // [Let] expressions and we need to have a mapping. |
| 270 if (node_->IsConstructor()) { |
| 271 Class* klass = Class::Cast(Constructor::Cast(node_)->parent()); |
| 272 |
| 273 for (intptr_t i = 0; i < klass->fields().length(); i++) { |
| 274 Field* field = klass->fields()[i]; |
| 275 if (!field->IsStatic() && (field->initializer() != NULL)) { |
| 276 EnterScope(field); |
| 277 field->initializer()->AcceptExpressionVisitor(this); |
| 278 ExitScope(); |
| 279 } |
| 280 } |
| 281 } |
| 282 } else if (function.IsFactory()) { |
| 283 LocalVariable* variable = MakeVariable( |
| 284 Symbols::TypeArgumentsParameter(), AbstractType::dynamic_type()); |
| 285 scope_->InsertParameterAt(pos++, variable); |
| 286 result_->type_arguments_variable = variable; |
| 287 } |
| 288 AddParameters(node, pos); |
| 289 |
| 290 // We generate a syntethic body for implicit closure functions - which |
| 291 // will forward the call to the real function. |
| 292 // -> see BuildGraphOfImplicitClosureFunction |
| 293 if (!function.IsImplicitClosureFunction()) { |
| 294 node_->AcceptVisitor(this); |
| 295 } |
| 296 break; |
| 297 } |
| 298 case RawFunction::kImplicitGetter: |
| 299 case RawFunction::kImplicitStaticFinalGetter: |
| 300 case RawFunction::kImplicitSetter: { |
| 301 ASSERT(node_->IsField()); |
| 302 if (IsStaticInitializer(function, Z)) { |
| 303 node_->AcceptVisitor(this); |
| 304 break; |
| 305 } |
| 306 bool is_setter = function.IsImplicitSetterFunction(); |
| 307 bool is_method = !function.IsStaticFunction(); |
| 308 intptr_t pos = 0; |
| 309 if (is_method) { |
| 310 dart::Class& klass = dart::Class::Handle(Z, function.Owner()); |
| 311 Type& klass_type = H.GetCanonicalType(klass); |
| 312 LocalVariable* variable = MakeVariable(Symbols::This(), klass_type); |
| 313 scope_->InsertParameterAt(pos++, variable); |
| 314 result_->this_variable = variable; |
| 315 } |
| 316 if (is_setter) { |
| 317 result_->setter_value = MakeVariable(Symbols::Value()); |
| 318 scope_->InsertParameterAt(pos++, result_->setter_value); |
| 319 } |
| 320 break; |
| 321 } |
| 322 case RawFunction::kMethodExtractor: { |
| 323 // Add a receiver parameter. Though it is captured, we emit code to |
| 324 // explicitly copy it to a fixed offset in a freshly-allocated context |
| 325 // instead of using the generic code for regular functions. |
| 326 // Therefore, it isn't necessary to mark it as captured here. |
| 327 dart::Class& klass = dart::Class::Handle(Z, function.Owner()); |
| 328 Type& klass_type = H.GetCanonicalType(klass); |
| 329 LocalVariable* variable = MakeVariable(Symbols::This(), klass_type); |
| 330 scope_->InsertParameterAt(0, variable); |
| 331 result_->this_variable = variable; |
| 332 break; |
| 333 } |
| 334 case RawFunction::kNoSuchMethodDispatcher: |
| 335 case RawFunction::kInvokeFieldDispatcher: |
| 336 for (intptr_t i = 0; i < function.NumParameters(); ++i) { |
| 337 LocalVariable* variable = MakeVariable( |
| 338 dart::String::ZoneHandle(Z, function.ParameterNameAt(i))); |
| 339 scope_->InsertParameterAt(i, variable); |
| 340 } |
| 341 break; |
| 342 case RawFunction::kSignatureFunction: |
| 343 case RawFunction::kIrregexpFunction: |
| 344 UNREACHABLE(); |
| 345 } |
| 346 |
| 347 parsed_function->AllocateVariables(); |
| 348 |
| 349 return result_; |
| 350 } |
| 351 |
| 352 |
| 353 void ScopeBuilder::VisitThisExpression(ThisExpression* node) { |
| 354 HandleSpecialLoad(&result_->this_variable, Symbols::This()); |
| 355 } |
| 356 |
| 357 |
| 358 void ScopeBuilder::VisitTypeParameterType(TypeParameterType* node) { |
| 359 Function& function = Function::Handle(Z, parsed_function_->function().raw()); |
| 360 while (function.IsClosureFunction()) { |
| 361 function = function.parent_function(); |
| 362 } |
| 363 |
| 364 if (function.IsFactory()) { |
| 365 // The type argument vector is passed as the very first argument to the |
| 366 // factory constructor function. |
| 367 HandleSpecialLoad(&result_->type_arguments_variable, |
| 368 Symbols::TypeArgumentsParameter()); |
| 369 } else { |
| 370 // The type argument vector is stored on the instance object. We therefore |
| 371 // need to capture `this`. |
| 372 HandleSpecialLoad(&result_->this_variable, Symbols::This()); |
| 373 } |
| 374 } |
| 375 |
| 376 |
| 377 void ScopeBuilder::VisitVariableGet(VariableGet* node) { |
| 378 LookupVariable(node->variable()); |
| 379 } |
| 380 |
| 381 |
| 382 void ScopeBuilder::VisitVariableSet(VariableSet* node) { |
| 383 LookupVariable(node->variable()); |
| 384 node->VisitChildren(this); |
| 385 } |
| 386 |
| 387 |
| 388 void ScopeBuilder::HandleLocalFunction(TreeNode* parent, |
| 389 FunctionNode* function) { |
| 390 LocalScope* saved_function_scope = current_function_scope_; |
| 391 FunctionNode* saved_function_node = current_function_node_; |
| 392 ScopeBuilder::DepthState saved_depth_state = depth_; |
| 393 depth_ = DepthState(depth_.function_ + 1); |
| 394 EnterScope(parent); |
| 395 current_function_scope_ = scope_; |
| 396 current_function_node_ = function; |
| 397 if (depth_.function_ == 1) { |
| 398 FunctionScope function_scope = { function, scope_ }; |
| 399 result_->function_scopes.Add(function_scope); |
| 400 } |
| 401 AddParameters(function); |
| 402 VisitFunctionNode(function); |
| 403 ExitScope(); |
| 404 depth_ = saved_depth_state; |
| 405 current_function_scope_ = saved_function_scope; |
| 406 current_function_node_ = saved_function_node; |
| 407 } |
| 408 |
| 409 |
| 410 void ScopeBuilder::HandleSpecialLoad(LocalVariable** variable, |
| 411 const dart::String& symbol) { |
| 412 if (current_function_scope_->parent() != NULL) { |
| 413 // We are building the scope tree of a closure function and saw [node]. We |
| 414 // lazily populate the variable using the parent function scope. |
| 415 if (*variable == NULL) { |
| 416 *variable = |
| 417 current_function_scope_->parent()->LookupVariable(symbol, true); |
| 418 ASSERT(*variable != NULL); |
| 419 } |
| 420 } |
| 421 |
| 422 if ((current_function_scope_->parent() != NULL) || |
| 423 (scope_->function_level() > 0)) { |
| 424 // Every scope we use the [variable] from needs to be notified of the usage |
| 425 // in order to ensure that preserving the context scope on that particular |
| 426 // use-site also includes the [variable]. |
| 427 scope_->CaptureVariable(*variable); |
| 428 } |
| 429 } |
| 430 |
| 431 |
| 432 void ScopeBuilder::VisitFunctionExpression(FunctionExpression* node) { |
| 433 HandleLocalFunction(node, node->function()); |
| 434 } |
| 435 |
| 436 |
| 437 void ScopeBuilder::VisitLet(Let* node) { |
| 438 EnterScope(node); |
| 439 node->VisitChildren(this); |
| 440 ExitScope(); |
| 441 } |
| 442 |
| 443 |
| 444 void ScopeBuilder::VisitBlock(Block* node) { |
| 445 EnterScope(node); |
| 446 node->VisitChildren(this); |
| 447 ExitScope(); |
| 448 } |
| 449 |
| 450 |
| 451 void ScopeBuilder::VisitVariableDeclaration(VariableDeclaration* node) { |
| 452 AddVariable(node); |
| 453 node->VisitChildren(this); |
| 454 } |
| 455 |
| 456 |
| 457 void ScopeBuilder::VisitFunctionDeclaration(FunctionDeclaration* node) { |
| 458 VisitVariableDeclaration(node->variable()); |
| 459 HandleLocalFunction(node, node->function()); |
| 460 } |
| 461 |
| 462 |
| 463 void ScopeBuilder::VisitWhileStatement(WhileStatement* node) { |
| 464 ++depth_.loop_; |
| 465 node->VisitChildren(this); |
| 466 --depth_.loop_; |
| 467 } |
| 468 |
| 469 |
| 470 void ScopeBuilder::VisitDoStatement(DoStatement* node) { |
| 471 ++depth_.loop_; |
| 472 node->VisitChildren(this); |
| 473 --depth_.loop_; |
| 474 } |
| 475 |
| 476 |
| 477 void ScopeBuilder::VisitForStatement(ForStatement* node) { |
| 478 EnterScope(node); |
| 479 List<VariableDeclaration>& variables = node->variables(); |
| 480 for (intptr_t i = 0; i < variables.length(); ++i) { |
| 481 VisitVariableDeclaration(variables[i]); |
| 482 } |
| 483 ++depth_.loop_; |
| 484 if (node->condition() != NULL) { |
| 485 node->condition()->AcceptExpressionVisitor(this); |
| 486 } |
| 487 node->body()->AcceptStatementVisitor(this); |
| 488 List<Expression>& updates = node->updates(); |
| 489 for (intptr_t i = 0; i < updates.length(); ++i) { |
| 490 updates[i]->AcceptExpressionVisitor(this); |
| 491 } |
| 492 --depth_.loop_; |
| 493 ExitScope(); |
| 494 } |
| 495 |
| 496 |
| 497 void ScopeBuilder::VisitForInStatement(ForInStatement* node) { |
| 498 node->iterable()->AcceptExpressionVisitor(this); |
| 499 ++depth_.for_in_; |
| 500 AddIteratorVariable(); |
| 501 ++depth_.loop_; |
| 502 EnterScope(node); |
| 503 VisitVariableDeclaration(node->variable()); |
| 504 node->body()->AcceptStatementVisitor(this); |
| 505 ExitScope(); |
| 506 --depth_.loop_; |
| 507 --depth_.for_in_; |
| 508 } |
| 509 |
| 510 |
| 511 void ScopeBuilder::AddSwitchVariable() { |
| 512 if ((depth_.function_ == 0) && (result_->switch_variable == NULL)) { |
| 513 LocalVariable* variable = MakeVariable(Symbols::SwitchExpr()); |
| 514 current_function_scope_->AddVariable(variable); |
| 515 result_->switch_variable = variable; |
| 516 } |
| 517 } |
| 518 |
| 519 |
| 520 void ScopeBuilder::VisitSwitchStatement(SwitchStatement* node) { |
| 521 AddSwitchVariable(); |
| 522 node->VisitChildren(this); |
| 523 } |
| 524 |
| 525 |
| 526 void ScopeBuilder::VisitReturnStatement(ReturnStatement* node) { |
| 527 if ((depth_.function_ == 0) && (depth_.finally_ > 0) && |
| 528 (result_->finally_return_variable == NULL)) { |
| 529 const dart::String& name = H.DartSymbol(":try_finally_return_value"); |
| 530 LocalVariable* variable = MakeVariable(name); |
| 531 current_function_scope_->AddVariable(variable); |
| 532 result_->finally_return_variable = variable; |
| 533 } |
| 534 node->VisitChildren(this); |
| 535 } |
| 536 |
| 537 |
| 538 void ScopeBuilder::VisitTryCatch(TryCatch* node) { |
| 539 ++depth_.try_; |
| 540 AddTryVariables(); |
| 541 node->body()->AcceptStatementVisitor(this); |
| 542 --depth_.try_; |
| 543 |
| 544 ++depth_.catch_; |
| 545 AddCatchVariables(); |
| 546 List<Catch>& catches = node->catches(); |
| 547 for (intptr_t i = 0; i < catches.length(); ++i) { |
| 548 Catch* ketch = catches[i]; |
| 549 EnterScope(ketch); |
| 550 if (ketch->exception() != NULL) { |
| 551 VisitVariableDeclaration(ketch->exception()); |
| 552 } |
| 553 if (ketch->stack_trace() != NULL) { |
| 554 VisitVariableDeclaration(ketch->stack_trace()); |
| 555 } |
| 556 ketch->body()->AcceptStatementVisitor(this); |
| 557 ExitScope(); |
| 558 } |
| 559 --depth_.catch_; |
| 560 } |
| 561 |
| 562 |
| 563 void ScopeBuilder::VisitTryFinally(TryFinally* node) { |
| 564 ++depth_.try_; |
| 565 ++depth_.finally_; |
| 566 AddTryVariables(); |
| 567 node->body()->AcceptStatementVisitor(this); |
| 568 --depth_.finally_; |
| 569 --depth_.try_; |
| 570 |
| 571 ++depth_.catch_; |
| 572 AddCatchVariables(); |
| 573 node->finalizer()->AcceptStatementVisitor(this); |
| 574 --depth_.catch_; |
| 575 } |
| 576 |
| 577 |
| 578 void ScopeBuilder::VisitFunctionNode(FunctionNode* node) { |
| 579 List<TypeParameter>& type_parameters = node->type_parameters(); |
| 580 for (intptr_t i = 0; i < type_parameters.length(); ++i) { |
| 581 VisitTypeParameter(type_parameters[i]); |
| 582 } |
| 583 // Do not visit the positional and named parameters, because they've |
| 584 // already been added to the scope. |
| 585 if (node->body() != NULL) { |
| 586 node->body()->AcceptStatementVisitor(this); |
| 587 } |
| 588 |
| 589 // Ensure that :await_jump_var and :await_ctx_var are captured. |
| 590 if (node->async_marker() == FunctionNode::kSyncYielding) { |
| 591 { |
| 592 LocalVariable* temp = NULL; |
| 593 LookupCapturedVariableByName( |
| 594 (depth_.function_ == 0) ? &result_->yield_jump_variable : &temp, |
| 595 Symbols::AwaitJumpVar()); |
| 596 } |
| 597 { |
| 598 LocalVariable* temp = NULL; |
| 599 LookupCapturedVariableByName( |
| 600 (depth_.function_ == 0) ? &result_->yield_context_variable : &temp, |
| 601 Symbols::AwaitContextVar()); |
| 602 } |
| 603 } |
| 604 } |
| 605 |
| 606 |
| 607 void ScopeBuilder::VisitYieldStatement(YieldStatement* node) { |
| 608 ASSERT(node->is_native()); |
| 609 if (depth_.function_ == 0) { |
| 610 AddSwitchVariable(); |
| 611 // Promote all currently visible local variables into the context. |
| 612 // TODO(vegorov) we don't need to promote those variables that are |
| 613 // not used across yields. |
| 614 scope_->CaptureLocalVariables(current_function_scope_); |
| 615 } |
| 616 } |
| 617 |
| 618 |
| 619 void ScopeBuilder::VisitAssertStatement(AssertStatement* node) { |
| 620 if (I->asserts()) { |
| 621 RecursiveVisitor::VisitAssertStatement(node); |
| 622 } |
| 623 } |
| 624 |
| 625 |
| 626 void ScopeBuilder::VisitConstructor(Constructor* node) { |
| 627 // Field initializers that come from non-static field declarations are |
| 628 // compiled as if they appear in the constructor initializer list. This is |
| 629 // important for closure-valued field initializers because the VM expects the |
| 630 // corresponding closure functions to appear as if they were nested inside the |
| 631 // constructor. |
| 632 List<Field>& fields = Class::Cast(node->parent())->fields(); |
| 633 for (intptr_t i = 0; i < fields.length(); ++i) { |
| 634 Field* field = fields[i]; |
| 635 Expression* initializer = field->initializer(); |
| 636 if (!field->IsStatic() && (initializer != NULL)) { |
| 637 initializer->AcceptExpressionVisitor(this); |
| 638 } |
| 639 } |
| 640 node->VisitChildren(this); |
| 641 } |
| 642 |
| 643 |
| 644 class BreakableBlock { |
| 645 public: |
| 646 BreakableBlock(FlowGraphBuilder* builder, LabeledStatement* statement) |
| 647 : builder_(builder), |
| 648 labeled_statement_(statement), |
| 649 outer_(builder->breakable_block_), |
| 650 destination_(NULL), |
| 651 outer_finally_(builder->try_finally_block_), |
| 652 context_depth_(builder->context_depth_) { |
| 653 builder_->breakable_block_ = this; |
| 654 } |
| 655 ~BreakableBlock() { builder_->breakable_block_ = outer_; } |
| 656 |
| 657 bool HadJumper() { return destination_ != NULL; } |
| 658 |
| 659 JoinEntryInstr* destination() { return destination_; } |
| 660 |
| 661 JoinEntryInstr* BreakDestination(LabeledStatement* label, |
| 662 TryFinallyBlock** outer_finally, |
| 663 intptr_t* context_depth) { |
| 664 BreakableBlock* block = builder_->breakable_block_; |
| 665 while (block->labeled_statement_ != label) { |
| 666 block = block->outer_; |
| 667 } |
| 668 ASSERT(block != NULL); |
| 669 *outer_finally = block->outer_finally_; |
| 670 *context_depth = block->context_depth_; |
| 671 return block->EnsureDestination(); |
| 672 } |
| 673 |
| 674 private: |
| 675 JoinEntryInstr* EnsureDestination() { |
| 676 if (destination_ == NULL) { |
| 677 destination_ = builder_->BuildJoinEntry(); |
| 678 } |
| 679 return destination_; |
| 680 } |
| 681 |
| 682 FlowGraphBuilder* builder_; |
| 683 LabeledStatement* labeled_statement_; |
| 684 BreakableBlock* outer_; |
| 685 JoinEntryInstr* destination_; |
| 686 TryFinallyBlock* outer_finally_; |
| 687 intptr_t context_depth_; |
| 688 }; |
| 689 |
| 690 |
| 691 class SwitchBlock { |
| 692 public: |
| 693 SwitchBlock(FlowGraphBuilder* builder, SwitchStatement* switch_stmt) |
| 694 : builder_(builder), |
| 695 outer_(builder->switch_block_), |
| 696 outer_finally_(builder->try_finally_block_), |
| 697 switch_statement_(switch_stmt), |
| 698 context_depth_(builder->context_depth_) { |
| 699 builder_->switch_block_ = this; |
| 700 } |
| 701 ~SwitchBlock() { builder_->switch_block_ = outer_; } |
| 702 |
| 703 bool HadJumper(SwitchCase* switch_case) { |
| 704 return destinations_.Lookup(switch_case) != NULL; |
| 705 } |
| 706 |
| 707 JoinEntryInstr* Destination(SwitchCase* label, |
| 708 TryFinallyBlock** outer_finally = NULL, |
| 709 intptr_t* context_depth = NULL) { |
| 710 // Find corresponding [SwitchStatement]. |
| 711 SwitchBlock* block = this; |
| 712 while (true) { |
| 713 block->EnsureSwitchCaseMapping(); |
| 714 if (block->Contains(label)) break; |
| 715 block = block->outer_; |
| 716 } |
| 717 |
| 718 // Set the outer finally block. |
| 719 if (outer_finally != NULL) { |
| 720 *outer_finally = block->outer_finally_; |
| 721 *context_depth = block->context_depth_; |
| 722 } |
| 723 |
| 724 // Ensure there's [JoinEntryInstr] for that [SwitchCase]. |
| 725 return block->EnsureDestination(label); |
| 726 } |
| 727 |
| 728 private: |
| 729 typedef std::set<SwitchCase*> DestinationSwitches; |
| 730 |
| 731 JoinEntryInstr* EnsureDestination(SwitchCase* switch_case) { |
| 732 JoinEntryInstr* cached_inst = destinations_.Lookup(switch_case); |
| 733 if (cached_inst == NULL) { |
| 734 JoinEntryInstr* inst = builder_->BuildJoinEntry(); |
| 735 destinations_.Insert(switch_case, inst); |
| 736 return inst; |
| 737 } |
| 738 return cached_inst; |
| 739 } |
| 740 |
| 741 void EnsureSwitchCaseMapping() { |
| 742 if (destination_switches_.begin() == destination_switches_.end()) { |
| 743 List<SwitchCase>& cases = switch_statement_->cases(); |
| 744 for (intptr_t i = 0; i < cases.length(); i++) { |
| 745 destination_switches_.insert(cases[i]); |
| 746 } |
| 747 } |
| 748 } |
| 749 |
| 750 bool Contains(SwitchCase* sc) { |
| 751 return destination_switches_.find(sc) != destination_switches_.end(); |
| 752 } |
| 753 |
| 754 FlowGraphBuilder* builder_; |
| 755 SwitchBlock* outer_; |
| 756 |
| 757 Map<SwitchCase, JoinEntryInstr*> destinations_; |
| 758 DestinationSwitches destination_switches_; |
| 759 |
| 760 TryFinallyBlock* outer_finally_; |
| 761 SwitchStatement* switch_statement_; |
| 762 intptr_t context_depth_; |
| 763 }; |
| 764 |
| 765 |
| 766 class TryFinallyBlock { |
| 767 public: |
| 768 TryFinallyBlock(FlowGraphBuilder* builder, Statement* finalizer) |
| 769 : builder_(builder), |
| 770 outer_(builder->try_finally_block_), |
| 771 finalizer_(finalizer), |
| 772 context_depth_(builder->context_depth_), |
| 773 // Finalizers are executed outside of the try block hence |
| 774 // try depth of finalizers are one less than current try |
| 775 // depth. |
| 776 try_depth_(builder->try_depth_ - 1) { |
| 777 builder_->try_finally_block_ = this; |
| 778 } |
| 779 ~TryFinallyBlock() { builder_->try_finally_block_ = outer_; } |
| 780 |
| 781 Statement* finalizer() const { return finalizer_; } |
| 782 intptr_t context_depth() const { return context_depth_; } |
| 783 intptr_t try_depth() const { return try_depth_; } |
| 784 TryFinallyBlock* outer() const { return outer_; } |
| 785 |
| 786 private: |
| 787 FlowGraphBuilder* const builder_; |
| 788 TryFinallyBlock* const outer_; |
| 789 Statement* const finalizer_; |
| 790 const intptr_t context_depth_; |
| 791 const intptr_t try_depth_; |
| 792 }; |
| 793 |
| 794 |
| 795 class TryCatchBlock { |
| 796 public: |
| 797 explicit TryCatchBlock(FlowGraphBuilder* builder, |
| 798 intptr_t try_handler_index = -1) |
| 799 : builder_(builder), |
| 800 outer_(builder->try_catch_block_), |
| 801 try_index_(try_handler_index) { |
| 802 if (try_index_ == -1) try_index_ = builder->AllocateTryIndex(); |
| 803 builder->try_catch_block_ = this; |
| 804 } |
| 805 ~TryCatchBlock() { builder_->try_catch_block_ = outer_; } |
| 806 |
| 807 intptr_t TryIndex() { return try_index_; } |
| 808 |
| 809 private: |
| 810 FlowGraphBuilder* builder_; |
| 811 TryCatchBlock* outer_; |
| 812 intptr_t try_index_; |
| 813 }; |
| 814 |
| 815 |
| 816 class CatchBlock { |
| 817 public: |
| 818 CatchBlock(FlowGraphBuilder* builder, LocalVariable* exception_var, |
| 819 LocalVariable* stack_trace_var, intptr_t catch_try_index) |
| 820 : builder_(builder), |
| 821 outer_(builder->catch_block_), |
| 822 exception_var_(exception_var), |
| 823 stack_trace_var_(stack_trace_var), |
| 824 catch_try_index_(catch_try_index) { |
| 825 builder_->catch_block_ = this; |
| 826 } |
| 827 ~CatchBlock() { builder_->catch_block_ = outer_; } |
| 828 |
| 829 LocalVariable* exception_var() { return exception_var_; } |
| 830 LocalVariable* stack_trace_var() { return stack_trace_var_; } |
| 831 intptr_t catch_try_index() { return catch_try_index_; } |
| 832 |
| 833 private: |
| 834 FlowGraphBuilder* builder_; |
| 835 CatchBlock* outer_; |
| 836 LocalVariable* exception_var_; |
| 837 LocalVariable* stack_trace_var_; |
| 838 intptr_t catch_try_index_; |
| 839 }; |
| 840 |
| 841 |
| 842 Fragment& Fragment::operator+=(const Fragment& other) { |
| 843 if (entry == NULL) { |
| 844 entry = other.entry; |
| 845 current = other.current; |
| 846 } else if (current != NULL && other.entry != NULL) { |
| 847 current->LinkTo(other.entry); |
| 848 current = other.current; |
| 849 } |
| 850 return *this; |
| 851 } |
| 852 |
| 853 |
| 854 Fragment& Fragment::operator<<=(Instruction* next) { |
| 855 if (entry == NULL) { |
| 856 entry = current = next; |
| 857 } else if (current != NULL) { |
| 858 current->LinkTo(next); |
| 859 current = next; |
| 860 } |
| 861 return *this; |
| 862 } |
| 863 |
| 864 |
| 865 Fragment Fragment::closed() { |
| 866 ASSERT(entry != NULL); |
| 867 return Fragment(entry, NULL); |
| 868 } |
| 869 |
| 870 |
| 871 Fragment operator+(const Fragment& first, const Fragment& second) { |
| 872 Fragment result = first; |
| 873 result += second; |
| 874 return result; |
| 875 } |
| 876 |
| 877 |
| 878 Fragment operator<<(const Fragment& fragment, Instruction* next) { |
| 879 Fragment result = fragment; |
| 880 result <<= next; |
| 881 return result; |
| 882 } |
| 883 |
| 884 |
| 885 RawInstance* TranslationHelper::Canonicalize(const Instance& instance) { |
| 886 if (instance.IsNull()) return instance.raw(); |
| 887 |
| 888 const char* error_str = NULL; |
| 889 RawInstance* result = instance.CheckAndCanonicalize(thread(), &error_str); |
| 890 if (result == Object::null()) { |
| 891 ReportError("Invalid const object %s", error_str); |
| 892 } |
| 893 return result; |
| 894 } |
| 895 |
| 896 |
| 897 const dart::String& TranslationHelper::DartString(const char* content, |
| 898 Heap::Space space) { |
| 899 return dart::String::ZoneHandle(Z, dart::String::New(content, space)); |
| 900 } |
| 901 |
| 902 |
| 903 dart::String& TranslationHelper::DartString(String* content, |
| 904 Heap::Space space) { |
| 905 return dart::String::ZoneHandle( |
| 906 Z, dart::String::FromUTF8(content->buffer(), content->size(), space)); |
| 907 } |
| 908 |
| 909 |
| 910 const dart::String& TranslationHelper::DartSymbol(const char* content) const { |
| 911 return dart::String::ZoneHandle(Z, Symbols::New(thread_, content)); |
| 912 } |
| 913 |
| 914 |
| 915 dart::String& TranslationHelper::DartSymbol(String* content) const { |
| 916 return dart::String::ZoneHandle( |
| 917 Z, dart::Symbols::FromUTF8(thread_, content->buffer(), content->size())); |
| 918 } |
| 919 |
| 920 |
| 921 const dart::String& TranslationHelper::DartClassName(dil::Class* dil_klass) { |
| 922 if (dil_klass->name() != NULL) { |
| 923 ASSERT(dil_klass->IsNormalClass()); |
| 924 dart::String& name = DartString(dil_klass->name()); |
| 925 return ManglePrivateName(dil_klass->parent(), &name); |
| 926 } else { |
| 927 // Mixin class names are not mangled. |
| 928 ASSERT(dil_klass->IsMixinClass()); |
| 929 |
| 930 // We construct the string from right to left: |
| 931 // "Base&Mixin1&Mixin2&...&MixinN" |
| 932 dart::String& partial = dart::String::Handle(Z, dart::String::New("")); |
| 933 dart::String& amp = dart::String::Handle(Z, dart::String::New("&")); |
| 934 dart::String& tmp = dart::String::Handle(Z); |
| 935 while (dil_klass->name() == NULL) { |
| 936 ASSERT(dil_klass->IsMixinClass()); |
| 937 |
| 938 MixinClass* dil_mixin_class = MixinClass::Cast(dil_klass); |
| 939 InterfaceType* base_type = dil_mixin_class->first(); |
| 940 InterfaceType* mixin_type = dil_mixin_class->second(); |
| 941 |
| 942 String* mixin_name = NormalClass::Cast(mixin_type->klass())->name(); |
| 943 |
| 944 tmp = dart::String::FromUTF8(mixin_name->buffer(), mixin_name->size()); |
| 945 |
| 946 partial = dart::String::Concat(amp, partial); |
| 947 partial = dart::String::Concat(tmp, partial); |
| 948 |
| 949 dil_klass = base_type->klass(); |
| 950 } |
| 951 |
| 952 tmp = dart::String::FromUTF8(dil_klass->name()->buffer(), |
| 953 dil_klass->name()->size()); |
| 954 |
| 955 partial = dart::String::Concat(amp, partial); |
| 956 partial = dart::String::Concat(tmp, partial); |
| 957 |
| 958 partial = dart::Symbols::New(thread_, partial); |
| 959 return partial; |
| 960 } |
| 961 } |
| 962 |
| 963 |
| 964 const dart::String& TranslationHelper::DartConstructorName(Constructor* node) { |
| 965 Class* klass = Class::Cast(node->parent()); |
| 966 return DartFactoryName(klass, node->name()); |
| 967 } |
| 968 |
| 969 |
| 970 const dart::String& TranslationHelper::DartProcedureName(Procedure* procedure) { |
| 971 if (procedure->kind() == Procedure::kSetter) { |
| 972 return DartSetterName(procedure->name()); |
| 973 } else if (procedure->kind() == Procedure::kGetter) { |
| 974 return DartGetterName(procedure->name()); |
| 975 } else if (procedure->kind() == Procedure::kFactory) { |
| 976 return DartFactoryName(Class::Cast(procedure->parent()), procedure->name()); |
| 977 } else { |
| 978 return DartMethodName(procedure->name()); |
| 979 } |
| 980 } |
| 981 |
| 982 |
| 983 const dart::String& TranslationHelper::DartSetterName(Name* dil_name) { |
| 984 // The names flowing into [content] are coming from the DILL file: |
| 985 // * user-defined setters: `fieldname=` |
| 986 // * property-set expressions: `fieldname` |
| 987 // |
| 988 // The VM uses `get:fieldname` and `set:fieldname`. |
| 989 // |
| 990 // => In order to be consistent, we remove the `=` always and adopt the VM |
| 991 // conventions. |
| 992 String* content = dil_name->string(); |
| 993 ASSERT(content->size() > 0); |
| 994 intptr_t skip = 0; |
| 995 if (content->buffer()[content->size() - 1] == '=') { |
| 996 skip = 1; |
| 997 } |
| 998 dart::String& name = dart::String::ZoneHandle( |
| 999 Z, dart::String::FromUTF8(content->buffer(), content->size() - skip)); |
| 1000 ManglePrivateName(dil_name->library(), &name, false); |
| 1001 name = dart::Field::SetterSymbol(name); |
| 1002 return name; |
| 1003 } |
| 1004 |
| 1005 |
| 1006 const dart::String& TranslationHelper::DartGetterName(Name* dil_name) { |
| 1007 dart::String& name = DartString(dil_name->string()); |
| 1008 ManglePrivateName(dil_name->library(), &name, false); |
| 1009 name = dart::Field::GetterSymbol(name); |
| 1010 return name; |
| 1011 } |
| 1012 |
| 1013 |
| 1014 const dart::String& TranslationHelper::DartFieldName(Name* dil_name) { |
| 1015 dart::String& name = DartString(dil_name->string()); |
| 1016 return ManglePrivateName(dil_name->library(), &name); |
| 1017 } |
| 1018 |
| 1019 |
| 1020 const dart::String& TranslationHelper::DartInitializerName(Name* dil_name) { |
| 1021 // The [DartFieldName] will take care of mangling the name. |
| 1022 dart::String& name = dart::String::Handle(Z, DartFieldName(dil_name).raw()); |
| 1023 name = Symbols::FromConcat(thread_, Symbols::InitPrefix(), name); |
| 1024 return name; |
| 1025 } |
| 1026 |
| 1027 |
| 1028 const dart::String& TranslationHelper::DartMethodName(Name* dil_name) { |
| 1029 dart::String& name = DartString(dil_name->string()); |
| 1030 return ManglePrivateName(dil_name->library(), &name); |
| 1031 } |
| 1032 |
| 1033 |
| 1034 const dart::String& TranslationHelper::DartFactoryName(Class* klass, |
| 1035 Name* method_name) { |
| 1036 // [DartMethodName] will mangle the name. |
| 1037 dart::String& name = |
| 1038 dart::String::Handle(Z, DartMethodName(method_name).raw()); |
| 1039 |
| 1040 // We build a String which looks like <classname>.<constructor-name>. |
| 1041 // [DartClassName] will mangle the name. |
| 1042 dart::String& temp = dart::String::Handle(Z, DartClassName(klass).raw()); |
| 1043 temp = dart::String::Concat(temp, Symbols::Dot()); |
| 1044 temp = dart::String::Concat(temp, name); |
| 1045 return dart::String::ZoneHandle(Z, dart::Symbols::New(thread_, temp)); |
| 1046 } |
| 1047 |
| 1048 |
| 1049 dart::RawLibrary* TranslationHelper::LookupLibraryByDilLibrary( |
| 1050 Library* dil_library) { |
| 1051 const dart::String& library_name = DartSymbol(dil_library->import_uri()); |
| 1052 ASSERT(!library_name.IsNull()); |
| 1053 dart::RawLibrary* library = |
| 1054 dart::Library::LookupLibrary(thread_, library_name); |
| 1055 ASSERT(library != Object::null()); |
| 1056 return library; |
| 1057 } |
| 1058 |
| 1059 |
| 1060 dart::RawClass* TranslationHelper::LookupClassByDilClass(Class* dil_klass) { |
| 1061 dart::RawClass* klass = NULL; |
| 1062 |
| 1063 const dart::String& class_name = DartClassName(dil_klass); |
| 1064 Library* dil_library = Library::Cast(dil_klass->parent()); |
| 1065 dart::Library& library = |
| 1066 dart::Library::Handle(Z, LookupLibraryByDilLibrary(dil_library)); |
| 1067 klass = library.LookupClassAllowPrivate(class_name); |
| 1068 |
| 1069 ASSERT(klass != Object::null()); |
| 1070 return klass; |
| 1071 } |
| 1072 |
| 1073 |
| 1074 dart::RawField* TranslationHelper::LookupFieldByDilField(Field* dil_field) { |
| 1075 TreeNode* node = dil_field->parent(); |
| 1076 |
| 1077 dart::Class& klass = dart::Class::Handle(Z); |
| 1078 if (node->IsClass()) { |
| 1079 klass = LookupClassByDilClass(Class::Cast(node)); |
| 1080 } else { |
| 1081 ASSERT(node->IsLibrary()); |
| 1082 dart::Library& library = dart::Library::Handle( |
| 1083 Z, LookupLibraryByDilLibrary(Library::Cast(node))); |
| 1084 klass = library.toplevel_class(); |
| 1085 } |
| 1086 dart::RawField* field = |
| 1087 klass.LookupFieldAllowPrivate(DartSymbol(dil_field->name()->string())); |
| 1088 ASSERT(field != Object::null()); |
| 1089 return field; |
| 1090 } |
| 1091 |
| 1092 |
| 1093 dart::RawFunction* TranslationHelper::LookupStaticMethodByDilProcedure( |
| 1094 Procedure* procedure) { |
| 1095 ASSERT(procedure->IsStatic()); |
| 1096 const dart::String& procedure_name = DartProcedureName(procedure); |
| 1097 |
| 1098 // The parent is either a library or a class (in which case the procedure is a |
| 1099 // static method). |
| 1100 TreeNode* parent = procedure->parent(); |
| 1101 if (parent->IsClass()) { |
| 1102 dart::Class& klass = |
| 1103 dart::Class::Handle(Z, LookupClassByDilClass(Class::Cast(parent))); |
| 1104 dart::RawFunction* raw_function = |
| 1105 klass.LookupFunctionAllowPrivate(procedure_name); |
| 1106 ASSERT(raw_function != Object::null()); |
| 1107 |
| 1108 // TODO(kustermann): We can probably get rid of this after no longer using |
| 1109 // the built-in core libraries. |
| 1110 dart::Function& function = dart::Function::ZoneHandle(Z, raw_function); |
| 1111 if (function.IsRedirectingFactory()) { |
| 1112 ClassFinalizer::ResolveRedirectingFactory(klass, function); |
| 1113 function = function.RedirectionTarget(); |
| 1114 } |
| 1115 return function.raw(); |
| 1116 } else { |
| 1117 ASSERT(parent->IsLibrary()); |
| 1118 dart::Library& library = dart::Library::Handle( |
| 1119 Z, LookupLibraryByDilLibrary(Library::Cast(parent))); |
| 1120 dart::RawFunction* function = |
| 1121 library.LookupFunctionAllowPrivate(procedure_name); |
| 1122 ASSERT(function != Object::null()); |
| 1123 return function; |
| 1124 } |
| 1125 } |
| 1126 |
| 1127 |
| 1128 dart::RawFunction* TranslationHelper::LookupConstructorByDilConstructor( |
| 1129 Constructor* constructor) { |
| 1130 Class* dil_klass = Class::Cast(constructor->parent()); |
| 1131 dart::Class& klass = dart::Class::Handle(Z, LookupClassByDilClass(dil_klass)); |
| 1132 return LookupConstructorByDilConstructor(klass, constructor); |
| 1133 } |
| 1134 |
| 1135 |
| 1136 dart::RawFunction* TranslationHelper::LookupConstructorByDilConstructor( |
| 1137 const dart::Class& owner, Constructor* constructor) { |
| 1138 dart::RawFunction* function = |
| 1139 owner.LookupConstructorAllowPrivate(DartConstructorName(constructor)); |
| 1140 ASSERT(function != Object::null()); |
| 1141 return function; |
| 1142 } |
| 1143 |
| 1144 |
| 1145 dart::Type& TranslationHelper::GetCanonicalType(const dart::Class& klass) { |
| 1146 ASSERT(!klass.IsNull()); |
| 1147 // Note that if cls is _Closure, the returned type will be _Closure, |
| 1148 // and not the signature type. |
| 1149 Type& type = Type::ZoneHandle(Z, klass.CanonicalType()); |
| 1150 if (!type.IsNull()) { |
| 1151 return type; |
| 1152 } |
| 1153 type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()), |
| 1154 klass.token_pos()); |
| 1155 // FIXME(kustermann): Should we assert that this is true? |
| 1156 if (klass.is_type_finalized()) { |
| 1157 type ^= ClassFinalizer::FinalizeType( |
| 1158 klass, type, ClassFinalizer::kCanonicalizeWellFormed); |
| 1159 // Note that the receiver type may now be a malbounded type. |
| 1160 klass.SetCanonicalType(type); |
| 1161 } |
| 1162 return type; |
| 1163 } |
| 1164 |
| 1165 |
| 1166 void TranslationHelper::ReportError(const char* format, ...) { |
| 1167 const Script& null_script = Script::Handle(Z); |
| 1168 |
| 1169 va_list args; |
| 1170 va_start(args, format); |
| 1171 Report::MessageV(Report::kError, null_script, TokenPosition::kNoSource, |
| 1172 Report::AtLocation, format, args); |
| 1173 va_end(args); |
| 1174 UNREACHABLE(); |
| 1175 } |
| 1176 |
| 1177 |
| 1178 void TranslationHelper::ReportError(const Error& prev_error, const char* format, |
| 1179 ...) { |
| 1180 const Script& null_script = Script::Handle(Z); |
| 1181 |
| 1182 va_list args; |
| 1183 va_start(args, format); |
| 1184 Report::LongJumpV(prev_error, null_script, TokenPosition::kNoSource, format, |
| 1185 args); |
| 1186 va_end(args); |
| 1187 UNREACHABLE(); |
| 1188 } |
| 1189 |
| 1190 |
| 1191 dart::String& TranslationHelper::ManglePrivateName(Library* dil_library, |
| 1192 dart::String* name_to_modify, |
| 1193 bool symbolize) { |
| 1194 if (name_to_modify->Length() >= 1 && name_to_modify->CharAt(0) == '_') { |
| 1195 const dart::Library& library = |
| 1196 dart::Library::Handle(Z, LookupLibraryByDilLibrary(dil_library)); |
| 1197 *name_to_modify = library.PrivateName(*name_to_modify); |
| 1198 } else if (symbolize) { |
| 1199 *name_to_modify = Symbols::New(thread_, *name_to_modify); |
| 1200 } |
| 1201 return *name_to_modify; |
| 1202 } |
| 1203 |
| 1204 |
| 1205 const Array& TranslationHelper::ArgumentNames(List<NamedExpression>* named) { |
| 1206 if (named->length() == 0) return Array::ZoneHandle(Z); |
| 1207 |
| 1208 const Array& names = Array::ZoneHandle(Z, Array::New(named->length())); |
| 1209 for (intptr_t i = 0; i < named->length(); ++i) { |
| 1210 names.SetAt(i, DartSymbol((*named)[i]->name())); |
| 1211 } |
| 1212 return names; |
| 1213 } |
| 1214 |
| 1215 |
| 1216 Instance& ConstantEvaluator::EvaluateExpression(Expression* expression) { |
| 1217 expression->AcceptExpressionVisitor(this); |
| 1218 // We return a new `ZoneHandle` here on purpose: The intermediate language |
| 1219 // instructions do not make a copy of the handle, so we do it. |
| 1220 return dart::Instance::ZoneHandle(Z, result_.raw()); |
| 1221 } |
| 1222 |
| 1223 |
| 1224 Object& ConstantEvaluator::EvaluateExpressionSafe(Expression* expression) { |
| 1225 LongJumpScope jump; |
| 1226 if (setjmp(*jump.Set()) == 0) { |
| 1227 return EvaluateExpression(expression); |
| 1228 } else { |
| 1229 Thread* thread = Thread::Current(); |
| 1230 Error& error = Error::Handle(); |
| 1231 error = thread->sticky_error(); |
| 1232 thread->clear_sticky_error(); |
| 1233 return error; |
| 1234 } |
| 1235 } |
| 1236 |
| 1237 |
| 1238 Instance& ConstantEvaluator::EvaluateConstructorInvocation( |
| 1239 ConstructorInvocation* node) { |
| 1240 VisitConstructorInvocation(node); |
| 1241 // We return a new `ZoneHandle` here on purpose: The intermediate language |
| 1242 // instructions do not make a copy of the handle, so we do it. |
| 1243 return dart::Instance::ZoneHandle(Z, result_.raw()); |
| 1244 } |
| 1245 |
| 1246 |
| 1247 Instance& ConstantEvaluator::EvaluateListLiteral(ListLiteral* node) { |
| 1248 VisitListLiteral(node); |
| 1249 // We return a new `ZoneHandle` here on purpose: The intermediate language |
| 1250 // instructions do not make a copy of the handle, so we do it. |
| 1251 return dart::Instance::ZoneHandle(Z, result_.raw()); |
| 1252 } |
| 1253 |
| 1254 |
| 1255 Instance& ConstantEvaluator::EvaluateMapLiteral(MapLiteral* node) { |
| 1256 VisitMapLiteral(node); |
| 1257 // We return a new `ZoneHandle` here on purpose: The intermediate language |
| 1258 // instructions do not make a copy of the handle, so we do it. |
| 1259 return dart::Instance::ZoneHandle(Z, result_.raw()); |
| 1260 } |
| 1261 |
| 1262 |
| 1263 void ConstantEvaluator::VisitBigintLiteral(BigintLiteral* node) { |
| 1264 const dart::String& value = H.DartString(node->value()); |
| 1265 result_ = Integer::New(value, Heap::kOld); |
| 1266 result_ = H.Canonicalize(result_); |
| 1267 } |
| 1268 |
| 1269 |
| 1270 void ConstantEvaluator::VisitBoolLiteral(BoolLiteral* node) { |
| 1271 result_ = dart::Bool::Get(node->value()).raw(); |
| 1272 } |
| 1273 |
| 1274 |
| 1275 void ConstantEvaluator::VisitDoubleLiteral(DoubleLiteral* node) { |
| 1276 result_ = dart::Double::New(H.DartString(node->value()), Heap::kOld); |
| 1277 result_ = H.Canonicalize(result_); |
| 1278 } |
| 1279 |
| 1280 |
| 1281 void ConstantEvaluator::VisitIntLiteral(IntLiteral* node) { |
| 1282 result_ = dart::Integer::New(node->value(), Heap::kOld); |
| 1283 result_ = H.Canonicalize(result_); |
| 1284 } |
| 1285 |
| 1286 |
| 1287 void ConstantEvaluator::VisitNullLiteral(NullLiteral* node) { |
| 1288 result_ = dart::Instance::null(); |
| 1289 } |
| 1290 |
| 1291 |
| 1292 void ConstantEvaluator::VisitStringLiteral(StringLiteral* node) { |
| 1293 result_ = H.DartSymbol(node->value()).raw(); |
| 1294 } |
| 1295 |
| 1296 |
| 1297 void ConstantEvaluator::VisitTypeLiteral(TypeLiteral* node) { |
| 1298 const AbstractType& type = T.TranslateType(node->type()); |
| 1299 if (type.IsMalformed()) { |
| 1300 H.ReportError("Malformed type literal in constant expression."); |
| 1301 } |
| 1302 result_ = type.raw(); |
| 1303 } |
| 1304 |
| 1305 |
| 1306 RawObject* ConstantEvaluator::EvaluateConstConstructorCall( |
| 1307 const dart::Class& type_class, const TypeArguments& type_arguments, |
| 1308 const Function& constructor, const Object& argument) { |
| 1309 // Factories have one extra argument: the type arguments. |
| 1310 // Constructors have 1 extra arguments: receiver. |
| 1311 const int kNumArgs = 1; |
| 1312 const int kNumExtraArgs = 1; |
| 1313 const int num_arguments = kNumArgs + kNumExtraArgs; |
| 1314 const Array& arg_values = |
| 1315 Array::Handle(Z, Array::New(num_arguments, Heap::kOld)); |
| 1316 Instance& instance = Instance::Handle(Z); |
| 1317 if (!constructor.IsFactory()) { |
| 1318 instance = Instance::New(type_class, Heap::kOld); |
| 1319 if (!type_arguments.IsNull()) { |
| 1320 ASSERT(type_arguments.IsInstantiated()); |
| 1321 instance.SetTypeArguments( |
| 1322 TypeArguments::Handle(Z, type_arguments.Canonicalize())); |
| 1323 } |
| 1324 arg_values.SetAt(0, instance); |
| 1325 } else { |
| 1326 // Prepend type_arguments to list of arguments to factory. |
| 1327 ASSERT(type_arguments.IsZoneHandle()); |
| 1328 arg_values.SetAt(0, type_arguments); |
| 1329 } |
| 1330 arg_values.SetAt((0 + kNumExtraArgs), argument); |
| 1331 const Array& args_descriptor = Array::Handle( |
| 1332 Z, ArgumentsDescriptor::New(num_arguments, Object::empty_array())); |
| 1333 const Object& result = Object::Handle( |
| 1334 Z, DartEntry::InvokeFunction(constructor, arg_values, args_descriptor)); |
| 1335 ASSERT(!result.IsError()); |
| 1336 if (constructor.IsFactory()) { |
| 1337 // The factory method returns the allocated object. |
| 1338 instance ^= result.raw(); |
| 1339 } |
| 1340 return H.Canonicalize(instance); |
| 1341 } |
| 1342 |
| 1343 |
| 1344 void ConstantEvaluator::VisitSymbolLiteral(SymbolLiteral* node) { |
| 1345 const dart::String& symbol_value = H.DartSymbol(node->value()); |
| 1346 |
| 1347 const dart::Class& symbol_class = |
| 1348 dart::Class::ZoneHandle(Z, I->object_store()->symbol_class()); |
| 1349 ASSERT(!symbol_class.IsNull()); |
| 1350 const dart::Function& symbol_constructor = Function::ZoneHandle( |
| 1351 Z, symbol_class.LookupConstructor(Symbols::SymbolCtor())); |
| 1352 ASSERT(!symbol_constructor.IsNull()); |
| 1353 result_ ^= EvaluateConstConstructorCall( |
| 1354 symbol_class, TypeArguments::Handle(Z), symbol_constructor, symbol_value); |
| 1355 } |
| 1356 |
| 1357 |
| 1358 void ConstantEvaluator::VisitListLiteral(ListLiteral* node) { |
| 1359 DartType* types[] = {node->type()}; |
| 1360 const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 1); |
| 1361 |
| 1362 intptr_t length = node->expressions().length(); |
| 1363 const Array& const_list = |
| 1364 Array::ZoneHandle(Z, Array::New(length, Heap::kOld)); |
| 1365 const_list.SetTypeArguments(type_arguments); |
| 1366 for (intptr_t i = 0; i < length; i++) { |
| 1367 const Instance& expression = EvaluateExpression(node->expressions()[i]); |
| 1368 const_list.SetAt(i, expression); |
| 1369 } |
| 1370 const_list.MakeImmutable(); |
| 1371 result_ = H.Canonicalize(const_list); |
| 1372 } |
| 1373 |
| 1374 |
| 1375 void ConstantEvaluator::VisitMapLiteral(MapLiteral* node) { |
| 1376 DartType* types[] = {node->key_type(), node->value_type()}; |
| 1377 const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 2); |
| 1378 |
| 1379 intptr_t length = node->entries().length(); |
| 1380 |
| 1381 Array& const_kv_array = |
| 1382 Array::ZoneHandle(Z, Array::New(2 * length, Heap::kOld)); |
| 1383 for (intptr_t i = 0; i < length; i++) { |
| 1384 const_kv_array.SetAt(2 * i + 0, |
| 1385 EvaluateExpression(node->entries()[i]->key())); |
| 1386 const_kv_array.SetAt(2 * i + 1, |
| 1387 EvaluateExpression(node->entries()[i]->value())); |
| 1388 } |
| 1389 |
| 1390 const_kv_array.MakeImmutable(); |
| 1391 const_kv_array ^= H.Canonicalize(const_kv_array); |
| 1392 |
| 1393 const dart::Class& map_class = dart::Class::Handle( |
| 1394 Z, dart::Library::LookupCoreClass(Symbols::ImmutableMap())); |
| 1395 ASSERT(!map_class.IsNull()); |
| 1396 ASSERT(map_class.NumTypeArguments() == 2); |
| 1397 |
| 1398 const dart::Field& field = dart::Field::Handle( |
| 1399 Z, map_class.LookupInstanceFieldAllowPrivate(H.DartSymbol("_kvPairs"))); |
| 1400 ASSERT(!field.IsNull()); |
| 1401 |
| 1402 // NOTE: This needs to be kept in sync with `runtime/lib/immutable_map.dart`! |
| 1403 result_ = Instance::New(map_class, Heap::kOld); |
| 1404 ASSERT(!result_.IsNull()); |
| 1405 result_.SetTypeArguments(type_arguments); |
| 1406 result_.SetField(field, const_kv_array); |
| 1407 result_ = H.Canonicalize(result_); |
| 1408 } |
| 1409 |
| 1410 |
| 1411 void ConstantEvaluator::VisitConstructorInvocation( |
| 1412 ConstructorInvocation* node) { |
| 1413 Arguments* dil_arguments = node->arguments(); |
| 1414 |
| 1415 const Function& constructor = |
| 1416 Function::Handle(Z, H.LookupConstructorByDilConstructor(node->target())); |
| 1417 dart::Class& klass = dart::Class::Handle(Z, constructor.Owner()); |
| 1418 |
| 1419 // Build the type arguments vector (if necessary). |
| 1420 const TypeArguments* type_arguments = |
| 1421 TranslateTypeArguments(constructor, &klass, dil_arguments); |
| 1422 |
| 1423 // Prepare either the instance or the type argument vector for the constructor |
| 1424 // call. |
| 1425 Instance* receiver = NULL; |
| 1426 const TypeArguments* type_arguments_argument = NULL; |
| 1427 if (!constructor.IsFactory()) { |
| 1428 receiver = &Instance::ZoneHandle(Z, Instance::New(klass, Heap::kOld)); |
| 1429 if (type_arguments != NULL) { |
| 1430 receiver->SetTypeArguments(*type_arguments); |
| 1431 } |
| 1432 } else { |
| 1433 type_arguments_argument = type_arguments; |
| 1434 } |
| 1435 |
| 1436 const Object& result = RunFunction(constructor, dil_arguments, receiver, |
| 1437 type_arguments_argument); |
| 1438 if (constructor.IsFactory()) { |
| 1439 // Factories return the new object. |
| 1440 result_ ^= result.raw(); |
| 1441 result_ = H.Canonicalize(result_); |
| 1442 } else { |
| 1443 ASSERT(!receiver->IsNull()); |
| 1444 result_ = H.Canonicalize(*receiver); |
| 1445 } |
| 1446 } |
| 1447 |
| 1448 |
| 1449 void ConstantEvaluator::VisitMethodInvocation(MethodInvocation* node) { |
| 1450 Arguments* dil_arguments = node->arguments(); |
| 1451 |
| 1452 // Dart does not support generic methods yet. |
| 1453 ASSERT(dil_arguments->types().length() == 0); |
| 1454 |
| 1455 const dart::Instance& receiver = EvaluateExpression(node->receiver()); |
| 1456 dart::Class& klass = dart::Class::Handle( |
| 1457 Z, isolate_->class_table()->At(receiver.GetClassId())); |
| 1458 ASSERT(!klass.IsNull()); |
| 1459 |
| 1460 // Search the superclass chain for the selector. |
| 1461 // TODO(kustermann): Are there convenience function in the VM which do this? |
| 1462 // TODO(kustermann): Can we assume this will never be a no-such-method error? |
| 1463 dart::Function& function = dart::Function::Handle(Z); |
| 1464 const dart::String& method_name = H.DartMethodName(node->name()); |
| 1465 while (!klass.IsNull()) { |
| 1466 function = klass.LookupDynamicFunctionAllowPrivate(method_name); |
| 1467 if (!function.IsNull()) break; |
| 1468 klass = klass.SuperClass(); |
| 1469 } |
| 1470 ASSERT(!function.IsNull()); |
| 1471 |
| 1472 // Run the method and canonicalize the result. |
| 1473 const Object& result = RunFunction(function, dil_arguments, &receiver); |
| 1474 result_ ^= result.raw(); |
| 1475 result_ = H.Canonicalize(result_); |
| 1476 } |
| 1477 |
| 1478 |
| 1479 void ConstantEvaluator::VisitStaticGet(StaticGet* node) { |
| 1480 Member* member = node->target(); |
| 1481 if (member->IsField()) { |
| 1482 Field* dil_field = Field::Cast(member); |
| 1483 const dart::Field& field = |
| 1484 dart::Field::Handle(Z, H.LookupFieldByDilField(dil_field)); |
| 1485 if (field.StaticValue() == Object::sentinel().raw() || |
| 1486 field.StaticValue() == Object::transition_sentinel().raw()) { |
| 1487 field.EvaluateInitializer(); |
| 1488 result_ = field.StaticValue(); |
| 1489 result_ = H.Canonicalize(result_); |
| 1490 field.SetStaticValue(result_, true); |
| 1491 } else { |
| 1492 result_ = field.StaticValue(); |
| 1493 } |
| 1494 } else if (member->IsProcedure()) { |
| 1495 Procedure* procedure = Procedure::Cast(member); |
| 1496 const Function& target = |
| 1497 Function::ZoneHandle(Z, H.LookupStaticMethodByDilProcedure(procedure)); |
| 1498 |
| 1499 if (procedure->kind() == Procedure::kMethod) { |
| 1500 ASSERT(procedure->IsStatic()); |
| 1501 Function& closure_function = |
| 1502 Function::ZoneHandle(Z, target.ImplicitClosureFunction()); |
| 1503 closure_function.set_dil_function(target.dil_function()); |
| 1504 result_ = closure_function.ImplicitStaticClosure(); |
| 1505 result_ = H.Canonicalize(result_); |
| 1506 } else if (procedure->kind() == Procedure::kGetter) { |
| 1507 UNIMPLEMENTED(); |
| 1508 } else { |
| 1509 UNIMPLEMENTED(); |
| 1510 } |
| 1511 } |
| 1512 } |
| 1513 |
| 1514 |
| 1515 void ConstantEvaluator::VisitVariableGet(VariableGet* node) { |
| 1516 // When we see a [VariableGet] the corresponding [VariableDeclaration] must've |
| 1517 // been executed already. It therefore must have a constant object associated |
| 1518 // with it. |
| 1519 LocalVariable* variable = builder_->LookupVariable(node->variable()); |
| 1520 ASSERT(variable->IsConst()); |
| 1521 result_ = variable->ConstValue()->raw(); |
| 1522 } |
| 1523 |
| 1524 |
| 1525 void ConstantEvaluator::VisitLet(Let* node) { |
| 1526 VariableDeclaration* variable = node->variable(); |
| 1527 LocalVariable* local = builder_->LookupVariable(variable); |
| 1528 local->SetConstValue(EvaluateExpression(variable->initializer())); |
| 1529 node->body()->AcceptExpressionVisitor(this); |
| 1530 } |
| 1531 |
| 1532 |
| 1533 void ConstantEvaluator::VisitStaticInvocation(StaticInvocation* node) { |
| 1534 const Function& function = Function::ZoneHandle( |
| 1535 Z, H.LookupStaticMethodByDilProcedure(node->procedure())); |
| 1536 dart::Class& klass = dart::Class::Handle(Z, function.Owner()); |
| 1537 |
| 1538 // Build the type arguments vector (if necessary). |
| 1539 const TypeArguments* type_arguments = |
| 1540 TranslateTypeArguments(function, &klass, node->arguments()); |
| 1541 |
| 1542 const Object& result = |
| 1543 RunFunction(function, node->arguments(), NULL, type_arguments); |
| 1544 result_ ^= result.raw(); |
| 1545 result_ = H.Canonicalize(result_); |
| 1546 } |
| 1547 |
| 1548 |
| 1549 void ConstantEvaluator::VisitStringConcatenation(StringConcatenation* node) { |
| 1550 intptr_t length = node->expressions().length(); |
| 1551 |
| 1552 bool all_string = true; |
| 1553 const Array& strings = Array::Handle(Z, Array::New(length)); |
| 1554 for (intptr_t i = 0; i < length; i++) { |
| 1555 EvaluateExpression(node->expressions()[i]); |
| 1556 strings.SetAt(i, result_); |
| 1557 all_string = all_string && result_.IsString(); |
| 1558 } |
| 1559 if (all_string) { |
| 1560 result_ = dart::String::ConcatAll(strings, Heap::kOld); |
| 1561 result_ = H.Canonicalize(result_); |
| 1562 } else { |
| 1563 // Get string interpolation function. |
| 1564 const dart::Class& cls = dart::Class::Handle( |
| 1565 Z, dart::Library::LookupCoreClass(Symbols::StringBase())); |
| 1566 ASSERT(!cls.IsNull()); |
| 1567 const Function& func = Function::Handle( |
| 1568 Z, cls.LookupStaticFunction( |
| 1569 dart::Library::PrivateCoreLibName(Symbols::Interpolate()))); |
| 1570 ASSERT(!func.IsNull()); |
| 1571 |
| 1572 // Build argument array to pass to the interpolation function. |
| 1573 const Array& interpolate_arg = Array::Handle(Z, Array::New(1, Heap::kOld)); |
| 1574 interpolate_arg.SetAt(0, strings); |
| 1575 |
| 1576 // Run and canonicalize. |
| 1577 const Object& result = |
| 1578 RunFunction(func, interpolate_arg, Array::null_array()); |
| 1579 result_ = H.Canonicalize(dart::String::Cast(result)); |
| 1580 } |
| 1581 } |
| 1582 |
| 1583 |
| 1584 void ConstantEvaluator::VisitConditionalExpression( |
| 1585 ConditionalExpression* node) { |
| 1586 EvaluateExpression(node->condition()); |
| 1587 if (Bool::Cast(result_).value()) { |
| 1588 EvaluateExpression(node->then()); |
| 1589 } else { |
| 1590 EvaluateExpression(node->otherwise()); |
| 1591 } |
| 1592 } |
| 1593 |
| 1594 |
| 1595 void ConstantEvaluator::VisitLogicalExpression(LogicalExpression* node) { |
| 1596 if (node->op() == LogicalExpression::kAnd) { |
| 1597 EvaluateExpression(node->left()); |
| 1598 if (Bool::Cast(result_).value()) { |
| 1599 EvaluateExpression(node->right()); |
| 1600 } |
| 1601 } else { |
| 1602 ASSERT(node->op() == LogicalExpression::kOr); |
| 1603 EvaluateExpression(node->left()); |
| 1604 if (!Bool::Cast(result_).value()) { |
| 1605 EvaluateExpression(node->right()); |
| 1606 } |
| 1607 } |
| 1608 } |
| 1609 |
| 1610 |
| 1611 void ConstantEvaluator::VisitNot(Not* node) { |
| 1612 EvaluateExpression(node->expression()); |
| 1613 ASSERT(result_.IsBool()); |
| 1614 result_ = |
| 1615 Bool::Cast(result_).value() ? Bool::False().raw() : Bool::True().raw(); |
| 1616 } |
| 1617 |
| 1618 |
| 1619 const TypeArguments* ConstantEvaluator::TranslateTypeArguments( |
| 1620 const Function& target, dart::Class* target_klass, |
| 1621 Arguments* dil_arguments) { |
| 1622 List<DartType>& dil_type_arguments = dil_arguments->types(); |
| 1623 |
| 1624 const TypeArguments* type_arguments = NULL; |
| 1625 if (dil_type_arguments.length() > 0) { |
| 1626 type_arguments = &T.TranslateInstantiatedTypeArguments( |
| 1627 *target_klass, dil_type_arguments.raw_array(), |
| 1628 dil_type_arguments.length()); |
| 1629 |
| 1630 if (!(type_arguments->IsNull() || type_arguments->IsInstantiated())) { |
| 1631 H.ReportError("Type must be constant in const constructor."); |
| 1632 } |
| 1633 } else if (target.IsFactory() && type_arguments == NULL) { |
| 1634 // All factories take a type arguments vector as first argument (independent |
| 1635 // of whether the class is generic or not). |
| 1636 type_arguments = &TypeArguments::ZoneHandle(Z, TypeArguments::null()); |
| 1637 } |
| 1638 return type_arguments; |
| 1639 } |
| 1640 |
| 1641 |
| 1642 const Object& ConstantEvaluator::RunFunction(const Function& function, |
| 1643 Arguments* dil_arguments, |
| 1644 const Instance* receiver, |
| 1645 const TypeArguments* type_args) { |
| 1646 // We do not support generic methods yet. |
| 1647 ASSERT((receiver == NULL) || (type_args == NULL)); |
| 1648 intptr_t extra_arguments = |
| 1649 (receiver != NULL ? 1 : 0) + (type_args != NULL ? 1 : 0); |
| 1650 |
| 1651 // Build up arguments. |
| 1652 const Array& arguments = Array::ZoneHandle( |
| 1653 Z, Array::New(extra_arguments + dil_arguments->count())); |
| 1654 const Array& names = |
| 1655 Array::ZoneHandle(Z, Array::New(dil_arguments->named().length())); |
| 1656 intptr_t pos = 0; |
| 1657 if (receiver != NULL) { |
| 1658 arguments.SetAt(pos++, *receiver); |
| 1659 } |
| 1660 if (type_args != NULL) { |
| 1661 arguments.SetAt(pos++, *type_args); |
| 1662 } |
| 1663 for (intptr_t i = 0; i < dil_arguments->positional().length(); i++) { |
| 1664 EvaluateExpression(dil_arguments->positional()[i]); |
| 1665 arguments.SetAt(pos++, result_); |
| 1666 } |
| 1667 for (intptr_t i = 0; i < dil_arguments->named().length(); i++) { |
| 1668 NamedExpression* named_expression = dil_arguments->named()[i]; |
| 1669 EvaluateExpression(named_expression->expression()); |
| 1670 arguments.SetAt(pos++, result_); |
| 1671 names.SetAt(i, H.DartSymbol(named_expression->name())); |
| 1672 } |
| 1673 return RunFunction(function, arguments, names); |
| 1674 } |
| 1675 |
| 1676 |
| 1677 const Object& ConstantEvaluator::RunFunction(const Function& function, |
| 1678 const Array& arguments, |
| 1679 const Array& names) { |
| 1680 const Array& args_descriptor = |
| 1681 Array::Handle(Z, ArgumentsDescriptor::New(arguments.Length(), names)); |
| 1682 const Object& result = Object::Handle( |
| 1683 Z, DartEntry::InvokeFunction(function, arguments, args_descriptor)); |
| 1684 if (result.IsError()) { |
| 1685 H.ReportError(Error::Cast(result), "error evaluating constant constructor"); |
| 1686 } |
| 1687 return result; |
| 1688 } |
| 1689 |
| 1690 |
| 1691 FlowGraphBuilder::FlowGraphBuilder( |
| 1692 TreeNode* node, ParsedFunction* parsed_function, |
| 1693 const ZoneGrowableArray<const ICData*>& ic_data_array, |
| 1694 InlineExitCollector* exit_collector, intptr_t osr_id, |
| 1695 intptr_t first_block_id) |
| 1696 : zone_(Thread::Current()->zone()), |
| 1697 translation_helper_(Thread::Current(), zone_, |
| 1698 Thread::Current()->isolate()), |
| 1699 node_(node), |
| 1700 parsed_function_(parsed_function), |
| 1701 osr_id_(osr_id), |
| 1702 ic_data_array_(ic_data_array), |
| 1703 exit_collector_(exit_collector), |
| 1704 next_block_id_(first_block_id), |
| 1705 next_function_id_(0), |
| 1706 context_depth_(0), |
| 1707 loop_depth_(0), |
| 1708 try_depth_(0), |
| 1709 catch_depth_(0), |
| 1710 for_in_depth_(0), |
| 1711 stack_(NULL), |
| 1712 pending_argument_count_(0), |
| 1713 graph_entry_(NULL), |
| 1714 scopes_(NULL), |
| 1715 breakable_block_(NULL), |
| 1716 switch_block_(NULL), |
| 1717 try_finally_block_(NULL), |
| 1718 try_catch_block_(NULL), |
| 1719 next_used_try_index_(0), |
| 1720 catch_block_(NULL), |
| 1721 type_translator_(&translation_helper_, &active_class_), |
| 1722 constant_evaluator_(this, zone_, &translation_helper_, |
| 1723 &type_translator_) {} |
| 1724 |
| 1725 |
| 1726 FlowGraphBuilder::~FlowGraphBuilder() {} |
| 1727 |
| 1728 |
| 1729 Fragment FlowGraphBuilder::TranslateFinallyFinalizers( |
| 1730 TryFinallyBlock* outer_finally, intptr_t target_context_depth) { |
| 1731 TryFinallyBlock* const saved_block = try_finally_block_; |
| 1732 const intptr_t saved_depth = context_depth_; |
| 1733 const intptr_t saved_try_depth = try_depth_; |
| 1734 |
| 1735 Fragment instructions; |
| 1736 |
| 1737 // While translating the body of a finalizer we need to set the try-finally |
| 1738 // block which is active when translating the body. |
| 1739 while (try_finally_block_ != outer_finally) { |
| 1740 // Set correct try depth (in case there are nested try statements). |
| 1741 try_depth_ = try_finally_block_->try_depth(); |
| 1742 |
| 1743 // Potentially restore the context to what is expected for the finally |
| 1744 // block. |
| 1745 instructions += AdjustContextTo(try_finally_block_->context_depth()); |
| 1746 |
| 1747 Statement* finalizer = try_finally_block_->finalizer(); |
| 1748 try_finally_block_ = try_finally_block_->outer(); |
| 1749 |
| 1750 // This will potentially have exceptional cases as described in |
| 1751 // [VisitTryFinally] and will handle them. |
| 1752 instructions += TranslateStatement(finalizer); |
| 1753 |
| 1754 // We only need to make sure that if the finalizer ended normally, we |
| 1755 // continue towards the next outer try-finally. |
| 1756 if (!instructions.is_open()) break; |
| 1757 } |
| 1758 |
| 1759 if (instructions.is_open() && target_context_depth != -1) { |
| 1760 // A target context depth of -1 indicates that we the code after this |
| 1761 // will not care about the context chain so we can leave it any way we |
| 1762 // want after the last finalizer. That is used when returning. |
| 1763 instructions += AdjustContextTo(target_context_depth); |
| 1764 } |
| 1765 |
| 1766 try_finally_block_ = saved_block; |
| 1767 context_depth_ = saved_depth; |
| 1768 try_depth_ = saved_try_depth; |
| 1769 |
| 1770 return instructions; |
| 1771 } |
| 1772 |
| 1773 |
| 1774 Fragment FlowGraphBuilder::EnterScope(TreeNode* node, bool* new_context) { |
| 1775 Fragment instructions; |
| 1776 const intptr_t context_size = |
| 1777 scopes_->scopes.Lookup(node)->num_context_variables(); |
| 1778 if (context_size > 0) { |
| 1779 instructions += PushContext(context_size); |
| 1780 instructions += Drop(); |
| 1781 if (new_context != NULL) { |
| 1782 *new_context = true; |
| 1783 } |
| 1784 } |
| 1785 return instructions; |
| 1786 } |
| 1787 |
| 1788 |
| 1789 Fragment FlowGraphBuilder::ExitScope(TreeNode* node) { |
| 1790 Fragment instructions; |
| 1791 const intptr_t context_size = |
| 1792 scopes_->scopes.Lookup(node)->num_context_variables(); |
| 1793 if (context_size > 0) { |
| 1794 instructions += PopContext(); |
| 1795 } |
| 1796 return instructions; |
| 1797 } |
| 1798 |
| 1799 |
| 1800 Fragment FlowGraphBuilder::LoadContextAt(int depth) { |
| 1801 intptr_t delta = context_depth_ - depth; |
| 1802 ASSERT(delta >= 0); |
| 1803 Fragment instructions = LoadLocal(parsed_function_->current_context_var()); |
| 1804 while (delta-- > 0) { |
| 1805 instructions += LoadField(Context::parent_offset()); |
| 1806 } |
| 1807 return instructions; |
| 1808 } |
| 1809 |
| 1810 |
| 1811 Fragment FlowGraphBuilder::AdjustContextTo(int depth) { |
| 1812 ASSERT(depth <= context_depth_ && depth >= 0); |
| 1813 Fragment instructions; |
| 1814 if (depth < context_depth_) { |
| 1815 instructions += LoadContextAt(depth); |
| 1816 instructions += StoreLocal(parsed_function_->current_context_var()); |
| 1817 instructions += Drop(); |
| 1818 context_depth_ = depth; |
| 1819 } |
| 1820 return instructions; |
| 1821 } |
| 1822 |
| 1823 |
| 1824 Fragment FlowGraphBuilder::PushContext(int size) { |
| 1825 ASSERT(size > 0); |
| 1826 Fragment instructions = AllocateContext(size); |
| 1827 LocalVariable* context = MakeTemporary(); |
| 1828 instructions += LoadLocal(context); |
| 1829 instructions += LoadLocal(parsed_function_->current_context_var()); |
| 1830 instructions += StoreInstanceField(Context::parent_offset()); |
| 1831 instructions += StoreLocal(parsed_function_->current_context_var()); |
| 1832 ++context_depth_; |
| 1833 return instructions; |
| 1834 } |
| 1835 |
| 1836 |
| 1837 Fragment FlowGraphBuilder::PopContext() { |
| 1838 return AdjustContextTo(context_depth_ - 1); |
| 1839 } |
| 1840 |
| 1841 |
| 1842 Fragment FlowGraphBuilder::LoadInstantiatorTypeArguments() { |
| 1843 // TODO(kustermann): We could use `active_class_->IsGeneric()`. |
| 1844 Fragment instructions; |
| 1845 if (scopes_->type_arguments_variable != NULL) { |
| 1846 #ifdef DEBUG |
| 1847 Function& function = |
| 1848 Function::Handle(Z, parsed_function_->function().raw()); |
| 1849 while (function.IsClosureFunction()) { |
| 1850 function = function.parent_function(); |
| 1851 } |
| 1852 ASSERT(function.IsFactory()); |
| 1853 #endif |
| 1854 instructions += LoadLocal(scopes_->type_arguments_variable); |
| 1855 } else if (scopes_->this_variable != NULL && |
| 1856 active_class_.dil_class != NULL && |
| 1857 active_class_.dil_class->type_parameters().length() > 0) { |
| 1858 ASSERT(!parsed_function_->function().IsFactory()); |
| 1859 intptr_t type_arguments_field_offset = |
| 1860 active_class_.klass->type_arguments_field_offset(); |
| 1861 ASSERT(type_arguments_field_offset != dart::Class::kNoTypeArguments); |
| 1862 |
| 1863 instructions += LoadLocal(scopes_->this_variable); |
| 1864 instructions += LoadField(type_arguments_field_offset); |
| 1865 } else { |
| 1866 instructions += NullConstant(); |
| 1867 } |
| 1868 return instructions; |
| 1869 } |
| 1870 |
| 1871 |
| 1872 Fragment FlowGraphBuilder::InstantiateTypeArguments( |
| 1873 const TypeArguments& type_arguments) { |
| 1874 InstantiateTypeArgumentsInstr* instr = new (Z) InstantiateTypeArgumentsInstr( |
| 1875 TokenPosition::kNoSource, type_arguments, *active_class_.klass, Pop()); |
| 1876 Push(instr); |
| 1877 return Fragment(instr); |
| 1878 } |
| 1879 |
| 1880 |
| 1881 Fragment FlowGraphBuilder::TranslateInstantiatedTypeArguments( |
| 1882 const TypeArguments& type_arguments) { |
| 1883 Fragment instructions; |
| 1884 |
| 1885 if (type_arguments.IsNull() || type_arguments.IsInstantiated()) { |
| 1886 // There are no type references to type parameters so we can just take it. |
| 1887 instructions += Constant(type_arguments); |
| 1888 } else { |
| 1889 // The [type_arguments] vector contains a type reference to a type |
| 1890 // parameter we need to resolve it. |
| 1891 const bool use_instantiator = |
| 1892 type_arguments.IsUninstantiatedIdentity() || |
| 1893 type_arguments.CanShareInstantiatorTypeArguments(*active_class_.klass); |
| 1894 if (use_instantiator) { |
| 1895 // If the instantiator type arguments are just passed on, we don't need to |
| 1896 // resolve the type parameters. |
| 1897 // |
| 1898 // This is for example the case here: |
| 1899 // class Foo<T> { |
| 1900 // newList() => new List<T>(); |
| 1901 // } |
| 1902 // We just use the type argument vector from the [Foo] object and pass it |
| 1903 // directly to the `new List<T>()` factory constructor. |
| 1904 instructions += LoadInstantiatorTypeArguments(); |
| 1905 } else { |
| 1906 // Otherwise we need to resolve [TypeParameterType]s in the type |
| 1907 // expression based on the current instantiator type argument vector. |
| 1908 instructions += LoadInstantiatorTypeArguments(); |
| 1909 instructions += InstantiateTypeArguments(type_arguments); |
| 1910 } |
| 1911 } |
| 1912 return instructions; |
| 1913 } |
| 1914 |
| 1915 |
| 1916 Fragment FlowGraphBuilder::AllocateContext(int size) { |
| 1917 AllocateContextInstr* allocate = |
| 1918 new (Z) AllocateContextInstr(TokenPosition::kNoSource, size); |
| 1919 Push(allocate); |
| 1920 return Fragment(allocate); |
| 1921 } |
| 1922 |
| 1923 |
| 1924 Fragment FlowGraphBuilder::AllocateObject(const dart::Class& klass, |
| 1925 intptr_t argument_count) { |
| 1926 ArgumentArray arguments = GetArguments(argument_count); |
| 1927 AllocateObjectInstr* allocate = |
| 1928 new (Z) AllocateObjectInstr(TokenPosition::kNoSource, klass, arguments); |
| 1929 Push(allocate); |
| 1930 return Fragment(allocate); |
| 1931 } |
| 1932 |
| 1933 |
| 1934 Fragment FlowGraphBuilder::AllocateObject(const dart::Class& klass, |
| 1935 const Function& closure_function) { |
| 1936 ArgumentArray arguments = new (Z) ZoneGrowableArray<PushArgumentInstr*>(Z, 0); |
| 1937 AllocateObjectInstr* allocate = |
| 1938 new (Z) AllocateObjectInstr(TokenPosition::kNoSource, klass, arguments); |
| 1939 allocate->set_closure_function(closure_function); |
| 1940 Push(allocate); |
| 1941 return Fragment(allocate); |
| 1942 } |
| 1943 |
| 1944 |
| 1945 Fragment FlowGraphBuilder::BooleanNegate() { |
| 1946 BooleanNegateInstr* negate = new (Z) BooleanNegateInstr(Pop()); |
| 1947 Push(negate); |
| 1948 return Fragment(negate); |
| 1949 } |
| 1950 |
| 1951 |
| 1952 Fragment FlowGraphBuilder::StrictCompare(Token::Kind kind, |
| 1953 bool number_check /* = false */) { |
| 1954 Value* right = Pop(); |
| 1955 Value* left = Pop(); |
| 1956 StrictCompareInstr* compare = new (Z) StrictCompareInstr( |
| 1957 TokenPosition::kNoSource, kind, left, right, number_check); |
| 1958 Push(compare); |
| 1959 return Fragment(compare); |
| 1960 } |
| 1961 |
| 1962 |
| 1963 Fragment FlowGraphBuilder::BranchIfTrue(TargetEntryInstr** then_entry, |
| 1964 TargetEntryInstr** otherwise_entry, |
| 1965 bool negate) { |
| 1966 Fragment instructions = Constant(Bool::True()); |
| 1967 return instructions + BranchIfEqual(then_entry, otherwise_entry, negate); |
| 1968 } |
| 1969 |
| 1970 |
| 1971 Fragment FlowGraphBuilder::BranchIfNull(TargetEntryInstr** then_entry, |
| 1972 TargetEntryInstr** otherwise_entry, |
| 1973 bool negate) { |
| 1974 Fragment instructions = NullConstant(); |
| 1975 return instructions + BranchIfEqual(then_entry, otherwise_entry, negate); |
| 1976 } |
| 1977 |
| 1978 Fragment FlowGraphBuilder::BranchIfEqual(TargetEntryInstr** then_entry, |
| 1979 TargetEntryInstr** otherwise_entry, |
| 1980 bool negate) { |
| 1981 Value* right_value = Pop(); |
| 1982 Value* left_value = Pop(); |
| 1983 StrictCompareInstr* compare = new (Z) StrictCompareInstr( |
| 1984 TokenPosition::kNoSource, negate ? Token::kNE_STRICT : Token::kEQ_STRICT, |
| 1985 left_value, right_value, false); |
| 1986 BranchInstr* branch = new (Z) BranchInstr(compare); |
| 1987 *then_entry = *branch->true_successor_address() = BuildTargetEntry(); |
| 1988 *otherwise_entry = *branch->false_successor_address() = BuildTargetEntry(); |
| 1989 return Fragment(branch).closed(); |
| 1990 } |
| 1991 |
| 1992 |
| 1993 Fragment FlowGraphBuilder::BranchIfStrictEqual( |
| 1994 TargetEntryInstr** then_entry, TargetEntryInstr** otherwise_entry) { |
| 1995 Value* rhs = Pop(); |
| 1996 Value* lhs = Pop(); |
| 1997 StrictCompareInstr* compare = new (Z) StrictCompareInstr( |
| 1998 TokenPosition::kNoSource, Token::kEQ_STRICT, lhs, rhs, false); |
| 1999 BranchInstr* branch = new (Z) BranchInstr(compare); |
| 2000 *then_entry = *branch->true_successor_address() = BuildTargetEntry(); |
| 2001 *otherwise_entry = *branch->false_successor_address() = BuildTargetEntry(); |
| 2002 return Fragment(branch).closed(); |
| 2003 } |
| 2004 |
| 2005 |
| 2006 Fragment FlowGraphBuilder::CatchBlockEntry(const Array& handler_types, |
| 2007 intptr_t handler_index) { |
| 2008 const bool should_restore_closure_context = |
| 2009 CurrentException()->is_captured() || CurrentStackTrace()->is_captured() || |
| 2010 CurrentCatchContext()->is_captured(); |
| 2011 CatchBlockEntryInstr* entry = new (Z) CatchBlockEntryInstr( |
| 2012 AllocateBlockId(), CurrentTryIndex(), graph_entry_, handler_types, |
| 2013 handler_index, *CurrentException(), *CurrentStackTrace(), |
| 2014 /* needs_stacktrace = */ true, Thread::Current()->GetNextDeoptId(), |
| 2015 should_restore_closure_context); |
| 2016 graph_entry_->AddCatchEntry(entry); |
| 2017 Fragment instructions(entry); |
| 2018 |
| 2019 // :saved_try_context_var can be captured in the context of |
| 2020 // of the closure, in this case CatchBlockEntryInstr restores |
| 2021 // :current_context_var to point to closure context in the |
| 2022 // same way as normal function prologue does. |
| 2023 // Update current context depth to reflect that. |
| 2024 const intptr_t saved_context_depth = context_depth_; |
| 2025 ASSERT(!CurrentCatchContext()->is_captured() || |
| 2026 CurrentCatchContext()->owner()->context_level() == 0); |
| 2027 context_depth_ = 0; |
| 2028 instructions += LoadLocal(CurrentCatchContext()); |
| 2029 instructions += StoreLocal(parsed_function_->current_context_var()); |
| 2030 instructions += Drop(); |
| 2031 context_depth_ = saved_context_depth; |
| 2032 |
| 2033 return instructions; |
| 2034 } |
| 2035 |
| 2036 |
| 2037 Fragment FlowGraphBuilder::TryCatch(int try_handler_index) { |
| 2038 // The body of the try needs to have it's own block in order to get a new try |
| 2039 // index. |
| 2040 // |
| 2041 // => We therefore create a block for the body (fresh try index) and another |
| 2042 // join block (with current try index). |
| 2043 Fragment body; |
| 2044 JoinEntryInstr* entry = |
| 2045 new (Z) JoinEntryInstr(AllocateBlockId(), try_handler_index); |
| 2046 body += LoadLocal(parsed_function_->current_context_var()); |
| 2047 body += StoreLocal(CurrentCatchContext()); |
| 2048 body += Drop(); |
| 2049 body += Goto(entry); |
| 2050 return Fragment(body.entry, entry); |
| 2051 } |
| 2052 |
| 2053 |
| 2054 Fragment FlowGraphBuilder::CheckStackOverflowInPrologue() { |
| 2055 if (IsInlining()) { |
| 2056 // If we are inlining don't actually attach the stack check. We must still |
| 2057 // create the stack check in order to allocate a deopt id. |
| 2058 CheckStackOverflow(); |
| 2059 return Fragment(); |
| 2060 } |
| 2061 return CheckStackOverflow(); |
| 2062 } |
| 2063 |
| 2064 |
| 2065 Fragment FlowGraphBuilder::CheckStackOverflow() { |
| 2066 return Fragment( |
| 2067 new (Z) CheckStackOverflowInstr(TokenPosition::kNoSource, loop_depth_)); |
| 2068 } |
| 2069 |
| 2070 |
| 2071 Fragment FlowGraphBuilder::CloneContext() { |
| 2072 LocalVariable* context_variable = parsed_function_->current_context_var(); |
| 2073 |
| 2074 Fragment instructions = LoadLocal(context_variable); |
| 2075 |
| 2076 CloneContextInstr* clone_instruction = |
| 2077 new (Z) CloneContextInstr(TokenPosition::kNoSource, Pop()); |
| 2078 instructions <<= clone_instruction; |
| 2079 Push(clone_instruction); |
| 2080 |
| 2081 instructions += StoreLocal(context_variable); |
| 2082 instructions += Drop(); |
| 2083 return instructions; |
| 2084 } |
| 2085 |
| 2086 |
| 2087 Fragment FlowGraphBuilder::Constant(const Object& value) { |
| 2088 ASSERT(value.IsNotTemporaryScopedHandle()); |
| 2089 ConstantInstr* constant = new (Z) ConstantInstr(value); |
| 2090 Push(constant); |
| 2091 return Fragment(constant); |
| 2092 } |
| 2093 |
| 2094 |
| 2095 Fragment FlowGraphBuilder::CreateArray() { |
| 2096 Value* element_count = Pop(); |
| 2097 CreateArrayInstr* array = new (Z) CreateArrayInstr(TokenPosition::kNoSource, |
| 2098 Pop(), // Element type. |
| 2099 element_count); |
| 2100 Push(array); |
| 2101 return Fragment(array); |
| 2102 } |
| 2103 |
| 2104 |
| 2105 Fragment FlowGraphBuilder::Goto(JoinEntryInstr* destination) { |
| 2106 return Fragment(new (Z) GotoInstr(destination)).closed(); |
| 2107 } |
| 2108 |
| 2109 |
| 2110 Fragment FlowGraphBuilder::IntConstant(int64_t value) { |
| 2111 return Fragment( |
| 2112 Constant(Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld)))); |
| 2113 } |
| 2114 |
| 2115 |
| 2116 Fragment FlowGraphBuilder::InstanceCall(const dart::String& name, |
| 2117 Token::Kind kind, |
| 2118 intptr_t argument_count, |
| 2119 intptr_t num_args_checked) { |
| 2120 return InstanceCall(name, kind, argument_count, Array::null_array(), |
| 2121 num_args_checked); |
| 2122 } |
| 2123 |
| 2124 |
| 2125 Fragment FlowGraphBuilder::InstanceCall(const dart::String& name, |
| 2126 Token::Kind kind, |
| 2127 intptr_t argument_count, |
| 2128 const Array& argument_names, |
| 2129 intptr_t num_args_checked) { |
| 2130 ArgumentArray arguments = GetArguments(argument_count); |
| 2131 InstanceCallInstr* call = new (Z) |
| 2132 InstanceCallInstr(TokenPosition::kNoSource, name, kind, arguments, |
| 2133 argument_names, num_args_checked, ic_data_array_); |
| 2134 Push(call); |
| 2135 return Fragment(call); |
| 2136 } |
| 2137 |
| 2138 |
| 2139 Fragment FlowGraphBuilder::ClosureCall(int argument_count, |
| 2140 const Array& argument_names) { |
| 2141 Value* function = Pop(); |
| 2142 ArgumentArray arguments = GetArguments(argument_count); |
| 2143 ClosureCallInstr* call = new (Z) ClosureCallInstr( |
| 2144 function, arguments, argument_names, TokenPosition::kNoSource); |
| 2145 Push(call); |
| 2146 return Fragment(call); |
| 2147 } |
| 2148 |
| 2149 |
| 2150 Fragment FlowGraphBuilder::ThrowException() { |
| 2151 Fragment instructions; |
| 2152 instructions += Drop(); |
| 2153 instructions += |
| 2154 Fragment(new (Z) ThrowInstr(TokenPosition::kNoSource)).closed(); |
| 2155 // Use it's side effect of leaving a constant on the stack (does not change |
| 2156 // the graph). |
| 2157 NullConstant(); |
| 2158 |
| 2159 pending_argument_count_ -= 1; |
| 2160 |
| 2161 return instructions; |
| 2162 } |
| 2163 |
| 2164 |
| 2165 Fragment FlowGraphBuilder::RethrowException(int catch_try_index) { |
| 2166 Fragment instructions; |
| 2167 instructions += Drop(); |
| 2168 instructions += Drop(); |
| 2169 instructions += |
| 2170 Fragment(new (Z) ReThrowInstr(TokenPosition::kNoSource, catch_try_index)) |
| 2171 .closed(); |
| 2172 // Use it's side effect of leaving a constant on the stack (does not change |
| 2173 // the graph). |
| 2174 NullConstant(); |
| 2175 |
| 2176 pending_argument_count_ -= 2; |
| 2177 |
| 2178 return instructions; |
| 2179 } |
| 2180 |
| 2181 |
| 2182 Fragment FlowGraphBuilder::LoadClassId() { |
| 2183 LoadClassIdInstr* load = new (Z) LoadClassIdInstr(Pop()); |
| 2184 Push(load); |
| 2185 return Fragment(load); |
| 2186 } |
| 2187 |
| 2188 |
| 2189 Fragment FlowGraphBuilder::LoadField(const dart::Field& field) { |
| 2190 LoadFieldInstr* load = new (Z) |
| 2191 LoadFieldInstr(Pop(), &field, AbstractType::ZoneHandle(Z, field.type()), |
| 2192 TokenPosition::kNoSource); |
| 2193 Push(load); |
| 2194 return Fragment(load); |
| 2195 } |
| 2196 |
| 2197 |
| 2198 Fragment FlowGraphBuilder::LoadField(intptr_t offset, intptr_t class_id) { |
| 2199 LoadFieldInstr* load = new (Z) LoadFieldInstr( |
| 2200 Pop(), offset, AbstractType::ZoneHandle(Z), TokenPosition::kNoSource); |
| 2201 load->set_result_cid(class_id); |
| 2202 Push(load); |
| 2203 return Fragment(load); |
| 2204 } |
| 2205 |
| 2206 |
| 2207 Fragment FlowGraphBuilder::LoadNativeField(MethodRecognizer::Kind kind, |
| 2208 intptr_t offset, const Type& type, |
| 2209 intptr_t class_id, |
| 2210 bool is_immutable) { |
| 2211 LoadFieldInstr* load = |
| 2212 new (Z) LoadFieldInstr(Pop(), offset, type, TokenPosition::kNoSource); |
| 2213 load->set_recognized_kind(kind); |
| 2214 load->set_result_cid(class_id); |
| 2215 load->set_is_immutable(is_immutable); |
| 2216 Push(load); |
| 2217 return Fragment(load); |
| 2218 } |
| 2219 |
| 2220 |
| 2221 Fragment FlowGraphBuilder::LoadLocal(LocalVariable* variable) { |
| 2222 Fragment instructions; |
| 2223 if (variable->is_captured()) { |
| 2224 instructions += LoadContextAt(variable->owner()->context_level()); |
| 2225 instructions += LoadField(Context::variable_offset(variable->index())); |
| 2226 } else { |
| 2227 LoadLocalInstr* load = |
| 2228 new (Z) LoadLocalInstr(*variable, TokenPosition::kNoSource); |
| 2229 instructions <<= load; |
| 2230 Push(load); |
| 2231 } |
| 2232 return instructions; |
| 2233 } |
| 2234 |
| 2235 |
| 2236 Fragment FlowGraphBuilder::InitStaticField(const dart::Field& field) { |
| 2237 InitStaticFieldInstr* init = new (Z) InitStaticFieldInstr(Pop(), field); |
| 2238 return Fragment(init); |
| 2239 } |
| 2240 |
| 2241 |
| 2242 Fragment FlowGraphBuilder::LoadStaticField() { |
| 2243 LoadStaticFieldInstr* load = |
| 2244 new (Z) LoadStaticFieldInstr(Pop(), TokenPosition::kNoSource); |
| 2245 Push(load); |
| 2246 return Fragment(load); |
| 2247 } |
| 2248 |
| 2249 |
| 2250 Fragment FlowGraphBuilder::NullConstant() { |
| 2251 return Constant(Instance::ZoneHandle(Z, Instance::null())); |
| 2252 } |
| 2253 |
| 2254 |
| 2255 Fragment FlowGraphBuilder::NativeCall(const dart::String* name, |
| 2256 const Function* function) { |
| 2257 InlineBailout("dil::FlowGraphBuilder::NativeCall"); |
| 2258 NativeCallInstr* call = new (Z) NativeCallInstr( |
| 2259 name, function, FLAG_link_natives_lazily, TokenPosition::kNoSource); |
| 2260 Push(call); |
| 2261 return Fragment(call); |
| 2262 } |
| 2263 |
| 2264 |
| 2265 Fragment FlowGraphBuilder::PushArgument() { |
| 2266 PushArgumentInstr* argument = new (Z) PushArgumentInstr(Pop()); |
| 2267 Push(argument); |
| 2268 |
| 2269 argument->set_temp_index(argument->temp_index() - 1); |
| 2270 ++pending_argument_count_; |
| 2271 |
| 2272 return Fragment(argument); |
| 2273 } |
| 2274 |
| 2275 |
| 2276 Fragment FlowGraphBuilder::Return() { |
| 2277 Value* value = Pop(); |
| 2278 ASSERT(stack_ == NULL); |
| 2279 ReturnInstr* return_instr = |
| 2280 new (Z) ReturnInstr(TokenPosition::kNoSource, value); |
| 2281 if (exit_collector_ != NULL) exit_collector_->AddExit(return_instr); |
| 2282 return Fragment(return_instr).closed(); |
| 2283 } |
| 2284 |
| 2285 |
| 2286 Fragment FlowGraphBuilder::StaticCall(const Function& target, |
| 2287 intptr_t argument_count) { |
| 2288 return StaticCall(target, argument_count, Array::null_array()); |
| 2289 } |
| 2290 |
| 2291 |
| 2292 static intptr_t GetResultCidOfListFactory(const Function& function, |
| 2293 intptr_t argument_count) { |
| 2294 if (!function.IsFactory()) { |
| 2295 return kDynamicCid; |
| 2296 } |
| 2297 |
| 2298 const dart::Class& owner = dart::Class::Handle(function.Owner()); |
| 2299 if ((owner.library() != dart::Library::CoreLibrary()) && |
| 2300 (owner.library() != dart::Library::TypedDataLibrary())) { |
| 2301 return kDynamicCid; |
| 2302 } |
| 2303 |
| 2304 if ((owner.Name() == Symbols::List().raw()) && |
| 2305 (function.name() == Symbols::ListFactory().raw())) { |
| 2306 ASSERT(argument_count == 1 || argument_count == 2); |
| 2307 return (argument_count == 1) ? kGrowableObjectArrayCid : kArrayCid; |
| 2308 } |
| 2309 return FactoryRecognizer::ResultCid(function); |
| 2310 } |
| 2311 |
| 2312 |
| 2313 Fragment FlowGraphBuilder::StaticCall(const Function& target, |
| 2314 intptr_t argument_count, |
| 2315 const Array& argument_names) { |
| 2316 ArgumentArray arguments = GetArguments(argument_count); |
| 2317 StaticCallInstr* call = |
| 2318 new (Z) StaticCallInstr(TokenPosition::kNoSource, target, argument_names, |
| 2319 arguments, ic_data_array_); |
| 2320 const intptr_t list_cid = GetResultCidOfListFactory(target, argument_count); |
| 2321 if (list_cid != kDynamicCid) { |
| 2322 call->set_result_cid(list_cid); |
| 2323 call->set_is_known_list_constructor(true); |
| 2324 } else if (target.recognized_kind() != MethodRecognizer::kUnknown) { |
| 2325 call->set_result_cid(MethodRecognizer::ResultCid(target)); |
| 2326 } |
| 2327 Push(call); |
| 2328 return Fragment(call); |
| 2329 } |
| 2330 |
| 2331 |
| 2332 Fragment FlowGraphBuilder::StoreIndexed(intptr_t class_id) { |
| 2333 Value* value = Pop(); |
| 2334 Value* index = Pop(); |
| 2335 // TODO(kmillikin): Omit store barrier when possible (e.g., storing |
| 2336 // some constants). |
| 2337 StoreIndexedInstr* store = new (Z) StoreIndexedInstr( |
| 2338 Pop(), // Array. |
| 2339 index, value, kEmitStoreBarrier, Instance::ElementSizeFor(class_id), |
| 2340 class_id, Thread::kNoDeoptId, TokenPosition::kNoSource); |
| 2341 Push(store); |
| 2342 return Fragment(store); |
| 2343 } |
| 2344 |
| 2345 |
| 2346 Fragment FlowGraphBuilder::StoreInstanceField(const dart::Field& field) { |
| 2347 Value* value = Pop(); |
| 2348 // TODO(kmillikin): Omit store barrier when possible (e.g., storing |
| 2349 // some constants). |
| 2350 StoreInstanceFieldInstr* store = new (Z) StoreInstanceFieldInstr( |
| 2351 field, Pop(), value, kEmitStoreBarrier, TokenPosition::kNoSource); |
| 2352 return Fragment(store); |
| 2353 } |
| 2354 |
| 2355 |
| 2356 Fragment FlowGraphBuilder::StoreInstanceField(intptr_t offset) { |
| 2357 Value* value = Pop(); |
| 2358 StoreInstanceFieldInstr* store = new (Z) StoreInstanceFieldInstr( |
| 2359 offset, Pop(), value, kEmitStoreBarrier, TokenPosition::kNoSource); |
| 2360 return Fragment(store); |
| 2361 } |
| 2362 |
| 2363 |
| 2364 Fragment FlowGraphBuilder::StoreLocal(LocalVariable* variable) { |
| 2365 Fragment instructions; |
| 2366 if (variable->is_captured()) { |
| 2367 LocalVariable* value = MakeTemporary(); |
| 2368 instructions += LoadContextAt(variable->owner()->context_level()); |
| 2369 instructions += LoadLocal(value); |
| 2370 instructions += |
| 2371 StoreInstanceField(Context::variable_offset(variable->index())); |
| 2372 } else { |
| 2373 StoreLocalInstr* store = |
| 2374 new (Z) StoreLocalInstr(*variable, Pop(), TokenPosition::kNoSource); |
| 2375 instructions <<= store; |
| 2376 Push(store); |
| 2377 } |
| 2378 return instructions; |
| 2379 } |
| 2380 |
| 2381 |
| 2382 Fragment FlowGraphBuilder::StoreStaticField(const dart::Field& field) { |
| 2383 return Fragment( |
| 2384 new (Z) StoreStaticFieldInstr(field, Pop(), TokenPosition::kNoSource)); |
| 2385 } |
| 2386 |
| 2387 |
| 2388 Fragment FlowGraphBuilder::StringInterpolate() { |
| 2389 Value* array = Pop(); |
| 2390 StringInterpolateInstr* interpolate = |
| 2391 new (Z) StringInterpolateInstr(array, TokenPosition::kNoSource); |
| 2392 Push(interpolate); |
| 2393 return Fragment(interpolate); |
| 2394 } |
| 2395 |
| 2396 |
| 2397 Fragment FlowGraphBuilder::ThrowTypeError() { |
| 2398 const dart::Class& klass = dart::Class::ZoneHandle( |
| 2399 Z, dart::Library::LookupCoreClass(Symbols::TypeError())); |
| 2400 ASSERT(!klass.IsNull()); |
| 2401 const dart::Function& constructor = dart::Function::ZoneHandle( |
| 2402 Z, |
| 2403 klass.LookupConstructorAllowPrivate(H.DartSymbol("_TypeError._create"))); |
| 2404 ASSERT(!constructor.IsNull()); |
| 2405 |
| 2406 const dart::String& url = H.DartString( |
| 2407 parsed_function_->function().ToLibNamePrefixedQualifiedCString(), |
| 2408 Heap::kOld); |
| 2409 |
| 2410 Fragment instructions; |
| 2411 |
| 2412 // Create instance of _FallThroughError |
| 2413 instructions += AllocateObject(klass, 0); |
| 2414 LocalVariable* instance = MakeTemporary(); |
| 2415 |
| 2416 // Call _AssertionError._create constructor. |
| 2417 instructions += LoadLocal(instance); |
| 2418 instructions += PushArgument(); // this |
| 2419 |
| 2420 instructions += Constant(url); |
| 2421 instructions += PushArgument(); // url |
| 2422 |
| 2423 instructions += NullConstant(); |
| 2424 instructions += PushArgument(); // line |
| 2425 |
| 2426 instructions += IntConstant(0); |
| 2427 instructions += PushArgument(); // column |
| 2428 |
| 2429 instructions += Constant(H.DartSymbol("Malformed type.")); |
| 2430 instructions += PushArgument(); // message |
| 2431 |
| 2432 instructions += StaticCall(constructor, 5); |
| 2433 instructions += Drop(); |
| 2434 |
| 2435 // Throw the exception |
| 2436 instructions += PushArgument(); |
| 2437 instructions += ThrowException(); |
| 2438 |
| 2439 return instructions; |
| 2440 } |
| 2441 |
| 2442 |
| 2443 Fragment FlowGraphBuilder::ThrowNoSuchMethodError() { |
| 2444 const dart::Class& klass = dart::Class::ZoneHandle( |
| 2445 Z, dart::Library::LookupCoreClass(Symbols::NoSuchMethodError())); |
| 2446 ASSERT(!klass.IsNull()); |
| 2447 const dart::Function& throw_function = dart::Function::ZoneHandle( |
| 2448 Z, klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNew())); |
| 2449 ASSERT(!throw_function.IsNull()); |
| 2450 |
| 2451 Fragment instructions; |
| 2452 |
| 2453 // Call NoSuchMethodError._throwNew static function. |
| 2454 instructions += NullConstant(); |
| 2455 instructions += PushArgument(); // receiver |
| 2456 |
| 2457 instructions += Constant(H.DartString("<unknown>", Heap::kOld)); |
| 2458 instructions += PushArgument(); // memberName |
| 2459 |
| 2460 instructions += IntConstant(-1); |
| 2461 instructions += PushArgument(); // invocation_type |
| 2462 |
| 2463 instructions += NullConstant(); |
| 2464 instructions += PushArgument(); // arguments |
| 2465 |
| 2466 instructions += NullConstant(); |
| 2467 instructions += PushArgument(); // argumentNames |
| 2468 |
| 2469 instructions += NullConstant(); |
| 2470 instructions += PushArgument(); // existingArgumentNames |
| 2471 |
| 2472 instructions += StaticCall(throw_function, 6); |
| 2473 // Leave "result" on the stack since callers expect it to be there (even |
| 2474 // though the function will result in an exception). |
| 2475 |
| 2476 return instructions; |
| 2477 } |
| 2478 |
| 2479 |
| 2480 dart::RawFunction* FlowGraphBuilder::LookupMethodByMember( |
| 2481 Member* target, const dart::String& method_name) { |
| 2482 Class* dil_klass = Class::Cast(target->parent()); |
| 2483 dart::Class& klass = |
| 2484 dart::Class::Handle(Z, H.LookupClassByDilClass(dil_klass)); |
| 2485 |
| 2486 dart::RawFunction* function = klass.LookupFunctionAllowPrivate(method_name); |
| 2487 ASSERT(function != Object::null()); |
| 2488 return function; |
| 2489 } |
| 2490 |
| 2491 |
| 2492 LocalVariable* FlowGraphBuilder::MakeTemporary() { |
| 2493 char name[64]; |
| 2494 intptr_t index = stack_->definition()->temp_index(); |
| 2495 OS::SNPrint(name, 64, ":temp%" Pd, index); |
| 2496 // TODO(kmillikin): When types are supported we will need to support |
| 2497 // closure signature types. |
| 2498 LocalVariable* variable = new (Z) LocalVariable( |
| 2499 TokenPosition::kNoSource, H.DartSymbol(name), Object::dynamic_type()); |
| 2500 // Set the index relative to the base of the expression stack including |
| 2501 // outgoing arguments. |
| 2502 variable->set_index(parsed_function_->first_stack_local_index() - |
| 2503 parsed_function_->num_stack_locals() - |
| 2504 pending_argument_count_ - index); |
| 2505 |
| 2506 // The value has uses as if it were a local variable. Mark the definition |
| 2507 // as used so that its temp index will not be cleared (causing it to never |
| 2508 // be materialized in the expression stack). |
| 2509 stack_->definition()->set_ssa_temp_index(0); |
| 2510 |
| 2511 return variable; |
| 2512 } |
| 2513 |
| 2514 |
| 2515 intptr_t FlowGraphBuilder::CurrentTryIndex() { |
| 2516 if (try_catch_block_ == NULL) { |
| 2517 return CatchClauseNode::kInvalidTryIndex; |
| 2518 } else { |
| 2519 return try_catch_block_->TryIndex(); |
| 2520 } |
| 2521 } |
| 2522 |
| 2523 |
| 2524 dart::LocalVariable* FlowGraphBuilder::LookupVariable( |
| 2525 VariableDeclaration* var) { |
| 2526 LocalVariable* local = scopes_->locals.Lookup(var); |
| 2527 ASSERT(local != NULL); |
| 2528 return local; |
| 2529 } |
| 2530 |
| 2531 |
| 2532 void FlowGraphBuilder::SetTempIndex(Definition* definition) { |
| 2533 definition->set_temp_index( |
| 2534 stack_ == NULL ? 0 : stack_->definition()->temp_index() + 1); |
| 2535 } |
| 2536 |
| 2537 |
| 2538 void FlowGraphBuilder::Push(Definition* definition) { |
| 2539 SetTempIndex(definition); |
| 2540 Value::AddToList(new (Z) Value(definition), &stack_); |
| 2541 } |
| 2542 |
| 2543 |
| 2544 Value* FlowGraphBuilder::Pop() { |
| 2545 ASSERT(stack_ != NULL); |
| 2546 Value* value = stack_; |
| 2547 stack_ = value->next_use(); |
| 2548 if (stack_ != NULL) stack_->set_previous_use(NULL); |
| 2549 |
| 2550 value->set_next_use(NULL); |
| 2551 value->set_previous_use(NULL); |
| 2552 value->definition()->ClearSSATempIndex(); |
| 2553 return value; |
| 2554 } |
| 2555 |
| 2556 |
| 2557 Fragment FlowGraphBuilder::Drop() { |
| 2558 ASSERT(stack_ != NULL); |
| 2559 Fragment instructions; |
| 2560 Definition* definition = stack_->definition(); |
| 2561 // The SSA renaming implementation doesn't like [LoadLocal]s without a |
| 2562 // tempindex. |
| 2563 if (definition->HasSSATemp() || definition->IsLoadLocal()) { |
| 2564 instructions <<= new (Z) DropTempsInstr(1, NULL); |
| 2565 } else { |
| 2566 definition->ClearTempIndex(); |
| 2567 } |
| 2568 |
| 2569 Pop(); |
| 2570 return instructions; |
| 2571 } |
| 2572 |
| 2573 |
| 2574 // TODO(kustermann): This method should be shared with |
| 2575 // runtime/vm/object.cc:RecognizeArithmeticOp. |
| 2576 Token::Kind FlowGraphBuilder::MethodKind(const dart::String& name) { |
| 2577 ASSERT(name.IsSymbol()); |
| 2578 if (name.raw() == Symbols::Plus().raw()) { |
| 2579 return Token::kADD; |
| 2580 } else if (name.raw() == Symbols::Minus().raw()) { |
| 2581 return Token::kSUB; |
| 2582 } else if (name.raw() == Symbols::Star().raw()) { |
| 2583 return Token::kMUL; |
| 2584 } else if (name.raw() == Symbols::Slash().raw()) { |
| 2585 return Token::kDIV; |
| 2586 } else if (name.raw() == Symbols::TruncDivOperator().raw()) { |
| 2587 return Token::kTRUNCDIV; |
| 2588 } else if (name.raw() == Symbols::Percent().raw()) { |
| 2589 return Token::kMOD; |
| 2590 } else if (name.raw() == Symbols::BitOr().raw()) { |
| 2591 return Token::kBIT_OR; |
| 2592 } else if (name.raw() == Symbols::Ampersand().raw()) { |
| 2593 return Token::kBIT_AND; |
| 2594 } else if (name.raw() == Symbols::Caret().raw()) { |
| 2595 return Token::kBIT_XOR; |
| 2596 } else if (name.raw() == Symbols::LeftShiftOperator().raw()) { |
| 2597 return Token::kSHL; |
| 2598 } else if (name.raw() == Symbols::RightShiftOperator().raw()) { |
| 2599 return Token::kSHR; |
| 2600 } else if (name.raw() == Symbols::Tilde().raw()) { |
| 2601 return Token::kBIT_NOT; |
| 2602 } else if (name.raw() == Symbols::UnaryMinus().raw()) { |
| 2603 return Token::kNEGATE; |
| 2604 } else if (name.raw() == Symbols::EqualOperator().raw()) { |
| 2605 return Token::kEQ; |
| 2606 } else if (name.raw() == Symbols::Token(Token::kNE).raw()) { |
| 2607 return Token::kNE; |
| 2608 } else if (name.raw() == Symbols::LAngleBracket().raw()) { |
| 2609 return Token::kLT; |
| 2610 } else if (name.raw() == Symbols::RAngleBracket().raw()) { |
| 2611 return Token::kGT; |
| 2612 } else if (name.raw() == Symbols::LessEqualOperator().raw()) { |
| 2613 return Token::kLTE; |
| 2614 } else if (name.raw() == Symbols::GreaterEqualOperator().raw()) { |
| 2615 return Token::kGTE; |
| 2616 } else if (dart::Field::IsGetterName(name)) { |
| 2617 return Token::kGET; |
| 2618 } else if (dart::Field::IsSetterName(name)) { |
| 2619 return Token::kSET; |
| 2620 } |
| 2621 return Token::kILLEGAL; |
| 2622 } |
| 2623 |
| 2624 |
| 2625 void FlowGraphBuilder::InlineBailout(const char* reason) { |
| 2626 bool is_inlining = exit_collector_ != NULL; |
| 2627 if (is_inlining) { |
| 2628 parsed_function_->function().set_is_inlinable(false); |
| 2629 parsed_function_->Bailout("dil::FlowGraphBuilder", reason); |
| 2630 } |
| 2631 } |
| 2632 |
| 2633 |
| 2634 FlowGraph* FlowGraphBuilder::BuildGraph() { |
| 2635 const dart::Function& function = parsed_function_->function(); |
| 2636 |
| 2637 if (function.IsConstructorClosureFunction()) return NULL; |
| 2638 |
| 2639 dart::Class& klass = |
| 2640 dart::Class::Handle(zone_, parsed_function_->function().Owner()); |
| 2641 |
| 2642 // Find out if there is an enclosing dil class (which will be used to resolve |
| 2643 // type parameters). |
| 2644 Class* dil_klass = NULL; |
| 2645 dart::Function& topmost = dart::Function::Handle(Z, function.raw()); |
| 2646 while (topmost.parent_function() != Object::null()) { |
| 2647 topmost = topmost.parent_function(); |
| 2648 } |
| 2649 TreeNode* topmost_node = reinterpret_cast<TreeNode*>(topmost.dil_function()); |
| 2650 if (topmost_node != NULL) { |
| 2651 // Going up the closure->parent chain needs to result in a Procedure or |
| 2652 // Constructor. |
| 2653 TreeNode* parent = NULL; |
| 2654 if (topmost_node->IsProcedure()) { |
| 2655 parent = Procedure::Cast(topmost_node)->parent(); |
| 2656 } else if (topmost_node->IsConstructor()) { |
| 2657 parent = Constructor::Cast(topmost_node)->parent(); |
| 2658 } else if (topmost_node->IsField()) { |
| 2659 parent = Field::Cast(topmost_node)->parent(); |
| 2660 } |
| 2661 if (parent != NULL && parent->IsClass()) dil_klass = Class::Cast(parent); |
| 2662 } |
| 2663 |
| 2664 // Mark that we are using [klass]/[dill_klass] as active class. Resolving of |
| 2665 // type parameters will get resolved via [dill_klass] unless we are nested |
| 2666 // inside a static factory in which case we will use [member]. |
| 2667 ActiveClassScope active_class_scope(&active_class_, dil_klass, &klass); |
| 2668 Member* member = topmost_node != NULL && topmost_node->IsMember() |
| 2669 ? Member::Cast(topmost_node) |
| 2670 : NULL; |
| 2671 ActiveMemberScope active_member(&active_class_, member); |
| 2672 |
| 2673 // The IR builder will create its own local variables and scopes, and it |
| 2674 // will not need an AST. The code generator will assume that there is a |
| 2675 // local variable stack slot allocated for the current context and (I |
| 2676 // think) that the runtime will expect it to be at a fixed offset which |
| 2677 // requires allocating an unused expression temporary variable. |
| 2678 scopes_ = parsed_function_->EnsureDilScopes(); |
| 2679 |
| 2680 switch (function.kind()) { |
| 2681 case RawFunction::kClosureFunction: |
| 2682 case RawFunction::kRegularFunction: |
| 2683 case RawFunction::kGetterFunction: |
| 2684 case RawFunction::kSetterFunction: { |
| 2685 FunctionNode* dil_function = node_->IsProcedure() |
| 2686 ? Procedure::Cast(node_)->function() |
| 2687 : FunctionNode::Cast(node_); |
| 2688 ActiveFunctionScope active_function_scope(&active_class_, dil_function); |
| 2689 return function.IsImplicitClosureFunction() |
| 2690 ? BuildGraphOfImplicitClosureFunction(dil_function, function) |
| 2691 : BuildGraphOfFunction(dil_function); |
| 2692 } |
| 2693 case RawFunction::kConstructor: { |
| 2694 bool is_factory = function.IsFactory(); |
| 2695 if (is_factory) { |
| 2696 Procedure* procedure = Procedure::Cast(node_); |
| 2697 FunctionNode* function = procedure->function(); |
| 2698 ActiveFunctionScope active_function_scope(&active_class_, function); |
| 2699 return BuildGraphOfFunction(function, NULL); |
| 2700 } else { |
| 2701 Constructor* constructor = Constructor::Cast(node_); |
| 2702 FunctionNode* function = constructor->function(); |
| 2703 ActiveFunctionScope active_function_scope(&active_class_, function); |
| 2704 return BuildGraphOfFunction(function, constructor); |
| 2705 } |
| 2706 } |
| 2707 case RawFunction::kImplicitGetter: |
| 2708 case RawFunction::kImplicitStaticFinalGetter: |
| 2709 case RawFunction::kImplicitSetter: { |
| 2710 Field* field = Field::Cast(node_); |
| 2711 return IsStaticInitializer(function, Z) |
| 2712 ? BuildGraphOfStaticFieldInitializer(field) |
| 2713 : BuildGraphOfFieldAccessor(field, scopes_->setter_value); |
| 2714 } |
| 2715 case RawFunction::kMethodExtractor: |
| 2716 return BuildGraphOfMethodExtractor(function); |
| 2717 case RawFunction::kNoSuchMethodDispatcher: |
| 2718 return BuildGraphOfNoSuchMethodDispatcher(function); |
| 2719 case RawFunction::kInvokeFieldDispatcher: |
| 2720 return BuildGraphOfInvokeFieldDispatcher(function); |
| 2721 case RawFunction::kSignatureFunction: |
| 2722 case RawFunction::kIrregexpFunction: |
| 2723 break; |
| 2724 } |
| 2725 UNREACHABLE(); |
| 2726 return NULL; |
| 2727 } |
| 2728 |
| 2729 |
| 2730 FlowGraph* FlowGraphBuilder::BuildGraphOfFunction(FunctionNode* function, |
| 2731 Constructor* constructor) { |
| 2732 const Function& dart_function = parsed_function_->function(); |
| 2733 TargetEntryInstr* normal_entry = BuildTargetEntry(); |
| 2734 graph_entry_ = new (Z) |
| 2735 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
| 2736 |
| 2737 SetupDefaultParameterValues(function); |
| 2738 |
| 2739 Fragment body; |
| 2740 if (!dart_function.is_native()) body += CheckStackOverflowInPrologue(); |
| 2741 intptr_t context_size = |
| 2742 parsed_function_->node_sequence()->scope()->num_context_variables(); |
| 2743 if (context_size > 0) { |
| 2744 body += PushContext(context_size); |
| 2745 LocalVariable* context = MakeTemporary(); |
| 2746 |
| 2747 // Copy captured parameters from the stack into the context. |
| 2748 LocalScope* scope = parsed_function_->node_sequence()->scope(); |
| 2749 intptr_t parameter_count = dart_function.NumParameters(); |
| 2750 intptr_t parameter_index = parsed_function_->first_parameter_index(); |
| 2751 for (intptr_t i = 0; i < parameter_count; ++i, --parameter_index) { |
| 2752 LocalVariable* variable = scope->VariableAt(i); |
| 2753 if (variable->is_captured()) { |
| 2754 // There is no LocalVariable describing the on-stack parameter so |
| 2755 // create one directly. |
| 2756 LocalVariable* parameter = |
| 2757 new (Z) LocalVariable(TokenPosition::kNoSource, |
| 2758 Symbols::TempParam(), Object::dynamic_type()); |
| 2759 parameter->set_index(parameter_index); |
| 2760 // Mark the stack variable so it will be ignored by the code for |
| 2761 // try/catch. |
| 2762 parameter->set_is_captured_parameter(true); |
| 2763 |
| 2764 // Copy the parameter from the stack to the context. Overwrite it |
| 2765 // with a null constant on the stack so the original value is |
| 2766 // eligible for garbage collection. |
| 2767 body += LoadLocal(context); |
| 2768 body += LoadLocal(parameter); |
| 2769 body += StoreInstanceField(Context::variable_offset(variable->index())); |
| 2770 body += NullConstant(); |
| 2771 body += StoreLocal(parameter); |
| 2772 body += Drop(); |
| 2773 } |
| 2774 } |
| 2775 body += Drop(); // The context. |
| 2776 } |
| 2777 if (constructor != NULL) { |
| 2778 // TODO(kustermann): Currently the [VariableDeclaration]s from the |
| 2779 // initializers will be visible inside the entire body of the constructor. |
| 2780 // We should make a separate scope for them. |
| 2781 Class* dil_klass = Class::Cast(constructor->parent()); |
| 2782 body += TranslateInitializers(dil_klass, &constructor->initializers()); |
| 2783 } |
| 2784 |
| 2785 // The specification defines the result of `a == b` to be: |
| 2786 // |
| 2787 // a) if either side is `null` then the result is `identical(a, b)`. |
| 2788 // b) else the result is `a.operator==(b)` |
| 2789 // |
| 2790 // For user-defined implementations of `operator==` we need therefore |
| 2791 // implement the handling of a). |
| 2792 // |
| 2793 // The default `operator==` implementation in `Object` is implemented in terms |
| 2794 // of identical (which we assume here!) which means that case a) is actually |
| 2795 // included in b). So we just use the normal implementation in the body. |
| 2796 if ((dart_function.NumParameters() == 2) && |
| 2797 (dart_function.name() == Symbols::EqualOperator().raw()) && |
| 2798 (dart_function.Owner() != I->object_store()->object_class())) { |
| 2799 LocalVariable* parameter = |
| 2800 LookupVariable(function->positional_parameters()[0]); |
| 2801 |
| 2802 TargetEntryInstr* null_entry; |
| 2803 TargetEntryInstr* non_null_entry; |
| 2804 |
| 2805 body += LoadLocal(parameter); |
| 2806 body += BranchIfNull(&null_entry, &non_null_entry); |
| 2807 |
| 2808 // The argument was `null` and the receiver is not the null class (we only |
| 2809 // go into this branch for user-defined == operators) so we can return |
| 2810 // false. |
| 2811 Fragment null_fragment(null_entry); |
| 2812 null_fragment += Constant(Bool::False()); |
| 2813 null_fragment += Return(); |
| 2814 |
| 2815 body = Fragment(body.entry, non_null_entry); |
| 2816 } |
| 2817 |
| 2818 if (dart_function.is_native()) { |
| 2819 body += NativeFunctionBody(function, dart_function); |
| 2820 } else if (function->body() != NULL) { |
| 2821 body += TranslateStatement(function->body()); |
| 2822 } |
| 2823 if (body.is_open()) { |
| 2824 body += NullConstant(); |
| 2825 body += Return(); |
| 2826 } |
| 2827 |
| 2828 // If functions body contains any yield points build switch statement that |
| 2829 // selects a continuation point based on the value of :await_jump_var. |
| 2830 if (!yield_continuations_.is_empty()) { |
| 2831 // The code we are building will be executed right after we enter |
| 2832 // the function and before any nested contexts are allocated. |
| 2833 // Reset current context_depth_ to match this. |
| 2834 intptr_t current_context_depth = context_depth_; |
| 2835 context_depth_ = scopes_->yield_jump_variable->owner()->context_level(); |
| 2836 |
| 2837 // Prepend an entry corresponding to normal entry to the function. |
| 2838 yield_continuations_.InsertAt( |
| 2839 0, YieldContinuation(new (Z) DropTempsInstr(0, NULL), |
| 2840 CatchClauseNode::kInvalidTryIndex)); |
| 2841 yield_continuations_[0].entry->LinkTo(body.entry); |
| 2842 |
| 2843 // Build a switch statement. |
| 2844 Fragment dispatch; |
| 2845 |
| 2846 // Load :await_jump_var into a temporary. |
| 2847 dispatch += LoadLocal(scopes_->yield_jump_variable); |
| 2848 dispatch += StoreLocal(scopes_->switch_variable); |
| 2849 dispatch += Drop(); |
| 2850 |
| 2851 BlockEntryInstr* block = NULL; |
| 2852 for (intptr_t i = 0; i < yield_continuations_.length(); i++) { |
| 2853 if (i == 1) { |
| 2854 // This is not a normal entry but a resumption. Restore |
| 2855 // :current_context_var from :await_ctx_var. |
| 2856 // Note: after this point context_depth_ does not match current context |
| 2857 // depth so we should not access any local variables anymore. |
| 2858 dispatch += LoadLocal(scopes_->yield_context_variable); |
| 2859 dispatch += StoreLocal(parsed_function_->current_context_var()); |
| 2860 dispatch += Drop(); |
| 2861 } |
| 2862 if (i == (yield_continuations_.length() - 1)) { |
| 2863 // We reached the last possility, no need to build more ifs. |
| 2864 // Coninue to the last continuation. |
| 2865 // Note: continuations start with nop DropTemps instruction |
| 2866 // which acts like an anchor, so we need to skip it. |
| 2867 block->set_try_index(yield_continuations_[i].try_index); |
| 2868 dispatch <<= yield_continuations_[i].entry->next(); |
| 2869 break; |
| 2870 } |
| 2871 |
| 2872 // Build comparison: |
| 2873 // |
| 2874 // if (:await_ctx_var == i) { |
| 2875 // -> yield_continuations_[i] |
| 2876 // } else ... |
| 2877 // |
| 2878 TargetEntryInstr* then; |
| 2879 TargetEntryInstr* otherwise; |
| 2880 dispatch += LoadLocal(scopes_->switch_variable); |
| 2881 dispatch += IntConstant(i); |
| 2882 dispatch += BranchIfStrictEqual(&then, &otherwise); |
| 2883 |
| 2884 // True branch is linked to appropriate continuation point. |
| 2885 // Note: continuations start with nop DropTemps instruction |
| 2886 // which acts like an anchor, so we need to skip it. |
| 2887 then->LinkTo(yield_continuations_[i].entry->next()); |
| 2888 then->set_try_index(yield_continuations_[i].try_index); |
| 2889 |
| 2890 // False branch will contain the next comparison. |
| 2891 dispatch = Fragment(dispatch.entry, otherwise); |
| 2892 block = otherwise; |
| 2893 } |
| 2894 body = dispatch; |
| 2895 |
| 2896 context_depth_ = current_context_depth; |
| 2897 } |
| 2898 normal_entry->LinkTo(body.entry); |
| 2899 |
| 2900 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
| 2901 } |
| 2902 |
| 2903 |
| 2904 Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* dil_function, |
| 2905 const Function& function) { |
| 2906 ASSERT(function.is_native()); |
| 2907 // We explicitly build the graph for native functions in the same way that the |
| 2908 // from-source backend does. We should find a way to have a single component |
| 2909 // to build these graphs so that this code is not duplicated. |
| 2910 |
| 2911 Fragment body; |
| 2912 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function); |
| 2913 switch (kind) { |
| 2914 case MethodRecognizer::kObjectEquals: |
| 2915 body += LoadLocal(scopes_->this_variable); |
| 2916 body += |
| 2917 LoadLocal(LookupVariable(dil_function->positional_parameters()[0])); |
| 2918 body += StrictCompare(Token::kEQ_STRICT); |
| 2919 break; |
| 2920 case MethodRecognizer::kStringBaseLength: |
| 2921 case MethodRecognizer::kStringBaseIsEmpty: |
| 2922 // Depending on FLAG_support_externalizable_strings, treat string length |
| 2923 // loads as mutable so that the class check that precedes them will not be |
| 2924 // hoisted. This is unsafe because string externalization can change the |
| 2925 // class. |
| 2926 body += LoadLocal(scopes_->this_variable); |
| 2927 body += LoadNativeField(MethodRecognizer::kStringBaseLength, |
| 2928 dart::String::length_offset(), |
| 2929 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, |
| 2930 !FLAG_support_externalizable_strings); |
| 2931 if (kind == MethodRecognizer::kStringBaseIsEmpty) { |
| 2932 body += IntConstant(0); |
| 2933 body += StrictCompare(Token::kEQ_STRICT); |
| 2934 } |
| 2935 break; |
| 2936 case MethodRecognizer::kGrowableArrayLength: |
| 2937 body += LoadLocal(scopes_->this_variable); |
| 2938 body += LoadNativeField(kind, GrowableObjectArray::length_offset(), |
| 2939 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
| 2940 break; |
| 2941 case MethodRecognizer::kObjectArrayLength: |
| 2942 case MethodRecognizer::kImmutableArrayLength: |
| 2943 body += LoadLocal(scopes_->this_variable); |
| 2944 body += |
| 2945 LoadNativeField(kind, Array::length_offset(), |
| 2946 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true); |
| 2947 break; |
| 2948 case MethodRecognizer::kTypedDataLength: |
| 2949 body += LoadLocal(scopes_->this_variable); |
| 2950 body += |
| 2951 LoadNativeField(kind, TypedData::length_offset(), |
| 2952 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true); |
| 2953 break; |
| 2954 case MethodRecognizer::kClassIDgetID: |
| 2955 body += |
| 2956 LoadLocal(LookupVariable(dil_function->positional_parameters()[0])); |
| 2957 body += LoadClassId(); |
| 2958 break; |
| 2959 |
| 2960 #if 0 |
| 2961 case MethodRecognizer::kClassID_getCidArray: |
| 2962 body += IntConstant(kArrayCid); |
| 2963 break; |
| 2964 case MethodRecognizer::kClassID_getCidExternalOneByteString: |
| 2965 body += IntConstant(kExternalOneByteStringCid); |
| 2966 break; |
| 2967 case MethodRecognizer::kClassID_getCidGrowableObjectArray: |
| 2968 body += IntConstant(kGrowableObjectArrayCid); |
| 2969 break; |
| 2970 case MethodRecognizer::kClassID_getCidImmutableArray: |
| 2971 body += IntConstant(kImmutableArrayCid); |
| 2972 break; |
| 2973 case MethodRecognizer::kClassID_getCidOneByteString: |
| 2974 body += IntConstant(kOneByteStringCid); |
| 2975 break; |
| 2976 case MethodRecognizer::kClassID_getCidTwoByteString: |
| 2977 body += IntConstant(kTwoByteStringCid); |
| 2978 break; |
| 2979 case MethodRecognizer::kClassID_getCidBigint: |
| 2980 body += IntConstant(kBigintCid); |
| 2981 break; |
| 2982 #endif |
| 2983 |
| 2984 case MethodRecognizer::kGrowableArrayCapacity: |
| 2985 body += LoadLocal(scopes_->this_variable); |
| 2986 body += LoadField(Array::data_offset(), kArrayCid); |
| 2987 body += LoadNativeField(MethodRecognizer::kObjectArrayLength, |
| 2988 Array::length_offset(), |
| 2989 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
| 2990 break; |
| 2991 case MethodRecognizer::kObjectArrayAllocate: |
| 2992 body += LoadLocal(scopes_->type_arguments_variable); |
| 2993 body += |
| 2994 LoadLocal(LookupVariable(dil_function->positional_parameters()[0])); |
| 2995 body += CreateArray(); |
| 2996 break; |
| 2997 case MethodRecognizer::kBigint_getDigits: |
| 2998 body += LoadLocal(scopes_->this_variable); |
| 2999 body += LoadNativeField(kind, Bigint::digits_offset(), |
| 3000 Object::dynamic_type(), kTypedDataUint32ArrayCid); |
| 3001 break; |
| 3002 case MethodRecognizer::kBigint_getUsed: |
| 3003 body += LoadLocal(scopes_->this_variable); |
| 3004 body += LoadNativeField(kind, Bigint::used_offset(), |
| 3005 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
| 3006 break; |
| 3007 case MethodRecognizer::kLinkedHashMap_getIndex: |
| 3008 body += LoadLocal(scopes_->this_variable); |
| 3009 body += LoadNativeField(kind, LinkedHashMap::index_offset(), |
| 3010 Object::dynamic_type(), kDynamicCid); |
| 3011 break; |
| 3012 case MethodRecognizer::kLinkedHashMap_setIndex: |
| 3013 body += LoadLocal(scopes_->this_variable); |
| 3014 body += |
| 3015 LoadLocal(LookupVariable(dil_function->positional_parameters()[0])); |
| 3016 body += StoreInstanceField(LinkedHashMap::index_offset()); |
| 3017 body += NullConstant(); |
| 3018 break; |
| 3019 case MethodRecognizer::kLinkedHashMap_getData: |
| 3020 body += LoadLocal(scopes_->this_variable); |
| 3021 body += LoadNativeField(kind, LinkedHashMap::data_offset(), |
| 3022 Object::dynamic_type(), kArrayCid); |
| 3023 break; |
| 3024 case MethodRecognizer::kLinkedHashMap_setData: |
| 3025 body += LoadLocal(scopes_->this_variable); |
| 3026 body += |
| 3027 LoadLocal(LookupVariable(dil_function->positional_parameters()[0])); |
| 3028 body += StoreInstanceField(LinkedHashMap::data_offset()); |
| 3029 body += NullConstant(); |
| 3030 break; |
| 3031 case MethodRecognizer::kLinkedHashMap_getHashMask: |
| 3032 body += LoadLocal(scopes_->this_variable); |
| 3033 body += LoadNativeField(kind, LinkedHashMap::hash_mask_offset(), |
| 3034 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
| 3035 break; |
| 3036 case MethodRecognizer::kLinkedHashMap_setHashMask: |
| 3037 body += LoadLocal(scopes_->this_variable); |
| 3038 body += |
| 3039 LoadLocal(LookupVariable(dil_function->positional_parameters()[0])); |
| 3040 // TODO(kmillikin): This store does not need a store barrier. |
| 3041 body += StoreInstanceField(LinkedHashMap::hash_mask_offset()); |
| 3042 body += NullConstant(); |
| 3043 break; |
| 3044 case MethodRecognizer::kLinkedHashMap_getUsedData: |
| 3045 body += LoadLocal(scopes_->this_variable); |
| 3046 body += LoadNativeField(kind, LinkedHashMap::used_data_offset(), |
| 3047 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
| 3048 break; |
| 3049 case MethodRecognizer::kLinkedHashMap_setUsedData: |
| 3050 body += LoadLocal(scopes_->this_variable); |
| 3051 body += |
| 3052 LoadLocal(LookupVariable(dil_function->positional_parameters()[0])); |
| 3053 // TODO(kmillikin): This store does not need a store barrier. |
| 3054 body += StoreInstanceField(LinkedHashMap::used_data_offset()); |
| 3055 body += NullConstant(); |
| 3056 break; |
| 3057 case MethodRecognizer::kLinkedHashMap_getDeletedKeys: |
| 3058 body += LoadLocal(scopes_->this_variable); |
| 3059 body += LoadNativeField(kind, LinkedHashMap::deleted_keys_offset(), |
| 3060 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
| 3061 break; |
| 3062 case MethodRecognizer::kLinkedHashMap_setDeletedKeys: |
| 3063 body += LoadLocal(scopes_->this_variable); |
| 3064 body += |
| 3065 LoadLocal(LookupVariable(dil_function->positional_parameters()[0])); |
| 3066 // TODO(kmillikin): This store does not need a store barrier. |
| 3067 body += StoreInstanceField(LinkedHashMap::deleted_keys_offset()); |
| 3068 body += NullConstant(); |
| 3069 break; |
| 3070 case MethodRecognizer::kBigint_getNeg: |
| 3071 body += LoadLocal(scopes_->this_variable); |
| 3072 body += LoadNativeField(kind, Bigint::neg_offset(), |
| 3073 Type::ZoneHandle(Z, Type::BoolType()), kBoolCid); |
| 3074 break; |
| 3075 default: { |
| 3076 dart::String& name = dart::String::ZoneHandle(Z, function.native_name()); |
| 3077 body += NativeCall(&name, &function); |
| 3078 break; |
| 3079 } |
| 3080 } |
| 3081 return body + Return(); |
| 3082 } |
| 3083 |
| 3084 |
| 3085 FlowGraph* FlowGraphBuilder::BuildGraphOfFieldAccessor( |
| 3086 Field* dil_field, LocalVariable* setter_value) { |
| 3087 const dart::Function& function = parsed_function_->function(); |
| 3088 |
| 3089 bool is_setter = function.IsImplicitSetterFunction(); |
| 3090 bool is_method = !function.IsStaticFunction(); |
| 3091 dart::Field& field = |
| 3092 dart::Field::ZoneHandle(Z, H.LookupFieldByDilField(dil_field)); |
| 3093 |
| 3094 TargetEntryInstr* normal_entry = BuildTargetEntry(); |
| 3095 graph_entry_ = new (Z) |
| 3096 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
| 3097 |
| 3098 // TODO(kustermann): Add support for FLAG_use_field_guards. |
| 3099 Fragment body(normal_entry); |
| 3100 if (is_setter) { |
| 3101 if (is_method) { |
| 3102 body += LoadLocal(scopes_->this_variable); |
| 3103 body += LoadLocal(setter_value); |
| 3104 body += StoreInstanceField(field); |
| 3105 } else { |
| 3106 body += LoadLocal(setter_value); |
| 3107 body += StoreStaticField(field); |
| 3108 } |
| 3109 body += NullConstant(); |
| 3110 } else if (is_method) { |
| 3111 body += LoadLocal(scopes_->this_variable); |
| 3112 body += LoadField(field); |
| 3113 } else if (field.is_const()) { |
| 3114 // If the parser needs to know the value of an uninitialized constant field |
| 3115 // it will set the value to the transition sentinel (used to detect circular |
| 3116 // initialization) and then call the implicit getter. Thus, the getter |
| 3117 // cannot contain the InitStaticField instruction that normal static getters |
| 3118 // contain because it would detect spurious circular initialization when it |
| 3119 // checks for the transition sentinel. |
| 3120 Expression* initializer = dil_field->initializer(); |
| 3121 ASSERT(initializer != NULL); |
| 3122 body += Constant(constant_evaluator_.EvaluateExpression(initializer)); |
| 3123 } else { |
| 3124 // The field always has an initializer because static fields without |
| 3125 // initializers are initialized eagerly and do not have implicit getters. |
| 3126 ASSERT(field.has_initializer()); |
| 3127 body += Constant(field); |
| 3128 body += InitStaticField(field); |
| 3129 body += Constant(field); |
| 3130 body += LoadStaticField(); |
| 3131 } |
| 3132 body += Return(); |
| 3133 |
| 3134 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
| 3135 } |
| 3136 |
| 3137 |
| 3138 FlowGraph* FlowGraphBuilder::BuildGraphOfStaticFieldInitializer( |
| 3139 Field* dil_field) { |
| 3140 ASSERT(dil_field->IsStatic()); |
| 3141 |
| 3142 Expression* initializer = dil_field->initializer(); |
| 3143 |
| 3144 TargetEntryInstr* normal_entry = BuildTargetEntry(); |
| 3145 graph_entry_ = new (Z) |
| 3146 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
| 3147 |
| 3148 Fragment body(normal_entry); |
| 3149 body += CheckStackOverflowInPrologue(); |
| 3150 if (dil_field->IsConst()) { |
| 3151 body += Constant(constant_evaluator_.EvaluateExpression(initializer)); |
| 3152 } else { |
| 3153 body += TranslateExpression(initializer); |
| 3154 } |
| 3155 body += Return(); |
| 3156 |
| 3157 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
| 3158 } |
| 3159 |
| 3160 |
| 3161 Fragment FlowGraphBuilder::BuildImplicitClosureCreation( |
| 3162 const Function& target) { |
| 3163 Fragment fragment; |
| 3164 const dart::Class& closure_class = |
| 3165 dart::Class::ZoneHandle(Z, I->object_store()->closure_class()); |
| 3166 fragment += AllocateObject(closure_class, target); |
| 3167 LocalVariable* closure = MakeTemporary(); |
| 3168 |
| 3169 // Allocate a context that closes over `this`. |
| 3170 fragment += AllocateContext(1); |
| 3171 LocalVariable* context = MakeTemporary(); |
| 3172 |
| 3173 // Store the function and the context in the closure. |
| 3174 fragment += LoadLocal(closure); |
| 3175 fragment += Constant(target); |
| 3176 fragment += StoreInstanceField(Closure::function_offset()); |
| 3177 |
| 3178 fragment += LoadLocal(closure); |
| 3179 fragment += LoadLocal(context); |
| 3180 fragment += StoreInstanceField(Closure::context_offset()); |
| 3181 |
| 3182 // The context is on top of the operand stack. Store `this`. The context |
| 3183 // doesn't need a parent pointer because it doesn't close over anything |
| 3184 // else. |
| 3185 fragment += LoadLocal(scopes_->this_variable); |
| 3186 fragment += StoreInstanceField(Context::variable_offset(0)); |
| 3187 |
| 3188 return fragment; |
| 3189 } |
| 3190 |
| 3191 |
| 3192 FlowGraph* FlowGraphBuilder::BuildGraphOfMethodExtractor( |
| 3193 const Function& method) { |
| 3194 // A method extractor is the implicit getter for a method. |
| 3195 const Function& function = |
| 3196 Function::ZoneHandle(Z, method.extracted_method_closure()); |
| 3197 |
| 3198 TargetEntryInstr* normal_entry = BuildTargetEntry(); |
| 3199 graph_entry_ = new (Z) |
| 3200 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
| 3201 Fragment body(normal_entry); |
| 3202 body += CheckStackOverflowInPrologue(); |
| 3203 body += BuildImplicitClosureCreation(function); |
| 3204 body += Return(); |
| 3205 |
| 3206 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
| 3207 } |
| 3208 |
| 3209 |
| 3210 FlowGraph* FlowGraphBuilder::BuildGraphOfImplicitClosureFunction( |
| 3211 FunctionNode* dil_function, const Function& function) { |
| 3212 const Function& target = Function::ZoneHandle(Z, function.parent_function()); |
| 3213 |
| 3214 TargetEntryInstr* normal_entry = BuildTargetEntry(); |
| 3215 graph_entry_ = new (Z) |
| 3216 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
| 3217 SetupDefaultParameterValues(dil_function); |
| 3218 |
| 3219 Fragment body(normal_entry); |
| 3220 body += CheckStackOverflowInPrologue(); |
| 3221 |
| 3222 // Load all the arguments. |
| 3223 if (!target.is_static()) { |
| 3224 // The context has a fixed shape: a single variable which is the |
| 3225 // closed-over receiver. |
| 3226 body += LoadLocal(parsed_function_->current_context_var()); |
| 3227 body += LoadField(Context::variable_offset(0)); |
| 3228 body += PushArgument(); |
| 3229 } |
| 3230 intptr_t positional_argument_count = |
| 3231 dil_function->positional_parameters().length(); |
| 3232 for (intptr_t i = 0; i < positional_argument_count; i++) { |
| 3233 body += LoadLocal(LookupVariable(dil_function->positional_parameters()[i])); |
| 3234 body += PushArgument(); |
| 3235 } |
| 3236 intptr_t named_argument_count = dil_function->named_parameters().length(); |
| 3237 Array& argument_names = Array::ZoneHandle(Z); |
| 3238 if (named_argument_count > 0) { |
| 3239 argument_names = Array::New(named_argument_count); |
| 3240 for (intptr_t i = 0; i < named_argument_count; i++) { |
| 3241 VariableDeclaration* variable = dil_function->named_parameters()[i]; |
| 3242 body += LoadLocal(LookupVariable(variable)); |
| 3243 body += PushArgument(); |
| 3244 argument_names.SetAt(i, H.DartSymbol(variable->name())); |
| 3245 } |
| 3246 } |
| 3247 // Forward them to the target. |
| 3248 intptr_t argument_count = positional_argument_count + named_argument_count; |
| 3249 if (!target.is_static()) ++argument_count; |
| 3250 body += StaticCall(target, argument_count, argument_names); |
| 3251 |
| 3252 // Return the result. |
| 3253 body += Return(); |
| 3254 |
| 3255 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
| 3256 } |
| 3257 |
| 3258 |
| 3259 FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher( |
| 3260 const Function& function) { |
| 3261 // This function is specialized for a receiver class, a method name, and |
| 3262 // the arguments descriptor at a call site. |
| 3263 |
| 3264 TargetEntryInstr* normal_entry = BuildTargetEntry(); |
| 3265 graph_entry_ = new (Z) |
| 3266 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
| 3267 |
| 3268 // The backend will expect an array of default values for all the named |
| 3269 // parameters, even if they are all known to be passed at the call site |
| 3270 // because the call site matches the arguments descriptor. Use null for |
| 3271 // the default values. |
| 3272 const Array& descriptor_array = |
| 3273 Array::ZoneHandle(Z, function.saved_args_desc()); |
| 3274 ArgumentsDescriptor descriptor(descriptor_array); |
| 3275 ZoneGrowableArray<const Instance*>* default_values = |
| 3276 new ZoneGrowableArray<const Instance*>(Z, descriptor.NamedCount()); |
| 3277 for (intptr_t i = 0; i < descriptor.NamedCount(); ++i) { |
| 3278 default_values->Add(&Object::null_instance()); |
| 3279 } |
| 3280 parsed_function_->set_default_parameter_values(default_values); |
| 3281 |
| 3282 Fragment body(normal_entry); |
| 3283 body += CheckStackOverflowInPrologue(); |
| 3284 |
| 3285 // The receiver is the first argument to noSuchMethod, and it is the first |
| 3286 // argument passed to the dispatcher function. |
| 3287 LocalScope* scope = parsed_function_->node_sequence()->scope(); |
| 3288 body += LoadLocal(scope->VariableAt(0)); |
| 3289 body += PushArgument(); |
| 3290 |
| 3291 // The second argument to noSuchMethod is an invocation mirror. Push the |
| 3292 // arguments for allocating the invocation mirror. First, the name. |
| 3293 body += Constant(dart::String::ZoneHandle(Z, function.name())); |
| 3294 body += PushArgument(); |
| 3295 |
| 3296 // Second, the arguments descriptor. |
| 3297 body += Constant(descriptor_array); |
| 3298 body += PushArgument(); |
| 3299 |
| 3300 // Third, an array containing the original arguments. Create it and fill |
| 3301 // it in. |
| 3302 body += Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null())); |
| 3303 body += IntConstant(descriptor.Count()); |
| 3304 body += CreateArray(); |
| 3305 LocalVariable* array = MakeTemporary(); |
| 3306 for (intptr_t i = 0; i < descriptor.PositionalCount(); ++i) { |
| 3307 body += LoadLocal(array); |
| 3308 body += IntConstant(i); |
| 3309 body += LoadLocal(scope->VariableAt(i)); |
| 3310 body += StoreIndexed(kArrayCid); |
| 3311 body += Drop(); |
| 3312 } |
| 3313 dart::String& name = dart::String::Handle(Z); |
| 3314 for (intptr_t i = 0; i < descriptor.NamedCount(); ++i) { |
| 3315 intptr_t parameter_index = descriptor.PositionalCount() + i; |
| 3316 name = descriptor.NameAt(i); |
| 3317 name = dart::Symbols::New(H.thread(), name); |
| 3318 body += LoadLocal(array); |
| 3319 body += IntConstant(descriptor.PositionAt(i)); |
| 3320 body += LoadLocal(scope->VariableAt(parameter_index)); |
| 3321 body += StoreIndexed(kArrayCid); |
| 3322 body += Drop(); |
| 3323 } |
| 3324 body += PushArgument(); |
| 3325 |
| 3326 // Fourth, false indicating this is not a super NoSuchMethod. |
| 3327 body += Constant(Bool::False()); |
| 3328 body += PushArgument(); |
| 3329 |
| 3330 const dart::Class& mirror_class = dart::Class::Handle( |
| 3331 Z, dart::Library::LookupCoreClass(Symbols::InvocationMirror())); |
| 3332 ASSERT(!mirror_class.IsNull()); |
| 3333 const Function& allocation_function = Function::ZoneHandle( |
| 3334 Z, mirror_class.LookupStaticFunction(dart::Library::PrivateCoreLibName( |
| 3335 Symbols::AllocateInvocationMirror()))); |
| 3336 ASSERT(!allocation_function.IsNull()); |
| 3337 body += StaticCall(allocation_function, 4); |
| 3338 body += PushArgument(); // For the call to noSuchMethod. |
| 3339 |
| 3340 ArgumentsDescriptor two_arguments( |
| 3341 Array::Handle(Z, ArgumentsDescriptor::New(2))); |
| 3342 Function& no_such_method = |
| 3343 Function::ZoneHandle(Z, Resolver::ResolveDynamicForReceiverClass( |
| 3344 dart::Class::Handle(Z, function.Owner()), |
| 3345 Symbols::NoSuchMethod(), two_arguments)); |
| 3346 if (no_such_method.IsNull()) { |
| 3347 // If noSuchMethod is not found on the receiver class, call |
| 3348 // Object.noSuchMethod. |
| 3349 no_such_method = Resolver::ResolveDynamicForReceiverClass( |
| 3350 dart::Class::Handle(Z, I->object_store()->object_class()), |
| 3351 Symbols::NoSuchMethod(), two_arguments); |
| 3352 } |
| 3353 body += StaticCall(no_such_method, 2); |
| 3354 body += Return(); |
| 3355 |
| 3356 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
| 3357 } |
| 3358 |
| 3359 |
| 3360 FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher( |
| 3361 const Function& function) { |
| 3362 // Find the name of the field we should dispatch to. |
| 3363 const dart::Class& owner = dart::Class::Handle(Z, function.Owner()); |
| 3364 ASSERT(!owner.IsNull()); |
| 3365 const dart::String& field_name = dart::String::Handle(Z, function.name()); |
| 3366 const dart::String& getter_name = dart::String::ZoneHandle( |
| 3367 Z, |
| 3368 Symbols::New(H.thread(), dart::String::Handle( |
| 3369 Z, dart::Field::GetterSymbol(field_name)))); |
| 3370 |
| 3371 // Determine if this is `class Closure { get call => this; }` |
| 3372 const dart::Class& closure_class = |
| 3373 dart::Class::Handle(I->object_store()->closure_class()); |
| 3374 const bool is_closure_call = (owner.raw() == closure_class.raw()) && |
| 3375 field_name.Equals(Symbols::Call()); |
| 3376 |
| 3377 // Set default parameters & construct argument names array. |
| 3378 // |
| 3379 // The backend will expect an array of default values for all the named |
| 3380 // parameters, even if they are all known to be passed at the call site |
| 3381 // because the call site matches the arguments descriptor. Use null for |
| 3382 // the default values. |
| 3383 const Array& descriptor_array = |
| 3384 Array::ZoneHandle(Z, function.saved_args_desc()); |
| 3385 ArgumentsDescriptor descriptor(descriptor_array); |
| 3386 const Array& argument_names = |
| 3387 Array::ZoneHandle(Z, Array::New(descriptor.NamedCount())); |
| 3388 ZoneGrowableArray<const Instance*>* default_values = |
| 3389 new ZoneGrowableArray<const Instance*>(Z, descriptor.NamedCount()); |
| 3390 dart::String& string_handle = dart::String::Handle(Z); |
| 3391 for (intptr_t i = 0; i < descriptor.NamedCount(); ++i) { |
| 3392 default_values->Add(&Object::null_instance()); |
| 3393 string_handle = descriptor.NameAt(i); |
| 3394 argument_names.SetAt(i, string_handle); |
| 3395 } |
| 3396 parsed_function_->set_default_parameter_values(default_values); |
| 3397 |
| 3398 TargetEntryInstr* normal_entry = BuildTargetEntry(); |
| 3399 graph_entry_ = new (Z) |
| 3400 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
| 3401 |
| 3402 Fragment body(normal_entry); |
| 3403 body += CheckStackOverflowInPrologue(); |
| 3404 |
| 3405 LocalScope* scope = parsed_function_->node_sequence()->scope(); |
| 3406 |
| 3407 LocalVariable* closure = NULL; |
| 3408 if (is_closure_call) { |
| 3409 closure = scope->VariableAt(0); |
| 3410 |
| 3411 // The closure itself is the first argument. |
| 3412 body += LoadLocal(closure); |
| 3413 } else { |
| 3414 // Invoke the getter to get the field value. |
| 3415 body += LoadLocal(scope->VariableAt(0)); |
| 3416 body += PushArgument(); |
| 3417 body += InstanceCall(getter_name, Token::kGET, 1); |
| 3418 } |
| 3419 |
| 3420 body += PushArgument(); |
| 3421 |
| 3422 // Push all arguments onto the stack. |
| 3423 intptr_t pos = 1; |
| 3424 for (; pos < descriptor.Count(); pos++) { |
| 3425 body += LoadLocal(scope->VariableAt(pos)); |
| 3426 body += PushArgument(); |
| 3427 } |
| 3428 |
| 3429 if (is_closure_call) { |
| 3430 // Lookup the function in the closure. |
| 3431 body += LoadLocal(closure); |
| 3432 body += LoadField(Closure::function_offset()); |
| 3433 |
| 3434 body += ClosureCall(descriptor.Count(), argument_names); |
| 3435 } else { |
| 3436 body += InstanceCall(Symbols::Call(), Token::kILLEGAL, descriptor.Count(), |
| 3437 argument_names); |
| 3438 } |
| 3439 |
| 3440 body += Return(); |
| 3441 |
| 3442 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
| 3443 } |
| 3444 |
| 3445 |
| 3446 void FlowGraphBuilder::SetupDefaultParameterValues(FunctionNode* function) { |
| 3447 intptr_t num_optional_parameters = |
| 3448 parsed_function_->function().NumOptionalParameters(); |
| 3449 if (num_optional_parameters > 0) { |
| 3450 ZoneGrowableArray<const Instance*>* default_values = |
| 3451 new ZoneGrowableArray<const Instance*>(Z, num_optional_parameters); |
| 3452 |
| 3453 if (parsed_function_->function().HasOptionalNamedParameters()) { |
| 3454 ASSERT(!parsed_function_->function().HasOptionalPositionalParameters()); |
| 3455 for (intptr_t i = 0; i < num_optional_parameters; i++) { |
| 3456 VariableDeclaration* variable = function->named_parameters()[i]; |
| 3457 Instance* default_value; |
| 3458 if (variable->initializer() != NULL) { |
| 3459 default_value = |
| 3460 &constant_evaluator_.EvaluateExpression(variable->initializer()); |
| 3461 } else { |
| 3462 default_value = &Instance::ZoneHandle(Z, Instance::null()); |
| 3463 } |
| 3464 default_values->Add(default_value); |
| 3465 } |
| 3466 } else { |
| 3467 ASSERT(parsed_function_->function().HasOptionalPositionalParameters()); |
| 3468 intptr_t required = function->required_parameter_count(); |
| 3469 for (intptr_t i = 0; i < num_optional_parameters; i++) { |
| 3470 VariableDeclaration* variable = |
| 3471 function->positional_parameters()[required + i]; |
| 3472 Instance* default_value; |
| 3473 if (variable->initializer() != NULL) { |
| 3474 default_value = |
| 3475 &constant_evaluator_.EvaluateExpression(variable->initializer()); |
| 3476 } else { |
| 3477 default_value = &Instance::ZoneHandle(Z, Instance::null()); |
| 3478 } |
| 3479 default_values->Add(default_value); |
| 3480 } |
| 3481 } |
| 3482 parsed_function_->set_default_parameter_values(default_values); |
| 3483 } |
| 3484 } |
| 3485 |
| 3486 |
| 3487 TargetEntryInstr* FlowGraphBuilder::BuildTargetEntry() { |
| 3488 return new (Z) TargetEntryInstr(AllocateBlockId(), CurrentTryIndex()); |
| 3489 } |
| 3490 |
| 3491 |
| 3492 JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry() { |
| 3493 return new (Z) JoinEntryInstr(AllocateBlockId(), CurrentTryIndex()); |
| 3494 } |
| 3495 |
| 3496 |
| 3497 Fragment FlowGraphBuilder::TranslateInitializers( |
| 3498 Class* dil_klass, List<Initializer>* initializers) { |
| 3499 Fragment instructions; |
| 3500 |
| 3501 // These come from: |
| 3502 // class A { |
| 3503 // var x = (expr); |
| 3504 // } |
| 3505 for (intptr_t i = 0; i < dil_klass->fields().length(); i++) { |
| 3506 Field* dil_field = dil_klass->fields()[i]; |
| 3507 Expression* init = dil_field->initializer(); |
| 3508 if (!dil_field->IsStatic() && init != NULL) { |
| 3509 dart::Field& field = |
| 3510 dart::Field::ZoneHandle(Z, H.LookupFieldByDilField(dil_field)); |
| 3511 |
| 3512 EnterScope(dil_field); |
| 3513 // TODO(kustermann): Support FLAG_use_field_guards. |
| 3514 instructions += LoadLocal(scopes_->this_variable); |
| 3515 instructions += TranslateExpression(init); |
| 3516 instructions += StoreInstanceField(field); |
| 3517 ExitScope(dil_field); |
| 3518 } |
| 3519 } |
| 3520 |
| 3521 // These to come from: |
| 3522 // class A { |
| 3523 // var x; |
| 3524 // var y; |
| 3525 // A(this.x) : super(expr), y = (expr); |
| 3526 // } |
| 3527 for (intptr_t i = 0; i < initializers->length(); i++) { |
| 3528 Initializer* initializer = (*initializers)[i]; |
| 3529 if (initializer->IsFieldInitializer()) { |
| 3530 FieldInitializer* init = FieldInitializer::Cast(initializer); |
| 3531 dart::Field& field = |
| 3532 dart::Field::ZoneHandle(Z, H.LookupFieldByDilField(init->field())); |
| 3533 |
| 3534 // TODO(kustermann): Support FLAG_use_field_guards. |
| 3535 instructions += LoadLocal(scopes_->this_variable); |
| 3536 instructions += TranslateExpression(init->value()); |
| 3537 instructions += StoreInstanceField(field); |
| 3538 } else if (initializer->IsSuperInitializer()) { |
| 3539 SuperInitializer* init = SuperInitializer::Cast(initializer); |
| 3540 |
| 3541 instructions += LoadLocal(scopes_->this_variable); |
| 3542 instructions += PushArgument(); |
| 3543 |
| 3544 ASSERT(init->arguments()->types().length() == 0); |
| 3545 Array& argument_names = Array::ZoneHandle(Z); |
| 3546 instructions += TranslateArguments(init->arguments(), &argument_names); |
| 3547 |
| 3548 const Function& target = Function::ZoneHandle( |
| 3549 Z, H.LookupConstructorByDilConstructor(init->target())); |
| 3550 intptr_t argument_count = init->arguments()->count() + 1; |
| 3551 instructions += StaticCall(target, argument_count, argument_names); |
| 3552 instructions += Drop(); |
| 3553 } else if (initializer->IsRedirectingInitializer()) { |
| 3554 RedirectingInitializer* init = RedirectingInitializer::Cast(initializer); |
| 3555 |
| 3556 instructions += LoadLocal(scopes_->this_variable); |
| 3557 instructions += PushArgument(); |
| 3558 |
| 3559 ASSERT(init->arguments()->types().length() == 0); |
| 3560 Array& argument_names = Array::ZoneHandle(Z); |
| 3561 instructions += TranslateArguments(init->arguments(), &argument_names); |
| 3562 |
| 3563 const Function& target = Function::ZoneHandle( |
| 3564 Z, H.LookupConstructorByDilConstructor(init->target())); |
| 3565 intptr_t argument_count = init->arguments()->count() + 1; |
| 3566 instructions += StaticCall(target, argument_count, argument_names); |
| 3567 instructions += Drop(); |
| 3568 } else if (initializer->IsLocalInitializer()) { |
| 3569 // The other initializers following this one might read the variable. This |
| 3570 // is used e.g. for evaluating the arguments to a super call first, run |
| 3571 // normal field initializers next and then make the actual super call: |
| 3572 // |
| 3573 // The frontend converts |
| 3574 // |
| 3575 // class A { |
| 3576 // var x; |
| 3577 // A(a, b) : super(a + b), x = 2*b {} |
| 3578 // } |
| 3579 // |
| 3580 // to |
| 3581 // |
| 3582 // class A { |
| 3583 // var x; |
| 3584 // A(a, b) : tmp = a + b, x = 2*b, super(tmp) {} |
| 3585 // } |
| 3586 // |
| 3587 // (This is strictly speaking not what one should do in terms of the |
| 3588 // specification but that is how it is currently implemented.) |
| 3589 LocalInitializer* init = LocalInitializer::Cast(initializer); |
| 3590 |
| 3591 VariableDeclaration* declaration = init->variable(); |
| 3592 LocalVariable* variable = LookupVariable(declaration); |
| 3593 Expression* initializer = init->variable()->initializer(); |
| 3594 ASSERT(initializer != NULL); |
| 3595 ASSERT(!declaration->IsConst()); |
| 3596 |
| 3597 instructions += TranslateExpression(initializer); |
| 3598 instructions += StoreLocal(variable); |
| 3599 instructions += Drop(); |
| 3600 |
| 3601 fragment_ = instructions; |
| 3602 } else { |
| 3603 UNIMPLEMENTED(); |
| 3604 } |
| 3605 } |
| 3606 return instructions; |
| 3607 } |
| 3608 |
| 3609 |
| 3610 Fragment FlowGraphBuilder::TranslateStatement(Statement* statement) { |
| 3611 #ifdef DEBUG |
| 3612 intptr_t original_context_depth = context_depth_; |
| 3613 #endif |
| 3614 statement->AcceptStatementVisitor(this); |
| 3615 DEBUG_ASSERT(context_depth_ == original_context_depth); |
| 3616 return fragment_; |
| 3617 } |
| 3618 |
| 3619 |
| 3620 Fragment FlowGraphBuilder::TranslateCondition(Expression* expression, |
| 3621 bool* negate) { |
| 3622 *negate = expression->IsNot(); |
| 3623 if (*negate) { |
| 3624 return TranslateExpression(Not::Cast(expression)->expression()); |
| 3625 } |
| 3626 return TranslateExpression(expression); |
| 3627 } |
| 3628 |
| 3629 |
| 3630 Fragment FlowGraphBuilder::TranslateExpression(Expression* expression) { |
| 3631 expression->AcceptExpressionVisitor(this); |
| 3632 return fragment_; |
| 3633 } |
| 3634 |
| 3635 |
| 3636 ArgumentArray FlowGraphBuilder::GetArguments(int count) { |
| 3637 ArgumentArray arguments = |
| 3638 new (Z) ZoneGrowableArray<PushArgumentInstr*>(Z, count); |
| 3639 arguments->SetLength(count); |
| 3640 for (intptr_t i = count - 1; i >= 0; --i) { |
| 3641 ASSERT(stack_->definition()->IsPushArgument()); |
| 3642 ASSERT(!stack_->definition()->HasSSATemp()); |
| 3643 arguments->data()[i] = stack_->definition()->AsPushArgument(); |
| 3644 Drop(); |
| 3645 } |
| 3646 pending_argument_count_ -= count; |
| 3647 ASSERT(pending_argument_count_ >= 0); |
| 3648 return arguments; |
| 3649 } |
| 3650 |
| 3651 |
| 3652 void FlowGraphBuilder::VisitInvalidExpression(InvalidExpression* node) { |
| 3653 // FIXME(kustermann): Once we have better error information we might need to |
| 3654 // make some invalid expressions not NSM errors but type/compile-time/... |
| 3655 // errors. |
| 3656 fragment_ = ThrowNoSuchMethodError(); |
| 3657 } |
| 3658 |
| 3659 |
| 3660 void FlowGraphBuilder::VisitNullLiteral(NullLiteral* node) { |
| 3661 fragment_ = Constant(Instance::ZoneHandle(Z, Instance::null())); |
| 3662 } |
| 3663 |
| 3664 |
| 3665 void FlowGraphBuilder::VisitBoolLiteral(BoolLiteral* node) { |
| 3666 fragment_ = Constant(Bool::Get(node->value())); |
| 3667 } |
| 3668 |
| 3669 |
| 3670 void FlowGraphBuilder::VisitIntLiteral(IntLiteral* node) { |
| 3671 fragment_ = IntConstant(node->value()); |
| 3672 } |
| 3673 |
| 3674 |
| 3675 void FlowGraphBuilder::VisitBigintLiteral(BigintLiteral* node) { |
| 3676 const dart::String& value = H.DartString(node->value()); |
| 3677 fragment_ = Constant(Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld))); |
| 3678 } |
| 3679 |
| 3680 |
| 3681 void FlowGraphBuilder::VisitDoubleLiteral(DoubleLiteral* node) { |
| 3682 fragment_ = Constant(constant_evaluator_.EvaluateExpression(node)); |
| 3683 } |
| 3684 |
| 3685 |
| 3686 void FlowGraphBuilder::VisitStringLiteral(StringLiteral* node) { |
| 3687 fragment_ = Constant(H.DartSymbol(node->value())); |
| 3688 } |
| 3689 |
| 3690 |
| 3691 void FlowGraphBuilder::VisitSymbolLiteral(SymbolLiteral* node) { |
| 3692 fragment_ = Constant(constant_evaluator_.EvaluateExpression(node)); |
| 3693 } |
| 3694 |
| 3695 |
| 3696 AbstractType& DartTypeTranslator::TranslateType(DartType* node) { |
| 3697 node->AcceptDartTypeVisitor(this); |
| 3698 |
| 3699 // We return a new `ZoneHandle` here on purpose: The intermediate language |
| 3700 // instructions do not make a copy of the handle, so we do it. |
| 3701 return dart::AbstractType::ZoneHandle(Z, result_.raw()); |
| 3702 } |
| 3703 |
| 3704 |
| 3705 AbstractType& DartTypeTranslator::TranslateTypeWithoutFinalization( |
| 3706 DartType* node) { |
| 3707 bool saved_finalize = finalize_; |
| 3708 finalize_ = false; |
| 3709 H.SetFinalize(false); |
| 3710 AbstractType& result = TranslateType(node); |
| 3711 finalize_ = saved_finalize; |
| 3712 H.SetFinalize(saved_finalize); |
| 3713 return result; |
| 3714 } |
| 3715 |
| 3716 |
| 3717 void DartTypeTranslator::VisitInvalidType(InvalidType* node) { |
| 3718 result_ = ClassFinalizer::NewFinalizedMalformedType( |
| 3719 Error::Handle(Z), // No previous error. |
| 3720 dart::Script::Handle(Z, dart::Script::null()), TokenPosition::kNoSource, |
| 3721 "[InvalidType] in Kernel IR."); |
| 3722 } |
| 3723 |
| 3724 |
| 3725 void DartTypeTranslator::VisitFunctionType(FunctionType* node) { |
| 3726 // TODO(kustermann): Fix function types which are composed of malformed types. |
| 3727 // We might need to convert them to dynamic types instead of making the |
| 3728 // function type malformed. |
| 3729 const Function& signature_function = Function::ZoneHandle( |
| 3730 Z, Function::NewSignatureFunction(*active_class_->klass, |
| 3731 TokenPosition::kNoSource)); |
| 3732 |
| 3733 node->return_type()->AcceptDartTypeVisitor(this); |
| 3734 if (result_.IsMalformed()) return; |
| 3735 signature_function.set_result_type(result_); |
| 3736 |
| 3737 const intptr_t positional_count = node->positional_parameters().length(); |
| 3738 const intptr_t named_count = node->named_parameters().length(); |
| 3739 const intptr_t all_count = positional_count + named_count; |
| 3740 const intptr_t required_count = node->required_parameter_count(); |
| 3741 |
| 3742 // The additional first parameter is the receiver type (set to dynamic). |
| 3743 signature_function.set_num_fixed_parameters(1 + required_count); |
| 3744 signature_function.SetNumOptionalParameters( |
| 3745 all_count - required_count, positional_count > required_count); |
| 3746 |
| 3747 const Array& parameter_types = |
| 3748 Array::Handle(Z, Array::New(1 + all_count, Heap::kOld)); |
| 3749 signature_function.set_parameter_types(parameter_types); |
| 3750 const Array& parameter_names = |
| 3751 Array::Handle(Z, Array::New(1 + all_count, Heap::kOld)); |
| 3752 signature_function.set_parameter_names(parameter_names); |
| 3753 |
| 3754 intptr_t pos = 0; |
| 3755 parameter_types.SetAt(pos, AbstractType::dynamic_type()); |
| 3756 parameter_names.SetAt(pos, H.DartSymbol("_receiver_")); |
| 3757 pos++; |
| 3758 for (intptr_t i = 0; i < positional_count; i++, pos++) { |
| 3759 node->positional_parameters()[i]->AcceptDartTypeVisitor(this); |
| 3760 if (result_.IsMalformed()) return; |
| 3761 parameter_types.SetAt(pos, result_); |
| 3762 parameter_names.SetAt(pos, H.DartSymbol("noname")); |
| 3763 } |
| 3764 for (intptr_t i = 0; i < named_count; i++, pos++) { |
| 3765 Tuple<String, DartType>* tuple = node->named_parameters()[i]; |
| 3766 tuple->second()->AcceptDartTypeVisitor(this); |
| 3767 if (result_.IsMalformed()) return; |
| 3768 parameter_types.SetAt(pos, result_); |
| 3769 parameter_names.SetAt(pos, H.DartSymbol(tuple->first())); |
| 3770 } |
| 3771 |
| 3772 Type& signature_type = |
| 3773 Type::ZoneHandle(Z, signature_function.SignatureType()); |
| 3774 |
| 3775 if (finalize_) { |
| 3776 signature_type ^= ClassFinalizer::FinalizeType( |
| 3777 *active_class_->klass, signature_type, ClassFinalizer::kCanonicalize); |
| 3778 } |
| 3779 signature_function.SetSignatureType(signature_type); |
| 3780 |
| 3781 result_ = signature_type.raw(); |
| 3782 } |
| 3783 |
| 3784 |
| 3785 void DartTypeTranslator::VisitTypeParameterType(TypeParameterType* node) { |
| 3786 ASSERT(active_class_->dil_class != NULL); |
| 3787 |
| 3788 List<TypeParameter>* parameters = |
| 3789 &active_class_->dil_class->type_parameters(); |
| 3790 if ((active_class_->member != NULL) && active_class_->member->IsProcedure()) { |
| 3791 Procedure* procedure = Procedure::Cast(active_class_->member); |
| 3792 if ((procedure->function() != NULL) && |
| 3793 (procedure->function()->type_parameters().length() > 0)) { |
| 3794 // |
| 3795 // WARNING: This is a little hackish: |
| 3796 // |
| 3797 // We have a static factory constructor. The kernel IR gives the factory |
| 3798 // constructor function it's own type parameters (which are equal in name |
| 3799 // and number to the ones of the enclosing class). |
| 3800 // I.e., |
| 3801 // |
| 3802 // class A<T> { |
| 3803 // factory A.x() { return new B<T>(); } |
| 3804 // } |
| 3805 // |
| 3806 // is basically translated to this: |
| 3807 // |
| 3808 // class A<T> { |
| 3809 // static A.x<T'>() { return new B<T'>(); } |
| 3810 // } |
| 3811 // |
| 3812 parameters = &procedure->function()->type_parameters(); |
| 3813 } |
| 3814 } |
| 3815 |
| 3816 for (intptr_t i = 0; i < parameters->length(); i++) { |
| 3817 TypeParameter* type_parameter = (*parameters)[i]; |
| 3818 if (node->parameter() == type_parameter) { |
| 3819 // The index of the type parameter in [parameters] is |
| 3820 // the same index into the `klass->type_parameters()` array. |
| 3821 result_ ^= dart::TypeArguments::Handle( |
| 3822 Z, active_class_->klass->type_parameters()) |
| 3823 .TypeAt(i); |
| 3824 return; |
| 3825 } |
| 3826 } |
| 3827 |
| 3828 UNREACHABLE(); |
| 3829 } |
| 3830 |
| 3831 |
| 3832 void DartTypeTranslator::VisitInterfaceType(InterfaceType* node) { |
| 3833 // NOTE: That an interface type like `T<A, B>` is considered to be |
| 3834 // malformed iff `T` is malformed. |
| 3835 // => We therefore ignore errors in `A` or `B`. |
| 3836 const TypeArguments& type_arguments = TranslateTypeArguments( |
| 3837 node->type_arguments().raw_array(), node->type_arguments().length()); |
| 3838 |
| 3839 const dart::Class& klass = |
| 3840 dart::Class::Handle(Z, H.LookupClassByDilClass(node->klass())); |
| 3841 |
| 3842 result_ = Type::New(klass, type_arguments, TokenPosition::kNoSource); |
| 3843 result_.SetIsResolved(); |
| 3844 if (finalize_) { |
| 3845 result_ = ClassFinalizer::FinalizeType(klass, result_, |
| 3846 ClassFinalizer::kCanonicalize); |
| 3847 } |
| 3848 } |
| 3849 |
| 3850 |
| 3851 void DartTypeTranslator::VisitDynamicType(DynamicType* node) { |
| 3852 result_ = Object::dynamic_type().raw(); |
| 3853 } |
| 3854 |
| 3855 |
| 3856 void DartTypeTranslator::VisitVoidType(VoidType* node) { |
| 3857 result_ = Object::void_type().raw(); |
| 3858 } |
| 3859 |
| 3860 |
| 3861 const TypeArguments& DartTypeTranslator::TranslateTypeArguments( |
| 3862 DartType** dart_types, intptr_t length) { |
| 3863 bool only_dynamic = true; |
| 3864 for (intptr_t i = 0; i < length; i++) { |
| 3865 if (!dart_types[i]->IsDynamicType()) { |
| 3866 only_dynamic = false; |
| 3867 break; |
| 3868 } |
| 3869 } |
| 3870 TypeArguments& type_arguments = TypeArguments::ZoneHandle(Z); |
| 3871 if (!only_dynamic) { |
| 3872 type_arguments = TypeArguments::New(length); |
| 3873 for (intptr_t i = 0; i < length; i++) { |
| 3874 dart_types[i]->AcceptDartTypeVisitor(this); |
| 3875 if (result_.IsMalformed()) { |
| 3876 type_arguments = TypeArguments::null(); |
| 3877 return type_arguments; |
| 3878 } |
| 3879 type_arguments.SetTypeAt(i, result_); |
| 3880 } |
| 3881 if (finalize_) { |
| 3882 type_arguments = type_arguments.Canonicalize(); |
| 3883 } |
| 3884 } |
| 3885 return type_arguments; |
| 3886 } |
| 3887 |
| 3888 |
| 3889 const TypeArguments& DartTypeTranslator::TranslateInstantiatedTypeArguments( |
| 3890 const dart::Class& receiver_class, DartType** receiver_type_arguments, |
| 3891 intptr_t length) { |
| 3892 const TypeArguments& type_arguments = |
| 3893 TranslateTypeArguments(receiver_type_arguments, length); |
| 3894 if (type_arguments.IsNull()) return type_arguments; |
| 3895 |
| 3896 // We make a temporary [Type] object and use `ClassFinalizer::FinalizeType` to |
| 3897 // finalize the argument types. |
| 3898 // (This can for example make the [type_arguments] vector larger) |
| 3899 Type& type = Type::Handle( |
| 3900 Z, Type::New(receiver_class, type_arguments, TokenPosition::kNoSource)); |
| 3901 if (finalize_) { |
| 3902 type ^= ClassFinalizer::FinalizeType( |
| 3903 *active_class_->klass, type, ClassFinalizer::kCanonicalizeWellFormed); |
| 3904 } |
| 3905 |
| 3906 const TypeArguments& instantiated_type_arguments = |
| 3907 TypeArguments::ZoneHandle(Z, type.arguments()); |
| 3908 return instantiated_type_arguments; |
| 3909 } |
| 3910 |
| 3911 |
| 3912 const Type& DartTypeTranslator::ReceiverType(const dart::Class& klass) { |
| 3913 ASSERT(!klass.IsNull()); |
| 3914 ASSERT(!klass.IsTypedefClass()); |
| 3915 // Note that if klass is _Closure, the returned type will be _Closure, |
| 3916 // and not the signature type. |
| 3917 Type& type = Type::ZoneHandle(Z, klass.CanonicalType()); |
| 3918 if (!type.IsNull()) { |
| 3919 return type; |
| 3920 } |
| 3921 type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()), |
| 3922 klass.token_pos()); |
| 3923 return type; |
| 3924 } |
| 3925 |
| 3926 |
| 3927 void FlowGraphBuilder::VisitTypeLiteral(TypeLiteral* node) { |
| 3928 const AbstractType& type = T.TranslateType(node->type()); |
| 3929 if (type.IsMalformed()) H.ReportError("Malformed type literal"); |
| 3930 |
| 3931 fragment_ = Constant(type); |
| 3932 } |
| 3933 |
| 3934 |
| 3935 void FlowGraphBuilder::VisitVariableGet(VariableGet* node) { |
| 3936 fragment_ = LoadLocal(LookupVariable(node->variable())); |
| 3937 } |
| 3938 |
| 3939 |
| 3940 void FlowGraphBuilder::VisitVariableSet(VariableSet* node) { |
| 3941 Fragment instructions = TranslateExpression(node->expression()); |
| 3942 // The IR should not include assignments to final or const variables. |
| 3943 // This is https://github.com/dart-lang/rasta/issues/83. |
| 3944 // |
| 3945 // TODO(kmillikin): simply ASSERT that the variable is not const or final |
| 3946 // when that issue is fixed. |
| 3947 fragment_ = instructions + |
| 3948 ((node->variable()->IsFinal() || node->variable()->IsConst()) |
| 3949 ? Drop() + ThrowNoSuchMethodError() |
| 3950 : StoreLocal(LookupVariable(node->variable()))); |
| 3951 } |
| 3952 |
| 3953 |
| 3954 void FlowGraphBuilder::VisitStaticGet(StaticGet* node) { |
| 3955 Member* target = node->target(); |
| 3956 if (target->IsField()) { |
| 3957 Field* dil_field = Field::Cast(target); |
| 3958 const dart::Field& field = |
| 3959 dart::Field::ZoneHandle(Z, H.LookupFieldByDilField(dil_field)); |
| 3960 if (dil_field->IsConst()) { |
| 3961 fragment_ = Constant(constant_evaluator_.EvaluateExpression(node)); |
| 3962 } else { |
| 3963 const dart::Class& owner = dart::Class::Handle(Z, field.Owner()); |
| 3964 const dart::String& getter_name = H.DartGetterName(dil_field->name()); |
| 3965 const Function& getter = |
| 3966 Function::ZoneHandle(Z, owner.LookupStaticFunction(getter_name)); |
| 3967 if (getter.IsNull() || !field.has_initializer()) { |
| 3968 Fragment instructions = Constant(field); |
| 3969 fragment_ = instructions + LoadStaticField(); |
| 3970 } else { |
| 3971 // TODO(kmillikin): figure out how to trigger this case and add tests. |
| 3972 fragment_ = StaticCall(getter, 0); |
| 3973 } |
| 3974 } |
| 3975 } else { |
| 3976 Procedure* procedure = Procedure::Cast(target); |
| 3977 const Function& target = |
| 3978 Function::ZoneHandle(Z, H.LookupStaticMethodByDilProcedure(procedure)); |
| 3979 |
| 3980 if (procedure->kind() == Procedure::kGetter) { |
| 3981 fragment_ = StaticCall(target, 0); |
| 3982 } else if (procedure->kind() == Procedure::kMethod) { |
| 3983 ASSERT(procedure->IsStatic()); |
| 3984 Function& closure_function = |
| 3985 Function::ZoneHandle(Z, target.ImplicitClosureFunction()); |
| 3986 closure_function.set_dil_function(target.dil_function()); |
| 3987 const Instance& closure = |
| 3988 Instance::ZoneHandle(Z, closure_function.ImplicitStaticClosure()); |
| 3989 fragment_ = Constant(closure); |
| 3990 } else { |
| 3991 UNIMPLEMENTED(); |
| 3992 } |
| 3993 } |
| 3994 } |
| 3995 |
| 3996 |
| 3997 void FlowGraphBuilder::VisitStaticSet(StaticSet* node) { |
| 3998 Member* target = node->target(); |
| 3999 if (target->IsField()) { |
| 4000 Field* dil_field = Field::Cast(target); |
| 4001 const dart::Field& field = |
| 4002 dart::Field::ZoneHandle(Z, H.LookupFieldByDilField(dil_field)); |
| 4003 Fragment instructions = TranslateExpression(node->expression()); |
| 4004 LocalVariable* variable = MakeTemporary(); |
| 4005 instructions += LoadLocal(variable); |
| 4006 fragment_ = instructions + StoreStaticField(field); |
| 4007 } else { |
| 4008 ASSERT(target->IsProcedure()); |
| 4009 |
| 4010 // Evaluate the expression on the right hand side. |
| 4011 Fragment instructions = TranslateExpression(node->expression()); |
| 4012 LocalVariable* variable = MakeTemporary(); |
| 4013 |
| 4014 // Prepare argument. |
| 4015 instructions += LoadLocal(variable); |
| 4016 instructions += PushArgument(); |
| 4017 |
| 4018 // Invoke the setter function. |
| 4019 Procedure* procedure = Procedure::Cast(target); |
| 4020 const Function& target = |
| 4021 Function::ZoneHandle(Z, H.LookupStaticMethodByDilProcedure(procedure)); |
| 4022 instructions += StaticCall(target, 1); |
| 4023 |
| 4024 // Drop the unused result & leave the stored value on the stack. |
| 4025 fragment_ = instructions + Drop(); |
| 4026 } |
| 4027 } |
| 4028 |
| 4029 |
| 4030 void FlowGraphBuilder::VisitPropertyGet(PropertyGet* node) { |
| 4031 Fragment instructions = TranslateExpression(node->receiver()); |
| 4032 instructions += PushArgument(); |
| 4033 const dart::String& getter_name = H.DartGetterName(node->name()); |
| 4034 fragment_ = instructions + InstanceCall(getter_name, Token::kGET, 1); |
| 4035 } |
| 4036 |
| 4037 |
| 4038 void FlowGraphBuilder::VisitPropertySet(PropertySet* node) { |
| 4039 Fragment instructions(NullConstant()); |
| 4040 LocalVariable* variable = MakeTemporary(); |
| 4041 instructions += TranslateExpression(node->receiver()); |
| 4042 instructions += PushArgument(); |
| 4043 instructions += TranslateExpression(node->value()); |
| 4044 instructions += StoreLocal(variable); |
| 4045 instructions += PushArgument(); |
| 4046 |
| 4047 const dart::String& setter_name = H.DartSetterName(node->name()); |
| 4048 instructions += InstanceCall(setter_name, Token::kSET, 2); |
| 4049 fragment_ = instructions + Drop(); |
| 4050 } |
| 4051 |
| 4052 |
| 4053 void FlowGraphBuilder::VisitDirectPropertyGet(DirectPropertyGet* node) { |
| 4054 Function& target = Function::ZoneHandle(Z); |
| 4055 if (node->target()->IsProcedure()) { |
| 4056 Procedure* dil_procedure = Procedure::Cast(node->target()); |
| 4057 Name* dil_name = dil_procedure->name(); |
| 4058 if (dil_procedure->kind() == Procedure::kGetter) { |
| 4059 target = LookupMethodByMember(dil_procedure, H.DartGetterName(dil_name)); |
| 4060 } else { |
| 4061 target = LookupMethodByMember(dil_procedure, H.DartMethodName(dil_name)); |
| 4062 target = target.ImplicitClosureFunction(); |
| 4063 ASSERT(!target.IsNull()); |
| 4064 fragment_ = BuildImplicitClosureCreation(target); |
| 4065 return; |
| 4066 } |
| 4067 } else { |
| 4068 ASSERT(node->target()->IsField()); |
| 4069 const dart::String& getter_name = H.DartGetterName(node->target()->name()); |
| 4070 target = LookupMethodByMember(node->target(), getter_name); |
| 4071 ASSERT(target.IsGetterFunction() || target.IsImplicitGetterFunction()); |
| 4072 } |
| 4073 |
| 4074 Fragment instructions = TranslateExpression(node->receiver()); |
| 4075 instructions += PushArgument(); |
| 4076 fragment_ = instructions + StaticCall(target, 1); |
| 4077 } |
| 4078 |
| 4079 |
| 4080 void FlowGraphBuilder::VisitDirectPropertySet(DirectPropertySet* node) { |
| 4081 const dart::String& method_name = H.DartSetterName(node->target()->name()); |
| 4082 const Function& target = Function::ZoneHandle( |
| 4083 Z, LookupMethodByMember(node->target(), method_name)); |
| 4084 ASSERT(target.IsSetterFunction() || target.IsImplicitSetterFunction()); |
| 4085 |
| 4086 Fragment instructions(NullConstant()); |
| 4087 LocalVariable* value = MakeTemporary(); |
| 4088 instructions += TranslateExpression(node->receiver()); |
| 4089 instructions += PushArgument(); |
| 4090 instructions += TranslateExpression(node->value()); |
| 4091 instructions += StoreLocal(value); |
| 4092 instructions += PushArgument(); |
| 4093 instructions += StaticCall(target, 2); |
| 4094 |
| 4095 fragment_ = instructions + Drop(); |
| 4096 } |
| 4097 |
| 4098 |
| 4099 void FlowGraphBuilder::VisitStaticInvocation(StaticInvocation* node) { |
| 4100 const Function& target = Function::ZoneHandle( |
| 4101 Z, H.LookupStaticMethodByDilProcedure(node->procedure())); |
| 4102 const dart::Class& klass = dart::Class::ZoneHandle(Z, target.Owner()); |
| 4103 intptr_t argument_count = node->arguments()->count(); |
| 4104 if (target.IsGenerativeConstructor() || target.IsFactory()) { |
| 4105 // The VM requires currently a TypeArguments object as first parameter for |
| 4106 // every factory constructor :-/ ! |
| 4107 // |
| 4108 // TODO(kustermann): Get rid of this after we're using our own core |
| 4109 // libraries. |
| 4110 ++argument_count; |
| 4111 } |
| 4112 List<NamedExpression>& named = node->arguments()->named(); |
| 4113 const Array& argument_names = H.ArgumentNames(&named); |
| 4114 |
| 4115 Fragment instructions; |
| 4116 if (!target.AreValidArguments(argument_count, argument_names, NULL)) { |
| 4117 // An argument mismatch for a static invocation really should not occur |
| 4118 // in the IR. This is issue https://github.com/dart-lang/rasta/issues/76. |
| 4119 // |
| 4120 // TODO(kmillikin): Change this to an ASSERT when that issue is fixed. |
| 4121 List<Expression>& positional = node->arguments()->positional(); |
| 4122 for (intptr_t i = 0; i < positional.length(); ++i) { |
| 4123 instructions += TranslateExpression(positional[i]); |
| 4124 instructions += Drop(); |
| 4125 } |
| 4126 |
| 4127 for (intptr_t i = 0; i < named.length(); ++i) { |
| 4128 instructions += TranslateExpression(named[i]->expression()); |
| 4129 instructions += Drop(); |
| 4130 } |
| 4131 |
| 4132 fragment_ = instructions + ThrowNoSuchMethodError(); |
| 4133 return; |
| 4134 } |
| 4135 |
| 4136 LocalVariable* instance_variable = NULL; |
| 4137 |
| 4138 // If we cross the Dil -> VM core library boundary, a [StaticInvocation] |
| 4139 // can appear, but the thing we're calling is not a static method, but a |
| 4140 // factory constructor. |
| 4141 // The `H.LookupStaticmethodByDilProcedure` will potentially resolve to the |
| 4142 // forwarded constructor. |
| 4143 // In that case we'll make an instance and pass it as first argument. |
| 4144 // |
| 4145 // TODO(kustermann): Get rid of this after we're using our own core |
| 4146 // libraries. |
| 4147 if (target.IsGenerativeConstructor()) { |
| 4148 if (klass.NumTypeArguments() > 0) { |
| 4149 List<DartType>& dil_type_arguments = node->arguments()->types(); |
| 4150 const TypeArguments& type_arguments = |
| 4151 T.TranslateInstantiatedTypeArguments(klass, |
| 4152 dil_type_arguments.raw_array(), |
| 4153 dil_type_arguments.length()); |
| 4154 instructions += TranslateInstantiatedTypeArguments(type_arguments); |
| 4155 instructions += PushArgument(); |
| 4156 instructions += AllocateObject(klass, 1); |
| 4157 } else { |
| 4158 instructions += AllocateObject(klass, 0); |
| 4159 } |
| 4160 |
| 4161 instance_variable = MakeTemporary(); |
| 4162 |
| 4163 instructions += LoadLocal(instance_variable); |
| 4164 instructions += PushArgument(); |
| 4165 } else if (target.IsFactory()) { |
| 4166 // The VM requires currently a TypeArguments object as first parameter for |
| 4167 // every factory constructor :-/ ! |
| 4168 // |
| 4169 // TODO(kustermann): Get rid of this after we're using our own core |
| 4170 // libraries. |
| 4171 List<DartType>& dil_type_arguments = node->arguments()->types(); |
| 4172 |
| 4173 const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments( |
| 4174 klass, dil_type_arguments.raw_array(), dil_type_arguments.length()); |
| 4175 |
| 4176 instructions += TranslateInstantiatedTypeArguments(type_arguments); |
| 4177 instructions += PushArgument(); |
| 4178 } else { |
| 4179 ASSERT(node->arguments()->types().length() == 0); |
| 4180 } |
| 4181 |
| 4182 // Special case identical(x, y) call. |
| 4183 // TODO(vegorov) consider moving this into the inliner and force inline it |
| 4184 // there. |
| 4185 if (klass.IsTopLevel() && (klass.library() == dart::Library::CoreLibrary()) && |
| 4186 (target.name() == Symbols::Identical().raw())) { |
| 4187 ASSERT(argument_count == 2); |
| 4188 |
| 4189 List<Expression>& positional = node->arguments()->positional(); |
| 4190 for (intptr_t i = 0; i < positional.length(); ++i) { |
| 4191 instructions += TranslateExpression(positional[i]); |
| 4192 } |
| 4193 instructions += StrictCompare(Token::kEQ_STRICT, /*number_check=*/true); |
| 4194 } else { |
| 4195 instructions += TranslateArguments(node->arguments(), NULL); |
| 4196 instructions += StaticCall(target, argument_count, argument_names); |
| 4197 |
| 4198 if (target.IsGenerativeConstructor()) { |
| 4199 // Drop the result of the constructor call and leave [instance_variable] |
| 4200 // on top-of-stack. |
| 4201 instructions += Drop(); |
| 4202 } |
| 4203 } |
| 4204 |
| 4205 fragment_ = instructions; |
| 4206 } |
| 4207 |
| 4208 |
| 4209 static bool IsNumberLiteral(Node* node) { |
| 4210 return node->IsIntLiteral() || node->IsDoubleLiteral(); |
| 4211 } |
| 4212 |
| 4213 |
| 4214 void FlowGraphBuilder::VisitMethodInvocation(MethodInvocation* node) { |
| 4215 const dart::String& name = H.DartMethodName(node->name()); |
| 4216 const intptr_t argument_count = node->arguments()->count() + 1; |
| 4217 const Token::Kind token_kind = MethodKind(name); |
| 4218 if (IsNumberLiteral(node->receiver())) { |
| 4219 if ((argument_count == 1) && (token_kind == Token::kNEGATE)) { |
| 4220 const Object& result = constant_evaluator_.EvaluateExpressionSafe(node); |
| 4221 if (!result.IsError()) { |
| 4222 fragment_ = Constant(result); |
| 4223 return; |
| 4224 } |
| 4225 } else if ((argument_count == 2) && |
| 4226 Token::IsBinaryArithmeticOperator(token_kind) && |
| 4227 IsNumberLiteral(node->arguments()->positional()[0])) { |
| 4228 const Object& result = constant_evaluator_.EvaluateExpressionSafe(node); |
| 4229 if (!result.IsError()) { |
| 4230 fragment_ = Constant(result); |
| 4231 return; |
| 4232 } |
| 4233 } |
| 4234 } |
| 4235 |
| 4236 Fragment instructions = TranslateExpression(node->receiver()); |
| 4237 instructions += PushArgument(); |
| 4238 |
| 4239 // Dart does not support generic methods yet. |
| 4240 ASSERT(node->arguments()->types().length() == 0); |
| 4241 |
| 4242 Array& argument_names = Array::ZoneHandle(Z); |
| 4243 instructions += TranslateArguments(node->arguments(), &argument_names); |
| 4244 |
| 4245 intptr_t num_args_checked = 1; |
| 4246 // If we have a special operation (e.g. +/-/==) we mark both arguments as |
| 4247 // to be checked. |
| 4248 if (token_kind != Token::kILLEGAL) { |
| 4249 ASSERT(argument_count <= 2); |
| 4250 num_args_checked = argument_count; |
| 4251 } |
| 4252 |
| 4253 fragment_ = instructions + InstanceCall(name, token_kind, argument_count, |
| 4254 argument_names, num_args_checked); |
| 4255 } |
| 4256 |
| 4257 |
| 4258 void FlowGraphBuilder::VisitDirectMethodInvocation( |
| 4259 DirectMethodInvocation* node) { |
| 4260 const dart::String& method_name = H.DartMethodName(node->target()->name()); |
| 4261 const Function& target = Function::ZoneHandle( |
| 4262 Z, LookupMethodByMember(node->target(), method_name)); |
| 4263 |
| 4264 intptr_t argument_count = node->arguments()->count() + 1; |
| 4265 Array& argument_names = Array::ZoneHandle(Z); |
| 4266 |
| 4267 ASSERT(node->arguments()->types().length() == 0); |
| 4268 Fragment instructions = TranslateExpression(node->receiver()); |
| 4269 instructions += PushArgument(); |
| 4270 instructions += TranslateArguments(node->arguments(), &argument_names); |
| 4271 fragment_ = instructions + StaticCall(target, argument_count, argument_names); |
| 4272 } |
| 4273 |
| 4274 |
| 4275 void FlowGraphBuilder::VisitConstructorInvocation(ConstructorInvocation* node) { |
| 4276 if (node->is_const()) { |
| 4277 fragment_ = |
| 4278 Constant(constant_evaluator_.EvaluateConstructorInvocation(node)); |
| 4279 return; |
| 4280 } |
| 4281 |
| 4282 Class* dil_class = Class::Cast(node->target()->parent()); |
| 4283 |
| 4284 dart::Class& klass = |
| 4285 dart::Class::ZoneHandle(Z, H.LookupClassByDilClass(dil_class)); |
| 4286 |
| 4287 Fragment instructions; |
| 4288 if (klass.NumTypeArguments() > 0) { |
| 4289 List<DartType>& dil_type_arguments = node->arguments()->types(); |
| 4290 const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments( |
| 4291 klass, dil_type_arguments.raw_array(), dil_type_arguments.length()); |
| 4292 |
| 4293 if (type_arguments.IsNull() || type_arguments.IsInstantiated()) { |
| 4294 instructions += TranslateInstantiatedTypeArguments(type_arguments); |
| 4295 } else { |
| 4296 if (!klass.IsGeneric()) { |
| 4297 Type& type = Type::ZoneHandle(Z, T.ReceiverType(klass).raw()); |
| 4298 |
| 4299 // TODO(kustermann): Can we move this code into [ReceiverType]? |
| 4300 type ^= ClassFinalizer::FinalizeType(*active_class_.klass, type, |
| 4301 ClassFinalizer::kFinalize); |
| 4302 ASSERT(!type.IsMalformedOrMalbounded()); |
| 4303 |
| 4304 TypeArguments& canonicalized_type_arguments = |
| 4305 TypeArguments::ZoneHandle(Z, type.arguments()); |
| 4306 canonicalized_type_arguments = |
| 4307 canonicalized_type_arguments.Canonicalize(); |
| 4308 instructions += Constant(canonicalized_type_arguments); |
| 4309 } else { |
| 4310 instructions += TranslateInstantiatedTypeArguments(type_arguments); |
| 4311 } |
| 4312 } |
| 4313 |
| 4314 instructions += PushArgument(); |
| 4315 instructions += AllocateObject(klass, 1); |
| 4316 } else { |
| 4317 instructions += AllocateObject(klass, 0); |
| 4318 } |
| 4319 LocalVariable* variable = MakeTemporary(); |
| 4320 |
| 4321 instructions += LoadLocal(variable); |
| 4322 instructions += PushArgument(); |
| 4323 |
| 4324 Array& argument_names = Array::ZoneHandle(Z); |
| 4325 instructions += TranslateArguments(node->arguments(), &argument_names); |
| 4326 |
| 4327 const Function& target = Function::ZoneHandle( |
| 4328 Z, H.LookupConstructorByDilConstructor(klass, node->target())); |
| 4329 intptr_t argument_count = node->arguments()->count() + 1; |
| 4330 instructions += StaticCall(target, argument_count, argument_names); |
| 4331 fragment_ = instructions + Drop(); |
| 4332 } |
| 4333 |
| 4334 |
| 4335 void FlowGraphBuilder::VisitIsExpression(IsExpression* node) { |
| 4336 Fragment instructions = TranslateExpression(node->operand()); |
| 4337 |
| 4338 // The VM does not like an instanceOf call with a dynamic type. We need to |
| 4339 // special case this situation. |
| 4340 const Type& object_type = Type::Handle(Z, Type::ObjectType()); |
| 4341 const AbstractType& type = T.TranslateType(node->type()); |
| 4342 if (type.IsMalformed()) { |
| 4343 instructions += Drop(); |
| 4344 instructions += ThrowTypeError(); |
| 4345 fragment_ = instructions; |
| 4346 return; |
| 4347 } |
| 4348 |
| 4349 if (type.IsInstantiated() && |
| 4350 object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) { |
| 4351 // Evaluate the expression on the left but ignore it's result. |
| 4352 instructions += Drop(); |
| 4353 |
| 4354 // Let condition be always true. |
| 4355 instructions += Constant(Bool::True()); |
| 4356 } else { |
| 4357 instructions += PushArgument(); |
| 4358 |
| 4359 if (!type.IsInstantiated()) { |
| 4360 instructions += LoadInstantiatorTypeArguments(); |
| 4361 } else { |
| 4362 instructions += NullConstant(); |
| 4363 } |
| 4364 instructions += PushArgument(); // Type arguments. |
| 4365 |
| 4366 instructions += Constant(type); |
| 4367 instructions += PushArgument(); // Type. |
| 4368 |
| 4369 instructions += Constant(Bool::False()); |
| 4370 instructions += PushArgument(); // Negate?. |
| 4371 |
| 4372 instructions += |
| 4373 InstanceCall(dart::Library::PrivateCoreLibName(Symbols::_instanceOf()), |
| 4374 Token::kIS, 4); |
| 4375 } |
| 4376 |
| 4377 fragment_ = instructions; |
| 4378 } |
| 4379 |
| 4380 |
| 4381 void FlowGraphBuilder::VisitAsExpression(AsExpression* node) { |
| 4382 Fragment instructions = TranslateExpression(node->operand()); |
| 4383 |
| 4384 // The VM does not like an Object_as call with a dynamic type. We need to |
| 4385 // special case this situation. |
| 4386 const Type& object_type = Type::Handle(Z, Type::ObjectType()); |
| 4387 const AbstractType& type = T.TranslateType(node->type()); |
| 4388 if (type.IsMalformed()) { |
| 4389 instructions += Drop(); |
| 4390 instructions += ThrowTypeError(); |
| 4391 fragment_ = instructions; |
| 4392 return; |
| 4393 } |
| 4394 |
| 4395 if (type.IsInstantiated() && |
| 4396 object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) { |
| 4397 // We already evaluated the operand on the left and just leave it there as |
| 4398 // the result of the `obj as dynamic` expression. |
| 4399 } else { |
| 4400 instructions += PushArgument(); |
| 4401 |
| 4402 if (!type.IsInstantiated()) { |
| 4403 instructions += LoadInstantiatorTypeArguments(); |
| 4404 } else { |
| 4405 instructions += NullConstant(); |
| 4406 } |
| 4407 instructions += PushArgument(); // Type arguments. |
| 4408 |
| 4409 instructions += Constant(type); |
| 4410 instructions += PushArgument(); // Type. |
| 4411 |
| 4412 instructions += InstanceCall( |
| 4413 dart::Library::PrivateCoreLibName(Symbols::_as()), Token::kAS, 3); |
| 4414 } |
| 4415 |
| 4416 fragment_ = instructions; |
| 4417 } |
| 4418 |
| 4419 |
| 4420 void FlowGraphBuilder::VisitConditionalExpression(ConditionalExpression* node) { |
| 4421 bool negate; |
| 4422 Fragment instructions = TranslateCondition(node->condition(), &negate); |
| 4423 |
| 4424 TargetEntryInstr* then_entry; |
| 4425 TargetEntryInstr* otherwise_entry; |
| 4426 instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate); |
| 4427 |
| 4428 Value* top = stack_; |
| 4429 Fragment then_fragment(then_entry); |
| 4430 then_fragment += TranslateExpression(node->then()); |
| 4431 then_fragment += StoreLocal(parsed_function_->expression_temp_var()); |
| 4432 then_fragment += Drop(); |
| 4433 |
| 4434 ASSERT(stack_ == top); |
| 4435 Fragment otherwise_fragment(otherwise_entry); |
| 4436 otherwise_fragment += TranslateExpression(node->otherwise()); |
| 4437 otherwise_fragment += StoreLocal(parsed_function_->expression_temp_var()); |
| 4438 otherwise_fragment += Drop(); |
| 4439 |
| 4440 JoinEntryInstr* join = BuildJoinEntry(); |
| 4441 then_fragment += Goto(join); |
| 4442 otherwise_fragment += Goto(join); |
| 4443 |
| 4444 fragment_ = Fragment(instructions.entry, join) + |
| 4445 LoadLocal(parsed_function_->expression_temp_var()); |
| 4446 } |
| 4447 |
| 4448 |
| 4449 void FlowGraphBuilder::VisitLogicalExpression(LogicalExpression* node) { |
| 4450 bool negate; |
| 4451 Fragment instructions = TranslateCondition(node->left(), &negate); |
| 4452 TargetEntryInstr* right_entry; |
| 4453 TargetEntryInstr* constant_entry; |
| 4454 |
| 4455 if (node->op() == LogicalExpression::kAnd) { |
| 4456 instructions += BranchIfTrue(&right_entry, &constant_entry, negate); |
| 4457 } else { |
| 4458 instructions += BranchIfTrue(&constant_entry, &right_entry, negate); |
| 4459 } |
| 4460 |
| 4461 Value* top = stack_; |
| 4462 Fragment right_fragment(right_entry); |
| 4463 right_fragment += TranslateCondition(node->right(), &negate); |
| 4464 right_fragment += Constant(Bool::True()); |
| 4465 right_fragment += |
| 4466 StrictCompare(negate ? Token::kNE_STRICT : Token::kEQ_STRICT); |
| 4467 right_fragment += StoreLocal(parsed_function_->expression_temp_var()); |
| 4468 right_fragment += Drop(); |
| 4469 |
| 4470 ASSERT(top == stack_); |
| 4471 Fragment constant_fragment(constant_entry); |
| 4472 constant_fragment += |
| 4473 Constant(Bool::Get(node->op() == LogicalExpression::kOr)); |
| 4474 constant_fragment += StoreLocal(parsed_function_->expression_temp_var()); |
| 4475 constant_fragment += Drop(); |
| 4476 |
| 4477 JoinEntryInstr* join = BuildJoinEntry(); |
| 4478 right_fragment += Goto(join); |
| 4479 constant_fragment += Goto(join); |
| 4480 |
| 4481 fragment_ = Fragment(instructions.entry, join) + |
| 4482 LoadLocal(parsed_function_->expression_temp_var()); |
| 4483 } |
| 4484 |
| 4485 |
| 4486 void FlowGraphBuilder::VisitNot(Not* node) { |
| 4487 Fragment instructions = TranslateExpression(node->expression()); |
| 4488 fragment_ = instructions + BooleanNegate(); |
| 4489 } |
| 4490 |
| 4491 |
| 4492 void FlowGraphBuilder::VisitThisExpression(ThisExpression* node) { |
| 4493 fragment_ = LoadLocal(scopes_->this_variable); |
| 4494 } |
| 4495 |
| 4496 |
| 4497 void FlowGraphBuilder::VisitStringConcatenation(StringConcatenation* node) { |
| 4498 List<Expression>& expressions = node->expressions(); |
| 4499 |
| 4500 Fragment instructions; |
| 4501 |
| 4502 // The type arguments for CreateArray. |
| 4503 instructions += Constant(TypeArguments::ZoneHandle(Z)); |
| 4504 instructions += IntConstant(expressions.length()); |
| 4505 instructions += CreateArray(); |
| 4506 LocalVariable* array = MakeTemporary(); |
| 4507 |
| 4508 for (intptr_t i = 0; i < node->expressions().length(); i++) { |
| 4509 instructions += LoadLocal(array); |
| 4510 instructions += IntConstant(i); |
| 4511 instructions += TranslateExpression(node->expressions()[i]); |
| 4512 instructions += StoreIndexed(kArrayCid); |
| 4513 instructions += Drop(); |
| 4514 } |
| 4515 |
| 4516 instructions += StringInterpolate(); |
| 4517 |
| 4518 fragment_ = instructions; |
| 4519 } |
| 4520 |
| 4521 |
| 4522 void FlowGraphBuilder::VisitListLiteral(ListLiteral* node) { |
| 4523 if (node->is_const()) { |
| 4524 fragment_ = Constant(constant_evaluator_.EvaluateListLiteral(node)); |
| 4525 return; |
| 4526 } |
| 4527 |
| 4528 DartType* types[] = {node->type()}; |
| 4529 const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 1); |
| 4530 |
| 4531 // The type argument for the factory call. |
| 4532 Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments); |
| 4533 instructions += PushArgument(); |
| 4534 List<Expression>& expressions = node->expressions(); |
| 4535 if (expressions.length() == 0) { |
| 4536 instructions += Constant(Object::empty_array()); |
| 4537 } else { |
| 4538 // The type arguments for CreateArray. |
| 4539 instructions += Constant(TypeArguments::ZoneHandle(Z)); |
| 4540 instructions += IntConstant(expressions.length()); |
| 4541 instructions += CreateArray(); |
| 4542 |
| 4543 LocalVariable* array = MakeTemporary(); |
| 4544 for (intptr_t i = 0; i < expressions.length(); ++i) { |
| 4545 instructions += LoadLocal(array); |
| 4546 instructions += IntConstant(i); |
| 4547 instructions += TranslateExpression(expressions[i]); |
| 4548 instructions += StoreIndexed(kArrayCid); |
| 4549 instructions += Drop(); |
| 4550 } |
| 4551 } |
| 4552 instructions += PushArgument(); // The array. |
| 4553 |
| 4554 const dart::Class& factory_class = |
| 4555 dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::List())); |
| 4556 const Function& factory_method = Function::ZoneHandle( |
| 4557 Z, factory_class.LookupFactory( |
| 4558 dart::Library::PrivateCoreLibName(Symbols::ListLiteralFactory()))); |
| 4559 fragment_ = instructions + StaticCall(factory_method, 2); |
| 4560 } |
| 4561 |
| 4562 |
| 4563 void FlowGraphBuilder::VisitMapLiteral(MapLiteral* node) { |
| 4564 if (node->is_const()) { |
| 4565 fragment_ = Constant(constant_evaluator_.EvaluateMapLiteral(node)); |
| 4566 return; |
| 4567 } |
| 4568 |
| 4569 const dart::Class& map_class = |
| 4570 dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::Map())); |
| 4571 const Function& factory_method = Function::ZoneHandle( |
| 4572 Z, map_class.LookupFactory( |
| 4573 dart::Library::PrivateCoreLibName(Symbols::MapLiteralFactory()))); |
| 4574 |
| 4575 DartType* types[] = {node->key_type(), node->value_type()}; |
| 4576 const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 2); |
| 4577 |
| 4578 // The type argument for the factory call `new Map<K, V>._fromLiteral(List)`. |
| 4579 Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments); |
| 4580 instructions += PushArgument(); |
| 4581 |
| 4582 List<MapEntry>& entries = node->entries(); |
| 4583 if (entries.length() == 0) { |
| 4584 instructions += Constant(Object::empty_array()); |
| 4585 } else { |
| 4586 // The type arguments for `new List<X>(int len)`. |
| 4587 instructions += Constant(TypeArguments::ZoneHandle(Z)); |
| 4588 |
| 4589 // We generate a list of tuples, i.e. [key1, value1, ..., keyN, valueN]. |
| 4590 instructions += IntConstant(2 * entries.length()); |
| 4591 instructions += CreateArray(); |
| 4592 |
| 4593 LocalVariable* array = MakeTemporary(); |
| 4594 for (intptr_t i = 0; i < entries.length(); ++i) { |
| 4595 instructions += LoadLocal(array); |
| 4596 instructions += IntConstant(2 * i); |
| 4597 instructions += TranslateExpression(entries[i]->key()); |
| 4598 instructions += StoreIndexed(kArrayCid); |
| 4599 instructions += Drop(); |
| 4600 |
| 4601 instructions += LoadLocal(array); |
| 4602 instructions += IntConstant(2 * i + 1); |
| 4603 instructions += TranslateExpression(entries[i]->value()); |
| 4604 instructions += StoreIndexed(kArrayCid); |
| 4605 instructions += Drop(); |
| 4606 } |
| 4607 } |
| 4608 instructions += PushArgument(); // The array. |
| 4609 |
| 4610 fragment_ = instructions + StaticCall(factory_method, 2); |
| 4611 } |
| 4612 |
| 4613 |
| 4614 void FlowGraphBuilder::VisitFunctionExpression(FunctionExpression* node) { |
| 4615 fragment_ = TranslateFunctionNode(node->function(), node); |
| 4616 } |
| 4617 |
| 4618 |
| 4619 void FlowGraphBuilder::VisitLet(Let* node) { |
| 4620 Fragment instructions = TranslateStatement(node->variable()); |
| 4621 instructions += TranslateExpression(node->body()); |
| 4622 fragment_ = instructions; |
| 4623 } |
| 4624 |
| 4625 |
| 4626 void FlowGraphBuilder::VisitThrow(Throw* node) { |
| 4627 Fragment instructions; |
| 4628 |
| 4629 instructions += TranslateExpression(node->expression()); |
| 4630 instructions += PushArgument(); |
| 4631 instructions += ThrowException(); |
| 4632 ASSERT(instructions.is_closed()); |
| 4633 |
| 4634 fragment_ = instructions; |
| 4635 } |
| 4636 |
| 4637 |
| 4638 void FlowGraphBuilder::VisitRethrow(Rethrow* node) { |
| 4639 Fragment instructions; |
| 4640 |
| 4641 instructions += LoadLocal(catch_block_->exception_var()); |
| 4642 instructions += PushArgument(); |
| 4643 instructions += LoadLocal(catch_block_->stack_trace_var()); |
| 4644 instructions += PushArgument(); |
| 4645 instructions += RethrowException(catch_block_->catch_try_index()); |
| 4646 |
| 4647 fragment_ = instructions; |
| 4648 } |
| 4649 |
| 4650 |
| 4651 void FlowGraphBuilder::VisitBlockExpression(BlockExpression* node) { |
| 4652 Fragment instructions = TranslateStatement(node->body()); |
| 4653 instructions += TranslateExpression(node->value()); |
| 4654 fragment_ = instructions; |
| 4655 } |
| 4656 |
| 4657 |
| 4658 Fragment FlowGraphBuilder::TranslateArguments(Arguments* node, |
| 4659 Array* argument_names) { |
| 4660 Fragment instructions; |
| 4661 |
| 4662 List<Expression>& positional = node->positional(); |
| 4663 for (intptr_t i = 0; i < positional.length(); ++i) { |
| 4664 instructions += TranslateExpression(positional[i]); |
| 4665 instructions += PushArgument(); |
| 4666 } |
| 4667 |
| 4668 List<NamedExpression>& named = node->named(); |
| 4669 if (argument_names != NULL) { |
| 4670 *argument_names = H.ArgumentNames(&named).raw(); |
| 4671 } |
| 4672 for (intptr_t i = 0; i < named.length(); ++i) { |
| 4673 NamedExpression* named_expression = named[i]; |
| 4674 instructions += TranslateExpression(named_expression->expression()); |
| 4675 instructions += PushArgument(); |
| 4676 } |
| 4677 return instructions; |
| 4678 } |
| 4679 |
| 4680 |
| 4681 void FlowGraphBuilder::VisitInvalidStatement(InvalidStatement* node) { |
| 4682 H.ReportError("Invalid statements not implemented yet!"); |
| 4683 } |
| 4684 |
| 4685 |
| 4686 void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* node) { |
| 4687 fragment_ = Fragment(); |
| 4688 } |
| 4689 |
| 4690 |
| 4691 void FlowGraphBuilder::VisitBlock(Block* node) { |
| 4692 Fragment instructions; |
| 4693 |
| 4694 instructions += EnterScope(node); |
| 4695 List<Statement>& statements = node->statements(); |
| 4696 for (intptr_t i = 0; i < statements.length(); ++i) { |
| 4697 instructions += TranslateStatement(statements[i]); |
| 4698 } |
| 4699 instructions += ExitScope(node); |
| 4700 |
| 4701 fragment_ = instructions; |
| 4702 } |
| 4703 |
| 4704 |
| 4705 void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* node) { |
| 4706 bool inside_try_finally = try_finally_block_ != NULL; |
| 4707 |
| 4708 Fragment instructions = node->expression() == NULL |
| 4709 ? NullConstant() |
| 4710 : TranslateExpression(node->expression()); |
| 4711 if (inside_try_finally) { |
| 4712 ASSERT(scopes_->finally_return_variable != NULL); |
| 4713 instructions += StoreLocal(scopes_->finally_return_variable); |
| 4714 instructions += Drop(); |
| 4715 instructions += TranslateFinallyFinalizers(NULL, -1); |
| 4716 if (instructions.is_open()) { |
| 4717 instructions += LoadLocal(scopes_->finally_return_variable); |
| 4718 instructions += Return(); |
| 4719 } |
| 4720 } else { |
| 4721 instructions += Return(); |
| 4722 } |
| 4723 fragment_ = instructions; |
| 4724 } |
| 4725 |
| 4726 |
| 4727 void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* node) { |
| 4728 Fragment instructions = TranslateExpression(node->expression()); |
| 4729 instructions += Drop(); |
| 4730 fragment_ = instructions; |
| 4731 } |
| 4732 |
| 4733 |
| 4734 void FlowGraphBuilder::VisitVariableDeclaration(VariableDeclaration* node) { |
| 4735 LocalVariable* variable = LookupVariable(node); |
| 4736 Expression* initializer = node->initializer(); |
| 4737 |
| 4738 Fragment instructions; |
| 4739 if (initializer == NULL) { |
| 4740 instructions += NullConstant(); |
| 4741 } else { |
| 4742 if (node->IsConst()) { |
| 4743 const Instance& constant_value = |
| 4744 constant_evaluator_.EvaluateExpression(initializer); |
| 4745 variable->SetConstValue(constant_value); |
| 4746 instructions += Constant(constant_value); |
| 4747 } else { |
| 4748 instructions += TranslateExpression(initializer); |
| 4749 } |
| 4750 } |
| 4751 instructions += StoreLocal(variable); |
| 4752 instructions += Drop(); |
| 4753 fragment_ = instructions; |
| 4754 } |
| 4755 |
| 4756 |
| 4757 void FlowGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* node) { |
| 4758 Fragment instructions = TranslateFunctionNode(node->function(), node); |
| 4759 instructions += StoreLocal(LookupVariable(node->variable())); |
| 4760 instructions += Drop(); |
| 4761 fragment_ = instructions; |
| 4762 } |
| 4763 |
| 4764 |
| 4765 void FlowGraphBuilder::VisitIfStatement(IfStatement* node) { |
| 4766 bool negate; |
| 4767 Fragment instructions = TranslateCondition(node->condition(), &negate); |
| 4768 TargetEntryInstr* then_entry; |
| 4769 TargetEntryInstr* otherwise_entry; |
| 4770 instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate); |
| 4771 |
| 4772 Fragment then_fragment(then_entry); |
| 4773 then_fragment += TranslateStatement(node->then()); |
| 4774 |
| 4775 Fragment otherwise_fragment(otherwise_entry); |
| 4776 otherwise_fragment += TranslateStatement(node->otherwise()); |
| 4777 |
| 4778 if (then_fragment.is_open()) { |
| 4779 if (otherwise_fragment.is_open()) { |
| 4780 JoinEntryInstr* join = BuildJoinEntry(); |
| 4781 then_fragment += Goto(join); |
| 4782 otherwise_fragment += Goto(join); |
| 4783 fragment_ = Fragment(instructions.entry, join); |
| 4784 } else { |
| 4785 fragment_ = Fragment(instructions.entry, then_fragment.current); |
| 4786 } |
| 4787 } else if (otherwise_fragment.is_open()) { |
| 4788 fragment_ = Fragment(instructions.entry, otherwise_fragment.current); |
| 4789 } else { |
| 4790 fragment_ = instructions.closed(); |
| 4791 } |
| 4792 } |
| 4793 |
| 4794 |
| 4795 void FlowGraphBuilder::VisitWhileStatement(WhileStatement* node) { |
| 4796 ++loop_depth_; |
| 4797 bool negate; |
| 4798 Fragment condition = TranslateCondition(node->condition(), &negate); |
| 4799 TargetEntryInstr* body_entry; |
| 4800 TargetEntryInstr* loop_exit; |
| 4801 condition += BranchIfTrue(&body_entry, &loop_exit, negate); |
| 4802 |
| 4803 Fragment body(body_entry); |
| 4804 body += TranslateStatement(node->body()); |
| 4805 |
| 4806 Instruction* entry; |
| 4807 if (body.is_open()) { |
| 4808 JoinEntryInstr* join = BuildJoinEntry(); |
| 4809 body += Goto(join); |
| 4810 |
| 4811 Fragment loop(join); |
| 4812 loop += CheckStackOverflow(); |
| 4813 loop += condition; |
| 4814 entry = new (Z) GotoInstr(join); |
| 4815 } else { |
| 4816 entry = condition.entry; |
| 4817 } |
| 4818 |
| 4819 |
| 4820 fragment_ = Fragment(entry, loop_exit); |
| 4821 --loop_depth_; |
| 4822 } |
| 4823 |
| 4824 |
| 4825 void FlowGraphBuilder::VisitDoStatement(DoStatement* node) { |
| 4826 ++loop_depth_; |
| 4827 Fragment body = TranslateStatement(node->body()); |
| 4828 |
| 4829 if (body.is_closed()) { |
| 4830 fragment_ = body; |
| 4831 --loop_depth_; |
| 4832 return; |
| 4833 } |
| 4834 |
| 4835 bool negate; |
| 4836 JoinEntryInstr* join = BuildJoinEntry(); |
| 4837 Fragment loop(join); |
| 4838 loop += CheckStackOverflow(); |
| 4839 loop += body; |
| 4840 loop += TranslateCondition(node->condition(), &negate); |
| 4841 TargetEntryInstr* loop_repeat; |
| 4842 TargetEntryInstr* loop_exit; |
| 4843 loop += BranchIfTrue(&loop_repeat, &loop_exit, negate); |
| 4844 |
| 4845 Fragment repeat(loop_repeat); |
| 4846 repeat += Goto(join); |
| 4847 |
| 4848 fragment_ = Fragment(new (Z) GotoInstr(join), loop_exit); |
| 4849 --loop_depth_; |
| 4850 } |
| 4851 |
| 4852 |
| 4853 void FlowGraphBuilder::VisitForStatement(ForStatement* node) { |
| 4854 Fragment declarations; |
| 4855 |
| 4856 bool new_context = false; |
| 4857 declarations += EnterScope(node, &new_context); |
| 4858 |
| 4859 List<VariableDeclaration>& variables = node->variables(); |
| 4860 for (intptr_t i = 0; i < variables.length(); ++i) { |
| 4861 declarations += TranslateStatement(variables[i]); |
| 4862 } |
| 4863 |
| 4864 ++loop_depth_; |
| 4865 bool negate = false; |
| 4866 Fragment condition = node->condition() == NULL |
| 4867 ? Constant(Bool::True()) |
| 4868 : TranslateCondition(node->condition(), &negate); |
| 4869 TargetEntryInstr* body_entry; |
| 4870 TargetEntryInstr* loop_exit; |
| 4871 condition += BranchIfTrue(&body_entry, &loop_exit, negate); |
| 4872 |
| 4873 Fragment body(body_entry); |
| 4874 body += TranslateStatement(node->body()); |
| 4875 |
| 4876 if (body.is_open()) { |
| 4877 // We allocated a fresh context before the loop which contains captured |
| 4878 // [ForStatement] variables. Before jumping back to the loop entry we clone |
| 4879 // the context object (at same depth) which ensures the next iteration of |
| 4880 // the body gets a fresh set of [ForStatement] variables (with the old |
| 4881 // (possibly updated) values). |
| 4882 if (new_context) body += CloneContext(); |
| 4883 |
| 4884 List<Expression>& updates = node->updates(); |
| 4885 for (intptr_t i = 0; i < updates.length(); ++i) { |
| 4886 body += TranslateExpression(updates[i]); |
| 4887 body += Drop(); |
| 4888 } |
| 4889 JoinEntryInstr* join = BuildJoinEntry(); |
| 4890 declarations += Goto(join); |
| 4891 body += Goto(join); |
| 4892 |
| 4893 Fragment loop(join); |
| 4894 loop += CheckStackOverflow(); |
| 4895 loop += condition; |
| 4896 } else { |
| 4897 declarations += condition; |
| 4898 } |
| 4899 |
| 4900 Fragment loop(declarations.entry, loop_exit); |
| 4901 --loop_depth_; |
| 4902 |
| 4903 loop += ExitScope(node); |
| 4904 |
| 4905 fragment_ = loop; |
| 4906 } |
| 4907 |
| 4908 |
| 4909 void FlowGraphBuilder::VisitForInStatement(ForInStatement* node) { |
| 4910 Fragment instructions = TranslateExpression(node->iterable()); |
| 4911 instructions += PushArgument(); |
| 4912 |
| 4913 const dart::String& iterator_getter = dart::String::ZoneHandle( |
| 4914 Z, dart::Field::GetterSymbol(Symbols::Iterator())); |
| 4915 instructions += InstanceCall(iterator_getter, Token::kGET, 1); |
| 4916 LocalVariable* iterator = scopes_->iterator_variables[for_in_depth_]; |
| 4917 instructions += StoreLocal(iterator); |
| 4918 instructions += Drop(); |
| 4919 |
| 4920 ++for_in_depth_; |
| 4921 ++loop_depth_; |
| 4922 Fragment condition = LoadLocal(iterator); |
| 4923 condition += PushArgument(); |
| 4924 condition += InstanceCall(Symbols::MoveNext(), Token::kILLEGAL, 1); |
| 4925 TargetEntryInstr* body_entry; |
| 4926 TargetEntryInstr* loop_exit; |
| 4927 condition += BranchIfTrue(&body_entry, &loop_exit); |
| 4928 |
| 4929 Fragment body(body_entry); |
| 4930 body += EnterScope(node); |
| 4931 body += LoadLocal(iterator); |
| 4932 body += PushArgument(); |
| 4933 const dart::String& current_getter = dart::String::ZoneHandle( |
| 4934 Z, dart::Field::GetterSymbol(Symbols::Current())); |
| 4935 body += InstanceCall(current_getter, Token::kGET, 1); |
| 4936 body += StoreLocal(LookupVariable(node->variable())); |
| 4937 body += Drop(); |
| 4938 body += TranslateStatement(node->body()); |
| 4939 body += ExitScope(node); |
| 4940 |
| 4941 if (body.is_open()) { |
| 4942 JoinEntryInstr* join = BuildJoinEntry(); |
| 4943 instructions += Goto(join); |
| 4944 body += Goto(join); |
| 4945 |
| 4946 Fragment loop(join); |
| 4947 loop += CheckStackOverflow(); |
| 4948 loop += condition; |
| 4949 } else { |
| 4950 instructions += condition; |
| 4951 } |
| 4952 |
| 4953 fragment_ = Fragment(instructions.entry, loop_exit); |
| 4954 --loop_depth_; |
| 4955 --for_in_depth_; |
| 4956 } |
| 4957 |
| 4958 |
| 4959 void FlowGraphBuilder::VisitLabeledStatement(LabeledStatement* node) { |
| 4960 // There can be serveral cases: |
| 4961 // |
| 4962 // * the body contains a break |
| 4963 // * the body doesn't contain a break |
| 4964 // |
| 4965 // * translating the body results in a closed fragment |
| 4966 // * translating the body results in a open fragment |
| 4967 // |
| 4968 // => We will only know which case we are in after the body has been |
| 4969 // traversed. |
| 4970 |
| 4971 BreakableBlock block(this, node); |
| 4972 Fragment instructions = TranslateStatement(node->body()); |
| 4973 if (block.HadJumper()) { |
| 4974 if (instructions.is_open()) { |
| 4975 instructions += Goto(block.destination()); |
| 4976 } |
| 4977 fragment_ = Fragment(instructions.entry, block.destination()); |
| 4978 } else { |
| 4979 fragment_ = instructions; |
| 4980 } |
| 4981 } |
| 4982 |
| 4983 |
| 4984 void FlowGraphBuilder::VisitBreakStatement(BreakStatement* node) { |
| 4985 TryFinallyBlock* outer_finally = NULL; |
| 4986 intptr_t target_context_depth = -1; |
| 4987 JoinEntryInstr* destination = breakable_block_->BreakDestination( |
| 4988 node->target(), &outer_finally, &target_context_depth); |
| 4989 |
| 4990 Fragment instructions; |
| 4991 instructions += |
| 4992 TranslateFinallyFinalizers(outer_finally, target_context_depth); |
| 4993 if (instructions.is_open()) { |
| 4994 instructions += Goto(destination); |
| 4995 } |
| 4996 fragment_ = instructions; |
| 4997 } |
| 4998 |
| 4999 |
| 5000 void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* node) { |
| 5001 SwitchBlock block(this, node); |
| 5002 |
| 5003 // Instead of using a variable we should reuse the expression on the stack, |
| 5004 // since it won't be assigned again, we don't need phi nodes. |
| 5005 Fragment head_instructions = TranslateExpression(node->condition()); |
| 5006 head_instructions += StoreLocal(scopes_->switch_variable); |
| 5007 head_instructions += Drop(); |
| 5008 |
| 5009 // Phase 1: Generate bodies and try to find out whether a body will be target |
| 5010 // of a jump due to: |
| 5011 // * `continue case_label` |
| 5012 // * `case e1: case e2: body` |
| 5013 Fragment* body_fragments = new Fragment[node->cases().length()]; |
| 5014 |
| 5015 intptr_t num_cases = node->cases().length(); |
| 5016 for (intptr_t i = 0; i < num_cases; i++) { |
| 5017 SwitchCase* switch_case = node->cases()[i]; |
| 5018 Fragment& body_fragment = body_fragments[i] = |
| 5019 TranslateStatement(switch_case->body()); |
| 5020 |
| 5021 if (body_fragment.entry == NULL) { |
| 5022 // Make a NOP in order to ensure linking works properly. |
| 5023 body_fragment = NullConstant(); |
| 5024 body_fragment += Drop(); |
| 5025 } |
| 5026 |
| 5027 // The Dart language specification mandates fall-throughs in [SwitchCase]es |
| 5028 // to be runtime errors. |
| 5029 if (!switch_case->is_default() && body_fragment.is_open() && |
| 5030 (i < (node->cases().length() - 1))) { |
| 5031 const dart::Class& klass = dart::Class::ZoneHandle( |
| 5032 Z, dart::Library::LookupCoreClass(Symbols::FallThroughError())); |
| 5033 ASSERT(!klass.IsNull()); |
| 5034 const dart::Function& constructor = dart::Function::ZoneHandle( |
| 5035 Z, klass.LookupConstructorAllowPrivate( |
| 5036 H.DartSymbol("FallThroughError._create"))); |
| 5037 ASSERT(!constructor.IsNull()); |
| 5038 const dart::String& url = H.DartString( |
| 5039 parsed_function_->function().ToLibNamePrefixedQualifiedCString(), |
| 5040 Heap::kOld); |
| 5041 |
| 5042 // Create instance of _FallThroughError |
| 5043 body_fragment += AllocateObject(klass, 0); |
| 5044 LocalVariable* instance = MakeTemporary(); |
| 5045 |
| 5046 // Call _AssertionError._create constructor. |
| 5047 body_fragment += LoadLocal(instance); |
| 5048 body_fragment += PushArgument(); // this |
| 5049 |
| 5050 body_fragment += Constant(url); |
| 5051 body_fragment += PushArgument(); // url |
| 5052 |
| 5053 body_fragment += NullConstant(); |
| 5054 body_fragment += PushArgument(); // line |
| 5055 |
| 5056 body_fragment += StaticCall(constructor, 3); |
| 5057 body_fragment += Drop(); |
| 5058 |
| 5059 // Throw the exception |
| 5060 body_fragment += PushArgument(); |
| 5061 body_fragment += ThrowException(); |
| 5062 body_fragment += Drop(); |
| 5063 } |
| 5064 |
| 5065 // If there is an implicit fall-through we have one [SwitchCase] and |
| 5066 // multiple expressions, e.g. |
| 5067 // |
| 5068 // switch(expr) { |
| 5069 // case a: |
| 5070 // case b: |
| 5071 // <stmt-body> |
| 5072 // } |
| 5073 // |
| 5074 // This means that the <stmt-body> will have more than 1 incoming edge (one |
| 5075 // from `a == expr` and one from `a != expr && b == expr`). The |
| 5076 // `block.Destination()` records the additional jump. |
| 5077 if (switch_case->expressions().length() > 1) { |
| 5078 block.Destination(switch_case); |
| 5079 } |
| 5080 } |
| 5081 |
| 5082 // Phase 2: Generate everything except the real bodies: |
| 5083 // * jump directly to a body (if there is no jumper) |
| 5084 // * jump to a wrapper block which jumps to the body (if there is a jumper) |
| 5085 Fragment current_instructions = head_instructions; |
| 5086 for (intptr_t i = 0; i < num_cases; i++) { |
| 5087 SwitchCase* switch_case = node->cases()[i]; |
| 5088 |
| 5089 if (switch_case->is_default()) { |
| 5090 ASSERT(i == (node->cases().length() - 1)); |
| 5091 |
| 5092 // Evaluate the conditions for the default [SwitchCase] just for the |
| 5093 // purpose of potentially triggering a compile-time error. |
| 5094 for (intptr_t k = 0; k < switch_case->expressions().length(); k++) { |
| 5095 constant_evaluator_.EvaluateExpression(switch_case->expressions()[k]); |
| 5096 } |
| 5097 |
| 5098 if (block.HadJumper(switch_case)) { |
| 5099 // There are several branches to the body, so we will make a goto to |
| 5100 // the join block (and prepend a join instruction to the real body). |
| 5101 JoinEntryInstr* join = block.Destination(switch_case); |
| 5102 current_instructions += Goto(join); |
| 5103 |
| 5104 current_instructions = Fragment(current_instructions.entry, join); |
| 5105 current_instructions += body_fragments[i]; |
| 5106 } else { |
| 5107 current_instructions += body_fragments[i]; |
| 5108 } |
| 5109 } else { |
| 5110 JoinEntryInstr* body_join = NULL; |
| 5111 if (block.HadJumper(switch_case)) { |
| 5112 body_join = block.Destination(switch_case); |
| 5113 body_fragments[i] = Fragment(body_join) + body_fragments[i]; |
| 5114 } |
| 5115 |
| 5116 for (intptr_t j = 0; j < switch_case->expressions().length(); j++) { |
| 5117 TargetEntryInstr* then; |
| 5118 TargetEntryInstr* otherwise; |
| 5119 |
| 5120 current_instructions += Constant(constant_evaluator_.EvaluateExpression( |
| 5121 switch_case->expressions()[j])); |
| 5122 current_instructions += PushArgument(); |
| 5123 current_instructions += LoadLocal(scopes_->switch_variable); |
| 5124 current_instructions += PushArgument(); |
| 5125 current_instructions += |
| 5126 InstanceCall(Symbols::EqualOperator(), Token::kEQ, |
| 5127 /*argument_count=*/2, |
| 5128 /*num_args_checked=*/2); |
| 5129 current_instructions += BranchIfTrue(&then, &otherwise); |
| 5130 |
| 5131 Fragment then_fragment(then); |
| 5132 |
| 5133 if (body_join != NULL) { |
| 5134 // There are several branches to the body, so we will make a goto to |
| 5135 // the join block (the real body has already been prepended with a |
| 5136 // join instruction). |
| 5137 then_fragment += Goto(body_join); |
| 5138 } else { |
| 5139 // There is only a signle branch to the body, so we will just append |
| 5140 // the body fragment. |
| 5141 then_fragment += body_fragments[i]; |
| 5142 } |
| 5143 |
| 5144 current_instructions = Fragment(otherwise); |
| 5145 } |
| 5146 } |
| 5147 } |
| 5148 |
| 5149 bool has_no_default = |
| 5150 num_cases > 0 && !node->cases()[num_cases - 1]->is_default(); |
| 5151 if (has_no_default) { |
| 5152 // There is no default, which means we have an open [current_instructions] |
| 5153 // (which is a [TargetEntryInstruction] for the last "otherwise" branch). |
| 5154 // |
| 5155 // Furthermore the last [SwitchCase] can be open as well. If so, we need |
| 5156 // to join these two. |
| 5157 Fragment& last_body = body_fragments[node->cases().length() - 1]; |
| 5158 if (last_body.is_open()) { |
| 5159 ASSERT(current_instructions.is_open()); |
| 5160 ASSERT(current_instructions.current->IsTargetEntry()); |
| 5161 |
| 5162 // Join the last "otherwise" branch and the last [SwitchCase] fragment. |
| 5163 JoinEntryInstr* join = BuildJoinEntry(); |
| 5164 current_instructions += Goto(join); |
| 5165 last_body += Goto(join); |
| 5166 |
| 5167 current_instructions = Fragment(join); |
| 5168 } |
| 5169 } else { |
| 5170 // All non-default cases will be closed (i.e. break/continue/throw/return) |
| 5171 // So it is fine to just let more statements after the switch append to the |
| 5172 // default case. |
| 5173 } |
| 5174 |
| 5175 delete[] body_fragments; |
| 5176 |
| 5177 fragment_ = Fragment(head_instructions.entry, current_instructions.current); |
| 5178 } |
| 5179 |
| 5180 |
| 5181 void FlowGraphBuilder::VisitContinueSwitchStatement( |
| 5182 ContinueSwitchStatement* node) { |
| 5183 TryFinallyBlock* outer_finally = NULL; |
| 5184 intptr_t target_context_depth = -1; |
| 5185 JoinEntryInstr* entry = switch_block_->Destination( |
| 5186 node->target(), &outer_finally, &target_context_depth); |
| 5187 |
| 5188 Fragment instructions; |
| 5189 instructions += |
| 5190 TranslateFinallyFinalizers(outer_finally, target_context_depth); |
| 5191 if (instructions.is_open()) { |
| 5192 instructions += Goto(entry); |
| 5193 } |
| 5194 fragment_ = instructions; |
| 5195 } |
| 5196 |
| 5197 |
| 5198 void FlowGraphBuilder::VisitAssertStatement(AssertStatement* node) { |
| 5199 if (!I->asserts()) { |
| 5200 fragment_ = Fragment(); |
| 5201 return; |
| 5202 } |
| 5203 |
| 5204 TargetEntryInstr* then; |
| 5205 TargetEntryInstr* otherwise; |
| 5206 |
| 5207 bool negate; |
| 5208 Fragment instructions; |
| 5209 instructions += TranslateCondition(node->condition(), &negate); |
| 5210 instructions += BranchIfTrue(&then, &otherwise, negate); |
| 5211 |
| 5212 const dart::Class& klass = dart::Class::ZoneHandle( |
| 5213 Z, dart::Library::LookupCoreClass(Symbols::AssertionError())); |
| 5214 ASSERT(!klass.IsNull()); |
| 5215 const dart::Function& constructor = dart::Function::ZoneHandle( |
| 5216 Z, klass.LookupConstructorAllowPrivate( |
| 5217 H.DartSymbol("_AssertionError._create"))); |
| 5218 ASSERT(!constructor.IsNull()); |
| 5219 |
| 5220 const dart::String& url = H.DartString( |
| 5221 parsed_function_->function().ToLibNamePrefixedQualifiedCString(), |
| 5222 Heap::kOld); |
| 5223 |
| 5224 // Create instance of _AssertionError |
| 5225 Fragment otherwise_fragment(otherwise); |
| 5226 otherwise_fragment += AllocateObject(klass, 0); |
| 5227 LocalVariable* instance = MakeTemporary(); |
| 5228 |
| 5229 // Call _AssertionError._create constructor. |
| 5230 otherwise_fragment += LoadLocal(instance); |
| 5231 otherwise_fragment += PushArgument(); // this |
| 5232 |
| 5233 otherwise_fragment += |
| 5234 node->message() != NULL |
| 5235 ? TranslateExpression(node->message()) |
| 5236 : Constant(H.DartString("<no message>", Heap::kOld)); |
| 5237 otherwise_fragment += PushArgument(); // message |
| 5238 |
| 5239 otherwise_fragment += Constant(url); |
| 5240 otherwise_fragment += PushArgument(); // url |
| 5241 |
| 5242 otherwise_fragment += IntConstant(0); |
| 5243 otherwise_fragment += PushArgument(); // line |
| 5244 |
| 5245 otherwise_fragment += IntConstant(0); |
| 5246 otherwise_fragment += PushArgument(); // column |
| 5247 |
| 5248 otherwise_fragment += StaticCall(constructor, 5); |
| 5249 otherwise_fragment += Drop(); |
| 5250 |
| 5251 // Throw _AssertionError exception. |
| 5252 otherwise_fragment += PushArgument(); |
| 5253 otherwise_fragment += ThrowException(); |
| 5254 otherwise_fragment += Drop(); |
| 5255 |
| 5256 fragment_ = Fragment(instructions.entry, then); |
| 5257 } |
| 5258 |
| 5259 |
| 5260 void FlowGraphBuilder::VisitTryFinally(TryFinally* node) { |
| 5261 InlineBailout("dil::FlowgraphBuilder::VisitTryFinally"); |
| 5262 |
| 5263 // There are 5 different cases where we need to execute the finally block: |
| 5264 // |
| 5265 // a) 1/2/3th case: Special control flow going out of `node->body()`: |
| 5266 // |
| 5267 // * [BreakStatement] transfers control to a [LabledStatement] |
| 5268 // * [ContinueSwitchStatement] transfers control to a [SwitchCase] |
| 5269 // * [ReturnStatement] returns a value |
| 5270 // |
| 5271 // => All three cases will automatically append all finally blocks |
| 5272 // between the branching point and the destination (so we don't need to |
| 5273 // do anything here). |
| 5274 // |
| 5275 // b) 4th case: Translating the body resulted in an open fragment (i.e. body |
| 5276 // executes without any control flow out of it) |
| 5277 // |
| 5278 // => We are responsible for jumping out of the body to a new block (with |
| 5279 // different try index) and execute the finalizer. |
| 5280 // |
| 5281 // c) 5th case: An exception occured inside the body. |
| 5282 // |
| 5283 // => We are responsible for catching it, executing the finally block and |
| 5284 // rethrowing the exception. |
| 5285 intptr_t try_handler_index = AllocateTryIndex(); |
| 5286 Fragment try_body = TryCatch(try_handler_index); |
| 5287 JoinEntryInstr* after_try = BuildJoinEntry(); |
| 5288 |
| 5289 // Fill in the body of the try. |
| 5290 ++try_depth_; |
| 5291 { |
| 5292 TryCatchBlock tcb(this, try_handler_index); |
| 5293 TryFinallyBlock tfb(this, node->finalizer()); |
| 5294 try_body += TranslateStatement(node->body()); |
| 5295 } |
| 5296 --try_depth_; |
| 5297 |
| 5298 if (try_body.is_open()) { |
| 5299 // Please note: The try index will be on level out of this block, |
| 5300 // thereby ensuring if there's an exception in the finally block we |
| 5301 // won't run it twice. |
| 5302 JoinEntryInstr* finally_entry = BuildJoinEntry(); |
| 5303 |
| 5304 try_body += Goto(finally_entry); |
| 5305 |
| 5306 Fragment finally_body(finally_entry); |
| 5307 finally_body += TranslateStatement(node->finalizer()); |
| 5308 finally_body += Goto(after_try); |
| 5309 } |
| 5310 |
| 5311 // Fill in the body of the catch. |
| 5312 ++catch_depth_; |
| 5313 const Array& handler_types = Array::ZoneHandle(Z, Array::New(1, Heap::kOld)); |
| 5314 handler_types.SetAt(0, Object::dynamic_type()); |
| 5315 Fragment finally_body = CatchBlockEntry(handler_types, try_handler_index); |
| 5316 finally_body += TranslateStatement(node->finalizer()); |
| 5317 if (finally_body.is_open()) { |
| 5318 finally_body += LoadLocal(CurrentException()); |
| 5319 finally_body += PushArgument(); |
| 5320 finally_body += LoadLocal(CurrentStackTrace()); |
| 5321 finally_body += PushArgument(); |
| 5322 finally_body += RethrowException(try_handler_index); |
| 5323 Drop(); |
| 5324 } |
| 5325 --catch_depth_; |
| 5326 |
| 5327 fragment_ = Fragment(try_body.entry, after_try); |
| 5328 } |
| 5329 |
| 5330 |
| 5331 void FlowGraphBuilder::VisitTryCatch(class TryCatch* node) { |
| 5332 InlineBailout("dil::FlowgraphBuilder::VisitTryCatch"); |
| 5333 |
| 5334 intptr_t try_handler_index = AllocateTryIndex(); |
| 5335 Fragment try_body = TryCatch(try_handler_index); |
| 5336 JoinEntryInstr* after_try = BuildJoinEntry(); |
| 5337 |
| 5338 // Fill in the body of the try. |
| 5339 ++try_depth_; |
| 5340 { |
| 5341 TryCatchBlock block(this, try_handler_index); |
| 5342 try_body += TranslateStatement(node->body()); |
| 5343 try_body += Goto(after_try); |
| 5344 } |
| 5345 --try_depth_; |
| 5346 |
| 5347 ++catch_depth_; |
| 5348 const Array& handler_types = |
| 5349 Array::ZoneHandle(Z, Array::New(node->catches().length(), Heap::kOld)); |
| 5350 Fragment catch_body = CatchBlockEntry(handler_types, try_handler_index); |
| 5351 // Fill in the body of the catch. |
| 5352 for (intptr_t i = 0; i < node->catches().length(); i++) { |
| 5353 Catch* catch_clause = node->catches()[i]; |
| 5354 |
| 5355 Fragment catch_handler_body; |
| 5356 |
| 5357 catch_handler_body += EnterScope(catch_clause); |
| 5358 |
| 5359 if (catch_clause->exception() != NULL) { |
| 5360 catch_handler_body += LoadLocal(CurrentException()); |
| 5361 catch_handler_body += |
| 5362 StoreLocal(LookupVariable(catch_clause->exception())); |
| 5363 catch_handler_body += Drop(); |
| 5364 } |
| 5365 if (catch_clause->stack_trace() != NULL) { |
| 5366 catch_handler_body += LoadLocal(CurrentStackTrace()); |
| 5367 catch_handler_body += |
| 5368 StoreLocal(LookupVariable(catch_clause->stack_trace())); |
| 5369 catch_handler_body += Drop(); |
| 5370 } |
| 5371 AbstractType* type_guard = NULL; |
| 5372 if (catch_clause->guard() != NULL && |
| 5373 !catch_clause->guard()->IsDynamicType()) { |
| 5374 type_guard = &T.TranslateType(catch_clause->guard()); |
| 5375 handler_types.SetAt(i, *type_guard); |
| 5376 } else { |
| 5377 handler_types.SetAt(i, Object::dynamic_type()); |
| 5378 } |
| 5379 |
| 5380 { |
| 5381 CatchBlock block(this, CurrentException(), CurrentStackTrace(), |
| 5382 try_handler_index); |
| 5383 |
| 5384 catch_handler_body += TranslateStatement(catch_clause->body()); |
| 5385 |
| 5386 // Note: ExitScope adjusts context_depth_ so even if catch_handler_body |
| 5387 // is closed we still need to execute ExitScope for its side effect. |
| 5388 catch_handler_body += ExitScope(catch_clause); |
| 5389 if (catch_handler_body.is_open()) { |
| 5390 catch_handler_body += Goto(after_try); |
| 5391 } |
| 5392 } |
| 5393 |
| 5394 if (type_guard != NULL) { |
| 5395 if (type_guard->IsMalformed()) { |
| 5396 catch_body += ThrowTypeError(); |
| 5397 catch_body += Drop(); |
| 5398 } else { |
| 5399 catch_body += LoadLocal(CurrentException()); |
| 5400 catch_body += PushArgument(); // exception |
| 5401 catch_body += NullConstant(); |
| 5402 catch_body += PushArgument(); // type arguments |
| 5403 catch_body += Constant(*type_guard); |
| 5404 catch_body += PushArgument(); // guard type |
| 5405 catch_body += Constant(Object::bool_false()); |
| 5406 catch_body += PushArgument(); // negate |
| 5407 catch_body += InstanceCall( |
| 5408 dart::Library::PrivateCoreLibName(Symbols::_instanceOf()), |
| 5409 Token::kIS, 4); |
| 5410 |
| 5411 TargetEntryInstr* catch_entry; |
| 5412 TargetEntryInstr* next_catch_entry; |
| 5413 catch_body += BranchIfTrue(&catch_entry, &next_catch_entry); |
| 5414 |
| 5415 Fragment(catch_entry) + catch_handler_body; |
| 5416 catch_body = Fragment(next_catch_entry); |
| 5417 } |
| 5418 } else { |
| 5419 catch_body += catch_handler_body; |
| 5420 } |
| 5421 } |
| 5422 |
| 5423 // In case the last catch body was not handling the exception and branching to |
| 5424 // after the try block, we will rethrow the exception (i.e. no default catch |
| 5425 // handler). |
| 5426 if (catch_body.is_open()) { |
| 5427 catch_body += LoadLocal(CurrentException()); |
| 5428 catch_body += PushArgument(); |
| 5429 catch_body += LoadLocal(CurrentStackTrace()); |
| 5430 catch_body += PushArgument(); |
| 5431 catch_body += RethrowException(try_handler_index); |
| 5432 Drop(); |
| 5433 } |
| 5434 --catch_depth_; |
| 5435 |
| 5436 fragment_ = Fragment(try_body.entry, after_try); |
| 5437 } |
| 5438 |
| 5439 |
| 5440 void FlowGraphBuilder::VisitYieldStatement(YieldStatement* node) { |
| 5441 ASSERT(node->is_native()); // Must have been desugared. |
| 5442 // Setup yield/continue point: |
| 5443 // |
| 5444 // ... |
| 5445 // :await_jump_var = index; |
| 5446 // :await_ctx_var = :current_context_var |
| 5447 // return <expr> |
| 5448 // |
| 5449 // Continuation<index>: |
| 5450 // Drop(1) |
| 5451 // ... |
| 5452 // |
| 5453 // BuildGraphOfFunction will create a dispatch that jumps to |
| 5454 // Continuation<:await_jump_var> upon entry to the function. |
| 5455 // |
| 5456 Fragment instructions = IntConstant(yield_continuations_.length() + 1); |
| 5457 instructions += StoreLocal(scopes_->yield_jump_variable); |
| 5458 instructions += Drop(); |
| 5459 instructions += LoadLocal(parsed_function_->current_context_var()); |
| 5460 instructions += StoreLocal(scopes_->yield_context_variable); |
| 5461 instructions += Drop(); |
| 5462 instructions += TranslateExpression(node->expression()); |
| 5463 instructions += Return(); |
| 5464 |
| 5465 // Note: DropTempsInstr serves as an anchor instruction. It will not |
| 5466 // be linked into the resulting graph. |
| 5467 DropTempsInstr* anchor = new (Z) DropTempsInstr(0, NULL); |
| 5468 yield_continuations_.Add(YieldContinuation(anchor, CurrentTryIndex())); |
| 5469 |
| 5470 Fragment continuation(instructions.entry, anchor); |
| 5471 |
| 5472 // TODO(vegorov): we need a better way to detect if we need to check for an |
| 5473 // exception after yield or not. |
| 5474 if (parsed_function_->function().NumOptionalPositionalParameters() == 3) { |
| 5475 // If function takes three parameters then the second and the third |
| 5476 // are exception and stack_trace. Check if exception is non-null |
| 5477 // and rethrow it. |
| 5478 // |
| 5479 // :async_op([:result, :exception, :stack_trace]) { |
| 5480 // ... |
| 5481 // Continuation<index>: |
| 5482 // if (:exception != null) rethrow(:exception, :stack_trace); |
| 5483 // ... |
| 5484 // } |
| 5485 // |
| 5486 LocalScope* scope = parsed_function_->node_sequence()->scope(); |
| 5487 LocalVariable* exception_var = scope->VariableAt(2); |
| 5488 LocalVariable* stack_trace_var = scope->VariableAt(3); |
| 5489 ASSERT(exception_var->name().raw() == Symbols::ExceptionParameter().raw()); |
| 5490 ASSERT(stack_trace_var->name().raw() == |
| 5491 Symbols::StackTraceParameter().raw()); |
| 5492 |
| 5493 TargetEntryInstr* no_error; |
| 5494 TargetEntryInstr* error; |
| 5495 |
| 5496 continuation += LoadLocal(exception_var); |
| 5497 continuation += BranchIfNull(&no_error, &error); |
| 5498 |
| 5499 Fragment rethrow(error); |
| 5500 rethrow += LoadLocal(exception_var); |
| 5501 rethrow += PushArgument(); |
| 5502 rethrow += LoadLocal(stack_trace_var); |
| 5503 rethrow += PushArgument(); |
| 5504 rethrow += RethrowException(CatchClauseNode::kInvalidTryIndex); |
| 5505 Drop(); |
| 5506 |
| 5507 |
| 5508 continuation = Fragment(continuation.entry, no_error); |
| 5509 } |
| 5510 |
| 5511 fragment_ = continuation; |
| 5512 } |
| 5513 |
| 5514 |
| 5515 Fragment FlowGraphBuilder::TranslateFunctionNode(FunctionNode* node, |
| 5516 TreeNode* parent) { |
| 5517 // The VM has a per-isolate table of functions indexed by the enclosing |
| 5518 // function and token position. We don't have token positions, so we've |
| 5519 // simply numbered the immediately-nested functions with respect to the |
| 5520 // parent. |
| 5521 Function& function = Function::ZoneHandle(Z); |
| 5522 for (intptr_t i = 0; i < scopes_->function_scopes.length(); ++i) { |
| 5523 if (scopes_->function_scopes[i].function != node) continue; |
| 5524 |
| 5525 function = I->LookupClosureFunction(parsed_function_->function(), |
| 5526 TokenPosition(i)); |
| 5527 if (function.IsNull()) { |
| 5528 const dart::String* name; |
| 5529 if (parent->IsFunctionExpression()) { |
| 5530 name = &Symbols::AnonymousClosure(); |
| 5531 } else { |
| 5532 ASSERT(parent->IsFunctionDeclaration()); |
| 5533 name = &H.DartSymbol( |
| 5534 FunctionDeclaration::Cast(parent)->variable()->name()); |
| 5535 } |
| 5536 function = Function::NewClosureFunction( |
| 5537 *name, parsed_function_->function(), TokenPosition(i)); |
| 5538 function.set_is_debuggable(false); |
| 5539 LocalScope* scope = scopes_->function_scopes[i].scope; |
| 5540 const ContextScope& context_scope = |
| 5541 ContextScope::Handle(Z, scope->PreserveOuterScope(context_depth_)); |
| 5542 function.set_context_scope(context_scope); |
| 5543 function.set_dil_function(reinterpret_cast<intptr_t>(node)); |
| 5544 DilReader::SetupFunctionParameters(H, T, dart::Class::Handle(Z), function, |
| 5545 node, |
| 5546 false, // is_method |
| 5547 true); // is_closure |
| 5548 // Finalize function type. |
| 5549 Type& signature_type = Type::Handle(Z, function.SignatureType()); |
| 5550 signature_type ^= ClassFinalizer::FinalizeType( |
| 5551 *active_class_.klass, signature_type, ClassFinalizer::kCanonicalize); |
| 5552 function.SetSignatureType(signature_type); |
| 5553 |
| 5554 I->AddClosureFunction(function); |
| 5555 } |
| 5556 break; |
| 5557 } |
| 5558 |
| 5559 const dart::Class& closure_class = |
| 5560 dart::Class::ZoneHandle(Z, I->object_store()->closure_class()); |
| 5561 ASSERT(!closure_class.IsNull()); |
| 5562 Fragment instructions = AllocateObject(closure_class, function); |
| 5563 LocalVariable* closure = MakeTemporary(); |
| 5564 |
| 5565 // TODO(kmillikin): Generic closures need type arguments. |
| 5566 |
| 5567 // Store the function and the context in the closure. |
| 5568 instructions += LoadLocal(closure); |
| 5569 instructions += Constant(function); |
| 5570 instructions += StoreInstanceField(Closure::function_offset()); |
| 5571 |
| 5572 instructions += LoadLocal(closure); |
| 5573 instructions += LoadLocal(parsed_function_->current_context_var()); |
| 5574 instructions += StoreInstanceField(Closure::context_offset()); |
| 5575 |
| 5576 return instructions; |
| 5577 } |
| 5578 |
| 5579 |
| 5580 } // namespace dil |
| 5581 } // namespace dart |
OLD | NEW |