Shorten live ranges for arguments to runtime calls.
Before, the live ranges of the arguments extended to the call itself, and they were pushed immediately before the call. Now, they are spilled eagerly as soon as their value is available and they are spilled to the right place. The inlined runtime calls in the optimized backend are changed to work as in all the other backends: they get their arguments untranslated and can choose their own custom evaluation order. Review URL: http://codereview.chromium.org/6526047 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6876 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
4e6635ad66
commit
c1386c3381
@ -1049,7 +1049,9 @@ class HLeaveInlined: public HInstruction {
|
||||
|
||||
class HPushArgument: public HUnaryOperation {
|
||||
public:
|
||||
explicit HPushArgument(HValue* value) : HUnaryOperation(value) { }
|
||||
explicit HPushArgument(HValue* value) : HUnaryOperation(value) {
|
||||
set_representation(Representation::Tagged());
|
||||
}
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) const {
|
||||
return Representation::Tagged();
|
||||
|
340
src/hydrogen.cc
340
src/hydrogen.cc
@ -2156,7 +2156,8 @@ void HGraphBuilder::VisitForControl(Expression* expr,
|
||||
|
||||
|
||||
void HGraphBuilder::VisitArgument(Expression* expr) {
|
||||
VisitForValue(expr);
|
||||
VISIT_FOR_VALUE(expr);
|
||||
Push(AddInstruction(new HPushArgument(Pop())));
|
||||
}
|
||||
|
||||
|
||||
@ -2168,6 +2169,13 @@ void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) {
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) {
|
||||
for (int i = 0; i < exprs->length(); ++i) {
|
||||
VISIT_FOR_VALUE(exprs->at(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HGraph* HGraphBuilder::CreateGraph(CompilationInfo* info) {
|
||||
ASSERT(current_subgraph_ == NULL);
|
||||
graph_ = new HGraph(info);
|
||||
@ -4352,8 +4360,7 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
||||
if (prop != NULL) {
|
||||
if (!prop->key()->IsPropertyName()) {
|
||||
// Keyed function call.
|
||||
VisitArgument(prop->obj());
|
||||
CHECK_BAILOUT;
|
||||
VISIT_FOR_VALUE(prop->obj());
|
||||
|
||||
VISIT_FOR_VALUE(prop->key());
|
||||
// Push receiver and key like the non-optimized code generator expects it.
|
||||
@ -4362,7 +4369,7 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
||||
Push(key);
|
||||
Push(receiver);
|
||||
|
||||
VisitArgumentList(expr->arguments());
|
||||
VisitExpressions(expr->arguments());
|
||||
CHECK_BAILOUT;
|
||||
|
||||
HContext* context = new HContext;
|
||||
@ -4381,9 +4388,8 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
||||
if (TryCallApply(expr)) return;
|
||||
CHECK_BAILOUT;
|
||||
|
||||
VisitArgument(prop->obj());
|
||||
CHECK_BAILOUT;
|
||||
VisitArgumentList(expr->arguments());
|
||||
VISIT_FOR_VALUE(prop->obj());
|
||||
VisitExpressions(expr->arguments());
|
||||
CHECK_BAILOUT;
|
||||
|
||||
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
|
||||
@ -4450,8 +4456,7 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
||||
|
||||
if (!global_call) {
|
||||
++argument_count;
|
||||
VisitArgument(expr->expression());
|
||||
CHECK_BAILOUT;
|
||||
VISIT_FOR_VALUE(expr->expression());
|
||||
}
|
||||
|
||||
if (global_call) {
|
||||
@ -4470,7 +4475,7 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
||||
HGlobalObject* global_object = new HGlobalObject(context);
|
||||
AddInstruction(context);
|
||||
PushAndAdd(global_object);
|
||||
VisitArgumentList(expr->arguments());
|
||||
VisitExpressions(expr->arguments());
|
||||
CHECK_BAILOUT;
|
||||
|
||||
VISIT_FOR_VALUE(expr->expression());
|
||||
@ -4508,7 +4513,7 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
||||
HContext* context = new HContext;
|
||||
AddInstruction(context);
|
||||
PushAndAdd(new HGlobalObject(context));
|
||||
VisitArgumentList(expr->arguments());
|
||||
VisitExpressions(expr->arguments());
|
||||
CHECK_BAILOUT;
|
||||
|
||||
call = new HCallGlobal(context, var->name(), argument_count);
|
||||
@ -4520,7 +4525,7 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
||||
AddInstruction(context);
|
||||
AddInstruction(global_object);
|
||||
PushAndAdd(new HGlobalReceiver(global_object));
|
||||
VisitArgumentList(expr->arguments());
|
||||
VisitExpressions(expr->arguments());
|
||||
CHECK_BAILOUT;
|
||||
|
||||
call = new HCallFunction(context, argument_count);
|
||||
@ -4536,9 +4541,8 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
||||
void HGraphBuilder::VisitCallNew(CallNew* expr) {
|
||||
// The constructor function is also used as the receiver argument to the
|
||||
// JS construct call builtin.
|
||||
VisitArgument(expr->expression());
|
||||
CHECK_BAILOUT;
|
||||
VisitArgumentList(expr->arguments());
|
||||
VISIT_FOR_VALUE(expr->expression());
|
||||
VisitExpressions(expr->arguments());
|
||||
CHECK_BAILOUT;
|
||||
|
||||
HContext* context = new HContext;
|
||||
@ -4571,25 +4575,15 @@ const HGraphBuilder::InlineFunctionGenerator
|
||||
|
||||
|
||||
void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
|
||||
Handle<String> name = expr->name();
|
||||
if (name->IsEqualTo(CStrVector("_Log"))) {
|
||||
ast_context()->ReturnValue(graph()->GetConstantUndefined());
|
||||
return;
|
||||
}
|
||||
|
||||
Runtime::Function* function = expr->function();
|
||||
if (expr->is_jsruntime()) {
|
||||
BAILOUT("call to a JavaScript runtime function");
|
||||
}
|
||||
|
||||
Runtime::Function* function = expr->function();
|
||||
ASSERT(function != NULL);
|
||||
|
||||
VisitArgumentList(expr->arguments());
|
||||
CHECK_BAILOUT;
|
||||
|
||||
int argument_count = expr->arguments()->length();
|
||||
if (function->intrinsic_type == Runtime::INLINE) {
|
||||
ASSERT(name->length() > 0);
|
||||
ASSERT(name->Get(0) == '_');
|
||||
ASSERT(expr->name()->length() > 0);
|
||||
ASSERT(expr->name()->Get(0) == '_');
|
||||
// Call to an inline function.
|
||||
int lookup_index = static_cast<int>(function->function_id) -
|
||||
static_cast<int>(Runtime::kFirstInlineFunction);
|
||||
@ -4599,12 +4593,17 @@ void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
|
||||
InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
|
||||
|
||||
// Call the inline code generator using the pointer-to-member.
|
||||
(this->*generator)(argument_count, expr->id());
|
||||
(this->*generator)(expr);
|
||||
} else {
|
||||
ASSERT(function->intrinsic_type == Runtime::RUNTIME);
|
||||
HCall* call = new HCallRuntime(name, expr->function(), argument_count);
|
||||
VisitArgumentList(expr->arguments());
|
||||
CHECK_BAILOUT;
|
||||
|
||||
Handle<String> name = expr->name();
|
||||
int argument_count = expr->arguments()->length();
|
||||
HCall* call = new HCallRuntime(name, function, argument_count);
|
||||
call->set_position(RelocInfo::kNoPosition);
|
||||
PreProcessCall(call);
|
||||
Drop(argument_count);
|
||||
ast_context()->ReturnInstruction(call, expr->id());
|
||||
}
|
||||
}
|
||||
@ -5194,343 +5193,360 @@ void HGraphBuilder::VisitDeclaration(Declaration* decl) {
|
||||
|
||||
// Generators for inline runtime functions.
|
||||
// Support for types.
|
||||
void HGraphBuilder::GenerateIsSmi(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 1);
|
||||
void HGraphBuilder::GenerateIsSmi(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 1);
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
HValue* value = Pop();
|
||||
HIsSmi* result = new HIsSmi(value);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateIsSpecObject(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 1);
|
||||
void HGraphBuilder::GenerateIsSpecObject(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 1);
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
HValue* value = Pop();
|
||||
HHasInstanceType* result =
|
||||
new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateIsFunction(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 1);
|
||||
void HGraphBuilder::GenerateIsFunction(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 1);
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
HValue* value = Pop();
|
||||
HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count,
|
||||
int ast_id) {
|
||||
ASSERT(argument_count == 1);
|
||||
void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 1);
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
HValue* value = Pop();
|
||||
HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateIsArray(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 1);
|
||||
void HGraphBuilder::GenerateIsArray(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 1);
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
HValue* value = Pop();
|
||||
HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 1);
|
||||
void HGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 1);
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
HValue* value = Pop();
|
||||
HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 1);
|
||||
|
||||
void HGraphBuilder::GenerateIsObject(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 1);
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
HValue* value = Pop();
|
||||
HIsObject* test = new HIsObject(value);
|
||||
ast_context()->ReturnInstruction(test, ast_id);
|
||||
ast_context()->ReturnInstruction(test, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count,
|
||||
int ast_id) {
|
||||
void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
|
||||
BAILOUT("inlined runtime function: IsNonNegativeSmi");
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateIsUndetectableObject(int argument_count,
|
||||
int ast_id) {
|
||||
void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
|
||||
BAILOUT("inlined runtime function: IsUndetectableObject");
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
|
||||
int argument_count,
|
||||
int ast_id) {
|
||||
CallRuntime* call) {
|
||||
BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf");
|
||||
}
|
||||
|
||||
|
||||
// Support for construct call checks.
|
||||
void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 0);
|
||||
ast_context()->ReturnInstruction(new HIsConstructCall, ast_id);
|
||||
void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 0);
|
||||
ast_context()->ReturnInstruction(new HIsConstructCall, call->id());
|
||||
}
|
||||
|
||||
|
||||
// Support for arguments.length and arguments[?].
|
||||
void HGraphBuilder::GenerateArgumentsLength(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 0);
|
||||
void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 0);
|
||||
HInstruction* elements = AddInstruction(new HArgumentsElements);
|
||||
HArgumentsLength* result = new HArgumentsLength(elements);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateArguments(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 1);
|
||||
void HGraphBuilder::GenerateArguments(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 1);
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
HValue* index = Pop();
|
||||
HInstruction* elements = AddInstruction(new HArgumentsElements);
|
||||
HInstruction* length = AddInstruction(new HArgumentsLength(elements));
|
||||
HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
// Support for accessing the class and value fields of an object.
|
||||
void HGraphBuilder::GenerateClassOf(int argument_count, int ast_id) {
|
||||
void HGraphBuilder::GenerateClassOf(CallRuntime* call) {
|
||||
// The special form detected by IsClassOfTest is detected before we get here
|
||||
// and does not cause a bailout.
|
||||
BAILOUT("inlined runtime function: ClassOf");
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateValueOf(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 1);
|
||||
void HGraphBuilder::GenerateValueOf(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 1);
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
HValue* value = Pop();
|
||||
HValueOf* result = new HValueOf(value);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) {
|
||||
void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
|
||||
BAILOUT("inlined runtime function: SetValueOf");
|
||||
}
|
||||
|
||||
|
||||
// Fast support for charCodeAt(n).
|
||||
void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 2);
|
||||
void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 2);
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
VISIT_FOR_VALUE(call->arguments()->at(1));
|
||||
HValue* index = Pop();
|
||||
HValue* string = Pop();
|
||||
HStringCharCodeAt* result = BuildStringCharCodeAt(string, index);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
// Fast support for string.charAt(n) and string[n].
|
||||
void HGraphBuilder::GenerateStringCharFromCode(int argument_count,
|
||||
int ast_id) {
|
||||
void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
|
||||
BAILOUT("inlined runtime function: StringCharFromCode");
|
||||
}
|
||||
|
||||
|
||||
// Fast support for string.charAt(n) and string[n].
|
||||
void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) {
|
||||
ASSERT_EQ(2, argument_count);
|
||||
void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
|
||||
ASSERT_EQ(2, call->arguments()->length());
|
||||
VisitArgumentList(call->arguments());
|
||||
CHECK_BAILOUT;
|
||||
HContext* context = new HContext;
|
||||
AddInstruction(context);
|
||||
HCallStub* result =
|
||||
new HCallStub(context, CodeStub::StringCharAt, argument_count);
|
||||
PreProcessCall(result);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
HCallStub* result = new HCallStub(context, CodeStub::StringCharAt, 2);
|
||||
Drop(2);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
// Fast support for object equality testing.
|
||||
void HGraphBuilder::GenerateObjectEquals(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 2);
|
||||
void HGraphBuilder::GenerateObjectEquals(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 2);
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
VISIT_FOR_VALUE(call->arguments()->at(1));
|
||||
HValue* right = Pop();
|
||||
HValue* left = Pop();
|
||||
HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateLog(int argument_count, int ast_id) {
|
||||
UNREACHABLE(); // We caught this in VisitCallRuntime.
|
||||
void HGraphBuilder::GenerateLog(CallRuntime* call) {
|
||||
// %_Log is ignored in optimized code.
|
||||
ast_context()->ReturnValue(graph()->GetConstantUndefined());
|
||||
}
|
||||
|
||||
|
||||
// Fast support for Math.random().
|
||||
void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) {
|
||||
void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) {
|
||||
BAILOUT("inlined runtime function: RandomHeapNumber");
|
||||
}
|
||||
|
||||
|
||||
// Fast support for StringAdd.
|
||||
void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) {
|
||||
ASSERT_EQ(2, argument_count);
|
||||
void HGraphBuilder::GenerateStringAdd(CallRuntime* call) {
|
||||
ASSERT_EQ(2, call->arguments()->length());
|
||||
VisitArgumentList(call->arguments());
|
||||
CHECK_BAILOUT;
|
||||
HContext* context = new HContext;
|
||||
AddInstruction(context);
|
||||
HCallStub* result =
|
||||
new HCallStub(context, CodeStub::StringAdd, argument_count);
|
||||
PreProcessCall(result);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
HCallStub* result = new HCallStub(context, CodeStub::StringAdd, 2);
|
||||
Drop(2);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
// Fast support for SubString.
|
||||
void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) {
|
||||
ASSERT_EQ(3, argument_count);
|
||||
void HGraphBuilder::GenerateSubString(CallRuntime* call) {
|
||||
ASSERT_EQ(3, call->arguments()->length());
|
||||
VisitArgumentList(call->arguments());
|
||||
CHECK_BAILOUT;
|
||||
HContext* context = new HContext;
|
||||
AddInstruction(context);
|
||||
HCallStub* result =
|
||||
new HCallStub(context, CodeStub::SubString, argument_count);
|
||||
PreProcessCall(result);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
HCallStub* result = new HCallStub(context, CodeStub::SubString, 3);
|
||||
Drop(3);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
// Fast support for StringCompare.
|
||||
void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) {
|
||||
ASSERT_EQ(2, argument_count);
|
||||
void HGraphBuilder::GenerateStringCompare(CallRuntime* call) {
|
||||
ASSERT_EQ(2, call->arguments()->length());
|
||||
VisitArgumentList(call->arguments());
|
||||
CHECK_BAILOUT;
|
||||
HContext* context = new HContext;
|
||||
AddInstruction(context);
|
||||
HCallStub* result =
|
||||
new HCallStub(context, CodeStub::StringCompare, argument_count);
|
||||
PreProcessCall(result);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
HCallStub* result = new HCallStub(context, CodeStub::StringCompare, 2);
|
||||
Drop(2);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
// Support for direct calls from JavaScript to native RegExp code.
|
||||
void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) {
|
||||
ASSERT_EQ(4, argument_count);
|
||||
void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
|
||||
ASSERT_EQ(4, call->arguments()->length());
|
||||
VisitArgumentList(call->arguments());
|
||||
CHECK_BAILOUT;
|
||||
HContext* context = new HContext;
|
||||
AddInstruction(context);
|
||||
HCallStub* result =
|
||||
new HCallStub(context, CodeStub::RegExpExec, argument_count);
|
||||
PreProcessCall(result);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
HCallStub* result = new HCallStub(context, CodeStub::RegExpExec, 4);
|
||||
Drop(4);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
// Construct a RegExp exec result with two in-object properties.
|
||||
void HGraphBuilder::GenerateRegExpConstructResult(int argument_count,
|
||||
int ast_id) {
|
||||
ASSERT_EQ(3, argument_count);
|
||||
void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
|
||||
ASSERT_EQ(3, call->arguments()->length());
|
||||
VisitArgumentList(call->arguments());
|
||||
CHECK_BAILOUT;
|
||||
HContext* context = new HContext;
|
||||
AddInstruction(context);
|
||||
HCallStub* result =
|
||||
new HCallStub(context, CodeStub::RegExpConstructResult, argument_count);
|
||||
PreProcessCall(result);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
HCallStub* result = new HCallStub(context, CodeStub::RegExpConstructResult, 3);
|
||||
Drop(3);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
// Support for fast native caches.
|
||||
void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) {
|
||||
void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
|
||||
BAILOUT("inlined runtime function: GetFromCache");
|
||||
}
|
||||
|
||||
|
||||
// Fast support for number to string.
|
||||
void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) {
|
||||
ASSERT_EQ(1, argument_count);
|
||||
void HGraphBuilder::GenerateNumberToString(CallRuntime* call) {
|
||||
ASSERT_EQ(1, call->arguments()->length());
|
||||
VisitArgumentList(call->arguments());
|
||||
CHECK_BAILOUT;
|
||||
HContext* context = new HContext;
|
||||
AddInstruction(context);
|
||||
HCallStub* result =
|
||||
new HCallStub(context, CodeStub::NumberToString, argument_count);
|
||||
PreProcessCall(result);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
HCallStub* result = new HCallStub(context, CodeStub::NumberToString, 1);
|
||||
Drop(1);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
// Fast swapping of elements. Takes three expressions, the object and two
|
||||
// indices. This should only be used if the indices are known to be
|
||||
// non-negative and within bounds of the elements array at the call site.
|
||||
void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) {
|
||||
void HGraphBuilder::GenerateSwapElements(CallRuntime* call) {
|
||||
BAILOUT("inlined runtime function: SwapElements");
|
||||
}
|
||||
|
||||
|
||||
// Fast call for custom callbacks.
|
||||
void HGraphBuilder::GenerateCallFunction(int argument_count, int ast_id) {
|
||||
void HGraphBuilder::GenerateCallFunction(CallRuntime* call) {
|
||||
BAILOUT("inlined runtime function: CallFunction");
|
||||
}
|
||||
|
||||
|
||||
// Fast call to math functions.
|
||||
void HGraphBuilder::GenerateMathPow(int argument_count, int ast_id) {
|
||||
ASSERT_EQ(2, argument_count);
|
||||
void HGraphBuilder::GenerateMathPow(CallRuntime* call) {
|
||||
ASSERT_EQ(2, call->arguments()->length());
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
VISIT_FOR_VALUE(call->arguments()->at(1));
|
||||
HValue* right = Pop();
|
||||
HValue* left = Pop();
|
||||
HPower* result = new HPower(left, right);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) {
|
||||
ASSERT_EQ(1, argument_count);
|
||||
void HGraphBuilder::GenerateMathSin(CallRuntime* call) {
|
||||
ASSERT_EQ(1, call->arguments()->length());
|
||||
VisitArgumentList(call->arguments());
|
||||
CHECK_BAILOUT;
|
||||
HContext* context = new HContext;
|
||||
AddInstruction(context);
|
||||
HCallStub* result =
|
||||
new HCallStub(context, CodeStub::TranscendentalCache, argument_count);
|
||||
HCallStub* result = new HCallStub(context, CodeStub::TranscendentalCache, 1);
|
||||
result->set_transcendental_type(TranscendentalCache::SIN);
|
||||
PreProcessCall(result);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
Drop(1);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) {
|
||||
ASSERT_EQ(1, argument_count);
|
||||
void HGraphBuilder::GenerateMathCos(CallRuntime* call) {
|
||||
ASSERT_EQ(1, call->arguments()->length());
|
||||
VisitArgumentList(call->arguments());
|
||||
CHECK_BAILOUT;
|
||||
HContext* context = new HContext;
|
||||
AddInstruction(context);
|
||||
HCallStub* result =
|
||||
new HCallStub(context, CodeStub::TranscendentalCache, argument_count);
|
||||
HCallStub* result = new HCallStub(context, CodeStub::TranscendentalCache, 1);
|
||||
result->set_transcendental_type(TranscendentalCache::COS);
|
||||
PreProcessCall(result);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
Drop(1);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) {
|
||||
ASSERT_EQ(1, argument_count);
|
||||
void HGraphBuilder::GenerateMathLog(CallRuntime* call) {
|
||||
ASSERT_EQ(1, call->arguments()->length());
|
||||
VisitArgumentList(call->arguments());
|
||||
CHECK_BAILOUT;
|
||||
HContext* context = new HContext;
|
||||
AddInstruction(context);
|
||||
HCallStub* result =
|
||||
new HCallStub(context, CodeStub::TranscendentalCache, argument_count);
|
||||
HCallStub* result = new HCallStub(context, CodeStub::TranscendentalCache, 1);
|
||||
result->set_transcendental_type(TranscendentalCache::LOG);
|
||||
PreProcessCall(result);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
Drop(1);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateMathSqrt(int argument_count, int ast_id) {
|
||||
void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
|
||||
BAILOUT("inlined runtime function: MathSqrt");
|
||||
}
|
||||
|
||||
|
||||
// Check whether two RegExps are equivalent
|
||||
void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count,
|
||||
int ast_id) {
|
||||
void HGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) {
|
||||
BAILOUT("inlined runtime function: IsRegExpEquivalent");
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count,
|
||||
int ast_id) {
|
||||
ASSERT(argument_count == 1);
|
||||
void HGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
|
||||
ASSERT(call->arguments()->length() == 1);
|
||||
VISIT_FOR_VALUE(call->arguments()->at(0));
|
||||
HValue* value = Pop();
|
||||
HGetCachedArrayIndex* result = new HGetCachedArrayIndex(value);
|
||||
ast_context()->ReturnInstruction(result, ast_id);
|
||||
ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count,
|
||||
int ast_id) {
|
||||
void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) {
|
||||
BAILOUT("inlined runtime function: FastAsciiArrayJoin");
|
||||
}
|
||||
|
||||
|
@ -647,8 +647,7 @@ class HGraphBuilder: public AstVisitor {
|
||||
|
||||
private:
|
||||
// Type of a member function that generates inline code for a native function.
|
||||
typedef void (HGraphBuilder::*InlineFunctionGenerator)(int argument_count,
|
||||
int ast_id);
|
||||
typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
|
||||
|
||||
// Forward declarations for inner scope classes.
|
||||
class SubgraphScope;
|
||||
@ -672,7 +671,7 @@ class HGraphBuilder: public AstVisitor {
|
||||
|
||||
// Generators for inline runtime functions.
|
||||
#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
|
||||
void Generate##Name(int argument_count, int ast_id);
|
||||
void Generate##Name(CallRuntime* call);
|
||||
|
||||
INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
|
||||
INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
|
||||
@ -699,10 +698,14 @@ class HGraphBuilder: public AstVisitor {
|
||||
HBasicBlock* true_block,
|
||||
HBasicBlock* false_block);
|
||||
|
||||
// Visit an argument subexpression.
|
||||
// Visit an argument subexpression and emit a push to the outgoing
|
||||
// arguments.
|
||||
void VisitArgument(Expression* expr);
|
||||
void VisitArgumentList(ZoneList<Expression*>* arguments);
|
||||
|
||||
// Visit a list of expressions from left to right, each in a value context.
|
||||
void VisitExpressions(ZoneList<Expression*>* exprs);
|
||||
|
||||
void AddPhi(HPhi* phi);
|
||||
|
||||
void PushAndAdd(HInstruction* instr);
|
||||
|
@ -536,10 +536,12 @@ class ShallowIterator BASE_EMBEDDED {
|
||||
inline LEnvironment* env() { return env_; }
|
||||
|
||||
private:
|
||||
inline bool ShouldSkip(LOperand* op) {
|
||||
return op == NULL || op->IsConstantOperand() || op->IsArgument();
|
||||
}
|
||||
|
||||
inline int AdvanceToNext(int start) {
|
||||
while (start < limit_ &&
|
||||
(env_->values()->at(start) == NULL ||
|
||||
env_->values()->at(start)->IsConstantOperand())) {
|
||||
while (start < limit_ && ShouldSkip(env_->values()->at(start))) {
|
||||
start++;
|
||||
}
|
||||
return start;
|
||||
|
Loading…
Reference in New Issue
Block a user