| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 1364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1375 | 1375 |
| 1376 | 1376 |
| 1377 void HGlobalValueNumberer::ComputeBlockSideEffects() { | 1377 void HGlobalValueNumberer::ComputeBlockSideEffects() { |
| 1378 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { | 1378 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { |
| 1379 // Compute side effects for the block. | 1379 // Compute side effects for the block. |
| 1380 HBasicBlock* block = graph_->blocks()->at(i); | 1380 HBasicBlock* block = graph_->blocks()->at(i); |
| 1381 HInstruction* instr = block->first(); | 1381 HInstruction* instr = block->first(); |
| 1382 int id = block->block_id(); | 1382 int id = block->block_id(); |
| 1383 int side_effects = 0; | 1383 int side_effects = 0; |
| 1384 while (instr != NULL) { | 1384 while (instr != NULL) { |
| 1385 side_effects |= (instr->flags() & HValue::ChangesFlagsMask()); | 1385 side_effects |= instr->ChangesFlags(); |
| 1386 instr = instr->next(); | 1386 instr = instr->next(); |
| 1387 } | 1387 } |
| 1388 block_side_effects_[id] |= side_effects; | 1388 block_side_effects_[id] |= side_effects; |
| 1389 | 1389 |
| 1390 // Loop headers are part of their loop. | 1390 // Loop headers are part of their loop. |
| 1391 if (block->IsLoopHeader()) { | 1391 if (block->IsLoopHeader()) { |
| 1392 loop_side_effects_[id] |= side_effects; | 1392 loop_side_effects_[id] |= side_effects; |
| 1393 } | 1393 } |
| 1394 | 1394 |
| 1395 // Propagate loop side effects upwards. | 1395 // Propagate loop side effects upwards. |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1492 | 1492 |
| 1493 // If this is a loop header kill everything killed by the loop. | 1493 // If this is a loop header kill everything killed by the loop. |
| 1494 if (block->IsLoopHeader()) { | 1494 if (block->IsLoopHeader()) { |
| 1495 map->Kill(loop_side_effects_[block->block_id()]); | 1495 map->Kill(loop_side_effects_[block->block_id()]); |
| 1496 } | 1496 } |
| 1497 | 1497 |
| 1498 // Go through all instructions of the current block. | 1498 // Go through all instructions of the current block. |
| 1499 HInstruction* instr = block->first(); | 1499 HInstruction* instr = block->first(); |
| 1500 while (instr != NULL) { | 1500 while (instr != NULL) { |
| 1501 HInstruction* next = instr->next(); | 1501 HInstruction* next = instr->next(); |
| 1502 int flags = (instr->flags() & HValue::ChangesFlagsMask()); | 1502 int flags = instr->ChangesFlags(); |
| 1503 if (flags != 0) { | 1503 if (flags != 0) { |
| 1504 ASSERT(!instr->CheckFlag(HValue::kUseGVN)); | 1504 ASSERT(!instr->CheckFlag(HValue::kUseGVN)); |
| 1505 // Clear all instructions in the map that are affected by side effects. | 1505 // Clear all instructions in the map that are affected by side effects. |
| 1506 map->Kill(flags); | 1506 map->Kill(flags); |
| 1507 TraceGVN("Instruction %d kills\n", instr->id()); | 1507 TraceGVN("Instruction %d kills\n", instr->id()); |
| 1508 } else if (instr->CheckFlag(HValue::kUseGVN)) { | 1508 } else if (instr->CheckFlag(HValue::kUseGVN)) { |
| 1509 HValue* other = map->Lookup(instr); | 1509 HValue* other = map->Lookup(instr); |
| 1510 if (other != NULL) { | 1510 if (other != NULL) { |
| 1511 ASSERT(instr->Equals(other) && other->Equals(instr)); | 1511 ASSERT(instr->Equals(other) && other->Equals(instr)); |
| 1512 TraceGVN("Replacing value %d (%s) with value %d (%s)\n", | 1512 TraceGVN("Replacing value %d (%s) with value %d (%s)\n", |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1668 connected_set->Add(i); | 1668 connected_set->Add(i); |
| 1669 connected_phis.Add(connected_set); | 1669 connected_phis.Add(connected_set); |
| 1670 } | 1670 } |
| 1671 | 1671 |
| 1672 // (2) Do a fixed point iteration to find the set of connected phis. A | 1672 // (2) Do a fixed point iteration to find the set of connected phis. A |
| 1673 // phi is connected to another phi if its value is used either directly or | 1673 // phi is connected to another phi if its value is used either directly or |
| 1674 // indirectly through a transitive closure of the def-use relation. | 1674 // indirectly through a transitive closure of the def-use relation. |
| 1675 bool change = true; | 1675 bool change = true; |
| 1676 while (change) { | 1676 while (change) { |
| 1677 change = false; | 1677 change = false; |
| 1678 for (int i = 0; i < phi_count; ++i) { | 1678 // We normally have far more "forward edges" than "backward edges", |
| 1679 // so we terminate faster when we walk backwards. |
| 1680 for (int i = phi_count - 1; i >= 0; --i) { |
| 1679 HPhi* phi = phi_list->at(i); | 1681 HPhi* phi = phi_list->at(i); |
| 1680 for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) { | 1682 for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) { |
| 1681 HValue* use = it.value(); | 1683 HValue* use = it.value(); |
| 1682 if (use->IsPhi()) { | 1684 if (use->IsPhi()) { |
| 1683 int id = HPhi::cast(use)->phi_id(); | 1685 int id = HPhi::cast(use)->phi_id(); |
| 1684 if (connected_phis[i]->UnionIsChanged(*connected_phis[id])) | 1686 if (connected_phis[i]->UnionIsChanged(*connected_phis[id])) |
| 1685 change = true; | 1687 change = true; |
| 1686 } | 1688 } |
| 1687 } | 1689 } |
| 1688 } | 1690 } |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2266 { | 2268 { |
| 2267 HPhase phase("Block building"); | 2269 HPhase phase("Block building"); |
| 2268 current_block_ = graph()->entry_block(); | 2270 current_block_ = graph()->entry_block(); |
| 2269 | 2271 |
| 2270 Scope* scope = info()->scope(); | 2272 Scope* scope = info()->scope(); |
| 2271 if (scope->HasIllegalRedeclaration()) { | 2273 if (scope->HasIllegalRedeclaration()) { |
| 2272 Bailout("function with illegal redeclaration"); | 2274 Bailout("function with illegal redeclaration"); |
| 2273 return NULL; | 2275 return NULL; |
| 2274 } | 2276 } |
| 2275 SetupScope(scope); | 2277 SetupScope(scope); |
| 2276 VisitDeclarations(scope->declarations()); | |
| 2277 HValue* context = environment()->LookupContext(); | |
| 2278 AddInstruction( | |
| 2279 new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry)); | |
| 2280 | 2278 |
| 2281 // Add an edge to the body entry. This is warty: the graph's start | 2279 // Add an edge to the body entry. This is warty: the graph's start |
| 2282 // environment will be used by the Lithium translation as the initial | 2280 // environment will be used by the Lithium translation as the initial |
| 2283 // environment on graph entry, but it has now been mutated by the | 2281 // environment on graph entry, but it has now been mutated by the |
| 2284 // Hydrogen translation of the instructions in the start block. This | 2282 // Hydrogen translation of the instructions in the start block. This |
| 2285 // environment uses values which have not been defined yet. These | 2283 // environment uses values which have not been defined yet. These |
| 2286 // Hydrogen instructions will then be replayed by the Lithium | 2284 // Hydrogen instructions will then be replayed by the Lithium |
| 2287 // translation, so they cannot have an environment effect. The edge to | 2285 // translation, so they cannot have an environment effect. The edge to |
| 2288 // the body's entry block (along with some special logic for the start | 2286 // the body's entry block (along with some special logic for the start |
| 2289 // block in HInstruction::InsertAfter) seals the start block from | 2287 // block in HInstruction::InsertAfter) seals the start block from |
| 2290 // getting unwanted instructions inserted. | 2288 // getting unwanted instructions inserted. |
| 2291 // | 2289 // |
| 2292 // TODO(kmillikin): Fix this. Stop mutating the initial environment. | 2290 // TODO(kmillikin): Fix this. Stop mutating the initial environment. |
| 2293 // Make the Hydrogen instructions in the initial block into Hydrogen | 2291 // Make the Hydrogen instructions in the initial block into Hydrogen |
| 2294 // values (but not instructions), present in the initial environment and | 2292 // values (but not instructions), present in the initial environment and |
| 2295 // not replayed by the Lithium translation. | 2293 // not replayed by the Lithium translation. |
| 2296 HEnvironment* initial_env = environment()->CopyWithoutHistory(); | 2294 HEnvironment* initial_env = environment()->CopyWithoutHistory(); |
| 2297 HBasicBlock* body_entry = CreateBasicBlock(initial_env); | 2295 HBasicBlock* body_entry = CreateBasicBlock(initial_env); |
| 2298 current_block()->Goto(body_entry); | 2296 current_block()->Goto(body_entry); |
| 2299 body_entry->SetJoinId(AstNode::kFunctionEntryId); | 2297 body_entry->SetJoinId(AstNode::kFunctionEntryId); |
| 2300 set_current_block(body_entry); | 2298 set_current_block(body_entry); |
| 2299 |
| 2300 // Handle implicit declaration of the function name in named function |
| 2301 // expressions before other declarations. |
| 2302 if (scope->is_function_scope() && scope->function() != NULL) { |
| 2303 HandleDeclaration(scope->function(), Variable::CONST, NULL); |
| 2304 } |
| 2305 VisitDeclarations(scope->declarations()); |
| 2306 AddSimulate(AstNode::kDeclarationsId); |
| 2307 |
| 2308 HValue* context = environment()->LookupContext(); |
| 2309 AddInstruction( |
| 2310 new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry)); |
| 2311 |
| 2301 VisitStatements(info()->function()->body()); | 2312 VisitStatements(info()->function()->body()); |
| 2302 if (HasStackOverflow()) return NULL; | 2313 if (HasStackOverflow()) return NULL; |
| 2303 | 2314 |
| 2304 if (current_block() != NULL) { | 2315 if (current_block() != NULL) { |
| 2305 HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined()); | 2316 HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined()); |
| 2306 current_block()->FinishExit(instr); | 2317 current_block()->FinishExit(instr); |
| 2307 set_current_block(NULL); | 2318 set_current_block(NULL); |
| 2308 } | 2319 } |
| 2309 } | 2320 } |
| 2310 | 2321 |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2636 | 2647 |
| 2637 | 2648 |
| 2638 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { | 2649 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { |
| 2639 ASSERT(!HasStackOverflow()); | 2650 ASSERT(!HasStackOverflow()); |
| 2640 ASSERT(current_block() != NULL); | 2651 ASSERT(current_block() != NULL); |
| 2641 ASSERT(current_block()->HasPredecessor()); | 2652 ASSERT(current_block()->HasPredecessor()); |
| 2642 return Bailout("WithStatement"); | 2653 return Bailout("WithStatement"); |
| 2643 } | 2654 } |
| 2644 | 2655 |
| 2645 | 2656 |
| 2646 void HGraphBuilder::VisitExitContextStatement(ExitContextStatement* stmt) { | |
| 2647 ASSERT(!HasStackOverflow()); | |
| 2648 ASSERT(current_block() != NULL); | |
| 2649 ASSERT(current_block()->HasPredecessor()); | |
| 2650 return Bailout("ExitContextStatement"); | |
| 2651 } | |
| 2652 | |
| 2653 | |
| 2654 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 2657 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| 2655 ASSERT(!HasStackOverflow()); | 2658 ASSERT(!HasStackOverflow()); |
| 2656 ASSERT(current_block() != NULL); | 2659 ASSERT(current_block() != NULL); |
| 2657 ASSERT(current_block()->HasPredecessor()); | 2660 ASSERT(current_block()->HasPredecessor()); |
| 2658 // We only optimize switch statements with smi-literal smi comparisons, | 2661 // We only optimize switch statements with smi-literal smi comparisons, |
| 2659 // with a bounded number of clauses. | 2662 // with a bounded number of clauses. |
| 2660 const int kCaseClauseLimit = 128; | 2663 const int kCaseClauseLimit = 128; |
| 2661 ZoneList<CaseClause*>* clauses = stmt->cases(); | 2664 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 2662 int clause_count = clauses->length(); | 2665 int clause_count = clauses->length(); |
| 2663 if (clause_count > kCaseClauseLimit) { | 2666 if (clause_count > kCaseClauseLimit) { |
| (...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3112 context = context_instruction; | 3115 context = context_instruction; |
| 3113 } | 3116 } |
| 3114 return context; | 3117 return context; |
| 3115 } | 3118 } |
| 3116 | 3119 |
| 3117 | 3120 |
| 3118 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 3121 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 3119 ASSERT(!HasStackOverflow()); | 3122 ASSERT(!HasStackOverflow()); |
| 3120 ASSERT(current_block() != NULL); | 3123 ASSERT(current_block() != NULL); |
| 3121 ASSERT(current_block()->HasPredecessor()); | 3124 ASSERT(current_block()->HasPredecessor()); |
| 3122 Variable* variable = expr->AsVariable(); | 3125 Variable* variable = expr->var(); |
| 3123 if (variable == NULL) { | 3126 if (variable->mode() == Variable::LET) { |
| 3124 return Bailout("reference to rewritten variable"); | 3127 return Bailout("reference to let variable"); |
| 3125 } else if (variable->IsStackAllocated()) { | 3128 } |
| 3126 HValue* value = environment()->Lookup(variable); | 3129 switch (variable->location()) { |
| 3127 if (variable->mode() == Variable::CONST && | 3130 case Variable::UNALLOCATED: { |
| 3128 value == graph()->GetConstantHole()) { | 3131 LookupResult lookup; |
| 3129 return Bailout("reference to uninitialized const variable"); | 3132 GlobalPropertyAccess type = |
| 3130 } | 3133 LookupGlobalProperty(variable, &lookup, false); |
| 3131 return ast_context()->ReturnValue(value); | |
| 3132 } else if (variable->IsContextSlot()) { | |
| 3133 if (variable->mode() == Variable::CONST) { | |
| 3134 return Bailout("reference to const context slot"); | |
| 3135 } | |
| 3136 HValue* context = BuildContextChainWalk(variable); | |
| 3137 int index = variable->AsSlot()->index(); | |
| 3138 HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, index); | |
| 3139 return ast_context()->ReturnInstruction(instr, expr->id()); | |
| 3140 } else if (variable->is_global()) { | |
| 3141 LookupResult lookup; | |
| 3142 GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false); | |
| 3143 | 3134 |
| 3144 if (type == kUseCell && | 3135 if (type == kUseCell && |
| 3145 info()->global_object()->IsAccessCheckNeeded()) { | 3136 info()->global_object()->IsAccessCheckNeeded()) { |
| 3146 type = kUseGeneric; | 3137 type = kUseGeneric; |
| 3138 } |
| 3139 |
| 3140 if (type == kUseCell) { |
| 3141 Handle<GlobalObject> global(info()->global_object()); |
| 3142 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 3143 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 3144 HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); |
| 3145 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 3146 } else { |
| 3147 HValue* context = environment()->LookupContext(); |
| 3148 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
| 3149 AddInstruction(global_object); |
| 3150 HLoadGlobalGeneric* instr = |
| 3151 new(zone()) HLoadGlobalGeneric(context, |
| 3152 global_object, |
| 3153 variable->name(), |
| 3154 ast_context()->is_for_typeof()); |
| 3155 instr->set_position(expr->position()); |
| 3156 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 3157 } |
| 3147 } | 3158 } |
| 3148 | 3159 |
| 3149 if (type == kUseCell) { | 3160 case Variable::PARAMETER: |
| 3150 Handle<GlobalObject> global(info()->global_object()); | 3161 case Variable::LOCAL: { |
| 3151 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3162 HValue* value = environment()->Lookup(variable); |
| 3152 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 3163 if (variable->mode() == Variable::CONST && |
| 3153 HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); | 3164 value == graph()->GetConstantHole()) { |
| 3154 return ast_context()->ReturnInstruction(instr, expr->id()); | 3165 return Bailout("reference to uninitialized const variable"); |
| 3155 } else { | 3166 } |
| 3156 HValue* context = environment()->LookupContext(); | 3167 return ast_context()->ReturnValue(value); |
| 3157 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 3168 } |
| 3158 AddInstruction(global_object); | 3169 |
| 3159 HLoadGlobalGeneric* instr = | 3170 case Variable::CONTEXT: { |
| 3160 new(zone()) HLoadGlobalGeneric(context, | 3171 if (variable->mode() == Variable::CONST) { |
| 3161 global_object, | 3172 return Bailout("reference to const context slot"); |
| 3162 variable->name(), | 3173 } |
| 3163 ast_context()->is_for_typeof()); | 3174 HValue* context = BuildContextChainWalk(variable); |
| 3164 instr->set_position(expr->position()); | 3175 HLoadContextSlot* instr = |
| 3165 ASSERT(instr->HasSideEffects()); | 3176 new(zone()) HLoadContextSlot(context, variable->index()); |
| 3166 return ast_context()->ReturnInstruction(instr, expr->id()); | 3177 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 3167 } | 3178 } |
| 3168 } else { | 3179 |
| 3169 return Bailout("reference to a variable which requires dynamic lookup"); | 3180 case Variable::LOOKUP: |
| 3181 return Bailout("reference to a variable which requires dynamic lookup"); |
| 3170 } | 3182 } |
| 3171 } | 3183 } |
| 3172 | 3184 |
| 3173 | 3185 |
| 3174 void HGraphBuilder::VisitLiteral(Literal* expr) { | 3186 void HGraphBuilder::VisitLiteral(Literal* expr) { |
| 3175 ASSERT(!HasStackOverflow()); | 3187 ASSERT(!HasStackOverflow()); |
| 3176 ASSERT(current_block() != NULL); | 3188 ASSERT(current_block() != NULL); |
| 3177 ASSERT(current_block()->HasPredecessor()); | 3189 ASSERT(current_block()->HasPredecessor()); |
| 3178 HConstant* instr = | 3190 HConstant* instr = |
| 3179 new(zone()) HConstant(expr->handle(), Representation::Tagged()); | 3191 new(zone()) HConstant(expr->handle(), Representation::Tagged()); |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3571 AddInstruction(instr); | 3583 AddInstruction(instr); |
| 3572 ASSERT(instr->HasSideEffects()); | 3584 ASSERT(instr->HasSideEffects()); |
| 3573 if (instr->HasSideEffects()) AddSimulate(ast_id); | 3585 if (instr->HasSideEffects()) AddSimulate(ast_id); |
| 3574 } | 3586 } |
| 3575 } | 3587 } |
| 3576 | 3588 |
| 3577 | 3589 |
| 3578 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { | 3590 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
| 3579 Expression* target = expr->target(); | 3591 Expression* target = expr->target(); |
| 3580 VariableProxy* proxy = target->AsVariableProxy(); | 3592 VariableProxy* proxy = target->AsVariableProxy(); |
| 3581 Variable* var = proxy->AsVariable(); | |
| 3582 Property* prop = target->AsProperty(); | 3593 Property* prop = target->AsProperty(); |
| 3583 ASSERT(var == NULL || prop == NULL); | 3594 ASSERT(proxy == NULL || prop == NULL); |
| 3584 | 3595 |
| 3585 // We have a second position recorded in the FullCodeGenerator to have | 3596 // We have a second position recorded in the FullCodeGenerator to have |
| 3586 // type feedback for the binary operation. | 3597 // type feedback for the binary operation. |
| 3587 BinaryOperation* operation = expr->binary_operation(); | 3598 BinaryOperation* operation = expr->binary_operation(); |
| 3588 | 3599 |
| 3589 if (var != NULL) { | 3600 if (proxy != NULL) { |
| 3590 if (var->mode() == Variable::CONST) { | 3601 Variable* var = proxy->var(); |
| 3591 return Bailout("unsupported const compound assignment"); | 3602 if (var->mode() == Variable::CONST || var->mode() == Variable::LET) { |
| 3603 return Bailout("unsupported let or const compound assignment"); |
| 3592 } | 3604 } |
| 3593 | 3605 |
| 3594 CHECK_ALIVE(VisitForValue(operation)); | 3606 CHECK_ALIVE(VisitForValue(operation)); |
| 3595 | 3607 |
| 3596 if (var->is_global()) { | 3608 switch (var->location()) { |
| 3597 HandleGlobalVariableAssignment(var, | 3609 case Variable::UNALLOCATED: |
| 3598 Top(), | 3610 HandleGlobalVariableAssignment(var, |
| 3599 expr->position(), | 3611 Top(), |
| 3600 expr->AssignmentId()); | 3612 expr->position(), |
| 3601 } else if (var->IsStackAllocated()) { | 3613 expr->AssignmentId()); |
| 3602 Bind(var, Top()); | 3614 break; |
| 3603 } else if (var->IsContextSlot()) { | 3615 |
| 3604 // Bail out if we try to mutate a parameter value in a function using | 3616 case Variable::PARAMETER: |
| 3605 // the arguments object. We do not (yet) correctly handle the | 3617 case Variable::LOCAL: |
| 3606 // arguments property of the function. | 3618 Bind(var, Top()); |
| 3607 if (info()->scope()->arguments() != NULL) { | 3619 break; |
| 3608 // Parameters will rewrite to context slots. We have no direct way | 3620 |
| 3609 // to detect that the variable is a parameter. | 3621 case Variable::CONTEXT: { |
| 3610 int count = info()->scope()->num_parameters(); | 3622 // Bail out if we try to mutate a parameter value in a function |
| 3611 for (int i = 0; i < count; ++i) { | 3623 // using the arguments object. We do not (yet) correctly handle the |
| 3612 if (var == info()->scope()->parameter(i)) { | 3624 // arguments property of the function. |
| 3613 Bailout("assignment to parameter, function uses arguments object"); | 3625 if (info()->scope()->arguments() != NULL) { |
| 3626 // Parameters will be allocated to context slots. We have no |
| 3627 // direct way to detect that the variable is a parameter so we do |
| 3628 // a linear search of the parameter variables. |
| 3629 int count = info()->scope()->num_parameters(); |
| 3630 for (int i = 0; i < count; ++i) { |
| 3631 if (var == info()->scope()->parameter(i)) { |
| 3632 Bailout( |
| 3633 "assignment to parameter, function uses arguments object"); |
| 3634 } |
| 3614 } | 3635 } |
| 3615 } | 3636 } |
| 3637 |
| 3638 HValue* context = BuildContextChainWalk(var); |
| 3639 HStoreContextSlot* instr = |
| 3640 new(zone()) HStoreContextSlot(context, var->index(), Top()); |
| 3641 AddInstruction(instr); |
| 3642 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3643 break; |
| 3616 } | 3644 } |
| 3617 | 3645 |
| 3618 HValue* context = BuildContextChainWalk(var); | 3646 case Variable::LOOKUP: |
| 3619 int index = var->AsSlot()->index(); | 3647 return Bailout("compound assignment to lookup slot"); |
| 3620 HStoreContextSlot* instr = | |
| 3621 new(zone()) HStoreContextSlot(context, index, Top()); | |
| 3622 AddInstruction(instr); | |
| 3623 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | |
| 3624 } else { | |
| 3625 return Bailout("compound assignment to lookup slot"); | |
| 3626 } | 3648 } |
| 3627 return ast_context()->ReturnValue(Pop()); | 3649 return ast_context()->ReturnValue(Pop()); |
| 3628 | 3650 |
| 3629 } else if (prop != NULL) { | 3651 } else if (prop != NULL) { |
| 3630 prop->RecordTypeFeedback(oracle()); | 3652 prop->RecordTypeFeedback(oracle()); |
| 3631 | 3653 |
| 3632 if (prop->key()->IsPropertyName()) { | 3654 if (prop->key()->IsPropertyName()) { |
| 3633 // Named property. | 3655 // Named property. |
| 3634 CHECK_ALIVE(VisitForValue(prop->obj())); | 3656 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 3635 HValue* obj = Top(); | 3657 HValue* obj = Top(); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3703 return Bailout("invalid lhs in compound assignment"); | 3725 return Bailout("invalid lhs in compound assignment"); |
| 3704 } | 3726 } |
| 3705 } | 3727 } |
| 3706 | 3728 |
| 3707 | 3729 |
| 3708 void HGraphBuilder::VisitAssignment(Assignment* expr) { | 3730 void HGraphBuilder::VisitAssignment(Assignment* expr) { |
| 3709 ASSERT(!HasStackOverflow()); | 3731 ASSERT(!HasStackOverflow()); |
| 3710 ASSERT(current_block() != NULL); | 3732 ASSERT(current_block() != NULL); |
| 3711 ASSERT(current_block()->HasPredecessor()); | 3733 ASSERT(current_block()->HasPredecessor()); |
| 3712 VariableProxy* proxy = expr->target()->AsVariableProxy(); | 3734 VariableProxy* proxy = expr->target()->AsVariableProxy(); |
| 3713 Variable* var = proxy->AsVariable(); | |
| 3714 Property* prop = expr->target()->AsProperty(); | 3735 Property* prop = expr->target()->AsProperty(); |
| 3715 ASSERT(var == NULL || prop == NULL); | 3736 ASSERT(proxy == NULL || prop == NULL); |
| 3716 | 3737 |
| 3717 if (expr->is_compound()) { | 3738 if (expr->is_compound()) { |
| 3718 HandleCompoundAssignment(expr); | 3739 HandleCompoundAssignment(expr); |
| 3719 return; | 3740 return; |
| 3720 } | 3741 } |
| 3721 | 3742 |
| 3722 if (var != NULL) { | 3743 if (prop != NULL) { |
| 3744 HandlePropertyAssignment(expr); |
| 3745 } else if (proxy != NULL) { |
| 3746 Variable* var = proxy->var(); |
| 3723 if (var->mode() == Variable::CONST) { | 3747 if (var->mode() == Variable::CONST) { |
| 3724 if (expr->op() != Token::INIT_CONST) { | 3748 if (expr->op() != Token::INIT_CONST) { |
| 3725 return Bailout("non-initializer assignment to const"); | 3749 return Bailout("non-initializer assignment to const"); |
| 3726 } | 3750 } |
| 3727 if (!var->IsStackAllocated()) { | 3751 if (!var->IsStackAllocated()) { |
| 3728 return Bailout("assignment to const context slot"); | 3752 return Bailout("assignment to const context slot"); |
| 3729 } | 3753 } |
| 3730 // We insert a use of the old value to detect unsupported uses of const | 3754 // We insert a use of the old value to detect unsupported uses of const |
| 3731 // variables (e.g. initialization inside a loop). | 3755 // variables (e.g. initialization inside a loop). |
| 3732 HValue* old_value = environment()->Lookup(var); | 3756 HValue* old_value = environment()->Lookup(var); |
| 3733 AddInstruction(new HUseConst(old_value)); | 3757 AddInstruction(new HUseConst(old_value)); |
| 3758 } else if (var->mode() == Variable::LET) { |
| 3759 return Bailout("unsupported assignment to let"); |
| 3734 } | 3760 } |
| 3735 | 3761 |
| 3736 if (proxy->IsArguments()) return Bailout("assignment to arguments"); | 3762 if (proxy->IsArguments()) return Bailout("assignment to arguments"); |
| 3737 | 3763 |
| 3738 // Handle the assignment. | 3764 // Handle the assignment. |
| 3739 if (var->IsStackAllocated()) { | 3765 switch (var->location()) { |
| 3740 // We do not allow the arguments object to occur in a context where it | 3766 case Variable::UNALLOCATED: |
| 3741 // may escape, but assignments to stack-allocated locals are | 3767 CHECK_ALIVE(VisitForValue(expr->value())); |
| 3742 // permitted. | 3768 HandleGlobalVariableAssignment(var, |
| 3743 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); | 3769 Top(), |
| 3744 HValue* value = Pop(); | 3770 expr->position(), |
| 3745 Bind(var, value); | 3771 expr->AssignmentId()); |
| 3746 return ast_context()->ReturnValue(value); | 3772 return ast_context()->ReturnValue(Pop()); |
| 3747 | 3773 |
| 3748 } else if (var->IsContextSlot()) { | 3774 case Variable::PARAMETER: |
| 3749 ASSERT(var->mode() != Variable::CONST); | 3775 case Variable::LOCAL: { |
| 3750 // Bail out if we try to mutate a parameter value in a function using | 3776 // We do not allow the arguments object to occur in a context where it |
| 3751 // the arguments object. We do not (yet) correctly handle the | 3777 // may escape, but assignments to stack-allocated locals are |
| 3752 // arguments property of the function. | 3778 // permitted. |
| 3753 if (info()->scope()->arguments() != NULL) { | 3779 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); |
| 3754 // Parameters will rewrite to context slots. We have no direct way | 3780 HValue* value = Pop(); |
| 3755 // to detect that the variable is a parameter. | 3781 Bind(var, value); |
| 3756 int count = info()->scope()->num_parameters(); | 3782 return ast_context()->ReturnValue(value); |
| 3757 for (int i = 0; i < count; ++i) { | 3783 } |
| 3758 if (var == info()->scope()->parameter(i)) { | 3784 |
| 3759 Bailout("assignment to parameter, function uses arguments object"); | 3785 case Variable::CONTEXT: { |
| 3786 ASSERT(var->mode() != Variable::CONST); |
| 3787 // Bail out if we try to mutate a parameter value in a function using |
| 3788 // the arguments object. We do not (yet) correctly handle the |
| 3789 // arguments property of the function. |
| 3790 if (info()->scope()->arguments() != NULL) { |
| 3791 // Parameters will rewrite to context slots. We have no direct way |
| 3792 // to detect that the variable is a parameter. |
| 3793 int count = info()->scope()->num_parameters(); |
| 3794 for (int i = 0; i < count; ++i) { |
| 3795 if (var == info()->scope()->parameter(i)) { |
| 3796 return Bailout("assignment to parameter in arguments object"); |
| 3797 } |
| 3760 } | 3798 } |
| 3761 } | 3799 } |
| 3800 |
| 3801 CHECK_ALIVE(VisitForValue(expr->value())); |
| 3802 HValue* context = BuildContextChainWalk(var); |
| 3803 HStoreContextSlot* instr = |
| 3804 new(zone()) HStoreContextSlot(context, var->index(), Top()); |
| 3805 AddInstruction(instr); |
| 3806 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3807 return ast_context()->ReturnValue(Pop()); |
| 3762 } | 3808 } |
| 3763 | 3809 |
| 3764 CHECK_ALIVE(VisitForValue(expr->value())); | 3810 case Variable::LOOKUP: |
| 3765 HValue* context = BuildContextChainWalk(var); | 3811 return Bailout("assignment to LOOKUP variable"); |
| 3766 int index = var->AsSlot()->index(); | |
| 3767 HStoreContextSlot* instr = | |
| 3768 new(zone()) HStoreContextSlot(context, index, Top()); | |
| 3769 AddInstruction(instr); | |
| 3770 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | |
| 3771 return ast_context()->ReturnValue(Pop()); | |
| 3772 | |
| 3773 } else if (var->is_global()) { | |
| 3774 CHECK_ALIVE(VisitForValue(expr->value())); | |
| 3775 HandleGlobalVariableAssignment(var, | |
| 3776 Top(), | |
| 3777 expr->position(), | |
| 3778 expr->AssignmentId()); | |
| 3779 return ast_context()->ReturnValue(Pop()); | |
| 3780 | |
| 3781 } else { | |
| 3782 return Bailout("assignment to LOOKUP or const CONTEXT variable"); | |
| 3783 } | 3812 } |
| 3784 | |
| 3785 } else if (prop != NULL) { | |
| 3786 HandlePropertyAssignment(expr); | |
| 3787 } else { | 3813 } else { |
| 3788 return Bailout("invalid left-hand side in assignment"); | 3814 return Bailout("invalid left-hand side in assignment"); |
| 3789 } | 3815 } |
| 3790 } | 3816 } |
| 3791 | 3817 |
| 3792 | 3818 |
| 3793 void HGraphBuilder::VisitThrow(Throw* expr) { | 3819 void HGraphBuilder::VisitThrow(Throw* expr) { |
| 3794 ASSERT(!HasStackOverflow()); | 3820 ASSERT(!HasStackOverflow()); |
| 3795 ASSERT(current_block() != NULL); | 3821 ASSERT(current_block() != NULL); |
| 3796 ASSERT(current_block()->HasPredecessor()); | 3822 ASSERT(current_block()->HasPredecessor()); |
| (...skipping 991 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4788 // Our implementation of arguments (based on this stack frame or an | 4814 // Our implementation of arguments (based on this stack frame or an |
| 4789 // adapter below it) does not work for inlined functions. | 4815 // adapter below it) does not work for inlined functions. |
| 4790 if (function_state()->outer() != NULL) { | 4816 if (function_state()->outer() != NULL) { |
| 4791 Bailout("Function.prototype.apply optimization in inlined function"); | 4817 Bailout("Function.prototype.apply optimization in inlined function"); |
| 4792 return true; | 4818 return true; |
| 4793 } | 4819 } |
| 4794 | 4820 |
| 4795 // Found pattern f.apply(receiver, arguments). | 4821 // Found pattern f.apply(receiver, arguments). |
| 4796 VisitForValue(prop->obj()); | 4822 VisitForValue(prop->obj()); |
| 4797 if (HasStackOverflow() || current_block() == NULL) return true; | 4823 if (HasStackOverflow() || current_block() == NULL) return true; |
| 4798 HValue* function = Pop(); | 4824 HValue* function = Top(); |
| 4825 AddCheckConstantFunction(expr, function, function_map, true); |
| 4826 Drop(1); |
| 4827 |
| 4799 VisitForValue(args->at(0)); | 4828 VisitForValue(args->at(0)); |
| 4800 if (HasStackOverflow() || current_block() == NULL) return true; | 4829 if (HasStackOverflow() || current_block() == NULL) return true; |
| 4801 HValue* receiver = Pop(); | 4830 HValue* receiver = Pop(); |
| 4802 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 4831 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
| 4803 HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); | 4832 HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); |
| 4804 AddCheckConstantFunction(expr, function, function_map, true); | |
| 4805 HInstruction* result = | 4833 HInstruction* result = |
| 4806 new(zone()) HApplyArguments(function, receiver, length, elements); | 4834 new(zone()) HApplyArguments(function, receiver, length, elements); |
| 4807 result->set_position(expr->position()); | 4835 result->set_position(expr->position()); |
| 4808 ast_context()->ReturnInstruction(result, expr->id()); | 4836 ast_context()->ReturnInstruction(result, expr->id()); |
| 4809 return true; | 4837 return true; |
| 4810 } | 4838 } |
| 4811 | 4839 |
| 4812 | 4840 |
| 4813 void HGraphBuilder::VisitCall(Call* expr) { | 4841 void HGraphBuilder::VisitCall(Call* expr) { |
| 4814 ASSERT(!HasStackOverflow()); | 4842 ASSERT(!HasStackOverflow()); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4886 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4914 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4887 return; | 4915 return; |
| 4888 | 4916 |
| 4889 } else { | 4917 } else { |
| 4890 HValue* context = environment()->LookupContext(); | 4918 HValue* context = environment()->LookupContext(); |
| 4891 call = PreProcessCall( | 4919 call = PreProcessCall( |
| 4892 new(zone()) HCallNamed(context, name, argument_count)); | 4920 new(zone()) HCallNamed(context, name, argument_count)); |
| 4893 } | 4921 } |
| 4894 | 4922 |
| 4895 } else { | 4923 } else { |
| 4896 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4924 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
| 4897 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); | 4925 // FIXME. |
| 4926 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); |
| 4898 | 4927 |
| 4899 if (global_call) { | 4928 if (global_call) { |
| 4929 Variable* var = proxy->var(); |
| 4900 bool known_global_function = false; | 4930 bool known_global_function = false; |
| 4901 // If there is a global property cell for the name at compile time and | 4931 // If there is a global property cell for the name at compile time and |
| 4902 // access check is not enabled we assume that the function will not change | 4932 // access check is not enabled we assume that the function will not change |
| 4903 // and generate optimized code for calling the function. | 4933 // and generate optimized code for calling the function. |
| 4904 LookupResult lookup; | 4934 LookupResult lookup; |
| 4905 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); | 4935 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); |
| 4906 if (type == kUseCell && | 4936 if (type == kUseCell && |
| 4907 !info()->global_object()->IsAccessCheckNeeded()) { | 4937 !info()->global_object()->IsAccessCheckNeeded()) { |
| 4908 Handle<GlobalObject> global(info()->global_object()); | 4938 Handle<GlobalObject> global(info()->global_object()); |
| 4909 known_global_function = expr->ComputeGlobalTarget(global, &lookup); | 4939 known_global_function = expr->ComputeGlobalTarget(global, &lookup); |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5053 case Token::ADD: return VisitAdd(expr); | 5083 case Token::ADD: return VisitAdd(expr); |
| 5054 case Token::SUB: return VisitSub(expr); | 5084 case Token::SUB: return VisitSub(expr); |
| 5055 case Token::BIT_NOT: return VisitBitNot(expr); | 5085 case Token::BIT_NOT: return VisitBitNot(expr); |
| 5056 case Token::NOT: return VisitNot(expr); | 5086 case Token::NOT: return VisitNot(expr); |
| 5057 default: UNREACHABLE(); | 5087 default: UNREACHABLE(); |
| 5058 } | 5088 } |
| 5059 } | 5089 } |
| 5060 | 5090 |
| 5061 void HGraphBuilder::VisitDelete(UnaryOperation* expr) { | 5091 void HGraphBuilder::VisitDelete(UnaryOperation* expr) { |
| 5062 Property* prop = expr->expression()->AsProperty(); | 5092 Property* prop = expr->expression()->AsProperty(); |
| 5063 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 5093 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
| 5064 if (prop == NULL && var == NULL) { | 5094 if (prop != NULL) { |
| 5095 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 5096 CHECK_ALIVE(VisitForValue(prop->key())); |
| 5097 HValue* key = Pop(); |
| 5098 HValue* obj = Pop(); |
| 5099 HValue* context = environment()->LookupContext(); |
| 5100 HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key); |
| 5101 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 5102 } else if (proxy != NULL) { |
| 5103 Variable* var = proxy->var(); |
| 5104 if (var->IsUnallocated()) { |
| 5105 Bailout("delete with global variable"); |
| 5106 } else if (var->IsStackAllocated() || var->IsContextSlot()) { |
| 5107 // Result of deleting non-global variables is false. 'this' is not |
| 5108 // really a variable, though we implement it as one. The |
| 5109 // subexpression does not have side effects. |
| 5110 HValue* value = var->is_this() |
| 5111 ? graph()->GetConstantTrue() |
| 5112 : graph()->GetConstantFalse(); |
| 5113 return ast_context()->ReturnValue(value); |
| 5114 } else { |
| 5115 Bailout("delete with non-global variable"); |
| 5116 } |
| 5117 } else { |
| 5065 // Result of deleting non-property, non-variable reference is true. | 5118 // Result of deleting non-property, non-variable reference is true. |
| 5066 // Evaluate the subexpression for side effects. | 5119 // Evaluate the subexpression for side effects. |
| 5067 CHECK_ALIVE(VisitForEffect(expr->expression())); | 5120 CHECK_ALIVE(VisitForEffect(expr->expression())); |
| 5068 return ast_context()->ReturnValue(graph()->GetConstantTrue()); | 5121 return ast_context()->ReturnValue(graph()->GetConstantTrue()); |
| 5069 } else if (var != NULL && | |
| 5070 !var->is_global() && | |
| 5071 var->AsSlot() != NULL && | |
| 5072 var->AsSlot()->type() != Slot::LOOKUP) { | |
| 5073 // Result of deleting non-global, non-dynamic variables is false. | |
| 5074 // The subexpression does not have side effects. | |
| 5075 return ast_context()->ReturnValue(graph()->GetConstantFalse()); | |
| 5076 } else if (prop != NULL) { | |
| 5077 if (prop->is_synthetic()) { | |
| 5078 // Result of deleting parameters is false, even when they rewrite | |
| 5079 // to accesses on the arguments object. | |
| 5080 return ast_context()->ReturnValue(graph()->GetConstantFalse()); | |
| 5081 } else { | |
| 5082 CHECK_ALIVE(VisitForValue(prop->obj())); | |
| 5083 CHECK_ALIVE(VisitForValue(prop->key())); | |
| 5084 HValue* key = Pop(); | |
| 5085 HValue* obj = Pop(); | |
| 5086 HValue* context = environment()->LookupContext(); | |
| 5087 HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key); | |
| 5088 return ast_context()->ReturnInstruction(instr, expr->id()); | |
| 5089 } | |
| 5090 } else if (var->is_global()) { | |
| 5091 Bailout("delete with global variable"); | |
| 5092 } else { | |
| 5093 Bailout("delete with non-global variable"); | |
| 5094 } | 5122 } |
| 5095 } | 5123 } |
| 5096 | 5124 |
| 5097 | 5125 |
| 5098 void HGraphBuilder::VisitVoid(UnaryOperation* expr) { | 5126 void HGraphBuilder::VisitVoid(UnaryOperation* expr) { |
| 5099 CHECK_ALIVE(VisitForEffect(expr->expression())); | 5127 CHECK_ALIVE(VisitForEffect(expr->expression())); |
| 5100 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 5128 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 5101 } | 5129 } |
| 5102 | 5130 |
| 5103 | 5131 |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5230 return instr; | 5258 return instr; |
| 5231 } | 5259 } |
| 5232 | 5260 |
| 5233 | 5261 |
| 5234 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { | 5262 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| 5235 ASSERT(!HasStackOverflow()); | 5263 ASSERT(!HasStackOverflow()); |
| 5236 ASSERT(current_block() != NULL); | 5264 ASSERT(current_block() != NULL); |
| 5237 ASSERT(current_block()->HasPredecessor()); | 5265 ASSERT(current_block()->HasPredecessor()); |
| 5238 Expression* target = expr->expression(); | 5266 Expression* target = expr->expression(); |
| 5239 VariableProxy* proxy = target->AsVariableProxy(); | 5267 VariableProxy* proxy = target->AsVariableProxy(); |
| 5240 Variable* var = proxy->AsVariable(); | |
| 5241 Property* prop = target->AsProperty(); | 5268 Property* prop = target->AsProperty(); |
| 5242 if (var == NULL && prop == NULL) { | 5269 if (proxy == NULL && prop == NULL) { |
| 5243 return Bailout("invalid lhs in count operation"); | 5270 return Bailout("invalid lhs in count operation"); |
| 5244 } | 5271 } |
| 5245 | 5272 |
| 5246 // Match the full code generator stack by simulating an extra stack | 5273 // Match the full code generator stack by simulating an extra stack |
| 5247 // element for postfix operations in a non-effect context. The return | 5274 // element for postfix operations in a non-effect context. The return |
| 5248 // value is ToNumber(input). | 5275 // value is ToNumber(input). |
| 5249 bool returns_original_input = | 5276 bool returns_original_input = |
| 5250 expr->is_postfix() && !ast_context()->IsEffect(); | 5277 expr->is_postfix() && !ast_context()->IsEffect(); |
| 5251 HValue* input = NULL; // ToNumber(original_input). | 5278 HValue* input = NULL; // ToNumber(original_input). |
| 5252 HValue* after = NULL; // The result after incrementing or decrementing. | 5279 HValue* after = NULL; // The result after incrementing or decrementing. |
| 5253 | 5280 |
| 5254 if (var != NULL) { | 5281 if (proxy != NULL) { |
| 5282 Variable* var = proxy->var(); |
| 5255 if (var->mode() == Variable::CONST) { | 5283 if (var->mode() == Variable::CONST) { |
| 5256 return Bailout("unsupported count operation with const"); | 5284 return Bailout("unsupported count operation with const"); |
| 5257 } | 5285 } |
| 5258 // Argument of the count operation is a variable, not a property. | 5286 // Argument of the count operation is a variable, not a property. |
| 5259 ASSERT(prop == NULL); | 5287 ASSERT(prop == NULL); |
| 5260 CHECK_ALIVE(VisitForValue(target)); | 5288 CHECK_ALIVE(VisitForValue(target)); |
| 5261 | 5289 |
| 5262 after = BuildIncrement(returns_original_input, expr); | 5290 after = BuildIncrement(returns_original_input, expr); |
| 5263 input = returns_original_input ? Top() : Pop(); | 5291 input = returns_original_input ? Top() : Pop(); |
| 5264 Push(after); | 5292 Push(after); |
| 5265 | 5293 |
| 5266 if (var->is_global()) { | 5294 switch (var->location()) { |
| 5267 HandleGlobalVariableAssignment(var, | 5295 case Variable::UNALLOCATED: |
| 5268 after, | 5296 HandleGlobalVariableAssignment(var, |
| 5269 expr->position(), | 5297 after, |
| 5270 expr->AssignmentId()); | 5298 expr->position(), |
| 5271 } else if (var->IsStackAllocated()) { | 5299 expr->AssignmentId()); |
| 5272 Bind(var, after); | 5300 break; |
| 5273 } else if (var->IsContextSlot()) { | 5301 |
| 5274 // Bail out if we try to mutate a parameter value in a function using | 5302 case Variable::PARAMETER: |
| 5275 // the arguments object. We do not (yet) correctly handle the | 5303 case Variable::LOCAL: |
| 5276 // arguments property of the function. | 5304 Bind(var, after); |
| 5277 if (info()->scope()->arguments() != NULL) { | 5305 break; |
| 5278 // Parameters will rewrite to context slots. We have no direct way | 5306 |
| 5279 // to detect that the variable is a parameter. | 5307 case Variable::CONTEXT: { |
| 5280 int count = info()->scope()->num_parameters(); | 5308 // Bail out if we try to mutate a parameter value in a function |
| 5281 for (int i = 0; i < count; ++i) { | 5309 // using the arguments object. We do not (yet) correctly handle the |
| 5282 if (var == info()->scope()->parameter(i)) { | 5310 // arguments property of the function. |
| 5283 Bailout("assignment to parameter, function uses arguments object"); | 5311 if (info()->scope()->arguments() != NULL) { |
| 5312 // Parameters will rewrite to context slots. We have no direct |
| 5313 // way to detect that the variable is a parameter so we use a |
| 5314 // linear search of the parameter list. |
| 5315 int count = info()->scope()->num_parameters(); |
| 5316 for (int i = 0; i < count; ++i) { |
| 5317 if (var == info()->scope()->parameter(i)) { |
| 5318 return Bailout("assignment to parameter in arguments object"); |
| 5319 } |
| 5284 } | 5320 } |
| 5285 } | 5321 } |
| 5322 |
| 5323 HValue* context = BuildContextChainWalk(var); |
| 5324 HStoreContextSlot* instr = |
| 5325 new(zone()) HStoreContextSlot(context, var->index(), after); |
| 5326 AddInstruction(instr); |
| 5327 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 5328 break; |
| 5286 } | 5329 } |
| 5287 | 5330 |
| 5288 HValue* context = BuildContextChainWalk(var); | 5331 case Variable::LOOKUP: |
| 5289 int index = var->AsSlot()->index(); | 5332 return Bailout("lookup variable in count operation"); |
| 5290 HStoreContextSlot* instr = | |
| 5291 new(zone()) HStoreContextSlot(context, index, after); | |
| 5292 AddInstruction(instr); | |
| 5293 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | |
| 5294 } else { | |
| 5295 return Bailout("lookup variable in count operation"); | |
| 5296 } | 5333 } |
| 5297 | 5334 |
| 5298 } else { | 5335 } else { |
| 5299 // Argument of the count operation is a property. | 5336 // Argument of the count operation is a property. |
| 5300 ASSERT(prop != NULL); | 5337 ASSERT(prop != NULL); |
| 5301 prop->RecordTypeFeedback(oracle()); | 5338 prop->RecordTypeFeedback(oracle()); |
| 5302 | 5339 |
| 5303 if (prop->key()->IsPropertyName()) { | 5340 if (prop->key()->IsPropertyName()) { |
| 5304 // Named property. | 5341 // Named property. |
| 5305 if (returns_original_input) Push(graph_->GetConstantUndefined()); | 5342 if (returns_original_input) Push(graph_->GetConstantUndefined()); |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5697 HValue* context = environment()->LookupContext(); | 5734 HValue* context = environment()->LookupContext(); |
| 5698 HValue* right = Pop(); | 5735 HValue* right = Pop(); |
| 5699 HValue* left = Pop(); | 5736 HValue* left = Pop(); |
| 5700 Token::Value op = expr->op(); | 5737 Token::Value op = expr->op(); |
| 5701 | 5738 |
| 5702 if (op == Token::INSTANCEOF) { | 5739 if (op == Token::INSTANCEOF) { |
| 5703 // Check to see if the rhs of the instanceof is a global function not | 5740 // Check to see if the rhs of the instanceof is a global function not |
| 5704 // residing in new space. If it is we assume that the function will stay the | 5741 // residing in new space. If it is we assume that the function will stay the |
| 5705 // same. | 5742 // same. |
| 5706 Handle<JSFunction> target = Handle<JSFunction>::null(); | 5743 Handle<JSFunction> target = Handle<JSFunction>::null(); |
| 5707 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); | 5744 VariableProxy* proxy = expr->right()->AsVariableProxy(); |
| 5708 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); | 5745 bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated(); |
| 5709 if (global_function && | 5746 if (global_function && |
| 5710 info()->has_global_object() && | 5747 info()->has_global_object() && |
| 5711 !info()->global_object()->IsAccessCheckNeeded()) { | 5748 !info()->global_object()->IsAccessCheckNeeded()) { |
| 5712 Handle<String> name = var->name(); | 5749 Handle<String> name = proxy->name(); |
| 5713 Handle<GlobalObject> global(info()->global_object()); | 5750 Handle<GlobalObject> global(info()->global_object()); |
| 5714 LookupResult lookup; | 5751 LookupResult lookup; |
| 5715 global->Lookup(*name, &lookup); | 5752 global->Lookup(*name, &lookup); |
| 5716 if (lookup.IsProperty() && | 5753 if (lookup.IsProperty() && |
| 5717 lookup.type() == NORMAL && | 5754 lookup.type() == NORMAL && |
| 5718 lookup.GetValue()->IsJSFunction()) { | 5755 lookup.GetValue()->IsJSFunction()) { |
| 5719 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); | 5756 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); |
| 5720 // If the function is in new space we assume it's more likely to | 5757 // If the function is in new space we assume it's more likely to |
| 5721 // change and thus prefer the general IC code. | 5758 // change and thus prefer the general IC code. |
| 5722 if (!isolate()->heap()->InNewSpace(*candidate)) { | 5759 if (!isolate()->heap()->InNewSpace(*candidate)) { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5801 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { | 5838 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { |
| 5802 ASSERT(!HasStackOverflow()); | 5839 ASSERT(!HasStackOverflow()); |
| 5803 ASSERT(current_block() != NULL); | 5840 ASSERT(current_block() != NULL); |
| 5804 ASSERT(current_block()->HasPredecessor()); | 5841 ASSERT(current_block()->HasPredecessor()); |
| 5805 HThisFunction* self = new(zone()) HThisFunction; | 5842 HThisFunction* self = new(zone()) HThisFunction; |
| 5806 return ast_context()->ReturnInstruction(self, expr->id()); | 5843 return ast_context()->ReturnInstruction(self, expr->id()); |
| 5807 } | 5844 } |
| 5808 | 5845 |
| 5809 | 5846 |
| 5810 void HGraphBuilder::VisitDeclaration(Declaration* decl) { | 5847 void HGraphBuilder::VisitDeclaration(Declaration* decl) { |
| 5811 // We support only declarations that do not require code generation. | 5848 HandleDeclaration(decl->proxy(), decl->mode(), decl->fun()); |
| 5812 Variable* var = decl->proxy()->var(); | 5849 } |
| 5813 if (!var->IsStackAllocated() || decl->fun() != NULL) { | |
| 5814 return Bailout("unsupported declaration"); | |
| 5815 } | |
| 5816 | 5850 |
| 5817 if (decl->mode() == Variable::CONST) { | 5851 |
| 5818 ASSERT(var->IsStackAllocated()); | 5852 void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, |
| 5819 environment()->Bind(var, graph()->GetConstantHole()); | 5853 Variable::Mode mode, |
| 5854 FunctionLiteral* function) { |
| 5855 if (mode == Variable::LET) return Bailout("unsupported let declaration"); |
| 5856 Variable* var = proxy->var(); |
| 5857 switch (var->location()) { |
| 5858 case Variable::UNALLOCATED: |
| 5859 return Bailout("unsupported global declaration"); |
| 5860 case Variable::PARAMETER: |
| 5861 case Variable::LOCAL: |
| 5862 case Variable::CONTEXT: |
| 5863 if (mode == Variable::CONST || function != NULL) { |
| 5864 HValue* value = NULL; |
| 5865 if (mode == Variable::CONST) { |
| 5866 value = graph()->GetConstantHole(); |
| 5867 } else { |
| 5868 VisitForValue(function); |
| 5869 value = Pop(); |
| 5870 } |
| 5871 if (var->IsContextSlot()) { |
| 5872 HValue* context = environment()->LookupContext(); |
| 5873 HStoreContextSlot* store = |
| 5874 new HStoreContextSlot(context, var->index(), value); |
| 5875 AddInstruction(store); |
| 5876 if (store->HasSideEffects()) AddSimulate(proxy->id()); |
| 5877 } else { |
| 5878 environment()->Bind(var, value); |
| 5879 } |
| 5880 } |
| 5881 break; |
| 5882 case Variable::LOOKUP: |
| 5883 return Bailout("unsupported lookup slot in declaration"); |
| 5820 } | 5884 } |
| 5821 } | 5885 } |
| 5822 | 5886 |
| 5823 | 5887 |
| 5824 // Generators for inline runtime functions. | 5888 // Generators for inline runtime functions. |
| 5825 // Support for types. | 5889 // Support for types. |
| 5826 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { | 5890 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { |
| 5827 ASSERT(call->arguments()->length() == 1); | 5891 ASSERT(call->arguments()->length() == 1); |
| 5828 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5892 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5829 HValue* value = Pop(); | 5893 HValue* value = Pop(); |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6215 HGetCachedArrayIndex* result = new(zone()) HGetCachedArrayIndex(value); | 6279 HGetCachedArrayIndex* result = new(zone()) HGetCachedArrayIndex(value); |
| 6216 return ast_context()->ReturnInstruction(result, call->id()); | 6280 return ast_context()->ReturnInstruction(result, call->id()); |
| 6217 } | 6281 } |
| 6218 | 6282 |
| 6219 | 6283 |
| 6220 void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { | 6284 void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { |
| 6221 return Bailout("inlined runtime function: FastAsciiArrayJoin"); | 6285 return Bailout("inlined runtime function: FastAsciiArrayJoin"); |
| 6222 } | 6286 } |
| 6223 | 6287 |
| 6224 | 6288 |
| 6225 void HGraphBuilder::GenerateIsNativeOrStrictMode(CallRuntime* call) { | |
| 6226 return Bailout("inlined runtime function: IsNativeOrStrictMode"); | |
| 6227 } | |
| 6228 | |
| 6229 | |
| 6230 #undef CHECK_BAILOUT | 6289 #undef CHECK_BAILOUT |
| 6231 #undef CHECK_ALIVE | 6290 #undef CHECK_ALIVE |
| 6232 | 6291 |
| 6233 | 6292 |
| 6234 HEnvironment::HEnvironment(HEnvironment* outer, | 6293 HEnvironment::HEnvironment(HEnvironment* outer, |
| 6235 Scope* scope, | 6294 Scope* scope, |
| 6236 Handle<JSFunction> closure) | 6295 Handle<JSFunction> closure) |
| 6237 : closure_(closure), | 6296 : closure_(closure), |
| 6238 values_(0), | 6297 values_(0), |
| 6239 assigned_variables_(4), | 6298 assigned_variables_(4), |
| (...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6751 } | 6810 } |
| 6752 } | 6811 } |
| 6753 | 6812 |
| 6754 #ifdef DEBUG | 6813 #ifdef DEBUG |
| 6755 if (graph_ != NULL) graph_->Verify(); | 6814 if (graph_ != NULL) graph_->Verify(); |
| 6756 if (allocator_ != NULL) allocator_->Verify(); | 6815 if (allocator_ != NULL) allocator_->Verify(); |
| 6757 #endif | 6816 #endif |
| 6758 } | 6817 } |
| 6759 | 6818 |
| 6760 } } // namespace v8::internal | 6819 } } // namespace v8::internal |
| OLD | NEW |