| Index: src/arm/macro-assembler-arm.h
|
| ===================================================================
|
| --- src/arm/macro-assembler-arm.h (revision 6800)
|
| +++ src/arm/macro-assembler-arm.h (working copy)
|
| @@ -33,6 +33,9 @@
|
| namespace v8 {
|
| namespace internal {
|
|
|
| +// Forward declaration.
|
| +class PostCallGenerator;
|
| +
|
| // ----------------------------------------------------------------------------
|
| // Static helper functions
|
|
|
| @@ -42,6 +45,12 @@
|
| }
|
|
|
|
|
| +static inline Operand SmiUntagOperand(Register object) {
|
| + return Operand(object, ASR, kSmiTagSize);
|
| +}
|
| +
|
| +
|
| +
|
| // Give alias names to registers
|
| const Register cp = { 8 }; // JavaScript context pointer
|
| const Register roots = { 10 }; // Roots array pointer.
|
| @@ -136,7 +145,7 @@
|
| // scratch can be object itself, but it will be clobbered.
|
| void InNewSpace(Register object,
|
| Register scratch,
|
| - Condition cc, // eq for new space, ne otherwise
|
| + Condition cond, // eq for new space, ne otherwise
|
| Label* branch);
|
|
|
|
|
| @@ -230,7 +239,14 @@
|
| // RegList constant kSafepointSavedRegisters.
|
| void PushSafepointRegisters();
|
| void PopSafepointRegisters();
|
| + void PushSafepointRegistersAndDoubles();
|
| + void PopSafepointRegistersAndDoubles();
|
| + void StoreToSafepointRegisterSlot(Register reg);
|
| + void StoreToSafepointRegistersAndDoublesSlot(Register reg);
|
| + void LoadFromSafepointRegisterSlot(Register reg);
|
| static int SafepointRegisterStackIndex(int reg_code);
|
| + static MemOperand SafepointRegisterSlot(Register reg);
|
| + static MemOperand SafepointRegistersAndDoublesSlot(Register reg);
|
|
|
| // Load two consecutive registers with two consecutive memory locations.
|
| void Ldrd(Register dst1,
|
| @@ -244,6 +260,30 @@
|
| const MemOperand& dst,
|
| Condition cond = al);
|
|
|
| + // Clear specified FPSCR bits.
|
| + void ClearFPSCRBits(const uint32_t bits_to_clear,
|
| + const Register scratch,
|
| + const Condition cond = al);
|
| +
|
| + // Compare double values and move the result to the normal condition flags.
|
| + void VFPCompareAndSetFlags(const DwVfpRegister src1,
|
| + const DwVfpRegister src2,
|
| + const Condition cond = al);
|
| + void VFPCompareAndSetFlags(const DwVfpRegister src1,
|
| + const double src2,
|
| + const Condition cond = al);
|
| +
|
| + // Compare double values and then load the fpscr flags to a register.
|
| + void VFPCompareAndLoadFlags(const DwVfpRegister src1,
|
| + const DwVfpRegister src2,
|
| + const Register fpscr_flags,
|
| + const Condition cond = al);
|
| + void VFPCompareAndLoadFlags(const DwVfpRegister src1,
|
| + const double src2,
|
| + const Register fpscr_flags,
|
| + const Condition cond = al);
|
| +
|
| +
|
| // ---------------------------------------------------------------------------
|
| // Activation frames
|
|
|
| @@ -254,13 +294,13 @@
|
| void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
|
|
|
| // Enter exit frame.
|
| - // Expects the number of arguments in register r0 and
|
| - // the builtin function to call in register r1. Exits with argc in
|
| - // r4, argv in r6, and and the builtin function to call in r5.
|
| - void EnterExitFrame(bool save_doubles);
|
| + // stack_space - extra stack space, used for alignment before call to C.
|
| + void EnterExitFrame(bool save_doubles, int stack_space = 0);
|
|
|
| // Leave the current exit frame. Expects the return value in r0.
|
| - void LeaveExitFrame(bool save_doubles);
|
| + // Expect the number of values, pushed prior to the exit frame, to
|
| + // remove in a register (or no_reg, if there is nothing to remove).
|
| + void LeaveExitFrame(bool save_doubles, Register argument_count);
|
|
|
| // Get the actual activation frame alignment for target environment.
|
| static int ActivationFrameAlignment();
|
| @@ -282,7 +322,8 @@
|
| 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,
|
| @@ -294,7 +335,8 @@
|
| // 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,
|
| @@ -332,6 +374,13 @@
|
| // Must preserve the result register.
|
| void PopTryHandler();
|
|
|
| + // Passes thrown value (in r0) to the handler of top of the try handler chain.
|
| + void Throw(Register value);
|
| +
|
| + // Propagates an uncatchable exception to the top of the current JS stack's
|
| + // handler chain.
|
| + void ThrowUncatchable(UncatchableExceptionType type, Register value);
|
| +
|
| // ---------------------------------------------------------------------------
|
| // Inline caching support
|
|
|
| @@ -380,12 +429,13 @@
|
| // ---------------------------------------------------------------------------
|
| // Allocation support
|
|
|
| - // Allocate an object in new space. The object_size is specified in words (not
|
| - // bytes). If the new space is exhausted control continues at the gc_required
|
| - // label. The allocated object is returned in result. If the flag
|
| - // tag_allocated_object is true the result is tagged as as a heap object. All
|
| - // registers are clobbered also when control continues at the gc_required
|
| - // label.
|
| + // Allocate an object in new space. The object_size is specified
|
| + // either in bytes or in words if the allocation flag SIZE_IN_WORDS
|
| + // is passed. If the new space is exhausted control continues at the
|
| + // gc_required label. The allocated object is returned in result. If
|
| + // the flag tag_allocated_object is true the result is tagged as as
|
| + // a heap object. All registers are clobbered also when control
|
| + // continues at the gc_required label.
|
| void AllocateInNewSpace(int object_size,
|
| Register result,
|
| Register scratch1,
|
| @@ -512,16 +562,6 @@
|
| }
|
|
|
|
|
| - inline void BranchOnSmi(Register value, Label* smi_label) {
|
| - tst(value, Operand(kSmiTagMask));
|
| - b(eq, smi_label);
|
| - }
|
| -
|
| - inline void BranchOnNotSmi(Register value, Label* not_smi_label) {
|
| - tst(value, Operand(kSmiTagMask));
|
| - b(ne, not_smi_label);
|
| - }
|
| -
|
| // Generates code for reporting that an illegal operation has
|
| // occurred.
|
| void IllegalOperation(int num_arguments);
|
| @@ -534,6 +574,7 @@
|
|
|
| // 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);
|
|
|
| // Uses VFP instructions to Convert a Smi to a double.
|
| void IntegerToDoubleConversionWithVFP3(Register inReg,
|
| @@ -563,11 +604,13 @@
|
|
|
| // Convert the HeapNumber pointed to by source to a 32bits signed integer
|
| // dest. If the HeapNumber does not fit into a 32bits signed integer branch
|
| - // to not_int32 label.
|
| + // to not_int32 label. If VFP3 is available double_scratch is used but not
|
| + // scratch2.
|
| void ConvertToInt32(Register source,
|
| Register dest,
|
| Register scratch,
|
| Register scratch2,
|
| + DwVfpRegister double_scratch,
|
| Label *not_int32);
|
|
|
| // Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz
|
| @@ -588,6 +631,12 @@
|
| // Call a code stub.
|
| void TailCallStub(CodeStub* stub, Condition cond = al);
|
|
|
| + // Tail call a code stub (jump) and return the code object called. Try to
|
| + // generate the code if necessary. Do not perform a GC but instead return
|
| + // a retry after GC failure.
|
| + MUST_USE_RESULT MaybeObject* TryTailCallStub(CodeStub* stub,
|
| + Condition cond = al);
|
| +
|
| // Call a runtime routine.
|
| void CallRuntime(Runtime::Function* f, int num_arguments);
|
| void CallRuntimeSaveDoubles(Runtime::FunctionId id);
|
| @@ -606,6 +655,12 @@
|
| int num_arguments,
|
| int result_size);
|
|
|
| + // Tail call of a runtime routine (jump). Try to generate the code if
|
| + // necessary. Do not perform a GC but instead return a retry after GC
|
| + // failure.
|
| + MUST_USE_RESULT MaybeObject* TryTailCallExternalReference(
|
| + const ExternalReference& ext, int num_arguments, int result_size);
|
| +
|
| // Convenience function: tail call a runtime routine (jump).
|
| void TailCallRuntime(Runtime::FunctionId fid,
|
| int num_arguments,
|
| @@ -629,12 +684,23 @@
|
| void CallCFunction(ExternalReference function, int num_arguments);
|
| void CallCFunction(Register function, int num_arguments);
|
|
|
| + // Calls an API function. Allocates HandleScope, extracts returned value
|
| + // from handle and propagates exceptions. Restores context.
|
| + // stack_space - space to be unwound on exit (includes the call js
|
| + // arguments space and the additional space allocated for the fast call).
|
| + MaybeObject* TryCallApiFunctionAndReturn(ApiFunction* function,
|
| + int stack_space);
|
| +
|
| // Jump to a runtime routine.
|
| void JumpToExternalReference(const ExternalReference& builtin);
|
|
|
| + MaybeObject* TryJumpToExternalReference(const ExternalReference& ext);
|
| +
|
| // Invoke specified builtin JavaScript function. Adds an entry to
|
| // the unresolved list if the name does not resolve.
|
| - void InvokeBuiltin(Builtins::JavaScript id, InvokeJSFlags flags);
|
| + void InvokeBuiltin(Builtins::JavaScript id,
|
| + InvokeJSFlags flags,
|
| + PostCallGenerator* post_call_generator = NULL);
|
|
|
| // Store the code object for the given builtin in the target register and
|
| // setup the function in r1.
|
| @@ -660,14 +726,14 @@
|
| // ---------------------------------------------------------------------------
|
| // Debugging
|
|
|
| - // Calls Abort(msg) if the condition cc is not satisfied.
|
| + // Calls Abort(msg) if the condition cond is not satisfied.
|
| // Use --debug_code to enable.
|
| - void Assert(Condition cc, const char* msg);
|
| + void Assert(Condition cond, const char* msg);
|
| void AssertRegisterIsRoot(Register reg, Heap::RootListIndex index);
|
| void AssertFastElements(Register elements);
|
|
|
| // Like Assert(), but always enabled.
|
| - void Check(Condition cc, const char* msg);
|
| + void Check(Condition cond, const char* msg);
|
|
|
| // Print a message to stdout and abort execution.
|
| void Abort(const char* msg);
|
| @@ -679,25 +745,79 @@
|
| bool allow_stub_calls() { return allow_stub_calls_; }
|
|
|
| // ---------------------------------------------------------------------------
|
| + // 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
|
| + // the register scratch contains the value of (reg - 1) when control falls
|
| + // through.
|
| + void JumpIfNotPowerOfTwoOrZero(Register reg,
|
| + Register scratch,
|
| + Label* not_power_of_two_or_zero);
|
| +
|
| + // ---------------------------------------------------------------------------
|
| // Smi utilities
|
|
|
| void SmiTag(Register reg, SBit s = LeaveCC) {
|
| add(reg, reg, Operand(reg), s);
|
| }
|
| + void SmiTag(Register dst, Register src, SBit s = LeaveCC) {
|
| + add(dst, src, Operand(src), s);
|
| + }
|
|
|
| + // 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
|
| + // sets flags.
|
| + void TrySmiTag(Register reg, Label* not_a_smi, Register scratch) {
|
| + mov(scratch, reg);
|
| + SmiTag(scratch, SetCC);
|
| + b(vs, not_a_smi);
|
| + mov(reg, scratch);
|
| + }
|
| +
|
| void SmiUntag(Register reg) {
|
| mov(reg, Operand(reg, ASR, kSmiTagSize));
|
| }
|
| + void SmiUntag(Register dst, Register src) {
|
| + mov(dst, Operand(src, ASR, kSmiTagSize));
|
| + }
|
|
|
| + // Jump the register contains a smi.
|
| + inline void JumpIfSmi(Register value, Label* smi_label) {
|
| + tst(value, Operand(kSmiTagMask));
|
| + b(eq, smi_label);
|
| + }
|
| // Jump if either of the registers contain a non-smi.
|
| + inline void JumpIfNotSmi(Register value, Label* not_smi_label) {
|
| + tst(value, Operand(kSmiTagMask));
|
| + b(ne, not_smi_label);
|
| + }
|
| + // Jump if either of the registers contain a non-smi.
|
| void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi);
|
| // Jump if either of the registers contain a smi.
|
| void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
|
|
|
| // Abort execution if argument is a smi. Used in debug code.
|
| 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
|
| +
|
| + void JumpIfNotHeapNumber(Register object,
|
| + Register heap_number_map,
|
| + Register scratch,
|
| + Label* on_not_heap_number);
|
| +
|
| + // ---------------------------------------------------------------------------
|
| // String utilities
|
|
|
| // Checks if both objects are sequential ASCII strings and jumps to label
|
| @@ -732,6 +852,15 @@
|
| Label* failure);
|
|
|
|
|
| + // ---------------------------------------------------------------------------
|
| + // Patching helpers.
|
| +
|
| + // Get the location of a relocated constant (its address in the constant pool)
|
| + // from its load site.
|
| + void GetRelocatedValueLocation(Register ldr_location,
|
| + Register result);
|
| +
|
| +
|
| private:
|
| void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
|
| void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
|
| @@ -742,7 +871,8 @@
|
| Handle<Code> code_constant,
|
| Register code_reg,
|
| Label* done,
|
| - InvokeFlag flag);
|
| + InvokeFlag flag,
|
| + PostCallGenerator* post_call_generator = NULL);
|
|
|
| // Activation support.
|
| void EnterFrame(StackFrame::Type type);
|
| @@ -776,11 +906,15 @@
|
| MacroAssembler* masm() { return &masm_; }
|
|
|
| // Emit an instruction directly.
|
| - void Emit(Instr x);
|
| + void Emit(Instr instr);
|
|
|
| // Emit an address directly.
|
| void Emit(Address addr);
|
|
|
| + // Emit the condition part of an instruction leaving the rest of the current
|
| + // instruction unchanged.
|
| + void EmitCondition(Condition cond);
|
| +
|
| private:
|
| byte* address_; // The address of the code being patched.
|
| int instructions_; // Number of instructions of the expected patch size.
|
|
|