Revision f230a1cf deps/v8/src/mips/macro-assembler-mips.cc
deps/v8/src/mips/macro-assembler-mips.cc | ||
---|---|---|
35 | 35 |
#include "codegen.h" |
36 | 36 |
#include "cpu-profiler.h" |
37 | 37 |
#include "debug.h" |
38 |
#include "isolate-inl.h" |
|
38 | 39 |
#include "runtime.h" |
39 | 40 |
|
40 | 41 |
namespace v8 { |
... | ... | |
248 | 249 |
SmiCheck smi_check) { |
249 | 250 |
ASSERT(!AreAliased(object, address, value, t8)); |
250 | 251 |
ASSERT(!AreAliased(object, address, value, t9)); |
251 |
// The compiled code assumes that record write doesn't change the |
|
252 |
// context register, so we check that none of the clobbered |
|
253 |
// registers are cp. |
|
254 |
ASSERT(!address.is(cp) && !value.is(cp)); |
|
255 | 252 |
|
256 | 253 |
if (emit_debug_code()) { |
257 | 254 |
lw(at, MemOperand(address)); |
... | ... | |
3220 | 3217 |
Register dst, |
3221 | 3218 |
Register length, |
3222 | 3219 |
Register scratch) { |
3223 |
Label align_loop, align_loop_1, word_loop, byte_loop, byte_loop_1, done;
|
|
3220 |
Label align_loop_1, word_loop, byte_loop, byte_loop_1, done; |
|
3224 | 3221 |
|
3225 | 3222 |
// Align src before copying in word size chunks. |
3226 |
bind(&align_loop); |
|
3227 |
Branch(&done, eq, length, Operand(zero_reg)); |
|
3223 |
Branch(&byte_loop, le, length, Operand(kPointerSize)); |
|
3228 | 3224 |
bind(&align_loop_1); |
3229 | 3225 |
And(scratch, src, kPointerSize - 1); |
3230 | 3226 |
Branch(&word_loop, eq, scratch, Operand(zero_reg)); |
... | ... | |
3233 | 3229 |
sb(scratch, MemOperand(dst)); |
3234 | 3230 |
Addu(dst, dst, 1); |
3235 | 3231 |
Subu(length, length, Operand(1)); |
3236 |
Branch(&byte_loop_1, ne, length, Operand(zero_reg));
|
|
3232 |
Branch(&align_loop_1, ne, length, Operand(zero_reg));
|
|
3237 | 3233 |
|
3238 | 3234 |
// Copy bytes in word size chunks. |
3239 | 3235 |
bind(&word_loop); |
... | ... | |
3847 | 3843 |
} |
3848 | 3844 |
|
3849 | 3845 |
|
3850 |
void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, |
|
3851 |
Address function_address, |
|
3852 |
ExternalReference thunk_ref, |
|
3853 |
Register thunk_last_arg, |
|
3854 |
int stack_space, |
|
3855 |
int return_value_offset_from_fp) { |
|
3846 |
void MacroAssembler::CallApiFunctionAndReturn( |
|
3847 |
ExternalReference function, |
|
3848 |
Address function_address, |
|
3849 |
ExternalReference thunk_ref, |
|
3850 |
Register thunk_last_arg, |
|
3851 |
int stack_space, |
|
3852 |
MemOperand return_value_operand, |
|
3853 |
MemOperand* context_restore_operand) { |
|
3856 | 3854 |
ExternalReference next_address = |
3857 | 3855 |
ExternalReference::handle_scope_next_address(isolate()); |
3858 | 3856 |
const int kNextOffset = 0; |
... | ... | |
3915 | 3913 |
} |
3916 | 3914 |
|
3917 | 3915 |
Label promote_scheduled_exception; |
3916 |
Label exception_handled; |
|
3918 | 3917 |
Label delete_allocated_handles; |
3919 | 3918 |
Label leave_exit_frame; |
3920 | 3919 |
Label return_value_loaded; |
3921 | 3920 |
|
3922 | 3921 |
// Load value from ReturnValue. |
3923 |
lw(v0, MemOperand(fp, return_value_offset_from_fp*kPointerSize));
|
|
3922 |
lw(v0, return_value_operand);
|
|
3924 | 3923 |
bind(&return_value_loaded); |
3925 | 3924 |
|
3926 | 3925 |
// No more valid handles (the result handle was the last one). Restore |
... | ... | |
3941 | 3940 |
li(at, Operand(ExternalReference::scheduled_exception_address(isolate()))); |
3942 | 3941 |
lw(t1, MemOperand(at)); |
3943 | 3942 |
Branch(&promote_scheduled_exception, ne, t0, Operand(t1)); |
3943 |
bind(&exception_handled); |
|
3944 |
|
|
3945 |
bool restore_context = context_restore_operand != NULL; |
|
3946 |
if (restore_context) { |
|
3947 |
lw(cp, *context_restore_operand); |
|
3948 |
} |
|
3944 | 3949 |
li(s0, Operand(stack_space)); |
3945 |
LeaveExitFrame(false, s0, true);
|
|
3950 |
LeaveExitFrame(false, s0, !restore_context, EMIT_RETURN);
|
|
3946 | 3951 |
|
3947 | 3952 |
bind(&promote_scheduled_exception); |
3948 |
TailCallExternalReference( |
|
3949 |
ExternalReference(Runtime::kPromoteScheduledException, isolate()), |
|
3950 |
0, |
|
3951 |
1); |
|
3953 |
{ |
|
3954 |
FrameScope frame(this, StackFrame::INTERNAL); |
|
3955 |
CallExternalReference( |
|
3956 |
ExternalReference(Runtime::kPromoteScheduledException, isolate()), |
|
3957 |
0); |
|
3958 |
} |
|
3959 |
jmp(&exception_handled); |
|
3952 | 3960 |
|
3953 | 3961 |
// HandleScope limit has changed. Delete allocated extensions. |
3954 | 3962 |
bind(&delete_allocated_handles); |
... | ... | |
4125 | 4133 |
|
4126 | 4134 |
|
4127 | 4135 |
void MacroAssembler::CallRuntime(const Runtime::Function* f, |
4128 |
int num_arguments) { |
|
4136 |
int num_arguments, |
|
4137 |
SaveFPRegsMode save_doubles) { |
|
4129 | 4138 |
// All parameters are on the stack. v0 has the return value after call. |
4130 | 4139 |
|
4131 | 4140 |
// If the expected number of arguments of the runtime function is |
... | ... | |
4142 | 4151 |
// smarter. |
4143 | 4152 |
PrepareCEntryArgs(num_arguments); |
4144 | 4153 |
PrepareCEntryFunction(ExternalReference(f, isolate())); |
4145 |
CEntryStub stub(1); |
|
4146 |
CallStub(&stub); |
|
4147 |
} |
|
4148 |
|
|
4149 |
|
|
4150 |
void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) { |
|
4151 |
const Runtime::Function* function = Runtime::FunctionForId(id); |
|
4152 |
PrepareCEntryArgs(function->nargs); |
|
4153 |
PrepareCEntryFunction(ExternalReference(function, isolate())); |
|
4154 |
CEntryStub stub(1, kSaveFPRegs); |
|
4154 |
CEntryStub stub(1, save_doubles); |
|
4155 | 4155 |
CallStub(&stub); |
4156 | 4156 |
} |
4157 | 4157 |
|
4158 | 4158 |
|
4159 |
void MacroAssembler::CallRuntime(Runtime::FunctionId fid, int num_arguments) { |
|
4160 |
CallRuntime(Runtime::FunctionForId(fid), num_arguments); |
|
4161 |
} |
|
4162 |
|
|
4163 |
|
|
4164 | 4159 |
void MacroAssembler::CallExternalReference(const ExternalReference& ext, |
4165 | 4160 |
int num_arguments, |
4166 | 4161 |
BranchDelaySlot bd) { |
... | ... | |
4591 | 4586 |
} |
4592 | 4587 |
|
4593 | 4588 |
|
4589 |
void MacroAssembler::Prologue(PrologueFrameMode frame_mode) { |
|
4590 |
if (frame_mode == BUILD_STUB_FRAME) { |
|
4591 |
Push(ra, fp, cp); |
|
4592 |
Push(Smi::FromInt(StackFrame::STUB)); |
|
4593 |
// Adjust FP to point to saved FP. |
|
4594 |
Addu(fp, sp, Operand(2 * kPointerSize)); |
|
4595 |
} else { |
|
4596 |
PredictableCodeSizeScope predictible_code_size_scope( |
|
4597 |
this, kNoCodeAgeSequenceLength * Assembler::kInstrSize); |
|
4598 |
// The following three instructions must remain together and unmodified |
|
4599 |
// for code aging to work properly. |
|
4600 |
if (isolate()->IsCodePreAgingActive()) { |
|
4601 |
// Pre-age the code. |
|
4602 |
Code* stub = Code::GetPreAgedCodeAgeStub(isolate()); |
|
4603 |
nop(Assembler::CODE_AGE_MARKER_NOP); |
|
4604 |
// Save the function's original return address |
|
4605 |
// (it will be clobbered by Call(t9)) |
|
4606 |
mov(at, ra); |
|
4607 |
// Load the stub address to t9 and call it |
|
4608 |
li(t9, |
|
4609 |
Operand(reinterpret_cast<uint32_t>(stub->instruction_start()))); |
|
4610 |
Call(t9); |
|
4611 |
// Record the stub address in the empty space for GetCodeAgeAndParity() |
|
4612 |
dd(reinterpret_cast<uint32_t>(stub->instruction_start())); |
|
4613 |
} else { |
|
4614 |
Push(ra, fp, cp, a1); |
|
4615 |
nop(Assembler::CODE_AGE_SEQUENCE_NOP); |
|
4616 |
// Adjust fp to point to caller's fp. |
|
4617 |
Addu(fp, sp, Operand(2 * kPointerSize)); |
|
4618 |
} |
|
4619 |
} |
|
4620 |
} |
|
4621 |
|
|
4622 |
|
|
4594 | 4623 |
void MacroAssembler::EnterFrame(StackFrame::Type type) { |
4595 | 4624 |
addiu(sp, sp, -5 * kPointerSize); |
4596 | 4625 |
li(t8, Operand(Smi::FromInt(type))); |
... | ... | |
4684 | 4713 |
|
4685 | 4714 |
void MacroAssembler::LeaveExitFrame(bool save_doubles, |
4686 | 4715 |
Register argument_count, |
4716 |
bool restore_context, |
|
4687 | 4717 |
bool do_return) { |
4688 | 4718 |
// Optionally restore all double registers. |
4689 | 4719 |
if (save_doubles) { |
... | ... | |
4700 | 4730 |
sw(zero_reg, MemOperand(t8)); |
4701 | 4731 |
|
4702 | 4732 |
// Restore current context from top and clear it in debug mode. |
4703 |
li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); |
|
4704 |
lw(cp, MemOperand(t8)); |
|
4733 |
if (restore_context) { |
|
4734 |
li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); |
|
4735 |
lw(cp, MemOperand(t8)); |
|
4736 |
} |
|
4705 | 4737 |
#ifdef DEBUG |
4738 |
li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); |
|
4706 | 4739 |
sw(a3, MemOperand(t8)); |
4707 | 4740 |
#endif |
4708 | 4741 |
|
... | ... | |
4929 | 4962 |
} |
4930 | 4963 |
|
4931 | 4964 |
|
4965 |
void MacroAssembler::LookupNumberStringCache(Register object, |
|
4966 |
Register result, |
|
4967 |
Register scratch1, |
|
4968 |
Register scratch2, |
|
4969 |
Register scratch3, |
|
4970 |
Label* not_found) { |
|
4971 |
// Use of registers. Register result is used as a temporary. |
|
4972 |
Register number_string_cache = result; |
|
4973 |
Register mask = scratch3; |
|
4974 |
|
|
4975 |
// Load the number string cache. |
|
4976 |
LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex); |
|
4977 |
|
|
4978 |
// Make the hash mask from the length of the number string cache. It |
|
4979 |
// contains two elements (number and string) for each cache entry. |
|
4980 |
lw(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset)); |
|
4981 |
// Divide length by two (length is a smi). |
|
4982 |
sra(mask, mask, kSmiTagSize + 1); |
|
4983 |
Addu(mask, mask, -1); // Make mask. |
|
4984 |
|
|
4985 |
// Calculate the entry in the number string cache. The hash value in the |
|
4986 |
// number string cache for smis is just the smi value, and the hash for |
|
4987 |
// doubles is the xor of the upper and lower words. See |
|
4988 |
// Heap::GetNumberStringCache. |
|
4989 |
Label is_smi; |
|
4990 |
Label load_result_from_cache; |
|
4991 |
JumpIfSmi(object, &is_smi); |
|
4992 |
CheckMap(object, |
|
4993 |
scratch1, |
|
4994 |
Heap::kHeapNumberMapRootIndex, |
|
4995 |
not_found, |
|
4996 |
DONT_DO_SMI_CHECK); |
|
4997 |
|
|
4998 |
STATIC_ASSERT(8 == kDoubleSize); |
|
4999 |
Addu(scratch1, |
|
5000 |
object, |
|
5001 |
Operand(HeapNumber::kValueOffset - kHeapObjectTag)); |
|
5002 |
lw(scratch2, MemOperand(scratch1, kPointerSize)); |
|
5003 |
lw(scratch1, MemOperand(scratch1, 0)); |
|
5004 |
Xor(scratch1, scratch1, Operand(scratch2)); |
|
5005 |
And(scratch1, scratch1, Operand(mask)); |
|
5006 |
|
|
5007 |
// Calculate address of entry in string cache: each entry consists |
|
5008 |
// of two pointer sized fields. |
|
5009 |
sll(scratch1, scratch1, kPointerSizeLog2 + 1); |
|
5010 |
Addu(scratch1, number_string_cache, scratch1); |
|
5011 |
|
|
5012 |
Register probe = mask; |
|
5013 |
lw(probe, FieldMemOperand(scratch1, FixedArray::kHeaderSize)); |
|
5014 |
JumpIfSmi(probe, not_found); |
|
5015 |
ldc1(f12, FieldMemOperand(object, HeapNumber::kValueOffset)); |
|
5016 |
ldc1(f14, FieldMemOperand(probe, HeapNumber::kValueOffset)); |
|
5017 |
BranchF(&load_result_from_cache, NULL, eq, f12, f14); |
|
5018 |
Branch(not_found); |
|
5019 |
|
|
5020 |
bind(&is_smi); |
|
5021 |
Register scratch = scratch1; |
|
5022 |
sra(scratch, object, 1); // Shift away the tag. |
|
5023 |
And(scratch, mask, Operand(scratch)); |
|
5024 |
|
|
5025 |
// Calculate address of entry in string cache: each entry consists |
|
5026 |
// of two pointer sized fields. |
|
5027 |
sll(scratch, scratch, kPointerSizeLog2 + 1); |
|
5028 |
Addu(scratch, number_string_cache, scratch); |
|
5029 |
|
|
5030 |
// Check if the entry is the smi we are looking for. |
|
5031 |
lw(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize)); |
|
5032 |
Branch(not_found, ne, object, Operand(probe)); |
|
5033 |
|
|
5034 |
// Get the result from the cache. |
|
5035 |
bind(&load_result_from_cache); |
|
5036 |
lw(result, FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize)); |
|
5037 |
|
|
5038 |
IncrementCounter(isolate()->counters()->number_to_string_native(), |
|
5039 |
1, |
|
5040 |
scratch1, |
|
5041 |
scratch2); |
|
5042 |
} |
|
5043 |
|
|
5044 |
|
|
4932 | 5045 |
void MacroAssembler::JumpIfNonSmisNotBothSequentialAsciiStrings( |
4933 | 5046 |
Register first, |
4934 | 5047 |
Register second, |
... | ... | |
5492 | 5605 |
void MacroAssembler::TestJSArrayForAllocationMemento( |
5493 | 5606 |
Register receiver_reg, |
5494 | 5607 |
Register scratch_reg, |
5608 |
Label* no_memento_found, |
|
5495 | 5609 |
Condition cond, |
5496 | 5610 |
Label* allocation_memento_present) { |
5497 |
Label no_memento_available; |
|
5498 | 5611 |
ExternalReference new_space_start = |
5499 | 5612 |
ExternalReference::new_space_start(isolate()); |
5500 | 5613 |
ExternalReference new_space_allocation_top = |
5501 | 5614 |
ExternalReference::new_space_allocation_top_address(isolate()); |
5502 | 5615 |
Addu(scratch_reg, receiver_reg, |
5503 | 5616 |
Operand(JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag)); |
5504 |
Branch(&no_memento_available, lt, scratch_reg, Operand(new_space_start));
|
|
5617 |
Branch(no_memento_found, lt, scratch_reg, Operand(new_space_start));
|
|
5505 | 5618 |
li(at, Operand(new_space_allocation_top)); |
5506 | 5619 |
lw(at, MemOperand(at)); |
5507 |
Branch(&no_memento_available, gt, scratch_reg, Operand(at));
|
|
5620 |
Branch(no_memento_found, gt, scratch_reg, Operand(at));
|
|
5508 | 5621 |
lw(scratch_reg, MemOperand(scratch_reg, -AllocationMemento::kSize)); |
5509 |
Branch(allocation_memento_present, cond, scratch_reg, |
|
5510 |
Operand(Handle<Map>(isolate()->heap()->allocation_memento_map()))); |
|
5511 |
bind(&no_memento_available); |
|
5622 |
if (allocation_memento_present) { |
|
5623 |
Branch(allocation_memento_present, cond, scratch_reg, |
|
5624 |
Operand(isolate()->factory()->allocation_memento_map())); |
|
5625 |
} |
|
5512 | 5626 |
} |
5513 | 5627 |
|
5514 | 5628 |
|
Also available in: Unified diff