| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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 <assert.h> // For assert | 5 #include <assert.h> // For assert |
| 6 #include <limits.h> // For LONG_MIN, LONG_MAX. | 6 #include <limits.h> // For LONG_MIN, LONG_MAX. |
| 7 | 7 |
| 8 #if V8_TARGET_ARCH_PPC | 8 #if V8_TARGET_ARCH_S390 |
| 9 | 9 |
| 10 #include "src/base/bits.h" | 10 #include "src/base/bits.h" |
| 11 #include "src/base/division-by-constant.h" | 11 #include "src/base/division-by-constant.h" |
| 12 #include "src/bootstrapper.h" | 12 #include "src/bootstrapper.h" |
| 13 #include "src/codegen.h" | 13 #include "src/codegen.h" |
| 14 #include "src/debug/debug.h" | 14 #include "src/debug/debug.h" |
| 15 #include "src/register-configuration.h" | 15 #include "src/register-configuration.h" |
| 16 #include "src/runtime/runtime.h" | 16 #include "src/runtime/runtime.h" |
| 17 | 17 |
| 18 #include "src/ppc/macro-assembler-ppc.h" | 18 #include "src/s390/macro-assembler-s390.h" |
| 19 | 19 |
| 20 namespace v8 { | 20 namespace v8 { |
| 21 namespace internal { | 21 namespace internal { |
| 22 | 22 |
| 23 MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size, | 23 MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size, |
| 24 CodeObjectRequired create_code_object) | 24 CodeObjectRequired create_code_object) |
| 25 : Assembler(arg_isolate, buffer, size), | 25 : Assembler(arg_isolate, buffer, size), |
| 26 generating_stub_(false), | 26 generating_stub_(false), |
| 27 has_frame_(false) { | 27 has_frame_(false) { |
| 28 if (create_code_object == CodeObjectRequired::kYes) { | 28 if (create_code_object == CodeObjectRequired::kYes) { |
| 29 code_object_ = | 29 code_object_ = |
| 30 Handle<Object>::New(isolate()->heap()->undefined_value(), isolate()); | 30 Handle<Object>::New(isolate()->heap()->undefined_value(), isolate()); |
| 31 } | 31 } |
| 32 } | 32 } |
| 33 | 33 |
| 34 | 34 void MacroAssembler::Jump(Register target) { b(target); } |
| 35 void MacroAssembler::Jump(Register target) { | |
| 36 mtctr(target); | |
| 37 bctr(); | |
| 38 } | |
| 39 | |
| 40 | 35 |
| 41 void MacroAssembler::JumpToJSEntry(Register target) { | 36 void MacroAssembler::JumpToJSEntry(Register target) { |
| 42 Move(ip, target); | 37 Move(ip, target); |
| 43 Jump(ip); | 38 Jump(ip); |
| 44 } | 39 } |
| 45 | 40 |
| 46 | |
| 47 void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode, | 41 void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode, |
| 48 Condition cond, CRegister cr) { | 42 Condition cond, CRegister) { |
| 49 Label skip; | 43 Label skip; |
| 50 | 44 |
| 51 if (cond != al) b(NegateCondition(cond), &skip, cr); | 45 if (cond != al) b(NegateCondition(cond), &skip); |
| 52 | 46 |
| 53 DCHECK(rmode == RelocInfo::CODE_TARGET || rmode == RelocInfo::RUNTIME_ENTRY); | 47 DCHECK(rmode == RelocInfo::CODE_TARGET || rmode == RelocInfo::RUNTIME_ENTRY); |
| 54 | 48 |
| 55 mov(ip, Operand(target, rmode)); | 49 mov(ip, Operand(target, rmode)); |
| 56 mtctr(ip); | 50 b(ip); |
| 57 bctr(); | |
| 58 | 51 |
| 59 bind(&skip); | 52 bind(&skip); |
| 60 } | 53 } |
| 61 | 54 |
| 62 | |
| 63 void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode, Condition cond, | 55 void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode, Condition cond, |
| 64 CRegister cr) { | 56 CRegister cr) { |
| 65 DCHECK(!RelocInfo::IsCodeTarget(rmode)); | 57 DCHECK(!RelocInfo::IsCodeTarget(rmode)); |
| 66 Jump(reinterpret_cast<intptr_t>(target), rmode, cond, cr); | 58 Jump(reinterpret_cast<intptr_t>(target), rmode, cond, cr); |
| 67 } | 59 } |
| 68 | 60 |
| 69 | |
| 70 void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode, | 61 void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode, |
| 71 Condition cond) { | 62 Condition cond) { |
| 72 DCHECK(RelocInfo::IsCodeTarget(rmode)); | 63 DCHECK(RelocInfo::IsCodeTarget(rmode)); |
| 73 // 'code' is always generated ppc code, never THUMB code | 64 jump(code, rmode, cond); |
| 74 AllowDeferredHandleDereference embedding_raw_address; | |
| 75 Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond); | |
| 76 } | 65 } |
| 77 | 66 |
| 78 | 67 int MacroAssembler::CallSize(Register target) { return 2; } // BASR |
| 79 int MacroAssembler::CallSize(Register target) { return 2 * kInstrSize; } | |
| 80 | |
| 81 | 68 |
| 82 void MacroAssembler::Call(Register target) { | 69 void MacroAssembler::Call(Register target) { |
| 83 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 84 Label start; | 70 Label start; |
| 85 bind(&start); | 71 bind(&start); |
| 86 | 72 |
| 87 // Statement positions are expected to be recorded when the target | 73 // Statement positions are expected to be recorded when the target |
| 88 // address is loaded. | 74 // address is loaded. |
| 89 positions_recorder()->WriteRecordedPositions(); | 75 positions_recorder()->WriteRecordedPositions(); |
| 90 | 76 |
| 91 // branch via link register and set LK bit for return point | 77 // Branch to target via indirect branch |
| 92 mtctr(target); | 78 basr(r14, target); |
| 93 bctrl(); | |
| 94 | 79 |
| 95 DCHECK_EQ(CallSize(target), SizeOfCodeGeneratedSince(&start)); | 80 DCHECK_EQ(CallSize(target), SizeOfCodeGeneratedSince(&start)); |
| 96 } | 81 } |
| 97 | 82 |
| 98 | |
| 99 void MacroAssembler::CallJSEntry(Register target) { | 83 void MacroAssembler::CallJSEntry(Register target) { |
| 100 DCHECK(target.is(ip)); | 84 DCHECK(target.is(ip)); |
| 101 Call(target); | 85 Call(target); |
| 102 } | 86 } |
| 103 | 87 |
| 104 | |
| 105 int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode, | 88 int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode, |
| 106 Condition cond) { | 89 Condition cond) { |
| 107 Operand mov_operand = Operand(reinterpret_cast<intptr_t>(target), rmode); | 90 // S390 Assembler::move sequence is IILF / IIHF |
| 108 return (2 + instructions_required_for_mov(ip, mov_operand)) * kInstrSize; | 91 int size; |
| 92 #if V8_TARGET_ARCH_S390X |
| 93 size = 14; // IILF + IIHF + BASR |
| 94 #else |
| 95 size = 8; // IILF + BASR |
| 96 #endif |
| 97 return size; |
| 109 } | 98 } |
| 110 | 99 |
| 111 | |
| 112 int MacroAssembler::CallSizeNotPredictableCodeSize(Address target, | 100 int MacroAssembler::CallSizeNotPredictableCodeSize(Address target, |
| 113 RelocInfo::Mode rmode, | 101 RelocInfo::Mode rmode, |
| 114 Condition cond) { | 102 Condition cond) { |
| 115 return (2 + kMovInstructionsNoConstantPool) * kInstrSize; | 103 // S390 Assembler::move sequence is IILF / IIHF |
| 104 int size; |
| 105 #if V8_TARGET_ARCH_S390X |
| 106 size = 14; // IILF + IIHF + BASR |
| 107 #else |
| 108 size = 8; // IILF + BASR |
| 109 #endif |
| 110 return size; |
| 116 } | 111 } |
| 117 | 112 |
| 118 | |
| 119 void MacroAssembler::Call(Address target, RelocInfo::Mode rmode, | 113 void MacroAssembler::Call(Address target, RelocInfo::Mode rmode, |
| 120 Condition cond) { | 114 Condition cond) { |
| 121 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 122 DCHECK(cond == al); | 115 DCHECK(cond == al); |
| 123 | 116 |
| 124 #ifdef DEBUG | 117 #ifdef DEBUG |
| 125 // Check the expected size before generating code to ensure we assume the same | 118 // Check the expected size before generating code to ensure we assume the same |
| 126 // constant pool availability (e.g., whether constant pool is full or not). | 119 // constant pool availability (e.g., whether constant pool is full or not). |
| 127 int expected_size = CallSize(target, rmode, cond); | 120 int expected_size = CallSize(target, rmode, cond); |
| 128 Label start; | 121 Label start; |
| 129 bind(&start); | 122 bind(&start); |
| 130 #endif | 123 #endif |
| 131 | 124 |
| 132 // Statement positions are expected to be recorded when the target | 125 // Statement positions are expected to be recorded when the target |
| 133 // address is loaded. | 126 // address is loaded. |
| 134 positions_recorder()->WriteRecordedPositions(); | 127 positions_recorder()->WriteRecordedPositions(); |
| 135 | 128 |
| 136 // This can likely be optimized to make use of bc() with 24bit relative | |
| 137 // | |
| 138 // RecordRelocInfo(x.rmode_, x.imm_); | |
| 139 // bc( BA, .... offset, LKset); | |
| 140 // | |
| 141 | |
| 142 mov(ip, Operand(reinterpret_cast<intptr_t>(target), rmode)); | 129 mov(ip, Operand(reinterpret_cast<intptr_t>(target), rmode)); |
| 143 mtctr(ip); | 130 basr(r14, ip); |
| 144 bctrl(); | |
| 145 | 131 |
| 146 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start)); | 132 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start)); |
| 147 } | 133 } |
| 148 | 134 |
| 149 | |
| 150 int MacroAssembler::CallSize(Handle<Code> code, RelocInfo::Mode rmode, | 135 int MacroAssembler::CallSize(Handle<Code> code, RelocInfo::Mode rmode, |
| 151 TypeFeedbackId ast_id, Condition cond) { | 136 TypeFeedbackId ast_id, Condition cond) { |
| 152 AllowDeferredHandleDereference using_raw_address; | 137 return 6; // BRASL |
| 153 return CallSize(reinterpret_cast<Address>(code.location()), rmode, cond); | |
| 154 } | 138 } |
| 155 | 139 |
| 156 | |
| 157 void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode, | 140 void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode, |
| 158 TypeFeedbackId ast_id, Condition cond) { | 141 TypeFeedbackId ast_id, Condition cond) { |
| 159 BlockTrampolinePoolScope block_trampoline_pool(this); | 142 DCHECK(RelocInfo::IsCodeTarget(rmode) && cond == al); |
| 160 DCHECK(RelocInfo::IsCodeTarget(rmode)); | |
| 161 | 143 |
| 162 #ifdef DEBUG | 144 #ifdef DEBUG |
| 163 // Check the expected size before generating code to ensure we assume the same | 145 // Check the expected size before generating code to ensure we assume the same |
| 164 // constant pool availability (e.g., whether constant pool is full or not). | 146 // constant pool availability (e.g., whether constant pool is full or not). |
| 165 int expected_size = CallSize(code, rmode, ast_id, cond); | 147 int expected_size = CallSize(code, rmode, ast_id, cond); |
| 166 Label start; | 148 Label start; |
| 167 bind(&start); | 149 bind(&start); |
| 168 #endif | 150 #endif |
| 169 | 151 call(code, rmode, ast_id); |
| 170 if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) { | |
| 171 SetRecordedAstId(ast_id); | |
| 172 rmode = RelocInfo::CODE_TARGET_WITH_ID; | |
| 173 } | |
| 174 AllowDeferredHandleDereference using_raw_address; | |
| 175 Call(reinterpret_cast<Address>(code.location()), rmode, cond); | |
| 176 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start)); | 152 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start)); |
| 177 } | 153 } |
| 178 | 154 |
| 179 | |
| 180 void MacroAssembler::Drop(int count) { | 155 void MacroAssembler::Drop(int count) { |
| 181 if (count > 0) { | 156 if (count > 0) { |
| 182 Add(sp, sp, count * kPointerSize, r0); | 157 la(sp, MemOperand(sp, count * kPointerSize)); |
| 183 } | 158 } |
| 184 } | 159 } |
| 185 | 160 |
| 186 void MacroAssembler::Drop(Register count, Register scratch) { | 161 void MacroAssembler::Drop(Register count, Register scratch) { |
| 187 ShiftLeftImm(scratch, count, Operand(kPointerSizeLog2)); | 162 ShiftLeftP(scratch, count, Operand(kPointerSizeLog2)); |
| 188 add(sp, sp, scratch); | 163 AddP(sp, sp, scratch); |
| 189 } | 164 } |
| 190 | 165 |
| 191 void MacroAssembler::Call(Label* target) { b(target, SetLK); } | 166 void MacroAssembler::Call(Label* target) { b(r14, target); } |
| 192 | |
| 193 | 167 |
| 194 void MacroAssembler::Push(Handle<Object> handle) { | 168 void MacroAssembler::Push(Handle<Object> handle) { |
| 195 mov(r0, Operand(handle)); | 169 mov(r0, Operand(handle)); |
| 196 push(r0); | 170 push(r0); |
| 197 } | 171 } |
| 198 | 172 |
| 199 | |
| 200 void MacroAssembler::Move(Register dst, Handle<Object> value) { | 173 void MacroAssembler::Move(Register dst, Handle<Object> value) { |
| 201 AllowDeferredHandleDereference smi_check; | 174 AllowDeferredHandleDereference smi_check; |
| 202 if (value->IsSmi()) { | 175 if (value->IsSmi()) { |
| 203 LoadSmiLiteral(dst, reinterpret_cast<Smi*>(*value)); | 176 LoadSmiLiteral(dst, reinterpret_cast<Smi*>(*value)); |
| 204 } else { | 177 } else { |
| 205 DCHECK(value->IsHeapObject()); | 178 DCHECK(value->IsHeapObject()); |
| 206 if (isolate()->heap()->InNewSpace(*value)) { | 179 if (isolate()->heap()->InNewSpace(*value)) { |
| 207 Handle<Cell> cell = isolate()->factory()->NewCell(value); | 180 Handle<Cell> cell = isolate()->factory()->NewCell(value); |
| 208 mov(dst, Operand(cell)); | 181 mov(dst, Operand(cell)); |
| 209 LoadP(dst, FieldMemOperand(dst, Cell::kValueOffset)); | 182 LoadP(dst, FieldMemOperand(dst, Cell::kValueOffset)); |
| 210 } else { | 183 } else { |
| 211 mov(dst, Operand(value)); | 184 mov(dst, Operand(value)); |
| 212 } | 185 } |
| 213 } | 186 } |
| 214 } | 187 } |
| 215 | 188 |
| 216 | |
| 217 void MacroAssembler::Move(Register dst, Register src, Condition cond) { | 189 void MacroAssembler::Move(Register dst, Register src, Condition cond) { |
| 218 DCHECK(cond == al); | |
| 219 if (!dst.is(src)) { | 190 if (!dst.is(src)) { |
| 220 mr(dst, src); | 191 LoadRR(dst, src); |
| 221 } | 192 } |
| 222 } | 193 } |
| 223 | 194 |
| 224 | |
| 225 void MacroAssembler::Move(DoubleRegister dst, DoubleRegister src) { | 195 void MacroAssembler::Move(DoubleRegister dst, DoubleRegister src) { |
| 226 if (!dst.is(src)) { | 196 if (!dst.is(src)) { |
| 227 fmr(dst, src); | 197 ldr(dst, src); |
| 228 } | 198 } |
| 229 } | 199 } |
| 230 | 200 |
| 201 void MacroAssembler::InsertDoubleLow(DoubleRegister dst, Register src) { |
| 202 StoreDouble(dst, MemOperand(sp, -kDoubleSize)); |
| 203 #if V8_TARGET_LITTLE_ENDIAN |
| 204 StoreW(src, MemOperand(sp, -kDoubleSize)); |
| 205 #else |
| 206 StoreW(src, MemOperand(sp, -kDoubleSize / 2)); |
| 207 #endif |
| 208 ldy(dst, MemOperand(sp, -kDoubleSize)); |
| 209 } |
| 210 |
| 211 void MacroAssembler::InsertDoubleHigh(DoubleRegister dst, Register src) { |
| 212 StoreDouble(dst, MemOperand(sp, -kDoubleSize)); |
| 213 #if V8_TARGET_LITTLE_ENDIAN |
| 214 StoreW(src, MemOperand(sp, -kDoubleSize / 2)); |
| 215 #else |
| 216 StoreW(src, MemOperand(sp, -kDoubleSize)); |
| 217 #endif |
| 218 ldy(dst, MemOperand(sp, -kDoubleSize)); |
| 219 } |
| 231 | 220 |
| 232 void MacroAssembler::MultiPush(RegList regs, Register location) { | 221 void MacroAssembler::MultiPush(RegList regs, Register location) { |
| 233 int16_t num_to_push = NumberOfBitsSet(regs); | 222 int16_t num_to_push = NumberOfBitsSet(regs); |
| 234 int16_t stack_offset = num_to_push * kPointerSize; | 223 int16_t stack_offset = num_to_push * kPointerSize; |
| 235 | 224 |
| 236 subi(location, location, Operand(stack_offset)); | 225 SubP(location, location, Operand(stack_offset)); |
| 237 for (int16_t i = Register::kNumRegisters - 1; i >= 0; i--) { | 226 for (int16_t i = Register::kNumRegisters - 1; i >= 0; i--) { |
| 238 if ((regs & (1 << i)) != 0) { | 227 if ((regs & (1 << i)) != 0) { |
| 239 stack_offset -= kPointerSize; | 228 stack_offset -= kPointerSize; |
| 240 StoreP(ToRegister(i), MemOperand(location, stack_offset)); | 229 StoreP(ToRegister(i), MemOperand(location, stack_offset)); |
| 241 } | 230 } |
| 242 } | 231 } |
| 243 } | 232 } |
| 244 | 233 |
| 245 | |
| 246 void MacroAssembler::MultiPop(RegList regs, Register location) { | 234 void MacroAssembler::MultiPop(RegList regs, Register location) { |
| 247 int16_t stack_offset = 0; | 235 int16_t stack_offset = 0; |
| 248 | 236 |
| 249 for (int16_t i = 0; i < Register::kNumRegisters; i++) { | 237 for (int16_t i = 0; i < Register::kNumRegisters; i++) { |
| 250 if ((regs & (1 << i)) != 0) { | 238 if ((regs & (1 << i)) != 0) { |
| 251 LoadP(ToRegister(i), MemOperand(location, stack_offset)); | 239 LoadP(ToRegister(i), MemOperand(location, stack_offset)); |
| 252 stack_offset += kPointerSize; | 240 stack_offset += kPointerSize; |
| 253 } | 241 } |
| 254 } | 242 } |
| 255 addi(location, location, Operand(stack_offset)); | 243 AddP(location, location, Operand(stack_offset)); |
| 256 } | 244 } |
| 257 | 245 |
| 258 | |
| 259 void MacroAssembler::MultiPushDoubles(RegList dregs, Register location) { | 246 void MacroAssembler::MultiPushDoubles(RegList dregs, Register location) { |
| 260 int16_t num_to_push = NumberOfBitsSet(dregs); | 247 int16_t num_to_push = NumberOfBitsSet(dregs); |
| 261 int16_t stack_offset = num_to_push * kDoubleSize; | 248 int16_t stack_offset = num_to_push * kDoubleSize; |
| 262 | 249 |
| 263 subi(location, location, Operand(stack_offset)); | 250 SubP(location, location, Operand(stack_offset)); |
| 264 for (int16_t i = DoubleRegister::kNumRegisters - 1; i >= 0; i--) { | 251 for (int16_t i = DoubleRegister::kNumRegisters - 1; i >= 0; i--) { |
| 265 if ((dregs & (1 << i)) != 0) { | 252 if ((dregs & (1 << i)) != 0) { |
| 266 DoubleRegister dreg = DoubleRegister::from_code(i); | 253 DoubleRegister dreg = DoubleRegister::from_code(i); |
| 267 stack_offset -= kDoubleSize; | 254 stack_offset -= kDoubleSize; |
| 268 stfd(dreg, MemOperand(location, stack_offset)); | 255 StoreDouble(dreg, MemOperand(location, stack_offset)); |
| 269 } | 256 } |
| 270 } | 257 } |
| 271 } | 258 } |
| 272 | 259 |
| 273 | |
| 274 void MacroAssembler::MultiPopDoubles(RegList dregs, Register location) { | 260 void MacroAssembler::MultiPopDoubles(RegList dregs, Register location) { |
| 275 int16_t stack_offset = 0; | 261 int16_t stack_offset = 0; |
| 276 | 262 |
| 277 for (int16_t i = 0; i < DoubleRegister::kNumRegisters; i++) { | 263 for (int16_t i = 0; i < DoubleRegister::kNumRegisters; i++) { |
| 278 if ((dregs & (1 << i)) != 0) { | 264 if ((dregs & (1 << i)) != 0) { |
| 279 DoubleRegister dreg = DoubleRegister::from_code(i); | 265 DoubleRegister dreg = DoubleRegister::from_code(i); |
| 280 lfd(dreg, MemOperand(location, stack_offset)); | 266 LoadDouble(dreg, MemOperand(location, stack_offset)); |
| 281 stack_offset += kDoubleSize; | 267 stack_offset += kDoubleSize; |
| 282 } | 268 } |
| 283 } | 269 } |
| 284 addi(location, location, Operand(stack_offset)); | 270 AddP(location, location, Operand(stack_offset)); |
| 285 } | 271 } |
| 286 | 272 |
| 287 | |
| 288 void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index, | 273 void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index, |
| 289 Condition cond) { | 274 Condition) { |
| 290 DCHECK(cond == al); | |
| 291 LoadP(destination, MemOperand(kRootRegister, index << kPointerSizeLog2), r0); | 275 LoadP(destination, MemOperand(kRootRegister, index << kPointerSizeLog2), r0); |
| 292 } | 276 } |
| 293 | 277 |
| 294 | |
| 295 void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index, | 278 void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index, |
| 296 Condition cond) { | 279 Condition) { |
| 297 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index)); | 280 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index)); |
| 298 DCHECK(cond == al); | 281 StoreP(source, MemOperand(kRootRegister, index << kPointerSizeLog2)); |
| 299 StoreP(source, MemOperand(kRootRegister, index << kPointerSizeLog2), r0); | |
| 300 } | 282 } |
| 301 | 283 |
| 302 | |
| 303 void MacroAssembler::InNewSpace(Register object, Register scratch, | 284 void MacroAssembler::InNewSpace(Register object, Register scratch, |
| 304 Condition cond, Label* branch) { | 285 Condition cond, Label* branch) { |
| 305 DCHECK(cond == eq || cond == ne); | 286 DCHECK(cond == eq || cond == ne); |
| 287 // TODO(joransiu): check if we can merge mov Operand into AndP. |
| 306 const int mask = | 288 const int mask = |
| 307 (1 << MemoryChunk::IN_FROM_SPACE) | (1 << MemoryChunk::IN_TO_SPACE); | 289 (1 << MemoryChunk::IN_FROM_SPACE) | (1 << MemoryChunk::IN_TO_SPACE); |
| 308 CheckPageFlag(object, scratch, mask, cond, branch); | 290 CheckPageFlag(object, scratch, mask, cond, branch); |
| 309 } | 291 } |
| 310 | 292 |
| 311 | |
| 312 void MacroAssembler::RecordWriteField( | 293 void MacroAssembler::RecordWriteField( |
| 313 Register object, int offset, Register value, Register dst, | 294 Register object, int offset, Register value, Register dst, |
| 314 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp, | 295 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp, |
| 315 RememberedSetAction remembered_set_action, SmiCheck smi_check, | 296 RememberedSetAction remembered_set_action, SmiCheck smi_check, |
| 316 PointersToHereCheck pointers_to_here_check_for_value) { | 297 PointersToHereCheck pointers_to_here_check_for_value) { |
| 317 // First, check if a write barrier is even needed. The tests below | 298 // First, check if a write barrier is even needed. The tests below |
| 318 // catch stores of Smis. | 299 // catch stores of Smis. |
| 319 Label done; | 300 Label done; |
| 320 | 301 |
| 321 // Skip barrier if writing a smi. | 302 // Skip barrier if writing a smi. |
| 322 if (smi_check == INLINE_SMI_CHECK) { | 303 if (smi_check == INLINE_SMI_CHECK) { |
| 323 JumpIfSmi(value, &done); | 304 JumpIfSmi(value, &done); |
| 324 } | 305 } |
| 325 | 306 |
| 326 // Although the object register is tagged, the offset is relative to the start | 307 // Although the object register is tagged, the offset is relative to the start |
| 327 // of the object, so so offset must be a multiple of kPointerSize. | 308 // of the object, so so offset must be a multiple of kPointerSize. |
| 328 DCHECK(IsAligned(offset, kPointerSize)); | 309 DCHECK(IsAligned(offset, kPointerSize)); |
| 329 | 310 |
| 330 Add(dst, object, offset - kHeapObjectTag, r0); | 311 lay(dst, MemOperand(object, offset - kHeapObjectTag)); |
| 331 if (emit_debug_code()) { | 312 if (emit_debug_code()) { |
| 332 Label ok; | 313 Label ok; |
| 333 andi(r0, dst, Operand((1 << kPointerSizeLog2) - 1)); | 314 AndP(r0, dst, Operand((1 << kPointerSizeLog2) - 1)); |
| 334 beq(&ok, cr0); | 315 beq(&ok, Label::kNear); |
| 335 stop("Unaligned cell in write barrier"); | 316 stop("Unaligned cell in write barrier"); |
| 336 bind(&ok); | 317 bind(&ok); |
| 337 } | 318 } |
| 338 | 319 |
| 339 RecordWrite(object, dst, value, lr_status, save_fp, remembered_set_action, | 320 RecordWrite(object, dst, value, lr_status, save_fp, remembered_set_action, |
| 340 OMIT_SMI_CHECK, pointers_to_here_check_for_value); | 321 OMIT_SMI_CHECK, pointers_to_here_check_for_value); |
| 341 | 322 |
| 342 bind(&done); | 323 bind(&done); |
| 343 | 324 |
| 344 // Clobber clobbered input registers when running with the debug-code flag | 325 // Clobber clobbered input registers when running with the debug-code flag |
| 345 // turned on to provoke errors. | 326 // turned on to provoke errors. |
| 346 if (emit_debug_code()) { | 327 if (emit_debug_code()) { |
| 347 mov(value, Operand(bit_cast<intptr_t>(kZapValue + 4))); | 328 mov(value, Operand(bit_cast<intptr_t>(kZapValue + 4))); |
| 348 mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 8))); | 329 mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 8))); |
| 349 } | 330 } |
| 350 } | 331 } |
| 351 | 332 |
| 352 | |
| 353 // Will clobber 4 registers: object, map, dst, ip. The | 333 // Will clobber 4 registers: object, map, dst, ip. The |
| 354 // register 'object' contains a heap object pointer. | 334 // register 'object' contains a heap object pointer. |
| 355 void MacroAssembler::RecordWriteForMap(Register object, Register map, | 335 void MacroAssembler::RecordWriteForMap(Register object, Register map, |
| 356 Register dst, | 336 Register dst, |
| 357 LinkRegisterStatus lr_status, | 337 LinkRegisterStatus lr_status, |
| 358 SaveFPRegsMode fp_mode) { | 338 SaveFPRegsMode fp_mode) { |
| 359 if (emit_debug_code()) { | 339 if (emit_debug_code()) { |
| 360 LoadP(dst, FieldMemOperand(map, HeapObject::kMapOffset)); | 340 LoadP(dst, FieldMemOperand(map, HeapObject::kMapOffset)); |
| 361 Cmpi(dst, Operand(isolate()->factory()->meta_map()), r0); | 341 CmpP(dst, Operand(isolate()->factory()->meta_map())); |
| 362 Check(eq, kWrongAddressOrValuePassedToRecordWrite); | 342 Check(eq, kWrongAddressOrValuePassedToRecordWrite); |
| 363 } | 343 } |
| 364 | 344 |
| 365 if (!FLAG_incremental_marking) { | 345 if (!FLAG_incremental_marking) { |
| 366 return; | 346 return; |
| 367 } | 347 } |
| 368 | 348 |
| 369 if (emit_debug_code()) { | 349 if (emit_debug_code()) { |
| 370 LoadP(ip, FieldMemOperand(object, HeapObject::kMapOffset)); | 350 CmpP(map, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 371 cmp(ip, map); | |
| 372 Check(eq, kWrongAddressOrValuePassedToRecordWrite); | 351 Check(eq, kWrongAddressOrValuePassedToRecordWrite); |
| 373 } | 352 } |
| 374 | 353 |
| 375 Label done; | 354 Label done; |
| 376 | 355 |
| 377 // A single check of the map's pages interesting flag suffices, since it is | 356 // A single check of the map's pages interesting flag suffices, since it is |
| 378 // only set during incremental collection, and then it's also guaranteed that | 357 // only set during incremental collection, and then it's also guaranteed that |
| 379 // the from object's page's interesting flag is also set. This optimization | 358 // the from object's page's interesting flag is also set. This optimization |
| 380 // relies on the fact that maps can never be in new space. | 359 // relies on the fact that maps can never be in new space. |
| 381 CheckPageFlag(map, | 360 CheckPageFlag(map, |
| 382 map, // Used as scratch. | 361 map, // Used as scratch. |
| 383 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done); | 362 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done); |
| 384 | 363 |
| 385 addi(dst, object, Operand(HeapObject::kMapOffset - kHeapObjectTag)); | 364 lay(dst, MemOperand(object, HeapObject::kMapOffset - kHeapObjectTag)); |
| 386 if (emit_debug_code()) { | 365 if (emit_debug_code()) { |
| 387 Label ok; | 366 Label ok; |
| 388 andi(r0, dst, Operand((1 << kPointerSizeLog2) - 1)); | 367 AndP(r0, dst, Operand((1 << kPointerSizeLog2) - 1)); |
| 389 beq(&ok, cr0); | 368 beq(&ok, Label::kNear); |
| 390 stop("Unaligned cell in write barrier"); | 369 stop("Unaligned cell in write barrier"); |
| 391 bind(&ok); | 370 bind(&ok); |
| 392 } | 371 } |
| 393 | 372 |
| 394 // Record the actual write. | 373 // Record the actual write. |
| 395 if (lr_status == kLRHasNotBeenSaved) { | 374 if (lr_status == kLRHasNotBeenSaved) { |
| 396 mflr(r0); | 375 push(r14); |
| 397 push(r0); | |
| 398 } | 376 } |
| 399 RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET, | 377 RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET, |
| 400 fp_mode); | 378 fp_mode); |
| 401 CallStub(&stub); | 379 CallStub(&stub); |
| 402 if (lr_status == kLRHasNotBeenSaved) { | 380 if (lr_status == kLRHasNotBeenSaved) { |
| 403 pop(r0); | 381 pop(r14); |
| 404 mtlr(r0); | |
| 405 } | 382 } |
| 406 | 383 |
| 407 bind(&done); | 384 bind(&done); |
| 408 | 385 |
| 409 // Count number of write barriers in generated code. | 386 // Count number of write barriers in generated code. |
| 410 isolate()->counters()->write_barriers_static()->Increment(); | 387 isolate()->counters()->write_barriers_static()->Increment(); |
| 411 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, dst); | 388 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, dst); |
| 412 | 389 |
| 413 // Clobber clobbered registers when running with the debug-code flag | 390 // Clobber clobbered registers when running with the debug-code flag |
| 414 // turned on to provoke errors. | 391 // turned on to provoke errors. |
| 415 if (emit_debug_code()) { | 392 if (emit_debug_code()) { |
| 416 mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 12))); | 393 mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 12))); |
| 417 mov(map, Operand(bit_cast<intptr_t>(kZapValue + 16))); | 394 mov(map, Operand(bit_cast<intptr_t>(kZapValue + 16))); |
| 418 } | 395 } |
| 419 } | 396 } |
| 420 | 397 |
| 421 | |
| 422 // Will clobber 4 registers: object, address, scratch, ip. The | 398 // Will clobber 4 registers: object, address, scratch, ip. The |
| 423 // register 'object' contains a heap object pointer. The heap object | 399 // register 'object' contains a heap object pointer. The heap object |
| 424 // tag is shifted away. | 400 // tag is shifted away. |
| 425 void MacroAssembler::RecordWrite( | 401 void MacroAssembler::RecordWrite( |
| 426 Register object, Register address, Register value, | 402 Register object, Register address, Register value, |
| 427 LinkRegisterStatus lr_status, SaveFPRegsMode fp_mode, | 403 LinkRegisterStatus lr_status, SaveFPRegsMode fp_mode, |
| 428 RememberedSetAction remembered_set_action, SmiCheck smi_check, | 404 RememberedSetAction remembered_set_action, SmiCheck smi_check, |
| 429 PointersToHereCheck pointers_to_here_check_for_value) { | 405 PointersToHereCheck pointers_to_here_check_for_value) { |
| 430 DCHECK(!object.is(value)); | 406 DCHECK(!object.is(value)); |
| 431 if (emit_debug_code()) { | 407 if (emit_debug_code()) { |
| 432 LoadP(r0, MemOperand(address)); | 408 CmpP(value, MemOperand(address)); |
| 433 cmp(r0, value); | |
| 434 Check(eq, kWrongAddressOrValuePassedToRecordWrite); | 409 Check(eq, kWrongAddressOrValuePassedToRecordWrite); |
| 435 } | 410 } |
| 436 | 411 |
| 437 if (remembered_set_action == OMIT_REMEMBERED_SET && | 412 if (remembered_set_action == OMIT_REMEMBERED_SET && |
| 438 !FLAG_incremental_marking) { | 413 !FLAG_incremental_marking) { |
| 439 return; | 414 return; |
| 440 } | 415 } |
| 441 | |
| 442 // First, check if a write barrier is even needed. The tests below | 416 // First, check if a write barrier is even needed. The tests below |
| 443 // catch stores of smis and stores into the young generation. | 417 // catch stores of smis and stores into the young generation. |
| 444 Label done; | 418 Label done; |
| 445 | 419 |
| 446 if (smi_check == INLINE_SMI_CHECK) { | 420 if (smi_check == INLINE_SMI_CHECK) { |
| 447 JumpIfSmi(value, &done); | 421 JumpIfSmi(value, &done); |
| 448 } | 422 } |
| 449 | 423 |
| 450 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) { | 424 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) { |
| 451 CheckPageFlag(value, | 425 CheckPageFlag(value, |
| 452 value, // Used as scratch. | 426 value, // Used as scratch. |
| 453 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done); | 427 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done); |
| 454 } | 428 } |
| 455 CheckPageFlag(object, | 429 CheckPageFlag(object, |
| 456 value, // Used as scratch. | 430 value, // Used as scratch. |
| 457 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done); | 431 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done); |
| 458 | 432 |
| 459 // Record the actual write. | 433 // Record the actual write. |
| 460 if (lr_status == kLRHasNotBeenSaved) { | 434 if (lr_status == kLRHasNotBeenSaved) { |
| 461 mflr(r0); | 435 push(r14); |
| 462 push(r0); | |
| 463 } | 436 } |
| 464 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, | 437 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, |
| 465 fp_mode); | 438 fp_mode); |
| 466 CallStub(&stub); | 439 CallStub(&stub); |
| 467 if (lr_status == kLRHasNotBeenSaved) { | 440 if (lr_status == kLRHasNotBeenSaved) { |
| 468 pop(r0); | 441 pop(r14); |
| 469 mtlr(r0); | |
| 470 } | 442 } |
| 471 | 443 |
| 472 bind(&done); | 444 bind(&done); |
| 473 | 445 |
| 474 // Count number of write barriers in generated code. | 446 // Count number of write barriers in generated code. |
| 475 isolate()->counters()->write_barriers_static()->Increment(); | 447 isolate()->counters()->write_barriers_static()->Increment(); |
| 476 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, | 448 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, |
| 477 value); | 449 value); |
| 478 | 450 |
| 479 // Clobber clobbered registers when running with the debug-code flag | 451 // Clobber clobbered registers when running with the debug-code flag |
| 480 // turned on to provoke errors. | 452 // turned on to provoke errors. |
| 481 if (emit_debug_code()) { | 453 if (emit_debug_code()) { |
| 482 mov(address, Operand(bit_cast<intptr_t>(kZapValue + 12))); | 454 mov(address, Operand(bit_cast<intptr_t>(kZapValue + 12))); |
| 483 mov(value, Operand(bit_cast<intptr_t>(kZapValue + 16))); | 455 mov(value, Operand(bit_cast<intptr_t>(kZapValue + 16))); |
| 484 } | 456 } |
| 485 } | 457 } |
| 486 | 458 |
| 487 void MacroAssembler::RecordWriteCodeEntryField(Register js_function, | 459 void MacroAssembler::RecordWriteCodeEntryField(Register js_function, |
| 488 Register code_entry, | 460 Register code_entry, |
| 489 Register scratch) { | 461 Register scratch) { |
| 490 const int offset = JSFunction::kCodeEntryOffset; | 462 const int offset = JSFunction::kCodeEntryOffset; |
| 491 | 463 |
| 492 // Since a code entry (value) is always in old space, we don't need to update | 464 // Since a code entry (value) is always in old space, we don't need to update |
| 493 // remembered set. If incremental marking is off, there is nothing for us to | 465 // remembered set. If incremental marking is off, there is nothing for us to |
| 494 // do. | 466 // do. |
| 495 if (!FLAG_incremental_marking) return; | 467 if (!FLAG_incremental_marking) return; |
| 496 | 468 |
| 497 DCHECK(js_function.is(r4)); | 469 DCHECK(js_function.is(r3)); |
| 498 DCHECK(code_entry.is(r7)); | 470 DCHECK(code_entry.is(r6)); |
| 499 DCHECK(scratch.is(r8)); | 471 DCHECK(scratch.is(r7)); |
| 500 AssertNotSmi(js_function); | 472 AssertNotSmi(js_function); |
| 501 | 473 |
| 502 if (emit_debug_code()) { | 474 if (emit_debug_code()) { |
| 503 addi(scratch, js_function, Operand(offset - kHeapObjectTag)); | 475 AddP(scratch, js_function, Operand(offset - kHeapObjectTag)); |
| 504 LoadP(ip, MemOperand(scratch)); | 476 LoadP(ip, MemOperand(scratch)); |
| 505 cmp(ip, code_entry); | 477 CmpP(ip, code_entry); |
| 506 Check(eq, kWrongAddressOrValuePassedToRecordWrite); | 478 Check(eq, kWrongAddressOrValuePassedToRecordWrite); |
| 507 } | 479 } |
| 508 | 480 |
| 509 // First, check if a write barrier is even needed. The tests below | 481 // First, check if a write barrier is even needed. The tests below |
| 510 // catch stores of Smis and stores into young gen. | 482 // catch stores of Smis and stores into young gen. |
| 511 Label done; | 483 Label done; |
| 512 | 484 |
| 513 CheckPageFlag(code_entry, scratch, | 485 CheckPageFlag(code_entry, scratch, |
| 514 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done); | 486 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done); |
| 515 CheckPageFlag(js_function, scratch, | 487 CheckPageFlag(js_function, scratch, |
| 516 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done); | 488 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done); |
| 517 | 489 |
| 518 const Register dst = scratch; | 490 const Register dst = scratch; |
| 519 addi(dst, js_function, Operand(offset - kHeapObjectTag)); | 491 AddP(dst, js_function, Operand(offset - kHeapObjectTag)); |
| 520 | 492 |
| 521 // Save caller-saved registers. js_function and code_entry are in the | 493 // Save caller-saved registers. js_function and code_entry are in the |
| 522 // caller-saved register list. | 494 // caller-saved register list. |
| 523 DCHECK(kJSCallerSaved & js_function.bit()); | 495 DCHECK(kJSCallerSaved & js_function.bit()); |
| 524 DCHECK(kJSCallerSaved & code_entry.bit()); | 496 DCHECK(kJSCallerSaved & code_entry.bit()); |
| 525 mflr(r0); | 497 MultiPush(kJSCallerSaved | r14.bit()); |
| 526 MultiPush(kJSCallerSaved | r0.bit()); | |
| 527 | 498 |
| 528 int argument_count = 3; | 499 int argument_count = 3; |
| 529 PrepareCallCFunction(argument_count, code_entry); | 500 PrepareCallCFunction(argument_count, code_entry); |
| 530 | 501 |
| 531 mr(r3, js_function); | 502 LoadRR(r2, js_function); |
| 532 mr(r4, dst); | 503 LoadRR(r3, dst); |
| 533 mov(r5, Operand(ExternalReference::isolate_address(isolate()))); | 504 mov(r4, Operand(ExternalReference::isolate_address(isolate()))); |
| 534 | 505 |
| 535 { | 506 { |
| 536 AllowExternalCallThatCantCauseGC scope(this); | 507 AllowExternalCallThatCantCauseGC scope(this); |
| 537 CallCFunction( | 508 CallCFunction( |
| 538 ExternalReference::incremental_marking_record_write_code_entry_function( | 509 ExternalReference::incremental_marking_record_write_code_entry_function( |
| 539 isolate()), | 510 isolate()), |
| 540 argument_count); | 511 argument_count); |
| 541 } | 512 } |
| 542 | 513 |
| 543 // Restore caller-saved registers (including js_function and code_entry). | 514 // Restore caller-saved registers (including js_function and code_entry). |
| 544 MultiPop(kJSCallerSaved | r0.bit()); | 515 MultiPop(kJSCallerSaved | r14.bit()); |
| 545 mtlr(r0); | |
| 546 | 516 |
| 547 bind(&done); | 517 bind(&done); |
| 548 } | 518 } |
| 549 | 519 |
| 550 void MacroAssembler::RememberedSetHelper(Register object, // For debug tests. | 520 void MacroAssembler::RememberedSetHelper(Register object, // For debug tests. |
| 551 Register address, Register scratch, | 521 Register address, Register scratch, |
| 552 SaveFPRegsMode fp_mode, | 522 SaveFPRegsMode fp_mode, |
| 553 RememberedSetFinalAction and_then) { | 523 RememberedSetFinalAction and_then) { |
| 554 Label done; | 524 Label done; |
| 555 if (emit_debug_code()) { | 525 if (emit_debug_code()) { |
| 556 Label ok; | 526 Label ok; |
| 557 JumpIfNotInNewSpace(object, scratch, &ok); | 527 JumpIfNotInNewSpace(object, scratch, &ok); |
| 558 stop("Remembered set pointer is in new space"); | 528 stop("Remembered set pointer is in new space"); |
| 559 bind(&ok); | 529 bind(&ok); |
| 560 } | 530 } |
| 561 // Load store buffer top. | 531 // Load store buffer top. |
| 562 ExternalReference store_buffer = | 532 ExternalReference store_buffer = |
| 563 ExternalReference::store_buffer_top(isolate()); | 533 ExternalReference::store_buffer_top(isolate()); |
| 564 mov(ip, Operand(store_buffer)); | 534 mov(ip, Operand(store_buffer)); |
| 565 LoadP(scratch, MemOperand(ip)); | 535 LoadP(scratch, MemOperand(ip)); |
| 566 // Store pointer to buffer and increment buffer top. | 536 // Store pointer to buffer and increment buffer top. |
| 567 StoreP(address, MemOperand(scratch)); | 537 StoreP(address, MemOperand(scratch)); |
| 568 addi(scratch, scratch, Operand(kPointerSize)); | 538 AddP(scratch, Operand(kPointerSize)); |
| 569 // Write back new top of buffer. | 539 // Write back new top of buffer. |
| 570 StoreP(scratch, MemOperand(ip)); | 540 StoreP(scratch, MemOperand(ip)); |
| 571 // Call stub on end of buffer. | 541 // Call stub on end of buffer. |
| 572 // Check for end of buffer. | 542 // Check for end of buffer. |
| 573 mov(r0, Operand(StoreBuffer::kStoreBufferOverflowBit)); | 543 AndP(scratch, Operand(StoreBuffer::kStoreBufferOverflowBit)); |
| 574 and_(r0, scratch, r0, SetRC); | |
| 575 | 544 |
| 576 if (and_then == kFallThroughAtEnd) { | 545 if (and_then == kFallThroughAtEnd) { |
| 577 beq(&done, cr0); | 546 beq(&done, Label::kNear); |
| 578 } else { | 547 } else { |
| 579 DCHECK(and_then == kReturnAtEnd); | 548 DCHECK(and_then == kReturnAtEnd); |
| 580 Ret(eq, cr0); | 549 beq(&done, Label::kNear); |
| 581 } | 550 } |
| 582 mflr(r0); | 551 push(r14); |
| 583 push(r0); | |
| 584 StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode); | 552 StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode); |
| 585 CallStub(&store_buffer_overflow); | 553 CallStub(&store_buffer_overflow); |
| 586 pop(r0); | 554 pop(r14); |
| 587 mtlr(r0); | |
| 588 bind(&done); | 555 bind(&done); |
| 589 if (and_then == kReturnAtEnd) { | 556 if (and_then == kReturnAtEnd) { |
| 590 Ret(); | 557 Ret(); |
| 591 } | 558 } |
| 592 } | 559 } |
| 593 | 560 |
| 594 | |
| 595 void MacroAssembler::PushFixedFrame(Register marker_reg) { | 561 void MacroAssembler::PushFixedFrame(Register marker_reg) { |
| 596 mflr(r0); | 562 CleanseP(r14); |
| 597 if (FLAG_enable_embedded_constant_pool) { | 563 if (marker_reg.is_valid()) { |
| 598 if (marker_reg.is_valid()) { | 564 Push(r14, fp, cp, marker_reg); |
| 599 Push(r0, fp, kConstantPoolRegister, cp, marker_reg); | |
| 600 } else { | |
| 601 Push(r0, fp, kConstantPoolRegister, cp); | |
| 602 } | |
| 603 } else { | 565 } else { |
| 604 if (marker_reg.is_valid()) { | 566 Push(r14, fp, cp); |
| 605 Push(r0, fp, cp, marker_reg); | |
| 606 } else { | |
| 607 Push(r0, fp, cp); | |
| 608 } | |
| 609 } | 567 } |
| 610 } | 568 } |
| 611 | 569 |
| 612 | |
| 613 void MacroAssembler::PopFixedFrame(Register marker_reg) { | 570 void MacroAssembler::PopFixedFrame(Register marker_reg) { |
| 614 if (FLAG_enable_embedded_constant_pool) { | 571 if (marker_reg.is_valid()) { |
| 615 if (marker_reg.is_valid()) { | 572 Pop(r14, fp, cp, marker_reg); |
| 616 Pop(r0, fp, kConstantPoolRegister, cp, marker_reg); | |
| 617 } else { | |
| 618 Pop(r0, fp, kConstantPoolRegister, cp); | |
| 619 } | |
| 620 } else { | 573 } else { |
| 621 if (marker_reg.is_valid()) { | 574 Pop(r14, fp, cp); |
| 622 Pop(r0, fp, cp, marker_reg); | |
| 623 } else { | |
| 624 Pop(r0, fp, cp); | |
| 625 } | |
| 626 } | 575 } |
| 627 mtlr(r0); | |
| 628 } | 576 } |
| 629 | 577 |
| 630 void MacroAssembler::RestoreFrameStateForTailCall() { | 578 void MacroAssembler::RestoreFrameStateForTailCall() { |
| 631 if (FLAG_enable_embedded_constant_pool) { | 579 // if (FLAG_enable_embedded_constant_pool) { |
| 632 LoadP(kConstantPoolRegister, | 580 // LoadP(kConstantPoolRegister, |
| 633 MemOperand(fp, StandardFrameConstants::kConstantPoolOffset)); | 581 // MemOperand(fp, StandardFrameConstants::kConstantPoolOffset)); |
| 634 set_constant_pool_available(false); | 582 // set_constant_pool_available(false); |
| 635 } | 583 // } |
| 636 LoadP(r0, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); | 584 DCHECK(!FLAG_enable_embedded_constant_pool); |
| 585 LoadP(r14, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); |
| 637 LoadP(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 586 LoadP(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 638 mtlr(r0); | |
| 639 } | 587 } |
| 640 | 588 |
| 641 const RegList MacroAssembler::kSafepointSavedRegisters = Register::kAllocatable; | 589 const RegList MacroAssembler::kSafepointSavedRegisters = Register::kAllocatable; |
| 642 const int MacroAssembler::kNumSafepointSavedRegisters = | 590 const int MacroAssembler::kNumSafepointSavedRegisters = |
| 643 Register::kNumAllocatable; | 591 Register::kNumAllocatable; |
| 644 | 592 |
| 645 // Push and pop all registers that can hold pointers. | 593 // Push and pop all registers that can hold pointers. |
| 646 void MacroAssembler::PushSafepointRegisters() { | 594 void MacroAssembler::PushSafepointRegisters() { |
| 647 // Safepoints expect a block of kNumSafepointRegisters values on the | 595 // Safepoints expect a block of kNumSafepointRegisters values on the |
| 648 // stack, so adjust the stack for unsaved registers. | 596 // stack, so adjust the stack for unsaved registers. |
| 649 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; | 597 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; |
| 650 DCHECK(num_unsaved >= 0); | 598 DCHECK(num_unsaved >= 0); |
| 651 if (num_unsaved > 0) { | 599 if (num_unsaved > 0) { |
| 652 subi(sp, sp, Operand(num_unsaved * kPointerSize)); | 600 lay(sp, MemOperand(sp, -(num_unsaved * kPointerSize))); |
| 653 } | 601 } |
| 654 MultiPush(kSafepointSavedRegisters); | 602 MultiPush(kSafepointSavedRegisters); |
| 655 } | 603 } |
| 656 | 604 |
| 657 | |
| 658 void MacroAssembler::PopSafepointRegisters() { | 605 void MacroAssembler::PopSafepointRegisters() { |
| 659 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; | 606 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; |
| 660 MultiPop(kSafepointSavedRegisters); | 607 MultiPop(kSafepointSavedRegisters); |
| 661 if (num_unsaved > 0) { | 608 if (num_unsaved > 0) { |
| 662 addi(sp, sp, Operand(num_unsaved * kPointerSize)); | 609 la(sp, MemOperand(sp, num_unsaved * kPointerSize)); |
| 663 } | 610 } |
| 664 } | 611 } |
| 665 | 612 |
| 666 | |
| 667 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) { | 613 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) { |
| 668 StoreP(src, SafepointRegisterSlot(dst)); | 614 StoreP(src, SafepointRegisterSlot(dst)); |
| 669 } | 615 } |
| 670 | 616 |
| 671 | |
| 672 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { | 617 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { |
| 673 LoadP(dst, SafepointRegisterSlot(src)); | 618 LoadP(dst, SafepointRegisterSlot(src)); |
| 674 } | 619 } |
| 675 | 620 |
| 676 | |
| 677 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { | 621 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { |
| 678 // The registers are pushed starting with the highest encoding, | 622 // The registers are pushed starting with the highest encoding, |
| 679 // which means that lowest encodings are closest to the stack pointer. | 623 // which means that lowest encodings are closest to the stack pointer. |
| 680 RegList regs = kSafepointSavedRegisters; | 624 RegList regs = kSafepointSavedRegisters; |
| 681 int index = 0; | 625 int index = 0; |
| 682 | 626 |
| 683 DCHECK(reg_code >= 0 && reg_code < kNumRegisters); | 627 DCHECK(reg_code >= 0 && reg_code < kNumRegisters); |
| 684 | 628 |
| 685 for (int16_t i = 0; i < reg_code; i++) { | 629 for (int16_t i = 0; i < reg_code; i++) { |
| 686 if ((regs & (1 << i)) != 0) { | 630 if ((regs & (1 << i)) != 0) { |
| 687 index++; | 631 index++; |
| 688 } | 632 } |
| 689 } | 633 } |
| 690 | 634 |
| 691 return index; | 635 return index; |
| 692 } | 636 } |
| 693 | 637 |
| 694 | |
| 695 MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) { | 638 MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) { |
| 696 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); | 639 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); |
| 697 } | 640 } |
| 698 | 641 |
| 699 | |
| 700 MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) { | 642 MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) { |
| 701 // General purpose registers are pushed last on the stack. | 643 // General purpose registers are pushed last on the stack. |
| 702 const RegisterConfiguration* config = | 644 const RegisterConfiguration* config = |
| 703 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT); | 645 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT); |
| 704 int doubles_size = config->num_allocatable_double_registers() * kDoubleSize; | 646 int doubles_size = config->num_allocatable_double_registers() * kDoubleSize; |
| 705 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize; | 647 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize; |
| 706 return MemOperand(sp, doubles_size + register_offset); | 648 return MemOperand(sp, doubles_size + register_offset); |
| 707 } | 649 } |
| 708 | 650 |
| 709 | |
| 710 void MacroAssembler::CanonicalizeNaN(const DoubleRegister dst, | 651 void MacroAssembler::CanonicalizeNaN(const DoubleRegister dst, |
| 711 const DoubleRegister src) { | 652 const DoubleRegister src) { |
| 712 // Turn potential sNaN into qNaN. | 653 // Turn potential sNaN into qNaN |
| 713 fsub(dst, src, kDoubleRegZero); | 654 if (!dst.is(src)) ldr(dst, src); |
| 655 lzdr(kDoubleRegZero); |
| 656 sdbr(dst, kDoubleRegZero); |
| 714 } | 657 } |
| 715 | 658 |
| 716 void MacroAssembler::ConvertIntToDouble(Register src, DoubleRegister dst) { | 659 void MacroAssembler::ConvertIntToDouble(Register src, DoubleRegister dst) { |
| 717 MovIntToDouble(dst, src, r0); | 660 cdfbr(dst, src); |
| 718 fcfid(dst, dst); | |
| 719 } | 661 } |
| 720 | 662 |
| 721 void MacroAssembler::ConvertUnsignedIntToDouble(Register src, | 663 void MacroAssembler::ConvertUnsignedIntToDouble(Register src, |
| 722 DoubleRegister dst) { | 664 DoubleRegister dst) { |
| 723 MovUnsignedIntToDouble(dst, src, r0); | 665 if (CpuFeatures::IsSupported(FLOATING_POINT_EXT)) { |
| 724 fcfid(dst, dst); | 666 cdlfbr(Condition(5), Condition(0), dst, src); |
| 667 } else { |
| 668 // zero-extend src |
| 669 llgfr(src, src); |
| 670 // convert to double |
| 671 cdgbr(dst, src); |
| 672 } |
| 725 } | 673 } |
| 726 | 674 |
| 727 void MacroAssembler::ConvertIntToFloat(Register src, DoubleRegister dst) { | 675 void MacroAssembler::ConvertIntToFloat(Register src, DoubleRegister dst) { |
| 728 MovIntToDouble(dst, src, r0); | 676 cefbr(dst, src); |
| 729 fcfids(dst, dst); | |
| 730 } | 677 } |
| 731 | 678 |
| 732 void MacroAssembler::ConvertUnsignedIntToFloat(Register src, | 679 void MacroAssembler::ConvertUnsignedIntToFloat(Register src, |
| 733 DoubleRegister dst) { | 680 DoubleRegister dst) { |
| 734 MovUnsignedIntToDouble(dst, src, r0); | 681 celfbr(Condition(0), Condition(0), dst, src); |
| 735 fcfids(dst, dst); | 682 } |
| 736 } | 683 |
| 737 | 684 #if V8_TARGET_ARCH_S390X |
| 738 #if V8_TARGET_ARCH_PPC64 | |
| 739 void MacroAssembler::ConvertInt64ToDouble(Register src, | 685 void MacroAssembler::ConvertInt64ToDouble(Register src, |
| 740 DoubleRegister double_dst) { | 686 DoubleRegister double_dst) { |
| 741 MovInt64ToDouble(double_dst, src); | 687 cdgbr(double_dst, src); |
| 742 fcfid(double_dst, double_dst); | 688 } |
| 743 } | |
| 744 | |
| 745 | 689 |
| 746 void MacroAssembler::ConvertUnsignedInt64ToFloat(Register src, | 690 void MacroAssembler::ConvertUnsignedInt64ToFloat(Register src, |
| 747 DoubleRegister double_dst) { | 691 DoubleRegister double_dst) { |
| 748 MovInt64ToDouble(double_dst, src); | 692 celgbr(Condition(0), Condition(0), double_dst, src); |
| 749 fcfidus(double_dst, double_dst); | 693 } |
| 750 } | |
| 751 | |
| 752 | 694 |
| 753 void MacroAssembler::ConvertUnsignedInt64ToDouble(Register src, | 695 void MacroAssembler::ConvertUnsignedInt64ToDouble(Register src, |
| 754 DoubleRegister double_dst) { | 696 DoubleRegister double_dst) { |
| 755 MovInt64ToDouble(double_dst, src); | 697 cdlgbr(Condition(0), Condition(0), double_dst, src); |
| 756 fcfidu(double_dst, double_dst); | 698 } |
| 757 } | |
| 758 | |
| 759 | 699 |
| 760 void MacroAssembler::ConvertInt64ToFloat(Register src, | 700 void MacroAssembler::ConvertInt64ToFloat(Register src, |
| 761 DoubleRegister double_dst) { | 701 DoubleRegister double_dst) { |
| 762 MovInt64ToDouble(double_dst, src); | 702 cegbr(double_dst, src); |
| 763 fcfids(double_dst, double_dst); | 703 } |
| 764 } | 704 #endif |
| 765 #endif | 705 |
| 766 | 706 void MacroAssembler::ConvertFloat32ToInt64(const DoubleRegister double_input, |
| 707 #if !V8_TARGET_ARCH_S390X |
| 708 const Register dst_hi, |
| 709 #endif |
| 710 const Register dst, |
| 711 const DoubleRegister double_dst, |
| 712 FPRoundingMode rounding_mode) { |
| 713 Condition m = Condition(0); |
| 714 switch (rounding_mode) { |
| 715 case kRoundToZero: |
| 716 m = Condition(5); |
| 717 break; |
| 718 case kRoundToNearest: |
| 719 UNIMPLEMENTED(); |
| 720 break; |
| 721 case kRoundToPlusInf: |
| 722 m = Condition(6); |
| 723 break; |
| 724 case kRoundToMinusInf: |
| 725 m = Condition(7); |
| 726 break; |
| 727 default: |
| 728 UNIMPLEMENTED(); |
| 729 break; |
| 730 } |
| 731 cgebr(m, dst, double_input); |
| 732 ldgr(double_dst, dst); |
| 733 #if !V8_TARGET_ARCH_S390X |
| 734 srlg(dst_hi, dst, Operand(32)); |
| 735 #endif |
| 736 } |
| 767 | 737 |
| 768 void MacroAssembler::ConvertDoubleToInt64(const DoubleRegister double_input, | 738 void MacroAssembler::ConvertDoubleToInt64(const DoubleRegister double_input, |
| 769 #if !V8_TARGET_ARCH_PPC64 | 739 #if !V8_TARGET_ARCH_S390X |
| 770 const Register dst_hi, | 740 const Register dst_hi, |
| 771 #endif | 741 #endif |
| 772 const Register dst, | 742 const Register dst, |
| 773 const DoubleRegister double_dst, | 743 const DoubleRegister double_dst, |
| 774 FPRoundingMode rounding_mode) { | 744 FPRoundingMode rounding_mode) { |
| 775 if (rounding_mode == kRoundToZero) { | 745 Condition m = Condition(0); |
| 776 fctidz(double_dst, double_input); | 746 switch (rounding_mode) { |
| 777 } else { | 747 case kRoundToZero: |
| 778 SetRoundingMode(rounding_mode); | 748 m = Condition(5); |
| 779 fctid(double_dst, double_input); | 749 break; |
| 780 ResetRoundingMode(); | 750 case kRoundToNearest: |
| 781 } | 751 UNIMPLEMENTED(); |
| 782 | 752 break; |
| 783 MovDoubleToInt64( | 753 case kRoundToPlusInf: |
| 784 #if !V8_TARGET_ARCH_PPC64 | 754 m = Condition(6); |
| 785 dst_hi, | 755 break; |
| 786 #endif | 756 case kRoundToMinusInf: |
| 787 dst, double_dst); | 757 m = Condition(7); |
| 788 } | 758 break; |
| 789 | 759 default: |
| 790 #if V8_TARGET_ARCH_PPC64 | 760 UNIMPLEMENTED(); |
| 761 break; |
| 762 } |
| 763 cgdbr(m, dst, double_input); |
| 764 ldgr(double_dst, dst); |
| 765 #if !V8_TARGET_ARCH_S390X |
| 766 srlg(dst_hi, dst, Operand(32)); |
| 767 #endif |
| 768 } |
| 769 |
| 770 void MacroAssembler::ConvertFloat32ToInt32(const DoubleRegister double_input, |
| 771 const Register dst, |
| 772 const DoubleRegister double_dst, |
| 773 FPRoundingMode rounding_mode) { |
| 774 Condition m = Condition(0); |
| 775 switch (rounding_mode) { |
| 776 case kRoundToZero: |
| 777 m = Condition(5); |
| 778 break; |
| 779 case kRoundToNearest: |
| 780 UNIMPLEMENTED(); |
| 781 break; |
| 782 case kRoundToPlusInf: |
| 783 m = Condition(6); |
| 784 break; |
| 785 case kRoundToMinusInf: |
| 786 m = Condition(7); |
| 787 break; |
| 788 default: |
| 789 UNIMPLEMENTED(); |
| 790 break; |
| 791 } |
| 792 cfebr(m, dst, double_input); |
| 793 ldgr(double_dst, dst); |
| 794 } |
| 795 |
| 796 void MacroAssembler::ConvertFloat32ToUnsignedInt32( |
| 797 const DoubleRegister double_input, const Register dst, |
| 798 const DoubleRegister double_dst, FPRoundingMode rounding_mode) { |
| 799 Condition m = Condition(0); |
| 800 switch (rounding_mode) { |
| 801 case kRoundToZero: |
| 802 m = Condition(5); |
| 803 break; |
| 804 case kRoundToNearest: |
| 805 UNIMPLEMENTED(); |
| 806 break; |
| 807 case kRoundToPlusInf: |
| 808 m = Condition(6); |
| 809 break; |
| 810 case kRoundToMinusInf: |
| 811 m = Condition(7); |
| 812 break; |
| 813 default: |
| 814 UNIMPLEMENTED(); |
| 815 break; |
| 816 } |
| 817 clfebr(m, Condition(0), dst, double_input); |
| 818 ldgr(double_dst, dst); |
| 819 } |
| 820 |
| 821 #if V8_TARGET_ARCH_S390X |
| 822 void MacroAssembler::ConvertFloat32ToUnsignedInt64( |
| 823 const DoubleRegister double_input, const Register dst, |
| 824 const DoubleRegister double_dst, FPRoundingMode rounding_mode) { |
| 825 Condition m = Condition(0); |
| 826 switch (rounding_mode) { |
| 827 case kRoundToZero: |
| 828 m = Condition(5); |
| 829 break; |
| 830 case kRoundToNearest: |
| 831 UNIMPLEMENTED(); |
| 832 break; |
| 833 case kRoundToPlusInf: |
| 834 m = Condition(6); |
| 835 break; |
| 836 case kRoundToMinusInf: |
| 837 m = Condition(7); |
| 838 break; |
| 839 default: |
| 840 UNIMPLEMENTED(); |
| 841 break; |
| 842 } |
| 843 clgebr(m, Condition(0), dst, double_input); |
| 844 ldgr(double_dst, dst); |
| 845 } |
| 846 |
| 791 void MacroAssembler::ConvertDoubleToUnsignedInt64( | 847 void MacroAssembler::ConvertDoubleToUnsignedInt64( |
| 792 const DoubleRegister double_input, const Register dst, | 848 const DoubleRegister double_input, const Register dst, |
| 793 const DoubleRegister double_dst, FPRoundingMode rounding_mode) { | 849 const DoubleRegister double_dst, FPRoundingMode rounding_mode) { |
| 794 if (rounding_mode == kRoundToZero) { | 850 Condition m = Condition(0); |
| 795 fctiduz(double_dst, double_input); | 851 switch (rounding_mode) { |
| 796 } else { | 852 case kRoundToZero: |
| 797 SetRoundingMode(rounding_mode); | 853 m = Condition(5); |
| 798 fctidu(double_dst, double_input); | 854 break; |
| 799 ResetRoundingMode(); | 855 case kRoundToNearest: |
| 800 } | 856 UNIMPLEMENTED(); |
| 801 | 857 break; |
| 802 MovDoubleToInt64(dst, double_dst); | 858 case kRoundToPlusInf: |
| 803 } | 859 m = Condition(6); |
| 804 #endif | 860 break; |
| 805 | 861 case kRoundToMinusInf: |
| 806 | 862 m = Condition(7); |
| 807 void MacroAssembler::LoadConstantPoolPointerRegisterFromCodeTargetAddress( | 863 break; |
| 808 Register code_target_address) { | 864 default: |
| 809 lwz(kConstantPoolRegister, | 865 UNIMPLEMENTED(); |
| 810 MemOperand(code_target_address, | 866 break; |
| 811 Code::kConstantPoolOffset - Code::kHeaderSize)); | 867 } |
| 812 add(kConstantPoolRegister, kConstantPoolRegister, code_target_address); | 868 clgdbr(m, Condition(0), dst, double_input); |
| 813 } | 869 ldgr(double_dst, dst); |
| 814 | 870 } |
| 815 | 871 #endif |
| 816 void MacroAssembler::LoadConstantPoolPointerRegister(Register base, | 872 |
| 817 int code_start_delta) { | 873 void MacroAssembler::MovDoubleToInt64(Register dst, DoubleRegister src) { |
| 818 add_label_offset(kConstantPoolRegister, base, ConstantPoolPosition(), | 874 lgdr(dst, src); |
| 819 code_start_delta); | 875 } |
| 820 } | 876 |
| 821 | 877 void MacroAssembler::MovInt64ToDouble(DoubleRegister dst, Register src) { |
| 822 | 878 ldgr(dst, src); |
| 823 void MacroAssembler::LoadConstantPoolPointerRegister() { | 879 } |
| 824 mov_label_addr(kConstantPoolRegister, ConstantPoolPosition()); | |
| 825 } | |
| 826 | |
| 827 | 880 |
| 828 void MacroAssembler::StubPrologue(Register base, int prologue_offset) { | 881 void MacroAssembler::StubPrologue(Register base, int prologue_offset) { |
| 829 LoadSmiLiteral(r11, Smi::FromInt(StackFrame::STUB)); | 882 PushFixedFrame(); |
| 830 PushFixedFrame(r11); | 883 Push(Smi::FromInt(StackFrame::STUB)); |
| 831 // Adjust FP to point to saved FP. | 884 // Adjust FP to point to saved FP. |
| 832 addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); | 885 la(fp, MemOperand(sp, StandardFrameConstants::kFixedFrameSizeFromFp)); |
| 833 if (FLAG_enable_embedded_constant_pool) { | 886 } |
| 834 if (!base.is(no_reg)) { | |
| 835 // base contains prologue address | |
| 836 LoadConstantPoolPointerRegister(base, -prologue_offset); | |
| 837 } else { | |
| 838 LoadConstantPoolPointerRegister(); | |
| 839 } | |
| 840 set_constant_pool_available(true); | |
| 841 } | |
| 842 } | |
| 843 | |
| 844 | 887 |
| 845 void MacroAssembler::Prologue(bool code_pre_aging, Register base, | 888 void MacroAssembler::Prologue(bool code_pre_aging, Register base, |
| 846 int prologue_offset) { | 889 int prologue_offset) { |
| 847 DCHECK(!base.is(no_reg)); | 890 DCHECK(!base.is(no_reg)); |
| 848 { | 891 { |
| 849 PredictableCodeSizeScope predictible_code_size_scope( | 892 PredictableCodeSizeScope predictible_code_size_scope( |
| 850 this, kNoCodeAgeSequenceLength); | 893 this, kNoCodeAgeSequenceLength); |
| 851 Assembler::BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 852 // The following instructions must remain together and unmodified | 894 // The following instructions must remain together and unmodified |
| 853 // for code aging to work properly. | 895 // for code aging to work properly. |
| 854 if (code_pre_aging) { | 896 if (code_pre_aging) { |
| 855 // Pre-age the code. | 897 // Pre-age the code. |
| 856 // This matches the code found in PatchPlatformCodeAge() | 898 // This matches the code found in PatchPlatformCodeAge() |
| 857 Code* stub = Code::GetPreAgedCodeAgeStub(isolate()); | 899 Code* stub = Code::GetPreAgedCodeAgeStub(isolate()); |
| 858 intptr_t target = reinterpret_cast<intptr_t>(stub->instruction_start()); | 900 intptr_t target = reinterpret_cast<intptr_t>(stub->instruction_start()); |
| 859 // Don't use Call -- we need to preserve ip and lr | 901 nop(); |
| 860 nop(); // marker to detect sequence (see IsOld) | 902 CleanseP(r14); |
| 861 mov(r3, Operand(target)); | 903 Push(r14); |
| 862 Jump(r3); | 904 mov(r2, Operand(target)); |
| 863 for (int i = 0; i < kCodeAgingSequenceNops; i++) { | 905 Call(r2); |
| 864 nop(); | 906 for (int i = 0; i < kNoCodeAgeSequenceLength - kCodeAgingSequenceLength; |
| 907 i += 2) { |
| 908 // TODO(joransiu): Create nop function to pad |
| 909 // (kNoCodeAgeSequenceLength - kCodeAgingSequenceLength) bytes. |
| 910 nop(); // 2-byte nops(). |
| 865 } | 911 } |
| 866 } else { | 912 } else { |
| 867 // This matches the code found in GetNoCodeAgeSequence() | 913 // This matches the code found in GetNoCodeAgeSequence() |
| 868 PushFixedFrame(r4); | 914 PushFixedFrame(r3); |
| 869 // Adjust fp to point to saved fp. | 915 // Adjust fp to point to saved fp. |
| 870 addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); | 916 la(fp, MemOperand(sp, StandardFrameConstants::kFixedFrameSizeFromFp)); |
| 871 for (int i = 0; i < kNoCodeAgeSequenceNops; i++) { | |
| 872 nop(); | |
| 873 } | |
| 874 } | 917 } |
| 875 } | 918 } |
| 876 if (FLAG_enable_embedded_constant_pool) { | |
| 877 // base contains prologue address | |
| 878 LoadConstantPoolPointerRegister(base, -prologue_offset); | |
| 879 set_constant_pool_available(true); | |
| 880 } | |
| 881 } | 919 } |
| 882 | 920 |
| 883 | |
| 884 void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) { | 921 void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) { |
| 885 LoadP(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 922 LoadP(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 886 LoadP(vector, FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset)); | 923 LoadP(vector, FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset)); |
| 887 LoadP(vector, | 924 LoadP(vector, |
| 888 FieldMemOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset)); | 925 FieldMemOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset)); |
| 889 } | 926 } |
| 890 | 927 |
| 891 | |
| 892 void MacroAssembler::EnterFrame(StackFrame::Type type, | 928 void MacroAssembler::EnterFrame(StackFrame::Type type, |
| 893 bool load_constant_pool_pointer_reg) { | 929 bool load_constant_pool_pointer_reg) { |
| 894 if (FLAG_enable_embedded_constant_pool && load_constant_pool_pointer_reg) { | 930 // We create a stack frame with: |
| 895 PushFixedFrame(); | 931 // Return Addr <-- old sp |
| 896 // This path should not rely on ip containing code entry. | 932 // Old FP <-- new fp |
| 897 LoadConstantPoolPointerRegister(); | 933 // CP |
| 898 LoadSmiLiteral(ip, Smi::FromInt(type)); | 934 // type |
| 899 push(ip); | 935 // CodeObject <-- new sp |
| 900 } else { | 936 |
| 901 LoadSmiLiteral(ip, Smi::FromInt(type)); | 937 LoadSmiLiteral(ip, Smi::FromInt(type)); |
| 902 PushFixedFrame(ip); | 938 PushFixedFrame(ip); |
| 903 } | |
| 904 // Adjust FP to point to saved FP. | |
| 905 addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); | |
| 906 | 939 |
| 907 mov(r0, Operand(CodeObject())); | 940 mov(r0, Operand(CodeObject())); |
| 908 push(r0); | 941 push(r0); |
| 942 // Adjust FP to point to saved FP |
| 943 la(fp, MemOperand( |
| 944 sp, StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize)); |
| 909 } | 945 } |
| 910 | 946 |
| 911 | |
| 912 int MacroAssembler::LeaveFrame(StackFrame::Type type, int stack_adjustment) { | 947 int MacroAssembler::LeaveFrame(StackFrame::Type type, int stack_adjustment) { |
| 913 ConstantPoolUnavailableScope constant_pool_unavailable(this); | |
| 914 // r3: preserved | |
| 915 // r4: preserved | |
| 916 // r5: preserved | |
| 917 | |
| 918 // Drop the execution stack down to the frame pointer and restore | 948 // Drop the execution stack down to the frame pointer and restore |
| 919 // the caller's state. | 949 // the caller frame pointer, return address and constant pool pointer. |
| 920 int frame_ends; | 950 LoadP(r14, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); |
| 921 LoadP(r0, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); | 951 lay(r1, MemOperand( |
| 922 LoadP(ip, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 952 fp, StandardFrameConstants::kCallerSPOffset + stack_adjustment)); |
| 923 if (FLAG_enable_embedded_constant_pool) { | 953 LoadP(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 924 const int exitOffset = ExitFrameConstants::kConstantPoolOffset; | 954 LoadRR(sp, r1); |
| 925 const int standardOffset = StandardFrameConstants::kConstantPoolOffset; | 955 int frame_ends = pc_offset(); |
| 926 const int offset = | |
| 927 ((type == StackFrame::EXIT) ? exitOffset : standardOffset); | |
| 928 LoadP(kConstantPoolRegister, MemOperand(fp, offset)); | |
| 929 } | |
| 930 mtlr(r0); | |
| 931 frame_ends = pc_offset(); | |
| 932 Add(sp, fp, StandardFrameConstants::kCallerSPOffset + stack_adjustment, r0); | |
| 933 mr(fp, ip); | |
| 934 return frame_ends; | 956 return frame_ends; |
| 935 } | 957 } |
| 936 | 958 |
| 937 | |
| 938 // ExitFrame layout (probably wrongish.. needs updating) | 959 // ExitFrame layout (probably wrongish.. needs updating) |
| 939 // | 960 // |
| 940 // SP -> previousSP | 961 // SP -> previousSP |
| 941 // LK reserved | 962 // LK reserved |
| 942 // code | 963 // code |
| 943 // sp_on_exit (for debug?) | 964 // sp_on_exit (for debug?) |
| 944 // oldSP->prev SP | 965 // oldSP->prev SP |
| 945 // LK | 966 // LK |
| 946 // <parameters on stack> | 967 // <parameters on stack> |
| 947 | 968 |
| 948 // Prior to calling EnterExitFrame, we've got a bunch of parameters | 969 // Prior to calling EnterExitFrame, we've got a bunch of parameters |
| 949 // on the stack that we need to wrap a real frame around.. so first | 970 // on the stack that we need to wrap a real frame around.. so first |
| 950 // we reserve a slot for LK and push the previous SP which is captured | 971 // we reserve a slot for LK and push the previous SP which is captured |
| 951 // in the fp register (r31) | 972 // in the fp register (r11) |
| 952 // Then - we buy a new frame | 973 // Then - we buy a new frame |
| 953 | 974 |
| 975 // r14 |
| 976 // oldFP <- newFP |
| 977 // SP |
| 978 // Code |
| 979 // Floats |
| 980 // gaps |
| 981 // Args |
| 982 // ABIRes <- newSP |
| 954 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) { | 983 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) { |
| 955 // Set up the frame structure on the stack. | 984 // Set up the frame structure on the stack. |
| 956 DCHECK_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); | 985 DCHECK_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); |
| 957 DCHECK_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); | 986 DCHECK_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); |
| 958 DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); | 987 DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); |
| 959 DCHECK(stack_space > 0); | 988 DCHECK(stack_space > 0); |
| 960 | 989 |
| 961 // This is an opportunity to build a frame to wrap | 990 // This is an opportunity to build a frame to wrap |
| 962 // all of the pushes that have happened inside of V8 | 991 // all of the pushes that have happened inside of V8 |
| 963 // since we were called from C code | 992 // since we were called from C code |
| 964 | 993 CleanseP(r14); |
| 965 // replicate ARM frame - TODO make this more closely follow PPC ABI | 994 Push(r14, fp); |
| 966 mflr(r0); | 995 LoadRR(fp, sp); |
| 967 Push(r0, fp); | |
| 968 mr(fp, sp); | |
| 969 // Reserve room for saved entry sp and code object. | 996 // Reserve room for saved entry sp and code object. |
| 970 subi(sp, sp, Operand(ExitFrameConstants::kFrameSize)); | 997 lay(sp, MemOperand(sp, -ExitFrameConstants::kFrameSize)); |
| 971 | 998 |
| 972 if (emit_debug_code()) { | 999 if (emit_debug_code()) { |
| 973 li(r8, Operand::Zero()); | 1000 StoreP(MemOperand(fp, ExitFrameConstants::kSPOffset), Operand::Zero(), r1); |
| 974 StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset)); | |
| 975 } | 1001 } |
| 976 if (FLAG_enable_embedded_constant_pool) { | 1002 mov(r1, Operand(CodeObject())); |
| 977 StoreP(kConstantPoolRegister, | 1003 StoreP(r1, MemOperand(fp, ExitFrameConstants::kCodeOffset)); |
| 978 MemOperand(fp, ExitFrameConstants::kConstantPoolOffset)); | |
| 979 } | |
| 980 mov(r8, Operand(CodeObject())); | |
| 981 StoreP(r8, MemOperand(fp, ExitFrameConstants::kCodeOffset)); | |
| 982 | 1004 |
| 983 // Save the frame pointer and the context in top. | 1005 // Save the frame pointer and the context in top. |
| 984 mov(r8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); | 1006 mov(r1, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); |
| 985 StoreP(fp, MemOperand(r8)); | 1007 StoreP(fp, MemOperand(r1)); |
| 986 mov(r8, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); | 1008 mov(r1, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); |
| 987 StoreP(cp, MemOperand(r8)); | 1009 StoreP(cp, MemOperand(r1)); |
| 988 | 1010 |
| 989 // Optionally save all volatile double registers. | 1011 // Optionally save all volatile double registers. |
| 990 if (save_doubles) { | 1012 if (save_doubles) { |
| 991 MultiPushDoubles(kCallerSavedDoubles); | 1013 MultiPushDoubles(kCallerSavedDoubles); |
| 992 // Note that d0 will be accessible at | 1014 // Note that d0 will be accessible at |
| 993 // fp - ExitFrameConstants::kFrameSize - | 1015 // fp - ExitFrameConstants::kFrameSize - |
| 994 // kNumCallerSavedDoubles * kDoubleSize, | 1016 // kNumCallerSavedDoubles * kDoubleSize, |
| 995 // since the sp slot and code slot were pushed after the fp. | 1017 // since the sp slot and code slot were pushed after the fp. |
| 996 } | 1018 } |
| 997 | 1019 |
| 998 addi(sp, sp, Operand(-stack_space * kPointerSize)); | 1020 lay(sp, MemOperand(sp, -stack_space * kPointerSize)); |
| 999 | 1021 |
| 1000 // Allocate and align the frame preparing for calling the runtime | 1022 // Allocate and align the frame preparing for calling the runtime |
| 1001 // function. | 1023 // function. |
| 1002 const int frame_alignment = ActivationFrameAlignment(); | 1024 const int frame_alignment = MacroAssembler::ActivationFrameAlignment(); |
| 1003 if (frame_alignment > kPointerSize) { | 1025 if (frame_alignment > 0) { |
| 1004 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); | 1026 DCHECK(frame_alignment == 8); |
| 1005 ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment))); | 1027 ClearRightImm(sp, sp, Operand(3)); // equivalent to &= -8 |
| 1006 } | 1028 } |
| 1007 li(r0, Operand::Zero()); | |
| 1008 StorePU(r0, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize)); | |
| 1009 | 1029 |
| 1030 StoreP(MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize), |
| 1031 Operand::Zero(), r0); |
| 1032 lay(sp, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize)); |
| 1010 // Set the exit frame sp value to point just before the return address | 1033 // Set the exit frame sp value to point just before the return address |
| 1011 // location. | 1034 // location. |
| 1012 addi(r8, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize)); | 1035 lay(r1, MemOperand(sp, kStackFrameSPSlot * kPointerSize)); |
| 1013 StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset)); | 1036 StoreP(r1, MemOperand(fp, ExitFrameConstants::kSPOffset)); |
| 1014 } | 1037 } |
| 1015 | 1038 |
| 1016 | |
| 1017 void MacroAssembler::InitializeNewString(Register string, Register length, | 1039 void MacroAssembler::InitializeNewString(Register string, Register length, |
| 1018 Heap::RootListIndex map_index, | 1040 Heap::RootListIndex map_index, |
| 1019 Register scratch1, Register scratch2) { | 1041 Register scratch1, Register scratch2) { |
| 1020 SmiTag(scratch1, length); | 1042 SmiTag(scratch1, length); |
| 1021 LoadRoot(scratch2, map_index); | 1043 LoadRoot(scratch2, map_index); |
| 1022 StoreP(scratch1, FieldMemOperand(string, String::kLengthOffset), r0); | 1044 StoreP(scratch1, FieldMemOperand(string, String::kLengthOffset)); |
| 1023 li(scratch1, Operand(String::kEmptyHashField)); | 1045 StoreP(FieldMemOperand(string, String::kHashFieldSlot), |
| 1024 StoreP(scratch2, FieldMemOperand(string, HeapObject::kMapOffset), r0); | 1046 Operand(String::kEmptyHashField), scratch1); |
| 1025 StoreP(scratch1, FieldMemOperand(string, String::kHashFieldSlot), r0); | 1047 StoreP(scratch2, FieldMemOperand(string, HeapObject::kMapOffset)); |
| 1026 } | 1048 } |
| 1027 | 1049 |
| 1028 | |
| 1029 int MacroAssembler::ActivationFrameAlignment() { | 1050 int MacroAssembler::ActivationFrameAlignment() { |
| 1030 #if !defined(USE_SIMULATOR) | 1051 #if !defined(USE_SIMULATOR) |
| 1031 // Running on the real platform. Use the alignment as mandated by the local | 1052 // Running on the real platform. Use the alignment as mandated by the local |
| 1032 // environment. | 1053 // environment. |
| 1033 // Note: This will break if we ever start generating snapshots on one PPC | 1054 // Note: This will break if we ever start generating snapshots on one S390 |
| 1034 // platform for another PPC platform with a different alignment. | 1055 // platform for another S390 platform with a different alignment. |
| 1035 return base::OS::ActivationFrameAlignment(); | 1056 return base::OS::ActivationFrameAlignment(); |
| 1036 #else // Simulated | 1057 #else // Simulated |
| 1037 // If we are using the simulator then we should always align to the expected | 1058 // If we are using the simulator then we should always align to the expected |
| 1038 // alignment. As the simulator is used to generate snapshots we do not know | 1059 // alignment. As the simulator is used to generate snapshots we do not know |
| 1039 // if the target platform will need alignment, so this is controlled from a | 1060 // if the target platform will need alignment, so this is controlled from a |
| 1040 // flag. | 1061 // flag. |
| 1041 return FLAG_sim_stack_alignment; | 1062 return FLAG_sim_stack_alignment; |
| 1042 #endif | 1063 #endif |
| 1043 } | 1064 } |
| 1044 | 1065 |
| 1045 | |
| 1046 void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count, | 1066 void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count, |
| 1047 bool restore_context, | 1067 bool restore_context, |
| 1048 bool argument_count_is_length) { | 1068 bool argument_count_is_length) { |
| 1049 ConstantPoolUnavailableScope constant_pool_unavailable(this); | |
| 1050 // Optionally restore all double registers. | 1069 // Optionally restore all double registers. |
| 1051 if (save_doubles) { | 1070 if (save_doubles) { |
| 1052 // Calculate the stack location of the saved doubles and restore them. | 1071 // Calculate the stack location of the saved doubles and restore them. |
| 1053 const int kNumRegs = kNumCallerSavedDoubles; | 1072 const int kNumRegs = kNumCallerSavedDoubles; |
| 1054 const int offset = | 1073 lay(r5, MemOperand(fp, -(ExitFrameConstants::kFrameSize + |
| 1055 (ExitFrameConstants::kFrameSize + kNumRegs * kDoubleSize); | 1074 kNumRegs * kDoubleSize))); |
| 1056 addi(r6, fp, Operand(-offset)); | 1075 MultiPopDoubles(kCallerSavedDoubles, r5); |
| 1057 MultiPopDoubles(kCallerSavedDoubles, r6); | |
| 1058 } | 1076 } |
| 1059 | 1077 |
| 1060 // Clear top frame. | 1078 // Clear top frame. |
| 1061 li(r6, Operand::Zero()); | |
| 1062 mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); | 1079 mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); |
| 1063 StoreP(r6, MemOperand(ip)); | 1080 StoreP(MemOperand(ip), Operand(0, kRelocInfo_NONEPTR), r0); |
| 1064 | 1081 |
| 1065 // Restore current context from top and clear it in debug mode. | 1082 // Restore current context from top and clear it in debug mode. |
| 1066 if (restore_context) { | 1083 if (restore_context) { |
| 1067 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); | 1084 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); |
| 1068 LoadP(cp, MemOperand(ip)); | 1085 LoadP(cp, MemOperand(ip)); |
| 1069 } | 1086 } |
| 1070 #ifdef DEBUG | 1087 #ifdef DEBUG |
| 1071 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); | 1088 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); |
| 1072 StoreP(r6, MemOperand(ip)); | 1089 StoreP(MemOperand(ip), Operand(0, kRelocInfo_NONEPTR), r0); |
| 1073 #endif | 1090 #endif |
| 1074 | 1091 |
| 1075 // Tear down the exit frame, pop the arguments, and return. | 1092 // Tear down the exit frame, pop the arguments, and return. |
| 1076 LeaveFrame(StackFrame::EXIT); | 1093 LeaveFrame(StackFrame::EXIT); |
| 1077 | 1094 |
| 1078 if (argument_count.is_valid()) { | 1095 if (argument_count.is_valid()) { |
| 1079 if (!argument_count_is_length) { | 1096 if (!argument_count_is_length) { |
| 1080 ShiftLeftImm(argument_count, argument_count, Operand(kPointerSizeLog2)); | 1097 ShiftLeftP(argument_count, argument_count, Operand(kPointerSizeLog2)); |
| 1081 } | 1098 } |
| 1082 add(sp, sp, argument_count); | 1099 la(sp, MemOperand(sp, argument_count)); |
| 1083 } | 1100 } |
| 1084 } | 1101 } |
| 1085 | 1102 |
| 1086 | |
| 1087 void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) { | 1103 void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) { |
| 1088 Move(dst, d1); | 1104 Move(dst, d0); |
| 1089 } | 1105 } |
| 1090 | 1106 |
| 1091 | |
| 1092 void MacroAssembler::MovFromFloatParameter(const DoubleRegister dst) { | 1107 void MacroAssembler::MovFromFloatParameter(const DoubleRegister dst) { |
| 1093 Move(dst, d1); | 1108 Move(dst, d0); |
| 1094 } | 1109 } |
| 1095 | 1110 |
| 1096 | |
| 1097 void MacroAssembler::InvokePrologue(const ParameterCount& expected, | 1111 void MacroAssembler::InvokePrologue(const ParameterCount& expected, |
| 1098 const ParameterCount& actual, Label* done, | 1112 const ParameterCount& actual, Label* done, |
| 1099 bool* definitely_mismatches, | 1113 bool* definitely_mismatches, |
| 1100 InvokeFlag flag, | 1114 InvokeFlag flag, |
| 1101 const CallWrapper& call_wrapper) { | 1115 const CallWrapper& call_wrapper) { |
| 1102 bool definitely_matches = false; | 1116 bool definitely_matches = false; |
| 1103 *definitely_mismatches = false; | 1117 *definitely_mismatches = false; |
| 1104 Label regular_invoke; | 1118 Label regular_invoke; |
| 1105 | 1119 |
| 1106 // Check whether the expected and actual arguments count match. If not, | 1120 // Check whether the expected and actual arguments count match. If not, |
| 1107 // setup registers according to contract with ArgumentsAdaptorTrampoline: | 1121 // setup registers according to contract with ArgumentsAdaptorTrampoline: |
| 1108 // r3: actual arguments count | 1122 // r2: actual arguments count |
| 1109 // r4: function (passed through to callee) | 1123 // r3: function (passed through to callee) |
| 1110 // r5: expected arguments count | 1124 // r4: expected arguments count |
| 1111 | 1125 |
| 1112 // The code below is made a lot easier because the calling code already sets | 1126 // The code below is made a lot easier because the calling code already sets |
| 1113 // up actual and expected registers according to the contract if values are | 1127 // up actual and expected registers according to the contract if values are |
| 1114 // passed in registers. | 1128 // passed in registers. |
| 1115 | 1129 |
| 1116 // ARM has some sanity checks as per below, considering add them for PPC | 1130 // ARM has some sanity checks as per below, considering add them for S390 |
| 1117 // DCHECK(actual.is_immediate() || actual.reg().is(r3)); | 1131 // DCHECK(actual.is_immediate() || actual.reg().is(r2)); |
| 1118 // DCHECK(expected.is_immediate() || expected.reg().is(r5)); | 1132 // DCHECK(expected.is_immediate() || expected.reg().is(r4)); |
| 1119 | 1133 |
| 1120 if (expected.is_immediate()) { | 1134 if (expected.is_immediate()) { |
| 1121 DCHECK(actual.is_immediate()); | 1135 DCHECK(actual.is_immediate()); |
| 1122 mov(r3, Operand(actual.immediate())); | 1136 mov(r2, Operand(actual.immediate())); |
| 1123 if (expected.immediate() == actual.immediate()) { | 1137 if (expected.immediate() == actual.immediate()) { |
| 1124 definitely_matches = true; | 1138 definitely_matches = true; |
| 1125 } else { | 1139 } else { |
| 1126 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel; | 1140 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel; |
| 1127 if (expected.immediate() == sentinel) { | 1141 if (expected.immediate() == sentinel) { |
| 1128 // Don't worry about adapting arguments for builtins that | 1142 // Don't worry about adapting arguments for builtins that |
| 1129 // don't want that done. Skip adaption code by making it look | 1143 // don't want that done. Skip adaption code by making it look |
| 1130 // like we have a match between expected and actual number of | 1144 // like we have a match between expected and actual number of |
| 1131 // arguments. | 1145 // arguments. |
| 1132 definitely_matches = true; | 1146 definitely_matches = true; |
| 1133 } else { | 1147 } else { |
| 1134 *definitely_mismatches = true; | 1148 *definitely_mismatches = true; |
| 1135 mov(r5, Operand(expected.immediate())); | 1149 mov(r4, Operand(expected.immediate())); |
| 1136 } | 1150 } |
| 1137 } | 1151 } |
| 1138 } else { | 1152 } else { |
| 1139 if (actual.is_immediate()) { | 1153 if (actual.is_immediate()) { |
| 1140 mov(r3, Operand(actual.immediate())); | 1154 mov(r2, Operand(actual.immediate())); |
| 1141 cmpi(expected.reg(), Operand(actual.immediate())); | 1155 CmpPH(expected.reg(), Operand(actual.immediate())); |
| 1142 beq(®ular_invoke); | 1156 beq(®ular_invoke); |
| 1143 } else { | 1157 } else { |
| 1144 cmp(expected.reg(), actual.reg()); | 1158 CmpP(expected.reg(), actual.reg()); |
| 1145 beq(®ular_invoke); | 1159 beq(®ular_invoke); |
| 1146 } | 1160 } |
| 1147 } | 1161 } |
| 1148 | 1162 |
| 1149 if (!definitely_matches) { | 1163 if (!definitely_matches) { |
| 1150 Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline(); | 1164 Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline(); |
| 1151 if (flag == CALL_FUNCTION) { | 1165 if (flag == CALL_FUNCTION) { |
| 1152 call_wrapper.BeforeCall(CallSize(adaptor)); | 1166 call_wrapper.BeforeCall(CallSize(adaptor)); |
| 1153 Call(adaptor); | 1167 Call(adaptor); |
| 1154 call_wrapper.AfterCall(); | 1168 call_wrapper.AfterCall(); |
| 1155 if (!*definitely_mismatches) { | 1169 if (!*definitely_mismatches) { |
| 1156 b(done); | 1170 b(done); |
| 1157 } | 1171 } |
| 1158 } else { | 1172 } else { |
| 1159 Jump(adaptor, RelocInfo::CODE_TARGET); | 1173 Jump(adaptor, RelocInfo::CODE_TARGET); |
| 1160 } | 1174 } |
| 1161 bind(®ular_invoke); | 1175 bind(®ular_invoke); |
| 1162 } | 1176 } |
| 1163 } | 1177 } |
| 1164 | 1178 |
| 1165 | |
| 1166 void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target, | 1179 void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target, |
| 1167 const ParameterCount& expected, | 1180 const ParameterCount& expected, |
| 1168 const ParameterCount& actual) { | 1181 const ParameterCount& actual) { |
| 1169 Label skip_flooding; | 1182 Label skip_flooding; |
| 1170 ExternalReference step_in_enabled = | 1183 ExternalReference step_in_enabled = |
| 1171 ExternalReference::debug_step_in_enabled_address(isolate()); | 1184 ExternalReference::debug_step_in_enabled_address(isolate()); |
| 1172 mov(r7, Operand(step_in_enabled)); | 1185 mov(r6, Operand(step_in_enabled)); |
| 1173 lbz(r7, MemOperand(r7)); | 1186 LoadlB(r6, MemOperand(r6)); |
| 1174 cmpi(r7, Operand::Zero()); | 1187 CmpP(r6, Operand::Zero()); |
| 1175 beq(&skip_flooding); | 1188 beq(&skip_flooding); |
| 1176 { | 1189 { |
| 1177 FrameScope frame(this, | 1190 FrameScope frame(this, |
| 1178 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); | 1191 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); |
| 1179 if (expected.is_reg()) { | 1192 if (expected.is_reg()) { |
| 1180 SmiTag(expected.reg()); | 1193 SmiTag(expected.reg()); |
| 1181 Push(expected.reg()); | 1194 Push(expected.reg()); |
| 1182 } | 1195 } |
| 1183 if (actual.is_reg()) { | 1196 if (actual.is_reg()) { |
| 1184 SmiTag(actual.reg()); | 1197 SmiTag(actual.reg()); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1198 SmiUntag(actual.reg()); | 1211 SmiUntag(actual.reg()); |
| 1199 } | 1212 } |
| 1200 if (expected.is_reg()) { | 1213 if (expected.is_reg()) { |
| 1201 Pop(expected.reg()); | 1214 Pop(expected.reg()); |
| 1202 SmiUntag(expected.reg()); | 1215 SmiUntag(expected.reg()); |
| 1203 } | 1216 } |
| 1204 } | 1217 } |
| 1205 bind(&skip_flooding); | 1218 bind(&skip_flooding); |
| 1206 } | 1219 } |
| 1207 | 1220 |
| 1208 | |
| 1209 void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, | 1221 void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, |
| 1210 const ParameterCount& expected, | 1222 const ParameterCount& expected, |
| 1211 const ParameterCount& actual, | 1223 const ParameterCount& actual, |
| 1212 InvokeFlag flag, | 1224 InvokeFlag flag, |
| 1213 const CallWrapper& call_wrapper) { | 1225 const CallWrapper& call_wrapper) { |
| 1214 // You can't call a function without a valid frame. | 1226 // You can't call a function without a valid frame. |
| 1215 DCHECK(flag == JUMP_FUNCTION || has_frame()); | 1227 DCHECK(flag == JUMP_FUNCTION || has_frame()); |
| 1216 DCHECK(function.is(r4)); | 1228 |
| 1217 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(r6)); | 1229 DCHECK(function.is(r3)); |
| 1230 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(r5)); |
| 1218 | 1231 |
| 1219 if (call_wrapper.NeedsDebugStepCheck()) { | 1232 if (call_wrapper.NeedsDebugStepCheck()) { |
| 1220 FloodFunctionIfStepping(function, new_target, expected, actual); | 1233 FloodFunctionIfStepping(function, new_target, expected, actual); |
| 1221 } | 1234 } |
| 1222 | 1235 |
| 1223 // Clear the new.target register if not given. | 1236 // Clear the new.target register if not given. |
| 1224 if (!new_target.is_valid()) { | 1237 if (!new_target.is_valid()) { |
| 1225 LoadRoot(r6, Heap::kUndefinedValueRootIndex); | 1238 LoadRoot(r5, Heap::kUndefinedValueRootIndex); |
| 1226 } | 1239 } |
| 1227 | 1240 |
| 1228 Label done; | 1241 Label done; |
| 1229 bool definitely_mismatches = false; | 1242 bool definitely_mismatches = false; |
| 1230 InvokePrologue(expected, actual, &done, &definitely_mismatches, flag, | 1243 InvokePrologue(expected, actual, &done, &definitely_mismatches, flag, |
| 1231 call_wrapper); | 1244 call_wrapper); |
| 1232 if (!definitely_mismatches) { | 1245 if (!definitely_mismatches) { |
| 1233 // We call indirectly through the code field in the function to | 1246 // We call indirectly through the code field in the function to |
| 1234 // allow recompilation to take effect without changing any of the | 1247 // allow recompilation to take effect without changing any of the |
| 1235 // call sites. | 1248 // call sites. |
| 1236 Register code = ip; | 1249 Register code = ip; |
| 1237 LoadP(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); | 1250 LoadP(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); |
| 1238 if (flag == CALL_FUNCTION) { | 1251 if (flag == CALL_FUNCTION) { |
| 1239 call_wrapper.BeforeCall(CallSize(code)); | 1252 call_wrapper.BeforeCall(CallSize(code)); |
| 1240 CallJSEntry(code); | 1253 CallJSEntry(code); |
| 1241 call_wrapper.AfterCall(); | 1254 call_wrapper.AfterCall(); |
| 1242 } else { | 1255 } else { |
| 1243 DCHECK(flag == JUMP_FUNCTION); | 1256 DCHECK(flag == JUMP_FUNCTION); |
| 1244 JumpToJSEntry(code); | 1257 JumpToJSEntry(code); |
| 1245 } | 1258 } |
| 1246 | 1259 |
| 1247 // Continue here if InvokePrologue does handle the invocation due to | 1260 // Continue here if InvokePrologue does handle the invocation due to |
| 1248 // mismatched parameter counts. | 1261 // mismatched parameter counts. |
| 1249 bind(&done); | 1262 bind(&done); |
| 1250 } | 1263 } |
| 1251 } | 1264 } |
| 1252 | 1265 |
| 1253 | |
| 1254 void MacroAssembler::InvokeFunction(Register fun, Register new_target, | 1266 void MacroAssembler::InvokeFunction(Register fun, Register new_target, |
| 1255 const ParameterCount& actual, | 1267 const ParameterCount& actual, |
| 1256 InvokeFlag flag, | 1268 InvokeFlag flag, |
| 1257 const CallWrapper& call_wrapper) { | 1269 const CallWrapper& call_wrapper) { |
| 1258 // You can't call a function without a valid frame. | 1270 // You can't call a function without a valid frame. |
| 1259 DCHECK(flag == JUMP_FUNCTION || has_frame()); | 1271 DCHECK(flag == JUMP_FUNCTION || has_frame()); |
| 1260 | 1272 |
| 1261 // Contract with called JS functions requires that function is passed in r4. | 1273 // Contract with called JS functions requires that function is passed in r3. |
| 1262 DCHECK(fun.is(r4)); | 1274 DCHECK(fun.is(r3)); |
| 1263 | 1275 |
| 1264 Register expected_reg = r5; | 1276 Register expected_reg = r4; |
| 1265 Register temp_reg = r7; | 1277 Register temp_reg = r6; |
| 1266 | 1278 LoadP(temp_reg, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset)); |
| 1267 LoadP(temp_reg, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); | 1279 LoadP(cp, FieldMemOperand(r3, JSFunction::kContextOffset)); |
| 1268 LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset)); | 1280 LoadW(expected_reg, |
| 1269 LoadWordArith(expected_reg, | 1281 FieldMemOperand(temp_reg, |
| 1270 FieldMemOperand( | 1282 SharedFunctionInfo::kFormalParameterCountOffset)); |
| 1271 temp_reg, SharedFunctionInfo::kFormalParameterCountOffset)); | 1283 #if !defined(V8_TARGET_ARCH_S390X) |
| 1272 #if !defined(V8_TARGET_ARCH_PPC64) | |
| 1273 SmiUntag(expected_reg); | 1284 SmiUntag(expected_reg); |
| 1274 #endif | 1285 #endif |
| 1275 | 1286 |
| 1276 ParameterCount expected(expected_reg); | 1287 ParameterCount expected(expected_reg); |
| 1277 InvokeFunctionCode(fun, new_target, expected, actual, flag, call_wrapper); | 1288 InvokeFunctionCode(fun, new_target, expected, actual, flag, call_wrapper); |
| 1278 } | 1289 } |
| 1279 | 1290 |
| 1280 | |
| 1281 void MacroAssembler::InvokeFunction(Register function, | 1291 void MacroAssembler::InvokeFunction(Register function, |
| 1282 const ParameterCount& expected, | 1292 const ParameterCount& expected, |
| 1283 const ParameterCount& actual, | 1293 const ParameterCount& actual, |
| 1284 InvokeFlag flag, | 1294 InvokeFlag flag, |
| 1285 const CallWrapper& call_wrapper) { | 1295 const CallWrapper& call_wrapper) { |
| 1286 // You can't call a function without a valid frame. | 1296 // You can't call a function without a valid frame. |
| 1287 DCHECK(flag == JUMP_FUNCTION || has_frame()); | 1297 DCHECK(flag == JUMP_FUNCTION || has_frame()); |
| 1288 | 1298 |
| 1289 // Contract with called JS functions requires that function is passed in r4. | 1299 // Contract with called JS functions requires that function is passed in r3. |
| 1290 DCHECK(function.is(r4)); | 1300 DCHECK(function.is(r3)); |
| 1291 | 1301 |
| 1292 // Get the function and setup the context. | 1302 // Get the function and setup the context. |
| 1293 LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset)); | 1303 LoadP(cp, FieldMemOperand(r3, JSFunction::kContextOffset)); |
| 1294 | 1304 |
| 1295 InvokeFunctionCode(r4, no_reg, expected, actual, flag, call_wrapper); | 1305 InvokeFunctionCode(r3, no_reg, expected, actual, flag, call_wrapper); |
| 1296 } | 1306 } |
| 1297 | 1307 |
| 1298 | |
| 1299 void MacroAssembler::InvokeFunction(Handle<JSFunction> function, | 1308 void MacroAssembler::InvokeFunction(Handle<JSFunction> function, |
| 1300 const ParameterCount& expected, | 1309 const ParameterCount& expected, |
| 1301 const ParameterCount& actual, | 1310 const ParameterCount& actual, |
| 1302 InvokeFlag flag, | 1311 InvokeFlag flag, |
| 1303 const CallWrapper& call_wrapper) { | 1312 const CallWrapper& call_wrapper) { |
| 1304 Move(r4, function); | 1313 Move(r3, function); |
| 1305 InvokeFunction(r4, expected, actual, flag, call_wrapper); | 1314 InvokeFunction(r3, expected, actual, flag, call_wrapper); |
| 1306 } | 1315 } |
| 1307 | 1316 |
| 1308 | |
| 1309 void MacroAssembler::IsObjectJSStringType(Register object, Register scratch, | 1317 void MacroAssembler::IsObjectJSStringType(Register object, Register scratch, |
| 1310 Label* fail) { | 1318 Label* fail) { |
| 1311 DCHECK(kNotStringTag != 0); | 1319 DCHECK(kNotStringTag != 0); |
| 1312 | 1320 |
| 1313 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); | 1321 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 1314 lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); | 1322 LoadlB(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); |
| 1315 andi(r0, scratch, Operand(kIsNotStringMask)); | 1323 mov(r0, Operand(kIsNotStringMask)); |
| 1316 bne(fail, cr0); | 1324 AndP(r0, scratch); |
| 1325 bne(fail); |
| 1317 } | 1326 } |
| 1318 | 1327 |
| 1319 | |
| 1320 void MacroAssembler::IsObjectNameType(Register object, Register scratch, | 1328 void MacroAssembler::IsObjectNameType(Register object, Register scratch, |
| 1321 Label* fail) { | 1329 Label* fail) { |
| 1322 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); | 1330 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 1323 lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); | 1331 LoadlB(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); |
| 1324 cmpi(scratch, Operand(LAST_NAME_TYPE)); | 1332 CmpP(scratch, Operand(LAST_NAME_TYPE)); |
| 1325 bgt(fail); | 1333 bgt(fail); |
| 1326 } | 1334 } |
| 1327 | 1335 |
| 1328 | |
| 1329 void MacroAssembler::DebugBreak() { | 1336 void MacroAssembler::DebugBreak() { |
| 1330 li(r3, Operand::Zero()); | 1337 LoadImmP(r2, Operand::Zero()); |
| 1331 mov(r4, | 1338 mov(r3, |
| 1332 Operand(ExternalReference(Runtime::kHandleDebuggerStatement, isolate()))); | 1339 Operand(ExternalReference(Runtime::kHandleDebuggerStatement, isolate()))); |
| 1333 CEntryStub ces(isolate(), 1); | 1340 CEntryStub ces(isolate(), 1); |
| 1334 DCHECK(AllowThisStubCall(&ces)); | 1341 DCHECK(AllowThisStubCall(&ces)); |
| 1335 Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT); | 1342 Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT); |
| 1336 } | 1343 } |
| 1337 | 1344 |
| 1338 | |
| 1339 void MacroAssembler::PushStackHandler() { | 1345 void MacroAssembler::PushStackHandler() { |
| 1340 // Adjust this code if not the case. | 1346 // Adjust this code if not the case. |
| 1341 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize); | 1347 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize); |
| 1342 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); | 1348 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); |
| 1343 | 1349 |
| 1344 // Link the current handler as the next handler. | 1350 // Link the current handler as the next handler. |
| 1345 // Preserve r3-r7. | 1351 mov(r7, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); |
| 1346 mov(r8, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); | |
| 1347 LoadP(r0, MemOperand(r8)); | |
| 1348 push(r0); | |
| 1349 | 1352 |
| 1353 // Buy the full stack frame for 5 slots. |
| 1354 lay(sp, MemOperand(sp, -StackHandlerConstants::kSize)); |
| 1355 |
| 1356 // Copy the old handler into the next handler slot. |
| 1357 mvc(MemOperand(sp, StackHandlerConstants::kNextOffset), MemOperand(r7), |
| 1358 kPointerSize); |
| 1350 // Set this new handler as the current one. | 1359 // Set this new handler as the current one. |
| 1351 StoreP(sp, MemOperand(r8)); | 1360 StoreP(sp, MemOperand(r7)); |
| 1352 } | 1361 } |
| 1353 | 1362 |
| 1354 | |
| 1355 void MacroAssembler::PopStackHandler() { | 1363 void MacroAssembler::PopStackHandler() { |
| 1356 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize); | 1364 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize); |
| 1357 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | 1365 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
| 1358 | 1366 |
| 1359 pop(r4); | 1367 // Pop the Next Handler into r3 and store it into Handler Address reference. |
| 1368 Pop(r3); |
| 1360 mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); | 1369 mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); |
| 1361 StoreP(r4, MemOperand(ip)); | 1370 |
| 1371 StoreP(r3, MemOperand(ip)); |
| 1362 } | 1372 } |
| 1363 | 1373 |
| 1364 | |
| 1365 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, | 1374 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, |
| 1366 Register scratch, Label* miss) { | 1375 Register scratch, Label* miss) { |
| 1367 Label same_contexts; | 1376 Label same_contexts; |
| 1368 | 1377 |
| 1369 DCHECK(!holder_reg.is(scratch)); | 1378 DCHECK(!holder_reg.is(scratch)); |
| 1370 DCHECK(!holder_reg.is(ip)); | 1379 DCHECK(!holder_reg.is(ip)); |
| 1371 DCHECK(!scratch.is(ip)); | 1380 DCHECK(!scratch.is(ip)); |
| 1372 | 1381 |
| 1373 // Load current lexical context from the stack frame. | 1382 // Load current lexical context from the stack frame. |
| 1374 LoadP(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1383 LoadP(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 1375 // In debug mode, make sure the lexical context is set. | 1384 // In debug mode, make sure the lexical context is set. |
| 1376 #ifdef DEBUG | 1385 #ifdef DEBUG |
| 1377 cmpi(scratch, Operand::Zero()); | 1386 CmpP(scratch, Operand::Zero()); |
| 1378 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext); | 1387 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext); |
| 1379 #endif | 1388 #endif |
| 1380 | 1389 |
| 1381 // Load the native context of the current context. | 1390 // Load the native context of the current context. |
| 1382 LoadP(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX)); | 1391 LoadP(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX)); |
| 1383 | 1392 |
| 1384 // Check the context is a native context. | 1393 // Check the context is a native context. |
| 1385 if (emit_debug_code()) { | 1394 if (emit_debug_code()) { |
| 1386 // Cannot use ip as a temporary in this verification code. Due to the fact | 1395 // Cannot use ip as a temporary in this verification code. Due to the fact |
| 1387 // that ip is clobbered as part of cmp with an object Operand. | 1396 // that ip is clobbered as part of cmp with an object Operand. |
| 1388 push(holder_reg); // Temporarily save holder on the stack. | 1397 push(holder_reg); // Temporarily save holder on the stack. |
| 1389 // Read the first word and compare to the native_context_map. | 1398 // Read the first word and compare to the native_context_map. |
| 1390 LoadP(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); | 1399 LoadP(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); |
| 1391 LoadRoot(ip, Heap::kNativeContextMapRootIndex); | 1400 CompareRoot(holder_reg, Heap::kNativeContextMapRootIndex); |
| 1392 cmp(holder_reg, ip); | |
| 1393 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext); | 1401 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext); |
| 1394 pop(holder_reg); // Restore holder. | 1402 pop(holder_reg); // Restore holder. |
| 1395 } | 1403 } |
| 1396 | 1404 |
| 1397 // Check if both contexts are the same. | 1405 // Check if both contexts are the same. |
| 1398 LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); | 1406 LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); |
| 1399 cmp(scratch, ip); | 1407 CmpP(scratch, ip); |
| 1400 beq(&same_contexts); | 1408 beq(&same_contexts, Label::kNear); |
| 1401 | 1409 |
| 1402 // Check the context is a native context. | 1410 // Check the context is a native context. |
| 1403 if (emit_debug_code()) { | 1411 if (emit_debug_code()) { |
| 1412 // TODO(119): avoid push(holder_reg)/pop(holder_reg) |
| 1404 // Cannot use ip as a temporary in this verification code. Due to the fact | 1413 // Cannot use ip as a temporary in this verification code. Due to the fact |
| 1405 // that ip is clobbered as part of cmp with an object Operand. | 1414 // that ip is clobbered as part of cmp with an object Operand. |
| 1406 push(holder_reg); // Temporarily save holder on the stack. | 1415 push(holder_reg); // Temporarily save holder on the stack. |
| 1407 mr(holder_reg, ip); // Move ip to its holding place. | 1416 LoadRR(holder_reg, ip); // Move ip to its holding place. |
| 1408 LoadRoot(ip, Heap::kNullValueRootIndex); | 1417 CompareRoot(holder_reg, Heap::kNullValueRootIndex); |
| 1409 cmp(holder_reg, ip); | |
| 1410 Check(ne, kJSGlobalProxyContextShouldNotBeNull); | 1418 Check(ne, kJSGlobalProxyContextShouldNotBeNull); |
| 1411 | 1419 |
| 1412 LoadP(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); | 1420 LoadP(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); |
| 1413 LoadRoot(ip, Heap::kNativeContextMapRootIndex); | 1421 CompareRoot(holder_reg, Heap::kNativeContextMapRootIndex); |
| 1414 cmp(holder_reg, ip); | |
| 1415 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext); | 1422 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext); |
| 1416 // Restore ip is not needed. ip is reloaded below. | 1423 // Restore ip is not needed. ip is reloaded below. |
| 1417 pop(holder_reg); // Restore holder. | 1424 pop(holder_reg); // Restore holder. |
| 1418 // Restore ip to holder's context. | 1425 // Restore ip to holder's context. |
| 1419 LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); | 1426 LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); |
| 1420 } | 1427 } |
| 1421 | 1428 |
| 1422 // Check that the security token in the calling global object is | 1429 // Check that the security token in the calling global object is |
| 1423 // compatible with the security token in the receiving global | 1430 // compatible with the security token in the receiving global |
| 1424 // object. | 1431 // object. |
| 1425 int token_offset = | 1432 int token_offset = |
| 1426 Context::kHeaderSize + Context::SECURITY_TOKEN_INDEX * kPointerSize; | 1433 Context::kHeaderSize + Context::SECURITY_TOKEN_INDEX * kPointerSize; |
| 1427 | 1434 |
| 1428 LoadP(scratch, FieldMemOperand(scratch, token_offset)); | 1435 LoadP(scratch, FieldMemOperand(scratch, token_offset)); |
| 1429 LoadP(ip, FieldMemOperand(ip, token_offset)); | 1436 LoadP(ip, FieldMemOperand(ip, token_offset)); |
| 1430 cmp(scratch, ip); | 1437 CmpP(scratch, ip); |
| 1431 bne(miss); | 1438 bne(miss); |
| 1432 | 1439 |
| 1433 bind(&same_contexts); | 1440 bind(&same_contexts); |
| 1434 } | 1441 } |
| 1435 | 1442 |
| 1436 | |
| 1437 // Compute the hash code from the untagged key. This must be kept in sync with | 1443 // Compute the hash code from the untagged key. This must be kept in sync with |
| 1438 // ComputeIntegerHash in utils.h and KeyedLoadGenericStub in | 1444 // ComputeIntegerHash in utils.h and KeyedLoadGenericStub in |
| 1439 // code-stub-hydrogen.cc | 1445 // code-stub-hydrogen.cc |
| 1440 void MacroAssembler::GetNumberHash(Register t0, Register scratch) { | 1446 void MacroAssembler::GetNumberHash(Register t0, Register scratch) { |
| 1441 // First of all we assign the hash seed to scratch. | 1447 // First of all we assign the hash seed to scratch. |
| 1442 LoadRoot(scratch, Heap::kHashSeedRootIndex); | 1448 LoadRoot(scratch, Heap::kHashSeedRootIndex); |
| 1443 SmiUntag(scratch); | 1449 SmiUntag(scratch); |
| 1444 | 1450 |
| 1445 // Xor original key with a seed. | 1451 // Xor original key with a seed. |
| 1446 xor_(t0, t0, scratch); | 1452 XorP(t0, scratch); |
| 1447 | 1453 |
| 1448 // Compute the hash code from the untagged key. This must be kept in sync | 1454 // Compute the hash code from the untagged key. This must be kept in sync |
| 1449 // with ComputeIntegerHash in utils.h. | 1455 // with ComputeIntegerHash in utils.h. |
| 1450 // | 1456 // |
| 1451 // hash = ~hash + (hash << 15); | 1457 // hash = ~hash + (hash << 15); |
| 1452 notx(scratch, t0); | 1458 LoadRR(scratch, t0); |
| 1453 slwi(t0, t0, Operand(15)); | 1459 NotP(scratch); |
| 1454 add(t0, scratch, t0); | 1460 sll(t0, Operand(15)); |
| 1461 AddP(t0, scratch, t0); |
| 1455 // hash = hash ^ (hash >> 12); | 1462 // hash = hash ^ (hash >> 12); |
| 1456 srwi(scratch, t0, Operand(12)); | 1463 ShiftRight(scratch, t0, Operand(12)); |
| 1457 xor_(t0, t0, scratch); | 1464 XorP(t0, scratch); |
| 1458 // hash = hash + (hash << 2); | 1465 // hash = hash + (hash << 2); |
| 1459 slwi(scratch, t0, Operand(2)); | 1466 ShiftLeft(scratch, t0, Operand(2)); |
| 1460 add(t0, t0, scratch); | 1467 AddP(t0, t0, scratch); |
| 1461 // hash = hash ^ (hash >> 4); | 1468 // hash = hash ^ (hash >> 4); |
| 1462 srwi(scratch, t0, Operand(4)); | 1469 ShiftRight(scratch, t0, Operand(4)); |
| 1463 xor_(t0, t0, scratch); | 1470 XorP(t0, scratch); |
| 1464 // hash = hash * 2057; | 1471 // hash = hash * 2057; |
| 1465 mr(r0, t0); | 1472 LoadRR(r0, t0); |
| 1466 slwi(scratch, t0, Operand(3)); | 1473 ShiftLeft(scratch, t0, Operand(3)); |
| 1467 add(t0, t0, scratch); | 1474 AddP(t0, t0, scratch); |
| 1468 slwi(scratch, r0, Operand(11)); | 1475 ShiftLeft(scratch, r0, Operand(11)); |
| 1469 add(t0, t0, scratch); | 1476 AddP(t0, t0, scratch); |
| 1470 // hash = hash ^ (hash >> 16); | 1477 // hash = hash ^ (hash >> 16); |
| 1471 srwi(scratch, t0, Operand(16)); | 1478 ShiftRight(scratch, t0, Operand(16)); |
| 1472 xor_(t0, t0, scratch); | 1479 XorP(t0, scratch); |
| 1473 // hash & 0x3fffffff | 1480 // hash & 0x3fffffff |
| 1474 ExtractBitRange(t0, t0, 29, 0); | 1481 ExtractBitRange(t0, t0, 29, 0); |
| 1475 } | 1482 } |
| 1476 | 1483 |
| 1477 | |
| 1478 void MacroAssembler::LoadFromNumberDictionary(Label* miss, Register elements, | 1484 void MacroAssembler::LoadFromNumberDictionary(Label* miss, Register elements, |
| 1479 Register key, Register result, | 1485 Register key, Register result, |
| 1480 Register t0, Register t1, | 1486 Register t0, Register t1, |
| 1481 Register t2) { | 1487 Register t2) { |
| 1482 // Register use: | 1488 // Register use: |
| 1483 // | 1489 // |
| 1484 // elements - holds the slow-case elements of the receiver on entry. | 1490 // elements - holds the slow-case elements of the receiver on entry. |
| 1485 // Unchanged unless 'result' is the same register. | 1491 // Unchanged unless 'result' is the same register. |
| 1486 // | 1492 // |
| 1487 // key - holds the smi key on entry. | 1493 // key - holds the smi key on entry. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1499 // t1 - used to hold the capacity mask of the dictionary | 1505 // t1 - used to hold the capacity mask of the dictionary |
| 1500 // | 1506 // |
| 1501 // t2 - used for the index into the dictionary. | 1507 // t2 - used for the index into the dictionary. |
| 1502 Label done; | 1508 Label done; |
| 1503 | 1509 |
| 1504 GetNumberHash(t0, t1); | 1510 GetNumberHash(t0, t1); |
| 1505 | 1511 |
| 1506 // Compute the capacity mask. | 1512 // Compute the capacity mask. |
| 1507 LoadP(t1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset)); | 1513 LoadP(t1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset)); |
| 1508 SmiUntag(t1); | 1514 SmiUntag(t1); |
| 1509 subi(t1, t1, Operand(1)); | 1515 SubP(t1, Operand(1)); |
| 1510 | 1516 |
| 1511 // Generate an unrolled loop that performs a few probes before giving up. | 1517 // Generate an unrolled loop that performs a few probes before giving up. |
| 1512 for (int i = 0; i < kNumberDictionaryProbes; i++) { | 1518 for (int i = 0; i < kNumberDictionaryProbes; i++) { |
| 1513 // Use t2 for index calculations and keep the hash intact in t0. | 1519 // Use t2 for index calculations and keep the hash intact in t0. |
| 1514 mr(t2, t0); | 1520 LoadRR(t2, t0); |
| 1515 // Compute the masked index: (hash + i + i * i) & mask. | 1521 // Compute the masked index: (hash + i + i * i) & mask. |
| 1516 if (i > 0) { | 1522 if (i > 0) { |
| 1517 addi(t2, t2, Operand(SeededNumberDictionary::GetProbeOffset(i))); | 1523 AddP(t2, Operand(SeededNumberDictionary::GetProbeOffset(i))); |
| 1518 } | 1524 } |
| 1519 and_(t2, t2, t1); | 1525 AndP(t2, t1); |
| 1520 | 1526 |
| 1521 // Scale the index by multiplying by the element size. | 1527 // Scale the index by multiplying by the element size. |
| 1522 DCHECK(SeededNumberDictionary::kEntrySize == 3); | 1528 DCHECK(SeededNumberDictionary::kEntrySize == 3); |
| 1523 slwi(ip, t2, Operand(1)); | 1529 LoadRR(ip, t2); |
| 1524 add(t2, t2, ip); // t2 = t2 * 3 | 1530 sll(ip, Operand(1)); |
| 1531 AddP(t2, ip); // t2 = t2 * 3 |
| 1525 | 1532 |
| 1526 // Check if the key is identical to the name. | 1533 // Check if the key is identical to the name. |
| 1527 slwi(t2, t2, Operand(kPointerSizeLog2)); | 1534 sll(t2, Operand(kPointerSizeLog2)); |
| 1528 add(t2, elements, t2); | 1535 AddP(t2, elements); |
| 1529 LoadP(ip, | 1536 LoadP(ip, |
| 1530 FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset)); | 1537 FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset)); |
| 1531 cmp(key, ip); | 1538 CmpP(key, ip); |
| 1532 if (i != kNumberDictionaryProbes - 1) { | 1539 if (i != kNumberDictionaryProbes - 1) { |
| 1533 beq(&done); | 1540 beq(&done, Label::kNear); |
| 1534 } else { | 1541 } else { |
| 1535 bne(miss); | 1542 bne(miss); |
| 1536 } | 1543 } |
| 1537 } | 1544 } |
| 1538 | 1545 |
| 1539 bind(&done); | 1546 bind(&done); |
| 1540 // Check that the value is a field property. | 1547 // Check that the value is a field property. |
| 1541 // t2: elements + (index * kPointerSize) | 1548 // t2: elements + (index * kPointerSize) |
| 1542 const int kDetailsOffset = | 1549 const int kDetailsOffset = |
| 1543 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize; | 1550 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
| 1544 LoadP(t1, FieldMemOperand(t2, kDetailsOffset)); | 1551 LoadP(t1, FieldMemOperand(t2, kDetailsOffset)); |
| 1545 LoadSmiLiteral(ip, Smi::FromInt(PropertyDetails::TypeField::kMask)); | 1552 LoadSmiLiteral(ip, Smi::FromInt(PropertyDetails::TypeField::kMask)); |
| 1546 DCHECK_EQ(DATA, 0); | 1553 DCHECK_EQ(DATA, 0); |
| 1547 and_(r0, t1, ip, SetRC); | 1554 AndP(r0, ip, t1); |
| 1548 bne(miss, cr0); | 1555 bne(miss); |
| 1549 | 1556 |
| 1550 // Get the value at the masked, scaled index and return. | 1557 // Get the value at the masked, scaled index and return. |
| 1551 const int kValueOffset = | 1558 const int kValueOffset = |
| 1552 SeededNumberDictionary::kElementsStartOffset + kPointerSize; | 1559 SeededNumberDictionary::kElementsStartOffset + kPointerSize; |
| 1553 LoadP(result, FieldMemOperand(t2, kValueOffset)); | 1560 LoadP(result, FieldMemOperand(t2, kValueOffset)); |
| 1554 } | 1561 } |
| 1555 | 1562 |
| 1556 | |
| 1557 void MacroAssembler::Allocate(int object_size, Register result, | 1563 void MacroAssembler::Allocate(int object_size, Register result, |
| 1558 Register scratch1, Register scratch2, | 1564 Register scratch1, Register scratch2, |
| 1559 Label* gc_required, AllocationFlags flags) { | 1565 Label* gc_required, AllocationFlags flags) { |
| 1560 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize); | 1566 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize); |
| 1561 if (!FLAG_inline_new) { | 1567 if (!FLAG_inline_new) { |
| 1562 if (emit_debug_code()) { | 1568 if (emit_debug_code()) { |
| 1563 // Trash the registers to simulate an allocation failure. | 1569 // Trash the registers to simulate an allocation failure. |
| 1564 li(result, Operand(0x7091)); | 1570 LoadImmP(result, Operand(0x7091)); |
| 1565 li(scratch1, Operand(0x7191)); | 1571 LoadImmP(scratch1, Operand(0x7191)); |
| 1566 li(scratch2, Operand(0x7291)); | 1572 LoadImmP(scratch2, Operand(0x7291)); |
| 1567 } | 1573 } |
| 1568 b(gc_required); | 1574 b(gc_required); |
| 1569 return; | 1575 return; |
| 1570 } | 1576 } |
| 1571 | 1577 |
| 1572 DCHECK(!AreAliased(result, scratch1, scratch2, ip)); | 1578 DCHECK(!AreAliased(result, scratch1, scratch2, ip)); |
| 1573 | 1579 |
| 1574 // Make object size into bytes. | 1580 // Make object size into bytes. |
| 1575 if ((flags & SIZE_IN_WORDS) != 0) { | 1581 if ((flags & SIZE_IN_WORDS) != 0) { |
| 1576 object_size *= kPointerSize; | 1582 object_size *= kPointerSize; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1596 mov(top_address, Operand(allocation_top)); | 1602 mov(top_address, Operand(allocation_top)); |
| 1597 | 1603 |
| 1598 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 1604 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
| 1599 // Load allocation top into result and allocation limit into ip. | 1605 // Load allocation top into result and allocation limit into ip. |
| 1600 LoadP(result, MemOperand(top_address)); | 1606 LoadP(result, MemOperand(top_address)); |
| 1601 LoadP(alloc_limit, MemOperand(top_address, kPointerSize)); | 1607 LoadP(alloc_limit, MemOperand(top_address, kPointerSize)); |
| 1602 } else { | 1608 } else { |
| 1603 if (emit_debug_code()) { | 1609 if (emit_debug_code()) { |
| 1604 // Assert that result actually contains top on entry. | 1610 // Assert that result actually contains top on entry. |
| 1605 LoadP(alloc_limit, MemOperand(top_address)); | 1611 LoadP(alloc_limit, MemOperand(top_address)); |
| 1606 cmp(result, alloc_limit); | 1612 CmpP(result, alloc_limit); |
| 1607 Check(eq, kUnexpectedAllocationTop); | 1613 Check(eq, kUnexpectedAllocationTop); |
| 1608 } | 1614 } |
| 1609 // Load allocation limit. Result already contains allocation top. | 1615 // Load allocation limit. Result already contains allocation top. |
| 1610 LoadP(alloc_limit, MemOperand(top_address, limit - top)); | 1616 LoadP(alloc_limit, MemOperand(top_address, limit - top)); |
| 1611 } | 1617 } |
| 1612 | 1618 |
| 1613 if ((flags & DOUBLE_ALIGNMENT) != 0) { | 1619 if ((flags & DOUBLE_ALIGNMENT) != 0) { |
| 1614 // Align the next allocation. Storing the filler map without checking top is | 1620 // Align the next allocation. Storing the filler map without checking top is |
| 1615 // safe in new-space because the limit of the heap is aligned there. | 1621 // safe in new-space because the limit of the heap is aligned there. |
| 1616 #if V8_TARGET_ARCH_PPC64 | 1622 #if V8_TARGET_ARCH_S390X |
| 1617 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment); | 1623 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment); |
| 1618 #else | 1624 #else |
| 1619 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment); | 1625 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment); |
| 1620 andi(result_end, result, Operand(kDoubleAlignmentMask)); | 1626 AndP(result_end, result, Operand(kDoubleAlignmentMask)); |
| 1621 Label aligned; | 1627 Label aligned; |
| 1622 beq(&aligned, cr0); | 1628 beq(&aligned); |
| 1623 if ((flags & PRETENURE) != 0) { | 1629 if ((flags & PRETENURE) != 0) { |
| 1624 cmpl(result, alloc_limit); | 1630 CmpLogicalP(result, alloc_limit); |
| 1625 bge(gc_required); | 1631 bge(gc_required); |
| 1626 } | 1632 } |
| 1627 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map())); | 1633 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map())); |
| 1628 stw(result_end, MemOperand(result)); | 1634 StoreW(result_end, MemOperand(result)); |
| 1629 addi(result, result, Operand(kDoubleSize / 2)); | 1635 AddP(result, result, Operand(kDoubleSize / 2)); |
| 1630 bind(&aligned); | 1636 bind(&aligned); |
| 1631 #endif | 1637 #endif |
| 1632 } | 1638 } |
| 1633 | 1639 |
| 1634 // Calculate new top and bail out if new space is exhausted. Use result | 1640 // Calculate new top and bail out if new space is exhausted. Use result |
| 1635 // to calculate the new top. | 1641 // to calculate the new top. |
| 1636 sub(r0, alloc_limit, result); | 1642 SubP(r0, alloc_limit, result); |
| 1637 if (is_int16(object_size)) { | 1643 if (is_int16(object_size)) { |
| 1638 cmpi(r0, Operand(object_size)); | 1644 CmpP(r0, Operand(object_size)); |
| 1639 blt(gc_required); | 1645 blt(gc_required); |
| 1640 addi(result_end, result, Operand(object_size)); | 1646 AddP(result_end, result, Operand(object_size)); |
| 1641 } else { | 1647 } else { |
| 1642 Cmpi(r0, Operand(object_size), result_end); | 1648 mov(result_end, Operand(object_size)); |
| 1649 CmpP(r0, result_end); |
| 1643 blt(gc_required); | 1650 blt(gc_required); |
| 1644 add(result_end, result, result_end); | 1651 AddP(result_end, result, result_end); |
| 1645 } | 1652 } |
| 1646 StoreP(result_end, MemOperand(top_address)); | 1653 StoreP(result_end, MemOperand(top_address)); |
| 1647 | 1654 |
| 1648 // Tag object if requested. | 1655 // Tag object if requested. |
| 1649 if ((flags & TAG_OBJECT) != 0) { | 1656 if ((flags & TAG_OBJECT) != 0) { |
| 1650 addi(result, result, Operand(kHeapObjectTag)); | 1657 AddP(result, result, Operand(kHeapObjectTag)); |
| 1651 } | 1658 } |
| 1652 } | 1659 } |
| 1653 | 1660 |
| 1654 | |
| 1655 void MacroAssembler::Allocate(Register object_size, Register result, | 1661 void MacroAssembler::Allocate(Register object_size, Register result, |
| 1656 Register result_end, Register scratch, | 1662 Register result_end, Register scratch, |
| 1657 Label* gc_required, AllocationFlags flags) { | 1663 Label* gc_required, AllocationFlags flags) { |
| 1658 if (!FLAG_inline_new) { | 1664 if (!FLAG_inline_new) { |
| 1659 if (emit_debug_code()) { | 1665 if (emit_debug_code()) { |
| 1660 // Trash the registers to simulate an allocation failure. | 1666 // Trash the registers to simulate an allocation failure. |
| 1661 li(result, Operand(0x7091)); | 1667 LoadImmP(result, Operand(0x7091)); |
| 1662 li(scratch, Operand(0x7191)); | 1668 LoadImmP(scratch, Operand(0x7191)); |
| 1663 li(result_end, Operand(0x7291)); | 1669 LoadImmP(result_end, Operand(0x7291)); |
| 1664 } | 1670 } |
| 1665 b(gc_required); | 1671 b(gc_required); |
| 1666 return; | 1672 return; |
| 1667 } | 1673 } |
| 1668 | 1674 |
| 1669 // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag | 1675 // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag |
| 1670 // is not specified. Other registers must not overlap. | 1676 // is not specified. Other registers must not overlap. |
| 1671 DCHECK(!AreAliased(object_size, result, scratch, ip)); | 1677 DCHECK(!AreAliased(object_size, result, scratch, ip)); |
| 1672 DCHECK(!AreAliased(result_end, result, scratch, ip)); | 1678 DCHECK(!AreAliased(result_end, result, scratch, ip)); |
| 1673 DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end)); | 1679 DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end)); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1689 mov(top_address, Operand(allocation_top)); | 1695 mov(top_address, Operand(allocation_top)); |
| 1690 | 1696 |
| 1691 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 1697 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
| 1692 // Load allocation top into result and allocation limit into alloc_limit.. | 1698 // Load allocation top into result and allocation limit into alloc_limit.. |
| 1693 LoadP(result, MemOperand(top_address)); | 1699 LoadP(result, MemOperand(top_address)); |
| 1694 LoadP(alloc_limit, MemOperand(top_address, kPointerSize)); | 1700 LoadP(alloc_limit, MemOperand(top_address, kPointerSize)); |
| 1695 } else { | 1701 } else { |
| 1696 if (emit_debug_code()) { | 1702 if (emit_debug_code()) { |
| 1697 // Assert that result actually contains top on entry. | 1703 // Assert that result actually contains top on entry. |
| 1698 LoadP(alloc_limit, MemOperand(top_address)); | 1704 LoadP(alloc_limit, MemOperand(top_address)); |
| 1699 cmp(result, alloc_limit); | 1705 CmpP(result, alloc_limit); |
| 1700 Check(eq, kUnexpectedAllocationTop); | 1706 Check(eq, kUnexpectedAllocationTop); |
| 1701 } | 1707 } |
| 1702 // Load allocation limit. Result already contains allocation top. | 1708 // Load allocation limit. Result already contains allocation top. |
| 1703 LoadP(alloc_limit, MemOperand(top_address, limit - top)); | 1709 LoadP(alloc_limit, MemOperand(top_address, limit - top)); |
| 1704 } | 1710 } |
| 1705 | 1711 |
| 1706 if ((flags & DOUBLE_ALIGNMENT) != 0) { | 1712 if ((flags & DOUBLE_ALIGNMENT) != 0) { |
| 1707 // Align the next allocation. Storing the filler map without checking top is | 1713 // Align the next allocation. Storing the filler map without checking top is |
| 1708 // safe in new-space because the limit of the heap is aligned there. | 1714 // safe in new-space because the limit of the heap is aligned there. |
| 1709 #if V8_TARGET_ARCH_PPC64 | 1715 #if V8_TARGET_ARCH_S390X |
| 1710 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment); | 1716 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment); |
| 1711 #else | 1717 #else |
| 1712 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment); | 1718 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment); |
| 1713 andi(result_end, result, Operand(kDoubleAlignmentMask)); | 1719 AndP(result_end, result, Operand(kDoubleAlignmentMask)); |
| 1714 Label aligned; | 1720 Label aligned; |
| 1715 beq(&aligned, cr0); | 1721 beq(&aligned); |
| 1716 if ((flags & PRETENURE) != 0) { | 1722 if ((flags & PRETENURE) != 0) { |
| 1717 cmpl(result, alloc_limit); | 1723 CmpLogicalP(result, alloc_limit); |
| 1718 bge(gc_required); | 1724 bge(gc_required); |
| 1719 } | 1725 } |
| 1720 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map())); | 1726 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map())); |
| 1721 stw(result_end, MemOperand(result)); | 1727 StoreW(result_end, MemOperand(result)); |
| 1722 addi(result, result, Operand(kDoubleSize / 2)); | 1728 AddP(result, result, Operand(kDoubleSize / 2)); |
| 1723 bind(&aligned); | 1729 bind(&aligned); |
| 1724 #endif | 1730 #endif |
| 1725 } | 1731 } |
| 1726 | 1732 |
| 1727 // Calculate new top and bail out if new space is exhausted. Use result | 1733 // Calculate new top and bail out if new space is exhausted. Use result |
| 1728 // to calculate the new top. Object size may be in words so a shift is | 1734 // to calculate the new top. Object size may be in words so a shift is |
| 1729 // required to get the number of bytes. | 1735 // required to get the number of bytes. |
| 1730 sub(r0, alloc_limit, result); | 1736 SubP(r0, alloc_limit, result); |
| 1731 if ((flags & SIZE_IN_WORDS) != 0) { | 1737 if ((flags & SIZE_IN_WORDS) != 0) { |
| 1732 ShiftLeftImm(result_end, object_size, Operand(kPointerSizeLog2)); | 1738 ShiftLeftP(result_end, object_size, Operand(kPointerSizeLog2)); |
| 1733 cmp(r0, result_end); | 1739 CmpP(r0, result_end); |
| 1734 blt(gc_required); | 1740 blt(gc_required); |
| 1735 add(result_end, result, result_end); | 1741 AddP(result_end, result, result_end); |
| 1736 } else { | 1742 } else { |
| 1737 cmp(r0, object_size); | 1743 CmpP(r0, object_size); |
| 1738 blt(gc_required); | 1744 blt(gc_required); |
| 1739 add(result_end, result, object_size); | 1745 AddP(result_end, result, object_size); |
| 1740 } | 1746 } |
| 1741 | 1747 |
| 1742 // Update allocation top. result temporarily holds the new top. | 1748 // Update allocation top. result temporarily holds the new top. |
| 1743 if (emit_debug_code()) { | 1749 if (emit_debug_code()) { |
| 1744 andi(r0, result_end, Operand(kObjectAlignmentMask)); | 1750 AndP(r0, result_end, Operand(kObjectAlignmentMask)); |
| 1745 Check(eq, kUnalignedAllocationInNewSpace, cr0); | 1751 Check(eq, kUnalignedAllocationInNewSpace, cr0); |
| 1746 } | 1752 } |
| 1747 StoreP(result_end, MemOperand(top_address)); | 1753 StoreP(result_end, MemOperand(top_address)); |
| 1748 | 1754 |
| 1749 // Tag object if requested. | 1755 // Tag object if requested. |
| 1750 if ((flags & TAG_OBJECT) != 0) { | 1756 if ((flags & TAG_OBJECT) != 0) { |
| 1751 addi(result, result, Operand(kHeapObjectTag)); | 1757 AddP(result, result, Operand(kHeapObjectTag)); |
| 1752 } | 1758 } |
| 1753 } | 1759 } |
| 1754 | 1760 |
| 1755 | |
| 1756 void MacroAssembler::AllocateTwoByteString(Register result, Register length, | 1761 void MacroAssembler::AllocateTwoByteString(Register result, Register length, |
| 1757 Register scratch1, Register scratch2, | 1762 Register scratch1, Register scratch2, |
| 1758 Register scratch3, | 1763 Register scratch3, |
| 1759 Label* gc_required) { | 1764 Label* gc_required) { |
| 1760 // Calculate the number of bytes needed for the characters in the string while | 1765 // Calculate the number of bytes needed for the characters in the string while |
| 1761 // observing object alignment. | 1766 // observing object alignment. |
| 1762 DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); | 1767 DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); |
| 1763 slwi(scratch1, length, Operand(1)); // Length in bytes, not chars. | 1768 |
| 1764 addi(scratch1, scratch1, | 1769 ShiftLeft(scratch1, length, Operand(1)); // Length in bytes, not chars. |
| 1765 Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize)); | 1770 AddP(scratch1, Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize)); |
| 1766 mov(r0, Operand(~kObjectAlignmentMask)); | 1771 |
| 1767 and_(scratch1, scratch1, r0); | 1772 AndP(scratch1, Operand(~kObjectAlignmentMask)); |
| 1768 | 1773 |
| 1769 // Allocate two-byte string in new space. | 1774 // Allocate two-byte string in new space. |
| 1770 Allocate(scratch1, result, scratch2, scratch3, gc_required, TAG_OBJECT); | 1775 Allocate(scratch1, result, scratch2, scratch3, gc_required, TAG_OBJECT); |
| 1771 | 1776 |
| 1772 // Set the map, length and hash field. | 1777 // Set the map, length and hash field. |
| 1773 InitializeNewString(result, length, Heap::kStringMapRootIndex, scratch1, | 1778 InitializeNewString(result, length, Heap::kStringMapRootIndex, scratch1, |
| 1774 scratch2); | 1779 scratch2); |
| 1775 } | 1780 } |
| 1776 | 1781 |
| 1777 | |
| 1778 void MacroAssembler::AllocateOneByteString(Register result, Register length, | 1782 void MacroAssembler::AllocateOneByteString(Register result, Register length, |
| 1779 Register scratch1, Register scratch2, | 1783 Register scratch1, Register scratch2, |
| 1780 Register scratch3, | 1784 Register scratch3, |
| 1781 Label* gc_required) { | 1785 Label* gc_required) { |
| 1782 // Calculate the number of bytes needed for the characters in the string while | 1786 // Calculate the number of bytes needed for the characters in the string while |
| 1783 // observing object alignment. | 1787 // observing object alignment. |
| 1784 DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); | 1788 DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); |
| 1785 DCHECK(kCharSize == 1); | 1789 DCHECK(kCharSize == 1); |
| 1786 addi(scratch1, length, | 1790 AddP(scratch1, length, |
| 1787 Operand(kObjectAlignmentMask + SeqOneByteString::kHeaderSize)); | 1791 Operand(kObjectAlignmentMask + SeqOneByteString::kHeaderSize)); |
| 1788 li(r0, Operand(~kObjectAlignmentMask)); | 1792 AndP(scratch1, Operand(~kObjectAlignmentMask)); |
| 1789 and_(scratch1, scratch1, r0); | |
| 1790 | 1793 |
| 1791 // Allocate one-byte string in new space. | 1794 // Allocate one-byte string in new space. |
| 1792 Allocate(scratch1, result, scratch2, scratch3, gc_required, TAG_OBJECT); | 1795 Allocate(scratch1, result, scratch2, scratch3, gc_required, TAG_OBJECT); |
| 1793 | 1796 |
| 1794 // Set the map, length and hash field. | 1797 // Set the map, length and hash field. |
| 1795 InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex, | 1798 InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex, |
| 1796 scratch1, scratch2); | 1799 scratch1, scratch2); |
| 1797 } | 1800 } |
| 1798 | 1801 |
| 1799 | |
| 1800 void MacroAssembler::AllocateTwoByteConsString(Register result, Register length, | 1802 void MacroAssembler::AllocateTwoByteConsString(Register result, Register length, |
| 1801 Register scratch1, | 1803 Register scratch1, |
| 1802 Register scratch2, | 1804 Register scratch2, |
| 1803 Label* gc_required) { | 1805 Label* gc_required) { |
| 1804 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, | 1806 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, |
| 1805 TAG_OBJECT); | 1807 TAG_OBJECT); |
| 1806 | 1808 |
| 1807 InitializeNewString(result, length, Heap::kConsStringMapRootIndex, scratch1, | 1809 InitializeNewString(result, length, Heap::kConsStringMapRootIndex, scratch1, |
| 1808 scratch2); | 1810 scratch2); |
| 1809 } | 1811 } |
| 1810 | 1812 |
| 1811 | |
| 1812 void MacroAssembler::AllocateOneByteConsString(Register result, Register length, | 1813 void MacroAssembler::AllocateOneByteConsString(Register result, Register length, |
| 1813 Register scratch1, | 1814 Register scratch1, |
| 1814 Register scratch2, | 1815 Register scratch2, |
| 1815 Label* gc_required) { | 1816 Label* gc_required) { |
| 1816 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, | 1817 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, |
| 1817 TAG_OBJECT); | 1818 TAG_OBJECT); |
| 1818 | 1819 |
| 1819 InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex, | 1820 InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex, |
| 1820 scratch1, scratch2); | 1821 scratch1, scratch2); |
| 1821 } | 1822 } |
| 1822 | 1823 |
| 1823 | |
| 1824 void MacroAssembler::AllocateTwoByteSlicedString(Register result, | 1824 void MacroAssembler::AllocateTwoByteSlicedString(Register result, |
| 1825 Register length, | 1825 Register length, |
| 1826 Register scratch1, | 1826 Register scratch1, |
| 1827 Register scratch2, | 1827 Register scratch2, |
| 1828 Label* gc_required) { | 1828 Label* gc_required) { |
| 1829 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, | 1829 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, |
| 1830 TAG_OBJECT); | 1830 TAG_OBJECT); |
| 1831 | 1831 |
| 1832 InitializeNewString(result, length, Heap::kSlicedStringMapRootIndex, scratch1, | 1832 InitializeNewString(result, length, Heap::kSlicedStringMapRootIndex, scratch1, |
| 1833 scratch2); | 1833 scratch2); |
| 1834 } | 1834 } |
| 1835 | 1835 |
| 1836 | |
| 1837 void MacroAssembler::AllocateOneByteSlicedString(Register result, | 1836 void MacroAssembler::AllocateOneByteSlicedString(Register result, |
| 1838 Register length, | 1837 Register length, |
| 1839 Register scratch1, | 1838 Register scratch1, |
| 1840 Register scratch2, | 1839 Register scratch2, |
| 1841 Label* gc_required) { | 1840 Label* gc_required) { |
| 1842 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, | 1841 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, |
| 1843 TAG_OBJECT); | 1842 TAG_OBJECT); |
| 1844 | 1843 |
| 1845 InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex, | 1844 InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex, |
| 1846 scratch1, scratch2); | 1845 scratch1, scratch2); |
| 1847 } | 1846 } |
| 1848 | 1847 |
| 1849 | |
| 1850 void MacroAssembler::CompareObjectType(Register object, Register map, | 1848 void MacroAssembler::CompareObjectType(Register object, Register map, |
| 1851 Register type_reg, InstanceType type) { | 1849 Register type_reg, InstanceType type) { |
| 1852 const Register temp = type_reg.is(no_reg) ? r0 : type_reg; | 1850 const Register temp = type_reg.is(no_reg) ? r0 : type_reg; |
| 1853 | 1851 |
| 1854 LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset)); | 1852 LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 1855 CompareInstanceType(map, temp, type); | 1853 CompareInstanceType(map, temp, type); |
| 1856 } | 1854 } |
| 1857 | 1855 |
| 1858 | |
| 1859 void MacroAssembler::CompareInstanceType(Register map, Register type_reg, | 1856 void MacroAssembler::CompareInstanceType(Register map, Register type_reg, |
| 1860 InstanceType type) { | 1857 InstanceType type) { |
| 1861 STATIC_ASSERT(Map::kInstanceTypeOffset < 4096); | 1858 STATIC_ASSERT(Map::kInstanceTypeOffset < 4096); |
| 1862 STATIC_ASSERT(LAST_TYPE < 256); | 1859 STATIC_ASSERT(LAST_TYPE < 256); |
| 1863 lbz(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 1860 LoadlB(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
| 1864 cmpi(type_reg, Operand(type)); | 1861 CmpP(type_reg, Operand(type)); |
| 1865 } | 1862 } |
| 1866 | 1863 |
| 1867 | |
| 1868 void MacroAssembler::CompareRoot(Register obj, Heap::RootListIndex index) { | 1864 void MacroAssembler::CompareRoot(Register obj, Heap::RootListIndex index) { |
| 1869 DCHECK(!obj.is(r0)); | 1865 CmpP(obj, MemOperand(kRootRegister, index << kPointerSizeLog2)); |
| 1870 LoadRoot(r0, index); | |
| 1871 cmp(obj, r0); | |
| 1872 } | 1866 } |
| 1873 | 1867 |
| 1874 | |
| 1875 void MacroAssembler::CheckFastElements(Register map, Register scratch, | 1868 void MacroAssembler::CheckFastElements(Register map, Register scratch, |
| 1876 Label* fail) { | 1869 Label* fail) { |
| 1877 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); | 1870 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); |
| 1878 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); | 1871 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); |
| 1879 STATIC_ASSERT(FAST_ELEMENTS == 2); | 1872 STATIC_ASSERT(FAST_ELEMENTS == 2); |
| 1880 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); | 1873 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); |
| 1881 lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset)); | |
| 1882 STATIC_ASSERT(Map::kMaximumBitField2FastHoleyElementValue < 0x8000); | 1874 STATIC_ASSERT(Map::kMaximumBitField2FastHoleyElementValue < 0x8000); |
| 1883 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue)); | 1875 CmpLogicalByte(FieldMemOperand(map, Map::kBitField2Offset), |
| 1876 Operand(Map::kMaximumBitField2FastHoleyElementValue)); |
| 1884 bgt(fail); | 1877 bgt(fail); |
| 1885 } | 1878 } |
| 1886 | 1879 |
| 1887 | |
| 1888 void MacroAssembler::CheckFastObjectElements(Register map, Register scratch, | 1880 void MacroAssembler::CheckFastObjectElements(Register map, Register scratch, |
| 1889 Label* fail) { | 1881 Label* fail) { |
| 1890 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); | 1882 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); |
| 1891 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); | 1883 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); |
| 1892 STATIC_ASSERT(FAST_ELEMENTS == 2); | 1884 STATIC_ASSERT(FAST_ELEMENTS == 2); |
| 1893 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); | 1885 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); |
| 1894 lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset)); | 1886 CmpLogicalByte(FieldMemOperand(map, Map::kBitField2Offset), |
| 1895 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue)); | 1887 Operand(Map::kMaximumBitField2FastHoleySmiElementValue)); |
| 1896 ble(fail); | 1888 ble(fail); |
| 1897 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue)); | 1889 CmpLogicalByte(FieldMemOperand(map, Map::kBitField2Offset), |
| 1890 Operand(Map::kMaximumBitField2FastHoleyElementValue)); |
| 1898 bgt(fail); | 1891 bgt(fail); |
| 1899 } | 1892 } |
| 1900 | 1893 |
| 1901 | |
| 1902 void MacroAssembler::CheckFastSmiElements(Register map, Register scratch, | 1894 void MacroAssembler::CheckFastSmiElements(Register map, Register scratch, |
| 1903 Label* fail) { | 1895 Label* fail) { |
| 1904 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); | 1896 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); |
| 1905 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); | 1897 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); |
| 1906 lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset)); | 1898 CmpLogicalByte(FieldMemOperand(map, Map::kBitField2Offset), |
| 1907 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue)); | 1899 Operand(Map::kMaximumBitField2FastHoleySmiElementValue)); |
| 1908 bgt(fail); | 1900 bgt(fail); |
| 1909 } | 1901 } |
| 1910 | 1902 |
| 1911 | 1903 void MacroAssembler::SmiToDouble(DoubleRegister value, Register smi) { |
| 1904 SmiUntag(ip, smi); |
| 1905 ConvertIntToDouble(ip, value); |
| 1906 } |
| 1912 void MacroAssembler::StoreNumberToDoubleElements( | 1907 void MacroAssembler::StoreNumberToDoubleElements( |
| 1913 Register value_reg, Register key_reg, Register elements_reg, | 1908 Register value_reg, Register key_reg, Register elements_reg, |
| 1914 Register scratch1, DoubleRegister double_scratch, Label* fail, | 1909 Register scratch1, DoubleRegister double_scratch, Label* fail, |
| 1915 int elements_offset) { | 1910 int elements_offset) { |
| 1916 DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1)); | 1911 DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1)); |
| 1917 Label smi_value, store; | 1912 Label smi_value, store; |
| 1918 | 1913 |
| 1919 // Handle smi values specially. | 1914 // Handle smi values specially. |
| 1920 JumpIfSmi(value_reg, &smi_value); | 1915 JumpIfSmi(value_reg, &smi_value); |
| 1921 | 1916 |
| 1922 // Ensure that the object is a heap number | 1917 // Ensure that the object is a heap number |
| 1923 CheckMap(value_reg, scratch1, isolate()->factory()->heap_number_map(), fail, | 1918 CheckMap(value_reg, scratch1, isolate()->factory()->heap_number_map(), fail, |
| 1924 DONT_DO_SMI_CHECK); | 1919 DONT_DO_SMI_CHECK); |
| 1925 | 1920 |
| 1926 lfd(double_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); | 1921 LoadDouble(double_scratch, |
| 1927 // Double value, turn potential sNaN into qNaN. | 1922 FieldMemOperand(value_reg, HeapNumber::kValueOffset)); |
| 1923 // Force a canonical NaN. |
| 1928 CanonicalizeNaN(double_scratch); | 1924 CanonicalizeNaN(double_scratch); |
| 1929 b(&store); | 1925 b(&store); |
| 1930 | 1926 |
| 1931 bind(&smi_value); | 1927 bind(&smi_value); |
| 1932 SmiToDouble(double_scratch, value_reg); | 1928 SmiToDouble(double_scratch, value_reg); |
| 1933 | 1929 |
| 1934 bind(&store); | 1930 bind(&store); |
| 1935 SmiToDoubleArrayOffset(scratch1, key_reg); | 1931 SmiToDoubleArrayOffset(scratch1, key_reg); |
| 1936 add(scratch1, elements_reg, scratch1); | 1932 StoreDouble(double_scratch, |
| 1937 stfd(double_scratch, FieldMemOperand(scratch1, FixedDoubleArray::kHeaderSize - | 1933 FieldMemOperand(elements_reg, scratch1, |
| 1938 elements_offset)); | 1934 FixedDoubleArray::kHeaderSize - elements_offset)); |
| 1939 } | 1935 } |
| 1940 | 1936 |
| 1941 | |
| 1942 void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left, | 1937 void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left, |
| 1943 Register right, | 1938 Register right, |
| 1944 Register overflow_dst, | 1939 Register overflow_dst, |
| 1945 Register scratch) { | 1940 Register scratch) { |
| 1946 DCHECK(!dst.is(overflow_dst)); | 1941 DCHECK(!dst.is(overflow_dst)); |
| 1947 DCHECK(!dst.is(scratch)); | 1942 DCHECK(!dst.is(scratch)); |
| 1948 DCHECK(!overflow_dst.is(scratch)); | 1943 DCHECK(!overflow_dst.is(scratch)); |
| 1949 DCHECK(!overflow_dst.is(left)); | 1944 DCHECK(!overflow_dst.is(left)); |
| 1950 DCHECK(!overflow_dst.is(right)); | 1945 DCHECK(!overflow_dst.is(right)); |
| 1951 | 1946 |
| 1947 // TODO(joransiu): Optimize paths for left == right. |
| 1952 bool left_is_right = left.is(right); | 1948 bool left_is_right = left.is(right); |
| 1953 RCBit xorRC = left_is_right ? SetRC : LeaveRC; | |
| 1954 | 1949 |
| 1955 // C = A+B; C overflows if A/B have same sign and C has diff sign than A | 1950 // C = A+B; C overflows if A/B have same sign and C has diff sign than A |
| 1956 if (dst.is(left)) { | 1951 if (dst.is(left)) { |
| 1957 mr(scratch, left); // Preserve left. | 1952 LoadRR(scratch, left); // Preserve left. |
| 1958 add(dst, left, right); // Left is overwritten. | 1953 AddP(dst, left, right); // Left is overwritten. |
| 1959 xor_(overflow_dst, dst, scratch, xorRC); // Original left. | 1954 XorP(overflow_dst, scratch, dst); // Original left. |
| 1960 if (!left_is_right) xor_(scratch, dst, right); | 1955 if (!left_is_right) XorP(scratch, dst, right); |
| 1961 } else if (dst.is(right)) { | 1956 } else if (dst.is(right)) { |
| 1962 mr(scratch, right); // Preserve right. | 1957 LoadRR(scratch, right); // Preserve right. |
| 1963 add(dst, left, right); // Right is overwritten. | 1958 AddP(dst, left, right); // Right is overwritten. |
| 1964 xor_(overflow_dst, dst, left, xorRC); | 1959 XorP(overflow_dst, dst, left); |
| 1965 if (!left_is_right) xor_(scratch, dst, scratch); // Original right. | 1960 if (!left_is_right) XorP(scratch, dst, scratch); |
| 1966 } else { | 1961 } else { |
| 1967 add(dst, left, right); | 1962 AddP(dst, left, right); |
| 1968 xor_(overflow_dst, dst, left, xorRC); | 1963 XorP(overflow_dst, dst, left); |
| 1969 if (!left_is_right) xor_(scratch, dst, right); | 1964 if (!left_is_right) XorP(scratch, dst, right); |
| 1970 } | 1965 } |
| 1971 if (!left_is_right) and_(overflow_dst, scratch, overflow_dst, SetRC); | 1966 if (!left_is_right) AndP(overflow_dst, scratch, overflow_dst); |
| 1967 LoadAndTestRR(overflow_dst, overflow_dst); |
| 1972 } | 1968 } |
| 1973 | 1969 |
| 1974 | |
| 1975 void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left, | 1970 void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left, |
| 1976 intptr_t right, | 1971 intptr_t right, |
| 1977 Register overflow_dst, | 1972 Register overflow_dst, |
| 1978 Register scratch) { | 1973 Register scratch) { |
| 1979 Register original_left = left; | |
| 1980 DCHECK(!dst.is(overflow_dst)); | 1974 DCHECK(!dst.is(overflow_dst)); |
| 1981 DCHECK(!dst.is(scratch)); | 1975 DCHECK(!dst.is(scratch)); |
| 1982 DCHECK(!overflow_dst.is(scratch)); | 1976 DCHECK(!overflow_dst.is(scratch)); |
| 1983 DCHECK(!overflow_dst.is(left)); | 1977 DCHECK(!overflow_dst.is(left)); |
| 1984 | 1978 |
| 1985 // C = A+B; C overflows if A/B have same sign and C has diff sign than A | 1979 mov(r1, Operand(right)); |
| 1986 if (dst.is(left)) { | 1980 AddAndCheckForOverflow(dst, left, r1, overflow_dst, scratch); |
| 1987 // Preserve left. | |
| 1988 original_left = overflow_dst; | |
| 1989 mr(original_left, left); | |
| 1990 } | |
| 1991 Add(dst, left, right, scratch); | |
| 1992 xor_(overflow_dst, dst, original_left); | |
| 1993 if (right >= 0) { | |
| 1994 and_(overflow_dst, overflow_dst, dst, SetRC); | |
| 1995 } else { | |
| 1996 andc(overflow_dst, overflow_dst, dst, SetRC); | |
| 1997 } | |
| 1998 } | 1981 } |
| 1999 | 1982 |
| 2000 | |
| 2001 void MacroAssembler::SubAndCheckForOverflow(Register dst, Register left, | 1983 void MacroAssembler::SubAndCheckForOverflow(Register dst, Register left, |
| 2002 Register right, | 1984 Register right, |
| 2003 Register overflow_dst, | 1985 Register overflow_dst, |
| 2004 Register scratch) { | 1986 Register scratch) { |
| 2005 DCHECK(!dst.is(overflow_dst)); | 1987 DCHECK(!dst.is(overflow_dst)); |
| 2006 DCHECK(!dst.is(scratch)); | 1988 DCHECK(!dst.is(scratch)); |
| 2007 DCHECK(!overflow_dst.is(scratch)); | 1989 DCHECK(!overflow_dst.is(scratch)); |
| 2008 DCHECK(!overflow_dst.is(left)); | 1990 DCHECK(!overflow_dst.is(left)); |
| 2009 DCHECK(!overflow_dst.is(right)); | 1991 DCHECK(!overflow_dst.is(right)); |
| 2010 | 1992 |
| 2011 // C = A-B; C overflows if A/B have diff signs and C has diff sign than A | 1993 // C = A-B; C overflows if A/B have diff signs and C has diff sign than A |
| 2012 if (dst.is(left)) { | 1994 if (dst.is(left)) { |
| 2013 mr(scratch, left); // Preserve left. | 1995 LoadRR(scratch, left); // Preserve left. |
| 2014 sub(dst, left, right); // Left is overwritten. | 1996 SubP(dst, left, right); // Left is overwritten. |
| 2015 xor_(overflow_dst, dst, scratch); | 1997 XorP(overflow_dst, dst, scratch); |
| 2016 xor_(scratch, scratch, right); | 1998 XorP(scratch, right); |
| 2017 and_(overflow_dst, overflow_dst, scratch, SetRC); | 1999 AndP(overflow_dst, scratch /*, SetRC*/); |
| 2000 LoadAndTestRR(overflow_dst, overflow_dst); |
| 2001 // Should be okay to remove rc |
| 2018 } else if (dst.is(right)) { | 2002 } else if (dst.is(right)) { |
| 2019 mr(scratch, right); // Preserve right. | 2003 LoadRR(scratch, right); // Preserve right. |
| 2020 sub(dst, left, right); // Right is overwritten. | 2004 SubP(dst, left, right); // Right is overwritten. |
| 2021 xor_(overflow_dst, dst, left); | 2005 XorP(overflow_dst, dst, left); |
| 2022 xor_(scratch, left, scratch); | 2006 XorP(scratch, left); |
| 2023 and_(overflow_dst, overflow_dst, scratch, SetRC); | 2007 AndP(overflow_dst, scratch /*, SetRC*/); |
| 2008 LoadAndTestRR(overflow_dst, overflow_dst); |
| 2009 // Should be okay to remove rc |
| 2024 } else { | 2010 } else { |
| 2025 sub(dst, left, right); | 2011 SubP(dst, left, right); |
| 2026 xor_(overflow_dst, dst, left); | 2012 XorP(overflow_dst, dst, left); |
| 2027 xor_(scratch, left, right); | 2013 XorP(scratch, left, right); |
| 2028 and_(overflow_dst, scratch, overflow_dst, SetRC); | 2014 AndP(overflow_dst, scratch /*, SetRC*/); |
| 2015 LoadAndTestRR(overflow_dst, overflow_dst); |
| 2016 // Should be okay to remove rc |
| 2029 } | 2017 } |
| 2030 } | 2018 } |
| 2031 | 2019 |
| 2032 | |
| 2033 void MacroAssembler::CompareMap(Register obj, Register scratch, Handle<Map> map, | 2020 void MacroAssembler::CompareMap(Register obj, Register scratch, Handle<Map> map, |
| 2034 Label* early_success) { | 2021 Label* early_success) { |
| 2035 LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); | 2022 LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); |
| 2036 CompareMap(scratch, map, early_success); | 2023 CompareMap(obj, map, early_success); |
| 2037 } | 2024 } |
| 2038 | 2025 |
| 2039 | |
| 2040 void MacroAssembler::CompareMap(Register obj_map, Handle<Map> map, | 2026 void MacroAssembler::CompareMap(Register obj_map, Handle<Map> map, |
| 2041 Label* early_success) { | 2027 Label* early_success) { |
| 2042 mov(r0, Operand(map)); | 2028 mov(r0, Operand(map)); |
| 2043 cmp(obj_map, r0); | 2029 CmpP(r0, FieldMemOperand(obj_map, HeapObject::kMapOffset)); |
| 2044 } | 2030 } |
| 2045 | 2031 |
| 2046 | |
| 2047 void MacroAssembler::CheckMap(Register obj, Register scratch, Handle<Map> map, | 2032 void MacroAssembler::CheckMap(Register obj, Register scratch, Handle<Map> map, |
| 2048 Label* fail, SmiCheckType smi_check_type) { | 2033 Label* fail, SmiCheckType smi_check_type) { |
| 2049 if (smi_check_type == DO_SMI_CHECK) { | 2034 if (smi_check_type == DO_SMI_CHECK) { |
| 2050 JumpIfSmi(obj, fail); | 2035 JumpIfSmi(obj, fail); |
| 2051 } | 2036 } |
| 2052 | 2037 |
| 2053 Label success; | 2038 Label success; |
| 2054 CompareMap(obj, scratch, map, &success); | 2039 CompareMap(obj, scratch, map, &success); |
| 2055 bne(fail); | 2040 bne(fail); |
| 2056 bind(&success); | 2041 bind(&success); |
| 2057 } | 2042 } |
| 2058 | 2043 |
| 2059 | |
| 2060 void MacroAssembler::CheckMap(Register obj, Register scratch, | 2044 void MacroAssembler::CheckMap(Register obj, Register scratch, |
| 2061 Heap::RootListIndex index, Label* fail, | 2045 Heap::RootListIndex index, Label* fail, |
| 2062 SmiCheckType smi_check_type) { | 2046 SmiCheckType smi_check_type) { |
| 2063 if (smi_check_type == DO_SMI_CHECK) { | 2047 if (smi_check_type == DO_SMI_CHECK) { |
| 2064 JumpIfSmi(obj, fail); | 2048 JumpIfSmi(obj, fail); |
| 2065 } | 2049 } |
| 2066 LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); | 2050 LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); |
| 2067 LoadRoot(r0, index); | 2051 CompareRoot(scratch, index); |
| 2068 cmp(scratch, r0); | |
| 2069 bne(fail); | 2052 bne(fail); |
| 2070 } | 2053 } |
| 2071 | 2054 |
| 2072 | |
| 2073 void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1, | 2055 void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1, |
| 2074 Register scratch2, Handle<WeakCell> cell, | 2056 Register scratch2, Handle<WeakCell> cell, |
| 2075 Handle<Code> success, | 2057 Handle<Code> success, |
| 2076 SmiCheckType smi_check_type) { | 2058 SmiCheckType smi_check_type) { |
| 2077 Label fail; | 2059 Label fail; |
| 2078 if (smi_check_type == DO_SMI_CHECK) { | 2060 if (smi_check_type == DO_SMI_CHECK) { |
| 2079 JumpIfSmi(obj, &fail); | 2061 JumpIfSmi(obj, &fail); |
| 2080 } | 2062 } |
| 2081 LoadP(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset)); | 2063 LoadP(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset)); |
| 2082 CmpWeakValue(scratch1, cell, scratch2); | 2064 CmpWeakValue(scratch1, cell, scratch2); |
| 2083 Jump(success, RelocInfo::CODE_TARGET, eq); | 2065 Jump(success, RelocInfo::CODE_TARGET, eq); |
| 2084 bind(&fail); | 2066 bind(&fail); |
| 2085 } | 2067 } |
| 2086 | 2068 |
| 2087 | |
| 2088 void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell, | 2069 void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell, |
| 2089 Register scratch, CRegister cr) { | 2070 Register scratch, CRegister) { |
| 2090 mov(scratch, Operand(cell)); | 2071 mov(scratch, Operand(cell)); |
| 2091 LoadP(scratch, FieldMemOperand(scratch, WeakCell::kValueOffset)); | 2072 CmpP(value, FieldMemOperand(scratch, WeakCell::kValueOffset)); |
| 2092 cmp(value, scratch, cr); | |
| 2093 } | 2073 } |
| 2094 | 2074 |
| 2095 | |
| 2096 void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) { | 2075 void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) { |
| 2097 mov(value, Operand(cell)); | 2076 mov(value, Operand(cell)); |
| 2098 LoadP(value, FieldMemOperand(value, WeakCell::kValueOffset)); | 2077 LoadP(value, FieldMemOperand(value, WeakCell::kValueOffset)); |
| 2099 } | 2078 } |
| 2100 | 2079 |
| 2101 | |
| 2102 void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell, | 2080 void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell, |
| 2103 Label* miss) { | 2081 Label* miss) { |
| 2104 GetWeakValue(value, cell); | 2082 GetWeakValue(value, cell); |
| 2105 JumpIfSmi(value, miss); | 2083 JumpIfSmi(value, miss); |
| 2106 } | 2084 } |
| 2107 | 2085 |
| 2108 | |
| 2109 void MacroAssembler::GetMapConstructor(Register result, Register map, | 2086 void MacroAssembler::GetMapConstructor(Register result, Register map, |
| 2110 Register temp, Register temp2) { | 2087 Register temp, Register temp2) { |
| 2111 Label done, loop; | 2088 Label done, loop; |
| 2112 LoadP(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset)); | 2089 LoadP(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset)); |
| 2113 bind(&loop); | 2090 bind(&loop); |
| 2114 JumpIfSmi(result, &done); | 2091 JumpIfSmi(result, &done); |
| 2115 CompareObjectType(result, temp, temp2, MAP_TYPE); | 2092 CompareObjectType(result, temp, temp2, MAP_TYPE); |
| 2116 bne(&done); | 2093 bne(&done); |
| 2117 LoadP(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset)); | 2094 LoadP(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset)); |
| 2118 b(&loop); | 2095 b(&loop); |
| 2119 bind(&done); | 2096 bind(&done); |
| 2120 } | 2097 } |
| 2121 | 2098 |
| 2122 | |
| 2123 void MacroAssembler::TryGetFunctionPrototype(Register function, Register result, | 2099 void MacroAssembler::TryGetFunctionPrototype(Register function, Register result, |
| 2124 Register scratch, Label* miss) { | 2100 Register scratch, Label* miss) { |
| 2125 // Get the prototype or initial map from the function. | 2101 // Get the prototype or initial map from the function. |
| 2126 LoadP(result, | 2102 LoadP(result, |
| 2127 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 2103 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
| 2128 | 2104 |
| 2129 // If the prototype or initial map is the hole, don't return it and | 2105 // If the prototype or initial map is the hole, don't return it and |
| 2130 // simply miss the cache instead. This will allow us to allocate a | 2106 // simply miss the cache instead. This will allow us to allocate a |
| 2131 // prototype object on-demand in the runtime system. | 2107 // prototype object on-demand in the runtime system. |
| 2132 LoadRoot(r0, Heap::kTheHoleValueRootIndex); | 2108 CompareRoot(result, Heap::kTheHoleValueRootIndex); |
| 2133 cmp(result, r0); | |
| 2134 beq(miss); | 2109 beq(miss); |
| 2135 | 2110 |
| 2136 // If the function does not have an initial map, we're done. | 2111 // If the function does not have an initial map, we're done. |
| 2137 Label done; | 2112 Label done; |
| 2138 CompareObjectType(result, scratch, scratch, MAP_TYPE); | 2113 CompareObjectType(result, scratch, scratch, MAP_TYPE); |
| 2139 bne(&done); | 2114 bne(&done, Label::kNear); |
| 2140 | 2115 |
| 2141 // Get the prototype from the initial map. | 2116 // Get the prototype from the initial map. |
| 2142 LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset)); | 2117 LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset)); |
| 2143 | 2118 |
| 2144 // All done. | 2119 // All done. |
| 2145 bind(&done); | 2120 bind(&done); |
| 2146 } | 2121 } |
| 2147 | 2122 |
| 2148 | |
| 2149 void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id, | 2123 void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id, |
| 2150 Condition cond) { | 2124 Condition cond) { |
| 2151 DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. | 2125 DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. |
| 2152 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, cond); | 2126 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, cond); |
| 2153 } | 2127 } |
| 2154 | 2128 |
| 2155 | |
| 2156 void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) { | 2129 void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) { |
| 2157 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond); | 2130 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond); |
| 2158 } | 2131 } |
| 2159 | 2132 |
| 2160 | |
| 2161 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { | 2133 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { |
| 2162 return has_frame_ || !stub->SometimesSetsUpAFrame(); | 2134 return has_frame_ || !stub->SometimesSetsUpAFrame(); |
| 2163 } | 2135 } |
| 2164 | 2136 |
| 2165 | |
| 2166 void MacroAssembler::IndexFromHash(Register hash, Register index) { | 2137 void MacroAssembler::IndexFromHash(Register hash, Register index) { |
| 2167 // If the hash field contains an array index pick it out. The assert checks | 2138 // If the hash field contains an array index pick it out. The assert checks |
| 2168 // that the constants for the maximum number of digits for an array index | 2139 // that the constants for the maximum number of digits for an array index |
| 2169 // cached in the hash field and the number of bits reserved for it does not | 2140 // cached in the hash field and the number of bits reserved for it does not |
| 2170 // conflict. | 2141 // conflict. |
| 2171 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) < | 2142 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) < |
| 2172 (1 << String::kArrayIndexValueBits)); | 2143 (1 << String::kArrayIndexValueBits)); |
| 2173 DecodeFieldToSmi<String::ArrayIndexValueBits>(index, hash); | 2144 DecodeFieldToSmi<String::ArrayIndexValueBits>(index, hash); |
| 2174 } | 2145 } |
| 2175 | 2146 |
| 2176 | |
| 2177 void MacroAssembler::SmiToDouble(DoubleRegister value, Register smi) { | |
| 2178 SmiUntag(ip, smi); | |
| 2179 ConvertIntToDouble(ip, value); | |
| 2180 } | |
| 2181 | |
| 2182 | |
| 2183 void MacroAssembler::TestDoubleIsInt32(DoubleRegister double_input, | 2147 void MacroAssembler::TestDoubleIsInt32(DoubleRegister double_input, |
| 2184 Register scratch1, Register scratch2, | 2148 Register scratch1, Register scratch2, |
| 2185 DoubleRegister double_scratch) { | 2149 DoubleRegister double_scratch) { |
| 2186 TryDoubleToInt32Exact(scratch1, double_input, scratch2, double_scratch); | 2150 TryDoubleToInt32Exact(scratch1, double_input, scratch2, double_scratch); |
| 2187 } | 2151 } |
| 2188 | 2152 |
| 2189 void MacroAssembler::TestDoubleIsMinusZero(DoubleRegister input, | 2153 void MacroAssembler::TestDoubleIsMinusZero(DoubleRegister input, |
| 2190 Register scratch1, | 2154 Register scratch1, |
| 2191 Register scratch2) { | 2155 Register scratch2) { |
| 2192 #if V8_TARGET_ARCH_PPC64 | 2156 lgdr(scratch1, input); |
| 2193 MovDoubleToInt64(scratch1, input); | 2157 #if V8_TARGET_ARCH_S390X |
| 2194 rotldi(scratch1, scratch1, 1); | 2158 llihf(scratch2, Operand(0x80000000)); // scratch2 = 0x80000000_00000000 |
| 2195 cmpi(scratch1, Operand(1)); | 2159 CmpP(scratch1, scratch2); |
| 2196 #else | 2160 #else |
| 2197 MovDoubleToInt64(scratch1, scratch2, input); | |
| 2198 Label done; | 2161 Label done; |
| 2199 cmpi(scratch2, Operand::Zero()); | 2162 CmpP(scratch1, Operand::Zero()); |
| 2200 bne(&done); | 2163 bne(&done, Label::kNear); |
| 2201 lis(scratch2, Operand(SIGN_EXT_IMM16(0x8000))); | 2164 |
| 2202 cmp(scratch1, scratch2); | 2165 srlg(scratch1, scratch1, Operand(32)); |
| 2166 CmpP(scratch1, Operand(HeapNumber::kSignMask)); |
| 2203 bind(&done); | 2167 bind(&done); |
| 2204 #endif | 2168 #endif |
| 2205 } | 2169 } |
| 2206 | 2170 |
| 2207 void MacroAssembler::TestDoubleSign(DoubleRegister input, Register scratch) { | 2171 void MacroAssembler::TestDoubleSign(DoubleRegister input, Register scratch) { |
| 2208 #if V8_TARGET_ARCH_PPC64 | 2172 stdy(input, MemOperand(sp, -kDoubleSize)); |
| 2209 MovDoubleToInt64(scratch, input); | 2173 LoadlW(scratch, MemOperand(sp, -kDoubleSize + Register::kExponentOffset)); |
| 2210 #else | 2174 Cmp32(scratch, Operand::Zero()); |
| 2211 MovDoubleHighToInt(scratch, input); | |
| 2212 #endif | |
| 2213 cmpi(scratch, Operand::Zero()); | |
| 2214 } | 2175 } |
| 2215 | 2176 |
| 2216 void MacroAssembler::TestHeapNumberSign(Register input, Register scratch) { | 2177 void MacroAssembler::TestHeapNumberSign(Register input, Register scratch) { |
| 2217 #if V8_TARGET_ARCH_PPC64 | 2178 LoadlW(scratch, FieldMemOperand(input, HeapNumber::kValueOffset + |
| 2218 LoadP(scratch, FieldMemOperand(input, HeapNumber::kValueOffset)); | 2179 Register::kExponentOffset)); |
| 2219 #else | 2180 Cmp32(scratch, Operand::Zero()); |
| 2220 lwz(scratch, FieldMemOperand(input, HeapNumber::kExponentOffset)); | |
| 2221 #endif | |
| 2222 cmpi(scratch, Operand::Zero()); | |
| 2223 } | 2181 } |
| 2224 | 2182 |
| 2225 void MacroAssembler::TryDoubleToInt32Exact(Register result, | 2183 void MacroAssembler::TryDoubleToInt32Exact(Register result, |
| 2226 DoubleRegister double_input, | 2184 DoubleRegister double_input, |
| 2227 Register scratch, | 2185 Register scratch, |
| 2228 DoubleRegister double_scratch) { | 2186 DoubleRegister double_scratch) { |
| 2229 Label done; | 2187 Label done; |
| 2230 DCHECK(!double_input.is(double_scratch)); | 2188 DCHECK(!double_input.is(double_scratch)); |
| 2231 | 2189 |
| 2232 ConvertDoubleToInt64(double_input, | 2190 ConvertDoubleToInt64(double_input, |
| 2233 #if !V8_TARGET_ARCH_PPC64 | 2191 #if !V8_TARGET_ARCH_S390X |
| 2234 scratch, | 2192 scratch, |
| 2235 #endif | 2193 #endif |
| 2236 result, double_scratch); | 2194 result, double_scratch); |
| 2237 | 2195 |
| 2238 #if V8_TARGET_ARCH_PPC64 | 2196 #if V8_TARGET_ARCH_S390X |
| 2239 TestIfInt32(result, r0); | 2197 TestIfInt32(result, r0); |
| 2240 #else | 2198 #else |
| 2241 TestIfInt32(scratch, result, r0); | 2199 TestIfInt32(scratch, result, r0); |
| 2242 #endif | 2200 #endif |
| 2243 bne(&done); | 2201 bne(&done); |
| 2244 | 2202 |
| 2245 // convert back and compare | 2203 // convert back and compare |
| 2246 fcfid(double_scratch, double_scratch); | 2204 lgdr(scratch, double_scratch); |
| 2247 fcmpu(double_scratch, double_input); | 2205 cdfbr(double_scratch, scratch); |
| 2206 cdbr(double_scratch, double_input); |
| 2248 bind(&done); | 2207 bind(&done); |
| 2249 } | 2208 } |
| 2250 | 2209 |
| 2251 | |
| 2252 void MacroAssembler::TryInt32Floor(Register result, DoubleRegister double_input, | 2210 void MacroAssembler::TryInt32Floor(Register result, DoubleRegister double_input, |
| 2253 Register input_high, Register scratch, | 2211 Register input_high, Register scratch, |
| 2254 DoubleRegister double_scratch, Label* done, | 2212 DoubleRegister double_scratch, Label* done, |
| 2255 Label* exact) { | 2213 Label* exact) { |
| 2256 DCHECK(!result.is(input_high)); | 2214 DCHECK(!result.is(input_high)); |
| 2257 DCHECK(!double_input.is(double_scratch)); | 2215 DCHECK(!double_input.is(double_scratch)); |
| 2258 Label exception; | 2216 Label exception; |
| 2259 | 2217 |
| 2260 MovDoubleHighToInt(input_high, double_input); | 2218 // Move high word into input_high |
| 2219 StoreDouble(double_input, MemOperand(sp, -kDoubleSize)); |
| 2220 lay(sp, MemOperand(sp, -kDoubleSize)); |
| 2221 LoadlW(input_high, MemOperand(sp, Register::kExponentOffset)); |
| 2222 la(sp, MemOperand(sp, kDoubleSize)); |
| 2261 | 2223 |
| 2262 // Test for NaN/Inf | 2224 // Test for NaN/Inf |
| 2263 ExtractBitMask(result, input_high, HeapNumber::kExponentMask); | 2225 ExtractBitMask(result, input_high, HeapNumber::kExponentMask); |
| 2264 cmpli(result, Operand(0x7ff)); | 2226 CmpLogicalP(result, Operand(0x7ff)); |
| 2265 beq(&exception); | 2227 beq(&exception); |
| 2266 | 2228 |
| 2267 // Convert (rounding to -Inf) | 2229 // Convert (rounding to -Inf) |
| 2268 ConvertDoubleToInt64(double_input, | 2230 ConvertDoubleToInt64(double_input, |
| 2269 #if !V8_TARGET_ARCH_PPC64 | 2231 #if !V8_TARGET_ARCH_S390X |
| 2270 scratch, | 2232 scratch, |
| 2271 #endif | 2233 #endif |
| 2272 result, double_scratch, kRoundToMinusInf); | 2234 result, double_scratch, kRoundToMinusInf); |
| 2273 | 2235 |
| 2274 // Test for overflow | 2236 // Test for overflow |
| 2275 #if V8_TARGET_ARCH_PPC64 | 2237 #if V8_TARGET_ARCH_S390X |
| 2276 TestIfInt32(result, r0); | 2238 TestIfInt32(result, r0); |
| 2277 #else | 2239 #else |
| 2278 TestIfInt32(scratch, result, r0); | 2240 TestIfInt32(scratch, result, r0); |
| 2279 #endif | 2241 #endif |
| 2280 bne(&exception); | 2242 bne(&exception); |
| 2281 | 2243 |
| 2282 // Test for exactness | 2244 // Test for exactness |
| 2283 fcfid(double_scratch, double_scratch); | 2245 lgdr(scratch, double_scratch); |
| 2284 fcmpu(double_scratch, double_input); | 2246 cdfbr(double_scratch, scratch); |
| 2247 cdbr(double_scratch, double_input); |
| 2285 beq(exact); | 2248 beq(exact); |
| 2286 b(done); | 2249 b(done); |
| 2287 | 2250 |
| 2288 bind(&exception); | 2251 bind(&exception); |
| 2289 } | 2252 } |
| 2290 | 2253 |
| 2254 void MacroAssembler::FloatCeiling32(DoubleRegister double_output, |
| 2255 DoubleRegister double_input, |
| 2256 Register scratch, |
| 2257 DoubleRegister double_scratch) { |
| 2258 Label not_zero, no_nan_inf, done, do_ceil; |
| 2259 Register scratch2 = r0; |
| 2260 |
| 2261 // Move high word into scratch |
| 2262 MovFloatToInt(scratch, double_input); |
| 2263 |
| 2264 // Test for NaN/Inf which results in NaN/Inf respectively |
| 2265 static const uint32_t float32ExponentMask = 0x7f800000u; |
| 2266 ExtractBitMask(scratch2, scratch, float32ExponentMask); |
| 2267 CmpLogical32(scratch2, Operand(0xff)); |
| 2268 bne(&no_nan_inf, Label::kNear); |
| 2269 Move(double_output, double_input); |
| 2270 b(&done); |
| 2271 bind(&no_nan_inf); |
| 2272 |
| 2273 // Test for double_input in (-1, -0) which results in -0 |
| 2274 LoadFloat32Literal(double_scratch, -1.0, scratch2); |
| 2275 cebr(double_input, double_scratch); |
| 2276 ble(&do_ceil, Label::kNear); |
| 2277 Cmp32(scratch, Operand::Zero()); |
| 2278 bgt(&do_ceil, Label::kNear); |
| 2279 bne(¬_zero, Label::kNear); |
| 2280 |
| 2281 // double_input = +/- 0 which results in +/- 0 respectively |
| 2282 Move(double_output, double_input); |
| 2283 b(&done); |
| 2284 bind(¬_zero); |
| 2285 |
| 2286 // double_output = -0 |
| 2287 llihf(scratch2, Operand(0x80000000)); |
| 2288 ldgr(double_output, scratch2); |
| 2289 b(&done); |
| 2290 bind(&do_ceil); |
| 2291 |
| 2292 // Regular case |
| 2293 // cgdbr(Condition(6), scratch, double_input); |
| 2294 // cdfbr(double_output, scratch); |
| 2295 fiebra(double_output, double_input, FIDBRA_ROUND_TOWARD_POS_INF); |
| 2296 bind(&done); |
| 2297 } |
| 2298 |
| 2299 void MacroAssembler::FloatFloor32(DoubleRegister double_output, |
| 2300 DoubleRegister double_input, |
| 2301 Register scratch) { |
| 2302 Label not_zero, no_nan_inf, done, do_floor; |
| 2303 Register scratch2 = r0; |
| 2304 |
| 2305 // Move high word into scratch |
| 2306 MovFloatToInt(scratch, double_input); |
| 2307 |
| 2308 // Test for NaN/Inf which results in NaN/Inf respectively |
| 2309 static const uint32_t float32ExponentMask = 0x7f800000u; |
| 2310 ExtractBitMask(scratch2, scratch, float32ExponentMask); |
| 2311 CmpLogical32(scratch2, Operand(0xff)); |
| 2312 bne(&no_nan_inf, Label::kNear); |
| 2313 Move(double_output, double_input); |
| 2314 b(&done); |
| 2315 bind(&no_nan_inf); |
| 2316 |
| 2317 // Test for double_input=+/- 0 which results in +/- 0 respectively |
| 2318 ltebr(double_input, double_input); |
| 2319 bne(&do_floor, Label::kNear); |
| 2320 Move(double_output, double_input); |
| 2321 b(&done); |
| 2322 bind(&do_floor); |
| 2323 |
| 2324 // Regular case |
| 2325 // cgdbr(Condition(7), scratch, double_input); |
| 2326 // cdfbr(double_output, scratch); |
| 2327 fiebra(double_output, double_input, FIDBRA_ROUND_TOWARD_NEG_INF); |
| 2328 bind(&done); |
| 2329 } |
| 2330 |
| 2331 void MacroAssembler::FloatCeiling64(DoubleRegister double_output, |
| 2332 DoubleRegister double_input, |
| 2333 Register scratch, |
| 2334 DoubleRegister double_scratch) { |
| 2335 Label not_zero, no_nan_inf, done, do_ceil; |
| 2336 Register scratch2 = r0; |
| 2337 |
| 2338 // Move high word into scratch |
| 2339 StoreDouble(double_input, MemOperand(sp, -kDoubleSize)); |
| 2340 LoadlW(scratch, MemOperand(sp, -kDoubleSize + Register::kExponentOffset)); |
| 2341 |
| 2342 // Test for NaN/Inf which results in NaN/Inf respectively |
| 2343 ExtractBitMask(scratch2, scratch, HeapNumber::kExponentMask); |
| 2344 CmpLogicalP(scratch2, Operand(0x7ff)); |
| 2345 bne(&no_nan_inf, Label::kNear); |
| 2346 Move(double_output, double_input); |
| 2347 b(&done); |
| 2348 bind(&no_nan_inf); |
| 2349 |
| 2350 // Test for double_input in (-1, -0) which results in -0 |
| 2351 LoadDoubleLiteral(double_scratch, -1.0, scratch2); |
| 2352 cdbr(double_input, double_scratch); |
| 2353 ble(&do_ceil, Label::kNear); |
| 2354 Cmp32(scratch, Operand::Zero()); |
| 2355 bgt(&do_ceil, Label::kNear); |
| 2356 bne(¬_zero, Label::kNear); |
| 2357 |
| 2358 // double_input = +/- 0 which results in +/- 0 respectively |
| 2359 Move(double_output, double_input); |
| 2360 b(&done); |
| 2361 bind(¬_zero); |
| 2362 |
| 2363 // double_output = -0 |
| 2364 llihf(scratch2, Operand(0x80000000)); |
| 2365 ldgr(double_output, scratch2); |
| 2366 b(&done); |
| 2367 bind(&do_ceil); |
| 2368 |
| 2369 // Regular case |
| 2370 // cgdbr(Condition(6), scratch, double_input); |
| 2371 // cdfbr(double_output, scratch); |
| 2372 fidbra(double_output, double_input, FIDBRA_ROUND_TOWARD_POS_INF); |
| 2373 bind(&done); |
| 2374 } |
| 2375 |
| 2376 void MacroAssembler::FloatFloor64(DoubleRegister double_output, |
| 2377 DoubleRegister double_input, |
| 2378 Register scratch) { |
| 2379 Label not_zero, no_nan_inf, done, do_floor; |
| 2380 Register scratch2 = r0; |
| 2381 |
| 2382 // Move high word into scratch |
| 2383 StoreDouble(double_input, MemOperand(sp, -kDoubleSize)); |
| 2384 LoadlW(scratch, MemOperand(sp, -kDoubleSize + Register::kExponentOffset)); |
| 2385 |
| 2386 // Test for NaN/Inf which results in NaN/Inf respectively |
| 2387 ExtractBitMask(scratch2, scratch, HeapNumber::kExponentMask); |
| 2388 CmpLogicalP(scratch2, Operand(0x7ff)); |
| 2389 bne(&no_nan_inf, Label::kNear); |
| 2390 Move(double_output, double_input); |
| 2391 b(&done); |
| 2392 bind(&no_nan_inf); |
| 2393 |
| 2394 // Test for double_input=+/- 0 which results in +/- 0 respectively |
| 2395 ltdbr(double_input, double_input); |
| 2396 bne(&do_floor, Label::kNear); |
| 2397 Move(double_output, double_input); |
| 2398 b(&done); |
| 2399 bind(&do_floor); |
| 2400 |
| 2401 // Regular case |
| 2402 // cgdbr(Condition(7), scratch, double_input); |
| 2403 // cdfbr(double_output, scratch); |
| 2404 fidbra(double_output, double_input, FIDBRA_ROUND_TOWARD_NEG_INF); |
| 2405 bind(&done); |
| 2406 } |
| 2291 | 2407 |
| 2292 void MacroAssembler::TryInlineTruncateDoubleToI(Register result, | 2408 void MacroAssembler::TryInlineTruncateDoubleToI(Register result, |
| 2293 DoubleRegister double_input, | 2409 DoubleRegister double_input, |
| 2294 Label* done) { | 2410 Label* done) { |
| 2295 DoubleRegister double_scratch = kScratchDoubleReg; | 2411 DoubleRegister double_scratch = kScratchDoubleReg; |
| 2296 #if !V8_TARGET_ARCH_PPC64 | 2412 #if !V8_TARGET_ARCH_S390X |
| 2297 Register scratch = ip; | 2413 Register scratch = ip; |
| 2298 #endif | 2414 #endif |
| 2299 | 2415 |
| 2300 ConvertDoubleToInt64(double_input, | 2416 ConvertDoubleToInt64(double_input, |
| 2301 #if !V8_TARGET_ARCH_PPC64 | 2417 #if !V8_TARGET_ARCH_S390X |
| 2302 scratch, | 2418 scratch, |
| 2303 #endif | 2419 #endif |
| 2304 result, double_scratch); | 2420 result, double_scratch); |
| 2305 | 2421 |
| 2306 // Test for overflow | 2422 // Test for overflow |
| 2307 #if V8_TARGET_ARCH_PPC64 | 2423 #if V8_TARGET_ARCH_S390X |
| 2308 TestIfInt32(result, r0); | 2424 TestIfInt32(result, r0); |
| 2309 #else | 2425 #else |
| 2310 TestIfInt32(scratch, result, r0); | 2426 TestIfInt32(scratch, result, r0); |
| 2311 #endif | 2427 #endif |
| 2312 beq(done); | 2428 beq(done); |
| 2313 } | 2429 } |
| 2314 | 2430 |
| 2315 | |
| 2316 void MacroAssembler::TruncateDoubleToI(Register result, | 2431 void MacroAssembler::TruncateDoubleToI(Register result, |
| 2317 DoubleRegister double_input) { | 2432 DoubleRegister double_input) { |
| 2318 Label done; | 2433 Label done; |
| 2319 | 2434 |
| 2320 TryInlineTruncateDoubleToI(result, double_input, &done); | 2435 TryInlineTruncateDoubleToI(result, double_input, &done); |
| 2321 | 2436 |
| 2322 // If we fell through then inline version didn't succeed - call stub instead. | 2437 // If we fell through then inline version didn't succeed - call stub instead. |
| 2323 mflr(r0); | 2438 push(r14); |
| 2324 push(r0); | |
| 2325 // Put input on stack. | 2439 // Put input on stack. |
| 2326 stfdu(double_input, MemOperand(sp, -kDoubleSize)); | 2440 StoreDouble(double_input, MemOperand(sp, -kDoubleSize)); |
| 2441 lay(sp, MemOperand(sp, -kDoubleSize)); |
| 2327 | 2442 |
| 2328 DoubleToIStub stub(isolate(), sp, result, 0, true, true); | 2443 DoubleToIStub stub(isolate(), sp, result, 0, true, true); |
| 2329 CallStub(&stub); | 2444 CallStub(&stub); |
| 2330 | 2445 |
| 2331 addi(sp, sp, Operand(kDoubleSize)); | 2446 la(sp, MemOperand(sp, kDoubleSize)); |
| 2332 pop(r0); | 2447 pop(r14); |
| 2333 mtlr(r0); | |
| 2334 | 2448 |
| 2335 bind(&done); | 2449 bind(&done); |
| 2336 } | 2450 } |
| 2337 | 2451 |
| 2338 | |
| 2339 void MacroAssembler::TruncateHeapNumberToI(Register result, Register object) { | 2452 void MacroAssembler::TruncateHeapNumberToI(Register result, Register object) { |
| 2340 Label done; | 2453 Label done; |
| 2341 DoubleRegister double_scratch = kScratchDoubleReg; | 2454 DoubleRegister double_scratch = kScratchDoubleReg; |
| 2342 DCHECK(!result.is(object)); | 2455 DCHECK(!result.is(object)); |
| 2343 | 2456 |
| 2344 lfd(double_scratch, FieldMemOperand(object, HeapNumber::kValueOffset)); | 2457 LoadDouble(double_scratch, FieldMemOperand(object, HeapNumber::kValueOffset)); |
| 2345 TryInlineTruncateDoubleToI(result, double_scratch, &done); | 2458 TryInlineTruncateDoubleToI(result, double_scratch, &done); |
| 2346 | 2459 |
| 2347 // If we fell through then inline version didn't succeed - call stub instead. | 2460 // If we fell through then inline version didn't succeed - call stub instead. |
| 2348 mflr(r0); | 2461 push(r14); |
| 2349 push(r0); | |
| 2350 DoubleToIStub stub(isolate(), object, result, | 2462 DoubleToIStub stub(isolate(), object, result, |
| 2351 HeapNumber::kValueOffset - kHeapObjectTag, true, true); | 2463 HeapNumber::kValueOffset - kHeapObjectTag, true, true); |
| 2352 CallStub(&stub); | 2464 CallStub(&stub); |
| 2353 pop(r0); | 2465 pop(r14); |
| 2354 mtlr(r0); | |
| 2355 | 2466 |
| 2356 bind(&done); | 2467 bind(&done); |
| 2357 } | 2468 } |
| 2358 | 2469 |
| 2359 | |
| 2360 void MacroAssembler::TruncateNumberToI(Register object, Register result, | 2470 void MacroAssembler::TruncateNumberToI(Register object, Register result, |
| 2361 Register heap_number_map, | 2471 Register heap_number_map, |
| 2362 Register scratch1, Label* not_number) { | 2472 Register scratch1, Label* not_number) { |
| 2363 Label done; | 2473 Label done; |
| 2364 DCHECK(!result.is(object)); | 2474 DCHECK(!result.is(object)); |
| 2365 | 2475 |
| 2366 UntagAndJumpIfSmi(result, object, &done); | 2476 UntagAndJumpIfSmi(result, object, &done); |
| 2367 JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); | 2477 JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); |
| 2368 TruncateHeapNumberToI(result, object); | 2478 TruncateHeapNumberToI(result, object); |
| 2369 | 2479 |
| 2370 bind(&done); | 2480 bind(&done); |
| 2371 } | 2481 } |
| 2372 | 2482 |
| 2373 | |
| 2374 void MacroAssembler::GetLeastBitsFromSmi(Register dst, Register src, | 2483 void MacroAssembler::GetLeastBitsFromSmi(Register dst, Register src, |
| 2375 int num_least_bits) { | 2484 int num_least_bits) { |
| 2376 #if V8_TARGET_ARCH_PPC64 | 2485 if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) { |
| 2377 rldicl(dst, src, kBitsPerPointer - kSmiShift, | 2486 // We rotate by kSmiShift amount, and extract the num_least_bits |
| 2378 kBitsPerPointer - num_least_bits); | 2487 risbg(dst, src, Operand(64 - num_least_bits), Operand(63), |
| 2379 #else | 2488 Operand(64 - kSmiShift), true); |
| 2380 rlwinm(dst, src, kBitsPerPointer - kSmiShift, | 2489 } else { |
| 2381 kBitsPerPointer - num_least_bits, 31); | 2490 SmiUntag(dst, src); |
| 2382 #endif | 2491 AndP(dst, Operand((1 << num_least_bits) - 1)); |
| 2492 } |
| 2383 } | 2493 } |
| 2384 | 2494 |
| 2385 | |
| 2386 void MacroAssembler::GetLeastBitsFromInt32(Register dst, Register src, | 2495 void MacroAssembler::GetLeastBitsFromInt32(Register dst, Register src, |
| 2387 int num_least_bits) { | 2496 int num_least_bits) { |
| 2388 rlwinm(dst, src, 0, 32 - num_least_bits, 31); | 2497 AndP(dst, src, Operand((1 << num_least_bits) - 1)); |
| 2389 } | 2498 } |
| 2390 | 2499 |
| 2391 | |
| 2392 void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments, | 2500 void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments, |
| 2393 SaveFPRegsMode save_doubles) { | 2501 SaveFPRegsMode save_doubles) { |
| 2394 // All parameters are on the stack. r3 has the return value after call. | 2502 // All parameters are on the stack. r2 has the return value after call. |
| 2395 | 2503 |
| 2396 // If the expected number of arguments of the runtime function is | 2504 // If the expected number of arguments of the runtime function is |
| 2397 // constant, we check that the actual number of arguments match the | 2505 // constant, we check that the actual number of arguments match the |
| 2398 // expectation. | 2506 // expectation. |
| 2399 CHECK(f->nargs < 0 || f->nargs == num_arguments); | 2507 CHECK(f->nargs < 0 || f->nargs == num_arguments); |
| 2400 | 2508 |
| 2401 // TODO(1236192): Most runtime routines don't need the number of | 2509 // TODO(1236192): Most runtime routines don't need the number of |
| 2402 // arguments passed in because it is constant. At some point we | 2510 // arguments passed in because it is constant. At some point we |
| 2403 // should remove this need and make the runtime routine entry code | 2511 // should remove this need and make the runtime routine entry code |
| 2404 // smarter. | 2512 // smarter. |
| 2405 mov(r3, Operand(num_arguments)); | 2513 mov(r2, Operand(num_arguments)); |
| 2406 mov(r4, Operand(ExternalReference(f, isolate()))); | 2514 mov(r3, Operand(ExternalReference(f, isolate()))); |
| 2407 CEntryStub stub(isolate(), | 2515 CEntryStub stub(isolate(), |
| 2408 #if V8_TARGET_ARCH_PPC64 | 2516 #if V8_TARGET_ARCH_S390X |
| 2409 f->result_size, | 2517 f->result_size, |
| 2410 #else | 2518 #else |
| 2411 1, | 2519 1, |
| 2412 #endif | 2520 #endif |
| 2413 save_doubles); | 2521 save_doubles); |
| 2414 CallStub(&stub); | 2522 CallStub(&stub); |
| 2415 } | 2523 } |
| 2416 | 2524 |
| 2417 | |
| 2418 void MacroAssembler::CallExternalReference(const ExternalReference& ext, | 2525 void MacroAssembler::CallExternalReference(const ExternalReference& ext, |
| 2419 int num_arguments) { | 2526 int num_arguments) { |
| 2420 mov(r3, Operand(num_arguments)); | 2527 mov(r2, Operand(num_arguments)); |
| 2421 mov(r4, Operand(ext)); | 2528 mov(r3, Operand(ext)); |
| 2422 | 2529 |
| 2423 CEntryStub stub(isolate(), 1); | 2530 CEntryStub stub(isolate(), 1); |
| 2424 CallStub(&stub); | 2531 CallStub(&stub); |
| 2425 } | 2532 } |
| 2426 | 2533 |
| 2427 | |
| 2428 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) { | 2534 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) { |
| 2429 const Runtime::Function* function = Runtime::FunctionForId(fid); | 2535 const Runtime::Function* function = Runtime::FunctionForId(fid); |
| 2430 DCHECK_EQ(1, function->result_size); | 2536 DCHECK_EQ(1, function->result_size); |
| 2431 if (function->nargs >= 0) { | 2537 if (function->nargs >= 0) { |
| 2432 mov(r3, Operand(function->nargs)); | 2538 mov(r2, Operand(function->nargs)); |
| 2433 } | 2539 } |
| 2434 JumpToExternalReference(ExternalReference(fid, isolate())); | 2540 JumpToExternalReference(ExternalReference(fid, isolate())); |
| 2435 } | 2541 } |
| 2436 | 2542 |
| 2437 | |
| 2438 void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) { | 2543 void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) { |
| 2439 mov(r4, Operand(builtin)); | 2544 mov(r3, Operand(builtin)); |
| 2440 CEntryStub stub(isolate(), 1); | 2545 CEntryStub stub(isolate(), 1); |
| 2441 Jump(stub.GetCode(), RelocInfo::CODE_TARGET); | 2546 Jump(stub.GetCode(), RelocInfo::CODE_TARGET); |
| 2442 } | 2547 } |
| 2443 | 2548 |
| 2444 | |
| 2445 void MacroAssembler::SetCounter(StatsCounter* counter, int value, | 2549 void MacroAssembler::SetCounter(StatsCounter* counter, int value, |
| 2446 Register scratch1, Register scratch2) { | 2550 Register scratch1, Register scratch2) { |
| 2447 if (FLAG_native_code_counters && counter->Enabled()) { | 2551 if (FLAG_native_code_counters && counter->Enabled()) { |
| 2448 mov(scratch1, Operand(value)); | 2552 mov(scratch1, Operand(value)); |
| 2449 mov(scratch2, Operand(ExternalReference(counter))); | 2553 mov(scratch2, Operand(ExternalReference(counter))); |
| 2450 stw(scratch1, MemOperand(scratch2)); | 2554 StoreW(scratch1, MemOperand(scratch2)); |
| 2451 } | 2555 } |
| 2452 } | 2556 } |
| 2453 | 2557 |
| 2454 | |
| 2455 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value, | 2558 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value, |
| 2456 Register scratch1, Register scratch2) { | 2559 Register scratch1, Register scratch2) { |
| 2457 DCHECK(value > 0); | 2560 DCHECK(value > 0 && is_int8(value)); |
| 2458 if (FLAG_native_code_counters && counter->Enabled()) { | 2561 if (FLAG_native_code_counters && counter->Enabled()) { |
| 2459 mov(scratch2, Operand(ExternalReference(counter))); | 2562 mov(scratch1, Operand(ExternalReference(counter))); |
| 2460 lwz(scratch1, MemOperand(scratch2)); | 2563 // @TODO(john.yan): can be optimized by asi() |
| 2461 addi(scratch1, scratch1, Operand(value)); | 2564 LoadW(scratch2, MemOperand(scratch1)); |
| 2462 stw(scratch1, MemOperand(scratch2)); | 2565 AddP(scratch2, Operand(value)); |
| 2566 StoreW(scratch2, MemOperand(scratch1)); |
| 2463 } | 2567 } |
| 2464 } | 2568 } |
| 2465 | 2569 |
| 2466 | |
| 2467 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value, | 2570 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value, |
| 2468 Register scratch1, Register scratch2) { | 2571 Register scratch1, Register scratch2) { |
| 2469 DCHECK(value > 0); | 2572 DCHECK(value > 0 && is_int8(value)); |
| 2470 if (FLAG_native_code_counters && counter->Enabled()) { | 2573 if (FLAG_native_code_counters && counter->Enabled()) { |
| 2471 mov(scratch2, Operand(ExternalReference(counter))); | 2574 mov(scratch1, Operand(ExternalReference(counter))); |
| 2472 lwz(scratch1, MemOperand(scratch2)); | 2575 // @TODO(john.yan): can be optimized by asi() |
| 2473 subi(scratch1, scratch1, Operand(value)); | 2576 LoadW(scratch2, MemOperand(scratch1)); |
| 2474 stw(scratch1, MemOperand(scratch2)); | 2577 AddP(scratch2, Operand(-value)); |
| 2578 StoreW(scratch2, MemOperand(scratch1)); |
| 2475 } | 2579 } |
| 2476 } | 2580 } |
| 2477 | 2581 |
| 2478 | |
| 2479 void MacroAssembler::Assert(Condition cond, BailoutReason reason, | 2582 void MacroAssembler::Assert(Condition cond, BailoutReason reason, |
| 2480 CRegister cr) { | 2583 CRegister cr) { |
| 2481 if (emit_debug_code()) Check(cond, reason, cr); | 2584 if (emit_debug_code()) Check(cond, reason, cr); |
| 2482 } | 2585 } |
| 2483 | 2586 |
| 2484 | |
| 2485 void MacroAssembler::AssertFastElements(Register elements) { | 2587 void MacroAssembler::AssertFastElements(Register elements) { |
| 2486 if (emit_debug_code()) { | 2588 if (emit_debug_code()) { |
| 2487 DCHECK(!elements.is(r0)); | 2589 DCHECK(!elements.is(r0)); |
| 2488 Label ok; | 2590 Label ok; |
| 2489 push(elements); | 2591 push(elements); |
| 2490 LoadP(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); | 2592 LoadP(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); |
| 2491 LoadRoot(r0, Heap::kFixedArrayMapRootIndex); | 2593 CompareRoot(elements, Heap::kFixedArrayMapRootIndex); |
| 2492 cmp(elements, r0); | 2594 beq(&ok, Label::kNear); |
| 2493 beq(&ok); | 2595 CompareRoot(elements, Heap::kFixedDoubleArrayMapRootIndex); |
| 2494 LoadRoot(r0, Heap::kFixedDoubleArrayMapRootIndex); | 2596 beq(&ok, Label::kNear); |
| 2495 cmp(elements, r0); | 2597 CompareRoot(elements, Heap::kFixedCOWArrayMapRootIndex); |
| 2496 beq(&ok); | 2598 beq(&ok, Label::kNear); |
| 2497 LoadRoot(r0, Heap::kFixedCOWArrayMapRootIndex); | |
| 2498 cmp(elements, r0); | |
| 2499 beq(&ok); | |
| 2500 Abort(kJSObjectWithFastElementsMapHasSlowElements); | 2599 Abort(kJSObjectWithFastElementsMapHasSlowElements); |
| 2501 bind(&ok); | 2600 bind(&ok); |
| 2502 pop(elements); | 2601 pop(elements); |
| 2503 } | 2602 } |
| 2504 } | 2603 } |
| 2505 | 2604 |
| 2506 | |
| 2507 void MacroAssembler::Check(Condition cond, BailoutReason reason, CRegister cr) { | 2605 void MacroAssembler::Check(Condition cond, BailoutReason reason, CRegister cr) { |
| 2508 Label L; | 2606 Label L; |
| 2509 b(cond, &L, cr); | 2607 b(cond, &L); |
| 2510 Abort(reason); | 2608 Abort(reason); |
| 2511 // will not return here | 2609 // will not return here |
| 2512 bind(&L); | 2610 bind(&L); |
| 2513 } | 2611 } |
| 2514 | 2612 |
| 2515 | |
| 2516 void MacroAssembler::Abort(BailoutReason reason) { | 2613 void MacroAssembler::Abort(BailoutReason reason) { |
| 2517 Label abort_start; | 2614 Label abort_start; |
| 2518 bind(&abort_start); | 2615 bind(&abort_start); |
| 2519 #ifdef DEBUG | 2616 #ifdef DEBUG |
| 2520 const char* msg = GetBailoutReason(reason); | 2617 const char* msg = GetBailoutReason(reason); |
| 2521 if (msg != NULL) { | 2618 if (msg != NULL) { |
| 2522 RecordComment("Abort message: "); | 2619 RecordComment("Abort message: "); |
| 2523 RecordComment(msg); | 2620 RecordComment(msg); |
| 2524 } | 2621 } |
| 2525 | 2622 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2536 // We don't actually want to generate a pile of code for this, so just | 2633 // We don't actually want to generate a pile of code for this, so just |
| 2537 // claim there is a stack frame, without generating one. | 2634 // claim there is a stack frame, without generating one. |
| 2538 FrameScope scope(this, StackFrame::NONE); | 2635 FrameScope scope(this, StackFrame::NONE); |
| 2539 CallRuntime(Runtime::kAbort); | 2636 CallRuntime(Runtime::kAbort); |
| 2540 } else { | 2637 } else { |
| 2541 CallRuntime(Runtime::kAbort); | 2638 CallRuntime(Runtime::kAbort); |
| 2542 } | 2639 } |
| 2543 // will not return here | 2640 // will not return here |
| 2544 } | 2641 } |
| 2545 | 2642 |
| 2546 | |
| 2547 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { | 2643 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { |
| 2548 if (context_chain_length > 0) { | 2644 if (context_chain_length > 0) { |
| 2549 // Move up the chain of contexts to the context containing the slot. | 2645 // Move up the chain of contexts to the context containing the slot. |
| 2550 LoadP(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX))); | 2646 LoadP(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX))); |
| 2551 for (int i = 1; i < context_chain_length; i++) { | 2647 for (int i = 1; i < context_chain_length; i++) { |
| 2552 LoadP(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX))); | 2648 LoadP(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX))); |
| 2553 } | 2649 } |
| 2554 } else { | 2650 } else { |
| 2555 // Slot is in the current function context. Move it into the | 2651 // Slot is in the current function context. Move it into the |
| 2556 // destination register in case we store into it (the write barrier | 2652 // destination register in case we store into it (the write barrier |
| 2557 // cannot be allowed to destroy the context in esi). | 2653 // cannot be allowed to destroy the context in esi). |
| 2558 mr(dst, cp); | 2654 LoadRR(dst, cp); |
| 2559 } | 2655 } |
| 2560 } | 2656 } |
| 2561 | 2657 |
| 2562 | |
| 2563 void MacroAssembler::LoadTransitionedArrayMapConditional( | 2658 void MacroAssembler::LoadTransitionedArrayMapConditional( |
| 2564 ElementsKind expected_kind, ElementsKind transitioned_kind, | 2659 ElementsKind expected_kind, ElementsKind transitioned_kind, |
| 2565 Register map_in_out, Register scratch, Label* no_map_match) { | 2660 Register map_in_out, Register scratch, Label* no_map_match) { |
| 2566 DCHECK(IsFastElementsKind(expected_kind)); | 2661 DCHECK(IsFastElementsKind(expected_kind)); |
| 2567 DCHECK(IsFastElementsKind(transitioned_kind)); | 2662 DCHECK(IsFastElementsKind(transitioned_kind)); |
| 2568 | 2663 |
| 2569 // Check that the function's map is the same as the expected cached map. | 2664 // Check that the function's map is the same as the expected cached map. |
| 2570 LoadP(scratch, NativeContextMemOperand()); | 2665 LoadP(scratch, NativeContextMemOperand()); |
| 2571 LoadP(ip, ContextMemOperand(scratch, Context::ArrayMapIndex(expected_kind))); | 2666 LoadP(ip, ContextMemOperand(scratch, Context::ArrayMapIndex(expected_kind))); |
| 2572 cmp(map_in_out, ip); | 2667 CmpP(map_in_out, ip); |
| 2573 bne(no_map_match); | 2668 bne(no_map_match); |
| 2574 | 2669 |
| 2575 // Use the transitioned cached map. | 2670 // Use the transitioned cached map. |
| 2576 LoadP(map_in_out, | 2671 LoadP(map_in_out, |
| 2577 ContextMemOperand(scratch, Context::ArrayMapIndex(transitioned_kind))); | 2672 ContextMemOperand(scratch, Context::ArrayMapIndex(transitioned_kind))); |
| 2578 } | 2673 } |
| 2579 | 2674 |
| 2580 | |
| 2581 void MacroAssembler::LoadNativeContextSlot(int index, Register dst) { | 2675 void MacroAssembler::LoadNativeContextSlot(int index, Register dst) { |
| 2582 LoadP(dst, NativeContextMemOperand()); | 2676 LoadP(dst, NativeContextMemOperand()); |
| 2583 LoadP(dst, ContextMemOperand(dst, index)); | 2677 LoadP(dst, ContextMemOperand(dst, index)); |
| 2584 } | 2678 } |
| 2585 | 2679 |
| 2586 | |
| 2587 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, | 2680 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, |
| 2588 Register map, | 2681 Register map, |
| 2589 Register scratch) { | 2682 Register scratch) { |
| 2590 // Load the initial map. The global functions all have initial maps. | 2683 // Load the initial map. The global functions all have initial maps. |
| 2591 LoadP(map, | 2684 LoadP(map, |
| 2592 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 2685 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
| 2593 if (emit_debug_code()) { | 2686 if (emit_debug_code()) { |
| 2594 Label ok, fail; | 2687 Label ok, fail; |
| 2595 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); | 2688 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); |
| 2596 b(&ok); | 2689 b(&ok); |
| 2597 bind(&fail); | 2690 bind(&fail); |
| 2598 Abort(kGlobalFunctionsMustHaveInitialMap); | 2691 Abort(kGlobalFunctionsMustHaveInitialMap); |
| 2599 bind(&ok); | 2692 bind(&ok); |
| 2600 } | 2693 } |
| 2601 } | 2694 } |
| 2602 | 2695 |
| 2603 | |
| 2604 void MacroAssembler::JumpIfNotPowerOfTwoOrZero( | 2696 void MacroAssembler::JumpIfNotPowerOfTwoOrZero( |
| 2605 Register reg, Register scratch, Label* not_power_of_two_or_zero) { | 2697 Register reg, Register scratch, Label* not_power_of_two_or_zero) { |
| 2606 subi(scratch, reg, Operand(1)); | 2698 SubP(scratch, reg, Operand(1)); |
| 2607 cmpi(scratch, Operand::Zero()); | 2699 CmpP(scratch, Operand::Zero()); |
| 2608 blt(not_power_of_two_or_zero); | 2700 blt(not_power_of_two_or_zero); |
| 2609 and_(r0, scratch, reg, SetRC); | 2701 AndP(r0, reg, scratch /*, SetRC*/); // Should be okay to remove rc |
| 2610 bne(not_power_of_two_or_zero, cr0); | 2702 bne(not_power_of_two_or_zero /*, cr0*/); |
| 2611 } | 2703 } |
| 2612 | 2704 |
| 2613 | |
| 2614 void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg, | 2705 void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg, |
| 2615 Register scratch, | 2706 Register scratch, |
| 2616 Label* zero_and_neg, | 2707 Label* zero_and_neg, |
| 2617 Label* not_power_of_two) { | 2708 Label* not_power_of_two) { |
| 2618 subi(scratch, reg, Operand(1)); | 2709 SubP(scratch, reg, Operand(1)); |
| 2619 cmpi(scratch, Operand::Zero()); | 2710 CmpP(scratch, Operand::Zero()); |
| 2620 blt(zero_and_neg); | 2711 blt(zero_and_neg); |
| 2621 and_(r0, scratch, reg, SetRC); | 2712 AndP(r0, reg, scratch /*, SetRC*/); // Should be okay to remove rc |
| 2622 bne(not_power_of_two, cr0); | 2713 bne(not_power_of_two /*, cr0*/); |
| 2623 } | 2714 } |
| 2624 | 2715 |
| 2625 #if !V8_TARGET_ARCH_PPC64 | 2716 #if !V8_TARGET_ARCH_S390X |
| 2626 void MacroAssembler::SmiTagCheckOverflow(Register reg, Register overflow) { | 2717 void MacroAssembler::SmiTagCheckOverflow(Register reg, Register overflow) { |
| 2627 DCHECK(!reg.is(overflow)); | 2718 DCHECK(!reg.is(overflow)); |
| 2628 mr(overflow, reg); // Save original value. | 2719 LoadRR(overflow, reg); // Save original value. |
| 2629 SmiTag(reg); | 2720 SmiTag(reg); |
| 2630 xor_(overflow, overflow, reg, SetRC); // Overflow if (value ^ 2 * value) < 0. | 2721 XorP(overflow, overflow, reg); // Overflow if (value ^ 2 * value) < 0. |
| 2722 LoadAndTestRR(overflow, overflow); |
| 2631 } | 2723 } |
| 2632 | 2724 |
| 2633 | |
| 2634 void MacroAssembler::SmiTagCheckOverflow(Register dst, Register src, | 2725 void MacroAssembler::SmiTagCheckOverflow(Register dst, Register src, |
| 2635 Register overflow) { | 2726 Register overflow) { |
| 2636 if (dst.is(src)) { | 2727 if (dst.is(src)) { |
| 2637 // Fall back to slower case. | 2728 // Fall back to slower case. |
| 2638 SmiTagCheckOverflow(dst, overflow); | 2729 SmiTagCheckOverflow(dst, overflow); |
| 2639 } else { | 2730 } else { |
| 2640 DCHECK(!dst.is(src)); | 2731 DCHECK(!dst.is(src)); |
| 2641 DCHECK(!dst.is(overflow)); | 2732 DCHECK(!dst.is(overflow)); |
| 2642 DCHECK(!src.is(overflow)); | 2733 DCHECK(!src.is(overflow)); |
| 2643 SmiTag(dst, src); | 2734 SmiTag(dst, src); |
| 2644 xor_(overflow, dst, src, SetRC); // Overflow if (value ^ 2 * value) < 0. | 2735 XorP(overflow, dst, src); // Overflow if (value ^ 2 * value) < 0. |
| 2736 LoadAndTestRR(overflow, overflow); |
| 2645 } | 2737 } |
| 2646 } | 2738 } |
| 2647 #endif | 2739 #endif |
| 2648 | 2740 |
| 2649 void MacroAssembler::JumpIfNotBothSmi(Register reg1, Register reg2, | 2741 void MacroAssembler::JumpIfNotBothSmi(Register reg1, Register reg2, |
| 2650 Label* on_not_both_smi) { | 2742 Label* on_not_both_smi) { |
| 2651 STATIC_ASSERT(kSmiTag == 0); | 2743 STATIC_ASSERT(kSmiTag == 0); |
| 2652 orx(r0, reg1, reg2, LeaveRC); | 2744 OrP(r0, reg1, reg2 /*, LeaveRC*/); // should be okay to remove LeaveRC |
| 2653 JumpIfNotSmi(r0, on_not_both_smi); | 2745 JumpIfNotSmi(r0, on_not_both_smi); |
| 2654 } | 2746 } |
| 2655 | 2747 |
| 2656 | |
| 2657 void MacroAssembler::UntagAndJumpIfSmi(Register dst, Register src, | 2748 void MacroAssembler::UntagAndJumpIfSmi(Register dst, Register src, |
| 2658 Label* smi_case) { | 2749 Label* smi_case) { |
| 2659 STATIC_ASSERT(kSmiTag == 0); | 2750 STATIC_ASSERT(kSmiTag == 0); |
| 2660 TestBitRange(src, kSmiTagSize - 1, 0, r0); | 2751 STATIC_ASSERT(kSmiTagSize == 1); |
| 2752 // this won't work if src == dst |
| 2753 DCHECK(src.code() != dst.code()); |
| 2661 SmiUntag(dst, src); | 2754 SmiUntag(dst, src); |
| 2662 beq(smi_case, cr0); | 2755 TestIfSmi(src); |
| 2756 beq(smi_case); |
| 2663 } | 2757 } |
| 2664 | 2758 |
| 2665 | |
| 2666 void MacroAssembler::UntagAndJumpIfNotSmi(Register dst, Register src, | 2759 void MacroAssembler::UntagAndJumpIfNotSmi(Register dst, Register src, |
| 2667 Label* non_smi_case) { | 2760 Label* non_smi_case) { |
| 2668 STATIC_ASSERT(kSmiTag == 0); | 2761 STATIC_ASSERT(kSmiTag == 0); |
| 2669 TestBitRange(src, kSmiTagSize - 1, 0, r0); | 2762 STATIC_ASSERT(kSmiTagSize == 1); |
| 2670 SmiUntag(dst, src); | 2763 |
| 2671 bne(non_smi_case, cr0); | 2764 // We can more optimally use TestIfSmi if dst != src |
| 2765 // otherwise, the UnTag operation will kill the CC and we cannot |
| 2766 // test the Tag bit. |
| 2767 if (src.code() != dst.code()) { |
| 2768 SmiUntag(dst, src); |
| 2769 TestIfSmi(src); |
| 2770 } else { |
| 2771 TestBit(src, 0, r0); |
| 2772 SmiUntag(dst, src); |
| 2773 LoadAndTestRR(r0, r0); |
| 2774 } |
| 2775 bne(non_smi_case); |
| 2672 } | 2776 } |
| 2673 | 2777 |
| 2674 | |
| 2675 void MacroAssembler::JumpIfEitherSmi(Register reg1, Register reg2, | 2778 void MacroAssembler::JumpIfEitherSmi(Register reg1, Register reg2, |
| 2676 Label* on_either_smi) { | 2779 Label* on_either_smi) { |
| 2677 STATIC_ASSERT(kSmiTag == 0); | 2780 STATIC_ASSERT(kSmiTag == 0); |
| 2678 JumpIfSmi(reg1, on_either_smi); | 2781 JumpIfSmi(reg1, on_either_smi); |
| 2679 JumpIfSmi(reg2, on_either_smi); | 2782 JumpIfSmi(reg2, on_either_smi); |
| 2680 } | 2783 } |
| 2681 | 2784 |
| 2682 | |
| 2683 void MacroAssembler::AssertNotSmi(Register object) { | 2785 void MacroAssembler::AssertNotSmi(Register object) { |
| 2684 if (emit_debug_code()) { | 2786 if (emit_debug_code()) { |
| 2685 STATIC_ASSERT(kSmiTag == 0); | 2787 STATIC_ASSERT(kSmiTag == 0); |
| 2686 TestIfSmi(object, r0); | 2788 TestIfSmi(object); |
| 2687 Check(ne, kOperandIsASmi, cr0); | 2789 Check(ne, kOperandIsASmi, cr0); |
| 2688 } | 2790 } |
| 2689 } | 2791 } |
| 2690 | 2792 |
| 2691 | |
| 2692 void MacroAssembler::AssertSmi(Register object) { | 2793 void MacroAssembler::AssertSmi(Register object) { |
| 2693 if (emit_debug_code()) { | 2794 if (emit_debug_code()) { |
| 2694 STATIC_ASSERT(kSmiTag == 0); | 2795 STATIC_ASSERT(kSmiTag == 0); |
| 2695 TestIfSmi(object, r0); | 2796 TestIfSmi(object); |
| 2696 Check(eq, kOperandIsNotSmi, cr0); | 2797 Check(eq, kOperandIsNotSmi, cr0); |
| 2697 } | 2798 } |
| 2698 } | 2799 } |
| 2699 | 2800 |
| 2700 | |
| 2701 void MacroAssembler::AssertString(Register object) { | 2801 void MacroAssembler::AssertString(Register object) { |
| 2702 if (emit_debug_code()) { | 2802 if (emit_debug_code()) { |
| 2703 STATIC_ASSERT(kSmiTag == 0); | 2803 STATIC_ASSERT(kSmiTag == 0); |
| 2704 TestIfSmi(object, r0); | 2804 TestIfSmi(object); |
| 2705 Check(ne, kOperandIsASmiAndNotAString, cr0); | 2805 Check(ne, kOperandIsASmiAndNotAString, cr0); |
| 2706 push(object); | 2806 push(object); |
| 2707 LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset)); | 2807 LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 2708 CompareInstanceType(object, object, FIRST_NONSTRING_TYPE); | 2808 CompareInstanceType(object, object, FIRST_NONSTRING_TYPE); |
| 2709 pop(object); | 2809 pop(object); |
| 2710 Check(lt, kOperandIsNotAString); | 2810 Check(lt, kOperandIsNotAString); |
| 2711 } | 2811 } |
| 2712 } | 2812 } |
| 2713 | 2813 |
| 2714 | |
| 2715 void MacroAssembler::AssertName(Register object) { | 2814 void MacroAssembler::AssertName(Register object) { |
| 2716 if (emit_debug_code()) { | 2815 if (emit_debug_code()) { |
| 2717 STATIC_ASSERT(kSmiTag == 0); | 2816 STATIC_ASSERT(kSmiTag == 0); |
| 2718 TestIfSmi(object, r0); | 2817 TestIfSmi(object); |
| 2719 Check(ne, kOperandIsASmiAndNotAName, cr0); | 2818 Check(ne, kOperandIsASmiAndNotAName, cr0); |
| 2720 push(object); | 2819 push(object); |
| 2721 LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset)); | 2820 LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 2722 CompareInstanceType(object, object, LAST_NAME_TYPE); | 2821 CompareInstanceType(object, object, LAST_NAME_TYPE); |
| 2723 pop(object); | 2822 pop(object); |
| 2724 Check(le, kOperandIsNotAName); | 2823 Check(le, kOperandIsNotAName); |
| 2725 } | 2824 } |
| 2726 } | 2825 } |
| 2727 | 2826 |
| 2728 | |
| 2729 void MacroAssembler::AssertFunction(Register object) { | 2827 void MacroAssembler::AssertFunction(Register object) { |
| 2730 if (emit_debug_code()) { | 2828 if (emit_debug_code()) { |
| 2731 STATIC_ASSERT(kSmiTag == 0); | 2829 STATIC_ASSERT(kSmiTag == 0); |
| 2732 TestIfSmi(object, r0); | 2830 TestIfSmi(object); |
| 2733 Check(ne, kOperandIsASmiAndNotAFunction, cr0); | 2831 Check(ne, kOperandIsASmiAndNotAFunction, cr0); |
| 2734 push(object); | 2832 push(object); |
| 2735 CompareObjectType(object, object, object, JS_FUNCTION_TYPE); | 2833 CompareObjectType(object, object, object, JS_FUNCTION_TYPE); |
| 2736 pop(object); | 2834 pop(object); |
| 2737 Check(eq, kOperandIsNotAFunction); | 2835 Check(eq, kOperandIsNotAFunction); |
| 2738 } | 2836 } |
| 2739 } | 2837 } |
| 2740 | 2838 |
| 2741 | |
| 2742 void MacroAssembler::AssertBoundFunction(Register object) { | 2839 void MacroAssembler::AssertBoundFunction(Register object) { |
| 2743 if (emit_debug_code()) { | 2840 if (emit_debug_code()) { |
| 2744 STATIC_ASSERT(kSmiTag == 0); | 2841 STATIC_ASSERT(kSmiTag == 0); |
| 2745 TestIfSmi(object, r0); | 2842 TestIfSmi(object); |
| 2746 Check(ne, kOperandIsASmiAndNotABoundFunction, cr0); | 2843 Check(ne, kOperandIsASmiAndNotABoundFunction, cr0); |
| 2747 push(object); | 2844 push(object); |
| 2748 CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE); | 2845 CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE); |
| 2749 pop(object); | 2846 pop(object); |
| 2750 Check(eq, kOperandIsNotABoundFunction); | 2847 Check(eq, kOperandIsNotABoundFunction); |
| 2751 } | 2848 } |
| 2752 } | 2849 } |
| 2753 | 2850 |
| 2754 void MacroAssembler::AssertReceiver(Register object) { | 2851 void MacroAssembler::AssertReceiver(Register object) { |
| 2755 if (emit_debug_code()) { | 2852 if (emit_debug_code()) { |
| 2756 STATIC_ASSERT(kSmiTag == 0); | 2853 STATIC_ASSERT(kSmiTag == 0); |
| 2757 TestIfSmi(object, r0); | 2854 TestIfSmi(object); |
| 2758 Check(ne, kOperandIsASmiAndNotAReceiver, cr0); | 2855 Check(ne, kOperandIsASmiAndNotAReceiver, cr0); |
| 2759 push(object); | 2856 push(object); |
| 2760 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | 2857 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 2761 CompareObjectType(object, object, object, FIRST_JS_RECEIVER_TYPE); | 2858 CompareObjectType(object, object, object, FIRST_JS_RECEIVER_TYPE); |
| 2762 pop(object); | 2859 pop(object); |
| 2763 Check(ge, kOperandIsNotAReceiver); | 2860 Check(ge, kOperandIsNotAReceiver); |
| 2764 } | 2861 } |
| 2765 } | 2862 } |
| 2766 | 2863 |
| 2767 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object, | 2864 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object, |
| 2768 Register scratch) { | 2865 Register scratch) { |
| 2769 if (emit_debug_code()) { | 2866 if (emit_debug_code()) { |
| 2770 Label done_checking; | 2867 Label done_checking; |
| 2771 AssertNotSmi(object); | 2868 AssertNotSmi(object); |
| 2772 CompareRoot(object, Heap::kUndefinedValueRootIndex); | 2869 CompareRoot(object, Heap::kUndefinedValueRootIndex); |
| 2773 beq(&done_checking); | 2870 beq(&done_checking, Label::kNear); |
| 2774 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); | 2871 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 2775 CompareRoot(scratch, Heap::kAllocationSiteMapRootIndex); | 2872 CompareRoot(scratch, Heap::kAllocationSiteMapRootIndex); |
| 2776 Assert(eq, kExpectedUndefinedOrCell); | 2873 Assert(eq, kExpectedUndefinedOrCell); |
| 2777 bind(&done_checking); | 2874 bind(&done_checking); |
| 2778 } | 2875 } |
| 2779 } | 2876 } |
| 2780 | 2877 |
| 2781 | |
| 2782 void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) { | 2878 void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) { |
| 2783 if (emit_debug_code()) { | 2879 if (emit_debug_code()) { |
| 2784 CompareRoot(reg, index); | 2880 CompareRoot(reg, index); |
| 2785 Check(eq, kHeapNumberMapRegisterClobbered); | 2881 Check(eq, kHeapNumberMapRegisterClobbered); |
| 2786 } | 2882 } |
| 2787 } | 2883 } |
| 2788 | 2884 |
| 2789 | |
| 2790 void MacroAssembler::JumpIfNotHeapNumber(Register object, | 2885 void MacroAssembler::JumpIfNotHeapNumber(Register object, |
| 2791 Register heap_number_map, | 2886 Register heap_number_map, |
| 2792 Register scratch, | 2887 Register scratch, |
| 2793 Label* on_not_heap_number) { | 2888 Label* on_not_heap_number) { |
| 2794 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); | 2889 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 2795 AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 2890 AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
| 2796 cmp(scratch, heap_number_map); | 2891 CmpP(scratch, heap_number_map); |
| 2797 bne(on_not_heap_number); | 2892 bne(on_not_heap_number); |
| 2798 } | 2893 } |
| 2799 | 2894 |
| 2800 | |
| 2801 void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings( | 2895 void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings( |
| 2802 Register first, Register second, Register scratch1, Register scratch2, | 2896 Register first, Register second, Register scratch1, Register scratch2, |
| 2803 Label* failure) { | 2897 Label* failure) { |
| 2804 // Test that both first and second are sequential one-byte strings. | 2898 // Test that both first and second are sequential one-byte strings. |
| 2805 // Assume that they are non-smis. | 2899 // Assume that they are non-smis. |
| 2806 LoadP(scratch1, FieldMemOperand(first, HeapObject::kMapOffset)); | 2900 LoadP(scratch1, FieldMemOperand(first, HeapObject::kMapOffset)); |
| 2807 LoadP(scratch2, FieldMemOperand(second, HeapObject::kMapOffset)); | 2901 LoadP(scratch2, FieldMemOperand(second, HeapObject::kMapOffset)); |
| 2808 lbz(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); | 2902 LoadlB(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); |
| 2809 lbz(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset)); | 2903 LoadlB(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset)); |
| 2810 | 2904 |
| 2811 JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1, | 2905 JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1, |
| 2812 scratch2, failure); | 2906 scratch2, failure); |
| 2813 } | 2907 } |
| 2814 | 2908 |
| 2815 void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first, | 2909 void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first, |
| 2816 Register second, | 2910 Register second, |
| 2817 Register scratch1, | 2911 Register scratch1, |
| 2818 Register scratch2, | 2912 Register scratch2, |
| 2819 Label* failure) { | 2913 Label* failure) { |
| 2820 // Check that neither is a smi. | 2914 // Check that neither is a smi. |
| 2821 and_(scratch1, first, second); | 2915 AndP(scratch1, first, second); |
| 2822 JumpIfSmi(scratch1, failure); | 2916 JumpIfSmi(scratch1, failure); |
| 2823 JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1, | 2917 JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1, |
| 2824 scratch2, failure); | 2918 scratch2, failure); |
| 2825 } | 2919 } |
| 2826 | 2920 |
| 2827 | |
| 2828 void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg, | 2921 void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg, |
| 2829 Label* not_unique_name) { | 2922 Label* not_unique_name) { |
| 2830 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); | 2923 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
| 2831 Label succeed; | 2924 Label succeed; |
| 2832 andi(r0, reg, Operand(kIsNotStringMask | kIsNotInternalizedMask)); | 2925 AndP(r0, reg, Operand(kIsNotStringMask | kIsNotInternalizedMask)); |
| 2833 beq(&succeed, cr0); | 2926 beq(&succeed, Label::kNear); |
| 2834 cmpi(reg, Operand(SYMBOL_TYPE)); | 2927 CmpP(reg, Operand(SYMBOL_TYPE)); |
| 2835 bne(not_unique_name); | 2928 bne(not_unique_name); |
| 2836 | 2929 |
| 2837 bind(&succeed); | 2930 bind(&succeed); |
| 2838 } | 2931 } |
| 2839 | 2932 |
| 2840 | |
| 2841 // Allocates a heap number or jumps to the need_gc label if the young space | 2933 // Allocates a heap number or jumps to the need_gc label if the young space |
| 2842 // is full and a scavenge is needed. | 2934 // is full and a scavenge is needed. |
| 2843 void MacroAssembler::AllocateHeapNumber(Register result, Register scratch1, | 2935 void MacroAssembler::AllocateHeapNumber(Register result, Register scratch1, |
| 2844 Register scratch2, | 2936 Register scratch2, |
| 2845 Register heap_number_map, | 2937 Register heap_number_map, |
| 2846 Label* gc_required, | 2938 Label* gc_required, |
| 2847 TaggingMode tagging_mode, | 2939 TaggingMode tagging_mode, |
| 2848 MutableMode mode) { | 2940 MutableMode mode) { |
| 2849 // Allocate an object in the heap for the heap number and tag it as a heap | 2941 // Allocate an object in the heap for the heap number and tag it as a heap |
| 2850 // object. | 2942 // object. |
| 2851 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required, | 2943 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required, |
| 2852 tagging_mode == TAG_RESULT ? TAG_OBJECT : NO_ALLOCATION_FLAGS); | 2944 tagging_mode == TAG_RESULT ? TAG_OBJECT : NO_ALLOCATION_FLAGS); |
| 2853 | 2945 |
| 2854 Heap::RootListIndex map_index = mode == MUTABLE | 2946 Heap::RootListIndex map_index = mode == MUTABLE |
| 2855 ? Heap::kMutableHeapNumberMapRootIndex | 2947 ? Heap::kMutableHeapNumberMapRootIndex |
| 2856 : Heap::kHeapNumberMapRootIndex; | 2948 : Heap::kHeapNumberMapRootIndex; |
| 2857 AssertIsRoot(heap_number_map, map_index); | 2949 AssertIsRoot(heap_number_map, map_index); |
| 2858 | 2950 |
| 2859 // Store heap number map in the allocated object. | 2951 // Store heap number map in the allocated object. |
| 2860 if (tagging_mode == TAG_RESULT) { | 2952 if (tagging_mode == TAG_RESULT) { |
| 2861 StoreP(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset), | 2953 StoreP(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset)); |
| 2862 r0); | |
| 2863 } else { | 2954 } else { |
| 2864 StoreP(heap_number_map, MemOperand(result, HeapObject::kMapOffset)); | 2955 StoreP(heap_number_map, MemOperand(result, HeapObject::kMapOffset)); |
| 2865 } | 2956 } |
| 2866 } | 2957 } |
| 2867 | 2958 |
| 2868 | |
| 2869 void MacroAssembler::AllocateHeapNumberWithValue( | 2959 void MacroAssembler::AllocateHeapNumberWithValue( |
| 2870 Register result, DoubleRegister value, Register scratch1, Register scratch2, | 2960 Register result, DoubleRegister value, Register scratch1, Register scratch2, |
| 2871 Register heap_number_map, Label* gc_required) { | 2961 Register heap_number_map, Label* gc_required) { |
| 2872 AllocateHeapNumber(result, scratch1, scratch2, heap_number_map, gc_required); | 2962 AllocateHeapNumber(result, scratch1, scratch2, heap_number_map, gc_required); |
| 2873 stfd(value, FieldMemOperand(result, HeapNumber::kValueOffset)); | 2963 StoreDouble(value, FieldMemOperand(result, HeapNumber::kValueOffset)); |
| 2874 } | 2964 } |
| 2875 | 2965 |
| 2876 | |
| 2877 void MacroAssembler::AllocateJSValue(Register result, Register constructor, | 2966 void MacroAssembler::AllocateJSValue(Register result, Register constructor, |
| 2878 Register value, Register scratch1, | 2967 Register value, Register scratch1, |
| 2879 Register scratch2, Label* gc_required) { | 2968 Register scratch2, Label* gc_required) { |
| 2880 DCHECK(!result.is(constructor)); | 2969 DCHECK(!result.is(constructor)); |
| 2881 DCHECK(!result.is(scratch1)); | 2970 DCHECK(!result.is(scratch1)); |
| 2882 DCHECK(!result.is(scratch2)); | 2971 DCHECK(!result.is(scratch2)); |
| 2883 DCHECK(!result.is(value)); | 2972 DCHECK(!result.is(value)); |
| 2884 | 2973 |
| 2885 // Allocate JSValue in new space. | 2974 // Allocate JSValue in new space. |
| 2886 Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT); | 2975 Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT); |
| 2887 | 2976 |
| 2888 // Initialize the JSValue. | 2977 // Initialize the JSValue. |
| 2889 LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2); | 2978 LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2); |
| 2890 StoreP(scratch1, FieldMemOperand(result, HeapObject::kMapOffset), r0); | 2979 StoreP(scratch1, FieldMemOperand(result, HeapObject::kMapOffset), r0); |
| 2891 LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex); | 2980 LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex); |
| 2892 StoreP(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset), r0); | 2981 StoreP(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset), r0); |
| 2893 StoreP(scratch1, FieldMemOperand(result, JSObject::kElementsOffset), r0); | 2982 StoreP(scratch1, FieldMemOperand(result, JSObject::kElementsOffset), r0); |
| 2894 StoreP(value, FieldMemOperand(result, JSValue::kValueOffset), r0); | 2983 StoreP(value, FieldMemOperand(result, JSValue::kValueOffset), r0); |
| 2895 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); | 2984 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); |
| 2896 } | 2985 } |
| 2897 | 2986 |
| 2898 | |
| 2899 void MacroAssembler::CopyBytes(Register src, Register dst, Register length, | 2987 void MacroAssembler::CopyBytes(Register src, Register dst, Register length, |
| 2900 Register scratch) { | 2988 Register scratch) { |
| 2901 Label align_loop, aligned, word_loop, byte_loop, byte_loop_1, done; | 2989 Label big_loop, left_bytes, done, fake_call; |
| 2902 | 2990 |
| 2903 DCHECK(!scratch.is(r0)); | 2991 DCHECK(!scratch.is(r0)); |
| 2904 | 2992 |
| 2905 cmpi(length, Operand::Zero()); | 2993 // big loop moves 256 bytes at a time |
| 2994 bind(&big_loop); |
| 2995 CmpP(length, Operand(static_cast<intptr_t>(0x100))); |
| 2996 blt(&left_bytes); |
| 2997 |
| 2998 mvc(MemOperand(dst), MemOperand(src), 0x100); |
| 2999 |
| 3000 AddP(src, Operand(static_cast<intptr_t>(0x100))); |
| 3001 AddP(dst, Operand(static_cast<intptr_t>(0x100))); |
| 3002 SubP(length, Operand(static_cast<intptr_t>(0x100))); |
| 3003 b(&big_loop); |
| 3004 |
| 3005 bind(&left_bytes); |
| 3006 CmpP(length, Operand::Zero()); |
| 2906 beq(&done); | 3007 beq(&done); |
| 2907 | 3008 |
| 2908 // Check src alignment and length to see whether word_loop is possible | 3009 // TODO(john.yan): More optimal version is to use MVC |
| 2909 andi(scratch, src, Operand(kPointerSize - 1)); | 3010 // Sequence below has some undiagnosed issue. |
| 2910 beq(&aligned, cr0); | 3011 /* |
| 2911 subfic(scratch, scratch, Operand(kPointerSize * 2)); | 3012 b(scratch, &fake_call); // use brasl to Save mvc addr to scratch |
| 2912 cmp(length, scratch); | 3013 mvc(MemOperand(dst), MemOperand(src), 1); |
| 2913 blt(&byte_loop); | 3014 bind(&fake_call); |
| 3015 SubP(length, Operand(static_cast<intptr_t>(-1))); |
| 3016 ex(length, MemOperand(scratch)); // execute mvc instr above |
| 3017 AddP(src, length); |
| 3018 AddP(dst, length); |
| 3019 AddP(src, Operand(static_cast<intptr_t>(0x1))); |
| 3020 AddP(dst, Operand(static_cast<intptr_t>(0x1))); |
| 3021 */ |
| 2914 | 3022 |
| 2915 // Align src before copying in word size chunks. | 3023 mvc(MemOperand(dst), MemOperand(src), 1); |
| 2916 subi(scratch, scratch, Operand(kPointerSize)); | 3024 AddP(src, Operand(static_cast<intptr_t>(0x1))); |
| 2917 mtctr(scratch); | 3025 AddP(dst, Operand(static_cast<intptr_t>(0x1))); |
| 2918 bind(&align_loop); | 3026 SubP(length, Operand(static_cast<intptr_t>(0x1))); |
| 2919 lbz(scratch, MemOperand(src)); | |
| 2920 addi(src, src, Operand(1)); | |
| 2921 subi(length, length, Operand(1)); | |
| 2922 stb(scratch, MemOperand(dst)); | |
| 2923 addi(dst, dst, Operand(1)); | |
| 2924 bdnz(&align_loop); | |
| 2925 | 3027 |
| 2926 bind(&aligned); | 3028 b(&left_bytes); |
| 2927 | |
| 2928 // Copy bytes in word size chunks. | |
| 2929 if (emit_debug_code()) { | |
| 2930 andi(r0, src, Operand(kPointerSize - 1)); | |
| 2931 Assert(eq, kExpectingAlignmentForCopyBytes, cr0); | |
| 2932 } | |
| 2933 | |
| 2934 ShiftRightImm(scratch, length, Operand(kPointerSizeLog2)); | |
| 2935 cmpi(scratch, Operand::Zero()); | |
| 2936 beq(&byte_loop); | |
| 2937 | |
| 2938 mtctr(scratch); | |
| 2939 bind(&word_loop); | |
| 2940 LoadP(scratch, MemOperand(src)); | |
| 2941 addi(src, src, Operand(kPointerSize)); | |
| 2942 subi(length, length, Operand(kPointerSize)); | |
| 2943 if (CpuFeatures::IsSupported(UNALIGNED_ACCESSES)) { | |
| 2944 // currently false for PPC - but possible future opt | |
| 2945 StoreP(scratch, MemOperand(dst)); | |
| 2946 addi(dst, dst, Operand(kPointerSize)); | |
| 2947 } else { | |
| 2948 #if V8_TARGET_LITTLE_ENDIAN | |
| 2949 stb(scratch, MemOperand(dst, 0)); | |
| 2950 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2951 stb(scratch, MemOperand(dst, 1)); | |
| 2952 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2953 stb(scratch, MemOperand(dst, 2)); | |
| 2954 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2955 stb(scratch, MemOperand(dst, 3)); | |
| 2956 #if V8_TARGET_ARCH_PPC64 | |
| 2957 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2958 stb(scratch, MemOperand(dst, 4)); | |
| 2959 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2960 stb(scratch, MemOperand(dst, 5)); | |
| 2961 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2962 stb(scratch, MemOperand(dst, 6)); | |
| 2963 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2964 stb(scratch, MemOperand(dst, 7)); | |
| 2965 #endif | |
| 2966 #else | |
| 2967 #if V8_TARGET_ARCH_PPC64 | |
| 2968 stb(scratch, MemOperand(dst, 7)); | |
| 2969 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2970 stb(scratch, MemOperand(dst, 6)); | |
| 2971 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2972 stb(scratch, MemOperand(dst, 5)); | |
| 2973 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2974 stb(scratch, MemOperand(dst, 4)); | |
| 2975 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2976 #endif | |
| 2977 stb(scratch, MemOperand(dst, 3)); | |
| 2978 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2979 stb(scratch, MemOperand(dst, 2)); | |
| 2980 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2981 stb(scratch, MemOperand(dst, 1)); | |
| 2982 ShiftRightImm(scratch, scratch, Operand(8)); | |
| 2983 stb(scratch, MemOperand(dst, 0)); | |
| 2984 #endif | |
| 2985 addi(dst, dst, Operand(kPointerSize)); | |
| 2986 } | |
| 2987 bdnz(&word_loop); | |
| 2988 | |
| 2989 // Copy the last bytes if any left. | |
| 2990 cmpi(length, Operand::Zero()); | |
| 2991 beq(&done); | |
| 2992 | |
| 2993 bind(&byte_loop); | |
| 2994 mtctr(length); | |
| 2995 bind(&byte_loop_1); | |
| 2996 lbz(scratch, MemOperand(src)); | |
| 2997 addi(src, src, Operand(1)); | |
| 2998 stb(scratch, MemOperand(dst)); | |
| 2999 addi(dst, dst, Operand(1)); | |
| 3000 bdnz(&byte_loop_1); | |
| 3001 | |
| 3002 bind(&done); | 3029 bind(&done); |
| 3003 } | 3030 } |
| 3004 | 3031 |
| 3005 | |
| 3006 void MacroAssembler::InitializeNFieldsWithFiller(Register current_address, | 3032 void MacroAssembler::InitializeNFieldsWithFiller(Register current_address, |
| 3007 Register count, | 3033 Register count, |
| 3008 Register filler) { | 3034 Register filler) { |
| 3009 Label loop; | 3035 Label loop; |
| 3010 mtctr(count); | |
| 3011 bind(&loop); | 3036 bind(&loop); |
| 3012 StoreP(filler, MemOperand(current_address)); | 3037 StoreP(filler, MemOperand(current_address)); |
| 3013 addi(current_address, current_address, Operand(kPointerSize)); | 3038 AddP(current_address, current_address, Operand(kPointerSize)); |
| 3014 bdnz(&loop); | 3039 BranchOnCount(r1, &loop); |
| 3015 } | 3040 } |
| 3016 | 3041 |
| 3017 void MacroAssembler::InitializeFieldsWithFiller(Register current_address, | 3042 void MacroAssembler::InitializeFieldsWithFiller(Register current_address, |
| 3018 Register end_address, | 3043 Register end_address, |
| 3019 Register filler) { | 3044 Register filler) { |
| 3020 Label done; | 3045 Label done; |
| 3021 sub(r0, end_address, current_address, LeaveOE, SetRC); | 3046 DCHECK(!filler.is(r1)); |
| 3022 beq(&done, cr0); | 3047 DCHECK(!current_address.is(r1)); |
| 3023 ShiftRightImm(r0, r0, Operand(kPointerSizeLog2)); | 3048 DCHECK(!end_address.is(r1)); |
| 3024 InitializeNFieldsWithFiller(current_address, r0, filler); | 3049 SubP(r1, end_address, current_address /*, LeaveOE, SetRC*/); |
| 3050 beq(&done, Label::kNear); |
| 3051 ShiftRightP(r1, r1, Operand(kPointerSizeLog2)); |
| 3052 InitializeNFieldsWithFiller(current_address, r1, filler); |
| 3025 bind(&done); | 3053 bind(&done); |
| 3026 } | 3054 } |
| 3027 | 3055 |
| 3028 | |
| 3029 void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte( | 3056 void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte( |
| 3030 Register first, Register second, Register scratch1, Register scratch2, | 3057 Register first, Register second, Register scratch1, Register scratch2, |
| 3031 Label* failure) { | 3058 Label* failure) { |
| 3032 const int kFlatOneByteStringMask = | 3059 const int kFlatOneByteStringMask = |
| 3033 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; | 3060 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; |
| 3034 const int kFlatOneByteStringTag = | 3061 const int kFlatOneByteStringTag = |
| 3035 kStringTag | kOneByteStringTag | kSeqStringTag; | 3062 kStringTag | kOneByteStringTag | kSeqStringTag; |
| 3036 andi(scratch1, first, Operand(kFlatOneByteStringMask)); | 3063 if (!scratch1.is(first)) LoadRR(scratch1, first); |
| 3037 andi(scratch2, second, Operand(kFlatOneByteStringMask)); | 3064 if (!scratch2.is(second)) LoadRR(scratch2, second); |
| 3038 cmpi(scratch1, Operand(kFlatOneByteStringTag)); | 3065 nilf(scratch1, Operand(kFlatOneByteStringMask)); |
| 3066 CmpP(scratch1, Operand(kFlatOneByteStringTag)); |
| 3039 bne(failure); | 3067 bne(failure); |
| 3040 cmpi(scratch2, Operand(kFlatOneByteStringTag)); | 3068 nilf(scratch2, Operand(kFlatOneByteStringMask)); |
| 3069 CmpP(scratch2, Operand(kFlatOneByteStringTag)); |
| 3041 bne(failure); | 3070 bne(failure); |
| 3042 } | 3071 } |
| 3043 | 3072 |
| 3044 | |
| 3045 void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(Register type, | 3073 void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(Register type, |
| 3046 Register scratch, | 3074 Register scratch, |
| 3047 Label* failure) { | 3075 Label* failure) { |
| 3048 const int kFlatOneByteStringMask = | 3076 const int kFlatOneByteStringMask = |
| 3049 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; | 3077 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; |
| 3050 const int kFlatOneByteStringTag = | 3078 const int kFlatOneByteStringTag = |
| 3051 kStringTag | kOneByteStringTag | kSeqStringTag; | 3079 kStringTag | kOneByteStringTag | kSeqStringTag; |
| 3052 andi(scratch, type, Operand(kFlatOneByteStringMask)); | 3080 |
| 3053 cmpi(scratch, Operand(kFlatOneByteStringTag)); | 3081 if (!scratch.is(type)) LoadRR(scratch, type); |
| 3082 nilf(scratch, Operand(kFlatOneByteStringMask)); |
| 3083 CmpP(scratch, Operand(kFlatOneByteStringTag)); |
| 3054 bne(failure); | 3084 bne(failure); |
| 3055 } | 3085 } |
| 3056 | 3086 |
| 3057 static const int kRegisterPassedArguments = 8; | 3087 static const int kRegisterPassedArguments = 5; |
| 3058 | |
| 3059 | 3088 |
| 3060 int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments, | 3089 int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments, |
| 3061 int num_double_arguments) { | 3090 int num_double_arguments) { |
| 3062 int stack_passed_words = 0; | 3091 int stack_passed_words = 0; |
| 3063 if (num_double_arguments > DoubleRegister::kNumRegisters) { | 3092 if (num_double_arguments > DoubleRegister::kNumRegisters) { |
| 3064 stack_passed_words += | 3093 stack_passed_words += |
| 3065 2 * (num_double_arguments - DoubleRegister::kNumRegisters); | 3094 2 * (num_double_arguments - DoubleRegister::kNumRegisters); |
| 3066 } | 3095 } |
| 3067 // Up to 8 simple arguments are passed in registers r3..r10. | 3096 // Up to five simple arguments are passed in registers r2..r6 |
| 3068 if (num_reg_arguments > kRegisterPassedArguments) { | 3097 if (num_reg_arguments > kRegisterPassedArguments) { |
| 3069 stack_passed_words += num_reg_arguments - kRegisterPassedArguments; | 3098 stack_passed_words += num_reg_arguments - kRegisterPassedArguments; |
| 3070 } | 3099 } |
| 3071 return stack_passed_words; | 3100 return stack_passed_words; |
| 3072 } | 3101 } |
| 3073 | 3102 |
| 3074 | |
| 3075 void MacroAssembler::EmitSeqStringSetCharCheck(Register string, Register index, | 3103 void MacroAssembler::EmitSeqStringSetCharCheck(Register string, Register index, |
| 3076 Register value, | 3104 Register value, |
| 3077 uint32_t encoding_mask) { | 3105 uint32_t encoding_mask) { |
| 3078 Label is_object; | 3106 Label is_object; |
| 3079 TestIfSmi(string, r0); | 3107 TestIfSmi(string); |
| 3080 Check(ne, kNonObject, cr0); | 3108 Check(ne, kNonObject, cr0); |
| 3081 | 3109 |
| 3082 LoadP(ip, FieldMemOperand(string, HeapObject::kMapOffset)); | 3110 LoadP(ip, FieldMemOperand(string, HeapObject::kMapOffset)); |
| 3083 lbz(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset)); | 3111 LoadlB(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset)); |
| 3084 | 3112 |
| 3085 andi(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask)); | 3113 AndP(ip, Operand(kStringRepresentationMask | kStringEncodingMask)); |
| 3086 cmpi(ip, Operand(encoding_mask)); | 3114 CmpP(ip, Operand(encoding_mask)); |
| 3087 Check(eq, kUnexpectedStringType); | 3115 Check(eq, kUnexpectedStringType); |
| 3088 | 3116 |
| 3089 // The index is assumed to be untagged coming in, tag it to compare with the | 3117 // The index is assumed to be untagged coming in, tag it to compare with the |
| 3090 // string length without using a temp register, it is restored at the end of | 3118 // string length without using a temp register, it is restored at the end of |
| 3091 // this function. | 3119 // this function. |
| 3092 #if !V8_TARGET_ARCH_PPC64 | 3120 #if !V8_TARGET_ARCH_S390X |
| 3093 Label index_tag_ok, index_tag_bad; | 3121 Label index_tag_ok, index_tag_bad; |
| 3094 JumpIfNotSmiCandidate(index, r0, &index_tag_bad); | 3122 JumpIfNotSmiCandidate(index, r0, &index_tag_bad); |
| 3095 #endif | 3123 #endif |
| 3096 SmiTag(index, index); | 3124 SmiTag(index, index); |
| 3097 #if !V8_TARGET_ARCH_PPC64 | 3125 #if !V8_TARGET_ARCH_S390X |
| 3098 b(&index_tag_ok); | 3126 b(&index_tag_ok); |
| 3099 bind(&index_tag_bad); | 3127 bind(&index_tag_bad); |
| 3100 Abort(kIndexIsTooLarge); | 3128 Abort(kIndexIsTooLarge); |
| 3101 bind(&index_tag_ok); | 3129 bind(&index_tag_ok); |
| 3102 #endif | 3130 #endif |
| 3103 | 3131 |
| 3104 LoadP(ip, FieldMemOperand(string, String::kLengthOffset)); | 3132 LoadP(ip, FieldMemOperand(string, String::kLengthOffset)); |
| 3105 cmp(index, ip); | 3133 CmpP(index, ip); |
| 3106 Check(lt, kIndexIsTooLarge); | 3134 Check(lt, kIndexIsTooLarge); |
| 3107 | 3135 |
| 3108 DCHECK(Smi::FromInt(0) == 0); | 3136 DCHECK(Smi::FromInt(0) == 0); |
| 3109 cmpi(index, Operand::Zero()); | 3137 CmpP(index, Operand::Zero()); |
| 3110 Check(ge, kIndexIsNegative); | 3138 Check(ge, kIndexIsNegative); |
| 3111 | 3139 |
| 3112 SmiUntag(index, index); | 3140 SmiUntag(index, index); |
| 3113 } | 3141 } |
| 3114 | 3142 |
| 3115 | |
| 3116 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, | 3143 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, |
| 3117 int num_double_arguments, | 3144 int num_double_arguments, |
| 3118 Register scratch) { | 3145 Register scratch) { |
| 3119 int frame_alignment = ActivationFrameAlignment(); | 3146 int frame_alignment = ActivationFrameAlignment(); |
| 3120 int stack_passed_arguments = | 3147 int stack_passed_arguments = |
| 3121 CalculateStackPassedWords(num_reg_arguments, num_double_arguments); | 3148 CalculateStackPassedWords(num_reg_arguments, num_double_arguments); |
| 3122 int stack_space = kNumRequiredStackFrameSlots; | 3149 int stack_space = kNumRequiredStackFrameSlots; |
| 3123 | |
| 3124 if (frame_alignment > kPointerSize) { | 3150 if (frame_alignment > kPointerSize) { |
| 3125 // Make stack end at alignment and make room for stack arguments | 3151 // Make stack end at alignment and make room for stack arguments |
| 3126 // -- preserving original value of sp. | 3152 // -- preserving original value of sp. |
| 3127 mr(scratch, sp); | 3153 LoadRR(scratch, sp); |
| 3128 addi(sp, sp, Operand(-(stack_passed_arguments + 1) * kPointerSize)); | 3154 lay(sp, MemOperand(sp, -(stack_passed_arguments + 1) * kPointerSize)); |
| 3129 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); | 3155 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); |
| 3130 ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment))); | 3156 ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment))); |
| 3131 StoreP(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); | 3157 StoreP(scratch, MemOperand(sp, (stack_passed_arguments)*kPointerSize)); |
| 3132 } else { | 3158 } else { |
| 3133 // Make room for stack arguments | |
| 3134 stack_space += stack_passed_arguments; | 3159 stack_space += stack_passed_arguments; |
| 3135 } | 3160 } |
| 3136 | 3161 lay(sp, MemOperand(sp, -(stack_space)*kPointerSize)); |
| 3137 // Allocate frame with required slots to make ABI work. | |
| 3138 li(r0, Operand::Zero()); | |
| 3139 StorePU(r0, MemOperand(sp, -stack_space * kPointerSize)); | |
| 3140 } | 3162 } |
| 3141 | 3163 |
| 3142 | |
| 3143 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, | 3164 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, |
| 3144 Register scratch) { | 3165 Register scratch) { |
| 3145 PrepareCallCFunction(num_reg_arguments, 0, scratch); | 3166 PrepareCallCFunction(num_reg_arguments, 0, scratch); |
| 3146 } | 3167 } |
| 3147 | 3168 |
| 3169 void MacroAssembler::MovToFloatParameter(DoubleRegister src) { Move(d0, src); } |
| 3148 | 3170 |
| 3149 void MacroAssembler::MovToFloatParameter(DoubleRegister src) { Move(d1, src); } | 3171 void MacroAssembler::MovToFloatResult(DoubleRegister src) { Move(d0, src); } |
| 3150 | |
| 3151 | |
| 3152 void MacroAssembler::MovToFloatResult(DoubleRegister src) { Move(d1, src); } | |
| 3153 | |
| 3154 | 3172 |
| 3155 void MacroAssembler::MovToFloatParameters(DoubleRegister src1, | 3173 void MacroAssembler::MovToFloatParameters(DoubleRegister src1, |
| 3156 DoubleRegister src2) { | 3174 DoubleRegister src2) { |
| 3157 if (src2.is(d1)) { | 3175 if (src2.is(d0)) { |
| 3158 DCHECK(!src1.is(d2)); | 3176 DCHECK(!src1.is(d2)); |
| 3159 Move(d2, src2); | 3177 Move(d2, src2); |
| 3160 Move(d1, src1); | 3178 Move(d0, src1); |
| 3161 } else { | 3179 } else { |
| 3162 Move(d1, src1); | 3180 Move(d0, src1); |
| 3163 Move(d2, src2); | 3181 Move(d2, src2); |
| 3164 } | 3182 } |
| 3165 } | 3183 } |
| 3166 | 3184 |
| 3167 | |
| 3168 void MacroAssembler::CallCFunction(ExternalReference function, | 3185 void MacroAssembler::CallCFunction(ExternalReference function, |
| 3169 int num_reg_arguments, | 3186 int num_reg_arguments, |
| 3170 int num_double_arguments) { | 3187 int num_double_arguments) { |
| 3171 mov(ip, Operand(function)); | 3188 mov(ip, Operand(function)); |
| 3172 CallCFunctionHelper(ip, num_reg_arguments, num_double_arguments); | 3189 CallCFunctionHelper(ip, num_reg_arguments, num_double_arguments); |
| 3173 } | 3190 } |
| 3174 | 3191 |
| 3175 | |
| 3176 void MacroAssembler::CallCFunction(Register function, int num_reg_arguments, | 3192 void MacroAssembler::CallCFunction(Register function, int num_reg_arguments, |
| 3177 int num_double_arguments) { | 3193 int num_double_arguments) { |
| 3178 CallCFunctionHelper(function, num_reg_arguments, num_double_arguments); | 3194 CallCFunctionHelper(function, num_reg_arguments, num_double_arguments); |
| 3179 } | 3195 } |
| 3180 | 3196 |
| 3181 | |
| 3182 void MacroAssembler::CallCFunction(ExternalReference function, | 3197 void MacroAssembler::CallCFunction(ExternalReference function, |
| 3183 int num_arguments) { | 3198 int num_arguments) { |
| 3184 CallCFunction(function, num_arguments, 0); | 3199 CallCFunction(function, num_arguments, 0); |
| 3185 } | 3200 } |
| 3186 | 3201 |
| 3187 | |
| 3188 void MacroAssembler::CallCFunction(Register function, int num_arguments) { | 3202 void MacroAssembler::CallCFunction(Register function, int num_arguments) { |
| 3189 CallCFunction(function, num_arguments, 0); | 3203 CallCFunction(function, num_arguments, 0); |
| 3190 } | 3204 } |
| 3191 | 3205 |
| 3192 | |
| 3193 void MacroAssembler::CallCFunctionHelper(Register function, | 3206 void MacroAssembler::CallCFunctionHelper(Register function, |
| 3194 int num_reg_arguments, | 3207 int num_reg_arguments, |
| 3195 int num_double_arguments) { | 3208 int num_double_arguments) { |
| 3196 DCHECK(has_frame()); | 3209 DCHECK(has_frame()); |
| 3197 | 3210 |
| 3198 // Just call directly. The function called cannot cause a GC, or | 3211 // Just call directly. The function called cannot cause a GC, or |
| 3199 // allow preemption, so the return address in the link register | 3212 // allow preemption, so the return address in the link register |
| 3200 // stays correct. | 3213 // stays correct. |
| 3201 Register dest = function; | 3214 Register dest = function; |
| 3202 if (ABI_USES_FUNCTION_DESCRIPTORS) { | 3215 if (ABI_CALL_VIA_IP) { |
| 3203 // AIX/PPC64BE Linux uses a function descriptor. When calling C code be | |
| 3204 // aware of this descriptor and pick up values from it | |
| 3205 LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(function, kPointerSize)); | |
| 3206 LoadP(ip, MemOperand(function, 0)); | |
| 3207 dest = ip; | |
| 3208 } else if (ABI_CALL_VIA_IP) { | |
| 3209 Move(ip, function); | 3216 Move(ip, function); |
| 3210 dest = ip; | 3217 dest = ip; |
| 3211 } | 3218 } |
| 3212 | 3219 |
| 3213 Call(dest); | 3220 Call(dest); |
| 3214 | 3221 |
| 3215 // Remove frame bought in PrepareCallCFunction | |
| 3216 int stack_passed_arguments = | 3222 int stack_passed_arguments = |
| 3217 CalculateStackPassedWords(num_reg_arguments, num_double_arguments); | 3223 CalculateStackPassedWords(num_reg_arguments, num_double_arguments); |
| 3218 int stack_space = kNumRequiredStackFrameSlots + stack_passed_arguments; | 3224 int stack_space = kNumRequiredStackFrameSlots + stack_passed_arguments; |
| 3219 if (ActivationFrameAlignment() > kPointerSize) { | 3225 if (ActivationFrameAlignment() > kPointerSize) { |
| 3226 // Load the original stack pointer (pre-alignment) from the stack |
| 3220 LoadP(sp, MemOperand(sp, stack_space * kPointerSize)); | 3227 LoadP(sp, MemOperand(sp, stack_space * kPointerSize)); |
| 3221 } else { | 3228 } else { |
| 3222 addi(sp, sp, Operand(stack_space * kPointerSize)); | 3229 la(sp, MemOperand(sp, stack_space * kPointerSize)); |
| 3223 } | 3230 } |
| 3224 } | 3231 } |
| 3225 | 3232 |
| 3226 | |
| 3227 void MacroAssembler::DecodeConstantPoolOffset(Register result, | |
| 3228 Register location) { | |
| 3229 Label overflow_access, done; | |
| 3230 DCHECK(!AreAliased(result, location, r0)); | |
| 3231 | |
| 3232 // Determine constant pool access type | |
| 3233 // Caller has already placed the instruction word at location in result. | |
| 3234 ExtractBitRange(r0, result, 31, 26); | |
| 3235 cmpi(r0, Operand(ADDIS >> 26)); | |
| 3236 beq(&overflow_access); | |
| 3237 | |
| 3238 // Regular constant pool access | |
| 3239 // extract the load offset | |
| 3240 andi(result, result, Operand(kImm16Mask)); | |
| 3241 b(&done); | |
| 3242 | |
| 3243 bind(&overflow_access); | |
| 3244 // Overflow constant pool access | |
| 3245 // shift addis immediate | |
| 3246 slwi(r0, result, Operand(16)); | |
| 3247 // sign-extend and add the load offset | |
| 3248 lwz(result, MemOperand(location, kInstrSize)); | |
| 3249 extsh(result, result); | |
| 3250 add(result, r0, result); | |
| 3251 | |
| 3252 bind(&done); | |
| 3253 } | |
| 3254 | |
| 3255 | |
| 3256 void MacroAssembler::CheckPageFlag( | 3233 void MacroAssembler::CheckPageFlag( |
| 3257 Register object, | 3234 Register object, |
| 3258 Register scratch, // scratch may be same register as object | 3235 Register scratch, // scratch may be same register as object |
| 3259 int mask, Condition cc, Label* condition_met) { | 3236 int mask, Condition cc, Label* condition_met) { |
| 3260 DCHECK(cc == ne || cc == eq); | 3237 DCHECK(cc == ne || cc == eq); |
| 3261 ClearRightImm(scratch, object, Operand(kPageSizeBits)); | 3238 ClearRightImm(scratch, object, Operand(kPageSizeBits)); |
| 3262 LoadP(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset)); | |
| 3263 | 3239 |
| 3264 And(r0, scratch, Operand(mask), SetRC); | 3240 if (base::bits::IsPowerOfTwo32(mask)) { |
| 3241 // If it's a power of two, we can use Test-Under-Mask Memory-Imm form |
| 3242 // which allows testing of a single byte in memory. |
| 3243 int32_t byte_offset = 4; |
| 3244 uint32_t shifted_mask = mask; |
| 3245 // Determine the byte offset to be tested |
| 3246 if (mask <= 0x80) { |
| 3247 byte_offset = kPointerSize - 1; |
| 3248 } else if (mask < 0x8000) { |
| 3249 byte_offset = kPointerSize - 2; |
| 3250 shifted_mask = mask >> 8; |
| 3251 } else if (mask < 0x800000) { |
| 3252 byte_offset = kPointerSize - 3; |
| 3253 shifted_mask = mask >> 16; |
| 3254 } else { |
| 3255 byte_offset = kPointerSize - 4; |
| 3256 shifted_mask = mask >> 24; |
| 3257 } |
| 3258 #if V8_TARGET_LITTLE_ENDIAN |
| 3259 // Reverse the byte_offset if emulating on little endian platform |
| 3260 byte_offset = kPointerSize - byte_offset - 1; |
| 3261 #endif |
| 3262 tm(MemOperand(scratch, MemoryChunk::kFlagsOffset + byte_offset), |
| 3263 Operand(shifted_mask)); |
| 3264 } else { |
| 3265 LoadP(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset)); |
| 3266 AndP(r0, scratch, Operand(mask)); |
| 3267 } |
| 3268 // Should be okay to remove rc |
| 3265 | 3269 |
| 3266 if (cc == ne) { | 3270 if (cc == ne) { |
| 3267 bne(condition_met, cr0); | 3271 bne(condition_met); |
| 3268 } | 3272 } |
| 3269 if (cc == eq) { | 3273 if (cc == eq) { |
| 3270 beq(condition_met, cr0); | 3274 beq(condition_met); |
| 3271 } | 3275 } |
| 3272 } | 3276 } |
| 3273 | 3277 |
| 3274 | |
| 3275 void MacroAssembler::JumpIfBlack(Register object, Register scratch0, | 3278 void MacroAssembler::JumpIfBlack(Register object, Register scratch0, |
| 3276 Register scratch1, Label* on_black) { | 3279 Register scratch1, Label* on_black) { |
| 3277 HasColor(object, scratch0, scratch1, on_black, 1, 1); // kBlackBitPattern. | 3280 HasColor(object, scratch0, scratch1, on_black, 1, 1); // kBlackBitPattern. |
| 3278 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); | 3281 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); |
| 3279 } | 3282 } |
| 3280 | 3283 |
| 3281 | |
| 3282 void MacroAssembler::HasColor(Register object, Register bitmap_scratch, | 3284 void MacroAssembler::HasColor(Register object, Register bitmap_scratch, |
| 3283 Register mask_scratch, Label* has_color, | 3285 Register mask_scratch, Label* has_color, |
| 3284 int first_bit, int second_bit) { | 3286 int first_bit, int second_bit) { |
| 3285 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, no_reg)); | 3287 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, no_reg)); |
| 3286 | 3288 |
| 3287 GetMarkBits(object, bitmap_scratch, mask_scratch); | 3289 GetMarkBits(object, bitmap_scratch, mask_scratch); |
| 3288 | 3290 |
| 3289 Label other_color, word_boundary; | 3291 Label other_color, word_boundary; |
| 3290 lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); | 3292 LoadlW(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); |
| 3291 // Test the first bit | 3293 // Test the first bit |
| 3292 and_(r0, ip, mask_scratch, SetRC); | 3294 AndP(r0, ip, mask_scratch /*, SetRC*/); // Should be okay to remove rc |
| 3293 b(first_bit == 1 ? eq : ne, &other_color, cr0); | 3295 b(first_bit == 1 ? eq : ne, &other_color, Label::kNear); |
| 3294 // Shift left 1 | 3296 // Shift left 1 |
| 3295 // May need to load the next cell | 3297 // May need to load the next cell |
| 3296 slwi(mask_scratch, mask_scratch, Operand(1), SetRC); | 3298 sll(mask_scratch, Operand(1) /*, SetRC*/); |
| 3297 beq(&word_boundary, cr0); | 3299 LoadAndTest32(mask_scratch, mask_scratch); |
| 3300 beq(&word_boundary, Label::kNear); |
| 3298 // Test the second bit | 3301 // Test the second bit |
| 3299 and_(r0, ip, mask_scratch, SetRC); | 3302 AndP(r0, ip, mask_scratch /*, SetRC*/); // Should be okay to remove rc |
| 3300 b(second_bit == 1 ? ne : eq, has_color, cr0); | 3303 b(second_bit == 1 ? ne : eq, has_color); |
| 3301 b(&other_color); | 3304 b(&other_color, Label::kNear); |
| 3302 | 3305 |
| 3303 bind(&word_boundary); | 3306 bind(&word_boundary); |
| 3304 lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize + kIntSize)); | 3307 LoadlW(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize + kIntSize)); |
| 3305 andi(r0, ip, Operand(1)); | 3308 AndP(r0, ip, Operand(1)); |
| 3306 b(second_bit == 1 ? ne : eq, has_color, cr0); | 3309 b(second_bit == 1 ? ne : eq, has_color); |
| 3307 bind(&other_color); | 3310 bind(&other_color); |
| 3308 } | 3311 } |
| 3309 | 3312 |
| 3310 | |
| 3311 void MacroAssembler::GetMarkBits(Register addr_reg, Register bitmap_reg, | 3313 void MacroAssembler::GetMarkBits(Register addr_reg, Register bitmap_reg, |
| 3312 Register mask_reg) { | 3314 Register mask_reg) { |
| 3313 DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg)); | 3315 DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg)); |
| 3314 DCHECK((~Page::kPageAlignmentMask & 0xffff) == 0); | 3316 LoadRR(bitmap_reg, addr_reg); |
| 3315 lis(r0, Operand((~Page::kPageAlignmentMask >> 16))); | 3317 nilf(bitmap_reg, Operand(~Page::kPageAlignmentMask)); |
| 3316 and_(bitmap_reg, addr_reg, r0); | |
| 3317 const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2; | 3318 const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2; |
| 3318 ExtractBitRange(mask_reg, addr_reg, kLowBits - 1, kPointerSizeLog2); | 3319 ExtractBitRange(mask_reg, addr_reg, kLowBits - 1, kPointerSizeLog2); |
| 3319 ExtractBitRange(ip, addr_reg, kPageSizeBits - 1, kLowBits); | 3320 ExtractBitRange(ip, addr_reg, kPageSizeBits - 1, kLowBits); |
| 3320 ShiftLeftImm(ip, ip, Operand(Bitmap::kBytesPerCellLog2)); | 3321 ShiftLeftP(ip, ip, Operand(Bitmap::kBytesPerCellLog2)); |
| 3321 add(bitmap_reg, bitmap_reg, ip); | 3322 AddP(bitmap_reg, ip); |
| 3322 li(ip, Operand(1)); | 3323 LoadRR(ip, mask_reg); // Have to do some funky reg shuffling as |
| 3323 slw(mask_reg, ip, mask_reg); | 3324 // 31-bit shift left clobbers on s390. |
| 3325 LoadImmP(mask_reg, Operand(1)); |
| 3326 ShiftLeftP(mask_reg, mask_reg, ip); |
| 3324 } | 3327 } |
| 3325 | 3328 |
| 3326 | |
| 3327 void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch, | 3329 void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch, |
| 3328 Register mask_scratch, Register load_scratch, | 3330 Register mask_scratch, Register load_scratch, |
| 3329 Label* value_is_white) { | 3331 Label* value_is_white) { |
| 3330 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ip)); | 3332 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ip)); |
| 3331 GetMarkBits(value, bitmap_scratch, mask_scratch); | 3333 GetMarkBits(value, bitmap_scratch, mask_scratch); |
| 3332 | 3334 |
| 3333 // If the value is black or grey we don't need to do anything. | 3335 // If the value is black or grey we don't need to do anything. |
| 3334 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); | 3336 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); |
| 3335 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); | 3337 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); |
| 3336 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); | 3338 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); |
| 3337 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); | 3339 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); |
| 3338 | 3340 |
| 3339 // Since both black and grey have a 1 in the first position and white does | 3341 // Since both black and grey have a 1 in the first position and white does |
| 3340 // not have a 1 there we only need to check one bit. | 3342 // not have a 1 there we only need to check one bit. |
| 3341 lwz(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); | 3343 LoadlW(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); |
| 3342 and_(r0, mask_scratch, load_scratch, SetRC); | 3344 LoadRR(r0, load_scratch); |
| 3343 beq(value_is_white, cr0); | 3345 AndP(r0, mask_scratch); |
| 3346 beq(value_is_white); |
| 3344 } | 3347 } |
| 3345 | 3348 |
| 3346 | |
| 3347 // Saturate a value into 8-bit unsigned integer | 3349 // Saturate a value into 8-bit unsigned integer |
| 3348 // if input_value < 0, output_value is 0 | 3350 // if input_value < 0, output_value is 0 |
| 3349 // if input_value > 255, output_value is 255 | 3351 // if input_value > 255, output_value is 255 |
| 3350 // otherwise output_value is the input_value | 3352 // otherwise output_value is the input_value |
| 3351 void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) { | 3353 void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) { |
| 3352 int satval = (1 << 8) - 1; | 3354 int satval = (1 << 8) - 1; |
| 3353 | 3355 |
| 3354 if (CpuFeatures::IsSupported(ISELECT)) { | 3356 Label done, negative_label, overflow_label; |
| 3355 // set to 0 if negative | 3357 CmpP(input_reg, Operand::Zero()); |
| 3356 cmpi(input_reg, Operand::Zero()); | 3358 blt(&negative_label); |
| 3357 isel(lt, output_reg, r0, input_reg); | |
| 3358 | 3359 |
| 3359 // set to satval if > satval | 3360 CmpP(input_reg, Operand(satval)); |
| 3360 li(r0, Operand(satval)); | 3361 bgt(&overflow_label); |
| 3361 cmpi(output_reg, Operand(satval)); | 3362 if (!output_reg.is(input_reg)) { |
| 3362 isel(lt, output_reg, output_reg, r0); | 3363 LoadRR(output_reg, input_reg); |
| 3363 } else { | 3364 } |
| 3364 Label done, negative_label, overflow_label; | 3365 b(&done); |
| 3365 cmpi(input_reg, Operand::Zero()); | |
| 3366 blt(&negative_label); | |
| 3367 | 3366 |
| 3368 cmpi(input_reg, Operand(satval)); | 3367 bind(&negative_label); |
| 3369 bgt(&overflow_label); | 3368 LoadImmP(output_reg, Operand::Zero()); // set to 0 if negative |
| 3370 if (!output_reg.is(input_reg)) { | 3369 b(&done); |
| 3371 mr(output_reg, input_reg); | |
| 3372 } | |
| 3373 b(&done); | |
| 3374 | 3370 |
| 3375 bind(&negative_label); | 3371 bind(&overflow_label); // set to satval if > satval |
| 3376 li(output_reg, Operand::Zero()); // set to 0 if negative | 3372 LoadImmP(output_reg, Operand(satval)); |
| 3377 b(&done); | |
| 3378 | 3373 |
| 3379 bind(&overflow_label); // set to satval if > satval | 3374 bind(&done); |
| 3380 li(output_reg, Operand(satval)); | |
| 3381 | |
| 3382 bind(&done); | |
| 3383 } | |
| 3384 } | 3375 } |
| 3385 | 3376 |
| 3386 | |
| 3387 void MacroAssembler::SetRoundingMode(FPRoundingMode RN) { mtfsfi(7, RN); } | |
| 3388 | |
| 3389 | |
| 3390 void MacroAssembler::ResetRoundingMode() { | |
| 3391 mtfsfi(7, kRoundToNearest); // reset (default is kRoundToNearest) | |
| 3392 } | |
| 3393 | |
| 3394 | |
| 3395 void MacroAssembler::ClampDoubleToUint8(Register result_reg, | 3377 void MacroAssembler::ClampDoubleToUint8(Register result_reg, |
| 3396 DoubleRegister input_reg, | 3378 DoubleRegister input_reg, |
| 3397 DoubleRegister double_scratch) { | 3379 DoubleRegister double_scratch) { |
| 3398 Label above_zero; | 3380 Label above_zero; |
| 3399 Label done; | 3381 Label done; |
| 3400 Label in_bounds; | 3382 Label in_bounds; |
| 3401 | 3383 |
| 3402 LoadDoubleLiteral(double_scratch, 0.0, result_reg); | 3384 LoadDoubleLiteral(double_scratch, 0.0, result_reg); |
| 3403 fcmpu(input_reg, double_scratch); | 3385 cdbr(input_reg, double_scratch); |
| 3404 bgt(&above_zero); | 3386 bgt(&above_zero, Label::kNear); |
| 3405 | 3387 |
| 3406 // Double value is less than zero, NaN or Inf, return 0. | 3388 // Double value is less than zero, NaN or Inf, return 0. |
| 3407 LoadIntLiteral(result_reg, 0); | 3389 LoadIntLiteral(result_reg, 0); |
| 3408 b(&done); | 3390 b(&done, Label::kNear); |
| 3409 | 3391 |
| 3410 // Double value is >= 255, return 255. | 3392 // Double value is >= 255, return 255. |
| 3411 bind(&above_zero); | 3393 bind(&above_zero); |
| 3412 LoadDoubleLiteral(double_scratch, 255.0, result_reg); | 3394 LoadDoubleLiteral(double_scratch, 255.0, result_reg); |
| 3413 fcmpu(input_reg, double_scratch); | 3395 cdbr(input_reg, double_scratch); |
| 3414 ble(&in_bounds); | 3396 ble(&in_bounds, Label::kNear); |
| 3415 LoadIntLiteral(result_reg, 255); | 3397 LoadIntLiteral(result_reg, 255); |
| 3416 b(&done); | 3398 b(&done, Label::kNear); |
| 3417 | 3399 |
| 3418 // In 0-255 range, round and truncate. | 3400 // In 0-255 range, round and truncate. |
| 3419 bind(&in_bounds); | 3401 bind(&in_bounds); |
| 3420 | 3402 |
| 3421 // round to nearest (default rounding mode) | 3403 // round to nearest (default rounding mode) |
| 3422 fctiw(double_scratch, input_reg); | 3404 cfdbr(ROUND_TO_NEAREST_WITH_TIES_TO_EVEN, result_reg, input_reg); |
| 3423 MovDoubleLowToInt(result_reg, double_scratch); | |
| 3424 bind(&done); | 3405 bind(&done); |
| 3425 } | 3406 } |
| 3426 | 3407 |
| 3427 | |
| 3428 void MacroAssembler::LoadInstanceDescriptors(Register map, | 3408 void MacroAssembler::LoadInstanceDescriptors(Register map, |
| 3429 Register descriptors) { | 3409 Register descriptors) { |
| 3430 LoadP(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset)); | 3410 LoadP(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset)); |
| 3431 } | 3411 } |
| 3432 | 3412 |
| 3433 | |
| 3434 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { | 3413 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { |
| 3435 lwz(dst, FieldMemOperand(map, Map::kBitField3Offset)); | 3414 LoadlW(dst, FieldMemOperand(map, Map::kBitField3Offset)); |
| 3436 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); | 3415 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); |
| 3437 } | 3416 } |
| 3438 | 3417 |
| 3439 | |
| 3440 void MacroAssembler::EnumLength(Register dst, Register map) { | 3418 void MacroAssembler::EnumLength(Register dst, Register map) { |
| 3441 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0); | 3419 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0); |
| 3442 lwz(dst, FieldMemOperand(map, Map::kBitField3Offset)); | 3420 LoadW(dst, FieldMemOperand(map, Map::kBitField3Offset)); |
| 3443 ExtractBitMask(dst, dst, Map::EnumLengthBits::kMask); | 3421 And(dst, Operand(Map::EnumLengthBits::kMask)); |
| 3444 SmiTag(dst); | 3422 SmiTag(dst); |
| 3445 } | 3423 } |
| 3446 | 3424 |
| 3447 | |
| 3448 void MacroAssembler::LoadAccessor(Register dst, Register holder, | 3425 void MacroAssembler::LoadAccessor(Register dst, Register holder, |
| 3449 int accessor_index, | 3426 int accessor_index, |
| 3450 AccessorComponent accessor) { | 3427 AccessorComponent accessor) { |
| 3451 LoadP(dst, FieldMemOperand(holder, HeapObject::kMapOffset)); | 3428 LoadP(dst, FieldMemOperand(holder, HeapObject::kMapOffset)); |
| 3452 LoadInstanceDescriptors(dst, dst); | 3429 LoadInstanceDescriptors(dst, dst); |
| 3453 LoadP(dst, | 3430 LoadP(dst, |
| 3454 FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index))); | 3431 FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index))); |
| 3455 const int getterOffset = AccessorPair::kGetterOffset; | 3432 const int getterOffset = AccessorPair::kGetterOffset; |
| 3456 const int setterOffset = AccessorPair::kSetterOffset; | 3433 const int setterOffset = AccessorPair::kSetterOffset; |
| 3457 int offset = ((accessor == ACCESSOR_GETTER) ? getterOffset : setterOffset); | 3434 int offset = ((accessor == ACCESSOR_GETTER) ? getterOffset : setterOffset); |
| 3458 LoadP(dst, FieldMemOperand(dst, offset)); | 3435 LoadP(dst, FieldMemOperand(dst, offset)); |
| 3459 } | 3436 } |
| 3460 | 3437 |
| 3461 | |
| 3462 void MacroAssembler::CheckEnumCache(Label* call_runtime) { | 3438 void MacroAssembler::CheckEnumCache(Label* call_runtime) { |
| 3463 Register null_value = r8; | 3439 Register null_value = r7; |
| 3464 Register empty_fixed_array_value = r9; | 3440 Register empty_fixed_array_value = r8; |
| 3465 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); | 3441 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); |
| 3466 Label next, start; | 3442 Label next, start; |
| 3467 mr(r5, r3); | 3443 LoadRR(r4, r2); |
| 3468 | 3444 |
| 3469 // Check if the enum length field is properly initialized, indicating that | 3445 // Check if the enum length field is properly initialized, indicating that |
| 3470 // there is an enum cache. | 3446 // there is an enum cache. |
| 3471 LoadP(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); | 3447 LoadP(r3, FieldMemOperand(r4, HeapObject::kMapOffset)); |
| 3472 | 3448 |
| 3473 EnumLength(r6, r4); | 3449 EnumLength(r5, r3); |
| 3474 CmpSmiLiteral(r6, Smi::FromInt(kInvalidEnumCacheSentinel), r0); | 3450 CmpSmiLiteral(r5, Smi::FromInt(kInvalidEnumCacheSentinel), r0); |
| 3475 beq(call_runtime); | 3451 beq(call_runtime); |
| 3476 | 3452 |
| 3477 LoadRoot(null_value, Heap::kNullValueRootIndex); | 3453 LoadRoot(null_value, Heap::kNullValueRootIndex); |
| 3478 b(&start); | 3454 b(&start, Label::kNear); |
| 3479 | 3455 |
| 3480 bind(&next); | 3456 bind(&next); |
| 3481 LoadP(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); | 3457 LoadP(r3, FieldMemOperand(r4, HeapObject::kMapOffset)); |
| 3482 | 3458 |
| 3483 // For all objects but the receiver, check that the cache is empty. | 3459 // For all objects but the receiver, check that the cache is empty. |
| 3484 EnumLength(r6, r4); | 3460 EnumLength(r5, r3); |
| 3485 CmpSmiLiteral(r6, Smi::FromInt(0), r0); | 3461 CmpSmiLiteral(r5, Smi::FromInt(0), r0); |
| 3486 bne(call_runtime); | 3462 bne(call_runtime); |
| 3487 | 3463 |
| 3488 bind(&start); | 3464 bind(&start); |
| 3489 | 3465 |
| 3490 // Check that there are no elements. Register r5 contains the current JS | 3466 // Check that there are no elements. Register r4 contains the current JS |
| 3491 // object we've reached through the prototype chain. | 3467 // object we've reached through the prototype chain. |
| 3492 Label no_elements; | 3468 Label no_elements; |
| 3493 LoadP(r5, FieldMemOperand(r5, JSObject::kElementsOffset)); | 3469 LoadP(r4, FieldMemOperand(r4, JSObject::kElementsOffset)); |
| 3494 cmp(r5, empty_fixed_array_value); | 3470 CmpP(r4, empty_fixed_array_value); |
| 3495 beq(&no_elements); | 3471 beq(&no_elements, Label::kNear); |
| 3496 | 3472 |
| 3497 // Second chance, the object may be using the empty slow element dictionary. | 3473 // Second chance, the object may be using the empty slow element dictionary. |
| 3498 CompareRoot(r5, Heap::kEmptySlowElementDictionaryRootIndex); | 3474 CompareRoot(r5, Heap::kEmptySlowElementDictionaryRootIndex); |
| 3499 bne(call_runtime); | 3475 bne(call_runtime); |
| 3500 | 3476 |
| 3501 bind(&no_elements); | 3477 bind(&no_elements); |
| 3502 LoadP(r5, FieldMemOperand(r4, Map::kPrototypeOffset)); | 3478 LoadP(r4, FieldMemOperand(r3, Map::kPrototypeOffset)); |
| 3503 cmp(r5, null_value); | 3479 CmpP(r4, null_value); |
| 3504 bne(&next); | 3480 bne(&next); |
| 3505 } | 3481 } |
| 3506 | 3482 |
| 3507 | |
| 3508 //////////////////////////////////////////////////////////////////////////////// | 3483 //////////////////////////////////////////////////////////////////////////////// |
| 3509 // | 3484 // |
| 3510 // New MacroAssembler Interfaces added for PPC | 3485 // New MacroAssembler Interfaces added for S390 |
| 3511 // | 3486 // |
| 3512 //////////////////////////////////////////////////////////////////////////////// | 3487 //////////////////////////////////////////////////////////////////////////////// |
| 3513 void MacroAssembler::LoadIntLiteral(Register dst, int value) { | 3488 // Primarily used for loading constants |
| 3514 mov(dst, Operand(value)); | 3489 // This should really move to be in macro-assembler as it |
| 3515 } | 3490 // is really a pseudo instruction |
| 3516 | 3491 // Some usages of this intend for a FIXED_SEQUENCE to be used |
| 3517 | 3492 // @TODO - break this dependency so we can optimize mov() in general |
| 3518 void MacroAssembler::LoadSmiLiteral(Register dst, Smi* smi) { | 3493 // and only use the generic version when we require a fixed sequence |
| 3519 mov(dst, Operand(smi)); | |
| 3520 } | |
| 3521 | |
| 3522 | |
| 3523 void MacroAssembler::LoadDoubleLiteral(DoubleRegister result, double value, | |
| 3524 Register scratch) { | |
| 3525 if (FLAG_enable_embedded_constant_pool && is_constant_pool_available() && | |
| 3526 !(scratch.is(r0) && ConstantPoolAccessIsInOverflow())) { | |
| 3527 ConstantPoolEntry::Access access = ConstantPoolAddEntry(value); | |
| 3528 if (access == ConstantPoolEntry::OVERFLOWED) { | |
| 3529 addis(scratch, kConstantPoolRegister, Operand::Zero()); | |
| 3530 lfd(result, MemOperand(scratch, 0)); | |
| 3531 } else { | |
| 3532 lfd(result, MemOperand(kConstantPoolRegister, 0)); | |
| 3533 } | |
| 3534 return; | |
| 3535 } | |
| 3536 | |
| 3537 // avoid gcc strict aliasing error using union cast | |
| 3538 union { | |
| 3539 double dval; | |
| 3540 #if V8_TARGET_ARCH_PPC64 | |
| 3541 intptr_t ival; | |
| 3542 #else | |
| 3543 intptr_t ival[2]; | |
| 3544 #endif | |
| 3545 } litVal; | |
| 3546 | |
| 3547 litVal.dval = value; | |
| 3548 | |
| 3549 #if V8_TARGET_ARCH_PPC64 | |
| 3550 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { | |
| 3551 mov(scratch, Operand(litVal.ival)); | |
| 3552 mtfprd(result, scratch); | |
| 3553 return; | |
| 3554 } | |
| 3555 #endif | |
| 3556 | |
| 3557 addi(sp, sp, Operand(-kDoubleSize)); | |
| 3558 #if V8_TARGET_ARCH_PPC64 | |
| 3559 mov(scratch, Operand(litVal.ival)); | |
| 3560 std(scratch, MemOperand(sp)); | |
| 3561 #else | |
| 3562 LoadIntLiteral(scratch, litVal.ival[0]); | |
| 3563 stw(scratch, MemOperand(sp, 0)); | |
| 3564 LoadIntLiteral(scratch, litVal.ival[1]); | |
| 3565 stw(scratch, MemOperand(sp, 4)); | |
| 3566 #endif | |
| 3567 nop(GROUP_ENDING_NOP); // LHS/RAW optimization | |
| 3568 lfd(result, MemOperand(sp, 0)); | |
| 3569 addi(sp, sp, Operand(kDoubleSize)); | |
| 3570 } | |
| 3571 | |
| 3572 | |
| 3573 void MacroAssembler::MovIntToDouble(DoubleRegister dst, Register src, | |
| 3574 Register scratch) { | |
| 3575 // sign-extend src to 64-bit | |
| 3576 #if V8_TARGET_ARCH_PPC64 | |
| 3577 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { | |
| 3578 mtfprwa(dst, src); | |
| 3579 return; | |
| 3580 } | |
| 3581 #endif | |
| 3582 | |
| 3583 DCHECK(!src.is(scratch)); | |
| 3584 subi(sp, sp, Operand(kDoubleSize)); | |
| 3585 #if V8_TARGET_ARCH_PPC64 | |
| 3586 extsw(scratch, src); | |
| 3587 std(scratch, MemOperand(sp, 0)); | |
| 3588 #else | |
| 3589 srawi(scratch, src, 31); | |
| 3590 stw(scratch, MemOperand(sp, Register::kExponentOffset)); | |
| 3591 stw(src, MemOperand(sp, Register::kMantissaOffset)); | |
| 3592 #endif | |
| 3593 nop(GROUP_ENDING_NOP); // LHS/RAW optimization | |
| 3594 lfd(dst, MemOperand(sp, 0)); | |
| 3595 addi(sp, sp, Operand(kDoubleSize)); | |
| 3596 } | |
| 3597 | |
| 3598 | |
| 3599 void MacroAssembler::MovUnsignedIntToDouble(DoubleRegister dst, Register src, | |
| 3600 Register scratch) { | |
| 3601 // zero-extend src to 64-bit | |
| 3602 #if V8_TARGET_ARCH_PPC64 | |
| 3603 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { | |
| 3604 mtfprwz(dst, src); | |
| 3605 return; | |
| 3606 } | |
| 3607 #endif | |
| 3608 | |
| 3609 DCHECK(!src.is(scratch)); | |
| 3610 subi(sp, sp, Operand(kDoubleSize)); | |
| 3611 #if V8_TARGET_ARCH_PPC64 | |
| 3612 clrldi(scratch, src, Operand(32)); | |
| 3613 std(scratch, MemOperand(sp, 0)); | |
| 3614 #else | |
| 3615 li(scratch, Operand::Zero()); | |
| 3616 stw(scratch, MemOperand(sp, Register::kExponentOffset)); | |
| 3617 stw(src, MemOperand(sp, Register::kMantissaOffset)); | |
| 3618 #endif | |
| 3619 nop(GROUP_ENDING_NOP); // LHS/RAW optimization | |
| 3620 lfd(dst, MemOperand(sp, 0)); | |
| 3621 addi(sp, sp, Operand(kDoubleSize)); | |
| 3622 } | |
| 3623 | |
| 3624 | |
| 3625 void MacroAssembler::MovInt64ToDouble(DoubleRegister dst, | |
| 3626 #if !V8_TARGET_ARCH_PPC64 | |
| 3627 Register src_hi, | |
| 3628 #endif | |
| 3629 Register src) { | |
| 3630 #if V8_TARGET_ARCH_PPC64 | |
| 3631 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { | |
| 3632 mtfprd(dst, src); | |
| 3633 return; | |
| 3634 } | |
| 3635 #endif | |
| 3636 | |
| 3637 subi(sp, sp, Operand(kDoubleSize)); | |
| 3638 #if V8_TARGET_ARCH_PPC64 | |
| 3639 std(src, MemOperand(sp, 0)); | |
| 3640 #else | |
| 3641 stw(src_hi, MemOperand(sp, Register::kExponentOffset)); | |
| 3642 stw(src, MemOperand(sp, Register::kMantissaOffset)); | |
| 3643 #endif | |
| 3644 nop(GROUP_ENDING_NOP); // LHS/RAW optimization | |
| 3645 lfd(dst, MemOperand(sp, 0)); | |
| 3646 addi(sp, sp, Operand(kDoubleSize)); | |
| 3647 } | |
| 3648 | |
| 3649 | |
| 3650 #if V8_TARGET_ARCH_PPC64 | |
| 3651 void MacroAssembler::MovInt64ComponentsToDouble(DoubleRegister dst, | |
| 3652 Register src_hi, | |
| 3653 Register src_lo, | |
| 3654 Register scratch) { | |
| 3655 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { | |
| 3656 sldi(scratch, src_hi, Operand(32)); | |
| 3657 rldimi(scratch, src_lo, 0, 32); | |
| 3658 mtfprd(dst, scratch); | |
| 3659 return; | |
| 3660 } | |
| 3661 | |
| 3662 subi(sp, sp, Operand(kDoubleSize)); | |
| 3663 stw(src_hi, MemOperand(sp, Register::kExponentOffset)); | |
| 3664 stw(src_lo, MemOperand(sp, Register::kMantissaOffset)); | |
| 3665 nop(GROUP_ENDING_NOP); // LHS/RAW optimization | |
| 3666 lfd(dst, MemOperand(sp)); | |
| 3667 addi(sp, sp, Operand(kDoubleSize)); | |
| 3668 } | |
| 3669 #endif | |
| 3670 | |
| 3671 | |
| 3672 void MacroAssembler::InsertDoubleLow(DoubleRegister dst, Register src, | |
| 3673 Register scratch) { | |
| 3674 #if V8_TARGET_ARCH_PPC64 | |
| 3675 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { | |
| 3676 mffprd(scratch, dst); | |
| 3677 rldimi(scratch, src, 0, 32); | |
| 3678 mtfprd(dst, scratch); | |
| 3679 return; | |
| 3680 } | |
| 3681 #endif | |
| 3682 | |
| 3683 subi(sp, sp, Operand(kDoubleSize)); | |
| 3684 stfd(dst, MemOperand(sp)); | |
| 3685 stw(src, MemOperand(sp, Register::kMantissaOffset)); | |
| 3686 nop(GROUP_ENDING_NOP); // LHS/RAW optimization | |
| 3687 lfd(dst, MemOperand(sp)); | |
| 3688 addi(sp, sp, Operand(kDoubleSize)); | |
| 3689 } | |
| 3690 | |
| 3691 | |
| 3692 void MacroAssembler::InsertDoubleHigh(DoubleRegister dst, Register src, | |
| 3693 Register scratch) { | |
| 3694 #if V8_TARGET_ARCH_PPC64 | |
| 3695 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { | |
| 3696 mffprd(scratch, dst); | |
| 3697 rldimi(scratch, src, 32, 0); | |
| 3698 mtfprd(dst, scratch); | |
| 3699 return; | |
| 3700 } | |
| 3701 #endif | |
| 3702 | |
| 3703 subi(sp, sp, Operand(kDoubleSize)); | |
| 3704 stfd(dst, MemOperand(sp)); | |
| 3705 stw(src, MemOperand(sp, Register::kExponentOffset)); | |
| 3706 nop(GROUP_ENDING_NOP); // LHS/RAW optimization | |
| 3707 lfd(dst, MemOperand(sp)); | |
| 3708 addi(sp, sp, Operand(kDoubleSize)); | |
| 3709 } | |
| 3710 | |
| 3711 | |
| 3712 void MacroAssembler::MovDoubleLowToInt(Register dst, DoubleRegister src) { | |
| 3713 #if V8_TARGET_ARCH_PPC64 | |
| 3714 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { | |
| 3715 mffprwz(dst, src); | |
| 3716 return; | |
| 3717 } | |
| 3718 #endif | |
| 3719 | |
| 3720 subi(sp, sp, Operand(kDoubleSize)); | |
| 3721 stfd(src, MemOperand(sp)); | |
| 3722 nop(GROUP_ENDING_NOP); // LHS/RAW optimization | |
| 3723 lwz(dst, MemOperand(sp, Register::kMantissaOffset)); | |
| 3724 addi(sp, sp, Operand(kDoubleSize)); | |
| 3725 } | |
| 3726 | |
| 3727 | |
| 3728 void MacroAssembler::MovDoubleHighToInt(Register dst, DoubleRegister src) { | |
| 3729 #if V8_TARGET_ARCH_PPC64 | |
| 3730 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { | |
| 3731 mffprd(dst, src); | |
| 3732 srdi(dst, dst, Operand(32)); | |
| 3733 return; | |
| 3734 } | |
| 3735 #endif | |
| 3736 | |
| 3737 subi(sp, sp, Operand(kDoubleSize)); | |
| 3738 stfd(src, MemOperand(sp)); | |
| 3739 nop(GROUP_ENDING_NOP); // LHS/RAW optimization | |
| 3740 lwz(dst, MemOperand(sp, Register::kExponentOffset)); | |
| 3741 addi(sp, sp, Operand(kDoubleSize)); | |
| 3742 } | |
| 3743 | |
| 3744 | |
| 3745 void MacroAssembler::MovDoubleToInt64( | |
| 3746 #if !V8_TARGET_ARCH_PPC64 | |
| 3747 Register dst_hi, | |
| 3748 #endif | |
| 3749 Register dst, DoubleRegister src) { | |
| 3750 #if V8_TARGET_ARCH_PPC64 | |
| 3751 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { | |
| 3752 mffprd(dst, src); | |
| 3753 return; | |
| 3754 } | |
| 3755 #endif | |
| 3756 | |
| 3757 subi(sp, sp, Operand(kDoubleSize)); | |
| 3758 stfd(src, MemOperand(sp)); | |
| 3759 nop(GROUP_ENDING_NOP); // LHS/RAW optimization | |
| 3760 #if V8_TARGET_ARCH_PPC64 | |
| 3761 ld(dst, MemOperand(sp, 0)); | |
| 3762 #else | |
| 3763 lwz(dst_hi, MemOperand(sp, Register::kExponentOffset)); | |
| 3764 lwz(dst, MemOperand(sp, Register::kMantissaOffset)); | |
| 3765 #endif | |
| 3766 addi(sp, sp, Operand(kDoubleSize)); | |
| 3767 } | |
| 3768 | |
| 3769 | |
| 3770 void MacroAssembler::MovIntToFloat(DoubleRegister dst, Register src) { | |
| 3771 subi(sp, sp, Operand(kFloatSize)); | |
| 3772 stw(src, MemOperand(sp, 0)); | |
| 3773 nop(GROUP_ENDING_NOP); // LHS/RAW optimization | |
| 3774 lfs(dst, MemOperand(sp, 0)); | |
| 3775 addi(sp, sp, Operand(kFloatSize)); | |
| 3776 } | |
| 3777 | |
| 3778 | |
| 3779 void MacroAssembler::MovFloatToInt(Register dst, DoubleRegister src) { | |
| 3780 subi(sp, sp, Operand(kFloatSize)); | |
| 3781 frsp(src, src); | |
| 3782 stfs(src, MemOperand(sp, 0)); | |
| 3783 nop(GROUP_ENDING_NOP); // LHS/RAW optimization | |
| 3784 lwz(dst, MemOperand(sp, 0)); | |
| 3785 addi(sp, sp, Operand(kFloatSize)); | |
| 3786 } | |
| 3787 | |
| 3788 | |
| 3789 void MacroAssembler::Add(Register dst, Register src, intptr_t value, | |
| 3790 Register scratch) { | |
| 3791 if (is_int16(value)) { | |
| 3792 addi(dst, src, Operand(value)); | |
| 3793 } else { | |
| 3794 mov(scratch, Operand(value)); | |
| 3795 add(dst, src, scratch); | |
| 3796 } | |
| 3797 } | |
| 3798 | |
| 3799 | |
| 3800 void MacroAssembler::Cmpi(Register src1, const Operand& src2, Register scratch, | |
| 3801 CRegister cr) { | |
| 3802 intptr_t value = src2.immediate(); | |
| 3803 if (is_int16(value)) { | |
| 3804 cmpi(src1, src2, cr); | |
| 3805 } else { | |
| 3806 mov(scratch, src2); | |
| 3807 cmp(src1, scratch, cr); | |
| 3808 } | |
| 3809 } | |
| 3810 | |
| 3811 | |
| 3812 void MacroAssembler::Cmpli(Register src1, const Operand& src2, Register scratch, | |
| 3813 CRegister cr) { | |
| 3814 intptr_t value = src2.immediate(); | |
| 3815 if (is_uint16(value)) { | |
| 3816 cmpli(src1, src2, cr); | |
| 3817 } else { | |
| 3818 mov(scratch, src2); | |
| 3819 cmpl(src1, scratch, cr); | |
| 3820 } | |
| 3821 } | |
| 3822 | |
| 3823 | |
| 3824 void MacroAssembler::Cmpwi(Register src1, const Operand& src2, Register scratch, | |
| 3825 CRegister cr) { | |
| 3826 intptr_t value = src2.immediate(); | |
| 3827 if (is_int16(value)) { | |
| 3828 cmpwi(src1, src2, cr); | |
| 3829 } else { | |
| 3830 mov(scratch, src2); | |
| 3831 cmpw(src1, scratch, cr); | |
| 3832 } | |
| 3833 } | |
| 3834 | |
| 3835 | |
| 3836 void MacroAssembler::Cmplwi(Register src1, const Operand& src2, | |
| 3837 Register scratch, CRegister cr) { | |
| 3838 intptr_t value = src2.immediate(); | |
| 3839 if (is_uint16(value)) { | |
| 3840 cmplwi(src1, src2, cr); | |
| 3841 } else { | |
| 3842 mov(scratch, src2); | |
| 3843 cmplw(src1, scratch, cr); | |
| 3844 } | |
| 3845 } | |
| 3846 | |
| 3847 | |
| 3848 void MacroAssembler::And(Register ra, Register rs, const Operand& rb, | |
| 3849 RCBit rc) { | |
| 3850 if (rb.is_reg()) { | |
| 3851 and_(ra, rs, rb.rm(), rc); | |
| 3852 } else { | |
| 3853 if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == SetRC) { | |
| 3854 andi(ra, rs, rb); | |
| 3855 } else { | |
| 3856 // mov handles the relocation. | |
| 3857 DCHECK(!rs.is(r0)); | |
| 3858 mov(r0, rb); | |
| 3859 and_(ra, rs, r0, rc); | |
| 3860 } | |
| 3861 } | |
| 3862 } | |
| 3863 | |
| 3864 | |
| 3865 void MacroAssembler::Or(Register ra, Register rs, const Operand& rb, RCBit rc) { | |
| 3866 if (rb.is_reg()) { | |
| 3867 orx(ra, rs, rb.rm(), rc); | |
| 3868 } else { | |
| 3869 if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == LeaveRC) { | |
| 3870 ori(ra, rs, rb); | |
| 3871 } else { | |
| 3872 // mov handles the relocation. | |
| 3873 DCHECK(!rs.is(r0)); | |
| 3874 mov(r0, rb); | |
| 3875 orx(ra, rs, r0, rc); | |
| 3876 } | |
| 3877 } | |
| 3878 } | |
| 3879 | |
| 3880 | |
| 3881 void MacroAssembler::Xor(Register ra, Register rs, const Operand& rb, | |
| 3882 RCBit rc) { | |
| 3883 if (rb.is_reg()) { | |
| 3884 xor_(ra, rs, rb.rm(), rc); | |
| 3885 } else { | |
| 3886 if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == LeaveRC) { | |
| 3887 xori(ra, rs, rb); | |
| 3888 } else { | |
| 3889 // mov handles the relocation. | |
| 3890 DCHECK(!rs.is(r0)); | |
| 3891 mov(r0, rb); | |
| 3892 xor_(ra, rs, r0, rc); | |
| 3893 } | |
| 3894 } | |
| 3895 } | |
| 3896 | |
| 3897 | |
| 3898 void MacroAssembler::CmpSmiLiteral(Register src1, Smi* smi, Register scratch, | |
| 3899 CRegister cr) { | |
| 3900 #if V8_TARGET_ARCH_PPC64 | |
| 3901 LoadSmiLiteral(scratch, smi); | |
| 3902 cmp(src1, scratch, cr); | |
| 3903 #else | |
| 3904 Cmpi(src1, Operand(smi), scratch, cr); | |
| 3905 #endif | |
| 3906 } | |
| 3907 | |
| 3908 | |
| 3909 void MacroAssembler::CmplSmiLiteral(Register src1, Smi* smi, Register scratch, | |
| 3910 CRegister cr) { | |
| 3911 #if V8_TARGET_ARCH_PPC64 | |
| 3912 LoadSmiLiteral(scratch, smi); | |
| 3913 cmpl(src1, scratch, cr); | |
| 3914 #else | |
| 3915 Cmpli(src1, Operand(smi), scratch, cr); | |
| 3916 #endif | |
| 3917 } | |
| 3918 | |
| 3919 | |
| 3920 void MacroAssembler::AddSmiLiteral(Register dst, Register src, Smi* smi, | |
| 3921 Register scratch) { | |
| 3922 #if V8_TARGET_ARCH_PPC64 | |
| 3923 LoadSmiLiteral(scratch, smi); | |
| 3924 add(dst, src, scratch); | |
| 3925 #else | |
| 3926 Add(dst, src, reinterpret_cast<intptr_t>(smi), scratch); | |
| 3927 #endif | |
| 3928 } | |
| 3929 | |
| 3930 | |
| 3931 void MacroAssembler::SubSmiLiteral(Register dst, Register src, Smi* smi, | |
| 3932 Register scratch) { | |
| 3933 #if V8_TARGET_ARCH_PPC64 | |
| 3934 LoadSmiLiteral(scratch, smi); | |
| 3935 sub(dst, src, scratch); | |
| 3936 #else | |
| 3937 Add(dst, src, -(reinterpret_cast<intptr_t>(smi)), scratch); | |
| 3938 #endif | |
| 3939 } | |
| 3940 | |
| 3941 | |
| 3942 void MacroAssembler::AndSmiLiteral(Register dst, Register src, Smi* smi, | |
| 3943 Register scratch, RCBit rc) { | |
| 3944 #if V8_TARGET_ARCH_PPC64 | |
| 3945 LoadSmiLiteral(scratch, smi); | |
| 3946 and_(dst, src, scratch, rc); | |
| 3947 #else | |
| 3948 And(dst, src, Operand(smi), rc); | |
| 3949 #endif | |
| 3950 } | |
| 3951 | |
| 3952 | |
| 3953 // Load a "pointer" sized value from the memory location | |
| 3954 void MacroAssembler::LoadP(Register dst, const MemOperand& mem, | |
| 3955 Register scratch) { | |
| 3956 int offset = mem.offset(); | |
| 3957 | |
| 3958 if (!is_int16(offset)) { | |
| 3959 /* cannot use d-form */ | |
| 3960 DCHECK(!scratch.is(no_reg)); | |
| 3961 mov(scratch, Operand(offset)); | |
| 3962 #if V8_TARGET_ARCH_PPC64 | |
| 3963 ldx(dst, MemOperand(mem.ra(), scratch)); | |
| 3964 #else | |
| 3965 lwzx(dst, MemOperand(mem.ra(), scratch)); | |
| 3966 #endif | |
| 3967 } else { | |
| 3968 #if V8_TARGET_ARCH_PPC64 | |
| 3969 int misaligned = (offset & 3); | |
| 3970 if (misaligned) { | |
| 3971 // adjust base to conform to offset alignment requirements | |
| 3972 // Todo: enhance to use scratch if dst is unsuitable | |
| 3973 DCHECK(!dst.is(r0)); | |
| 3974 addi(dst, mem.ra(), Operand((offset & 3) - 4)); | |
| 3975 ld(dst, MemOperand(dst, (offset & ~3) + 4)); | |
| 3976 } else { | |
| 3977 ld(dst, mem); | |
| 3978 } | |
| 3979 #else | |
| 3980 lwz(dst, mem); | |
| 3981 #endif | |
| 3982 } | |
| 3983 } | |
| 3984 | |
| 3985 | |
| 3986 // Store a "pointer" sized value to the memory location | |
| 3987 void MacroAssembler::StoreP(Register src, const MemOperand& mem, | |
| 3988 Register scratch) { | |
| 3989 int offset = mem.offset(); | |
| 3990 | |
| 3991 if (!is_int16(offset)) { | |
| 3992 /* cannot use d-form */ | |
| 3993 DCHECK(!scratch.is(no_reg)); | |
| 3994 mov(scratch, Operand(offset)); | |
| 3995 #if V8_TARGET_ARCH_PPC64 | |
| 3996 stdx(src, MemOperand(mem.ra(), scratch)); | |
| 3997 #else | |
| 3998 stwx(src, MemOperand(mem.ra(), scratch)); | |
| 3999 #endif | |
| 4000 } else { | |
| 4001 #if V8_TARGET_ARCH_PPC64 | |
| 4002 int misaligned = (offset & 3); | |
| 4003 if (misaligned) { | |
| 4004 // adjust base to conform to offset alignment requirements | |
| 4005 // a suitable scratch is required here | |
| 4006 DCHECK(!scratch.is(no_reg)); | |
| 4007 if (scratch.is(r0)) { | |
| 4008 LoadIntLiteral(scratch, offset); | |
| 4009 stdx(src, MemOperand(mem.ra(), scratch)); | |
| 4010 } else { | |
| 4011 addi(scratch, mem.ra(), Operand((offset & 3) - 4)); | |
| 4012 std(src, MemOperand(scratch, (offset & ~3) + 4)); | |
| 4013 } | |
| 4014 } else { | |
| 4015 std(src, mem); | |
| 4016 } | |
| 4017 #else | |
| 4018 stw(src, mem); | |
| 4019 #endif | |
| 4020 } | |
| 4021 } | |
| 4022 | |
| 4023 void MacroAssembler::LoadWordArith(Register dst, const MemOperand& mem, | |
| 4024 Register scratch) { | |
| 4025 int offset = mem.offset(); | |
| 4026 | |
| 4027 if (!is_int16(offset)) { | |
| 4028 DCHECK(!scratch.is(no_reg)); | |
| 4029 mov(scratch, Operand(offset)); | |
| 4030 lwax(dst, MemOperand(mem.ra(), scratch)); | |
| 4031 } else { | |
| 4032 #if V8_TARGET_ARCH_PPC64 | |
| 4033 int misaligned = (offset & 3); | |
| 4034 if (misaligned) { | |
| 4035 // adjust base to conform to offset alignment requirements | |
| 4036 // Todo: enhance to use scratch if dst is unsuitable | |
| 4037 DCHECK(!dst.is(r0)); | |
| 4038 addi(dst, mem.ra(), Operand((offset & 3) - 4)); | |
| 4039 lwa(dst, MemOperand(dst, (offset & ~3) + 4)); | |
| 4040 } else { | |
| 4041 lwa(dst, mem); | |
| 4042 } | |
| 4043 #else | |
| 4044 lwz(dst, mem); | |
| 4045 #endif | |
| 4046 } | |
| 4047 } | |
| 4048 | |
| 4049 | |
| 4050 // Variable length depending on whether offset fits into immediate field | |
| 4051 // MemOperand currently only supports d-form | |
| 4052 void MacroAssembler::LoadWord(Register dst, const MemOperand& mem, | |
| 4053 Register scratch) { | |
| 4054 Register base = mem.ra(); | |
| 4055 int offset = mem.offset(); | |
| 4056 | |
| 4057 if (!is_int16(offset)) { | |
| 4058 LoadIntLiteral(scratch, offset); | |
| 4059 lwzx(dst, MemOperand(base, scratch)); | |
| 4060 } else { | |
| 4061 lwz(dst, mem); | |
| 4062 } | |
| 4063 } | |
| 4064 | |
| 4065 | |
| 4066 // Variable length depending on whether offset fits into immediate field | |
| 4067 // MemOperand current only supports d-form | |
| 4068 void MacroAssembler::StoreWord(Register src, const MemOperand& mem, | |
| 4069 Register scratch) { | |
| 4070 Register base = mem.ra(); | |
| 4071 int offset = mem.offset(); | |
| 4072 | |
| 4073 if (!is_int16(offset)) { | |
| 4074 LoadIntLiteral(scratch, offset); | |
| 4075 stwx(src, MemOperand(base, scratch)); | |
| 4076 } else { | |
| 4077 stw(src, mem); | |
| 4078 } | |
| 4079 } | |
| 4080 | |
| 4081 | |
| 4082 void MacroAssembler::LoadHalfWordArith(Register dst, const MemOperand& mem, | |
| 4083 Register scratch) { | |
| 4084 int offset = mem.offset(); | |
| 4085 | |
| 4086 if (!is_int16(offset)) { | |
| 4087 DCHECK(!scratch.is(no_reg)); | |
| 4088 mov(scratch, Operand(offset)); | |
| 4089 lhax(dst, MemOperand(mem.ra(), scratch)); | |
| 4090 } else { | |
| 4091 lha(dst, mem); | |
| 4092 } | |
| 4093 } | |
| 4094 | |
| 4095 | |
| 4096 // Variable length depending on whether offset fits into immediate field | |
| 4097 // MemOperand currently only supports d-form | |
| 4098 void MacroAssembler::LoadHalfWord(Register dst, const MemOperand& mem, | |
| 4099 Register scratch) { | |
| 4100 Register base = mem.ra(); | |
| 4101 int offset = mem.offset(); | |
| 4102 | |
| 4103 if (!is_int16(offset)) { | |
| 4104 LoadIntLiteral(scratch, offset); | |
| 4105 lhzx(dst, MemOperand(base, scratch)); | |
| 4106 } else { | |
| 4107 lhz(dst, mem); | |
| 4108 } | |
| 4109 } | |
| 4110 | |
| 4111 | |
| 4112 // Variable length depending on whether offset fits into immediate field | |
| 4113 // MemOperand current only supports d-form | |
| 4114 void MacroAssembler::StoreHalfWord(Register src, const MemOperand& mem, | |
| 4115 Register scratch) { | |
| 4116 Register base = mem.ra(); | |
| 4117 int offset = mem.offset(); | |
| 4118 | |
| 4119 if (!is_int16(offset)) { | |
| 4120 LoadIntLiteral(scratch, offset); | |
| 4121 sthx(src, MemOperand(base, scratch)); | |
| 4122 } else { | |
| 4123 sth(src, mem); | |
| 4124 } | |
| 4125 } | |
| 4126 | |
| 4127 | |
| 4128 // Variable length depending on whether offset fits into immediate field | |
| 4129 // MemOperand currently only supports d-form | |
| 4130 void MacroAssembler::LoadByte(Register dst, const MemOperand& mem, | |
| 4131 Register scratch) { | |
| 4132 Register base = mem.ra(); | |
| 4133 int offset = mem.offset(); | |
| 4134 | |
| 4135 if (!is_int16(offset)) { | |
| 4136 LoadIntLiteral(scratch, offset); | |
| 4137 lbzx(dst, MemOperand(base, scratch)); | |
| 4138 } else { | |
| 4139 lbz(dst, mem); | |
| 4140 } | |
| 4141 } | |
| 4142 | |
| 4143 | |
| 4144 // Variable length depending on whether offset fits into immediate field | |
| 4145 // MemOperand current only supports d-form | |
| 4146 void MacroAssembler::StoreByte(Register src, const MemOperand& mem, | |
| 4147 Register scratch) { | |
| 4148 Register base = mem.ra(); | |
| 4149 int offset = mem.offset(); | |
| 4150 | |
| 4151 if (!is_int16(offset)) { | |
| 4152 LoadIntLiteral(scratch, offset); | |
| 4153 stbx(src, MemOperand(base, scratch)); | |
| 4154 } else { | |
| 4155 stb(src, mem); | |
| 4156 } | |
| 4157 } | |
| 4158 | |
| 4159 | |
| 4160 void MacroAssembler::LoadRepresentation(Register dst, const MemOperand& mem, | 3494 void MacroAssembler::LoadRepresentation(Register dst, const MemOperand& mem, |
| 4161 Representation r, Register scratch) { | 3495 Representation r, Register scratch) { |
| 4162 DCHECK(!r.IsDouble()); | 3496 DCHECK(!r.IsDouble()); |
| 4163 if (r.IsInteger8()) { | 3497 if (r.IsInteger8()) { |
| 4164 LoadByte(dst, mem, scratch); | 3498 LoadB(dst, mem); |
| 4165 extsb(dst, dst); | 3499 lgbr(dst, dst); |
| 4166 } else if (r.IsUInteger8()) { | 3500 } else if (r.IsUInteger8()) { |
| 4167 LoadByte(dst, mem, scratch); | 3501 LoadlB(dst, mem); |
| 4168 } else if (r.IsInteger16()) { | 3502 } else if (r.IsInteger16()) { |
| 4169 LoadHalfWordArith(dst, mem, scratch); | 3503 LoadHalfWordP(dst, mem, scratch); |
| 3504 lghr(dst, dst); |
| 4170 } else if (r.IsUInteger16()) { | 3505 } else if (r.IsUInteger16()) { |
| 4171 LoadHalfWord(dst, mem, scratch); | 3506 LoadHalfWordP(dst, mem, scratch); |
| 4172 #if V8_TARGET_ARCH_PPC64 | 3507 #if V8_TARGET_ARCH_S390X |
| 4173 } else if (r.IsInteger32()) { | 3508 } else if (r.IsInteger32()) { |
| 4174 LoadWordArith(dst, mem, scratch); | 3509 LoadW(dst, mem, scratch); |
| 4175 #endif | 3510 #endif |
| 4176 } else { | 3511 } else { |
| 4177 LoadP(dst, mem, scratch); | 3512 LoadP(dst, mem, scratch); |
| 4178 } | 3513 } |
| 4179 } | 3514 } |
| 4180 | 3515 |
| 4181 | |
| 4182 void MacroAssembler::StoreRepresentation(Register src, const MemOperand& mem, | 3516 void MacroAssembler::StoreRepresentation(Register src, const MemOperand& mem, |
| 4183 Representation r, Register scratch) { | 3517 Representation r, Register scratch) { |
| 4184 DCHECK(!r.IsDouble()); | 3518 DCHECK(!r.IsDouble()); |
| 4185 if (r.IsInteger8() || r.IsUInteger8()) { | 3519 if (r.IsInteger8() || r.IsUInteger8()) { |
| 4186 StoreByte(src, mem, scratch); | 3520 StoreByte(src, mem, scratch); |
| 4187 } else if (r.IsInteger16() || r.IsUInteger16()) { | 3521 } else if (r.IsInteger16() || r.IsUInteger16()) { |
| 4188 StoreHalfWord(src, mem, scratch); | 3522 StoreHalfWord(src, mem, scratch); |
| 4189 #if V8_TARGET_ARCH_PPC64 | 3523 #if V8_TARGET_ARCH_S390X |
| 4190 } else if (r.IsInteger32()) { | 3524 } else if (r.IsInteger32()) { |
| 4191 StoreWord(src, mem, scratch); | 3525 StoreW(src, mem, scratch); |
| 4192 #endif | 3526 #endif |
| 4193 } else { | 3527 } else { |
| 4194 if (r.IsHeapObject()) { | 3528 if (r.IsHeapObject()) { |
| 4195 AssertNotSmi(src); | 3529 AssertNotSmi(src); |
| 4196 } else if (r.IsSmi()) { | 3530 } else if (r.IsSmi()) { |
| 4197 AssertSmi(src); | 3531 AssertSmi(src); |
| 4198 } | 3532 } |
| 4199 StoreP(src, mem, scratch); | 3533 StoreP(src, mem, scratch); |
| 4200 } | 3534 } |
| 4201 } | 3535 } |
| 4202 | 3536 |
| 4203 | |
| 4204 void MacroAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem, | |
| 4205 Register scratch) { | |
| 4206 Register base = mem.ra(); | |
| 4207 int offset = mem.offset(); | |
| 4208 | |
| 4209 if (!is_int16(offset)) { | |
| 4210 mov(scratch, Operand(offset)); | |
| 4211 lfdx(dst, MemOperand(base, scratch)); | |
| 4212 } else { | |
| 4213 lfd(dst, mem); | |
| 4214 } | |
| 4215 } | |
| 4216 | |
| 4217 | |
| 4218 void MacroAssembler::StoreDouble(DoubleRegister src, const MemOperand& mem, | |
| 4219 Register scratch) { | |
| 4220 Register base = mem.ra(); | |
| 4221 int offset = mem.offset(); | |
| 4222 | |
| 4223 if (!is_int16(offset)) { | |
| 4224 mov(scratch, Operand(offset)); | |
| 4225 stfdx(src, MemOperand(base, scratch)); | |
| 4226 } else { | |
| 4227 stfd(src, mem); | |
| 4228 } | |
| 4229 } | |
| 4230 | |
| 4231 | |
| 4232 void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg, | 3537 void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg, |
| 4233 Register scratch_reg, | 3538 Register scratch_reg, |
| 4234 Label* no_memento_found) { | 3539 Label* no_memento_found) { |
| 4235 ExternalReference new_space_start = | 3540 ExternalReference new_space_start = |
| 4236 ExternalReference::new_space_start(isolate()); | 3541 ExternalReference::new_space_start(isolate()); |
| 4237 ExternalReference new_space_allocation_top = | 3542 ExternalReference new_space_allocation_top = |
| 4238 ExternalReference::new_space_allocation_top_address(isolate()); | 3543 ExternalReference::new_space_allocation_top_address(isolate()); |
| 4239 addi(scratch_reg, receiver_reg, | 3544 AddP(scratch_reg, receiver_reg, |
| 4240 Operand(JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag)); | 3545 Operand(JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag)); |
| 4241 Cmpi(scratch_reg, Operand(new_space_start), r0); | 3546 CmpP(scratch_reg, Operand(new_space_start)); |
| 4242 blt(no_memento_found); | 3547 blt(no_memento_found); |
| 4243 mov(ip, Operand(new_space_allocation_top)); | 3548 mov(ip, Operand(new_space_allocation_top)); |
| 4244 LoadP(ip, MemOperand(ip)); | 3549 LoadP(ip, MemOperand(ip)); |
| 4245 cmp(scratch_reg, ip); | 3550 CmpP(scratch_reg, ip); |
| 4246 bgt(no_memento_found); | 3551 bgt(no_memento_found); |
| 4247 LoadP(scratch_reg, MemOperand(scratch_reg, -AllocationMemento::kSize)); | 3552 LoadP(scratch_reg, MemOperand(scratch_reg, -AllocationMemento::kSize)); |
| 4248 Cmpi(scratch_reg, Operand(isolate()->factory()->allocation_memento_map()), | 3553 CmpP(scratch_reg, Operand(isolate()->factory()->allocation_memento_map())); |
| 4249 r0); | 3554 } |
| 4250 } | |
| 4251 | |
| 4252 | 3555 |
| 4253 Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3, | 3556 Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3, |
| 4254 Register reg4, Register reg5, | 3557 Register reg4, Register reg5, |
| 4255 Register reg6) { | 3558 Register reg6) { |
| 4256 RegList regs = 0; | 3559 RegList regs = 0; |
| 4257 if (reg1.is_valid()) regs |= reg1.bit(); | 3560 if (reg1.is_valid()) regs |= reg1.bit(); |
| 4258 if (reg2.is_valid()) regs |= reg2.bit(); | 3561 if (reg2.is_valid()) regs |= reg2.bit(); |
| 4259 if (reg3.is_valid()) regs |= reg3.bit(); | 3562 if (reg3.is_valid()) regs |= reg3.bit(); |
| 4260 if (reg4.is_valid()) regs |= reg4.bit(); | 3563 if (reg4.is_valid()) regs |= reg4.bit(); |
| 4261 if (reg5.is_valid()) regs |= reg5.bit(); | 3564 if (reg5.is_valid()) regs |= reg5.bit(); |
| 4262 if (reg6.is_valid()) regs |= reg6.bit(); | 3565 if (reg6.is_valid()) regs |= reg6.bit(); |
| 4263 | 3566 |
| 4264 const RegisterConfiguration* config = | 3567 const RegisterConfiguration* config = |
| 4265 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT); | 3568 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT); |
| 4266 for (int i = 0; i < config->num_allocatable_general_registers(); ++i) { | 3569 for (int i = 0; i < config->num_allocatable_general_registers(); ++i) { |
| 4267 int code = config->GetAllocatableGeneralCode(i); | 3570 int code = config->GetAllocatableGeneralCode(i); |
| 4268 Register candidate = Register::from_code(code); | 3571 Register candidate = Register::from_code(code); |
| 4269 if (regs & candidate.bit()) continue; | 3572 if (regs & candidate.bit()) continue; |
| 4270 return candidate; | 3573 return candidate; |
| 4271 } | 3574 } |
| 4272 UNREACHABLE(); | 3575 UNREACHABLE(); |
| 4273 return no_reg; | 3576 return no_reg; |
| 4274 } | 3577 } |
| 4275 | 3578 |
| 4276 | |
| 4277 void MacroAssembler::JumpIfDictionaryInPrototypeChain(Register object, | 3579 void MacroAssembler::JumpIfDictionaryInPrototypeChain(Register object, |
| 4278 Register scratch0, | 3580 Register scratch0, |
| 4279 Register scratch1, | 3581 Register scratch1, |
| 4280 Label* found) { | 3582 Label* found) { |
| 4281 DCHECK(!scratch1.is(scratch0)); | 3583 DCHECK(!scratch1.is(scratch0)); |
| 4282 Register current = scratch0; | 3584 Register current = scratch0; |
| 4283 Label loop_again, end; | 3585 Label loop_again, end; |
| 4284 | 3586 |
| 4285 // scratch contained elements pointer. | 3587 // scratch contained elements pointer. |
| 4286 mr(current, object); | 3588 LoadRR(current, object); |
| 4287 LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset)); | 3589 LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset)); |
| 4288 LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset)); | 3590 LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset)); |
| 4289 CompareRoot(current, Heap::kNullValueRootIndex); | 3591 CompareRoot(current, Heap::kNullValueRootIndex); |
| 4290 beq(&end); | 3592 beq(&end); |
| 4291 | 3593 |
| 4292 // Loop based on the map going up the prototype chain. | 3594 // Loop based on the map going up the prototype chain. |
| 4293 bind(&loop_again); | 3595 bind(&loop_again); |
| 4294 LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset)); | 3596 LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset)); |
| 4295 | 3597 |
| 4296 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE); | 3598 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE); |
| 4297 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE); | 3599 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE); |
| 4298 lbz(scratch1, FieldMemOperand(current, Map::kInstanceTypeOffset)); | 3600 LoadlB(scratch1, FieldMemOperand(current, Map::kInstanceTypeOffset)); |
| 4299 cmpi(scratch1, Operand(JS_OBJECT_TYPE)); | 3601 CmpP(scratch1, Operand(JS_OBJECT_TYPE)); |
| 4300 blt(found); | 3602 blt(found); |
| 4301 | 3603 |
| 4302 lbz(scratch1, FieldMemOperand(current, Map::kBitField2Offset)); | 3604 LoadlB(scratch1, FieldMemOperand(current, Map::kBitField2Offset)); |
| 4303 DecodeField<Map::ElementsKindBits>(scratch1); | 3605 DecodeField<Map::ElementsKindBits>(scratch1); |
| 4304 cmpi(scratch1, Operand(DICTIONARY_ELEMENTS)); | 3606 CmpP(scratch1, Operand(DICTIONARY_ELEMENTS)); |
| 4305 beq(found); | 3607 beq(found); |
| 4306 LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset)); | 3608 LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset)); |
| 4307 CompareRoot(current, Heap::kNullValueRootIndex); | 3609 CompareRoot(current, Heap::kNullValueRootIndex); |
| 4308 bne(&loop_again); | 3610 bne(&loop_again); |
| 4309 | 3611 |
| 4310 bind(&end); | 3612 bind(&end); |
| 4311 } | 3613 } |
| 4312 | 3614 |
| 3615 void MacroAssembler::mov(Register dst, const Operand& src) { |
| 3616 if (src.rmode_ != kRelocInfo_NONEPTR) { |
| 3617 // some form of relocation needed |
| 3618 RecordRelocInfo(src.rmode_, src.imm_); |
| 3619 } |
| 3620 |
| 3621 #if V8_TARGET_ARCH_S390X |
| 3622 int64_t value = src.immediate(); |
| 3623 int32_t hi_32 = static_cast<int64_t>(value) >> 32; |
| 3624 int32_t lo_32 = static_cast<int32_t>(value); |
| 3625 |
| 3626 iihf(dst, Operand(hi_32)); |
| 3627 iilf(dst, Operand(lo_32)); |
| 3628 #else |
| 3629 int value = src.immediate(); |
| 3630 iilf(dst, Operand(value)); |
| 3631 #endif |
| 3632 } |
| 3633 |
| 3634 void MacroAssembler::Mul(Register dst, Register src1, Register src2) { |
| 3635 if (dst.is(src2)) { |
| 3636 MulP(dst, src1); |
| 3637 } else if (dst.is(src1)) { |
| 3638 MulP(dst, src2); |
| 3639 } else { |
| 3640 Move(dst, src1); |
| 3641 MulP(dst, src2); |
| 3642 } |
| 3643 } |
| 3644 |
| 3645 void MacroAssembler::DivP(Register dividend, Register divider) { |
| 3646 // have to make sure the src and dst are reg pairs |
| 3647 DCHECK(dividend.code() % 2 == 0); |
| 3648 #if V8_TARGET_ARCH_S390X |
| 3649 dsgr(dividend, divider); |
| 3650 #else |
| 3651 dr(dividend, divider); |
| 3652 #endif |
| 3653 } |
| 3654 |
| 3655 void MacroAssembler::MulP(Register dst, const Operand& opnd) { |
| 3656 #if V8_TARGET_ARCH_S390X |
| 3657 msgfi(dst, opnd); |
| 3658 #else |
| 3659 msfi(dst, opnd); |
| 3660 #endif |
| 3661 } |
| 3662 |
| 3663 void MacroAssembler::MulP(Register dst, Register src) { |
| 3664 #if V8_TARGET_ARCH_S390X |
| 3665 msgr(dst, src); |
| 3666 #else |
| 3667 msr(dst, src); |
| 3668 #endif |
| 3669 } |
| 3670 |
| 3671 void MacroAssembler::MulP(Register dst, const MemOperand& opnd) { |
| 3672 #if V8_TARGET_ARCH_S390X |
| 3673 if (is_uint16(opnd.offset())) { |
| 3674 ms(dst, opnd); |
| 3675 } else if (is_int20(opnd.offset())) { |
| 3676 msy(dst, opnd); |
| 3677 } else { |
| 3678 UNIMPLEMENTED(); |
| 3679 } |
| 3680 #else |
| 3681 if (is_int20(opnd.offset())) { |
| 3682 msg(dst, opnd); |
| 3683 } else { |
| 3684 UNIMPLEMENTED(); |
| 3685 } |
| 3686 #endif |
| 3687 } |
| 3688 |
| 3689 //---------------------------------------------------------------------------- |
| 3690 // Add Instructions |
| 3691 //---------------------------------------------------------------------------- |
| 3692 |
| 3693 // Add 32-bit (Register dst = Register dst + Immediate opnd) |
| 3694 void MacroAssembler::Add32(Register dst, const Operand& opnd) { |
| 3695 if (is_int16(opnd.immediate())) |
| 3696 ahi(dst, opnd); |
| 3697 else |
| 3698 afi(dst, opnd); |
| 3699 } |
| 3700 |
| 3701 // Add Pointer Size (Register dst = Register dst + Immediate opnd) |
| 3702 void MacroAssembler::AddP(Register dst, const Operand& opnd) { |
| 3703 #if V8_TARGET_ARCH_S390X |
| 3704 if (is_int16(opnd.immediate())) |
| 3705 aghi(dst, opnd); |
| 3706 else |
| 3707 agfi(dst, opnd); |
| 3708 #else |
| 3709 Add32(dst, opnd); |
| 3710 #endif |
| 3711 } |
| 3712 |
| 3713 // Add 32-bit (Register dst = Register src + Immediate opnd) |
| 3714 void MacroAssembler::Add32(Register dst, Register src, const Operand& opnd) { |
| 3715 if (!dst.is(src)) { |
| 3716 if (CpuFeatures::IsSupported(DISTINCT_OPS) && is_int16(opnd.immediate())) { |
| 3717 ahik(dst, src, opnd); |
| 3718 return; |
| 3719 } |
| 3720 lr(dst, src); |
| 3721 } |
| 3722 Add32(dst, opnd); |
| 3723 } |
| 3724 |
| 3725 // Add Pointer Size (Register dst = Register src + Immediate opnd) |
| 3726 void MacroAssembler::AddP(Register dst, Register src, const Operand& opnd) { |
| 3727 if (!dst.is(src)) { |
| 3728 if (CpuFeatures::IsSupported(DISTINCT_OPS) && is_int16(opnd.immediate())) { |
| 3729 AddPImm_RRI(dst, src, opnd); |
| 3730 return; |
| 3731 } |
| 3732 LoadRR(dst, src); |
| 3733 } |
| 3734 AddP(dst, opnd); |
| 3735 } |
| 3736 |
| 3737 // Add 32-bit (Register dst = Register dst + Register src) |
| 3738 void MacroAssembler::Add32(Register dst, Register src) { ar(dst, src); } |
| 3739 |
| 3740 // Add Pointer Size (Register dst = Register dst + Register src) |
| 3741 void MacroAssembler::AddP(Register dst, Register src) { AddRR(dst, src); } |
| 3742 |
| 3743 // Add Pointer Size with src extension |
| 3744 // (Register dst(ptr) = Register dst (ptr) + Register src (32 | 32->64)) |
| 3745 // src is treated as a 32-bit signed integer, which is sign extended to |
| 3746 // 64-bit if necessary. |
| 3747 void MacroAssembler::AddP_ExtendSrc(Register dst, Register src) { |
| 3748 #if V8_TARGET_ARCH_S390X |
| 3749 agfr(dst, src); |
| 3750 #else |
| 3751 ar(dst, src); |
| 3752 #endif |
| 3753 } |
| 3754 |
| 3755 // Add 32-bit (Register dst = Register src1 + Register src2) |
| 3756 void MacroAssembler::Add32(Register dst, Register src1, Register src2) { |
| 3757 if (!dst.is(src1) && !dst.is(src2)) { |
| 3758 // We prefer to generate AR/AGR, over the non clobbering ARK/AGRK |
| 3759 // as AR is a smaller instruction |
| 3760 if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 3761 ark(dst, src1, src2); |
| 3762 return; |
| 3763 } else { |
| 3764 lr(dst, src1); |
| 3765 } |
| 3766 } else if (dst.is(src2)) { |
| 3767 src2 = src1; |
| 3768 } |
| 3769 ar(dst, src2); |
| 3770 } |
| 3771 |
| 3772 // Add Pointer Size (Register dst = Register src1 + Register src2) |
| 3773 void MacroAssembler::AddP(Register dst, Register src1, Register src2) { |
| 3774 if (!dst.is(src1) && !dst.is(src2)) { |
| 3775 // We prefer to generate AR/AGR, over the non clobbering ARK/AGRK |
| 3776 // as AR is a smaller instruction |
| 3777 if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 3778 AddP_RRR(dst, src1, src2); |
| 3779 return; |
| 3780 } else { |
| 3781 LoadRR(dst, src1); |
| 3782 } |
| 3783 } else if (dst.is(src2)) { |
| 3784 src2 = src1; |
| 3785 } |
| 3786 AddRR(dst, src2); |
| 3787 } |
| 3788 |
| 3789 // Add Pointer Size with src extension |
| 3790 // (Register dst (ptr) = Register dst (ptr) + Register src1 (ptr) + |
| 3791 // Register src2 (32 | 32->64)) |
| 3792 // src is treated as a 32-bit signed integer, which is sign extended to |
| 3793 // 64-bit if necessary. |
| 3794 void MacroAssembler::AddP_ExtendSrc(Register dst, Register src1, |
| 3795 Register src2) { |
| 3796 #if V8_TARGET_ARCH_S390X |
| 3797 if (dst.is(src2)) { |
| 3798 // The source we need to sign extend is the same as result. |
| 3799 lgfr(dst, src2); |
| 3800 agr(dst, src1); |
| 3801 } else { |
| 3802 if (!dst.is(src1)) LoadRR(dst, src1); |
| 3803 agfr(dst, src2); |
| 3804 } |
| 3805 #else |
| 3806 AddP(dst, src1, src2); |
| 3807 #endif |
| 3808 } |
| 3809 |
| 3810 // Add 32-bit (Register-Memory) |
| 3811 void MacroAssembler::Add32(Register dst, const MemOperand& opnd) { |
| 3812 DCHECK(is_int20(opnd.offset())); |
| 3813 if (is_uint12(opnd.offset())) |
| 3814 a(dst, opnd); |
| 3815 else |
| 3816 ay(dst, opnd); |
| 3817 } |
| 3818 |
| 3819 // Add Pointer Size (Register-Memory) |
| 3820 void MacroAssembler::AddP(Register dst, const MemOperand& opnd) { |
| 3821 #if V8_TARGET_ARCH_S390X |
| 3822 DCHECK(is_int20(opnd.offset())); |
| 3823 ag(dst, opnd); |
| 3824 #else |
| 3825 Add32(dst, opnd); |
| 3826 #endif |
| 3827 } |
| 3828 |
| 3829 // Add Pointer Size with src extension |
| 3830 // (Register dst (ptr) = Register dst (ptr) + Mem opnd (32 | 32->64)) |
| 3831 // src is treated as a 32-bit signed integer, which is sign extended to |
| 3832 // 64-bit if necessary. |
| 3833 void MacroAssembler::AddP_ExtendSrc(Register dst, const MemOperand& opnd) { |
| 3834 #if V8_TARGET_ARCH_S390X |
| 3835 DCHECK(is_int20(opnd.offset())); |
| 3836 agf(dst, opnd); |
| 3837 #else |
| 3838 Add32(dst, opnd); |
| 3839 #endif |
| 3840 } |
| 3841 |
| 3842 // Add 32-bit (Memory - Immediate) |
| 3843 void MacroAssembler::Add32(const MemOperand& opnd, const Operand& imm) { |
| 3844 DCHECK(is_int8(imm.immediate())); |
| 3845 DCHECK(is_int20(opnd.offset())); |
| 3846 DCHECK(CpuFeatures::IsSupported(GENERAL_INSTR_EXT)); |
| 3847 asi(opnd, imm); |
| 3848 } |
| 3849 |
| 3850 // Add Pointer-sized (Memory - Immediate) |
| 3851 void MacroAssembler::AddP(const MemOperand& opnd, const Operand& imm) { |
| 3852 DCHECK(is_int8(imm.immediate())); |
| 3853 DCHECK(is_int20(opnd.offset())); |
| 3854 DCHECK(CpuFeatures::IsSupported(GENERAL_INSTR_EXT)); |
| 3855 #if V8_TARGET_ARCH_S390X |
| 3856 agsi(opnd, imm); |
| 3857 #else |
| 3858 asi(opnd, imm); |
| 3859 #endif |
| 3860 } |
| 3861 |
| 3862 //---------------------------------------------------------------------------- |
| 3863 // Add Logical Instructions |
| 3864 //---------------------------------------------------------------------------- |
| 3865 |
| 3866 // Add Logical 32-bit (Register dst = Register dst + Immediate opnd) |
| 3867 void MacroAssembler::AddLogical(Register dst, const Operand& imm) { |
| 3868 alfi(dst, imm); |
| 3869 } |
| 3870 |
| 3871 // Add Logical Pointer Size (Register dst = Register dst + Immediate opnd) |
| 3872 void MacroAssembler::AddLogicalP(Register dst, const Operand& imm) { |
| 3873 #ifdef V8_TARGET_ARCH_S390X |
| 3874 algfi(dst, imm); |
| 3875 #else |
| 3876 AddLogical(dst, imm); |
| 3877 #endif |
| 3878 } |
| 3879 |
| 3880 // Add Logical 32-bit (Register-Memory) |
| 3881 void MacroAssembler::AddLogical(Register dst, const MemOperand& opnd) { |
| 3882 DCHECK(is_int20(opnd.offset())); |
| 3883 if (is_uint12(opnd.offset())) |
| 3884 al_z(dst, opnd); |
| 3885 else |
| 3886 aly(dst, opnd); |
| 3887 } |
| 3888 |
| 3889 // Add Logical Pointer Size (Register-Memory) |
| 3890 void MacroAssembler::AddLogicalP(Register dst, const MemOperand& opnd) { |
| 3891 #if V8_TARGET_ARCH_S390X |
| 3892 DCHECK(is_int20(opnd.offset())); |
| 3893 alg(dst, opnd); |
| 3894 #else |
| 3895 AddLogical(dst, opnd); |
| 3896 #endif |
| 3897 } |
| 3898 |
| 3899 //---------------------------------------------------------------------------- |
| 3900 // Subtract Instructions |
| 3901 //---------------------------------------------------------------------------- |
| 3902 |
| 3903 // Subtract 32-bit (Register dst = Register dst - Immediate opnd) |
| 3904 void MacroAssembler::Sub32(Register dst, const Operand& imm) { |
| 3905 Add32(dst, Operand(-(imm.imm_))); |
| 3906 } |
| 3907 |
| 3908 // Subtract Pointer Size (Register dst = Register dst - Immediate opnd) |
| 3909 void MacroAssembler::SubP(Register dst, const Operand& imm) { |
| 3910 AddP(dst, Operand(-(imm.imm_))); |
| 3911 } |
| 3912 |
| 3913 // Subtract 32-bit (Register dst = Register src - Immediate opnd) |
| 3914 void MacroAssembler::Sub32(Register dst, Register src, const Operand& imm) { |
| 3915 Add32(dst, src, Operand(-(imm.imm_))); |
| 3916 } |
| 3917 |
| 3918 // Subtract Pointer Sized (Register dst = Register src - Immediate opnd) |
| 3919 void MacroAssembler::SubP(Register dst, Register src, const Operand& imm) { |
| 3920 AddP(dst, src, Operand(-(imm.imm_))); |
| 3921 } |
| 3922 |
| 3923 // Subtract 32-bit (Register dst = Register dst - Register src) |
| 3924 void MacroAssembler::Sub32(Register dst, Register src) { sr(dst, src); } |
| 3925 |
| 3926 // Subtract Pointer Size (Register dst = Register dst - Register src) |
| 3927 void MacroAssembler::SubP(Register dst, Register src) { SubRR(dst, src); } |
| 3928 |
| 3929 // Subtract Pointer Size with src extension |
| 3930 // (Register dst(ptr) = Register dst (ptr) - Register src (32 | 32->64)) |
| 3931 // src is treated as a 32-bit signed integer, which is sign extended to |
| 3932 // 64-bit if necessary. |
| 3933 void MacroAssembler::SubP_ExtendSrc(Register dst, Register src) { |
| 3934 #if V8_TARGET_ARCH_S390X |
| 3935 sgfr(dst, src); |
| 3936 #else |
| 3937 sr(dst, src); |
| 3938 #endif |
| 3939 } |
| 3940 |
| 3941 // Subtract 32-bit (Register = Register - Register) |
| 3942 void MacroAssembler::Sub32(Register dst, Register src1, Register src2) { |
| 3943 // Use non-clobbering version if possible |
| 3944 if (CpuFeatures::IsSupported(DISTINCT_OPS) && !dst.is(src1)) { |
| 3945 srk(dst, src1, src2); |
| 3946 return; |
| 3947 } |
| 3948 if (!dst.is(src1) && !dst.is(src2)) lr(dst, src1); |
| 3949 // In scenario where we have dst = src - dst, we need to swap and negate |
| 3950 if (!dst.is(src1) && dst.is(src2)) { |
| 3951 sr(dst, src1); // dst = (dst - src) |
| 3952 lcr(dst, dst); // dst = -dst |
| 3953 } else { |
| 3954 sr(dst, src2); |
| 3955 } |
| 3956 } |
| 3957 |
| 3958 // Subtract Pointer Sized (Register = Register - Register) |
| 3959 void MacroAssembler::SubP(Register dst, Register src1, Register src2) { |
| 3960 // Use non-clobbering version if possible |
| 3961 if (CpuFeatures::IsSupported(DISTINCT_OPS) && !dst.is(src1)) { |
| 3962 SubP_RRR(dst, src1, src2); |
| 3963 return; |
| 3964 } |
| 3965 if (!dst.is(src1) && !dst.is(src2)) LoadRR(dst, src1); |
| 3966 // In scenario where we have dst = src - dst, we need to swap and negate |
| 3967 if (!dst.is(src1) && dst.is(src2)) { |
| 3968 SubP(dst, src1); // dst = (dst - src) |
| 3969 LoadComplementRR(dst, dst); // dst = -dst |
| 3970 } else { |
| 3971 SubP(dst, src2); |
| 3972 } |
| 3973 } |
| 3974 |
| 3975 // Subtract Pointer Size with src extension |
| 3976 // (Register dst(ptr) = Register dst (ptr) - Register src (32 | 32->64)) |
| 3977 // src is treated as a 32-bit signed integer, which is sign extended to |
| 3978 // 64-bit if necessary. |
| 3979 void MacroAssembler::SubP_ExtendSrc(Register dst, Register src1, |
| 3980 Register src2) { |
| 3981 #if V8_TARGET_ARCH_S390X |
| 3982 if (!dst.is(src1) && !dst.is(src2)) LoadRR(dst, src1); |
| 3983 |
| 3984 // In scenario where we have dst = src - dst, we need to swap and negate |
| 3985 if (!dst.is(src1) && dst.is(src2)) { |
| 3986 lgfr(dst, dst); // Sign extend this operand first. |
| 3987 SubP(dst, src1); // dst = (dst - src) |
| 3988 LoadComplementRR(dst, dst); // dst = -dst |
| 3989 } else { |
| 3990 sgfr(dst, src2); |
| 3991 } |
| 3992 #else |
| 3993 SubP(dst, src1, src2); |
| 3994 #endif |
| 3995 } |
| 3996 |
| 3997 // Subtract 32-bit (Register-Memory) |
| 3998 void MacroAssembler::Sub32(Register dst, const MemOperand& opnd) { |
| 3999 DCHECK(is_int20(opnd.offset())); |
| 4000 if (is_uint12(opnd.offset())) |
| 4001 s(dst, opnd); |
| 4002 else |
| 4003 sy(dst, opnd); |
| 4004 } |
| 4005 |
| 4006 // Subtract Pointer Sized (Register - Memory) |
| 4007 void MacroAssembler::SubP(Register dst, const MemOperand& opnd) { |
| 4008 #if V8_TARGET_ARCH_S390X |
| 4009 sg(dst, opnd); |
| 4010 #else |
| 4011 Sub32(dst, opnd); |
| 4012 #endif |
| 4013 } |
| 4014 |
| 4015 void MacroAssembler::MovIntToFloat(DoubleRegister dst, Register src) { |
| 4016 sllg(src, src, Operand(32)); |
| 4017 ldgr(dst, src); |
| 4018 } |
| 4019 |
| 4020 void MacroAssembler::MovFloatToInt(Register dst, DoubleRegister src) { |
| 4021 lgdr(dst, src); |
| 4022 srlg(dst, dst, Operand(32)); |
| 4023 } |
| 4024 |
| 4025 void MacroAssembler::SubP_ExtendSrc(Register dst, const MemOperand& opnd) { |
| 4026 #if V8_TARGET_ARCH_S390X |
| 4027 DCHECK(is_int20(opnd.offset())); |
| 4028 sgf(dst, opnd); |
| 4029 #else |
| 4030 Sub32(dst, opnd); |
| 4031 #endif |
| 4032 } |
| 4033 |
| 4034 //---------------------------------------------------------------------------- |
| 4035 // Subtract Logical Instructions |
| 4036 //---------------------------------------------------------------------------- |
| 4037 |
| 4038 // Subtract Logical 32-bit (Register - Memory) |
| 4039 void MacroAssembler::SubLogical(Register dst, const MemOperand& opnd) { |
| 4040 DCHECK(is_int20(opnd.offset())); |
| 4041 if (is_uint12(opnd.offset())) |
| 4042 sl(dst, opnd); |
| 4043 else |
| 4044 sly(dst, opnd); |
| 4045 } |
| 4046 |
| 4047 // Subtract Logical Pointer Sized (Register - Memory) |
| 4048 void MacroAssembler::SubLogicalP(Register dst, const MemOperand& opnd) { |
| 4049 DCHECK(is_int20(opnd.offset())); |
| 4050 #if V8_TARGET_ARCH_S390X |
| 4051 slgf(dst, opnd); |
| 4052 #else |
| 4053 SubLogical(dst, opnd); |
| 4054 #endif |
| 4055 } |
| 4056 |
| 4057 // Subtract Logical Pointer Size with src extension |
| 4058 // (Register dst (ptr) = Register dst (ptr) - Mem opnd (32 | 32->64)) |
| 4059 // src is treated as a 32-bit signed integer, which is sign extended to |
| 4060 // 64-bit if necessary. |
| 4061 void MacroAssembler::SubLogicalP_ExtendSrc(Register dst, |
| 4062 const MemOperand& opnd) { |
| 4063 #if V8_TARGET_ARCH_S390X |
| 4064 DCHECK(is_int20(opnd.offset())); |
| 4065 slgf(dst, opnd); |
| 4066 #else |
| 4067 SubLogical(dst, opnd); |
| 4068 #endif |
| 4069 } |
| 4070 |
| 4071 //---------------------------------------------------------------------------- |
| 4072 // Bitwise Operations |
| 4073 //---------------------------------------------------------------------------- |
| 4074 |
| 4075 // AND 32-bit - dst = dst & src |
| 4076 void MacroAssembler::And(Register dst, Register src) { nr(dst, src); } |
| 4077 |
| 4078 // AND Pointer Size - dst = dst & src |
| 4079 void MacroAssembler::AndP(Register dst, Register src) { AndRR(dst, src); } |
| 4080 |
| 4081 // Non-clobbering AND 32-bit - dst = src1 & src1 |
| 4082 void MacroAssembler::And(Register dst, Register src1, Register src2) { |
| 4083 if (!dst.is(src1) && !dst.is(src2)) { |
| 4084 // We prefer to generate XR/XGR, over the non clobbering XRK/XRK |
| 4085 // as XR is a smaller instruction |
| 4086 if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 4087 nrk(dst, src1, src2); |
| 4088 return; |
| 4089 } else { |
| 4090 lr(dst, src1); |
| 4091 } |
| 4092 } else if (dst.is(src2)) { |
| 4093 src2 = src1; |
| 4094 } |
| 4095 And(dst, src2); |
| 4096 } |
| 4097 |
| 4098 // Non-clobbering AND pointer size - dst = src1 & src1 |
| 4099 void MacroAssembler::AndP(Register dst, Register src1, Register src2) { |
| 4100 if (!dst.is(src1) && !dst.is(src2)) { |
| 4101 // We prefer to generate XR/XGR, over the non clobbering XRK/XRK |
| 4102 // as XR is a smaller instruction |
| 4103 if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 4104 AndP_RRR(dst, src1, src2); |
| 4105 return; |
| 4106 } else { |
| 4107 LoadRR(dst, src1); |
| 4108 } |
| 4109 } else if (dst.is(src2)) { |
| 4110 src2 = src1; |
| 4111 } |
| 4112 AndP(dst, src2); |
| 4113 } |
| 4114 |
| 4115 // AND 32-bit (Reg - Mem) |
| 4116 void MacroAssembler::And(Register dst, const MemOperand& opnd) { |
| 4117 DCHECK(is_int20(opnd.offset())); |
| 4118 if (is_uint12(opnd.offset())) |
| 4119 n(dst, opnd); |
| 4120 else |
| 4121 ny(dst, opnd); |
| 4122 } |
| 4123 |
| 4124 // AND Pointer Size (Reg - Mem) |
| 4125 void MacroAssembler::AndP(Register dst, const MemOperand& opnd) { |
| 4126 DCHECK(is_int20(opnd.offset())); |
| 4127 #if V8_TARGET_ARCH_S390X |
| 4128 ng(dst, opnd); |
| 4129 #else |
| 4130 And(dst, opnd); |
| 4131 #endif |
| 4132 } |
| 4133 |
| 4134 // AND 32-bit - dst = dst & imm |
| 4135 void MacroAssembler::And(Register dst, const Operand& opnd) { nilf(dst, opnd); } |
| 4136 |
| 4137 // AND Pointer Size - dst = dst & imm |
| 4138 void MacroAssembler::AndP(Register dst, const Operand& opnd) { |
| 4139 #if V8_TARGET_ARCH_S390X |
| 4140 intptr_t value = opnd.imm_; |
| 4141 if (value >> 32 != -1) { |
| 4142 // this may not work b/c condition code won't be set correctly |
| 4143 nihf(dst, Operand(value >> 32)); |
| 4144 } |
| 4145 nilf(dst, Operand(value & 0xFFFFFFFF)); |
| 4146 #else |
| 4147 And(dst, opnd); |
| 4148 #endif |
| 4149 } |
| 4150 |
| 4151 // AND 32-bit - dst = src & imm |
| 4152 void MacroAssembler::And(Register dst, Register src, const Operand& opnd) { |
| 4153 if (!dst.is(src)) lr(dst, src); |
| 4154 nilf(dst, opnd); |
| 4155 } |
| 4156 |
| 4157 // AND Pointer Size - dst = src & imm |
| 4158 void MacroAssembler::AndP(Register dst, Register src, const Operand& opnd) { |
| 4159 // Try to exploit RISBG first |
| 4160 intptr_t value = opnd.imm_; |
| 4161 if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) { |
| 4162 intptr_t shifted_value = value; |
| 4163 int trailing_zeros = 0; |
| 4164 |
| 4165 // We start checking how many trailing zeros are left at the end. |
| 4166 while ((0 != shifted_value) && (0 == (shifted_value & 1))) { |
| 4167 trailing_zeros++; |
| 4168 shifted_value >>= 1; |
| 4169 } |
| 4170 |
| 4171 // If temp (value with right-most set of zeros shifted out) is 1 less |
| 4172 // than power of 2, we have consecutive bits of 1. |
| 4173 // Special case: If shift_value is zero, we cannot use RISBG, as it requires |
| 4174 // selection of at least 1 bit. |
| 4175 if ((0 != shifted_value) && base::bits::IsPowerOfTwo64(shifted_value + 1)) { |
| 4176 int startBit = |
| 4177 base::bits::CountLeadingZeros64(shifted_value) - trailing_zeros; |
| 4178 int endBit = 63 - trailing_zeros; |
| 4179 // Start: startBit, End: endBit, Shift = 0, true = zero unselected bits. |
| 4180 risbg(dst, src, Operand(startBit), Operand(endBit), Operand::Zero(), |
| 4181 true); |
| 4182 return; |
| 4183 } else if (-1 == shifted_value) { |
| 4184 // A Special case in which all top bits up to MSB are 1's. In this case, |
| 4185 // we can set startBit to be 0. |
| 4186 int endBit = 63 - trailing_zeros; |
| 4187 risbg(dst, src, Operand::Zero(), Operand(endBit), Operand::Zero(), true); |
| 4188 return; |
| 4189 } |
| 4190 } |
| 4191 |
| 4192 // If we are &'ing zero, we can just whack the dst register and skip copy |
| 4193 if (!dst.is(src) && (0 != value)) LoadRR(dst, src); |
| 4194 AndP(dst, opnd); |
| 4195 } |
| 4196 |
| 4197 // OR 32-bit - dst = dst & src |
| 4198 void MacroAssembler::Or(Register dst, Register src) { or_z(dst, src); } |
| 4199 |
| 4200 // OR Pointer Size - dst = dst & src |
| 4201 void MacroAssembler::OrP(Register dst, Register src) { OrRR(dst, src); } |
| 4202 |
| 4203 // Non-clobbering OR 32-bit - dst = src1 & src1 |
| 4204 void MacroAssembler::Or(Register dst, Register src1, Register src2) { |
| 4205 if (!dst.is(src1) && !dst.is(src2)) { |
| 4206 // We prefer to generate XR/XGR, over the non clobbering XRK/XRK |
| 4207 // as XR is a smaller instruction |
| 4208 if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 4209 ork(dst, src1, src2); |
| 4210 return; |
| 4211 } else { |
| 4212 lr(dst, src1); |
| 4213 } |
| 4214 } else if (dst.is(src2)) { |
| 4215 src2 = src1; |
| 4216 } |
| 4217 Or(dst, src2); |
| 4218 } |
| 4219 |
| 4220 // Non-clobbering OR pointer size - dst = src1 & src1 |
| 4221 void MacroAssembler::OrP(Register dst, Register src1, Register src2) { |
| 4222 if (!dst.is(src1) && !dst.is(src2)) { |
| 4223 // We prefer to generate XR/XGR, over the non clobbering XRK/XRK |
| 4224 // as XR is a smaller instruction |
| 4225 if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 4226 OrP_RRR(dst, src1, src2); |
| 4227 return; |
| 4228 } else { |
| 4229 LoadRR(dst, src1); |
| 4230 } |
| 4231 } else if (dst.is(src2)) { |
| 4232 src2 = src1; |
| 4233 } |
| 4234 OrP(dst, src2); |
| 4235 } |
| 4236 |
| 4237 // OR 32-bit (Reg - Mem) |
| 4238 void MacroAssembler::Or(Register dst, const MemOperand& opnd) { |
| 4239 DCHECK(is_int20(opnd.offset())); |
| 4240 if (is_uint12(opnd.offset())) |
| 4241 o(dst, opnd); |
| 4242 else |
| 4243 oy(dst, opnd); |
| 4244 } |
| 4245 |
| 4246 // OR Pointer Size (Reg - Mem) |
| 4247 void MacroAssembler::OrP(Register dst, const MemOperand& opnd) { |
| 4248 DCHECK(is_int20(opnd.offset())); |
| 4249 #if V8_TARGET_ARCH_S390X |
| 4250 og(dst, opnd); |
| 4251 #else |
| 4252 Or(dst, opnd); |
| 4253 #endif |
| 4254 } |
| 4255 |
| 4256 // OR 32-bit - dst = dst & imm |
| 4257 void MacroAssembler::Or(Register dst, const Operand& opnd) { oilf(dst, opnd); } |
| 4258 |
| 4259 // OR Pointer Size - dst = dst & imm |
| 4260 void MacroAssembler::OrP(Register dst, const Operand& opnd) { |
| 4261 #if V8_TARGET_ARCH_S390X |
| 4262 intptr_t value = opnd.imm_; |
| 4263 if (value >> 32 != 0) { |
| 4264 // this may not work b/c condition code won't be set correctly |
| 4265 oihf(dst, Operand(value >> 32)); |
| 4266 } |
| 4267 oilf(dst, Operand(value & 0xFFFFFFFF)); |
| 4268 #else |
| 4269 Or(dst, opnd); |
| 4270 #endif |
| 4271 } |
| 4272 |
| 4273 // OR 32-bit - dst = src & imm |
| 4274 void MacroAssembler::Or(Register dst, Register src, const Operand& opnd) { |
| 4275 if (!dst.is(src)) lr(dst, src); |
| 4276 oilf(dst, opnd); |
| 4277 } |
| 4278 |
| 4279 // OR Pointer Size - dst = src & imm |
| 4280 void MacroAssembler::OrP(Register dst, Register src, const Operand& opnd) { |
| 4281 if (!dst.is(src)) LoadRR(dst, src); |
| 4282 OrP(dst, opnd); |
| 4283 } |
| 4284 |
| 4285 // XOR 32-bit - dst = dst & src |
| 4286 void MacroAssembler::Xor(Register dst, Register src) { xr(dst, src); } |
| 4287 |
| 4288 // XOR Pointer Size - dst = dst & src |
| 4289 void MacroAssembler::XorP(Register dst, Register src) { XorRR(dst, src); } |
| 4290 |
| 4291 // Non-clobbering XOR 32-bit - dst = src1 & src1 |
| 4292 void MacroAssembler::Xor(Register dst, Register src1, Register src2) { |
| 4293 if (!dst.is(src1) && !dst.is(src2)) { |
| 4294 // We prefer to generate XR/XGR, over the non clobbering XRK/XRK |
| 4295 // as XR is a smaller instruction |
| 4296 if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 4297 xrk(dst, src1, src2); |
| 4298 return; |
| 4299 } else { |
| 4300 lr(dst, src1); |
| 4301 } |
| 4302 } else if (dst.is(src2)) { |
| 4303 src2 = src1; |
| 4304 } |
| 4305 Xor(dst, src2); |
| 4306 } |
| 4307 |
| 4308 // Non-clobbering XOR pointer size - dst = src1 & src1 |
| 4309 void MacroAssembler::XorP(Register dst, Register src1, Register src2) { |
| 4310 if (!dst.is(src1) && !dst.is(src2)) { |
| 4311 // We prefer to generate XR/XGR, over the non clobbering XRK/XRK |
| 4312 // as XR is a smaller instruction |
| 4313 if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 4314 XorP_RRR(dst, src1, src2); |
| 4315 return; |
| 4316 } else { |
| 4317 LoadRR(dst, src1); |
| 4318 } |
| 4319 } else if (dst.is(src2)) { |
| 4320 src2 = src1; |
| 4321 } |
| 4322 XorP(dst, src2); |
| 4323 } |
| 4324 |
| 4325 // XOR 32-bit (Reg - Mem) |
| 4326 void MacroAssembler::Xor(Register dst, const MemOperand& opnd) { |
| 4327 DCHECK(is_int20(opnd.offset())); |
| 4328 if (is_uint12(opnd.offset())) |
| 4329 x(dst, opnd); |
| 4330 else |
| 4331 xy(dst, opnd); |
| 4332 } |
| 4333 |
| 4334 // XOR Pointer Size (Reg - Mem) |
| 4335 void MacroAssembler::XorP(Register dst, const MemOperand& opnd) { |
| 4336 DCHECK(is_int20(opnd.offset())); |
| 4337 #if V8_TARGET_ARCH_S390X |
| 4338 xg(dst, opnd); |
| 4339 #else |
| 4340 Xor(dst, opnd); |
| 4341 #endif |
| 4342 } |
| 4343 |
| 4344 // XOR 32-bit - dst = dst & imm |
| 4345 void MacroAssembler::Xor(Register dst, const Operand& opnd) { xilf(dst, opnd); } |
| 4346 |
| 4347 // XOR Pointer Size - dst = dst & imm |
| 4348 void MacroAssembler::XorP(Register dst, const Operand& opnd) { |
| 4349 #if V8_TARGET_ARCH_S390X |
| 4350 intptr_t value = opnd.imm_; |
| 4351 xihf(dst, Operand(value >> 32)); |
| 4352 xilf(dst, Operand(value & 0xFFFFFFFF)); |
| 4353 #else |
| 4354 Xor(dst, opnd); |
| 4355 #endif |
| 4356 } |
| 4357 |
| 4358 // XOR 32-bit - dst = src & imm |
| 4359 void MacroAssembler::Xor(Register dst, Register src, const Operand& opnd) { |
| 4360 if (!dst.is(src)) lr(dst, src); |
| 4361 xilf(dst, opnd); |
| 4362 } |
| 4363 |
| 4364 // XOR Pointer Size - dst = src & imm |
| 4365 void MacroAssembler::XorP(Register dst, Register src, const Operand& opnd) { |
| 4366 if (!dst.is(src)) LoadRR(dst, src); |
| 4367 XorP(dst, opnd); |
| 4368 } |
| 4369 |
| 4370 void MacroAssembler::NotP(Register dst) { |
| 4371 #if V8_TARGET_ARCH_S390X |
| 4372 xihf(dst, Operand(0xFFFFFFFF)); |
| 4373 xilf(dst, Operand(0xFFFFFFFF)); |
| 4374 #else |
| 4375 XorP(dst, Operand(0xFFFFFFFF)); |
| 4376 #endif |
| 4377 } |
| 4378 |
| 4379 // works the same as mov |
| 4380 void MacroAssembler::Load(Register dst, const Operand& opnd) { |
| 4381 intptr_t value = opnd.immediate(); |
| 4382 if (is_int16(value)) { |
| 4383 #if V8_TARGET_ARCH_S390X |
| 4384 lghi(dst, opnd); |
| 4385 #else |
| 4386 lhi(dst, opnd); |
| 4387 #endif |
| 4388 } else { |
| 4389 #if V8_TARGET_ARCH_S390X |
| 4390 llilf(dst, opnd); |
| 4391 #else |
| 4392 iilf(dst, opnd); |
| 4393 #endif |
| 4394 } |
| 4395 } |
| 4396 |
| 4397 void MacroAssembler::Load(Register dst, const MemOperand& opnd) { |
| 4398 DCHECK(is_int20(opnd.offset())); |
| 4399 #if V8_TARGET_ARCH_S390X |
| 4400 lgf(dst, opnd); // 64<-32 |
| 4401 #else |
| 4402 if (is_uint12(opnd.offset())) { |
| 4403 l(dst, opnd); |
| 4404 } else { |
| 4405 ly(dst, opnd); |
| 4406 } |
| 4407 #endif |
| 4408 } |
| 4409 |
| 4410 //----------------------------------------------------------------------------- |
| 4411 // Compare Helpers |
| 4412 //----------------------------------------------------------------------------- |
| 4413 |
| 4414 // Compare 32-bit Register vs Register |
| 4415 void MacroAssembler::Cmp32(Register src1, Register src2) { cr_z(src1, src2); } |
| 4416 |
| 4417 // Compare Pointer Sized Register vs Register |
| 4418 void MacroAssembler::CmpP(Register src1, Register src2) { |
| 4419 #if V8_TARGET_ARCH_S390X |
| 4420 cgr(src1, src2); |
| 4421 #else |
| 4422 Cmp32(src1, src2); |
| 4423 #endif |
| 4424 } |
| 4425 |
| 4426 // Compare 32-bit Register vs Immediate |
| 4427 // This helper will set up proper relocation entries if required. |
| 4428 void MacroAssembler::Cmp32(Register dst, const Operand& opnd) { |
| 4429 if (opnd.rmode_ == kRelocInfo_NONEPTR) { |
| 4430 intptr_t value = opnd.immediate(); |
| 4431 if (is_int16(value)) |
| 4432 chi(dst, opnd); |
| 4433 else |
| 4434 cfi(dst, opnd); |
| 4435 } else { |
| 4436 // Need to generate relocation record here |
| 4437 RecordRelocInfo(opnd.rmode_, opnd.imm_); |
| 4438 cfi(dst, opnd); |
| 4439 } |
| 4440 } |
| 4441 |
| 4442 // Compare Pointer Sized Register vs Immediate |
| 4443 // This helper will set up proper relocation entries if required. |
| 4444 void MacroAssembler::CmpP(Register dst, const Operand& opnd) { |
| 4445 #if V8_TARGET_ARCH_S390X |
| 4446 if (opnd.rmode_ == kRelocInfo_NONEPTR) { |
| 4447 cgfi(dst, opnd); |
| 4448 } else { |
| 4449 mov(r0, opnd); // Need to generate 64-bit relocation |
| 4450 cgr(dst, r0); |
| 4451 } |
| 4452 #else |
| 4453 Cmp32(dst, opnd); |
| 4454 #endif |
| 4455 } |
| 4456 |
| 4457 // Compare 32-bit Register vs Memory |
| 4458 void MacroAssembler::Cmp32(Register dst, const MemOperand& opnd) { |
| 4459 // make sure offset is within 20 bit range |
| 4460 DCHECK(is_int20(opnd.offset())); |
| 4461 if (is_uint12(opnd.offset())) |
| 4462 c(dst, opnd); |
| 4463 else |
| 4464 cy(dst, opnd); |
| 4465 } |
| 4466 |
| 4467 // Compare Pointer Size Register vs Memory |
| 4468 void MacroAssembler::CmpP(Register dst, const MemOperand& opnd) { |
| 4469 // make sure offset is within 20 bit range |
| 4470 DCHECK(is_int20(opnd.offset())); |
| 4471 #if V8_TARGET_ARCH_S390X |
| 4472 cg(dst, opnd); |
| 4473 #else |
| 4474 Cmp32(dst, opnd); |
| 4475 #endif |
| 4476 } |
| 4477 |
| 4478 //----------------------------------------------------------------------------- |
| 4479 // Compare Logical Helpers |
| 4480 //----------------------------------------------------------------------------- |
| 4481 |
| 4482 // Compare Logical 32-bit Register vs Register |
| 4483 void MacroAssembler::CmpLogical32(Register dst, Register src) { clr(dst, src); } |
| 4484 |
| 4485 // Compare Logical Pointer Sized Register vs Register |
| 4486 void MacroAssembler::CmpLogicalP(Register dst, Register src) { |
| 4487 #ifdef V8_TARGET_ARCH_S390X |
| 4488 clgr(dst, src); |
| 4489 #else |
| 4490 CmpLogical32(dst, src); |
| 4491 #endif |
| 4492 } |
| 4493 |
| 4494 // Compare Logical 32-bit Register vs Immediate |
| 4495 void MacroAssembler::CmpLogical32(Register dst, const Operand& opnd) { |
| 4496 clfi(dst, opnd); |
| 4497 } |
| 4498 |
| 4499 // Compare Logical Pointer Sized Register vs Immediate |
| 4500 void MacroAssembler::CmpLogicalP(Register dst, const Operand& opnd) { |
| 4501 #if V8_TARGET_ARCH_S390X |
| 4502 DCHECK(static_cast<uint32_t>(opnd.immediate() >> 32) == 0); |
| 4503 clgfi(dst, opnd); |
| 4504 #else |
| 4505 CmpLogical32(dst, opnd); |
| 4506 #endif |
| 4507 } |
| 4508 |
| 4509 // Compare Logical 32-bit Register vs Memory |
| 4510 void MacroAssembler::CmpLogical32(Register dst, const MemOperand& opnd) { |
| 4511 // make sure offset is within 20 bit range |
| 4512 DCHECK(is_int20(opnd.offset())); |
| 4513 if (is_uint12(opnd.offset())) |
| 4514 cl(dst, opnd); |
| 4515 else |
| 4516 cly(dst, opnd); |
| 4517 } |
| 4518 |
| 4519 // Compare Logical Pointer Sized Register vs Memory |
| 4520 void MacroAssembler::CmpLogicalP(Register dst, const MemOperand& opnd) { |
| 4521 // make sure offset is within 20 bit range |
| 4522 DCHECK(is_int20(opnd.offset())); |
| 4523 #if V8_TARGET_ARCH_S390X |
| 4524 clg(dst, opnd); |
| 4525 #else |
| 4526 CmpLogical32(dst, opnd); |
| 4527 #endif |
| 4528 } |
| 4529 |
| 4530 // Compare Logical Byte (Mem - Imm) |
| 4531 void MacroAssembler::CmpLogicalByte(const MemOperand& mem, const Operand& imm) { |
| 4532 DCHECK(is_uint8(imm.immediate())); |
| 4533 if (is_uint12(mem.offset())) |
| 4534 cli(mem, imm); |
| 4535 else |
| 4536 cliy(mem, imm); |
| 4537 } |
| 4538 |
| 4539 void MacroAssembler::Branch(Condition c, const Operand& opnd) { |
| 4540 intptr_t value = opnd.immediate(); |
| 4541 if (is_int16(value)) |
| 4542 brc(c, opnd); |
| 4543 else |
| 4544 brcl(c, opnd); |
| 4545 } |
| 4546 |
| 4547 // Branch On Count. Decrement R1, and branch if R1 != 0. |
| 4548 void MacroAssembler::BranchOnCount(Register r1, Label* l) { |
| 4549 int32_t offset = branch_offset(l); |
| 4550 positions_recorder()->WriteRecordedPositions(); |
| 4551 if (is_int16(offset)) { |
| 4552 #if V8_TARGET_ARCH_S390X |
| 4553 brctg(r1, Operand(offset)); |
| 4554 #else |
| 4555 brct(r1, Operand(offset)); |
| 4556 #endif |
| 4557 } else { |
| 4558 AddP(r1, Operand(-1)); |
| 4559 Branch(ne, Operand(offset)); |
| 4560 } |
| 4561 } |
| 4562 |
| 4563 void MacroAssembler::LoadIntLiteral(Register dst, int value) { |
| 4564 Load(dst, Operand(value)); |
| 4565 } |
| 4566 |
| 4567 void MacroAssembler::LoadSmiLiteral(Register dst, Smi* smi) { |
| 4568 intptr_t value = reinterpret_cast<intptr_t>(smi); |
| 4569 #if V8_TARGET_ARCH_S390X |
| 4570 DCHECK((value & 0xffffffff) == 0); |
| 4571 // The smi value is loaded in upper 32-bits. Lower 32-bit are zeros. |
| 4572 llihf(dst, Operand(value >> 32)); |
| 4573 #else |
| 4574 llilf(dst, Operand(value)); |
| 4575 #endif |
| 4576 } |
| 4577 |
| 4578 void MacroAssembler::LoadDoubleLiteral(DoubleRegister result, uint64_t value, |
| 4579 Register scratch) { |
| 4580 uint32_t hi_32 = value >> 32; |
| 4581 uint32_t lo_32 = static_cast<uint32_t>(value); |
| 4582 |
| 4583 // Load the 64-bit value into a GPR, then transfer it to FPR via LDGR |
| 4584 iihf(scratch, Operand(hi_32)); |
| 4585 iilf(scratch, Operand(lo_32)); |
| 4586 ldgr(result, scratch); |
| 4587 } |
| 4588 |
| 4589 void MacroAssembler::LoadDoubleLiteral(DoubleRegister result, double value, |
| 4590 Register scratch) { |
| 4591 uint64_t int_val = bit_cast<uint64_t, double>(value); |
| 4592 LoadDoubleLiteral(result, int_val, scratch); |
| 4593 } |
| 4594 |
| 4595 void MacroAssembler::LoadFloat32Literal(DoubleRegister result, float value, |
| 4596 Register scratch) { |
| 4597 uint32_t hi_32 = bit_cast<uint32_t>(value); |
| 4598 uint32_t lo_32 = 0; |
| 4599 |
| 4600 // Load the 64-bit value into a GPR, then transfer it to FPR via LDGR |
| 4601 iihf(scratch, Operand(hi_32)); |
| 4602 iilf(scratch, Operand(lo_32)); |
| 4603 ldgr(result, scratch); |
| 4604 } |
| 4605 |
| 4606 void MacroAssembler::CmpSmiLiteral(Register src1, Smi* smi, Register scratch) { |
| 4607 #if V8_TARGET_ARCH_S390X |
| 4608 LoadSmiLiteral(scratch, smi); |
| 4609 cgr(src1, scratch); |
| 4610 #else |
| 4611 // CFI takes 32-bit immediate. |
| 4612 cfi(src1, Operand(smi)); |
| 4613 #endif |
| 4614 } |
| 4615 |
| 4616 void MacroAssembler::CmpLogicalSmiLiteral(Register src1, Smi* smi, |
| 4617 Register scratch) { |
| 4618 #if V8_TARGET_ARCH_S390X |
| 4619 LoadSmiLiteral(scratch, smi); |
| 4620 clgr(src1, scratch); |
| 4621 #else |
| 4622 // CLFI takes 32-bit immediate |
| 4623 clfi(src1, Operand(smi)); |
| 4624 #endif |
| 4625 } |
| 4626 |
| 4627 void MacroAssembler::AddSmiLiteral(Register dst, Register src, Smi* smi, |
| 4628 Register scratch) { |
| 4629 #if V8_TARGET_ARCH_S390X |
| 4630 LoadSmiLiteral(scratch, smi); |
| 4631 AddP(dst, src, scratch); |
| 4632 #else |
| 4633 AddP(dst, src, Operand(reinterpret_cast<intptr_t>(smi))); |
| 4634 #endif |
| 4635 } |
| 4636 |
| 4637 void MacroAssembler::SubSmiLiteral(Register dst, Register src, Smi* smi, |
| 4638 Register scratch) { |
| 4639 #if V8_TARGET_ARCH_S390X |
| 4640 LoadSmiLiteral(scratch, smi); |
| 4641 SubP(dst, src, scratch); |
| 4642 #else |
| 4643 AddP(dst, src, Operand(-(reinterpret_cast<intptr_t>(smi)))); |
| 4644 #endif |
| 4645 } |
| 4646 |
| 4647 void MacroAssembler::AndSmiLiteral(Register dst, Register src, Smi* smi) { |
| 4648 if (!dst.is(src)) LoadRR(dst, src); |
| 4649 #if V8_TARGET_ARCH_S390X |
| 4650 DCHECK((reinterpret_cast<intptr_t>(smi) & 0xffffffff) == 0); |
| 4651 int value = static_cast<int>(reinterpret_cast<intptr_t>(smi) >> 32); |
| 4652 nihf(dst, Operand(value)); |
| 4653 #else |
| 4654 nilf(dst, Operand(reinterpret_cast<int>(smi))); |
| 4655 #endif |
| 4656 } |
| 4657 |
| 4658 // Load a "pointer" sized value from the memory location |
| 4659 void MacroAssembler::LoadP(Register dst, const MemOperand& mem, |
| 4660 Register scratch) { |
| 4661 int offset = mem.offset(); |
| 4662 |
| 4663 if (!scratch.is(no_reg) && !is_int20(offset)) { |
| 4664 /* cannot use d-form */ |
| 4665 LoadIntLiteral(scratch, offset); |
| 4666 #if V8_TARGET_ARCH_S390X |
| 4667 lg(dst, MemOperand(mem.rb(), scratch)); |
| 4668 #else |
| 4669 l(dst, MemOperand(mem.rb(), scratch)); |
| 4670 #endif |
| 4671 } else { |
| 4672 #if V8_TARGET_ARCH_S390X |
| 4673 lg(dst, mem); |
| 4674 #else |
| 4675 if (is_uint12(offset)) { |
| 4676 l(dst, mem); |
| 4677 } else { |
| 4678 ly(dst, mem); |
| 4679 } |
| 4680 #endif |
| 4681 } |
| 4682 } |
| 4683 |
| 4684 // Store a "pointer" sized value to the memory location |
| 4685 void MacroAssembler::StoreP(Register src, const MemOperand& mem, |
| 4686 Register scratch) { |
| 4687 if (!is_int20(mem.offset())) { |
| 4688 DCHECK(!scratch.is(no_reg)); |
| 4689 DCHECK(!scratch.is(r0)); |
| 4690 LoadIntLiteral(scratch, mem.offset()); |
| 4691 #if V8_TARGET_ARCH_S390X |
| 4692 stg(src, MemOperand(mem.rb(), scratch)); |
| 4693 #else |
| 4694 st(src, MemOperand(mem.rb(), scratch)); |
| 4695 #endif |
| 4696 } else { |
| 4697 #if V8_TARGET_ARCH_S390X |
| 4698 stg(src, mem); |
| 4699 #else |
| 4700 // StoreW will try to generate ST if offset fits, otherwise |
| 4701 // it'll generate STY. |
| 4702 StoreW(src, mem); |
| 4703 #endif |
| 4704 } |
| 4705 } |
| 4706 |
| 4707 // Store a "pointer" sized constant to the memory location |
| 4708 void MacroAssembler::StoreP(const MemOperand& mem, const Operand& opnd, |
| 4709 Register scratch) { |
| 4710 // Relocations not supported |
| 4711 DCHECK(opnd.rmode_ == kRelocInfo_NONEPTR); |
| 4712 |
| 4713 // Try to use MVGHI/MVHI |
| 4714 if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT) && is_uint12(mem.offset()) && |
| 4715 mem.getIndexRegister().is(r0) && is_int16(opnd.imm_)) { |
| 4716 #if V8_TARGET_ARCH_S390X |
| 4717 mvghi(mem, opnd); |
| 4718 #else |
| 4719 mvhi(mem, opnd); |
| 4720 #endif |
| 4721 } else { |
| 4722 LoadImmP(scratch, opnd); |
| 4723 StoreP(scratch, mem); |
| 4724 } |
| 4725 } |
| 4726 |
| 4727 void MacroAssembler::LoadMultipleP(Register dst1, Register dst2, |
| 4728 const MemOperand& mem) { |
| 4729 #if V8_TARGET_ARCH_S390X |
| 4730 DCHECK(is_int20(mem.offset())); |
| 4731 lmg(dst1, dst2, mem); |
| 4732 #else |
| 4733 if (is_uint12(mem.offset())) { |
| 4734 lm(dst1, dst2, mem); |
| 4735 } else { |
| 4736 DCHECK(is_int20(mem.offset())); |
| 4737 lmy(dst1, dst2, mem); |
| 4738 } |
| 4739 #endif |
| 4740 } |
| 4741 |
| 4742 void MacroAssembler::StoreMultipleP(Register src1, Register src2, |
| 4743 const MemOperand& mem) { |
| 4744 #if V8_TARGET_ARCH_S390X |
| 4745 DCHECK(is_int20(mem.offset())); |
| 4746 stmg(src1, src2, mem); |
| 4747 #else |
| 4748 if (is_uint12(mem.offset())) { |
| 4749 stm(src1, src2, mem); |
| 4750 } else { |
| 4751 DCHECK(is_int20(mem.offset())); |
| 4752 stmy(src1, src2, mem); |
| 4753 } |
| 4754 #endif |
| 4755 } |
| 4756 |
| 4757 void MacroAssembler::LoadMultipleW(Register dst1, Register dst2, |
| 4758 const MemOperand& mem) { |
| 4759 if (is_uint12(mem.offset())) { |
| 4760 lm(dst1, dst2, mem); |
| 4761 } else { |
| 4762 DCHECK(is_int20(mem.offset())); |
| 4763 lmy(dst1, dst2, mem); |
| 4764 } |
| 4765 } |
| 4766 |
| 4767 void MacroAssembler::StoreMultipleW(Register src1, Register src2, |
| 4768 const MemOperand& mem) { |
| 4769 if (is_uint12(mem.offset())) { |
| 4770 stm(src1, src2, mem); |
| 4771 } else { |
| 4772 DCHECK(is_int20(mem.offset())); |
| 4773 stmy(src1, src2, mem); |
| 4774 } |
| 4775 } |
| 4776 |
| 4777 // Load 32-bits and sign extend if necessary. |
| 4778 void MacroAssembler::LoadW(Register dst, const MemOperand& mem, |
| 4779 Register scratch) { |
| 4780 int offset = mem.offset(); |
| 4781 |
| 4782 if (!is_int20(offset)) { |
| 4783 DCHECK(!scratch.is(no_reg)); |
| 4784 LoadIntLiteral(scratch, offset); |
| 4785 #if V8_TARGET_ARCH_S390X |
| 4786 lgf(dst, MemOperand(mem.rb(), scratch)); |
| 4787 #else |
| 4788 l(dst, MemOperand(mem.rb(), scratch)); |
| 4789 #endif |
| 4790 } else { |
| 4791 #if V8_TARGET_ARCH_S390X |
| 4792 lgf(dst, mem); |
| 4793 #else |
| 4794 if (is_uint12(offset)) { |
| 4795 l(dst, mem); |
| 4796 } else { |
| 4797 ly(dst, mem); |
| 4798 } |
| 4799 #endif |
| 4800 } |
| 4801 } |
| 4802 |
| 4803 // Variable length depending on whether offset fits into immediate field |
| 4804 // MemOperand of RX or RXY format |
| 4805 void MacroAssembler::LoadlW(Register dst, const MemOperand& mem, |
| 4806 Register scratch) { |
| 4807 Register base = mem.rb(); |
| 4808 int offset = mem.offset(); |
| 4809 |
| 4810 #if V8_TARGET_ARCH_S390X |
| 4811 if (is_int20(offset)) { |
| 4812 llgf(dst, mem); |
| 4813 } else if (!scratch.is(no_reg)) { |
| 4814 // Materialize offset into scratch register. |
| 4815 LoadIntLiteral(scratch, offset); |
| 4816 llgf(dst, MemOperand(base, scratch)); |
| 4817 } else { |
| 4818 DCHECK(false); |
| 4819 } |
| 4820 #else |
| 4821 bool use_RXform = false; |
| 4822 bool use_RXYform = false; |
| 4823 if (is_uint12(offset)) { |
| 4824 // RX-format supports unsigned 12-bits offset. |
| 4825 use_RXform = true; |
| 4826 } else if (is_int20(offset)) { |
| 4827 // RXY-format supports signed 20-bits offset. |
| 4828 use_RXYform = true; |
| 4829 } else if (!scratch.is(no_reg)) { |
| 4830 // Materialize offset into scratch register. |
| 4831 LoadIntLiteral(scratch, offset); |
| 4832 } else { |
| 4833 DCHECK(false); |
| 4834 } |
| 4835 |
| 4836 if (use_RXform) { |
| 4837 l(dst, mem); |
| 4838 } else if (use_RXYform) { |
| 4839 ly(dst, mem); |
| 4840 } else { |
| 4841 ly(dst, MemOperand(base, scratch)); |
| 4842 } |
| 4843 #endif |
| 4844 } |
| 4845 |
| 4846 void MacroAssembler::LoadB(Register dst, const MemOperand& mem) { |
| 4847 #if V8_TARGET_ARCH_S390X |
| 4848 lgb(dst, mem); |
| 4849 #else |
| 4850 lb(dst, mem); |
| 4851 #endif |
| 4852 } |
| 4853 |
| 4854 void MacroAssembler::LoadlB(Register dst, const MemOperand& mem) { |
| 4855 #if V8_TARGET_ARCH_S390X |
| 4856 llgc(dst, mem); |
| 4857 #else |
| 4858 llc(dst, mem); |
| 4859 #endif |
| 4860 } |
| 4861 |
| 4862 // Load And Test (Reg <- Reg) |
| 4863 void MacroAssembler::LoadAndTest32(Register dst, Register src) { |
| 4864 ltr(dst, src); |
| 4865 } |
| 4866 |
| 4867 // Load And Test |
| 4868 // (Register dst(ptr) = Register src (32 | 32->64)) |
| 4869 // src is treated as a 32-bit signed integer, which is sign extended to |
| 4870 // 64-bit if necessary. |
| 4871 void MacroAssembler::LoadAndTestP_ExtendSrc(Register dst, Register src) { |
| 4872 #if V8_TARGET_ARCH_S390X |
| 4873 ltgfr(dst, src); |
| 4874 #else |
| 4875 ltr(dst, src); |
| 4876 #endif |
| 4877 } |
| 4878 |
| 4879 // Load And Test Pointer Sized (Reg <- Reg) |
| 4880 void MacroAssembler::LoadAndTestP(Register dst, Register src) { |
| 4881 #if V8_TARGET_ARCH_S390X |
| 4882 ltgr(dst, src); |
| 4883 #else |
| 4884 ltr(dst, src); |
| 4885 #endif |
| 4886 } |
| 4887 |
| 4888 // Load And Test 32-bit (Reg <- Mem) |
| 4889 void MacroAssembler::LoadAndTest32(Register dst, const MemOperand& mem) { |
| 4890 lt_z(dst, mem); |
| 4891 } |
| 4892 |
| 4893 // Load And Test Pointer Sized (Reg <- Mem) |
| 4894 void MacroAssembler::LoadAndTestP(Register dst, const MemOperand& mem) { |
| 4895 #if V8_TARGET_ARCH_S390X |
| 4896 ltg(dst, mem); |
| 4897 #else |
| 4898 lt_z(dst, mem); |
| 4899 #endif |
| 4900 } |
| 4901 |
| 4902 // Load Double Precision (64-bit) Floating Point number from memory |
| 4903 void MacroAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem) { |
| 4904 // for 32bit and 64bit we all use 64bit floating point regs |
| 4905 if (is_uint12(mem.offset())) { |
| 4906 ld(dst, mem); |
| 4907 } else { |
| 4908 ldy(dst, mem); |
| 4909 } |
| 4910 } |
| 4911 |
| 4912 // Load Single Precision (32-bit) Floating Point number from memory |
| 4913 void MacroAssembler::LoadFloat32(DoubleRegister dst, const MemOperand& mem) { |
| 4914 if (is_uint12(mem.offset())) { |
| 4915 le_z(dst, mem); |
| 4916 } else { |
| 4917 DCHECK(is_int20(mem.offset())); |
| 4918 ley(dst, mem); |
| 4919 } |
| 4920 } |
| 4921 |
| 4922 // Load Single Precision (32-bit) Floating Point number from memory, |
| 4923 // and convert to Double Precision (64-bit) |
| 4924 void MacroAssembler::LoadFloat32ConvertToDouble(DoubleRegister dst, |
| 4925 const MemOperand& mem) { |
| 4926 LoadFloat32(dst, mem); |
| 4927 ldebr(dst, dst); |
| 4928 } |
| 4929 |
| 4930 // Store Double Precision (64-bit) Floating Point number to memory |
| 4931 void MacroAssembler::StoreDouble(DoubleRegister dst, const MemOperand& mem) { |
| 4932 if (is_uint12(mem.offset())) { |
| 4933 std(dst, mem); |
| 4934 } else { |
| 4935 stdy(dst, mem); |
| 4936 } |
| 4937 } |
| 4938 |
| 4939 // Store Single Precision (32-bit) Floating Point number to memory |
| 4940 void MacroAssembler::StoreFloat32(DoubleRegister src, const MemOperand& mem) { |
| 4941 if (is_uint12(mem.offset())) { |
| 4942 ste(src, mem); |
| 4943 } else { |
| 4944 stey(src, mem); |
| 4945 } |
| 4946 } |
| 4947 |
| 4948 // Convert Double precision (64-bit) to Single Precision (32-bit) |
| 4949 // and store resulting Float32 to memory |
| 4950 void MacroAssembler::StoreDoubleAsFloat32(DoubleRegister src, |
| 4951 const MemOperand& mem, |
| 4952 DoubleRegister scratch) { |
| 4953 ledbr(scratch, src); |
| 4954 StoreFloat32(scratch, mem); |
| 4955 } |
| 4956 |
| 4957 // Variable length depending on whether offset fits into immediate field |
| 4958 // MemOperand of RX or RXY format |
| 4959 void MacroAssembler::StoreW(Register src, const MemOperand& mem, |
| 4960 Register scratch) { |
| 4961 Register base = mem.rb(); |
| 4962 int offset = mem.offset(); |
| 4963 |
| 4964 bool use_RXform = false; |
| 4965 bool use_RXYform = false; |
| 4966 |
| 4967 if (is_uint12(offset)) { |
| 4968 // RX-format supports unsigned 12-bits offset. |
| 4969 use_RXform = true; |
| 4970 } else if (is_int20(offset)) { |
| 4971 // RXY-format supports signed 20-bits offset. |
| 4972 use_RXYform = true; |
| 4973 } else if (!scratch.is(no_reg)) { |
| 4974 // Materialize offset into scratch register. |
| 4975 LoadIntLiteral(scratch, offset); |
| 4976 } else { |
| 4977 // scratch is no_reg |
| 4978 DCHECK(false); |
| 4979 } |
| 4980 |
| 4981 if (use_RXform) { |
| 4982 st(src, mem); |
| 4983 } else if (use_RXYform) { |
| 4984 sty(src, mem); |
| 4985 } else { |
| 4986 StoreW(src, MemOperand(base, scratch)); |
| 4987 } |
| 4988 } |
| 4989 |
| 4990 // Loads 16-bits half-word value from memory and sign extends to pointer |
| 4991 // sized register |
| 4992 void MacroAssembler::LoadHalfWordP(Register dst, const MemOperand& mem, |
| 4993 Register scratch) { |
| 4994 Register base = mem.rb(); |
| 4995 int offset = mem.offset(); |
| 4996 |
| 4997 if (!is_int20(offset)) { |
| 4998 DCHECK(!scratch.is(no_reg)); |
| 4999 LoadIntLiteral(scratch, offset); |
| 5000 #if V8_TARGET_ARCH_S390X |
| 5001 lgh(dst, MemOperand(base, scratch)); |
| 5002 #else |
| 5003 lh(dst, MemOperand(base, scratch)); |
| 5004 #endif |
| 5005 } else { |
| 5006 #if V8_TARGET_ARCH_S390X |
| 5007 lgh(dst, mem); |
| 5008 #else |
| 5009 if (is_uint12(offset)) { |
| 5010 lh(dst, mem); |
| 5011 } else { |
| 5012 lhy(dst, mem); |
| 5013 } |
| 5014 #endif |
| 5015 } |
| 5016 } |
| 5017 |
| 5018 // Variable length depending on whether offset fits into immediate field |
| 5019 // MemOperand current only supports d-form |
| 5020 void MacroAssembler::StoreHalfWord(Register src, const MemOperand& mem, |
| 5021 Register scratch) { |
| 5022 Register base = mem.rb(); |
| 5023 int offset = mem.offset(); |
| 5024 |
| 5025 if (is_uint12(offset)) { |
| 5026 sth(src, mem); |
| 5027 } else if (is_int20(offset)) { |
| 5028 sthy(src, mem); |
| 5029 } else { |
| 5030 DCHECK(!scratch.is(no_reg)); |
| 5031 LoadIntLiteral(scratch, offset); |
| 5032 sth(src, MemOperand(base, scratch)); |
| 5033 } |
| 5034 } |
| 5035 |
| 5036 // Variable length depending on whether offset fits into immediate field |
| 5037 // MemOperand current only supports d-form |
| 5038 void MacroAssembler::StoreByte(Register src, const MemOperand& mem, |
| 5039 Register scratch) { |
| 5040 Register base = mem.rb(); |
| 5041 int offset = mem.offset(); |
| 5042 |
| 5043 if (is_uint12(offset)) { |
| 5044 stc(src, mem); |
| 5045 } else if (is_int20(offset)) { |
| 5046 stcy(src, mem); |
| 5047 } else { |
| 5048 DCHECK(!scratch.is(no_reg)); |
| 5049 LoadIntLiteral(scratch, offset); |
| 5050 stc(src, MemOperand(base, scratch)); |
| 5051 } |
| 5052 } |
| 5053 |
| 5054 // Shift left logical for 32-bit integer types. |
| 5055 void MacroAssembler::ShiftLeft(Register dst, Register src, const Operand& val) { |
| 5056 if (dst.is(src)) { |
| 5057 sll(dst, val); |
| 5058 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 5059 sllk(dst, src, val); |
| 5060 } else { |
| 5061 lr(dst, src); |
| 5062 sll(dst, val); |
| 5063 } |
| 5064 } |
| 5065 |
| 5066 // Shift left logical for 32-bit integer types. |
| 5067 void MacroAssembler::ShiftLeft(Register dst, Register src, Register val) { |
| 5068 if (dst.is(src)) { |
| 5069 sll(dst, val); |
| 5070 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 5071 sllk(dst, src, val); |
| 5072 } else { |
| 5073 DCHECK(!dst.is(val)); // The lr/sll path clobbers val. |
| 5074 lr(dst, src); |
| 5075 sll(dst, val); |
| 5076 } |
| 5077 } |
| 5078 |
| 5079 // Shift right logical for 32-bit integer types. |
| 5080 void MacroAssembler::ShiftRight(Register dst, Register src, |
| 5081 const Operand& val) { |
| 5082 if (dst.is(src)) { |
| 5083 srl(dst, val); |
| 5084 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 5085 srlk(dst, src, val); |
| 5086 } else { |
| 5087 lr(dst, src); |
| 5088 srl(dst, val); |
| 5089 } |
| 5090 } |
| 5091 |
| 5092 // Shift right logical for 32-bit integer types. |
| 5093 void MacroAssembler::ShiftRight(Register dst, Register src, Register val) { |
| 5094 DCHECK(!dst.is(val)); // The lr/srl path clobbers val. |
| 5095 if (dst.is(src)) { |
| 5096 srl(dst, val); |
| 5097 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 5098 srlk(dst, src, val); |
| 5099 } else { |
| 5100 lr(dst, src); |
| 5101 srl(dst, val); |
| 5102 } |
| 5103 } |
| 5104 |
| 5105 // Shift left arithmetic for 32-bit integer types. |
| 5106 void MacroAssembler::ShiftLeftArith(Register dst, Register src, |
| 5107 const Operand& val) { |
| 5108 if (dst.is(src)) { |
| 5109 sla(dst, val); |
| 5110 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 5111 slak(dst, src, val); |
| 5112 } else { |
| 5113 lr(dst, src); |
| 5114 sla(dst, val); |
| 5115 } |
| 5116 } |
| 5117 |
| 5118 // Shift left arithmetic for 32-bit integer types. |
| 5119 void MacroAssembler::ShiftLeftArith(Register dst, Register src, Register val) { |
| 5120 DCHECK(!dst.is(val)); // The lr/sla path clobbers val. |
| 5121 if (dst.is(src)) { |
| 5122 sla(dst, val); |
| 5123 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 5124 slak(dst, src, val); |
| 5125 } else { |
| 5126 lr(dst, src); |
| 5127 sla(dst, val); |
| 5128 } |
| 5129 } |
| 5130 |
| 5131 // Shift right arithmetic for 32-bit integer types. |
| 5132 void MacroAssembler::ShiftRightArith(Register dst, Register src, |
| 5133 const Operand& val) { |
| 5134 if (dst.is(src)) { |
| 5135 sra(dst, val); |
| 5136 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 5137 srak(dst, src, val); |
| 5138 } else { |
| 5139 lr(dst, src); |
| 5140 sra(dst, val); |
| 5141 } |
| 5142 } |
| 5143 |
| 5144 // Shift right arithmetic for 32-bit integer types. |
| 5145 void MacroAssembler::ShiftRightArith(Register dst, Register src, Register val) { |
| 5146 DCHECK(!dst.is(val)); // The lr/sra path clobbers val. |
| 5147 if (dst.is(src)) { |
| 5148 sra(dst, val); |
| 5149 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) { |
| 5150 srak(dst, src, val); |
| 5151 } else { |
| 5152 lr(dst, src); |
| 5153 sra(dst, val); |
| 5154 } |
| 5155 } |
| 5156 |
| 5157 // Clear right most # of bits |
| 5158 void MacroAssembler::ClearRightImm(Register dst, Register src, |
| 5159 const Operand& val) { |
| 5160 int numBitsToClear = val.imm_ % (kPointerSize * 8); |
| 5161 |
| 5162 // Try to use RISBG if possible |
| 5163 if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) { |
| 5164 int endBit = 63 - numBitsToClear; |
| 5165 risbg(dst, src, Operand::Zero(), Operand(endBit), Operand::Zero(), true); |
| 5166 return; |
| 5167 } |
| 5168 |
| 5169 uint64_t hexMask = ~((1L << numBitsToClear) - 1); |
| 5170 |
| 5171 // S390 AND instr clobbers source. Make a copy if necessary |
| 5172 if (!dst.is(src)) LoadRR(dst, src); |
| 5173 |
| 5174 if (numBitsToClear <= 16) { |
| 5175 nill(dst, Operand(static_cast<uint16_t>(hexMask))); |
| 5176 } else if (numBitsToClear <= 32) { |
| 5177 nilf(dst, Operand(static_cast<uint32_t>(hexMask))); |
| 5178 } else if (numBitsToClear <= 64) { |
| 5179 nilf(dst, Operand(static_cast<intptr_t>(0))); |
| 5180 nihf(dst, Operand(hexMask >> 32)); |
| 5181 } |
| 5182 } |
| 5183 |
| 5184 void MacroAssembler::Popcnt32(Register dst, Register src) { |
| 5185 DCHECK(!src.is(r0)); |
| 5186 DCHECK(!dst.is(r0)); |
| 5187 |
| 5188 popcnt(dst, src); |
| 5189 ShiftRight(r0, dst, Operand(16)); |
| 5190 ar(dst, r0); |
| 5191 ShiftRight(r0, dst, Operand(8)); |
| 5192 ar(dst, r0); |
| 5193 lbr(dst, dst); |
| 5194 } |
| 5195 |
| 5196 #ifdef V8_TARGET_ARCH_S390X |
| 5197 void MacroAssembler::Popcnt64(Register dst, Register src) { |
| 5198 DCHECK(!src.is(r0)); |
| 5199 DCHECK(!dst.is(r0)); |
| 5200 |
| 5201 popcnt(dst, src); |
| 5202 ShiftRightP(r0, dst, Operand(32)); |
| 5203 AddP(dst, r0); |
| 5204 ShiftRightP(r0, dst, Operand(16)); |
| 5205 AddP(dst, r0); |
| 5206 ShiftRightP(r0, dst, Operand(8)); |
| 5207 AddP(dst, r0); |
| 5208 lbr(dst, dst); |
| 5209 } |
| 5210 #endif |
| 4313 | 5211 |
| 4314 #ifdef DEBUG | 5212 #ifdef DEBUG |
| 4315 bool AreAliased(Register reg1, Register reg2, Register reg3, Register reg4, | 5213 bool AreAliased(Register reg1, Register reg2, Register reg3, Register reg4, |
| 4316 Register reg5, Register reg6, Register reg7, Register reg8, | 5214 Register reg5, Register reg6, Register reg7, Register reg8, |
| 4317 Register reg9, Register reg10) { | 5215 Register reg9, Register reg10) { |
| 4318 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + reg3.is_valid() + | 5216 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + reg3.is_valid() + |
| 4319 reg4.is_valid() + reg5.is_valid() + reg6.is_valid() + | 5217 reg4.is_valid() + reg5.is_valid() + reg6.is_valid() + |
| 4320 reg7.is_valid() + reg8.is_valid() + reg9.is_valid() + | 5218 reg7.is_valid() + reg8.is_valid() + reg9.is_valid() + |
| 4321 reg10.is_valid(); | 5219 reg10.is_valid(); |
| 4322 | 5220 |
| 4323 RegList regs = 0; | 5221 RegList regs = 0; |
| 4324 if (reg1.is_valid()) regs |= reg1.bit(); | 5222 if (reg1.is_valid()) regs |= reg1.bit(); |
| 4325 if (reg2.is_valid()) regs |= reg2.bit(); | 5223 if (reg2.is_valid()) regs |= reg2.bit(); |
| 4326 if (reg3.is_valid()) regs |= reg3.bit(); | 5224 if (reg3.is_valid()) regs |= reg3.bit(); |
| 4327 if (reg4.is_valid()) regs |= reg4.bit(); | 5225 if (reg4.is_valid()) regs |= reg4.bit(); |
| 4328 if (reg5.is_valid()) regs |= reg5.bit(); | 5226 if (reg5.is_valid()) regs |= reg5.bit(); |
| 4329 if (reg6.is_valid()) regs |= reg6.bit(); | 5227 if (reg6.is_valid()) regs |= reg6.bit(); |
| 4330 if (reg7.is_valid()) regs |= reg7.bit(); | 5228 if (reg7.is_valid()) regs |= reg7.bit(); |
| 4331 if (reg8.is_valid()) regs |= reg8.bit(); | 5229 if (reg8.is_valid()) regs |= reg8.bit(); |
| 4332 if (reg9.is_valid()) regs |= reg9.bit(); | 5230 if (reg9.is_valid()) regs |= reg9.bit(); |
| 4333 if (reg10.is_valid()) regs |= reg10.bit(); | 5231 if (reg10.is_valid()) regs |= reg10.bit(); |
| 4334 int n_of_non_aliasing_regs = NumRegs(regs); | 5232 int n_of_non_aliasing_regs = NumRegs(regs); |
| 4335 | 5233 |
| 4336 return n_of_valid_regs != n_of_non_aliasing_regs; | 5234 return n_of_valid_regs != n_of_non_aliasing_regs; |
| 4337 } | 5235 } |
| 4338 #endif | 5236 #endif |
| 4339 | 5237 |
| 4340 | 5238 CodePatcher::CodePatcher(Isolate* isolate, byte* address, int size, |
| 4341 CodePatcher::CodePatcher(Isolate* isolate, byte* address, int instructions, | |
| 4342 FlushICache flush_cache) | 5239 FlushICache flush_cache) |
| 4343 : address_(address), | 5240 : address_(address), |
| 4344 size_(instructions * Assembler::kInstrSize), | 5241 size_(size), |
| 4345 masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo), | 5242 masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo), |
| 4346 flush_cache_(flush_cache) { | 5243 flush_cache_(flush_cache) { |
| 4347 // Create a new macro assembler pointing to the address of the code to patch. | 5244 // Create a new macro assembler pointing to the address of the code to patch. |
| 4348 // The size is adjusted with kGap on order for the assembler to generate size | 5245 // The size is adjusted with kGap on order for the assembler to generate size |
| 4349 // bytes of instructions without failing with buffer size constraints. | 5246 // bytes of instructions without failing with buffer size constraints. |
| 4350 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 5247 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
| 4351 } | 5248 } |
| 4352 | 5249 |
| 4353 | |
| 4354 CodePatcher::~CodePatcher() { | 5250 CodePatcher::~CodePatcher() { |
| 4355 // Indicate that code has changed. | 5251 // Indicate that code has changed. |
| 4356 if (flush_cache_ == FLUSH) { | 5252 if (flush_cache_ == FLUSH) { |
| 4357 Assembler::FlushICache(masm_.isolate(), address_, size_); | 5253 Assembler::FlushICache(masm_.isolate(), address_, size_); |
| 4358 } | 5254 } |
| 4359 | 5255 |
| 4360 // Check that the code was patched as expected. | 5256 // Check that the code was patched as expected. |
| 4361 DCHECK(masm_.pc_ == address_ + size_); | 5257 DCHECK(masm_.pc_ == address_ + size_); |
| 4362 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 5258 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
| 4363 } | 5259 } |
| 4364 | 5260 |
| 4365 | |
| 4366 void CodePatcher::Emit(Instr instr) { masm()->emit(instr); } | |
| 4367 | |
| 4368 | |
| 4369 void CodePatcher::EmitCondition(Condition cond) { | |
| 4370 Instr instr = Assembler::instr_at(masm_.pc_); | |
| 4371 switch (cond) { | |
| 4372 case eq: | |
| 4373 instr = (instr & ~kCondMask) | BT; | |
| 4374 break; | |
| 4375 case ne: | |
| 4376 instr = (instr & ~kCondMask) | BF; | |
| 4377 break; | |
| 4378 default: | |
| 4379 UNIMPLEMENTED(); | |
| 4380 } | |
| 4381 masm_.emit(instr); | |
| 4382 } | |
| 4383 | |
| 4384 | |
| 4385 void MacroAssembler::TruncatingDiv(Register result, Register dividend, | 5261 void MacroAssembler::TruncatingDiv(Register result, Register dividend, |
| 4386 int32_t divisor) { | 5262 int32_t divisor) { |
| 4387 DCHECK(!dividend.is(result)); | 5263 DCHECK(!dividend.is(result)); |
| 4388 DCHECK(!dividend.is(r0)); | 5264 DCHECK(!dividend.is(r0)); |
| 4389 DCHECK(!result.is(r0)); | 5265 DCHECK(!result.is(r0)); |
| 4390 base::MagicNumbersForDivision<uint32_t> mag = | 5266 base::MagicNumbersForDivision<uint32_t> mag = |
| 4391 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor)); | 5267 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor)); |
| 4392 mov(r0, Operand(mag.multiplier)); | 5268 #ifdef V8_TARGET_ARCH_S390X |
| 4393 mulhw(result, dividend, r0); | 5269 LoadRR(result, dividend); |
| 5270 MulP(result, Operand(mag.multiplier)); |
| 5271 ShiftRightArithP(result, result, Operand(32)); |
| 5272 |
| 5273 #else |
| 5274 lay(sp, MemOperand(sp, -kPointerSize)); |
| 5275 StoreP(r1, MemOperand(sp)); |
| 5276 |
| 5277 mov(r1, Operand(mag.multiplier)); |
| 5278 mr_z(r0, dividend); // r0:r1 = r1 * dividend |
| 5279 |
| 5280 LoadRR(result, r0); |
| 5281 LoadP(r1, MemOperand(sp)); |
| 5282 la(sp, MemOperand(sp, kPointerSize)); |
| 5283 #endif |
| 4394 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0; | 5284 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0; |
| 4395 if (divisor > 0 && neg) { | 5285 if (divisor > 0 && neg) { |
| 4396 add(result, result, dividend); | 5286 AddP(result, dividend); |
| 4397 } | 5287 } |
| 4398 if (divisor < 0 && !neg && mag.multiplier > 0) { | 5288 if (divisor < 0 && !neg && mag.multiplier > 0) { |
| 4399 sub(result, result, dividend); | 5289 SubP(result, dividend); |
| 4400 } | 5290 } |
| 4401 if (mag.shift > 0) srawi(result, result, mag.shift); | 5291 if (mag.shift > 0) ShiftRightArith(result, result, Operand(mag.shift)); |
| 4402 ExtractBit(r0, dividend, 31); | 5292 ExtractBit(r0, dividend, 31); |
| 4403 add(result, result, r0); | 5293 AddP(result, r0); |
| 4404 } | 5294 } |
| 4405 | 5295 |
| 4406 } // namespace internal | 5296 } // namespace internal |
| 4407 } // namespace v8 | 5297 } // namespace v8 |
| 4408 | 5298 |
| 4409 #endif // V8_TARGET_ARCH_PPC | 5299 #endif // V8_TARGET_ARCH_S390 |
| OLD | NEW |