| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "src/compiler/ast-graph-builder.h" |
| 6 |
| 7 #include "src/compiler.h" |
| 8 #include "src/compiler/control-builders.h" |
| 9 #include "src/compiler/node-properties.h" |
| 10 #include "src/compiler/node-properties-inl.h" |
| 11 #include "src/full-codegen.h" |
| 12 #include "src/parser.h" |
| 13 #include "src/scopes.h" |
| 14 |
| 15 namespace v8 { |
| 16 namespace internal { |
| 17 namespace compiler { |
| 18 |
| 19 AstGraphBuilder::AstGraphBuilder(CompilationInfo* info, JSGraph* jsgraph, |
| 20 SourcePositionTable* source_positions) |
| 21 : StructuredGraphBuilder(jsgraph->graph(), jsgraph->common()), |
| 22 info_(info), |
| 23 jsgraph_(jsgraph), |
| 24 source_positions_(source_positions), |
| 25 globals_(0, info->zone()), |
| 26 breakable_(NULL), |
| 27 execution_context_(NULL) { |
| 28 InitializeAstVisitor(info->zone()); |
| 29 } |
| 30 |
| 31 |
| 32 Node* AstGraphBuilder::GetFunctionClosure() { |
| 33 if (!function_closure_.is_set()) { |
| 34 // Parameter -1 is special for the function closure |
| 35 Operator* op = common()->Parameter(-1); |
| 36 Node* node = NewNode(op); |
| 37 function_closure_.set(node); |
| 38 } |
| 39 return function_closure_.get(); |
| 40 } |
| 41 |
| 42 |
| 43 Node* AstGraphBuilder::GetFunctionContext() { |
| 44 if (!function_context_.is_set()) { |
| 45 // Parameter (arity + 1) is special for the outer context of the function |
| 46 Operator* op = common()->Parameter(info()->num_parameters() + 1); |
| 47 Node* node = NewNode(op); |
| 48 function_context_.set(node); |
| 49 } |
| 50 return function_context_.get(); |
| 51 } |
| 52 |
| 53 |
| 54 bool AstGraphBuilder::CreateGraph() { |
| 55 Scope* scope = info()->scope(); |
| 56 ASSERT(graph() != NULL); |
| 57 |
| 58 SourcePositionTable::Scope start_pos( |
| 59 source_positions(), |
| 60 SourcePosition(info()->shared_info()->start_position())); |
| 61 |
| 62 // Set up the basic structure of the graph. |
| 63 graph()->SetStart(graph()->NewNode(common()->Start())); |
| 64 |
| 65 // Initialize the top-level environment. |
| 66 Environment env(this, scope, graph()->start()); |
| 67 set_environment(&env); |
| 68 |
| 69 // Build node to initialize local function context. |
| 70 Node* closure = GetFunctionClosure(); |
| 71 Node* outer = GetFunctionContext(); |
| 72 Node* inner = BuildLocalFunctionContext(outer, closure); |
| 73 |
| 74 // Push top-level function scope for the function body. |
| 75 ContextScope top_context(this, scope, inner); |
| 76 |
| 77 // Build the arguments object if it is used. |
| 78 BuildArgumentsObject(scope->arguments()); |
| 79 |
| 80 // Emit tracing call if requested to do so. |
| 81 if (FLAG_trace) { |
| 82 NewNode(javascript()->Runtime(Runtime::kTraceEnter, 0)); |
| 83 } |
| 84 |
| 85 // Visit implicit declaration of the function name. |
| 86 if (scope->is_function_scope() && scope->function() != NULL) { |
| 87 VisitVariableDeclaration(scope->function()); |
| 88 } |
| 89 |
| 90 // Visit declarations within the function scope. |
| 91 VisitDeclarations(scope->declarations()); |
| 92 |
| 93 // TODO(mstarzinger): This should do an inlined stack check. |
| 94 NewNode(javascript()->Runtime(Runtime::kStackGuard, 0)); |
| 95 |
| 96 // Visit statements in the function body. |
| 97 VisitStatements(info()->function()->body()); |
| 98 if (HasStackOverflow()) return false; |
| 99 |
| 100 SourcePositionTable::Scope end_pos( |
| 101 source_positions(), |
| 102 SourcePosition(info()->shared_info()->end_position() - 1)); |
| 103 |
| 104 // Emit tracing call if requested to do so. |
| 105 if (FLAG_trace) { |
| 106 // TODO(mstarzinger): Only traces implicit return. |
| 107 Node* return_value = jsgraph()->UndefinedConstant(); |
| 108 NewNode(javascript()->Runtime(Runtime::kTraceExit, 1), return_value); |
| 109 } |
| 110 |
| 111 // Return 'undefined' in case we can fall off the end. |
| 112 Node* control = NewNode(common()->Return(), jsgraph()->UndefinedConstant()); |
| 113 UpdateControlDependencyToLeaveFunction(control); |
| 114 |
| 115 // Finish the basic structure of the graph. |
| 116 environment()->UpdateControlDependency(exit_control()); |
| 117 graph()->SetEnd(NewNode(common()->End())); |
| 118 |
| 119 return true; |
| 120 } |
| 121 |
| 122 |
| 123 // Left-hand side can only be a property, a global or a variable slot. |
| 124 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 125 |
| 126 |
| 127 // Determine the left-hand side kind of an assignment. |
| 128 static LhsKind DetermineLhsKind(Expression* expr) { |
| 129 Property* property = expr->AsProperty(); |
| 130 ASSERT(expr->IsValidReferenceExpression()); |
| 131 LhsKind lhs_kind = |
| 132 (property == NULL) ? VARIABLE : |
| 133 (property->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
| 134 return lhs_kind; |
| 135 } |
| 136 |
| 137 |
| 138 // Helper to find an existing shared function info in the baseline code for the |
| 139 // given function literal. Used to canonicalize SharedFunctionInfo objects. |
| 140 static Handle<SharedFunctionInfo> SearchSharedFunctionInfo( |
| 141 Code* unoptimized_code, FunctionLiteral* expr) { |
| 142 int start_position = expr->start_position(); |
| 143 for (RelocIterator it(unoptimized_code); !it.done(); it.next()) { |
| 144 RelocInfo* rinfo = it.rinfo(); |
| 145 if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue; |
| 146 Object* obj = rinfo->target_object(); |
| 147 if (obj->IsSharedFunctionInfo()) { |
| 148 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); |
| 149 if (shared->start_position() == start_position) { |
| 150 return Handle<SharedFunctionInfo>(shared); |
| 151 } |
| 152 } |
| 153 } |
| 154 return Handle<SharedFunctionInfo>(); |
| 155 } |
| 156 |
| 157 |
| 158 StructuredGraphBuilder::Environment* AstGraphBuilder::CopyEnvironment( |
| 159 StructuredGraphBuilder::Environment* env) { |
| 160 return new(zone()) Environment(*reinterpret_cast<Environment*>(env)); |
| 161 } |
| 162 |
| 163 |
| 164 AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder, |
| 165 Scope* scope, |
| 166 Node* control_dependency) |
| 167 : StructuredGraphBuilder::Environment(builder, control_dependency), |
| 168 parameters_count_(scope->num_parameters() + 1), |
| 169 locals_count_(scope->num_stack_slots()), |
| 170 parameters_node_(NULL), |
| 171 locals_node_(NULL), |
| 172 stack_node_(NULL), |
| 173 parameters_dirty_(false), |
| 174 locals_dirty_(false), |
| 175 stack_dirty_(false) { |
| 176 ASSERT_EQ(scope->num_parameters() + 1, parameters_count()); |
| 177 |
| 178 // Bind the receiver variable. |
| 179 values()->insert( |
| 180 values()->end(), parameters_count(), static_cast<Node*>(NULL)); |
| 181 Node* receiver = builder->graph()->NewNode(common()->Parameter(0)); |
| 182 Bind(scope->receiver(), receiver); |
| 183 |
| 184 // Bind all parameter variables. The parameter indices are shifted by 1 |
| 185 // (receiver is parameter index -1 but environment index 0). |
| 186 for (int i = 0; i < scope->num_parameters(); ++i) { |
| 187 // Unused parameters are allocated to Variable::UNALLOCATED. |
| 188 if (!scope->parameter(i)->IsParameter()) continue; |
| 189 Node* parameter = builder->graph()->NewNode(common()->Parameter(i + 1)); |
| 190 Bind(scope->parameter(i), parameter); |
| 191 } |
| 192 |
| 193 // Bind all local variables to undefined. |
| 194 Node* undefined_constant = builder->jsgraph()->UndefinedConstant(); |
| 195 values()->insert(values()->end(), locals_count(), undefined_constant); |
| 196 } |
| 197 |
| 198 |
| 199 AstGraphBuilder::Environment::Environment(const Environment& copy) |
| 200 : StructuredGraphBuilder::Environment( |
| 201 static_cast<StructuredGraphBuilder::Environment>(copy)), |
| 202 parameters_count_(copy.parameters_count_), |
| 203 locals_count_(copy.locals_count_), |
| 204 parameters_node_(copy.parameters_node_), |
| 205 locals_node_(copy.locals_node_), |
| 206 stack_node_(copy.stack_node_), |
| 207 parameters_dirty_(copy.parameters_dirty_), |
| 208 locals_dirty_(copy.locals_dirty_), |
| 209 stack_dirty_(copy.stack_dirty_) {} |
| 210 |
| 211 |
| 212 Node* AstGraphBuilder::Environment::Checkpoint(BailoutId ast_id) { |
| 213 UNIMPLEMENTED(); // TODO(mstarzinger): Implementation below is incomplete. |
| 214 if (parameters_dirty_) { |
| 215 Node** parameters = &values()->front(); |
| 216 parameters_node_ = graph()->NewNode(NULL, parameters_count(), parameters); |
| 217 parameters_dirty_ = false; |
| 218 } |
| 219 if (locals_dirty_) { |
| 220 Node** locals = &values()->at(parameters_count_); |
| 221 locals_node_ = graph()->NewNode(NULL, locals_count(), locals); |
| 222 locals_dirty_ = false; |
| 223 } |
| 224 FrameStateDescriptor descriptor(ast_id); |
| 225 // TODO(jarin): add environment to the node. |
| 226 Operator* op = common()->FrameState(descriptor); |
| 227 |
| 228 return graph()->NewNode(op); |
| 229 } |
| 230 |
| 231 |
| 232 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own, |
| 233 Expression::Context kind) |
| 234 : kind_(kind), owner_(own), outer_(own->ast_context()) { |
| 235 owner()->set_ast_context(this); // Push. |
| 236 #ifdef DEBUG |
| 237 original_height_ = environment()->stack_height(); |
| 238 #endif |
| 239 } |
| 240 |
| 241 |
| 242 AstGraphBuilder::AstContext::~AstContext() { |
| 243 owner()->set_ast_context(outer_); // Pop. |
| 244 } |
| 245 |
| 246 |
| 247 AstGraphBuilder::AstEffectContext::~AstEffectContext() { |
| 248 ASSERT(environment()->stack_height() == original_height_); |
| 249 } |
| 250 |
| 251 |
| 252 AstGraphBuilder::AstValueContext::~AstValueContext() { |
| 253 ASSERT(environment()->stack_height() == original_height_ + 1); |
| 254 } |
| 255 |
| 256 |
| 257 AstGraphBuilder::AstTestContext::~AstTestContext() { |
| 258 ASSERT(environment()->stack_height() == original_height_ + 1); |
| 259 } |
| 260 |
| 261 |
| 262 void AstGraphBuilder::AstEffectContext::ProduceValue(Node* value) { |
| 263 // The value is ignored. |
| 264 } |
| 265 |
| 266 |
| 267 void AstGraphBuilder::AstValueContext::ProduceValue(Node* value) { |
| 268 environment()->Push(value); |
| 269 } |
| 270 |
| 271 |
| 272 void AstGraphBuilder::AstTestContext::ProduceValue(Node* value) { |
| 273 environment()->Push(owner()->BuildToBoolean(value)); |
| 274 } |
| 275 |
| 276 |
| 277 Node* AstGraphBuilder::AstEffectContext::ConsumeValue() { |
| 278 return NULL; |
| 279 } |
| 280 |
| 281 |
| 282 Node* AstGraphBuilder::AstValueContext::ConsumeValue() { |
| 283 return environment()->Pop(); |
| 284 } |
| 285 |
| 286 |
| 287 Node* AstGraphBuilder::AstTestContext::ConsumeValue() { |
| 288 return environment()->Pop(); |
| 289 } |
| 290 |
| 291 |
| 292 AstGraphBuilder::BreakableScope* |
| 293 AstGraphBuilder::BreakableScope::FindBreakable(BreakableStatement* target) { |
| 294 BreakableScope* current = this; |
| 295 while (current != NULL && current->target_ != target) { |
| 296 owner_->environment()->Drop(current->drop_extra_); |
| 297 current = current->next_; |
| 298 } |
| 299 ASSERT(current != NULL); // Always found (unless stack is malformed). |
| 300 return current; |
| 301 } |
| 302 |
| 303 |
| 304 void AstGraphBuilder::BreakableScope::BreakTarget(BreakableStatement* stmt) { |
| 305 FindBreakable(stmt)->control_->Break(); |
| 306 } |
| 307 |
| 308 |
| 309 void AstGraphBuilder::BreakableScope::ContinueTarget(BreakableStatement* stmt) { |
| 310 FindBreakable(stmt)->control_->Continue(); |
| 311 } |
| 312 |
| 313 |
| 314 void AstGraphBuilder::VisitForValueOrNull(Expression* expr) { |
| 315 if (expr == NULL) { |
| 316 return environment()->Push(jsgraph()->NullConstant()); |
| 317 } |
| 318 VisitForValue(expr); |
| 319 } |
| 320 |
| 321 |
| 322 void AstGraphBuilder::VisitForValues(ZoneList<Expression*>* exprs) { |
| 323 for (int i = 0; i < exprs->length(); ++i) { |
| 324 VisitForValue(exprs->at(i)); |
| 325 } |
| 326 } |
| 327 |
| 328 |
| 329 void AstGraphBuilder::VisitForValue(Expression* expr) { |
| 330 AstValueContext for_value(this); |
| 331 if (!HasStackOverflow()) { |
| 332 expr->Accept(this); |
| 333 } |
| 334 } |
| 335 |
| 336 |
| 337 void AstGraphBuilder::VisitForEffect(Expression* expr) { |
| 338 AstEffectContext for_effect(this); |
| 339 if (!HasStackOverflow()) { |
| 340 expr->Accept(this); |
| 341 } |
| 342 } |
| 343 |
| 344 |
| 345 void AstGraphBuilder::VisitForTest(Expression* expr) { |
| 346 AstTestContext for_condition(this); |
| 347 if (!HasStackOverflow()) { |
| 348 expr->Accept(this); |
| 349 } |
| 350 } |
| 351 |
| 352 |
| 353 void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) { |
| 354 Variable* variable = decl->proxy()->var(); |
| 355 VariableMode mode = decl->mode(); |
| 356 bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET; |
| 357 switch (variable->location()) { |
| 358 case Variable::UNALLOCATED: { |
| 359 Handle<Oddball> value = variable->binding_needs_init() |
| 360 ? isolate()->factory()->the_hole_value() |
| 361 : isolate()->factory()->undefined_value(); |
| 362 globals()->Add(variable->name(), zone()); |
| 363 globals()->Add(value, zone()); |
| 364 break; |
| 365 } |
| 366 case Variable::PARAMETER: |
| 367 case Variable::LOCAL: |
| 368 if (hole_init) { |
| 369 Node* value = jsgraph()->TheHoleConstant(); |
| 370 environment()->Bind(variable, value); |
| 371 } |
| 372 break; |
| 373 case Variable::CONTEXT: |
| 374 if (hole_init) { |
| 375 Node* value = jsgraph()->TheHoleConstant(); |
| 376 Operator* op = javascript()->StoreContext(0, variable->index()); |
| 377 NewNode(op, current_context(), value); |
| 378 } |
| 379 break; |
| 380 case Variable::LOOKUP: |
| 381 UNIMPLEMENTED(); |
| 382 } |
| 383 } |
| 384 |
| 385 |
| 386 void AstGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) { |
| 387 Variable* variable = decl->proxy()->var(); |
| 388 switch (variable->location()) { |
| 389 case Variable::UNALLOCATED: { |
| 390 Handle<SharedFunctionInfo> function = |
| 391 Compiler::BuildFunctionInfo(decl->fun(), info()->script()); |
| 392 // Check for stack-overflow exception. |
| 393 if (function.is_null()) return SetStackOverflow(); |
| 394 globals()->Add(variable->name(), zone()); |
| 395 globals()->Add(function, zone()); |
| 396 break; |
| 397 } |
| 398 case Variable::PARAMETER: |
| 399 case Variable::LOCAL: { |
| 400 VisitForValue(decl->fun()); |
| 401 Node* value = environment()->Pop(); |
| 402 environment()->Bind(variable, value); |
| 403 break; |
| 404 } |
| 405 case Variable::CONTEXT: { |
| 406 VisitForValue(decl->fun()); |
| 407 Node* value = environment()->Pop(); |
| 408 Operator* op = javascript()->StoreContext(0, variable->index()); |
| 409 NewNode(op, current_context(), value); |
| 410 break; |
| 411 } |
| 412 case Variable::LOOKUP: |
| 413 UNIMPLEMENTED(); |
| 414 } |
| 415 } |
| 416 |
| 417 |
| 418 void AstGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* decl) { |
| 419 UNREACHABLE(); |
| 420 } |
| 421 |
| 422 |
| 423 void AstGraphBuilder::VisitImportDeclaration(ImportDeclaration* decl) { |
| 424 UNREACHABLE(); |
| 425 } |
| 426 |
| 427 |
| 428 void AstGraphBuilder::VisitExportDeclaration(ExportDeclaration* decl) { |
| 429 UNREACHABLE(); |
| 430 } |
| 431 |
| 432 |
| 433 void AstGraphBuilder::VisitModuleLiteral(ModuleLiteral* modl) { |
| 434 UNREACHABLE(); |
| 435 } |
| 436 |
| 437 |
| 438 void AstGraphBuilder::VisitModuleVariable(ModuleVariable* modl) { |
| 439 UNREACHABLE(); |
| 440 } |
| 441 |
| 442 |
| 443 void AstGraphBuilder::VisitModulePath(ModulePath* modl) { |
| 444 UNREACHABLE(); |
| 445 } |
| 446 |
| 447 |
| 448 void AstGraphBuilder::VisitModuleUrl(ModuleUrl* modl) { |
| 449 UNREACHABLE(); |
| 450 } |
| 451 |
| 452 |
| 453 void AstGraphBuilder::VisitBlock(Block* stmt) { |
| 454 BlockBuilder block(this); |
| 455 BreakableScope scope(this, stmt, &block, 0); |
| 456 if (stmt->labels() != NULL) block.BeginBlock(); |
| 457 if (stmt->scope() == NULL) { |
| 458 // Visit statements in the same scope, no declarations. |
| 459 VisitStatements(stmt->statements()); |
| 460 } else { |
| 461 Operator* op = javascript()->CreateBlockContext(); |
| 462 Node* scope_info = jsgraph()->Constant(stmt->scope()->GetScopeInfo()); |
| 463 Node* context = NewNode(op, scope_info, GetFunctionClosure()); |
| 464 ContextScope scope(this, stmt->scope(), context); |
| 465 |
| 466 // Visit declarations and statements in a block scope. |
| 467 VisitDeclarations(stmt->scope()->declarations()); |
| 468 VisitStatements(stmt->statements()); |
| 469 } |
| 470 if (stmt->labels() != NULL) block.EndBlock(); |
| 471 } |
| 472 |
| 473 |
| 474 void AstGraphBuilder::VisitModuleStatement(ModuleStatement* stmt) { |
| 475 UNREACHABLE(); |
| 476 } |
| 477 |
| 478 |
| 479 void AstGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { |
| 480 VisitForEffect(stmt->expression()); |
| 481 } |
| 482 |
| 483 |
| 484 void AstGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { |
| 485 // Do nothing. |
| 486 } |
| 487 |
| 488 |
| 489 void AstGraphBuilder::VisitIfStatement(IfStatement* stmt) { |
| 490 IfBuilder compare_if(this); |
| 491 VisitForTest(stmt->condition()); |
| 492 Node* condition = environment()->Pop(); |
| 493 compare_if.If(condition); |
| 494 compare_if.Then(); |
| 495 Visit(stmt->then_statement()); |
| 496 compare_if.Else(); |
| 497 Visit(stmt->else_statement()); |
| 498 compare_if.End(); |
| 499 } |
| 500 |
| 501 |
| 502 void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { |
| 503 StructuredGraphBuilder::Environment* env = environment()->CopyAsUnreachable(); |
| 504 breakable()->ContinueTarget(stmt->target()); |
| 505 set_environment(env); |
| 506 } |
| 507 |
| 508 |
| 509 void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { |
| 510 StructuredGraphBuilder::Environment* env = environment()->CopyAsUnreachable(); |
| 511 breakable()->BreakTarget(stmt->target()); |
| 512 set_environment(env); |
| 513 } |
| 514 |
| 515 |
| 516 void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
| 517 VisitForValue(stmt->expression()); |
| 518 Node* result = environment()->Pop(); |
| 519 Node* control = NewNode(common()->Return(), result); |
| 520 UpdateControlDependencyToLeaveFunction(control); |
| 521 } |
| 522 |
| 523 |
| 524 void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) { |
| 525 VisitForValue(stmt->expression()); |
| 526 Node* value = environment()->Pop(); |
| 527 Operator* op = javascript()->CreateWithContext(); |
| 528 Node* context = NewNode(op, value, GetFunctionClosure()); |
| 529 ContextScope scope(this, stmt->scope(), context); |
| 530 Visit(stmt->statement()); |
| 531 } |
| 532 |
| 533 |
| 534 void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| 535 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 536 SwitchBuilder compare_switch(this, clauses->length()); |
| 537 BreakableScope scope(this, stmt, &compare_switch, 0); |
| 538 compare_switch.BeginSwitch(); |
| 539 int default_index = -1; |
| 540 |
| 541 // Keep the switch value on the stack until a case matches. |
| 542 VisitForValue(stmt->tag()); |
| 543 Node* tag = environment()->Top(); |
| 544 |
| 545 // Iterate over all cases and create nodes for label comparison. |
| 546 for (int i = 0; i < clauses->length(); i++) { |
| 547 CaseClause* clause = clauses->at(i); |
| 548 |
| 549 // The default is not a test, remember index. |
| 550 if (clause->is_default()) { |
| 551 default_index = i; |
| 552 continue; |
| 553 } |
| 554 |
| 555 // Create nodes to perform label comparison as if via '==='. The switch |
| 556 // value is still on the operand stack while the label is evaluated. |
| 557 VisitForValue(clause->label()); |
| 558 Node* label = environment()->Pop(); |
| 559 Operator* op = javascript()->StrictEqual(); |
| 560 Node* condition = NewNode(op, tag, label); |
| 561 compare_switch.BeginLabel(i, condition); |
| 562 |
| 563 // Discard the switch value at label match. |
| 564 environment()->Pop(); |
| 565 compare_switch.EndLabel(); |
| 566 } |
| 567 |
| 568 // Discard the switch value and mark the default case. |
| 569 environment()->Pop(); |
| 570 if (default_index >= 0) { |
| 571 compare_switch.DefaultAt(default_index); |
| 572 } |
| 573 |
| 574 // Iterate over all cases and create nodes for case bodies. |
| 575 for (int i = 0; i < clauses->length(); i++) { |
| 576 CaseClause* clause = clauses->at(i); |
| 577 compare_switch.BeginCase(i); |
| 578 VisitStatements(clause->statements()); |
| 579 compare_switch.EndCase(); |
| 580 } |
| 581 |
| 582 compare_switch.EndSwitch(); |
| 583 } |
| 584 |
| 585 |
| 586 void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| 587 LoopBuilder while_loop(this); |
| 588 while_loop.BeginLoop(); |
| 589 VisitIterationBody(stmt, &while_loop, 0); |
| 590 while_loop.EndBody(); |
| 591 VisitForTest(stmt->cond()); |
| 592 Node* condition = environment()->Pop(); |
| 593 while_loop.BreakUnless(condition); |
| 594 while_loop.EndLoop(); |
| 595 } |
| 596 |
| 597 |
| 598 void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { |
| 599 LoopBuilder while_loop(this); |
| 600 while_loop.BeginLoop(); |
| 601 VisitForTest(stmt->cond()); |
| 602 Node* condition = environment()->Pop(); |
| 603 while_loop.BreakUnless(condition); |
| 604 VisitIterationBody(stmt, &while_loop, 0); |
| 605 while_loop.EndBody(); |
| 606 while_loop.EndLoop(); |
| 607 } |
| 608 |
| 609 |
| 610 void AstGraphBuilder::VisitForStatement(ForStatement* stmt) { |
| 611 LoopBuilder for_loop(this); |
| 612 VisitIfNotNull(stmt->init()); |
| 613 for_loop.BeginLoop(); |
| 614 if (stmt->cond() != NULL) { |
| 615 VisitForTest(stmt->cond()); |
| 616 Node* condition = environment()->Pop(); |
| 617 for_loop.BreakUnless(condition); |
| 618 } |
| 619 VisitIterationBody(stmt, &for_loop, 0); |
| 620 for_loop.EndBody(); |
| 621 VisitIfNotNull(stmt->next()); |
| 622 for_loop.EndLoop(); |
| 623 } |
| 624 |
| 625 |
| 626 // TODO(dcarney): this is a big function. Try to clean up some. |
| 627 void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
| 628 VisitForValue(stmt->subject()); |
| 629 Node* obj = environment()->Pop(); |
| 630 // Check for undefined or null before entering loop. |
| 631 IfBuilder is_undefined(this); |
| 632 Node* is_undefined_cond = |
| 633 NewNode(javascript()->StrictEqual(), obj, jsgraph()->UndefinedConstant()); |
| 634 is_undefined.If(is_undefined_cond); |
| 635 is_undefined.Then(); |
| 636 is_undefined.Else(); |
| 637 { |
| 638 IfBuilder is_null(this); |
| 639 Node* is_null_cond = |
| 640 NewNode(javascript()->StrictEqual(), obj, jsgraph()->NullConstant()); |
| 641 is_null.If(is_null_cond); |
| 642 is_null.Then(); |
| 643 is_null.Else(); |
| 644 // Convert object to jsobject. |
| 645 // PrepareForBailoutForId(stmt->PrepareId(), TOS_REG); |
| 646 obj = NewNode(javascript()->ToObject(), obj); |
| 647 environment()->Push(obj); |
| 648 // TODO(dcarney): should do a fast enum cache check here to skip runtime. |
| 649 environment()->Push(obj); |
| 650 Node* cache_type = ProcessArguments( |
| 651 javascript()->Runtime(Runtime::kGetPropertyNamesFast, 1), 1); |
| 652 // TODO(dcarney): these next runtime calls should be removed in favour of |
| 653 // a few simplified instructions. |
| 654 environment()->Push(obj); |
| 655 environment()->Push(cache_type); |
| 656 Node* cache_pair = ProcessArguments( |
| 657 javascript()->Runtime(Runtime::kForInInit, 2), 2); |
| 658 // cache_type may have been replaced. |
| 659 Node* cache_array = NewNode(common()->Projection(0), cache_pair); |
| 660 cache_type = NewNode(common()->Projection(1), cache_pair); |
| 661 environment()->Push(cache_type); |
| 662 environment()->Push(cache_array); |
| 663 Node* cache_length = ProcessArguments( |
| 664 javascript()->Runtime(Runtime::kForInCacheArrayLength, 2), 2); |
| 665 { |
| 666 // TODO(dcarney): this check is actually supposed to be for the |
| 667 // empty enum case only. |
| 668 IfBuilder have_no_properties(this); |
| 669 Node* empty_array_cond = NewNode(javascript()->StrictEqual(), |
| 670 cache_length, jsgraph()->ZeroConstant()); |
| 671 have_no_properties.If(empty_array_cond); |
| 672 have_no_properties.Then(); |
| 673 // Pop obj and skip loop. |
| 674 environment()->Pop(); |
| 675 have_no_properties.Else(); |
| 676 { |
| 677 // Construct the rest of the environment. |
| 678 environment()->Push(cache_type); |
| 679 environment()->Push(cache_array); |
| 680 environment()->Push(cache_length); |
| 681 environment()->Push(jsgraph()->ZeroConstant()); |
| 682 // PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); |
| 683 LoopBuilder for_loop(this); |
| 684 for_loop.BeginLoop(); |
| 685 // Check loop termination condition. |
| 686 Node* index = environment()->Peek(0); |
| 687 Node* exit_cond = |
| 688 NewNode(javascript()->LessThan(), index, cache_length); |
| 689 for_loop.BreakUnless(exit_cond); |
| 690 // TODO(dcarney): this runtime call should be a handful of |
| 691 // simplified instructions that |
| 692 // basically produce |
| 693 // value = array[index] |
| 694 environment()->Push(obj); |
| 695 environment()->Push(cache_array); |
| 696 environment()->Push(cache_type); |
| 697 environment()->Push(index); |
| 698 Node* pair = ProcessArguments( |
| 699 javascript()->Runtime(Runtime::kForInNext, 4), 4); |
| 700 Node* value = NewNode(common()->Projection(0), pair); |
| 701 Node* should_filter = NewNode(common()->Projection(1), pair); |
| 702 environment()->Push(value); |
| 703 { |
| 704 // Test if FILTER_KEY needs to be called. |
| 705 IfBuilder test_should_filter(this); |
| 706 Node* should_filter_cond = |
| 707 NewNode(javascript()->StrictEqual(), should_filter, |
| 708 jsgraph()->TrueConstant()); |
| 709 test_should_filter.If(should_filter_cond); |
| 710 test_should_filter.Then(); |
| 711 value = environment()->Pop(); |
| 712 // TODO(dcarney): Better load from function context. |
| 713 // See comment in BuildLoadBuiltinsObject. |
| 714 Handle<JSFunction> function(JSFunction::cast( |
| 715 info()->context()->builtins()->javascript_builtin( |
| 716 Builtins::FILTER_KEY))); |
| 717 // Callee. |
| 718 environment()->Push(jsgraph()->HeapConstant(function)); |
| 719 // Receiver. |
| 720 environment()->Push(obj); |
| 721 // Args. |
| 722 environment()->Push(value); |
| 723 // result is either the string key or Smi(0) indicating the property |
| 724 // is gone. |
| 725 Node* res = ProcessArguments( |
| 726 javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), 3); |
| 727 Node* property_missing = NewNode(javascript()->StrictEqual(), res, |
| 728 jsgraph()->ZeroConstant()); |
| 729 { |
| 730 IfBuilder is_property_missing(this); |
| 731 is_property_missing.If(property_missing); |
| 732 is_property_missing.Then(); |
| 733 // Inc counter and continue. |
| 734 Node* index_inc = |
| 735 NewNode(javascript()->Add(), index, jsgraph()->OneConstant()); |
| 736 environment()->Poke(0, index_inc); |
| 737 for_loop.Continue(); |
| 738 is_property_missing.Else(); |
| 739 is_property_missing.End(); |
| 740 } |
| 741 // Replace 'value' in environment. |
| 742 environment()->Push(res); |
| 743 test_should_filter.Else(); |
| 744 test_should_filter.End(); |
| 745 } |
| 746 value = environment()->Pop(); |
| 747 // Bind value and do loop body. |
| 748 VisitForInAssignment(stmt->each(), value); |
| 749 VisitIterationBody(stmt, &for_loop, 5); |
| 750 // Inc counter and continue. |
| 751 Node* index_inc = |
| 752 NewNode(javascript()->Add(), index, jsgraph()->OneConstant()); |
| 753 environment()->Poke(0, index_inc); |
| 754 for_loop.EndBody(); |
| 755 for_loop.EndLoop(); |
| 756 environment()->Drop(5); |
| 757 // PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 758 } |
| 759 have_no_properties.End(); |
| 760 } |
| 761 is_null.End(); |
| 762 } |
| 763 is_undefined.End(); |
| 764 } |
| 765 |
| 766 |
| 767 void AstGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) { |
| 768 VisitForValue(stmt->subject()); |
| 769 environment()->Pop(); |
| 770 // TODO(turbofan): create and use loop builder. |
| 771 } |
| 772 |
| 773 |
| 774 void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { |
| 775 UNREACHABLE(); |
| 776 } |
| 777 |
| 778 |
| 779 void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
| 780 UNREACHABLE(); |
| 781 } |
| 782 |
| 783 |
| 784 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { |
| 785 // TODO(turbofan): Do we really need a separate reloc-info for this? |
| 786 NewNode(javascript()->Runtime(Runtime::kDebugBreak, 0)); |
| 787 } |
| 788 |
| 789 |
| 790 void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 791 Node* context = current_context(); |
| 792 |
| 793 // Build a new shared function info if we cannot find one in the baseline |
| 794 // code. We also have a stack overflow if the recursive compilation did. |
| 795 Handle<SharedFunctionInfo> shared_info = |
| 796 SearchSharedFunctionInfo(info()->shared_info()->code(), expr); |
| 797 if (shared_info.is_null()) { |
| 798 shared_info = Compiler::BuildFunctionInfo(expr, info()->script()); |
| 799 CHECK(!shared_info.is_null()); // TODO(mstarzinger): Set stack overflow? |
| 800 } |
| 801 |
| 802 // Create node to instantiate a new closure. |
| 803 Node* info = jsgraph()->Constant(shared_info); |
| 804 Node* pretenure = expr->pretenure() ? jsgraph()->TrueConstant() |
| 805 : jsgraph()->FalseConstant(); |
| 806 Operator* op = javascript()->Runtime(Runtime::kNewClosure, 3); |
| 807 Node* value = NewNode(op, context, info, pretenure); |
| 808 ast_context()->ProduceValue(value); |
| 809 } |
| 810 |
| 811 |
| 812 void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { |
| 813 UNREACHABLE(); |
| 814 } |
| 815 |
| 816 |
| 817 void AstGraphBuilder::VisitConditional(Conditional* expr) { |
| 818 IfBuilder compare_if(this); |
| 819 VisitForTest(expr->condition()); |
| 820 Node* condition = environment()->Pop(); |
| 821 compare_if.If(condition); |
| 822 compare_if.Then(); |
| 823 Visit(expr->then_expression()); |
| 824 compare_if.Else(); |
| 825 Visit(expr->else_expression()); |
| 826 compare_if.End(); |
| 827 ast_context()->ReplaceValue(); |
| 828 } |
| 829 |
| 830 |
| 831 void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 832 Node* value = BuildVariableLoad(expr->var()); |
| 833 ast_context()->ProduceValue(value); |
| 834 } |
| 835 |
| 836 |
| 837 void AstGraphBuilder::VisitLiteral(Literal* expr) { |
| 838 Node* value = jsgraph()->Constant(expr->value()); |
| 839 ast_context()->ProduceValue(value); |
| 840 } |
| 841 |
| 842 |
| 843 void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 844 Handle<JSFunction> closure = info()->closure(); |
| 845 |
| 846 // Create node to materialize a regular expression literal. |
| 847 Node* literals_array = jsgraph()->Constant(handle(closure->literals())); |
| 848 Node* literal_index = jsgraph()->Constant(expr->literal_index()); |
| 849 Node* pattern = jsgraph()->Constant(expr->pattern()); |
| 850 Node* flags = jsgraph()->Constant(expr->flags()); |
| 851 Operator* op = javascript()->Runtime(Runtime::kMaterializeRegExpLiteral, 4); |
| 852 Node* literal = NewNode(op, literals_array, literal_index, pattern, flags); |
| 853 ast_context()->ProduceValue(literal); |
| 854 } |
| 855 |
| 856 |
| 857 void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
| 858 Handle<JSFunction> closure = info()->closure(); |
| 859 |
| 860 // Create node to deep-copy the literal boilerplate. |
| 861 expr->BuildConstantProperties(isolate()); |
| 862 Node* literals_array = jsgraph()->Constant(handle(closure->literals())); |
| 863 Node* literal_index = jsgraph()->Constant(expr->literal_index()); |
| 864 Node* constants = jsgraph()->Constant(expr->constant_properties()); |
| 865 Node* flags = jsgraph()->Constant(expr->ComputeFlags()); |
| 866 Operator* op = javascript()->Runtime(Runtime::kCreateObjectLiteral, 4); |
| 867 Node* literal = NewNode(op, literals_array, literal_index, constants, flags); |
| 868 |
| 869 // The object is expected on the operand stack during computation of the |
| 870 // property values and is the value of the entire expression. |
| 871 environment()->Push(literal); |
| 872 |
| 873 // Mark all computed expressions that are bound to a key that is shadowed by |
| 874 // a later occurrence of the same key. For the marked expressions, no store |
| 875 // code is emitted. |
| 876 expr->CalculateEmitStore(zone()); |
| 877 |
| 878 // Create nodes to store computed values into the literal. |
| 879 AccessorTable accessor_table(zone()); |
| 880 for (int i = 0; i < expr->properties()->length(); i++) { |
| 881 ObjectLiteral::Property* property = expr->properties()->at(i); |
| 882 if (property->IsCompileTimeValue()) continue; |
| 883 |
| 884 Literal* key = property->key(); |
| 885 switch (property->kind()) { |
| 886 case ObjectLiteral::Property::CONSTANT: |
| 887 UNREACHABLE(); |
| 888 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 889 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); |
| 890 // Fall through. |
| 891 case ObjectLiteral::Property::COMPUTED: { |
| 892 // It is safe to use [[Put]] here because the boilerplate already |
| 893 // contains computed properties with an uninitialized value. |
| 894 if (key->value()->IsInternalizedString()) { |
| 895 if (property->emit_store()) { |
| 896 VisitForValue(property->value()); |
| 897 Node* value = environment()->Pop(); |
| 898 PrintableUnique<Name> name = MakeUnique(key->AsPropertyName()); |
| 899 NewNode(javascript()->StoreNamed(name), literal, value); |
| 900 } else { |
| 901 VisitForEffect(property->value()); |
| 902 } |
| 903 break; |
| 904 } |
| 905 environment()->Push(literal); // Duplicate receiver. |
| 906 VisitForValue(property->key()); |
| 907 VisitForValue(property->value()); |
| 908 Node* value = environment()->Pop(); |
| 909 Node* key = environment()->Pop(); |
| 910 Node* receiver = environment()->Pop(); |
| 911 if (property->emit_store()) { |
| 912 Node* strict = jsgraph()->Constant(SLOPPY); |
| 913 Operator* op = javascript()->Runtime(Runtime::kSetProperty, 4); |
| 914 NewNode(op, receiver, key, value, strict); |
| 915 } |
| 916 break; |
| 917 } |
| 918 case ObjectLiteral::Property::PROTOTYPE: { |
| 919 environment()->Push(literal); // Duplicate receiver. |
| 920 VisitForValue(property->value()); |
| 921 Node* value = environment()->Pop(); |
| 922 Node* receiver = environment()->Pop(); |
| 923 if (property->emit_store()) { |
| 924 Operator* op = javascript()->Runtime(Runtime::kSetPrototype, 2); |
| 925 NewNode(op, receiver, value); |
| 926 } |
| 927 break; |
| 928 } |
| 929 case ObjectLiteral::Property::GETTER: |
| 930 accessor_table.lookup(key)->second->getter = property->value(); |
| 931 break; |
| 932 case ObjectLiteral::Property::SETTER: |
| 933 accessor_table.lookup(key)->second->setter = property->value(); |
| 934 break; |
| 935 } |
| 936 } |
| 937 |
| 938 // Create nodes to define accessors, using only a single call to the runtime |
| 939 // for each pair of corresponding getters and setters. |
| 940 for (AccessorTable::Iterator it = accessor_table.begin(); |
| 941 it != accessor_table.end(); |
| 942 ++it) { |
| 943 VisitForValue(it->first); |
| 944 VisitForValueOrNull(it->second->getter); |
| 945 VisitForValueOrNull(it->second->setter); |
| 946 Node* setter = environment()->Pop(); |
| 947 Node* getter = environment()->Pop(); |
| 948 Node* name = environment()->Pop(); |
| 949 Node* attr = jsgraph()->Constant(NONE); |
| 950 Operator* op = |
| 951 javascript()->Runtime(Runtime::kDefineAccessorPropertyUnchecked, 5); |
| 952 NewNode(op, literal, name, getter, setter, attr); |
| 953 } |
| 954 |
| 955 // Transform literals that contain functions to fast properties. |
| 956 if (expr->has_function()) { |
| 957 Operator* op = javascript()->Runtime(Runtime::kToFastProperties, 1); |
| 958 NewNode(op, literal); |
| 959 } |
| 960 |
| 961 ast_context()->ProduceValue(environment()->Pop()); |
| 962 } |
| 963 |
| 964 |
| 965 void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
| 966 Handle<JSFunction> closure = info()->closure(); |
| 967 |
| 968 // Create node to deep-copy the literal boilerplate. |
| 969 expr->BuildConstantElements(isolate()); |
| 970 Node* literals_array = jsgraph()->Constant(handle(closure->literals())); |
| 971 Node* literal_index = jsgraph()->Constant(expr->literal_index()); |
| 972 Node* constants = jsgraph()->Constant(expr->constant_elements()); |
| 973 Node* flags = jsgraph()->Constant(expr->ComputeFlags()); |
| 974 Operator* op = javascript()->Runtime(Runtime::kCreateArrayLiteral, 4); |
| 975 Node* literal = NewNode(op, literals_array, literal_index, constants, flags); |
| 976 |
| 977 // The array and the literal index are both expected on the operand stack |
| 978 // during computation of the element values. |
| 979 environment()->Push(literal); |
| 980 environment()->Push(literal_index); |
| 981 |
| 982 // Create nodes to evaluate all the non-constant subexpressions and to store |
| 983 // them into the newly cloned array. |
| 984 for (int i = 0; i < expr->values()->length(); i++) { |
| 985 Expression* subexpr = expr->values()->at(i); |
| 986 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; |
| 987 |
| 988 VisitForValue(subexpr); |
| 989 Node* value = environment()->Pop(); |
| 990 Node* index = jsgraph()->Constant(i); |
| 991 NewNode(javascript()->StoreProperty(), literal, index, value); |
| 992 } |
| 993 |
| 994 environment()->Pop(); // Array literal index. |
| 995 ast_context()->ProduceValue(environment()->Pop()); |
| 996 } |
| 997 |
| 998 |
| 999 void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value) { |
| 1000 ASSERT(expr->IsValidReferenceExpression()); |
| 1001 |
| 1002 // Left-hand side can only be a property, a global or a variable slot. |
| 1003 Property* property = expr->AsProperty(); |
| 1004 LhsKind assign_type = DetermineLhsKind(expr); |
| 1005 |
| 1006 // Evaluate LHS expression and store the value. |
| 1007 switch (assign_type) { |
| 1008 case VARIABLE: { |
| 1009 Variable* var = expr->AsVariableProxy()->var(); |
| 1010 BuildVariableAssignment(var, value, Token::ASSIGN); |
| 1011 break; |
| 1012 } |
| 1013 case NAMED_PROPERTY: { |
| 1014 environment()->Push(value); |
| 1015 VisitForValue(property->obj()); |
| 1016 Node* object = environment()->Pop(); |
| 1017 value = environment()->Pop(); |
| 1018 PrintableUnique<Name> name = |
| 1019 MakeUnique(property->key()->AsLiteral()->AsPropertyName()); |
| 1020 NewNode(javascript()->StoreNamed(name), object, value); |
| 1021 break; |
| 1022 } |
| 1023 case KEYED_PROPERTY: { |
| 1024 environment()->Push(value); |
| 1025 VisitForValue(property->obj()); |
| 1026 VisitForValue(property->key()); |
| 1027 Node* key = environment()->Pop(); |
| 1028 Node* object = environment()->Pop(); |
| 1029 value = environment()->Pop(); |
| 1030 NewNode(javascript()->StoreProperty(), object, key, value); |
| 1031 break; |
| 1032 } |
| 1033 } |
| 1034 } |
| 1035 |
| 1036 |
| 1037 void AstGraphBuilder::VisitAssignment(Assignment* expr) { |
| 1038 ASSERT(expr->target()->IsValidReferenceExpression()); |
| 1039 |
| 1040 // Left-hand side can only be a property, a global or a variable slot. |
| 1041 Property* property = expr->target()->AsProperty(); |
| 1042 LhsKind assign_type = DetermineLhsKind(expr->target()); |
| 1043 |
| 1044 // Evaluate LHS expression. |
| 1045 switch (assign_type) { |
| 1046 case VARIABLE: |
| 1047 // Nothing to do here. |
| 1048 break; |
| 1049 case NAMED_PROPERTY: |
| 1050 VisitForValue(property->obj()); |
| 1051 break; |
| 1052 case KEYED_PROPERTY: { |
| 1053 VisitForValue(property->obj()); |
| 1054 VisitForValue(property->key()); |
| 1055 break; |
| 1056 } |
| 1057 } |
| 1058 |
| 1059 // Evaluate the value and potentially handle compound assignments by loading |
| 1060 // the left-hand side value and performing a binary operation. |
| 1061 if (expr->is_compound()) { |
| 1062 Node* old_value = NULL; |
| 1063 switch (assign_type) { |
| 1064 case VARIABLE: { |
| 1065 Variable* variable = expr->target()->AsVariableProxy()->var(); |
| 1066 old_value = BuildVariableLoad(variable); |
| 1067 break; |
| 1068 } |
| 1069 case NAMED_PROPERTY: { |
| 1070 Node* object = environment()->Top(); |
| 1071 PrintableUnique<Name> name = |
| 1072 MakeUnique(property->key()->AsLiteral()->AsPropertyName()); |
| 1073 old_value = NewNode(javascript()->LoadNamed(name), object); |
| 1074 break; |
| 1075 } |
| 1076 case KEYED_PROPERTY: { |
| 1077 Node* key = environment()->Top(); |
| 1078 Node* object = environment()->Peek(1); |
| 1079 old_value = NewNode(javascript()->LoadProperty(), object, key); |
| 1080 break; |
| 1081 } |
| 1082 } |
| 1083 environment()->Push(old_value); |
| 1084 VisitForValue(expr->value()); |
| 1085 Node* right = environment()->Pop(); |
| 1086 Node* left = environment()->Pop(); |
| 1087 Node* value = BuildBinaryOp(left, right, expr->binary_op()); |
| 1088 environment()->Push(value); |
| 1089 } else { |
| 1090 VisitForValue(expr->value()); |
| 1091 } |
| 1092 |
| 1093 // Store the value. |
| 1094 Node* value = environment()->Pop(); |
| 1095 switch (assign_type) { |
| 1096 case VARIABLE: { |
| 1097 Variable* variable = expr->target()->AsVariableProxy()->var(); |
| 1098 BuildVariableAssignment(variable, value, expr->op()); |
| 1099 break; |
| 1100 } |
| 1101 case NAMED_PROPERTY: { |
| 1102 Node* object = environment()->Pop(); |
| 1103 PrintableUnique<Name> name = |
| 1104 MakeUnique(property->key()->AsLiteral()->AsPropertyName()); |
| 1105 NewNode(javascript()->StoreNamed(name), object, value); |
| 1106 break; |
| 1107 } |
| 1108 case KEYED_PROPERTY: { |
| 1109 Node* key = environment()->Pop(); |
| 1110 Node* object = environment()->Pop(); |
| 1111 NewNode(javascript()->StoreProperty(), object, key, value); |
| 1112 break; |
| 1113 } |
| 1114 } |
| 1115 |
| 1116 ast_context()->ProduceValue(value); |
| 1117 } |
| 1118 |
| 1119 |
| 1120 void AstGraphBuilder::VisitYield(Yield* expr) { |
| 1121 VisitForValue(expr->generator_object()); |
| 1122 VisitForValue(expr->expression()); |
| 1123 environment()->Pop(); |
| 1124 environment()->Pop(); |
| 1125 // TODO(turbofan): VisitYield |
| 1126 ast_context()->ProduceValue(jsgraph()->UndefinedConstant()); |
| 1127 } |
| 1128 |
| 1129 |
| 1130 void AstGraphBuilder::VisitThrow(Throw* expr) { |
| 1131 VisitForValue(expr->exception()); |
| 1132 Node* exception = environment()->Pop(); |
| 1133 Operator* op = javascript()->Runtime(Runtime::kThrow, 1); |
| 1134 Node* value = NewNode(op, exception); |
| 1135 ast_context()->ProduceValue(value); |
| 1136 } |
| 1137 |
| 1138 |
| 1139 void AstGraphBuilder::VisitProperty(Property* expr) { |
| 1140 Node* value; |
| 1141 if (expr->key()->IsPropertyName()) { |
| 1142 VisitForValue(expr->obj()); |
| 1143 Node* object = environment()->Pop(); |
| 1144 PrintableUnique<Name> name = |
| 1145 MakeUnique(expr->key()->AsLiteral()->AsPropertyName()); |
| 1146 value = NewNode(javascript()->LoadNamed(name), object); |
| 1147 } else { |
| 1148 VisitForValue(expr->obj()); |
| 1149 VisitForValue(expr->key()); |
| 1150 Node* key = environment()->Pop(); |
| 1151 Node* object = environment()->Pop(); |
| 1152 value = NewNode(javascript()->LoadProperty(), object, key); |
| 1153 } |
| 1154 ast_context()->ProduceValue(value); |
| 1155 } |
| 1156 |
| 1157 |
| 1158 void AstGraphBuilder::VisitCall(Call* expr) { |
| 1159 Expression* callee = expr->expression(); |
| 1160 Call::CallType call_type = expr->GetCallType(isolate()); |
| 1161 |
| 1162 // Prepare the callee and the receiver to the function call. This depends on |
| 1163 // the semantics of the underlying call type. |
| 1164 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS; |
| 1165 Node* receiver_value = NULL; |
| 1166 Node* callee_value = NULL; |
| 1167 bool possibly_eval = false; |
| 1168 switch (call_type) { |
| 1169 case Call::GLOBAL_CALL: { |
| 1170 Variable* variable = callee->AsVariableProxy()->var(); |
| 1171 callee_value = BuildVariableLoad(variable); |
| 1172 receiver_value = jsgraph()->UndefinedConstant(); |
| 1173 break; |
| 1174 } |
| 1175 case Call::LOOKUP_SLOT_CALL: { |
| 1176 Variable* variable = callee->AsVariableProxy()->var(); |
| 1177 ASSERT(variable->location() == Variable::LOOKUP); |
| 1178 Node* name = jsgraph()->Constant(variable->name()); |
| 1179 Operator* op = javascript()->Runtime(Runtime::kLoadLookupSlot, 2); |
| 1180 Node* pair = NewNode(op, current_context(), name); |
| 1181 callee_value = NewNode(common()->Projection(0), pair); |
| 1182 receiver_value = NewNode(common()->Projection(1), pair); |
| 1183 break; |
| 1184 } |
| 1185 case Call::PROPERTY_CALL: { |
| 1186 Property* property = callee->AsProperty(); |
| 1187 VisitForValue(property->obj()); |
| 1188 Node* object = environment()->Top(); |
| 1189 if (property->key()->IsPropertyName()) { |
| 1190 PrintableUnique<Name> name = |
| 1191 MakeUnique(property->key()->AsLiteral()->AsPropertyName()); |
| 1192 callee_value = NewNode(javascript()->LoadNamed(name), object); |
| 1193 } else { |
| 1194 VisitForValue(property->key()); |
| 1195 Node* key = environment()->Pop(); |
| 1196 callee_value = NewNode(javascript()->LoadProperty(), object, key); |
| 1197 } |
| 1198 receiver_value = environment()->Pop(); |
| 1199 // Note that a PROPERTY_CALL requires the receiver to be wrapped into an |
| 1200 // object for sloppy callees. This could also be modeled explicitly here, |
| 1201 // thereby obsoleting the need for a flag to the call operator. |
| 1202 flags = CALL_AS_METHOD; |
| 1203 break; |
| 1204 } |
| 1205 case Call::POSSIBLY_EVAL_CALL: |
| 1206 possibly_eval = true; |
| 1207 // Fall through. |
| 1208 case Call::OTHER_CALL: |
| 1209 VisitForValue(callee); |
| 1210 callee_value = environment()->Pop(); |
| 1211 receiver_value = jsgraph()->UndefinedConstant(); |
| 1212 break; |
| 1213 } |
| 1214 |
| 1215 // The callee and the receiver both have to be pushed onto the operand stack |
| 1216 // before arguments are being evaluated. |
| 1217 environment()->Push(callee_value); |
| 1218 environment()->Push(receiver_value); |
| 1219 |
| 1220 // Evaluate all arguments to the function call, |
| 1221 ZoneList<Expression*>* args = expr->arguments(); |
| 1222 VisitForValues(args); |
| 1223 |
| 1224 // Resolve callee and receiver for a potential direct eval call. This block |
| 1225 // will mutate the callee and receiver values pushed onto the environment. |
| 1226 if (possibly_eval && args->length() > 0) { |
| 1227 int arg_count = args->length(); |
| 1228 |
| 1229 // Extract callee and source string from the environment. |
| 1230 Node* callee = environment()->Peek(arg_count + 1); |
| 1231 Node* source = environment()->Peek(arg_count - 1); |
| 1232 |
| 1233 // Create node to ask for help resolving potential eval call. This will |
| 1234 // provide a fully resolved callee and the corresponding receiver. |
| 1235 Node* receiver = environment()->Lookup(info()->scope()->receiver()); |
| 1236 Node* strict = jsgraph()->Constant(strict_mode()); |
| 1237 Node* position = jsgraph()->Constant(info()->scope()->start_position()); |
| 1238 Operator* op = |
| 1239 javascript()->Runtime(Runtime::kResolvePossiblyDirectEval, 5); |
| 1240 Node* pair = NewNode(op, callee, source, receiver, strict, position); |
| 1241 Node* new_callee = NewNode(common()->Projection(0), pair); |
| 1242 Node* new_receiver = NewNode(common()->Projection(1), pair); |
| 1243 |
| 1244 // Patch callee and receiver on the environment. |
| 1245 environment()->Poke(arg_count + 1, new_callee); |
| 1246 environment()->Poke(arg_count + 0, new_receiver); |
| 1247 } |
| 1248 |
| 1249 // Create node to perform the function call. |
| 1250 Operator* call = javascript()->Call(args->length() + 2, flags); |
| 1251 Node* value = ProcessArguments(call, args->length() + 2); |
| 1252 ast_context()->ProduceValue(value); |
| 1253 } |
| 1254 |
| 1255 |
| 1256 void AstGraphBuilder::VisitCallNew(CallNew* expr) { |
| 1257 VisitForValue(expr->expression()); |
| 1258 |
| 1259 // Evaluate all arguments to the construct call. |
| 1260 ZoneList<Expression*>* args = expr->arguments(); |
| 1261 VisitForValues(args); |
| 1262 |
| 1263 // Create node to perform the construct call. |
| 1264 Operator* call = javascript()->CallNew(args->length() + 1); |
| 1265 Node* value = ProcessArguments(call, args->length() + 1); |
| 1266 ast_context()->ProduceValue(value); |
| 1267 } |
| 1268 |
| 1269 |
| 1270 void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) { |
| 1271 Handle<String> name = expr->name(); |
| 1272 |
| 1273 // The callee and the receiver both have to be pushed onto the operand stack |
| 1274 // before arguments are being evaluated. |
| 1275 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS; |
| 1276 Node* receiver_value = BuildLoadBuiltinsObject(); |
| 1277 PrintableUnique<String> unique = MakeUnique(name); |
| 1278 Node* callee_value = NewNode(javascript()->LoadNamed(unique), receiver_value); |
| 1279 environment()->Push(callee_value); |
| 1280 environment()->Push(receiver_value); |
| 1281 |
| 1282 // Evaluate all arguments to the JS runtime call. |
| 1283 ZoneList<Expression*>* args = expr->arguments(); |
| 1284 VisitForValues(args); |
| 1285 |
| 1286 // Create node to perform the JS runtime call. |
| 1287 Operator* call = javascript()->Call(args->length() + 2, flags); |
| 1288 Node* value = ProcessArguments(call, args->length() + 2); |
| 1289 ast_context()->ProduceValue(value); |
| 1290 } |
| 1291 |
| 1292 |
| 1293 void AstGraphBuilder::VisitCallRuntime(CallRuntime* expr) { |
| 1294 const Runtime::Function* function = expr->function(); |
| 1295 |
| 1296 // Handle calls to runtime functions implemented in JavaScript separately as |
| 1297 // the call follows JavaScript ABI and the callee is statically unknown. |
| 1298 if (expr->is_jsruntime()) { |
| 1299 ASSERT(function == NULL && expr->name()->length() > 0); |
| 1300 return VisitCallJSRuntime(expr); |
| 1301 } |
| 1302 |
| 1303 // Evaluate all arguments to the runtime call. |
| 1304 ZoneList<Expression*>* args = expr->arguments(); |
| 1305 VisitForValues(args); |
| 1306 |
| 1307 // Create node to perform the runtime call. |
| 1308 Runtime::FunctionId functionId = function->function_id; |
| 1309 Operator* call = javascript()->Runtime(functionId, args->length()); |
| 1310 Node* value = ProcessArguments(call, args->length()); |
| 1311 ast_context()->ProduceValue(value); |
| 1312 |
| 1313 BuildLazyBailout(value, expr->id()); |
| 1314 } |
| 1315 |
| 1316 |
| 1317 void AstGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
| 1318 switch (expr->op()) { |
| 1319 case Token::DELETE: |
| 1320 return VisitDelete(expr); |
| 1321 case Token::VOID: |
| 1322 return VisitVoid(expr); |
| 1323 case Token::TYPEOF: |
| 1324 return VisitTypeof(expr); |
| 1325 case Token::NOT: |
| 1326 return VisitNot(expr); |
| 1327 default: UNREACHABLE(); |
| 1328 } |
| 1329 } |
| 1330 |
| 1331 |
| 1332 void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| 1333 ASSERT(expr->expression()->IsValidReferenceExpression()); |
| 1334 |
| 1335 // Left-hand side can only be a property, a global or a variable slot. |
| 1336 Property* property = expr->expression()->AsProperty(); |
| 1337 LhsKind assign_type = DetermineLhsKind(expr->expression()); |
| 1338 |
| 1339 // Reserve space for result of postfix operation. |
| 1340 bool is_postfix = expr->is_postfix() && !ast_context()->IsEffect(); |
| 1341 if (is_postfix) environment()->Push(jsgraph()->UndefinedConstant()); |
| 1342 |
| 1343 // Evaluate LHS expression and get old value. |
| 1344 Node* old_value = NULL; |
| 1345 int stack_depth = -1; |
| 1346 switch (assign_type) { |
| 1347 case VARIABLE: { |
| 1348 Variable* variable = expr->expression()->AsVariableProxy()->var(); |
| 1349 old_value = BuildVariableLoad(variable); |
| 1350 stack_depth = 0; |
| 1351 break; |
| 1352 } |
| 1353 case NAMED_PROPERTY: { |
| 1354 VisitForValue(property->obj()); |
| 1355 Node* object = environment()->Top(); |
| 1356 PrintableUnique<Name> name = |
| 1357 MakeUnique(property->key()->AsLiteral()->AsPropertyName()); |
| 1358 old_value = NewNode(javascript()->LoadNamed(name), object); |
| 1359 stack_depth = 1; |
| 1360 break; |
| 1361 } |
| 1362 case KEYED_PROPERTY: { |
| 1363 VisitForValue(property->obj()); |
| 1364 VisitForValue(property->key()); |
| 1365 Node* key = environment()->Top(); |
| 1366 Node* object = environment()->Peek(1); |
| 1367 old_value = NewNode(javascript()->LoadProperty(), object, key); |
| 1368 stack_depth = 2; |
| 1369 break; |
| 1370 } |
| 1371 } |
| 1372 |
| 1373 // Convert old value into a number. |
| 1374 old_value = NewNode(javascript()->ToNumber(), old_value); |
| 1375 |
| 1376 // Save result for postfix expressions at correct stack depth. |
| 1377 if (is_postfix) environment()->Poke(stack_depth, old_value); |
| 1378 |
| 1379 // Create node to perform +1/-1 operation. |
| 1380 Node* value = |
| 1381 BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op()); |
| 1382 |
| 1383 // Store the value. |
| 1384 switch (assign_type) { |
| 1385 case VARIABLE: { |
| 1386 Variable* variable = expr->expression()->AsVariableProxy()->var(); |
| 1387 BuildVariableAssignment(variable, value, expr->op()); |
| 1388 break; |
| 1389 } |
| 1390 case NAMED_PROPERTY: { |
| 1391 Node* object = environment()->Pop(); |
| 1392 PrintableUnique<Name> name = |
| 1393 MakeUnique(property->key()->AsLiteral()->AsPropertyName()); |
| 1394 NewNode(javascript()->StoreNamed(name), object, value); |
| 1395 break; |
| 1396 } |
| 1397 case KEYED_PROPERTY: { |
| 1398 Node* key = environment()->Pop(); |
| 1399 Node* object = environment()->Pop(); |
| 1400 NewNode(javascript()->StoreProperty(), object, key, value); |
| 1401 break; |
| 1402 } |
| 1403 } |
| 1404 |
| 1405 // Restore old value for postfix expressions. |
| 1406 if (is_postfix) value = environment()->Pop(); |
| 1407 |
| 1408 ast_context()->ProduceValue(value); |
| 1409 } |
| 1410 |
| 1411 |
| 1412 void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
| 1413 switch (expr->op()) { |
| 1414 case Token::COMMA: |
| 1415 return VisitComma(expr); |
| 1416 case Token::OR: |
| 1417 case Token::AND: |
| 1418 return VisitLogicalExpression(expr); |
| 1419 default: { |
| 1420 VisitForValue(expr->left()); |
| 1421 VisitForValue(expr->right()); |
| 1422 Node* right = environment()->Pop(); |
| 1423 Node* left = environment()->Pop(); |
| 1424 Node* value = BuildBinaryOp(left, right, expr->op()); |
| 1425 ast_context()->ProduceValue(value); |
| 1426 } |
| 1427 } |
| 1428 } |
| 1429 |
| 1430 |
| 1431 void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| 1432 Operator* op; |
| 1433 switch (expr->op()) { |
| 1434 case Token::EQ: |
| 1435 op = javascript()->Equal(); |
| 1436 break; |
| 1437 case Token::NE: |
| 1438 op = javascript()->NotEqual(); |
| 1439 break; |
| 1440 case Token::EQ_STRICT: |
| 1441 op = javascript()->StrictEqual(); |
| 1442 break; |
| 1443 case Token::NE_STRICT: |
| 1444 op = javascript()->StrictNotEqual(); |
| 1445 break; |
| 1446 case Token::LT: |
| 1447 op = javascript()->LessThan(); |
| 1448 break; |
| 1449 case Token::GT: |
| 1450 op = javascript()->GreaterThan(); |
| 1451 break; |
| 1452 case Token::LTE: |
| 1453 op = javascript()->LessThanOrEqual(); |
| 1454 break; |
| 1455 case Token::GTE: |
| 1456 op = javascript()->GreaterThanOrEqual(); |
| 1457 break; |
| 1458 case Token::INSTANCEOF: |
| 1459 op = javascript()->InstanceOf(); |
| 1460 break; |
| 1461 case Token::IN: |
| 1462 op = javascript()->HasProperty(); |
| 1463 break; |
| 1464 default: |
| 1465 op = NULL; |
| 1466 UNREACHABLE(); |
| 1467 } |
| 1468 VisitForValue(expr->left()); |
| 1469 VisitForValue(expr->right()); |
| 1470 Node* right = environment()->Pop(); |
| 1471 Node* left = environment()->Pop(); |
| 1472 Node* value = NewNode(op, left, right); |
| 1473 ast_context()->ProduceValue(value); |
| 1474 } |
| 1475 |
| 1476 |
| 1477 void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) { |
| 1478 Node* value = GetFunctionClosure(); |
| 1479 ast_context()->ProduceValue(value); |
| 1480 } |
| 1481 |
| 1482 |
| 1483 void AstGraphBuilder::VisitCaseClause(CaseClause* expr) { |
| 1484 UNREACHABLE(); |
| 1485 } |
| 1486 |
| 1487 |
| 1488 void AstGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) { |
| 1489 ASSERT(globals()->is_empty()); |
| 1490 AstVisitor::VisitDeclarations(declarations); |
| 1491 if (globals()->is_empty()) return; |
| 1492 Handle<FixedArray> data = |
| 1493 isolate()->factory()->NewFixedArray(globals()->length(), TENURED); |
| 1494 for (int i = 0; i < globals()->length(); ++i) data->set(i, *globals()->at(i)); |
| 1495 int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) | |
| 1496 DeclareGlobalsNativeFlag::encode(info()->is_native()) | |
| 1497 DeclareGlobalsStrictMode::encode(info()->strict_mode()); |
| 1498 Node* flags = jsgraph()->Constant(encoded_flags); |
| 1499 Node* pairs = jsgraph()->Constant(data); |
| 1500 Operator* op = javascript()->Runtime(Runtime::kDeclareGlobals, 3); |
| 1501 NewNode(op, current_context(), pairs, flags); |
| 1502 globals()->Rewind(0); |
| 1503 } |
| 1504 |
| 1505 |
| 1506 void AstGraphBuilder::VisitIfNotNull(Statement* stmt) { |
| 1507 if (stmt == NULL) return; |
| 1508 Visit(stmt); |
| 1509 } |
| 1510 |
| 1511 |
| 1512 void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt, |
| 1513 LoopBuilder* loop, int drop_extra) { |
| 1514 BreakableScope scope(this, stmt, loop, drop_extra); |
| 1515 Visit(stmt->body()); |
| 1516 } |
| 1517 |
| 1518 |
| 1519 void AstGraphBuilder::VisitDelete(UnaryOperation* expr) { |
| 1520 Node* value; |
| 1521 if (expr->expression()->IsVariableProxy()) { |
| 1522 // Delete of an unqualified identifier is only allowed in classic mode but |
| 1523 // deleting "this" is allowed in all language modes. |
| 1524 Variable* variable = expr->expression()->AsVariableProxy()->var(); |
| 1525 ASSERT(strict_mode() == SLOPPY || variable->is_this()); |
| 1526 value = BuildVariableDelete(variable); |
| 1527 } else if (expr->expression()->IsProperty()) { |
| 1528 Property* property = expr->expression()->AsProperty(); |
| 1529 VisitForValue(property->obj()); |
| 1530 VisitForValue(property->key()); |
| 1531 Node* key = environment()->Pop(); |
| 1532 Node* object = environment()->Pop(); |
| 1533 value = NewNode(javascript()->DeleteProperty(strict_mode()), object, key); |
| 1534 } else { |
| 1535 VisitForEffect(expr->expression()); |
| 1536 value = jsgraph()->TrueConstant(); |
| 1537 } |
| 1538 ast_context()->ProduceValue(value); |
| 1539 } |
| 1540 |
| 1541 |
| 1542 void AstGraphBuilder::VisitVoid(UnaryOperation* expr) { |
| 1543 VisitForEffect(expr->expression()); |
| 1544 Node* value = jsgraph()->UndefinedConstant(); |
| 1545 ast_context()->ProduceValue(value); |
| 1546 } |
| 1547 |
| 1548 |
| 1549 void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) { |
| 1550 Node* operand; |
| 1551 if (expr->expression()->IsVariableProxy()) { |
| 1552 // Typeof does not throw a reference error on global variables, hence we |
| 1553 // perform a non-contextual load in case the operand is a variable proxy. |
| 1554 Variable* variable = expr->expression()->AsVariableProxy()->var(); |
| 1555 operand = BuildVariableLoad(variable, NOT_CONTEXTUAL); |
| 1556 } else { |
| 1557 VisitForValue(expr->expression()); |
| 1558 operand = environment()->Pop(); |
| 1559 } |
| 1560 Node* value = NewNode(javascript()->TypeOf(), operand); |
| 1561 ast_context()->ProduceValue(value); |
| 1562 } |
| 1563 |
| 1564 |
| 1565 void AstGraphBuilder::VisitNot(UnaryOperation* expr) { |
| 1566 VisitForValue(expr->expression()); |
| 1567 Node* operand = environment()->Pop(); |
| 1568 // TODO(mstarzinger): Possible optimization when we are in effect context. |
| 1569 Node* value = NewNode(javascript()->UnaryNot(), operand); |
| 1570 ast_context()->ProduceValue(value); |
| 1571 } |
| 1572 |
| 1573 |
| 1574 void AstGraphBuilder::VisitComma(BinaryOperation* expr) { |
| 1575 VisitForEffect(expr->left()); |
| 1576 Visit(expr->right()); |
| 1577 ast_context()->ReplaceValue(); |
| 1578 } |
| 1579 |
| 1580 |
| 1581 void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) { |
| 1582 bool is_logical_and = expr->op() == Token::AND; |
| 1583 IfBuilder compare_if(this); |
| 1584 VisitForValue(expr->left()); |
| 1585 Node* condition = environment()->Top(); |
| 1586 compare_if.If(BuildToBoolean(condition)); |
| 1587 compare_if.Then(); |
| 1588 if (is_logical_and) { |
| 1589 environment()->Pop(); |
| 1590 Visit(expr->right()); |
| 1591 } else if (ast_context()->IsEffect()) { |
| 1592 environment()->Pop(); |
| 1593 } |
| 1594 compare_if.Else(); |
| 1595 if (!is_logical_and) { |
| 1596 environment()->Pop(); |
| 1597 Visit(expr->right()); |
| 1598 } else if (ast_context()->IsEffect()) { |
| 1599 environment()->Pop(); |
| 1600 } |
| 1601 compare_if.End(); |
| 1602 ast_context()->ReplaceValue(); |
| 1603 } |
| 1604 |
| 1605 |
| 1606 Node* AstGraphBuilder::ProcessArguments(Operator* op, int arity) { |
| 1607 ASSERT(environment()->stack_height() >= arity); |
| 1608 Node** all = info()->zone()->NewArray<Node*>(arity); // XXX: alloca? |
| 1609 for (int i = arity - 1; i >= 0; --i) { |
| 1610 all[i] = environment()->Pop(); |
| 1611 } |
| 1612 Node* value = NewNode(op, arity, all); |
| 1613 return value; |
| 1614 } |
| 1615 |
| 1616 |
| 1617 Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context, Node* closure) { |
| 1618 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 1619 if (heap_slots <= 0) return context; |
| 1620 set_current_context(context); |
| 1621 |
| 1622 // Allocate a new local context. |
| 1623 Operator* op = javascript()->CreateFunctionContext(); |
| 1624 Node* local_context = NewNode(op, closure); |
| 1625 set_current_context(local_context); |
| 1626 |
| 1627 // Copy parameters into context if necessary. |
| 1628 int num_parameters = info()->scope()->num_parameters(); |
| 1629 for (int i = 0; i < num_parameters; i++) { |
| 1630 Variable* variable = info()->scope()->parameter(i); |
| 1631 if (!variable->IsContextSlot()) continue; |
| 1632 // Temporary parameter node. The parameter indices are shifted by 1 |
| 1633 // (receiver is parameter index -1 but environment index 0). |
| 1634 Node* parameter = NewNode(common()->Parameter(i + 1)); |
| 1635 // Context variable (at bottom of the context chain). |
| 1636 ASSERT_EQ(0, info()->scope()->ContextChainLength(variable->scope())); |
| 1637 Operator* op = javascript()->StoreContext(0, variable->index()); |
| 1638 NewNode(op, local_context, parameter); |
| 1639 } |
| 1640 |
| 1641 return local_context; |
| 1642 } |
| 1643 |
| 1644 |
| 1645 Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) { |
| 1646 if (arguments == NULL) return NULL; |
| 1647 |
| 1648 // Allocate and initialize a new arguments object. |
| 1649 Node* callee = GetFunctionClosure(); |
| 1650 Operator* op = javascript()->Runtime(Runtime::kNewArguments, 1); |
| 1651 Node* object = NewNode(op, callee); |
| 1652 |
| 1653 // Assign the object to the arguments variable. |
| 1654 ASSERT(arguments->IsContextSlot() || arguments->IsStackAllocated()); |
| 1655 BuildVariableAssignment(arguments, object, Token::ASSIGN); |
| 1656 |
| 1657 return object; |
| 1658 } |
| 1659 |
| 1660 |
| 1661 Node* AstGraphBuilder::BuildHoleCheckSilent( |
| 1662 Node* value, Node* for_hole, Node* not_hole) { |
| 1663 IfBuilder hole_check(this); |
| 1664 Node* the_hole = jsgraph()->TheHoleConstant(); |
| 1665 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole); |
| 1666 hole_check.If(check); |
| 1667 hole_check.Then(); |
| 1668 environment()->Push(for_hole); |
| 1669 hole_check.Else(); |
| 1670 environment()->Push(not_hole); |
| 1671 hole_check.End(); |
| 1672 return environment()->Pop(); |
| 1673 } |
| 1674 |
| 1675 |
| 1676 Node* AstGraphBuilder::BuildHoleCheckThrow( |
| 1677 Node* value, Variable* variable, Node* not_hole) { |
| 1678 IfBuilder hole_check(this); |
| 1679 Node* the_hole = jsgraph()->TheHoleConstant(); |
| 1680 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole); |
| 1681 hole_check.If(check); |
| 1682 hole_check.Then(); |
| 1683 environment()->Push(BuildThrowReferenceError(variable)); |
| 1684 hole_check.Else(); |
| 1685 environment()->Push(not_hole); |
| 1686 hole_check.End(); |
| 1687 return environment()->Pop(); |
| 1688 } |
| 1689 |
| 1690 |
| 1691 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, |
| 1692 ContextualMode contextual_mode) { |
| 1693 Node* the_hole = jsgraph()->TheHoleConstant(); |
| 1694 VariableMode mode = variable->mode(); |
| 1695 switch (variable->location()) { |
| 1696 case Variable::UNALLOCATED: { |
| 1697 // Global var, const, or let variable. |
| 1698 if (!info()->is_native()) { |
| 1699 // TODO(turbofan): This special case is needed only because we don't |
| 1700 // use LoadICs yet. Remove this once LoadNamed is lowered to an IC. |
| 1701 Node* name = jsgraph()->Constant(variable->name()); |
| 1702 Runtime::FunctionId function_id = |
| 1703 (contextual_mode == CONTEXTUAL) |
| 1704 ? Runtime::kLoadLookupSlot |
| 1705 : Runtime::kLoadLookupSlotNoReferenceError; |
| 1706 Operator* op = javascript()->Runtime(function_id, 2); |
| 1707 Node* pair = NewNode(op, current_context(), name); |
| 1708 return NewNode(common()->Projection(0), pair); |
| 1709 } |
| 1710 Node* global = BuildLoadGlobalObject(); |
| 1711 PrintableUnique<Name> name = MakeUnique(variable->name()); |
| 1712 Operator* op = javascript()->LoadNamed(name); |
| 1713 return NewNode(op, global); |
| 1714 } |
| 1715 case Variable::PARAMETER: |
| 1716 case Variable::LOCAL: { |
| 1717 // Local var, const, or let variable. |
| 1718 Node* value = environment()->Lookup(variable); |
| 1719 if (mode == CONST_LEGACY) { |
| 1720 // Perform check for uninitialized legacy const variables. |
| 1721 if (value->op() == the_hole->op()) { |
| 1722 value = jsgraph()->UndefinedConstant(); |
| 1723 } else if (value->opcode() == IrOpcode::kPhi) { |
| 1724 Node* undefined = jsgraph()->UndefinedConstant(); |
| 1725 value = BuildHoleCheckSilent(value, undefined, value); |
| 1726 } |
| 1727 } else if (mode == LET || mode == CONST) { |
| 1728 // Perform check for uninitialized let/const variables. |
| 1729 if (value->op() == the_hole->op()) { |
| 1730 value = BuildThrowReferenceError(variable); |
| 1731 } else if (value->opcode() == IrOpcode::kPhi) { |
| 1732 value = BuildHoleCheckThrow(value, variable, value); |
| 1733 } |
| 1734 } |
| 1735 return value; |
| 1736 } |
| 1737 case Variable::CONTEXT: { |
| 1738 // Context variable (potentially up the context chain). |
| 1739 int depth = current_scope()->ContextChainLength(variable->scope()); |
| 1740 bool immutable = variable->maybe_assigned() == kNotAssigned; |
| 1741 Operator* op = javascript()->LoadContext(depth, variable->index(), |
| 1742 immutable); |
| 1743 Node* value = NewNode(op, current_context()); |
| 1744 // TODO(titzer): initialization checks are redundant for already |
| 1745 // initialized immutable context loads, but only specialization knows. |
| 1746 // Maybe specializer should be a parameter to the graph builder? |
| 1747 if (mode == CONST_LEGACY) { |
| 1748 // Perform check for uninitialized legacy const variables. |
| 1749 Node* undefined = jsgraph()->UndefinedConstant(); |
| 1750 value = BuildHoleCheckSilent(value, undefined, value); |
| 1751 } else if (mode == LET || mode == CONST) { |
| 1752 // Perform check for uninitialized let/const variables. |
| 1753 value = BuildHoleCheckThrow(value, variable, value); |
| 1754 } |
| 1755 return value; |
| 1756 } |
| 1757 case Variable::LOOKUP: { |
| 1758 // Dynamic lookup of context variable (anywhere in the chain). |
| 1759 Node* name = jsgraph()->Constant(variable->name()); |
| 1760 Runtime::FunctionId function_id = |
| 1761 (contextual_mode == CONTEXTUAL) |
| 1762 ? Runtime::kLoadLookupSlot |
| 1763 : Runtime::kLoadLookupSlotNoReferenceError; |
| 1764 Operator* op = javascript()->Runtime(function_id, 2); |
| 1765 Node* pair = NewNode(op, current_context(), name); |
| 1766 return NewNode(common()->Projection(0), pair); |
| 1767 } |
| 1768 } |
| 1769 UNREACHABLE(); |
| 1770 return NULL; |
| 1771 } |
| 1772 |
| 1773 |
| 1774 Node* AstGraphBuilder::BuildVariableDelete(Variable* variable) { |
| 1775 switch (variable->location()) { |
| 1776 case Variable::UNALLOCATED: { |
| 1777 // Global var, const, or let variable. |
| 1778 Node* global = BuildLoadGlobalObject(); |
| 1779 Node* name = jsgraph()->Constant(variable->name()); |
| 1780 Operator* op = javascript()->DeleteProperty(strict_mode()); |
| 1781 return NewNode(op, global, name); |
| 1782 } |
| 1783 case Variable::PARAMETER: |
| 1784 case Variable::LOCAL: |
| 1785 case Variable::CONTEXT: |
| 1786 // Local var, const, or let variable or context variable. |
| 1787 return variable->is_this() ? jsgraph()->TrueConstant() |
| 1788 : jsgraph()->FalseConstant(); |
| 1789 case Variable::LOOKUP: { |
| 1790 // Dynamic lookup of context variable (anywhere in the chain). |
| 1791 Node* name = jsgraph()->Constant(variable->name()); |
| 1792 Operator* op = javascript()->Runtime(Runtime::kDeleteLookupSlot, 2); |
| 1793 return NewNode(op, current_context(), name); |
| 1794 } |
| 1795 } |
| 1796 UNREACHABLE(); |
| 1797 return NULL; |
| 1798 } |
| 1799 |
| 1800 |
| 1801 Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, |
| 1802 Node* value, |
| 1803 Token::Value op) { |
| 1804 Node* the_hole = jsgraph()->TheHoleConstant(); |
| 1805 VariableMode mode = variable->mode(); |
| 1806 switch (variable->location()) { |
| 1807 case Variable::UNALLOCATED: { |
| 1808 // Global var, const, or let variable. |
| 1809 if (!info()->is_native()) { |
| 1810 // TODO(turbofan): This special case is needed only because we don't |
| 1811 // use StoreICs yet. Remove this once StoreNamed is lowered to an IC. |
| 1812 Node* name = jsgraph()->Constant(variable->name()); |
| 1813 Node* strict = jsgraph()->Constant(strict_mode()); |
| 1814 Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4); |
| 1815 return NewNode(op, value, current_context(), name, strict); |
| 1816 } |
| 1817 Node* global = BuildLoadGlobalObject(); |
| 1818 PrintableUnique<Name> name = MakeUnique(variable->name()); |
| 1819 Operator* op = javascript()->StoreNamed(name); |
| 1820 return NewNode(op, global, value); |
| 1821 } |
| 1822 case Variable::PARAMETER: |
| 1823 case Variable::LOCAL: |
| 1824 // Local var, const, or let variable. |
| 1825 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) { |
| 1826 // Perform an initialization check for legacy const variables. |
| 1827 Node* current = environment()->Lookup(variable); |
| 1828 if (current->op() != the_hole->op()) { |
| 1829 value = BuildHoleCheckSilent(current, value, current); |
| 1830 } |
| 1831 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) { |
| 1832 // Non-initializing assignments to legacy const is ignored. |
| 1833 return value; |
| 1834 } else if (mode == LET && op != Token::INIT_LET) { |
| 1835 // Perform an initialization check for let declared variables. |
| 1836 // Also note that the dynamic hole-check is only done to ensure that |
| 1837 // this does not break in the presence of do-expressions within the |
| 1838 // temporal dead zone of a let declared variable. |
| 1839 Node* current = environment()->Lookup(variable); |
| 1840 if (current->op() == the_hole->op()) { |
| 1841 value = BuildThrowReferenceError(variable); |
| 1842 } else if (value->opcode() == IrOpcode::kPhi) { |
| 1843 value = BuildHoleCheckThrow(current, variable, value); |
| 1844 } |
| 1845 } else if (mode == CONST && op != Token::INIT_CONST) { |
| 1846 // All assignments to const variables are early errors. |
| 1847 UNREACHABLE(); |
| 1848 } |
| 1849 environment()->Bind(variable, value); |
| 1850 return value; |
| 1851 case Variable::CONTEXT: { |
| 1852 // Context variable (potentially up the context chain). |
| 1853 int depth = current_scope()->ContextChainLength(variable->scope()); |
| 1854 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) { |
| 1855 // Perform an initialization check for legacy const variables. |
| 1856 Operator* op = javascript()->LoadContext(depth, variable->index(), |
| 1857 false); |
| 1858 Node* current = NewNode(op, current_context()); |
| 1859 value = BuildHoleCheckSilent(current, value, current); |
| 1860 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) { |
| 1861 // Non-initializing assignments to legacy const is ignored. |
| 1862 return value; |
| 1863 } else if (mode == LET && op != Token::INIT_LET) { |
| 1864 // Perform an initialization check for let declared variables. |
| 1865 Operator* op = javascript()->LoadContext(depth, variable->index(), |
| 1866 false); |
| 1867 Node* current = NewNode(op, current_context()); |
| 1868 value = BuildHoleCheckThrow(current, variable, value); |
| 1869 } else if (mode == CONST && op != Token::INIT_CONST) { |
| 1870 // All assignments to const variables are early errors. |
| 1871 UNREACHABLE(); |
| 1872 } |
| 1873 Operator* op = javascript()->StoreContext(depth, variable->index()); |
| 1874 return NewNode(op, current_context(), value); |
| 1875 } |
| 1876 case Variable::LOOKUP: { |
| 1877 // Dynamic lookup of context variable (anywhere in the chain). |
| 1878 Node* name = jsgraph()->Constant(variable->name()); |
| 1879 Node* strict = jsgraph()->Constant(strict_mode()); |
| 1880 // TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for |
| 1881 // initializations of const declarations. |
| 1882 Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4); |
| 1883 return NewNode(op, value, current_context(), name, strict); |
| 1884 } |
| 1885 } |
| 1886 UNREACHABLE(); |
| 1887 return NULL; |
| 1888 } |
| 1889 |
| 1890 |
| 1891 Node* AstGraphBuilder::BuildLoadBuiltinsObject() { |
| 1892 // TODO(mstarzinger): Better load from function context, otherwise optimized |
| 1893 // code cannot be shared across native contexts. |
| 1894 return jsgraph()->Constant(handle(info()->context()->builtins())); |
| 1895 } |
| 1896 |
| 1897 |
| 1898 Node* AstGraphBuilder::BuildLoadGlobalObject() { |
| 1899 #if 0 |
| 1900 Node* context = GetFunctionContext(); |
| 1901 // TODO(mstarzinger): Use mid-level operator on FixedArray instead of the |
| 1902 // JS-level operator that targets JSObject. |
| 1903 Node* index = jsgraph()->Constant(Context::GLOBAL_OBJECT_INDEX); |
| 1904 return NewNode(javascript()->LoadProperty(), context, index); |
| 1905 #else |
| 1906 // TODO(mstarzinger): Better load from function context, otherwise optimized |
| 1907 // code cannot be shared across native contexts. See unused code above. |
| 1908 return jsgraph()->Constant(handle(info()->context()->global_object())); |
| 1909 #endif |
| 1910 } |
| 1911 |
| 1912 |
| 1913 Node* AstGraphBuilder::BuildToBoolean(Node* value) { |
| 1914 // TODO(mstarzinger): Possible optimization is to NOP for boolean values. |
| 1915 return NewNode(javascript()->ToBoolean(), value); |
| 1916 } |
| 1917 |
| 1918 |
| 1919 Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable) { |
| 1920 // TODO(mstarzinger): Should be unified with the VisitThrow implementation. |
| 1921 Node* variable_name = jsgraph()->Constant(variable->name()); |
| 1922 Operator* op = javascript()->Runtime(Runtime::kThrowReferenceError, 1); |
| 1923 return NewNode(op, variable_name); |
| 1924 } |
| 1925 |
| 1926 |
| 1927 Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) { |
| 1928 Operator* js_op; |
| 1929 switch (op) { |
| 1930 case Token::BIT_OR: |
| 1931 js_op = javascript()->BitwiseOr(); |
| 1932 break; |
| 1933 case Token::BIT_AND: |
| 1934 js_op = javascript()->BitwiseAnd(); |
| 1935 break; |
| 1936 case Token::BIT_XOR: |
| 1937 js_op = javascript()->BitwiseXor(); |
| 1938 break; |
| 1939 case Token::SHL: |
| 1940 js_op = javascript()->ShiftLeft(); |
| 1941 break; |
| 1942 case Token::SAR: |
| 1943 js_op = javascript()->ShiftRight(); |
| 1944 break; |
| 1945 case Token::SHR: |
| 1946 js_op = javascript()->ShiftRightLogical(); |
| 1947 break; |
| 1948 case Token::ADD: |
| 1949 js_op = javascript()->Add(); |
| 1950 break; |
| 1951 case Token::SUB: |
| 1952 js_op = javascript()->Subtract(); |
| 1953 break; |
| 1954 case Token::MUL: |
| 1955 js_op = javascript()->Multiply(); |
| 1956 break; |
| 1957 case Token::DIV: |
| 1958 js_op = javascript()->Divide(); |
| 1959 break; |
| 1960 case Token::MOD: |
| 1961 js_op = javascript()->Modulus(); |
| 1962 break; |
| 1963 default: |
| 1964 UNREACHABLE(); |
| 1965 js_op = NULL; |
| 1966 } |
| 1967 return NewNode(js_op, left, right); |
| 1968 } |
| 1969 |
| 1970 |
| 1971 void AstGraphBuilder::BuildLazyBailout(Node* node, BailoutId ast_id) { |
| 1972 if (OperatorProperties::CanLazilyDeoptimize(node->op())) { |
| 1973 // The deopting node should have an outgoing control dependency. |
| 1974 ASSERT(GetControlDependency() == node); |
| 1975 |
| 1976 StructuredGraphBuilder::Environment* continuation_env = |
| 1977 environment_internal(); |
| 1978 // Create environment for the deoptimization block, and build the block. |
| 1979 StructuredGraphBuilder::Environment* deopt_env = |
| 1980 CopyEnvironment(continuation_env); |
| 1981 set_environment(deopt_env); |
| 1982 |
| 1983 NewNode(common()->LazyDeoptimization()); |
| 1984 |
| 1985 FrameStateDescriptor stateDescriptor(ast_id); |
| 1986 Node* state_node = NewNode(common()->FrameState(stateDescriptor)); |
| 1987 |
| 1988 Node* deoptimize_node = NewNode(common()->Deoptimize(), state_node); |
| 1989 |
| 1990 UpdateControlDependencyToLeaveFunction(deoptimize_node); |
| 1991 |
| 1992 // Continue with the original environment. |
| 1993 set_environment(continuation_env); |
| 1994 |
| 1995 NewNode(common()->Continuation()); |
| 1996 } |
| 1997 } |
| 1998 } } } // namespace v8::internal::compiler |
| OLD | NEW |