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
This commit is contained in:
parent
c411adca55
commit
1e89c4aa67
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user