diff options
Diffstat (limited to 'deps/v8/src/x87/macro-assembler-x87.h')
-rw-r--r-- | deps/v8/src/x87/macro-assembler-x87.h | 914 |
1 files changed, 0 insertions, 914 deletions
diff --git a/deps/v8/src/x87/macro-assembler-x87.h b/deps/v8/src/x87/macro-assembler-x87.h deleted file mode 100644 index 63c8dad194..0000000000 --- a/deps/v8/src/x87/macro-assembler-x87.h +++ /dev/null @@ -1,914 +0,0 @@ -// Copyright 2012 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_X87_MACRO_ASSEMBLER_X87_H_ -#define V8_X87_MACRO_ASSEMBLER_X87_H_ - -#include "src/assembler.h" -#include "src/bailout-reason.h" -#include "src/frames.h" -#include "src/globals.h" - -namespace v8 { -namespace internal { - -// Give alias names to registers for calling conventions. -const Register kReturnRegister0 = {Register::kCode_eax}; -const Register kReturnRegister1 = {Register::kCode_edx}; -const Register kReturnRegister2 = {Register::kCode_edi}; -const Register kJSFunctionRegister = {Register::kCode_edi}; -const Register kContextRegister = {Register::kCode_esi}; -const Register kAllocateSizeRegister = {Register::kCode_edx}; -const Register kInterpreterAccumulatorRegister = {Register::kCode_eax}; -const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_ecx}; -const Register kInterpreterBytecodeArrayRegister = {Register::kCode_edi}; -const Register kInterpreterDispatchTableRegister = {Register::kCode_esi}; -const Register kJavaScriptCallArgCountRegister = {Register::kCode_eax}; -const Register kJavaScriptCallNewTargetRegister = {Register::kCode_edx}; -const Register kRuntimeCallFunctionRegister = {Register::kCode_ebx}; -const Register kRuntimeCallArgCountRegister = {Register::kCode_eax}; - -// Spill slots used by interpreter dispatch calling convention. -const int kInterpreterDispatchTableSpillSlot = -1; - -// Convenience for platform-independent signatures. We do not normally -// distinguish memory operands from other operands on ia32. -typedef Operand MemOperand; - -enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET }; -enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; -enum PointersToHereCheck { - kPointersToHereMaybeInteresting, - kPointersToHereAreAlwaysInteresting -}; - -enum RegisterValueType { REGISTER_VALUE_IS_SMI, REGISTER_VALUE_IS_INT32 }; - -enum class ReturnAddressState { kOnStack, kNotOnStack }; - -#ifdef DEBUG -bool AreAliased(Register reg1, Register reg2, Register reg3 = no_reg, - Register reg4 = no_reg, Register reg5 = no_reg, - Register reg6 = no_reg, Register reg7 = no_reg, - Register reg8 = no_reg); -#endif - -// MacroAssembler implements a collection of frequently used macros. -class MacroAssembler: public Assembler { - public: - MacroAssembler(Isolate* isolate, void* buffer, int size, - CodeObjectRequired create_code_object); - - Isolate* isolate() const { return isolate_; } - - void Load(Register dst, const Operand& src, Representation r); - void Store(Register src, const Operand& dst, Representation r); - - // Load a register with a long value as efficiently as possible. - void Set(Register dst, int32_t x) { - if (x == 0) { - xor_(dst, dst); - } else { - mov(dst, Immediate(x)); - } - } - void Set(const Operand& dst, int32_t x) { mov(dst, Immediate(x)); } - - // Operations on roots in the root-array. - void LoadRoot(Register destination, Heap::RootListIndex index); - void StoreRoot(Register source, Register scratch, Heap::RootListIndex index); - void CompareRoot(Register with, Register scratch, Heap::RootListIndex index); - // These methods can only be used with constant roots (i.e. non-writable - // and not in new space). - void CompareRoot(Register with, Heap::RootListIndex index); - void CompareRoot(const Operand& with, Heap::RootListIndex index); - void PushRoot(Heap::RootListIndex index); - - // Compare the object in a register to a value and jump if they are equal. - void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal, - Label::Distance if_equal_distance = Label::kFar) { - CompareRoot(with, index); - j(equal, if_equal, if_equal_distance); - } - void JumpIfRoot(const Operand& with, Heap::RootListIndex index, - Label* if_equal, - Label::Distance if_equal_distance = Label::kFar) { - CompareRoot(with, index); - j(equal, if_equal, if_equal_distance); - } - - // Compare the object in a register to a value and jump if they are not equal. - void JumpIfNotRoot(Register with, Heap::RootListIndex index, - Label* if_not_equal, - Label::Distance if_not_equal_distance = Label::kFar) { - CompareRoot(with, index); - j(not_equal, if_not_equal, if_not_equal_distance); - } - void JumpIfNotRoot(const Operand& with, Heap::RootListIndex index, - Label* if_not_equal, - Label::Distance if_not_equal_distance = Label::kFar) { - CompareRoot(with, index); - j(not_equal, if_not_equal, if_not_equal_distance); - } - - // 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); - - // --------------------------------------------------------------------------- - // GC Support - enum RememberedSetFinalAction { kReturnAtEnd, kFallThroughAtEnd }; - - // 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); - - void CheckPageFlagForMap( - Handle<Map> map, 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, zero, 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, not_zero, branch, distance); - } - - // Check if an object has a given incremental marking color. Also uses ecx! - void HasColor(Register object, Register scratch0, Register scratch1, - Label* has_color, Label::Distance has_color_distance, - int first_bit, int second_bit); - - void JumpIfBlack(Register object, Register scratch0, Register scratch1, - Label* on_black, - Label::Distance on_black_distance = Label::kFar); - - // Checks the color of an object. If the object is white we jump to the - // incremental marker. - void JumpIfWhite(Register value, Register scratch1, Register scratch2, - Label* value_is_white, 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, - PointersToHereCheck pointers_to_here_check_for_value = - kPointersToHereMaybeInteresting); - - // 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, - PointersToHereCheck pointers_to_here_check_for_value = - kPointersToHereMaybeInteresting) { - RecordWriteField(context, offset + kHeapObjectTag, value, scratch, save_fp, - remembered_set_action, smi_check, - pointers_to_here_check_for_value); - } - - // For page containing |object| mark region covering |address| - // dirty. |object| is the object being stored into, |value| is 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, SaveFPRegsMode save_fp, - RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, - SmiCheck smi_check = INLINE_SMI_CHECK, - PointersToHereCheck pointers_to_here_check_for_value = - kPointersToHereMaybeInteresting); - - // Notify the garbage collector that we wrote a code entry into a - // JSFunction. Only scratch is clobbered by the operation. - void RecordWriteCodeEntryField(Register js_function, Register code_entry, - Register scratch); - - // For page containing |object| mark the region covering the object's map - // dirty. |object| is the object being stored into, |map| is the Map object - // that was stored. - void RecordWriteForMap(Register object, Handle<Map> map, Register scratch1, - Register scratch2, SaveFPRegsMode save_fp); - - // --------------------------------------------------------------------------- - // Debugger Support - - void DebugBreak(); - - // Generates function and stub prologue code. - void StubPrologue(StackFrame::Type type); - void Prologue(bool code_pre_aging); - - // Enter specific kind of exit frame. Expects the number of - // arguments in register eax and sets up the number of arguments in - // register edi and the pointer to the first argument in register - // esi. - void EnterExitFrame(int argc, bool save_doubles, StackFrame::Type frame_type); - - void EnterApiExitFrame(int argc); - - // Leave the current exit frame. Expects the return value in - // register eax:edx (untouched) and the pointer to the first - // argument in register esi (if pop_arguments == true). - void LeaveExitFrame(bool save_doubles, bool pop_arguments = true); - - // Leave the current exit frame. Expects the return value in - // register eax (untouched). - void LeaveApiExitFrame(bool restore_context); - - // Find the function context up the context chain. - void LoadContext(Register dst, int context_chain_length); - - // Load the global proxy from the current context. - void LoadGlobalProxy(Register dst); - - // Load the global function with the given index. - void LoadGlobalFunction(int index, Register function); - - // Load the initial map from the global function. The registers - // function and map can be the same. - void LoadGlobalFunctionInitialMap(Register function, Register map); - - // Push and pop the registers that can hold pointers. - void PushSafepointRegisters() { pushad(); } - void PopSafepointRegisters() { popad(); } - // Store the value in register/immediate src in the safepoint - // register stack slot for register dst. - void StoreToSafepointRegisterSlot(Register dst, Register src); - void StoreToSafepointRegisterSlot(Register dst, Immediate src); - void LoadFromSafepointRegisterSlot(Register dst, Register src); - - // Nop, because x87 does not have a root register. - void InitializeRootRegister() {} - - void LoadHeapObject(Register result, Handle<HeapObject> object); - void CmpHeapObject(Register reg, Handle<HeapObject> object); - void PushHeapObject(Handle<HeapObject> object); - - void LoadObject(Register result, Handle<Object> object) { - AllowDeferredHandleDereference heap_object_check; - if (object->IsHeapObject()) { - LoadHeapObject(result, Handle<HeapObject>::cast(object)); - } else { - Move(result, Immediate(object)); - } - } - - void CmpObject(Register reg, Handle<Object> object) { - AllowDeferredHandleDereference heap_object_check; - if (object->IsHeapObject()) { - CmpHeapObject(reg, Handle<HeapObject>::cast(object)); - } else { - cmp(reg, Immediate(object)); - } - } - - void GetWeakValue(Register value, Handle<WeakCell> cell); - void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss); - - // --------------------------------------------------------------------------- - // JavaScript invokes - - // Removes current frame and its arguments from the stack preserving - // the arguments and a return address pushed to the stack for the next call. - // |ra_state| defines whether return address is already pushed to stack or - // not. Both |callee_args_count| and |caller_args_count_reg| do not include - // receiver. |callee_args_count| is not modified, |caller_args_count_reg| - // is trashed. |number_of_temp_values_after_return_address| specifies - // the number of words pushed to the stack after the return address. This is - // to allow "allocation" of scratch registers that this function requires - // by saving their values on the stack. - void PrepareForTailCall(const ParameterCount& callee_args_count, - Register caller_args_count_reg, Register scratch0, - Register scratch1, ReturnAddressState ra_state, - int number_of_temp_values_after_return_address); - - // Invoke the JavaScript function code by either calling or jumping. - - void InvokeFunctionCode(Register function, Register new_target, - const ParameterCount& expected, - const ParameterCount& actual, InvokeFlag flag, - const CallWrapper& call_wrapper); - - // On function call, call into the debugger if necessary. - void CheckDebugHook(Register fun, Register new_target, - const ParameterCount& expected, - const ParameterCount& actual); - - // Invoke the JavaScript function in the given register. Changes the - // current context to the context in the function before invoking. - void InvokeFunction(Register function, Register new_target, - const ParameterCount& actual, InvokeFlag flag, - const CallWrapper& call_wrapper); - - void InvokeFunction(Register function, const ParameterCount& expected, - const ParameterCount& actual, InvokeFlag flag, - const CallWrapper& call_wrapper); - - void InvokeFunction(Handle<JSFunction> function, - const ParameterCount& expected, - const ParameterCount& actual, InvokeFlag flag, - const CallWrapper& call_wrapper); - - void ShlPair(Register high, Register low, uint8_t imm8); - void ShlPair_cl(Register high, Register low); - void ShrPair(Register high, Register low, uint8_t imm8); - void ShrPair_cl(Register high, Register src); - void SarPair(Register high, Register low, uint8_t imm8); - void SarPair_cl(Register high, Register low); - - // Expression support - // Support for constant splitting. - bool IsUnsafeImmediate(const Immediate& x); - void SafeMove(Register dst, const Immediate& x); - void SafePush(const Immediate& x); - - // Compare object type for heap object. - // Incoming register is heap_object and outgoing register is map. - void CmpObjectType(Register heap_object, InstanceType type, Register map); - - // Compare instance type for map. - void CmpInstanceType(Register map, InstanceType type); - - // Compare an object's map with the specified map. - void CompareMap(Register obj, Handle<Map> map); - - // 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). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match - // against maps that are ElementsKind transition maps of the specified map. - void CheckMap(Register obj, Handle<Map> map, Label* fail, - SmiCheckType smi_check_type); - - // Check if the object in register heap_object is a string. Afterwards the - // register map contains the object map and the register instance_type - // contains the instance_type. The registers map and instance_type can be the - // same in which case it contains the instance type afterwards. Either of the - // registers map and instance_type can be the same as heap_object. - Condition IsObjectStringType(Register heap_object, Register map, - Register instance_type); - - // FCmp is similar to integer cmp, but requires unsigned - // jcc instructions (je, ja, jae, jb, jbe, je, and jz). - void FCmp(); - void FXamMinusZero(); - void FXamSign(); - void X87CheckIA(); - void X87SetRC(int rc); - void X87SetFPUCW(int cw); - - void ClampUint8(Register reg); - void ClampTOSToUint8(Register result_reg); - - void SlowTruncateToI(Register result_reg, Register input_reg, - int offset = HeapNumber::kValueOffset - kHeapObjectTag); - - void TruncateHeapNumberToI(Register result_reg, Register input_reg); - void TruncateX87TOSToI(Register result_reg); - - void X87TOSToI(Register result_reg, MinusZeroMode minus_zero_mode, - Label* lost_precision, Label* is_nan, Label* minus_zero, - Label::Distance dst = Label::kFar); - - // Smi tagging support. - void SmiTag(Register reg) { - STATIC_ASSERT(kSmiTag == 0); - STATIC_ASSERT(kSmiTagSize == 1); - add(reg, reg); - } - void SmiUntag(Register reg) { - sar(reg, kSmiTagSize); - } - - // Modifies the register even if it does not contain a Smi! - void SmiUntag(Register reg, Label* is_smi) { - STATIC_ASSERT(kSmiTagSize == 1); - sar(reg, kSmiTagSize); - STATIC_ASSERT(kSmiTag == 0); - j(not_carry, is_smi); - } - - void LoadUint32NoSSE2(Register src) { - LoadUint32NoSSE2(Operand(src)); - } - void LoadUint32NoSSE2(const Operand& src); - - // Jump the register contains a smi. - inline void JumpIfSmi(Register value, Label* smi_label, - Label::Distance distance = Label::kFar) { - test(value, Immediate(kSmiTagMask)); - j(zero, smi_label, distance); - } - // Jump if the operand is a smi. - inline void JumpIfSmi(Operand value, Label* smi_label, - Label::Distance distance = Label::kFar) { - test(value, Immediate(kSmiTagMask)); - j(zero, smi_label, distance); - } - // Jump if register contain a non-smi. - inline void JumpIfNotSmi(Register value, Label* not_smi_label, - Label::Distance distance = Label::kFar) { - test(value, Immediate(kSmiTagMask)); - j(not_zero, not_smi_label, distance); - } - // Jump if the operand is not a smi. - inline void JumpIfNotSmi(Operand value, Label* smi_label, - Label::Distance distance = Label::kFar) { - test(value, Immediate(kSmiTagMask)); - j(not_zero, smi_label, distance); - } - // Jump if the value cannot be represented by a smi. - inline void JumpIfNotValidSmiValue(Register value, Register scratch, - Label* on_invalid, - Label::Distance distance = Label::kFar) { - mov(scratch, value); - add(scratch, Immediate(0x40000000U)); - j(sign, on_invalid, distance); - } - - // Jump if the unsigned integer value cannot be represented by a smi. - inline void JumpIfUIntNotValidSmiValue( - Register value, Label* on_invalid, - Label::Distance distance = Label::kFar) { - cmp(value, Immediate(0x40000000U)); - j(above_equal, on_invalid, distance); - } - - void LoadInstanceDescriptors(Register map, Register descriptors); - void EnumLength(Register dst, Register map); - void NumberOfOwnDescriptors(Register dst, Register map); - void LoadAccessor(Register dst, Register holder, int accessor_index, - AccessorComponent accessor); - - template<typename Field> - void DecodeField(Register reg) { - static const int shift = Field::kShift; - static const int mask = Field::kMask >> Field::kShift; - if (shift != 0) { - sar(reg, shift); - } - and_(reg, Immediate(mask)); - } - - template<typename Field> - void DecodeFieldToSmi(Register reg) { - static const int shift = Field::kShift; - static const int mask = (Field::kMask >> Field::kShift) << kSmiTagSize; - STATIC_ASSERT((mask & (0x80000000u >> (kSmiTagSize - 1))) == 0); - STATIC_ASSERT(kSmiTag == 0); - if (shift < kSmiTagSize) { - shl(reg, kSmiTagSize - shift); - } else if (shift > kSmiTagSize) { - sar(reg, shift - kSmiTagSize); - } - and_(reg, Immediate(mask)); - } - - // Abort execution if argument is not a smi, enabled via --debug-code. - void AssertSmi(Register object); - - // Abort execution if argument is a smi, enabled via --debug-code. - void AssertNotSmi(Register object); - - // Abort execution if argument is not a JSFunction, enabled via --debug-code. - void AssertFunction(Register object); - - // Abort execution if argument is not a JSBoundFunction, - // enabled via --debug-code. - void AssertBoundFunction(Register object); - - // Abort execution if argument is not a JSGeneratorObject, - // enabled via --debug-code. - void AssertGeneratorObject(Register object); - - // Abort execution if argument is not undefined or an AllocationSite, enabled - // via --debug-code. - void AssertUndefinedOrAllocationSite(Register object); - - // --------------------------------------------------------------------------- - // Exception handling - - // Push a new stack handler and link it into stack handler chain. - void PushStackHandler(); - - // Unlink the stack handler on top of the stack from the stack handler chain. - void PopStackHandler(); - - // --------------------------------------------------------------------------- - // Inline caching support - - void GetNumberHash(Register r0, Register scratch); - - // --------------------------------------------------------------------------- - // Allocation support - - // Allocate an object in new space or old space. If the given space - // is exhausted control continues at the gc_required label. The allocated - // object is returned in result and end of the new object is returned in - // result_end. The register scratch can be passed as no_reg in which case - // an additional object reference will be added to the reloc info. The - // returned pointers in result and result_end have not yet been tagged as - // heap objects. If result_contains_top_on_entry is true the content of - // result is known to be the allocation top on entry (could be result_end - // from a previous call). If result_contains_top_on_entry is true scratch - // should be no_reg as it is never used. - void Allocate(int object_size, Register result, Register result_end, - Register scratch, Label* gc_required, AllocationFlags flags); - - void Allocate(int header_size, ScaleFactor element_size, - Register element_count, RegisterValueType element_count_type, - Register result, Register result_end, Register scratch, - Label* gc_required, AllocationFlags flags); - - void Allocate(Register object_size, Register result, Register result_end, - Register scratch, Label* gc_required, AllocationFlags flags); - - // FastAllocate is right now only used for folded allocations. It just - // increments the top pointer without checking against limit. This can only - // be done if it was proved earlier that the allocation will succeed. - void FastAllocate(int object_size, Register result, Register result_end, - AllocationFlags flags); - void FastAllocate(Register object_size, Register result, Register result_end, - AllocationFlags flags); - - // Allocate a heap number in new space with undefined value. The - // register scratch2 can be passed as no_reg; the others must be - // valid registers. Returns tagged pointer in result register, or - // jumps to gc_required if new space is full. - void AllocateHeapNumber(Register result, Register scratch1, Register scratch2, - Label* gc_required, MutableMode mode = IMMUTABLE); - - // Allocate and initialize a JSValue wrapper with the specified {constructor} - // and {value}. - void AllocateJSValue(Register result, Register constructor, Register value, - Register scratch, Label* gc_required); - - // Initialize fields with filler values. Fields starting at |current_address| - // not including |end_address| are overwritten with the value in |filler|. At - // the end the loop, |current_address| takes the value of |end_address|. - void InitializeFieldsWithFiller(Register current_address, - Register end_address, Register filler); - - // --------------------------------------------------------------------------- - // Support functions. - - // Check a boolean-bit of a Smi field. - void BooleanBitTest(Register object, int field_offset, int bit_index); - - // Machine code version of Map::GetConstructor(). - // |temp| holds |result|'s map when done. - void GetMapConstructor(Register result, Register map, Register temp); - - // --------------------------------------------------------------------------- - // Runtime calls - - // Call a code stub. Generate the code if necessary. - void CallStub(CodeStub* stub, TypeFeedbackId ast_id = TypeFeedbackId::None()); - - // Tail call a code stub (jump). Generate the code if necessary. - void TailCallStub(CodeStub* stub); - - // Call a runtime routine. - void CallRuntime(const Runtime::Function* f, int num_arguments, - SaveFPRegsMode save_doubles = kDontSaveFPRegs); - void CallRuntimeSaveDoubles(Runtime::FunctionId fid) { - const Runtime::Function* function = Runtime::FunctionForId(fid); - CallRuntime(function, function->nargs, kSaveFPRegs); - } - - // Convenience function: Same as above, but takes the fid instead. - void CallRuntime(Runtime::FunctionId fid, - SaveFPRegsMode save_doubles = kDontSaveFPRegs) { - const Runtime::Function* function = Runtime::FunctionForId(fid); - CallRuntime(function, function->nargs, save_doubles); - } - - // Convenience function: Same as above, but takes the fid instead. - void CallRuntime(Runtime::FunctionId fid, int num_arguments, - SaveFPRegsMode save_doubles = kDontSaveFPRegs) { - CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles); - } - - // Convenience function: call an external reference. - void CallExternalReference(ExternalReference ref, int num_arguments); - - // Convenience function: tail call a runtime routine (jump). - void TailCallRuntime(Runtime::FunctionId fid); - - // Before calling a C-function from generated code, align arguments on stack. - // After aligning the frame, arguments must be stored in esp[0], esp[4], - // etc., not pushed. The argument count assumes all arguments are word sized. - // Some compilers/platforms require the stack to be aligned when calling - // C++ code. - // Needs a scratch register to do some arithmetic. This register will be - // trashed. - void PrepareCallCFunction(int num_arguments, Register scratch); - - // Calls a C function and cleans up the space for arguments allocated - // by PrepareCallCFunction. The called function is not allowed to trigger a - // garbage collection, since that might move the code and invalidate the - // return address (unless this is somehow accounted for by the called - // function). - void CallCFunction(ExternalReference function, int num_arguments); - void CallCFunction(Register function, int num_arguments); - - // Jump to a runtime routine. - void JumpToExternalReference(const ExternalReference& ext, - bool builtin_exit_frame = false); - - // --------------------------------------------------------------------------- - // Utilities - - void Ret(); - - // Return and drop arguments from stack, where the number of arguments - // may be bigger than 2^16 - 1. Requires a scratch register. - void Ret(int bytes_dropped, Register scratch); - - // Emit code that loads |parameter_index|'th parameter from the stack to - // the register according to the CallInterfaceDescriptor definition. - // |sp_to_caller_sp_offset_in_words| specifies the number of words pushed - // below the caller's sp (on x87 it's at least return address). - template <class Descriptor> - void LoadParameterFromStack( - Register reg, typename Descriptor::ParameterIndices parameter_index, - int sp_to_ra_offset_in_words = 1) { - DCHECK(Descriptor::kPassLastArgsOnStack); - DCHECK_LT(parameter_index, Descriptor::kParameterCount); - DCHECK_LE(Descriptor::kParameterCount - Descriptor::kStackArgumentsCount, - parameter_index); - int offset = (Descriptor::kParameterCount - parameter_index - 1 + - sp_to_ra_offset_in_words) * - kPointerSize; - mov(reg, Operand(esp, offset)); - } - - // Emit code to discard a non-negative number of pointer-sized elements - // from the stack, clobbering only the esp register. - void Drop(int element_count); - - void Call(Label* target) { call(target); } - void Call(Handle<Code> target, RelocInfo::Mode rmode, - TypeFeedbackId id = TypeFeedbackId::None()) { - call(target, rmode, id); - } - void Jump(Handle<Code> target, RelocInfo::Mode rmode) { jmp(target, rmode); } - void Push(Register src) { push(src); } - void Push(const Operand& src) { push(src); } - void Push(Immediate value) { push(value); } - void Pop(Register dst) { pop(dst); } - void Pop(const Operand& dst) { pop(dst); } - void PushReturnAddressFrom(Register src) { push(src); } - void PopReturnAddressTo(Register dst) { pop(dst); } - - void Lzcnt(Register dst, Register src) { Lzcnt(dst, Operand(src)); } - void Lzcnt(Register dst, const Operand& src); - - void Tzcnt(Register dst, Register src) { Tzcnt(dst, Operand(src)); } - void Tzcnt(Register dst, const Operand& src); - - void Popcnt(Register dst, Register src) { Popcnt(dst, Operand(src)); } - void Popcnt(Register dst, const Operand& src); - - // Move if the registers are not identical. - void Move(Register target, Register source); - - // Move a constant into a destination using the most efficient encoding. - void Move(Register dst, const Immediate& x); - void Move(const Operand& dst, const Immediate& x); - - void Move(Register dst, Handle<Object> handle) { LoadObject(dst, handle); } - void Move(Register dst, Smi* source) { Move(dst, Immediate(source)); } - - // Push a handle value. - void Push(Handle<Object> handle) { push(Immediate(handle)); } - void Push(Smi* smi) { Push(Immediate(smi)); } - - Handle<Object> CodeObject() { - DCHECK(!code_object_.is_null()); - return code_object_; - } - - // Insert code to verify that the x87 stack has the specified depth (0-7) - void VerifyX87StackDepth(uint32_t depth); - - // Emit code for a truncating division by a constant. The dividend register is - // unchanged, the result is in edx, and eax gets clobbered. - void TruncatingDiv(Register dividend, int32_t divisor); - - // --------------------------------------------------------------------------- - // StatsCounter support - - void SetCounter(StatsCounter* counter, int value); - void IncrementCounter(StatsCounter* counter, int value); - void DecrementCounter(StatsCounter* counter, int value); - void IncrementCounter(Condition cc, StatsCounter* counter, int value); - void DecrementCounter(Condition cc, StatsCounter* counter, int value); - - // --------------------------------------------------------------------------- - // Debugging - - // Calls Abort(msg) if the condition cc is not satisfied. - // Use --debug_code to enable. - void Assert(Condition cc, BailoutReason reason); - - // Like Assert(), but always enabled. - void Check(Condition cc, BailoutReason reason); - - // Print a message to stdout and abort execution. - void Abort(BailoutReason reason); - - // Check that the stack is aligned. - void CheckStackAlignment(); - - // Verify restrictions about code generated in stubs. - void set_generating_stub(bool value) { generating_stub_ = value; } - bool generating_stub() { return generating_stub_; } - void set_has_frame(bool value) { has_frame_ = value; } - bool has_frame() { return has_frame_; } - inline bool AllowThisStubCall(CodeStub* stub); - - // --------------------------------------------------------------------------- - // String utilities. - - // Checks if both objects are sequential one-byte strings, and jumps to label - // if either is not. - void JumpIfNotBothSequentialOneByteStrings( - Register object1, Register object2, Register scratch1, Register scratch2, - Label* on_not_flat_one_byte_strings); - - // Checks if the given register or operand is a unique name - void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name, - Label::Distance distance = Label::kFar) { - JumpIfNotUniqueNameInstanceType(Operand(reg), not_unique_name, distance); - } - - void JumpIfNotUniqueNameInstanceType(Operand operand, Label* not_unique_name, - Label::Distance distance = Label::kFar); - - void EmitSeqStringSetCharCheck(Register string, Register index, - Register value, uint32_t encoding_mask); - - static int SafepointRegisterStackIndex(Register reg) { - return SafepointRegisterStackIndex(reg.code()); - } - - // Load the type feedback vector from a JavaScript frame. - void EmitLoadFeedbackVector(Register vector); - - // Activation support. - void EnterFrame(StackFrame::Type type); - void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg); - void LeaveFrame(StackFrame::Type type); - - void EnterBuiltinFrame(Register context, Register target, Register argc); - void LeaveBuiltinFrame(Register context, Register target, Register argc); - - // Expects object in eax and returns map with validated enum cache - // in eax. Assumes that any other register can be used as a scratch. - void CheckEnumCache(Label* call_runtime); - - // AllocationMemento support. Arrays may have an associated - // AllocationMemento object that can be checked for in order to pretransition - // to another type. - // On entry, receiver_reg should point to the array object. - // scratch_reg gets clobbered. - // If allocation info is present, conditional code is set to equal. - void TestJSArrayForAllocationMemento(Register receiver_reg, - Register scratch_reg, - Label* no_memento_found); - - private: - bool generating_stub_; - bool has_frame_; - Isolate* isolate_; - // This handle will be patched with the code object on installation. - Handle<Object> code_object_; - - // Helper functions for generating invokes. - void InvokePrologue(const ParameterCount& expected, - const ParameterCount& actual, Label* done, - bool* definitely_mismatches, InvokeFlag flag, - Label::Distance done_distance, - const CallWrapper& call_wrapper); - - void EnterExitFramePrologue(StackFrame::Type frame_type); - void EnterExitFrameEpilogue(int argc, bool save_doubles); - - void LeaveExitFrameEpilogue(bool restore_context); - - // Allocation support helpers. - void LoadAllocationTopHelper(Register result, Register scratch, - AllocationFlags flags); - - void UpdateAllocationTopHelper(Register result_end, Register scratch, - AllocationFlags flags); - - // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace. - void InNewSpace(Register object, Register scratch, Condition cc, - Label* condition_met, - Label::Distance condition_met_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 ecx 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); - - // Needs access to SafepointRegisterStackIndex for compiled frame - // traversal. - friend class StandardFrame; -}; - -// The code patcher is used to patch (typically) small parts of code e.g. for -// debugging and other types of instrumentation. When using the code patcher -// the exact number of bytes specified must be emitted. Is not legal to emit -// relocation information. If any of these constraints are violated it causes -// an assertion. -class CodePatcher { - public: - CodePatcher(Isolate* isolate, byte* address, int size); - ~CodePatcher(); - - // Macro assembler to emit code. - MacroAssembler* masm() { return &masm_; } - - private: - byte* address_; // The address of the code being patched. - int size_; // Number of bytes of the expected patch size. - MacroAssembler masm_; // Macro assembler used to generate the code. -}; - -// ----------------------------------------------------------------------------- -// Static helper functions. - -// Generate an Operand for loading a field from an object. -inline Operand FieldOperand(Register object, int offset) { - return Operand(object, offset - kHeapObjectTag); -} - -// Generate an Operand for loading an indexed field from an object. -inline Operand FieldOperand(Register object, Register index, ScaleFactor scale, - int offset) { - return Operand(object, index, scale, offset - kHeapObjectTag); -} - -inline Operand FixedArrayElementOperand(Register array, Register index_as_smi, - int additional_offset = 0) { - int offset = FixedArray::kHeaderSize + additional_offset * kPointerSize; - return FieldOperand(array, index_as_smi, times_half_pointer_size, offset); -} - -inline Operand ContextOperand(Register context, int index) { - return Operand(context, Context::SlotOffset(index)); -} - -inline Operand ContextOperand(Register context, Register index) { - return Operand(context, index, times_pointer_size, Context::SlotOffset(0)); -} - -inline Operand NativeContextOperand() { - return ContextOperand(esi, Context::NATIVE_CONTEXT_INDEX); -} - -#define ACCESS_MASM(masm) masm-> - -} // namespace internal -} // namespace v8 - -#endif // V8_X87_MACRO_ASSEMBLER_X87_H_ |