Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | * vim: set ts=8 sts=4 et sw=4 tw=99: |
michael@0 | 3 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "jit/x64/CodeGenerator-x64.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "jit/IonCaches.h" |
michael@0 | 10 | #include "jit/MIR.h" |
michael@0 | 11 | |
michael@0 | 12 | #include "jsscriptinlines.h" |
michael@0 | 13 | |
michael@0 | 14 | #include "jit/shared/CodeGenerator-shared-inl.h" |
michael@0 | 15 | |
michael@0 | 16 | using namespace js; |
michael@0 | 17 | using namespace js::jit; |
michael@0 | 18 | |
michael@0 | 19 | CodeGeneratorX64::CodeGeneratorX64(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm) |
michael@0 | 20 | : CodeGeneratorX86Shared(gen, graph, masm) |
michael@0 | 21 | { |
michael@0 | 22 | } |
michael@0 | 23 | |
michael@0 | 24 | ValueOperand |
michael@0 | 25 | CodeGeneratorX64::ToValue(LInstruction *ins, size_t pos) |
michael@0 | 26 | { |
michael@0 | 27 | return ValueOperand(ToRegister(ins->getOperand(pos))); |
michael@0 | 28 | } |
michael@0 | 29 | |
michael@0 | 30 | ValueOperand |
michael@0 | 31 | CodeGeneratorX64::ToOutValue(LInstruction *ins) |
michael@0 | 32 | { |
michael@0 | 33 | return ValueOperand(ToRegister(ins->getDef(0))); |
michael@0 | 34 | } |
michael@0 | 35 | |
michael@0 | 36 | ValueOperand |
michael@0 | 37 | CodeGeneratorX64::ToTempValue(LInstruction *ins, size_t pos) |
michael@0 | 38 | { |
michael@0 | 39 | return ValueOperand(ToRegister(ins->getTemp(pos))); |
michael@0 | 40 | } |
michael@0 | 41 | |
michael@0 | 42 | FrameSizeClass |
michael@0 | 43 | FrameSizeClass::FromDepth(uint32_t frameDepth) |
michael@0 | 44 | { |
michael@0 | 45 | return FrameSizeClass::None(); |
michael@0 | 46 | } |
michael@0 | 47 | |
michael@0 | 48 | FrameSizeClass |
michael@0 | 49 | FrameSizeClass::ClassLimit() |
michael@0 | 50 | { |
michael@0 | 51 | return FrameSizeClass(0); |
michael@0 | 52 | } |
michael@0 | 53 | |
michael@0 | 54 | uint32_t |
michael@0 | 55 | FrameSizeClass::frameSize() const |
michael@0 | 56 | { |
michael@0 | 57 | MOZ_ASSUME_UNREACHABLE("x64 does not use frame size classes"); |
michael@0 | 58 | } |
michael@0 | 59 | |
michael@0 | 60 | bool |
michael@0 | 61 | CodeGeneratorX64::visitValue(LValue *value) |
michael@0 | 62 | { |
michael@0 | 63 | LDefinition *reg = value->getDef(0); |
michael@0 | 64 | masm.moveValue(value->value(), ToRegister(reg)); |
michael@0 | 65 | return true; |
michael@0 | 66 | } |
michael@0 | 67 | |
michael@0 | 68 | bool |
michael@0 | 69 | CodeGeneratorX64::visitBox(LBox *box) |
michael@0 | 70 | { |
michael@0 | 71 | const LAllocation *in = box->getOperand(0); |
michael@0 | 72 | const LDefinition *result = box->getDef(0); |
michael@0 | 73 | |
michael@0 | 74 | if (IsFloatingPointType(box->type())) { |
michael@0 | 75 | FloatRegister reg = ToFloatRegister(in); |
michael@0 | 76 | if (box->type() == MIRType_Float32) { |
michael@0 | 77 | masm.convertFloat32ToDouble(reg, ScratchFloatReg); |
michael@0 | 78 | reg = ScratchFloatReg; |
michael@0 | 79 | } |
michael@0 | 80 | masm.movq(reg, ToRegister(result)); |
michael@0 | 81 | } else { |
michael@0 | 82 | masm.boxValue(ValueTypeFromMIRType(box->type()), ToRegister(in), ToRegister(result)); |
michael@0 | 83 | } |
michael@0 | 84 | return true; |
michael@0 | 85 | } |
michael@0 | 86 | |
michael@0 | 87 | bool |
michael@0 | 88 | CodeGeneratorX64::visitUnbox(LUnbox *unbox) |
michael@0 | 89 | { |
michael@0 | 90 | const ValueOperand value = ToValue(unbox, LUnbox::Input); |
michael@0 | 91 | const LDefinition *result = unbox->output(); |
michael@0 | 92 | MUnbox *mir = unbox->mir(); |
michael@0 | 93 | |
michael@0 | 94 | if (mir->fallible()) { |
michael@0 | 95 | Assembler::Condition cond; |
michael@0 | 96 | switch (mir->type()) { |
michael@0 | 97 | case MIRType_Int32: |
michael@0 | 98 | cond = masm.testInt32(Assembler::NotEqual, value); |
michael@0 | 99 | break; |
michael@0 | 100 | case MIRType_Boolean: |
michael@0 | 101 | cond = masm.testBoolean(Assembler::NotEqual, value); |
michael@0 | 102 | break; |
michael@0 | 103 | case MIRType_Object: |
michael@0 | 104 | cond = masm.testObject(Assembler::NotEqual, value); |
michael@0 | 105 | break; |
michael@0 | 106 | case MIRType_String: |
michael@0 | 107 | cond = masm.testString(Assembler::NotEqual, value); |
michael@0 | 108 | break; |
michael@0 | 109 | default: |
michael@0 | 110 | MOZ_ASSUME_UNREACHABLE("Given MIRType cannot be unboxed."); |
michael@0 | 111 | } |
michael@0 | 112 | if (!bailoutIf(cond, unbox->snapshot())) |
michael@0 | 113 | return false; |
michael@0 | 114 | } |
michael@0 | 115 | |
michael@0 | 116 | switch (mir->type()) { |
michael@0 | 117 | case MIRType_Int32: |
michael@0 | 118 | masm.unboxInt32(value, ToRegister(result)); |
michael@0 | 119 | break; |
michael@0 | 120 | case MIRType_Boolean: |
michael@0 | 121 | masm.unboxBoolean(value, ToRegister(result)); |
michael@0 | 122 | break; |
michael@0 | 123 | case MIRType_Object: |
michael@0 | 124 | masm.unboxObject(value, ToRegister(result)); |
michael@0 | 125 | break; |
michael@0 | 126 | case MIRType_String: |
michael@0 | 127 | masm.unboxString(value, ToRegister(result)); |
michael@0 | 128 | break; |
michael@0 | 129 | default: |
michael@0 | 130 | MOZ_ASSUME_UNREACHABLE("Given MIRType cannot be unboxed."); |
michael@0 | 131 | } |
michael@0 | 132 | |
michael@0 | 133 | return true; |
michael@0 | 134 | } |
michael@0 | 135 | |
michael@0 | 136 | bool |
michael@0 | 137 | CodeGeneratorX64::visitLoadSlotV(LLoadSlotV *load) |
michael@0 | 138 | { |
michael@0 | 139 | ValueOperand dest = ToOutValue(load); |
michael@0 | 140 | Register base = ToRegister(load->input()); |
michael@0 | 141 | int32_t offset = load->mir()->slot() * sizeof(js::Value); |
michael@0 | 142 | |
michael@0 | 143 | masm.loadValue(Address(base, offset), dest); |
michael@0 | 144 | return true; |
michael@0 | 145 | } |
michael@0 | 146 | |
michael@0 | 147 | void |
michael@0 | 148 | CodeGeneratorX64::loadUnboxedValue(Operand source, MIRType type, const LDefinition *dest) |
michael@0 | 149 | { |
michael@0 | 150 | switch (type) { |
michael@0 | 151 | case MIRType_Double: |
michael@0 | 152 | masm.loadInt32OrDouble(source, ToFloatRegister(dest)); |
michael@0 | 153 | break; |
michael@0 | 154 | |
michael@0 | 155 | case MIRType_Object: |
michael@0 | 156 | case MIRType_String: |
michael@0 | 157 | masm.unboxObject(source, ToRegister(dest)); |
michael@0 | 158 | break; |
michael@0 | 159 | |
michael@0 | 160 | case MIRType_Int32: |
michael@0 | 161 | case MIRType_Boolean: |
michael@0 | 162 | masm.movl(source, ToRegister(dest)); |
michael@0 | 163 | break; |
michael@0 | 164 | |
michael@0 | 165 | default: |
michael@0 | 166 | MOZ_ASSUME_UNREACHABLE("unexpected type"); |
michael@0 | 167 | } |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | bool |
michael@0 | 171 | CodeGeneratorX64::visitLoadSlotT(LLoadSlotT *load) |
michael@0 | 172 | { |
michael@0 | 173 | Register base = ToRegister(load->input()); |
michael@0 | 174 | int32_t offset = load->mir()->slot() * sizeof(js::Value); |
michael@0 | 175 | |
michael@0 | 176 | loadUnboxedValue(Operand(base, offset), load->mir()->type(), load->output()); |
michael@0 | 177 | |
michael@0 | 178 | return true; |
michael@0 | 179 | } |
michael@0 | 180 | |
michael@0 | 181 | void |
michael@0 | 182 | CodeGeneratorX64::storeUnboxedValue(const LAllocation *value, MIRType valueType, |
michael@0 | 183 | Operand dest, MIRType slotType) |
michael@0 | 184 | { |
michael@0 | 185 | if (valueType == MIRType_Double) { |
michael@0 | 186 | masm.storeDouble(ToFloatRegister(value), dest); |
michael@0 | 187 | return; |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | // For known integers and booleans, we can just store the unboxed value if |
michael@0 | 191 | // the slot has the same type. |
michael@0 | 192 | if ((valueType == MIRType_Int32 || valueType == MIRType_Boolean) && slotType == valueType) { |
michael@0 | 193 | if (value->isConstant()) { |
michael@0 | 194 | Value val = *value->toConstant(); |
michael@0 | 195 | if (valueType == MIRType_Int32) |
michael@0 | 196 | masm.movl(Imm32(val.toInt32()), dest); |
michael@0 | 197 | else |
michael@0 | 198 | masm.movl(Imm32(val.toBoolean() ? 1 : 0), dest); |
michael@0 | 199 | } else { |
michael@0 | 200 | masm.movl(ToRegister(value), dest); |
michael@0 | 201 | } |
michael@0 | 202 | return; |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | if (value->isConstant()) { |
michael@0 | 206 | masm.moveValue(*value->toConstant(), ScratchReg); |
michael@0 | 207 | masm.movq(ScratchReg, dest); |
michael@0 | 208 | } else { |
michael@0 | 209 | masm.storeValue(ValueTypeFromMIRType(valueType), ToRegister(value), dest); |
michael@0 | 210 | } |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | bool |
michael@0 | 214 | CodeGeneratorX64::visitStoreSlotT(LStoreSlotT *store) |
michael@0 | 215 | { |
michael@0 | 216 | Register base = ToRegister(store->slots()); |
michael@0 | 217 | int32_t offset = store->mir()->slot() * sizeof(js::Value); |
michael@0 | 218 | |
michael@0 | 219 | const LAllocation *value = store->value(); |
michael@0 | 220 | MIRType valueType = store->mir()->value()->type(); |
michael@0 | 221 | MIRType slotType = store->mir()->slotType(); |
michael@0 | 222 | |
michael@0 | 223 | if (store->mir()->needsBarrier()) |
michael@0 | 224 | emitPreBarrier(Address(base, offset), slotType); |
michael@0 | 225 | |
michael@0 | 226 | storeUnboxedValue(value, valueType, Operand(base, offset), slotType); |
michael@0 | 227 | return true; |
michael@0 | 228 | } |
michael@0 | 229 | |
michael@0 | 230 | bool |
michael@0 | 231 | CodeGeneratorX64::visitLoadElementT(LLoadElementT *load) |
michael@0 | 232 | { |
michael@0 | 233 | Operand source = createArrayElementOperand(ToRegister(load->elements()), load->index()); |
michael@0 | 234 | |
michael@0 | 235 | if (load->mir()->loadDoubles()) { |
michael@0 | 236 | FloatRegister fpreg = ToFloatRegister(load->output()); |
michael@0 | 237 | if (source.kind() == Operand::MEM_REG_DISP) |
michael@0 | 238 | masm.loadDouble(source.toAddress(), fpreg); |
michael@0 | 239 | else |
michael@0 | 240 | masm.loadDouble(source.toBaseIndex(), fpreg); |
michael@0 | 241 | } else { |
michael@0 | 242 | loadUnboxedValue(source, load->mir()->type(), load->output()); |
michael@0 | 243 | } |
michael@0 | 244 | |
michael@0 | 245 | JS_ASSERT(!load->mir()->needsHoleCheck()); |
michael@0 | 246 | return true; |
michael@0 | 247 | } |
michael@0 | 248 | |
michael@0 | 249 | |
michael@0 | 250 | void |
michael@0 | 251 | CodeGeneratorX64::storeElementTyped(const LAllocation *value, MIRType valueType, MIRType elementType, |
michael@0 | 252 | const Register &elements, const LAllocation *index) |
michael@0 | 253 | { |
michael@0 | 254 | Operand dest = createArrayElementOperand(elements, index); |
michael@0 | 255 | storeUnboxedValue(value, valueType, dest, elementType); |
michael@0 | 256 | } |
michael@0 | 257 | |
michael@0 | 258 | bool |
michael@0 | 259 | CodeGeneratorX64::visitImplicitThis(LImplicitThis *lir) |
michael@0 | 260 | { |
michael@0 | 261 | Register callee = ToRegister(lir->callee()); |
michael@0 | 262 | |
michael@0 | 263 | // The implicit |this| is always |undefined| if the function's environment |
michael@0 | 264 | // is the current global. |
michael@0 | 265 | GlobalObject *global = &gen->info().script()->global(); |
michael@0 | 266 | masm.cmpPtr(Operand(callee, JSFunction::offsetOfEnvironment()), ImmGCPtr(global)); |
michael@0 | 267 | |
michael@0 | 268 | // TODO: OOL stub path. |
michael@0 | 269 | if (!bailoutIf(Assembler::NotEqual, lir->snapshot())) |
michael@0 | 270 | return false; |
michael@0 | 271 | |
michael@0 | 272 | masm.moveValue(UndefinedValue(), ToOutValue(lir)); |
michael@0 | 273 | return true; |
michael@0 | 274 | } |
michael@0 | 275 | |
michael@0 | 276 | bool |
michael@0 | 277 | CodeGeneratorX64::visitInterruptCheck(LInterruptCheck *lir) |
michael@0 | 278 | { |
michael@0 | 279 | OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing()); |
michael@0 | 280 | if (!ool) |
michael@0 | 281 | return false; |
michael@0 | 282 | |
michael@0 | 283 | masm.branch32(Assembler::NotEqual, |
michael@0 | 284 | AbsoluteAddress(GetIonContext()->runtime->addressOfInterrupt()), Imm32(0), |
michael@0 | 285 | ool->entry()); |
michael@0 | 286 | masm.bind(ool->rejoin()); |
michael@0 | 287 | return true; |
michael@0 | 288 | } |
michael@0 | 289 | |
michael@0 | 290 | bool |
michael@0 | 291 | CodeGeneratorX64::visitCompareB(LCompareB *lir) |
michael@0 | 292 | { |
michael@0 | 293 | MCompare *mir = lir->mir(); |
michael@0 | 294 | |
michael@0 | 295 | const ValueOperand lhs = ToValue(lir, LCompareB::Lhs); |
michael@0 | 296 | const LAllocation *rhs = lir->rhs(); |
michael@0 | 297 | const Register output = ToRegister(lir->output()); |
michael@0 | 298 | |
michael@0 | 299 | JS_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE); |
michael@0 | 300 | |
michael@0 | 301 | // Load boxed boolean in ScratchReg. |
michael@0 | 302 | if (rhs->isConstant()) |
michael@0 | 303 | masm.moveValue(*rhs->toConstant(), ScratchReg); |
michael@0 | 304 | else |
michael@0 | 305 | masm.boxValue(JSVAL_TYPE_BOOLEAN, ToRegister(rhs), ScratchReg); |
michael@0 | 306 | |
michael@0 | 307 | // Perform the comparison. |
michael@0 | 308 | masm.cmpq(lhs.valueReg(), ScratchReg); |
michael@0 | 309 | masm.emitSet(JSOpToCondition(mir->compareType(), mir->jsop()), output); |
michael@0 | 310 | return true; |
michael@0 | 311 | } |
michael@0 | 312 | |
michael@0 | 313 | bool |
michael@0 | 314 | CodeGeneratorX64::visitCompareBAndBranch(LCompareBAndBranch *lir) |
michael@0 | 315 | { |
michael@0 | 316 | MCompare *mir = lir->cmpMir(); |
michael@0 | 317 | |
michael@0 | 318 | const ValueOperand lhs = ToValue(lir, LCompareBAndBranch::Lhs); |
michael@0 | 319 | const LAllocation *rhs = lir->rhs(); |
michael@0 | 320 | |
michael@0 | 321 | JS_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE); |
michael@0 | 322 | |
michael@0 | 323 | // Load boxed boolean in ScratchReg. |
michael@0 | 324 | if (rhs->isConstant()) |
michael@0 | 325 | masm.moveValue(*rhs->toConstant(), ScratchReg); |
michael@0 | 326 | else |
michael@0 | 327 | masm.boxValue(JSVAL_TYPE_BOOLEAN, ToRegister(rhs), ScratchReg); |
michael@0 | 328 | |
michael@0 | 329 | // Perform the comparison. |
michael@0 | 330 | masm.cmpq(lhs.valueReg(), ScratchReg); |
michael@0 | 331 | emitBranch(JSOpToCondition(mir->compareType(), mir->jsop()), lir->ifTrue(), lir->ifFalse()); |
michael@0 | 332 | return true; |
michael@0 | 333 | } |
michael@0 | 334 | bool |
michael@0 | 335 | CodeGeneratorX64::visitCompareV(LCompareV *lir) |
michael@0 | 336 | { |
michael@0 | 337 | MCompare *mir = lir->mir(); |
michael@0 | 338 | const ValueOperand lhs = ToValue(lir, LCompareV::LhsInput); |
michael@0 | 339 | const ValueOperand rhs = ToValue(lir, LCompareV::RhsInput); |
michael@0 | 340 | const Register output = ToRegister(lir->output()); |
michael@0 | 341 | |
michael@0 | 342 | JS_ASSERT(IsEqualityOp(mir->jsop())); |
michael@0 | 343 | |
michael@0 | 344 | masm.cmpq(lhs.valueReg(), rhs.valueReg()); |
michael@0 | 345 | masm.emitSet(JSOpToCondition(mir->compareType(), mir->jsop()), output); |
michael@0 | 346 | return true; |
michael@0 | 347 | } |
michael@0 | 348 | |
michael@0 | 349 | bool |
michael@0 | 350 | CodeGeneratorX64::visitCompareVAndBranch(LCompareVAndBranch *lir) |
michael@0 | 351 | { |
michael@0 | 352 | MCompare *mir = lir->cmpMir(); |
michael@0 | 353 | |
michael@0 | 354 | const ValueOperand lhs = ToValue(lir, LCompareVAndBranch::LhsInput); |
michael@0 | 355 | const ValueOperand rhs = ToValue(lir, LCompareVAndBranch::RhsInput); |
michael@0 | 356 | |
michael@0 | 357 | JS_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || |
michael@0 | 358 | mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE); |
michael@0 | 359 | |
michael@0 | 360 | masm.cmpq(lhs.valueReg(), rhs.valueReg()); |
michael@0 | 361 | emitBranch(JSOpToCondition(mir->compareType(), mir->jsop()), lir->ifTrue(), lir->ifFalse()); |
michael@0 | 362 | return true; |
michael@0 | 363 | } |
michael@0 | 364 | |
michael@0 | 365 | bool |
michael@0 | 366 | CodeGeneratorX64::visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble *lir) |
michael@0 | 367 | { |
michael@0 | 368 | masm.convertUInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output())); |
michael@0 | 369 | return true; |
michael@0 | 370 | } |
michael@0 | 371 | |
michael@0 | 372 | bool |
michael@0 | 373 | CodeGeneratorX64::visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32 *lir) |
michael@0 | 374 | { |
michael@0 | 375 | masm.convertUInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output())); |
michael@0 | 376 | return true; |
michael@0 | 377 | } |
michael@0 | 378 | |
michael@0 | 379 | bool |
michael@0 | 380 | CodeGeneratorX64::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins) |
michael@0 | 381 | { |
michael@0 | 382 | MOZ_ASSUME_UNREACHABLE("NYI"); |
michael@0 | 383 | } |
michael@0 | 384 | |
michael@0 | 385 | bool |
michael@0 | 386 | CodeGeneratorX64::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins) |
michael@0 | 387 | { |
michael@0 | 388 | MOZ_ASSUME_UNREACHABLE("NYI"); |
michael@0 | 389 | } |
michael@0 | 390 | |
michael@0 | 391 | bool |
michael@0 | 392 | CodeGeneratorX64::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins) |
michael@0 | 393 | { |
michael@0 | 394 | MAsmJSLoadHeap *mir = ins->mir(); |
michael@0 | 395 | ArrayBufferView::ViewType vt = mir->viewType(); |
michael@0 | 396 | const LAllocation *ptr = ins->ptr(); |
michael@0 | 397 | |
michael@0 | 398 | // No need to note the access if it will never fault. |
michael@0 | 399 | bool skipNote = mir->skipBoundsCheck(); |
michael@0 | 400 | Operand srcAddr(HeapReg); |
michael@0 | 401 | |
michael@0 | 402 | if (ptr->isConstant()) { |
michael@0 | 403 | int32_t ptrImm = ptr->toConstant()->toInt32(); |
michael@0 | 404 | // Note only a positive index is accepted here because a negative offset would |
michael@0 | 405 | // not wrap back into the protected area reserved for the heap. |
michael@0 | 406 | JS_ASSERT(ptrImm >= 0); |
michael@0 | 407 | srcAddr = Operand(HeapReg, ptrImm); |
michael@0 | 408 | } else { |
michael@0 | 409 | srcAddr = Operand(HeapReg, ToRegister(ptr), TimesOne); |
michael@0 | 410 | } |
michael@0 | 411 | |
michael@0 | 412 | uint32_t before = masm.size(); |
michael@0 | 413 | switch (vt) { |
michael@0 | 414 | case ArrayBufferView::TYPE_INT8: masm.movsbl(srcAddr, ToRegister(ins->output())); break; |
michael@0 | 415 | case ArrayBufferView::TYPE_UINT8: masm.movzbl(srcAddr, ToRegister(ins->output())); break; |
michael@0 | 416 | case ArrayBufferView::TYPE_INT16: masm.movswl(srcAddr, ToRegister(ins->output())); break; |
michael@0 | 417 | case ArrayBufferView::TYPE_UINT16: masm.movzwl(srcAddr, ToRegister(ins->output())); break; |
michael@0 | 418 | case ArrayBufferView::TYPE_INT32: |
michael@0 | 419 | case ArrayBufferView::TYPE_UINT32: masm.movl(srcAddr, ToRegister(ins->output())); break; |
michael@0 | 420 | case ArrayBufferView::TYPE_FLOAT32: masm.loadFloat32(srcAddr, ToFloatRegister(ins->output())); break; |
michael@0 | 421 | case ArrayBufferView::TYPE_FLOAT64: masm.loadDouble(srcAddr, ToFloatRegister(ins->output())); break; |
michael@0 | 422 | default: MOZ_ASSUME_UNREACHABLE("unexpected array type"); |
michael@0 | 423 | } |
michael@0 | 424 | uint32_t after = masm.size(); |
michael@0 | 425 | return skipNote || masm.append(AsmJSHeapAccess(before, after, vt, ToAnyRegister(ins->output()))); |
michael@0 | 426 | } |
michael@0 | 427 | |
michael@0 | 428 | bool |
michael@0 | 429 | CodeGeneratorX64::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins) |
michael@0 | 430 | { |
michael@0 | 431 | MAsmJSStoreHeap *mir = ins->mir(); |
michael@0 | 432 | ArrayBufferView::ViewType vt = mir->viewType(); |
michael@0 | 433 | const LAllocation *ptr = ins->ptr(); |
michael@0 | 434 | // No need to note the access if it will never fault. |
michael@0 | 435 | bool skipNote = mir->skipBoundsCheck(); |
michael@0 | 436 | Operand dstAddr(HeapReg); |
michael@0 | 437 | |
michael@0 | 438 | if (ptr->isConstant()) { |
michael@0 | 439 | int32_t ptrImm = ptr->toConstant()->toInt32(); |
michael@0 | 440 | // Note only a positive index is accepted here because a negative offset would |
michael@0 | 441 | // not wrap back into the protected area reserved for the heap. |
michael@0 | 442 | JS_ASSERT(ptrImm >= 0); |
michael@0 | 443 | dstAddr = Operand(HeapReg, ptrImm); |
michael@0 | 444 | } else { |
michael@0 | 445 | dstAddr = Operand(HeapReg, ToRegister(ins->ptr()), TimesOne); |
michael@0 | 446 | } |
michael@0 | 447 | |
michael@0 | 448 | uint32_t before = masm.size(); |
michael@0 | 449 | if (ins->value()->isConstant()) { |
michael@0 | 450 | switch (vt) { |
michael@0 | 451 | case ArrayBufferView::TYPE_INT8: |
michael@0 | 452 | case ArrayBufferView::TYPE_UINT8: masm.movb(Imm32(ToInt32(ins->value())), dstAddr); break; |
michael@0 | 453 | case ArrayBufferView::TYPE_INT16: |
michael@0 | 454 | case ArrayBufferView::TYPE_UINT16: masm.movw(Imm32(ToInt32(ins->value())), dstAddr); break; |
michael@0 | 455 | case ArrayBufferView::TYPE_INT32: |
michael@0 | 456 | case ArrayBufferView::TYPE_UINT32: masm.movl(Imm32(ToInt32(ins->value())), dstAddr); break; |
michael@0 | 457 | default: MOZ_ASSUME_UNREACHABLE("unexpected array type"); |
michael@0 | 458 | } |
michael@0 | 459 | } else { |
michael@0 | 460 | switch (vt) { |
michael@0 | 461 | case ArrayBufferView::TYPE_INT8: |
michael@0 | 462 | case ArrayBufferView::TYPE_UINT8: masm.movb(ToRegister(ins->value()), dstAddr); break; |
michael@0 | 463 | case ArrayBufferView::TYPE_INT16: |
michael@0 | 464 | case ArrayBufferView::TYPE_UINT16: masm.movw(ToRegister(ins->value()), dstAddr); break; |
michael@0 | 465 | case ArrayBufferView::TYPE_INT32: |
michael@0 | 466 | case ArrayBufferView::TYPE_UINT32: masm.movl(ToRegister(ins->value()), dstAddr); break; |
michael@0 | 467 | case ArrayBufferView::TYPE_FLOAT32: masm.storeFloat32(ToFloatRegister(ins->value()), dstAddr); break; |
michael@0 | 468 | case ArrayBufferView::TYPE_FLOAT64: masm.storeDouble(ToFloatRegister(ins->value()), dstAddr); break; |
michael@0 | 469 | default: MOZ_ASSUME_UNREACHABLE("unexpected array type"); |
michael@0 | 470 | } |
michael@0 | 471 | } |
michael@0 | 472 | uint32_t after = masm.size(); |
michael@0 | 473 | return skipNote || masm.append(AsmJSHeapAccess(before, after)); |
michael@0 | 474 | } |
michael@0 | 475 | |
michael@0 | 476 | bool |
michael@0 | 477 | CodeGeneratorX64::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins) |
michael@0 | 478 | { |
michael@0 | 479 | MAsmJSLoadGlobalVar *mir = ins->mir(); |
michael@0 | 480 | |
michael@0 | 481 | CodeOffsetLabel label; |
michael@0 | 482 | if (mir->type() == MIRType_Int32) |
michael@0 | 483 | label = masm.loadRipRelativeInt32(ToRegister(ins->output())); |
michael@0 | 484 | else |
michael@0 | 485 | label = masm.loadRipRelativeDouble(ToFloatRegister(ins->output())); |
michael@0 | 486 | |
michael@0 | 487 | return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset())); |
michael@0 | 488 | } |
michael@0 | 489 | |
michael@0 | 490 | bool |
michael@0 | 491 | CodeGeneratorX64::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins) |
michael@0 | 492 | { |
michael@0 | 493 | MAsmJSStoreGlobalVar *mir = ins->mir(); |
michael@0 | 494 | |
michael@0 | 495 | MIRType type = mir->value()->type(); |
michael@0 | 496 | JS_ASSERT(IsNumberType(type)); |
michael@0 | 497 | |
michael@0 | 498 | CodeOffsetLabel label; |
michael@0 | 499 | if (type == MIRType_Int32) |
michael@0 | 500 | label = masm.storeRipRelativeInt32(ToRegister(ins->value())); |
michael@0 | 501 | else |
michael@0 | 502 | label = masm.storeRipRelativeDouble(ToFloatRegister(ins->value())); |
michael@0 | 503 | |
michael@0 | 504 | return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset())); |
michael@0 | 505 | } |
michael@0 | 506 | |
michael@0 | 507 | bool |
michael@0 | 508 | CodeGeneratorX64::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr *ins) |
michael@0 | 509 | { |
michael@0 | 510 | MAsmJSLoadFuncPtr *mir = ins->mir(); |
michael@0 | 511 | |
michael@0 | 512 | Register index = ToRegister(ins->index()); |
michael@0 | 513 | Register tmp = ToRegister(ins->temp()); |
michael@0 | 514 | Register out = ToRegister(ins->output()); |
michael@0 | 515 | |
michael@0 | 516 | CodeOffsetLabel label = masm.leaRipRelative(tmp); |
michael@0 | 517 | masm.loadPtr(Operand(tmp, index, TimesEight, 0), out); |
michael@0 | 518 | |
michael@0 | 519 | return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset())); |
michael@0 | 520 | } |
michael@0 | 521 | |
michael@0 | 522 | bool |
michael@0 | 523 | CodeGeneratorX64::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc *ins) |
michael@0 | 524 | { |
michael@0 | 525 | MAsmJSLoadFFIFunc *mir = ins->mir(); |
michael@0 | 526 | |
michael@0 | 527 | CodeOffsetLabel label = masm.loadRipRelativeInt64(ToRegister(ins->output())); |
michael@0 | 528 | |
michael@0 | 529 | return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset())); |
michael@0 | 530 | } |
michael@0 | 531 | |
michael@0 | 532 | void |
michael@0 | 533 | DispatchIonCache::initializeAddCacheState(LInstruction *ins, AddCacheState *addState) |
michael@0 | 534 | { |
michael@0 | 535 | // Can always use the scratch register on x64. |
michael@0 | 536 | addState->dispatchScratch = ScratchReg; |
michael@0 | 537 | } |
michael@0 | 538 | |
michael@0 | 539 | bool |
michael@0 | 540 | CodeGeneratorX64::visitTruncateDToInt32(LTruncateDToInt32 *ins) |
michael@0 | 541 | { |
michael@0 | 542 | FloatRegister input = ToFloatRegister(ins->input()); |
michael@0 | 543 | Register output = ToRegister(ins->output()); |
michael@0 | 544 | |
michael@0 | 545 | // On x64, branchTruncateDouble uses cvttsd2sq. Unlike the x86 |
michael@0 | 546 | // implementation, this should handle most doubles and we can just |
michael@0 | 547 | // call a stub if it fails. |
michael@0 | 548 | return emitTruncateDouble(input, output); |
michael@0 | 549 | } |
michael@0 | 550 | |
michael@0 | 551 | bool |
michael@0 | 552 | CodeGeneratorX64::visitTruncateFToInt32(LTruncateFToInt32 *ins) |
michael@0 | 553 | { |
michael@0 | 554 | FloatRegister input = ToFloatRegister(ins->input()); |
michael@0 | 555 | Register output = ToRegister(ins->output()); |
michael@0 | 556 | |
michael@0 | 557 | // On x64, branchTruncateFloat32 uses cvttss2sq. Unlike the x86 |
michael@0 | 558 | // implementation, this should handle most floats and we can just |
michael@0 | 559 | // call a stub if it fails. |
michael@0 | 560 | return emitTruncateFloat32(input, output); |
michael@0 | 561 | } |