Index: src/x64/macro-assembler-x64.h |
=================================================================== |
--- src/x64/macro-assembler-x64.h (revision 9531) |
+++ src/x64/macro-assembler-x64.h (working copy) |
@@ -29,6 +29,7 @@ |
#define V8_X64_MACRO_ASSEMBLER_X64_H_ |
#include "assembler.h" |
+#include "frames.h" |
#include "v8globals.h" |
namespace v8 { |
@@ -61,6 +62,11 @@ |
// Convenience for platform-independent signatures. |
typedef Operand MemOperand; |
+enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET }; |
+enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; |
+ |
+bool AreAliased(Register r1, Register r2, Register r3, Register r4); |
+ |
// Forward declaration. |
class JumpTarget; |
@@ -72,6 +78,7 @@ |
ScaleFactor scale; |
}; |
+ |
// MacroAssembler implements a collection of frequently used macros. |
class MacroAssembler: public Assembler { |
public: |
@@ -134,57 +141,146 @@ |
void CompareRoot(const Operand& with, Heap::RootListIndex index); |
void PushRoot(Heap::RootListIndex index); |
- // --------------------------------------------------------------------------- |
- // GC Support |
+ // These functions do not arrange the registers in any particular order so |
+ // they are not useful for calls that can cause a GC. The caller can |
+ // exclude up to 3 registers that do not need to be saved and restored. |
+ void PushCallerSaved(SaveFPRegsMode fp_mode, |
+ Register exclusion1 = no_reg, |
+ Register exclusion2 = no_reg, |
+ Register exclusion3 = no_reg); |
+ void PopCallerSaved(SaveFPRegsMode fp_mode, |
+ Register exclusion1 = no_reg, |
+ Register exclusion2 = no_reg, |
+ Register exclusion3 = no_reg); |
- // For page containing |object| mark region covering |addr| dirty. |
- // RecordWriteHelper only works if the object is not in new |
- // space. |
- void RecordWriteHelper(Register object, |
- Register addr, |
- Register scratch); |
+// --------------------------------------------------------------------------- |
+// GC Support |
- // Check if object is in new space. The condition cc can be equal or |
- // not_equal. If it is equal a jump will be done if the object is on new |
- // space. The register scratch can be object itself, but it will be clobbered. |
- void InNewSpace(Register object, |
- Register scratch, |
- Condition cc, |
- Label* branch, |
- Label::Distance near_jump = Label::kFar); |
- // For page containing |object| mark region covering [object+offset] |
- // dirty. |object| is the object being stored into, |value| is the |
- // object being stored. If |offset| is zero, then the |scratch| |
- // register contains the array index into the elements array |
- // represented as an untagged 32-bit integer. All registers are |
- // clobbered by the operation. RecordWrite filters out smis so it |
- // does not update the write barrier if the value is a smi. |
- void RecordWrite(Register object, |
- int offset, |
- Register value, |
- Register scratch); |
+ enum RememberedSetFinalAction { |
+ kReturnAtEnd, |
+ kFallThroughAtEnd |
+ }; |
- // For page containing |object| mark region covering [address] |
+ // Record in the remembered set the fact that we have a pointer to new space |
+ // at the address pointed to by the addr register. Only works if addr is not |
+ // in new space. |
+ void RememberedSetHelper(Register object, // Used for debug code. |
+ Register addr, |
+ Register scratch, |
+ SaveFPRegsMode save_fp, |
+ RememberedSetFinalAction and_then); |
+ |
+ void CheckPageFlag(Register object, |
+ Register scratch, |
+ int mask, |
+ Condition cc, |
+ Label* condition_met, |
+ Label::Distance condition_met_distance = Label::kFar); |
+ |
+ // Check if object is in new space. Jumps if the object is not in new space. |
+ // The register scratch can be object itself, but scratch will be clobbered. |
+ void JumpIfNotInNewSpace(Register object, |
+ Register scratch, |
+ Label* branch, |
+ Label::Distance distance = Label::kFar) { |
+ InNewSpace(object, scratch, not_equal, branch, distance); |
+ } |
+ |
+ // Check if object is in new space. Jumps if the object is in new space. |
+ // The register scratch can be object itself, but it will be clobbered. |
+ void JumpIfInNewSpace(Register object, |
+ Register scratch, |
+ Label* branch, |
+ Label::Distance distance = Label::kFar) { |
+ InNewSpace(object, scratch, equal, branch, distance); |
+ } |
+ |
+ // Check if an object has the black incremental marking color. Also uses rcx! |
+ void JumpIfBlack(Register object, |
+ Register scratch0, |
+ Register scratch1, |
+ Label* on_black, |
+ Label::Distance on_black_distance = Label::kFar); |
+ |
+ // Detects conservatively whether an object is data-only, ie it does need to |
+ // be scanned by the garbage collector. |
+ void JumpIfDataObject(Register value, |
+ Register scratch, |
+ Label* not_data_object, |
+ Label::Distance not_data_object_distance); |
+ |
+ // Checks the color of an object. If the object is already grey or black |
+ // then we just fall through, since it is already live. If it is white and |
+ // we can determine that it doesn't need to be scanned, then we just mark it |
+ // black and fall through. For the rest we jump to the label so the |
+ // incremental marker can fix its assumptions. |
+ void EnsureNotWhite(Register object, |
+ Register scratch1, |
+ Register scratch2, |
+ Label* object_is_white_and_not_data, |
+ Label::Distance distance); |
+ |
+ // Notify the garbage collector that we wrote a pointer into an object. |
+ // |object| is the object being stored into, |value| is the object being |
+ // stored. value and scratch registers are clobbered by the operation. |
+ // The offset is the offset from the start of the object, not the offset from |
+ // the tagged HeapObject pointer. For use with FieldOperand(reg, off). |
+ void RecordWriteField( |
+ Register object, |
+ int offset, |
+ Register value, |
+ Register scratch, |
+ SaveFPRegsMode save_fp, |
+ RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, |
+ SmiCheck smi_check = INLINE_SMI_CHECK); |
+ |
+ // As above, but the offset has the tag presubtracted. For use with |
+ // Operand(reg, off). |
+ void RecordWriteContextSlot( |
+ Register context, |
+ int offset, |
+ Register value, |
+ Register scratch, |
+ SaveFPRegsMode save_fp, |
+ RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, |
+ SmiCheck smi_check = INLINE_SMI_CHECK) { |
+ RecordWriteField(context, |
+ offset + kHeapObjectTag, |
+ value, |
+ scratch, |
+ save_fp, |
+ remembered_set_action, |
+ smi_check); |
+ } |
+ |
+ // Notify the garbage collector that we wrote a pointer into a fixed array. |
+ // |array| is the array being stored into, |value| is the |
+ // object being stored. |index| is the array index represented as a |
+ // Smi. All registers are clobbered by the operation RecordWriteArray |
+ // filters out smis so it does not update the write barrier if the |
+ // value is a smi. |
+ void RecordWriteArray( |
+ Register array, |
+ Register value, |
+ Register index, |
+ SaveFPRegsMode save_fp, |
+ RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, |
+ SmiCheck smi_check = INLINE_SMI_CHECK); |
+ |
+ // For page containing |object| mark region covering |address| |
// dirty. |object| is the object being stored into, |value| is the |
- // object being stored. All registers are clobbered by the |
+ // object being stored. The address and value registers are clobbered by the |
// operation. RecordWrite filters out smis so it does not update |
// the write barrier if the value is a smi. |
- void RecordWrite(Register object, |
- Register address, |
- Register value); |
+ void RecordWrite( |
+ Register object, |
+ Register address, |
+ Register value, |
+ SaveFPRegsMode save_fp, |
+ RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, |
+ SmiCheck smi_check = INLINE_SMI_CHECK); |
- // For page containing |object| mark region covering [object+offset] dirty. |
- // The value is known to not be a smi. |
- // object is the object being stored into, value is the object being stored. |
- // If offset is zero, then the scratch register contains the array index into |
- // the elements array represented as an untagged 32-bit integer. |
- // All registers are clobbered by the operation. |
- void RecordWriteNonSmi(Register object, |
- int offset, |
- Register value, |
- Register scratch); |
- |
#ifdef ENABLE_DEBUGGER_SUPPORT |
// --------------------------------------------------------------------------- |
// Debugger Support |
@@ -192,15 +288,6 @@ |
void DebugBreak(); |
#endif |
- // --------------------------------------------------------------------------- |
- // Activation frames |
- |
- void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); } |
- void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); } |
- |
- void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); } |
- void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); } |
- |
// Enter specific kind of exit frame; either in normal or |
// debug mode. Expects the number of arguments in register rax and |
// sets up the number of arguments in register rdi and the pointer |
@@ -760,6 +847,28 @@ |
Label* fail, |
Label::Distance distance = Label::kFar); |
+ // Check if a map for a JSObject indicates that the object can have both smi |
+ // and HeapObject elements. Jump to the specified label if it does not. |
+ void CheckFastObjectElements(Register map, |
+ Label* fail, |
+ Label::Distance distance = Label::kFar); |
+ |
+ // Check if a map for a JSObject indicates that the object has fast smi only |
+ // elements. Jump to the specified label if it does not. |
+ void CheckFastSmiOnlyElements(Register map, |
+ Label* fail, |
+ Label::Distance distance = Label::kFar); |
+ |
+ // Check to see if maybe_number can be stored as a double in |
+ // FastDoubleElements. If it can, store it at the index specified by key in |
+ // the FastDoubleElements array elements, otherwise jump to fail. |
+ // Note that key must not be smi-tagged. |
+ void StoreNumberToDoubleElements(Register maybe_number, |
+ Register elements, |
+ Register key, |
+ XMMRegister xmm_scratch, |
+ Label* fail); |
+ |
// Check if the map of an object is equal to a specified map and |
// branch to label if not. Skip the smi check if not required |
// (object is known to be a heap object) |
@@ -1119,7 +1228,14 @@ |
int min_length = 0, |
Register scratch = kScratchRegister); |
+ // Initialize fields with filler values. Fields starting at |start_offset| |
+ // not including end_offset are overwritten with the value in |filler|. At |
+ // the end the loop, |start_offset| takes the value of |end_offset|. |
+ void InitializeFieldsWithFiller(Register start_offset, |
+ Register end_offset, |
+ Register filler); |
+ |
// --------------------------------------------------------------------------- |
// StatsCounter support |
@@ -1151,11 +1267,18 @@ |
bool generating_stub() { return generating_stub_; } |
void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; } |
bool allow_stub_calls() { return allow_stub_calls_; } |
+ void set_has_frame(bool value) { has_frame_ = value; } |
+ bool has_frame() { return has_frame_; } |
+ inline bool AllowThisStubCall(CodeStub* stub); |
static int SafepointRegisterStackIndex(Register reg) { |
return SafepointRegisterStackIndex(reg.code()); |
} |
+ // Activation support. |
+ void EnterFrame(StackFrame::Type type); |
+ void LeaveFrame(StackFrame::Type type); |
+ |
private: |
// Order general registers are pushed by Pushad. |
// rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15. |
@@ -1165,6 +1288,7 @@ |
bool generating_stub_; |
bool allow_stub_calls_; |
+ bool has_frame_; |
bool root_array_available_; |
// Returns a register holding the smi value. The register MUST NOT be |
@@ -1188,10 +1312,6 @@ |
const CallWrapper& call_wrapper = NullCallWrapper(), |
CallKind call_kind = CALL_AS_METHOD); |
- // Activation support. |
- void EnterFrame(StackFrame::Type type); |
- void LeaveFrame(StackFrame::Type type); |
- |
void EnterExitFramePrologue(bool save_rax); |
// Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack |
@@ -1218,7 +1338,21 @@ |
Register scratch, |
bool gc_allowed); |
+ // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace. |
+ void InNewSpace(Register object, |
+ Register scratch, |
+ Condition cc, |
+ Label* branch, |
+ Label::Distance distance = Label::kFar); |
+ // Helper for finding the mark bits for an address. Afterwards, the |
+ // bitmap register points at the word with the mark bits and the mask |
+ // the position of the first bit. Uses rcx as scratch and leaves addr_reg |
+ // unchanged. |
+ inline void GetMarkBits(Register addr_reg, |
+ Register bitmap_reg, |
+ Register mask_reg); |
+ |
// Compute memory operands for safepoint stack slots. |
Operand SafepointRegisterSlot(Register reg); |
static int SafepointRegisterStackIndex(int reg_code) { |