Chromium Code Reviews| 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 4092 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4139 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 4140 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 4140 ASSERT(target->IsInlineReturnTarget()); | 4141 ASSERT(target->IsInlineReturnTarget()); |
| 4141 AddInstruction(new HLeaveInlined); | 4142 AddInstruction(new HLeaveInlined); |
| 4142 HEnvironment* outer = last_environment()->outer(); | 4143 HEnvironment* outer = last_environment()->outer(); |
| 4143 if (return_value != NULL) outer->Push(return_value); | 4144 if (return_value != NULL) outer->Push(return_value); |
| 4144 UpdateEnvironment(outer); | 4145 UpdateEnvironment(outer); |
| 4145 Goto(target); | 4146 Goto(target); |
| 4146 } | 4147 } |
| 4147 | 4148 |
| 4148 | 4149 |
| 4149 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { | 4150 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
| 4151 HValue* receiver, | |
| 4152 Handle<Map> receiver_map, | |
| 4153 CheckType check_type) { | |
| 4154 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); | |
| 4150 // Try to inline calls like Math.* as operations in the calling function. | 4155 // Try to inline calls like Math.* as operations in the calling function. |
| 4151 if (!expr->target()->shared()->IsBuiltinMathFunction()) return false; | 4156 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
|
fschneider
2011/01/19 16:23:44
Maybe we don't need IsBuiltinMathFunction() anymor
Vitaly Repeshko
2011/01/19 20:08:41
Done.
| |
| 4152 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 4157 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 4153 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4158 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4154 switch (id) { | 4159 switch (id) { |
| 4160 case kStringCharCodeAt: | |
| 4161 if (argument_count == 2 && check_type == STRING_CHECK) { | |
| 4162 HValue* index = Pop(); | |
| 4163 HValue* string = Pop(); | |
| 4164 ASSERT(!expr->holder().is_null()); | |
| 4165 AddInstruction(new HCheckPrototypeMaps( | |
| 4166 oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK), | |
| 4167 expr->holder())); | |
| 4168 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); | |
| 4169 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4170 return true; | |
| 4171 } | |
| 4172 break; | |
| 4155 case kMathRound: | 4173 case kMathRound: |
| 4156 case kMathFloor: | 4174 case kMathFloor: |
| 4157 case kMathAbs: | 4175 case kMathAbs: |
| 4158 case kMathSqrt: | 4176 case kMathSqrt: |
| 4159 case kMathLog: | 4177 case kMathLog: |
| 4160 case kMathSin: | 4178 case kMathSin: |
| 4161 case kMathCos: | 4179 case kMathCos: |
| 4162 if (argument_count == 2) { | 4180 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { |
| 4181 AddCheckConstantFunction(expr, receiver, receiver_map, true); | |
| 4163 HValue* argument = Pop(); | 4182 HValue* argument = Pop(); |
| 4164 Drop(1); // Receiver. | 4183 Drop(1); // Receiver. |
| 4165 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); | 4184 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); |
| 4166 op->set_position(expr->position()); | 4185 op->set_position(expr->position()); |
| 4167 ast_context()->ReturnInstruction(op, expr->id()); | 4186 ast_context()->ReturnInstruction(op, expr->id()); |
| 4168 return true; | 4187 return true; |
| 4169 } | 4188 } |
| 4170 break; | 4189 break; |
| 4171 case kMathPow: | 4190 case kMathPow: |
| 4172 if (argument_count == 3) { | 4191 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { |
| 4192 AddCheckConstantFunction(expr, receiver, receiver_map, true); | |
| 4173 HValue* right = Pop(); | 4193 HValue* right = Pop(); |
| 4174 HValue* left = Pop(); | 4194 HValue* left = Pop(); |
| 4175 Pop(); // Pop receiver. | 4195 Pop(); // Pop receiver. |
| 4176 HInstruction* result = NULL; | 4196 HInstruction* result = NULL; |
| 4177 // Use sqrt() if exponent is 0.5 or -0.5. | 4197 // Use sqrt() if exponent is 0.5 or -0.5. |
| 4178 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { | 4198 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
| 4179 double exponent = HConstant::cast(right)->DoubleValue(); | 4199 double exponent = HConstant::cast(right)->DoubleValue(); |
| 4180 if (exponent == 0.5) { | 4200 if (exponent == 0.5) { |
| 4181 result = new HUnaryMathOperation(left, kMathPowHalf); | 4201 result = new HUnaryMathOperation(left, kMathPowHalf); |
| 4182 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4183 return true; | |
| 4184 } else if (exponent == -0.5) { | 4202 } else if (exponent == -0.5) { |
| 4185 HConstant* double_one = | 4203 HConstant* double_one = |
| 4186 new HConstant(Handle<Object>(Smi::FromInt(1)), | 4204 new HConstant(Handle<Object>(Smi::FromInt(1)), |
| 4187 Representation::Double()); | 4205 Representation::Double()); |
| 4188 AddInstruction(double_one); | 4206 AddInstruction(double_one); |
| 4189 HUnaryMathOperation* square_root = | 4207 HUnaryMathOperation* square_root = |
| 4190 new HUnaryMathOperation(left, kMathPowHalf); | 4208 new HUnaryMathOperation(left, kMathPowHalf); |
| 4191 AddInstruction(square_root); | 4209 AddInstruction(square_root); |
| 4192 // MathPowHalf doesn't have side effects so there's no need for | 4210 // MathPowHalf doesn't have side effects so there's no need for |
| 4193 // an environment simulation here. | 4211 // an environment simulation here. |
| 4194 ASSERT(!square_root->HasSideEffects()); | 4212 ASSERT(!square_root->HasSideEffects()); |
| 4195 result = new HDiv(double_one, square_root); | 4213 result = new HDiv(double_one, square_root); |
| 4196 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4197 return true; | |
| 4198 } else if (exponent == 2.0) { | 4214 } else if (exponent == 2.0) { |
| 4199 result = new HMul(left, left); | 4215 result = new HMul(left, left); |
| 4200 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4201 return true; | |
| 4202 } | 4216 } |
| 4203 } else if (right->IsConstant() && | 4217 } else if (right->IsConstant() && |
| 4204 HConstant::cast(right)->HasInteger32Value() && | 4218 HConstant::cast(right)->HasInteger32Value() && |
| 4205 HConstant::cast(right)->Integer32Value() == 2) { | 4219 HConstant::cast(right)->Integer32Value() == 2) { |
| 4206 result = new HMul(left, left); | 4220 result = new HMul(left, left); |
| 4207 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4208 return true; | |
| 4209 } | 4221 } |
| 4210 | 4222 |
| 4211 result = new HPower(left, right); | 4223 if (result == NULL) { |
| 4224 result = new HPower(left, right); | |
| 4225 } | |
| 4212 ast_context()->ReturnInstruction(result, expr->id()); | 4226 ast_context()->ReturnInstruction(result, expr->id()); |
| 4213 return true; | 4227 return true; |
| 4214 } | 4228 } |
| 4215 break; | 4229 break; |
| 4216 default: | 4230 default: |
| 4217 // Not yet supported for inlining. | 4231 // Not yet supported for inlining. |
| 4218 break; | 4232 break; |
| 4219 } | 4233 } |
| 4220 return false; | 4234 return false; |
| 4221 } | 4235 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4256 expr->GetReceiverTypes()->first(), | 4270 expr->GetReceiverTypes()->first(), |
| 4257 true); | 4271 true); |
| 4258 HInstruction* result = | 4272 HInstruction* result = |
| 4259 new HApplyArguments(function, receiver, length, elements); | 4273 new HApplyArguments(function, receiver, length, elements); |
| 4260 result->set_position(expr->position()); | 4274 result->set_position(expr->position()); |
| 4261 ast_context()->ReturnInstruction(result, expr->id()); | 4275 ast_context()->ReturnInstruction(result, expr->id()); |
| 4262 return true; | 4276 return true; |
| 4263 } | 4277 } |
| 4264 | 4278 |
| 4265 | 4279 |
| 4280 static bool HasCustomCallGenerator(Handle<JSFunction> function) { | |
| 4281 SharedFunctionInfo* info = function->shared(); | |
| 4282 return info->HasBuiltinFunctionId() && | |
| 4283 CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id()); | |
| 4284 } | |
| 4285 | |
| 4286 | |
| 4266 void HGraphBuilder::VisitCall(Call* expr) { | 4287 void HGraphBuilder::VisitCall(Call* expr) { |
| 4267 Expression* callee = expr->expression(); | 4288 Expression* callee = expr->expression(); |
| 4268 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4289 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4269 HCall* call = NULL; | 4290 HCall* call = NULL; |
| 4270 | 4291 |
| 4271 Property* prop = callee->AsProperty(); | 4292 Property* prop = callee->AsProperty(); |
| 4272 if (prop != NULL) { | 4293 if (prop != NULL) { |
| 4273 if (!prop->key()->IsPropertyName()) { | 4294 if (!prop->key()->IsPropertyName()) { |
| 4274 // Keyed function call. | 4295 // Keyed function call. |
| 4275 VisitArgument(prop->obj()); | 4296 VisitArgument(prop->obj()); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 4302 HValue* receiver = VisitArgument(prop->obj()); | 4323 HValue* receiver = VisitArgument(prop->obj()); |
| 4303 CHECK_BAILOUT; | 4324 CHECK_BAILOUT; |
| 4304 VisitArgumentList(expr->arguments()); | 4325 VisitArgumentList(expr->arguments()); |
| 4305 CHECK_BAILOUT; | 4326 CHECK_BAILOUT; |
| 4306 | 4327 |
| 4307 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4328 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4308 | 4329 |
| 4309 expr->RecordTypeFeedback(oracle()); | 4330 expr->RecordTypeFeedback(oracle()); |
| 4310 ZoneMapList* types = expr->GetReceiverTypes(); | 4331 ZoneMapList* types = expr->GetReceiverTypes(); |
| 4311 | 4332 |
| 4312 if (expr->IsMonomorphic() && expr->check_type() == RECEIVER_MAP_CHECK) { | 4333 if (expr->IsMonomorphic()) { |
| 4313 AddCheckConstantFunction(expr, receiver, types->first(), true); | 4334 Handle<Map> receiver_map = |
| 4314 | 4335 (types == NULL) ? Handle<Map>::null() : types->first(); |
| 4315 if (TryMathFunctionInline(expr)) { | 4336 if (TryInlineBuiltinFunction(expr, |
| 4337 receiver, | |
| 4338 receiver_map, | |
| 4339 expr->check_type())) { | |
| 4316 return; | 4340 return; |
| 4317 } else if (TryInline(expr)) { | |
| 4318 if (subgraph()->HasExit()) { | |
| 4319 HValue* return_value = Pop(); | |
| 4320 // If we inlined a function in a test context then we need to emit | |
| 4321 // a simulate here to shadow the ones at the end of the | |
| 4322 // predecessor blocks. Those environments contain the return | |
| 4323 // value on top and do not correspond to any actual state of the | |
| 4324 // unoptimized code. | |
| 4325 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | |
| 4326 ast_context()->ReturnValue(return_value); | |
| 4327 } | |
| 4328 return; | |
| 4329 } else { | |
| 4330 // Check for bailout, as the TryInline call in the if condition above | |
| 4331 // might return false due to bailout during hydrogen processing. | |
| 4332 CHECK_BAILOUT; | |
| 4333 call = new HCallConstantFunction(expr->target(), argument_count); | |
| 4334 } | 4341 } |
| 4335 | 4342 |
| 4343 if (HasCustomCallGenerator(expr->target()) || | |
| 4344 expr->check_type() != RECEIVER_MAP_CHECK) { | |
| 4345 // When the target has a custom call IC generator, use the IC, | |
| 4346 // because it is likely to generate better code. Also use the | |
| 4347 // IC when a primitive receiver check is required. | |
| 4348 call = new HCallNamed(name, argument_count); | |
| 4349 } else { | |
| 4350 AddCheckConstantFunction(expr, receiver, receiver_map, true); | |
| 4351 | |
| 4352 if (TryInline(expr)) { | |
| 4353 if (subgraph()->HasExit()) { | |
| 4354 HValue* return_value = Pop(); | |
| 4355 // If we inlined a function in a test context then we need to emit | |
| 4356 // a simulate here to shadow the ones at the end of the | |
| 4357 // predecessor blocks. Those environments contain the return | |
| 4358 // value on top and do not correspond to any actual state of the | |
| 4359 // unoptimized code. | |
| 4360 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | |
| 4361 ast_context()->ReturnValue(return_value); | |
| 4362 } | |
| 4363 return; | |
| 4364 } else { | |
| 4365 // Check for bailout, as the TryInline call in the if condition above | |
| 4366 // might return false due to bailout during hydrogen processing. | |
| 4367 CHECK_BAILOUT; | |
| 4368 call = new HCallConstantFunction(expr->target(), argument_count); | |
| 4369 } | |
| 4370 } | |
| 4336 } else if (types != NULL && types->length() > 1) { | 4371 } else if (types != NULL && types->length() > 1) { |
| 4337 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 4372 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| 4338 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4373 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4339 return; | 4374 return; |
| 4340 | 4375 |
| 4341 } else { | 4376 } else { |
| 4342 call = new HCallNamed(name, argument_count); | 4377 call = new HCallNamed(name, argument_count); |
| 4343 } | 4378 } |
| 4344 | 4379 |
| 4345 } else { | 4380 } else { |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4713 | 4748 |
| 4714 ast_context()->ReturnValue(expr->is_postfix() ? before : after); | 4749 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4715 } | 4750 } |
| 4716 | 4751 |
| 4717 } else { | 4752 } else { |
| 4718 BAILOUT("invalid lhs in count operation"); | 4753 BAILOUT("invalid lhs in count operation"); |
| 4719 } | 4754 } |
| 4720 } | 4755 } |
| 4721 | 4756 |
| 4722 | 4757 |
| 4758 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string, | |
| 4759 HValue* index) { | |
| 4760 AddInstruction(new HCheckNonSmi(string)); | |
| 4761 AddInstruction(new HCheckInstanceType( | |
| 4762 string, FIRST_STRING_TYPE, LAST_STRING_TYPE)); | |
| 4763 HStringLength* length = new HStringLength(string); | |
| 4764 AddInstruction(length); | |
| 4765 AddInstruction(new HBoundsCheck(index, length)); | |
| 4766 return new HStringCharCodeAt(string, index); | |
| 4767 } | |
| 4768 | |
| 4769 | |
| 4723 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, | 4770 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, |
| 4724 HValue* left, | 4771 HValue* left, |
| 4725 HValue* right) { | 4772 HValue* right) { |
| 4726 HInstruction* instr = NULL; | 4773 HInstruction* instr = NULL; |
| 4727 switch (expr->op()) { | 4774 switch (expr->op()) { |
| 4728 case Token::ADD: | 4775 case Token::ADD: |
| 4729 instr = new HAdd(left, right); | 4776 instr = new HAdd(left, right); |
| 4730 break; | 4777 break; |
| 4731 case Token::SUB: | 4778 case Token::SUB: |
| 4732 instr = new HSub(left, right); | 4779 instr = new HSub(left, right); |
| (...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5122 } | 5169 } |
| 5123 | 5170 |
| 5124 | 5171 |
| 5125 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { | 5172 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { |
| 5126 BAILOUT("inlined runtime function: SetValueOf"); | 5173 BAILOUT("inlined runtime function: SetValueOf"); |
| 5127 } | 5174 } |
| 5128 | 5175 |
| 5129 | 5176 |
| 5130 // Fast support for charCodeAt(n). | 5177 // Fast support for charCodeAt(n). |
| 5131 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { | 5178 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { |
| 5132 BAILOUT("inlined runtime function: StringCharCodeAt"); | 5179 ASSERT(argument_count == 2); |
| 5180 HValue* index = Pop(); | |
| 5181 HValue* string = Pop(); | |
| 5182 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); | |
| 5183 ast_context()->ReturnInstruction(result, ast_id); | |
| 5133 } | 5184 } |
| 5134 | 5185 |
| 5135 | 5186 |
| 5136 // Fast support for string.charAt(n) and string[n]. | 5187 // Fast support for string.charAt(n) and string[n]. |
| 5137 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, | 5188 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, |
| 5138 int ast_id) { | 5189 int ast_id) { |
| 5139 BAILOUT("inlined runtime function: StringCharFromCode"); | 5190 BAILOUT("inlined runtime function: StringCharFromCode"); |
| 5140 } | 5191 } |
| 5141 | 5192 |
| 5142 | 5193 |
| (...skipping 673 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5816 } | 5867 } |
| 5817 } | 5868 } |
| 5818 | 5869 |
| 5819 #ifdef DEBUG | 5870 #ifdef DEBUG |
| 5820 if (graph_ != NULL) graph_->Verify(); | 5871 if (graph_ != NULL) graph_->Verify(); |
| 5821 if (allocator_ != NULL) allocator_->Verify(); | 5872 if (allocator_ != NULL) allocator_->Verify(); |
| 5822 #endif | 5873 #endif |
| 5823 } | 5874 } |
| 5824 | 5875 |
| 5825 } } // namespace v8::internal | 5876 } } // namespace v8::internal |
| OLD | NEW |