| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/s390/codegen-s390.h" | 5 #include "src/s390/codegen-s390.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_S390 | 7 #if V8_TARGET_ARCH_S390 |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 | 10 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 masm->LeaveFrame(StackFrame::INTERNAL); | 59 masm->LeaveFrame(StackFrame::INTERNAL); |
| 60 DCHECK(masm->has_frame()); | 60 DCHECK(masm->has_frame()); |
| 61 masm->set_has_frame(false); | 61 masm->set_has_frame(false); |
| 62 } | 62 } |
| 63 | 63 |
| 64 // ------------------------------------------------------------------------- | 64 // ------------------------------------------------------------------------- |
| 65 // Code generators | 65 // Code generators |
| 66 | 66 |
| 67 #define __ ACCESS_MASM(masm) | 67 #define __ ACCESS_MASM(masm) |
| 68 | 68 |
| 69 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition( | |
| 70 MacroAssembler* masm, Register receiver, Register key, Register value, | |
| 71 Register target_map, AllocationSiteMode mode, | |
| 72 Label* allocation_memento_found) { | |
| 73 Register scratch_elements = r6; | |
| 74 DCHECK(!AreAliased(receiver, key, value, target_map, scratch_elements)); | |
| 75 | |
| 76 if (mode == TRACK_ALLOCATION_SITE) { | |
| 77 DCHECK(allocation_memento_found != NULL); | |
| 78 __ JumpIfJSArrayHasAllocationMemento(receiver, scratch_elements, r1, | |
| 79 allocation_memento_found); | |
| 80 } | |
| 81 | |
| 82 // Set transitioned map. | |
| 83 __ StoreP(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 84 __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, r1, | |
| 85 kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET, | |
| 86 OMIT_SMI_CHECK); | |
| 87 } | |
| 88 | |
| 89 void ElementsTransitionGenerator::GenerateSmiToDouble( | |
| 90 MacroAssembler* masm, Register receiver, Register key, Register value, | |
| 91 Register target_map, AllocationSiteMode mode, Label* fail) { | |
| 92 // lr contains the return address | |
| 93 Label loop, entry, convert_hole, gc_required, only_change_map, done; | |
| 94 Register elements = r6; | |
| 95 Register length = r7; | |
| 96 Register array = r8; | |
| 97 Register array_end = array; | |
| 98 | |
| 99 // target_map parameter can be clobbered. | |
| 100 Register scratch1 = target_map; | |
| 101 Register scratch2 = r1; | |
| 102 | |
| 103 // Verify input registers don't conflict with locals. | |
| 104 DCHECK(!AreAliased(receiver, key, value, target_map, elements, length, array, | |
| 105 scratch2)); | |
| 106 | |
| 107 if (mode == TRACK_ALLOCATION_SITE) { | |
| 108 __ JumpIfJSArrayHasAllocationMemento(receiver, elements, scratch2, fail); | |
| 109 } | |
| 110 | |
| 111 // Check for empty arrays, which only require a map transition and no changes | |
| 112 // to the backing store. | |
| 113 __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 114 __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex); | |
| 115 __ beq(&only_change_map, Label::kNear); | |
| 116 | |
| 117 // Preserve lr and use r14 as a temporary register. | |
| 118 __ push(r14); | |
| 119 | |
| 120 __ LoadP(length, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 121 // length: number of elements (smi-tagged) | |
| 122 | |
| 123 // Allocate new FixedDoubleArray. | |
| 124 __ SmiToDoubleArrayOffset(r14, length); | |
| 125 __ AddP(r14, Operand(FixedDoubleArray::kHeaderSize)); | |
| 126 __ Allocate(r14, array, r9, scratch2, &gc_required, DOUBLE_ALIGNMENT); | |
| 127 __ SubP(array, array, Operand(kHeapObjectTag)); | |
| 128 // Set destination FixedDoubleArray's length and map. | |
| 129 __ LoadRoot(scratch2, Heap::kFixedDoubleArrayMapRootIndex); | |
| 130 __ StoreP(length, MemOperand(array, FixedDoubleArray::kLengthOffset)); | |
| 131 // Update receiver's map. | |
| 132 __ StoreP(scratch2, MemOperand(array, HeapObject::kMapOffset)); | |
| 133 | |
| 134 __ StoreP(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 135 __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch2, | |
| 136 kLRHasBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, | |
| 137 OMIT_SMI_CHECK); | |
| 138 // Replace receiver's backing store with newly created FixedDoubleArray. | |
| 139 __ AddP(scratch1, array, Operand(kHeapObjectTag)); | |
| 140 __ StoreP(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 141 __ RecordWriteField(receiver, JSObject::kElementsOffset, scratch1, scratch2, | |
| 142 kLRHasBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET, | |
| 143 OMIT_SMI_CHECK); | |
| 144 | |
| 145 // Prepare for conversion loop. | |
| 146 __ AddP(target_map, elements, | |
| 147 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
| 148 __ AddP(r9, array, Operand(FixedDoubleArray::kHeaderSize)); | |
| 149 __ SmiToDoubleArrayOffset(array, length); | |
| 150 __ AddP(array_end, r9, array); | |
| 151 // Repurpose registers no longer in use. | |
| 152 #if V8_TARGET_ARCH_S390X | |
| 153 Register hole_int64 = elements; | |
| 154 #else | |
| 155 Register hole_lower = elements; | |
| 156 Register hole_upper = length; | |
| 157 #endif | |
| 158 // scratch1: begin of source FixedArray element fields, not tagged | |
| 159 // hole_lower: kHoleNanLower32 OR hol_int64 | |
| 160 // hole_upper: kHoleNanUpper32 | |
| 161 // array_end: end of destination FixedDoubleArray, not tagged | |
| 162 // scratch2: begin of FixedDoubleArray element fields, not tagged | |
| 163 | |
| 164 __ b(&entry, Label::kNear); | |
| 165 | |
| 166 __ bind(&only_change_map); | |
| 167 __ StoreP(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 168 __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch2, | |
| 169 kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, | |
| 170 OMIT_SMI_CHECK); | |
| 171 __ b(&done, Label::kNear); | |
| 172 | |
| 173 // Call into runtime if GC is required. | |
| 174 __ bind(&gc_required); | |
| 175 __ pop(r14); | |
| 176 __ b(fail); | |
| 177 | |
| 178 // Convert and copy elements. | |
| 179 __ bind(&loop); | |
| 180 __ LoadP(r14, MemOperand(scratch1)); | |
| 181 __ la(scratch1, MemOperand(scratch1, kPointerSize)); | |
| 182 // r1: current element | |
| 183 __ UntagAndJumpIfNotSmi(r14, r14, &convert_hole); | |
| 184 | |
| 185 // Normal smi, convert to double and store. | |
| 186 __ ConvertIntToDouble(r14, d0); | |
| 187 __ StoreDouble(d0, MemOperand(r9, 0)); | |
| 188 __ la(r9, MemOperand(r9, 8)); | |
| 189 | |
| 190 __ b(&entry, Label::kNear); | |
| 191 | |
| 192 // Hole found, store the-hole NaN. | |
| 193 __ bind(&convert_hole); | |
| 194 if (FLAG_debug_code) { | |
| 195 // Restore a "smi-untagged" heap object. | |
| 196 __ LoadP(r1, MemOperand(r5, -kPointerSize)); | |
| 197 __ CompareRoot(r1, Heap::kTheHoleValueRootIndex); | |
| 198 __ Assert(eq, kObjectFoundInSmiOnlyArray); | |
| 199 } | |
| 200 #if V8_TARGET_ARCH_S390X | |
| 201 __ stg(hole_int64, MemOperand(r9, 0)); | |
| 202 #else | |
| 203 __ StoreW(hole_upper, MemOperand(r9, Register::kExponentOffset)); | |
| 204 __ StoreW(hole_lower, MemOperand(r9, Register::kMantissaOffset)); | |
| 205 #endif | |
| 206 __ AddP(r9, Operand(8)); | |
| 207 | |
| 208 __ bind(&entry); | |
| 209 __ CmpP(r9, array_end); | |
| 210 __ blt(&loop); | |
| 211 | |
| 212 __ pop(r14); | |
| 213 __ bind(&done); | |
| 214 } | |
| 215 | |
| 216 void ElementsTransitionGenerator::GenerateDoubleToObject( | |
| 217 MacroAssembler* masm, Register receiver, Register key, Register value, | |
| 218 Register target_map, AllocationSiteMode mode, Label* fail) { | |
| 219 // Register lr contains the return address. | |
| 220 Label loop, convert_hole, gc_required, only_change_map; | |
| 221 Register elements = r6; | |
| 222 Register array = r8; | |
| 223 Register length = r7; | |
| 224 Register scratch = r1; | |
| 225 Register scratch3 = r9; | |
| 226 Register hole_value = r9; | |
| 227 | |
| 228 // Verify input registers don't conflict with locals. | |
| 229 DCHECK(!AreAliased(receiver, key, value, target_map, elements, array, length, | |
| 230 scratch)); | |
| 231 | |
| 232 if (mode == TRACK_ALLOCATION_SITE) { | |
| 233 __ JumpIfJSArrayHasAllocationMemento(receiver, elements, scratch3, fail); | |
| 234 } | |
| 235 | |
| 236 // Check for empty arrays, which only require a map transition and no changes | |
| 237 // to the backing store. | |
| 238 __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 239 __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex); | |
| 240 __ beq(&only_change_map); | |
| 241 | |
| 242 __ Push(target_map, receiver, key, value); | |
| 243 __ LoadP(length, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 244 // elements: source FixedDoubleArray | |
| 245 // length: number of elements (smi-tagged) | |
| 246 | |
| 247 // Allocate new FixedArray. | |
| 248 // Re-use value and target_map registers, as they have been saved on the | |
| 249 // stack. | |
| 250 Register array_size = value; | |
| 251 Register allocate_scratch = target_map; | |
| 252 __ LoadImmP(array_size, Operand(FixedDoubleArray::kHeaderSize)); | |
| 253 __ SmiToPtrArrayOffset(r0, length); | |
| 254 __ AddP(array_size, r0); | |
| 255 __ Allocate(array_size, array, allocate_scratch, scratch, &gc_required, | |
| 256 NO_ALLOCATION_FLAGS); | |
| 257 // array: destination FixedArray, tagged as heap object | |
| 258 // Set destination FixedDoubleArray's length and map. | |
| 259 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex); | |
| 260 __ StoreP(length, FieldMemOperand(array, FixedDoubleArray::kLengthOffset), | |
| 261 r0); | |
| 262 __ StoreP(scratch, FieldMemOperand(array, HeapObject::kMapOffset), r0); | |
| 263 | |
| 264 // Prepare for conversion loop. | |
| 265 Register src_elements = elements; | |
| 266 Register dst_elements = target_map; | |
| 267 Register dst_end = length; | |
| 268 Register heap_number_map = scratch; | |
| 269 __ AddP(src_elements, | |
| 270 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); | |
| 271 __ SmiToPtrArrayOffset(length, length); | |
| 272 __ LoadRoot(hole_value, Heap::kTheHoleValueRootIndex); | |
| 273 | |
| 274 Label initialization_loop, loop_done; | |
| 275 __ ShiftRightP(scratch, length, Operand(kPointerSizeLog2)); | |
| 276 __ beq(&loop_done, Label::kNear); | |
| 277 | |
| 278 // Allocating heap numbers in the loop below can fail and cause a jump to | |
| 279 // gc_required. We can't leave a partly initialized FixedArray behind, | |
| 280 // so pessimistically fill it with holes now. | |
| 281 __ AddP(dst_elements, array, | |
| 282 Operand(FixedArray::kHeaderSize - kHeapObjectTag - kPointerSize)); | |
| 283 __ bind(&initialization_loop); | |
| 284 __ StoreP(hole_value, MemOperand(dst_elements, kPointerSize)); | |
| 285 __ lay(dst_elements, MemOperand(dst_elements, kPointerSize)); | |
| 286 __ BranchOnCount(scratch, &initialization_loop); | |
| 287 | |
| 288 __ AddP(dst_elements, array, | |
| 289 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
| 290 __ AddP(dst_end, dst_elements, length); | |
| 291 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | |
| 292 // Using offsetted addresses in src_elements to fully take advantage of | |
| 293 // post-indexing. | |
| 294 // dst_elements: begin of destination FixedArray element fields, not tagged | |
| 295 // src_elements: begin of source FixedDoubleArray element fields, | |
| 296 // not tagged, +4 | |
| 297 // dst_end: end of destination FixedArray, not tagged | |
| 298 // array: destination FixedArray | |
| 299 // hole_value: the-hole pointer | |
| 300 // heap_number_map: heap number map | |
| 301 __ b(&loop, Label::kNear); | |
| 302 | |
| 303 // Call into runtime if GC is required. | |
| 304 __ bind(&gc_required); | |
| 305 __ Pop(target_map, receiver, key, value); | |
| 306 __ b(fail); | |
| 307 | |
| 308 // Replace the-hole NaN with the-hole pointer. | |
| 309 __ bind(&convert_hole); | |
| 310 __ StoreP(hole_value, MemOperand(dst_elements)); | |
| 311 __ AddP(dst_elements, Operand(kPointerSize)); | |
| 312 __ CmpLogicalP(dst_elements, dst_end); | |
| 313 __ bge(&loop_done); | |
| 314 | |
| 315 __ bind(&loop); | |
| 316 Register upper_bits = key; | |
| 317 __ LoadlW(upper_bits, MemOperand(src_elements, Register::kExponentOffset)); | |
| 318 __ AddP(src_elements, Operand(kDoubleSize)); | |
| 319 // upper_bits: current element's upper 32 bit | |
| 320 // src_elements: address of next element's upper 32 bit | |
| 321 __ Cmp32(upper_bits, Operand(kHoleNanUpper32)); | |
| 322 __ beq(&convert_hole, Label::kNear); | |
| 323 | |
| 324 // Non-hole double, copy value into a heap number. | |
| 325 Register heap_number = receiver; | |
| 326 Register scratch2 = value; | |
| 327 __ AllocateHeapNumber(heap_number, scratch2, scratch3, heap_number_map, | |
| 328 &gc_required); | |
| 329 // heap_number: new heap number | |
| 330 #if V8_TARGET_ARCH_S390X | |
| 331 __ lg(scratch2, MemOperand(src_elements, -kDoubleSize)); | |
| 332 // subtract tag for std | |
| 333 __ AddP(upper_bits, heap_number, Operand(-kHeapObjectTag)); | |
| 334 __ stg(scratch2, MemOperand(upper_bits, HeapNumber::kValueOffset)); | |
| 335 #else | |
| 336 __ LoadlW(scratch2, | |
| 337 MemOperand(src_elements, Register::kMantissaOffset - kDoubleSize)); | |
| 338 __ LoadlW(upper_bits, | |
| 339 MemOperand(src_elements, Register::kExponentOffset - kDoubleSize)); | |
| 340 __ StoreW(scratch2, | |
| 341 FieldMemOperand(heap_number, HeapNumber::kMantissaOffset)); | |
| 342 __ StoreW(upper_bits, | |
| 343 FieldMemOperand(heap_number, HeapNumber::kExponentOffset)); | |
| 344 #endif | |
| 345 __ LoadRR(scratch2, dst_elements); | |
| 346 __ StoreP(heap_number, MemOperand(dst_elements)); | |
| 347 __ AddP(dst_elements, Operand(kPointerSize)); | |
| 348 __ RecordWrite(array, scratch2, heap_number, kLRHasNotBeenSaved, | |
| 349 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | |
| 350 __ CmpLogicalP(dst_elements, dst_end); | |
| 351 __ blt(&loop); | |
| 352 __ bind(&loop_done); | |
| 353 | |
| 354 __ Pop(target_map, receiver, key, value); | |
| 355 // Replace receiver's backing store with newly created and filled FixedArray. | |
| 356 __ StoreP(array, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 357 __ RecordWriteField(receiver, JSObject::kElementsOffset, array, scratch, | |
| 358 kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET, | |
| 359 OMIT_SMI_CHECK); | |
| 360 | |
| 361 __ bind(&only_change_map); | |
| 362 // Update receiver's map. | |
| 363 __ StoreP(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 364 __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch, | |
| 365 kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, | |
| 366 OMIT_SMI_CHECK); | |
| 367 } | |
| 368 | |
| 369 // assume ip can be used as a scratch register below | 69 // assume ip can be used as a scratch register below |
| 370 void StringCharLoadGenerator::Generate(MacroAssembler* masm, Register string, | 70 void StringCharLoadGenerator::Generate(MacroAssembler* masm, Register string, |
| 371 Register index, Register result, | 71 Register index, Register result, |
| 372 Label* call_runtime) { | 72 Label* call_runtime) { |
| 373 // Fetch the instance type of the receiver into result register. | 73 // Fetch the instance type of the receiver into result register. |
| 374 __ LoadP(result, FieldMemOperand(string, HeapObject::kMapOffset)); | 74 __ LoadP(result, FieldMemOperand(string, HeapObject::kMapOffset)); |
| 375 __ LoadlB(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); | 75 __ LoadlB(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
| 376 | 76 |
| 377 // We need special handling for indirect strings. | 77 // We need special handling for indirect strings. |
| 378 Label check_sequential; | 78 Label check_sequential; |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 // (kNoCodeAgeSequenceLength - kCodeAgingSequenceLength) bytes. | 229 // (kNoCodeAgeSequenceLength - kCodeAgingSequenceLength) bytes. |
| 530 patcher.masm()->nop(); // 2-byte nops(). | 230 patcher.masm()->nop(); // 2-byte nops(). |
| 531 } | 231 } |
| 532 } | 232 } |
| 533 } | 233 } |
| 534 | 234 |
| 535 } // namespace internal | 235 } // namespace internal |
| 536 } // namespace v8 | 236 } // namespace v8 |
| 537 | 237 |
| 538 #endif // V8_TARGET_ARCH_S390 | 238 #endif // V8_TARGET_ARCH_S390 |
| OLD | NEW |