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 |