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 35 namespace v8 { 36 namespace internal { 37 38 #define __ ACCESS_MASM(masm) 39 40 UnaryMathFunction 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 52 UnaryMathFunction CreateSqrtFunction() { 53 return &sqrt; 54 } 55 56 // ------------------------------------------------------------------------- 57 // Platform-specific RuntimeCallHelper functions. 58 59 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { 60 masm->EnterFrame(StackFrame::INTERNAL); 61 ASSERT(!masm->has_frame()); 62 masm->set_has_frame(true); 63 } 64 65 66 void 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 75 void 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 98 void 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 241 void 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 358 void 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