1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#if defined(V8_TARGET_ARCH_MIPS)
31
32#include "codegen.h"
33#include "macro-assembler.h"
34
35namespace v8 {
36namespace internal {
37
38#define __ ACCESS_MASM(masm)
39
40UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) {
41  switch (type) {
42    case TranscendentalCache::SIN: return &sin;
43    case TranscendentalCache::COS: return &cos;
44    case TranscendentalCache::TAN: return &tan;
45    case TranscendentalCache::LOG: return &log;
46    default: UNIMPLEMENTED();
47  }
48  return NULL;
49}
50
51
52UnaryMathFunction CreateSqrtFunction() {
53  return &sqrt;
54}
55
56// -------------------------------------------------------------------------
57// Platform-specific RuntimeCallHelper functions.
58
59void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
60  masm->EnterFrame(StackFrame::INTERNAL);
61  ASSERT(!masm->has_frame());
62  masm->set_has_frame(true);
63}
64
65
66void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
67  masm->LeaveFrame(StackFrame::INTERNAL);
68  ASSERT(masm->has_frame());
69  masm->set_has_frame(false);
70}
71
72// -------------------------------------------------------------------------
73// Code generators
74
75void ElementsTransitionGenerator::GenerateSmiOnlyToObject(
76    MacroAssembler* masm) {
77  // ----------- S t a t e -------------
78  //  -- a0    : value
79  //  -- a1    : key
80  //  -- a2    : receiver
81  //  -- ra    : return address
82  //  -- a3    : target map, scratch for subsequent call
83  //  -- t0    : scratch (elements)
84  // -----------------------------------
85  // Set transitioned map.
86  __ sw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
87  __ RecordWriteField(a2,
88                      HeapObject::kMapOffset,
89                      a3,
90                      t5,
91                      kRAHasNotBeenSaved,
92                      kDontSaveFPRegs,
93                      EMIT_REMEMBERED_SET,
94                      OMIT_SMI_CHECK);
95}
96
97
98void ElementsTransitionGenerator::GenerateSmiOnlyToDouble(
99    MacroAssembler* masm, Label* fail) {
100  // ----------- S t a t e -------------
101  //  -- a0    : value
102  //  -- a1    : key
103  //  -- a2    : receiver
104  //  -- ra    : return address
105  //  -- a3    : target map, scratch for subsequent call
106  //  -- t0    : scratch (elements)
107  // -----------------------------------
108  Label loop, entry, convert_hole, gc_required, only_change_map, done;
109  bool fpu_supported = CpuFeatures::IsSupported(FPU);
110
111  Register scratch = t6;
112
113  // Check for empty arrays, which only require a map transition and no changes
114  // to the backing store.
115  __ lw(t0, FieldMemOperand(a2, JSObject::kElementsOffset));
116  __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
117  __ Branch(&only_change_map, eq, at, Operand(t0));
118
119  __ push(ra);
120  __ lw(t1, FieldMemOperand(t0, FixedArray::kLengthOffset));
121  // t0: source FixedArray
122  // t1: number of elements (smi-tagged)
123
124  // Allocate new FixedDoubleArray.
125  __ sll(scratch, t1, 2);
126  __ Addu(scratch, scratch, FixedDoubleArray::kHeaderSize);
127  __ AllocateInNewSpace(scratch, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS);
128  // t2: destination FixedDoubleArray, not tagged as heap object
129  // Set destination FixedDoubleArray's length and map.
130  __ LoadRoot(t5, Heap::kFixedDoubleArrayMapRootIndex);
131  __ sw(t1, MemOperand(t2, FixedDoubleArray::kLengthOffset));
132  __ sw(t5, MemOperand(t2, HeapObject::kMapOffset));
133  // Update receiver's map.
134
135  __ sw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
136  __ RecordWriteField(a2,
137                      HeapObject::kMapOffset,
138                      a3,
139                      t5,
140                      kRAHasBeenSaved,
141                      kDontSaveFPRegs,
142                      OMIT_REMEMBERED_SET,
143                      OMIT_SMI_CHECK);
144  // Replace receiver's backing store with newly created FixedDoubleArray.
145  __ Addu(a3, t2, Operand(kHeapObjectTag));
146  __ sw(a3, FieldMemOperand(a2, JSObject::kElementsOffset));
147  __ RecordWriteField(a2,
148                      JSObject::kElementsOffset,
149                      a3,
150                      t5,
151                      kRAHasBeenSaved,
152                      kDontSaveFPRegs,
153                      EMIT_REMEMBERED_SET,
154                      OMIT_SMI_CHECK);
155
156
157  // Prepare for conversion loop.
158  __ Addu(a3, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
159  __ Addu(t3, t2, Operand(FixedDoubleArray::kHeaderSize));
160  __ sll(t2, t1, 2);
161  __ Addu(t2, t2, t3);
162  __ li(t0, Operand(kHoleNanLower32));
163  __ li(t1, Operand(kHoleNanUpper32));
164  // t0: kHoleNanLower32
165  // t1: kHoleNanUpper32
166  // t2: end of destination FixedDoubleArray, not tagged
167  // t3: begin of FixedDoubleArray element fields, not tagged
168
169  if (!fpu_supported) __ Push(a1, a0);
170
171  __ Branch(&entry);
172
173  __ bind(&only_change_map);
174  __ sw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
175  __ RecordWriteField(a2,
176                      HeapObject::kMapOffset,
177                      a3,
178                      t5,
179                      kRAHasBeenSaved,
180                      kDontSaveFPRegs,
181                      OMIT_REMEMBERED_SET,
182                      OMIT_SMI_CHECK);
183  __ Branch(&done);
184
185  // Call into runtime if GC is required.
186  __ bind(&gc_required);
187  __ pop(ra);
188  __ Branch(fail);
189
190  // Convert and copy elements.
191  __ bind(&loop);
192  __ lw(t5, MemOperand(a3));
193  __ Addu(a3, a3, kIntSize);
194  // t5: current element
195  __ UntagAndJumpIfNotSmi(t5, t5, &convert_hole);
196
197  // Normal smi, convert to double and store.
198  if (fpu_supported) {
199    CpuFeatures::Scope scope(FPU);
200    __ mtc1(t5, f0);
201    __ cvt_d_w(f0, f0);
202    __ sdc1(f0, MemOperand(t3));
203    __ Addu(t3, t3, kDoubleSize);
204  } else {
205    FloatingPointHelper::ConvertIntToDouble(masm,
206                                            t5,
207                                            FloatingPointHelper::kCoreRegisters,
208                                            f0,
209                                            a0,
210                                            a1,
211                                            t7,
212                                            f0);
213    __ sw(a0, MemOperand(t3));  // mantissa
214    __ sw(a1, MemOperand(t3, kIntSize));  // exponent
215    __ Addu(t3, t3, kDoubleSize);
216  }
217  __ Branch(&entry);
218
219  // Hole found, store the-hole NaN.
220  __ bind(&convert_hole);
221  if (FLAG_debug_code) {
222    // Restore a "smi-untagged" heap object.
223    __ SmiTag(t5);
224    __ Or(t5, t5, Operand(1));
225    __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
226    __ Assert(eq, "object found in smi-only array", at, Operand(t5));
227  }
228  __ sw(t0, MemOperand(t3));  // mantissa
229  __ sw(t1, MemOperand(t3, kIntSize));  // exponent
230  __ Addu(t3, t3, kDoubleSize);
231
232  __ bind(&entry);
233  __ Branch(&loop, lt, t3, Operand(t2));
234
235  if (!fpu_supported) __ Pop(a1, a0);
236  __ pop(ra);
237  __ bind(&done);
238}
239
240
241void ElementsTransitionGenerator::GenerateDoubleToObject(
242    MacroAssembler* masm, Label* fail) {
243  // ----------- S t a t e -------------
244  //  -- a0    : value
245  //  -- a1    : key
246  //  -- a2    : receiver
247  //  -- ra    : return address
248  //  -- a3    : target map, scratch for subsequent call
249  //  -- t0    : scratch (elements)
250  // -----------------------------------
251  Label entry, loop, convert_hole, gc_required, only_change_map;
252
253  // Check for empty arrays, which only require a map transition and no changes
254  // to the backing store.
255  __ lw(t0, FieldMemOperand(a2, JSObject::kElementsOffset));
256  __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
257  __ Branch(&only_change_map, eq, at, Operand(t0));
258
259  __ MultiPush(a0.bit() | a1.bit() | a2.bit() | a3.bit() | ra.bit());
260
261  __ lw(t1, FieldMemOperand(t0, FixedArray::kLengthOffset));
262  // t0: source FixedArray
263  // t1: number of elements (smi-tagged)
264
265  // Allocate new FixedArray.
266  __ sll(a0, t1, 1);
267  __ Addu(a0, a0, FixedDoubleArray::kHeaderSize);
268  __ AllocateInNewSpace(a0, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS);
269  // t2: destination FixedArray, not tagged as heap object
270  // Set destination FixedDoubleArray's length and map.
271  __ LoadRoot(t5, Heap::kFixedArrayMapRootIndex);
272  __ sw(t1, MemOperand(t2, FixedDoubleArray::kLengthOffset));
273  __ sw(t5, MemOperand(t2, HeapObject::kMapOffset));
274
275  // Prepare for conversion loop.
276  __ Addu(t0, t0, Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag + 4));
277  __ Addu(a3, t2, Operand(FixedArray::kHeaderSize));
278  __ Addu(t2, t2, Operand(kHeapObjectTag));
279  __ sll(t1, t1, 1);
280  __ Addu(t1, a3, t1);
281  __ LoadRoot(t3, Heap::kTheHoleValueRootIndex);
282  __ LoadRoot(t5, Heap::kHeapNumberMapRootIndex);
283  // Using offsetted addresses.
284  // a3: begin of destination FixedArray element fields, not tagged
285  // t0: begin of source FixedDoubleArray element fields, not tagged, +4
286  // t1: end of destination FixedArray, not tagged
287  // t2: destination FixedArray
288  // t3: the-hole pointer
289  // t5: heap number map
290  __ Branch(&entry);
291
292  // Call into runtime if GC is required.
293  __ bind(&gc_required);
294  __ MultiPop(a0.bit() | a1.bit() | a2.bit() | a3.bit() | ra.bit());
295
296  __ Branch(fail);
297
298  __ bind(&loop);
299  __ lw(a1, MemOperand(t0));
300  __ Addu(t0, t0, kDoubleSize);
301  // a1: current element's upper 32 bit
302  // t0: address of next element's upper 32 bit
303  __ Branch(&convert_hole, eq, a1, Operand(kHoleNanUpper32));
304
305  // Non-hole double, copy value into a heap number.
306  __ AllocateHeapNumber(a2, a0, t6, t5, &gc_required);
307  // a2: new heap number
308  __ lw(a0, MemOperand(t0, -12));
309  __ sw(a0, FieldMemOperand(a2, HeapNumber::kMantissaOffset));
310  __ sw(a1, FieldMemOperand(a2, HeapNumber::kExponentOffset));
311  __ mov(a0, a3);
312  __ sw(a2, MemOperand(a3));
313  __ Addu(a3, a3, kIntSize);
314  __ RecordWrite(t2,
315                 a0,
316                 a2,
317                 kRAHasBeenSaved,
318                 kDontSaveFPRegs,
319                 EMIT_REMEMBERED_SET,
320                 OMIT_SMI_CHECK);
321  __ Branch(&entry);
322
323  // Replace the-hole NaN with the-hole pointer.
324  __ bind(&convert_hole);
325  __ sw(t3, MemOperand(a3));
326  __ Addu(a3, a3, kIntSize);
327
328  __ bind(&entry);
329  __ Branch(&loop, lt, a3, Operand(t1));
330
331  __ MultiPop(a2.bit() | a3.bit() | a0.bit() | a1.bit());
332  // Replace receiver's backing store with newly created and filled FixedArray.
333  __ sw(t2, FieldMemOperand(a2, JSObject::kElementsOffset));
334  __ RecordWriteField(a2,
335                      JSObject::kElementsOffset,
336                      t2,
337                      t5,
338                      kRAHasBeenSaved,
339                      kDontSaveFPRegs,
340                      EMIT_REMEMBERED_SET,
341                      OMIT_SMI_CHECK);
342  __ pop(ra);
343
344  __ bind(&only_change_map);
345  // Update receiver's map.
346  __ sw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
347  __ RecordWriteField(a2,
348                      HeapObject::kMapOffset,
349                      a3,
350                      t5,
351                      kRAHasNotBeenSaved,
352                      kDontSaveFPRegs,
353                      OMIT_REMEMBERED_SET,
354                      OMIT_SMI_CHECK);
355}
356
357
358void StringCharLoadGenerator::Generate(MacroAssembler* masm,
359                                       Register string,
360                                       Register index,
361                                       Register result,
362                                       Label* call_runtime) {
363  // Fetch the instance type of the receiver into result register.
364  __ lw(result, FieldMemOperand(string, HeapObject::kMapOffset));
365  __ lbu(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
366
367  // We need special handling for indirect strings.
368  Label check_sequential;
369  __ And(at, result, Operand(kIsIndirectStringMask));
370  __ Branch(&check_sequential, eq, at, Operand(zero_reg));
371
372  // Dispatch on the indirect string shape: slice or cons.
373  Label cons_string;
374  __ And(at, result, Operand(kSlicedNotConsMask));
375  __ Branch(&cons_string, eq, at, Operand(zero_reg));
376
377  // Handle slices.
378  Label indirect_string_loaded;
379  __ lw(result, FieldMemOperand(string, SlicedString::kOffsetOffset));
380  __ lw(string, FieldMemOperand(string, SlicedString::kParentOffset));
381  __ sra(at, result, kSmiTagSize);
382  __ Addu(index, index, at);
383  __ jmp(&indirect_string_loaded);
384
385  // Handle cons strings.
386  // Check whether the right hand side is the empty string (i.e. if
387  // this is really a flat string in a cons string). If that is not
388  // the case we would rather go to the runtime system now to flatten
389  // the string.
390  __ bind(&cons_string);
391  __ lw(result, FieldMemOperand(string, ConsString::kSecondOffset));
392  __ LoadRoot(at, Heap::kEmptyStringRootIndex);
393  __ Branch(call_runtime, ne, result, Operand(at));
394  // Get the first of the two strings and load its instance type.
395  __ lw(string, FieldMemOperand(string, ConsString::kFirstOffset));
396
397  __ bind(&indirect_string_loaded);
398  __ lw(result, FieldMemOperand(string, HeapObject::kMapOffset));
399  __ lbu(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
400
401  // Distinguish sequential and external strings. Only these two string
402  // representations can reach here (slices and flat cons strings have been
403  // reduced to the underlying sequential or external string).
404  Label external_string, check_encoding;
405  __ bind(&check_sequential);
406  STATIC_ASSERT(kSeqStringTag == 0);
407  __ And(at, result, Operand(kStringRepresentationMask));
408  __ Branch(&external_string, ne, at, Operand(zero_reg));
409
410  // Prepare sequential strings
411  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
412  __ Addu(string,
413          string,
414          SeqTwoByteString::kHeaderSize - kHeapObjectTag);
415  __ jmp(&check_encoding);
416
417  // Handle external strings.
418  __ bind(&external_string);
419  if (FLAG_debug_code) {
420    // Assert that we do not have a cons or slice (indirect strings) here.
421    // Sequential strings have already been ruled out.
422    __ And(at, result, Operand(kIsIndirectStringMask));
423    __ Assert(eq, "external string expected, but not found",
424        at, Operand(zero_reg));
425  }
426  // Rule out short external strings.
427  STATIC_CHECK(kShortExternalStringTag != 0);
428  __ And(at, result, Operand(kShortExternalStringMask));
429  __ Branch(call_runtime, ne, at, Operand(zero_reg));
430  __ lw(string, FieldMemOperand(string, ExternalString::kResourceDataOffset));
431
432  Label ascii, done;
433  __ bind(&check_encoding);
434  STATIC_ASSERT(kTwoByteStringTag == 0);
435  __ And(at, result, Operand(kStringEncodingMask));
436  __ Branch(&ascii, ne, at, Operand(zero_reg));
437  // Two-byte string.
438  __ sll(at, index, 1);
439  __ Addu(at, string, at);
440  __ lhu(result, MemOperand(at));
441  __ jmp(&done);
442  __ bind(&ascii);
443  // Ascii string.
444  __ Addu(at, string, index);
445  __ lbu(result, MemOperand(at));
446  __ bind(&done);
447}
448
449#undef __
450
451} }  // namespace v8::internal
452
453#endif  // V8_TARGET_ARCH_MIPS
454