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 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 } | 415 } |
416 } | 416 } |
417 | 417 |
418 int visited_count_; | 418 int visited_count_; |
419 ZoneList<HBasicBlock*> stack_; | 419 ZoneList<HBasicBlock*> stack_; |
420 BitVector reachable_; | 420 BitVector reachable_; |
421 HBasicBlock* dont_visit_; | 421 HBasicBlock* dont_visit_; |
422 }; | 422 }; |
423 | 423 |
424 | 424 |
425 void HGraph::Verify() const { | 425 void HGraph::Verify(bool do_full_verify) const { |
426 for (int i = 0; i < blocks_.length(); i++) { | 426 for (int i = 0; i < blocks_.length(); i++) { |
427 HBasicBlock* block = blocks_.at(i); | 427 HBasicBlock* block = blocks_.at(i); |
428 | 428 |
429 block->Verify(); | 429 block->Verify(); |
430 | 430 |
431 // Check that every block contains at least one node and that only the last | 431 // Check that every block contains at least one node and that only the last |
432 // node is a control instruction. | 432 // node is a control instruction. |
433 HInstruction* current = block->first(); | 433 HInstruction* current = block->first(); |
434 ASSERT(current != NULL && current->IsBlockEntry()); | 434 ASSERT(current != NULL && current->IsBlockEntry()); |
435 while (current != NULL) { | 435 while (current != NULL) { |
(...skipping 30 matching lines...) Expand all Loading... |
466 HBasicBlock* predecessor = block->predecessors()->at(k); | 466 HBasicBlock* predecessor = block->predecessors()->at(k); |
467 ASSERT(predecessor->end()->IsGoto()); | 467 ASSERT(predecessor->end()->IsGoto()); |
468 ASSERT(predecessor->last_environment()->ast_id() == id); | 468 ASSERT(predecessor->last_environment()->ast_id() == id); |
469 } | 469 } |
470 } | 470 } |
471 } | 471 } |
472 | 472 |
473 // Check special property of first block to have no predecessors. | 473 // Check special property of first block to have no predecessors. |
474 ASSERT(blocks_.at(0)->predecessors()->is_empty()); | 474 ASSERT(blocks_.at(0)->predecessors()->is_empty()); |
475 | 475 |
476 // Check that the graph is fully connected. | 476 if (do_full_verify) { |
477 ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL); | 477 // Check that the graph is fully connected. |
478 ASSERT(analyzer.visited_count() == blocks_.length()); | 478 ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL); |
| 479 ASSERT(analyzer.visited_count() == blocks_.length()); |
479 | 480 |
480 // Check that entry block dominator is NULL. | 481 // Check that entry block dominator is NULL. |
481 ASSERT(entry_block_->dominator() == NULL); | 482 ASSERT(entry_block_->dominator() == NULL); |
482 | 483 |
483 // Check dominators. | 484 // Check dominators. |
484 for (int i = 0; i < blocks_.length(); ++i) { | 485 for (int i = 0; i < blocks_.length(); ++i) { |
485 HBasicBlock* block = blocks_.at(i); | 486 HBasicBlock* block = blocks_.at(i); |
486 if (block->dominator() == NULL) { | 487 if (block->dominator() == NULL) { |
487 // Only start block may have no dominator assigned to. | 488 // Only start block may have no dominator assigned to. |
488 ASSERT(i == 0); | 489 ASSERT(i == 0); |
489 } else { | 490 } else { |
490 // Assert that block is unreachable if dominator must not be visited. | 491 // Assert that block is unreachable if dominator must not be visited. |
491 ReachabilityAnalyzer dominator_analyzer(entry_block_, | 492 ReachabilityAnalyzer dominator_analyzer(entry_block_, |
492 blocks_.length(), | 493 blocks_.length(), |
493 block->dominator()); | 494 block->dominator()); |
494 ASSERT(!dominator_analyzer.reachable()->Contains(block->block_id())); | 495 ASSERT(!dominator_analyzer.reachable()->Contains(block->block_id())); |
| 496 } |
495 } | 497 } |
496 } | 498 } |
497 } | 499 } |
498 | 500 |
499 #endif | 501 #endif |
500 | 502 |
501 | 503 |
502 HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer, | 504 HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer, |
503 Object* value) { | 505 Object* value) { |
504 if (!pointer->is_set()) { | 506 if (!pointer->is_set()) { |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
843 HPhi* phi = phi_list[i]; | 845 HPhi* phi = phi_list[i]; |
844 if (!phi->is_live()) { | 846 if (!phi->is_live()) { |
845 HBasicBlock* block = phi->block(); | 847 HBasicBlock* block = phi->block(); |
846 block->RemovePhi(phi); | 848 block->RemovePhi(phi); |
847 block->RecordDeletedPhi(phi->merged_index()); | 849 block->RecordDeletedPhi(phi->merged_index()); |
848 } | 850 } |
849 } | 851 } |
850 } | 852 } |
851 | 853 |
852 | 854 |
853 bool HGraph::CheckPhis() { | 855 bool HGraph::CheckArgumentsPhiUses() { |
854 int block_count = blocks_.length(); | 856 int block_count = blocks_.length(); |
855 for (int i = 0; i < block_count; ++i) { | 857 for (int i = 0; i < block_count; ++i) { |
856 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { | 858 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { |
857 HPhi* phi = blocks_[i]->phis()->at(j); | 859 HPhi* phi = blocks_[i]->phis()->at(j); |
858 // We don't support phi uses of arguments for now. | 860 // We don't support phi uses of arguments for now. |
859 if (phi->CheckFlag(HValue::kIsArguments)) return false; | 861 if (phi->CheckFlag(HValue::kIsArguments)) return false; |
860 } | 862 } |
861 } | 863 } |
862 return true; | 864 return true; |
863 } | 865 } |
864 | 866 |
865 | 867 |
866 bool HGraph::CollectPhis() { | 868 bool HGraph::CheckConstPhiUses() { |
867 int block_count = blocks_.length(); | 869 int block_count = blocks_.length(); |
868 phi_list_ = new ZoneList<HPhi*>(block_count); | |
869 for (int i = 0; i < block_count; ++i) { | 870 for (int i = 0; i < block_count; ++i) { |
870 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { | 871 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { |
871 HPhi* phi = blocks_[i]->phis()->at(j); | 872 HPhi* phi = blocks_[i]->phis()->at(j); |
872 phi_list_->Add(phi); | |
873 // Check for the hole value (from an uninitialized const). | 873 // Check for the hole value (from an uninitialized const). |
874 for (int k = 0; k < phi->OperandCount(); k++) { | 874 for (int k = 0; k < phi->OperandCount(); k++) { |
875 if (phi->OperandAt(k) == GetConstantHole()) return false; | 875 if (phi->OperandAt(k) == GetConstantHole()) return false; |
876 } | 876 } |
877 } | 877 } |
878 } | 878 } |
879 return true; | 879 return true; |
880 } | 880 } |
881 | 881 |
882 | 882 |
| 883 void HGraph::CollectPhis() { |
| 884 int block_count = blocks_.length(); |
| 885 phi_list_ = new ZoneList<HPhi*>(block_count); |
| 886 for (int i = 0; i < block_count; ++i) { |
| 887 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { |
| 888 HPhi* phi = blocks_[i]->phis()->at(j); |
| 889 phi_list_->Add(phi); |
| 890 } |
| 891 } |
| 892 } |
| 893 |
| 894 |
883 void HGraph::InferTypes(ZoneList<HValue*>* worklist) { | 895 void HGraph::InferTypes(ZoneList<HValue*>* worklist) { |
884 BitVector in_worklist(GetMaximumValueID()); | 896 BitVector in_worklist(GetMaximumValueID()); |
885 for (int i = 0; i < worklist->length(); ++i) { | 897 for (int i = 0; i < worklist->length(); ++i) { |
886 ASSERT(!in_worklist.Contains(worklist->at(i)->id())); | 898 ASSERT(!in_worklist.Contains(worklist->at(i)->id())); |
887 in_worklist.Add(worklist->at(i)->id()); | 899 in_worklist.Add(worklist->at(i)->id()); |
888 } | 900 } |
889 | 901 |
890 while (!worklist->is_empty()) { | 902 while (!worklist->is_empty()) { |
891 HValue* current = worklist->RemoveLast(); | 903 HValue* current = worklist->RemoveLast(); |
892 in_worklist.Remove(current->id()); | 904 in_worklist.Remove(current->id()); |
(...skipping 948 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1841 use_value->CheckFlag(HValue::kDeoptimizeOnUndefined); | 1853 use_value->CheckFlag(HValue::kDeoptimizeOnUndefined); |
1842 if (value->IsConstant()) { | 1854 if (value->IsConstant()) { |
1843 HConstant* constant = HConstant::cast(value); | 1855 HConstant* constant = HConstant::cast(value); |
1844 // Try to create a new copy of the constant with the new representation. | 1856 // Try to create a new copy of the constant with the new representation. |
1845 new_value = is_truncating | 1857 new_value = is_truncating |
1846 ? constant->CopyToTruncatedInt32() | 1858 ? constant->CopyToTruncatedInt32() |
1847 : constant->CopyToRepresentation(to); | 1859 : constant->CopyToRepresentation(to); |
1848 } | 1860 } |
1849 | 1861 |
1850 if (new_value == NULL) { | 1862 if (new_value == NULL) { |
1851 new_value = new(zone()) HChange(value, value->representation(), to, | 1863 new_value = new(zone()) HChange(value, to, |
1852 is_truncating, deoptimize_on_undefined); | 1864 is_truncating, deoptimize_on_undefined); |
1853 } | 1865 } |
1854 | 1866 |
1855 new_value->InsertBefore(next); | 1867 new_value->InsertBefore(next); |
1856 use_value->SetOperandAt(use_index, new_value); | 1868 use_value->SetOperandAt(use_index, new_value); |
1857 } | 1869 } |
1858 | 1870 |
1859 | 1871 |
1860 void HGraph::InsertRepresentationChangesForValue(HValue* value) { | 1872 void HGraph::InsertRepresentationChangesForValue(HValue* value) { |
1861 Representation r = value->representation(); | 1873 Representation r = value->representation(); |
(...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2313 | 2325 |
2314 if (current_block() != NULL) { | 2326 if (current_block() != NULL) { |
2315 HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined()); | 2327 HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined()); |
2316 current_block()->FinishExit(instr); | 2328 current_block()->FinishExit(instr); |
2317 set_current_block(NULL); | 2329 set_current_block(NULL); |
2318 } | 2330 } |
2319 } | 2331 } |
2320 | 2332 |
2321 graph()->OrderBlocks(); | 2333 graph()->OrderBlocks(); |
2322 graph()->AssignDominators(); | 2334 graph()->AssignDominators(); |
| 2335 |
| 2336 #ifdef DEBUG |
| 2337 // Do a full verify after building the graph and computing dominators. |
| 2338 graph()->Verify(true); |
| 2339 #endif |
| 2340 |
2323 graph()->PropagateDeoptimizingMark(); | 2341 graph()->PropagateDeoptimizingMark(); |
| 2342 if (!graph()->CheckConstPhiUses()) { |
| 2343 Bailout("Unsupported phi use of const variable"); |
| 2344 return NULL; |
| 2345 } |
2324 graph()->EliminateRedundantPhis(); | 2346 graph()->EliminateRedundantPhis(); |
2325 if (!graph()->CheckPhis()) { | 2347 if (!graph()->CheckArgumentsPhiUses()) { |
2326 Bailout("Unsupported phi use of arguments object"); | 2348 Bailout("Unsupported phi use of arguments"); |
2327 return NULL; | 2349 return NULL; |
2328 } | 2350 } |
2329 if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis(); | 2351 if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis(); |
2330 if (!graph()->CollectPhis()) { | 2352 graph()->CollectPhis(); |
2331 Bailout("Unsupported phi use of uninitialized constant"); | |
2332 return NULL; | |
2333 } | |
2334 | 2353 |
2335 HInferRepresentation rep(graph()); | 2354 HInferRepresentation rep(graph()); |
2336 rep.Analyze(); | 2355 rep.Analyze(); |
2337 | 2356 |
2338 graph()->MarkDeoptimizeOnUndefined(); | 2357 graph()->MarkDeoptimizeOnUndefined(); |
2339 graph()->InsertRepresentationChanges(); | 2358 graph()->InsertRepresentationChanges(); |
2340 | 2359 |
2341 graph()->InitializeInferredTypes(); | 2360 graph()->InitializeInferredTypes(); |
2342 graph()->Canonicalize(); | 2361 graph()->Canonicalize(); |
2343 | 2362 |
(...skipping 776 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3120 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 3139 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
3121 ASSERT(!HasStackOverflow()); | 3140 ASSERT(!HasStackOverflow()); |
3122 ASSERT(current_block() != NULL); | 3141 ASSERT(current_block() != NULL); |
3123 ASSERT(current_block()->HasPredecessor()); | 3142 ASSERT(current_block()->HasPredecessor()); |
3124 Variable* variable = expr->var(); | 3143 Variable* variable = expr->var(); |
3125 if (variable->mode() == Variable::LET) { | 3144 if (variable->mode() == Variable::LET) { |
3126 return Bailout("reference to let variable"); | 3145 return Bailout("reference to let variable"); |
3127 } | 3146 } |
3128 switch (variable->location()) { | 3147 switch (variable->location()) { |
3129 case Variable::UNALLOCATED: { | 3148 case Variable::UNALLOCATED: { |
| 3149 // Handle known global constants like 'undefined' specially to avoid a |
| 3150 // load from a global cell for them. |
| 3151 Handle<Object> constant_value = |
| 3152 isolate()->factory()->GlobalConstantFor(variable->name()); |
| 3153 if (!constant_value.is_null()) { |
| 3154 HConstant* instr = |
| 3155 new(zone()) HConstant(constant_value, Representation::Tagged()); |
| 3156 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 3157 } |
| 3158 |
3130 LookupResult lookup; | 3159 LookupResult lookup; |
3131 GlobalPropertyAccess type = | 3160 GlobalPropertyAccess type = |
3132 LookupGlobalProperty(variable, &lookup, false); | 3161 LookupGlobalProperty(variable, &lookup, false); |
3133 | 3162 |
3134 if (type == kUseCell && | 3163 if (type == kUseCell && |
3135 info()->global_object()->IsAccessCheckNeeded()) { | 3164 info()->global_object()->IsAccessCheckNeeded()) { |
3136 type = kUseGeneric; | 3165 type = kUseGeneric; |
3137 } | 3166 } |
3138 | 3167 |
3139 if (type == kUseCell) { | 3168 if (type == kUseCell) { |
3140 Handle<GlobalObject> global(info()->global_object()); | 3169 Handle<GlobalObject> global(info()->global_object()); |
3141 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3170 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
3142 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 3171 HLoadGlobalCell* instr = |
3143 HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); | 3172 new(zone()) HLoadGlobalCell(cell, lookup.GetPropertyDetails()); |
3144 return ast_context()->ReturnInstruction(instr, expr->id()); | 3173 return ast_context()->ReturnInstruction(instr, expr->id()); |
3145 } else { | 3174 } else { |
3146 HValue* context = environment()->LookupContext(); | 3175 HValue* context = environment()->LookupContext(); |
3147 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 3176 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
3148 AddInstruction(global_object); | 3177 AddInstruction(global_object); |
3149 HLoadGlobalGeneric* instr = | 3178 HLoadGlobalGeneric* instr = |
3150 new(zone()) HLoadGlobalGeneric(context, | 3179 new(zone()) HLoadGlobalGeneric(context, |
3151 global_object, | 3180 global_object, |
3152 variable->name(), | 3181 variable->name(), |
3153 ast_context()->is_for_typeof()); | 3182 ast_context()->is_for_typeof()); |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3310 | 3339 |
3311 // Load the elements array before the first store. | 3340 // Load the elements array before the first store. |
3312 if (elements == NULL) { | 3341 if (elements == NULL) { |
3313 elements = new(zone()) HLoadElements(literal); | 3342 elements = new(zone()) HLoadElements(literal); |
3314 AddInstruction(elements); | 3343 AddInstruction(elements); |
3315 } | 3344 } |
3316 | 3345 |
3317 HValue* key = AddInstruction( | 3346 HValue* key = AddInstruction( |
3318 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), | 3347 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), |
3319 Representation::Integer32())); | 3348 Representation::Integer32())); |
3320 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); | 3349 if (FLAG_smi_only_arrays) { |
| 3350 HInstruction* elements_kind = |
| 3351 AddInstruction(new(zone()) HElementsKind(literal)); |
| 3352 HBasicBlock* store_fast = graph()->CreateBasicBlock(); |
| 3353 // Two empty blocks to satisfy edge split form. |
| 3354 HBasicBlock* store_fast_edgesplit1 = graph()->CreateBasicBlock(); |
| 3355 HBasicBlock* store_fast_edgesplit2 = graph()->CreateBasicBlock(); |
| 3356 HBasicBlock* store_generic = graph()->CreateBasicBlock(); |
| 3357 HBasicBlock* check_smi_only_elements = graph()->CreateBasicBlock(); |
| 3358 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 3359 |
| 3360 HIsSmiAndBranch* smicheck = new(zone()) HIsSmiAndBranch(value); |
| 3361 smicheck->SetSuccessorAt(0, store_fast_edgesplit1); |
| 3362 smicheck->SetSuccessorAt(1, check_smi_only_elements); |
| 3363 current_block()->Finish(smicheck); |
| 3364 store_fast_edgesplit1->Finish(new(zone()) HGoto(store_fast)); |
| 3365 |
| 3366 set_current_block(check_smi_only_elements); |
| 3367 HCompareConstantEqAndBranch* smi_elements_check = |
| 3368 new(zone()) HCompareConstantEqAndBranch(elements_kind, |
| 3369 FAST_SMI_ONLY_ELEMENTS, |
| 3370 Token::EQ_STRICT); |
| 3371 smi_elements_check->SetSuccessorAt(0, store_generic); |
| 3372 smi_elements_check->SetSuccessorAt(1, store_fast_edgesplit2); |
| 3373 current_block()->Finish(smi_elements_check); |
| 3374 store_fast_edgesplit2->Finish(new(zone()) HGoto(store_fast)); |
| 3375 |
| 3376 set_current_block(store_fast); |
| 3377 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); |
| 3378 store_fast->Goto(join); |
| 3379 |
| 3380 set_current_block(store_generic); |
| 3381 AddInstruction(BuildStoreKeyedGeneric(literal, key, value)); |
| 3382 store_generic->Goto(join); |
| 3383 |
| 3384 join->SetJoinId(expr->id()); |
| 3385 set_current_block(join); |
| 3386 } else { |
| 3387 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); |
| 3388 } |
| 3389 |
3321 AddSimulate(expr->GetIdForElement(i)); | 3390 AddSimulate(expr->GetIdForElement(i)); |
3322 } | 3391 } |
3323 return ast_context()->ReturnValue(Pop()); | 3392 return ast_context()->ReturnValue(Pop()); |
3324 } | 3393 } |
3325 | 3394 |
3326 | 3395 |
3327 // Sets the lookup result and returns true if the store can be inlined. | 3396 // Sets the lookup result and returns true if the store can be inlined. |
3328 static bool ComputeStoredField(Handle<Map> type, | 3397 static bool ComputeStoredField(Handle<Map> type, |
3329 Handle<String> name, | 3398 Handle<String> name, |
3330 LookupResult* lookup) { | 3399 LookupResult* lookup) { |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3554 // Because not every expression has a position and there is not common | 3623 // Because not every expression has a position and there is not common |
3555 // superclass of Assignment and CountOperation, we cannot just pass the | 3624 // superclass of Assignment and CountOperation, we cannot just pass the |
3556 // owning expression instead of position and ast_id separately. | 3625 // owning expression instead of position and ast_id separately. |
3557 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, | 3626 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, |
3558 HValue* value, | 3627 HValue* value, |
3559 int position, | 3628 int position, |
3560 int ast_id) { | 3629 int ast_id) { |
3561 LookupResult lookup; | 3630 LookupResult lookup; |
3562 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true); | 3631 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true); |
3563 if (type == kUseCell) { | 3632 if (type == kUseCell) { |
3564 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | |
3565 Handle<GlobalObject> global(info()->global_object()); | 3633 Handle<GlobalObject> global(info()->global_object()); |
3566 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3634 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
3567 HInstruction* instr = new(zone()) HStoreGlobalCell(value, cell, check_hole); | 3635 HInstruction* instr = |
| 3636 new(zone()) HStoreGlobalCell(value, cell, lookup.GetPropertyDetails()); |
3568 instr->set_position(position); | 3637 instr->set_position(position); |
3569 AddInstruction(instr); | 3638 AddInstruction(instr); |
3570 if (instr->HasSideEffects()) AddSimulate(ast_id); | 3639 if (instr->HasSideEffects()) AddSimulate(ast_id); |
3571 } else { | 3640 } else { |
3572 HValue* context = environment()->LookupContext(); | 3641 HValue* context = environment()->LookupContext(); |
3573 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 3642 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
3574 AddInstruction(global_object); | 3643 AddInstruction(global_object); |
3575 HStoreGlobalGeneric* instr = | 3644 HStoreGlobalGeneric* instr = |
3576 new(zone()) HStoreGlobalGeneric(context, | 3645 new(zone()) HStoreGlobalGeneric(context, |
3577 global_object, | 3646 global_object, |
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3921 case EXTERNAL_INT_ELEMENTS: | 3990 case EXTERNAL_INT_ELEMENTS: |
3922 case EXTERNAL_UNSIGNED_INT_ELEMENTS: { | 3991 case EXTERNAL_UNSIGNED_INT_ELEMENTS: { |
3923 HToInt32* floor_val = new(zone()) HToInt32(val); | 3992 HToInt32* floor_val = new(zone()) HToInt32(val); |
3924 AddInstruction(floor_val); | 3993 AddInstruction(floor_val); |
3925 val = floor_val; | 3994 val = floor_val; |
3926 break; | 3995 break; |
3927 } | 3996 } |
3928 case EXTERNAL_FLOAT_ELEMENTS: | 3997 case EXTERNAL_FLOAT_ELEMENTS: |
3929 case EXTERNAL_DOUBLE_ELEMENTS: | 3998 case EXTERNAL_DOUBLE_ELEMENTS: |
3930 break; | 3999 break; |
| 4000 case FAST_SMI_ONLY_ELEMENTS: |
3931 case FAST_ELEMENTS: | 4001 case FAST_ELEMENTS: |
3932 case FAST_DOUBLE_ELEMENTS: | 4002 case FAST_DOUBLE_ELEMENTS: |
3933 case DICTIONARY_ELEMENTS: | 4003 case DICTIONARY_ELEMENTS: |
3934 case NON_STRICT_ARGUMENTS_ELEMENTS: | 4004 case NON_STRICT_ARGUMENTS_ELEMENTS: |
3935 UNREACHABLE(); | 4005 UNREACHABLE(); |
3936 break; | 4006 break; |
3937 } | 4007 } |
3938 return new(zone()) HStoreKeyedSpecializedArrayElement( | 4008 return new(zone()) HStoreKeyedSpecializedArrayElement( |
3939 external_elements, checked_key, val, elements_kind); | 4009 external_elements, checked_key, val, elements_kind); |
3940 } else { | 4010 } else { |
3941 return new(zone()) HLoadKeyedSpecializedArrayElement( | 4011 return new(zone()) HLoadKeyedSpecializedArrayElement( |
3942 external_elements, checked_key, elements_kind); | 4012 external_elements, checked_key, elements_kind); |
3943 } | 4013 } |
3944 } | 4014 } |
3945 | 4015 |
3946 | 4016 |
| 4017 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, |
| 4018 HValue* checked_key, |
| 4019 HValue* val, |
| 4020 ElementsKind elements_kind, |
| 4021 bool is_store) { |
| 4022 if (is_store) { |
| 4023 ASSERT(val != NULL); |
| 4024 if (elements_kind == FAST_DOUBLE_ELEMENTS) { |
| 4025 return new(zone()) HStoreKeyedFastDoubleElement( |
| 4026 elements, checked_key, val); |
| 4027 } else { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS. |
| 4028 return new(zone()) HStoreKeyedFastElement( |
| 4029 elements, checked_key, val, elements_kind); |
| 4030 } |
| 4031 } |
| 4032 // It's an element load (!is_store). |
| 4033 if (elements_kind == FAST_DOUBLE_ELEMENTS) { |
| 4034 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); |
| 4035 } else { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS. |
| 4036 return new(zone()) HLoadKeyedFastElement(elements, checked_key); |
| 4037 } |
| 4038 } |
| 4039 |
| 4040 |
3947 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, | 4041 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
3948 HValue* key, | 4042 HValue* key, |
3949 HValue* val, | 4043 HValue* val, |
3950 Expression* expr, | 4044 Expression* expr, |
3951 bool is_store) { | 4045 bool is_store) { |
3952 ASSERT(expr->IsMonomorphic()); | 4046 ASSERT(expr->IsMonomorphic()); |
3953 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 4047 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
3954 if (!map->has_fast_elements() && | 4048 AddInstruction(new(zone()) HCheckNonSmi(object)); |
3955 !map->has_fast_double_elements() && | 4049 HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); |
| 4050 bool fast_smi_only_elements = map->has_fast_smi_only_elements(); |
| 4051 bool fast_elements = map->has_fast_elements(); |
| 4052 bool fast_double_elements = map->has_fast_double_elements(); |
| 4053 if (!fast_smi_only_elements && |
| 4054 !fast_elements && |
| 4055 !fast_double_elements && |
3956 !map->has_external_array_elements()) { | 4056 !map->has_external_array_elements()) { |
3957 return is_store ? BuildStoreKeyedGeneric(object, key, val) | 4057 return is_store ? BuildStoreKeyedGeneric(object, key, val) |
3958 : BuildLoadKeyedGeneric(object, key); | 4058 : BuildLoadKeyedGeneric(object, key); |
3959 } | 4059 } |
3960 AddInstruction(new(zone()) HCheckNonSmi(object)); | |
3961 HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); | |
3962 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | 4060 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
3963 bool fast_double_elements = map->has_fast_double_elements(); | 4061 if (is_store && (fast_elements || fast_smi_only_elements)) { |
3964 if (is_store && map->has_fast_elements()) { | |
3965 AddInstruction(new(zone()) HCheckMap( | 4062 AddInstruction(new(zone()) HCheckMap( |
3966 elements, isolate()->factory()->fixed_array_map())); | 4063 elements, isolate()->factory()->fixed_array_map())); |
3967 } | 4064 } |
3968 HInstruction* length = NULL; | 4065 HInstruction* length = NULL; |
3969 HInstruction* checked_key = NULL; | 4066 HInstruction* checked_key = NULL; |
3970 if (map->has_external_array_elements()) { | 4067 if (map->has_external_array_elements()) { |
3971 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 4068 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
3972 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4069 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
3973 HLoadExternalArrayPointer* external_elements = | 4070 HLoadExternalArrayPointer* external_elements = |
3974 new(zone()) HLoadExternalArrayPointer(elements); | 4071 new(zone()) HLoadExternalArrayPointer(elements); |
3975 AddInstruction(external_elements); | 4072 AddInstruction(external_elements); |
3976 return BuildExternalArrayElementAccess(external_elements, checked_key, | 4073 return BuildExternalArrayElementAccess(external_elements, checked_key, |
3977 val, map->elements_kind(), is_store); | 4074 val, map->elements_kind(), is_store); |
3978 } | 4075 } |
3979 ASSERT(map->has_fast_elements() || fast_double_elements); | 4076 ASSERT(fast_smi_only_elements || fast_elements || fast_double_elements); |
3980 if (map->instance_type() == JS_ARRAY_TYPE) { | 4077 if (map->instance_type() == JS_ARRAY_TYPE) { |
3981 length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck)); | 4078 length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck)); |
3982 } else { | 4079 } else { |
3983 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 4080 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
3984 } | 4081 } |
3985 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4082 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
3986 if (is_store) { | 4083 return BuildFastElementAccess(elements, checked_key, val, |
3987 if (fast_double_elements) { | 4084 map->elements_kind(), is_store); |
3988 return new(zone()) HStoreKeyedFastDoubleElement(elements, | |
3989 checked_key, | |
3990 val); | |
3991 } else { | |
3992 return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); | |
3993 } | |
3994 } else { | |
3995 if (fast_double_elements) { | |
3996 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); | |
3997 } else { | |
3998 return new(zone()) HLoadKeyedFastElement(elements, checked_key); | |
3999 } | |
4000 } | |
4001 } | 4085 } |
4002 | 4086 |
4003 | 4087 |
4004 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, | 4088 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
4005 HValue* key, | 4089 HValue* key, |
4006 HValue* val, | 4090 HValue* val, |
4007 Expression* prop, | 4091 Expression* prop, |
4008 int ast_id, | 4092 int ast_id, |
4009 int position, | 4093 int position, |
4010 bool is_store, | 4094 bool is_store, |
(...skipping 21 matching lines...) Expand all Loading... |
4032 | 4116 |
4033 HBasicBlock* join = graph()->CreateBasicBlock(); | 4117 HBasicBlock* join = graph()->CreateBasicBlock(); |
4034 | 4118 |
4035 HInstruction* elements_kind_instr = | 4119 HInstruction* elements_kind_instr = |
4036 AddInstruction(new(zone()) HElementsKind(object)); | 4120 AddInstruction(new(zone()) HElementsKind(object)); |
4037 HCompareConstantEqAndBranch* elements_kind_branch = NULL; | 4121 HCompareConstantEqAndBranch* elements_kind_branch = NULL; |
4038 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | 4122 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
4039 HLoadExternalArrayPointer* external_elements = NULL; | 4123 HLoadExternalArrayPointer* external_elements = NULL; |
4040 HInstruction* checked_key = NULL; | 4124 HInstruction* checked_key = NULL; |
4041 | 4125 |
4042 // FAST_ELEMENTS is assumed to be the first case. | 4126 // Generated code assumes that FAST_SMI_ONLY_ELEMENTS, FAST_ELEMENTS, |
4043 STATIC_ASSERT(FAST_ELEMENTS == 0); | 4127 // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS are handled before external |
| 4128 // arrays. |
| 4129 STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 4130 STATIC_ASSERT(FAST_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 4131 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 4132 STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
4044 | 4133 |
4045 for (ElementsKind elements_kind = FAST_ELEMENTS; | 4134 for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; |
4046 elements_kind <= LAST_ELEMENTS_KIND; | 4135 elements_kind <= LAST_ELEMENTS_KIND; |
4047 elements_kind = ElementsKind(elements_kind + 1)) { | 4136 elements_kind = ElementsKind(elements_kind + 1)) { |
4048 // After having handled FAST_ELEMENTS and DICTIONARY_ELEMENTS, we | 4137 // After having handled FAST_ELEMENTS, FAST_SMI_ONLY_ELEMENTS, |
4049 // need to add some code that's executed for all external array cases. | 4138 // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS, we need to add some code |
| 4139 // that's executed for all external array cases. |
4050 STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == | 4140 STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == |
4051 LAST_ELEMENTS_KIND); | 4141 LAST_ELEMENTS_KIND); |
4052 if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND | 4142 if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND |
4053 && todo_external_array) { | 4143 && todo_external_array) { |
4054 HInstruction* length = | 4144 HInstruction* length = |
4055 AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 4145 AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
4056 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4146 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
4057 external_elements = new(zone()) HLoadExternalArrayPointer(elements); | 4147 external_elements = new(zone()) HLoadExternalArrayPointer(elements); |
4058 AddInstruction(external_elements); | 4148 AddInstruction(external_elements); |
4059 } | 4149 } |
4060 if (type_todo[elements_kind]) { | 4150 if (type_todo[elements_kind]) { |
4061 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 4151 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
4062 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 4152 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
4063 elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( | 4153 elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( |
4064 elements_kind_instr, elements_kind, Token::EQ_STRICT); | 4154 elements_kind_instr, elements_kind, Token::EQ_STRICT); |
4065 elements_kind_branch->SetSuccessorAt(0, if_true); | 4155 elements_kind_branch->SetSuccessorAt(0, if_true); |
4066 elements_kind_branch->SetSuccessorAt(1, if_false); | 4156 elements_kind_branch->SetSuccessorAt(1, if_false); |
4067 current_block()->Finish(elements_kind_branch); | 4157 current_block()->Finish(elements_kind_branch); |
4068 | 4158 |
4069 set_current_block(if_true); | 4159 set_current_block(if_true); |
4070 HInstruction* access; | 4160 HInstruction* access; |
4071 if (elements_kind == FAST_ELEMENTS || | 4161 if (elements_kind == FAST_SMI_ONLY_ELEMENTS || |
| 4162 elements_kind == FAST_ELEMENTS || |
4072 elements_kind == FAST_DOUBLE_ELEMENTS) { | 4163 elements_kind == FAST_DOUBLE_ELEMENTS) { |
4073 bool fast_double_elements = | 4164 if (is_store && elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
4074 elements_kind == FAST_DOUBLE_ELEMENTS; | 4165 AddInstruction(new(zone()) HCheckSmi(val)); |
4075 if (is_store && elements_kind == FAST_ELEMENTS) { | 4166 } |
| 4167 if (is_store && elements_kind != FAST_DOUBLE_ELEMENTS) { |
4076 AddInstruction(new(zone()) HCheckMap( | 4168 AddInstruction(new(zone()) HCheckMap( |
4077 elements, isolate()->factory()->fixed_array_map(), | 4169 elements, isolate()->factory()->fixed_array_map(), |
4078 elements_kind_branch)); | 4170 elements_kind_branch)); |
4079 } | 4171 } |
| 4172 // TODO(jkummerow): The need for these two blocks could be avoided |
| 4173 // in one of two ways: |
| 4174 // (1) Introduce ElementsKinds for JSArrays that are distinct from |
| 4175 // those for fast objects. |
| 4176 // (2) Put the common instructions into a third "join" block. This |
| 4177 // requires additional AST IDs that we can deopt to from inside |
| 4178 // that join block. They must be added to the Property class (when |
| 4179 // it's a keyed property) and registered in the full codegen. |
4080 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); | 4180 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); |
4081 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); | 4181 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); |
4082 HHasInstanceTypeAndBranch* typecheck = | 4182 HHasInstanceTypeAndBranch* typecheck = |
4083 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); | 4183 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); |
4084 typecheck->SetSuccessorAt(0, if_jsarray); | 4184 typecheck->SetSuccessorAt(0, if_jsarray); |
4085 typecheck->SetSuccessorAt(1, if_fastobject); | 4185 typecheck->SetSuccessorAt(1, if_fastobject); |
4086 current_block()->Finish(typecheck); | 4186 current_block()->Finish(typecheck); |
4087 | 4187 |
4088 set_current_block(if_jsarray); | 4188 set_current_block(if_jsarray); |
4089 HInstruction* length = new(zone()) HJSArrayLength(object, typecheck); | 4189 HInstruction* length; |
4090 AddInstruction(length); | 4190 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck)); |
4091 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4191 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
4092 if (is_store) { | 4192 access = AddInstruction(BuildFastElementAccess( |
4093 if (fast_double_elements) { | 4193 elements, checked_key, val, elements_kind, is_store)); |
4094 access = AddInstruction( | 4194 if (!is_store) { |
4095 new(zone()) HStoreKeyedFastDoubleElement(elements, | |
4096 checked_key, | |
4097 val)); | |
4098 } else { | |
4099 access = AddInstruction( | |
4100 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); | |
4101 } | |
4102 } else { | |
4103 if (fast_double_elements) { | |
4104 access = AddInstruction( | |
4105 new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key)); | |
4106 } else { | |
4107 access = AddInstruction( | |
4108 new(zone()) HLoadKeyedFastElement(elements, checked_key)); | |
4109 } | |
4110 Push(access); | 4195 Push(access); |
4111 } | 4196 } |
| 4197 |
4112 *has_side_effects |= access->HasSideEffects(); | 4198 *has_side_effects |= access->HasSideEffects(); |
4113 if (position != -1) { | 4199 if (position != -1) { |
4114 access->set_position(position); | 4200 access->set_position(position); |
4115 } | 4201 } |
4116 if_jsarray->Goto(join); | 4202 if_jsarray->Goto(join); |
4117 | 4203 |
4118 set_current_block(if_fastobject); | 4204 set_current_block(if_fastobject); |
4119 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 4205 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
4120 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4206 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
4121 if (is_store) { | 4207 access = AddInstruction(BuildFastElementAccess( |
4122 if (fast_double_elements) { | 4208 elements, checked_key, val, elements_kind, is_store)); |
4123 access = AddInstruction( | |
4124 new(zone()) HStoreKeyedFastDoubleElement(elements, | |
4125 checked_key, | |
4126 val)); | |
4127 } else { | |
4128 access = AddInstruction( | |
4129 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); | |
4130 } | |
4131 } else { | |
4132 if (fast_double_elements) { | |
4133 access = AddInstruction( | |
4134 new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key)); | |
4135 } else { | |
4136 access = AddInstruction( | |
4137 new(zone()) HLoadKeyedFastElement(elements, checked_key)); | |
4138 } | |
4139 } | |
4140 } else if (elements_kind == DICTIONARY_ELEMENTS) { | 4209 } else if (elements_kind == DICTIONARY_ELEMENTS) { |
4141 if (is_store) { | 4210 if (is_store) { |
4142 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); | 4211 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); |
4143 } else { | 4212 } else { |
4144 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); | 4213 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); |
4145 } | 4214 } |
4146 } else { // External array elements. | 4215 } else { // External array elements. |
4147 access = AddInstruction(BuildExternalArrayElementAccess( | 4216 access = AddInstruction(BuildExternalArrayElementAccess( |
4148 external_elements, checked_key, val, elements_kind, is_store)); | 4217 external_elements, checked_key, val, elements_kind, is_store)); |
4149 } | 4218 } |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4467 TraceInline(target, caller, "target text too big"); | 4536 TraceInline(target, caller, "target text too big"); |
4468 return false; | 4537 return false; |
4469 } | 4538 } |
4470 | 4539 |
4471 // Target must be inlineable. | 4540 // Target must be inlineable. |
4472 if (!target->IsInlineable()) { | 4541 if (!target->IsInlineable()) { |
4473 TraceInline(target, caller, "target not inlineable"); | 4542 TraceInline(target, caller, "target not inlineable"); |
4474 return false; | 4543 return false; |
4475 } | 4544 } |
4476 | 4545 |
4477 // No context change required. | |
4478 CompilationInfo* outer_info = info(); | 4546 CompilationInfo* outer_info = info(); |
| 4547 #if !defined(V8_TARGET_ARCH_IA32) |
| 4548 // Target must be able to use caller's context. |
4479 if (target->context() != outer_info->closure()->context() || | 4549 if (target->context() != outer_info->closure()->context() || |
4480 outer_info->scope()->contains_with() || | 4550 outer_info->scope()->contains_with() || |
4481 outer_info->scope()->num_heap_slots() > 0) { | 4551 outer_info->scope()->num_heap_slots() > 0) { |
4482 TraceInline(target, caller, "target requires context change"); | 4552 TraceInline(target, caller, "target requires context change"); |
4483 return false; | 4553 return false; |
4484 } | 4554 } |
| 4555 #endif |
| 4556 |
4485 | 4557 |
4486 // Don't inline deeper than kMaxInliningLevels calls. | 4558 // Don't inline deeper than kMaxInliningLevels calls. |
4487 HEnvironment* env = environment(); | 4559 HEnvironment* env = environment(); |
4488 int current_level = 1; | 4560 int current_level = 1; |
4489 while (env->outer() != NULL) { | 4561 while (env->outer() != NULL) { |
4490 if (current_level == Compiler::kMaxInliningLevels) { | 4562 if (current_level == (FLAG_limit_inlining |
| 4563 ? Compiler::kMaxInliningLevels |
| 4564 : 2 * Compiler::kMaxInliningLevels)) { |
4491 TraceInline(target, caller, "inline depth limit reached"); | 4565 TraceInline(target, caller, "inline depth limit reached"); |
4492 return false; | 4566 return false; |
4493 } | 4567 } |
4494 current_level++; | 4568 current_level++; |
4495 env = env->outer(); | 4569 env = env->outer(); |
4496 } | 4570 } |
4497 | 4571 |
4498 // Don't inline recursive functions. | 4572 // Don't inline recursive functions. |
4499 if (*target_shared == outer_info->closure()->shared()) { | 4573 if (*target_shared == outer_info->closure()->shared()) { |
4500 TraceInline(target, caller, "target is recursive"); | 4574 TraceInline(target, caller, "target is recursive"); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4595 Handle<Code>(target_shared->code()), | 4669 Handle<Code>(target_shared->code()), |
4596 Handle<Context>(target->context()->global_context())); | 4670 Handle<Context>(target->context()->global_context())); |
4597 FunctionState target_state(this, &target_info, &target_oracle); | 4671 FunctionState target_state(this, &target_info, &target_oracle); |
4598 | 4672 |
4599 HConstant* undefined = graph()->GetConstantUndefined(); | 4673 HConstant* undefined = graph()->GetConstantUndefined(); |
4600 HEnvironment* inner_env = | 4674 HEnvironment* inner_env = |
4601 environment()->CopyForInlining(target, | 4675 environment()->CopyForInlining(target, |
4602 function, | 4676 function, |
4603 undefined, | 4677 undefined, |
4604 call_kind); | 4678 call_kind); |
| 4679 #ifdef V8_TARGET_ARCH_IA32 |
| 4680 // IA32 only, overwrite the caller's context in the deoptimization |
| 4681 // environment with the correct one. |
| 4682 // |
| 4683 // TODO(kmillikin): implement the same inlining on other platforms so we |
| 4684 // can remove the unsightly ifdefs in this function. |
| 4685 HConstant* context = new HConstant(Handle<Context>(target->context()), |
| 4686 Representation::Tagged()); |
| 4687 AddInstruction(context); |
| 4688 inner_env->BindContext(context); |
| 4689 #endif |
4605 HBasicBlock* body_entry = CreateBasicBlock(inner_env); | 4690 HBasicBlock* body_entry = CreateBasicBlock(inner_env); |
4606 current_block()->Goto(body_entry); | 4691 current_block()->Goto(body_entry); |
4607 body_entry->SetJoinId(expr->ReturnId()); | 4692 body_entry->SetJoinId(expr->ReturnId()); |
4608 set_current_block(body_entry); | 4693 set_current_block(body_entry); |
4609 AddInstruction(new(zone()) HEnterInlined(target, | 4694 AddInstruction(new(zone()) HEnterInlined(target, |
4610 function, | 4695 function, |
4611 call_kind)); | 4696 call_kind)); |
4612 VisitDeclarations(target_info.scope()->declarations()); | 4697 VisitDeclarations(target_info.scope()->declarations()); |
4613 VisitStatements(function->body()); | 4698 VisitStatements(function->body()); |
4614 if (HasStackOverflow()) { | 4699 if (HasStackOverflow()) { |
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4915 HandlePolymorphicCallNamed(expr, receiver, types, name); | 5000 HandlePolymorphicCallNamed(expr, receiver, types, name); |
4916 return; | 5001 return; |
4917 | 5002 |
4918 } else { | 5003 } else { |
4919 HValue* context = environment()->LookupContext(); | 5004 HValue* context = environment()->LookupContext(); |
4920 call = PreProcessCall( | 5005 call = PreProcessCall( |
4921 new(zone()) HCallNamed(context, name, argument_count)); | 5006 new(zone()) HCallNamed(context, name, argument_count)); |
4922 } | 5007 } |
4923 | 5008 |
4924 } else { | 5009 } else { |
| 5010 expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION); |
4925 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 5011 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
4926 // FIXME. | |
4927 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); | 5012 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); |
4928 | 5013 |
4929 if (global_call) { | 5014 if (global_call) { |
4930 Variable* var = proxy->var(); | 5015 Variable* var = proxy->var(); |
4931 bool known_global_function = false; | 5016 bool known_global_function = false; |
4932 // If there is a global property cell for the name at compile time and | 5017 // If there is a global property cell for the name at compile time and |
4933 // access check is not enabled we assume that the function will not change | 5018 // access check is not enabled we assume that the function will not change |
4934 // and generate optimized code for calling the function. | 5019 // and generate optimized code for calling the function. |
4935 LookupResult lookup; | 5020 LookupResult lookup; |
4936 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); | 5021 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4968 HValue* context = environment()->LookupContext(); | 5053 HValue* context = environment()->LookupContext(); |
4969 HGlobalObject* receiver = new(zone()) HGlobalObject(context); | 5054 HGlobalObject* receiver = new(zone()) HGlobalObject(context); |
4970 AddInstruction(receiver); | 5055 AddInstruction(receiver); |
4971 PushAndAdd(new(zone()) HPushArgument(receiver)); | 5056 PushAndAdd(new(zone()) HPushArgument(receiver)); |
4972 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 5057 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
4973 | 5058 |
4974 call = new(zone()) HCallGlobal(context, var->name(), argument_count); | 5059 call = new(zone()) HCallGlobal(context, var->name(), argument_count); |
4975 Drop(argument_count); | 5060 Drop(argument_count); |
4976 } | 5061 } |
4977 | 5062 |
| 5063 } else if (expr->IsMonomorphic()) { |
| 5064 // The function is on the stack in the unoptimized code during |
| 5065 // evaluation of the arguments. |
| 5066 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 5067 HValue* function = Top(); |
| 5068 HValue* context = environment()->LookupContext(); |
| 5069 HGlobalObject* global = new(zone()) HGlobalObject(context); |
| 5070 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global); |
| 5071 AddInstruction(global); |
| 5072 PushAndAdd(receiver); |
| 5073 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 5074 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); |
| 5075 if (TryInline(expr)) { |
| 5076 // The function is lingering in the deoptimization environment. |
| 5077 // Handle it by case analysis on the AST context. |
| 5078 if (ast_context()->IsEffect()) { |
| 5079 Drop(1); |
| 5080 } else if (ast_context()->IsValue()) { |
| 5081 HValue* result = Pop(); |
| 5082 Drop(1); |
| 5083 Push(result); |
| 5084 } else if (ast_context()->IsTest()) { |
| 5085 TestContext* context = TestContext::cast(ast_context()); |
| 5086 if (context->if_true()->HasPredecessor()) { |
| 5087 context->if_true()->last_environment()->Drop(1); |
| 5088 } |
| 5089 if (context->if_false()->HasPredecessor()) { |
| 5090 context->if_true()->last_environment()->Drop(1); |
| 5091 } |
| 5092 } else { |
| 5093 UNREACHABLE(); |
| 5094 } |
| 5095 return; |
| 5096 } else { |
| 5097 call = PreProcessCall(new(zone()) HInvokeFunction(context, |
| 5098 function, |
| 5099 argument_count)); |
| 5100 Drop(1); // The function. |
| 5101 } |
| 5102 |
4978 } else { | 5103 } else { |
4979 CHECK_ALIVE(VisitArgument(expr->expression())); | 5104 CHECK_ALIVE(VisitArgument(expr->expression())); |
4980 HValue* context = environment()->LookupContext(); | 5105 HValue* context = environment()->LookupContext(); |
4981 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 5106 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
4982 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object); | 5107 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object); |
4983 AddInstruction(global_object); | 5108 AddInstruction(global_object); |
4984 AddInstruction(receiver); | 5109 AddInstruction(receiver); |
4985 PushAndAdd(new(zone()) HPushArgument(receiver)); | 5110 PushAndAdd(new(zone()) HPushArgument(receiver)); |
4986 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 5111 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
4987 | 5112 |
(...skipping 673 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5661 | 5786 |
5662 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { | 5787 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { |
5663 if (info.IsSmi()) return Representation::Integer32(); | 5788 if (info.IsSmi()) return Representation::Integer32(); |
5664 if (info.IsInteger32()) return Representation::Integer32(); | 5789 if (info.IsInteger32()) return Representation::Integer32(); |
5665 if (info.IsDouble()) return Representation::Double(); | 5790 if (info.IsDouble()) return Representation::Double(); |
5666 if (info.IsNumber()) return Representation::Double(); | 5791 if (info.IsNumber()) return Representation::Double(); |
5667 return Representation::Tagged(); | 5792 return Representation::Tagged(); |
5668 } | 5793 } |
5669 | 5794 |
5670 | 5795 |
5671 void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* compare_expr, | 5796 void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, |
5672 Expression* expr, | 5797 Expression* sub_expr, |
5673 Handle<String> check) { | 5798 Handle<String> check) { |
5674 CHECK_ALIVE(VisitForTypeOf(expr)); | 5799 CHECK_ALIVE(VisitForTypeOf(sub_expr)); |
5675 HValue* expr_value = Pop(); | 5800 HValue* value = Pop(); |
5676 HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(expr_value, check); | 5801 HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check); |
5677 instr->set_position(compare_expr->position()); | 5802 instr->set_position(expr->position()); |
5678 return ast_context()->ReturnControl(instr, compare_expr->id()); | 5803 return ast_context()->ReturnControl(instr, expr->id()); |
5679 } | 5804 } |
5680 | 5805 |
5681 | 5806 |
5682 void HGraphBuilder::HandleLiteralCompareUndefined( | 5807 bool HGraphBuilder::TryLiteralCompare(CompareOperation* expr) { |
5683 CompareOperation* compare_expr, Expression* expr) { | 5808 Expression *sub_expr; |
5684 CHECK_ALIVE(VisitForValue(expr)); | 5809 Handle<String> check; |
5685 HValue* lhs = Pop(); | 5810 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { |
5686 HValue* rhs = graph()->GetConstantUndefined(); | 5811 HandleLiteralCompareTypeof(expr, sub_expr, check); |
5687 HCompareObjectEqAndBranch* instr = | 5812 return true; |
5688 new(zone()) HCompareObjectEqAndBranch(lhs, rhs); | 5813 } |
5689 instr->set_position(compare_expr->position()); | 5814 |
5690 return ast_context()->ReturnControl(instr, compare_expr->id()); | 5815 if (expr->IsLiteralCompareUndefined(&sub_expr)) { |
| 5816 HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue); |
| 5817 return true; |
| 5818 } |
| 5819 |
| 5820 if (expr->IsLiteralCompareNull(&sub_expr)) { |
| 5821 HandleLiteralCompareNil(expr, sub_expr, kNullValue); |
| 5822 return true; |
| 5823 } |
| 5824 |
| 5825 return false; |
5691 } | 5826 } |
5692 | 5827 |
5693 | 5828 |
5694 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { | 5829 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
5695 ASSERT(!HasStackOverflow()); | 5830 ASSERT(!HasStackOverflow()); |
5696 ASSERT(current_block() != NULL); | 5831 ASSERT(current_block() != NULL); |
5697 ASSERT(current_block()->HasPredecessor()); | 5832 ASSERT(current_block()->HasPredecessor()); |
5698 if (IsClassOfTest(expr)) { | 5833 if (IsClassOfTest(expr)) { |
5699 CallRuntime* call = expr->left()->AsCallRuntime(); | 5834 CallRuntime* call = expr->left()->AsCallRuntime(); |
5700 ASSERT(call->arguments()->length() == 1); | 5835 ASSERT(call->arguments()->length() == 1); |
5701 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5836 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
5702 HValue* value = Pop(); | 5837 HValue* value = Pop(); |
5703 Literal* literal = expr->right()->AsLiteral(); | 5838 Literal* literal = expr->right()->AsLiteral(); |
5704 Handle<String> rhs = Handle<String>::cast(literal->handle()); | 5839 Handle<String> rhs = Handle<String>::cast(literal->handle()); |
5705 HClassOfTestAndBranch* instr = | 5840 HClassOfTestAndBranch* instr = |
5706 new(zone()) HClassOfTestAndBranch(value, rhs); | 5841 new(zone()) HClassOfTestAndBranch(value, rhs); |
5707 instr->set_position(expr->position()); | 5842 instr->set_position(expr->position()); |
5708 return ast_context()->ReturnControl(instr, expr->id()); | 5843 return ast_context()->ReturnControl(instr, expr->id()); |
5709 } | 5844 } |
5710 | 5845 |
5711 // Check for special cases that compare against literals. | 5846 // Check for special cases that compare against literals. |
5712 Expression *sub_expr; | 5847 if (TryLiteralCompare(expr)) return; |
5713 Handle<String> check; | |
5714 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { | |
5715 HandleLiteralCompareTypeof(expr, sub_expr, check); | |
5716 return; | |
5717 } | |
5718 | |
5719 if (expr->IsLiteralCompareUndefined(&sub_expr)) { | |
5720 HandleLiteralCompareUndefined(expr, sub_expr); | |
5721 return; | |
5722 } | |
5723 | 5848 |
5724 TypeInfo type_info = oracle()->CompareType(expr); | 5849 TypeInfo type_info = oracle()->CompareType(expr); |
5725 // Check if this expression was ever executed according to type feedback. | 5850 // Check if this expression was ever executed according to type feedback. |
5726 if (type_info.IsUninitialized()) { | 5851 if (type_info.IsUninitialized()) { |
5727 AddInstruction(new(zone()) HSoftDeoptimize); | 5852 AddInstruction(new(zone()) HSoftDeoptimize); |
5728 current_block()->MarkAsDeoptimizing(); | 5853 current_block()->MarkAsDeoptimizing(); |
5729 type_info = TypeInfo::Unknown(); | 5854 type_info = TypeInfo::Unknown(); |
5730 } | 5855 } |
5731 | 5856 |
5732 CHECK_ALIVE(VisitForValue(expr->left())); | 5857 CHECK_ALIVE(VisitForValue(expr->left())); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5817 HCompareIDAndBranch* result = | 5942 HCompareIDAndBranch* result = |
5818 new(zone()) HCompareIDAndBranch(left, right, op); | 5943 new(zone()) HCompareIDAndBranch(left, right, op); |
5819 result->set_position(expr->position()); | 5944 result->set_position(expr->position()); |
5820 result->SetInputRepresentation(r); | 5945 result->SetInputRepresentation(r); |
5821 return ast_context()->ReturnControl(result, expr->id()); | 5946 return ast_context()->ReturnControl(result, expr->id()); |
5822 } | 5947 } |
5823 } | 5948 } |
5824 } | 5949 } |
5825 | 5950 |
5826 | 5951 |
5827 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { | 5952 void HGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, |
| 5953 Expression* sub_expr, |
| 5954 NilValue nil) { |
5828 ASSERT(!HasStackOverflow()); | 5955 ASSERT(!HasStackOverflow()); |
5829 ASSERT(current_block() != NULL); | 5956 ASSERT(current_block() != NULL); |
5830 ASSERT(current_block()->HasPredecessor()); | 5957 ASSERT(current_block()->HasPredecessor()); |
5831 CHECK_ALIVE(VisitForValue(expr->expression())); | 5958 CHECK_ALIVE(VisitForValue(sub_expr)); |
5832 HValue* value = Pop(); | 5959 HValue* value = Pop(); |
5833 HIsNullAndBranch* instr = | 5960 EqualityKind kind = |
5834 new(zone()) HIsNullAndBranch(value, expr->is_strict()); | 5961 expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality; |
| 5962 HIsNilAndBranch* instr = new(zone()) HIsNilAndBranch(value, kind, nil); |
| 5963 instr->set_position(expr->position()); |
5835 return ast_context()->ReturnControl(instr, expr->id()); | 5964 return ast_context()->ReturnControl(instr, expr->id()); |
5836 } | 5965 } |
5837 | 5966 |
5838 | 5967 |
5839 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { | 5968 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { |
5840 ASSERT(!HasStackOverflow()); | 5969 ASSERT(!HasStackOverflow()); |
5841 ASSERT(current_block() != NULL); | 5970 ASSERT(current_block() != NULL); |
5842 ASSERT(current_block()->HasPredecessor()); | 5971 ASSERT(current_block()->HasPredecessor()); |
5843 HThisFunction* self = new(zone()) HThisFunction; | 5972 HThisFunction* self = new(zone()) HThisFunction; |
5844 return ast_context()->ReturnInstruction(self, expr->id()); | 5973 return ast_context()->ReturnInstruction(self, expr->id()); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5907 LAST_SPEC_OBJECT_TYPE); | 6036 LAST_SPEC_OBJECT_TYPE); |
5908 return ast_context()->ReturnControl(result, call->id()); | 6037 return ast_context()->ReturnControl(result, call->id()); |
5909 } | 6038 } |
5910 | 6039 |
5911 | 6040 |
5912 void HGraphBuilder::GenerateIsFunction(CallRuntime* call) { | 6041 void HGraphBuilder::GenerateIsFunction(CallRuntime* call) { |
5913 ASSERT(call->arguments()->length() == 1); | 6042 ASSERT(call->arguments()->length() == 1); |
5914 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 6043 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
5915 HValue* value = Pop(); | 6044 HValue* value = Pop(); |
5916 HHasInstanceTypeAndBranch* result = | 6045 HHasInstanceTypeAndBranch* result = |
5917 new(zone()) HHasInstanceTypeAndBranch(value, | 6046 new(zone()) HHasInstanceTypeAndBranch(value, JS_FUNCTION_TYPE); |
5918 JS_FUNCTION_TYPE, | |
5919 JS_FUNCTION_PROXY_TYPE); | |
5920 return ast_context()->ReturnControl(result, call->id()); | 6047 return ast_context()->ReturnControl(result, call->id()); |
5921 } | 6048 } |
5922 | 6049 |
5923 | 6050 |
5924 void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { | 6051 void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { |
5925 ASSERT(call->arguments()->length() == 1); | 6052 ASSERT(call->arguments()->length() == 1); |
5926 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 6053 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
5927 HValue* value = Pop(); | 6054 HValue* value = Pop(); |
5928 HHasCachedArrayIndexAndBranch* result = | 6055 HHasCachedArrayIndexAndBranch* result = |
5929 new(zone()) HHasCachedArrayIndexAndBranch(value); | 6056 new(zone()) HHasCachedArrayIndexAndBranch(value); |
(...skipping 879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6809 | 6936 |
6810 if (FLAG_trace_hydrogen) { | 6937 if (FLAG_trace_hydrogen) { |
6811 if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_); | 6938 if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_); |
6812 if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_); | 6939 if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_); |
6813 if (allocator_ != NULL) { | 6940 if (allocator_ != NULL) { |
6814 HTracer::Instance()->TraceLiveRanges(name_, allocator_); | 6941 HTracer::Instance()->TraceLiveRanges(name_, allocator_); |
6815 } | 6942 } |
6816 } | 6943 } |
6817 | 6944 |
6818 #ifdef DEBUG | 6945 #ifdef DEBUG |
6819 if (graph_ != NULL) graph_->Verify(); | 6946 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
6820 if (allocator_ != NULL) allocator_->Verify(); | 6947 if (allocator_ != NULL) allocator_->Verify(); |
6821 #endif | 6948 #endif |
6822 } | 6949 } |
6823 | 6950 |
6824 } } // namespace v8::internal | 6951 } } // namespace v8::internal |
OLD | NEW |