| Index: src/hydrogen.cc
 | 
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
 | 
| index f62a2835fcca26a4e8a75f1ee2ef31d5e19486a0..00207c142f44d528805a7172698ae09cf21388a2 100644
 | 
| --- a/src/hydrogen.cc
 | 
| +++ b/src/hydrogen.cc
 | 
| @@ -221,8 +221,9 @@ void HBasicBlock::SetJoinId(BailoutId ast_id) {
 | 
|      HSimulate* simulate = HSimulate::cast(predecessor->end()->previous());
 | 
|      // We only need to verify the ID once.
 | 
|      ASSERT(i != 0 ||
 | 
| -           predecessor->last_environment()->closure()->shared()
 | 
| -               ->VerifyBailoutId(ast_id));
 | 
| +           (predecessor->last_environment()->closure().is_null() ||
 | 
| +            predecessor->last_environment()->closure()->shared()
 | 
| +              ->VerifyBailoutId(ast_id)));
 | 
|      simulate->set_ast_id(ast_id);
 | 
|    }
 | 
|  }
 | 
| @@ -602,6 +603,11 @@ HConstant* HGraph::GetConstantInt32(SetOncePointer<HConstant>* pointer,
 | 
|  }
 | 
|  
 | 
|  
 | 
| +HConstant* HGraph::GetConstant0() {
 | 
| +  return GetConstantInt32(&constant_0_, 0);
 | 
| +}
 | 
| +
 | 
| +
 | 
|  HConstant* HGraph::GetConstant1() {
 | 
|    return GetConstantInt32(&constant_1_, 1);
 | 
|  }
 | 
| @@ -627,6 +633,128 @@ HConstant* HGraph::GetConstantHole() {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, BailoutId id)
 | 
| +    : builder_(builder),
 | 
| +      finished_(false),
 | 
