| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index a179e808a3f63a11b6ab784e02b6bce06e597670..ab61ef761218b4908ad321a352583ddd82a2e310 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -5662,39 +5662,6 @@ void HGraphBuilder::AddCheckConstantFunction(Call* expr,
|
| }
|
|
|
|
|
| -class FunctionSorter {
|
| - public:
|
| - FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { }
|
| - FunctionSorter(int index, int ticks, int ast_length, int src_length)
|
| - : index_(index),
|
| - ticks_(ticks),
|
| - ast_length_(ast_length),
|
| - src_length_(src_length) { }
|
| -
|
| - int index() const { return index_; }
|
| - int ticks() const { return ticks_; }
|
| - int ast_length() const { return ast_length_; }
|
| - int src_length() const { return src_length_; }
|
| -
|
| - private:
|
| - int index_;
|
| - int ticks_;
|
| - int ast_length_;
|
| - int src_length_;
|
| -};
|
| -
|
| -
|
| -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();
|
| -}
|
| -
|
| -
|
| void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
|
| HValue* receiver,
|
| SmallMapList* types,
|
| @@ -5703,73 +5670,51 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
|
| // maps are identical. In that case we can avoid repeatedly generating the
|
| // same prototype map checks.
|
| int argument_count = expr->arguments()->length() + 1; // Includes receiver.
|
| + int count = 0;
|
| HBasicBlock* join = NULL;
|
| - FunctionSorter order[kMaxCallPolymorphism];
|
| - int ordered_functions = 0;
|
| - for (int i = 0;
|
| - i < types->length() && ordered_functions < kMaxCallPolymorphism;
|
| - ++i) {
|
| + for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) {
|
| Handle<Map> map = types->at(i);
|
| if (expr->ComputeTarget(map, name)) {
|
| - order[ordered_functions++] =
|
| - FunctionSorter(i,
|
| - expr->target()->shared()->code()->profiler_ticks(),
|
| - InliningAstSize(expr->target()),
|
| - expr->target()->shared()->SourceSize());
|
| - }
|
| - }
|
| -
|
| - qsort(reinterpret_cast<void*>(&order[0]),
|
| - ordered_functions,
|
| - sizeof(order[0]),
|
| - &CompareHotness);
|
| + if (count == 0) {
|
| + // Only needed once.
|
| + AddInstruction(new(zone()) HCheckNonSmi(receiver));
|
| + join = graph()->CreateBasicBlock();
|
| + }
|
| + ++count;
|
| + HBasicBlock* if_true = graph()->CreateBasicBlock();
|
| + HBasicBlock* if_false = graph()->CreateBasicBlock();
|
| + HCompareMap* compare =
|
| + new(zone()) HCompareMap(receiver, map, if_true, if_false);
|
| + current_block()->Finish(compare);
|
|
|
| - for (int fn = 0; fn < ordered_functions; ++fn) {
|
| - int i = order[fn].index();
|
| - Handle<Map> map = types->at(i);
|
| - if (fn == 0) {
|
| - // Only needed once.
|
| - AddInstruction(new(zone()) HCheckNonSmi(receiver));
|
| - join = graph()->CreateBasicBlock();
|
| - }
|
| - HBasicBlock* if_true = graph()->CreateBasicBlock();
|
| - HBasicBlock* if_false = graph()->CreateBasicBlock();
|
| - HCompareMap* compare =
|
| - new(zone()) HCompareMap(receiver, map, if_true, if_false);
|
| - current_block()->Finish(compare);
|
| + set_current_block(if_true);
|
| + AddCheckConstantFunction(expr, receiver, map, false);
|
| + if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
|
| + PrintF("Trying to inline the polymorphic call to %s\n",
|
| + *name->ToCString());
|
| + }
|
| + if (FLAG_polymorphic_inlining && TryInlineCall(expr)) {
|
| + // Trying to inline will signal that we should bailout from the
|
| + // entire compilation by setting stack overflow on the visitor.
|
| + if (HasStackOverflow()) return;
|
| + } else {
|
| + HCallConstantFunction* call =
|
| + new(zone()) HCallConstantFunction(expr->target(), argument_count);
|
| + call->set_position(expr->position());
|
| + PreProcessCall(call);
|
| + AddInstruction(call);
|
| + if (!ast_context()->IsEffect()) Push(call);
|
| + }
|
|
|
| - set_current_block(if_true);
|
| - expr->ComputeTarget(map, name);
|
| - AddCheckConstantFunction(expr, receiver, map, false);
|
| - if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
|
| - Handle<JSFunction> caller = info()->closure();
|
| - SmartArrayPointer<char> caller_name =
|
| - caller->shared()->DebugName()->ToCString();
|
| - PrintF("Trying to inline the polymorphic call to %s from %s\n",
|
| - *name->ToCString(),
|
| - *caller_name);
|
| - }
|
| - if (FLAG_polymorphic_inlining && TryInlineCall(expr)) {
|
| - // Trying to inline will signal that we should bailout from the
|
| - // entire compilation by setting stack overflow on the visitor.
|
| - if (HasStackOverflow()) return;
|
| - } else {
|
| - HCallConstantFunction* call =
|
| - new(zone()) HCallConstantFunction(expr->target(), argument_count);
|
| - call->set_position(expr->position());
|
| - PreProcessCall(call);
|
| - AddInstruction(call);
|
| - if (!ast_context()->IsEffect()) Push(call);
|
| + if (current_block() != NULL) current_block()->Goto(join);
|
| + set_current_block(if_false);
|
| }
|
| -
|
| - if (current_block() != NULL) current_block()->Goto(join);
|
| - set_current_block(if_false);
|
| }
|
|
|
| // Finish up. Unconditionally deoptimize if we've handled all the maps we
|
| // know about and do not want to handle ones we've never seen. Otherwise
|
| // use a generic IC.
|
| - if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) {
|
| + if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
|
| current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
|
| } else {
|
| HValue* context = environment()->LookupContext();
|
| @@ -5818,11 +5763,14 @@ void HGraphBuilder::TraceInline(Handle<JSFunction> target,
|
| }
|
|
|
|
|
| -static const int kNotInlinable = 1000000000;
|
| -
|
| -
|
| -int HGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
|
| - if (!FLAG_use_inlining) return kNotInlinable;
|
| +bool HGraphBuilder::TryInline(CallKind call_kind,
|
| + Handle<JSFunction> target,
|
| + ZoneList<Expression*>* arguments,
|
| + HValue* receiver,
|
| + int ast_id,
|
| + int return_id,
|
| + ReturnHandlingFlag return_handling) {
|
| + if (!FLAG_use_inlining) return false;
|
|
|
| // Precondition: call is monomorphic and we have found a target with the
|
| // appropriate arity.
|
| @@ -5834,43 +5782,25 @@ int HGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
|
| if (target_shared->SourceSize() >
|
| Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) {
|
| TraceInline(target, caller, "target text too big");
|
| - return kNotInlinable;
|
| + return false;
|
| }
|
|
|
| // Target must be inlineable.
|
| if (!target->IsInlineable()) {
|
| TraceInline(target, caller, "target not inlineable");
|
| - return kNotInlinable;
|
| + return false;
|
| }
|
| if (target_shared->dont_inline() || target_shared->dont_optimize()) {
|
| TraceInline(target, caller, "target contains unsupported syntax [early]");
|
| - return kNotInlinable;
|
| + return false;
|
| }
|
|
|
| int nodes_added = target_shared->ast_node_count();
|
| - return nodes_added;
|
| -}
|
| -
|
| -
|
| -bool HGraphBuilder::TryInline(CallKind call_kind,
|
| - Handle<JSFunction> target,
|
| - ZoneList<Expression*>* arguments,
|
| - HValue* receiver,
|
| - int ast_id,
|
| - int return_id,
|
| - ReturnHandlingFlag return_handling) {
|
| - int nodes_added = InliningAstSize(target);
|
| - if (nodes_added == kNotInlinable) return false;
|
| -
|
| - Handle<JSFunction> caller = info()->closure();
|
| -
|
| if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
|
| TraceInline(target, caller, "target AST is too large [early]");
|
| return false;
|
| }
|
|
|
| - Handle<SharedFunctionInfo> target_shared(target->shared());
|
| -
|
| #if !defined(V8_TARGET_ARCH_IA32)
|
| // Target must be able to use caller's context.
|
| CompilationInfo* outer_info = info();
|
|
|