| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 16 matching lines...) Expand all Loading... |
| 27 | 27 |
| 28 #include "hydrogen.h" | 28 #include "hydrogen.h" |
| 29 | 29 |
| 30 #include "codegen.h" | 30 #include "codegen.h" |
| 31 #include "data-flow.h" | 31 #include "data-flow.h" |
| 32 #include "full-codegen.h" | 32 #include "full-codegen.h" |
| 33 #include "hashmap.h" | 33 #include "hashmap.h" |
| 34 #include "lithium-allocator.h" | 34 #include "lithium-allocator.h" |
| 35 #include "parser.h" | 35 #include "parser.h" |
| 36 #include "scopes.h" | 36 #include "scopes.h" |
| 37 #include "stub-cache.h" |
| 37 | 38 |
| 38 #if V8_TARGET_ARCH_IA32 | 39 #if V8_TARGET_ARCH_IA32 |
| 39 #include "ia32/lithium-codegen-ia32.h" | 40 #include "ia32/lithium-codegen-ia32.h" |
| 40 #elif V8_TARGET_ARCH_X64 | 41 #elif V8_TARGET_ARCH_X64 |
| 41 #include "x64/lithium-codegen-x64.h" | 42 #include "x64/lithium-codegen-x64.h" |
| 42 #elif V8_TARGET_ARCH_ARM | 43 #elif V8_TARGET_ARCH_ARM |
| 43 #include "arm/lithium-codegen-arm.h" | 44 #include "arm/lithium-codegen-arm.h" |
| 44 #else | 45 #else |
| 45 #error Unsupported target architecture. | 46 #error Unsupported target architecture. |
| 46 #endif | 47 #endif |
| (...skipping 4066 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4113 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 4114 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 4114 ASSERT(target->IsInlineReturnTarget()); | 4115 ASSERT(target->IsInlineReturnTarget()); |
| 4115 AddInstruction(new HLeaveInlined); | 4116 AddInstruction(new HLeaveInlined); |
| 4116 HEnvironment* outer = last_environment()->outer(); | 4117 HEnvironment* outer = last_environment()->outer(); |
| 4117 if (return_value != NULL) outer->Push(return_value); | 4118 if (return_value != NULL) outer->Push(return_value); |
| 4118 UpdateEnvironment(outer); | 4119 UpdateEnvironment(outer); |
| 4119 Goto(target); | 4120 Goto(target); |
| 4120 } | 4121 } |
| 4121 | 4122 |
| 4122 | 4123 |
| 4123 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { | 4124 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
| 4125 HValue* receiver, |
| 4126 Handle<Map> receiver_map, |
| 4127 CheckType check_type) { |
| 4128 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
| 4124 // Try to inline calls like Math.* as operations in the calling function. | 4129 // Try to inline calls like Math.* as operations in the calling function. |
| 4125 if (!expr->target()->shared()->IsBuiltinMathFunction()) return false; | 4130 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
| 4126 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 4131 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 4127 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4132 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4128 switch (id) { | 4133 switch (id) { |
| 4134 case kStringCharCodeAt: |
| 4135 if (argument_count == 2 && check_type == STRING_CHECK) { |
| 4136 HValue* index = Pop(); |
| 4137 HValue* string = Pop(); |
| 4138 ASSERT(!expr->holder().is_null()); |
| 4139 AddInstruction(new HCheckPrototypeMaps( |
| 4140 oracle()->GetPrototypeForPrimitiveCheck(check_type), |
| 4141 expr->holder())); |
| 4142 AddInstruction(new HCheckNonSmi(string)); |
| 4143 AddInstruction(new HCheckInstanceType( |
| 4144 string, FIRST_STRING_TYPE, LAST_STRING_TYPE)); |
| 4145 HStringLength* length = new HStringLength(string); |
| 4146 AddInstruction(length); |
| 4147 AddInstruction(new HBoundsCheck(index, length)); |
| 4148 HStringCharCodeAt* result = new HStringCharCodeAt(string, index); |
| 4149 ast_context()->ReturnInstruction(result, expr->id()); |
| 4150 return true; |
| 4151 } |
| 4152 break; |
| 4129 case kMathRound: | 4153 case kMathRound: |
| 4130 case kMathFloor: | 4154 case kMathFloor: |
| 4131 case kMathAbs: | 4155 case kMathAbs: |
| 4132 case kMathSqrt: | 4156 case kMathSqrt: |
| 4133 case kMathLog: | 4157 case kMathLog: |
| 4134 case kMathSin: | 4158 case kMathSin: |
| 4135 case kMathCos: | 4159 case kMathCos: |
| 4136 if (argument_count == 2) { | 4160 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { |
| 4161 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4137 HValue* argument = Pop(); | 4162 HValue* argument = Pop(); |
| 4138 Drop(1); // Receiver. | 4163 Drop(1); // Receiver. |
| 4139 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); | 4164 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); |
| 4140 op->set_position(expr->position()); | 4165 op->set_position(expr->position()); |
| 4141 ast_context()->ReturnInstruction(op, expr->id()); | 4166 ast_context()->ReturnInstruction(op, expr->id()); |
| 4142 return true; | 4167 return true; |
| 4143 } | 4168 } |
| 4144 break; | 4169 break; |
| 4145 case kMathPow: | 4170 case kMathPow: |
| 4146 if (argument_count == 3) { | 4171 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { |
| 4172 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4147 HValue* right = Pop(); | 4173 HValue* right = Pop(); |
| 4148 HValue* left = Pop(); | 4174 HValue* left = Pop(); |
| 4149 Pop(); // Pop receiver. | 4175 Pop(); // Pop receiver. |
| 4150 HInstruction* result = NULL; | 4176 HInstruction* result = NULL; |
| 4151 // Use sqrt() if exponent is 0.5 or -0.5. | 4177 // Use sqrt() if exponent is 0.5 or -0.5. |
| 4152 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { | 4178 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
| 4153 double exponent = HConstant::cast(right)->DoubleValue(); | 4179 double exponent = HConstant::cast(right)->DoubleValue(); |
| 4154 if (exponent == 0.5) { | 4180 if (exponent == 0.5) { |
| 4155 result = new HUnaryMathOperation(left, kMathPowHalf); | 4181 result = new HUnaryMathOperation(left, kMathPowHalf); |
| 4156 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4157 return true; | |
| 4158 } else if (exponent == -0.5) { | 4182 } else if (exponent == -0.5) { |
| 4159 HConstant* double_one = | 4183 HConstant* double_one = |
| 4160 new HConstant(Handle<Object>(Smi::FromInt(1)), | 4184 new HConstant(Handle<Object>(Smi::FromInt(1)), |
| 4161 Representation::Double()); | 4185 Representation::Double()); |
| 4162 AddInstruction(double_one); | 4186 AddInstruction(double_one); |
| 4163 HUnaryMathOperation* square_root = | 4187 HUnaryMathOperation* square_root = |
| 4164 new HUnaryMathOperation(left, kMathPowHalf); | 4188 new HUnaryMathOperation(left, kMathPowHalf); |
| 4165 AddInstruction(square_root); | 4189 AddInstruction(square_root); |
| 4166 // MathPowHalf doesn't have side effects so there's no need for | 4190 // MathPowHalf doesn't have side effects so there's no need for |
| 4167 // an environment simulation here. | 4191 // an environment simulation here. |
| 4168 ASSERT(!square_root->HasSideEffects()); | 4192 ASSERT(!square_root->HasSideEffects()); |
| 4169 result = new HDiv(double_one, square_root); | 4193 result = new HDiv(double_one, square_root); |
| 4170 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4171 return true; | |
| 4172 } else if (exponent == 2.0) { | 4194 } else if (exponent == 2.0) { |
| 4173 result = new HMul(left, left); | 4195 result = new HMul(left, left); |
| 4174 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4175 return true; | |
| 4176 } | 4196 } |
| 4177 } else if (right->IsConstant() && | 4197 } else if (right->IsConstant() && |
| 4178 HConstant::cast(right)->HasInteger32Value() && | 4198 HConstant::cast(right)->HasInteger32Value() && |
| 4179 HConstant::cast(right)->Integer32Value() == 2) { | 4199 HConstant::cast(right)->Integer32Value() == 2) { |
| 4180 result = new HMul(left, left); | 4200 result = new HMul(left, left); |
| 4181 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4182 return true; | |
| 4183 } | 4201 } |
| 4184 | 4202 |
| 4185 result = new HPower(left, right); | 4203 if (result == NULL) { |
| 4204 result = new HPower(left, right); |
| 4205 } |
| 4186 ast_context()->ReturnInstruction(result, expr->id()); | 4206 ast_context()->ReturnInstruction(result, expr->id()); |
| 4187 return true; | 4207 return true; |
| 4188 } | 4208 } |
| 4189 break; | 4209 break; |
| 4190 default: | 4210 default: |
| 4191 // Not yet supported for inlining. | 4211 // Not yet supported for inlining. |
| 4192 break; | 4212 break; |
| 4193 } | 4213 } |
| 4194 return false; | 4214 return false; |
| 4195 } | 4215 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4230 expr->GetReceiverTypes()->first(), | 4250 expr->GetReceiverTypes()->first(), |
| 4231 true); | 4251 true); |
| 4232 HInstruction* result = | 4252 HInstruction* result = |
| 4233 new HApplyArguments(function, receiver, length, elements); | 4253 new HApplyArguments(function, receiver, length, elements); |
| 4234 result->set_position(expr->position()); | 4254 result->set_position(expr->position()); |
| 4235 ast_context()->ReturnInstruction(result, expr->id()); | 4255 ast_context()->ReturnInstruction(result, expr->id()); |
| 4236 return true; | 4256 return true; |
| 4237 } | 4257 } |
| 4238 | 4258 |
| 4239 | 4259 |
| 4260 static bool HasCustomCallGenerator(Handle<JSFunction> function) { |
| 4261 SharedFunctionInfo* info = function->shared(); |
| 4262 return info->HasBuiltinFunctionId() && |
| 4263 CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id()); |
| 4264 } |
| 4265 |
| 4266 |
| 4240 void HGraphBuilder::VisitCall(Call* expr) { | 4267 void HGraphBuilder::VisitCall(Call* expr) { |
| 4241 Expression* callee = expr->expression(); | 4268 Expression* callee = expr->expression(); |
| 4242 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4269 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4243 HCall* call = NULL; | 4270 HCall* call = NULL; |
| 4244 | 4271 |
| 4245 Property* prop = callee->AsProperty(); | 4272 Property* prop = callee->AsProperty(); |
| 4246 if (prop != NULL) { | 4273 if (prop != NULL) { |
| 4247 if (!prop->key()->IsPropertyName()) { | 4274 if (!prop->key()->IsPropertyName()) { |
| 4248 // Keyed function call. | 4275 // Keyed function call. |
| 4249 VisitArgument(prop->obj()); | 4276 VisitArgument(prop->obj()); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 4276 HValue* receiver = VisitArgument(prop->obj()); | 4303 HValue* receiver = VisitArgument(prop->obj()); |
| 4277 CHECK_BAILOUT; | 4304 CHECK_BAILOUT; |
| 4278 VisitArgumentList(expr->arguments()); | 4305 VisitArgumentList(expr->arguments()); |
| 4279 CHECK_BAILOUT; | 4306 CHECK_BAILOUT; |
| 4280 | 4307 |
| 4281 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4308 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4282 | 4309 |
| 4283 expr->RecordTypeFeedback(oracle()); | 4310 expr->RecordTypeFeedback(oracle()); |
| 4284 ZoneMapList* types = expr->GetReceiverTypes(); | 4311 ZoneMapList* types = expr->GetReceiverTypes(); |
| 4285 | 4312 |
| 4286 if (expr->IsMonomorphic() && expr->check_type() == RECEIVER_MAP_CHECK) { | 4313 if (expr->IsMonomorphic()) { |
| 4287 AddCheckConstantFunction(expr, receiver, types->first(), true); | 4314 Handle<Map> receiver_map = |
| 4288 | 4315 (types == NULL) ? Handle<Map>::null() : types->first(); |
| 4289 if (TryMathFunctionInline(expr)) { | 4316 if (TryInlineBuiltinFunction(expr, |
| 4317 receiver, |
| 4318 receiver_map, |
| 4319 expr->check_type())) { |
| 4290 return; | 4320 return; |
| 4291 } else if (TryInline(expr)) { | |
| 4292 if (subgraph()->HasExit()) { | |
| 4293 HValue* return_value = Pop(); | |
| 4294 // If we inlined a function in a test context then we need to emit | |
| 4295 // a simulate here to shadow the ones at the end of the | |
| 4296 // predecessor blocks. Those environments contain the return | |
| 4297 // value on top and do not correspond to any actual state of the | |
| 4298 // unoptimized code. | |
| 4299 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | |
| 4300 ast_context()->ReturnValue(return_value); | |
| 4301 } | |
| 4302 return; | |
| 4303 } else { | |
| 4304 // Check for bailout, as the TryInline call in the if condition above | |
| 4305 // might return false due to bailout during hydrogen processing. | |
| 4306 CHECK_BAILOUT; | |
| 4307 call = new HCallConstantFunction(expr->target(), argument_count); | |
| 4308 } | 4321 } |
| 4309 | 4322 |
| 4323 if (HasCustomCallGenerator(expr->target()) || |
| 4324 expr->check_type() != RECEIVER_MAP_CHECK) { |
| 4325 // When the target has a custom call IC generator, use the IC, |
| 4326 // because it is likely to generate better code. Also use the |
| 4327 // IC when a primitive receiver check is required. |
| 4328 call = new HCallNamed(name, argument_count); |
| 4329 } else { |
| 4330 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4331 |
| 4332 if (TryInline(expr)) { |
| 4333 if (subgraph()->HasExit()) { |
| 4334 HValue* return_value = Pop(); |
| 4335 // If we inlined a function in a test context then we need to emit |
| 4336 // a simulate here to shadow the ones at the end of the |
| 4337 // predecessor blocks. Those environments contain the return |
| 4338 // value on top and do not correspond to any actual state of the |
| 4339 // unoptimized code. |
| 4340 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| 4341 ast_context()->ReturnValue(return_value); |
| 4342 } |
| 4343 return; |
| 4344 } else { |
| 4345 // Check for bailout, as the TryInline call in the if condition above |
| 4346 // might return false due to bailout during hydrogen processing. |
| 4347 CHECK_BAILOUT; |
| 4348 call = new HCallConstantFunction(expr->target(), argument_count); |
| 4349 } |
| 4350 } |
| 4310 } else if (types != NULL && types->length() > 1) { | 4351 } else if (types != NULL && types->length() > 1) { |
| 4311 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 4352 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| 4312 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4353 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4313 return; | 4354 return; |
| 4314 | 4355 |
| 4315 } else { | 4356 } else { |
| 4316 call = new HCallNamed(name, argument_count); | 4357 call = new HCallNamed(name, argument_count); |
| 4317 } | 4358 } |
| 4318 | 4359 |
| 4319 } else { | 4360 } else { |
| (...skipping 1470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5790 } | 5831 } |
| 5791 } | 5832 } |
| 5792 | 5833 |
| 5793 #ifdef DEBUG | 5834 #ifdef DEBUG |
| 5794 if (graph_ != NULL) graph_->Verify(); | 5835 if (graph_ != NULL) graph_->Verify(); |
| 5795 if (allocator_ != NULL) allocator_->Verify(); | 5836 if (allocator_ != NULL) allocator_->Verify(); |
| 5796 #endif | 5837 #endif |
| 5797 } | 5838 } |
| 5798 | 5839 |
| 5799 } } // namespace v8::internal | 5840 } } // namespace v8::internal |
| OLD | NEW |