Commit 1e89c4aa authored by ager@chromium.org's avatar ager@chromium.org

x64: implement apply with arguments in lithium backend.

Includes the plumbing to make sure that all calls generated by the macroassembler for lithium will generate record a safepoint.

Review URL: http://codereview.chromium.org/6469053

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6859 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c411adca
......@@ -3119,8 +3119,8 @@ void Assembler::RecordDebugBreakSlot() {
}
void Assembler::RecordComment(const char* msg) {
if (FLAG_code_comments) {
void Assembler::RecordComment(const char* msg, bool force) {
if (FLAG_code_comments || force) {
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
}
......
......@@ -1319,7 +1319,7 @@ class Assembler : public Malloced {
// Record a comment relocation entry that can be used by a disassembler.
// Use --code-comments to enable.
void RecordComment(const char* msg);
void RecordComment(const char* msg, bool force = false);
// Writes a single word of data in the code stream.
// Used for inline tables, e.g., jump-tables.
......
......@@ -37,6 +37,37 @@ namespace v8 {
namespace internal {
// When invoking builtins, we need to record the safepoint in the middle of
// the invoke instruction sequence generated by the macro assembler.
class SafepointGenerator : public PostCallGenerator {
public:
SafepointGenerator(LCodeGen* codegen,
LPointerMap* pointers,
int deoptimization_index,
bool ensure_reloc_space = false)
: codegen_(codegen),
pointers_(pointers),
deoptimization_index_(deoptimization_index),
ensure_reloc_space_(ensure_reloc_space) { }
virtual ~SafepointGenerator() { }
virtual void Generate() {
// Ensure that we have enough space in the reloc info to patch
// this with calls when doing deoptimization.
if (ensure_reloc_space_) {
codegen_->masm()->RecordComment(RelocInfo::kFillerCommentString, true);
}
codegen_->RecordSafepoint(pointers_, deoptimization_index_);
}
private:
LCodeGen* codegen_;
LPointerMap* pointers_;
int deoptimization_index_;
bool ensure_reloc_space_;
};
#define __ masm()->
bool LCodeGen::GenerateCode() {
......@@ -1996,7 +2027,70 @@ void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
Abort("Unimplemented: %s", "DoApplyArguments");
Register receiver = ToRegister(instr->receiver());
Register function = ToRegister(instr->function());
Register length = ToRegister(instr->length());
Register elements = ToRegister(instr->elements());
ASSERT(receiver.is(rax)); // Used for parameter count.
ASSERT(function.is(rdi)); // Required by InvokeFunction.
ASSERT(ToRegister(instr->result()).is(rax));
// If the receiver is null or undefined, we have to pass the global object
// as a receiver.
NearLabel global_object, receiver_ok;
__ CompareRoot(receiver, Heap::kNullValueRootIndex);
__ j(equal, &global_object);
__ CompareRoot(receiver, Heap::kUndefinedValueRootIndex);
__ j(equal, &global_object);
// The receiver should be a JS object.
Condition is_smi = __ CheckSmi(receiver);
DeoptimizeIf(is_smi, instr->environment());
__ CmpObjectType(receiver, FIRST_JS_OBJECT_TYPE, kScratchRegister);
DeoptimizeIf(below, instr->environment());
__ jmp(&receiver_ok);
__ bind(&global_object);
// TODO(kmillikin): We have a hydrogen value for the global object. See
// if it's better to use it than to explicitly fetch it from the context
// here.
__ movq(receiver, Operand(rbp, StandardFrameConstants::kContextOffset));
__ movq(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX));
__ bind(&receiver_ok);
// Copy the arguments to this function possibly from the
// adaptor frame below it.
const uint32_t kArgumentsLimit = 1 * KB;
__ cmpq(length, Immediate(kArgumentsLimit));
DeoptimizeIf(above, instr->environment());
__ push(receiver);
__ movq(receiver, length);
// Loop through the arguments pushing them onto the execution
// stack.
NearLabel invoke, loop;
// length is a small non-negative integer, due to the test above.
__ testl(length, length);
__ j(zero, &invoke);
__ bind(&loop);
__ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
__ decl(length);
__ j(not_zero, &loop);
// Invoke the function.
__ bind(&invoke);
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env);
SafepointGenerator safepoint_generator(this,
pointers,
env->deoptimization_index(),
true);
v8::internal::ParameterCount actual(rax);
__ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
}
......
......@@ -1140,8 +1140,15 @@ LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
Abort("Unimplemented: %s", "DoApplyArguments");
return NULL;
LOperand* function = UseFixed(instr->function(), rdi);
LOperand* receiver = UseFixed(instr->receiver(), rax);
LOperand* length = UseFixed(instr->length(), rbx);
LOperand* elements = UseFixed(instr->elements(), rcx);
LApplyArguments* result = new LApplyArguments(function,
receiver,
length,
elements);
return MarkAsCall(DefineFixed(result, rax), instr, CAN_DEOPTIMIZE_EAGERLY);
}
......
......@@ -623,7 +623,9 @@ MaybeObject* MacroAssembler::TryJumpToExternalReference(
}
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag,
PostCallGenerator* post_call_generator) {
// Calls are not allowed in some stubs.
ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
......@@ -632,7 +634,7 @@ void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
// parameter count to avoid emitting code to do the check.
ParameterCount expected(0);
GetBuiltinEntry(rdx, id);
InvokeCode(rdx, expected, expected, flag);
InvokeCode(rdx, expected, expected, flag, post_call_generator);
}
......@@ -1835,11 +1837,19 @@ void MacroAssembler::DebugBreak() {
void MacroAssembler::InvokeCode(Register code,
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag) {
InvokeFlag flag,
PostCallGenerator* post_call_generator) {
NearLabel done;
InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
InvokePrologue(expected,
actual,
Handle<Code>::null(),
code,
&done,
flag,
post_call_generator);
if (flag == CALL_FUNCTION) {
call(code);
if (post_call_generator != NULL) post_call_generator->Generate();
} else {
ASSERT(flag == JUMP_FUNCTION);
jmp(code);
......@@ -1852,12 +1862,20 @@ void MacroAssembler::InvokeCode(Handle<Code> code,
const ParameterCount& expected,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag) {
InvokeFlag flag,
PostCallGenerator* post_call_generator) {
NearLabel done;
Register dummy = rax;
InvokePrologue(expected, actual, code, dummy, &done, flag);
InvokePrologue(expected,
actual,
code,
dummy,
&done,
flag,
post_call_generator);
if (flag == CALL_FUNCTION) {
Call(code, rmode);
if (post_call_generator != NULL) post_call_generator->Generate();
} else {
ASSERT(flag == JUMP_FUNCTION);
Jump(code, rmode);
......@@ -1868,7 +1886,8 @@ void MacroAssembler::InvokeCode(Handle<Code> code,
void MacroAssembler::InvokeFunction(Register function,
const ParameterCount& actual,
InvokeFlag flag) {
InvokeFlag flag,
PostCallGenerator* post_call_generator) {
ASSERT(function.is(rdi));
movq(rdx, FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
movq(rsi, FieldOperand(function, JSFunction::kContextOffset));
......@@ -1879,13 +1898,14 @@ void MacroAssembler::InvokeFunction(Register function,
movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
ParameterCount expected(rbx);
InvokeCode(rdx, expected, actual, flag);
InvokeCode(rdx, expected, actual, flag, post_call_generator);
}
void MacroAssembler::InvokeFunction(JSFunction* function,
const ParameterCount& actual,
InvokeFlag flag) {
InvokeFlag flag,
PostCallGenerator* post_call_generator) {
ASSERT(function->is_compiled());
// Get the function and setup the context.
Move(rdi, Handle<JSFunction>(function));
......@@ -1896,12 +1916,17 @@ void MacroAssembler::InvokeFunction(JSFunction* function,
// the Code object every time we call the function.
movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
ParameterCount expected(function->shared()->formal_parameter_count());
InvokeCode(rdx, expected, actual, flag);
InvokeCode(rdx, expected, actual, flag, post_call_generator);
} else {
// Invoke the cached code.
Handle<Code> code(function->code());
ParameterCount expected(function->shared()->formal_parameter_count());
InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag);
InvokeCode(code,
expected,
actual,
RelocInfo::CODE_TARGET,
flag,
post_call_generator);
}
}
......
......@@ -58,6 +58,7 @@ typedef Operand MemOperand;
// Forward declaration.
class JumpTarget;
class PostCallGenerator;
struct SmiIndex {
SmiIndex(Register index_register, ScaleFactor scale)
......@@ -183,27 +184,33 @@ class MacroAssembler: public Assembler {
void InvokeCode(Register code,
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag);
InvokeFlag flag,
PostCallGenerator* post_call_generator = NULL);
void InvokeCode(Handle<Code> code,
const ParameterCount& expected,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag);
InvokeFlag flag,
PostCallGenerator* post_call_generator = NULL);
// Invoke the JavaScript function in the given register. Changes the
// current context to the context in the function before invoking.
void InvokeFunction(Register function,
const ParameterCount& actual,
InvokeFlag flag);
InvokeFlag flag,
PostCallGenerator* post_call_generator = NULL);
void InvokeFunction(JSFunction* function,
const ParameterCount& actual,
InvokeFlag flag);
InvokeFlag flag,
PostCallGenerator* post_call_generator = NULL);
// Invoke specified builtin JavaScript function. Adds an entry to
// the unresolved list if the name does not resolve.
void InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag);
void InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag,
PostCallGenerator* post_call_generator = NULL);
// Store the function for the given builtin in the target register.
void GetBuiltinFunction(Register target, Builtins::JavaScript id);
......@@ -996,7 +1003,8 @@ class MacroAssembler: public Assembler {
Handle<Code> code_constant,
Register code_register,
LabelType* done,
InvokeFlag flag);
InvokeFlag flag,
PostCallGenerator* post_call_generator);
// Activation support.
void EnterFrame(StackFrame::Type type);
......@@ -1050,6 +1058,17 @@ class CodePatcher {
};
// Helper class for generating code or data associated with the code
// right after a call instruction. As an example this can be used to
// generate safepoint data after calls for crankshaft.
class PostCallGenerator {
public:
PostCallGenerator() { }
virtual ~PostCallGenerator() { }
virtual void Generate() = 0;
};
// -----------------------------------------------------------------------------
// Static helper functions.
......@@ -1756,7 +1775,8 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
Handle<Code> code_constant,
Register code_register,
LabelType* done,
InvokeFlag flag) {
InvokeFlag flag,
PostCallGenerator* post_call_generator) {
bool definitely_matches = false;
NearLabel invoke;
if (expected.is_immediate()) {
......@@ -1807,6 +1827,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
if (flag == CALL_FUNCTION) {
Call(adaptor, RelocInfo::CODE_TARGET);
if (post_call_generator != NULL) post_call_generator->Generate();
jmp(done);
} else {
Jump(adaptor, RelocInfo::CODE_TARGET);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment