| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/hydrogen.h" | 5 #include "src/hydrogen.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "src/v8.h" | 9 #include "src/v8.h" |
| 10 | 10 |
| (...skipping 7909 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7920 if (TryInlineApiSetter(setter, receiver_map, id)) return true; | 7920 if (TryInlineApiSetter(setter, receiver_map, id)) return true; |
| 7921 return TryInline(setter, | 7921 return TryInline(setter, |
| 7922 1, | 7922 1, |
| 7923 implicit_return_value, | 7923 implicit_return_value, |
| 7924 id, assignment_id, | 7924 id, assignment_id, |
| 7925 SETTER_CALL_RETURN, | 7925 SETTER_CALL_RETURN, |
| 7926 source_position()); | 7926 source_position()); |
| 7927 } | 7927 } |
| 7928 | 7928 |
| 7929 | 7929 |
| 7930 bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, | 7930 bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function, |
| 7931 Call* expr, | 7931 Call* expr, |
| 7932 int arguments_count) { | 7932 int arguments_count) { |
| 7933 return TryInline(function, | 7933 return TryInline(function, |
| 7934 arguments_count, | 7934 arguments_count, |
| 7935 NULL, | 7935 NULL, |
| 7936 expr->id(), | 7936 expr->id(), |
| 7937 expr->ReturnId(), | 7937 expr->ReturnId(), |
| 7938 NORMAL_RETURN, | 7938 NORMAL_RETURN, |
| 7939 ScriptPositionToSourcePosition(expr->position())); | 7939 ScriptPositionToSourcePosition(expr->position())); |
| 7940 } | 7940 } |
| 7941 | 7941 |
| 7942 | 7942 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7974 default: | 7974 default: |
| 7975 // Not supported for inlining yet. | 7975 // Not supported for inlining yet. |
| 7976 break; | 7976 break; |
| 7977 } | 7977 } |
| 7978 return false; | 7978 return false; |
| 7979 } | 7979 } |
| 7980 | 7980 |
| 7981 | 7981 |
| 7982 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( | 7982 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
| 7983 Call* expr, | 7983 Call* expr, |
| 7984 HValue* receiver, | 7984 Handle<JSFunction> function, |
| 7985 Handle<Map> receiver_map) { | 7985 Handle<Map> receiver_map, |
| 7986 int args_count_no_receiver, |
| 7987 int drop_extra) { |
| 7988 if (!function->shared()->HasBuiltinFunctionId()) return false; |
| 7989 BuiltinFunctionId id = function->shared()->builtin_function_id(); |
| 7990 int argument_count = args_count_no_receiver + 1; // Plus receiver. |
| 7991 |
| 7992 if (receiver_map.is_null()) { |
| 7993 HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver); |
| 7994 if (receiver->IsConstant() && |
| 7995 HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) { |
| 7996 receiver_map = handle(Handle<HeapObject>::cast( |
| 7997 HConstant::cast(receiver)->handle(isolate()))->map()); |
| 7998 } |
| 7999 } |
| 7986 // Try to inline calls like Math.* as operations in the calling function. | 8000 // Try to inline calls like Math.* as operations in the calling function. |
| 7987 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | |
| 7988 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | |
| 7989 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | |
| 7990 switch (id) { | 8001 switch (id) { |
| 7991 case kStringCharCodeAt: | 8002 case kStringCharCodeAt: |
| 7992 case kStringCharAt: | 8003 case kStringCharAt: |
| 7993 if (argument_count == 2) { | 8004 if (argument_count == 2) { |
| 7994 HValue* index = Pop(); | 8005 HValue* index = Pop(); |
| 7995 HValue* string = Pop(); | 8006 HValue* string = Pop(); |
| 7996 Drop(1); // Function. | 8007 Drop(1 + drop_extra); // Function + extra. |
| 7997 HInstruction* char_code = | 8008 HInstruction* char_code = |
| 7998 BuildStringCharCodeAt(string, index); | 8009 BuildStringCharCodeAt(string, index); |
| 7999 if (id == kStringCharCodeAt) { | 8010 if (id == kStringCharCodeAt) { |
| 8000 ast_context()->ReturnInstruction(char_code, expr->id()); | 8011 ast_context()->ReturnInstruction(char_code, expr->id()); |
| 8001 return true; | 8012 return true; |
| 8002 } | 8013 } |
| 8003 AddInstruction(char_code); | 8014 AddInstruction(char_code); |
| 8004 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code); | 8015 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code); |
| 8005 ast_context()->ReturnInstruction(result, expr->id()); | 8016 ast_context()->ReturnInstruction(result, expr->id()); |
| 8006 return true; | 8017 return true; |
| 8007 } | 8018 } |
| 8008 break; | 8019 break; |
| 8009 case kStringFromCharCode: | 8020 case kStringFromCharCode: |
| 8010 if (argument_count == 2) { | 8021 if (argument_count == 2) { |
| 8011 HValue* argument = Pop(); | 8022 HValue* argument = Pop(); |
| 8012 Drop(2); // Receiver and function. | 8023 Drop(2 + drop_extra); // Receiver and function + extra. |
| 8013 HInstruction* result = NewUncasted<HStringCharFromCode>(argument); | 8024 HInstruction* result = NewUncasted<HStringCharFromCode>(argument); |
| 8014 ast_context()->ReturnInstruction(result, expr->id()); | 8025 ast_context()->ReturnInstruction(result, expr->id()); |
| 8015 return true; | 8026 return true; |
| 8016 } | 8027 } |
| 8017 break; | 8028 break; |
| 8018 case kMathExp: | 8029 case kMathExp: |
| 8019 if (!FLAG_fast_math) break; | 8030 if (!FLAG_fast_math) break; |
| 8020 // Fall through if FLAG_fast_math. | 8031 // Fall through if FLAG_fast_math. |
| 8021 case kMathRound: | 8032 case kMathRound: |
| 8022 case kMathFloor: | 8033 case kMathFloor: |
| 8023 case kMathAbs: | 8034 case kMathAbs: |
| 8024 case kMathSqrt: | 8035 case kMathSqrt: |
| 8025 case kMathLog: | 8036 case kMathLog: |
| 8026 case kMathClz32: | 8037 case kMathClz32: |
| 8027 if (argument_count == 2) { | 8038 if (argument_count == 2) { |
| 8028 HValue* argument = Pop(); | 8039 HValue* argument = Pop(); |
| 8029 Drop(2); // Receiver and function. | 8040 Drop(2 + drop_extra); // Receiver and function + extra. |
| 8030 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 8041 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
| 8031 ast_context()->ReturnInstruction(op, expr->id()); | 8042 ast_context()->ReturnInstruction(op, expr->id()); |
| 8032 return true; | 8043 return true; |
| 8033 } | 8044 } |
| 8034 break; | 8045 break; |
| 8035 case kMathPow: | 8046 case kMathPow: |
| 8036 if (argument_count == 3) { | 8047 if (argument_count == 3) { |
| 8037 HValue* right = Pop(); | 8048 HValue* right = Pop(); |
| 8038 HValue* left = Pop(); | 8049 HValue* left = Pop(); |
| 8039 Drop(2); // Receiver and function. | 8050 Drop(2 + drop_extra); // Receiver and function + extra. |
| 8040 HInstruction* result = NULL; | 8051 HInstruction* result = NULL; |
| 8041 // Use sqrt() if exponent is 0.5 or -0.5. | 8052 // Use sqrt() if exponent is 0.5 or -0.5. |
| 8042 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { | 8053 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
| 8043 double exponent = HConstant::cast(right)->DoubleValue(); | 8054 double exponent = HConstant::cast(right)->DoubleValue(); |
| 8044 if (exponent == 0.5) { | 8055 if (exponent == 0.5) { |
| 8045 result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf); | 8056 result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf); |
| 8046 } else if (exponent == -0.5) { | 8057 } else if (exponent == -0.5) { |
| 8047 HValue* one = graph()->GetConstant1(); | 8058 HValue* one = graph()->GetConstant1(); |
| 8048 HInstruction* sqrt = AddUncasted<HUnaryMathOperation>( | 8059 HInstruction* sqrt = AddUncasted<HUnaryMathOperation>( |
| 8049 left, kMathPowHalf); | 8060 left, kMathPowHalf); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 8061 } | 8072 } |
| 8062 ast_context()->ReturnInstruction(result, expr->id()); | 8073 ast_context()->ReturnInstruction(result, expr->id()); |
| 8063 return true; | 8074 return true; |
| 8064 } | 8075 } |
| 8065 break; | 8076 break; |
| 8066 case kMathMax: | 8077 case kMathMax: |
| 8067 case kMathMin: | 8078 case kMathMin: |
| 8068 if (argument_count == 3) { | 8079 if (argument_count == 3) { |
| 8069 HValue* right = Pop(); | 8080 HValue* right = Pop(); |
| 8070 HValue* left = Pop(); | 8081 HValue* left = Pop(); |
| 8071 Drop(2); // Receiver and function. | 8082 Drop(2 + drop_extra); // Receiver and function + extra. |
| 8072 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin | 8083 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin |
| 8073 : HMathMinMax::kMathMax; | 8084 : HMathMinMax::kMathMax; |
| 8074 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); | 8085 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); |
| 8075 ast_context()->ReturnInstruction(result, expr->id()); | 8086 ast_context()->ReturnInstruction(result, expr->id()); |
| 8076 return true; | 8087 return true; |
| 8077 } | 8088 } |
| 8078 break; | 8089 break; |
| 8079 case kMathImul: | 8090 case kMathImul: |
| 8080 if (argument_count == 3) { | 8091 if (argument_count == 3) { |
| 8081 HValue* right = Pop(); | 8092 HValue* right = Pop(); |
| 8082 HValue* left = Pop(); | 8093 HValue* left = Pop(); |
| 8083 Drop(2); // Receiver and function. | 8094 Drop(2 + drop_extra); // Receiver and function + extra. |
| 8084 HInstruction* result = HMul::NewImul(zone(), context(), left, right); | 8095 HInstruction* result = HMul::NewImul(zone(), context(), left, right); |
| 8085 ast_context()->ReturnInstruction(result, expr->id()); | 8096 ast_context()->ReturnInstruction(result, expr->id()); |
| 8086 return true; | 8097 return true; |
| 8087 } | 8098 } |
| 8088 break; | 8099 break; |
| 8089 case kArrayPop: { | 8100 case kArrayPop: { |
| 8090 if (receiver_map.is_null()) return false; | 8101 if (receiver_map.is_null()) return false; |
| 8091 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; | 8102 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; |
| 8092 ElementsKind elements_kind = receiver_map->elements_kind(); | 8103 ElementsKind elements_kind = receiver_map->elements_kind(); |
| 8093 if (!IsFastElementsKind(elements_kind)) return false; | 8104 if (!IsFastElementsKind(elements_kind)) return false; |
| 8094 if (receiver_map->is_observed()) return false; | 8105 if (receiver_map->is_observed()) return false; |
| 8095 ASSERT(receiver_map->is_extensible()); | 8106 ASSERT(receiver_map->is_extensible()); |
| 8096 | 8107 |
| 8097 Drop(expr->arguments()->length()); | 8108 Drop(args_count_no_receiver); |
| 8098 HValue* result; | 8109 HValue* result; |
| 8099 HValue* reduced_length; | 8110 HValue* reduced_length; |
| 8100 HValue* receiver = Pop(); | 8111 HValue* receiver = Pop(); |
| 8101 | 8112 |
| 8102 HValue* checked_object = AddCheckMap(receiver, receiver_map); | 8113 HValue* checked_object = AddCheckMap(receiver, receiver_map); |
| 8103 HValue* length = Add<HLoadNamedField>( | 8114 HValue* length = Add<HLoadNamedField>( |
| 8104 checked_object, static_cast<HValue*>(NULL), | 8115 checked_object, static_cast<HValue*>(NULL), |
| 8105 HObjectAccess::ForArrayLength(elements_kind)); | 8116 HObjectAccess::ForArrayLength(elements_kind)); |
| 8106 | 8117 |
| 8107 Drop(1); // Function. | 8118 Drop(1 + drop_extra); // Function + extra. |
| 8108 | 8119 |
| 8109 { NoObservableSideEffectsScope scope(this); | 8120 { NoObservableSideEffectsScope scope(this); |
| 8110 IfBuilder length_checker(this); | 8121 IfBuilder length_checker(this); |
| 8111 | 8122 |
| 8112 HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>( | 8123 HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>( |
| 8113 length, graph()->GetConstant0(), Token::EQ); | 8124 length, graph()->GetConstant0(), Token::EQ); |
| 8114 length_checker.Then(); | 8125 length_checker.Then(); |
| 8115 | 8126 |
| 8116 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); | 8127 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); |
| 8117 | 8128 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8163 // inlined version can't be used. | 8174 // inlined version can't be used. |
| 8164 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false; | 8175 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false; |
| 8165 // If there currently can be no elements accessors on the prototype chain, | 8176 // If there currently can be no elements accessors on the prototype chain, |
| 8166 // it doesn't mean that there won't be any later. Install a full prototype | 8177 // it doesn't mean that there won't be any later. Install a full prototype |
| 8167 // chain check to trap element accessors being installed on the prototype | 8178 // chain check to trap element accessors being installed on the prototype |
| 8168 // chain, which would cause elements to go to dictionary mode and result | 8179 // chain, which would cause elements to go to dictionary mode and result |
| 8169 // in a map change. | 8180 // in a map change. |
| 8170 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); | 8181 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); |
| 8171 BuildCheckPrototypeMaps(prototype, Handle<JSObject>()); | 8182 BuildCheckPrototypeMaps(prototype, Handle<JSObject>()); |
| 8172 | 8183 |
| 8173 const int argc = expr->arguments()->length(); | 8184 const int argc = args_count_no_receiver; |
| 8174 if (argc != 1) return false; | 8185 if (argc != 1) return false; |
| 8175 | 8186 |
| 8176 HValue* value_to_push = Pop(); | 8187 HValue* value_to_push = Pop(); |
| 8177 HValue* array = Pop(); | 8188 HValue* array = Pop(); |
| 8178 Drop(1); // Drop function. | 8189 Drop(1 + drop_extra); // Drop function + extra. |
| 8179 | 8190 |
| 8180 HInstruction* new_size = NULL; | 8191 HInstruction* new_size = NULL; |
| 8181 HValue* length = NULL; | 8192 HValue* length = NULL; |
| 8182 | 8193 |
| 8183 { | 8194 { |
| 8184 NoObservableSideEffectsScope scope(this); | 8195 NoObservableSideEffectsScope scope(this); |
| 8185 | 8196 |
| 8186 length = Add<HLoadNamedField>(array, static_cast<HValue*>(NULL), | 8197 length = Add<HLoadNamedField>(array, static_cast<HValue*>(NULL), |
| 8187 HObjectAccess::ForArrayLength(elements_kind)); | 8198 HObjectAccess::ForArrayLength(elements_kind)); |
| 8188 | 8199 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8220 // chain check to trap element accessors being installed on the prototype | 8231 // chain check to trap element accessors being installed on the prototype |
| 8221 // chain, which would cause elements to go to dictionary mode and result | 8232 // chain, which would cause elements to go to dictionary mode and result |
| 8222 // in a map change. | 8233 // in a map change. |
| 8223 BuildCheckPrototypeMaps( | 8234 BuildCheckPrototypeMaps( |
| 8224 handle(JSObject::cast(receiver_map->prototype()), isolate()), | 8235 handle(JSObject::cast(receiver_map->prototype()), isolate()), |
| 8225 Handle<JSObject>::null()); | 8236 Handle<JSObject>::null()); |
| 8226 | 8237 |
| 8227 // Threshold for fast inlined Array.shift(). | 8238 // Threshold for fast inlined Array.shift(). |
| 8228 HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16)); | 8239 HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16)); |
| 8229 | 8240 |
| 8230 Drop(expr->arguments()->length()); | 8241 Drop(args_count_no_receiver); |
| 8231 HValue* receiver = Pop(); | 8242 HValue* receiver = Pop(); |
| 8232 HValue* function = Pop(); | 8243 HValue* function = Pop(); |
| 8244 Drop(drop_extra); // Drop extras after function. |
| 8233 HValue* result; | 8245 HValue* result; |
| 8234 | 8246 |
| 8235 { | 8247 { |
| 8236 NoObservableSideEffectsScope scope(this); | 8248 NoObservableSideEffectsScope scope(this); |
| 8237 | 8249 |
| 8238 HValue* length = Add<HLoadNamedField>( | 8250 HValue* length = Add<HLoadNamedField>( |
| 8239 receiver, static_cast<HValue*>(NULL), | 8251 receiver, static_cast<HValue*>(NULL), |
| 8240 HObjectAccess::ForArrayLength(kind)); | 8252 HObjectAccess::ForArrayLength(kind)); |
| 8241 | 8253 |
| 8242 IfBuilder if_lengthiszero(this); | 8254 IfBuilder if_lengthiszero(this); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8334 // it doesn't mean that there won't be any later. Install a full prototype | 8346 // it doesn't mean that there won't be any later. Install a full prototype |
| 8335 // chain check to trap element accessors being installed on the prototype | 8347 // chain check to trap element accessors being installed on the prototype |
| 8336 // chain, which would cause elements to go to dictionary mode and result | 8348 // chain, which would cause elements to go to dictionary mode and result |
| 8337 // in a map change. | 8349 // in a map change. |
| 8338 BuildCheckPrototypeMaps( | 8350 BuildCheckPrototypeMaps( |
| 8339 handle(JSObject::cast(receiver_map->prototype()), isolate()), | 8351 handle(JSObject::cast(receiver_map->prototype()), isolate()), |
| 8340 Handle<JSObject>::null()); | 8352 Handle<JSObject>::null()); |
| 8341 | 8353 |
| 8342 HValue* search_element = Pop(); | 8354 HValue* search_element = Pop(); |
| 8343 HValue* receiver = Pop(); | 8355 HValue* receiver = Pop(); |
| 8344 Drop(1); // Drop function. | 8356 Drop(1 + drop_extra); // Drop function + extra. |
| 8345 | 8357 |
| 8346 ArrayIndexOfMode mode = (id == kArrayIndexOf) | 8358 ArrayIndexOfMode mode = (id == kArrayIndexOf) |
| 8347 ? kFirstIndexOf : kLastIndexOf; | 8359 ? kFirstIndexOf : kLastIndexOf; |
| 8348 HValue* index = BuildArrayIndexOf(receiver, search_element, kind, mode); | 8360 HValue* index = BuildArrayIndexOf(receiver, search_element, kind, mode); |
| 8349 | 8361 |
| 8350 if (!ast_context()->IsEffect()) Push(index); | 8362 if (!ast_context()->IsEffect()) Push(index); |
| 8351 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 8363 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| 8352 if (!ast_context()->IsEffect()) Drop(1); | 8364 if (!ast_context()->IsEffect()) Drop(1); |
| 8353 ast_context()->ReturnValue(index); | 8365 ast_context()->ReturnValue(index); |
| 8354 return true; | 8366 return true; |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8531 HInstruction* call = New<HCallWithDescriptor>( | 8543 HInstruction* call = New<HCallWithDescriptor>( |
| 8532 code_value, argc + 1, descriptor, | 8544 code_value, argc + 1, descriptor, |
| 8533 Vector<HValue*>(op_vals, descriptor->environment_length())); | 8545 Vector<HValue*>(op_vals, descriptor->environment_length())); |
| 8534 | 8546 |
| 8535 if (drop_extra) Drop(1); // Drop function. | 8547 if (drop_extra) Drop(1); // Drop function. |
| 8536 ast_context()->ReturnInstruction(call, ast_id); | 8548 ast_context()->ReturnInstruction(call, ast_id); |
| 8537 return true; | 8549 return true; |
| 8538 } | 8550 } |
| 8539 | 8551 |
| 8540 | 8552 |
| 8541 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { | 8553 void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, |
| 8554 HValue* function, |
| 8555 int arguments_count, |
| 8556 int drop_extra) { |
| 8557 Handle<JSFunction> known_function; |
| 8558 int args_count_no_receiver = arguments_count - 1; |
| 8559 if (function->IsConstant() && |
| 8560 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
| 8561 known_function = Handle<JSFunction>::cast( |
| 8562 HConstant::cast(function)->handle(isolate())); |
| 8563 if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) { |
| 8564 Drop(drop_extra); |
| 8565 return; |
| 8566 } |
| 8567 |
| 8568 Handle<Map> map; |
| 8569 if (TryInlineBuiltinMethodCall(expr, known_function, map, |
| 8570 args_count_no_receiver, drop_extra)) { |
| 8571 if (FLAG_trace_inlining) { |
| 8572 PrintF("Inlining builtin "); |
| 8573 known_function->ShortPrint(); |
| 8574 PrintF("\n"); |
| 8575 } |
| 8576 return; |
| 8577 } |
| 8578 } |
| 8579 |
| 8580 PushArgumentsFromEnvironment(arguments_count); |
| 8581 HInvokeFunction* call = New<HInvokeFunction>( |
| 8582 function, known_function, arguments_count); |
| 8583 Drop(1 + drop_extra); // Function + extra. |
| 8584 ast_context()->ReturnInstruction(call, expr->id()); |
| 8585 } |
| 8586 |
| 8587 |
| 8588 bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) { |
| 8542 ASSERT(expr->expression()->IsProperty()); | 8589 ASSERT(expr->expression()->IsProperty()); |
| 8543 | 8590 |
| 8544 if (!expr->IsMonomorphic()) { | 8591 if (!expr->IsMonomorphic()) { |
| 8545 return false; | 8592 return false; |
| 8546 } | 8593 } |
| 8594 |
| 8547 Handle<Map> function_map = expr->GetReceiverTypes()->first(); | 8595 Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
| 8548 if (function_map->instance_type() != JS_FUNCTION_TYPE || | 8596 if (function_map->instance_type() != JS_FUNCTION_TYPE || |
| 8549 !expr->target()->shared()->HasBuiltinFunctionId() || | 8597 !expr->target()->shared()->HasBuiltinFunctionId()) { |
| 8550 expr->target()->shared()->builtin_function_id() != kFunctionApply) { | |
| 8551 return false; | 8598 return false; |
| 8552 } | 8599 } |
| 8553 | 8600 |
| 8554 if (current_info()->scope()->arguments() == NULL) return false; | 8601 switch (expr->target()->shared()->builtin_function_id()) { |
| 8602 case kFunctionCall: { |
| 8603 BuildFunctionCall(expr); |
| 8604 return true; |
| 8605 } |
| 8606 case kFunctionApply: { |
| 8607 // For .apply, only the pattern f.apply(receiver, arguments) |
| 8608 // is supported. |
| 8609 if (current_info()->scope()->arguments() == NULL) return false; |
| 8555 | 8610 |
| 8611 ZoneList<Expression*>* args = expr->arguments(); |
| 8612 if (args->length() != 2) return false; |
| 8613 |
| 8614 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
| 8615 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
| 8616 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); |
| 8617 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
| 8618 BuildFunctionApply(expr); |
| 8619 return true; |
| 8620 } |
| 8621 default: { |
| 8622 return false; |
| 8623 } |
| 8624 } |
| 8625 UNREACHABLE(); |
| 8626 } |
| 8627 |
| 8628 |
| 8629 void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) { |
| 8556 ZoneList<Expression*>* args = expr->arguments(); | 8630 ZoneList<Expression*>* args = expr->arguments(); |
| 8557 if (args->length() != 2) return false; | 8631 CHECK_ALIVE(VisitForValue(args->at(0))); |
| 8558 | |
| 8559 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | |
| 8560 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | |
| 8561 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); | |
| 8562 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; | |
| 8563 | |
| 8564 // Found pattern f.apply(receiver, arguments). | |
| 8565 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); | |
| 8566 HValue* receiver = Pop(); // receiver | 8632 HValue* receiver = Pop(); // receiver |
| 8567 HValue* function = Pop(); // f | 8633 HValue* function = Pop(); // f |
| 8568 Drop(1); // apply | 8634 Drop(1); // apply |
| 8569 | 8635 |
| 8636 Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
| 8570 HValue* checked_function = AddCheckMap(function, function_map); | 8637 HValue* checked_function = AddCheckMap(function, function_map); |
| 8571 | 8638 |
| 8572 if (function_state()->outer() == NULL) { | 8639 if (function_state()->outer() == NULL) { |
| 8573 HInstruction* elements = Add<HArgumentsElements>(false); | 8640 HInstruction* elements = Add<HArgumentsElements>(false); |
| 8574 HInstruction* length = Add<HArgumentsLength>(elements); | 8641 HInstruction* length = Add<HArgumentsLength>(elements); |
| 8575 HValue* wrapped_receiver = BuildWrapReceiver(receiver, checked_function); | 8642 HValue* wrapped_receiver = BuildWrapReceiver(receiver, checked_function); |
| 8576 HInstruction* result = New<HApplyArguments>(function, | 8643 HInstruction* result = New<HApplyArguments>(function, |
| 8577 wrapped_receiver, | 8644 wrapped_receiver, |
| 8578 length, | 8645 length, |
| 8579 elements); | 8646 elements); |
| 8580 ast_context()->ReturnInstruction(result, expr->id()); | 8647 ast_context()->ReturnInstruction(result, expr->id()); |
| 8581 return true; | |
| 8582 } else { | 8648 } else { |
| 8583 // We are inside inlined function and we know exactly what is inside | 8649 // We are inside inlined function and we know exactly what is inside |
| 8584 // arguments object. But we need to be able to materialize at deopt. | 8650 // arguments object. But we need to be able to materialize at deopt. |
| 8585 ASSERT_EQ(environment()->arguments_environment()->parameter_count(), | 8651 ASSERT_EQ(environment()->arguments_environment()->parameter_count(), |
| 8586 function_state()->entry()->arguments_object()->arguments_count()); | 8652 function_state()->entry()->arguments_object()->arguments_count()); |
| 8587 HArgumentsObject* args = function_state()->entry()->arguments_object(); | 8653 HArgumentsObject* args = function_state()->entry()->arguments_object(); |
| 8588 const ZoneList<HValue*>* arguments_values = args->arguments_values(); | 8654 const ZoneList<HValue*>* arguments_values = args->arguments_values(); |
| 8589 int arguments_count = arguments_values->length(); | 8655 int arguments_count = arguments_values->length(); |
| 8590 Push(function); | 8656 Push(function); |
| 8591 Push(BuildWrapReceiver(receiver, checked_function)); | 8657 Push(BuildWrapReceiver(receiver, checked_function)); |
| 8592 for (int i = 1; i < arguments_count; i++) { | 8658 for (int i = 1; i < arguments_count; i++) { |
| 8593 Push(arguments_values->at(i)); | 8659 Push(arguments_values->at(i)); |
| 8594 } | 8660 } |
| 8595 | 8661 HandleIndirectCall(expr, function, arguments_count, 0); |
| 8596 Handle<JSFunction> known_function; | |
| 8597 if (function->IsConstant() && | |
| 8598 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { | |
| 8599 known_function = Handle<JSFunction>::cast( | |
| 8600 HConstant::cast(function)->handle(isolate())); | |
| 8601 int args_count = arguments_count - 1; // Excluding receiver. | |
| 8602 if (TryInlineApply(known_function, expr, args_count)) return true; | |
| 8603 } | |
| 8604 | |
| 8605 PushArgumentsFromEnvironment(arguments_count); | |
| 8606 HInvokeFunction* call = New<HInvokeFunction>( | |
| 8607 function, known_function, arguments_count); | |
| 8608 Drop(1); // Function. | |
| 8609 ast_context()->ReturnInstruction(call, expr->id()); | |
| 8610 return true; | |
| 8611 } | 8662 } |
| 8612 } | 8663 } |
| 8613 | 8664 |
| 8614 | 8665 |
| 8666 // f.call(...) |
| 8667 void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) { |
| 8668 HValue* function = Top(); // f |
| 8669 Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
| 8670 HValue* checked_function = AddCheckMap(function, function_map); |
| 8671 |
| 8672 int drop_extra = 0; |
| 8673 ZoneList<Expression*>* args = expr->arguments(); |
| 8674 int args_length = args->length(); |
| 8675 if (args_length == 0) { |
| 8676 Drop(2); // function and call |
| 8677 Push(function); |
| 8678 Push(BuildWrapReceiver( |
| 8679 graph()->GetConstantUndefined(), checked_function)); |
| 8680 args_length = 1; |
| 8681 } else { |
| 8682 CHECK_ALIVE(VisitForValue(args->at(0))); |
| 8683 Push(BuildWrapReceiver(Pop(), checked_function)); |
| 8684 for (int i = 1; i < args_length; i++) { |
| 8685 CHECK_ALIVE(VisitForValue(args->at(i))); |
| 8686 } |
| 8687 drop_extra = 1; // drop call later |
| 8688 } |
| 8689 |
| 8690 HandleIndirectCall(expr, function, args_length, drop_extra); |
| 8691 } |
| 8692 |
| 8693 |
| 8615 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, | 8694 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, |
| 8616 Handle<JSFunction> target) { | 8695 Handle<JSFunction> target) { |
| 8617 SharedFunctionInfo* shared = target->shared(); | 8696 SharedFunctionInfo* shared = target->shared(); |
| 8618 if (shared->strict_mode() == SLOPPY && !shared->native()) { | 8697 if (shared->strict_mode() == SLOPPY && !shared->native()) { |
| 8619 // Cannot embed a direct reference to the global proxy | 8698 // Cannot embed a direct reference to the global proxy |
| 8620 // as is it dropped on deserialization. | 8699 // as is it dropped on deserialization. |
| 8621 CHECK(!isolate()->serializer_enabled()); | 8700 CHECK(!isolate()->serializer_enabled()); |
| 8622 Handle<JSObject> global_receiver( | 8701 Handle<JSObject> global_receiver( |
| 8623 target->context()->global_object()->global_receiver()); | 8702 target->context()->global_object()->global_receiver()); |
| 8624 return Add<HConstant>(global_receiver); | 8703 return Add<HConstant>(global_receiver); |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8866 environment()->SetExpressionStackAt(0, function); | 8945 environment()->SetExpressionStackAt(0, function); |
| 8867 | 8946 |
| 8868 Push(receiver); | 8947 Push(receiver); |
| 8869 | 8948 |
| 8870 if (function->IsConstant() && | 8949 if (function->IsConstant() && |
| 8871 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { | 8950 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
| 8872 Handle<JSFunction> known_function = Handle<JSFunction>::cast( | 8951 Handle<JSFunction> known_function = Handle<JSFunction>::cast( |
| 8873 HConstant::cast(function)->handle(isolate())); | 8952 HConstant::cast(function)->handle(isolate())); |
| 8874 expr->set_target(known_function); | 8953 expr->set_target(known_function); |
| 8875 | 8954 |
| 8876 if (TryCallApply(expr)) return; | 8955 if (TryIndirectCall(expr)) return; |
| 8877 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8956 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 8878 | 8957 |
| 8879 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); | 8958 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); |
| 8880 if (TryInlineBuiltinMethodCall(expr, receiver, map)) { | 8959 if (TryInlineBuiltinMethodCall(expr, known_function, map, |
| 8960 expr->arguments()->length())) { |
| 8881 if (FLAG_trace_inlining) { | 8961 if (FLAG_trace_inlining) { |
| 8882 PrintF("Inlining builtin "); | 8962 PrintF("Inlining builtin "); |
| 8883 known_function->ShortPrint(); | 8963 known_function->ShortPrint(); |
| 8884 PrintF("\n"); | 8964 PrintF("\n"); |
| 8885 } | 8965 } |
| 8886 return; | 8966 return; |
| 8887 } | 8967 } |
| 8888 if (TryInlineApiMethodCall(expr, receiver, types)) return; | 8968 if (TryInlineApiMethodCall(expr, receiver, types)) return; |
| 8889 | 8969 |
| 8890 // Wrap the receiver if necessary. | 8970 // Wrap the receiver if necessary. |
| (...skipping 3461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12352 if (ShouldProduceTraceOutput()) { | 12432 if (ShouldProduceTraceOutput()) { |
| 12353 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 12433 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 12354 } | 12434 } |
| 12355 | 12435 |
| 12356 #ifdef DEBUG | 12436 #ifdef DEBUG |
| 12357 graph_->Verify(false); // No full verify. | 12437 graph_->Verify(false); // No full verify. |
| 12358 #endif | 12438 #endif |
| 12359 } | 12439 } |
| 12360 | 12440 |
| 12361 } } // namespace v8::internal | 12441 } } // namespace v8::internal |
| OLD | NEW |