mirror of
https://github.com/UOX3DevTeam/UOX3
synced 2026-08-13 12:27:04 -04:00
546 lines
20 KiB
C++
546 lines
20 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: set ts=4 sw=4 et tw=99:
|
|
*
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
|
* May 28, 2008.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Brendan Eich <brendan@mozilla.org>
|
|
*
|
|
* Contributor(s):
|
|
* David Anderson <danderson@mozilla.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#ifndef js_typedarray_ic_h___
|
|
#define js_typedarray_ic_h___
|
|
|
|
#include "jscntxt.h"
|
|
#include "jstypedarray.h"
|
|
|
|
namespace js {
|
|
namespace mjit {
|
|
|
|
#if defined(JS_POLYIC) && (defined JS_CPU_X86 || defined JS_CPU_X64)
|
|
|
|
typedef JSC::MacroAssembler::RegisterID RegisterID;
|
|
typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
|
|
typedef JSC::MacroAssembler::Jump Jump;
|
|
typedef JSC::MacroAssembler::Imm32 Imm32;
|
|
typedef JSC::MacroAssembler::ImmDouble ImmDouble;
|
|
|
|
template <typename T>
|
|
static void
|
|
LoadFromTypedArray(Assembler &masm, js::TypedArray *tarray, T address,
|
|
RegisterID typeReg, RegisterID dataReg)
|
|
{
|
|
switch (tarray->type) {
|
|
case js::TypedArray::TYPE_INT8:
|
|
masm.load8SignExtend(address, dataReg);
|
|
masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
|
|
break;
|
|
case js::TypedArray::TYPE_UINT8:
|
|
case js::TypedArray::TYPE_UINT8_CLAMPED:
|
|
masm.load8ZeroExtend(address, dataReg);
|
|
masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
|
|
break;
|
|
case js::TypedArray::TYPE_INT16:
|
|
masm.load16SignExtend(address, dataReg);
|
|
masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
|
|
break;
|
|
case js::TypedArray::TYPE_UINT16:
|
|
masm.load16(address, dataReg);
|
|
masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
|
|
break;
|
|
case js::TypedArray::TYPE_INT32:
|
|
masm.load32(address, dataReg);
|
|
masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
|
|
break;
|
|
case js::TypedArray::TYPE_UINT32:
|
|
{
|
|
masm.load32(address, dataReg);
|
|
masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
|
|
Jump safeInt = masm.branch32(Assembler::Below, dataReg, Imm32(0x80000000));
|
|
masm.convertUInt32ToDouble(dataReg, FPRegisters::First);
|
|
masm.breakDouble(FPRegisters::First, typeReg, dataReg);
|
|
safeInt.linkTo(masm.label(), &masm);
|
|
break;
|
|
}
|
|
case js::TypedArray::TYPE_FLOAT32:
|
|
case js::TypedArray::TYPE_FLOAT64:
|
|
{
|
|
if (tarray->type == js::TypedArray::TYPE_FLOAT32)
|
|
masm.loadFloat(address, FPRegisters::First);
|
|
else
|
|
masm.loadDouble(address, FPRegisters::First);
|
|
// Make sure NaN gets canonicalized.
|
|
Jump notNaN = masm.branchDouble(Assembler::DoubleEqual,
|
|
FPRegisters::First,
|
|
FPRegisters::First);
|
|
masm.loadStaticDouble(&js_NaN, FPRegisters::First, dataReg);
|
|
notNaN.linkTo(masm.label(), &masm);
|
|
masm.breakDouble(FPRegisters::First, typeReg, dataReg);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline bool
|
|
ConstantFoldForFloatArray(JSContext *cx, ValueRemat *vr)
|
|
{
|
|
if (!vr->isTypeKnown())
|
|
return true;
|
|
|
|
// Objects and undefined coerce to NaN, which coerces to 0.
|
|
// Null converts to 0.
|
|
if (vr->knownType() == JSVAL_TYPE_OBJECT ||
|
|
vr->knownType() == JSVAL_TYPE_UNDEFINED) {
|
|
*vr = ValueRemat::FromConstant(DoubleValue(js_NaN));
|
|
return true;
|
|
}
|
|
if (vr->knownType() == JSVAL_TYPE_NULL) {
|
|
*vr = ValueRemat::FromConstant(DoubleValue(0));
|
|
return true;
|
|
}
|
|
|
|
if (!vr->isConstant())
|
|
return true;
|
|
|
|
if (vr->knownType() == JSVAL_TYPE_DOUBLE)
|
|
return true;
|
|
|
|
jsdouble d = 0;
|
|
Value v = vr->value();
|
|
if (v.isString()) {
|
|
if (!StringToNumberType<jsdouble>(cx, v.toString(), &d))
|
|
return false;
|
|
} else if (v.isBoolean()) {
|
|
d = v.toBoolean() ? 1 : 0;
|
|
} else if (v.isInt32()) {
|
|
d = v.toInt32();
|
|
} else {
|
|
JS_NOT_REACHED("unknown constant type");
|
|
}
|
|
*vr = ValueRemat::FromConstant(DoubleValue(d));
|
|
return true;
|
|
}
|
|
|
|
static inline int32
|
|
ClampIntForUint8Array(int32 x)
|
|
{
|
|
if (x < 0)
|
|
return 0;
|
|
if (x > 255)
|
|
return 255;
|
|
return x;
|
|
}
|
|
|
|
static inline bool
|
|
ConstantFoldForIntArray(JSContext *cx, js::TypedArray *tarray, ValueRemat *vr)
|
|
{
|
|
if (!vr->isTypeKnown())
|
|
return true;
|
|
|
|
// Objects and undefined coerce to NaN, which coerces to 0.
|
|
// Null converts to 0.
|
|
if (vr->knownType() == JSVAL_TYPE_OBJECT ||
|
|
vr->knownType() == JSVAL_TYPE_UNDEFINED ||
|
|
vr->knownType() == JSVAL_TYPE_NULL) {
|
|
*vr = ValueRemat::FromConstant(Int32Value(0));
|
|
return true;
|
|
}
|
|
|
|
if (!vr->isConstant())
|
|
return true;
|
|
|
|
// Convert from string to double first (see bug 624483).
|
|
Value v = vr->value();
|
|
if (v.isString()) {
|
|
double d;
|
|
if (!StringToNumberType<double>(cx, v.toString(), &d))
|
|
return false;
|
|
v.setNumber(d);
|
|
}
|
|
|
|
int32 i32 = 0;
|
|
if (v.isDouble()) {
|
|
i32 = (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED)
|
|
? js_TypedArray_uint8_clamp_double(v.toDouble())
|
|
: js_DoubleToECMAInt32(v.toDouble());
|
|
} else if (v.isInt32()) {
|
|
i32 = v.toInt32();
|
|
if (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED)
|
|
i32 = ClampIntForUint8Array(i32);
|
|
} else if (v.isBoolean()) {
|
|
i32 = v.toBoolean() ? 1 : 0;
|
|
} else {
|
|
JS_NOT_REACHED("unknown constant type");
|
|
}
|
|
|
|
*vr = ValueRemat::FromConstant(Int32Value(i32));
|
|
|
|
return true;
|
|
}
|
|
|
|
template <typename S, typename T>
|
|
static void
|
|
StoreToIntArray(Assembler &masm, js::TypedArray *tarray, S src, T address)
|
|
{
|
|
switch (tarray->type) {
|
|
case js::TypedArray::TYPE_INT8:
|
|
case js::TypedArray::TYPE_UINT8:
|
|
case js::TypedArray::TYPE_UINT8_CLAMPED:
|
|
masm.store8(src, address);
|
|
break;
|
|
case js::TypedArray::TYPE_INT16:
|
|
case js::TypedArray::TYPE_UINT16:
|
|
masm.store16(src, address);
|
|
break;
|
|
case js::TypedArray::TYPE_INT32:
|
|
case js::TypedArray::TYPE_UINT32:
|
|
masm.store32(src, address);
|
|
break;
|
|
default:
|
|
JS_NOT_REACHED("unknown int array type");
|
|
}
|
|
}
|
|
|
|
template <typename S, typename T>
|
|
static void
|
|
StoreToFloatArray(Assembler &masm, js::TypedArray *tarray, S src, T address)
|
|
{
|
|
if (tarray->type == js::TypedArray::TYPE_FLOAT32)
|
|
masm.storeFloat(src, address);
|
|
else
|
|
masm.storeDouble(src, address);
|
|
}
|
|
|
|
// Generate code that will ensure a dynamically typed value, pinned in |vr|,
|
|
// can be stored in an integer typed array. If any sort of conversion is
|
|
// required, |dataReg| will be clobbered by a new value. |saveMask| is
|
|
// used to ensure that |dataReg| (and volatile registers) are preserved
|
|
// across any conversion process.
|
|
static void
|
|
GenConversionForIntArray(Assembler &masm, js::TypedArray *tarray, const ValueRemat &vr,
|
|
uint32 saveMask)
|
|
{
|
|
if (vr.isConstant()) {
|
|
// Constants are always folded to ints up-front.
|
|
JS_ASSERT(vr.knownType() == JSVAL_TYPE_INT32);
|
|
return;
|
|
}
|
|
|
|
if (!vr.isTypeKnown() || vr.knownType() != JSVAL_TYPE_INT32) {
|
|
// If a conversion is necessary, save registers now.
|
|
MaybeJump checkInt32;
|
|
if (!vr.isTypeKnown())
|
|
checkInt32 = masm.testInt32(Assembler::Equal, vr.typeReg());
|
|
|
|
// Store the value to convert.
|
|
StackMarker vp = masm.allocStack(sizeof(Value), sizeof(double));
|
|
masm.storeValue(vr, masm.addressOfExtra(vp));
|
|
|
|
// Preserve volatile registers.
|
|
PreserveRegisters saveForCall(masm);
|
|
saveForCall.preserve(saveMask & Registers::TempRegs);
|
|
|
|
masm.setupABICall(Registers::FastCall, 2);
|
|
masm.storeArg(0, masm.vmFrameOffset(offsetof(VMFrame, cx)));
|
|
masm.storeArgAddr(1, masm.addressOfExtra(vp));
|
|
|
|
typedef int32 (JS_FASTCALL *Int32CxVp)(JSContext *, Value *);
|
|
Int32CxVp stub;
|
|
if (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED)
|
|
stub = stubs::ConvertToTypedInt<true>;
|
|
else
|
|
stub = stubs::ConvertToTypedInt<false>;
|
|
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, stub), false);
|
|
if (vr.dataReg() != Registers::ReturnReg)
|
|
masm.move(Registers::ReturnReg, vr.dataReg());
|
|
|
|
saveForCall.restore();
|
|
masm.freeStack(vp);
|
|
|
|
if (checkInt32.isSet())
|
|
checkInt32.get().linkTo(masm.label(), &masm);
|
|
}
|
|
|
|
// Performing clamping, if needed.
|
|
if (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED) {
|
|
// cmp dr, 0
|
|
// jge _min
|
|
// mov dr, 0
|
|
// jump _done
|
|
// _min:
|
|
// cmp dr, 255
|
|
// jle _done
|
|
// mov dr, 255
|
|
// _done:
|
|
//
|
|
Jump j = masm.branch32(Assembler::GreaterThanOrEqual, vr.dataReg(), Imm32(0));
|
|
masm.move(Imm32(0), vr.dataReg());
|
|
Jump done = masm.jump();
|
|
j.linkTo(masm.label(), &masm);
|
|
j = masm.branch32(Assembler::LessThanOrEqual, vr.dataReg(), Imm32(255));
|
|
masm.move(Imm32(255), vr.dataReg());
|
|
j.linkTo(masm.label(), &masm);
|
|
done.linkTo(masm.label(), &masm);
|
|
}
|
|
}
|
|
|
|
// Generate code that will ensure a dynamically typed value, pinned in |vr|,
|
|
// can be stored in an integer typed array. saveMask| is used to ensure that
|
|
// |dataReg| (and volatile registers) are preserved across any conversion
|
|
// process.
|
|
//
|
|
// Constants are left untouched. Any other value is placed into
|
|
// FPRegisters::First.
|
|
static void
|
|
GenConversionForFloatArray(Assembler &masm, js::TypedArray *tarray, const ValueRemat &vr,
|
|
FPRegisterID destReg, uint32 saveMask)
|
|
{
|
|
if (vr.isConstant()) {
|
|
// Constants are always folded to doubles up-front.
|
|
JS_ASSERT(vr.knownType() == JSVAL_TYPE_DOUBLE);
|
|
return;
|
|
}
|
|
|
|
// Fast-path, if the value is a double, skip converting.
|
|
MaybeJump isDouble;
|
|
if (!vr.isTypeKnown())
|
|
isDouble = masm.testDouble(Assembler::Equal, vr.typeReg());
|
|
|
|
// If the value is an integer, inline the conversion.
|
|
MaybeJump skip1, skip2;
|
|
if (!vr.isTypeKnown() || vr.knownType() == JSVAL_TYPE_INT32) {
|
|
MaybeJump isNotInt32;
|
|
if (!vr.isTypeKnown())
|
|
isNotInt32 = masm.testInt32(Assembler::NotEqual, vr.typeReg());
|
|
masm.convertInt32ToDouble(vr.dataReg(), destReg);
|
|
if (isNotInt32.isSet()) {
|
|
skip1 = masm.jump();
|
|
isNotInt32.get().linkTo(masm.label(), &masm);
|
|
}
|
|
}
|
|
|
|
// Generate a generic conversion call, if not known to be int32 or double.
|
|
if (!vr.isTypeKnown() ||
|
|
(vr.knownType() != JSVAL_TYPE_INT32 &&
|
|
vr.knownType() != JSVAL_TYPE_DOUBLE)) {
|
|
// Store this value, which is also an outparam.
|
|
StackMarker vp = masm.allocStack(sizeof(Value), sizeof(double));
|
|
masm.storeValue(vr, masm.addressOfExtra(vp));
|
|
|
|
// Preserve volatile registers, and make the call.
|
|
PreserveRegisters saveForCall(masm);
|
|
saveForCall.preserve(saveMask & Registers::TempRegs);
|
|
masm.setupABICall(Registers::FastCall, 2);
|
|
masm.storeArg(0, masm.vmFrameOffset(offsetof(VMFrame, cx)));
|
|
masm.storeArgAddr(1, masm.addressOfExtra(vp));
|
|
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, stubs::ConvertToTypedFloat), false);
|
|
saveForCall.restore();
|
|
|
|
// Load the value from the outparam, then pop the stack.
|
|
masm.loadDouble(masm.addressOfExtra(vp), destReg);
|
|
masm.freeStack(vp);
|
|
skip2 = masm.jump();
|
|
}
|
|
|
|
if (isDouble.isSet())
|
|
isDouble.get().linkTo(masm.label(), &masm);
|
|
|
|
// If it's possible the value was already a double, load it directly
|
|
// from registers (the known type is distinct from typeReg, which has
|
|
// 32-bits of the 64-bit double).
|
|
if (!vr.isTypeKnown() || vr.knownType() == JSVAL_TYPE_DOUBLE)
|
|
masm.fastLoadDouble(vr.dataReg(), vr.typeReg(), destReg);
|
|
|
|
// At this point, all loads into xmm1 are complete.
|
|
if (skip1.isSet())
|
|
skip1.get().linkTo(masm.label(), &masm);
|
|
if (skip2.isSet())
|
|
skip2.get().linkTo(masm.label(), &masm);
|
|
|
|
if (tarray->type == js::TypedArray::TYPE_FLOAT32)
|
|
masm.convertDoubleToFloat(destReg, destReg);
|
|
}
|
|
|
|
template <typename T>
|
|
static bool
|
|
StoreToTypedArray(JSContext *cx, Assembler &masm, js::TypedArray *tarray, T address,
|
|
const ValueRemat &vrIn, uint32 saveMask)
|
|
{
|
|
ValueRemat vr = vrIn;
|
|
|
|
switch (tarray->type) {
|
|
case js::TypedArray::TYPE_INT8:
|
|
case js::TypedArray::TYPE_UINT8:
|
|
case js::TypedArray::TYPE_UINT8_CLAMPED:
|
|
case js::TypedArray::TYPE_INT16:
|
|
case js::TypedArray::TYPE_UINT16:
|
|
case js::TypedArray::TYPE_INT32:
|
|
case js::TypedArray::TYPE_UINT32:
|
|
{
|
|
if (!ConstantFoldForIntArray(cx, tarray, &vr))
|
|
return false;
|
|
|
|
PreserveRegisters saveRHS(masm);
|
|
PreserveRegisters saveLHS(masm);
|
|
|
|
// There are three tricky situations to handle:
|
|
// (1) The RHS needs conversion. saveMask will be stomped, and
|
|
// the RHS may need to be stomped.
|
|
// (2) The RHS may need to be clamped, which clobbers it.
|
|
// (3) The RHS may need to be in a single-byte register.
|
|
//
|
|
// In all of these cases, we try to find a free register that can be
|
|
// used to mutate the RHS. Failing that, we evict an existing volatile
|
|
// register.
|
|
//
|
|
// Note that we are careful to preserve the RHS before saving registers
|
|
// for the conversion call. This is because the object and key may be
|
|
// in temporary registers, and we want to restore those without killing
|
|
// the mutated RHS.
|
|
bool singleByte = (tarray->type == js::TypedArray::TYPE_INT8 ||
|
|
tarray->type == js::TypedArray::TYPE_UINT8 ||
|
|
tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED);
|
|
bool mayNeedConversion = (!vr.isTypeKnown() || vr.knownType() != JSVAL_TYPE_INT32);
|
|
bool mayNeedClamping = !vr.isConstant() && (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED);
|
|
bool needsSingleByteReg = singleByte &&
|
|
!vr.isConstant() &&
|
|
!(Registers::SingleByteRegs & Registers::maskReg(vr.dataReg()));
|
|
bool rhsIsMutable = !vr.isConstant() && !(saveMask & Registers::maskReg(vr.dataReg()));
|
|
|
|
if (((mayNeedConversion || mayNeedClamping) && !rhsIsMutable) || needsSingleByteReg) {
|
|
// First attempt to find a free temporary register that:
|
|
// - is compatible with the RHS constraints
|
|
// - won't clobber the key, object, or RHS type regs
|
|
// - is temporary, but
|
|
// - is not in saveMask, which contains live volatile registers.
|
|
uint32 allowMask = Registers::AvailRegs;
|
|
if (singleByte)
|
|
allowMask &= Registers::SingleByteRegs;
|
|
|
|
// Create a mask of registers we absolutely cannot clobber.
|
|
uint32 pinned = Assembler::maskAddress(address);
|
|
if (!vr.isTypeKnown())
|
|
pinned |= Registers::maskReg(vr.typeReg());
|
|
|
|
Registers avail = allowMask & ~(pinned | saveMask);
|
|
|
|
RegisterID newReg;
|
|
if (!avail.empty()) {
|
|
newReg = avail.takeAnyReg();
|
|
} else {
|
|
// If no registers meet the ideal set, relax a constraint and spill.
|
|
avail = allowMask & ~pinned;
|
|
|
|
if (!avail.empty()) {
|
|
newReg = avail.takeAnyReg();
|
|
saveRHS.preserve(Registers::maskReg(newReg));
|
|
} else {
|
|
// Oh no! *All* single byte registers are pinned. This
|
|
// sucks. We'll swap the type and data registers in |vr|
|
|
// and unswap them later.
|
|
|
|
// If |vr|'s registers are part of the address, swapping is
|
|
// going to cause problems during the store.
|
|
uint32 vrRegs = Registers::mask2Regs(vr.dataReg(), vr.typeReg());
|
|
uint32 lhsMask = vrRegs & Assembler::maskAddress(address);
|
|
|
|
// We'll also need to save any of the registers which won't
|
|
// be restored via |lhsMask| above.
|
|
uint32 rhsMask = vrRegs & ~lhsMask;
|
|
|
|
// Push them, but get the order right. We'll pop LHS first.
|
|
saveRHS.preserve(rhsMask);
|
|
saveLHS.preserve(lhsMask);
|
|
|
|
// Don't store/restore registers if we dont have to.
|
|
saveMask &= ~lhsMask;
|
|
|
|
// Actually perform the swap.
|
|
masm.swap(vr.typeReg(), vr.dataReg());
|
|
vr = ValueRemat::FromRegisters(vr.dataReg(), vr.typeReg());
|
|
newReg = vr.dataReg();
|
|
}
|
|
|
|
// Now, make sure the new register is not in the saveMask,
|
|
// so it won't get restored right after the call.
|
|
saveMask &= ~Registers::maskReg(newReg);
|
|
}
|
|
|
|
if (vr.dataReg() != newReg)
|
|
masm.move(vr.dataReg(), newReg);
|
|
|
|
// Update |vr|.
|
|
if (vr.isTypeKnown())
|
|
vr = ValueRemat::FromKnownType(vr.knownType(), newReg);
|
|
else
|
|
vr = ValueRemat::FromRegisters(vr.typeReg(), newReg);
|
|
}
|
|
|
|
GenConversionForIntArray(masm, tarray, vr, saveMask);
|
|
|
|
// Restore the registers in |address|. |GenConversionForIntArray| won't
|
|
// restore them because we told it not to by fiddling with |saveMask|.
|
|
saveLHS.restore();
|
|
|
|
if (vr.isConstant())
|
|
StoreToIntArray(masm, tarray, Imm32(vr.value().toInt32()), address);
|
|
else
|
|
StoreToIntArray(masm, tarray, vr.dataReg(), address);
|
|
|
|
// Note that this will finish restoring the damage from the
|
|
// earlier register swap.
|
|
saveRHS.restore();
|
|
break;
|
|
}
|
|
|
|
case js::TypedArray::TYPE_FLOAT32:
|
|
case js::TypedArray::TYPE_FLOAT64:
|
|
if (!ConstantFoldForFloatArray(cx, &vr))
|
|
return false;
|
|
GenConversionForFloatArray(masm, tarray, vr, FPRegisters::First, saveMask);
|
|
if (vr.isConstant())
|
|
StoreToFloatArray(masm, tarray, ImmDouble(vr.value().toDouble()), address);
|
|
else
|
|
StoreToFloatArray(masm, tarray, FPRegisters::First, address);
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif // defined(JS_POLYIC) && (defined JS_CPU_X86 || defined JS_CPU_X64)
|
|
|
|
} /* namespace mjit */
|
|
} /* namespace js */
|
|
|
|
#endif /* js_typedarray_ic_h___ */
|
|
|