| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index 537ec149d17bac55118a7f73e7bba14428aee29f..478d938cf6fa27d74994d43674af59ca7f05ef41 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -225,7 +225,7 @@ void HBasicBlock::Goto(HBasicBlock* block,
|
| FunctionState* state,
|
| bool add_simulate) {
|
| bool drop_extra = state != NULL &&
|
| - state->inlining_kind() == DROP_EXTRA_ON_RETURN;
|
| + state->inlining_kind() == NORMAL_RETURN;
|
|
|
| if (block->IsInlineReturnTarget()) {
|
| HEnvironment* env = last_environment();
|
| @@ -246,7 +246,7 @@ void HBasicBlock::AddLeaveInlined(HValue* return_value,
|
| FunctionState* state,
|
| int position) {
|
| HBasicBlock* target = state->function_return();
|
| - bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN;
|
| + bool drop_extra = state->inlining_kind() == NORMAL_RETURN;
|
|
|
| ASSERT(target->IsInlineReturnTarget());
|
| ASSERT(return_value != NULL);
|
| @@ -5672,10 +5672,9 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
|
|
|
| if (info->lookup()->IsPropertyCallbacks()) {
|
| if (NeedsWrappingFor(info->type(), info->accessor())) {
|
| - return New<HLoadNamedGeneric>(checked_object, info->name());
|
| - // HValue* function = Add<HConstant>(info->accessor());
|
| - // Add<HPushArgument>(checked_object);
|
| - // return New<HCallFunction>(function, 1, WRAP_AND_CALL);
|
| + HValue* function = Add<HConstant>(info->accessor());
|
| + Add<HPushArgument>(checked_object);
|
| + return New<HCallFunction>(function, 1, WRAP_AND_CALL);
|
| } else {
|
| Push(checked_object);
|
| if (FLAG_inline_accessors &&
|
| @@ -6027,11 +6026,12 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
|
| return;
|
| }
|
| Drop(2);
|
| + Add<HPushArgument>(object);
|
| + Add<HPushArgument>(value);
|
| if (needs_wrapping) {
|
| - instr = BuildStoreNamedGeneric(object, name, value);
|
| + HValue* function = Add<HConstant>(setter);
|
| + instr = New<HCallFunction>(function, 2, WRAP_AND_CALL);
|
| } else {
|
| - Add<HPushArgument>(object);
|
| - Add<HPushArgument>(value);
|
| instr = BuildCallConstantFunction(setter, 2);
|
| }
|
| } else {
|
| @@ -6429,7 +6429,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric(
|
| HValue* object,
|
| Handle<String> name,
|
| Property* expr) {
|
| - if (expr->IsUninitialized()) {
|
| + if (!expr->IsForCall() && expr->IsUninitialized()) {
|
| Add<HDeoptimize>("Insufficient type feedback for generic named load",
|
| Deoptimizer::SOFT);
|
| }
|
| @@ -6991,18 +6991,6 @@ void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder,
|
| }
|
|
|
|
|
| -void HOptimizedGraphBuilder::AddCheckConstantFunction(
|
| - Handle<JSObject> holder,
|
| - HValue* receiver,
|
| - Handle<Map> receiver_map) {
|
| - // Constant functions have the nice property that the map will change if they
|
| - // are overwritten. Therefore it is enough to check the map of the holder and
|
| - // its prototypes.
|
| - AddCheckMap(receiver, receiver_map);
|
| - AddCheckPrototypeMaps(holder, receiver_map);
|
| -}
|
| -
|
| -
|
| HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall(
|
| HValue* fun, int argument_count, bool pass_argument_count) {
|
| return New<HCallJSFunction>(
|
| @@ -7043,6 +7031,9 @@ HInstruction* HOptimizedGraphBuilder::BuildCallConstantFunction(
|
| bool can_invoke_directly =
|
| dont_adapt_arguments || formal_parameter_count == arity;
|
| if (can_invoke_directly) {
|
| + if (jsfun.is_identical_to(current_info()->closure())) {
|
| + graph()->MarkRecursive();
|
| + }
|
| return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments);
|
| } else {
|
| HValue* param_count_value = Add<HConstant>(formal_parameter_count);
|
| @@ -7057,33 +7048,6 @@ HInstruction* HOptimizedGraphBuilder::BuildCallConstantFunction(
|
| }
|
|
|
|
|
| -HInstruction* HOptimizedGraphBuilder::NewCallNamed(
|
| - Handle<String> name, int argument_count) {
|
| - CallInterfaceDescriptor* descriptor =
|
| - isolate()->call_descriptor(Isolate::NamedCall);
|
| - HValue* op_vals[] = { context(), Add<HConstant>(name) };
|
| - int arity = argument_count - 1;
|
| - Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity);
|
| -
|
| - return New<HCallWithDescriptor>(
|
| - Add<HConstant>(ic), argument_count, descriptor,
|
| - Vector<HValue*>(op_vals, descriptor->environment_length()));
|
| -}
|
| -
|
| -
|
| -HInstruction* HOptimizedGraphBuilder::NewCallKeyed(
|
| - HValue* key, int argument_count) {
|
| - CallInterfaceDescriptor* descriptor =
|
| - isolate()->call_descriptor(Isolate::KeyedCall);
|
| - HValue* op_vals[] = { context(), key };
|
| - int arity = argument_count - 1;
|
| - Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
|
| -
|
| - return New<HCallWithDescriptor>(
|
| - Add<HConstant>(ic), argument_count, descriptor,
|
| - Vector<HValue*>(op_vals, descriptor->environment_length()));
|
| -}
|
| -
|
| class FunctionSorter {
|
| public:
|
| FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { }
|
| @@ -7115,73 +7079,34 @@ inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) {
|
| }
|
|
|
|
|
| -bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic(
|
| - Call* expr,
|
| - HValue* receiver,
|
| - SmallMapList* types,
|
| - Handle<String> name) {
|
| - if (types->length() > kMaxCallPolymorphism) return false;
|
| -
|
| - PropertyAccessInfo info(this, IC::MapToType(types->at(0)), name);
|
| - if (!info.CanLoadAsMonomorphic(types)) return false;
|
| - if (!expr->ComputeTarget(info.map(), name)) return false;
|
| -
|
| - BuildCheckHeapObject(receiver);
|
| - Add<HCheckMaps>(receiver, types);
|
| - AddCheckPrototypeMaps(expr->holder(), info.map());
|
| - if (FLAG_trace_inlining) {
|
| - Handle<JSFunction> caller = current_info()->closure();
|
| - SmartArrayPointer<char> caller_name =
|
| - caller->shared()->DebugName()->ToCString();
|
| - PrintF("Trying to inline the polymorphic call to %s from %s\n",
|
| - name->ToCString().get(), caller_name.get());
|
| - }
|
| -
|
| - if (!TryInlineCall(expr)) {
|
| - int argument_count = expr->arguments()->length() + 1; // Includes receiver.
|
| - HInstruction* call = BuildCallConstantFunction(
|
| - expr->target(), argument_count);
|
| - PushArgumentsFromEnvironment(argument_count);
|
| - AddInstruction(call);
|
| - if (!ast_context()->IsEffect()) Push(call);
|
| - Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
|
| - if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -
|
| void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
| Call* expr,
|
| HValue* receiver,
|
| SmallMapList* types,
|
| Handle<String> name) {
|
| - if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return;
|
| -
|
| int argument_count = expr->arguments()->length() + 1; // Includes receiver.
|
| - HBasicBlock* join = NULL;
|
| FunctionSorter order[kMaxCallPolymorphism];
|
| - int ordered_functions = 0;
|
| -
|
| - Handle<Map> initial_string_map(
|
| - isolate()->native_context()->string_function()->initial_map());
|
| - Handle<Map> string_marker_map(
|
| - JSObject::cast(initial_string_map->prototype())->map());
|
| - Handle<Map> initial_number_map(
|
| - isolate()->native_context()->number_function()->initial_map());
|
| - Handle<Map> number_marker_map(
|
| - JSObject::cast(initial_number_map->prototype())->map());
|
| - Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
|
|
|
| bool handle_smi = false;
|
| + bool handled_string = false;
|
| + int ordered_functions = 0;
|
|
|
| for (int i = 0;
|
| i < types->length() && ordered_functions < kMaxCallPolymorphism;
|
| ++i) {
|
| - Handle<Map> map = types->at(i);
|
| - if (expr->ComputeTarget(map, name)) {
|
| - if (map.is_identical_to(number_marker_map)) handle_smi = true;
|
| + PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name);
|
| + if (info.CanLoadMonomorphic() &&
|
| + info.lookup()->IsConstant() &&
|
| + info.constant()->IsJSFunction()) {
|
| + if (info.type()->Is(HeapType::String())) {
|
| + if (handled_string) continue;
|
| + handled_string = true;
|
| + }
|
| + Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
|
| + if (info.type()->Is(HeapType::Number())) {
|
| + handle_smi = true;
|
| + }
|
| + expr->set_target(target);
|
| order[ordered_functions++] =
|
| FunctionSorter(i,
|
| expr->target()->shared()->profiler_ticks(),
|
| @@ -7193,11 +7118,23 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
| std::sort(order, order + ordered_functions);
|
|
|
| HBasicBlock* number_block = NULL;
|
| + HBasicBlock* join = NULL;
|
| + handled_string = false;
|
| + int count = 0;
|
|
|
| for (int fn = 0; fn < ordered_functions; ++fn) {
|
| int i = order[fn].index();
|
| - Handle<Map> map = types->at(i);
|
| - if (fn == 0) {
|
| + PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name);
|
| + if (info.type()->Is(HeapType::String())) {
|
| + if (handled_string) continue;
|
| + handled_string = true;
|
| + }
|
| + // Reloads the target.
|
| + info.CanLoadMonomorphic();
|
| + Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
|
| +
|
| + expr->set_target(target);
|
| + if (count == 0) {
|
| // Only needed once.
|
| join = graph()->CreateBasicBlock();
|
| if (handle_smi) {
|
| @@ -7212,37 +7149,39 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
| BuildCheckHeapObject(receiver);
|
| }
|
| }
|
| + ++count;
|
| HBasicBlock* if_true = graph()->CreateBasicBlock();
|
| HBasicBlock* if_false = graph()->CreateBasicBlock();
|
| HUnaryControlInstruction* compare;
|
|
|
| - if (handle_smi && map.is_identical_to(number_marker_map)) {
|
| + Handle<Map> map = info.map();
|
| + if (info.type()->Is(HeapType::Number())) {
|
| + Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
|
| compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false);
|
| - map = initial_number_map;
|
| - expr->set_number_check(
|
| - Handle<JSObject>(JSObject::cast(map->prototype())));
|
| - } else if (map.is_identical_to(string_marker_map)) {
|
| + } else if (info.type()->Is(HeapType::String())) {
|
| compare = New<HIsStringAndBranch>(receiver, if_true, if_false);
|
| - map = initial_string_map;
|
| - expr->set_string_check(
|
| - Handle<JSObject>(JSObject::cast(map->prototype())));
|
| } else {
|
| compare = New<HCompareMap>(receiver, map, if_true, if_false);
|
| - expr->set_map_check();
|
| }
|
| -
|
| FinishCurrentBlock(compare);
|
|
|
| - if (expr->check_type() == NUMBER_CHECK) {
|
| + if (info.type()->Is(HeapType::Number())) {
|
| Goto(if_true, number_block);
|
| if_true = number_block;
|
| number_block->SetJoinId(expr->id());
|
| }
|
| +
|
| set_current_block(if_true);
|
|
|
| - expr->ComputeTarget(map, name);
|
| - AddCheckPrototypeMaps(expr->holder(), map);
|
| - if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
|
| + AddCheckPrototypeMaps(info.holder(), map);
|
| +
|
| + HValue* function = Add<HConstant>(expr->target());
|
| + environment()->SetExpressionStackAt(0, function);
|
| + Push(receiver);
|
| + CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
| + bool needs_wrapping = NeedsWrappingFor(info.type(), target);
|
| + bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping;
|
| + if (FLAG_trace_inlining && try_inline) {
|
| Handle<JSFunction> caller = current_info()->closure();
|
| SmartArrayPointer<char> caller_name =
|
| caller->shared()->DebugName()->ToCString();
|
| @@ -7250,15 +7189,22 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
| name->ToCString().get(),
|
| caller_name.get());
|
| }
|
| - if (FLAG_polymorphic_inlining && TryInlineCall(expr)) {
|
| + if (try_inline && 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 {
|
| - HInstruction* call = BuildCallConstantFunction(
|
| - expr->target(), argument_count);
|
| + // Since HWrapReceiver currently cannot actually wrap numbers and strings,
|
| + // use the regular CallFunctionStub for method calls to wrap the receiver.
|
| + // TODO(verwaest): Support creation of value wrappers directly in
|
| + // HWrapReceiver.
|
| + HInstruction* call = needs_wrapping
|
| + ? NewUncasted<HCallFunction>(
|
| + function, argument_count, WRAP_AND_CALL)
|
| + : BuildCallConstantFunction(target, argument_count);
|
| PushArgumentsFromEnvironment(argument_count);
|
| AddInstruction(call);
|
| + Drop(1); // Drop the function.
|
| if (!ast_context()->IsEffect()) Push(call);
|
| }
|
|
|
| @@ -7273,13 +7219,29 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
| // Because the deopt may be the only path in the polymorphic call, make sure
|
| // that the environment stack matches the depth on deopt that it otherwise
|
| // would have had after a successful call.
|
| - Drop(argument_count);
|
| + Drop(1); // Drop receiver.
|
| if (!ast_context()->IsEffect()) Push(graph()->GetConstant0());
|
| FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join);
|
| } else {
|
| - HInstruction* call = NewCallNamed(name, argument_count);
|
| + Property* prop = expr->expression()->AsProperty();
|
| + HInstruction* function = BuildLoadNamedGeneric(receiver, name, prop);
|
| + AddInstruction(function);
|
| + Push(function);
|
| + AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
|
| +
|
| + environment()->SetExpressionStackAt(1, function);
|
| + environment()->SetExpressionStackAt(0, receiver);
|
| + CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
| +
|
| + CallFunctionFlags flags = receiver->type().IsJSObject()
|
| + ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD;
|
| + HInstruction* call = New<HCallFunction>(
|
| + function, argument_count, flags);
|
| +
|
| PushArgumentsFromEnvironment(argument_count);
|
|
|
| + Drop(1); // Function.
|
| +
|
| if (join != NULL) {
|
| AddInstruction(call);
|
| if (!ast_context()->IsEffect()) Push(call);
|
| @@ -7643,13 +7605,13 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
|
| }
|
|
|
|
|
| -bool HOptimizedGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) {
|
| +bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) {
|
| return TryInline(expr->target(),
|
| expr->arguments()->length(),
|
| NULL,
|
| expr->id(),
|
| expr->ReturnId(),
|
| - drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN);
|
| + NORMAL_RETURN);
|
| }
|
|
|
|
|
| @@ -7700,8 +7662,7 @@ bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function,
|
| }
|
|
|
|
|
| -bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr,
|
| - bool drop_extra) {
|
| +bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) {
|
| if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
|
| BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
|
| switch (id) {
|
| @@ -7715,9 +7676,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr,
|
| case kMathLog:
|
| if (expr->arguments()->length() == 1) {
|
| HValue* argument = Pop();
|
| - Drop(1); // Receiver.
|
| + Drop(2); // Receiver and function.
|
| HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
|
| - if (drop_extra) Drop(1); // Optionally drop the function.
|
| ast_context()->ReturnInstruction(op, expr->id());
|
| return true;
|
| }
|
| @@ -7726,9 +7686,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr,
|
| if (expr->arguments()->length() == 2) {
|
| HValue* right = Pop();
|
| HValue* left = Pop();
|
| - Drop(1); // Receiver.
|
| + Drop(2); // Receiver and function.
|
| 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;
|
| }
|
| @@ -7744,9 +7703,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr,
|
| bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| Call* expr,
|
| HValue* receiver,
|
| - Handle<Map> receiver_map,
|
| - CheckType check_type) {
|
| - ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null());
|
| + Handle<Map> receiver_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();
|
| @@ -7754,13 +7711,10 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| switch (id) {
|
| case kStringCharCodeAt:
|
| case kStringCharAt:
|
| - if (argument_count == 2 && check_type == STRING_CHECK) {
|
| + if (argument_count == 2) {
|
| HValue* index = Pop();
|
| HValue* string = Pop();
|
| - ASSERT(!expr->holder().is_null());
|
| - BuildCheckPrototypeMaps(Call::GetPrototypeForPrimitiveCheck(
|
| - STRING_CHECK, expr->holder()->GetIsolate()),
|
| - expr->holder());
|
| + Drop(1); // Function.
|
| HInstruction* char_code =
|
| BuildStringCharCodeAt(string, index);
|
| if (id == kStringCharCodeAt) {
|
| @@ -7774,10 +7728,9 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| }
|
| break;
|
| case kStringFromCharCode:
|
| - if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
|
| - AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| + if (argument_count == 2) {
|
| HValue* argument = Pop();
|
| - Drop(1); // Receiver.
|
| + Drop(2); // Receiver and function.
|
| HInstruction* result = NewUncasted<HStringCharFromCode>(argument);
|
| ast_context()->ReturnInstruction(result, expr->id());
|
| return true;
|
| @@ -7791,21 +7744,19 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| case kMathAbs:
|
| case kMathSqrt:
|
| case kMathLog:
|
| - if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
|
| - AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| + if (argument_count == 2) {
|
| HValue* argument = Pop();
|
| - Drop(1); // Receiver.
|
| + Drop(2); // Receiver and function.
|
| HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
|
| ast_context()->ReturnInstruction(op, expr->id());
|
| return true;
|
| }
|
| break;
|
| case kMathPow:
|
| - if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
|
| - AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| + if (argument_count == 3) {
|
| HValue* right = Pop();
|
| HValue* left = Pop();
|
| - Pop(); // Pop receiver.
|
| + Drop(2); // Receiver and function.
|
| HInstruction* result = NULL;
|
| // Use sqrt() if exponent is 0.5 or -0.5.
|
| if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
|
| @@ -7834,11 +7785,10 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| break;
|
| case kMathMax:
|
| case kMathMin:
|
| - if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
|
| - AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| + if (argument_count == 3) {
|
| HValue* right = Pop();
|
| HValue* left = Pop();
|
| - Drop(1); // Receiver.
|
| + Drop(2); // Receiver and function.
|
| HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin
|
| : HMathMinMax::kMathMax;
|
| HInstruction* result = NewUncasted<HMathMinMax>(left, right, op);
|
| @@ -7847,24 +7797,20 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| }
|
| break;
|
| case kMathImul:
|
| - if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
|
| - AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| + if (argument_count == 3) {
|
| HValue* right = Pop();
|
| HValue* left = Pop();
|
| - Drop(1); // Receiver.
|
| + Drop(2); // Receiver and function.
|
| HInstruction* result = HMul::NewImul(zone(), context(), left, right);
|
| ast_context()->ReturnInstruction(result, expr->id());
|
| return true;
|
| }
|
| break;
|
| case kArrayPop: {
|
| - if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) {
|
| - return false;
|
| - }
|
| + if (receiver_map.is_null()) return false;
|
| if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
|
| ElementsKind elements_kind = receiver_map->elements_kind();
|
| if (!IsFastElementsKind(elements_kind)) return false;
|
| - AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
|
|
| Drop(expr->arguments()->length());
|
| HValue* result;
|
| @@ -7876,6 +7822,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| checked_object, static_cast<HValue*>(NULL),
|
| HObjectAccess::ForArrayLength(elements_kind));
|
|
|
| + Drop(1); // Function.
|
| +
|
| { NoObservableSideEffectsScope scope(this);
|
| IfBuilder length_checker(this);
|
|
|
| @@ -7921,13 +7869,10 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| return true;
|
| }
|
| case kArrayPush: {
|
| - if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) {
|
| - return false;
|
| - }
|
| + if (receiver_map.is_null()) return false;
|
| if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
|
| ElementsKind elements_kind = receiver_map->elements_kind();
|
| if (!IsFastElementsKind(elements_kind)) return false;
|
| - AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
|
|
| HValue* op_vals[] = {
|
| context(),
|
| @@ -7952,6 +7897,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| HInstruction* call = New<HCallWithDescriptor>(
|
| code_value, argc + 1, descriptor,
|
| Vector<HValue*>(op_vals, descriptor->environment_length()));
|
| + Drop(1); // Drop function.
|
| ast_context()->ReturnInstruction(call, expr->id());
|
| return true;
|
| }
|
| @@ -7964,27 +7910,23 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
|
|
|
|
| bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr,
|
| - HValue* receiver,
|
| - bool drop_extra) {
|
| + HValue* receiver) {
|
| return TryInlineApiCall(
|
| - expr, receiver, Handle<Map>::null(), drop_extra, true);
|
| + expr, receiver, Handle<Map>::null(), true);
|
| }
|
|
|
|
|
| bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr,
|
| HValue* receiver,
|
| Handle<Map> receiver_map) {
|
| - return TryInlineApiCall(expr, receiver, receiver_map, false, false);
|
| + return TryInlineApiCall(expr, receiver, receiver_map, false);
|
| }
|
|
|
| bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr,
|
| HValue* receiver,
|
| Handle<Map> receiver_map,
|
| - bool drop_extra,
|
| bool is_function_call) {
|
| - if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) {
|
| - return false;
|
| - }
|
| + if (!expr->IsMonomorphic()) return false;
|
| CallOptimization optimization(expr->target());
|
| if (!optimization.is_simple_api_call()) return false;
|
| Handle<Map> holder_map;
|
| @@ -8007,6 +7949,10 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr,
|
| PrintF("\n");
|
| }
|
|
|
| + const int argc = expr->arguments()->length();
|
| + // Includes receiver.
|
| + PushArgumentsFromEnvironment(argc + 1);
|
| +
|
| // Need to ensure the chain between receiver and api_holder is intact
|
| AddCheckMap(receiver, receiver_map);
|
| if (holder_lookup == CallOptimization::kHolderFound) {
|
| @@ -8015,18 +7961,13 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr,
|
| ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver);
|
| }
|
|
|
| - // TODO(verwaest): remove.
|
| - if (!is_function_call) {
|
| - AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
|
| - }
|
| -
|
| HValue* holder = NULL;
|
| switch (holder_lookup) {
|
| case CallOptimization::kHolderFound:
|
| holder = Add<HConstant>(api_holder);
|
| break;
|
| case CallOptimization::kHolderIsReceiver:
|
| - holder = environment()->ExpressionStackAt(expr->arguments()->length());
|
| + holder = receiver;
|
| break;
|
| case CallOptimization::kHolderNotFound:
|
| UNREACHABLE();
|
| @@ -8051,10 +7992,6 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr,
|
| context()
|
| };
|
|
|
| - const int argc = expr->arguments()->length();
|
| - // Includes receiver.
|
| - PushArgumentsFromEnvironment(argc + 1);
|
| -
|
| CallInterfaceDescriptor* descriptor =
|
| isolate()->call_descriptor(Isolate::ApiFunctionCall);
|
|
|
| @@ -8069,18 +8006,16 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr,
|
| code_value, argc + 1, descriptor,
|
| Vector<HValue*>(op_vals, descriptor->environment_length()));
|
|
|
| - if (drop_extra) Drop(1); // Drop function.
|
| + Drop(1); // Drop function.
|
| ast_context()->ReturnInstruction(call, expr->id());
|
| return true;
|
| }
|
|
|
|
|
| bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
|
| - Expression* callee = expr->expression();
|
| - Property* prop = callee->AsProperty();
|
| - ASSERT(prop != NULL);
|
| + ASSERT(expr->expression()->IsProperty());
|
|
|
| - if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) {
|
| + if (!expr->IsMonomorphic()) {
|
| return false;
|
| }
|
| Handle<Map> function_map = expr->GetReceiverTypes()->first();
|
| @@ -8101,15 +8036,10 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
|
| if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
|
|
|
| // Found pattern f.apply(receiver, arguments).
|
| - CHECK_ALIVE_OR_RETURN(VisitForValue(prop->obj()), true);
|
| - HValue* function = Top();
|
| -
|
| - AddCheckConstantFunction(expr->holder(), function, function_map);
|
| -
|
| CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true);
|
| - HValue* receiver = Pop();
|
| -
|
| - Drop(1); // Pop the function.
|
| + HValue* receiver = Pop(); // receiver
|
| + HValue* function = Pop(); // f
|
| + Drop(1); // apply
|
|
|
| if (function_state()->outer() == NULL) {
|
| HInstruction* elements = Add<HArgumentsElements>(false);
|
| @@ -8129,6 +8059,7 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
|
| HArgumentsObject* args = function_state()->entry()->arguments_object();
|
| const ZoneList<HValue*>* arguments_values = args->arguments_values();
|
| int arguments_count = arguments_values->length();
|
| + Push(function);
|
| Push(BuildWrapReceiver(receiver, function));
|
| for (int i = 1; i < arguments_count; i++) {
|
| Push(arguments_values->at(i));
|
| @@ -8143,16 +8074,10 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
|
| if (TryInlineApply(known_function, expr, args_count)) return true;
|
| }
|
|
|
| - Drop(arguments_count - 1);
|
| - Push(Add<HPushArgument>(Pop()));
|
| - for (int i = 1; i < arguments_count; i++) {
|
| - Push(Add<HPushArgument>(arguments_values->at(i)));
|
| - }
|
| -
|
| - HInvokeFunction* call = New<HInvokeFunction>(function,
|
| - known_function,
|
| - arguments_count);
|
| - Drop(arguments_count);
|
| + PushArgumentsFromEnvironment(arguments_count);
|
| + HInvokeFunction* call = New<HInvokeFunction>(
|
| + function, known_function, arguments_count);
|
| + Drop(1); // Function.
|
| ast_context()->ReturnInstruction(call, expr->id());
|
| return true;
|
| }
|
| @@ -8184,84 +8109,78 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
|
|
| Property* prop = callee->AsProperty();
|
| if (prop != NULL) {
|
| - if (!prop->key()->IsPropertyName()) {
|
| - // Keyed function call.
|
| - CHECK_ALIVE(VisitForValue(prop->obj()));
|
| - CHECK_ALIVE(VisitForValue(prop->key()));
|
| -
|
| - // Push receiver and key like the non-optimized code generator expects it.
|
| - HValue* key = Pop();
|
| - HValue* receiver = Pop();
|
| - Push(key);
|
| - Push(Add<HPushArgument>(receiver));
|
| - CHECK_ALIVE(VisitArgumentList(expr->arguments()));
|
| -
|
| - if (expr->IsMonomorphic()) {
|
| - BuildCheckHeapObject(receiver);
|
| - ElementsKind kind = expr->KeyedArrayCallIsHoley()
|
| - ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
|
| -
|
| - Handle<Map> map(isolate()->get_initial_js_array_map(kind));
|
| + CHECK_ALIVE(VisitForValue(prop->obj()));
|
| + HValue* receiver = Top();
|
|
|
| - HValue* function = BuildMonomorphicElementAccess(
|
| - receiver, key, NULL, NULL, map, false, STANDARD_STORE);
|
| + SmallMapList* types;
|
| + ComputeReceiverTypes(expr, receiver, &types);
|
|
|
| - call = New<HCallFunction>(function, argument_count);
|
| - } else {
|
| - call = NewCallKeyed(key, argument_count);
|
| + if (prop->key()->IsPropertyName() && types->length() > 0) {
|
| + Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
|
| + PropertyAccessInfo info(this, IC::MapToType(types->first()), name);
|
| + if (!info.CanLoadAsMonomorphic(types)) {
|
| + HandlePolymorphicCallNamed(expr, receiver, types, name);
|
| + return;
|
| }
|
| - Drop(argument_count + 1); // 1 is the key.
|
| - return ast_context()->ReturnInstruction(call, expr->id());
|
| }
|
|
|
| - // Named function call.
|
| - if (TryCallApply(expr)) return;
|
| + HValue* key = NULL;
|
| + if (!prop->key()->IsPropertyName()) {
|
| + CHECK_ALIVE(VisitForValue(prop->key()));
|
| + key = Pop();
|
| + }
|
|
|
| - CHECK_ALIVE(VisitForValue(prop->obj()));
|
| - CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
| + CHECK_ALIVE(PushLoad(prop, receiver, key));
|
| + HValue* function = Pop();
|
|
|
| - Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
|
| - HValue* receiver =
|
| - environment()->ExpressionStackAt(expr->arguments()->length());
|
| + // Push the function under the receiver.
|
| + environment()->SetExpressionStackAt(0, function);
|
|
|
| - SmallMapList* types;
|
| - bool was_monomorphic = expr->IsMonomorphic();
|
| - bool monomorphic = ComputeReceiverTypes(expr, receiver, &types);
|
| - if (!was_monomorphic && monomorphic) {
|
| - monomorphic = expr->ComputeTarget(types->first(), name);
|
| - }
|
| + Push(receiver);
|
| +
|
| + if (function->IsConstant() &&
|
| + HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
|
| + Handle<JSFunction> known_function = Handle<JSFunction>::cast(
|
| + HConstant::cast(function)->handle(isolate()));
|
| + expr->set_target(known_function);
|
|
|
| - if (monomorphic) {
|
| - Handle<Map> map = types->first();
|
| - if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) {
|
| + if (TryCallApply(expr)) return;
|
| + CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
| +
|
| + Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>();
|
| + if (TryInlineBuiltinMethodCall(expr, receiver, map)) {
|
| if (FLAG_trace_inlining) {
|
| PrintF("Inlining builtin ");
|
| - expr->target()->ShortPrint();
|
| + known_function->ShortPrint();
|
| PrintF("\n");
|
| }
|
| return;
|
| }
|
| if (TryInlineApiMethodCall(expr, receiver, map)) return;
|
|
|
| - if (expr->check_type() != RECEIVER_MAP_CHECK) {
|
| - call = NewCallNamed(name, argument_count);
|
| - PushArgumentsFromEnvironment(argument_count);
|
| + // Wrap the receiver if necessary.
|
| + if (NeedsWrappingFor(IC::MapToType(types->first()), known_function)) {
|
| + // Since HWrapReceiver currently cannot actually wrap numbers and
|
| + // strings, use the regular CallFunctionStub for method calls to wrap
|
| + // the receiver.
|
| + // TODO(verwaest): Support creation of value wrappers directly in
|
| + // HWrapReceiver.
|
| + call = New<HCallFunction>(
|
| + function, argument_count, WRAP_AND_CALL);
|
| + } else if (TryInlineCall(expr)) {
|
| + return;
|
| } else {
|
| - AddCheckConstantFunction(expr->holder(), receiver, map);
|
| -
|
| - if (TryInlineCall(expr)) return;
|
| - call = BuildCallConstantFunction(expr->target(), argument_count);
|
| - PushArgumentsFromEnvironment(argument_count);
|
| + call = BuildCallConstantFunction(known_function, argument_count);
|
| }
|
| - } else if (types != NULL && types->length() > 1) {
|
| - ASSERT(expr->check_type() == RECEIVER_MAP_CHECK);
|
| - HandlePolymorphicCallNamed(expr, receiver, types, name);
|
| - return;
|
|
|
| } else {
|
| - call = NewCallNamed(name, argument_count);
|
| - PushArgumentsFromEnvironment(argument_count);
|
| + CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
| + CallFunctionFlags flags = receiver->type().IsJSObject()
|
| + ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD;
|
| + call = New<HCallFunction>(function, argument_count, flags);
|
| }
|
| + PushArgumentsFromEnvironment(argument_count);
|
| +
|
| } else {
|
| VariableProxy* proxy = expr->expression()->AsVariableProxy();
|
| if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
|
| @@ -8282,26 +8201,21 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
| Handle<GlobalObject> global(current_info()->global_object());
|
| known_global_function = expr->ComputeGlobalTarget(global, &lookup);
|
| }
|
| + CHECK_ALIVE(VisitForValue(expr->expression()));
|
| + HValue* function = Top();
|
| if (known_global_function) {
|
| - // Push the global object instead of the global receiver because
|
| - // code generated by the full code generator expects it.
|
| - HValue* global_object = Add<HLoadNamedField>(
|
| - context(), static_cast<HValue*>(NULL),
|
| - HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
|
| - Push(global_object);
|
| + Add<HCheckValue>(function, expr->target());
|
|
|
| + // Placeholder for the receiver.
|
| + Push(graph()->GetConstantUndefined());
|
| CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
|
|
| - CHECK_ALIVE(VisitForValue(expr->expression()));
|
| - HValue* function = Pop();
|
| - Add<HCheckValue>(function, expr->target());
|
| -
|
| // Patch the global object on the stack by the expected receiver.
|
| HValue* receiver = ImplicitReceiverFor(function, expr->target());
|
| const int receiver_index = argument_count - 1;
|
| environment()->SetExpressionStackAt(receiver_index, receiver);
|
|
|
| - if (TryInlineBuiltinFunctionCall(expr, false)) { // Nothing to drop.
|
| + if (TryInlineBuiltinFunctionCall(expr)) {
|
| if (FLAG_trace_inlining) {
|
| PrintF("Inlining builtin ");
|
| expr->target()->ShortPrint();
|
| @@ -8309,23 +8223,15 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
| }
|
| return;
|
| }
|
| - if (TryInlineApiFunctionCall(expr, receiver, false)) return;
|
| + if (TryInlineApiFunctionCall(expr, receiver)) return;
|
| if (TryInlineCall(expr)) return;
|
|
|
| - if (expr->target().is_identical_to(current_info()->closure())) {
|
| - graph()->MarkRecursive();
|
| - }
|
| -
|
| - call = BuildCallConstantFunction(expr->target(), argument_count);
|
| PushArgumentsFromEnvironment(argument_count);
|
| + call = BuildCallConstantFunction(expr->target(), argument_count);
|
| } else {
|
| - HValue* receiver = Add<HLoadNamedField>(
|
| - context(), static_cast<HValue*>(NULL),
|
| - HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
|
| - Push(Add<HPushArgument>(receiver));
|
| + Push(Add<HPushArgument>(graph()->GetConstantUndefined()));
|
| CHECK_ALIVE(VisitArgumentList(expr->arguments()));
|
| -
|
| - call = NewCallNamed(var->name(), argument_count);
|
| + call = New<HCallFunction>(function, argument_count);
|
| Drop(argument_count);
|
| }
|
|
|
| @@ -8337,12 +8243,14 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
|
|
| Add<HCheckValue>(function, expr->target());
|
|
|
| - HValue* receiver = ImplicitReceiverFor(function, expr->target());
|
| - Push(receiver);
|
| -
|
| + Push(graph()->GetConstantUndefined());
|
| CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
|
|
| - if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function.
|
| + HValue* receiver = ImplicitReceiverFor(function, expr->target());
|
| + const int receiver_index = argument_count - 1;
|
| + environment()->SetExpressionStackAt(receiver_index, receiver);
|
| +
|
| + if (TryInlineBuiltinFunctionCall(expr)) {
|
| if (FLAG_trace_inlining) {
|
| PrintF("Inlining builtin ");
|
| expr->target()->ShortPrint();
|
| @@ -8350,15 +8258,12 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
| }
|
| return;
|
| }
|
| - if (TryInlineApiFunctionCall(expr, receiver, true)) return;
|
| + if (TryInlineApiFunctionCall(expr, receiver)) return;
|
|
|
| - if (TryInlineCall(expr, true)) { // Drop function from environment.
|
| - return;
|
| - } else {
|
| - call = PreProcessCall(New<HInvokeFunction>(function, expr->target(),
|
| - argument_count));
|
| - Drop(1); // The function.
|
| - }
|
| + if (TryInlineCall(expr)) return;
|
| +
|
| + call = PreProcessCall(New<HInvokeFunction>(
|
| + function, expr->target(), argument_count));
|
|
|
| } else {
|
| CHECK_ALIVE(VisitForValue(expr->expression()));
|
| @@ -8366,12 +8271,12 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
| HValue* receiver = graph()->GetConstantUndefined();
|
| Push(Add<HPushArgument>(receiver));
|
| CHECK_ALIVE(VisitArgumentList(expr->arguments()));
|
| - call = New<HCallFunction>(
|
| - function, argument_count, NORMAL_CONTEXTUAL_CALL);
|
| - Drop(argument_count + 1);
|
| + call = New<HCallFunction>(function, argument_count);
|
| + Drop(argument_count);
|
| }
|
| }
|
|
|
| + Drop(1); // Drop the function.
|
| return ast_context()->ReturnInstruction(call, expr->id());
|
| }
|
|
|
|
|