Chromium Code Reviews| Index: src/hydrogen.cc |
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
| index da41ef94dc36e9e8e2f8a694d3126e664831ff3b..b906127d46fe267cfb7c0105286856e46f248ec2 100644 |
| --- a/src/hydrogen.cc |
| +++ b/src/hydrogen.cc |
| @@ -34,6 +34,7 @@ |
| #include "lithium-allocator.h" |
| #include "parser.h" |
| #include "scopes.h" |
| +#include "stub-cache.h" |
| #if V8_TARGET_ARCH_IA32 |
| #include "ia32/lithium-codegen-ia32.h" |
| @@ -4146,12 +4147,29 @@ void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| } |
| -bool HGraphBuilder::TryMathFunctionInline(Call* expr) { |
| +bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
| + HValue* receiver, |
| + Handle<Map> receiver_map, |
| + CheckType check_type) { |
| + ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
| // Try to inline calls like Math.* as operations in the calling function. |
| - if (!expr->target()->shared()->IsBuiltinMathFunction()) return false; |
| + 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.
|
| BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| switch (id) { |
| + case kStringCharCodeAt: |
| + if (argument_count == 2 && check_type == STRING_CHECK) { |
| + HValue* index = Pop(); |
| + HValue* string = Pop(); |
| + ASSERT(!expr->holder().is_null()); |
| + AddInstruction(new HCheckPrototypeMaps( |
| + oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK), |
| + expr->holder())); |
| + HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); |
| + ast_context()->ReturnInstruction(result, expr->id()); |
| + return true; |
| + } |
| + break; |
| case kMathRound: |
| case kMathFloor: |
| case kMathAbs: |
| @@ -4159,7 +4177,8 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) { |
| case kMathLog: |
| case kMathSin: |
| case kMathCos: |
| - if (argument_count == 2) { |
| + if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { |
| + AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| HValue* argument = Pop(); |
| Drop(1); // Receiver. |
| HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); |
| @@ -4169,7 +4188,8 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) { |
| } |
| break; |
| case kMathPow: |
| - if (argument_count == 3) { |
| + if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { |
| + AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| HValue* right = Pop(); |
| HValue* left = Pop(); |
| Pop(); // Pop receiver. |
| @@ -4179,8 +4199,6 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) { |
| double exponent = HConstant::cast(right)->DoubleValue(); |
| if (exponent == 0.5) { |
| result = new HUnaryMathOperation(left, kMathPowHalf); |
| - ast_context()->ReturnInstruction(result, expr->id()); |
| - return true; |
| } else if (exponent == -0.5) { |
| HConstant* double_one = |
| new HConstant(Handle<Object>(Smi::FromInt(1)), |
| @@ -4193,22 +4211,18 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) { |
| // an environment simulation here. |
| ASSERT(!square_root->HasSideEffects()); |
| result = new HDiv(double_one, square_root); |
| - ast_context()->ReturnInstruction(result, expr->id()); |
| - return true; |
| } else if (exponent == 2.0) { |
| result = new HMul(left, left); |
| - ast_context()->ReturnInstruction(result, expr->id()); |
| - return true; |
| } |
| } else if (right->IsConstant() && |
| - HConstant::cast(right)->HasInteger32Value() && |
| - HConstant::cast(right)->Integer32Value() == 2) { |
| + HConstant::cast(right)->HasInteger32Value() && |
| + HConstant::cast(right)->Integer32Value() == 2) { |
| result = new HMul(left, left); |
| - ast_context()->ReturnInstruction(result, expr->id()); |
| - return true; |
| } |
| - result = new HPower(left, right); |
| + if (result == NULL) { |
| + result = new HPower(left, right); |
| + } |
| ast_context()->ReturnInstruction(result, expr->id()); |
| return true; |
| } |
| @@ -4263,6 +4277,13 @@ bool HGraphBuilder::TryCallApply(Call* expr) { |
| } |
| +static bool HasCustomCallGenerator(Handle<JSFunction> function) { |
| + SharedFunctionInfo* info = function->shared(); |
| + return info->HasBuiltinFunctionId() && |
| + CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id()); |
| +} |
| + |
| + |
| void HGraphBuilder::VisitCall(Call* expr) { |
| Expression* callee = expr->expression(); |
| int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| @@ -4309,30 +4330,44 @@ void HGraphBuilder::VisitCall(Call* expr) { |
| expr->RecordTypeFeedback(oracle()); |
| ZoneMapList* types = expr->GetReceiverTypes(); |
| - if (expr->IsMonomorphic() && expr->check_type() == RECEIVER_MAP_CHECK) { |
| - AddCheckConstantFunction(expr, receiver, types->first(), true); |
| - |
| - if (TryMathFunctionInline(expr)) { |
| - return; |
| - } else if (TryInline(expr)) { |
| - if (subgraph()->HasExit()) { |
| - HValue* return_value = Pop(); |
| - // If we inlined a function in a test context then we need to emit |
| - // a simulate here to shadow the ones at the end of the |
| - // predecessor blocks. Those environments contain the return |
| - // value on top and do not correspond to any actual state of the |
| - // unoptimized code. |
| - if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| - ast_context()->ReturnValue(return_value); |
| - } |
| + if (expr->IsMonomorphic()) { |
| + Handle<Map> receiver_map = |
| + (types == NULL) ? Handle<Map>::null() : types->first(); |
| + if (TryInlineBuiltinFunction(expr, |
| + receiver, |
| + receiver_map, |
| + expr->check_type())) { |
| return; |
| - } else { |
| - // Check for bailout, as the TryInline call in the if condition above |
| - // might return false due to bailout during hydrogen processing. |
| - CHECK_BAILOUT; |
| - call = new HCallConstantFunction(expr->target(), argument_count); |
| } |
| + if (HasCustomCallGenerator(expr->target()) || |
| + expr->check_type() != RECEIVER_MAP_CHECK) { |
| + // When the target has a custom call IC generator, use the IC, |
| + // because it is likely to generate better code. Also use the |
| + // IC when a primitive receiver check is required. |
| + call = new HCallNamed(name, argument_count); |
| + } else { |
| + AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| + |
| + if (TryInline(expr)) { |
| + if (subgraph()->HasExit()) { |
| + HValue* return_value = Pop(); |
| + // If we inlined a function in a test context then we need to emit |
| + // a simulate here to shadow the ones at the end of the |
| + // predecessor blocks. Those environments contain the return |
| + // value on top and do not correspond to any actual state of the |
| + // unoptimized code. |
| + if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| + ast_context()->ReturnValue(return_value); |
| + } |
| + return; |
| + } else { |
| + // Check for bailout, as the TryInline call in the if condition above |
| + // might return false due to bailout during hydrogen processing. |
| + CHECK_BAILOUT; |
| + call = new HCallConstantFunction(expr->target(), argument_count); |
| + } |
| + } |
| } else if (types != NULL && types->length() > 1) { |
| ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| HandlePolymorphicCallNamed(expr, receiver, types, name); |
| @@ -4720,6 +4755,18 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| } |
| +HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string, |
| + HValue* index) { |
| + AddInstruction(new HCheckNonSmi(string)); |
| + AddInstruction(new HCheckInstanceType( |
| + string, FIRST_STRING_TYPE, LAST_STRING_TYPE)); |
| + HStringLength* length = new HStringLength(string); |
| + AddInstruction(length); |
| + AddInstruction(new HBoundsCheck(index, length)); |
| + return new HStringCharCodeAt(string, index); |
| +} |
| + |
| + |
| HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, |
| HValue* left, |
| HValue* right) { |
| @@ -5129,7 +5176,11 @@ void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { |
| // Fast support for charCodeAt(n). |
| void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { |
| - BAILOUT("inlined runtime function: StringCharCodeAt"); |
| + ASSERT(argument_count == 2); |
| + HValue* index = Pop(); |
| + HValue* string = Pop(); |
| + HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); |
| + ast_context()->ReturnInstruction(result, ast_id); |
| } |