diff options
Diffstat (limited to 'deps/v8/src/hydrogen.cc')
-rw-r--r-- | deps/v8/src/hydrogen.cc | 408 |
1 files changed, 222 insertions, 186 deletions
diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 63174aa5db..301e7e40fa 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -34,12 +34,15 @@ #include "src/hydrogen-sce.h" #include "src/hydrogen-store-elimination.h" #include "src/hydrogen-uint32-analysis.h" +#include "src/ic/call-optimization.h" +#include "src/ic/ic.h" +// GetRootConstructor +#include "src/ic/ic-inl.h" #include "src/lithium-allocator.h" #include "src/parser.h" -#include "src/runtime.h" +#include "src/runtime/runtime.h" #include "src/scopeinfo.h" #include "src/scopes.h" -#include "src/stub-cache.h" #include "src/typing.h" #if V8_TARGET_ARCH_IA32 @@ -1853,9 +1856,11 @@ HValue* HGraphBuilder::BuildRegExpConstructResult(HValue* length, HAllocate* elements = BuildAllocateElements(elements_kind, size); BuildInitializeElementsHeader(elements, elements_kind, length); - HConstant* size_in_bytes_upper_bound = EstablishElementsAllocationSize( - elements_kind, max_length->Integer32Value()); - elements->set_size_upper_bound(size_in_bytes_upper_bound); + if (!elements->has_size_upper_bound()) { + HConstant* size_in_bytes_upper_bound = EstablishElementsAllocationSize( + elements_kind, max_length->Integer32Value()); + elements->set_size_upper_bound(size_in_bytes_upper_bound); + } Add<HStoreNamedField>( result, HObjectAccess::ForJSArrayOffset(JSArray::kElementsOffset), @@ -2063,11 +2068,11 @@ HValue* HGraphBuilder::BuildCreateConsString( HInstruction* right_instance_type = AddLoadStringInstanceType(right); // Allocate the cons string object. HAllocate does not care whether we - // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use + // pass CONS_STRING_TYPE or CONS_ONE_BYTE_STRING_TYPE here, so we just use // CONS_STRING_TYPE here. Below we decide whether the cons string is // one-byte or two-byte and set the appropriate map. DCHECK(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE, - CONS_ASCII_STRING_TYPE)); + CONS_ONE_BYTE_STRING_TYPE)); HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize), HType::String(), CONS_STRING_TYPE, allocation_mode); @@ -2112,7 +2117,7 @@ HValue* HGraphBuilder::BuildCreateConsString( // We can safely skip the write barrier for storing the map here. Add<HStoreNamedField>( result, HObjectAccess::ForMap(), - Add<HConstant>(isolate()->factory()->cons_ascii_string_map())); + Add<HConstant>(isolate()->factory()->cons_one_byte_string_map())); } if_onebyte.Else(); { @@ -2240,8 +2245,8 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd( { HConstant* string_map = Add<HConstant>(isolate()->factory()->string_map()); - HConstant* ascii_string_map = - Add<HConstant>(isolate()->factory()->ascii_string_map()); + HConstant* one_byte_string_map = + Add<HConstant>(isolate()->factory()->one_byte_string_map()); // Determine map and size depending on whether result is one-byte string. IfBuilder if_onebyte(this); @@ -2255,7 +2260,7 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd( { // Allocate sequential one-byte string object. Push(length); - Push(ascii_string_map); + Push(one_byte_string_map); } if_onebyte.Else(); { @@ -2275,7 +2280,7 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd( HValue* size = BuildObjectSizeAlignment(Pop(), SeqString::kHeaderSize); // Allocate the string object. HAllocate does not care whether we pass - // STRING_TYPE or ASCII_STRING_TYPE here, so we just use STRING_TYPE here. + // STRING_TYPE or ONE_BYTE_STRING_TYPE here, so we just use STRING_TYPE. HAllocate* result = BuildAllocate( size, HType::String(), STRING_TYPE, allocation_mode); Add<HStoreNamedField>(result, HObjectAccess::ForMap(), map); @@ -3321,7 +3326,6 @@ HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) break_scope_(NULL), inlined_count_(0), globals_(10, info->zone()), - inline_bailout_(false), osr_(new(info->zone()) HOsrBuilder(this)) { // This is not initialized in the initializer list because the // constructor for the initial state relies on function_state_ == NULL @@ -3430,10 +3434,10 @@ HGraph::HGraph(CompilationInfo* info) next_inline_id_(0), inlined_functions_(5, info->zone()) { if (info->IsStub()) { - HydrogenCodeStub* stub = info->code_stub(); - CodeStubInterfaceDescriptor* descriptor = stub->GetInterfaceDescriptor(); - start_environment_ = new(zone_) HEnvironment( - zone_, descriptor->GetEnvironmentParameterCount()); + CallInterfaceDescriptor descriptor = + info->code_stub()->GetCallInterfaceDescriptor(); + start_environment_ = new (zone_) + HEnvironment(zone_, descriptor.GetEnvironmentParameterCount()); } else { TraceInlinedFunction(info->shared_info(), HSourcePosition::Unknown()); start_environment_ = @@ -4206,7 +4210,7 @@ void TestContext::BuildBranch(HValue* value) { void HOptimizedGraphBuilder::Bailout(BailoutReason reason) { - current_info()->set_bailout_reason(reason); + current_info()->AbortOptimization(reason); SetStackOverflow(); } @@ -4506,6 +4510,11 @@ void HOptimizedGraphBuilder::SetUpScope(Scope* scope) { } +Type* HOptimizedGraphBuilder::ToType(Handle<Map> map) { + return IC::MapToType<Type>(map, zone()); +} + + void HOptimizedGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { for (int i = 0; i < statements->length(); i++) { Statement* stmt = statements->at(i); @@ -4824,14 +4833,9 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { DCHECK(current_block() != NULL); DCHECK(current_block()->HasPredecessor()); - // We only optimize switch statements with a bounded number of clauses. - const int kCaseClauseLimit = 128; ZoneList<CaseClause*>* clauses = stmt->cases(); int clause_count = clauses->length(); ZoneList<HBasicBlock*> body_blocks(clause_count, zone()); - if (clause_count > kCaseClauseLimit) { - return Bailout(kSwitchStatementTooManyClauses); - } CHECK_ALIVE(VisitForValue(stmt->tag())); Add<HSimulate>(stmt->EntryId()); @@ -5238,6 +5242,14 @@ void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { } +void HOptimizedGraphBuilder::VisitClassLiteral(ClassLiteral* lit) { + DCHECK(!HasStackOverflow()); + DCHECK(current_block() != NULL); + DCHECK(current_block()->HasPredecessor()); + return Bailout(kClassLiteral); +} + + void HOptimizedGraphBuilder::VisitNativeFunctionLiteral( NativeFunctionLiteral* expr) { DCHECK(!HasStackOverflow()); @@ -5286,20 +5298,27 @@ void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) { HOptimizedGraphBuilder::GlobalPropertyAccess - HOptimizedGraphBuilder::LookupGlobalProperty( - Variable* var, LookupResult* lookup, PropertyAccessType access_type) { +HOptimizedGraphBuilder::LookupGlobalProperty(Variable* var, LookupIterator* it, + PropertyAccessType access_type) { if (var->is_this() || !current_info()->has_global_object()) { return kUseGeneric; } - Handle<GlobalObject> global(current_info()->global_object()); - global->Lookup(var->name(), lookup); - if (!lookup->IsNormal() || - (access_type == STORE && lookup->IsReadOnly()) || - lookup->holder() != *global) { - return kUseGeneric; - } - return kUseCell; + switch (it->state()) { + case LookupIterator::ACCESSOR: + case LookupIterator::ACCESS_CHECK: + case LookupIterator::INTERCEPTOR: + case LookupIterator::NOT_FOUND: + return kUseGeneric; + case LookupIterator::DATA: + if (access_type == STORE && it->IsReadOnly()) return kUseGeneric; + return kUseCell; + case LookupIterator::JSPROXY: + case LookupIterator::TRANSITION: + UNREACHABLE(); + } + UNREACHABLE(); + return kUseGeneric; } @@ -5340,17 +5359,13 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { return ast_context()->ReturnInstruction(instr, expr->id()); } - LookupResult lookup(isolate()); - GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, LOAD); - - if (type == kUseCell && - current_info()->global_object()->IsAccessCheckNeeded()) { - type = kUseGeneric; - } + Handle<GlobalObject> global(current_info()->global_object()); + LookupIterator it(global, variable->name(), + LookupIterator::OWN_SKIP_INTERCEPTOR); + GlobalPropertyAccess type = LookupGlobalProperty(variable, &it, LOAD); if (type == kUseCell) { - Handle<GlobalObject> global(current_info()->global_object()); - Handle<PropertyCell> cell(global->GetPropertyCell(&lookup)); + Handle<PropertyCell> cell = it.GetPropertyCell(); if (cell->type()->IsConstant()) { PropertyCell::AddDependentCompilationInfo(cell, top_info()); Handle<Object> constant_object = cell->type()->AsConstant()->Value(); @@ -5362,7 +5377,7 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { return ast_context()->ReturnInstruction(constant, expr->id()); } else { HLoadGlobalCell* instr = - New<HLoadGlobalCell>(cell, lookup.GetPropertyDetails()); + New<HLoadGlobalCell>(cell, it.property_details()); return ast_context()->ReturnInstruction(instr, expr->id()); } } else { @@ -5603,7 +5618,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { PropertyAccessInfo info(this, STORE, ToType(map), name); if (info.CanAccessMonomorphic()) { HValue* checked_literal = Add<HCheckMaps>(literal, map); - DCHECK(!info.lookup()->IsPropertyCallbacks()); + DCHECK(!info.IsAccessor()); store = BuildMonomorphicAccess( &info, literal, checked_literal, value, BailoutId::None(), BailoutId::None()); @@ -5790,19 +5805,17 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField( PropertyAccessInfo* info, HValue* checked_object) { // See if this is a load for an immutable property - if (checked_object->ActualValue()->IsConstant() && - info->lookup()->IsCacheable() && - info->lookup()->IsReadOnly() && info->lookup()->IsDontDelete()) { + if (checked_object->ActualValue()->IsConstant()) { Handle<Object> object( HConstant::cast(checked_object->ActualValue())->handle(isolate())); if (object->IsJSObject()) { - LookupResult lookup(isolate()); - Handle<JSObject>::cast(object)->Lookup(info->name(), &lookup); - Handle<Object> value(lookup.GetLazyValue(), isolate()); - - DCHECK(!value->IsTheHole()); - return New<HConstant>(value); + LookupIterator it(object, info->name(), + LookupIterator::OWN_SKIP_INTERCEPTOR); + Handle<Object> value = JSObject::GetDataProperty(&it); + if (it.IsFound() && it.IsReadOnly() && !it.IsConfigurable()) { + return New<HConstant>(value); + } } } @@ -5834,7 +5847,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( PropertyAccessInfo* info, HValue* checked_object, HValue* value) { - bool transition_to_field = info->lookup()->IsTransition(); + bool transition_to_field = info->IsTransition(); // TODO(verwaest): Move this logic into PropertyAccessInfo. HObjectAccess field_access = info->access(); @@ -5911,26 +5924,26 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible( if (!LookupDescriptor()) return false; - if (!lookup_.IsFound()) { - return (!info->lookup_.IsFound() || info->has_holder()) && - map()->prototype() == info->map()->prototype(); + if (!IsFound()) { + return (!info->IsFound() || info->has_holder()) && + map()->prototype() == info->map()->prototype(); } // Mismatch if the other access info found the property in the prototype // chain. if (info->has_holder()) return false; - if (lookup_.IsPropertyCallbacks()) { + if (IsAccessor()) { return accessor_.is_identical_to(info->accessor_) && api_holder_.is_identical_to(info->api_holder_); } - if (lookup_.IsConstant()) { + if (IsConstant()) { return constant_.is_identical_to(info->constant_); } - DCHECK(lookup_.IsField()); - if (!info->lookup_.IsField()) return false; + DCHECK(IsField()); + if (!info->IsField()) return false; Representation r = access_.representation(); if (IsLoad()) { @@ -5973,23 +5986,23 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { - if (!IsLoad() && lookup_.IsProperty() && - (lookup_.IsReadOnly() || !lookup_.IsCacheable())) { + if (!IsLoad() && IsProperty() && IsReadOnly()) { return false; } - if (lookup_.IsField()) { + if (IsField()) { // Construct the object field access. - access_ = HObjectAccess::ForField(map, &lookup_, name_); + int index = GetLocalFieldIndexFromMap(map); + access_ = HObjectAccess::ForField(map, index, representation(), name_); // Load field map for heap objects. LoadFieldMaps(map); - } else if (lookup_.IsPropertyCallbacks()) { - Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); - if (!callback->IsAccessorPair()) return false; - Object* raw_accessor = IsLoad() - ? Handle<AccessorPair>::cast(callback)->getter() - : Handle<AccessorPair>::cast(callback)->setter(); + } else if (IsAccessor()) { + Handle<Object> accessors = GetAccessorsFromMap(map); + if (!accessors->IsAccessorPair()) return false; + Object* raw_accessor = + IsLoad() ? Handle<AccessorPair>::cast(accessors)->getter() + : Handle<AccessorPair>::cast(accessors)->setter(); if (!raw_accessor->IsJSFunction()) return false; Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor)); if (accessor->shared()->IsApiFunction()) { @@ -6002,8 +6015,8 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { } } accessor_ = accessor; - } else if (lookup_.IsConstant()) { - constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); + } else if (IsConstant()) { + constant_ = GetConstantFromMap(map); } return true; @@ -6017,7 +6030,7 @@ void HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps( field_type_ = HType::Tagged(); // Figure out the field type from the accessor map. - Handle<HeapType> field_type(lookup_.GetFieldTypeFromMap(*map), isolate()); + Handle<HeapType> field_type = GetFieldTypeFromMap(map); // Collect the (stable) maps from the field type. int num_field_maps = field_type->NumClasses(); @@ -6042,9 +6055,8 @@ void HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps( DCHECK(field_type_.IsHeapObject()); // Add dependency on the map that introduced the field. - Map::AddDependentCompilationInfo( - handle(lookup_.GetFieldOwnerFromMap(*map), isolate()), - DependentCode::kFieldTypeGroup, top_info()); + Map::AddDependentCompilationInfo(GetFieldOwnerFromMap(map), + DependentCode::kFieldTypeGroup, top_info()); } @@ -6062,7 +6074,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { return false; } map->LookupDescriptor(*holder_, *name_, &lookup_); - if (lookup_.IsFound()) return LoadResult(map); + if (IsFound()) return LoadResult(map); } lookup_.NotFound(); return true; @@ -6078,19 +6090,23 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() { return IsLoad(); } if (!LookupDescriptor()) return false; - if (lookup_.IsFound()) { - if (IsLoad()) return true; - return !lookup_.IsReadOnly() && lookup_.IsCacheable(); - } + if (IsFound()) return IsLoad() || !IsReadOnly(); if (!LookupInPrototypes()) return false; if (IsLoad()) return true; - if (lookup_.IsPropertyCallbacks()) return true; + if (IsAccessor()) return true; Handle<Map> map = this->map(); map->LookupTransition(NULL, *name_, &lookup_); if (lookup_.IsTransitionToField() && map->unused_property_fields() > 0) { // Construct the object field access. - access_ = HObjectAccess::ForField(map, &lookup_, name_); + int descriptor = transition()->LastAdded(); + int index = + transition()->instance_descriptors()->GetFieldIndex(descriptor) - + map->inobject_properties(); + PropertyDetails details = + transition()->instance_descriptors()->GetDetails(descriptor); + Representation representation = details.representation(); + access_ = HObjectAccess::ForField(map, index, representation, name_); // Load field map for heap objects. LoadFieldMaps(transition()); @@ -6125,8 +6141,8 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic( if (type_->Is(Type::Number())) return false; // Multiple maps cannot transition to the same target map. - DCHECK(!IsLoad() || !lookup_.IsTransition()); - if (lookup_.IsTransition() && types->length() > 1) return false; + DCHECK(!IsLoad() || !IsTransition()); + if (IsTransition() && types->length() > 1) return false; for (int i = 1; i < types->length(); ++i) { PropertyAccessInfo test_info( @@ -6180,12 +6196,12 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess( checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); } - if (!info->lookup()->IsFound()) { + if (!info->IsFound()) { DCHECK(info->IsLoad()); return graph()->GetConstantUndefined(); } - if (info->lookup()->IsField()) { + if (info->IsField()) { if (info->IsLoad()) { return BuildLoadNamedField(info, checked_holder); } else { @@ -6193,12 +6209,12 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess( } } - if (info->lookup()->IsTransition()) { + if (info->IsTransition()) { DCHECK(!info->IsLoad()); return BuildStoreNamedField(info, checked_object, value); } - if (info->lookup()->IsPropertyCallbacks()) { + if (info->IsAccessor()) { Push(checked_object); int argument_count = 1; if (!info->IsLoad()) { @@ -6222,7 +6238,7 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess( return BuildCallConstantFunction(info->accessor(), argument_count); } - DCHECK(info->lookup()->IsConstant()); + DCHECK(info->IsConstant()); if (info->IsLoad()) { return New<HConstant>(info->constant()); } else { @@ -6248,7 +6264,8 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( bool handle_smi = false; STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism); - for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { + int i; + for (i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name); if (info.type()->Is(Type::String())) { if (handled_string) continue; @@ -6263,7 +6280,12 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( } } - count = 0; + if (i < types->length()) { + count = -1; + types->Clear(); + } else { + count = 0; + } HControlInstruction* smi_check = NULL; handled_string = false; @@ -6384,8 +6406,8 @@ static bool ComputeReceiverTypes(Expression* expr, types->FilterForPossibleTransitions(root_map); monomorphic = types->length() == 1; } - return monomorphic && CanInlinePropertyAccess( - IC::MapToType<Type>(types->first(), zone)); + return monomorphic && + CanInlinePropertyAccess(IC::MapToType<Type>(types->first(), zone)); } @@ -6408,8 +6430,8 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr, HValue* key = environment()->ExpressionStackAt(1); HValue* object = environment()->ExpressionStackAt(2); bool has_side_effects = false; - HandleKeyedElementAccess(object, key, value, expr, - STORE, &has_side_effects); + HandleKeyedElementAccess(object, key, value, expr, ast_id, return_id, STORE, + &has_side_effects); Drop(3); Push(value); Add<HSimulate>(return_id, REMOVABLE_SIMULATE); @@ -6458,11 +6480,11 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( Variable* var, HValue* value, BailoutId ast_id) { - LookupResult lookup(isolate()); - GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, STORE); + Handle<GlobalObject> global(current_info()->global_object()); + LookupIterator it(global, var->name(), LookupIterator::OWN_SKIP_INTERCEPTOR); + GlobalPropertyAccess type = LookupGlobalProperty(var, &it, STORE); if (type == kUseCell) { - Handle<GlobalObject> global(current_info()->global_object()); - Handle<PropertyCell> cell(global->GetPropertyCell(&lookup)); + Handle<PropertyCell> cell = it.GetPropertyCell(); if (cell->type()->IsConstant()) { Handle<Object> constant = cell->type()->AsConstant()->Value(); if (value->IsConstant()) { @@ -6487,7 +6509,7 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( } } HInstruction* instr = - Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails()); + Add<HStoreGlobalCell>(value, cell, it.property_details()); if (instr->HasObservableSideEffects()) { Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); } @@ -6744,10 +6766,12 @@ void HOptimizedGraphBuilder::VisitThrow(Throw* expr) { DCHECK(!HasStackOverflow()); DCHECK(current_block() != NULL); DCHECK(current_block()->HasPredecessor()); - // We don't optimize functions with invalid left-hand sides in - // assignments, count operations, or for-in. Consequently throw can - // currently only occur in an effect context. - DCHECK(ast_context()->IsEffect()); + if (!ast_context()->IsEffect()) { + // The parser turns invalid left-hand sides in assignments into throw + // statements, which may not be in effect contexts. We might still try + // to optimize such functions; bail out now if we do. + return Bailout(kInvalidLeftHandSideInAssignment); + } CHECK_ALIVE(VisitForValue(expr->exception())); HValue* value = environment()->Pop(); @@ -7099,12 +7123,32 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( - HValue* obj, - HValue* key, - HValue* val, - Expression* expr, - PropertyAccessType access_type, + HValue* obj, HValue* key, HValue* val, Expression* expr, BailoutId ast_id, + BailoutId return_id, PropertyAccessType access_type, bool* has_side_effects) { + if (key->ActualValue()->IsConstant()) { + Handle<Object> constant = + HConstant::cast(key->ActualValue())->handle(isolate()); + uint32_t array_index; + if (constant->IsString() && + !Handle<String>::cast(constant)->AsArrayIndex(&array_index)) { + if (!constant->IsUniqueName()) { + constant = isolate()->factory()->InternalizeString( + Handle<String>::cast(constant)); + } + HInstruction* instr = + BuildNamedAccess(access_type, ast_id, return_id, expr, obj, + Handle<String>::cast(constant), val, false); + if (instr == NULL || instr->IsLinked()) { + *has_side_effects = false; + } else { + AddInstruction(instr); + *has_side_effects = instr->HasObservableSideEffects(); + } + return instr; + } + } + DCHECK(!expr->IsPropertyName()); HInstruction* instr = NULL; @@ -7201,7 +7245,9 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) { HInstruction* result = NULL; if (expr->key()->IsPropertyName()) { Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); - if (!name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("length"))) return false; + if (!String::Equals(name, isolate()->factory()->length_string())) { + return false; + } if (function_state()->outer() == NULL) { HInstruction* elements = Add<HArgumentsElements>(false); @@ -7313,7 +7359,7 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr, bool has_side_effects = false; HValue* load = HandleKeyedElementAccess( - obj, key, NULL, expr, LOAD, &has_side_effects); + obj, key, NULL, expr, ast_id, expr->LoadId(), LOAD, &has_side_effects); if (has_side_effects) { if (ast_context()->IsEffect()) { Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); @@ -7323,6 +7369,7 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr, Drop(1); } } + if (load == NULL) return; return ast_context()->ReturnValue(load); } return ast_context()->ReturnInstruction(instr, ast_id); @@ -7390,9 +7437,7 @@ HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall( HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall( HValue* fun, HValue* context, int argument_count, HValue* expected_param_count) { - CallInterfaceDescriptor* descriptor = - isolate()->call_descriptor(Isolate::ArgumentAdaptorCall); - + ArgumentAdaptorDescriptor descriptor(isolate()); HValue* arity = Add<HConstant>(argument_count - 1); HValue* op_vals[] = { context, fun, arity, expected_param_count }; @@ -7403,7 +7448,7 @@ HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall( return New<HCallWithDescriptor>( adaptor_value, argument_count, descriptor, - Vector<HValue*>(op_vals, descriptor->GetEnvironmentLength())); + Vector<HValue*>(op_vals, descriptor.GetEnvironmentLength())); } @@ -7472,12 +7517,11 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( bool handled_string = false; int ordered_functions = 0; - for (int i = 0; - i < types->length() && ordered_functions < kMaxCallPolymorphism; + int i; + for (i = 0; i < types->length() && ordered_functions < kMaxCallPolymorphism; ++i) { PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); - if (info.CanAccessMonomorphic() && - info.lookup()->IsConstant() && + if (info.CanAccessMonomorphic() && info.IsConstant() && info.constant()->IsJSFunction()) { if (info.type()->Is(Type::String())) { if (handled_string) continue; @@ -7495,6 +7539,11 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( std::sort(order, order + ordered_functions); + if (i < types->length()) { + types->Clear(); + ordered_functions = -1; + } + HBasicBlock* number_block = NULL; HBasicBlock* join = NULL; handled_string = false; @@ -7812,26 +7861,9 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, // Generate the deoptimization data for the unoptimized version of // the target function if we don't already have it. - if (!target_shared->has_deoptimization_support()) { - // Note that we compile here using the same AST that we will use for - // generating the optimized inline code. - target_info.EnableDeoptimizationSupport(); - if (!FullCodeGenerator::MakeCode(&target_info)) { - TraceInline(target, caller, "could not generate deoptimization info"); - return false; - } - if (target_shared->scope_info() == ScopeInfo::Empty(isolate())) { - // The scope info might not have been set if a lazily compiled - // function is inlined before being called for the first time. - Handle<ScopeInfo> target_scope_info = - ScopeInfo::Create(target_info.scope(), zone()); - target_shared->set_scope_info(*target_scope_info); - } - target_shared->EnableDeoptimizationSupport(*target_info.code()); - target_shared->set_feedback_vector(*target_info.feedback_vector()); - Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG, - &target_info, - target_shared); + if (!Compiler::EnsureDeoptimizationSupport(&target_info)) { + TraceInline(target, caller, "could not generate deoptimization info"); + return false; } // ---------------------------------------------------------------- @@ -7888,10 +7920,9 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, Scope* saved_scope = scope(); set_scope(target_info.scope()); HEnterInlined* enter_inlined = - Add<HEnterInlined>(return_id, target, arguments_count, function, + Add<HEnterInlined>(return_id, target, context, arguments_count, function, function_state()->inlining_kind(), - function->scope()->arguments(), - arguments_object); + function->scope()->arguments(), arguments_object); function_state()->set_entry(enter_inlined); VisitDeclarations(target_info.scope()->declarations()); @@ -7899,10 +7930,10 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, set_scope(saved_scope); if (HasStackOverflow()) { // Bail out if the inline function did, as we cannot residualize a call - // instead. + // instead, but do not disable optimization for the outer function. TraceInline(target, caller, "inline graph construction failed"); target_shared->DisableOptimization(kInliningBailedOut); - inline_bailout_ = true; + current_info()->RetryOptimization(kInliningBailedOut); delete target_state; return true; } @@ -8218,7 +8249,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( ElementsKind elements_kind = receiver_map->elements_kind(); if (!IsFastElementsKind(elements_kind)) return false; if (receiver_map->is_observed()) return false; - DCHECK(receiver_map->is_extensible()); + if (!receiver_map->is_extensible()) return false; Drop(expr->arguments()->length()); HValue* result; @@ -8283,7 +8314,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( if (!IsFastElementsKind(elements_kind)) return false; if (receiver_map->is_observed()) return false; if (JSArray::IsReadOnlyLengthDescriptor(receiver_map)) return false; - DCHECK(receiver_map->is_extensible()); + if (!receiver_map->is_extensible()) return false; // If there may be elements accessors in the prototype chain, the fast // inlined version can't be used. @@ -8335,7 +8366,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( ElementsKind kind = receiver_map->elements_kind(); if (!IsFastElementsKind(kind)) return false; if (receiver_map->is_observed()) return false; - DCHECK(receiver_map->is_extensible()); + if (!receiver_map->is_extensible()) return false; // If there may be elements accessors in the prototype chain, the fast // inlined version can't be used. @@ -8450,7 +8481,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( if (!IsFastElementsKind(kind)) return false; if (receiver_map->is_observed()) return false; if (argument_count != 2) return false; - DCHECK(receiver_map->is_extensible()); + if (!receiver_map->is_extensible()) return false; // If there may be elements accessors in the prototype chain, the fast // inlined version can't be used. @@ -8642,19 +8673,16 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function, api_function_address }; - CallInterfaceDescriptor* descriptor = - isolate()->call_descriptor(Isolate::ApiFunctionCall); - + ApiFunctionDescriptor descriptor(isolate()); CallApiFunctionStub stub(isolate(), is_store, call_data_is_undefined, argc); Handle<Code> code = stub.GetCode(); HConstant* code_value = Add<HConstant>(code); - DCHECK((sizeof(op_vals) / kPointerSize) == - descriptor->GetEnvironmentLength()); + DCHECK((sizeof(op_vals) / kPointerSize) == descriptor.GetEnvironmentLength()); HInstruction* call = New<HCallWithDescriptor>( code_value, argc + 1, descriptor, - Vector<HValue*>(op_vals, descriptor->GetEnvironmentLength())); + Vector<HValue*>(op_vals, descriptor.GetEnvironmentLength())); if (drop_extra) Drop(1); // Drop function. ast_context()->ReturnInstruction(call, ast_id); @@ -8800,6 +8828,12 @@ HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver, Push(graph()->GetConstantMinus1()); if (IsFastDoubleElementsKind(kind) || IsFastSmiElementsKind(kind)) { + // Make sure that we can actually compare numbers correctly below, see + // https://code.google.com/p/chromium/issues/detail?id=407946 for details. + search_element = AddUncasted<HForceRepresentation>( + search_element, IsFastSmiElementsKind(kind) ? Representation::Smi() + : Representation::Double()); + LoopBuilder loop(this, context(), direction); { HValue* index = loop.BeginBody(initial, terminating, token); @@ -8807,12 +8841,8 @@ HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver, elements, index, static_cast<HValue*>(NULL), kind, ALLOW_RETURN_HOLE); IfBuilder if_issame(this); - if (IsFastDoubleElementsKind(kind)) { - if_issame.If<HCompareNumericAndBranch>( - element, search_element, Token::EQ_STRICT); - } else { - if_issame.If<HCompareObjectEqAndBranch>(element, search_element); - } + if_issame.If<HCompareNumericAndBranch>(element, search_element, + Token::EQ_STRICT); if_issame.Then(); { Drop(1); @@ -9049,12 +9079,13 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { // If there is a global property cell for the name at compile time and // access check is not enabled we assume that the function will not change // and generate optimized code for calling the function. - LookupResult lookup(isolate()); - GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, LOAD); - if (type == kUseCell && - !current_info()->global_object()->IsAccessCheckNeeded()) { + Handle<GlobalObject> global(current_info()->global_object()); + LookupIterator it(global, var->name(), + LookupIterator::OWN_SKIP_INTERCEPTOR); + GlobalPropertyAccess type = LookupGlobalProperty(var, &it, LOAD); + if (type == kUseCell) { Handle<GlobalObject> global(current_info()->global_object()); - known_global_function = expr->ComputeGlobalTarget(global, &lookup); + known_global_function = expr->ComputeGlobalTarget(global, &it); } if (known_global_function) { Add<HCheckValue>(function, expr->target()); @@ -9762,7 +9793,7 @@ void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) { static_cast<int>(Runtime::kFirstInlineFunction); DCHECK(lookup_index >= 0); DCHECK(static_cast<size_t>(lookup_index) < - ARRAY_SIZE(kInlineFunctionGenerators)); + arraysize(kInlineFunctionGenerators)); InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; // Call the inline code generator using the pointer-to-member. @@ -10244,7 +10275,7 @@ HValue* HGraphBuilder::BuildBinaryOperation( right_type->Maybe(Type::String()) || right_type->Maybe(Type::Receiver())); - if (left_type->Is(Type::None())) { + if (!left_type->IsInhabited()) { Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", Deoptimizer::SOFT); // TODO(rossberg): we should be able to get rid of non-continuous @@ -10255,7 +10286,7 @@ HValue* HGraphBuilder::BuildBinaryOperation( left_rep = Representation::FromType(left_type); } - if (right_type->Is(Type::None())) { + if (!right_type->IsInhabited()) { Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", Deoptimizer::SOFT); right_type = Type::Any(zone()); @@ -10451,7 +10482,7 @@ static bool IsClassOfTest(CompareOperation* expr) { Literal* literal = expr->right()->AsLiteral(); if (literal == NULL) return false; if (!literal->value()->IsString()) return false; - if (!call->name()->IsOneByteEqualTo(STATIC_ASCII_VECTOR("_ClassOf"))) { + if (!call->name()->IsOneByteEqualTo(STATIC_CHAR_VECTOR("_ClassOf"))) { return false; } DCHECK(call->arguments()->length() == 1); @@ -10688,15 +10719,13 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { Handle<JSFunction> target = Handle<JSFunction>::null(); VariableProxy* proxy = expr->right()->AsVariableProxy(); bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated(); - if (global_function && - current_info()->has_global_object() && - !current_info()->global_object()->IsAccessCheckNeeded()) { + if (global_function && current_info()->has_global_object()) { Handle<String> name = proxy->name(); Handle<GlobalObject> global(current_info()->global_object()); - LookupResult lookup(isolate()); - global->Lookup(name, &lookup); - if (lookup.IsNormal() && lookup.GetValue()->IsJSFunction()) { - Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); + LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR); + Handle<Object> value = JSObject::GetDataProperty(&it); + if (it.IsFound() && value->IsJSFunction()) { + Handle<JSFunction> candidate = Handle<JSFunction>::cast(value); // If the function is in new space we assume it's more likely to // change and thus prefer the general IC code. if (!isolate()->heap()->InNewSpace(*candidate)) { @@ -10754,7 +10783,7 @@ HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction( BailoutId bailout_id) { // Cases handled below depend on collected type feedback. They should // soft deoptimize when there is no type feedback. - if (combined_type->Is(Type::None())) { + if (!combined_type->IsInhabited()) { Add<HDeoptimize>("Insufficient type feedback for combined type " "of binary operation", Deoptimizer::SOFT); @@ -10970,7 +10999,8 @@ HInstruction* HOptimizedGraphBuilder::BuildFastLiteral( } // Copy in-object properties. - if (boilerplate_object->map()->NumberOfFields() != 0) { + if (boilerplate_object->map()->NumberOfFields() != 0 || + boilerplate_object->map()->unused_property_fields() > 0) { BuildEmitInObjectProperties(boilerplate_object, object, site_context, pretenure_flag); } @@ -11183,6 +11213,14 @@ void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) { } +void HOptimizedGraphBuilder::VisitSuperReference(SuperReference* expr) { + DCHECK(!HasStackOverflow()); + DCHECK(current_block() != NULL); + DCHECK(current_block()->HasPredecessor()); + return Bailout(kSuperReference); +} + + void HOptimizedGraphBuilder::VisitDeclarations( ZoneList<Declaration*>* declarations) { DCHECK(globals_.is_empty()); @@ -11527,10 +11565,9 @@ void HOptimizedGraphBuilder::GenerateDateField(CallRuntime* call) { void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar( CallRuntime* call) { DCHECK(call->arguments()->length() == 3); - // We need to follow the evaluation order of full codegen. + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); - CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); HValue* string = Pop(); HValue* value = Pop(); HValue* index = Pop(); @@ -11544,10 +11581,9 @@ void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar( void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar( CallRuntime* call) { DCHECK(call->arguments()->length() == 3); - // We need to follow the evaluation order of full codegen. + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); - CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); HValue* string = Pop(); HValue* value = Pop(); HValue* index = Pop(); @@ -11830,8 +11866,8 @@ void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { } -void HOptimizedGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { - return Bailout(kInlinedRuntimeFunctionFastAsciiArrayJoin); +void HOptimizedGraphBuilder::GenerateFastOneByteArrayJoin(CallRuntime* call) { + return Bailout(kInlinedRuntimeFunctionFastOneByteArrayJoin); } |