| Index: src/mips/macro-assembler-mips.h
|
| diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
|
| index 266ef7129700d0a20551cccddcfb29170e9396be..0b89951e692f7793e6a5166a0decc9ea5dbd3f58 100644
|
| --- a/src/mips/macro-assembler-mips.h
|
| +++ b/src/mips/macro-assembler-mips.h
|
| @@ -1,4 +1,4 @@
|
| -// Copyright 2010 the V8 project authors. All rights reserved.
|
| +// Copyright 2011 the V8 project authors. All rights reserved.
|
| // Redistribution and use in source and binary forms, with or without
|
| // modification, are permitted provided that the following conditions are
|
| // met:
|
| @@ -52,9 +52,9 @@ class JumpTarget;
|
| // Registers aliases
|
| // cp is assumed to be a callee saved register.
|
| const Register roots = s6; // Roots array pointer.
|
| -const Register cp = s7; // JavaScript context pointer
|
| -const Register fp = s8_fp; // Alias fp
|
| -// Register used for condition evaluation.
|
| +const Register cp = s7; // JavaScript context pointer.
|
| +const Register fp = s8_fp; // Alias for fp.
|
| +// Registers used for condition evaluation.
|
| const Register condReg1 = s4;
|
| const Register condReg2 = s5;
|
|
|
| @@ -92,15 +92,19 @@ enum BranchDelaySlot {
|
| // MacroAssembler implements a collection of frequently used macros.
|
| class MacroAssembler: public Assembler {
|
| public:
|
| - MacroAssembler(void* buffer, int size);
|
| + // The isolate parameter can be NULL if the macro assembler should
|
| + // not use isolate-dependent functionality. In this case, it's the
|
| + // responsibility of the caller to never invoke such function on the
|
| + // macro assembler.
|
| + MacroAssembler(Isolate* isolate, void* buffer, int size);
|
|
|
| -// Arguments macros
|
| +// Arguments macros.
|
| #define COND_TYPED_ARGS Condition cond, Register r1, const Operand& r2
|
| #define COND_ARGS cond, r1, r2
|
|
|
| -// ** Prototypes
|
| +// Prototypes.
|
|
|
| -// * Prototypes for functions with no target (eg Ret()).
|
| +// Prototypes for functions with no target (eg Ret()).
|
| #define DECLARE_NOTARGET_PROTOTYPE(Name) \
|
| void Name(BranchDelaySlot bd = PROTECT); \
|
| void Name(COND_TYPED_ARGS, BranchDelaySlot bd = PROTECT); \
|
| @@ -108,7 +112,7 @@ class MacroAssembler: public Assembler {
|
| Name(COND_ARGS, bd); \
|
| }
|
|
|
| -// * Prototypes for functions with a target.
|
| +// Prototypes for functions with a target.
|
|
|
| // Cases when relocation may be needed.
|
| #define DECLARE_RELOC_PROTOTYPE(Name, target_type) \
|
| @@ -146,7 +150,7 @@ class MacroAssembler: public Assembler {
|
| Name(target, COND_ARGS, bd); \
|
| }
|
|
|
| -// ** Target prototypes.
|
| +// Target prototypes.
|
|
|
| #define DECLARE_JUMP_CALL_PROTOTYPES(Name) \
|
| DECLARE_NORELOC_PROTOTYPE(Name, Register) \
|
| @@ -175,6 +179,16 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| #undef DECLARE_JUMP_CALL_PROTOTYPES
|
| #undef DECLARE_BRANCH_PROTOTYPES
|
|
|
| + void CallWithAstId(Handle<Code> code,
|
| + RelocInfo::Mode rmode,
|
| + unsigned ast_id,
|
| + Condition cond = al,
|
| + Register r1 = zero_reg,
|
| + const Operand& r2 = Operand(zero_reg));
|
| +
|
| + int CallSize(Register reg);
|
| + int CallSize(Handle<Code> code, RelocInfo::Mode rmode);
|
| +
|
| // Emit code to discard a non-negative number of pointer-sized elements
|
| // from the stack, clobbering only the sp register.
|
| void Drop(int count,
|
| @@ -256,7 +270,7 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
|
|
|
|
| // ---------------------------------------------------------------------------
|
| - // Inline caching support
|
| + // Inline caching support.
|
|
|
| // Generate code for checking access rights - used for security checks
|
| // on access to global objects across environments. The holder register
|
| @@ -300,7 +314,7 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
|
|
|
|
| // ---------------------------------------------------------------------------
|
| - // Allocation support
|
| + // Allocation support.
|
|
|
| // Allocate an object in new space. The object_size is specified
|
| // either in bytes or in words if the allocation flag SIZE_IN_WORDS
|
| @@ -367,7 +381,7 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| Label* gc_required);
|
|
|
| // ---------------------------------------------------------------------------
|
| - // Instruction macros
|
| + // Instruction macros.
|
|
|
| #define DEFINE_INSTRUCTION(instr) \
|
| void instr(Register rd, Register rs, const Operand& rt); \
|
| @@ -399,6 +413,7 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| DEFINE_INSTRUCTION(Or);
|
| DEFINE_INSTRUCTION(Xor);
|
| DEFINE_INSTRUCTION(Nor);
|
| + DEFINE_INSTRUCTION2(Neg);
|
|
|
| DEFINE_INSTRUCTION(Slt);
|
| DEFINE_INSTRUCTION(Sltu);
|
| @@ -410,12 +425,12 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| #undef DEFINE_INSTRUCTION2
|
|
|
|
|
| - //------------Pseudo-instructions-------------
|
| + // ---------------------------------------------------------------------------
|
| + // Pseudo-instructions.
|
|
|
| void mov(Register rd, Register rt) { or_(rd, rt, zero_reg); }
|
|
|
| -
|
| - // load int32 in the rd register
|
| + // Load int32 in the rd register.
|
| void li(Register rd, Operand j, bool gen2instr = false);
|
| inline void li(Register rd, int32_t j, bool gen2instr = false) {
|
| li(rd, Operand(j), gen2instr);
|
| @@ -424,68 +439,71 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| li(dst, Operand(value), gen2instr);
|
| }
|
|
|
| - // Exception-generating instructions and debugging support
|
| + // Exception-generating instructions and debugging support.
|
| void stop(const char* msg);
|
|
|
| -
|
| // Push multiple registers on the stack.
|
| // Registers are saved in numerical order, with higher numbered registers
|
| - // saved in higher memory addresses
|
| + // saved in higher memory addresses.
|
| void MultiPush(RegList regs);
|
| void MultiPushReversed(RegList regs);
|
|
|
| - void Push(Register src) {
|
| + // Lower case push() for compatibility with arch-independent code.
|
| + void push(Register src) {
|
| Addu(sp, sp, Operand(-kPointerSize));
|
| sw(src, MemOperand(sp, 0));
|
| }
|
|
|
| - // Push two registers. Pushes leftmost register first (to highest address).
|
| - void Push(Register src1, Register src2, Condition cond = al) {
|
| - ASSERT(cond == al); // Do not support conditional versions yet.
|
| + // Push two registers. Pushes leftmost register first (to highest address).
|
| + void Push(Register src1, Register src2) {
|
| Subu(sp, sp, Operand(2 * kPointerSize));
|
| sw(src1, MemOperand(sp, 1 * kPointerSize));
|
| sw(src2, MemOperand(sp, 0 * kPointerSize));
|
| }
|
|
|
| - // Push three registers. Pushes leftmost register first (to highest address).
|
| - void Push(Register src1, Register src2, Register src3, Condition cond = al) {
|
| - ASSERT(cond == al); // Do not support conditional versions yet.
|
| - Addu(sp, sp, Operand(3 * -kPointerSize));
|
| + // Push three registers. Pushes leftmost register first (to highest address).
|
| + void Push(Register src1, Register src2, Register src3) {
|
| + Subu(sp, sp, Operand(3 * kPointerSize));
|
| sw(src1, MemOperand(sp, 2 * kPointerSize));
|
| sw(src2, MemOperand(sp, 1 * kPointerSize));
|
| sw(src3, MemOperand(sp, 0 * kPointerSize));
|
| }
|
|
|
| - // Push four registers. Pushes leftmost register first (to highest address).
|
| - void Push(Register src1, Register src2,
|
| - Register src3, Register src4, Condition cond = al) {
|
| - ASSERT(cond == al); // Do not support conditional versions yet.
|
| - Addu(sp, sp, Operand(4 * -kPointerSize));
|
| + // Push four registers. Pushes leftmost register first (to highest address).
|
| + void Push(Register src1, Register src2, Register src3, Register src4) {
|
| + Subu(sp, sp, Operand(4 * kPointerSize));
|
| sw(src1, MemOperand(sp, 3 * kPointerSize));
|
| sw(src2, MemOperand(sp, 2 * kPointerSize));
|
| sw(src3, MemOperand(sp, 1 * kPointerSize));
|
| sw(src4, MemOperand(sp, 0 * kPointerSize));
|
| }
|
|
|
| - inline void push(Register src) { Push(src); }
|
| - inline void pop(Register src) { Pop(src); }
|
| -
|
| void Push(Register src, Condition cond, Register tst1, Register tst2) {
|
| - // Since we don't have conditionnal execution we use a Branch.
|
| + // Since we don't have conditional execution we use a Branch.
|
| Branch(3, cond, tst1, Operand(tst2));
|
| - Addu(sp, sp, Operand(-kPointerSize));
|
| + Subu(sp, sp, Operand(kPointerSize));
|
| sw(src, MemOperand(sp, 0));
|
| }
|
|
|
| -
|
| // Pops multiple values from the stack and load them in the
|
| // registers specified in regs. Pop order is the opposite as in MultiPush.
|
| void MultiPop(RegList regs);
|
| void MultiPopReversed(RegList regs);
|
| - void Pop(Register dst) {
|
| +
|
| + // Lower case pop() for compatibility with arch-independent code.
|
| + void pop(Register dst) {
|
| lw(dst, MemOperand(sp, 0));
|
| Addu(sp, sp, Operand(kPointerSize));
|
| }
|
| +
|
| + // Pop two registers. Pops rightmost register first (from lower address).
|
| + void Pop(Register src1, Register src2) {
|
| + ASSERT(!src1.is(src2));
|
| + lw(src2, MemOperand(sp, 0 * kPointerSize));
|
| + lw(src1, MemOperand(sp, 1 * kPointerSize));
|
| + Addu(sp, sp, 2 * kPointerSize);
|
| + }
|
| +
|
| void Pop(uint32_t count = 1) {
|
| Addu(sp, sp, Operand(count * kPointerSize));
|
| }
|
| @@ -542,8 +560,19 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| FPURegister double_scratch,
|
| Label *not_int32);
|
|
|
| + // Helper for EmitECMATruncate.
|
| + // This will truncate a floating-point value outside of the singed 32bit
|
| + // integer range to a 32bit signed integer.
|
| + // Expects the double value loaded in input_high and input_low.
|
| + // Exits with the answer in 'result'.
|
| + // Note that this code does not work for values in the 32bit range!
|
| + void EmitOutOfInt32RangeTruncate(Register result,
|
| + Register input_high,
|
| + Register input_low,
|
| + Register scratch);
|
| +
|
| // -------------------------------------------------------------------------
|
| - // Activation frames
|
| + // Activation frames.
|
|
|
| void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
|
| void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
|
| @@ -580,7 +609,7 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| Register scratch);
|
|
|
| // -------------------------------------------------------------------------
|
| - // JavaScript invokes
|
| + // JavaScript invokes.
|
|
|
| // Invoke the JavaScript function code by either calling or jumping.
|
| void InvokeCode(Register code,
|
| @@ -622,14 +651,14 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
|
|
| #ifdef ENABLE_DEBUGGER_SUPPORT
|
| // -------------------------------------------------------------------------
|
| - // Debugger Support
|
| + // Debugger Support.
|
|
|
| void DebugBreak();
|
| #endif
|
|
|
|
|
| // -------------------------------------------------------------------------
|
| - // Exception handling
|
| + // Exception handling.
|
|
|
| // Push a new try handler and link into try handler chain.
|
| // The return address must be passed in register ra.
|
| @@ -643,6 +672,14 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| // Copies a fixed number of fields of heap objects from src to dst.
|
| void CopyFields(Register dst, Register src, RegList temps, int field_count);
|
|
|
| + // Copies a number of bytes from src to dst. All registers are clobbered. On
|
| + // exit src and dst will point to the place just after where the last byte was
|
| + // read or written and length will be zero.
|
| + void CopyBytes(Register src,
|
| + Register dst,
|
| + Register length,
|
| + Register scratch);
|
| +
|
| // -------------------------------------------------------------------------
|
| // Support functions.
|
|
|
| @@ -663,7 +700,7 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| // Check if the map of an object is equal to a specified map (either
|
| // given directly or as an index into the root list) and branch to
|
| // label if not. Skip the smi check if not required (object is known
|
| - // to be a heap object)
|
| + // to be a heap object).
|
| void CheckMap(Register obj,
|
| Register scratch,
|
| Handle<Map> map,
|
| @@ -686,6 +723,10 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| // index - holds the overwritten index on exit.
|
| void IndexFromHash(Register hash, Register index);
|
|
|
| + // Get the number of least significant bits from a register.
|
| + void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
|
| + void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits);
|
| +
|
| // Load the value of a number object into a FPU double register. If the
|
| // object is not a number a jump to the label not_number is performed
|
| // and the FPU double register is unchanged.
|
| @@ -706,7 +747,44 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| Register scratch1);
|
|
|
| // -------------------------------------------------------------------------
|
| - // Runtime calls
|
| + // Overflow handling functions.
|
| + // Usage: first call the appropriate arithmetic function, then call one of the
|
| + // jump functions with the overflow_dst register as the second parameter.
|
| +
|
| + void AdduAndCheckForOverflow(Register dst,
|
| + Register left,
|
| + Register right,
|
| + Register overflow_dst,
|
| + Register scratch = at);
|
| +
|
| + void SubuAndCheckForOverflow(Register dst,
|
| + Register left,
|
| + Register right,
|
| + Register overflow_dst,
|
| + Register scratch = at);
|
| +
|
| + void BranchOnOverflow(Label* label,
|
| + Register overflow_check,
|
| + BranchDelaySlot bd = PROTECT) {
|
| + Branch(label, lt, overflow_check, Operand(zero_reg), bd);
|
| + }
|
| +
|
| + void BranchOnNoOverflow(Label* label,
|
| + Register overflow_check,
|
| + BranchDelaySlot bd = PROTECT) {
|
| + Branch(label, ge, overflow_check, Operand(zero_reg), bd);
|
| + }
|
| +
|
| + void RetOnOverflow(Register overflow_check, BranchDelaySlot bd = PROTECT) {
|
| + Ret(lt, overflow_check, Operand(zero_reg), bd);
|
| + }
|
| +
|
| + void RetOnNoOverflow(Register overflow_check, BranchDelaySlot bd = PROTECT) {
|
| + Ret(ge, overflow_check, Operand(zero_reg), bd);
|
| + }
|
| +
|
| + // -------------------------------------------------------------------------
|
| + // Runtime calls.
|
|
|
| // Call a code stub.
|
| void CallStub(CodeStub* stub, Condition cond = cc_always,
|
| @@ -763,6 +841,8 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| void CallCFunction(ExternalReference function, int num_arguments);
|
| void CallCFunction(Register function, Register scratch, int num_arguments);
|
|
|
| + void GetCFunctionDoubleResult(const DoubleRegister dst);
|
| +
|
| // Jump to the builtin routine.
|
| void JumpToExternalReference(const ExternalReference& builtin);
|
|
|
| @@ -781,14 +861,17 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
|
|
| struct Unresolved {
|
| int pc;
|
| - uint32_t flags; // see Bootstrapper::FixupFlags decoders/encoders.
|
| + uint32_t flags; // See Bootstrapper::FixupFlags decoders/encoders.
|
| const char* name;
|
| };
|
|
|
| - Handle<Object> CodeObject() { return code_object_; }
|
| + Handle<Object> CodeObject() {
|
| + ASSERT(!code_object_.is_null());
|
| + return code_object_;
|
| + }
|
|
|
| // -------------------------------------------------------------------------
|
| - // StatsCounter support
|
| + // StatsCounter support.
|
|
|
| void SetCounter(StatsCounter* counter, int value,
|
| Register scratch1, Register scratch2);
|
| @@ -799,7 +882,7 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
|
|
|
|
| // -------------------------------------------------------------------------
|
| - // Debugging
|
| + // Debugging.
|
|
|
| // Calls Abort(msg) if the condition cc is not satisfied.
|
| // Use --debug_code to enable.
|
| @@ -820,7 +903,7 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| bool allow_stub_calls() { return allow_stub_calls_; }
|
|
|
| // ---------------------------------------------------------------------------
|
| - // Number utilities
|
| + // Number utilities.
|
|
|
| // Check whether the value of reg is a power of two and not zero. If not
|
| // control continues at the label not_power_of_two. If reg is a power of two
|
| @@ -831,7 +914,7 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| Label* not_power_of_two_or_zero);
|
|
|
| // -------------------------------------------------------------------------
|
| - // Smi utilities
|
| + // Smi utilities.
|
|
|
| // Try to convert int32 to smi. If the value is to large, preserve
|
| // the original value and jump to not_a_smi. Destroys scratch and
|
| @@ -882,13 +965,16 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| void AbortIfSmi(Register object);
|
| void AbortIfNotSmi(Register object);
|
|
|
| + // Abort execution if argument is a string. Used in debug code.
|
| + void AbortIfNotString(Register object);
|
| +
|
| // Abort execution if argument is not the root value with the given index.
|
| void AbortIfNotRootValue(Register src,
|
| Heap::RootListIndex root_value_index,
|
| const char* message);
|
|
|
| // ---------------------------------------------------------------------------
|
| - // HeapNumber utilities
|
| + // HeapNumber utilities.
|
|
|
| void JumpIfNotHeapNumber(Register object,
|
| Register heap_number_map,
|
| @@ -896,7 +982,7 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| Label* on_not_heap_number);
|
|
|
| // -------------------------------------------------------------------------
|
| - // String utilities
|
| + // String utilities.
|
|
|
| // Checks if both instance types are sequential ASCII strings and jumps to
|
| // label if either is not.
|
| @@ -977,7 +1063,6 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
|
| };
|
|
|
|
|
| -#ifdef ENABLE_DEBUGGER_SUPPORT
|
| // 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. It is not legal to emit
|
| @@ -992,18 +1077,21 @@ class CodePatcher {
|
| MacroAssembler* masm() { return &masm_; }
|
|
|
| // Emit an instruction directly.
|
| - void Emit(Instr x);
|
| + void Emit(Instr instr);
|
|
|
| // Emit an address directly.
|
| void Emit(Address addr);
|
|
|
| + // Change the condition part of an instruction leaving the rest of the current
|
| + // instruction unchanged.
|
| + void ChangeBranchCondition(Condition cond);
|
| +
|
| private:
|
| byte* address_; // The address of the code being patched.
|
| int instructions_; // Number of instructions of the expected patch size.
|
| int size_; // Number of bytes of the expected patch size.
|
| MacroAssembler masm_; // Macro assembler used to generate the code.
|
| };
|
| -#endif // ENABLE_DEBUGGER_SUPPORT
|
|
|
|
|
| // -----------------------------------------------------------------------------
|
| @@ -1025,6 +1113,16 @@ static inline MemOperand FieldMemOperand(Register object, int offset) {
|
| }
|
|
|
|
|
| +// Generate a MemOperand for storing arguments 5..N on the stack
|
| +// when calling CallCFunction().
|
| +static inline MemOperand CFunctionArgumentOperand(int index) {
|
| + ASSERT(index > StandardFrameConstants::kCArgSlotCount);
|
| + // Argument 5 takes the slot just past the four Arg-slots.
|
| + int offset =
|
| + (index - 5) * kPointerSize + StandardFrameConstants::kCArgsSlotsSize;
|
| + return MemOperand(sp, offset);
|
| +}
|
| +
|
|
|
| #ifdef GENERATED_CODE_COVERAGE
|
| #define CODE_COVERAGE_STRINGIFY(x) #x
|
|
|