diff options
Diffstat (limited to 'deps/v8/src/hydrogen.cc')
-rw-r--r-- | deps/v8/src/hydrogen.cc | 393 |
1 files changed, 274 insertions, 119 deletions
diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 301e7e40fa..6184bb9e46 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -4,14 +4,13 @@ #include "src/hydrogen.h" -#include <algorithm> +#include <sstream> #include "src/v8.h" #include "src/allocation-site-scopes.h" -#include "src/codegen.h" +#include "src/ast-numbering.h" #include "src/full-codegen.h" -#include "src/hashmap.h" #include "src/hydrogen-bce.h" #include "src/hydrogen-bch.h" #include "src/hydrogen-canonicalize.h" @@ -42,7 +41,6 @@ #include "src/parser.h" #include "src/runtime/runtime.h" #include "src/scopeinfo.h" -#include "src/scopes.h" #include "src/typing.h" #if V8_TARGET_ARCH_IA32 @@ -147,7 +145,7 @@ void HBasicBlock::AddInstruction(HInstruction* instr, entry->set_position(position); } else { DCHECK(!FLAG_hydrogen_track_positions || - !graph()->info()->IsOptimizing()); + !graph()->info()->IsOptimizing() || instr->IsAbnormalExit()); } first_ = last_ = entry; } @@ -2626,16 +2624,15 @@ void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements, } -HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader( - ElementsKind kind, - HValue* capacity) { +HValue* HGraphBuilder::BuildAllocateAndInitializeArray(ElementsKind kind, + HValue* capacity) { // The HForceRepresentation is to prevent possible deopt on int-smi // conversion after allocation but before the new object fields are set. capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi()); HValue* size_in_bytes = BuildCalculateElementsSize(kind, capacity); - HValue* new_elements = BuildAllocateElements(kind, size_in_bytes); - BuildInitializeElementsHeader(new_elements, kind, capacity); - return new_elements; + HValue* new_array = BuildAllocateElements(kind, size_in_bytes); + BuildInitializeElementsHeader(new_array, kind, capacity); + return new_array; } @@ -2690,9 +2687,8 @@ HInstruction* HGraphBuilder::AddElementAccess( DCHECK(val == NULL); HLoadKeyed* load = Add<HLoadKeyed>( elements, checked_key, dependency, elements_kind, load_mode); - if (FLAG_opt_safe_uint32_operations && - (elements_kind == EXTERNAL_UINT32_ELEMENTS || - elements_kind == UINT32_ELEMENTS)) { + if (elements_kind == EXTERNAL_UINT32_ELEMENTS || + elements_kind == UINT32_ELEMENTS) { graph()->RecordUint32Instruction(load); } return load; @@ -2754,8 +2750,8 @@ HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object, (Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) >> ElementsKindToShiftSize(new_kind))); - HValue* new_elements = BuildAllocateElementsAndInitializeElementsHeader( - new_kind, new_capacity); + HValue* new_elements = + BuildAllocateAndInitializeArray(new_kind, new_capacity); BuildCopyElements(elements, kind, new_elements, new_kind, length, new_capacity); @@ -2789,12 +2785,6 @@ void HGraphBuilder::BuildFillElementsWithValue(HValue* elements, } } - // Since we're about to store a hole value, the store instruction below must - // assume an elements kind that supports heap object values. - if (IsFastSmiOrObjectElementsKind(elements_kind)) { - elements_kind = FAST_HOLEY_ELEMENTS; - } - if (initial_capacity >= 0) { for (int i = 0; i < initial_capacity; i++) { HInstruction* key = Add<HConstant>(i); @@ -2832,10 +2822,40 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements, ? Add<HConstant>(factory->the_hole_value()) : Add<HConstant>(nan_double); + // Since we're about to store a hole value, the store instruction below must + // assume an elements kind that supports heap object values. + if (IsFastSmiOrObjectElementsKind(elements_kind)) { + elements_kind = FAST_HOLEY_ELEMENTS; + } + BuildFillElementsWithValue(elements, elements_kind, from, to, hole); } +void HGraphBuilder::BuildCopyProperties(HValue* from_properties, + HValue* to_properties, HValue* length, + HValue* capacity) { + ElementsKind kind = FAST_ELEMENTS; + + BuildFillElementsWithValue(to_properties, kind, length, capacity, + graph()->GetConstantUndefined()); + + LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement); + + HValue* key = builder.BeginBody(length, graph()->GetConstant0(), Token::GT); + + key = AddUncasted<HSub>(key, graph()->GetConstant1()); + key->ClearFlag(HValue::kCanOverflow); + + HValue* element = + Add<HLoadKeyed>(from_properties, key, static_cast<HValue*>(NULL), kind); + + Add<HStoreKeyed>(to_properties, key, element, kind); + + builder.EndBody(); +} + + void HGraphBuilder::BuildCopyElements(HValue* from_elements, ElementsKind from_elements_kind, HValue* to_elements, @@ -2879,10 +2899,6 @@ void HGraphBuilder::BuildCopyElements(HValue* from_elements, length, NULL); } - if (capacity == NULL) { - capacity = AddLoadFixedArrayLength(to_elements); - } - LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement); HValue* key = builder.BeginBody(length, graph()->GetConstant0(), @@ -3408,7 +3424,7 @@ void HBasicBlock::FinishExit(HControlInstruction* instruction, } -OStream& operator<<(OStream& os, const HBasicBlock& b) { +std::ostream& operator<<(std::ostream& os, const HBasicBlock& b) { return os << "B" << b.block_id(); } @@ -3431,8 +3447,9 @@ HGraph::HGraph(CompilationInfo* info) maximum_environment_size_(0), no_side_effects_scope_count_(0), disallow_adding_new_values_(false), - next_inline_id_(0), - inlined_functions_(5, info->zone()) { + inlined_functions_(FLAG_hydrogen_track_positions ? 5 : 0, info->zone()), + inlining_id_to_function_id_(FLAG_hydrogen_track_positions ? 5 : 0, + info->zone()) { if (info->IsStub()) { CallInterfaceDescriptor descriptor = info->code_stub()->GetCallInterfaceDescriptor(); @@ -3492,9 +3509,7 @@ int HGraph::TraceInlinedFunction( os << "--- FUNCTION SOURCE (" << shared->DebugName()->ToCString().get() << ") id{" << info()->optimization_id() << "," << id << "} ---\n"; { - ConsStringIteratorOp op; StringCharacterStream stream(String::cast(script->source()), - &op, shared->start_position()); // fun->end_position() points to the last character in the stream. We // need to compensate by adding one to calculate the length. @@ -3512,14 +3527,15 @@ int HGraph::TraceInlinedFunction( } } - int inline_id = next_inline_id_++; + int inline_id = inlining_id_to_function_id_.length(); + inlining_id_to_function_id_.Add(id, zone()); if (inline_id != 0) { CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); OFStream os(tracing_scope.file()); os << "INLINE (" << shared->DebugName()->ToCString().get() << ") id{" << info()->optimization_id() << "," << id << "} AS " << inline_id - << " AT " << position << endl; + << " AT " << position << std::endl; } return inline_id; @@ -3531,8 +3547,8 @@ int HGraph::SourcePositionToScriptPosition(HSourcePosition pos) { return pos.raw(); } - return inlined_functions_[pos.inlining_id()].start_position() + - pos.position(); + const int id = inlining_id_to_function_id_[pos.inlining_id()]; + return inlined_functions_[id].start_position() + pos.position(); } @@ -4384,7 +4400,7 @@ bool HGraph::Optimize(BailoutReason* bailout_reason) { // Must be performed before canonicalization to ensure that Canonicalize // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with // zero. - if (FLAG_opt_safe_uint32_operations) Run<HUint32AnalysisPhase>(); + Run<HUint32AnalysisPhase>(); if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>(); @@ -5603,6 +5619,8 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { DCHECK(!CompileTimeValue::IsCompileTimeValue(value)); // Fall through. case ObjectLiteral::Property::COMPUTED: + // It is safe to use [[Put]] here because the boilerplate already + // contains computed properties with an uninitialized value. if (key->value()->IsInternalizedString()) { if (property->emit_store()) { CHECK_ALIVE(VisitForValue(value)); @@ -6096,7 +6114,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() { if (IsAccessor()) return true; Handle<Map> map = this->map(); - map->LookupTransition(NULL, *name_, &lookup_); + map->LookupTransition(NULL, *name_, NONE, &lookup_); if (lookup_.IsTransitionToField() && map->unused_property_fields() > 0) { // Construct the object field access. int descriptor = transition()->LastAdded(); @@ -6289,7 +6307,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( HControlInstruction* smi_check = NULL; handled_string = false; - for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++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; @@ -6367,7 +6385,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( // know about and do not want to handle ones we've never seen. Otherwise // use a generic IC. if (count == types->length() && FLAG_deoptimize_uncommon_cases) { - FinishExitWithHardDeoptimization("Uknown map in polymorphic access"); + FinishExitWithHardDeoptimization("Unknown map in polymorphic access"); } else { HInstruction* instr = BuildNamedGeneric(access_type, expr, object, name, value); @@ -6426,16 +6444,19 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr, bool is_uninitialized) { if (!prop->key()->IsPropertyName()) { // Keyed store. - HValue* value = environment()->ExpressionStackAt(0); - HValue* key = environment()->ExpressionStackAt(1); - HValue* object = environment()->ExpressionStackAt(2); + HValue* value = Pop(); + HValue* key = Pop(); + HValue* object = Pop(); bool has_side_effects = false; - HandleKeyedElementAccess(object, key, value, expr, ast_id, return_id, STORE, - &has_side_effects); - Drop(3); - Push(value); - Add<HSimulate>(return_id, REMOVABLE_SIMULATE); - return ast_context()->ReturnValue(Pop()); + HValue* result = HandleKeyedElementAccess( + object, key, value, expr, ast_id, return_id, STORE, &has_side_effects); + if (has_side_effects) { + if (!ast_context()->IsEffect()) Push(value); + Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); + if (!ast_context()->IsEffect()) Drop(1); + } + if (result == NULL) return; + return ast_context()->ReturnValue(value); } // Named store. @@ -6920,6 +6941,12 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( } +static bool CanInlineElementAccess(Handle<Map> map) { + return map->IsJSObjectMap() && !map->has_slow_elements_kind() && + !map->has_indexed_interceptor(); +} + + HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( HValue* object, HValue* key, @@ -6937,7 +6964,7 @@ HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( Handle<Map> most_general_consolidated_map; for (int i = 0; i < maps->length(); ++i) { Handle<Map> map = maps->at(i); - if (!map->IsJSObjectMap()) return NULL; + if (!CanInlineElementAccess(map)) return NULL; // Don't allow mixing of JSArrays with JSObjects. if (map->instance_type() == JS_ARRAY_TYPE) { if (has_non_js_array_access) return NULL; @@ -7013,8 +7040,9 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( MapHandleList possible_transitioned_maps(maps->length()); for (int i = 0; i < maps->length(); ++i) { Handle<Map> map = maps->at(i); + DCHECK(!map->IsStringMap()); ElementsKind elements_kind = map->elements_kind(); - if (IsFastElementsKind(elements_kind) && + if (CanInlineElementAccess(map) && IsFastElementsKind(elements_kind) && elements_kind != GetInitialFastElementsKind()) { possible_transitioned_maps.Add(map); } @@ -7055,8 +7083,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( if (untransitionable_maps.length() == 1) { Handle<Map> untransitionable_map = untransitionable_maps[0]; HInstruction* instr = NULL; - if (untransitionable_map->has_slow_elements_kind() || - !untransitionable_map->IsJSObjectMap()) { + if (!CanInlineElementAccess(untransitionable_map)) { instr = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key, val)); } else { @@ -7065,14 +7092,13 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( store_mode); } *has_side_effects |= instr->HasObservableSideEffects(); - return access_type == STORE ? NULL : instr; + return access_type == STORE ? val : instr; } HBasicBlock* join = graph()->CreateBasicBlock(); for (int i = 0; i < untransitionable_maps.length(); ++i) { Handle<Map> map = untransitionable_maps[i]; - if (!map->IsJSObjectMap()) continue; ElementsKind elements_kind = map->elements_kind(); HBasicBlock* this_map = graph()->CreateBasicBlock(); HBasicBlock* other_map = graph()->CreateBasicBlock(); @@ -7082,7 +7108,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( set_current_block(this_map); HInstruction* access = NULL; - if (IsDictionaryElementsKind(elements_kind)) { + if (!CanInlineElementAccess(map)) { access = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key, val)); } else { @@ -7118,7 +7144,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( NoObservableSideEffectsScope scope(this); FinishExitWithHardDeoptimization("Unknown map in polymorphic element access"); set_current_block(join); - return access_type == STORE ? NULL : Pop(); + return access_type == STORE ? val : Pop(); } @@ -7156,8 +7182,14 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( bool monomorphic = ComputeReceiverTypes(expr, obj, &types, zone()); bool force_generic = false; - if (access_type == STORE && - (monomorphic || (types != NULL && !types->is_empty()))) { + if (access_type == STORE && expr->GetKeyType() == PROPERTY) { + // Non-Generic accesses assume that elements are being accessed, and will + // deopt for non-index keys, which the IC knows will occur. + // TODO(jkummerow): Consider adding proper support for property accesses. + force_generic = true; + monomorphic = false; + } else if (access_type == STORE && + (monomorphic || (types != NULL && !types->is_empty()))) { // Stores can't be mono/polymorphic if their prototype chain has dictionary // elements. However a receiver map that has dictionary elements itself // should be left to normal mono/poly behavior (the other maps may benefit @@ -7170,11 +7202,24 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( break; } } + } else if (access_type == LOAD && !monomorphic && + (types != NULL && !types->is_empty())) { + // Polymorphic loads have to go generic if any of the maps are strings. + // If some, but not all of the maps are strings, we should go generic + // because polymorphic access wants to key on ElementsKind and isn't + // compatible with strings. + for (int i = 0; i < types->length(); i++) { + Handle<Map> current_map = types->at(i); + if (current_map->IsStringMap()) { + force_generic = true; + break; + } + } } if (monomorphic) { Handle<Map> map = types->first(); - if (map->has_slow_elements_kind() || !map->IsJSObjectMap()) { + if (!CanInlineElementAccess(map)) { instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key, val)); } else { @@ -7804,7 +7849,7 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, // step, but don't transfer ownership to target_info. target_info.SetAstValueFactory(top_info()->ast_value_factory(), false); Handle<SharedFunctionInfo> target_shared(target->shared()); - if (!Parser::Parse(&target_info) || !Scope::Analyze(&target_info)) { + if (!Compiler::ParseAndAnalyze(&target_info)) { if (target_info.isolate()->has_pending_exception()) { // Parse or scope error, never optimize this function. SetStackOverflow(); @@ -8082,9 +8127,9 @@ bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, } -bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, - Call* expr, - int arguments_count) { +bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function, + Call* expr, + int arguments_count) { return TryInline(function, arguments_count, NULL, @@ -8136,13 +8181,22 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( - Call* expr, - HValue* receiver, - Handle<Map> receiver_map) { + Call* expr, Handle<JSFunction> function, Handle<Map> receiver_map, + int args_count_no_receiver) { + if (!function->shared()->HasBuiltinFunctionId()) return false; + BuiltinFunctionId id = function->shared()->builtin_function_id(); + int argument_count = args_count_no_receiver + 1; // Plus receiver. + + if (receiver_map.is_null()) { + HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver); + if (receiver->IsConstant() && + HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) { + receiver_map = + handle(Handle<HeapObject>::cast( + HConstant::cast(receiver)->handle(isolate()))->map()); + } + } // Try to inline calls like Math.* as operations in the calling function. - if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; - BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); - int argument_count = expr->arguments()->length() + 1; // Plus receiver. switch (id) { case kStringCharCodeAt: case kStringCharAt: @@ -8251,7 +8305,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( if (receiver_map->is_observed()) return false; if (!receiver_map->is_extensible()) return false; - Drop(expr->arguments()->length()); + Drop(args_count_no_receiver); HValue* result; HValue* reduced_length; HValue* receiver = Pop(); @@ -8327,7 +8381,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); BuildCheckPrototypeMaps(prototype, Handle<JSObject>()); - const int argc = expr->arguments()->length(); + const int argc = args_count_no_receiver; if (argc != 1) return false; HValue* value_to_push = Pop(); @@ -8384,7 +8438,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( // Threshold for fast inlined Array.shift(). HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16)); - Drop(expr->arguments()->length()); + Drop(args_count_no_receiver); HValue* receiver = Pop(); HValue* function = Pop(); HValue* result; @@ -8690,7 +8744,47 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function, } -bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { +void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function, + int arguments_count) { + Handle<JSFunction> known_function; + int args_count_no_receiver = arguments_count - 1; + if (function->IsConstant() && + HConstant::cast(function)->handle(isolate())->IsJSFunction()) { + HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver); + Handle<Map> receiver_map; + if (receiver->IsConstant() && + HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) { + receiver_map = + handle(Handle<HeapObject>::cast( + HConstant::cast(receiver)->handle(isolate()))->map()); + } + + known_function = + Handle<JSFunction>::cast(HConstant::cast(function)->handle(isolate())); + if (TryInlineBuiltinMethodCall(expr, known_function, receiver_map, + args_count_no_receiver)) { + if (FLAG_trace_inlining) { + PrintF("Inlining builtin "); + known_function->ShortPrint(); + PrintF("\n"); + } + return; + } + + if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) { + return; + } + } + + PushArgumentsFromEnvironment(arguments_count); + HInvokeFunction* call = + New<HInvokeFunction>(function, known_function, arguments_count); + Drop(1); // Function + ast_context()->ReturnInstruction(call, expr->id()); +} + + +bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) { DCHECK(expr->expression()->IsProperty()); if (!expr->IsMonomorphic()) { @@ -8698,27 +8792,45 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { } Handle<Map> function_map = expr->GetReceiverTypes()->first(); if (function_map->instance_type() != JS_FUNCTION_TYPE || - !expr->target()->shared()->HasBuiltinFunctionId() || - expr->target()->shared()->builtin_function_id() != kFunctionApply) { + !expr->target()->shared()->HasBuiltinFunctionId()) { return false; } - if (current_info()->scope()->arguments() == NULL) return false; + switch (expr->target()->shared()->builtin_function_id()) { + case kFunctionCall: { + if (expr->arguments()->length() == 0) return false; + BuildFunctionCall(expr); + return true; + } + case kFunctionApply: { + // For .apply, only the pattern f.apply(receiver, arguments) + // is supported. + if (current_info()->scope()->arguments() == NULL) return false; - ZoneList<Expression*>* args = expr->arguments(); - if (args->length() != 2) return false; + ZoneList<Expression*>* args = expr->arguments(); + if (args->length() != 2) return false; + + VariableProxy* arg_two = args->at(1)->AsVariableProxy(); + if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; + HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); + if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; + BuildFunctionApply(expr); + return true; + } + default: { return false; } + } + UNREACHABLE(); +} - VariableProxy* arg_two = args->at(1)->AsVariableProxy(); - if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; - HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); - if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; - // Found pattern f.apply(receiver, arguments). - CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); +void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) { + ZoneList<Expression*>* args = expr->arguments(); + CHECK_ALIVE(VisitForValue(args->at(0))); HValue* receiver = Pop(); // receiver HValue* function = Pop(); // f Drop(1); // apply + Handle<Map> function_map = expr->GetReceiverTypes()->first(); HValue* checked_function = AddCheckMap(function, function_map); if (function_state()->outer() == NULL) { @@ -8730,7 +8842,6 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { length, elements); ast_context()->ReturnInstruction(result, expr->id()); - return true; } else { // We are inside inlined function and we know exactly what is inside // arguments object. But we need to be able to materialize at deopt. @@ -8744,23 +8855,33 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { for (int i = 1; i < arguments_count; i++) { Push(arguments_values->at(i)); } + HandleIndirectCall(expr, function, arguments_count); + } +} - Handle<JSFunction> known_function; - if (function->IsConstant() && - HConstant::cast(function)->handle(isolate())->IsJSFunction()) { - known_function = Handle<JSFunction>::cast( - HConstant::cast(function)->handle(isolate())); - int args_count = arguments_count - 1; // Excluding receiver. - if (TryInlineApply(known_function, expr, args_count)) return true; - } - PushArgumentsFromEnvironment(arguments_count); - HInvokeFunction* call = New<HInvokeFunction>( - function, known_function, arguments_count); - Drop(1); // Function. - ast_context()->ReturnInstruction(call, expr->id()); - return true; - } +// f.call(...) +void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) { + HValue* function = Top(); // f + Handle<Map> function_map = expr->GetReceiverTypes()->first(); + HValue* checked_function = AddCheckMap(function, function_map); + + // f and call are on the stack in the unoptimized code + // during evaluation of the arguments. + CHECK_ALIVE(VisitExpressions(expr->arguments())); + + int args_length = expr->arguments()->length(); + int receiver_index = args_length - 1; + // Patch the receiver. + HValue* receiver = BuildWrapReceiver( + environment()->ExpressionStackAt(receiver_index), checked_function); + environment()->SetExpressionStackAt(receiver_index, receiver); + + // Call must not be on the stack from now on. + int call_index = args_length + 1; + environment()->RemoveExpressionStackAt(call_index); + + HandleIndirectCall(expr, function, args_length); } @@ -9026,11 +9147,12 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { HConstant::cast(function)->handle(isolate())); expr->set_target(known_function); - if (TryCallApply(expr)) return; + if (TryIndirectCall(expr)) return; CHECK_ALIVE(VisitExpressions(expr->arguments())); Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); - if (TryInlineBuiltinMethodCall(expr, receiver, map)) { + if (TryInlineBuiltinMethodCall(expr, known_function, map, + expr->arguments()->length())) { if (FLAG_trace_inlining) { PrintF("Inlining builtin "); known_function->ShortPrint(); @@ -9084,7 +9206,6 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { 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, &it); } if (known_global_function) { @@ -10438,8 +10559,7 @@ HValue* HGraphBuilder::BuildBinaryOperation( break; case Token::SHR: instr = AddUncasted<HShr>(left, right); - if (FLAG_opt_safe_uint32_operations && instr->IsShr() && - CanBeZero(right)) { + if (instr->IsShr() && CanBeZero(right)) { graph()->RecordUint32Instruction(instr); } break; @@ -11437,6 +11557,29 @@ void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) { } +void HOptimizedGraphBuilder::GenerateIsJSProxy(CallRuntime* call) { + DCHECK(call->arguments()->length() == 1); + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); + HValue* value = Pop(); + HIfContinuation continuation; + IfBuilder if_proxy(this); + + HValue* smicheck = if_proxy.IfNot<HIsSmiAndBranch>(value); + if_proxy.And(); + HValue* map = Add<HLoadNamedField>(value, smicheck, HObjectAccess::ForMap()); + HValue* instance_type = Add<HLoadNamedField>( + map, static_cast<HValue*>(NULL), HObjectAccess::ForMapInstanceType()); + if_proxy.If<HCompareNumericAndBranch>( + instance_type, Add<HConstant>(FIRST_JS_PROXY_TYPE), Token::GTE); + if_proxy.And(); + if_proxy.If<HCompareNumericAndBranch>( + instance_type, Add<HConstant>(LAST_JS_PROXY_TYPE), Token::LTE); + + if_proxy.CaptureContinuation(&continuation); + return ast_context()->ReturnContinuation(&continuation, call->id()); +} + + void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi); } @@ -12068,6 +12211,18 @@ void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) { } +HValue* HEnvironment::RemoveExpressionStackAt(int index_from_top) { + int count = index_from_top + 1; + int index = values_.length() - count; + DCHECK(HasExpressionAt(index)); + // Simulate popping 'count' elements and then + // pushing 'count - 1' elements back. + pop_count_ += Max(count - push_count_, 0); + push_count_ = Max(push_count_ - count, 0) + (count - 1); + return values_.Remove(index); +} + + void HEnvironment::Drop(int count) { for (int i = 0; i < count; ++i) { Pop(); @@ -12167,7 +12322,7 @@ HEnvironment* HEnvironment::CopyForInlining( } -OStream& operator<<(OStream& os, const HEnvironment& env) { +std::ostream& operator<<(std::ostream& os, const HEnvironment& env) { for (int i = 0; i < env.length(); i++) { if (i == 0) os << "parameters\n"; if (i == env.parameter_count()) os << "specials\n"; @@ -12299,9 +12454,9 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) { for (int j = 0; j < total; ++j) { HPhi* phi = current->phis()->at(j); PrintIndent(); - OStringStream os; + std::ostringstream os; os << phi->merged_index() << " " << NameOf(phi) << " " << *phi << "\n"; - trace_.Add(os.c_str()); + trace_.Add(os.str().c_str()); } } @@ -12311,7 +12466,7 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) { HInstruction* instruction = it.Current(); int uses = instruction->UseCount(); PrintIndent(); - OStringStream os; + std::ostringstream os; os << "0 " << uses << " " << NameOf(instruction) << " " << *instruction; if (FLAG_hydrogen_track_positions && instruction->has_position() && @@ -12322,7 +12477,7 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) { os << pos.position(); } os << " <|@\n"; - trace_.Add(os.c_str()); + trace_.Add(os.str().c_str()); } } @@ -12340,9 +12495,9 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) { trace_.Add("%d ", LifetimePosition::FromInstructionIndex(i).Value()); linstr->PrintTo(&trace_); - OStringStream os; + std::ostringstream os; os << " [hir:" << NameOf(linstr->hydrogen_value()) << "] <|@\n"; - trace_.Add(os.c_str()); + trace_.Add(os.str().c_str()); } } } @@ -12442,15 +12597,14 @@ void HStatistics::Initialize(CompilationInfo* info) { } -void HStatistics::Print(const char* stats_name) { +void HStatistics::Print() { PrintF( "\n" "----------------------------------------" "----------------------------------------\n" - "--- %s timing results:\n" + "--- Hydrogen timing results:\n" "----------------------------------------" - "----------------------------------------\n", - stats_name); + "----------------------------------------\n"); base::TimeDelta sum; for (int i = 0; i < times_.length(); ++i) { sum += times_[i]; @@ -12489,9 +12643,10 @@ void HStatistics::Print(const char* stats_name) { double normalized_time = source_size_in_kb > 0 ? total.InMillisecondsF() / source_size_in_kb : 0; - double normalized_size_in_kb = source_size_in_kb > 0 - ? total_size_ / 1024 / source_size_in_kb - : 0; + double normalized_size_in_kb = + source_size_in_kb > 0 + ? static_cast<double>(total_size_) / 1024 / source_size_in_kb + : 0; PrintF("%33s %8.3f ms %7.3f kB allocated\n", "Average per kB source", normalized_time, normalized_size_in_kb); } |