const ParameterCount& actual,
Handle<Code> code_constant,
const Operand& code_operand,
- Label* done,
+ NearLabel* done,
InvokeFlag flag,
PostCallGenerator* post_call_generator) {
bool definitely_matches = false;
const ParameterCount& actual,
InvokeFlag flag,
PostCallGenerator* post_call_generator) {
- Label done;
+ NearLabel done;
InvokePrologue(expected, actual, Handle<Code>::null(), code,
&done, flag, post_call_generator);
if (flag == CALL_FUNCTION) {
RelocInfo::Mode rmode,
InvokeFlag flag,
PostCallGenerator* post_call_generator) {
- Label done;
+ NearLabel done;
Operand dummy(eax);
InvokePrologue(expected, actual, code, dummy, &done,
flag, post_call_generator);
const ParameterCount& actual,
Handle<Code> code_constant,
const Operand& code_operand,
- Label* done,
+ NearLabel* done,
InvokeFlag flag,
PostCallGenerator* post_call_generator = NULL);
deoptimization_info_[index].pc_after_gap = pc;
}
+ // Get the end pc offset of the last safepoint, including the code generated
+ // until the end of the gap following it.
+ unsigned GetPcAfterGap() {
+ int index = deoptimization_info_.length();
+ if (index == 0) return 0;
+ return deoptimization_info_[index - 1].pc_after_gap;
+ }
+
// Emit the safepoint table after the body. The number of bits per
// entry must be enough to hold all the pointer indexes.
void Emit(Assembler* assembler, int bits_per_entry);
// Does not check the "reg" part of the Operand.
bool AddressUsesRegister(Register reg) const;
+ // Queries related to the size of the generated instruction.
+ // Whether the generated instruction will have a REX prefix.
+ bool requires_rex() const { return rex_ != 0; }
+ // Size of the ModR/M, SIB and displacement parts of the generated
+ // instruction.
+ int operand_size() const { return len_; }
+
private:
byte rex_;
byte buf_[6];
// 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 {
+class SafepointGenerator : public CallWrapper {
public:
SafepointGenerator(LCodeGen* codegen,
LPointerMap* pointers,
: codegen_(codegen),
pointers_(pointers),
deoptimization_index_(deoptimization_index),
- ensure_reloc_space_(ensure_reloc_space),
- previous_safepoint_position_(-kMinSafepointSize) { }
+ ensure_reloc_space_(ensure_reloc_space) { }
virtual ~SafepointGenerator() { }
- virtual void Generate() {
+ virtual void BeforeCall(int call_size) {
+ ASSERT(call_size >= 0);
// Ensure that we have enough space after the previous safepoint position
- // for the generated code there.
- int position = codegen_->masm()->pc_offset();
- ASSERT(position > previous_safepoint_position_);
- if (position < previous_safepoint_position_ + kMinSafepointSize) {
- int padding_size =
- previous_safepoint_position_ + kMinSafepointSize - position;
+ // for the jump generated there.
+ int call_end = codegen_->masm()->pc_offset() + call_size;
+ int prev_jump_end = codegen_->LastSafepointEnd() + kMinSafepointSize;
+ if (call_end < prev_jump_end) {
+ int padding_size = prev_jump_end - call_end;
STATIC_ASSERT(kMinSafepointSize <= 9); // One multibyte nop is enough.
codegen_->masm()->nop(padding_size);
- position += padding_size;
}
+ }
+
+ virtual void AfterCall() {
// 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_);
- previous_safepoint_position_ = position;
}
private:
LPointerMap* pointers_;
int deoptimization_index_;
bool ensure_reloc_space_;
- int previous_safepoint_position_;
};
int arguments,
int deoptimization_index);
void RecordPosition(int position);
+ int LastSafepointEnd() {
+ return static_cast<int>(safepoints_.GetPcAfterGap());
+ }
static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
// 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, post_call_generator);
+ InvokeCode(rdx, expected, expected, flag, call_wrapper);
}
void MacroAssembler::Call(ExternalReference ext) {
+#ifdef DEBUG
+ int pre_position = pc_offset();
+#endif
movq(kScratchRegister, ext);
call(kScratchRegister);
+#ifdef DEBUG
+ int post_position = pc_offset();
+ CHECK_EQ(pre_position + CallSize(ext), post_position);
+#endif
}
void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) {
+#ifdef DEBUG
+ int pre_position = pc_offset();
+#endif
movq(kScratchRegister, destination, rmode);
call(kScratchRegister);
+#ifdef DEBUG
+ int post_position = pc_offset();
+ CHECK_EQ(pre_position + CallSize(destination, rmode), post_position);
+#endif
}
void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
+#ifdef DEBUG
+ int pre_position = pc_offset();
+#endif
ASSERT(RelocInfo::IsCodeTarget(rmode));
call(code_object, rmode);
+#ifdef DEBUG
+ int post_position = pc_offset();
+ CHECK_EQ(pre_position + CallSize(code_object), post_position);
+#endif
}
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
NearLabel done;
InvokePrologue(expected,
actual,
code,
&done,
flag,
- post_call_generator);
+ call_wrapper);
if (flag == CALL_FUNCTION) {
+ if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(code));
call(code);
- if (post_call_generator != NULL) post_call_generator->Generate();
+ if (call_wrapper != NULL) call_wrapper->AfterCall();
} else {
ASSERT(flag == JUMP_FUNCTION);
jmp(code);
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
NearLabel done;
Register dummy = rax;
InvokePrologue(expected,
dummy,
&done,
flag,
- post_call_generator);
+ call_wrapper);
if (flag == CALL_FUNCTION) {
+ if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(code));
Call(code, rmode);
- if (post_call_generator != NULL) post_call_generator->Generate();
+ if (call_wrapper != NULL) call_wrapper->AfterCall();
} else {
ASSERT(flag == JUMP_FUNCTION);
Jump(code, rmode);
void MacroAssembler::InvokeFunction(Register function,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
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, post_call_generator);
+ InvokeCode(rdx, expected, actual, flag, call_wrapper);
}
void MacroAssembler::InvokeFunction(JSFunction* function,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
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, post_call_generator);
+ InvokeCode(rdx, expected, actual, flag, call_wrapper);
} else {
// Invoke the cached code.
Handle<Code> code(function->code());
actual,
RelocInfo::CODE_TARGET,
flag,
- post_call_generator);
+ call_wrapper);
}
}
// Forward declaration.
class JumpTarget;
-class PostCallGenerator;
+class CallWrapper;
struct SmiIndex {
SmiIndex(Register index_register, ScaleFactor scale)
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = NULL);
void InvokeCode(Handle<Code> code,
const ParameterCount& expected,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = 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,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = NULL);
void InvokeFunction(JSFunction* function,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = 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,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = NULL);
// Store the function for the given builtin in the target register.
void GetBuiltinFunction(Register target, Builtins::JavaScript id);
void Call(ExternalReference ext);
void Call(Handle<Code> code_object, RelocInfo::Mode rmode);
+ // The size of the code generated for different call instructions.
+ int CallSize(Address destination, RelocInfo::Mode rmode) {
+ return kCallInstructionLength;
+ }
+ int CallSize(ExternalReference ext) {
+ return kCallInstructionLength;
+ }
+ int CallSize(Handle<Code> code_object) {
+ // Code calls use 32-bit relative addressing.
+ return kShortCallInstructionLength;
+ }
+ int CallSize(Register target) {
+ // Opcode: REX_opt FF /2 m64
+ return (target.high_bit() != 0) ? 3 : 2;
+ }
+ int CallSize(const Operand& target) {
+ // Opcode: REX_opt FF /2 m64
+ return (target.requires_rex() ? 2 : 1) + target.operand_size();
+ }
+
// Emit call to the code we are currently generating.
void CallSelf() {
Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
Register code_register,
LabelType* done,
InvokeFlag flag,
- PostCallGenerator* post_call_generator);
+ CallWrapper* call_wrapper);
// 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
+// right before or after a call instruction. As an example this can be used to
// generate safepoint data after calls for crankshaft.
-class PostCallGenerator {
+class CallWrapper {
public:
- PostCallGenerator() { }
- virtual ~PostCallGenerator() { }
- virtual void Generate() = 0;
+ CallWrapper() { }
+ virtual ~CallWrapper() { }
+ // Called just before emitting a call. Argument is the size of the generated
+ // call code.
+ virtual void BeforeCall(int call_size) = 0;
+ // Called just after emitting a call, i.e., at the return site for the call.
+ virtual void AfterCall() = 0;
};
Register code_register,
LabelType* done,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
bool definitely_matches = false;
NearLabel invoke;
if (expected.is_immediate()) {
}
if (flag == CALL_FUNCTION) {
+ if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(adaptor));
Call(adaptor, RelocInfo::CODE_TARGET);
- if (post_call_generator != NULL) post_call_generator->Generate();
+ if (call_wrapper != NULL) call_wrapper->AfterCall();
jmp(done);
} else {
Jump(adaptor, RelocInfo::CODE_TARGET);