}
-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));
}
// 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.
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() {
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);
}
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);
}
}
-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());
// 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);
}
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);
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);
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));
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));
// 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);
}
}
// Forward declaration.
class JumpTarget;
+class PostCallGenerator;
struct SmiIndex {
SmiIndex(Register index_register, ScaleFactor scale)
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);
Handle<Code> code_constant,
Register code_register,
LabelType* done,
- InvokeFlag flag);
+ InvokeFlag flag,
+ PostCallGenerator* post_call_generator);
// Activation support.
void EnterFrame(StackFrame::Type type);
};
+// 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.
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()) {
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);