diff options
Diffstat (limited to 'deps/v8/src/hydrogen.cc')
-rw-r--r-- | deps/v8/src/hydrogen.cc | 595 |
1 files changed, 448 insertions, 147 deletions
diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index e5270575e9..a978834c0f 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -25,9 +25,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" #include "hydrogen.h" +#include <algorithm> + +#include "v8.h" #include "codegen.h" #include "full-codegen.h" #include "hashmap.h" @@ -509,9 +511,8 @@ class ReachabilityAnalyzer BASE_EMBEDDED { void HGraph::Verify(bool do_full_verify) const { - // Allow dereferencing for debug mode verification. - HandleDereferenceGuard allow_handle_deref(isolate(), - HandleDereferenceGuard::ALLOW); + Heap::RelocationLock(isolate()->heap()); + ALLOW_HANDLE_DEREF(isolate(), "debug mode verification"); for (int i = 0; i < blocks_.length(); i++) { HBasicBlock* block = blocks_.at(i); @@ -603,6 +604,19 @@ HConstant* HGraph::GetConstantInt32(SetOncePointer<HConstant>* pointer, } +HConstant* HGraph::GetConstantSmi(SetOncePointer<HConstant>* pointer, + int32_t value) { + if (!pointer->is_set()) { + HConstant* constant = + new(zone()) HConstant(Handle<Object>(Smi::FromInt(value), isolate()), + Representation::Tagged()); + constant->InsertAfter(GetConstantUndefined()); + pointer->set(constant); + } + return pointer->get(); +} + + HConstant* HGraph::GetConstant0() { return GetConstantInt32(&constant_0_, 0); } @@ -638,69 +652,20 @@ HConstant* HGraph::GetConstant##Name() { \ DEFINE_GET_CONSTANT(True, true, HType::Boolean(), true) DEFINE_GET_CONSTANT(False, false, HType::Boolean(), false) DEFINE_GET_CONSTANT(Hole, the_hole, HType::Tagged(), false) - -#undef DEFINE_GET_CONSTANT - - -HGraphBuilder::CheckBuilder::CheckBuilder(HGraphBuilder* builder) - : builder_(builder), - finished_(false) { - HEnvironment* env = builder->environment(); - failure_block_ = builder->CreateBasicBlock(env->Copy()); - merge_block_ = builder->CreateBasicBlock(env->Copy()); -} - - -HValue* HGraphBuilder::CheckBuilder::CheckNotUndefined(HValue* value) { - HEnvironment* env = builder_->environment(); - HCompareObjectEqAndBranch* compare = - new(zone()) HCompareObjectEqAndBranch( - value, - builder_->graph()->GetConstantUndefined()); - HBasicBlock* success_block = builder_->CreateBasicBlock(env->Copy()); - HBasicBlock* failure_block = builder_->CreateBasicBlock(env->Copy()); - compare->SetSuccessorAt(0, failure_block); - compare->SetSuccessorAt(1, success_block); - failure_block->GotoNoSimulate(failure_block_); - builder_->current_block()->Finish(compare); - builder_->set_current_block(success_block); - return compare; -} +DEFINE_GET_CONSTANT(Null, null, HType::Tagged(), false) -HValue* HGraphBuilder::CheckBuilder::CheckIntegerCompare(HValue* left, - HValue* right, - Token::Value op) { - HEnvironment* env = builder_->environment(); - HCompareIDAndBranch* compare = - new(zone()) HCompareIDAndBranch(left, right, op); - compare->AssumeRepresentation(Representation::Integer32()); - HBasicBlock* success_block = builder_->CreateBasicBlock(env->Copy()); - HBasicBlock* failure_block = builder_->CreateBasicBlock(env->Copy()); - compare->SetSuccessorAt(0, success_block); - compare->SetSuccessorAt(1, failure_block); - failure_block->GotoNoSimulate(failure_block_); - builder_->current_block()->Finish(compare); - builder_->set_current_block(success_block); - return compare; +HConstant* HGraph::GetConstantSmi0() { + return GetConstantSmi(&constant_smi_0_, 0); } -HValue* HGraphBuilder::CheckBuilder::CheckIntegerEq(HValue* left, - HValue* right) { - return CheckIntegerCompare(left, right, Token::EQ); +HConstant* HGraph::GetConstantSmi1() { + return GetConstantSmi(&constant_smi_1_, 1); } -void HGraphBuilder::CheckBuilder::End() { - ASSERT(!finished_); - builder_->current_block()->GotoNoSimulate(merge_block_); - if (failure_block_->HasPredecessor()) { - failure_block_->FinishExitWithDeoptimization(HDeoptimize::kUseAll); - } - builder_->set_current_block(merge_block_); - finished_ = true; -} +#undef DEFINE_GET_CONSTANT HConstant* HGraph::GetInvalidContext() { @@ -714,8 +679,6 @@ HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, int position) finished_(false), did_then_(false), did_else_(false), - deopt_then_(false), - deopt_else_(false), did_and_(false), did_or_(false), captured_(false), @@ -736,8 +699,6 @@ HGraphBuilder::IfBuilder::IfBuilder( finished_(false), did_then_(false), did_else_(false), - deopt_then_(false), - deopt_else_(false), did_and_(false), did_or_(false), captured_(false), @@ -835,8 +796,9 @@ void HGraphBuilder::IfBuilder::CaptureContinuation( HBasicBlock* true_block = last_true_block_ == NULL ? first_true_block_ : last_true_block_; - HBasicBlock* false_block = - did_else_ ? builder_->current_block() : first_false_block_; + HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL) + ? builder_->current_block() + : first_false_block_; continuation->Capture(true_block, false_block, position_); captured_ = true; End(); @@ -869,12 +831,23 @@ void HGraphBuilder::IfBuilder::Else() { void HGraphBuilder::IfBuilder::Deopt() { - ASSERT(!(did_then_ ^ did_else_)); HBasicBlock* block = builder_->current_block(); block->FinishExitWithDeoptimization(HDeoptimize::kUseAll); if (did_else_) { first_false_block_ = NULL; - did_else_ = false; + } else { + first_true_block_ = NULL; + } +} + + +void HGraphBuilder::IfBuilder::Return(HValue* value) { + HBasicBlock* block = builder_->current_block(); + block->Finish(new(zone()) HReturn(value, + builder_->environment()->LookupContext(), + builder_->graph()->GetConstantMinus1())); + if (did_else_) { + first_false_block_ = NULL; } else { first_true_block_ = NULL; } @@ -888,8 +861,9 @@ void HGraphBuilder::IfBuilder::End() { last_true_block_ = builder_->current_block(); } if (first_true_block_ == NULL) { - // Deopt on true. Nothing to do, just continue the else block. + // Deopt on true. Nothing to do, just continue the false block. } else if (first_false_block_ == NULL) { + // Deopt on false. Nothing to do except switching to the true block. builder_->set_current_block(last_true_block_); } else { HEnvironment* merge_env = last_true_block_->last_environment()->Copy(); @@ -1081,7 +1055,7 @@ HValue* HGraphBuilder::BuildCheckNonSmi(HValue* obj) { HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) { - HCheckMaps* check = new(zone()) HCheckMaps(obj, map, zone()); + HCheckMaps* check = HCheckMaps::New(obj, map, zone()); AddInstruction(check); return check; } @@ -1297,7 +1271,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( AddInstruction(new(zone) HLoadElements(object, mapcheck)); if (is_store && (fast_elements || fast_smi_only_elements) && store_mode != STORE_NO_TRANSITION_HANDLE_COW) { - HCheckMaps* check_cow_map = new(zone) HCheckMaps( + HCheckMaps* check_cow_map = HCheckMaps::New( elements, isolate()->factory()->fixed_array_map(), zone); check_cow_map->ClearGVNFlag(kDependsOnElementsKind); AddInstruction(check_cow_map); @@ -1319,14 +1293,15 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( IfBuilder length_checker(this); length_checker.IfCompare(key, length, Token::LT); length_checker.Then(); - CheckBuilder negative_checker(this); - HValue* bounds_check = negative_checker.CheckIntegerCompare( + IfBuilder negative_checker(this); + HValue* bounds_check = negative_checker.IfCompare( key, graph()->GetConstant0(), Token::GTE); - negative_checker.End(); + negative_checker.Then(); HInstruction* result = BuildExternalArrayElementAccess( external_elements, key, val, bounds_check, elements_kind, is_store); AddInstruction(result); + negative_checker.ElseDeopt(); length_checker.End(); return result; } else { @@ -1371,7 +1346,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( elements = BuildCopyElementsOnWrite(object, elements, elements_kind, length); } else { - HCheckMaps* check_cow_map = new(zone) HCheckMaps( + HCheckMaps* check_cow_map = HCheckMaps::New( elements, isolate()->factory()->fixed_array_map(), zone); check_cow_map->ClearGVNFlag(kDependsOnElementsKind); AddInstruction(check_cow_map); @@ -1407,8 +1382,10 @@ HValue* HGraphBuilder::BuildAllocateElements(HValue* context, total_size->ChangeRepresentation(Representation::Integer32()); total_size->ClearFlag(HValue::kCanOverflow); - HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE; + HAllocate::Flags flags = HAllocate::DefaultFlags(kind); if (FLAG_pretenure_literals) { + // TODO(hpayer): When pretenuring can be internalized, flags can become + // private to HAllocate. if (IsFastDoubleElementsKind(kind)) { flags = static_cast<HAllocate::Flags>( flags | HAllocate::CAN_ALLOCATE_IN_OLD_DATA_SPACE); @@ -1417,10 +1394,6 @@ HValue* HGraphBuilder::BuildAllocateElements(HValue* context, flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE); } } - if (IsFastDoubleElementsKind(kind)) { - flags = static_cast<HAllocate::Flags>( - flags | HAllocate::ALLOCATE_DOUBLE_ALIGNED); - } HValue* elements = AddInstruction(new(zone) HAllocate(context, total_size, @@ -1456,6 +1429,63 @@ HValue* HGraphBuilder::BuildAllocateAndInitializeElements(HValue* context, } +HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array, + HValue* array_map, + AllocationSiteMode mode, + HValue* allocation_site_payload, + HValue* length_field) { + + BuildStoreMap(array, array_map); + + HConstant* empty_fixed_array = + new(zone()) HConstant( + Handle<FixedArray>(isolate()->heap()->empty_fixed_array()), + Representation::Tagged()); + AddInstruction(empty_fixed_array); + + AddInstruction(new(zone()) HStoreNamedField(array, + isolate()->factory()->properties_field_symbol(), + empty_fixed_array, + true, + JSArray::kPropertiesOffset)); + + HInstruction* length_store = AddInstruction( + new(zone()) HStoreNamedField(array, + isolate()->factory()->length_field_string(), + length_field, + true, + JSArray::kLengthOffset)); + length_store->SetGVNFlag(kChangesArrayLengths); + + if (mode == TRACK_ALLOCATION_SITE) { + BuildCreateAllocationSiteInfo(array, + JSArray::kSize, + allocation_site_payload); + } + + int elements_location = JSArray::kSize; + if (mode == TRACK_ALLOCATION_SITE) { + elements_location += AllocationSiteInfo::kSize; + } + + HInnerAllocatedObject* elements = new(zone()) HInnerAllocatedObject( + array, + elements_location); + AddInstruction(elements); + + HInstruction* elements_store = AddInstruction( + new(zone()) HStoreNamedField( + array, + isolate()->factory()->elements_field_string(), + elements, + true, + JSArray::kElementsOffset)); + elements_store->SetGVNFlag(kChangesElementsPointer); + + return elements; +} + + HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, HValue* map) { Zone* zone = this->zone(); @@ -1569,13 +1599,38 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* context, : AddInstruction(new(zone) HConstant(nan_double, Representation::Double())); - LoopBuilder builder(this, context, LoopBuilder::kPostIncrement); + // Special loop unfolding case + static const int kLoopUnfoldLimit = 4; + bool unfold_loop = false; + int initial_capacity = JSArray::kPreallocatedArrayElements; + if (from->IsConstant() && to->IsConstant() && + initial_capacity <= kLoopUnfoldLimit) { + HConstant* constant_from = HConstant::cast(from); + HConstant* constant_to = HConstant::cast(to); - HValue* key = builder.BeginBody(from, to, Token::LT); + if (constant_from->HasInteger32Value() && + constant_from->Integer32Value() == 0 && + constant_to->HasInteger32Value() && + constant_to->Integer32Value() == initial_capacity) { + unfold_loop = true; + } + } - AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind)); + if (unfold_loop) { + for (int i = 0; i < initial_capacity; i++) { + HInstruction* key = AddInstruction(new(zone) + HConstant(i, Representation::Integer32())); + AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind)); + } + } else { + LoopBuilder builder(this, context, LoopBuilder::kPostIncrement); - builder.EndBody(); + HValue* key = builder.BeginBody(from, to, Token::LT); + + AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind)); + + builder.EndBody(); + } } @@ -1642,12 +1697,7 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context, : FixedArray::SizeFor(length); } - HAllocate::Flags allocate_flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE; - if (IsFastDoubleElementsKind(kind)) { - allocate_flags = static_cast<HAllocate::Flags>( - allocate_flags | HAllocate::ALLOCATE_DOUBLE_ALIGNED); - } - + HAllocate::Flags allocate_flags = HAllocate::DefaultFlags(kind); // Allocate both the JS array and the elements array in one big // allocation. This avoids multiple limit checks. HValue* size_in_bytes = @@ -1676,15 +1726,7 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context, // Create an allocation site info if requested. if (mode == TRACK_ALLOCATION_SITE) { - HValue* alloc_site = - AddInstruction(new(zone) HInnerAllocatedObject(object, JSArray::kSize)); - Handle<Map> alloc_site_map(isolate()->heap()->allocation_site_info_map()); - BuildStoreMap(alloc_site, alloc_site_map); - int alloc_payload_offset = AllocationSiteInfo::kPayloadOffset; - AddInstruction(new(zone) HStoreNamedField(alloc_site, - factory->empty_string(), - boilerplate, - true, alloc_payload_offset)); + BuildCreateAllocationSiteInfo(object, JSArray::kSize, boilerplate); } if (length > 0) { @@ -1733,6 +1775,205 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context, } +void HGraphBuilder::BuildCompareNil( + HValue* value, + EqualityKind kind, + CompareNilICStub::Types types, + Handle<Map> map, + int position, + HIfContinuation* continuation) { + IfBuilder if_nil(this, position); + bool needs_or = false; + if ((types & CompareNilICStub::kCompareAgainstNull) != 0) { + if (needs_or) if_nil.Or(); + if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull()); + needs_or = true; + } + if ((types & CompareNilICStub::kCompareAgainstUndefined) != 0) { + if (needs_or) if_nil.Or(); + if_nil.If<HCompareObjectEqAndBranch>(value, + graph()->GetConstantUndefined()); + needs_or = true; + } + // Handle either undetectable or monomorphic, not both. + ASSERT(((types & CompareNilICStub::kCompareAgainstUndetectable) == 0) || + ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) == 0)); + if ((types & CompareNilICStub::kCompareAgainstUndetectable) != 0) { + if (needs_or) if_nil.Or(); + if_nil.If<HIsUndetectableAndBranch>(value); + } else { + if_nil.Then(); + if_nil.Else(); + if ((types & CompareNilICStub::kCompareAgainstMonomorphicMap) != 0) { + BuildCheckNonSmi(value); + // For ICs, the map checked below is a sentinel map that gets replaced by + // the monomorphic map when the code is used as a template to generate a + // new IC. For optimized functions, there is no sentinel map, the map + // emitted below is the actual monomorphic map. + BuildCheckMap(value, map); + } else { + if (kind == kNonStrictEquality) { + if_nil.Deopt(); + } + } + } + + if_nil.CaptureContinuation(continuation); +} + + +HValue* HGraphBuilder::BuildCreateAllocationSiteInfo(HValue* previous_object, + int previous_object_size, + HValue* payload) { + HInnerAllocatedObject* alloc_site = new(zone()) + HInnerAllocatedObject(previous_object, previous_object_size); + AddInstruction(alloc_site); + Handle<Map> alloc_site_map(isolate()->heap()->allocation_site_info_map()); + BuildStoreMap(alloc_site, alloc_site_map); + AddInstruction(new(zone()) HStoreNamedField(alloc_site, + isolate()->factory()->payload_string(), + payload, + true, + AllocationSiteInfo::kPayloadOffset)); + return alloc_site; +} + + +HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, + ElementsKind kind, + HValue* allocation_site_payload, + AllocationSiteMode mode) : + builder_(builder), + kind_(kind), + allocation_site_payload_(allocation_site_payload) { + if (mode == DONT_TRACK_ALLOCATION_SITE) { + mode_ = mode; + } else { + mode_ = AllocationSiteInfo::GetMode(kind); + } +} + + +HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode(HValue* context) { + // Get the global context, the native context, the map array + HInstruction* global_object = AddInstruction(new(zone()) + HGlobalObject(context)); + HInstruction* native_context = AddInstruction(new(zone()) + HLoadNamedField(global_object, true, GlobalObject::kNativeContextOffset)); + int offset = Context::kHeaderSize + + kPointerSize * Context::JS_ARRAY_MAPS_INDEX; + HInstruction* map_array = AddInstruction(new(zone()) + HLoadNamedField(native_context, true, offset)); + offset = kind_ * kPointerSize + FixedArrayBase::kHeaderSize; + return AddInstruction(new(zone()) HLoadNamedField(map_array, true, offset)); +} + + +HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize( + HValue* length_node) { + HValue* context = builder()->environment()->LookupContext(); + ASSERT(length_node != NULL); + + int base_size = JSArray::kSize; + if (mode_ == TRACK_ALLOCATION_SITE) { + base_size += AllocationSiteInfo::kSize; + } + + if (IsFastDoubleElementsKind(kind_)) { + base_size += FixedDoubleArray::kHeaderSize; + } else { + base_size += FixedArray::kHeaderSize; + } + + HInstruction* elements_size_value = new(zone()) + HConstant(elements_size(), Representation::Integer32()); + AddInstruction(elements_size_value); + HInstruction* mul = HMul::New(zone(), context, length_node, + elements_size_value); + mul->ChangeRepresentation(Representation::Integer32()); + mul->ClearFlag(HValue::kCanOverflow); + AddInstruction(mul); + + HInstruction* base = new(zone()) HConstant(base_size, + Representation::Integer32()); + AddInstruction(base); + HInstruction* total_size = HAdd::New(zone(), context, base, mul); + total_size->ChangeRepresentation(Representation::Integer32()); + total_size->ClearFlag(HValue::kCanOverflow); + AddInstruction(total_size); + return total_size; +} + + +HValue* HGraphBuilder::JSArrayBuilder::EstablishEmptyArrayAllocationSize() { + int base_size = JSArray::kSize; + if (mode_ == TRACK_ALLOCATION_SITE) { + base_size += AllocationSiteInfo::kSize; + } + + base_size += IsFastDoubleElementsKind(kind_) + ? FixedDoubleArray::SizeFor(initial_capacity()) + : FixedArray::SizeFor(initial_capacity()); + + HConstant* array_size = + new(zone()) HConstant(base_size, Representation::Integer32()); + AddInstruction(array_size); + return array_size; +} + + +HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() { + HValue* size_in_bytes = EstablishEmptyArrayAllocationSize(); + HConstant* capacity = + new(zone()) HConstant(initial_capacity(), Representation::Integer32()); + AddInstruction(capacity); + return AllocateArray(size_in_bytes, + capacity, + builder()->graph()->GetConstant0(), + true); +} + + +HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity, + HValue* length_field, + bool fill_with_hole) { + HValue* size_in_bytes = EstablishAllocationSize(capacity); + return AllocateArray(size_in_bytes, capacity, length_field, fill_with_hole); +} + + +HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, + HValue* capacity, + HValue* length_field, + bool fill_with_hole) { + HValue* context = builder()->environment()->LookupContext(); + + // Allocate (dealing with failure appropriately) + HAllocate::Flags flags = HAllocate::DefaultFlags(kind_); + HAllocate* new_object = new(zone()) HAllocate(context, size_in_bytes, + HType::JSArray(), flags); + AddInstruction(new_object); + + // Fill in the fields: map, properties, length + HValue* map = EmitMapCode(context); + elements_location_ = builder()->BuildJSArrayHeader(new_object, + map, + mode_, + allocation_site_payload_, + length_field); + + // Initialize the elements + builder()->BuildInitializeElements(elements_location_, kind_, capacity); + + if (fill_with_hole) { + builder()->BuildFillElementsWithHole(context, elements_location_, kind_, + graph()->GetConstant0(), capacity); + } + + return new_object; +} + + HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle) : HGraphBuilder(info), @@ -3506,7 +3747,12 @@ void HInferRepresentation::Analyze() { } } - // (3a) Use the phi reachability information from step 2 to + // Simplify constant phi inputs where possible. + for (int i = 0; i < phi_count; ++i) { + phi_list->at(i)->SimplifyConstantInputs(); + } + + // Use the phi reachability information from step 2 to // push information about values which can't be converted to integer // without deoptimization through the phi use-def chains, avoiding // unnecessary deoptimizations later. @@ -3523,7 +3769,7 @@ void HInferRepresentation::Analyze() { } } - // (3b) Use the phi reachability information from step 2 to + // Use the phi reachability information from step 2 to // sum up the non-phi use counts of all connected phis. for (int i = 0; i < phi_count; ++i) { HPhi* phi = phi_list->at(i); @@ -6412,9 +6658,11 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { pointer_size, DONT_TRACK_ALLOCATION_SITE); } else { + Handle<FixedArray> closure_literals(closure->literals(), isolate()); literal = AddInstruction( new(zone()) HObjectLiteral(context, expr->constant_properties(), + closure_literals, expr->fast_elements(), expr->literal_index(), expr->depth(), @@ -6503,7 +6751,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { HValue* context = environment()->LookupContext(); HInstruction* literal; - Handle<FixedArray> literals(environment()->closure()->literals()); + Handle<FixedArray> literals(environment()->closure()->literals(), isolate()); Handle<Object> raw_boilerplate(literals->get(expr->literal_index()), isolate()); @@ -6555,6 +6803,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { literal = AddInstruction( new(zone()) HArrayLiteral(context, original_boilerplate_object, + literals, length, expr->literal_index(), expr->depth(), @@ -6652,7 +6901,7 @@ static int ComputeLoadStoreFieldIndex(Handle<Map> type, void HOptimizedGraphBuilder::AddCheckMap(HValue* object, Handle<Map> map) { AddInstruction(new(zone()) HCheckNonSmi(object)); - AddInstruction(new(zone()) HCheckMaps(object, map, zone())); + AddInstruction(HCheckMaps::New(object, map, zone())); } @@ -6781,7 +7030,7 @@ bool HOptimizedGraphBuilder::HandlePolymorphicArrayLengthLoad( AddInstruction(new(zone()) HCheckNonSmi(object)); HInstruction* typecheck = - AddInstruction(new(zone()) HCheckMaps(object, types, zone())); + AddInstruction(HCheckMaps::New(object, types, zone())); HInstruction* instr = HLoadNamedField::NewArrayLength(zone(), object, typecheck); instr->set_position(expr->position()); @@ -6833,7 +7082,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, AddInstruction(new(zone()) HCheckNonSmi(object)); HInstruction* instr; if (count == types->length() && is_monomorphic_field) { - AddInstruction(new(zone()) HCheckMaps(object, types, zone())); + AddInstruction(HCheckMaps::New(object, types, zone())); instr = BuildLoadNamedField(object, map, &lookup); } else { HValue* context = environment()->LookupContext(); @@ -7510,8 +7759,7 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( Handle<Map> map, bool is_store, KeyedAccessStoreMode store_mode) { - HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, - zone(), dependency); + HCheckMaps* mapcheck = HCheckMaps::New(object, map, zone(), dependency); AddInstruction(mapcheck); if (dependency) { mapcheck->ClearGVNFlag(kDependsOnElementsKind); @@ -7568,7 +7816,7 @@ HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( } if (!has_double_maps && !has_smi_or_object_maps) return NULL; - HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); + HCheckMaps* check_maps = HCheckMaps::New(object, maps, zone()); AddInstruction(check_maps); HInstruction* instr = BuildUncheckedMonomorphicElementAccess( object, key, val, check_maps, @@ -7720,7 +7968,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( HInstruction* access; if (IsFastElementsKind(elements_kind)) { if (is_store && !IsFastDoubleElementsKind(elements_kind)) { - AddInstruction(new(zone()) HCheckMaps( + AddInstruction(HCheckMaps::New( elements, isolate()->factory()->fixed_array_map(), zone(), elements_kind_branch)); } @@ -7754,10 +8002,12 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( } *has_side_effects |= access->HasObservableSideEffects(); + // The caller will use has_side_effects and add correct Simulate. + access->SetFlag(HValue::kHasNoObservableSideEffects); if (position != -1) { access->set_position(position); } - if_jsarray->Goto(join); + if_jsarray->GotoNoSimulate(join); set_current_block(if_fastobject); length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); @@ -7777,18 +8027,19 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( elements_kind_branch, elements_kind, is_store)); } *has_side_effects |= access->HasObservableSideEffects(); + // The caller will use has_side_effects and add correct Simulate. + access->SetFlag(HValue::kHasNoObservableSideEffects); if (position != RelocInfo::kNoPosition) access->set_position(position); if (!is_store) { Push(access); } - current_block()->Goto(join); + current_block()->GotoNoSimulate(join); set_current_block(if_false); } } // Deopt if none of the cases matched. current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); - join->SetJoinId(ast_id); set_current_block(join); return is_store ? NULL : Pop(); } @@ -8067,14 +8318,12 @@ class FunctionSorter { }; -static int CompareHotness(void const* a, void const* b) { - FunctionSorter const* function1 = reinterpret_cast<FunctionSorter const*>(a); - FunctionSorter const* function2 = reinterpret_cast<FunctionSorter const*>(b); - int diff = function1->ticks() - function2->ticks(); - if (diff != 0) return -diff; - diff = function1->ast_length() - function2->ast_length(); - if (diff != 0) return diff; - return function1->src_length() - function2->src_length(); +inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) { + int diff = lhs.ticks() - rhs.ticks(); + if (diff != 0) return diff > 0; + diff = lhs.ast_length() - rhs.ast_length(); + if (diff != 0) return diff < 0; + return lhs.src_length() < rhs.src_length(); } @@ -8117,10 +8366,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( } } - qsort(reinterpret_cast<void*>(&order[0]), - ordered_functions, - sizeof(order[0]), - &CompareHotness); + std::sort(order, order + ordered_functions); HBasicBlock* number_block = NULL; @@ -8697,6 +8943,18 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, return true; } break; + case kMathImul: + if (expr->arguments()->length() == 2) { + HValue* right = Pop(); + HValue* left = Pop(); + Drop(1); // Receiver. + HValue* context = environment()->LookupContext(); + HInstruction* op = HMul::NewImul(zone(), context, left, right); + if (drop_extra) Drop(1); // Optionally drop the function. + ast_context()->ReturnInstruction(op, expr->id()); + return true; + } + break; default: // Not supported for inlining yet. break; @@ -8844,6 +9102,18 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( return true; } break; + case kMathImul: + if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { + AddCheckConstantFunction(expr->holder(), receiver, receiver_map); + HValue* right = Pop(); + HValue* left = Pop(); + Drop(1); // Receiver. + HValue* context = environment()->LookupContext(); + HInstruction* result = HMul::NewImul(zone(), context, left, right); + ast_context()->ReturnInstruction(result, expr->id()); + return true; + } + break; default: // Not yet supported for inlining. break; @@ -9276,19 +9546,31 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { } else { // The constructor function is both an operand to the instruction and an // argument to the construct call. + bool use_call_new_array = FLAG_optimize_constructed_arrays && + !(expr->target().is_null()) && + *(expr->target()) == isolate()->global_context()->array_function(); + CHECK_ALIVE(VisitArgument(expr->expression())); HValue* constructor = HPushArgument::cast(Top())->argument(); CHECK_ALIVE(VisitArgumentList(expr->arguments())); HCallNew* call; - if (FLAG_optimize_constructed_arrays && - !(expr->target().is_null()) && - *(expr->target()) == isolate()->global_context()->array_function()) { + if (use_call_new_array) { + AddInstruction(new(zone()) HCheckFunction(constructor, + Handle<JSFunction>(isolate()->global_context()->array_function()))); Handle<Object> feedback = oracle()->GetInfo(expr->CallNewFeedbackId()); ASSERT(feedback->IsSmi()); + + // TODO(mvstanton): It would be better to use the already created global + // property cell that is shared by full code gen. That way, any transition + // information that happened after crankshaft won't be lost. The right + // way to do that is to begin passing the cell to the type feedback oracle + // instead of just the value in the cell. Do this in a follow-up checkin. Handle<JSGlobalPropertyCell> cell = isolate()->factory()->NewJSGlobalPropertyCell(feedback); - AddInstruction(new(zone()) HCheckFunction(constructor, - Handle<JSFunction>(isolate()->global_context()->array_function()))); + + // TODO(mvstanton): Here we should probably insert code to check if the + // type cell elements kind is different from when we compiled, and deopt + // in that case. Do this in a follow-up checin. call = new(zone()) HCallNewArray(context, constructor, argument_count, cell); } else { @@ -9433,7 +9715,8 @@ void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) { info = TypeInfo::Unknown(); } if (instr->IsBinaryOperation()) { - HBinaryOperation::cast(instr)->set_observed_input_representation(rep, rep); + HBinaryOperation::cast(instr)->set_observed_input_representation(1, rep); + HBinaryOperation::cast(instr)->set_observed_input_representation(2, rep); } return ast_context()->ReturnInstruction(instr, expr->id()); } @@ -9874,7 +10157,8 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( if (instr->IsBinaryOperation()) { HBinaryOperation* binop = HBinaryOperation::cast(instr); - binop->set_observed_input_representation(left_rep, right_rep); + binop->set_observed_input_representation(1, left_rep); + binop->set_observed_input_representation(2, right_rep); binop->initialize_output_representation(result_rep); } return instr; @@ -10254,7 +10538,8 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { if (combined_rep.IsTagged() || combined_rep.IsNone()) { HCompareGeneric* result = new(zone()) HCompareGeneric(context, left, right, op); - result->set_observed_input_representation(left_rep, right_rep); + result->set_observed_input_representation(1, left_rep); + result->set_observed_input_representation(2, right_rep); result->set_position(expr->position()); return ast_context()->ReturnInstruction(result, expr->id()); } else { @@ -10276,9 +10561,24 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, ASSERT(current_block()->HasPredecessor()); EqualityKind kind = expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality; - HIsNilAndBranch* instr = new(zone()) HIsNilAndBranch(value, kind, nil); - instr->set_position(expr->position()); - return ast_context()->ReturnControl(instr, expr->id()); + HIfContinuation continuation; + TypeFeedbackId id = expr->CompareOperationFeedbackId(); + CompareNilICStub::Types types; + if (kind == kStrictEquality) { + if (nil == kNullValue) { + types = CompareNilICStub::kCompareAgainstNull; + } else { + types = CompareNilICStub::kCompareAgainstUndefined; + } + } else { + types = static_cast<CompareNilICStub::Types>( + oracle()->CompareNilTypes(id)); + if (types == 0) types = CompareNilICStub::kFullCompare; + } + Handle<Map> map_handle(oracle()->CompareNilMonomorphicReceiverType(id)); + BuildCompareNil(value, kind, types, map_handle, + expr->position(), &continuation); + return ast_context()->ReturnContinuation(&continuation, expr->id()); } @@ -10401,15 +10701,7 @@ void HOptimizedGraphBuilder::BuildEmitDeepCopy( // Build Allocation Site Info if desired if (create_allocation_site_info) { - HValue* alloc_site = - AddInstruction(new(zone) HInnerAllocatedObject(target, JSArray::kSize)); - Handle<Map> alloc_site_map(isolate()->heap()->allocation_site_info_map()); - BuildStoreMap(alloc_site, alloc_site_map); - int alloc_payload_offset = AllocationSiteInfo::kPayloadOffset; - AddInstruction(new(zone) HStoreNamedField(alloc_site, - factory->payload_string(), - original_boilerplate, - true, alloc_payload_offset)); + BuildCreateAllocationSiteInfo(target, JSArray::kSize, original_boilerplate); } if (object_elements != NULL) { @@ -11201,6 +11493,17 @@ void HOptimizedGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { } +// Support for generators. +void HOptimizedGraphBuilder::GenerateGeneratorSend(CallRuntime* call) { + return Bailout("inlined runtime function: GeneratorSend"); +} + + +void HOptimizedGraphBuilder::GenerateGeneratorThrow(CallRuntime* call) { + return Bailout("inlined runtime function: GeneratorThrow"); +} + + #undef CHECK_BAILOUT #undef CHECK_ALIVE @@ -11521,16 +11824,14 @@ void HTracer::TraceCompilation(CompilationInfo* info) { void HTracer::TraceLithium(const char* name, LChunk* chunk) { ASSERT(!FLAG_parallel_recompilation); - HandleDereferenceGuard allow_handle_deref(chunk->isolate(), - HandleDereferenceGuard::ALLOW); + ALLOW_HANDLE_DEREF(chunk->isolate(), "debug output"); Trace(name, chunk->graph(), chunk); } void HTracer::TraceHydrogen(const char* name, HGraph* graph) { ASSERT(!FLAG_parallel_recompilation); - HandleDereferenceGuard allow_handle_deref(graph->isolate(), - HandleDereferenceGuard::ALLOW); + ALLOW_HANDLE_DEREF(graph->isolate(), "debug output"); Trace(name, graph, NULL); } |