OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 it.Current()->RegisterPredecessor(this); | 218 it.Current()->RegisterPredecessor(this); |
219 } | 219 } |
220 } | 220 } |
221 | 221 |
222 | 222 |
223 void HBasicBlock::Goto(HBasicBlock* block, | 223 void HBasicBlock::Goto(HBasicBlock* block, |
224 int position, | 224 int position, |
225 FunctionState* state, | 225 FunctionState* state, |
226 bool add_simulate) { | 226 bool add_simulate) { |
227 bool drop_extra = state != NULL && | 227 bool drop_extra = state != NULL && |
228 state->inlining_kind() == DROP_EXTRA_ON_RETURN; | 228 state->inlining_kind() == NORMAL_RETURN; |
229 | 229 |
230 if (block->IsInlineReturnTarget()) { | 230 if (block->IsInlineReturnTarget()) { |
231 HEnvironment* env = last_environment(); | 231 HEnvironment* env = last_environment(); |
232 int argument_count = env->arguments_environment()->parameter_count(); | 232 int argument_count = env->arguments_environment()->parameter_count(); |
233 AddInstruction(new(zone()) | 233 AddInstruction(new(zone()) |
234 HLeaveInlined(state->entry(), argument_count), | 234 HLeaveInlined(state->entry(), argument_count), |
235 position); | 235 position); |
236 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); | 236 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); |
237 } | 237 } |
238 | 238 |
239 if (add_simulate) AddNewSimulate(BailoutId::None(), position); | 239 if (add_simulate) AddNewSimulate(BailoutId::None(), position); |
240 HGoto* instr = new(zone()) HGoto(block); | 240 HGoto* instr = new(zone()) HGoto(block); |
241 Finish(instr, position); | 241 Finish(instr, position); |
242 } | 242 } |
243 | 243 |
244 | 244 |
245 void HBasicBlock::AddLeaveInlined(HValue* return_value, | 245 void HBasicBlock::AddLeaveInlined(HValue* return_value, |
246 FunctionState* state, | 246 FunctionState* state, |
247 int position) { | 247 int position) { |
248 HBasicBlock* target = state->function_return(); | 248 HBasicBlock* target = state->function_return(); |
249 bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN; | 249 bool drop_extra = state->inlining_kind() == NORMAL_RETURN; |
250 | 250 |
251 ASSERT(target->IsInlineReturnTarget()); | 251 ASSERT(target->IsInlineReturnTarget()); |
252 ASSERT(return_value != NULL); | 252 ASSERT(return_value != NULL); |
253 HEnvironment* env = last_environment(); | 253 HEnvironment* env = last_environment(); |
254 int argument_count = env->arguments_environment()->parameter_count(); | 254 int argument_count = env->arguments_environment()->parameter_count(); |
255 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count), | 255 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count), |
256 position); | 256 position); |
257 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); | 257 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); |
258 last_environment()->Push(return_value); | 258 last_environment()->Push(return_value); |
259 AddNewSimulate(BailoutId::None(), position); | 259 AddNewSimulate(BailoutId::None(), position); |
(...skipping 5405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5665 } | 5665 } |
5666 | 5666 |
5667 if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined(); | 5667 if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined(); |
5668 | 5668 |
5669 if (info->lookup()->IsField()) { | 5669 if (info->lookup()->IsField()) { |
5670 return BuildLoadNamedField(checked_holder, info->access()); | 5670 return BuildLoadNamedField(checked_holder, info->access()); |
5671 } | 5671 } |
5672 | 5672 |
5673 if (info->lookup()->IsPropertyCallbacks()) { | 5673 if (info->lookup()->IsPropertyCallbacks()) { |
5674 if (NeedsWrappingFor(info->type(), info->accessor())) { | 5674 if (NeedsWrappingFor(info->type(), info->accessor())) { |
5675 return New<HLoadNamedGeneric>(checked_object, info->name()); | 5675 HValue* function = Add<HConstant>(info->accessor()); |
5676 // HValue* function = Add<HConstant>(info->accessor()); | 5676 Add<HPushArgument>(checked_object); |
5677 // Add<HPushArgument>(checked_object); | 5677 return New<HCallFunction>(function, 1, WRAP_AND_CALL); |
5678 // return New<HCallFunction>(function, 1, WRAP_AND_CALL); | |
5679 } else { | 5678 } else { |
5680 Push(checked_object); | 5679 Push(checked_object); |
5681 if (FLAG_inline_accessors && | 5680 if (FLAG_inline_accessors && |
5682 can_inline_accessor && | 5681 can_inline_accessor && |
5683 TryInlineGetter(info->accessor(), ast_id, return_id)) { | 5682 TryInlineGetter(info->accessor(), ast_id, return_id)) { |
5684 return NULL; | 5683 return NULL; |
5685 } | 5684 } |
5686 Add<HPushArgument>(Pop()); | 5685 Add<HPushArgument>(Pop()); |
5687 return BuildCallConstantFunction(info->accessor(), 1); | 5686 return BuildCallConstantFunction(info->accessor(), 1); |
5688 } | 5687 } |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6020 Handle<JSObject> holder; | 6019 Handle<JSObject> holder; |
6021 if (LookupSetter(map, name, &setter, &holder)) { | 6020 if (LookupSetter(map, name, &setter, &holder)) { |
6022 AddCheckMap(object, map); | 6021 AddCheckMap(object, map); |
6023 AddCheckPrototypeMaps(holder, map); | 6022 AddCheckPrototypeMaps(holder, map); |
6024 bool needs_wrapping = NeedsWrappingFor(IC::MapToType(map), setter); | 6023 bool needs_wrapping = NeedsWrappingFor(IC::MapToType(map), setter); |
6025 bool try_inline = FLAG_inline_accessors && !needs_wrapping; | 6024 bool try_inline = FLAG_inline_accessors && !needs_wrapping; |
6026 if (try_inline && TryInlineSetter(setter, ast_id, return_id, value)) { | 6025 if (try_inline && TryInlineSetter(setter, ast_id, return_id, value)) { |
6027 return; | 6026 return; |
6028 } | 6027 } |
6029 Drop(2); | 6028 Drop(2); |
| 6029 Add<HPushArgument>(object); |
| 6030 Add<HPushArgument>(value); |
6030 if (needs_wrapping) { | 6031 if (needs_wrapping) { |
6031 instr = BuildStoreNamedGeneric(object, name, value); | 6032 HValue* function = Add<HConstant>(setter); |
| 6033 instr = New<HCallFunction>(function, 2, WRAP_AND_CALL); |
6032 } else { | 6034 } else { |
6033 Add<HPushArgument>(object); | |
6034 Add<HPushArgument>(value); | |
6035 instr = BuildCallConstantFunction(setter, 2); | 6035 instr = BuildCallConstantFunction(setter, 2); |
6036 } | 6036 } |
6037 } else { | 6037 } else { |
6038 Drop(2); | 6038 Drop(2); |
6039 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, | 6039 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, |
6040 name, | 6040 name, |
6041 value, | 6041 value, |
6042 map)); | 6042 map)); |
6043 } | 6043 } |
6044 } else if (types != NULL && types->length() > 1) { | 6044 } else if (types != NULL && types->length() > 1) { |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6422 } | 6422 } |
6423 } | 6423 } |
6424 return AddLoadNamedField(string, HObjectAccess::ForStringLength()); | 6424 return AddLoadNamedField(string, HObjectAccess::ForStringLength()); |
6425 } | 6425 } |
6426 | 6426 |
6427 | 6427 |
6428 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( | 6428 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( |
6429 HValue* object, | 6429 HValue* object, |
6430 Handle<String> name, | 6430 Handle<String> name, |
6431 Property* expr) { | 6431 Property* expr) { |
6432 if (expr->IsUninitialized()) { | 6432 if (!expr->IsForCall() && expr->IsUninitialized()) { |
6433 Add<HDeoptimize>("Insufficient type feedback for generic named load", | 6433 Add<HDeoptimize>("Insufficient type feedback for generic named load", |
6434 Deoptimizer::SOFT); | 6434 Deoptimizer::SOFT); |
6435 } | 6435 } |
6436 return New<HLoadNamedGeneric>(object, name); | 6436 return New<HLoadNamedGeneric>(object, name); |
6437 } | 6437 } |
6438 | 6438 |
6439 | 6439 |
6440 | 6440 |
6441 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 6441 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
6442 HValue* key) { | 6442 HValue* key) { |
(...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6984 | 6984 |
6985 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, | 6985 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, |
6986 Handle<Map> receiver_map) { | 6986 Handle<Map> receiver_map) { |
6987 if (!holder.is_null()) { | 6987 if (!holder.is_null()) { |
6988 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); | 6988 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); |
6989 BuildCheckPrototypeMaps(prototype, holder); | 6989 BuildCheckPrototypeMaps(prototype, holder); |
6990 } | 6990 } |
6991 } | 6991 } |
6992 | 6992 |
6993 | 6993 |
6994 void HOptimizedGraphBuilder::AddCheckConstantFunction( | |
6995 Handle<JSObject> holder, | |
6996 HValue* receiver, | |
6997 Handle<Map> receiver_map) { | |
6998 // Constant functions have the nice property that the map will change if they | |
6999 // are overwritten. Therefore it is enough to check the map of the holder and | |
7000 // its prototypes. | |
7001 AddCheckMap(receiver, receiver_map); | |
7002 AddCheckPrototypeMaps(holder, receiver_map); | |
7003 } | |
7004 | |
7005 | |
7006 HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall( | 6994 HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall( |
7007 HValue* fun, int argument_count, bool pass_argument_count) { | 6995 HValue* fun, int argument_count, bool pass_argument_count) { |
7008 return New<HCallJSFunction>( | 6996 return New<HCallJSFunction>( |
7009 fun, argument_count, pass_argument_count); | 6997 fun, argument_count, pass_argument_count); |
7010 } | 6998 } |
7011 | 6999 |
7012 | 7000 |
7013 HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall( | 7001 HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall( |
7014 HValue* fun, HValue* context, | 7002 HValue* fun, HValue* context, |
7015 int argument_count, HValue* expected_param_count) { | 7003 int argument_count, HValue* expected_param_count) { |
(...skipping 20 matching lines...) Expand all Loading... |
7036 // For constant functions, we try to avoid calling the | 7024 // For constant functions, we try to avoid calling the |
7037 // argument adaptor and instead call the function directly | 7025 // argument adaptor and instead call the function directly |
7038 int formal_parameter_count = jsfun->shared()->formal_parameter_count(); | 7026 int formal_parameter_count = jsfun->shared()->formal_parameter_count(); |
7039 bool dont_adapt_arguments = | 7027 bool dont_adapt_arguments = |
7040 (formal_parameter_count == | 7028 (formal_parameter_count == |
7041 SharedFunctionInfo::kDontAdaptArgumentsSentinel); | 7029 SharedFunctionInfo::kDontAdaptArgumentsSentinel); |
7042 int arity = argument_count - 1; | 7030 int arity = argument_count - 1; |
7043 bool can_invoke_directly = | 7031 bool can_invoke_directly = |
7044 dont_adapt_arguments || formal_parameter_count == arity; | 7032 dont_adapt_arguments || formal_parameter_count == arity; |
7045 if (can_invoke_directly) { | 7033 if (can_invoke_directly) { |
| 7034 if (jsfun.is_identical_to(current_info()->closure())) { |
| 7035 graph()->MarkRecursive(); |
| 7036 } |
7046 return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments); | 7037 return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments); |
7047 } else { | 7038 } else { |
7048 HValue* param_count_value = Add<HConstant>(formal_parameter_count); | 7039 HValue* param_count_value = Add<HConstant>(formal_parameter_count); |
7049 HValue* context = Add<HLoadNamedField>( | 7040 HValue* context = Add<HLoadNamedField>( |
7050 target, static_cast<HValue*>(NULL), | 7041 target, static_cast<HValue*>(NULL), |
7051 HObjectAccess::ForFunctionContextPointer()); | 7042 HObjectAccess::ForFunctionContextPointer()); |
7052 return NewArgumentAdaptorCall(target, context, | 7043 return NewArgumentAdaptorCall(target, context, |
7053 argument_count, param_count_value); | 7044 argument_count, param_count_value); |
7054 } | 7045 } |
7055 UNREACHABLE(); | 7046 UNREACHABLE(); |
7056 return NULL; | 7047 return NULL; |
7057 } | 7048 } |
7058 | 7049 |
7059 | 7050 |
7060 HInstruction* HOptimizedGraphBuilder::NewCallNamed( | |
7061 Handle<String> name, int argument_count) { | |
7062 CallInterfaceDescriptor* descriptor = | |
7063 isolate()->call_descriptor(Isolate::NamedCall); | |
7064 HValue* op_vals[] = { context(), Add<HConstant>(name) }; | |
7065 int arity = argument_count - 1; | |
7066 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity); | |
7067 | |
7068 return New<HCallWithDescriptor>( | |
7069 Add<HConstant>(ic), argument_count, descriptor, | |
7070 Vector<HValue*>(op_vals, descriptor->environment_length())); | |
7071 } | |
7072 | |
7073 | |
7074 HInstruction* HOptimizedGraphBuilder::NewCallKeyed( | |
7075 HValue* key, int argument_count) { | |
7076 CallInterfaceDescriptor* descriptor = | |
7077 isolate()->call_descriptor(Isolate::KeyedCall); | |
7078 HValue* op_vals[] = { context(), key }; | |
7079 int arity = argument_count - 1; | |
7080 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(arity); | |
7081 | |
7082 return New<HCallWithDescriptor>( | |
7083 Add<HConstant>(ic), argument_count, descriptor, | |
7084 Vector<HValue*>(op_vals, descriptor->environment_length())); | |
7085 } | |
7086 | |
7087 class FunctionSorter { | 7051 class FunctionSorter { |
7088 public: | 7052 public: |
7089 FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { } | 7053 FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { } |
7090 FunctionSorter(int index, int ticks, int ast_length, int src_length) | 7054 FunctionSorter(int index, int ticks, int ast_length, int src_length) |
7091 : index_(index), | 7055 : index_(index), |
7092 ticks_(ticks), | 7056 ticks_(ticks), |
7093 ast_length_(ast_length), | 7057 ast_length_(ast_length), |
7094 src_length_(src_length) { } | 7058 src_length_(src_length) { } |
7095 | 7059 |
7096 int index() const { return index_; } | 7060 int index() const { return index_; } |
(...skipping 11 matching lines...) Expand all Loading... |
7108 | 7072 |
7109 inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) { | 7073 inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) { |
7110 int diff = lhs.ticks() - rhs.ticks(); | 7074 int diff = lhs.ticks() - rhs.ticks(); |
7111 if (diff != 0) return diff > 0; | 7075 if (diff != 0) return diff > 0; |
7112 diff = lhs.ast_length() - rhs.ast_length(); | 7076 diff = lhs.ast_length() - rhs.ast_length(); |
7113 if (diff != 0) return diff < 0; | 7077 if (diff != 0) return diff < 0; |
7114 return lhs.src_length() < rhs.src_length(); | 7078 return lhs.src_length() < rhs.src_length(); |
7115 } | 7079 } |
7116 | 7080 |
7117 | 7081 |
7118 bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic( | |
7119 Call* expr, | |
7120 HValue* receiver, | |
7121 SmallMapList* types, | |
7122 Handle<String> name) { | |
7123 if (types->length() > kMaxCallPolymorphism) return false; | |
7124 | |
7125 PropertyAccessInfo info(this, IC::MapToType(types->at(0)), name); | |
7126 if (!info.CanLoadAsMonomorphic(types)) return false; | |
7127 if (!expr->ComputeTarget(info.map(), name)) return false; | |
7128 | |
7129 BuildCheckHeapObject(receiver); | |
7130 Add<HCheckMaps>(receiver, types); | |
7131 AddCheckPrototypeMaps(expr->holder(), info.map()); | |
7132 if (FLAG_trace_inlining) { | |
7133 Handle<JSFunction> caller = current_info()->closure(); | |
7134 SmartArrayPointer<char> caller_name = | |
7135 caller->shared()->DebugName()->ToCString(); | |
7136 PrintF("Trying to inline the polymorphic call to %s from %s\n", | |
7137 name->ToCString().get(), caller_name.get()); | |
7138 } | |
7139 | |
7140 if (!TryInlineCall(expr)) { | |
7141 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | |
7142 HInstruction* call = BuildCallConstantFunction( | |
7143 expr->target(), argument_count); | |
7144 PushArgumentsFromEnvironment(argument_count); | |
7145 AddInstruction(call); | |
7146 if (!ast_context()->IsEffect()) Push(call); | |
7147 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | |
7148 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | |
7149 } | |
7150 | |
7151 return true; | |
7152 } | |
7153 | |
7154 | |
7155 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( | 7082 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
7156 Call* expr, | 7083 Call* expr, |
7157 HValue* receiver, | 7084 HValue* receiver, |
7158 SmallMapList* types, | 7085 SmallMapList* types, |
7159 Handle<String> name) { | 7086 Handle<String> name) { |
7160 if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return; | |
7161 | |
7162 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 7087 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
7163 HBasicBlock* join = NULL; | |
7164 FunctionSorter order[kMaxCallPolymorphism]; | 7088 FunctionSorter order[kMaxCallPolymorphism]; |
7165 int ordered_functions = 0; | |
7166 | |
7167 Handle<Map> initial_string_map( | |
7168 isolate()->native_context()->string_function()->initial_map()); | |
7169 Handle<Map> string_marker_map( | |
7170 JSObject::cast(initial_string_map->prototype())->map()); | |
7171 Handle<Map> initial_number_map( | |
7172 isolate()->native_context()->number_function()->initial_map()); | |
7173 Handle<Map> number_marker_map( | |
7174 JSObject::cast(initial_number_map->prototype())->map()); | |
7175 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); | |
7176 | 7089 |
7177 bool handle_smi = false; | 7090 bool handle_smi = false; |
| 7091 bool handled_string = false; |
| 7092 int ordered_functions = 0; |
7178 | 7093 |
7179 for (int i = 0; | 7094 for (int i = 0; |
7180 i < types->length() && ordered_functions < kMaxCallPolymorphism; | 7095 i < types->length() && ordered_functions < kMaxCallPolymorphism; |
7181 ++i) { | 7096 ++i) { |
7182 Handle<Map> map = types->at(i); | 7097 PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name); |
7183 if (expr->ComputeTarget(map, name)) { | 7098 if (info.CanLoadMonomorphic() && |
7184 if (map.is_identical_to(number_marker_map)) handle_smi = true; | 7099 info.lookup()->IsConstant() && |
| 7100 info.constant()->IsJSFunction()) { |
| 7101 if (info.type()->Is(HeapType::String())) { |
| 7102 if (handled_string) continue; |
| 7103 handled_string = true; |
| 7104 } |
| 7105 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); |
| 7106 if (info.type()->Is(HeapType::Number())) { |
| 7107 handle_smi = true; |
| 7108 } |
| 7109 expr->set_target(target); |
7185 order[ordered_functions++] = | 7110 order[ordered_functions++] = |
7186 FunctionSorter(i, | 7111 FunctionSorter(i, |
7187 expr->target()->shared()->profiler_ticks(), | 7112 expr->target()->shared()->profiler_ticks(), |
7188 InliningAstSize(expr->target()), | 7113 InliningAstSize(expr->target()), |
7189 expr->target()->shared()->SourceSize()); | 7114 expr->target()->shared()->SourceSize()); |
7190 } | 7115 } |
7191 } | 7116 } |
7192 | 7117 |
7193 std::sort(order, order + ordered_functions); | 7118 std::sort(order, order + ordered_functions); |
7194 | 7119 |
7195 HBasicBlock* number_block = NULL; | 7120 HBasicBlock* number_block = NULL; |
| 7121 HBasicBlock* join = NULL; |
| 7122 handled_string = false; |
| 7123 int count = 0; |
7196 | 7124 |
7197 for (int fn = 0; fn < ordered_functions; ++fn) { | 7125 for (int fn = 0; fn < ordered_functions; ++fn) { |
7198 int i = order[fn].index(); | 7126 int i = order[fn].index(); |
7199 Handle<Map> map = types->at(i); | 7127 PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name); |
7200 if (fn == 0) { | 7128 if (info.type()->Is(HeapType::String())) { |
| 7129 if (handled_string) continue; |
| 7130 handled_string = true; |
| 7131 } |
| 7132 // Reloads the target. |
| 7133 info.CanLoadMonomorphic(); |
| 7134 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); |
| 7135 |
| 7136 expr->set_target(target); |
| 7137 if (count == 0) { |
7201 // Only needed once. | 7138 // Only needed once. |
7202 join = graph()->CreateBasicBlock(); | 7139 join = graph()->CreateBasicBlock(); |
7203 if (handle_smi) { | 7140 if (handle_smi) { |
7204 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | 7141 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
7205 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); | 7142 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
7206 number_block = graph()->CreateBasicBlock(); | 7143 number_block = graph()->CreateBasicBlock(); |
7207 FinishCurrentBlock(New<HIsSmiAndBranch>( | 7144 FinishCurrentBlock(New<HIsSmiAndBranch>( |
7208 receiver, empty_smi_block, not_smi_block)); | 7145 receiver, empty_smi_block, not_smi_block)); |
7209 Goto(empty_smi_block, number_block); | 7146 Goto(empty_smi_block, number_block); |
7210 set_current_block(not_smi_block); | 7147 set_current_block(not_smi_block); |
7211 } else { | 7148 } else { |
7212 BuildCheckHeapObject(receiver); | 7149 BuildCheckHeapObject(receiver); |
7213 } | 7150 } |
7214 } | 7151 } |
| 7152 ++count; |
7215 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 7153 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
7216 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 7154 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
7217 HUnaryControlInstruction* compare; | 7155 HUnaryControlInstruction* compare; |
7218 | 7156 |
7219 if (handle_smi && map.is_identical_to(number_marker_map)) { | 7157 Handle<Map> map = info.map(); |
| 7158 if (info.type()->Is(HeapType::Number())) { |
| 7159 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
7220 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); | 7160 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); |
7221 map = initial_number_map; | 7161 } else if (info.type()->Is(HeapType::String())) { |
7222 expr->set_number_check( | |
7223 Handle<JSObject>(JSObject::cast(map->prototype()))); | |
7224 } else if (map.is_identical_to(string_marker_map)) { | |
7225 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); | 7162 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); |
7226 map = initial_string_map; | |
7227 expr->set_string_check( | |
7228 Handle<JSObject>(JSObject::cast(map->prototype()))); | |
7229 } else { | 7163 } else { |
7230 compare = New<HCompareMap>(receiver, map, if_true, if_false); | 7164 compare = New<HCompareMap>(receiver, map, if_true, if_false); |
7231 expr->set_map_check(); | |
7232 } | 7165 } |
7233 | |
7234 FinishCurrentBlock(compare); | 7166 FinishCurrentBlock(compare); |
7235 | 7167 |
7236 if (expr->check_type() == NUMBER_CHECK) { | 7168 if (info.type()->Is(HeapType::Number())) { |
7237 Goto(if_true, number_block); | 7169 Goto(if_true, number_block); |
7238 if_true = number_block; | 7170 if_true = number_block; |
7239 number_block->SetJoinId(expr->id()); | 7171 number_block->SetJoinId(expr->id()); |
7240 } | 7172 } |
| 7173 |
7241 set_current_block(if_true); | 7174 set_current_block(if_true); |
7242 | 7175 |
7243 expr->ComputeTarget(map, name); | 7176 AddCheckPrototypeMaps(info.holder(), map); |
7244 AddCheckPrototypeMaps(expr->holder(), map); | 7177 |
7245 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 7178 HValue* function = Add<HConstant>(expr->target()); |
| 7179 environment()->SetExpressionStackAt(0, function); |
| 7180 Push(receiver); |
| 7181 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7182 bool needs_wrapping = NeedsWrappingFor(info.type(), target); |
| 7183 bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping; |
| 7184 if (FLAG_trace_inlining && try_inline) { |
7246 Handle<JSFunction> caller = current_info()->closure(); | 7185 Handle<JSFunction> caller = current_info()->closure(); |
7247 SmartArrayPointer<char> caller_name = | 7186 SmartArrayPointer<char> caller_name = |
7248 caller->shared()->DebugName()->ToCString(); | 7187 caller->shared()->DebugName()->ToCString(); |
7249 PrintF("Trying to inline the polymorphic call to %s from %s\n", | 7188 PrintF("Trying to inline the polymorphic call to %s from %s\n", |
7250 name->ToCString().get(), | 7189 name->ToCString().get(), |
7251 caller_name.get()); | 7190 caller_name.get()); |
7252 } | 7191 } |
7253 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { | 7192 if (try_inline && TryInlineCall(expr)) { |
7254 // Trying to inline will signal that we should bailout from the | 7193 // Trying to inline will signal that we should bailout from the |
7255 // entire compilation by setting stack overflow on the visitor. | 7194 // entire compilation by setting stack overflow on the visitor. |
7256 if (HasStackOverflow()) return; | 7195 if (HasStackOverflow()) return; |
7257 } else { | 7196 } else { |
7258 HInstruction* call = BuildCallConstantFunction( | 7197 // Since HWrapReceiver currently cannot actually wrap numbers and strings, |
7259 expr->target(), argument_count); | 7198 // use the regular CallFunctionStub for method calls to wrap the receiver. |
| 7199 // TODO(verwaest): Support creation of value wrappers directly in |
| 7200 // HWrapReceiver. |
| 7201 HInstruction* call = needs_wrapping |
| 7202 ? NewUncasted<HCallFunction>( |
| 7203 function, argument_count, WRAP_AND_CALL) |
| 7204 : BuildCallConstantFunction(target, argument_count); |
7260 PushArgumentsFromEnvironment(argument_count); | 7205 PushArgumentsFromEnvironment(argument_count); |
7261 AddInstruction(call); | 7206 AddInstruction(call); |
| 7207 Drop(1); // Drop the function. |
7262 if (!ast_context()->IsEffect()) Push(call); | 7208 if (!ast_context()->IsEffect()) Push(call); |
7263 } | 7209 } |
7264 | 7210 |
7265 if (current_block() != NULL) Goto(join); | 7211 if (current_block() != NULL) Goto(join); |
7266 set_current_block(if_false); | 7212 set_current_block(if_false); |
7267 } | 7213 } |
7268 | 7214 |
7269 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 7215 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
7270 // know about and do not want to handle ones we've never seen. Otherwise | 7216 // know about and do not want to handle ones we've never seen. Otherwise |
7271 // use a generic IC. | 7217 // use a generic IC. |
7272 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { | 7218 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { |
7273 // Because the deopt may be the only path in the polymorphic call, make sure | 7219 // Because the deopt may be the only path in the polymorphic call, make sure |
7274 // that the environment stack matches the depth on deopt that it otherwise | 7220 // that the environment stack matches the depth on deopt that it otherwise |
7275 // would have had after a successful call. | 7221 // would have had after a successful call. |
7276 Drop(argument_count); | 7222 Drop(1); // Drop receiver. |
7277 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); | 7223 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); |
7278 FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); | 7224 FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); |
7279 } else { | 7225 } else { |
7280 HInstruction* call = NewCallNamed(name, argument_count); | 7226 Property* prop = expr->expression()->AsProperty(); |
| 7227 HInstruction* function = BuildLoadNamedGeneric(receiver, name, prop); |
| 7228 AddInstruction(function); |
| 7229 Push(function); |
| 7230 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
| 7231 |
| 7232 environment()->SetExpressionStackAt(1, function); |
| 7233 environment()->SetExpressionStackAt(0, receiver); |
| 7234 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7235 |
| 7236 CallFunctionFlags flags = receiver->type().IsJSObject() |
| 7237 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; |
| 7238 HInstruction* call = New<HCallFunction>( |
| 7239 function, argument_count, flags); |
| 7240 |
7281 PushArgumentsFromEnvironment(argument_count); | 7241 PushArgumentsFromEnvironment(argument_count); |
7282 | 7242 |
| 7243 Drop(1); // Function. |
| 7244 |
7283 if (join != NULL) { | 7245 if (join != NULL) { |
7284 AddInstruction(call); | 7246 AddInstruction(call); |
7285 if (!ast_context()->IsEffect()) Push(call); | 7247 if (!ast_context()->IsEffect()) Push(call); |
7286 Goto(join); | 7248 Goto(join); |
7287 } else { | 7249 } else { |
7288 return ast_context()->ReturnInstruction(call, expr->id()); | 7250 return ast_context()->ReturnInstruction(call, expr->id()); |
7289 } | 7251 } |
7290 } | 7252 } |
7291 | 7253 |
7292 // We assume that control flow is always live after an expression. So | 7254 // We assume that control flow is always live after an expression. So |
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7636 function_return()->SetJoinId(ast_id); | 7598 function_return()->SetJoinId(ast_id); |
7637 set_current_block(function_return()); | 7599 set_current_block(function_return()); |
7638 } else { | 7600 } else { |
7639 set_current_block(NULL); | 7601 set_current_block(NULL); |
7640 } | 7602 } |
7641 delete target_state; | 7603 delete target_state; |
7642 return true; | 7604 return true; |
7643 } | 7605 } |
7644 | 7606 |
7645 | 7607 |
7646 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) { | 7608 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) { |
7647 return TryInline(expr->target(), | 7609 return TryInline(expr->target(), |
7648 expr->arguments()->length(), | 7610 expr->arguments()->length(), |
7649 NULL, | 7611 NULL, |
7650 expr->id(), | 7612 expr->id(), |
7651 expr->ReturnId(), | 7613 expr->ReturnId(), |
7652 drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN); | 7614 NORMAL_RETURN); |
7653 } | 7615 } |
7654 | 7616 |
7655 | 7617 |
7656 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, | 7618 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, |
7657 HValue* implicit_return_value) { | 7619 HValue* implicit_return_value) { |
7658 return TryInline(expr->target(), | 7620 return TryInline(expr->target(), |
7659 expr->arguments()->length(), | 7621 expr->arguments()->length(), |
7660 implicit_return_value, | 7622 implicit_return_value, |
7661 expr->id(), | 7623 expr->id(), |
7662 expr->ReturnId(), | 7624 expr->ReturnId(), |
(...skipping 30 matching lines...) Expand all Loading... |
7693 int arguments_count) { | 7655 int arguments_count) { |
7694 return TryInline(function, | 7656 return TryInline(function, |
7695 arguments_count, | 7657 arguments_count, |
7696 NULL, | 7658 NULL, |
7697 expr->id(), | 7659 expr->id(), |
7698 expr->ReturnId(), | 7660 expr->ReturnId(), |
7699 NORMAL_RETURN); | 7661 NORMAL_RETURN); |
7700 } | 7662 } |
7701 | 7663 |
7702 | 7664 |
7703 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, | 7665 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { |
7704 bool drop_extra) { | |
7705 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 7666 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
7706 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 7667 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
7707 switch (id) { | 7668 switch (id) { |
7708 case kMathExp: | 7669 case kMathExp: |
7709 if (!FLAG_fast_math) break; | 7670 if (!FLAG_fast_math) break; |
7710 // Fall through if FLAG_fast_math. | 7671 // Fall through if FLAG_fast_math. |
7711 case kMathRound: | 7672 case kMathRound: |
7712 case kMathFloor: | 7673 case kMathFloor: |
7713 case kMathAbs: | 7674 case kMathAbs: |
7714 case kMathSqrt: | 7675 case kMathSqrt: |
7715 case kMathLog: | 7676 case kMathLog: |
7716 if (expr->arguments()->length() == 1) { | 7677 if (expr->arguments()->length() == 1) { |
7717 HValue* argument = Pop(); | 7678 HValue* argument = Pop(); |
7718 Drop(1); // Receiver. | 7679 Drop(2); // Receiver and function. |
7719 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 7680 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
7720 if (drop_extra) Drop(1); // Optionally drop the function. | |
7721 ast_context()->ReturnInstruction(op, expr->id()); | 7681 ast_context()->ReturnInstruction(op, expr->id()); |
7722 return true; | 7682 return true; |
7723 } | 7683 } |
7724 break; | 7684 break; |
7725 case kMathImul: | 7685 case kMathImul: |
7726 if (expr->arguments()->length() == 2) { | 7686 if (expr->arguments()->length() == 2) { |
7727 HValue* right = Pop(); | 7687 HValue* right = Pop(); |
7728 HValue* left = Pop(); | 7688 HValue* left = Pop(); |
7729 Drop(1); // Receiver. | 7689 Drop(2); // Receiver and function. |
7730 HInstruction* op = HMul::NewImul(zone(), context(), left, right); | 7690 HInstruction* op = HMul::NewImul(zone(), context(), left, right); |
7731 if (drop_extra) Drop(1); // Optionally drop the function. | |
7732 ast_context()->ReturnInstruction(op, expr->id()); | 7691 ast_context()->ReturnInstruction(op, expr->id()); |
7733 return true; | 7692 return true; |
7734 } | 7693 } |
7735 break; | 7694 break; |
7736 default: | 7695 default: |
7737 // Not supported for inlining yet. | 7696 // Not supported for inlining yet. |
7738 break; | 7697 break; |
7739 } | 7698 } |
7740 return false; | 7699 return false; |
7741 } | 7700 } |
7742 | 7701 |
7743 | 7702 |
7744 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( | 7703 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
7745 Call* expr, | 7704 Call* expr, |
7746 HValue* receiver, | 7705 HValue* receiver, |
7747 Handle<Map> receiver_map, | 7706 Handle<Map> receiver_map) { |
7748 CheckType check_type) { | |
7749 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); | |
7750 // Try to inline calls like Math.* as operations in the calling function. | 7707 // Try to inline calls like Math.* as operations in the calling function. |
7751 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 7708 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
7752 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 7709 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
7753 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 7710 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
7754 switch (id) { | 7711 switch (id) { |
7755 case kStringCharCodeAt: | 7712 case kStringCharCodeAt: |
7756 case kStringCharAt: | 7713 case kStringCharAt: |
7757 if (argument_count == 2 && check_type == STRING_CHECK) { | 7714 if (argument_count == 2) { |
7758 HValue* index = Pop(); | 7715 HValue* index = Pop(); |
7759 HValue* string = Pop(); | 7716 HValue* string = Pop(); |
7760 ASSERT(!expr->holder().is_null()); | 7717 Drop(1); // Function. |
7761 BuildCheckPrototypeMaps(Call::GetPrototypeForPrimitiveCheck( | |
7762 STRING_CHECK, expr->holder()->GetIsolate()), | |
7763 expr->holder()); | |
7764 HInstruction* char_code = | 7718 HInstruction* char_code = |
7765 BuildStringCharCodeAt(string, index); | 7719 BuildStringCharCodeAt(string, index); |
7766 if (id == kStringCharCodeAt) { | 7720 if (id == kStringCharCodeAt) { |
7767 ast_context()->ReturnInstruction(char_code, expr->id()); | 7721 ast_context()->ReturnInstruction(char_code, expr->id()); |
7768 return true; | 7722 return true; |
7769 } | 7723 } |
7770 AddInstruction(char_code); | 7724 AddInstruction(char_code); |
7771 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code); | 7725 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code); |
7772 ast_context()->ReturnInstruction(result, expr->id()); | 7726 ast_context()->ReturnInstruction(result, expr->id()); |
7773 return true; | 7727 return true; |
7774 } | 7728 } |
7775 break; | 7729 break; |
7776 case kStringFromCharCode: | 7730 case kStringFromCharCode: |
7777 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { | 7731 if (argument_count == 2) { |
7778 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7779 HValue* argument = Pop(); | 7732 HValue* argument = Pop(); |
7780 Drop(1); // Receiver. | 7733 Drop(2); // Receiver and function. |
7781 HInstruction* result = NewUncasted<HStringCharFromCode>(argument); | 7734 HInstruction* result = NewUncasted<HStringCharFromCode>(argument); |
7782 ast_context()->ReturnInstruction(result, expr->id()); | 7735 ast_context()->ReturnInstruction(result, expr->id()); |
7783 return true; | 7736 return true; |
7784 } | 7737 } |
7785 break; | 7738 break; |
7786 case kMathExp: | 7739 case kMathExp: |
7787 if (!FLAG_fast_math) break; | 7740 if (!FLAG_fast_math) break; |
7788 // Fall through if FLAG_fast_math. | 7741 // Fall through if FLAG_fast_math. |
7789 case kMathRound: | 7742 case kMathRound: |
7790 case kMathFloor: | 7743 case kMathFloor: |
7791 case kMathAbs: | 7744 case kMathAbs: |
7792 case kMathSqrt: | 7745 case kMathSqrt: |
7793 case kMathLog: | 7746 case kMathLog: |
7794 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { | 7747 if (argument_count == 2) { |
7795 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7796 HValue* argument = Pop(); | 7748 HValue* argument = Pop(); |
7797 Drop(1); // Receiver. | 7749 Drop(2); // Receiver and function. |
7798 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 7750 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
7799 ast_context()->ReturnInstruction(op, expr->id()); | 7751 ast_context()->ReturnInstruction(op, expr->id()); |
7800 return true; | 7752 return true; |
7801 } | 7753 } |
7802 break; | 7754 break; |
7803 case kMathPow: | 7755 case kMathPow: |
7804 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { | 7756 if (argument_count == 3) { |
7805 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7806 HValue* right = Pop(); | 7757 HValue* right = Pop(); |
7807 HValue* left = Pop(); | 7758 HValue* left = Pop(); |
7808 Pop(); // Pop receiver. | 7759 Drop(2); // Receiver and function. |
7809 HInstruction* result = NULL; | 7760 HInstruction* result = NULL; |
7810 // Use sqrt() if exponent is 0.5 or -0.5. | 7761 // Use sqrt() if exponent is 0.5 or -0.5. |
7811 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { | 7762 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
7812 double exponent = HConstant::cast(right)->DoubleValue(); | 7763 double exponent = HConstant::cast(right)->DoubleValue(); |
7813 if (exponent == 0.5) { | 7764 if (exponent == 0.5) { |
7814 result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf); | 7765 result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf); |
7815 } else if (exponent == -0.5) { | 7766 } else if (exponent == -0.5) { |
7816 HValue* one = graph()->GetConstant1(); | 7767 HValue* one = graph()->GetConstant1(); |
7817 HInstruction* sqrt = AddUncasted<HUnaryMathOperation>( | 7768 HInstruction* sqrt = AddUncasted<HUnaryMathOperation>( |
7818 left, kMathPowHalf); | 7769 left, kMathPowHalf); |
7819 // MathPowHalf doesn't have side effects so there's no need for | 7770 // MathPowHalf doesn't have side effects so there's no need for |
7820 // an environment simulation here. | 7771 // an environment simulation here. |
7821 ASSERT(!sqrt->HasObservableSideEffects()); | 7772 ASSERT(!sqrt->HasObservableSideEffects()); |
7822 result = NewUncasted<HDiv>(one, sqrt); | 7773 result = NewUncasted<HDiv>(one, sqrt); |
7823 } else if (exponent == 2.0) { | 7774 } else if (exponent == 2.0) { |
7824 result = NewUncasted<HMul>(left, left); | 7775 result = NewUncasted<HMul>(left, left); |
7825 } | 7776 } |
7826 } | 7777 } |
7827 | 7778 |
7828 if (result == NULL) { | 7779 if (result == NULL) { |
7829 result = NewUncasted<HPower>(left, right); | 7780 result = NewUncasted<HPower>(left, right); |
7830 } | 7781 } |
7831 ast_context()->ReturnInstruction(result, expr->id()); | 7782 ast_context()->ReturnInstruction(result, expr->id()); |
7832 return true; | 7783 return true; |
7833 } | 7784 } |
7834 break; | 7785 break; |
7835 case kMathMax: | 7786 case kMathMax: |
7836 case kMathMin: | 7787 case kMathMin: |
7837 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { | 7788 if (argument_count == 3) { |
7838 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7839 HValue* right = Pop(); | 7789 HValue* right = Pop(); |
7840 HValue* left = Pop(); | 7790 HValue* left = Pop(); |
7841 Drop(1); // Receiver. | 7791 Drop(2); // Receiver and function. |
7842 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin | 7792 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin |
7843 : HMathMinMax::kMathMax; | 7793 : HMathMinMax::kMathMax; |
7844 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); | 7794 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); |
7845 ast_context()->ReturnInstruction(result, expr->id()); | 7795 ast_context()->ReturnInstruction(result, expr->id()); |
7846 return true; | 7796 return true; |
7847 } | 7797 } |
7848 break; | 7798 break; |
7849 case kMathImul: | 7799 case kMathImul: |
7850 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { | 7800 if (argument_count == 3) { |
7851 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7852 HValue* right = Pop(); | 7801 HValue* right = Pop(); |
7853 HValue* left = Pop(); | 7802 HValue* left = Pop(); |
7854 Drop(1); // Receiver. | 7803 Drop(2); // Receiver and function. |
7855 HInstruction* result = HMul::NewImul(zone(), context(), left, right); | 7804 HInstruction* result = HMul::NewImul(zone(), context(), left, right); |
7856 ast_context()->ReturnInstruction(result, expr->id()); | 7805 ast_context()->ReturnInstruction(result, expr->id()); |
7857 return true; | 7806 return true; |
7858 } | 7807 } |
7859 break; | 7808 break; |
7860 case kArrayPop: { | 7809 case kArrayPop: { |
7861 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { | 7810 if (receiver_map.is_null()) return false; |
7862 return false; | |
7863 } | |
7864 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; | 7811 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; |
7865 ElementsKind elements_kind = receiver_map->elements_kind(); | 7812 ElementsKind elements_kind = receiver_map->elements_kind(); |
7866 if (!IsFastElementsKind(elements_kind)) return false; | 7813 if (!IsFastElementsKind(elements_kind)) return false; |
7867 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7868 | 7814 |
7869 Drop(expr->arguments()->length()); | 7815 Drop(expr->arguments()->length()); |
7870 HValue* result; | 7816 HValue* result; |
7871 HValue* reduced_length; | 7817 HValue* reduced_length; |
7872 HValue* receiver = Pop(); | 7818 HValue* receiver = Pop(); |
7873 | 7819 |
7874 HValue* checked_object = AddCheckMap(receiver, receiver_map); | 7820 HValue* checked_object = AddCheckMap(receiver, receiver_map); |
7875 HValue* length = Add<HLoadNamedField>( | 7821 HValue* length = Add<HLoadNamedField>( |
7876 checked_object, static_cast<HValue*>(NULL), | 7822 checked_object, static_cast<HValue*>(NULL), |
7877 HObjectAccess::ForArrayLength(elements_kind)); | 7823 HObjectAccess::ForArrayLength(elements_kind)); |
7878 | 7824 |
| 7825 Drop(1); // Function. |
| 7826 |
7879 { NoObservableSideEffectsScope scope(this); | 7827 { NoObservableSideEffectsScope scope(this); |
7880 IfBuilder length_checker(this); | 7828 IfBuilder length_checker(this); |
7881 | 7829 |
7882 HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>( | 7830 HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>( |
7883 length, graph()->GetConstant0(), Token::EQ); | 7831 length, graph()->GetConstant0(), Token::EQ); |
7884 length_checker.Then(); | 7832 length_checker.Then(); |
7885 | 7833 |
7886 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); | 7834 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); |
7887 | 7835 |
7888 length_checker.Else(); | 7836 length_checker.Else(); |
(...skipping 25 matching lines...) Expand all Loading... |
7914 length_checker.End(); | 7862 length_checker.End(); |
7915 } | 7863 } |
7916 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); | 7864 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); |
7917 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 7865 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
7918 if (!ast_context()->IsEffect()) Drop(1); | 7866 if (!ast_context()->IsEffect()) Drop(1); |
7919 | 7867 |
7920 ast_context()->ReturnValue(result); | 7868 ast_context()->ReturnValue(result); |
7921 return true; | 7869 return true; |
7922 } | 7870 } |
7923 case kArrayPush: { | 7871 case kArrayPush: { |
7924 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { | 7872 if (receiver_map.is_null()) return false; |
7925 return false; | |
7926 } | |
7927 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; | 7873 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; |
7928 ElementsKind elements_kind = receiver_map->elements_kind(); | 7874 ElementsKind elements_kind = receiver_map->elements_kind(); |
7929 if (!IsFastElementsKind(elements_kind)) return false; | 7875 if (!IsFastElementsKind(elements_kind)) return false; |
7930 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7931 | 7876 |
7932 HValue* op_vals[] = { | 7877 HValue* op_vals[] = { |
7933 context(), | 7878 context(), |
7934 // Receiver. | 7879 // Receiver. |
7935 environment()->ExpressionStackAt(expr->arguments()->length()) | 7880 environment()->ExpressionStackAt(expr->arguments()->length()) |
7936 }; | 7881 }; |
7937 | 7882 |
7938 const int argc = expr->arguments()->length(); | 7883 const int argc = expr->arguments()->length(); |
7939 // Includes receiver. | 7884 // Includes receiver. |
7940 PushArgumentsFromEnvironment(argc + 1); | 7885 PushArgumentsFromEnvironment(argc + 1); |
7941 | 7886 |
7942 CallInterfaceDescriptor* descriptor = | 7887 CallInterfaceDescriptor* descriptor = |
7943 isolate()->call_descriptor(Isolate::CallHandler); | 7888 isolate()->call_descriptor(Isolate::CallHandler); |
7944 | 7889 |
7945 ArrayPushStub stub(receiver_map->elements_kind(), argc); | 7890 ArrayPushStub stub(receiver_map->elements_kind(), argc); |
7946 Handle<Code> code = stub.GetCode(isolate()); | 7891 Handle<Code> code = stub.GetCode(isolate()); |
7947 HConstant* code_value = Add<HConstant>(code); | 7892 HConstant* code_value = Add<HConstant>(code); |
7948 | 7893 |
7949 ASSERT((sizeof(op_vals) / kPointerSize) == | 7894 ASSERT((sizeof(op_vals) / kPointerSize) == |
7950 descriptor->environment_length()); | 7895 descriptor->environment_length()); |
7951 | 7896 |
7952 HInstruction* call = New<HCallWithDescriptor>( | 7897 HInstruction* call = New<HCallWithDescriptor>( |
7953 code_value, argc + 1, descriptor, | 7898 code_value, argc + 1, descriptor, |
7954 Vector<HValue*>(op_vals, descriptor->environment_length())); | 7899 Vector<HValue*>(op_vals, descriptor->environment_length())); |
| 7900 Drop(1); // Drop function. |
7955 ast_context()->ReturnInstruction(call, expr->id()); | 7901 ast_context()->ReturnInstruction(call, expr->id()); |
7956 return true; | 7902 return true; |
7957 } | 7903 } |
7958 default: | 7904 default: |
7959 // Not yet supported for inlining. | 7905 // Not yet supported for inlining. |
7960 break; | 7906 break; |
7961 } | 7907 } |
7962 return false; | 7908 return false; |
7963 } | 7909 } |
7964 | 7910 |
7965 | 7911 |
7966 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, | 7912 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, |
7967 HValue* receiver, | 7913 HValue* receiver) { |
7968 bool drop_extra) { | |
7969 return TryInlineApiCall( | 7914 return TryInlineApiCall( |
7970 expr, receiver, Handle<Map>::null(), drop_extra, true); | 7915 expr, receiver, Handle<Map>::null(), true); |
7971 } | 7916 } |
7972 | 7917 |
7973 | 7918 |
7974 bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr, | 7919 bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr, |
7975 HValue* receiver, | 7920 HValue* receiver, |
7976 Handle<Map> receiver_map) { | 7921 Handle<Map> receiver_map) { |
7977 return TryInlineApiCall(expr, receiver, receiver_map, false, false); | 7922 return TryInlineApiCall(expr, receiver, receiver_map, false); |
7978 } | 7923 } |
7979 | 7924 |
7980 bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr, | 7925 bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr, |
7981 HValue* receiver, | 7926 HValue* receiver, |
7982 Handle<Map> receiver_map, | 7927 Handle<Map> receiver_map, |
7983 bool drop_extra, | |
7984 bool is_function_call) { | 7928 bool is_function_call) { |
7985 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { | 7929 if (!expr->IsMonomorphic()) return false; |
7986 return false; | |
7987 } | |
7988 CallOptimization optimization(expr->target()); | 7930 CallOptimization optimization(expr->target()); |
7989 if (!optimization.is_simple_api_call()) return false; | 7931 if (!optimization.is_simple_api_call()) return false; |
7990 Handle<Map> holder_map; | 7932 Handle<Map> holder_map; |
7991 if (is_function_call) { | 7933 if (is_function_call) { |
7992 // Cannot embed a direct reference to the global proxy map | 7934 // Cannot embed a direct reference to the global proxy map |
7993 // as it maybe dropped on deserialization. | 7935 // as it maybe dropped on deserialization. |
7994 CHECK(!Serializer::enabled()); | 7936 CHECK(!Serializer::enabled()); |
7995 receiver_map = Handle<Map>( | 7937 receiver_map = Handle<Map>( |
7996 expr->target()->context()->global_object()->global_receiver()->map()); | 7938 expr->target()->context()->global_object()->global_receiver()->map()); |
7997 } | 7939 } |
7998 CallOptimization::HolderLookup holder_lookup = | 7940 CallOptimization::HolderLookup holder_lookup = |
7999 CallOptimization::kHolderNotFound; | 7941 CallOptimization::kHolderNotFound; |
8000 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( | 7942 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( |
8001 receiver_map, &holder_lookup); | 7943 receiver_map, &holder_lookup); |
8002 if (holder_lookup == CallOptimization::kHolderNotFound) return false; | 7944 if (holder_lookup == CallOptimization::kHolderNotFound) return false; |
8003 | 7945 |
8004 if (FLAG_trace_inlining) { | 7946 if (FLAG_trace_inlining) { |
8005 PrintF("Inlining api function "); | 7947 PrintF("Inlining api function "); |
8006 expr->target()->ShortPrint(); | 7948 expr->target()->ShortPrint(); |
8007 PrintF("\n"); | 7949 PrintF("\n"); |
8008 } | 7950 } |
8009 | 7951 |
| 7952 const int argc = expr->arguments()->length(); |
| 7953 // Includes receiver. |
| 7954 PushArgumentsFromEnvironment(argc + 1); |
| 7955 |
8010 // Need to ensure the chain between receiver and api_holder is intact | 7956 // Need to ensure the chain between receiver and api_holder is intact |
8011 AddCheckMap(receiver, receiver_map); | 7957 AddCheckMap(receiver, receiver_map); |
8012 if (holder_lookup == CallOptimization::kHolderFound) { | 7958 if (holder_lookup == CallOptimization::kHolderFound) { |
8013 AddCheckPrototypeMaps(api_holder, receiver_map); | 7959 AddCheckPrototypeMaps(api_holder, receiver_map); |
8014 } else { | 7960 } else { |
8015 ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); | 7961 ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); |
8016 } | 7962 } |
8017 | 7963 |
8018 // TODO(verwaest): remove. | |
8019 if (!is_function_call) { | |
8020 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
8021 } | |
8022 | |
8023 HValue* holder = NULL; | 7964 HValue* holder = NULL; |
8024 switch (holder_lookup) { | 7965 switch (holder_lookup) { |
8025 case CallOptimization::kHolderFound: | 7966 case CallOptimization::kHolderFound: |
8026 holder = Add<HConstant>(api_holder); | 7967 holder = Add<HConstant>(api_holder); |
8027 break; | 7968 break; |
8028 case CallOptimization::kHolderIsReceiver: | 7969 case CallOptimization::kHolderIsReceiver: |
8029 holder = environment()->ExpressionStackAt(expr->arguments()->length()); | 7970 holder = receiver; |
8030 break; | 7971 break; |
8031 case CallOptimization::kHolderNotFound: | 7972 case CallOptimization::kHolderNotFound: |
8032 UNREACHABLE(); | 7973 UNREACHABLE(); |
8033 break; | 7974 break; |
8034 } | 7975 } |
8035 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); | 7976 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
8036 Handle<Object> call_data_obj(api_call_info->data(), isolate()); | 7977 Handle<Object> call_data_obj(api_call_info->data(), isolate()); |
8037 bool call_data_is_undefined = call_data_obj->IsUndefined(); | 7978 bool call_data_is_undefined = call_data_obj->IsUndefined(); |
8038 HValue* call_data = Add<HConstant>(call_data_obj); | 7979 HValue* call_data = Add<HConstant>(call_data_obj); |
8039 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback())); | 7980 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback())); |
8040 ExternalReference ref = ExternalReference(&fun, | 7981 ExternalReference ref = ExternalReference(&fun, |
8041 ExternalReference::DIRECT_API_CALL, | 7982 ExternalReference::DIRECT_API_CALL, |
8042 isolate()); | 7983 isolate()); |
8043 HValue* api_function_address = Add<HConstant>(ExternalReference(ref)); | 7984 HValue* api_function_address = Add<HConstant>(ExternalReference(ref)); |
8044 | 7985 |
8045 HValue* op_vals[] = { | 7986 HValue* op_vals[] = { |
8046 // callee | 7987 // callee |
8047 Add<HConstant>(expr->target()), | 7988 Add<HConstant>(expr->target()), |
8048 call_data, | 7989 call_data, |
8049 holder, | 7990 holder, |
8050 api_function_address, | 7991 api_function_address, |
8051 context() | 7992 context() |
8052 }; | 7993 }; |
8053 | 7994 |
8054 const int argc = expr->arguments()->length(); | |
8055 // Includes receiver. | |
8056 PushArgumentsFromEnvironment(argc + 1); | |
8057 | |
8058 CallInterfaceDescriptor* descriptor = | 7995 CallInterfaceDescriptor* descriptor = |
8059 isolate()->call_descriptor(Isolate::ApiFunctionCall); | 7996 isolate()->call_descriptor(Isolate::ApiFunctionCall); |
8060 | 7997 |
8061 CallApiFunctionStub stub(true, call_data_is_undefined, argc); | 7998 CallApiFunctionStub stub(true, call_data_is_undefined, argc); |
8062 Handle<Code> code = stub.GetCode(isolate()); | 7999 Handle<Code> code = stub.GetCode(isolate()); |
8063 HConstant* code_value = Add<HConstant>(code); | 8000 HConstant* code_value = Add<HConstant>(code); |
8064 | 8001 |
8065 ASSERT((sizeof(op_vals) / kPointerSize) == | 8002 ASSERT((sizeof(op_vals) / kPointerSize) == |
8066 descriptor->environment_length()); | 8003 descriptor->environment_length()); |
8067 | 8004 |
8068 HInstruction* call = New<HCallWithDescriptor>( | 8005 HInstruction* call = New<HCallWithDescriptor>( |
8069 code_value, argc + 1, descriptor, | 8006 code_value, argc + 1, descriptor, |
8070 Vector<HValue*>(op_vals, descriptor->environment_length())); | 8007 Vector<HValue*>(op_vals, descriptor->environment_length())); |
8071 | 8008 |
8072 if (drop_extra) Drop(1); // Drop function. | 8009 Drop(1); // Drop function. |
8073 ast_context()->ReturnInstruction(call, expr->id()); | 8010 ast_context()->ReturnInstruction(call, expr->id()); |
8074 return true; | 8011 return true; |
8075 } | 8012 } |
8076 | 8013 |
8077 | 8014 |
8078 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { | 8015 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
8079 Expression* callee = expr->expression(); | 8016 ASSERT(expr->expression()->IsProperty()); |
8080 Property* prop = callee->AsProperty(); | |
8081 ASSERT(prop != NULL); | |
8082 | 8017 |
8083 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { | 8018 if (!expr->IsMonomorphic()) { |
8084 return false; | 8019 return false; |
8085 } | 8020 } |
8086 Handle<Map> function_map = expr->GetReceiverTypes()->first(); | 8021 Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
8087 if (function_map->instance_type() != JS_FUNCTION_TYPE || | 8022 if (function_map->instance_type() != JS_FUNCTION_TYPE || |
8088 !expr->target()->shared()->HasBuiltinFunctionId() || | 8023 !expr->target()->shared()->HasBuiltinFunctionId() || |
8089 expr->target()->shared()->builtin_function_id() != kFunctionApply) { | 8024 expr->target()->shared()->builtin_function_id() != kFunctionApply) { |
8090 return false; | 8025 return false; |
8091 } | 8026 } |
8092 | 8027 |
8093 if (current_info()->scope()->arguments() == NULL) return false; | 8028 if (current_info()->scope()->arguments() == NULL) return false; |
8094 | 8029 |
8095 ZoneList<Expression*>* args = expr->arguments(); | 8030 ZoneList<Expression*>* args = expr->arguments(); |
8096 if (args->length() != 2) return false; | 8031 if (args->length() != 2) return false; |
8097 | 8032 |
8098 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 8033 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
8099 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | 8034 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
8100 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); | 8035 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); |
8101 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; | 8036 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
8102 | 8037 |
8103 // Found pattern f.apply(receiver, arguments). | 8038 // Found pattern f.apply(receiver, arguments). |
8104 CHECK_ALIVE_OR_RETURN(VisitForValue(prop->obj()), true); | |
8105 HValue* function = Top(); | |
8106 | |
8107 AddCheckConstantFunction(expr->holder(), function, function_map); | |
8108 | |
8109 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); | 8039 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); |
8110 HValue* receiver = Pop(); | 8040 HValue* receiver = Pop(); // receiver |
8111 | 8041 HValue* function = Pop(); // f |
8112 Drop(1); // Pop the function. | 8042 Drop(1); // apply |
8113 | 8043 |
8114 if (function_state()->outer() == NULL) { | 8044 if (function_state()->outer() == NULL) { |
8115 HInstruction* elements = Add<HArgumentsElements>(false); | 8045 HInstruction* elements = Add<HArgumentsElements>(false); |
8116 HInstruction* length = Add<HArgumentsLength>(elements); | 8046 HInstruction* length = Add<HArgumentsLength>(elements); |
8117 HValue* wrapped_receiver = BuildWrapReceiver(receiver, function); | 8047 HValue* wrapped_receiver = BuildWrapReceiver(receiver, function); |
8118 HInstruction* result = New<HApplyArguments>(function, | 8048 HInstruction* result = New<HApplyArguments>(function, |
8119 wrapped_receiver, | 8049 wrapped_receiver, |
8120 length, | 8050 length, |
8121 elements); | 8051 elements); |
8122 ast_context()->ReturnInstruction(result, expr->id()); | 8052 ast_context()->ReturnInstruction(result, expr->id()); |
8123 return true; | 8053 return true; |
8124 } else { | 8054 } else { |
8125 // We are inside inlined function and we know exactly what is inside | 8055 // We are inside inlined function and we know exactly what is inside |
8126 // arguments object. But we need to be able to materialize at deopt. | 8056 // arguments object. But we need to be able to materialize at deopt. |
8127 ASSERT_EQ(environment()->arguments_environment()->parameter_count(), | 8057 ASSERT_EQ(environment()->arguments_environment()->parameter_count(), |
8128 function_state()->entry()->arguments_object()->arguments_count()); | 8058 function_state()->entry()->arguments_object()->arguments_count()); |
8129 HArgumentsObject* args = function_state()->entry()->arguments_object(); | 8059 HArgumentsObject* args = function_state()->entry()->arguments_object(); |
8130 const ZoneList<HValue*>* arguments_values = args->arguments_values(); | 8060 const ZoneList<HValue*>* arguments_values = args->arguments_values(); |
8131 int arguments_count = arguments_values->length(); | 8061 int arguments_count = arguments_values->length(); |
| 8062 Push(function); |
8132 Push(BuildWrapReceiver(receiver, function)); | 8063 Push(BuildWrapReceiver(receiver, function)); |
8133 for (int i = 1; i < arguments_count; i++) { | 8064 for (int i = 1; i < arguments_count; i++) { |
8134 Push(arguments_values->at(i)); | 8065 Push(arguments_values->at(i)); |
8135 } | 8066 } |
8136 | 8067 |
8137 Handle<JSFunction> known_function; | 8068 Handle<JSFunction> known_function; |
8138 if (function->IsConstant() && | 8069 if (function->IsConstant() && |
8139 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { | 8070 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
8140 known_function = Handle<JSFunction>::cast( | 8071 known_function = Handle<JSFunction>::cast( |
8141 HConstant::cast(function)->handle(isolate())); | 8072 HConstant::cast(function)->handle(isolate())); |
8142 int args_count = arguments_count - 1; // Excluding receiver. | 8073 int args_count = arguments_count - 1; // Excluding receiver. |
8143 if (TryInlineApply(known_function, expr, args_count)) return true; | 8074 if (TryInlineApply(known_function, expr, args_count)) return true; |
8144 } | 8075 } |
8145 | 8076 |
8146 Drop(arguments_count - 1); | 8077 PushArgumentsFromEnvironment(arguments_count); |
8147 Push(Add<HPushArgument>(Pop())); | 8078 HInvokeFunction* call = New<HInvokeFunction>( |
8148 for (int i = 1; i < arguments_count; i++) { | 8079 function, known_function, arguments_count); |
8149 Push(Add<HPushArgument>(arguments_values->at(i))); | 8080 Drop(1); // Function. |
8150 } | |
8151 | |
8152 HInvokeFunction* call = New<HInvokeFunction>(function, | |
8153 known_function, | |
8154 arguments_count); | |
8155 Drop(arguments_count); | |
8156 ast_context()->ReturnInstruction(call, expr->id()); | 8081 ast_context()->ReturnInstruction(call, expr->id()); |
8157 return true; | 8082 return true; |
8158 } | 8083 } |
8159 } | 8084 } |
8160 | 8085 |
8161 | 8086 |
8162 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, | 8087 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, |
8163 Handle<JSFunction> target) { | 8088 Handle<JSFunction> target) { |
8164 SharedFunctionInfo* shared = target->shared(); | 8089 SharedFunctionInfo* shared = target->shared(); |
8165 if (shared->is_classic_mode() && !shared->native()) { | 8090 if (shared->is_classic_mode() && !shared->native()) { |
(...skipping 11 matching lines...) Expand all Loading... |
8177 void HOptimizedGraphBuilder::VisitCall(Call* expr) { | 8102 void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
8178 ASSERT(!HasStackOverflow()); | 8103 ASSERT(!HasStackOverflow()); |
8179 ASSERT(current_block() != NULL); | 8104 ASSERT(current_block() != NULL); |
8180 ASSERT(current_block()->HasPredecessor()); | 8105 ASSERT(current_block()->HasPredecessor()); |
8181 Expression* callee = expr->expression(); | 8106 Expression* callee = expr->expression(); |
8182 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 8107 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
8183 HInstruction* call = NULL; | 8108 HInstruction* call = NULL; |
8184 | 8109 |
8185 Property* prop = callee->AsProperty(); | 8110 Property* prop = callee->AsProperty(); |
8186 if (prop != NULL) { | 8111 if (prop != NULL) { |
8187 if (!prop->key()->IsPropertyName()) { | 8112 CHECK_ALIVE(VisitForValue(prop->obj())); |
8188 // Keyed function call. | 8113 HValue* receiver = Top(); |
8189 CHECK_ALIVE(VisitForValue(prop->obj())); | |
8190 CHECK_ALIVE(VisitForValue(prop->key())); | |
8191 | 8114 |
8192 // Push receiver and key like the non-optimized code generator expects it. | 8115 SmallMapList* types; |
8193 HValue* key = Pop(); | 8116 ComputeReceiverTypes(expr, receiver, &types); |
8194 HValue* receiver = Pop(); | |
8195 Push(key); | |
8196 Push(Add<HPushArgument>(receiver)); | |
8197 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | |
8198 | 8117 |
8199 if (expr->IsMonomorphic()) { | 8118 if (prop->key()->IsPropertyName() && types->length() > 0) { |
8200 BuildCheckHeapObject(receiver); | 8119 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
8201 ElementsKind kind = expr->KeyedArrayCallIsHoley() | 8120 PropertyAccessInfo info(this, IC::MapToType(types->first()), name); |
8202 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS; | 8121 if (!info.CanLoadAsMonomorphic(types)) { |
8203 | 8122 HandlePolymorphicCallNamed(expr, receiver, types, name); |
8204 Handle<Map> map(isolate()->get_initial_js_array_map(kind)); | 8123 return; |
8205 | |
8206 HValue* function = BuildMonomorphicElementAccess( | |
8207 receiver, key, NULL, NULL, map, false, STANDARD_STORE); | |
8208 | |
8209 call = New<HCallFunction>(function, argument_count); | |
8210 } else { | |
8211 call = NewCallKeyed(key, argument_count); | |
8212 } | 8124 } |
8213 Drop(argument_count + 1); // 1 is the key. | |
8214 return ast_context()->ReturnInstruction(call, expr->id()); | |
8215 } | 8125 } |
8216 | 8126 |
8217 // Named function call. | 8127 HValue* key = NULL; |
8218 if (TryCallApply(expr)) return; | 8128 if (!prop->key()->IsPropertyName()) { |
8219 | 8129 CHECK_ALIVE(VisitForValue(prop->key())); |
8220 CHECK_ALIVE(VisitForValue(prop->obj())); | 8130 key = Pop(); |
8221 CHECK_ALIVE(VisitExpressions(expr->arguments())); | |
8222 | |
8223 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | |
8224 HValue* receiver = | |
8225 environment()->ExpressionStackAt(expr->arguments()->length()); | |
8226 | |
8227 SmallMapList* types; | |
8228 bool was_monomorphic = expr->IsMonomorphic(); | |
8229 bool monomorphic = ComputeReceiverTypes(expr, receiver, &types); | |
8230 if (!was_monomorphic && monomorphic) { | |
8231 monomorphic = expr->ComputeTarget(types->first(), name); | |
8232 } | 8131 } |
8233 | 8132 |
8234 if (monomorphic) { | 8133 CHECK_ALIVE(PushLoad(prop, receiver, key)); |
8235 Handle<Map> map = types->first(); | 8134 HValue* function = Pop(); |
8236 if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) { | 8135 |
| 8136 // Push the function under the receiver. |
| 8137 environment()->SetExpressionStackAt(0, function); |
| 8138 |
| 8139 Push(receiver); |
| 8140 |
| 8141 if (function->IsConstant() && |
| 8142 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
| 8143 Handle<JSFunction> known_function = Handle<JSFunction>::cast( |
| 8144 HConstant::cast(function)->handle(isolate())); |
| 8145 expr->set_target(known_function); |
| 8146 |
| 8147 if (TryCallApply(expr)) return; |
| 8148 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 8149 |
| 8150 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); |
| 8151 if (TryInlineBuiltinMethodCall(expr, receiver, map)) { |
8237 if (FLAG_trace_inlining) { | 8152 if (FLAG_trace_inlining) { |
8238 PrintF("Inlining builtin "); | 8153 PrintF("Inlining builtin "); |
8239 expr->target()->ShortPrint(); | 8154 known_function->ShortPrint(); |
8240 PrintF("\n"); | 8155 PrintF("\n"); |
8241 } | 8156 } |
8242 return; | 8157 return; |
8243 } | 8158 } |
8244 if (TryInlineApiMethodCall(expr, receiver, map)) return; | 8159 if (TryInlineApiMethodCall(expr, receiver, map)) return; |
8245 | 8160 |
8246 if (expr->check_type() != RECEIVER_MAP_CHECK) { | 8161 // Wrap the receiver if necessary. |
8247 call = NewCallNamed(name, argument_count); | 8162 if (NeedsWrappingFor(IC::MapToType(types->first()), known_function)) { |
8248 PushArgumentsFromEnvironment(argument_count); | 8163 // Since HWrapReceiver currently cannot actually wrap numbers and |
| 8164 // strings, use the regular CallFunctionStub for method calls to wrap |
| 8165 // the receiver. |
| 8166 // TODO(verwaest): Support creation of value wrappers directly in |
| 8167 // HWrapReceiver. |
| 8168 call = New<HCallFunction>( |
| 8169 function, argument_count, WRAP_AND_CALL); |
| 8170 } else if (TryInlineCall(expr)) { |
| 8171 return; |
8249 } else { | 8172 } else { |
8250 AddCheckConstantFunction(expr->holder(), receiver, map); | 8173 call = BuildCallConstantFunction(known_function, argument_count); |
8251 | |
8252 if (TryInlineCall(expr)) return; | |
8253 call = BuildCallConstantFunction(expr->target(), argument_count); | |
8254 PushArgumentsFromEnvironment(argument_count); | |
8255 } | 8174 } |
8256 } else if (types != NULL && types->length() > 1) { | |
8257 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | |
8258 HandlePolymorphicCallNamed(expr, receiver, types, name); | |
8259 return; | |
8260 | 8175 |
8261 } else { | 8176 } else { |
8262 call = NewCallNamed(name, argument_count); | 8177 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
8263 PushArgumentsFromEnvironment(argument_count); | 8178 CallFunctionFlags flags = receiver->type().IsJSObject() |
| 8179 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; |
| 8180 call = New<HCallFunction>(function, argument_count, flags); |
8264 } | 8181 } |
| 8182 PushArgumentsFromEnvironment(argument_count); |
| 8183 |
8265 } else { | 8184 } else { |
8266 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 8185 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
8267 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { | 8186 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { |
8268 return Bailout(kPossibleDirectCallToEval); | 8187 return Bailout(kPossibleDirectCallToEval); |
8269 } | 8188 } |
8270 | 8189 |
8271 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); | 8190 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); |
8272 if (global_call) { | 8191 if (global_call) { |
8273 Variable* var = proxy->var(); | 8192 Variable* var = proxy->var(); |
8274 bool known_global_function = false; | 8193 bool known_global_function = false; |
8275 // If there is a global property cell for the name at compile time and | 8194 // If there is a global property cell for the name at compile time and |
8276 // access check is not enabled we assume that the function will not change | 8195 // access check is not enabled we assume that the function will not change |
8277 // and generate optimized code for calling the function. | 8196 // and generate optimized code for calling the function. |
8278 LookupResult lookup(isolate()); | 8197 LookupResult lookup(isolate()); |
8279 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); | 8198 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); |
8280 if (type == kUseCell && | 8199 if (type == kUseCell && |
8281 !current_info()->global_object()->IsAccessCheckNeeded()) { | 8200 !current_info()->global_object()->IsAccessCheckNeeded()) { |
8282 Handle<GlobalObject> global(current_info()->global_object()); | 8201 Handle<GlobalObject> global(current_info()->global_object()); |
8283 known_global_function = expr->ComputeGlobalTarget(global, &lookup); | 8202 known_global_function = expr->ComputeGlobalTarget(global, &lookup); |
8284 } | 8203 } |
| 8204 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 8205 HValue* function = Top(); |
8285 if (known_global_function) { | 8206 if (known_global_function) { |
8286 // Push the global object instead of the global receiver because | 8207 Add<HCheckValue>(function, expr->target()); |
8287 // code generated by the full code generator expects it. | |
8288 HValue* global_object = Add<HLoadNamedField>( | |
8289 context(), static_cast<HValue*>(NULL), | |
8290 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | |
8291 Push(global_object); | |
8292 | 8208 |
| 8209 // Placeholder for the receiver. |
| 8210 Push(graph()->GetConstantUndefined()); |
8293 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8211 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
8294 | 8212 |
8295 CHECK_ALIVE(VisitForValue(expr->expression())); | |
8296 HValue* function = Pop(); | |
8297 Add<HCheckValue>(function, expr->target()); | |
8298 | |
8299 // Patch the global object on the stack by the expected receiver. | 8213 // Patch the global object on the stack by the expected receiver. |
8300 HValue* receiver = ImplicitReceiverFor(function, expr->target()); | 8214 HValue* receiver = ImplicitReceiverFor(function, expr->target()); |
8301 const int receiver_index = argument_count - 1; | 8215 const int receiver_index = argument_count - 1; |
8302 environment()->SetExpressionStackAt(receiver_index, receiver); | 8216 environment()->SetExpressionStackAt(receiver_index, receiver); |
8303 | 8217 |
8304 if (TryInlineBuiltinFunctionCall(expr, false)) { // Nothing to drop. | 8218 if (TryInlineBuiltinFunctionCall(expr)) { |
8305 if (FLAG_trace_inlining) { | 8219 if (FLAG_trace_inlining) { |
8306 PrintF("Inlining builtin "); | 8220 PrintF("Inlining builtin "); |
8307 expr->target()->ShortPrint(); | 8221 expr->target()->ShortPrint(); |
8308 PrintF("\n"); | 8222 PrintF("\n"); |
8309 } | 8223 } |
8310 return; | 8224 return; |
8311 } | 8225 } |
8312 if (TryInlineApiFunctionCall(expr, receiver, false)) return; | 8226 if (TryInlineApiFunctionCall(expr, receiver)) return; |
8313 if (TryInlineCall(expr)) return; | 8227 if (TryInlineCall(expr)) return; |
8314 | 8228 |
8315 if (expr->target().is_identical_to(current_info()->closure())) { | 8229 PushArgumentsFromEnvironment(argument_count); |
8316 graph()->MarkRecursive(); | |
8317 } | |
8318 | |
8319 call = BuildCallConstantFunction(expr->target(), argument_count); | 8230 call = BuildCallConstantFunction(expr->target(), argument_count); |
8320 PushArgumentsFromEnvironment(argument_count); | |
8321 } else { | 8231 } else { |
8322 HValue* receiver = Add<HLoadNamedField>( | 8232 Push(Add<HPushArgument>(graph()->GetConstantUndefined())); |
8323 context(), static_cast<HValue*>(NULL), | |
8324 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | |
8325 Push(Add<HPushArgument>(receiver)); | |
8326 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 8233 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
8327 | 8234 call = New<HCallFunction>(function, argument_count); |
8328 call = NewCallNamed(var->name(), argument_count); | |
8329 Drop(argument_count); | 8235 Drop(argument_count); |
8330 } | 8236 } |
8331 | 8237 |
8332 } else if (expr->IsMonomorphic()) { | 8238 } else if (expr->IsMonomorphic()) { |
8333 // The function is on the stack in the unoptimized code during | 8239 // The function is on the stack in the unoptimized code during |
8334 // evaluation of the arguments. | 8240 // evaluation of the arguments. |
8335 CHECK_ALIVE(VisitForValue(expr->expression())); | 8241 CHECK_ALIVE(VisitForValue(expr->expression())); |
8336 HValue* function = Top(); | 8242 HValue* function = Top(); |
8337 | 8243 |
8338 Add<HCheckValue>(function, expr->target()); | 8244 Add<HCheckValue>(function, expr->target()); |
8339 | 8245 |
8340 HValue* receiver = ImplicitReceiverFor(function, expr->target()); | 8246 Push(graph()->GetConstantUndefined()); |
8341 Push(receiver); | |
8342 | |
8343 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8247 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
8344 | 8248 |
8345 if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function. | 8249 HValue* receiver = ImplicitReceiverFor(function, expr->target()); |
| 8250 const int receiver_index = argument_count - 1; |
| 8251 environment()->SetExpressionStackAt(receiver_index, receiver); |
| 8252 |
| 8253 if (TryInlineBuiltinFunctionCall(expr)) { |
8346 if (FLAG_trace_inlining) { | 8254 if (FLAG_trace_inlining) { |
8347 PrintF("Inlining builtin "); | 8255 PrintF("Inlining builtin "); |
8348 expr->target()->ShortPrint(); | 8256 expr->target()->ShortPrint(); |
8349 PrintF("\n"); | 8257 PrintF("\n"); |
8350 } | 8258 } |
8351 return; | 8259 return; |
8352 } | 8260 } |
8353 if (TryInlineApiFunctionCall(expr, receiver, true)) return; | 8261 if (TryInlineApiFunctionCall(expr, receiver)) return; |
8354 | 8262 |
8355 if (TryInlineCall(expr, true)) { // Drop function from environment. | 8263 if (TryInlineCall(expr)) return; |
8356 return; | 8264 |
8357 } else { | 8265 call = PreProcessCall(New<HInvokeFunction>( |
8358 call = PreProcessCall(New<HInvokeFunction>(function, expr->target(), | 8266 function, expr->target(), argument_count)); |
8359 argument_count)); | |
8360 Drop(1); // The function. | |
8361 } | |
8362 | 8267 |
8363 } else { | 8268 } else { |
8364 CHECK_ALIVE(VisitForValue(expr->expression())); | 8269 CHECK_ALIVE(VisitForValue(expr->expression())); |
8365 HValue* function = Top(); | 8270 HValue* function = Top(); |
8366 HValue* receiver = graph()->GetConstantUndefined(); | 8271 HValue* receiver = graph()->GetConstantUndefined(); |
8367 Push(Add<HPushArgument>(receiver)); | 8272 Push(Add<HPushArgument>(receiver)); |
8368 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 8273 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
8369 call = New<HCallFunction>( | 8274 call = New<HCallFunction>(function, argument_count); |
8370 function, argument_count, NORMAL_CONTEXTUAL_CALL); | 8275 Drop(argument_count); |
8371 Drop(argument_count + 1); | |
8372 } | 8276 } |
8373 } | 8277 } |
8374 | 8278 |
| 8279 Drop(1); // Drop the function. |
8375 return ast_context()->ReturnInstruction(call, expr->id()); | 8280 return ast_context()->ReturnInstruction(call, expr->id()); |
8376 } | 8281 } |
8377 | 8282 |
8378 | 8283 |
8379 void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { | 8284 void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { |
8380 NoObservableSideEffectsScope no_effects(this); | 8285 NoObservableSideEffectsScope no_effects(this); |
8381 | 8286 |
8382 int argument_count = expr->arguments()->length(); | 8287 int argument_count = expr->arguments()->length(); |
8383 // We should at least have the constructor on the expression stack. | 8288 // We should at least have the constructor on the expression stack. |
8384 HValue* constructor = environment()->ExpressionStackAt(argument_count); | 8289 HValue* constructor = environment()->ExpressionStackAt(argument_count); |
(...skipping 3075 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11460 if (ShouldProduceTraceOutput()) { | 11365 if (ShouldProduceTraceOutput()) { |
11461 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 11366 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
11462 } | 11367 } |
11463 | 11368 |
11464 #ifdef DEBUG | 11369 #ifdef DEBUG |
11465 graph_->Verify(false); // No full verify. | 11370 graph_->Verify(false); // No full verify. |
11466 #endif | 11371 #endif |
11467 } | 11372 } |
11468 | 11373 |
11469 } } // namespace v8::internal | 11374 } } // namespace v8::internal |
OLD | NEW |