| +      id_(id) {
 | 
| +  HEnvironment* env = builder->environment();
 | 
| +  HEnvironment* true_env = env->Copy();
 | 
| +  HEnvironment* false_env = env->Copy();
 | 
| +  HEnvironment* merge_env = env->Copy();
 | 
| +  true_block_ = builder->CreateBasicBlock(true_env);
 | 
| +  false_block_ = builder->CreateBasicBlock(false_env);
 | 
| +  merge_block_ = builder->CreateBasicBlock(merge_env);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HGraphBuilder::IfBuilder::BeginTrue(HValue* left,
 | 
| +                                         HValue* right,
 | 
| +                                         Token::Value token) {
 | 
| +  HCompareIDAndBranch* compare =
 | 
| +      new(zone()) HCompareIDAndBranch(left, right, token);
 | 
| +  compare->ChangeRepresentation(Representation::Integer32());
 | 
| +  compare->SetSuccessorAt(0, true_block_);
 | 
| +  compare->SetSuccessorAt(1, false_block_);
 | 
| +  builder_->current_block()->Finish(compare);
 | 
| +  builder_->set_current_block(true_block_);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HGraphBuilder::IfBuilder::BeginFalse() {
 | 
| +  builder_->current_block()->Goto(merge_block_);
 | 
| +  builder_->set_current_block(false_block_);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HGraphBuilder::IfBuilder::End() {
 | 
| +  ASSERT(!finished_);
 | 
| +  builder_->current_block()->Goto(merge_block_);
 | 
| +  builder_->set_current_block(merge_block_);
 | 
| +  merge_block_->SetJoinId(id_);
 | 
| +  finished_ = true;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder,
 | 
| +                                        HValue* context,
 | 
| +                                        LoopBuilder::Direction direction,
 | 
| +                                        BailoutId id)
 | 
| +    : builder_(builder),
 | 
| +      context_(context),
 | 
| +      direction_(direction),
 | 
| +      id_(id),
 | 
| +      finished_(false) {
 | 
| +  HEnvironment* env = builder_->environment();
 | 
| +  HEnvironment* body_env = env->Copy();
 | 
| +  HEnvironment* exit_env = env->Copy();
 | 
| +  header_block_ = builder->CreateLoopHeaderBlock();
 | 
| +  body_block_ = builder->CreateBasicBlock(body_env);
 | 
| +  exit_block_ = builder->CreateBasicBlock(exit_env);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +HValue* HGraphBuilder::LoopBuilder::BeginBody(HValue* initial,
 | 
| +                                              HValue* terminating,
 | 
| +                                              Token::Value token) {
 | 
| +  phi_ = new(zone()) HPhi(0, zone());
 | 
| +  header_block_->AddPhi(phi_);
 | 
| +  phi_->AddInput(initial);
 | 
| +  phi_->ChangeRepresentation(Representation::Integer32());
 | 
| +  HEnvironment* env = builder_->environment();
 | 
| +  env->Push(initial);
 | 
| +  builder_->current_block()->Goto(header_block_);
 | 
| +  builder_->set_current_block(header_block_);
 | 
| +
 | 
| +  builder_->set_current_block(header_block_);
 | 
| +  HCompareIDAndBranch* compare =
 | 
| +      new(zone()) HCompareIDAndBranch(phi_, terminating, token);
 | 
| +  compare->ChangeRepresentation(Representation::Integer32());
 | 
| +  compare->SetSuccessorAt(0, body_block_);
 | 
| +  compare->SetSuccessorAt(1, exit_block_);
 | 
| +  builder_->current_block()->Finish(compare);
 | 
| +
 | 
| +  builder_->set_current_block(body_block_);
 | 
| +  if (direction_ == kPreIncrement || direction_ == kPreDecrement) {
 | 
| +    HValue* one = builder_->graph()->GetConstant1();
 | 
| +    if (direction_ == kPreIncrement) {
 | 
| +      increment_ = new(zone()) HAdd(context_, phi_, one);
 | 
| +    } else {
 | 
| +      increment_ = new(zone()) HSub(context_, phi_, one);
 | 
| +    }
 | 
| +    increment_->ClearFlag(HValue::kCanOverflow);
 | 
| +    increment_->ChangeRepresentation(Representation::Integer32());
 | 
| +    builder_->AddInstruction(increment_);
 | 
| +    return increment_;
 | 
| +  } else {
 | 
| +    return phi_;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HGraphBuilder::LoopBuilder::EndBody() {
 | 
| +  ASSERT(!finished_);
 | 
| +
 | 
| +  if (direction_ == kPostIncrement || direction_ == kPostDecrement) {
 | 
| +    HValue* one = builder_->graph()->GetConstant1();
 | 
| +    if (direction_ == kPostIncrement) {
 | 
| +      increment_ = new(zone()) HAdd(context_, phi_, one);
 | 
| +    } else {
 | 
| +      increment_ = new(zone()) HSub(context_, phi_, one);
 | 
| +    }
 | 
| +    increment_->ClearFlag(HValue::kCanOverflow);
 | 
| +    increment_->ChangeRepresentation(Representation::Integer32());
 | 
| +    builder_->AddInstruction(increment_);
 | 
| +  }
 | 
| +
 | 
| +  builder_->environment()->Push(increment_);
 | 
| +  builder_->current_block()->Goto(header_block_);
 | 
| +  header_block_->loop_information()->RegisterBackEdge(body_block_);
 | 
| +  header_block_->SetJoinId(BailoutId::StubEntry());
 | 
| +  builder_->set_current_block(exit_block_);
 | 
| +  finished_ = true;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  HGraph* HGraphBuilder::CreateGraph() {
 | 
|    graph_ = new(zone()) HGraph(info_);
 | 
|    if (FLAG_hydrogen_stats) HStatistics::Instance()->Initialize(info_);
 | 
| @@ -651,6 +779,22 @@ void HGraphBuilder::AddSimulate(BailoutId id,
 | 
|  }
 | 
|  
 | 
|  
 | 
| +HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
 | 
| +  HBasicBlock* b = graph()->CreateBasicBlock();
 | 
| +  b->SetInitialEnvironment(env);
 | 
| +  return b;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
 | 
| +  HBasicBlock* header = graph()->CreateBasicBlock();
 | 
| +  HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
 | 
| +  header->SetInitialEnvironment(entry_env);
 | 
| +  header->AttachLoopInformation();
 | 
| +  return header;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
 | 
|      HValue* external_elements,
 | 
|      HValue* checked_key,
 | 
| @@ -799,6 +943,109 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
 | 
|  }
 | 
|  
 | 
|  
 | 
| +HValue* HGraphBuilder::BuildAllocateElements(HContext* context,
 | 
| +                                             ElementsKind kind,
 | 
| +                                             HValue* capacity) {
 | 
| +  Zone* zone = this->zone();
 | 
| +
 | 
| +  int elements_size = IsFastDoubleElementsKind(kind)
 | 
| +      ? kDoubleSize : kPointerSize;
 | 
| +  HConstant* elements_size_value =
 | 
| +      new(zone) HConstant(elements_size, Representation::Integer32());
 | 
| +  AddInstruction(elements_size_value);
 | 
| +  HValue* mul = AddInstruction(
 | 
| +      new(zone) HMul(context, capacity, elements_size_value));
 | 
| +  mul->ChangeRepresentation(Representation::Integer32());
 | 
| +  mul->ClearFlag(HValue::kCanOverflow);
 | 
| +
 | 
| +  HConstant* header_size =
 | 
| +      new(zone) HConstant(FixedArray::kHeaderSize, Representation::Integer32());
 | 
| +  AddInstruction(header_size);
 | 
| +  HValue* total_size = AddInstruction(
 | 
| +      new(zone) HAdd(context, mul, header_size));
 | 
| +  total_size->ChangeRepresentation(Representation::Integer32());
 | 
| +  total_size->ClearFlag(HValue::kCanOverflow);
 | 
| +
 | 
| +  HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE;
 | 
| +  if (IsFastDoubleElementsKind(kind)) {
 | 
| +    flags = static_cast<HAllocate::Flags>(
 | 
| +        flags | HAllocate::ALLOCATE_DOUBLE_ALIGNED);
 | 
| +  }
 | 
| +
 | 
| +  HValue* elements =
 | 
| +      AddInstruction(new(zone) HAllocate(context, total_size,
 | 
| +                                         HType::JSArray(), flags));
 | 
| +  Isolate* isolate = graph()->isolate();
 | 
| +
 | 
| +  Factory* factory = isolate->factory();
 | 
| +  Handle<Map> map = IsFastDoubleElementsKind(kind)
 | 
| +      ? factory->fixed_double_array_map()
 | 
| +      : factory->fixed_array_map();
 | 
| +  BuildStoreMap(elements, map, BailoutId::StubEntry());
 | 
| +
 | 
| +  Handle<String> fixed_array_length_field_name =
 | 
| +      isolate->factory()->length_field_symbol();
 | 
| +  HInstruction* store_length =
 | 
| +      new(zone) HStoreNamedField(elements, fixed_array_length_field_name,
 | 
| +                                 capacity, true, FixedArray::kLengthOffset);
 | 
| +  AddInstruction(store_length);
 | 
| +  AddSimulate(BailoutId::StubEntry(), FIXED_SIMULATE);
 | 
| +
 | 
| +  return elements;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +HInstruction* HGraphBuilder::BuildStoreMap(HValue* object,
 | 
| +                                           HValue* map,
 | 
| +                                           BailoutId id) {
 | 
| +  Zone* zone = this->zone();
 | 
| +  Isolate* isolate = graph()->isolate();
 | 
| +  Factory* factory = isolate->factory();
 | 
| +  Handle<String> map_field_name = factory->map_field_symbol();
 | 
| +  HInstruction* store_map =
 | 
| +      new(zone) HStoreNamedField(object, map_field_name, map,
 | 
| +                                 true, JSObject::kMapOffset);
 | 
| +  store_map->SetGVNFlag(kChangesMaps);
 | 
| +  AddInstruction(store_map);
 | 
| +  AddSimulate(id, FIXED_SIMULATE);
 | 
| +  return store_map;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +HInstruction* HGraphBuilder::BuildStoreMap(HValue* object,
 | 
| +                                           Handle<Map> map,
 | 
| +                                           BailoutId id) {
 | 
| +  Zone* zone = this->zone();
 | 
| +  HValue* map_constant =
 | 
| +      AddInstruction(new(zone) HConstant(map, Representation::Tagged()));
 | 
| +  return BuildStoreMap(object, map_constant, id);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HGraphBuilder::BuildCopyElements(HContext* context,
 | 
| +                                      HValue* from_elements,
 | 
| +                                      ElementsKind from_elements_kind,
 | 
| +                                      HValue* to_elements,
 | 
| +                                      ElementsKind to_elements_kind,
 | 
| +                                      HValue* length) {
 | 
| +  LoopBuilder builder(this, context, LoopBuilder::kPostIncrement);
 | 
| +
 | 
| +  HValue* key = builder.BeginBody(graph()->GetConstant0(),
 | 
| +                                  length, Token::LT);
 | 
| +
 | 
| +  HValue* element =
 | 
| +      AddInstruction(new(zone()) HLoadKeyed(from_elements, key, NULL,
 | 
| +                                            from_elements_kind,
 | 
| +                                            ALLOW_RETURN_HOLE));
 | 
| +
 | 
| +  AddInstruction(new(zone()) HStoreKeyed(to_elements, key, element,
 | 
| +                                         to_elements_kind));
 | 
| +  AddSimulate(BailoutId::StubEntry(), REMOVABLE_SIMULATE);
 | 
| +
 | 
| +  builder.EndBody();
 | 
| +}
 | 
| +
 | 
| +
 | 
|  HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info,
 | 
|                                                 TypeFeedbackOracle* oracle)
 | 
|      : HGraphBuilder(info),
 | 
| @@ -2258,7 +2505,7 @@ void HGlobalValueNumberer::ProcessLoopBlock(
 | 
|  
 | 
|  
 | 
|  bool HGlobalValueNumberer::AllowCodeMotion() {
 | 
| -  return info()->opt_count() + 1 < FLAG_max_opt_count;
 | 
| +  return info()->IsStub() || info()->opt_count() + 1 < FLAG_max_opt_count;
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -3510,6 +3757,23 @@ bool HOptimizedGraphBuilder::BuildGraph() {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void HGraph::GlobalValueNumbering() {
 | 
| +  // Perform common subexpression elimination and loop-invariant code motion.
 | 
| +  if (FLAG_use_gvn) {
 | 
| +    HPhase phase("H_Global value numbering", this);
 | 
| +    HGlobalValueNumberer gvn(this, info());
 | 
| +    bool removed_side_effects = gvn.Analyze();
 | 
| +    // Trigger a second analysis pass to further eliminate duplicate values that
 | 
| +    // could only be discovered by removing side-effect-generating instructions
 | 
| +    // during the first pass.
 | 
| +    if (FLAG_smi_only_arrays && removed_side_effects) {
 | 
| +      removed_side_effects = gvn.Analyze();
 | 
| +      ASSERT(!removed_side_effects);
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
|  bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) {
 | 
|    *bailout_reason = SmartArrayPointer<char>();
 | 
|    OrderBlocks();
 | 
| @@ -3563,19 +3827,7 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) {
 | 
|  
 | 
|    Canonicalize();
 | 
|  
 | 
| -  // Perform common subexpression elimination and loop-invariant code motion.
 | 
| -  if (FLAG_use_gvn) {
 | 
| -    HPhase phase("H_Global value numbering", this);
 | 
| -    HGlobalValueNumberer gvn(this, info());
 | 
| -    bool removed_side_effects = gvn.Analyze();
 | 
| -    // Trigger a second analysis pass to further eliminate duplicate values that
 | 
| -    // could only be discovered by removing side-effect-generating instructions
 | 
| -    // during the first pass.
 | 
| -    if (FLAG_smi_only_arrays && removed_side_effects) {
 | 
| -      removed_side_effects = gvn.Analyze();
 | 
| -      ASSERT(!removed_side_effects);
 | 
| -    }
 | 
| -  }
 | 
| +  GlobalValueNumbering();
 | 
|  
 | 
|    if (FLAG_use_range) {
 | 
|      HRangeAnalysis rangeAnalysis(this);
 | 
| @@ -4201,22 +4453,6 @@ void HOptimizedGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -HBasicBlock* HOptimizedGraphBuilder::CreateBasicBlock(HEnvironment* env) {
 | 
| -  HBasicBlock* b = graph()->CreateBasicBlock();
 | 
| -  b->SetInitialEnvironment(env);
 | 
| -  return b;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -HBasicBlock* HOptimizedGraphBuilder::CreateLoopHeaderBlock() {
 | 
| -  HBasicBlock* header = graph()->CreateBasicBlock();
 | 
| -  HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
 | 
| -  header->SetInitialEnvironment(entry_env);
 | 
| -  header->AttachLoopInformation();
 | 
| -  return header;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  void HOptimizedGraphBuilder::VisitBlock(Block* stmt) {
 | 
|    ASSERT(!HasStackOverflow());
 | 
|    ASSERT(current_block() != NULL);
 | 
| @@ -6538,8 +6774,9 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
 | 
|        ASSERT(Map::IsValidElementsTransition(
 | 
|            map->elements_kind(),
 | 
|            transition_target.at(i)->elements_kind()));
 | 
| +      HValue* context = environment()->LookupContext();
 | 
|        transition = new(zone()) HTransitionElementsKind(
 | 
| -          object, map, transition_target.at(i));
 | 
| +          context, object, map, transition_target.at(i));
 | 
|        AddInstruction(transition);
 | 
|      } else {
 | 
|        type_todo[map->elements_kind()] = true;
 | 
| @@ -9791,7 +10028,7 @@ HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone)
 | 
|      : values_(0, zone),
 | 
|        frame_type_(JS_FUNCTION),
 | 
|        parameter_count_(0),
 | 
| -      specials_count_(1),
 | 
| +      specials_count_(0),
 | 
|        local_count_(0),
 | 
|        outer_(NULL),
 | 
|        entry_(NULL),
 | 
| @@ -9846,6 +10083,7 @@ void HEnvironment::Initialize(const HEnvironment* other) {
 | 
|    entry_ = other->entry_;
 | 
|    pop_count_ = other->pop_count_;
 | 
|    push_count_ = other->push_count_;
 | 
| +  specials_count_ = other->specials_count_;
 | 
|    ast_id_ = other->ast_id_;
 | 
|  }
 | 
|  
 | 
| 
 |