import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1164391 - record an address within the instruction. r=luke (b55506f22)
- Bug 1172638 - guard a test case. r=bbouvier (7e372b400)
- Bug 1155176 - correct return types for atomics. r=luke (16ddf75f0)
- Bug 1172517 - track sharedness in global. r=luke (2b8a664e7)
- pointer style (9f9af957c)
- Bug 1142668: Fix int32x4 to float32x4 conversion in asm.js; r=luke (79867d66f)
- Bug 1155211 - SIMD: Rename lane mutators - with -> replaceLane. r=bbouvier (ea7f5e3f1)
- Bug 1181318 - Eliminate duplicate mRefCnt members in nsRunnable subclasses. r=ehsan (abb9c7d3d)
- Bug 1176406 - IonMonkey: Poor type refinement of element access results during inlininig (873686ca4)
- Bug 1157624: Odin: split parsing/validation from codegen; r=luke (bf20abaf8)
- Bug 1164042 - Log weak map entries in DumpHeapComplete. r=terrence (f9be8e243)
- Bug 1167795 - Share the root and child tracing code in DumpHeapComplete; r=mccr8 (0a946f546)
- Bug 1168103 - "Execution cannot reach the expression "?unknown?" inside this statement in jsfriendapi.cpp". r=evilpies (906b8e714)
- Bug 1168103 - Convert tabs to spaces. r=me (5cf8a2b07)
- Bug 1169692 - Use virtual dispatch in WeakMapTracer instead of function pointers; r=sfink, r=mccr8 (0ce57cae9)
- Bug 1135993 - Remove js::IsInNonStrictPropertySet. r=jorendorff (bf2bee8c7)
- Bug 1164815 - Use an enum to define GlobalObject slot constants r=luke (21e53a9bb)
- Bug 1124291 - added ToInt8 and ToInt16. r=Waldo (350f2ece9)
- Bug 1124291 - SIMD (interpreter): Implemented int8x16 and int16x8 on a CLOSED TREE. r=bbouvier (8055710fb)
- Bug 1165654 - Cleanup how libjpeg-turbo assembly build variables are set. r=mshal (e32f6db51)
- Bug 1155211: Part 3.0 - Implement SIMD[type].extractLane; p=flomerz;bbouvier; r=h4writer (ca61952ba)
- Bug 1127932 - IonMonkey: Inline SIMD.float32x4.add/sub/mul calls; r=bbouvier (0472a833c)
- Bug 1112158 - Optimize MSimdUnbox with GVN. r=bbouvier (b89048669)
- Bug 1136189 - SIMD: inline SIMD constructors with missing arguments. r=bbouvier (e5cdc380f)
- revert some PM changes for escaped expressions (b20b2a292)
- Bug 1147817 - Part 1: Add RegExpInitialize. r=till (b00f0a12b)
- revert some changes, update closer to gecko code (74b20a236)
- Bug 1147817 - Part 2: Use IsRegExp in RegExp constructor. r=till (ffb568ffb)
- Bug 1124456 - Check channel's contentPolicyType to see if it is XMLHttpRequest. r=vporof (b4e4d4aaf)
- Bug 1150697 - Add IP address to the Network Monitor domain tooltip. r=bgrins (ec37b3505)
- Bug 1150697 - Fix confusing messages in Network Monitor tests. r=bgrins (40987b29c)
- Bug 764958 - Show cached network requests in the net monitor. r=jsantell (1507a9c7e)
- add as of Get rid of JSOP_{GET,CALL}UPVAR and simplify code greatly (592202) (29e91f1bc)
- Bug 1155900 - Make destructuring right-hand-side expressions that correspond to left-hand-side object patterns pass the RequireObjectCoercible gauntlet before any properties are destructured out of them. r=shu (3a93c0aa6)
- Bug 1131043 - Part 2: Implement Map[@@species] and Set[@@species] getter. r=evilpie (07bd91ec1)
- Bug 1063946 SIMD: Group tests in logical units - typed objects; r=bbouvier (43f4b18ee)
- Bug 1063946 SIMD: Group tests in logical units - unary operations; r=bbouvier (b30903604)
- Bug 1063946 SIMD: Group tests in logical units - binary operations; r=bbouvier (469f31c8c)
- Bug 1124291 - SIMD (interpreter): Added test cases for int8x16 and inBug 1124291 - SIMD (interpreter): Added test cases for int8x16 and in (e2d35c44b)
- Bug 1156365 - IonMonkey MIPS: Fix build failure on MIPS; rename Registers::code() to Registers::Encoding(). r=rankov (7fc1252e9)
- pointer style (385d63410)
- Bug 1181151 - Fix Registers::GetName typedef issue with clang. r=rankov (fc11c5a13)
- Bug 1163168 - Prettify IonAssemblerBuffer.h. r=dougc (33f0e1430)
- Bug 1165793 - Add executableCopy() back for MIPS. r=sstangl (5b44df890)
- Bug 1139299 - Fix align stack in Simulator-mips::call. r=rankov, r=nbp (d4e45e869)
- Bug 1140821 - IonMonkey: MIPS: Fix profiler enter frame calculating. r=nbp (69c16c5d6)
- Bug 1144005 - IonMonkey: MIPS: Fix encode break instruction. r=rankov (02bb1a736)
- Bug 1147424 - IonMonkey MIPS: Fix build failures on MIPS caused by recent updates (MacroAssemblerMIPS::ma_b). r=rankov (757605049)
- Bug 1147908 - IonMonkey: MIPS: Fix UDiv and UMod for double and merge them. r=rankov (6de529261)
- adapted Bug 1136799 - SIMD (interpreter): Fix order of operations of ReciprocalSqrt. r=bbouvier, a=me (2290b4e19)
- Bug 1150836 - SIMD (interpreter): change order of operations of ReciprocalSqrtApproximation. r=bbouvier (35a3354b5)
- Bug 1153602 - SIMD (interpreter): Added more test cases for ReciprocalSqrtApproximation. r=Waldo (aaedd70d6)
- Bug 1148494: SimdUnbox shouldn't be removed; r=sunfish (c120c51a7)
- pointer style (5f3ce20ca)
- Bug 1061909: Add breakdown argument to Debugger.Memory.prototype.takeCensus, covering all existing count types. r=fitzgen (3503e969b)
- Bug 1061909: Add documentation for Debugger.Memory.prototype.takeCensus's 'breakdown' parameter. r=fitzgen (1cd40cc94)
- Bug 1061909: Define a testing function to introduce easily traceable objects. r=fitzgen (f6e09a60b)
- Bug 1061909: Arrange for trees of census counts to be traced by the GC. r=fitzgen (13c7fb169)
- Bug 1061909: Implement 'allocationStack' breakdown for Debugger.Memory.prototype.takeCensus. r=fitzgen (c7cb27fe6)
- Bug 1061909 followup: Add missing 'override' keyword to count() methods in DebuggerMemory.cpp. rs=ehsan (059b6b9eb)
- Bug 1060567: Debugger.Memory.prototype.takeCensus: provide byte counts on request. r=fitzgen (b6a0f1bef)
- Bug 1169639 - Make intrinsicsHolder-accesses fallible, now that it's possible to access it without having previously gone through intrinsics-object creation code to ensure its existence. r=shu (3fe01f933)
- Bug 1159469 - Add public jsapi ES6 Set convenience functions; r=jorendorff (ca74a2a09)
- Bug 1159469 - Add ForEach C++ public function for ES6 Maps/Sets; r=jorendorff (19f28135a)
- fix parenthesis and redundant new lines (63618bc8a)
- Bug 1151333: Reserve enough stack space for SIMD shuffles; r=sunfish (100f2fbc8)
- Bug 1159469 - Add public jsapi ES6 Map delete method; r=jorendorff (b1db40c51)
- Bug 1159469 - Make sure public jsapi Map/Set calls deal with compartments/proxies; r=bz r=jorendorff (69bf75c49)
- Bug 1159469 - Add get function to JSJitCallArguments; r=jorendorff (583cec75a)
- Bug 1173722: Part 1 - Capitalize all the SIMD types names; r=nbp (70c68229f)
This commit is contained in:
2020-11-16 21:05:21 +08:00
parent 2d158c2a36
commit bcff8a12b4
204 changed files with 12056 additions and 5054 deletions
+15 -42
View File
@@ -3845,11 +3845,6 @@ VPX_X86_ASM=
VPX_ARM_ASM=
LIBJPEG_TURBO_AS=
LIBJPEG_TURBO_ASFLAGS=
LIBJPEG_TURBO_X86_ASM=
LIBJPEG_TURBO_X64_ASM=
LIBJPEG_TURBO_ARM_ASM=
LIBJPEG_TURBO_ARM64_ASM=
LIBJPEG_TURBO_MIPS_ASM=
MOZ_PERMISSIONS=1
MOZ_PLACES=1
MOZ_SOCIAL=1
@@ -5856,55 +5851,47 @@ dnl files.
if test -n "$MOZ_LIBJPEG_TURBO"; then
dnl Do we support libjpeg-turbo on this platform?
case "$OS_ARCH:$OS_TEST" in
Darwin:i?86)
case "$OS_ARCH:$CPU_ARCH" in
Darwin:x86)
LIBJPEG_TURBO_ASFLAGS="-f macho32 -rnasm -pnasm -DPIC -DMACHO"
LIBJPEG_TURBO_X86_ASM=1
;;
Darwin:x86_64)
LIBJPEG_TURBO_ASFLAGS="-f macho64 -rnasm -pnasm -D__x86_64__ -DPIC -DMACHO"
LIBJPEG_TURBO_X64_ASM=1
;;
WINNT:x86|WINNT:i?86)
WINNT:x86)
LIBJPEG_TURBO_ASFLAGS="-f win32 -rnasm -pnasm -DPIC -DWIN32"
LIBJPEG_TURBO_X86_ASM=1
;;
WINNT:x86_64)
LIBJPEG_TURBO_ASFLAGS="-f win64 -rnasm -pnasm -D__x86_64__ -DPIC -DWIN64 -DMSVC"
LIBJPEG_TURBO_X64_ASM=1
;;
*:arm*)
*:arm)
LIBJPEG_TURBO_ASFLAGS="-march=armv7-a -mfpu=neon"
LIBJPEG_TURBO_ARM_ASM=1
;;
*:aarch64*)
*:aarch64)
LIBJPEG_TURBO_ASFLAGS="-march=armv8-a"
LIBJPEG_TURBO_ARM64_ASM=1
;;
*:mips*)
*:mips)
LIBJPEG_TURBO_ASFLAGS="-mdspr2"
LIBJPEG_TURBO_MIPS_ASM=1
;;
*:x86|*:i?86)
*:x86)
if $CC -E -dM -</dev/null | grep -q __ELF__; then
LIBJPEG_TURBO_ASFLAGS="-f elf32 -rnasm -pnasm -DPIC -DELF"
LIBJPEG_TURBO_X86_ASM=1
fi
;;
*:x86_64)
if $CC -E -dM -</dev/null | grep -q __ELF__; then
LIBJPEG_TURBO_ASFLAGS="-f elf64 -rnasm -pnasm -D__x86_64__ -DPIC -DELF"
LIBJPEG_TURBO_X64_ASM=1
fi
;;
esac
fi
if test -n "$LIBJPEG_TURBO_ASFLAGS"; then
case "$CPU_ARCH" in
dnl If we're on an x86 or x64 system which supports libjpeg-turbo's asm routines
dnl and --disable-libjpeg-turbo wasn't passed, check for Yasm, and error out if
dnl it doesn't exist or we have too old of a version.
if test -n "$LIBJPEG_TURBO_X86_ASM" -o -n "$LIBJPEG_TURBO_X64_ASM" ; then
x86_64|x86)
LIBJPEG_TURBO_AS=$YASM
if test -z "$LIBJPEG_TURBO_AS" ; then
@@ -5922,21 +5909,12 @@ if test -n "$LIBJPEG_TURBO_X86_ASM" -o -n "$LIBJPEG_TURBO_X64_ASM" ; then
AC_MSG_ERROR([Yasm 1.1 or greater is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you appear to have version $_YASM_MAJOR_VERSION.$_YASM_MINOR_VERSION. Upgrade to the newest version or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder. See https://developer.mozilla.org/en/YASM for more details.])
fi
fi
fi
dnl If we're on an ARM system which supports libjpeg-turbo's asm routines and
dnl --disable-libjpeg-turbo wasn't passed, use the C compiler as the assembler.
if test -n "$LIBJPEG_TURBO_ARM_ASM" ; then
echo "Using $AS as the assembler for ARM code."
;;
dnl On other platforms, use the C compiler as the assembler.
*)
LIBJPEG_TURBO_AS=$AS
fi
if test -n "$LIBJPEG_TURBO_X86_ASM"; then
AC_DEFINE(LIBJPEG_TURBO_X86_ASM)
elif test -n "$LIBJPEG_TURBO_X64_ASM"; then
AC_DEFINE(LIBJPEG_TURBO_X64_ASM)
elif test -n "$LIBJPEG_TURBO_ARM_ASM"; then
AC_DEFINE(LIBJPEG_TURBO_ARM_ASM)
;;
esac
elif test -n "$MOZ_LIBJPEG_TURBO"; then
dnl Warn if we're not building the optimized routines, even though the user
dnl didn't specify --disable-libjpeg-turbo.
@@ -8543,11 +8521,6 @@ AC_SUBST(MOZ_INSTRUMENT_EVENT_LOOP)
AC_SUBST(MOZ_CODE_COVERAGE)
AC_SUBST(LIBJPEG_TURBO_AS)
AC_SUBST_LIST(LIBJPEG_TURBO_ASFLAGS)
AC_SUBST(LIBJPEG_TURBO_X86_ASM)
AC_SUBST(LIBJPEG_TURBO_X64_ASM)
AC_SUBST(LIBJPEG_TURBO_ARM_ASM)
AC_SUBST(LIBJPEG_TURBO_ARM64_ASM)
AC_SUBST(LIBJPEG_TURBO_MIPS_ASM)
AC_SUBST(MOZ_PACKAGE_JSSHELL)
AC_SUBST(MOZ_FOLD_LIBS)
+7 -11
View File
@@ -10393,15 +10393,13 @@ class CGDOMJSProxyHandler_defineProperty(ClassMethod):
# indexed setter. That's how the object would normally behave if
# you tried to set the property on it. That means we don't need to
# do anything special for Xrays here.
set += fill(
set += dedent(
"""
if (IsArrayIndex(GetArrayIndexFromId(cx, id))) {
return js::IsInNonStrictPropertySet(cx)
? opresult.succeed()
: ThrowErrorMessage(cx, MSG_NO_INDEXED_SETTER, "${name}");
*defined = true;
return opresult.failNoIndexedSetter();
}
""",
name=self.descriptor.name)
""")
namedSetter = self.descriptor.operations['NamedSetter']
if namedSetter:
@@ -10434,13 +10432,11 @@ class CGDOMJSProxyHandler_defineProperty(ClassMethod):
$*{presenceChecker}
if (found) {
return js::IsInNonStrictPropertySet(cx)
? opresult.succeed()
: ThrowErrorMessage(cx, MSG_NO_NAMED_SETTER, "${name}");
*defined = true;
return opresult.failNoNamedSetter();
}
""",
presenceChecker=CGProxyNamedPresenceChecker(self.descriptor, foundVar="found").define(),
name=self.descriptor.name)
presenceChecker=CGProxyNamedPresenceChecker(self.descriptor, foundVar="found").define())
set += ("return mozilla::dom::DOMProxyHandler::defineProperty(%s);\n" %
", ".join(a.name for a in self.args))
return set
-2
View File
@@ -34,8 +34,6 @@ MSG_DEF(MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 1, JSEXN_TYPEERR, "\"this\" objec
MSG_DEF(MSG_NOT_IN_UNION, 2, JSEXN_TYPEERR, "{0} could not be converted to any of: {1}.")
MSG_DEF(MSG_ILLEGAL_CONSTRUCTOR, 0, JSEXN_TYPEERR, "Illegal constructor.")
MSG_DEF(MSG_CONSTRUCTOR_WITHOUT_NEW, 1, JSEXN_TYPEERR, "Constructor {0} requires 'new'")
MSG_DEF(MSG_NO_INDEXED_SETTER, 1, JSEXN_TYPEERR, "{0} doesn't have an indexed property setter.")
MSG_DEF(MSG_NO_NAMED_SETTER, 1, JSEXN_TYPEERR, "{0} doesn't have a named property setter.")
MSG_DEF(MSG_ENFORCE_RANGE_NON_FINITE, 1, JSEXN_TYPEERR, "Non-finite value is out of range for {0}.")
MSG_DEF(MSG_ENFORCE_RANGE_OUT_OF_RANGE, 1, JSEXN_TYPEERR, "Value is out of range for {0}.")
MSG_DEF(MSG_NOT_SEQUENCE, 1, JSEXN_TYPEERR, "{0} can't be converted to a sequence.")
-2
View File
@@ -35,8 +35,6 @@ private:
class DelayedResolveOrReject : public nsRunnable
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DelayedResolveOrReject)
DelayedResolveOrReject(MediaTaskQueue* aTaskQueue,
TestPromise::Private* aPromise,
TestPromise::ResolveOrRejectValue aValue,
-4
View File
@@ -25,8 +25,6 @@ public:
: mManager(aManager), mDebugger(aDebugger), mHasListeners(aHasListeners)
{ }
NS_DECL_THREADSAFE_ISUPPORTS
private:
~RegisterDebuggerRunnable()
{ }
@@ -40,8 +38,6 @@ private:
}
};
NS_IMPL_ISUPPORTS(RegisterDebuggerRunnable, nsIRunnable);
BEGIN_WORKERS_NAMESPACE
class WorkerDebuggerEnumerator final : public nsISimpleEnumerator
+3 -1
View File
@@ -142,6 +142,8 @@ class ObjectOpResult
JS_PUBLIC_API(bool) failCantDeleteWindowElement();
JS_PUBLIC_API(bool) failCantDeleteWindowNamedProperty();
JS_PUBLIC_API(bool) failCantPreventExtensions();
JS_PUBLIC_API(bool) failNoNamedSetter();
JS_PUBLIC_API(bool) failNoIndexedSetter();
uint32_t failureCode() const {
MOZ_ASSERT(!ok());
@@ -668,7 +670,7 @@ struct JSClass {
// the beginning of every global object's slots for use by the
// application.
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
#define JSCLASS_GLOBAL_SLOT_COUNT (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 33)
#define JSCLASS_GLOBAL_SLOT_COUNT (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 35)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \
+48
View File
@@ -32,6 +32,14 @@ ToBooleanSlow(JS::HandleValue v);
extern JS_PUBLIC_API(bool)
ToNumberSlow(JSContext* cx, JS::Value v, double* dp);
/* DO NOT CALL THIS. Use JS::ToInt8. */
extern JS_PUBLIC_API(bool)
ToInt8Slow(JSContext *cx, JS::HandleValue v, int8_t *out);
/* DO NOT CALL THIS. Use JS::ToInt16. */
extern JS_PUBLIC_API(bool)
ToInt16Slow(JSContext *cx, JS::HandleValue v, int16_t *out);
/* DO NOT CALL THIS. Use JS::ToInt32. */
extern JS_PUBLIC_API(bool)
ToInt32Slow(JSContext* cx, JS::HandleValue v, int32_t* out);
@@ -168,6 +176,19 @@ ToUint32(JSContext* cx, HandleValue v, uint32_t* out)
return js::ToUint32Slow(cx, v, out);
}
/* ES6 draft 20141224, 7.1.7. */
MOZ_ALWAYS_INLINE bool
ToInt16(JSContext *cx, JS::HandleValue v, int16_t *out)
{
detail::AssertArgumentsAreSane(cx, v);
if (v.isInt32()) {
*out = int16_t(v.toInt32());
return true;
}
return js::ToInt16Slow(cx, v, out);
}
/* ES6 draft 20141224, 7.1.8. */
MOZ_ALWAYS_INLINE bool
ToUint16(JSContext* cx, HandleValue v, uint16_t* out)
@@ -181,6 +202,19 @@ ToUint16(JSContext* cx, HandleValue v, uint16_t* out)
return js::ToUint16Slow(cx, v, out);
}
/* ES6 draft 20141224, 7.1.9 */
MOZ_ALWAYS_INLINE bool
ToInt8(JSContext *cx, JS::HandleValue v, int8_t *out)
{
detail::AssertArgumentsAreSane(cx, v);
if (v.isInt32()) {
*out = int8_t(v.toInt32());
return true;
}
return js::ToInt8Slow(cx, v, out);
}
/*
* Non-standard, with behavior similar to that of ToInt32, except in its
* producing an int64_t.
@@ -482,6 +516,20 @@ ToUint32(double d)
return detail::ToUintWidth<uint32_t>(d);
}
/* WEBIDL 4.2.4 */
inline int8_t
ToInt8(double d)
{
return detail::ToIntWidth<int8_t>(d);
}
/* WEBIDL 4.2.6 */
inline int16_t
ToInt16(double d)
{
return detail::ToIntWidth<int16_t>(d);
}
/* WEBIDL 4.2.10 */
inline int64_t
ToInt64(double d)
-5
View File
@@ -133,11 +133,6 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer
contextName_(nullptr), contextIndex_(InvalidIndex), contextFunctor_(nullptr)
{}
// Update the trace callback.
void setTraceCallback(JSTraceCallback traceCallback) {
callback = traceCallback;
}
// Test if the given callback is the same as our callback.
bool hasCallback(JSTraceCallback maybeCallback) const {
return maybeCallback == callback;
+9
View File
@@ -480,6 +480,13 @@ OnOutOfBounds()
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
}
static void
OnImpreciseConversion()
{
JSContext* cx = JSRuntime::innermostAsmJSActivation()->cx();
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_SIMD_FAILED_CONVERSION);
}
static bool
AsmJSHandleExecutionInterrupt()
{
@@ -676,6 +683,8 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext* cx)
return RedirectCall(FuncCast(OnDetached), Args_General0);
case AsmJSImm_OnOutOfBounds:
return RedirectCall(FuncCast(OnOutOfBounds), Args_General0);
case AsmJSImm_OnImpreciseConversion:
return RedirectCall(FuncCast(OnImpreciseConversion), Args_General0);
case AsmJSImm_HandleExecutionInterrupt:
return RedirectCall(FuncCast(AsmJSHandleExecutionInterrupt), Args_General0);
case AsmJSImm_InvokeFromAsmJS_Ignore:
File diff suppressed because it is too large Load Diff
+336 -38
View File
@@ -1351,7 +1351,6 @@ MapObject::extract(CallReceiver call)
uint32_t
MapObject::size(JSContext* cx, HandleObject obj)
{
MOZ_ASSERT(MapObject::is(obj));
ValueMap& map = extract(obj);
static_assert(sizeof(map.count()) <= sizeof(uint32_t),
"map count must be precisely representable as a JS number");
@@ -1377,8 +1376,6 @@ bool
MapObject::get(JSContext* cx, HandleObject obj,
HandleValue key, MutableHandleValue rval)
{
MOZ_ASSERT(MapObject::is(obj));
ValueMap& map = extract(obj);
AutoHashableValueRooter k(cx);
@@ -1410,8 +1407,6 @@ MapObject::get(JSContext* cx, unsigned argc, Value* vp)
bool
MapObject::has(JSContext* cx, HandleObject obj, HandleValue key, bool* rval)
{
MOZ_ASSERT(MapObject::is(obj));
ValueMap& map = extract(obj);
AutoHashableValueRooter k(cx);
@@ -1466,7 +1461,23 @@ MapObject::set(JSContext* cx, unsigned argc, Value* vp)
}
bool
MapObject::delete_impl(JSContext* cx, const CallArgs& args)
MapObject::delete_(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
{
ValueMap &map = extract(obj);
AutoHashableValueRooter k(cx);
if (!k.setValue(cx, key))
return false;
if (!map.remove(k, rval)) {
ReportOutOfMemory(cx);
return false;
}
return true;
}
bool
MapObject::delete_impl(JSContext *cx, const CallArgs& args)
{
// MapObject::mark does not mark deleted entries. Incremental GC therefore
// requires that no RelocatableValue objects pointing to heap values be
@@ -1501,7 +1512,6 @@ bool
MapObject::iterator(JSContext* cx, IteratorKind kind,
HandleObject obj, MutableHandleValue iter)
{
MOZ_ASSERT(MapObject::is(obj));
ValueMap& map = extract(obj);
Rooted<JSObject*> iterobj(cx, MapIteratorObject::create(cx, obj, &map, kind));
return iterobj && (iter.setObject(*iterobj), true);
@@ -1571,7 +1581,6 @@ MapObject::clear(JSContext* cx, unsigned argc, Value* vp)
bool
MapObject::clear(JSContext* cx, HandleObject obj)
{
MOZ_ASSERT(MapObject::is(obj));
ValueMap& map = extract(obj);
if (!map.clear()) {
ReportOutOfMemory(cx);
@@ -1955,7 +1964,20 @@ SetObject::is(HandleValue v)
return v.isObject() && v.toObject().hasClass(&class_) && v.toObject().as<SetObject>().getPrivate();
}
ValueSet&
bool
SetObject::is(HandleObject o)
{
return o->hasClass(&class_) && o->as<SetObject>().getPrivate();
}
ValueSet &
SetObject::extract(HandleObject o)
{
MOZ_ASSERT(o->hasClass(&SetObject::class_));
return *o->as<SetObject>().getData();
}
ValueSet &
SetObject::extract(CallReceiver call)
{
MOZ_ASSERT(call.thisv().isObject());
@@ -1963,6 +1985,16 @@ SetObject::extract(CallReceiver call)
return *static_cast<SetObject&>(call.thisv().toObject()).getData();
}
uint32_t
SetObject::size(JSContext *cx, HandleObject obj)
{
MOZ_ASSERT(SetObject::is(obj));
ValueSet &set = extract(obj);
static_assert(sizeof(set.count()) <= sizeof(uint32_t),
"set count must be precisely representable as a JS number");
return set.count();
}
bool
SetObject::size_impl(JSContext* cx, const CallArgs& args)
{
@@ -1994,7 +2026,22 @@ SetObject::has_impl(JSContext* cx, const CallArgs& args)
}
bool
SetObject::has(JSContext* cx, unsigned argc, Value* vp)
SetObject::has(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
{
MOZ_ASSERT(SetObject::is(obj));
ValueSet &set = extract(obj);
AutoHashableValueRooter k(cx);
if (!k.setValue(cx, key))
return false;
*rval = set.has(k);
return true;
}
bool
SetObject::has(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<SetObject::is, SetObject::has_impl>(cx, args);
@@ -2024,7 +2071,25 @@ SetObject::add(JSContext* cx, unsigned argc, Value* vp)
}
bool
SetObject::delete_impl(JSContext* cx, const CallArgs& args)
SetObject::delete_(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
{
MOZ_ASSERT(SetObject::is(obj));
ValueSet &set = extract(obj);
AutoHashableValueRooter k(cx);
if (!k.setValue(cx, key))
return false;
if (!set.remove(k, rval)) {
ReportOutOfMemory(cx);
return false;
}
return true;
}
bool
SetObject::delete_impl(JSContext *cx, const CallArgs& args)
{
MOZ_ASSERT(is(args.thisv()));
@@ -2047,7 +2112,17 @@ SetObject::delete_(JSContext* cx, unsigned argc, Value* vp)
}
bool
SetObject::iterator_impl(JSContext* cx, const CallArgs& args, IteratorKind kind)
SetObject::iterator(JSContext *cx, IteratorKind kind,
HandleObject obj, MutableHandleValue iter)
{
MOZ_ASSERT(SetObject::is(obj));
ValueSet &set = extract(obj);
Rooted<JSObject*> iterobj(cx, SetIteratorObject::create(cx, obj, &set, kind));
return iterobj && (iter.setObject(*iterobj), true);
}
bool
SetObject::iterator_impl(JSContext *cx, const CallArgs& args, IteratorKind kind)
{
Rooted<SetObject*> setobj(cx, &args.thisv().toObject().as<SetObject>());
ValueSet& set = *setobj->getData();
@@ -2085,7 +2160,19 @@ SetObject::entries(JSContext* cx, unsigned argc, Value* vp)
}
bool
SetObject::clear_impl(JSContext* cx, const CallArgs& args)
SetObject::clear(JSContext *cx, HandleObject obj)
{
MOZ_ASSERT(SetObject::is(obj));
ValueSet &set = extract(obj);
if (!set.clear()) {
ReportOutOfMemory(cx);
return false;
}
return true;
}
bool
SetObject::clear_impl(JSContext *cx, const CallArgs& args)
{
Rooted<SetObject*> setobj(cx, &args.thisv().toObject().as<SetObject>());
if (!setobj->getData()->clear()) {
@@ -2121,6 +2208,98 @@ js::InitSelfHostingCollectionIteratorFunctions(JSContext* cx, HandleObject obj)
return JS_DefineFunctions(cx, obj, selfhosting_collection_iterator_methods);
}
/*** JS static utility functions *********************************************/
static
bool
forEach(const char* funcName, JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisArg)
{
CHECK_REQUEST(cx);
RootedId forEachId(cx, NameToId(cx->names().forEach));
RootedFunction forEachFunc(cx, JS::GetSelfHostedFunction(cx, funcName, forEachId, 2));
if (!forEachFunc)
return false;
InvokeArgs args(cx);
if (!args.init(2))
return false;
args.setCallee(JS::ObjectValue(*forEachFunc));
args.setThis(JS::ObjectValue(*obj));
args[0].set(callbackFn);
args[1].set(thisArg);
return Invoke(cx, args);
}
// Handles Clear/Size for public jsapi map/set access
template<typename RetT>
RetT
CallObjFunc(RetT(*ObjFunc)(JSContext*, HandleObject), JSContext* cx, HandleObject obj)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
// Always unwrap, in case this is an xray or cross-compartment wrapper.
RootedObject unwrappedObj(cx);
unwrappedObj = UncheckedUnwrap(obj);
// Enter the compartment of the backing object before calling functions on
// it.
JSAutoCompartment ac(cx, unwrappedObj);
return ObjFunc(cx, unwrappedObj);
}
// Handles Has/Delete for public jsapi map/set access
bool
CallObjFunc(bool(*ObjFunc)(JSContext *cx, HandleObject obj, HandleValue key, bool *rval),
JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, key);
// Always unwrap, in case this is an xray or cross-compartment wrapper.
RootedObject unwrappedObj(cx);
unwrappedObj = UncheckedUnwrap(obj);
JSAutoCompartment ac(cx, unwrappedObj);
// If we're working with a wrapped map/set, rewrap the key into the
// compartment of the unwrapped map/set.
RootedValue wrappedKey(cx, key);
if (obj != unwrappedObj) {
if (!JS_WrapValue(cx, &wrappedKey))
return false;
}
return ObjFunc(cx, unwrappedObj, wrappedKey, rval);
}
// Handles iterator generation for public jsapi map/set access
template<typename Iter>
bool
CallObjFunc(bool(*ObjFunc)(JSContext* cx, Iter kind,
HandleObject obj, MutableHandleValue iter),
JSContext *cx, Iter iterType, HandleObject obj, MutableHandleValue rval)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
// Always unwrap, in case this is an xray or cross-compartment wrapper.
RootedObject unwrappedObj(cx);
unwrappedObj = UncheckedUnwrap(obj);
{
// Retrieve the iterator while in the unwrapped map/set's compartment,
// otherwise we'll crash on a compartment assert.
JSAutoCompartment ac(cx, unwrappedObj);
if (!ObjFunc(cx, iterType, unwrappedObj, rval))
return false;
}
// If the caller is in a different compartment than the map/set, rewrap the
// iterator object into the caller's compartment.
if (obj != unwrappedObj) {
if (!JS_WrapValue(cx, rval))
return false;
}
return true;
}
/*** JS public APIs **********************************************************/
JS_PUBLIC_API(JSObject*)
@@ -2132,63 +2311,182 @@ JS::NewMapObject(JSContext* cx)
JS_PUBLIC_API(uint32_t)
JS::MapSize(JSContext* cx, HandleObject obj)
{
CHECK_REQUEST(cx);
return MapObject::size(cx, obj);
return CallObjFunc<uint32_t>(&MapObject::size, cx, obj);
}
JS_PUBLIC_API(bool)
JS::MapGet(JSContext* cx, HandleObject obj,
HandleValue key, MutableHandleValue rval)
JS::MapGet(JSContext* cx, HandleObject obj, HandleValue key, MutableHandleValue rval)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, key, rval);
return MapObject::get(cx, obj, key, rval);
assertSameCompartment(cx, obj, key, rval);
// Unwrap the object, and enter its compartment. If object isn't wrapped,
// this is essentially a noop.
RootedObject unwrappedObj(cx);
unwrappedObj = UncheckedUnwrap(obj);
{
JSAutoCompartment ac(cx, unwrappedObj);
RootedValue wrappedKey(cx, key);
// If we passed in a wrapper, wrap our key into its compartment now.
if (obj != unwrappedObj) {
if (!JS_WrapValue(cx, &wrappedKey))
return false;
}
if (!MapObject::get(cx, unwrappedObj, wrappedKey, rval))
return false;
}
// If we passed in a wrapper, wrap our return value on the way out.
if (obj != unwrappedObj) {
if (!JS_WrapValue(cx, rval))
return false;
}
return true;
}
JS_PUBLIC_API(bool)
JS::MapSet(JSContext *cx, HandleObject obj, HandleValue key, HandleValue val)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, key, val);
// Unwrap the object, and enter its compartment. If object isn't wrapped,
// this is essentially a noop.
RootedObject unwrappedObj(cx);
unwrappedObj = UncheckedUnwrap(obj);
{
JSAutoCompartment ac(cx, unwrappedObj);
// If we passed in a wrapper, wrap both key and value before adding to
// the map
RootedValue wrappedKey(cx, key);
RootedValue wrappedValue(cx, val);
if (obj != unwrappedObj) {
if (!JS_WrapValue(cx, &wrappedKey) ||
!JS_WrapValue(cx, &wrappedValue)) {
return false;
}
}
return MapObject::set(cx, unwrappedObj, wrappedKey, wrappedValue);
}
}
JS_PUBLIC_API(bool)
JS::MapHas(JSContext* cx, HandleObject obj, HandleValue key, bool* rval)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, key);
return MapObject::has(cx, obj, key, rval);
return CallObjFunc(MapObject::has, cx, obj, key, rval);
}
JS_PUBLIC_API(bool)
JS::MapSet(JSContext* cx, HandleObject obj,
HandleValue key, HandleValue val)
JS::MapDelete(JSContext *cx, HandleObject obj, HandleValue key, bool* rval)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, key, val);
return MapObject::set(cx, obj, key, val);
return CallObjFunc(MapObject::delete_, cx, obj, key, rval);
}
JS_PUBLIC_API(bool)
JS::MapClear(JSContext* cx, HandleObject obj)
{
CHECK_REQUEST(cx);
return MapObject::clear(cx, obj);
return CallObjFunc(&MapObject::clear, cx, obj);
}
JS_PUBLIC_API(bool)
JS::MapKeys(JSContext* cx, HandleObject obj, MutableHandleValue rval)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, rval);
return MapObject::iterator(cx, MapObject::Keys, obj, rval);
return CallObjFunc(&MapObject::iterator, cx, MapObject::Keys, obj, rval);
}
JS_PUBLIC_API(bool)
JS::MapValues(JSContext* cx, HandleObject obj, MutableHandleValue rval)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, rval);
return MapObject::iterator(cx, MapObject::Values, obj, rval);
return CallObjFunc(&MapObject::iterator, cx, MapObject::Values, obj, rval);
}
JS_PUBLIC_API(bool)
JS::MapEntries(JSContext* cx, HandleObject obj, MutableHandleValue rval)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, rval);
return MapObject::iterator(cx, MapObject::Entries, obj, rval);
return CallObjFunc(&MapObject::iterator, cx, MapObject::Entries, obj, rval);
}
JS_PUBLIC_API(bool)
JS::MapForEach(JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisVal)
{
return forEach("MapForEach", cx, obj, callbackFn, thisVal);
}
JS_PUBLIC_API(JSObject *)
JS::NewSetObject(JSContext *cx)
{
return SetObject::create(cx);
}
JS_PUBLIC_API(uint32_t)
JS::SetSize(JSContext *cx, HandleObject obj)
{
return CallObjFunc<uint32_t>(&SetObject::size, cx, obj);
}
JS_PUBLIC_API(bool)
JS::SetAdd(JSContext *cx, HandleObject obj, HandleValue key)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, key);
// Unwrap the object, and enter its compartment. If object isn't wrapped,
// this is essentially a noop.
RootedObject unwrappedObj(cx);
unwrappedObj = UncheckedUnwrap(obj);
{
JSAutoCompartment ac(cx, unwrappedObj);
// If we passed in a wrapper, wrap key before adding to the set
RootedValue wrappedKey(cx, key);
if (obj != unwrappedObj) {
if (!JS_WrapValue(cx, &wrappedKey))
return false;
}
return SetObject::add(cx, unwrappedObj, wrappedKey);
}
}
JS_PUBLIC_API(bool)
JS::SetHas(JSContext* cx, HandleObject obj, HandleValue key, bool* rval)
{
return CallObjFunc(SetObject::has, cx, obj, key, rval);
}
JS_PUBLIC_API(bool)
JS::SetDelete(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
{
return CallObjFunc(SetObject::delete_, cx, obj, key, rval);
}
JS_PUBLIC_API(bool)
JS::SetClear(JSContext* cx, HandleObject obj)
{
return CallObjFunc(&SetObject::clear, cx, obj);
}
JS_PUBLIC_API(bool)
JS::SetKeys(JSContext* cx, HandleObject obj, MutableHandleValue rval)
{
return SetValues(cx, obj, rval);
}
JS_PUBLIC_API(bool)
JS::SetValues(JSContext* cx, HandleObject obj, MutableHandleValue rval)
{
return CallObjFunc(&SetObject::iterator, cx, SetObject::Values, obj, rval);
}
JS_PUBLIC_API(bool)
JS::SetEntries(JSContext* cx, HandleObject obj, MutableHandleValue rval)
{
return CallObjFunc(&SetObject::iterator, cx, SetObject::Entries, obj, rval);
}
JS_PUBLIC_API(bool)
JS::SetForEach(JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisVal)
{
return forEach("SetForEach", cx, obj, callbackFn, thisVal);
}
+28 -11
View File
@@ -98,12 +98,19 @@ class MapObject : public NativeObject {
static bool has(JSContext* cx, unsigned argc, Value* vp);
static MapObject* create(JSContext* cx);
static uint32_t size(JSContext* cx, HandleObject obj);
static bool get(JSContext* cx, HandleObject obj, HandleValue key, MutableHandleValue rval);
static bool has(JSContext* cx, HandleObject obj, HandleValue key, bool* rval);
static bool set(JSContext* cx, HandleObject obj, HandleValue key, HandleValue val);
static bool clear(JSContext* cx, HandleObject obj);
static bool iterator(JSContext* cx, IteratorKind kind, HandleObject obj, MutableHandleValue iter);
// Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
// interfaces, etc.)
static uint32_t size(JSContext *cx, HandleObject obj);
static bool get(JSContext *cx, HandleObject obj, HandleValue key, MutableHandleValue rval);
static bool has(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
static bool delete_(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
// Set call for public JSAPI exposure. Does not actually return map object
// as stated in spec, expects caller to return a value. for instance, with
// webidl maplike/setlike, should return interface object.
static bool set(JSContext *cx, HandleObject obj, HandleValue key, HandleValue val);
static bool clear(JSContext *cx, HandleObject obj);
static bool iterator(JSContext *cx, IteratorKind kind, HandleObject obj, MutableHandleValue iter);
private:
static const JSPropertySpec properties[];
@@ -145,23 +152,33 @@ class SetObject : public NativeObject {
static JSObject* initClass(JSContext* cx, JSObject* obj);
static const Class class_;
static bool keys(JSContext* cx, HandleObject obj, JS::AutoValueVector* keys);
static bool values(JSContext* cx, unsigned argc, Value* vp);
static bool add(JSContext* cx, HandleObject obj, HandleValue key);
static bool has(JSContext* cx, unsigned argc, Value* vp);
static SetObject* create(JSContext* cx);
static bool keys(JSContext *cx, HandleObject obj, JS::AutoValueVector *keys);
static bool values(JSContext *cx, unsigned argc, Value *vp);
static bool add(JSContext *cx, HandleObject obj, HandleValue key);
static bool has(JSContext *cx, unsigned argc, Value *vp);
// Publicly exposed Set calls for JSAPI access (webidl maplike/setlike
// interfaces, etc.)
static SetObject* create(JSContext *cx);
static uint32_t size(JSContext *cx, HandleObject obj);
static bool has(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
static bool clear(JSContext *cx, HandleObject obj);
static bool iterator(JSContext *cx, IteratorKind kind, HandleObject obj, MutableHandleValue iter);
static bool delete_(JSContext *cx, HandleObject obj, HandleValue key, bool *rval);
private:
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
static const JSPropertySpec staticProperties[];
ValueSet* getData() { return static_cast<ValueSet*>(getPrivate()); }
static ValueSet & extract(HandleObject o);
static ValueSet & extract(CallReceiver call);
static void mark(JSTracer* trc, JSObject* obj);
static void finalize(FreeOp* fop, JSObject* obj);
static bool construct(JSContext* cx, unsigned argc, Value* vp);
static bool is(HandleValue v);
static bool is(HandleObject o);
static bool iterator_impl(JSContext* cx, const CallArgs& args, IteratorKind kind);
+10 -22
View File
@@ -1121,39 +1121,25 @@ CreateObjectPrototype(JSContext* cx, JSProtoKey key)
static bool
FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
{
Rooted<GlobalObject*> self(cx, cx->global());
Rooted<GlobalObject*> global(cx, cx->global());
/* ES5 15.1.2.1. */
RootedId evalId(cx, NameToId(cx->names().eval));
JSObject* evalobj = DefineFunction(cx, self, evalId, IndirectEval, 1,
JSObject* evalobj = DefineFunction(cx, global, evalId, IndirectEval, 1,
JSFUN_STUB_GSOPS | JSPROP_RESOLVING);
if (!evalobj)
return false;
self->setOriginalEval(evalobj);
global->setOriginalEval(evalobj);
RootedObject intrinsicsHolder(cx);
bool isSelfHostingGlobal = cx->runtime()->isSelfHostingGlobal(self);
if (isSelfHostingGlobal) {
intrinsicsHolder = self;
} else {
intrinsicsHolder = NewObjectWithGivenProto<PlainObject>(cx, proto, TenuredObject);
if (!intrinsicsHolder)
return false;
}
self->setIntrinsicsHolder(intrinsicsHolder);
/* Define a property 'global' with the current global as its value. */
RootedValue global(cx, ObjectValue(*self));
if (!DefineProperty(cx, intrinsicsHolder, cx->names().global, global,
nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY))
{
Rooted<NativeObject*> holder(cx, GlobalObject::getIntrinsicsHolder(cx, global));
if (!holder)
return false;
}
/*
* Define self-hosted functions after setting the intrinsics holder
* (which is needed to define self-hosted functions)
*/
if (!isSelfHostingGlobal) {
if (!cx->runtime()->isSelfHostingGlobal(global)) {
if (!JS_DefineFunctions(cx, ctor, object_static_methods, OnlyDefineLateProperties))
return false;
if (!JS_DefineFunctions(cx, proto, object_methods, OnlyDefineLateProperties))
@@ -1169,8 +1155,10 @@ FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject pro
* only set the [[Prototype]] if it hasn't already been set.
*/
Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
if (self->shouldSplicePrototype(cx) && !self->splicePrototype(cx, self->getClass(), tagged))
return false;
if (global->shouldSplicePrototype(cx)) {
if (!global->splicePrototype(cx, global->getClass(), tagged))
return false;
}
return true;
}
+200 -118
View File
@@ -139,117 +139,39 @@ js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, RegExpObject& reobj,
return CreateRegExpMatchResult(cx, input, matches, rval);
}
/*
* Compile a new |RegExpShared| for the |RegExpObject|.
*/
static bool
CompileRegExpObject(JSContext* cx, RegExpObjectBuilder& builder,
const CallArgs& args, RegExpStaticsUse staticsUse,
RegExpCreationMode creationMode)
/* ES6 draft rc4 21.2.3.2.2. */
bool
RegExpInitialize(JSContext* cx, RegExpObjectBuilder& builder,
HandleValue patternValue, HandleValue flagsValue,
RegExpStaticsUse staticsUse, MutableHandleObject result)
{
if (args.length() == 0) {
MOZ_ASSERT(staticsUse == UseRegExpStatics);
RegExpStatics* res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
Rooted<JSAtom*> empty(cx, cx->names().emptyRegExp);
RegExpObject* reobj = builder.build(empty, res->getFlags());
if (!reobj)
return false;
args.rval().setObject(*reobj);
return true;
}
RootedValue sourceValue(cx, args[0]);
if (IsObjectWithClass(sourceValue, ESClass_RegExp, cx)) {
/*
* For RegExp.prototype.compile, if the first argument is a RegExp object,
* the second argument must be undefined. Otherwise, throw a TypeError.
*/
if (args.hasDefined(1) && creationMode == CreateForCompile) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NEWREGEXP_FLAGGED);
return false;
}
/*
* Beware, sourceObj may be a (transparent) proxy to a RegExp, so only
* use generic (proxyable) operations on sourceObj that do not assume
* sourceObj.is<RegExpObject>().
*/
RootedObject sourceObj(cx, &sourceValue.toObject());
RegExpFlag flags;
{
/*
* Only extract the 'flags' out of sourceObj; do not reuse the
* RegExpShared since it may be from a different compartment.
*/
RegExpGuard g(cx);
if (!RegExpToShared(cx, sourceObj, &g))
return false;
/*
* If args[1] is not undefined, then parse the 'flags' from args[1].
* Otherwise, extract the 'flags' from sourceObj.
*/
if (args.hasDefined(1)) {
flags = RegExpFlag(0);
RootedString flagStr(cx, ToString<CanGC>(cx, args[1]));
if (!flagStr)
return false;
if (!ParseRegExpFlags(cx, flagStr, &flags))
return false;
} else {
flags = g->getFlags();
}
}
/*
* 'toSource' is a permanent read-only property, so this is equivalent
* to executing RegExpObject::getSource on the unwrapped object.
*/
RootedValue v(cx);
if (!GetProperty(cx, sourceObj, sourceObj, cx->names().source, &v))
return false;
// For proxies like CPOWs, we can't assume the result of a property get
// for 'source' is atomized.
Rooted<JSAtom*> sourceAtom(cx, AtomizeString(cx, v.toString()));
RegExpObject* reobj = builder.build(sourceAtom, flags);
if (!reobj)
return false;
args.rval().setObject(*reobj);
return true;
}
RootedAtom source(cx);
if (sourceValue.isUndefined()) {
source = cx->runtime()->emptyString;
RootedAtom pattern(cx);
if (patternValue.isUndefined()) {
/* Step 1. */
pattern = cx->runtime()->emptyString;
} else {
/* Coerce to string and compile. */
source = ToAtom<CanGC>(cx, sourceValue);
if (!source)
/* Steps 2-3. */
pattern = ToAtom<CanGC>(cx, patternValue);
if (!pattern)
return false;
}
/* Step 4. */
RegExpFlag flags = RegExpFlag(0);
if (args.hasDefined(1)) {
RootedString flagStr(cx, ToString<CanGC>(cx, args[1]));
if (!flagsValue.isUndefined()) {
/* Steps 5-6. */
RootedString flagStr(cx, ToString<CanGC>(cx, flagsValue));
if (!flagStr)
return false;
/* Step 7. */
if (!ParseRegExpFlags(cx, flagStr, &flags))
return false;
}
RootedAtom escapedSourceStr(cx, EscapeRegExpPattern(cx, source));
if (!escapedSourceStr)
return false;
/* Steps 9-10. */
CompileOptions options(cx);
frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
if (!irregexp::ParsePatternSyntax(dummyTokenStream, cx->tempLifoAlloc(), escapedSourceStr))
if (!irregexp::ParsePatternSyntax(dummyTokenStream, cx->tempLifoAlloc(), pattern))
return false;
if (staticsUse == UseRegExpStatics) {
@@ -258,10 +180,146 @@ CompileRegExpObject(JSContext* cx, RegExpObjectBuilder& builder,
return false;
flags = RegExpFlag(flags | res->getFlags());
}
RegExpObject* reobj = builder.build(escapedSourceStr, flags);
/* Steps 11-15. */
RootedObject reobj(cx, builder.build(pattern, flags));
if (!reobj)
return false;
/* Step 16. */
result.set(reobj);
return true;
}
/*
* ES6 draft rc4 21.2.3.1 steps 5-10.
* ES6 draft rc4 B.2.5.1 steps 3-5.
* Compile a new |RegExpShared| for the |RegExpObject|.
*/
static bool
CompileRegExpObject(JSContext* cx, RegExpObjectBuilder& builder, CallArgs args,
RegExpCreationMode creationMode, bool patternIsRegExp=false)
{
if (args.length() == 0) {
/*
* 21.2.3.1 step 10.
* B.2.5.1 step 5.
*/
RegExpStatics* res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
RootedAtom empty(cx, cx->runtime()->emptyString);
RegExpObject* reobj = builder.build(empty, res->getFlags());
if (!reobj)
return false;
args.rval().setObject(*reobj);
return true;
}
RootedValue patternValue(cx, args.get(0));
/*
* 21.2.3.1 step 5
* B.2.5.1 step 3.
*/
if (IsObjectWithClass(patternValue, ESClass_RegExp, cx)) {
/*
* B.2.5.1 step 3.a.
*/
if (args.hasDefined(1) && creationMode == CreateForCompile) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NEWREGEXP_FLAGGED);
return false;
}
/*
* Beware, patternObj may be a (transparent) proxy to a RegExp, so only
* use generic (proxyable) operations on patternObj that do not assume
* patternObj.is<RegExpObject>().
*/
RootedObject patternObj(cx, &patternValue.toObject());
RootedAtom sourceAtom(cx);
RegExpFlag flags;
{
/*
* 21.2.3.1 step 5.a.
* B.2.5.1 step 3.a.
* Extract the 'source' from patternObj; do not reuse the
* RegExpShared since it may be from a different compartment.
*/
RegExpGuard g(cx);
if (!RegExpToShared(cx, patternObj, &g))
return false;
sourceAtom = g->getSource();
if (args.hasDefined(1)) {
/* 21.2.3.1 step 5.c. */
flags = RegExpFlag(0);
RootedString flagStr(cx, ToString<CanGC>(cx, args[1]));
if (!flagStr)
return false;
if (!ParseRegExpFlags(cx, flagStr, &flags))
return false;
} else {
/*
* 21.2.3.1 step 5.b.
* B.2.5.1 step 3.c.
*/
flags = g->getFlags();
}
}
/*
* 21.2.3.1 steps 8-10.
* B.2.5.1 step 5.
*/
RegExpObject* reobj = builder.build(sourceAtom, flags);
if (!reobj)
return false;
args.rval().setObject(*reobj);
return true;
}
RootedValue P(cx);
RootedValue F(cx);
/* 21.2.3.1 step 6. */
if (patternIsRegExp) {
MOZ_ASSERT(creationMode == CreateForConstruct);
RootedObject patternObj(cx, &patternValue.toObject());
/* 21.2.3.1 steps 6.a-b. */
if (!GetProperty(cx, patternObj, patternObj, cx->names().source, &P))
return false;
/* 21.2.3.1 step 6.c. */
if (!args.hasDefined(1)) {
/* 21.2.3.1 steps 6.c.i-ii. */
if (!GetProperty(cx, patternObj, patternObj, cx->names().flags, &F))
return false;
} else {
/* 21.2.3.1 steps 6.d. */
F = args[1];
}
} else {
/*
* 21.2.3.1 steps 7.a-b.
* B.2.5.1 steps 4.a-b.
*/
P = patternValue;
F = args.get(1);
}
/*
* 21.2.3.1 steps 8-10.
* B.2.5.1 step 5.
*/
RootedObject reobj(cx);
if (!RegExpInitialize(cx, builder, P, F, UseRegExpStatics, &reobj))
return false;
args.rval().setObject(*reobj);
return true;
}
@@ -300,43 +358,59 @@ IsRegExpObject(HandleValue v)
return v.isObject() && v.toObject().is<RegExpObject>();
}
/* ES6 draft rc4 B.2.5.1. */
MOZ_ALWAYS_INLINE bool
regexp_compile_impl(JSContext *cx, const CallArgs &args)
regexp_compile_impl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsRegExpObject(args.thisv()));
/* Steps 3-5. */
RegExpObjectBuilder builder(cx, &args.thisv().toObject().as<RegExpObject>());
return CompileRegExpObject(cx, builder, args, UseRegExpStatics, CreateForCompile);
return CompileRegExpObject(cx, builder, args, CreateForCompile);
}
static bool
regexp_compile(JSContext *cx, unsigned argc, Value *vp)
regexp_compile(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
/* Steps 1-2. */
return CallNonGenericMethod<IsRegExpObject, regexp_compile_impl>(cx, args);
}
/* ES6 draft rc4 21.2.3.1. */
bool
js::regexp_construct(JSContext *cx, unsigned argc, Value *vp)
js::regexp_construct(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
/* Steps 1-2. */
bool patternIsRegExp;
if (!IsRegExp(cx, args.get(0), &patternIsRegExp))
return false;
/* Step 4. */
if (!args.isConstructing()) {
/*
* If first arg is regexp and no flags are given, just return the arg.
* Otherwise, delegate to the standard constructor.
* See ECMAv5 15.10.3.1.
*/
if (args.hasDefined(0) &&
IsObjectWithClass(args[0], ESClass_RegExp, cx) &&
!args.hasDefined(1))
{
args.rval().set(args[0]);
return true;
/* Step 4.b. */
if (patternIsRegExp && !args.hasDefined(1)) {
RootedObject patternObj(cx, &args[0].toObject());
/* Steps 4.b.i-ii. */
RootedValue patternConstructor(cx);
if (!GetProperty(cx, patternObj, patternObj, cx->names().constructor, &patternConstructor))
return false;
/* Step 4.b.iii. */
if (patternConstructor.isObject() && patternConstructor.toObject() == args.callee()) {
args.rval().set(args[0]);
return true;
}
}
}
/* Steps 5-10. */
RegExpObjectBuilder builder(cx);
return CompileRegExpObject(cx, builder, args, UseRegExpStatics, CreateForConstruct);
return CompileRegExpObject(cx, builder, args, CreateForConstruct, patternIsRegExp);
}
bool
@@ -349,8 +423,16 @@ js::regexp_construct_no_statics(JSContext* cx, unsigned argc, Value* vp)
MOZ_ASSERT_IF(args.length() == 2, args[1].isString());
MOZ_ASSERT(!args.isConstructing());
/* Steps 1-6 are not required since pattern is always string. */
/* Steps 7-10. */
RegExpObjectBuilder builder(cx);
return CompileRegExpObject(cx, builder, args, DontUseRegExpStatics, CreateForConstruct);
RootedObject reobj(cx);
if (!RegExpInitialize(cx, builder, args[0], args.get(1), DontUseRegExpStatics, &reobj))
return false;
args.rval().setObject(*reobj);
return true;
}
/* ES6 draft rev32 21.2.5.4. */
@@ -571,8 +653,8 @@ const JSPropertySpec js::regexp_static_props[] = {
JS_PS_END
};
JSObject *
js::CreateRegExpPrototype(JSContext *cx, JSProtoKey key)
JSObject*
js::CreateRegExpPrototype(JSContext* cx, JSProtoKey key)
{
MOZ_ASSERT(key == JSProto_RegExp);
@@ -581,7 +663,7 @@ js::CreateRegExpPrototype(JSContext *cx, JSProtoKey key)
return nullptr;
proto->NativeObject::setPrivate(nullptr);
HandlePropertyName empty = cx->names().emptyRegExp;
HandlePropertyName empty = cx->names().empty;
RegExpObjectBuilder builder(cx, proto);
if (!builder.build(empty, RegExpFlag(0)))
return nullptr;
+246 -72
View File
@@ -13,6 +13,7 @@
#include "builtin/SIMD.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/IntegerTypeTraits.h"
#include "jsapi.h"
@@ -30,11 +31,13 @@ using mozilla::ArrayLength;
using mozilla::IsFinite;
using mozilla::IsNaN;
using mozilla::FloorLog2;
using mozilla::NumberIsInt32;
///////////////////////////////////////////////////////////////////////////
// SIMD
static const char* laneNames[] = {"lane 0", "lane 1", "lane 2", "lane3"};
static const char* laneNames[] = {"lane 0", "lane 1", "lane 2", "lane 3", "lane 4", "lane 5", "lane 6", "lane 7",
"lane 8", "lane 9", "lane 10", "lane 11", "lane 12", "lane 13", "lane 14", "lane 15"};
static bool
CheckVectorObject(HandleValue v, SimdTypeDescr::Type expectedType)
@@ -60,6 +63,8 @@ js::IsVectorObject(HandleValue v)
return CheckVectorObject(v, V::type);
}
template bool js::IsVectorObject<Int8x16>(HandleValue v);
template bool js::IsVectorObject<Int16x8>(HandleValue v);
template bool js::IsVectorObject<Int32x4>(HandleValue v);
template bool js::IsVectorObject<Float32x4>(HandleValue v);
template bool js::IsVectorObject<Float64x2>(HandleValue v);
@@ -145,7 +150,27 @@ static bool type##Lane##lane(JSContext* cx, unsigned argc, Value* vp) { \
FOUR_LANES_ACCESSOR(Int32x4);
FOUR_LANES_ACCESSOR(Float32x4);
#define EIGHT_LANES_ACCESSOR(type) \
FOUR_LANES_ACCESSOR(type) \
LANE_ACCESSOR(type, 4) \
LANE_ACCESSOR(type, 5) \
LANE_ACCESSOR(type, 6) \
LANE_ACCESSOR(type, 7)
EIGHT_LANES_ACCESSOR(Int16x8);
EIGHT_LANES_ACCESSOR(Int8x16);
LANE_ACCESSOR(Int8x16, 8);
LANE_ACCESSOR(Int8x16, 9);
LANE_ACCESSOR(Int8x16, 10);
LANE_ACCESSOR(Int8x16, 11);
LANE_ACCESSOR(Int8x16, 12);
LANE_ACCESSOR(Int8x16, 13);
LANE_ACCESSOR(Int8x16, 14);
LANE_ACCESSOR(Int8x16, 15);
#undef FOUR_LANES_ACCESSOR
#undef EIGHT_LANES_ACCESSOR
LANE_ACCESSOR(Float64x2, 0);
LANE_ACCESSOR(Float64x2, 1);
@@ -194,6 +219,8 @@ static bool type##SignMask(JSContext* cx, unsigned argc, Value* vp) { \
}
SIGN_MASK(Float32x4);
SIGN_MASK(Float64x2);
SIGN_MASK(Int8x16);
SIGN_MASK(Int16x8);
SIGN_MASK(Int32x4);
#undef SIGN_MASK
@@ -215,6 +242,22 @@ const Class SimdTypeDescr::class_ = {
namespace {
// These classes just exist to group together various properties and so on.
class Int8x16Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Int8x16;
static const JSFunctionSpec TypeDescriptorMethods[];
static const JSPropertySpec TypedObjectProperties[];
static const JSFunctionSpec TypedObjectMethods[];
static const JSFunctionSpec Methods[];
};
class Int16x8Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Int16x8;
static const JSFunctionSpec TypeDescriptorMethods[];
static const JSPropertySpec TypedObjectProperties[];
static const JSFunctionSpec TypedObjectMethods[];
static const JSFunctionSpec Methods[];
};
class Int32x4Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Int32x4;
@@ -298,6 +341,80 @@ const JSFunctionSpec Float64x2Defn::Methods[] = {
JS_FS_END
};
const JSFunctionSpec Int8x16Defn::TypeDescriptorMethods[] = {
JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
JS_FS_END,
};
const JSPropertySpec Int8x16Defn::TypedObjectProperties[] = {
JS_PSG("s0", Int8x16Lane0, JSPROP_PERMANENT),
JS_PSG("s1", Int8x16Lane1, JSPROP_PERMANENT),
JS_PSG("s2", Int8x16Lane2, JSPROP_PERMANENT),
JS_PSG("s3", Int8x16Lane3, JSPROP_PERMANENT),
JS_PSG("s4", Int8x16Lane4, JSPROP_PERMANENT),
JS_PSG("s5", Int8x16Lane5, JSPROP_PERMANENT),
JS_PSG("s6", Int8x16Lane6, JSPROP_PERMANENT),
JS_PSG("s7", Int8x16Lane7, JSPROP_PERMANENT),
JS_PSG("s8", Int8x16Lane8, JSPROP_PERMANENT),
JS_PSG("s9", Int8x16Lane9, JSPROP_PERMANENT),
JS_PSG("s10", Int8x16Lane10, JSPROP_PERMANENT),
JS_PSG("s11", Int8x16Lane11, JSPROP_PERMANENT),
JS_PSG("s12", Int8x16Lane12, JSPROP_PERMANENT),
JS_PSG("s13", Int8x16Lane13, JSPROP_PERMANENT),
JS_PSG("s14", Int8x16Lane14, JSPROP_PERMANENT),
JS_PSG("s15", Int8x16Lane15, JSPROP_PERMANENT),
JS_PSG("signMask", Int8x16SignMask, JSPROP_PERMANENT),
JS_PS_END
};
const JSFunctionSpec Int8x16Defn::TypedObjectMethods[] = {
JS_SELF_HOSTED_FN("toSource", "SimdToSource", 0, 0),
JS_FS_END
};
const JSFunctionSpec Int8x16Defn::Methods[] = {
#define SIMD_INT8X16_FUNCTION_ITEM(Name, Func, Operands) \
JS_FN(#Name, js::simd_int8x16_##Name, Operands, 0),
INT8X16_FUNCTION_LIST(SIMD_INT8X16_FUNCTION_ITEM)
#undef SIMD_INT8X16_FUNCTION_ITEM
JS_FS_END
};
const JSFunctionSpec Int16x8Defn::TypeDescriptorMethods[] = {
JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
JS_FS_END,
};
const JSPropertySpec Int16x8Defn::TypedObjectProperties[] = {
JS_PSG("s0", Int16x8Lane0, JSPROP_PERMANENT),
JS_PSG("s1", Int16x8Lane1, JSPROP_PERMANENT),
JS_PSG("s2", Int16x8Lane2, JSPROP_PERMANENT),
JS_PSG("s3", Int16x8Lane3, JSPROP_PERMANENT),
JS_PSG("s4", Int16x8Lane4, JSPROP_PERMANENT),
JS_PSG("s5", Int16x8Lane5, JSPROP_PERMANENT),
JS_PSG("s6", Int16x8Lane6, JSPROP_PERMANENT),
JS_PSG("s7", Int16x8Lane7, JSPROP_PERMANENT),
JS_PSG("signMask", Int16x8SignMask, JSPROP_PERMANENT),
JS_PS_END
};
const JSFunctionSpec Int16x8Defn::TypedObjectMethods[] = {
JS_SELF_HOSTED_FN("toSource", "SimdToSource", 0, 0),
JS_FS_END
};
const JSFunctionSpec Int16x8Defn::Methods[] = {
#define SIMD_INT16X8_FUNCTION_ITEM(Name, Func, Operands) \
JS_FN(#Name, js::simd_int16x8_##Name, Operands, 0),
INT16X8_FUNCTION_LIST(SIMD_INT16X8_FUNCTION_ITEM)
#undef SIMD_INT16X8_FUNCTION_ITEM
JS_FS_END
};
const JSFunctionSpec Int32x4Defn::TypeDescriptorMethods[] = {
JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
@@ -418,6 +535,8 @@ SimdTypeDescr::call(JSContext* cx, unsigned argc, Value* vp)
return false;
switch (descr->type()) {
case SimdTypeDescr::Int8x16: return FillLanes< ::Int8x16>(cx, result, args);
case SimdTypeDescr::Int16x8: return FillLanes< ::Int16x8>(cx, result, args);
case SimdTypeDescr::Int32x4: return FillLanes< ::Int32x4>(cx, result, args);
case SimdTypeDescr::Float32x4: return FillLanes< ::Float32x4>(cx, result, args);
case SimdTypeDescr::Float64x2: return FillLanes< ::Float64x2>(cx, result, args);
@@ -455,6 +574,18 @@ SIMDObject::initClass(JSContext* cx, Handle<GlobalObject*> global)
if (!SIMD)
return nullptr;
RootedObject i8x16(cx);
i8x16 = CreateAndBindSimdClass<Int8x16Defn>(cx, global, SIMD, cx->names().int8x16);
if (!i8x16)
return nullptr;
global->setInt8x16TypeDescr(*i8x16);
RootedObject i16x8(cx);
i16x8 = CreateAndBindSimdClass<Int16x8Defn>(cx, global, SIMD, cx->names().int16x8);
if (!i16x8)
return nullptr;
global->setInt16x8TypeDescr(*i16x8);
RootedObject f32x4(cx);
f32x4 = CreateAndBindSimdClass<Float32x4Defn>(cx, global, SIMD, cx->names().float32x4);
if (!f32x4)
@@ -512,6 +643,8 @@ js::CreateSimd(JSContext* cx, const typename V::Elem* data)
template JSObject* js::CreateSimd<Float32x4>(JSContext* cx, const Float32x4::Elem* data);
template JSObject* js::CreateSimd<Float64x2>(JSContext* cx, const Float64x2::Elem* data);
template JSObject* js::CreateSimd<Int8x16>(JSContext* cx, const Int8x16::Elem* data);
template JSObject* js::CreateSimd<Int16x8>(JSContext* cx, const Int16x8::Elem* data);
template JSObject* js::CreateSimd<Int32x4>(JSContext* cx, const Int32x4::Elem* data);
namespace js {
@@ -538,7 +671,7 @@ struct RecApprox {
};
template<typename T>
struct RecSqrtApprox {
static T apply(T x) { return 1 / sqrt(x); }
static inline T apply(T x) { return 1 / sqrt(x); }
};
template<typename T>
struct Sqrt {
@@ -580,27 +713,27 @@ struct MaxNum {
};
template<typename T>
struct LessThan {
static int32_t apply(T l, T r) { return l < r ? 0xFFFFFFFF : 0x0; }
static bool apply(T l, T r) { return l < r; }
};
template<typename T>
struct LessThanOrEqual {
static int32_t apply(T l, T r) { return l <= r ? 0xFFFFFFFF : 0x0; }
static bool apply(T l, T r) { return l <= r; }
};
template<typename T>
struct GreaterThan {
static int32_t apply(T l, T r) { return l > r ? 0xFFFFFFFF : 0x0; }
static bool apply(T l, T r) { return l > r; }
};
template<typename T>
struct GreaterThanOrEqual {
static int32_t apply(T l, T r) { return l >= r ? 0xFFFFFFFF : 0x0; }
static bool apply(T l, T r) { return l >= r; }
};
template<typename T>
struct Equal {
static int32_t apply(T l, T r) { return l == r ? 0xFFFFFFFF : 0x0; }
static bool apply(T l, T r) { return l == r; }
};
template<typename T>
struct NotEqual {
static int32_t apply(T l, T r) { return l != r ? 0xFFFFFFFF : 0x0; }
static bool apply(T l, T r) { return l != r; }
};
template<typename T>
struct Xor {
@@ -614,38 +747,26 @@ template<typename T>
struct Or {
static T apply(T l, T r) { return l | r; }
};
template<typename T>
struct WithX {
static T apply(int32_t lane, T scalar, T x) { return lane == 0 ? scalar : x; }
};
template<typename T>
struct WithY {
static T apply(int32_t lane, T scalar, T x) { return lane == 1 ? scalar : x; }
};
template<typename T>
struct WithZ {
static T apply(int32_t lane, T scalar, T x) { return lane == 2 ? scalar : x; }
};
template<typename T>
struct WithW {
static T apply(int32_t lane, T scalar, T x) { return lane == 3 ? scalar : x; }
};
// For the following three operators, if the value v we're trying to shift is
// such that v << bits can't fit in the int32 range, then we have undefined
// behavior, according to C++11 [expr.shift]p2.
template<typename T>
struct ShiftLeft {
static int32_t apply(int32_t v, int32_t bits) {
return uint32_t(bits) >= 32 ? 0 : v << bits;
static T apply(T v, int32_t bits) {
return uint32_t(bits) >= sizeof(T) * 8 ? 0 : v << bits;
}
};
template<typename T>
struct ShiftRightArithmetic {
static int32_t apply(int32_t v, int32_t bits) {
return v >> (uint32_t(bits) >= 32 ? 31 : bits);
static T apply(T v, int32_t bits) {
uint32_t maxBits = sizeof(T) * 8;
return v >> (uint32_t(bits) >= maxBits ? maxBits - 1 : bits);
}
};
template<typename T>
struct ShiftRightLogical {
static int32_t apply(int32_t v, int32_t bits) {
return uint32_t(bits) >= 32 ? 0 : uint32_t(v) >> bits;
static T apply(T v, int32_t bits) {
return uint32_t(bits) >= sizeof(T) * 8 ? 0 : uint32_t(v) >> bits;
}
};
@@ -718,26 +839,54 @@ BinaryFunc(JSContext* cx, unsigned argc, Value* vp)
return CoercedBinaryFunc<In, Out, Op, Out>(cx, argc, vp);
}
template<typename V, template<typename T> class OpWith>
template<typename V>
static bool
FuncWith(JSContext* cx, unsigned argc, Value* vp)
ExtractLane(JSContext* cx, unsigned argc, Value* vp)
{
typedef typename V::Elem Elem;
CallArgs args = CallArgsFromVp(argc, vp);
// Only the first argument is mandatory
if (args.length() < 1 || !IsVectorObject<V>(args[0]))
if (args.length() < 2 || !IsVectorObject<V>(args[0]) || !args[1].isNumber())
return ErrorBadArgs(cx);
int32_t lane;
if (!NumberIsInt32(args[1].toNumber(), &lane))
return ErrorBadArgs(cx);
if (lane < 0 || uint32_t(lane) >= V::lanes)
return ErrorBadArgs(cx);
Elem* vec = TypedObjectMemory<Elem*>(args[0]);
V::setReturn(args, vec[lane]);
return true;
}
template<typename V>
static bool
ReplaceLane(JSContext* cx, unsigned argc, Value* vp)
{
typedef typename V::Elem Elem;
CallArgs args = CallArgsFromVp(argc, vp);
// Only the first and second arguments are mandatory
if (args.length() < 2 || !IsVectorObject<V>(args[0]))
return ErrorBadArgs(cx);
Elem* vec = TypedObjectMemory<Elem*>(args[0]);
Elem result[V::lanes];
if (!args[1].isInt32())
return ErrorBadArgs(cx);
int32_t lanearg = args[1].toInt32();
if (lanearg < 0 || uint32_t(lanearg) >= V::lanes)
return ErrorBadArgs(cx);
uint32_t lane = uint32_t(lanearg);
Elem value;
if (!V::toType(cx, args.get(1), &value))
if (!V::toType(cx, args.get(2), &value))
return false;
for (unsigned i = 0; i < V::lanes; i++)
result[i] = OpWith<Elem>::apply(i, value, vec[i]);
result[i] = i == lane ? value : vec[i];
return StoreResult<V>(cx, args, result);
}
@@ -802,47 +951,50 @@ Shuffle(JSContext* cx, unsigned argc, Value* vp)
return StoreResult<V>(cx, args, result);
}
template<typename Op>
template<typename V, template<typename T> class Op>
static bool
Int32x4BinaryScalar(JSContext* cx, unsigned argc, Value* vp)
BinaryScalar(JSContext* cx, unsigned argc, Value* vp)
{
typedef typename V::Elem Elem;
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 2)
return ErrorBadArgs(cx);
int32_t result[4];
if (!IsVectorObject<Int32x4>(args[0]))
Elem result[V::lanes];
if (!IsVectorObject<V>(args[0]))
return ErrorBadArgs(cx);
int32_t* val = TypedObjectMemory<int32_t*>(args[0]);
Elem* val = TypedObjectMemory<Elem*>(args[0]);
int32_t bits;
if (!ToInt32(cx, args[1], &bits))
return false;
for (unsigned i = 0; i < 4; i++)
result[i] = Op::apply(val[i], bits);
return StoreResult<Int32x4>(cx, args, result);
for (unsigned i = 0; i < V::lanes; i++)
result[i] = Op<Elem>::apply(val[i], bits);
return StoreResult<V>(cx, args, result);
}
template<typename In, template<typename C> class Op>
template<typename In, template<typename C> class Op, typename Out>
static bool
CompareFunc(JSContext* cx, unsigned argc, Value* vp)
{
typedef typename In::Elem InElem;
typedef typename Out::Elem OutElem;
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 2 || !IsVectorObject<In>(args[0]) || !IsVectorObject<In>(args[1]))
return ErrorBadArgs(cx);
int32_t result[Int32x4::lanes];
OutElem result[Out::lanes];
InElem* left = TypedObjectMemory<InElem*>(args[0]);
InElem* right = TypedObjectMemory<InElem*>(args[1]);
for (unsigned i = 0; i < Int32x4::lanes; i++) {
unsigned j = (i * In::lanes) / Int32x4::lanes;
result[i] = Op<InElem>::apply(left[j], right[j]);
for (unsigned i = 0; i < Out::lanes; i++) {
unsigned j = (i * In::lanes) / Out::lanes;
result[i] = Op<InElem>::apply(left[j], right[j]) ? -1 : 0;
}
return StoreResult<Int32x4>(cx, args, result);
return StoreResult<Out>(cx, args, result);
}
// This struct defines whether we should throw during a conversion attempt,
@@ -967,15 +1119,18 @@ FuncSplat(JSContext* cx, unsigned argc, Value* vp)
return StoreResult<Vret>(cx, args, result);
}
template<typename V>
static bool
Int32x4Bool(JSContext* cx, unsigned argc, Value* vp)
Bool(JSContext* cx, unsigned argc, Value* vp)
{
typedef typename V::Elem Elem;
CallArgs args = CallArgsFromVp(argc, vp);
int32_t result[Int32x4::lanes];
for (unsigned i = 0; i < Int32x4::lanes; i++)
Elem result[V::lanes];
for (unsigned i = 0; i < V::lanes; i++)
result[i] = ToBoolean(args.get(i)) ? -1 : 0;
return StoreResult<Int32x4>(cx, args, result);
return StoreResult<V>(cx, args, result);
}
template<typename In>
@@ -1003,53 +1158,55 @@ Clamp(JSContext* cx, unsigned argc, Value* vp)
return StoreResult<In>(cx, args, result);
}
template<typename V>
template<typename V, typename MaskType>
static bool
BitSelect(JSContext* cx, unsigned argc, Value* vp)
{
typedef typename V::Elem Elem;
typedef typename MaskType::Elem MaskTypeElem;
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 3 || !IsVectorObject<Int32x4>(args[0]) ||
if (args.length() != 3 || !IsVectorObject<MaskType>(args[0]) ||
!IsVectorObject<V>(args[1]) || !IsVectorObject<V>(args[2]))
{
return ErrorBadArgs(cx);
}
int32_t* val = TypedObjectMemory<int32_t*>(args[0]);
int32_t* tv = TypedObjectMemory<int32_t*>(args[1]);
int32_t* fv = TypedObjectMemory<int32_t*>(args[2]);
MaskTypeElem* val = TypedObjectMemory<MaskTypeElem*>(args[0]);
MaskTypeElem* tv = TypedObjectMemory<MaskTypeElem*>(args[1]);
MaskTypeElem* fv = TypedObjectMemory<MaskTypeElem*>(args[2]);
int32_t tr[Int32x4::lanes];
for (unsigned i = 0; i < Int32x4::lanes; i++)
tr[i] = And<int32_t>::apply(val[i], tv[i]);
MaskTypeElem tr[MaskType::lanes];
for (unsigned i = 0; i < MaskType::lanes; i++)
tr[i] = And<MaskTypeElem>::apply(val[i], tv[i]);
int32_t fr[Int32x4::lanes];
for (unsigned i = 0; i < Int32x4::lanes; i++)
fr[i] = And<int32_t>::apply(Not<int32_t>::apply(val[i]), fv[i]);
MaskTypeElem fr[MaskType::lanes];
for (unsigned i = 0; i < MaskType::lanes; i++)
fr[i] = And<MaskTypeElem>::apply(Not<MaskTypeElem>::apply(val[i]), fv[i]);
int32_t orInt[Int32x4::lanes];
for (unsigned i = 0; i < Int32x4::lanes; i++)
orInt[i] = Or<int32_t>::apply(tr[i], fr[i]);
MaskTypeElem orInt[MaskType::lanes];
for (unsigned i = 0; i < MaskType::lanes; i++)
orInt[i] = Or<MaskTypeElem>::apply(tr[i], fr[i]);
Elem* result = reinterpret_cast<Elem*>(orInt);
return StoreResult<V>(cx, args, result);
}
template<typename V>
template<typename V, typename MaskType>
static bool
Select(JSContext* cx, unsigned argc, Value* vp)
{
typedef typename V::Elem Elem;
typedef typename MaskType::Elem MaskTypeElem;
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 3 || !IsVectorObject<Int32x4>(args[0]) ||
if (args.length() != 3 || !IsVectorObject<MaskType>(args[0]) ||
!IsVectorObject<V>(args[1]) || !IsVectorObject<V>(args[2]))
{
return ErrorBadArgs(cx);
}
int32_t* mask = TypedObjectMemory<int32_t*>(args[0]);
MaskTypeElem* mask = TypedObjectMemory<MaskTypeElem*>(args[0]);
Elem* tv = TypedObjectMemory<Elem*>(args[1]);
Elem* fv = TypedObjectMemory<Elem*>(args[2]);
@@ -1163,6 +1320,24 @@ js::simd_float64x2_##Name(JSContext* cx, unsigned argc, Value* vp) \
FLOAT64X2_FUNCTION_LIST(DEFINE_SIMD_FLOAT64X2_FUNCTION)
#undef DEFINE_SIMD_FLOAT64X2_FUNCTION
#define DEFINE_SIMD_INT8X16_FUNCTION(Name, Func, Operands) \
bool \
js::simd_int8x16_##Name(JSContext* cx, unsigned argc, Value* vp) \
{ \
return Func(cx, argc, vp); \
}
INT8X16_FUNCTION_LIST(DEFINE_SIMD_INT8X16_FUNCTION)
#undef DEFINE_SIMD_INT8X16_FUNCTION
#define DEFINE_SIMD_INT16X8_FUNCTION(Name, Func, Operands) \
bool \
js::simd_int16x8_##Name(JSContext* cx, unsigned argc, Value* vp) \
{ \
return Func(cx, argc, vp); \
}
INT16X8_FUNCTION_LIST(DEFINE_SIMD_INT16X8_FUNCTION)
#undef DEFINE_SIMD_INT16X8_FUNCTION
#define DEFINE_SIMD_INT32X4_FUNCTION(Name, Func, Operands) \
bool \
js::simd_int32x4_##Name(JSContext* cx, unsigned argc, Value* vp) \
@@ -1171,4 +1346,3 @@ js::simd_int32x4_##Name(JSContext* cx, unsigned argc, Value* vp) \
}
INT32X4_FUNCTION_LIST(DEFINE_SIMD_INT32X4_FUNCTION)
#undef DEFINE_SIMD_INT32X4_FUNCTION
+207 -61
View File
@@ -25,6 +25,8 @@
V(check, (UnaryFunc<Float32x4, Identity, Float32x4>), 1) \
V(fromFloat64x2, (FuncConvert<Float64x2, Float32x4> ), 1) \
V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Float32x4>), 1) \
V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Float32x4>), 1) \
V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Float32x4>), 1) \
V(fromInt32x4, (FuncConvert<Int32x4, Float32x4> ), 1) \
V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Float32x4>), 1) \
V(neg, (UnaryFunc<Float32x4, Neg, Float32x4>), 1) \
@@ -38,11 +40,12 @@
V(add, (BinaryFunc<Float32x4, Add, Float32x4>), 2) \
V(and, (CoercedBinaryFunc<Float32x4, Int32x4, And, Float32x4>), 2) \
V(div, (BinaryFunc<Float32x4, Div, Float32x4>), 2) \
V(equal, (CompareFunc<Float32x4, Equal>), 2) \
V(greaterThan, (CompareFunc<Float32x4, GreaterThan>), 2) \
V(greaterThanOrEqual, (CompareFunc<Float32x4, GreaterThanOrEqual>), 2) \
V(lessThan, (CompareFunc<Float32x4, LessThan>), 2) \
V(lessThanOrEqual, (CompareFunc<Float32x4, LessThanOrEqual>), 2) \
V(equal, (CompareFunc<Float32x4, Equal, Int32x4>), 2) \
V(extractLane, (ExtractLane<Float32x4>), 2) \
V(greaterThan, (CompareFunc<Float32x4, GreaterThan, Int32x4>), 2) \
V(greaterThanOrEqual, (CompareFunc<Float32x4, GreaterThanOrEqual, Int32x4>), 2) \
V(lessThan, (CompareFunc<Float32x4, LessThan, Int32x4>), 2) \
V(lessThanOrEqual, (CompareFunc<Float32x4, LessThanOrEqual, Int32x4>), 2) \
V(load, (Load<Float32x4, 4>), 2) \
V(load3, (Load<Float32x4, 3>), 2) \
V(load2, (Load<Float32x4, 2>), 2) \
@@ -52,27 +55,24 @@
V(min, (BinaryFunc<Float32x4, Minimum, Float32x4>), 2) \
V(minNum, (BinaryFunc<Float32x4, MinNum, Float32x4>), 2) \
V(mul, (BinaryFunc<Float32x4, Mul, Float32x4>), 2) \
V(notEqual, (CompareFunc<Float32x4, NotEqual>), 2) \
V(notEqual, (CompareFunc<Float32x4, NotEqual, Int32x4>), 2) \
V(or, (CoercedBinaryFunc<Float32x4, Int32x4, Or, Float32x4>), 2) \
V(store, (Store<Float32x4, 4>), 3) \
V(store3, (Store<Float32x4, 3>), 3) \
V(store2, (Store<Float32x4, 2>), 3) \
V(store1, (Store<Float32x4, 1>), 3) \
V(sub, (BinaryFunc<Float32x4, Sub, Float32x4>), 2) \
V(withX, (FuncWith<Float32x4, WithX>), 2) \
V(withY, (FuncWith<Float32x4, WithY>), 2) \
V(withZ, (FuncWith<Float32x4, WithZ>), 2) \
V(withW, (FuncWith<Float32x4, WithW>), 2) \
V(xor, (CoercedBinaryFunc<Float32x4, Int32x4, Xor, Float32x4>), 2)
#define FLOAT32X4_TERNARY_FUNCTION_LIST(V) \
V(bitselect, BitSelect<Float32x4>, 3) \
V(bitselect, (BitSelect<Float32x4, Int32x4>), 3) \
V(clamp, Clamp<Float32x4>, 3) \
V(select, Select<Float32x4>, 3)
V(replaceLane, (ReplaceLane<Float32x4>), 3) \
V(select, (Select<Float32x4, Int32x4>), 3) \
V(store, (Store<Float32x4, 4>), 3) \
V(store3, (Store<Float32x4, 3>), 3) \
V(store2, (Store<Float32x4, 2>), 3) \
V(store1, (Store<Float32x4, 1>), 3)
#define FLOAT32X4_SHUFFLE_FUNCTION_LIST(V) \
V(swizzle, Swizzle<Float32x4>, 2) \
V(shuffle, Shuffle<Float32x4>, 3)
V(swizzle, Swizzle<Float32x4>, 5) \
V(shuffle, Shuffle<Float32x4>, 6)
#define FLOAT32X4_FUNCTION_LIST(V) \
FLOAT32X4_UNARY_FUNCTION_LIST(V) \
@@ -85,6 +85,8 @@
V(check, (UnaryFunc<Float64x2, Identity, Float64x2>), 1) \
V(fromFloat32x4, (FuncConvert<Float32x4, Float64x2> ), 1) \
V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Float64x2>), 1) \
V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Float64x2>), 1) \
V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Float64x2>), 1) \
V(fromInt32x4, (FuncConvert<Int32x4, Float64x2> ), 1) \
V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Float64x2>), 1) \
V(neg, (UnaryFunc<Float64x2, Neg, Float64x2>), 1) \
@@ -96,11 +98,12 @@
#define FLOAT64X2_BINARY_FUNCTION_LIST(V) \
V(add, (BinaryFunc<Float64x2, Add, Float64x2>), 2) \
V(div, (BinaryFunc<Float64x2, Div, Float64x2>), 2) \
V(equal, (CompareFunc<Float64x2, Equal>), 2) \
V(greaterThan, (CompareFunc<Float64x2, GreaterThan>), 2) \
V(greaterThanOrEqual, (CompareFunc<Float64x2, GreaterThanOrEqual>), 2) \
V(lessThan, (CompareFunc<Float64x2, LessThan>), 2) \
V(lessThanOrEqual, (CompareFunc<Float64x2, LessThanOrEqual>), 2) \
V(equal, (CompareFunc<Float64x2, Equal, Int32x4>), 2) \
V(extractLane, (ExtractLane<Float64x2>), 2) \
V(greaterThan, (CompareFunc<Float64x2, GreaterThan, Int32x4>), 2) \
V(greaterThanOrEqual, (CompareFunc<Float64x2, GreaterThanOrEqual, Int32x4>), 2) \
V(lessThan, (CompareFunc<Float64x2, LessThan, Int32x4>), 2) \
V(lessThanOrEqual, (CompareFunc<Float64x2, LessThanOrEqual, Int32x4>), 2) \
V(load, (Load<Float64x2, 2>), 2) \
V(load1, (Load<Float64x2, 1>), 2) \
V(max, (BinaryFunc<Float64x2, Maximum, Float64x2>), 2) \
@@ -108,21 +111,20 @@
V(min, (BinaryFunc<Float64x2, Minimum, Float64x2>), 2) \
V(minNum, (BinaryFunc<Float64x2, MinNum, Float64x2>), 2) \
V(mul, (BinaryFunc<Float64x2, Mul, Float64x2>), 2) \
V(notEqual, (CompareFunc<Float64x2, NotEqual>), 2) \
V(store, (Store<Float64x2, 2>), 3) \
V(store1, (Store<Float64x2, 1>), 3) \
V(sub, (BinaryFunc<Float64x2, Sub, Float64x2>), 2) \
V(withX, (FuncWith<Float64x2, WithX>), 2) \
V(withY, (FuncWith<Float64x2, WithY>), 2)
V(notEqual, (CompareFunc<Float64x2, NotEqual, Int32x4>), 2) \
V(sub, (BinaryFunc<Float64x2, Sub, Float64x2>), 2)
#define FLOAT64X2_TERNARY_FUNCTION_LIST(V) \
V(bitselect, BitSelect<Float64x2>, 3) \
V(bitselect, (BitSelect<Float64x2, Int32x4>), 3) \
V(clamp, Clamp<Float64x2>, 3) \
V(select, Select<Float64x2>, 3)
V(replaceLane, (ReplaceLane<Float64x2>), 3) \
V(select, (Select<Float64x2, Int32x4>), 3) \
V(store, (Store<Float64x2, 2>), 3) \
V(store1, (Store<Float64x2, 1>), 3)
#define FLOAT64X2_SHUFFLE_FUNCTION_LIST(V) \
V(swizzle, Swizzle<Float64x2>, 2) \
V(shuffle, Shuffle<Float64x2>, 3)
V(swizzle, Swizzle<Float64x2>, 3) \
V(shuffle, Shuffle<Float64x2>, 4)
#define FLOAT64X2_FUNCTION_LIST(V) \
FLOAT64X2_UNARY_FUNCTION_LIST(V) \
@@ -130,12 +132,112 @@
FLOAT64X2_TERNARY_FUNCTION_LIST(V) \
FLOAT64X2_SHUFFLE_FUNCTION_LIST(V)
#define INT8X16_UNARY_FUNCTION_LIST(V) \
V(check, (UnaryFunc<Int8x16, Identity, Int8x16>), 1) \
V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int8x16>), 1) \
V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int8x16>), 1) \
V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Int8x16>), 1) \
V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Int8x16>), 1) \
V(neg, (UnaryFunc<Int8x16, Neg, Int8x16>), 1) \
V(not, (UnaryFunc<Int8x16, Not, Int8x16>), 1) \
V(splat, (FuncSplat<Int8x16>), 1)
#define INT8X16_BINARY_FUNCTION_LIST(V) \
V(add, (BinaryFunc<Int8x16, Add, Int8x16>), 2) \
V(and, (BinaryFunc<Int8x16, And, Int8x16>), 2) \
V(equal, (CompareFunc<Int8x16, Equal, Int8x16>), 2) \
V(extractLane, (ExtractLane<Int8x16>), 2) \
V(greaterThan, (CompareFunc<Int8x16, GreaterThan, Int8x16>), 2) \
V(greaterThanOrEqual, (CompareFunc<Int8x16, GreaterThanOrEqual, Int8x16>), 2) \
V(lessThan, (CompareFunc<Int8x16, LessThan, Int8x16>), 2) \
V(lessThanOrEqual, (CompareFunc<Int8x16, LessThanOrEqual, Int8x16>), 2) \
V(load, (Load<Int8x16, 16>), 2) \
V(mul, (BinaryFunc<Int8x16, Mul, Int8x16>), 2) \
V(notEqual, (CompareFunc<Int8x16, NotEqual, Int8x16>), 2) \
V(or, (BinaryFunc<Int8x16, Or, Int8x16>), 2) \
V(sub, (BinaryFunc<Int8x16, Sub, Int8x16>), 2) \
V(shiftLeftByScalar, (BinaryScalar<Int8x16, ShiftLeft>), 2) \
V(shiftRightArithmeticByScalar, (BinaryScalar<Int8x16, ShiftRightArithmetic>), 2) \
V(shiftRightLogicalByScalar, (BinaryScalar<Int8x16, ShiftRightLogical>), 2) \
V(xor, (BinaryFunc<Int8x16, Xor, Int8x16>), 2)
#define INT8X16_TERNARY_FUNCTION_LIST(V) \
V(bitselect, (BitSelect<Int8x16, Int8x16>), 3) \
V(replaceLane, (ReplaceLane<Int8x16>), 3) \
V(select, (Select<Int8x16, Int8x16>), 3) \
V(store, (Store<Int8x16, 16>), 3)
#define INT8X16_BOOL_FUNCTION_LIST(V) \
V(bool, Bool<Int8x16>, 16)
#define INT8X16_SHUFFLE_FUNCTION_LIST(V) \
V(swizzle, Swizzle<Int8x16>, 17) \
V(shuffle, Shuffle<Int8x16>, 18)
#define INT8X16_FUNCTION_LIST(V) \
INT8X16_UNARY_FUNCTION_LIST(V) \
INT8X16_BINARY_FUNCTION_LIST(V) \
INT8X16_TERNARY_FUNCTION_LIST(V) \
INT8X16_BOOL_FUNCTION_LIST(V) \
INT8X16_SHUFFLE_FUNCTION_LIST(V)
#define INT16X8_UNARY_FUNCTION_LIST(V) \
V(check, (UnaryFunc<Int16x8, Identity, Int16x8>), 1) \
V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int16x8>), 1) \
V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int16x8>), 1) \
V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Int16x8>), 1) \
V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Int16x8>), 1) \
V(neg, (UnaryFunc<Int16x8, Neg, Int16x8>), 1) \
V(not, (UnaryFunc<Int16x8, Not, Int16x8>), 1) \
V(splat, (FuncSplat<Int16x8>), 1)
#define INT16X8_BINARY_FUNCTION_LIST(V) \
V(add, (BinaryFunc<Int16x8, Add, Int16x8>), 2) \
V(and, (BinaryFunc<Int16x8, And, Int16x8>), 2) \
V(equal, (CompareFunc<Int16x8, Equal, Int16x8>), 2) \
V(extractLane, (ExtractLane<Int16x8>), 2) \
V(greaterThan, (CompareFunc<Int16x8, GreaterThan, Int16x8>), 2) \
V(greaterThanOrEqual, (CompareFunc<Int16x8, GreaterThanOrEqual, Int16x8>), 2) \
V(lessThan, (CompareFunc<Int16x8, LessThan, Int16x8>), 2) \
V(lessThanOrEqual, (CompareFunc<Int16x8, LessThanOrEqual, Int16x8>), 2) \
V(load, (Load<Int16x8, 8>), 2) \
V(mul, (BinaryFunc<Int16x8, Mul, Int16x8>), 2) \
V(notEqual, (CompareFunc<Int16x8, NotEqual, Int16x8>), 2) \
V(or, (BinaryFunc<Int16x8, Or, Int16x8>), 2) \
V(sub, (BinaryFunc<Int16x8, Sub, Int16x8>), 2) \
V(shiftLeftByScalar, (BinaryScalar<Int16x8, ShiftLeft>), 2) \
V(shiftRightArithmeticByScalar, (BinaryScalar<Int16x8, ShiftRightArithmetic>), 2) \
V(shiftRightLogicalByScalar, (BinaryScalar<Int16x8, ShiftRightLogical>), 2) \
V(xor, (BinaryFunc<Int16x8, Xor, Int16x8>), 2)
#define INT16X8_TERNARY_FUNCTION_LIST(V) \
V(bitselect, (BitSelect<Int16x8, Int16x8>), 3) \
V(replaceLane, (ReplaceLane<Int16x8>), 3) \
V(select, (Select<Int16x8, Int16x8>), 3) \
V(store, (Store<Int16x8, 8>), 3)
#define INT16X8_BOOL_FUNCTION_LIST(V) \
V(bool, Bool<Int16x8>, 8)
#define INT16X8_SHUFFLE_FUNCTION_LIST(V) \
V(swizzle, Swizzle<Int16x8>, 9) \
V(shuffle, Shuffle<Int16x8>, 10)
#define INT16X8_FUNCTION_LIST(V) \
INT16X8_UNARY_FUNCTION_LIST(V) \
INT16X8_BINARY_FUNCTION_LIST(V) \
INT16X8_TERNARY_FUNCTION_LIST(V) \
INT16X8_BOOL_FUNCTION_LIST(V) \
INT16X8_SHUFFLE_FUNCTION_LIST(V)
#define INT32X4_UNARY_FUNCTION_LIST(V) \
V(check, (UnaryFunc<Int32x4, Identity, Int32x4>), 1) \
V(fromFloat32x4, (FuncConvert<Float32x4, Int32x4>), 1) \
V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int32x4>), 1) \
V(fromFloat64x2, (FuncConvert<Float64x2, Int32x4>), 1) \
V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int32x4>), 1) \
V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Int32x4>), 1) \
V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Int32x4>), 1) \
V(neg, (UnaryFunc<Int32x4, Neg, Int32x4>), 1) \
V(not, (UnaryFunc<Int32x4, Not, Int32x4>), 1) \
V(splat, (FuncSplat<Int32x4>), 0)
@@ -143,42 +245,40 @@
#define INT32X4_BINARY_FUNCTION_LIST(V) \
V(add, (BinaryFunc<Int32x4, Add, Int32x4>), 2) \
V(and, (BinaryFunc<Int32x4, And, Int32x4>), 2) \
V(equal, (CompareFunc<Int32x4, Equal>), 2) \
V(greaterThan, (CompareFunc<Int32x4, GreaterThan>), 2) \
V(greaterThanOrEqual, (CompareFunc<Int32x4, GreaterThanOrEqual>), 2) \
V(lessThan, (CompareFunc<Int32x4, LessThan>), 2) \
V(lessThanOrEqual, (CompareFunc<Int32x4, LessThanOrEqual>), 2) \
V(equal, (CompareFunc<Int32x4, Equal, Int32x4>), 2) \
V(extractLane, (ExtractLane<Int32x4>), 2) \
V(greaterThan, (CompareFunc<Int32x4, GreaterThan, Int32x4>), 2) \
V(greaterThanOrEqual, (CompareFunc<Int32x4, GreaterThanOrEqual, Int32x4>), 2) \
V(lessThan, (CompareFunc<Int32x4, LessThan, Int32x4>), 2) \
V(lessThanOrEqual, (CompareFunc<Int32x4, LessThanOrEqual, Int32x4>), 2) \
V(load, (Load<Int32x4, 4>), 2) \
V(load3, (Load<Int32x4, 3>), 2) \
V(load2, (Load<Int32x4, 2>), 2) \
V(load1, (Load<Int32x4, 1>), 2) \
V(mul, (BinaryFunc<Int32x4, Mul, Int32x4>), 2) \
V(notEqual, (CompareFunc<Int32x4, NotEqual>), 2) \
V(notEqual, (CompareFunc<Int32x4, NotEqual, Int32x4>), 2) \
V(or, (BinaryFunc<Int32x4, Or, Int32x4>), 2) \
V(sub, (BinaryFunc<Int32x4, Sub, Int32x4>), 2) \
V(shiftLeftByScalar, (Int32x4BinaryScalar<ShiftLeft>), 2) \
V(shiftRightArithmeticByScalar, (Int32x4BinaryScalar<ShiftRightArithmetic>), 2) \
V(shiftRightLogicalByScalar, (Int32x4BinaryScalar<ShiftRightLogical>), 2) \
V(store, (Store<Int32x4, 4>), 3) \
V(store3, (Store<Int32x4, 3>), 3) \
V(store2, (Store<Int32x4, 2>), 3) \
V(store1, (Store<Int32x4, 1>), 3) \
V(withX, (FuncWith<Int32x4, WithX>), 2) \
V(withY, (FuncWith<Int32x4, WithY>), 2) \
V(withZ, (FuncWith<Int32x4, WithZ>), 2) \
V(withW, (FuncWith<Int32x4, WithW>), 2) \
V(shiftLeftByScalar, (BinaryScalar<Int32x4, ShiftLeft>), 2) \
V(shiftRightArithmeticByScalar, (BinaryScalar<Int32x4, ShiftRightArithmetic>), 2) \
V(shiftRightLogicalByScalar, (BinaryScalar<Int32x4, ShiftRightLogical>), 2) \
V(xor, (BinaryFunc<Int32x4, Xor, Int32x4>), 2)
#define INT32X4_TERNARY_FUNCTION_LIST(V) \
V(bitselect, BitSelect<Int32x4>, 3) \
V(select, Select<Int32x4>, 3)
V(bitselect, (BitSelect<Int32x4, Int32x4>), 3) \
V(replaceLane, (ReplaceLane<Int32x4>), 3) \
V(select, (Select<Int32x4, Int32x4>), 3) \
V(store, (Store<Int32x4, 4>), 3) \
V(store3, (Store<Int32x4, 3>), 3) \
V(store2, (Store<Int32x4, 2>), 3) \
V(store1, (Store<Int32x4, 1>), 3)
#define INT32X4_QUARTERNARY_FUNCTION_LIST(V) \
V(bool, Int32x4Bool, 4)
V(bool, Bool<Int32x4>, 4)
#define INT32X4_SHUFFLE_FUNCTION_LIST(V) \
V(swizzle, Swizzle<Int32x4>, 2) \
V(shuffle, Shuffle<Int32x4>, 3)
V(swizzle, Swizzle<Int32x4>, 5) \
V(shuffle, Shuffle<Int32x4>, 6)
#define INT32X4_FUNCTION_LIST(V) \
INT32X4_UNARY_FUNCTION_LIST(V) \
@@ -226,16 +326,12 @@
_(notEqual) \
_(greaterThan) \
_(greaterThanOrEqual)
#define WITH_COMMONX4_SIMD_OP(_) \
_(withX) \
_(withY) \
_(withZ) \
_(withW)
// TODO: remove when all SIMD calls are inlined (bug 1112155)
#define ION_COMMONX4_SIMD_OP(_) \
ARITH_COMMONX4_SIMD_OP(_) \
BITWISE_COMMONX4_SIMD_OP(_) \
WITH_COMMONX4_SIMD_OP(_) \
_(extractLane) \
_(replaceLane) \
_(bitselect) \
_(select) \
_(splat) \
@@ -316,6 +412,44 @@ struct Float64x2 {
}
};
struct Int8x16 {
typedef int8_t Elem;
static const unsigned lanes = 16;
static const SimdTypeDescr::Type type = SimdTypeDescr::Int8x16;
static TypeDescr& GetTypeDescr(GlobalObject& global) {
return global.int8x16TypeDescr().as<TypeDescr>();
}
static Elem toType(Elem a) {
return JS::ToInt8(a);
}
static bool toType(JSContext* cx, JS::HandleValue v, Elem* out) {
return ToInt8(cx, v, out);
}
static void setReturn(CallArgs& args, Elem value) {
args.rval().setInt32(value);
}
};
struct Int16x8 {
typedef int16_t Elem;
static const unsigned lanes = 8;
static const SimdTypeDescr::Type type = SimdTypeDescr::Int16x8;
static TypeDescr& GetTypeDescr(GlobalObject& global) {
return global.int16x8TypeDescr().as<TypeDescr>();
}
static Elem toType(Elem a) {
return JS::ToInt16(a);
}
static bool toType(JSContext* cx, JS::HandleValue v, Elem* out) {
return ToInt16(cx, v, out);
}
static void setReturn(CallArgs& args, Elem value) {
args.rval().setInt32(value);
}
};
struct Int32x4 {
typedef int32_t Elem;
static const unsigned lanes = 4;
@@ -356,6 +490,18 @@ simd_float64x2_##Name(JSContext* cx, unsigned argc, Value* vp);
FLOAT64X2_FUNCTION_LIST(DECLARE_SIMD_FLOAT64X2_FUNCTION)
#undef DECLARE_SIMD_FLOAT64X2_FUNCTION
#define DECLARE_SIMD_INT8X16_FUNCTION(Name, Func, Operands) \
extern bool \
simd_int8x16_##Name(JSContext* cx, unsigned argc, Value* vp);
INT8X16_FUNCTION_LIST(DECLARE_SIMD_INT8X16_FUNCTION)
#undef DECLARE_SIMD_INT8X16_FUNCTION
#define DECLARE_SIMD_INT16X8_FUNCTION(Name, Func, Operands) \
extern bool \
simd_int16x8_##Name(JSContext* cx, unsigned argc, Value* vp);
INT16X8_FUNCTION_LIST(DECLARE_SIMD_INT16X8_FUNCTION)
#undef DECLARE_SIMD_INT16X8_FUNCTION
#define DECLARE_SIMD_INT32x4_FUNCTION(Name, Func, Operands) \
extern bool \
simd_int32x4_##Name(JSContext* cx, unsigned argc, Value* vp);
+20 -20
View File
@@ -7,7 +7,7 @@
/* ES6 Draft Oct 14, 2014 21.1.3.19 */
function String_substring(start, end) {
// Steps 1-3.
CheckObjectCoercible(this);
RequireObjectCoercible(this);
var str = ToString(this);
// Step 4.
@@ -51,7 +51,7 @@ function String_static_substring(string, start, end) {
/* ES6 Draft Oct 14, 2014 B.2.3.1 */
function String_substr(start, length) {
// Steps 1-2.
CheckObjectCoercible(this);
RequireObjectCoercible(this);
var str = ToString(this);
// Steps 3-4.
@@ -90,7 +90,7 @@ function String_static_substr(string, start, length) {
/* ES6 Draft Oct 14, 2014 21.1.3.16 */
function String_slice(start, end) {
// Steps 1-3.
CheckObjectCoercible(this);
RequireObjectCoercible(this);
var str = ToString(this);
// Step 4.
@@ -127,7 +127,7 @@ function String_static_slice(string, start, end) {
/* ES6 Draft September 5, 2013 21.1.3.3 */
function String_codePointAt(pos) {
// Steps 1-3.
CheckObjectCoercible(this);
RequireObjectCoercible(this);
var S = ToString(this);
// Steps 4-5.
@@ -159,7 +159,7 @@ var collatorCache = new Record();
/* ES6 20121122 draft 15.5.4.21. */
function String_repeat(count) {
// Steps 1-3.
CheckObjectCoercible(this);
RequireObjectCoercible(this);
var S = ToString(this);
// Steps 4-5.
@@ -194,7 +194,7 @@ function String_repeat(count) {
// ES6 draft specification, section 21.1.3.27, version 2013-09-27.
function String_iterator() {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
var S = ToString(this);
var iterator = NewStringIterator();
UnsafeSetReservedSlot(iterator, STRING_ITERATOR_SLOT_ITERATED_STRING, S);
@@ -244,7 +244,7 @@ function StringIteratorNext() {
*/
function String_localeCompare(that) {
// Steps 1-3.
CheckObjectCoercible(this);
RequireObjectCoercible(this);
var S = ToString(this);
var That = ToString(that);
@@ -377,55 +377,55 @@ function String_static_localeCompare(str1, str2) {
// ES6 draft 2014-04-27 B.2.3.3
function String_big() {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
return "<big>" + ToString(this) + "</big>";
}
// ES6 draft 2014-04-27 B.2.3.4
function String_blink() {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
return "<blink>" + ToString(this) + "</blink>";
}
// ES6 draft 2014-04-27 B.2.3.5
function String_bold() {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
return "<b>" + ToString(this) + "</b>";
}
// ES6 draft 2014-04-27 B.2.3.6
function String_fixed() {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
return "<tt>" + ToString(this) + "</tt>";
}
// ES6 draft 2014-04-27 B.2.3.9
function String_italics() {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
return "<i>" + ToString(this) + "</i>";
}
// ES6 draft 2014-04-27 B.2.3.11
function String_small() {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
return "<small>" + ToString(this) + "</small>";
}
// ES6 draft 2014-04-27 B.2.3.12
function String_strike() {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
return "<strike>" + ToString(this) + "</strike>";
}
// ES6 draft 2014-04-27 B.2.3.13
function String_sub() {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
return "<sub>" + ToString(this) + "</sub>";
}
// ES6 draft 2014-04-27 B.2.3.14
function String_sup() {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
return "<sup>" + ToString(this) + "</sup>";
}
@@ -449,28 +449,28 @@ function EscapeAttributeValue(v) {
// ES6 draft 2014-04-27 B.2.3.2
function String_anchor(name) {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
var S = ToString(this);
return '<a name="' + EscapeAttributeValue(name) + '">' + S + "</a>";
}
// ES6 draft 2014-04-27 B.2.3.7
function String_fontcolor(color) {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
var S = ToString(this);
return '<font color="' + EscapeAttributeValue(color) + '">' + S + "</font>";
}
// ES6 draft 2014-04-27 B.2.3.8
function String_fontsize(size) {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
var S = ToString(this);
return '<font size="' + EscapeAttributeValue(size) + '">' + S + "</font>";
}
// ES6 draft 2014-04-27 B.2.3.10
function String_link(url) {
CheckObjectCoercible(this);
RequireObjectCoercible(this);
var S = ToString(this);
return '<a href="' + EscapeAttributeValue(url) + '">' + S + "</a>";
}
+21
View File
@@ -2551,6 +2551,20 @@ GetConstructorName(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
AllocationMarker(JSContext* cx, unsigned argc, jsval* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
static const JSClass cls = { "AllocationMarker" };
RootedObject obj(cx, JS_NewObject(cx, &cls));
if (!obj)
return false;
args.rval().setObject(*obj);
return true;
}
static const JSFunctionSpecWithHelp TestingFunctions[] = {
JS_FN_HELP("gc", ::GC, 0, 0,
"gc([obj] | 'compartment' [, 'shrinking'])",
@@ -2948,6 +2962,13 @@ gc::ZealModeHelpText),
" If the given object was created with `new Ctor`, return the constructor's display name. "
" Otherwise, return null."),
JS_FN_HELP("allocationMarker", AllocationMarker, 0, 0,
"allocationMarker()",
" Return a freshly allocated object whose [[Class]] name is\n"
" \"AllocationMarker\". Such objects are allocated only by calls\n"
" to this function, never implicitly by the system, making them\n"
" suitable for use in allocation tooling tests.\n"),
JS_FS_HELP_END
};
+20
View File
@@ -2620,6 +2620,26 @@ js::GetFloat64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp)
return true;
}
bool
js::GetInt8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(global->int8x16TypeDescr());
return true;
}
bool
js::GetInt16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(global->int16x8TypeDescr());
return true;
}
bool
js::GetInt32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
{
+21 -1
View File
@@ -328,12 +328,14 @@ class ComplexTypeDescr : public TypeDescr
};
/*
* Type descriptors `float32x4`, `int32x4` and `float64x2`
* Type descriptors `int8x16`, `int16x8`, `int32x4`, `float32x4` and `float64x2`
*/
class SimdTypeDescr : public ComplexTypeDescr
{
public:
enum Type {
Int8x16 = JS_SIMDTYPEREPR_INT8,
Int16x8 = JS_SIMDTYPEREPR_INT16,
Int32x4 = JS_SIMDTYPEREPR_INT32,
Float32x4 = JS_SIMDTYPEREPR_FLOAT32,
Float64x2 = JS_SIMDTYPEREPR_FLOAT64,
@@ -356,6 +358,8 @@ class SimdTypeDescr : public ComplexTypeDescr
};
#define JS_FOR_EACH_SIMD_TYPE_REPR(macro_) \
macro_(SimdTypeDescr::Int8x16, int8_t, int8, 16) \
macro_(SimdTypeDescr::Int16x8, int16_t, int16, 8) \
macro_(SimdTypeDescr::Int32x4, int32_t, int32, 4) \
macro_(SimdTypeDescr::Float32x4, float, float32, 4) \
macro_(SimdTypeDescr::Float64x2, double, float64, 2)
@@ -863,6 +867,22 @@ bool GetFloat32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp);
*/
bool GetFloat64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp);
/*
* Usage: GetInt8x16TypeDescr()
*
* Returns the int8x16 type object. SIMD pseudo-module must have
* been initialized for this to be safe.
*/
bool GetInt8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp);
/*
* Usage: GetInt16x8TypeDescr()
*
* Returns the int16x8 type object. SIMD pseudo-module must have
* been initialized for this to be safe.
*/
bool GetInt16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp);
/*
* Usage: GetInt32x4TypeDescr()
*
+128 -14
View File
@@ -157,6 +157,37 @@ function TypedObjectGetSimd(descr, typedObj, offset) {
var y = Load_float64(typedObj, offset + 8);
return GetFloat64x2TypeDescr()(x, y);
case JS_SIMDTYPEREPR_INT8:
var s0 = Load_int8(typedObj, offset + 0);
var s1 = Load_int8(typedObj, offset + 1);
var s2 = Load_int8(typedObj, offset + 2);
var s3 = Load_int8(typedObj, offset + 3);
var s4 = Load_int8(typedObj, offset + 4);
var s5 = Load_int8(typedObj, offset + 5);
var s6 = Load_int8(typedObj, offset + 6);
var s7 = Load_int8(typedObj, offset + 7);
var s8 = Load_int8(typedObj, offset + 8);
var s9 = Load_int8(typedObj, offset + 9);
var s10 = Load_int8(typedObj, offset + 10);
var s11 = Load_int8(typedObj, offset + 11);
var s12 = Load_int8(typedObj, offset + 12);
var s13 = Load_int8(typedObj, offset + 13);
var s14 = Load_int8(typedObj, offset + 14);
var s15 = Load_int8(typedObj, offset + 15);
return GetInt8x16TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7,
s8, s9, s10, s11, s12, s13, s14, s15);
case JS_SIMDTYPEREPR_INT16:
var s0 = Load_int16(typedObj, offset + 0);
var s1 = Load_int16(typedObj, offset + 2);
var s2 = Load_int16(typedObj, offset + 4);
var s3 = Load_int16(typedObj, offset + 6);
var s4 = Load_int16(typedObj, offset + 8);
var s5 = Load_int16(typedObj, offset + 10);
var s6 = Load_int16(typedObj, offset + 12);
var s7 = Load_int16(typedObj, offset + 14);
return GetInt16x8TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7);
case JS_SIMDTYPEREPR_INT32:
var x = Load_int32(typedObj, offset + 0);
var y = Load_int32(typedObj, offset + 4);
@@ -252,11 +283,11 @@ function TypedObjectSetScalar(descr, typedObj, offset, fromValue) {
switch (type) {
case JS_SCALARTYPEREPR_INT8:
return Store_int8(typedObj, offset,
TO_INT32(fromValue) & 0xFF);
TO_INT32(fromValue) & 0xFF);
case JS_SCALARTYPEREPR_UINT8:
return Store_uint8(typedObj, offset,
TO_UINT32(fromValue) & 0xFF);
TO_UINT32(fromValue) & 0xFF);
case JS_SCALARTYPEREPR_UINT8_CLAMPED:
var v = ClampToUint8(+fromValue);
@@ -264,19 +295,19 @@ function TypedObjectSetScalar(descr, typedObj, offset, fromValue) {
case JS_SCALARTYPEREPR_INT16:
return Store_int16(typedObj, offset,
TO_INT32(fromValue) & 0xFFFF);
TO_INT32(fromValue) & 0xFFFF);
case JS_SCALARTYPEREPR_UINT16:
return Store_uint16(typedObj, offset,
TO_UINT32(fromValue) & 0xFFFF);
TO_UINT32(fromValue) & 0xFFFF);
case JS_SCALARTYPEREPR_INT32:
return Store_int32(typedObj, offset,
TO_INT32(fromValue));
TO_INT32(fromValue));
case JS_SCALARTYPEREPR_UINT32:
return Store_uint32(typedObj, offset,
TO_UINT32(fromValue));
TO_UINT32(fromValue));
case JS_SCALARTYPEREPR_FLOAT32:
return Store_float32(typedObj, offset, +fromValue);
@@ -331,6 +362,34 @@ function TypedObjectSetSimd(descr, typedObj, offset, fromValue) {
Store_float64(typedObj, offset + 0, Load_float64(fromValue, 0));
Store_float64(typedObj, offset + 8, Load_float64(fromValue, 8));
break;
case JS_SIMDTYPEREPR_INT8:
Store_int8(typedObj, offset + 0, Load_int8(fromValue, 0));
Store_int8(typedObj, offset + 1, Load_int8(fromValue, 1));
Store_int8(typedObj, offset + 2, Load_int8(fromValue, 2));
Store_int8(typedObj, offset + 3, Load_int8(fromValue, 3));
Store_int8(typedObj, offset + 4, Load_int8(fromValue, 4));
Store_int8(typedObj, offset + 5, Load_int8(fromValue, 5));
Store_int8(typedObj, offset + 6, Load_int8(fromValue, 6));
Store_int8(typedObj, offset + 7, Load_int8(fromValue, 7));
Store_int8(typedObj, offset + 8, Load_int8(fromValue, 8));
Store_int8(typedObj, offset + 9, Load_int8(fromValue, 9));
Store_int8(typedObj, offset + 10, Load_int8(fromValue, 10));
Store_int8(typedObj, offset + 11, Load_int8(fromValue, 11));
Store_int8(typedObj, offset + 12, Load_int8(fromValue, 12));
Store_int8(typedObj, offset + 13, Load_int8(fromValue, 13));
Store_int8(typedObj, offset + 14, Load_int8(fromValue, 14));
Store_int8(typedObj, offset + 15, Load_int8(fromValue, 15));
break;
case JS_SIMDTYPEREPR_INT16:
Store_int16(typedObj, offset + 0, Load_int16(fromValue, 0));
Store_int16(typedObj, offset + 2, Load_int16(fromValue, 2));
Store_int16(typedObj, offset + 4, Load_int16(fromValue, 4));
Store_int16(typedObj, offset + 6, Load_int16(fromValue, 6));
Store_int16(typedObj, offset + 8, Load_int16(fromValue, 8));
Store_int16(typedObj, offset + 10, Load_int16(fromValue, 10));
Store_int16(typedObj, offset + 12, Load_int16(fromValue, 12));
Store_int16(typedObj, offset + 14, Load_int16(fromValue, 14));
break;
case JS_SIMDTYPEREPR_INT32:
Store_int32(typedObj, offset + 0, Load_int32(fromValue, 0));
Store_int32(typedObj, offset + 4, Load_int32(fromValue, 4));
@@ -462,6 +521,10 @@ function TypedObjectArrayRedimension(newArrayType) {
function SimdProtoString(type) {
switch (type) {
case JS_SIMDTYPEREPR_INT8:
return "int8x16";
case JS_SIMDTYPEREPR_INT16:
return "int16x8";
case JS_SIMDTYPEREPR_INT32:
return "int32x4";
case JS_SIMDTYPEREPR_FLOAT32:
@@ -476,6 +539,10 @@ function SimdProtoString(type) {
function SimdTypeToLength(type) {
switch (type) {
case JS_SIMDTYPEREPR_INT8:
return 16;
case JS_SIMDTYPEREPR_INT16:
return 8;
case JS_SIMDTYPEREPR_INT32:
case JS_SIMDTYPEREPR_FLOAT32:
return 4;
@@ -495,14 +562,61 @@ function SimdToSource() {
if (DESCR_KIND(descr) != JS_TYPEREPR_SIMD_KIND)
ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "SIMD", "toSource", typeof this);
var type = DESCR_TYPE(descr);
var protoString = SimdProtoString(type);
var length = SimdTypeToLength(type);
if (length == 4)
return protoString+"("+this.x+", "+this.y+", "+this.z+", "+this.w+")";
else if (length == 2)
return protoString+"("+this.x+", "+this.y+")";
var typerepr = DESCR_TYPE(descr);
var protoString = SimdProtoString(typerepr);
switch (typerepr) {
case JS_SIMDTYPEREPR_INT8: {
var s1 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 0);
var s2 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 1);
var s3 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 2);
var s4 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 3);
var s5 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 4);
var s6 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 5);
var s7 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 6);
var s8 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 7);
var s9 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 0);
var s10 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 1);
var s11 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 2);
var s12 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 3);
var s13 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 4);
var s14 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 5);
var s15 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 6);
var s16 = callFunction(std_SIMD_Int8x16_extractLane, null, this, 7);
return `${protoString}(${s1}, ${s2}, ${s3}, ${s4}, ${s5}, ${s6}, ${s7}, ${s8}, ${s9}, ${s10}, ${s11}, ${s12}, ${s13}, ${s14}, ${s15}, ${s16})`;
}
case JS_SIMDTYPEREPR_INT16: {
var s1 = callFunction(std_SIMD_Int16x8_extractLane, null, this, 0);
var s2 = callFunction(std_SIMD_Int16x8_extractLane, null, this, 1);
var s3 = callFunction(std_SIMD_Int16x8_extractLane, null, this, 2);
var s4 = callFunction(std_SIMD_Int16x8_extractLane, null, this, 3);
var s5 = callFunction(std_SIMD_Int16x8_extractLane, null, this, 4);
var s6 = callFunction(std_SIMD_Int16x8_extractLane, null, this, 5);
var s7 = callFunction(std_SIMD_Int16x8_extractLane, null, this, 6);
var s8 = callFunction(std_SIMD_Int16x8_extractLane, null, this, 7);
return `${protoString}(${s1}, ${s2}, ${s3}, ${s4}, ${s5}, ${s6}, ${s7}, ${s8})`;
}
case JS_SIMDTYPEREPR_INT32: {
var x = callFunction(std_SIMD_Int32x4_extractLane, null, this, 0);
var y = callFunction(std_SIMD_Int32x4_extractLane, null, this, 1);
var z = callFunction(std_SIMD_Int32x4_extractLane, null, this, 2);
var w = callFunction(std_SIMD_Int32x4_extractLane, null, this, 3);
return `${protoString}(${x}, ${y}, ${z}, ${w})`;
}
case JS_SIMDTYPEREPR_FLOAT32: {
var x = callFunction(std_SIMD_Float32x4_extractLane, null, this, 0);
var y = callFunction(std_SIMD_Float32x4_extractLane, null, this, 1);
var z = callFunction(std_SIMD_Float32x4_extractLane, null, this, 2);
var w = callFunction(std_SIMD_Float32x4_extractLane, null, this, 3);
return `${protoString}(${x}, ${y}, ${z}, ${w})`;
}
case JS_SIMDTYPEREPR_FLOAT64: {
var x = callFunction(std_SIMD_Float64x2_extractLane, null, this, 0);
var y = callFunction(std_SIMD_Float64x2_extractLane, null, this, 1);
return `${protoString}(${x}, ${y})`;
}
}
assert(false, "unexpected SIMD kind");
return '?';
}
///////////////////////////////////////////////////////////////////////////
+5 -3
View File
@@ -105,8 +105,10 @@
// prefer SimdTypeRepresentation::TYPE_INT32 etc, since that allows
// you to write a switch which will receive a warning if you omit a
// case.
#define JS_SIMDTYPEREPR_INT32 0
#define JS_SIMDTYPEREPR_FLOAT32 1
#define JS_SIMDTYPEREPR_FLOAT64 2
#define JS_SIMDTYPEREPR_INT8 0
#define JS_SIMDTYPEREPR_INT16 1
#define JS_SIMDTYPEREPR_INT32 2
#define JS_SIMDTYPEREPR_FLOAT32 3
#define JS_SIMDTYPEREPR_FLOAT64 4
#endif
+2 -2
View File
@@ -88,8 +88,8 @@ function ToNumber(v) {
}
/* Spec: ECMAScript Language Specification, 5.1 edition, 9.10 */
function CheckObjectCoercible(v) {
// ES6 7.2.1 (previously, ES5 9.10 under the name "CheckObjectCoercible").
function RequireObjectCoercible(v) {
if (v === undefined || v === null)
ThrowTypeError(JSMSG_CANT_CONVERT_TO, ToString(v), "object");
}
+1 -1
View File
@@ -38,7 +38,7 @@ function indirectCallCannotGC(fullCaller, fullVariable)
if (name == "op" && /GetWeakmapKeyDelegate/.test(caller))
return true;
var CheckCallArgs = "AsmJSValidate.cpp:uint8 CheckCallArgs(FunctionCompiler*, js::frontend::ParseNode*, (uint8)(FunctionCompiler*,js::frontend::ParseNode*,Type)*, FunctionCompiler::Call*)";
var CheckCallArgs = "AsmJSValidate.cpp:uint8 CheckCallArgs(FunctionBuilder*, js::frontend::ParseNode*, (uint8)(FunctionBuilder*,js::frontend::ParseNode*,Type)*, Signature*)";
if (name == "checkArg" && caller == CheckCallArgs)
return true;
+172 -21
View File
@@ -241,42 +241,193 @@ Function Properties of the `Debugger.Memory.prototype` Object
When `trackingAllocationSites` is `false`, `drainAllocationsLog()` throws an
`Error`.
<code id='take-census'>takeCensus()</code>
<code id='take-census'>takeCensus(<i>options</i>)</code>
: Carry out a census of the debuggee compartments' contents. A *census* is a
complete traversal of the graph of all reachable memory items belonging to a
particular `Debugger`'s debuggees. The census produces a count of those
items, broken down by various criteria.
The `takeCensus` method returns an object of the form:
The <i>options</i> argument is an object whose properties specify how the
census should be carried out.
If <i>options</i> has a `breakdown` property, that determines how the census
categorizes the items it finds, and what data it collects about them. For
example, if `dbg` is a `Debugger` instance, the following performs a simple
count of debuggee items:
dbg.memory.takeCensus({ breakdown: { by: 'count' } })
That might produce a result like:
{ "count": 1616, "bytes": 93240 }
Here is a breakdown that groups JavaScript objects by their class name, and
non-string, non-script items by their C++ type name:
{
by: "coarseType",
objects: { by: "objectClass" },
other: { by: "internalType" }
}
which produces a result like this:
{
"objects": {
"Function": { "count": 404, "bytes": 37328 },
"Object": { "count": 11, "bytes": 1264 },
"Debugger": { "count": 1, "bytes": 416 },
"ScriptSource": { "count": 1, "bytes": 64 },
// ... omitted for brevity...
},
"scripts": { "count": 1, "bytes": 0 },
"strings": { "count": 701, "bytes": 49080 },
"other": {
"js::Shape": { "count": 450, "bytes": 0 },
"js::BaseShape": { "count": 21, "bytes": 0 },
"js::ObjectGroup": { "count": 17, "bytes": 0 }
}
}
In general, a `breakdown` value has one of the following forms:
<code>{ by: "count", count:<i>count<i>, bytes:<i>bytes</i> }</code>
: The trivial categorization: none whatsoever. Simply tally up the items
visited. If <i>count</i> is true, count the number of items visited; if
<i>bytes</i> is true, total the number of bytes the items use directly.
Both <i>count</i> and <i>bytes</i> are optional; if omitted, they
default to `true`. In the result of the census, this breakdown produces
a value of the form:
{ "count":<i>n</b>, "bytes":<i>b</i> }
where the `count` and `bytes` properties are present as directed by the
<i>count</i> and <i>bytes</i> properties on the breakdown.
Note that the census can produce byte sizes only for the most common
types. When the census cannot find the byte size for a given type, it
returns zero.
<code>{ by: "allocationStack", then:<i>breakdown</i>, noStack:<i>noStackBreakdown</i> }</code>
: Group items by the full JavaScript stack trace at which they were
allocated.
Further categorize all the items allocated at each distinct stack using
<i>breakdown</i>.
In the result of the census, this breakdown produces a JavaScript `Map`
value whose keys are `SavedFrame` values, and whose values are whatever
sort of result <i>breakdown</i> produces. Objects allocated on an empty
JavaScript stack appear under the key `null`.
SpiderMonkey only tracks allocation sites for items if requested via the
[`trackingAllocationSites`][tracking-allocs] flag; even then, it does
not record allocation sites for every kind of item that appears in the
heap. Items that lack allocation site information are counted using
<i>noStackBreakdown</i>. These appear in the result `Map` under the key
string `"noStack"`.
<code>{ by: "objectClass", then:<i>breakdown</i>, other:<i>otherBreakdown</i> }</code>
: Group JavaScript objects by their ECMAScript `[[Class]]` internal property values.
Further categorize JavaScript objects in each class using
<i>breakdown</i>. Further categorize items that are not JavaScript
objects using <i>otherBreakdown</i>.
In the result of the census, this breakdown produces a JavaScript object
with no prototype whose own property names are strings naming classes,
and whose values are whatever sort of result <i>breakdown</i> produces.
The results for non-object items appear as the value of the property
named `"other"`.
<code>{ by: "coarseType", objects:<i>objects</i>, scripts:<i>scripts</i>, strings:<i>strings</i>, other:<i>other</i> }</code>
: Group items by their coarse type.
Use the breakdown value <i>objects</i> for items that are JavaScript
objects.
Use the breakdown value <i>scripts</i> for items that are
representations of JavaScript code. This includes bytecode, compiled
machine code, and saved source code.
Use the breakdown value <i>strings</i> for JavaScript strings.
Use the breakdown value <i>other</i> for items that don't fit into any of
the above categories.
In the result of the census, this breakdown produces a JavaScript object
of the form:
<pre class='language-js'><code>
{
"objects": <i>result</i>,
"scripts": <i>result</i>,
"strings": <i>result</i>,
"other": <i>result</i>
}
</code></pre>
where each <i>result</i> is a value of whatever sort the corresponding
breakdown value produces. All breakdown values are optional, and default
to `{ type: "count" }`.
<code>{ by: "internalType", then:<i>breakdown</i> }</code>
: Group items by the names given their types internally by SpiderMonkey.
These names are not meaningful to web developers, but this type of
breakdown does serve as a catch-all that can be useful to Firefox tool
developers.
For example, a census of a pristine debuggee global broken down by
internal type name typically looks like this:
{
"JSString": { "count": 701, "bytes": 49080 },
"js::Shape": { "count": 450, "bytes": 0 },
"JSObject": { "count": 426, "bytes": 44160 },
"js::BaseShape": { "count": 21, "bytes": 0 },
"js::ObjectGroup": { "count": 17, "bytes": 0 },
"JSScript": { "count": 1, "bytes": 0 }
}
In the result of the census, this breakdown produces a JavaScript object
with no prototype whose own property names are strings naming types,
and whose values are whatever sort of result <i>breakdown</i> produces.
<code>[ <i>breakdown</i>, ... ]</code>
: Group each item using all the given breakdown values. In the result of
the census, this breakdown produces an array of values of the sort
produced by each listed breakdown.
To simplify breakdown values, all `then` and `other` properties are optional.
If omitted, they are treated as if they were `{ type: "count" }`.
If the `options` argument has no `breakdown` property, `takeCensus` defaults
to the following:
<pre class='language-js'><code>
{
"objects": { <i>class</i>: <i>tally</i>, ... },
"scripts": <i>tally</i>,
"strings": <i>tally</i>,
"other": { <i>type name</i>: <i>tally</i>, ... }
by: "coarseType",
objects: { by: "objectClass" },
other: { by: "internalType" }
}
</code></pre>
Each <i>tally</i> has the form:
which produces results of the form:
<pre class='language-js'><code>
{ "count": <i>count</i> }
{
objects: { <i>class</i>: <i>count</i>, ... },
scripts: <i>count</i>,
strings: <i>count</i>,
other: { <i>type name</i>: <i>count</i>, ... }
}
</code></pre>
where <i>count</i> is the number of items in the category.
where each <i>count</i> has the form:
The `"objects"` property's value contains the tallies of JavaScript objects,
broken down by their ECMAScript `[[Class]]` internal property values. Each
<i>class</i> is a string.
The `"scripts"` property's value tallies the in-memory representation of
JavaScript code.
The `"strings"` property's value tallies the debuggee's strings.
The `"other"` property's value contains the tallies of other items used
internally by SpiderMonkey, broken down by their C++ type name.
<pre class='language-js'><code>
{ "count": <i>count</i>, bytes:<i>bytes</i> }
</code></pre>
Because performing a census requires traversing the entire graph of objects
in debuggee compartments, it is an expensive operation. On developer
@@ -336,7 +487,7 @@ simpler ones when it pleases. Such conversions usually increase memory
consumption.
SpiderMonkey shares some strings amongst all web pages and browser JS. These
shared strings, called *atoms*, are not included in censuses' string tallies.
shared strings, called *atoms*, are not included in censuses' string counts.
### Scripts
+48 -9
View File
@@ -3721,11 +3721,14 @@ BytecodeEmitter::emitDestructuringOpsObjectHelper(ParseNode* pattern, VarEmitOpt
MOZ_ASSERT(pattern->isKind(PNK_OBJECT));
MOZ_ASSERT(pattern->isArity(PN_LIST));
MOZ_ASSERT(this->stackDepth != 0); // ... OBJ
MOZ_ASSERT(this->stackDepth > 0); // ... RHS
if (!emitRequireObjectCoercible()) // ... RHS
return false;
for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
// Duplicate the value being destructured to use as a reference base.
if (!emit1(JSOP_DUP)) // ... OBJ OBJ
if (!emit1(JSOP_DUP)) // ... RHS RHS
return false;
// Now push the property name currently being matched, which is the
@@ -3735,7 +3738,7 @@ BytecodeEmitter::emitDestructuringOpsObjectHelper(ParseNode* pattern, VarEmitOpt
ParseNode* subpattern;
if (member->isKind(PNK_MUTATEPROTO)) {
if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) // ... OBJ PROP
if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) // ... RHS PROP
return false;
needsGetElem = false;
subpattern = member->pn_kid;
@@ -3744,7 +3747,7 @@ BytecodeEmitter::emitDestructuringOpsObjectHelper(ParseNode* pattern, VarEmitOpt
ParseNode* key = member->pn_left;
if (key->isKind(PNK_NUMBER)) {
if (!emitNumberOp(key->pn_dval)) // ... OBJ OBJ KEY
if (!emitNumberOp(key->pn_dval)) // ... RHS RHS KEY
return false;
} else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) {
PropertyName* name = key->pn_atom->asPropertyName();
@@ -3754,16 +3757,16 @@ BytecodeEmitter::emitDestructuringOpsObjectHelper(ParseNode* pattern, VarEmitOpt
// as indexes for simplification of downstream analysis.
jsid id = NameToId(name);
if (id != IdToTypeId(id)) {
if (!emitTree(key)) // ... OBJ OBJ KEY
if (!emitTree(key)) // ... RHS RHS KEY
return false;
} else {
if (!emitAtomOp(name, JSOP_GETPROP)) // ...OBJ PROP
if (!emitAtomOp(name, JSOP_GETPROP)) // ...RHS PROP
return false;
needsGetElem = false;
}
} else {
MOZ_ASSERT(key->isKind(PNK_COMPUTED_NAME));
if (!emitTree(key->pn_kid)) // ... OBJ OBJ KEY
if (!emitTree(key->pn_kid)) // ... RHS RHS KEY
return false;
}
@@ -3771,7 +3774,7 @@ BytecodeEmitter::emitDestructuringOpsObjectHelper(ParseNode* pattern, VarEmitOpt
}
// Get the property value if not done already.
if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) // ... OBJ PROP
if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) // ... RHS PROP
return false;
if (subpattern->isKind(PNK_ASSIGN)) {
@@ -3789,7 +3792,7 @@ BytecodeEmitter::emitDestructuringOpsObjectHelper(ParseNode* pattern, VarEmitOpt
// target in the subpattern's LHS as it went, then popped PROP. We've
// correctly returned to the loop-entry stack, and we continue to the
// next member.
if (emitOption == InitializeVars) // ... OBJ
if (emitOption == InitializeVars) // ... RHS
continue;
MOZ_ASSERT(emitOption == PushInitialValues);
@@ -4921,6 +4924,42 @@ BytecodeEmitter::emitWith(ParseNode* pn)
return true;
}
bool
BytecodeEmitter::emitRequireObjectCoercible()
{
// For simplicity, handle this in self-hosted code, at cost of 13 bytes of
// bytecode versus 1 byte for a dedicated opcode. As more places need this
// behavior, we may want to reconsider this tradeoff.
#ifdef DEBUG
auto depth = this->stackDepth;
#endif
MOZ_ASSERT(depth > 0); // VAL
if (!emit1(JSOP_DUP)) // VAL VAL
return false;
// Note that "intrinsic" is a misnomer: we're calling a *self-hosted*
// function that's not an intrinsic! But it nonetheless works as desired.
if (!emitAtomOp(cx->names().RequireObjectCoercible,
JSOP_GETINTRINSIC)) // VAL VAL REQUIREOBJECTCOERCIBLE
{
return false;
}
if (!emit1(JSOP_UNDEFINED)) // VAL VAL REQUIREOBJECTCOERCIBLE UNDEFINED
return false;
if (!emit2(JSOP_PICK, jsbytecode(2))) // VAL REQUIREOBJECTCOERCIBLE UNDEFINED VAL
return false;
if (!emitCall(JSOP_CALL, 1)) // VAL IGNORED
return false;
checkTypeSet(JSOP_CALL);
if (!emit1(JSOP_POP)) // VAL
return false;
MOZ_ASSERT(depth == this->stackDepth);
return true;
}
bool
BytecodeEmitter::emitIterator()
{
+4
View File
@@ -522,6 +522,10 @@ struct BytecodeEmitter
// the stack.
bool emitInitializeDestructuringDecls(JSOp prologueOp, ParseNode* pattern);
// Throw a TypeError if the value atop the stack isn't convertible to an
// object, with no overall effect on the stack.
bool emitRequireObjectCoercible();
// emitIterator expects the iterable to already be on the stack.
// It will replace that stack value with the corresponding iterator
bool emitIterator();
+4 -4
View File
@@ -1,10 +1,10 @@
if (typeof SIMD === "undefined")
quit();
var float32x4 = SIMD.float32x4;
var f = float32x4(11, 22, 33, 44);
var Float32x4 = SIMD.Float32x4;
var f = Float32x4(11, 22, 33, 44);
assertEq(f.toSource(), "float32x4(11, 22, 33, 44)");
var int32x4 = SIMD.int32x4;
var f = int32x4(11, 22, 33, 44);
var Int32x4 = SIMD.Int32x4;
var f = Int32x4(11, 22, 33, 44);
assertEq(f.toSource(), "int32x4(11, 22, 33, 44)");
@@ -0,0 +1,23 @@
load(libdir + 'simd.js');
setJitCompilerOption("ion.warmup.trigger", 50);
function f() {
var i1 = SIMD.Int32x4(1, 2, 3, 4);
var i2 = SIMD.Int32x4(4, 3, 2, 1);
var f1 = SIMD.Float32x4(1, 2, 3, 4);
var f2 = SIMD.Float32x4(4, 3, 2, 1);
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.Float32x4.add(f1, f2), binaryX4((x, y) => x + y, f1, f2));
assertEqX4(SIMD.Float32x4.sub(f1, f2), binaryX4((x, y) => x - y, f1, f2));
assertEqX4(SIMD.Float32x4.mul(f1, f2), binaryX4((x, y) => x * y, f1, f2));
assertEqX4(SIMD.Int32x4.add(i1, i2), binaryX4((x, y) => x + y, i1, i2));
assertEqX4(SIMD.Int32x4.sub(i1, i2), binaryX4((x, y) => x - y, i1, i2));
assertEqX4(SIMD.Int32x4.mul(i1, i2), binaryX4((x, y) => x * y, i1, i2));
}
}
f();
+3 -3
View File
@@ -6,9 +6,9 @@ const T = -1, F = 0;
function f() {
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.int32x4.bool(i + 1, true, 'hey', null), [T, T, T, F]);
assertEqX4(SIMD.int32x4.bool(undefined, '', {}, objectEmulatingUndefined()), [F, F, T, F]);
assertEqX4(SIMD.int32x4.bool(null, NaN, false, Infinity), [F, F, F, T]);
assertEqX4(SIMD.Int32x4.bool(i + 1, true, 'hey', null), [T, T, T, F]);
assertEqX4(SIMD.Int32x4.bool(undefined, '', {}, objectEmulatingUndefined()), [F, F, T, F]);
assertEqX4(SIMD.Int32x4.bool(null, NaN, false, Infinity), [F, F, F, T]);
}
}
+11
View File
@@ -0,0 +1,11 @@
if (typeof TypedObject === "undefined" || typeof SIMD === 'undefined')
quit();
var Int32x4 = SIMD.Int32x4;
var a = Int32x4((4294967295), 200, 300, 400);
addCase( new Array(Math.pow(2,12)) );
for ( var arg = "", i = 0; i < Math.pow(2,12); i++ ) {}
addCase( a );
function addCase(object) {
object.length
}
+7 -7
View File
@@ -7,20 +7,20 @@ setJitCompilerOption("ion.warmup.trigger", 30);
function test_1(i) {
if (i >= 40)
return;
var a = SIMD.float32x4(1.1, 2.2, 3.3, 4.6);
SIMD.int32x4.fromFloat32x4(a);
var a = SIMD.Float32x4(1.1, 2.2, 3.3, 4.6);
SIMD.Int32x4.fromFloat32x4(a);
test_1(i + 1);
}
test_1(0);
var float32x4 = SIMD.float32x4;
var Float32x4 = SIMD.Float32x4;
function test_2() {
var Array = float32x4.array(3);
var Array = Float32x4.array(3);
var array = new Array([
float32x4(1, 2, 3, 4),
float32x4(5, 6, 7, 8),
float32x4(9, 10, 11, 12)
Float32x4(1, 2, 3, 4),
Float32x4(5, 6, 7, 8),
Float32x4(9, 10, 11, 12)
]);
if (typeof reportCompare === "function")
reportCompare(true, true);
+2 -2
View File
@@ -1,9 +1,9 @@
if (!this.hasOwnProperty("SIMD"))
quit();
var float64x2 = SIMD.float64x2;
var Float64x2 = SIMD.Float64x2;
function test() {
var a = float64x2(1, 2);
var a = Float64x2(1, 2);
}
test();
test();
+4 -4
View File
@@ -1,11 +1,11 @@
if (!this.hasOwnProperty("SIMD"))
quit();
var int32x4 = SIMD.int32x4;
var Int32x4 = SIMD.Int32x4;
function test() {
var a = int32x4();
var b = int32x4(10, 20, 30, 40);
var c = SIMD.int32x4.and(a, b);
var a = Int32x4();
var b = Int32x4(10, 20, 30, 40);
var c = SIMD.Int32x4.and(a, b);
assertEq(c.x, 0);
return 0;
}
+10
View File
@@ -0,0 +1,10 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
if (!this.hasOwnProperty("TypedObject") || !this.hasOwnProperty("SIMD"))
quit();
var Float32x4 = SIMD.Float32x4;
Float32x4.array(1);
+4 -6
View File
@@ -3,17 +3,15 @@ load(libdir + 'simd.js');
setJitCompilerOption("ion.warmup.trigger", 50);
function f() {
var f1 = SIMD.float32x4(1, 2, 3, 4);
var i1 = SIMD.int32x4(1, 2, -3, 4);
var f1 = SIMD.Float32x4(1, 2, 3, 4);
var i1 = SIMD.Int32x4(1, 2, -3, 4);
var i = 0;
try {
for (; i < 150; i++) {
if (i > 148)
i1 = f1;
assertEqVec(SIMD.int32x4.check(i1), i1);
assertEqVec(SIMD.float32x4.check(f1), f1);
assertEqVec(SIMD.Int32x4.check(i1), i1);
assertEqVec(SIMD.Float32x4.check(f1), f1);
}
} catch (ex) {
assertEq(i, 149);
+16 -16
View File
@@ -7,26 +7,26 @@ function bool(x) {
}
function f() {
var f1 = SIMD.float32x4(1, 2, 3, 4);
var f2 = SIMD.float32x4(NaN, Infinity, 3.14, -0);
var f1 = SIMD.Float32x4(1, 2, 3, 4);
var f2 = SIMD.Float32x4(NaN, Infinity, 3.14, -0);
var i1 = SIMD.int32x4(1, 2, -3, 4);
var i2 = SIMD.int32x4(1, -2, 3, 0);
var i1 = SIMD.Int32x4(1, 2, -3, 4);
var i2 = SIMD.Int32x4(1, -2, 3, 0);
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.int32x4.lessThan(i1, i2), [0, 0, 1, 0].map(bool));
assertEqX4(SIMD.int32x4.lessThanOrEqual(i1, i2), [1, 0, 1, 0].map(bool));
assertEqX4(SIMD.int32x4.equal(i1, i2), [1, 0, 0, 0].map(bool));
assertEqX4(SIMD.int32x4.notEqual(i1, i2), [0, 1, 1, 1].map(bool));
assertEqX4(SIMD.int32x4.greaterThan(i1, i2), [0, 1, 0, 1].map(bool));
assertEqX4(SIMD.int32x4.greaterThanOrEqual(i1, i2), [1, 1, 0, 1].map(bool));
assertEqX4(SIMD.Int32x4.lessThan(i1, i2), [0, 0, 1, 0].map(bool));
assertEqX4(SIMD.Int32x4.lessThanOrEqual(i1, i2), [1, 0, 1, 0].map(bool));
assertEqX4(SIMD.Int32x4.equal(i1, i2), [1, 0, 0, 0].map(bool));
assertEqX4(SIMD.Int32x4.notEqual(i1, i2), [0, 1, 1, 1].map(bool));
assertEqX4(SIMD.Int32x4.greaterThan(i1, i2), [0, 1, 0, 1].map(bool));
assertEqX4(SIMD.Int32x4.greaterThanOrEqual(i1, i2), [1, 1, 0, 1].map(bool));
assertEqX4(SIMD.float32x4.lessThan(f1, f2), [0, 1, 1, 0].map(bool));
assertEqX4(SIMD.float32x4.lessThanOrEqual(f1, f2), [0, 1, 1, 0].map(bool));
assertEqX4(SIMD.float32x4.equal(f1, f2), [0, 0, 0, 0].map(bool));
assertEqX4(SIMD.float32x4.notEqual(f1, f2), [1, 1, 1, 1].map(bool));
assertEqX4(SIMD.float32x4.greaterThan(f1, f2), [0, 0, 0, 1].map(bool));
assertEqX4(SIMD.float32x4.greaterThanOrEqual(f1, f2), [0, 0, 0, 1].map(bool));
assertEqX4(SIMD.Float32x4.lessThan(f1, f2), [0, 1, 1, 0].map(bool));
assertEqX4(SIMD.Float32x4.lessThanOrEqual(f1, f2), [0, 1, 1, 0].map(bool));
assertEqX4(SIMD.Float32x4.equal(f1, f2), [0, 0, 0, 0].map(bool));
assertEqX4(SIMD.Float32x4.notEqual(f1, f2), [1, 1, 1, 1].map(bool));
assertEqX4(SIMD.Float32x4.greaterThan(f1, f2), [0, 0, 0, 1].map(bool));
assertEqX4(SIMD.Float32x4.greaterThanOrEqual(f1, f2), [0, 0, 0, 1].map(bool));
}
}
+70
View File
@@ -0,0 +1,70 @@
load(libdir + 'simd.js');
if (typeof SIMD === "undefined")
quit();
setJitCompilerOption("baseline.warmup.trigger", 10);
setJitCompilerOption("ion.warmup.trigger", 90);
var max = 100; // Make have the warm-up counter high enough to
// consider inlining functions.
var f4 = SIMD.Int32x4; // :TODO: Support Float32x4 arith.
var f4add = f4.add;
var f4sub = f4.sub;
var f4mul = f4.mul;
function c4mul(z1, z2) {
var { re: re1, im: im1 } = z1;
var { re: re2, im: im2 } = z2;
var rere = f4mul(re1, re2);
var reim = f4mul(re1, im2);
var imre = f4mul(im1, re2);
var imim = f4mul(im1, im2);
return { re: f4sub(rere, imim), im: f4add(reim, imre) };
}
function c4inv(z) {
var { re: re, im: im } = z;
var minus = f4(-1, -1, -1, -1);
return { re: re, im: f4mul(im, minus) };
}
function c4inv_inplace(z) {
var res = c4inv(z);
z.re = res.re;
z.im = res.im;
}
function c4norm(z) {
var { re: re, im: im } = c4mul(z, c4inv(z));
return re;
}
function c4scale(z, s) {
var { re: re, im: im } = z;
var f4s = f4(s, s, s, s);
return { re: f4mul(re, f4s), im: f4mul(im, f4s) };
}
var rotate90 = { re: f4(0, 0, 0, 0), im: f4(1, 1, 1, 1) };
var cardinals = { re: f4(1, 0, -1, 0), im: f4(0, 1, 0, -1) };
function test(dots) {
for (var j = 0; j < 4; j++) {
dots = c4mul(rotate90, dots);
if (j % 2 == 0) // Magic !
c4inv_inplace(dots);
dots = c4scale(dots, 2);
}
return dots;
}
assertEqX4(c4norm(cardinals), simdToArray(f4.splat(1)));
var cardinals16 = c4scale(cardinals, 16);
for (var i = 0; i < max; i++) {
var res = test(cardinals);
assertEqX4(c4norm(res), simdToArray(f4.splat(16 * 16)));
assertEqX4(res.re, simdToArray(cardinals16.re));
assertEqX4(res.im, simdToArray(cardinals16.im));
}
+10 -12
View File
@@ -20,27 +20,26 @@ var cast = (function() {
function f() {
// No bailout here.
var f4 = SIMD.float32x4(1, 2, 3, 4);
var i4 = SIMD.int32x4(1, 2, 3, 4);
var f4 = SIMD.Float32x4(1, 2, 3, 4);
var i4 = SIMD.Int32x4(1, 2, 3, 4);
var BitOrZero = (x) => x | 0;
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.float32x4.fromInt32x4(i4), unaryX4(BitOrZero, f4, Math.fround));
assertEqX4(SIMD.float32x4.fromInt32x4Bits(i4), unaryX4(cast.fromInt32Bits, f4, Math.fround));
assertEqX4(SIMD.int32x4.fromFloat32x4(f4), unaryX4(Math.fround, i4, BitOrZero));
assertEqX4(SIMD.int32x4.fromFloat32x4Bits(f4), unaryX4(cast.fromFloat32Bits, i4, BitOrZero));
assertEqX4(SIMD.Float32x4.fromInt32x4(i4), unaryX4(BitOrZero, f4, Math.fround));
assertEqX4(SIMD.Float32x4.fromInt32x4Bits(i4), unaryX4(cast.fromInt32Bits, f4, Math.fround));
assertEqX4(SIMD.Int32x4.fromFloat32x4(f4), unaryX4(Math.fround, i4, BitOrZero));
assertEqX4(SIMD.Int32x4.fromFloat32x4Bits(f4), unaryX4(cast.fromFloat32Bits, i4, BitOrZero));
}
}
function uglyDuckling(val) {
// We bail out when i == 149 because the conversion will return
// 0x80000000 and the input actually wasn't in bounds.
print('entering uglyDuckling');
val = Math.fround(val);
for (var i = 0; i < 150; i++) {
var caught = false;
try {
var v = SIMD.float32x4(i < 149 ? 0 : val, 0, 0, 0)
SIMD.int32x4.fromFloat32x4(v);
var v = SIMD.Float32x4(i < 149 ? 0 : val, 0, 0, 0)
SIMD.Int32x4.fromFloat32x4(v);
} catch(e) {
assertEq(e instanceof RangeError, true);
assertEq(i, 149);
@@ -51,12 +50,11 @@ function uglyDuckling(val) {
}
function dontBail() {
print('entering dontbail');
// On x86, the conversion will return 0x80000000, which will imply that we
// check the input values. However, we shouldn't bail out in this case.
for (var i = 0; i < 150; i++) {
var v = SIMD.float32x4(i < 149 ? 0 : -Math.pow(2, 31), 0, 0, 0)
SIMD.int32x4.fromFloat32x4(v);
var v = SIMD.Float32x4(i < 149 ? 0 : -Math.pow(2, 31), 0, 0, 0)
SIMD.Int32x4.fromFloat32x4(v);
}
}
@@ -19,14 +19,14 @@ function minNum(x, y) {
}
function f() {
var f1 = SIMD.float32x4(1, 2, 3, 4);
var f2 = SIMD.float32x4(4, 3, 2, 1);
var f1 = SIMD.Float32x4(1, 2, 3, 4);
var f2 = SIMD.Float32x4(4, 3, 2, 1);
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.float32x4.div(f1, f2), binaryX4((x, y) => x / y, f1, f2));
assertEqX4(SIMD.float32x4.min(f1, f2), binaryX4(Math.min, f1, f2));
assertEqX4(SIMD.float32x4.max(f1, f2), binaryX4(Math.max, f1, f2));
assertEqX4(SIMD.float32x4.minNum(f1, f2), binaryX4(minNum, f1, f2));
assertEqX4(SIMD.float32x4.maxNum(f1, f2), binaryX4(maxNum, f1, f2));
assertEqX4(SIMD.Float32x4.div(f1, f2), binaryX4((x, y) => x / y, f1, f2));
assertEqX4(SIMD.Float32x4.min(f1, f2), binaryX4(Math.min, f1, f2));
assertEqX4(SIMD.Float32x4.max(f1, f2), binaryX4(Math.max, f1, f2));
assertEqX4(SIMD.Float32x4.minNum(f1, f2), binaryX4(minNum, f1, f2));
assertEqX4(SIMD.Float32x4.maxNum(f1, f2), binaryX4(maxNum, f1, f2));
}
}
@@ -28,12 +28,12 @@ var helpers = (function() {
})();
function f() {
var f1 = SIMD.float32x4(1, 2, 3, 4);
var f2 = SIMD.float32x4(4, 3, 2, 1);
var f1 = SIMD.Float32x4(1, 2, 3, 4);
var f2 = SIMD.Float32x4(4, 3, 2, 1);
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.float32x4.and(f1, f2), binaryX4(helpers.and, f1, f2));
assertEqX4(SIMD.float32x4.or(f1, f2), binaryX4(helpers.or, f1, f2));
assertEqX4(SIMD.float32x4.xor(f1, f2), binaryX4(helpers.xor, f1, f2));
assertEqX4(SIMD.Float32x4.and(f1, f2), binaryX4(helpers.and, f1, f2));
assertEqX4(SIMD.Float32x4.or(f1, f2), binaryX4(helpers.or, f1, f2));
assertEqX4(SIMD.Float32x4.xor(f1, f2), binaryX4(helpers.xor, f1, f2));
}
}
+2 -2
View File
@@ -3,10 +3,10 @@ load(libdir + 'simd.js');
setJitCompilerOption("ion.warmup.trigger", 50);
function f() {
var i4 = SIMD.int32x4(1, -2, 3, -4);
var i4 = SIMD.Int32x4(1, -2, 3, -4);
var v = Math.fround(13.37);
var f4 = SIMD.float32x4(13.37, NaN, Infinity, -0);
var f4 = SIMD.Float32x4(13.37, NaN, Infinity, -0);
for (var i = 0; i < 150; i++) {
assertEq(i4.x, 1);
@@ -0,0 +1,23 @@
load(libdir + 'simd.js');
setJitCompilerOption("ion.warmup.trigger", 50);
function test(i) {
assertEqX4(SIMD.Int32x4(), [0, 0, 0, 0]);
assertEqX4(SIMD.Int32x4(i), [i, 0, 0, 0]);
assertEqX4(SIMD.Int32x4(i, 1), [i, 1, 0, 0]);
assertEqX4(SIMD.Int32x4(i, 1, 2), [i, 1, 2, 0]);
assertEqX4(SIMD.Int32x4(i, 1, 2, 3), [i, 1, 2, 3]);
assertEqX4(SIMD.Int32x4(i, 1, 2, 3, 4), [i, 1, 2, 3]);
assertEqX4(SIMD.Float32x4(), [NaN, NaN, NaN, NaN]);
assertEqX4(SIMD.Float32x4(i), [i, NaN, NaN, NaN]);
assertEqX4(SIMD.Float32x4(i, 1), [i, 1, NaN, NaN]);
assertEqX4(SIMD.Float32x4(i, 1, 2), [i, 1, 2, NaN]);
assertEqX4(SIMD.Float32x4(i, 1, 2, 3), [i, 1, 2, 3 ]);
assertEqX4(SIMD.Float32x4(i, 1, 2, 3, 4), [i, 1, 2, 3 ]);
}
for(var i=0; i<300; i++) {
test(i);
}
+58 -60
View File
@@ -16,76 +16,75 @@ function f() {
var u8 = new Uint8Array(f32.buffer);
function testLoad() {
assertEqX4(SIMD.float32x4.load(f64, 0), [1,2,3,4]);
assertEqX4(SIMD.float32x4.load(f32, 1), [2,3,4,5]);
assertEqX4(SIMD.float32x4.load(i32, 2), [3,4,5,6]);
assertEqX4(SIMD.float32x4.load(i16, 3 << 1), [4,5,6,7]);
assertEqX4(SIMD.float32x4.load(u16, 4 << 1), [5,6,7,8]);
assertEqX4(SIMD.float32x4.load(i8 , 5 << 2), [6,7,8,9]);
assertEqX4(SIMD.float32x4.load(u8 , 6 << 2), [7,8,9,10]);
assertEqX4(SIMD.float32x4.load(f64, (16 >> 1) - (4 >> 1)), [13,14,15,16]);
assertEqX4(SIMD.float32x4.load(f32, 16 - 4), [13,14,15,16]);
assertEqX4(SIMD.float32x4.load(i32, 16 - 4), [13,14,15,16]);
assertEqX4(SIMD.float32x4.load(i16, (16 << 1) - (4 << 1)), [13,14,15,16]);
assertEqX4(SIMD.float32x4.load(u16, (16 << 1) - (4 << 1)), [13,14,15,16]);
assertEqX4(SIMD.float32x4.load(i8, (16 << 2) - (4 << 2)), [13,14,15,16]);
assertEqX4(SIMD.float32x4.load(u8, (16 << 2) - (4 << 2)), [13,14,15,16]);
assertEqX4(SIMD.Float32x4.load(f64, 0), [1,2,3,4]);
assertEqX4(SIMD.Float32x4.load(f32, 1), [2,3,4,5]);
assertEqX4(SIMD.Float32x4.load(i32, 2), [3,4,5,6]);
assertEqX4(SIMD.Float32x4.load(i16, 3 << 1), [4,5,6,7]);
assertEqX4(SIMD.Float32x4.load(u16, 4 << 1), [5,6,7,8]);
assertEqX4(SIMD.Float32x4.load(i8 , 5 << 2), [6,7,8,9]);
assertEqX4(SIMD.Float32x4.load(u8 , 6 << 2), [7,8,9,10]);
assertEqX4(SIMD.Float32x4.load(f64, (16 >> 1) - (4 >> 1)), [13,14,15,16]);
assertEqX4(SIMD.Float32x4.load(f32, 16 - 4), [13,14,15,16]);
assertEqX4(SIMD.Float32x4.load(i32, 16 - 4), [13,14,15,16]);
assertEqX4(SIMD.Float32x4.load(i16, (16 << 1) - (4 << 1)), [13,14,15,16]);
assertEqX4(SIMD.Float32x4.load(u16, (16 << 1) - (4 << 1)), [13,14,15,16]);
assertEqX4(SIMD.Float32x4.load(i8, (16 << 2) - (4 << 2)), [13,14,15,16]);
assertEqX4(SIMD.Float32x4.load(u8, (16 << 2) - (4 << 2)), [13,14,15,16]);
}
function testLoad1() {
assertEqX4(SIMD.float32x4.load1(f64, 0), [1,0,0,0]);
assertEqX4(SIMD.float32x4.load1(f32, 1), [2,0,0,0]);
assertEqX4(SIMD.float32x4.load1(i32, 2), [3,0,0,0]);
assertEqX4(SIMD.float32x4.load1(i16, 3 << 1), [4,0,0,0]);
assertEqX4(SIMD.float32x4.load1(u16, 4 << 1), [5,0,0,0]);
assertEqX4(SIMD.float32x4.load1(i8 , 5 << 2), [6,0,0,0]);
assertEqX4(SIMD.float32x4.load1(u8 , 6 << 2), [7,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(f64, 0), [1,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(f32, 1), [2,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(i32, 2), [3,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(i16, 3 << 1), [4,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(u16, 4 << 1), [5,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(i8 , 5 << 2), [6,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(u8 , 6 << 2), [7,0,0,0]);
assertEqX4(SIMD.float32x4.load1(f64, (16 >> 1) - (4 >> 1)), [13,0,0,0]);
assertEqX4(SIMD.float32x4.load1(f32, 16 - 4), [13,0,0,0]);
assertEqX4(SIMD.float32x4.load1(i32, 16 - 4), [13,0,0,0]);
assertEqX4(SIMD.float32x4.load1(i16, (16 << 1) - (4 << 1)), [13,0,0,0]);
assertEqX4(SIMD.float32x4.load1(u16, (16 << 1) - (4 << 1)), [13,0,0,0]);
assertEqX4(SIMD.float32x4.load1(i8, (16 << 2) - (4 << 2)), [13,0,0,0]);
assertEqX4(SIMD.float32x4.load1(u8, (16 << 2) - (4 << 2)), [13,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(f64, (16 >> 1) - (4 >> 1)), [13,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(f32, 16 - 4), [13,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(i32, 16 - 4), [13,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(i16, (16 << 1) - (4 << 1)), [13,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(u16, (16 << 1) - (4 << 1)), [13,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(i8, (16 << 2) - (4 << 2)), [13,0,0,0]);
assertEqX4(SIMD.Float32x4.load1(u8, (16 << 2) - (4 << 2)), [13,0,0,0]);
}
function testLoad2() {
assertEqX4(SIMD.float32x4.load2(f64, 0), [1,2,0,0]);
assertEqX4(SIMD.float32x4.load2(f32, 1), [2,3,0,0]);
assertEqX4(SIMD.float32x4.load2(i32, 2), [3,4,0,0]);
assertEqX4(SIMD.float32x4.load2(i16, 3 << 1), [4,5,0,0]);
assertEqX4(SIMD.float32x4.load2(u16, 4 << 1), [5,6,0,0]);
assertEqX4(SIMD.float32x4.load2(i8 , 5 << 2), [6,7,0,0]);
assertEqX4(SIMD.float32x4.load2(u8 , 6 << 2), [7,8,0,0]);
assertEqX4(SIMD.Float32x4.load2(f64, 0), [1,2,0,0]);
assertEqX4(SIMD.Float32x4.load2(f32, 1), [2,3,0,0]);
assertEqX4(SIMD.Float32x4.load2(i32, 2), [3,4,0,0]);
assertEqX4(SIMD.Float32x4.load2(i16, 3 << 1), [4,5,0,0]);
assertEqX4(SIMD.Float32x4.load2(u16, 4 << 1), [5,6,0,0]);
assertEqX4(SIMD.Float32x4.load2(i8 , 5 << 2), [6,7,0,0]);
assertEqX4(SIMD.Float32x4.load2(u8 , 6 << 2), [7,8,0,0]);
assertEqX4(SIMD.float32x4.load2(f64, (16 >> 1) - (4 >> 1)), [13,14,0,0]);
assertEqX4(SIMD.float32x4.load2(f32, 16 - 4), [13,14,0,0]);
assertEqX4(SIMD.float32x4.load2(i32, 16 - 4), [13,14,0,0]);
assertEqX4(SIMD.float32x4.load2(i16, (16 << 1) - (4 << 1)), [13,14,0,0]);
assertEqX4(SIMD.float32x4.load2(u16, (16 << 1) - (4 << 1)), [13,14,0,0]);
assertEqX4(SIMD.float32x4.load2(i8, (16 << 2) - (4 << 2)), [13,14,0,0]);
assertEqX4(SIMD.float32x4.load2(u8, (16 << 2) - (4 << 2)), [13,14,0,0]);
assertEqX4(SIMD.Float32x4.load2(f64, (16 >> 1) - (4 >> 1)), [13,14,0,0]);
assertEqX4(SIMD.Float32x4.load2(f32, 16 - 4), [13,14,0,0]);
assertEqX4(SIMD.Float32x4.load2(i32, 16 - 4), [13,14,0,0]);
assertEqX4(SIMD.Float32x4.load2(i16, (16 << 1) - (4 << 1)), [13,14,0,0]);
assertEqX4(SIMD.Float32x4.load2(u16, (16 << 1) - (4 << 1)), [13,14,0,0]);
assertEqX4(SIMD.Float32x4.load2(i8, (16 << 2) - (4 << 2)), [13,14,0,0]);
assertEqX4(SIMD.Float32x4.load2(u8, (16 << 2) - (4 << 2)), [13,14,0,0]);
}
function testLoad3() {
assertEqX4(SIMD.float32x4.load3(f64, 0), [1,2,3,0]);
assertEqX4(SIMD.float32x4.load3(f32, 1), [2,3,4,0]);
assertEqX4(SIMD.float32x4.load3(i32, 2), [3,4,5,0]);
assertEqX4(SIMD.float32x4.load3(i16, 3 << 1), [4,5,6,0]);
assertEqX4(SIMD.float32x4.load3(u16, 4 << 1), [5,6,7,0]);
assertEqX4(SIMD.float32x4.load3(i8 , 5 << 2), [6,7,8,0]);
assertEqX4(SIMD.float32x4.load3(u8 , 6 << 2), [7,8,9,0]);
assertEqX4(SIMD.Float32x4.load3(f64, 0), [1,2,3,0]);
assertEqX4(SIMD.Float32x4.load3(f32, 1), [2,3,4,0]);
assertEqX4(SIMD.Float32x4.load3(i32, 2), [3,4,5,0]);
assertEqX4(SIMD.Float32x4.load3(i16, 3 << 1), [4,5,6,0]);
assertEqX4(SIMD.Float32x4.load3(u16, 4 << 1), [5,6,7,0]);
assertEqX4(SIMD.Float32x4.load3(i8 , 5 << 2), [6,7,8,0]);
assertEqX4(SIMD.Float32x4.load3(u8 , 6 << 2), [7,8,9,0]);
assertEqX4(SIMD.float32x4.load3(f64, (16 >> 1) - (4 >> 1)), [13,14,15,0]);
assertEqX4(SIMD.float32x4.load3(f32, 16 - 4), [13,14,15,0]);
assertEqX4(SIMD.float32x4.load3(i32, 16 - 4), [13,14,15,0]);
assertEqX4(SIMD.float32x4.load3(i16, (16 << 1) - (4 << 1)), [13,14,15,0]);
assertEqX4(SIMD.float32x4.load3(u16, (16 << 1) - (4 << 1)), [13,14,15,0]);
assertEqX4(SIMD.float32x4.load3(i8, (16 << 2) - (4 << 2)), [13,14,15,0]);
assertEqX4(SIMD.float32x4.load3(u8, (16 << 2) - (4 << 2)), [13,14,15,0]);
assertEqX4(SIMD.Float32x4.load3(f64, (16 >> 1) - (4 >> 1)), [13,14,15,0]);
assertEqX4(SIMD.Float32x4.load3(f32, 16 - 4), [13,14,15,0]);
assertEqX4(SIMD.Float32x4.load3(i32, 16 - 4), [13,14,15,0]);
assertEqX4(SIMD.Float32x4.load3(i16, (16 << 1) - (4 << 1)), [13,14,15,0]);
assertEqX4(SIMD.Float32x4.load3(u16, (16 << 1) - (4 << 1)), [13,14,15,0]);
assertEqX4(SIMD.Float32x4.load3(i8, (16 << 2) - (4 << 2)), [13,14,15,0]);
assertEqX4(SIMD.Float32x4.load3(u8, (16 << 2) - (4 << 2)), [13,14,15,0]);
}
for (var i = 0; i < 150; i++) {
@@ -106,10 +105,9 @@ function testBailout(uglyDuckling) {
var i8 = new Int8Array(f32.buffer);
for (var i = 0; i < 150; i++) {
var caught = false;
try {
SIMD.float32x4.load(i8, (i < 149) ? 0 : uglyDuckling);
SIMD.Float32x4.load(i8, (i < 149) ? 0 : uglyDuckling);
} catch (e) {
print(e);
assertEq(e instanceof RangeError, true);
@@ -6,8 +6,8 @@ if (typeof SIMD === "undefined")
setJitCompilerOption("baseline.warmup.trigger", 10);
setJitCompilerOption("ion.warmup.trigger", 30);
var i4 = SIMD.int32x4;
var i4sub = SIMD.int32x4.sub;
var i4 = SIMD.Int32x4;
var i4sub = SIMD.Int32x4.sub;
function simdbox(i) {
return i4(i, i, i, i);
+2 -2
View File
@@ -25,7 +25,7 @@ var uceFault = function (i) {
// Check that we can correctly recover a boxed value.
var uceFault_simdBox_i4 = eval(uneval(uceFault).replace('uceFault', 'uceFault_simdBox_i4'));
function simdBox_i4(i) {
var a = SIMD.int32x4(i, i, i, i);
var a = SIMD.Int32x4(i, i, i, i);
if (uceFault_simdBox_i4(i) || uceFault_simdBox_i4(i))
assertEqX4(a, [i, i, i, i]);
assertRecoveredOnBailout(a, true);
@@ -34,7 +34,7 @@ function simdBox_i4(i) {
var uceFault_simdBox_f4 = eval(uneval(uceFault).replace('uceFault', 'uceFault_simdBox_f4'));
function simdBox_f4(i) {
var a = SIMD.float32x4(i, i + 0.1, i + 0.2, i + 0.3);
var a = SIMD.Float32x4(i, i + 0.1, i + 0.2, i + 0.3);
if (uceFault_simdBox_f4(i) || uceFault_simdBox_f4(i))
assertEqX4(a, [i, i + 0.1, i + 0.2, i + 0.3].map(Math.fround));
assertRecoveredOnBailout(a, true);
+101
View File
@@ -0,0 +1,101 @@
load(libdir + 'simd.js');
setJitCompilerOption("ion.warmup.trigger", 50);
function f() {
var f4 = SIMD.Float32x4(1, 2, 3, 4);
var i4 = SIMD.Int32x4(1, 2, 3, 4);
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.Int32x4.replaceLane(i4, 0, 42), [42, 2, 3, 4]);
assertEqX4(SIMD.Int32x4.replaceLane(i4, 1, 42), [1, 42, 3, 4]);
assertEqX4(SIMD.Int32x4.replaceLane(i4, 2, 42), [1, 2, 42, 4]);
assertEqX4(SIMD.Int32x4.replaceLane(i4, 3, 42), [1, 2, 3, 42]);
assertEqX4(SIMD.Float32x4.replaceLane(f4, 0, 42), [42, 2, 3, 4]);
assertEqX4(SIMD.Float32x4.replaceLane(f4, 1, 42), [1, 42, 3, 4]);
assertEqX4(SIMD.Float32x4.replaceLane(f4, 2, 42), [1, 2, 42, 4]);
assertEqX4(SIMD.Float32x4.replaceLane(f4, 3, 42), [1, 2, 3, 42]);
}
}
f();
function e() {
var f4 = SIMD.Float32x4(1, 2, 3, 4);
var i4 = SIMD.Int32x4(1, 2, 3, 4);
for (let i = 0; i < 150; i++) {
let caught = false;
try {
let x = SIMD.Int32x4.replaceLane(i < 149 ? i4 : f4, 0, 42);
} catch(e) {
assertEq(e instanceof TypeError, true);
assertEq(i, 149);
caught = true;
}
assertEq(i < 149 || caught, true);
}
for (let i = 0; i < 150; i++) {
let caught = false;
try {
let x = SIMD.Int32x4.replaceLane(i4, i < 149 ? 0 : 4, 42);
} catch(e) {
assertEq(e instanceof TypeError, true);
assertEq(i, 149);
caught = true;
}
assertEq(i < 149 || caught, true);
}
for (let i = 0; i < 150; i++) {
let caught = false;
try {
let x = SIMD.Int32x4.replaceLane(i4, i < 149 ? 0 : 1.1, 42);
} catch(e) {
assertEq(e instanceof TypeError, true);
assertEq(i, 149);
caught = true;
}
assertEq(i < 149 || caught, true);
}
for (let i = 0; i < 150; i++) {
let caught = false;
try {
let x = SIMD.Float32x4.replaceLane(i < 149 ? f4 : i4, 0, 42);
} catch(e) {
assertEq(e instanceof TypeError, true);
assertEq(i, 149);
caught = true;
}
assertEq(i < 149 || caught, true);
}
for (let i = 0; i < 150; i++) {
let caught = false;
try {
let x = SIMD.Float32x4.replaceLane(f4, i < 149 ? 0 : 4, 42);
} catch(e) {
assertEq(e instanceof TypeError, true);
assertEq(i, 149);
caught = true;
}
assertEq(i < 149 || caught, true);
}
for (let i = 0; i < 150; i++) {
let caught = false;
try {
let x = SIMD.Float32x4.replaceLane(f4, i < 149 ? 0 : 1.1, 42);
} catch(e) {
assertEq(e instanceof TypeError, true);
assertEq(i, 149);
caught = true;
}
assertEq(i < 149 || caught, true);
}
}
e();
+24 -24
View File
@@ -2,45 +2,45 @@ load(libdir + 'simd.js');
setJitCompilerOption("ion.warmup.trigger", 50);
function int32x4FromTypeBits(type, vec) {
if (type == SIMD.int32x4)
function Int32x4FromTypeBits(type, vec) {
if (type == SIMD.Int32x4)
return vec;
if (type == SIMD.float32x4)
return SIMD.int32x4.fromFloat32x4Bits(vec);
if (type == SIMD.Float32x4)
return SIMD.Int32x4.fromFloat32x4Bits(vec);
throw 'unimplemented';
}
function bitselect(type, mask, ifTrue, ifFalse) {
var int32x4 = SIMD.int32x4;
var tv = int32x4FromTypeBits(type, ifTrue);
var fv = int32x4FromTypeBits(type, ifFalse);
var tr = int32x4.and(mask, tv);
var fr = int32x4.and(int32x4.not(mask), fv);
var orApplied = int32x4.or(tr, fr);
var converted = type == int32x4 ? orApplied : type.fromInt32x4Bits(orApplied);
var Int32x4 = SIMD.Int32x4;
var tv = Int32x4FromTypeBits(type, ifTrue);
var fv = Int32x4FromTypeBits(type, ifFalse);
var tr = Int32x4.and(mask, tv);
var fr = Int32x4.and(Int32x4.not(mask), fv);
var orApplied = Int32x4.or(tr, fr);
var converted = type == Int32x4 ? orApplied : type.fromInt32x4Bits(orApplied);
return simdToArray(converted);
}
function f() {
var f1 = SIMD.float32x4(1, 2, 3, 4);
var f2 = SIMD.float32x4(NaN, Infinity, 3.14, -0);
var f1 = SIMD.Float32x4(1, 2, 3, 4);
var f2 = SIMD.Float32x4(NaN, Infinity, 3.14, -0);
var i1 = SIMD.int32x4(2, 3, 5, 8);
var i2 = SIMD.int32x4(13, 37, 24, 42);
var i1 = SIMD.Int32x4(2, 3, 5, 8);
var i2 = SIMD.Int32x4(13, 37, 24, 42);
var TTFT = SIMD.int32x4(-1, -1, 0, -1);
var TFTF = SIMD.int32x4(-1, 0, -1, 0);
var TTFT = SIMD.Int32x4(-1, -1, 0, -1);
var TFTF = SIMD.Int32x4(-1, 0, -1, 0);
var mask = SIMD.int32x4(0xdeadbeef, 0xbaadf00d, 0x00ff1ce, 0xdeadc0de);
var mask = SIMD.Int32x4(0xdeadbeef, 0xbaadf00d, 0x00ff1ce, 0xdeadc0de);
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.float32x4.select(TTFT, f1, f2), [f1.x, f1.y, f2.z, f1.w]);
assertEqX4(SIMD.float32x4.select(TFTF, f1, f2), [f1.x, f2.y, f1.z, f2.w]);
assertEqX4(SIMD.int32x4.select(TFTF, i1, i2), [i1.x, i2.y, i1.z, i2.w]);
assertEqX4(SIMD.int32x4.select(TTFT, i1, i2), [i1.x, i1.y, i2.z, i1.w]);
assertEqX4(SIMD.Float32x4.select(TTFT, f1, f2), [f1.x, f1.y, f2.z, f1.w]);
assertEqX4(SIMD.Float32x4.select(TFTF, f1, f2), [f1.x, f2.y, f1.z, f2.w]);
assertEqX4(SIMD.Int32x4.select(TFTF, i1, i2), [i1.x, i2.y, i1.z, i2.w]);
assertEqX4(SIMD.Int32x4.select(TTFT, i1, i2), [i1.x, i1.y, i2.z, i1.w]);
assertEqX4(SIMD.float32x4.bitselect(mask, f1, f2), bitselect(SIMD.float32x4, mask, f1, f2));
assertEqX4(SIMD.int32x4.bitselect(mask, i1, i2), bitselect(SIMD.int32x4, mask, i1, i2));
assertEqX4(SIMD.Float32x4.bitselect(mask, f1, f2), bitselect(SIMD.Float32x4, mask, f1, f2));
assertEqX4(SIMD.Int32x4.bitselect(mask, i1, i2), bitselect(SIMD.Int32x4, mask, i1, i2));
}
}
+22 -22
View File
@@ -14,7 +14,7 @@ function binaryUrsh(count, v) { if (count>>>0 >= 32) return 0; return (v >>> cou
function ursh(count) { return curry(binaryUrsh, count); }
function f() {
var v = SIMD.int32x4(1, 2, -3, 4);
var v = SIMD.Int32x4(1, 2, -3, 4);
var a = [1, 2, -3, 4];
var zeros = [0,0,0,0];
@@ -23,32 +23,32 @@ function f() {
var r;
for (var i = 0; i < 150; i++) {
// Constant shift counts
assertEqX4(SIMD.int32x4.shiftLeftByScalar(v, -1), a.map(lsh(-1)));
assertEqX4(SIMD.int32x4.shiftLeftByScalar(v, 0), a.map(lsh(0)));
assertEqX4(SIMD.int32x4.shiftLeftByScalar(v, 1), a.map(lsh(1)));
assertEqX4(SIMD.int32x4.shiftLeftByScalar(v, 2), a.map(lsh(2)));
assertEqX4(SIMD.int32x4.shiftLeftByScalar(v, 31), a.map(lsh(31)));
assertEqX4(SIMD.int32x4.shiftLeftByScalar(v, 32), a.map(lsh(32)));
assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, -1), a.map(lsh(-1)));
assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 0), a.map(lsh(0)));
assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 1), a.map(lsh(1)));
assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 2), a.map(lsh(2)));
assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 31), a.map(lsh(31)));
assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 32), a.map(lsh(32)));
assertEqX4(SIMD.int32x4.shiftRightArithmeticByScalar(v, -1), a.map(rsh(31)));
assertEqX4(SIMD.int32x4.shiftRightArithmeticByScalar(v, 0), a.map(rsh(0)));
assertEqX4(SIMD.int32x4.shiftRightArithmeticByScalar(v, 1), a.map(rsh(1)));
assertEqX4(SIMD.int32x4.shiftRightArithmeticByScalar(v, 2), a.map(rsh(2)));
assertEqX4(SIMD.int32x4.shiftRightArithmeticByScalar(v, 31), a.map(rsh(31)));
assertEqX4(SIMD.int32x4.shiftRightArithmeticByScalar(v, 32), a.map(rsh(31)));
assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, -1), a.map(rsh(31)));
assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, 0), a.map(rsh(0)));
assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, 1), a.map(rsh(1)));
assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, 2), a.map(rsh(2)));
assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, 31), a.map(rsh(31)));
assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, 32), a.map(rsh(31)));
assertEqX4(SIMD.int32x4.shiftRightLogicalByScalar(v, -1), a.map(ursh(-1)));
assertEqX4(SIMD.int32x4.shiftRightLogicalByScalar(v, 0), a.map(ursh(0)));
assertEqX4(SIMD.int32x4.shiftRightLogicalByScalar(v, 1), a.map(ursh(1)));
assertEqX4(SIMD.int32x4.shiftRightLogicalByScalar(v, 2), a.map(ursh(2)));
assertEqX4(SIMD.int32x4.shiftRightLogicalByScalar(v, 31), a.map(ursh(31)));
assertEqX4(SIMD.int32x4.shiftRightLogicalByScalar(v, 32), a.map(ursh(32)));
assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, -1), a.map(ursh(-1)));
assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, 0), a.map(ursh(0)));
assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, 1), a.map(ursh(1)));
assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, 2), a.map(ursh(2)));
assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, 31), a.map(ursh(31)));
assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, 32), a.map(ursh(32)));
// Non constant shift counts
var c = shifts[i % shifts.length];
assertEqX4(SIMD.int32x4.shiftLeftByScalar(v, c), a.map(lsh(c)));
assertEqX4(SIMD.int32x4.shiftRightArithmeticByScalar(v, c), a.map(rsh(c)));
assertEqX4(SIMD.int32x4.shiftRightLogicalByScalar(v, c), a.map(ursh(c)));
assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, c), a.map(lsh(c)));
assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, c), a.map(rsh(c)));
assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, c), a.map(ursh(c)));
}
return r;
}
+11 -11
View File
@@ -6,12 +6,12 @@ load(libdir + 'simd.js');
setJitCompilerOption("ion.warmup.trigger", 50);
function f() {
var i1 = SIMD.int32x4(1, 2, 3, 4);
var i2 = SIMD.int32x4(5, 6, 7, 8);
var i1 = SIMD.Int32x4(1, 2, 3, 4);
var i2 = SIMD.Int32x4(5, 6, 7, 8);
var leet = Math.fround(13.37);
var f1 = SIMD.float32x4(-.5, -0, Infinity, leet);
var f2 = SIMD.float32x4(42, .5, 23, -10);
var f1 = SIMD.Float32x4(-.5, -0, Infinity, leet);
var f2 = SIMD.Float32x4(42, .5, 23, -10);
// computes all rotations of a given array
function *gen(arr) {
@@ -35,31 +35,31 @@ function f() {
for (var i = 0; i < 150; i++) {
// Variable lanes
var r = SIMD.float32x4.shuffle(f1, f2, i % 8, (i + 1) % 8, (i + 2) % 8, (i + 3) % 8);
var r = SIMD.Float32x4.shuffle(f1, f2, i % 8, (i + 1) % 8, (i + 2) % 8, (i + 3) % 8);
assertEqX4(r, compF[i % 8]);
// Constant lanes
assertEqX4(SIMD.float32x4.shuffle(f1, f2, 3, 2, 4, 5), [leet, Infinity, 42, .5]);
assertEqX4(SIMD.Float32x4.shuffle(f1, f2, 3, 2, 4, 5), [leet, Infinity, 42, .5]);
// Variable lanes
var r = SIMD.int32x4.shuffle(i1, i2, i % 8, (i + 1) % 8, (i + 2) % 8, (i + 3) % 8);
var r = SIMD.Int32x4.shuffle(i1, i2, i % 8, (i + 1) % 8, (i + 2) % 8, (i + 3) % 8);
assertEqX4(r, compI[i % 8]);
// Constant lanes
assertEqX4(SIMD.int32x4.shuffle(i1, i2, 3, 2, 4, 5), [4, 3, 5, 6]);
assertEqX4(SIMD.Int32x4.shuffle(i1, i2, 3, 2, 4, 5), [4, 3, 5, 6]);
}
}
function testBailouts(uglyDuckling) {
var i1 = SIMD.int32x4(1, 2, 3, 4);
var i2 = SIMD.int32x4(5, 6, 7, 8);
var i1 = SIMD.Int32x4(1, 2, 3, 4);
var i2 = SIMD.Int32x4(5, 6, 7, 8);
for (var i = 0; i < 150; i++) {
// Test bailouts
var value = i == 149 ? uglyDuckling : 3;
var caught = false;
try {
assertEqX4(SIMD.int32x4.shuffle(i1, i2, value, 2, 4, 5), [4, 3, 5, 6]);
assertEqX4(SIMD.Int32x4.shuffle(i1, i2, value, 2, 4, 5), [4, 3, 5, 6]);
} catch(e) {
print(e);
caught = true;
+2 -2
View File
@@ -4,8 +4,8 @@ setJitCompilerOption("ion.warmup.trigger", 50);
function f() {
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.int32x4.splat(42), [42, 42, 42, 42]);
assertEqX4(SIMD.float32x4.splat(42), [42, 42, 42, 42]);
assertEqX4(SIMD.Int32x4.splat(42), [42, 42, 42, 42]);
assertEqX4(SIMD.Float32x4.splat(42), [42, 42, 42, 42]);
}
}
+35 -35
View File
@@ -15,7 +15,7 @@ function f() {
var i8 = new Int8Array(f32.buffer);
var u8 = new Uint8Array(f32.buffer);
var f4 = SIMD.float32x4(42, 43, 44, 45);
var f4 = SIMD.Float32x4(42, 43, 44, 45);
function check(n) {
assertEq(f32[0], 42);
@@ -30,78 +30,78 @@ function f() {
}
function testStore() {
SIMD.float32x4.store(f64, 0, f4);
SIMD.Float32x4.store(f64, 0, f4);
check(4);
SIMD.float32x4.store(f32, 0, f4);
SIMD.Float32x4.store(f32, 0, f4);
check(4);
SIMD.float32x4.store(i32, 0, f4);
SIMD.Float32x4.store(i32, 0, f4);
check(4);
SIMD.float32x4.store(u32, 0, f4);
SIMD.Float32x4.store(u32, 0, f4);
check(4);
SIMD.float32x4.store(i16, 0, f4);
SIMD.Float32x4.store(i16, 0, f4);
check(4);
SIMD.float32x4.store(u16, 0, f4);
SIMD.Float32x4.store(u16, 0, f4);
check(4);
SIMD.float32x4.store(i8, 0, f4);
SIMD.Float32x4.store(i8, 0, f4);
check(4);
SIMD.float32x4.store(u8, 0, f4);
SIMD.Float32x4.store(u8, 0, f4);
check(4);
}
function testStore1() {
SIMD.float32x4.store1(f64, 0, f4);
SIMD.Float32x4.store1(f64, 0, f4);
check(1);
SIMD.float32x4.store1(f32, 0, f4);
SIMD.Float32x4.store1(f32, 0, f4);
check(1);
SIMD.float32x4.store1(i32, 0, f4);
SIMD.Float32x4.store1(i32, 0, f4);
check(1);
SIMD.float32x4.store1(u32, 0, f4);
SIMD.Float32x4.store1(u32, 0, f4);
check(1);
SIMD.float32x4.store1(i16, 0, f4);
SIMD.Float32x4.store1(i16, 0, f4);
check(1);
SIMD.float32x4.store1(u16, 0, f4);
SIMD.Float32x4.store1(u16, 0, f4);
check(1);
SIMD.float32x4.store1(i8, 0, f4);
SIMD.Float32x4.store1(i8, 0, f4);
check(1);
SIMD.float32x4.store1(u8, 0, f4);
SIMD.Float32x4.store1(u8, 0, f4);
check(1);
}
function testStore2() {
SIMD.float32x4.store2(f64, 0, f4);
SIMD.Float32x4.store2(f64, 0, f4);
check(2);
SIMD.float32x4.store2(f32, 0, f4);
SIMD.Float32x4.store2(f32, 0, f4);
check(2);
SIMD.float32x4.store2(i32, 0, f4);
SIMD.Float32x4.store2(i32, 0, f4);
check(2);
SIMD.float32x4.store2(u32, 0, f4);
SIMD.Float32x4.store2(u32, 0, f4);
check(2);
SIMD.float32x4.store2(i16, 0, f4);
SIMD.Float32x4.store2(i16, 0, f4);
check(2);
SIMD.float32x4.store2(u16, 0, f4);
SIMD.Float32x4.store2(u16, 0, f4);
check(2);
SIMD.float32x4.store2(i8, 0, f4);
SIMD.Float32x4.store2(i8, 0, f4);
check(2);
SIMD.float32x4.store2(u8, 0, f4);
SIMD.Float32x4.store2(u8, 0, f4);
check(2);
}
function testStore3() {
SIMD.float32x4.store3(f64, 0, f4);
SIMD.Float32x4.store3(f64, 0, f4);
check(3);
SIMD.float32x4.store3(f32, 0, f4);
SIMD.Float32x4.store3(f32, 0, f4);
check(3);
SIMD.float32x4.store3(i32, 0, f4);
SIMD.Float32x4.store3(i32, 0, f4);
check(3);
SIMD.float32x4.store3(u32, 0, f4);
SIMD.Float32x4.store3(u32, 0, f4);
check(3);
SIMD.float32x4.store3(i16, 0, f4);
SIMD.Float32x4.store3(i16, 0, f4);
check(3);
SIMD.float32x4.store3(u16, 0, f4);
SIMD.Float32x4.store3(u16, 0, f4);
check(3);
SIMD.float32x4.store3(i8, 0, f4);
SIMD.Float32x4.store3(i8, 0, f4);
check(3);
SIMD.float32x4.store3(u8, 0, f4);
SIMD.Float32x4.store3(u8, 0, f4);
check(3);
}
@@ -122,12 +122,12 @@ function testBailout(uglyDuckling) {
var i8 = new Int8Array(f32.buffer);
var f4 = SIMD.float32x4(42, 43, 44, 45);
var f4 = SIMD.Float32x4(42, 43, 44, 45);
for (var i = 0; i < 150; i++) {
var caught = false;
try {
SIMD.float32x4.store(i8, (i < 149) ? 0 : (16 << 2) - (4 << 2) + 1, f4);
SIMD.Float32x4.store(i8, (i < 149) ? 0 : (16 << 2) - (4 << 2) + 1, f4);
} catch (e) {
print(e);
assertEq(e instanceof RangeError, true);
+23 -8
View File
@@ -6,10 +6,10 @@ load(libdir + 'simd.js');
setJitCompilerOption("ion.warmup.trigger", 50);
function f() {
var i4 = SIMD.int32x4(1, 2, 3, 4);
var i4 = SIMD.Int32x4(1, 2, 3, 4);
var leet = Math.fround(13.37);
var f4 = SIMD.float32x4(-.5, -0, Infinity, leet);
var f4 = SIMD.Float32x4(-.5, -0, Infinity, leet);
var compI = [
[1,2,3,4],
@@ -27,29 +27,29 @@ function f() {
for (var i = 0; i < 150; i++) {
// Variable lanes
var r = SIMD.float32x4.swizzle(f4, i % 4, (i + 1) % 4, (i + 2) % 4, (i + 3) % 4);
var r = SIMD.Float32x4.swizzle(f4, i % 4, (i + 1) % 4, (i + 2) % 4, (i + 3) % 4);
assertEqX4(r, compF[i % 4]);
// Constant lanes
assertEqX4(SIMD.float32x4.swizzle(f4, 3, 2, 1, 0), [leet, Infinity, -0, -.5]);
assertEqX4(SIMD.Float32x4.swizzle(f4, 3, 2, 1, 0), [leet, Infinity, -0, -.5]);
// Variable lanes
var r = SIMD.int32x4.swizzle(i4, i % 4, (i + 1) % 4, (i + 2) % 4, (i + 3) % 4);
var r = SIMD.Int32x4.swizzle(i4, i % 4, (i + 1) % 4, (i + 2) % 4, (i + 3) % 4);
assertEqX4(r, compI[i % 4]);
// Constant lanes
assertEqX4(SIMD.int32x4.swizzle(i4, 3, 2, 1, 0), [4, 3, 2, 1]);
assertEqX4(SIMD.Int32x4.swizzle(i4, 3, 2, 1, 0), [4, 3, 2, 1]);
}
}
function testBailouts(uglyDuckling) {
var i4 = SIMD.int32x4(1, 2, 3, 4);
var i4 = SIMD.Int32x4(1, 2, 3, 4);
for (var i = 0; i < 150; i++) {
// Test bailouts
var value = i == 149 ? uglyDuckling : 0;
var caught = false;
try {
assertEqX4(SIMD.int32x4.swizzle(i4, value, 3, 2, 0), [1, 4, 3, 1]);
assertEqX4(SIMD.Int32x4.swizzle(i4, value, 3, 2, 0), [1, 4, 3, 1]);
} catch(e) {
print(e);
caught = true;
@@ -60,6 +60,14 @@ function testBailouts(uglyDuckling) {
}
}
function testInt32x4SwizzleBailout() {
// Test out-of-bounds non-constant indices. This is expected to throw.
var i4 = SIMD.Int32x4(1, 2, 3, 4);
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.Int32x4.swizzle(i4, i, 3, 2, 0), [i + 1, 4, 3, 1]);
}
}
f();
testBailouts(-1);
testBailouts(4);
@@ -69,3 +77,10 @@ testBailouts(null);
testBailouts({});
testBailouts('one');
testBailouts(true);
try {
testInt32x4SwizzleBailout();
throw 'not caught';
} catch(e) {
assertEq(e instanceof TypeError, true);
}
+10 -10
View File
@@ -13,20 +13,20 @@ var notf = (function() {
})();
function f() {
var f4 = SIMD.float32x4(1, 2, 3, 4);
var i4 = SIMD.int32x4(1, 2, 3, 4);
var f4 = SIMD.Float32x4(1, 2, 3, 4);
var i4 = SIMD.Int32x4(1, 2, 3, 4);
var BitOrZero = (x) => x | 0;
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.float32x4.not(f4), unaryX4(notf, f4, Math.fround));
assertEqX4(SIMD.float32x4.neg(f4), unaryX4((x) => -x, f4, Math.fround));
assertEqX4(SIMD.float32x4.abs(f4), unaryX4(Math.abs, f4, Math.fround));
assertEqX4(SIMD.float32x4.sqrt(f4), unaryX4(Math.sqrt, f4, Math.fround));
assertEqX4(SIMD.Float32x4.not(f4), unaryX4(notf, f4, Math.fround));
assertEqX4(SIMD.Float32x4.neg(f4), unaryX4((x) => -x, f4, Math.fround));
assertEqX4(SIMD.Float32x4.abs(f4), unaryX4(Math.abs, f4, Math.fround));
assertEqX4(SIMD.Float32x4.sqrt(f4), unaryX4(Math.sqrt, f4, Math.fround));
assertEqX4(SIMD.float32x4.reciprocalApproximation(f4), unaryX4((x) => 1 / x, f4, Math.fround), assertNear);
assertEqX4(SIMD.float32x4.reciprocalSqrtApproximation(f4), unaryX4((x) => 1 / Math.sqrt(x), f4, Math.fround), assertNear);
assertEqX4(SIMD.Float32x4.reciprocalApproximation(f4), unaryX4((x) => 1 / x, f4, Math.fround), assertNear);
assertEqX4(SIMD.Float32x4.reciprocalSqrtApproximation(f4), unaryX4((x) => 1 / Math.sqrt(x), f4, Math.fround), assertNear);
assertEqX4(SIMD.int32x4.not(i4), unaryX4((x) => ~x, i4, BitOrZero));
assertEqX4(SIMD.int32x4.neg(i4), unaryX4((x) => -x, i4, BitOrZero));
assertEqX4(SIMD.Int32x4.not(i4), unaryX4((x) => ~x, i4, BitOrZero));
assertEqX4(SIMD.Int32x4.neg(i4), unaryX4((x) => -x, i4, BitOrZero));
}
}
+40 -4
View File
@@ -5,9 +5,9 @@ setJitCompilerOption("baseline.warmup.trigger", 10);
setJitCompilerOption("ion.warmup.trigger", 30);
var max = 40, pivot = 35;
var i32x4 = SIMD.int32x4;
var f32x4 = SIMD.float32x4;
var i32x4Add = SIMD.int32x4.add;
var i32x4 = SIMD.Int32x4;
var f32x4 = SIMD.Float32x4;
var i32x4Add = SIMD.Int32x4.add;
var FakeSIMDType = function (o) { this.x = o.x; this.y = o.y; this.z = o.z; this.w = o.w; };
if (this.hasOwnProperty("TypedObject")) {
@@ -15,7 +15,6 @@ if (this.hasOwnProperty("TypedObject")) {
FakeSIMDType = new TO.StructType({ x: TO.int32, y: TO.int32, z: TO.int32, w: TO.int32 });
}
function simdunbox_bail_undef(i, lhs, rhs) {
return i32x4Add(lhs, rhs);
}
@@ -106,3 +105,40 @@ for (i = 0; i < max; i++) {
assertEqX4(arr_typeobj[i], ref);
assertEqX4(arr_badsimd[i], ref);
}
// Check that unbox operations aren't removed
(function() {
function add(i, v, w) {
if (i % 2 == 0) {
SIMD.Int32x4.add(v, w);
} else {
SIMD.Float32x4.add(v, w);
}
}
var i = 0;
var caught = false;
var f4 = SIMD.Float32x4(1,2,3,4);
var i4 = SIMD.Int32x4(1,2,3,4);
try {
for (; i < 200; i++) {
if (i % 2 == 0) {
add(i, i4, i4);
} else if (i == 199) {
add(i, i4, f4);
} else {
add(i, f4, f4);
}
}
} catch(e) {
print(e);
assertEq(e instanceof TypeError, true);
assertEq(i, 199);
caught = true;
}
assertEq(i < 199 || caught, true);
})();
-23
View File
@@ -1,23 +0,0 @@
load(libdir + 'simd.js');
setJitCompilerOption("ion.warmup.trigger", 50);
function f() {
var f4 = SIMD.float32x4(1, 2, 3, 4);
var i4 = SIMD.int32x4(1, 2, 3, 4);
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.int32x4.withX(i4, 42), [42, 2, 3, 4]);
assertEqX4(SIMD.int32x4.withY(i4, 42), [1, 42, 3, 4]);
assertEqX4(SIMD.int32x4.withZ(i4, 42), [1, 2, 42, 4]);
assertEqX4(SIMD.int32x4.withW(i4, 42), [1, 2, 3, 42]);
assertEqX4(SIMD.float32x4.withX(f4, 42), [42, 2, 3, 4]);
assertEqX4(SIMD.float32x4.withY(f4, 42), [1, 42, 3, 4]);
assertEqX4(SIMD.float32x4.withZ(f4, 42), [1, 2, 42, 4]);
assertEqX4(SIMD.float32x4.withW(f4, 42), [1, 2, 3, 42]);
}
}
f();
@@ -1,12 +0,0 @@
if (typeof TypedObject === "undefined")
quit();
var int32x4 = SIMD.int32x4;
var a = int32x4((4294967295), 200, 300, 400);
addCase( new Array(Math.pow(2,12)) );
for ( var arg = "", i = 0; i < Math.pow(2,12); i++ ) {}
addCase( a );
function addCase(object) {
object.length
}
@@ -1,10 +0,0 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
if (!this.hasOwnProperty("TypedObject"))
quit();
var float32x4 = SIMD.float32x4;
float32x4.array(1);
+5 -5
View File
@@ -21,10 +21,10 @@ if (!isSimdAvailable() || typeof SIMD === 'undefined') {
var v = asmLink(asmCompile('global', `
"use asm";
var frd = global.Math.fround;
var float32x4 = global.SIMD.float32x4;
var splat = float32x4.splat;
var Float32x4 = global.SIMD.Float32x4;
var splat = Float32x4.splat;
function e() {
var v = float32x4(0,0,0,0);
var v = Float32x4(0,0,0,0);
var x = frd(0.);
v = splat(.1e+71);
x = v.x;
@@ -40,8 +40,8 @@ assertEq(v, NaN);
setJitCompilerOption("ion.gvn.enable", 0);
var v = asmLink(asmCompile('global', `
"use asm";
var float32x4 = global.SIMD.float32x4;
var splat = float32x4.splat;
var Float32x4 = global.SIMD.Float32x4;
var splat = Float32x4.splat;
function e() {
return +splat(.1e+71).x;
}
-7
View File
@@ -10,11 +10,6 @@
if (!isAsmJSCompilationAvailable())
quit(0);
/*
// Commented out until we can fix bug #1172517, which makes this fail
// for other reasons.
function module_a(stdlib, foreign, heap) {
"use asm";
@@ -35,8 +30,6 @@ function module_a(stdlib, foreign, heap) {
if (this.SharedArrayBuffer)
assertEq(isAsmJSModule(module_a), true);
*/
function module_b(stdlib, foreign, heap) {
"use asm";
+2 -2
View File
@@ -56,8 +56,8 @@ var code = `
const getAccelDataSteps = imp.accelDataSteps | 0;
var getActualBirds = imp.getActualBirds;
var i4 = global.SIMD.int32x4;
var f4 = global.SIMD.float32x4;
var i4 = global.SIMD.Int32x4;
var f4 = global.SIMD.Float32x4;
var i4add = i4.add;
var i4and = i4.and;
var f4select = f4.select;
@@ -28,9 +28,9 @@ var moduleCode = `
"use asm"
var b8 = new global.Uint8Array(buffer);
var toF = global.Math.fround;
var i4 = global.SIMD.int32x4;
var i4 = global.SIMD.Int32x4;
var ci4 = i4.check;
var f4 = global.SIMD.float32x4;
var f4 = global.SIMD.Float32x4;
var i4add = i4.add;
var i4and = i4.and;
var f4add = f4.add;
@@ -30,6 +30,9 @@ function m(stdlib, ffi, heap)
return {add_sharedEv:add_sharedEv};
}
if (isAsmJSCompilationAvailable())
assertEq(isAsmJSModule(m), true);
var x;
var sab = new SharedArrayBuffer(65536);
+42 -36
View File
@@ -24,7 +24,7 @@ function loadModule_int32(stdlib, foreign, heap) {
// Load element 0
function do_load() {
var v = 0;
v = atomic_load(i32a, 0);
v = atomic_load(i32a, 0)|0;
return v|0;
}
@@ -32,14 +32,14 @@ function loadModule_int32(stdlib, foreign, heap) {
function do_load_i(i) {
i = i|0;
var v = 0;
v = atomic_load(i32a, i>>2);
v = atomic_load(i32a, i>>2)|0;
return v|0;
}
// Store 37 in element 0
function do_store() {
var v = 0;
v = atomic_store(i32a, 0, 37);
v = atomic_store(i32a, 0, 37)|0;
return v|0;
}
@@ -47,14 +47,14 @@ function loadModule_int32(stdlib, foreign, heap) {
function do_store_i(i) {
i = i|0;
var v = 0;
v = atomic_store(i32a, i>>2, 37);
v = atomic_store(i32a, i>>2, 37)|0;
return v|0;
}
// Add 37 to element 10
function do_add() {
var v = 0;
v = atomic_add(i32a, 10, 37);
v = atomic_add(i32a, 10, 37)|0;
return v|0;
}
@@ -62,14 +62,14 @@ function loadModule_int32(stdlib, foreign, heap) {
function do_add_i(i) {
i = i|0;
var v = 0;
v = atomic_add(i32a, i>>2, 37);
v = atomic_add(i32a, i>>2, 37)|0;
return v|0;
}
// Subtract 148 from element 20
function do_sub() {
var v = 0;
v = atomic_sub(i32a, 20, 148);
v = atomic_sub(i32a, 20, 148)|0;
return v|0;
}
@@ -77,14 +77,14 @@ function loadModule_int32(stdlib, foreign, heap) {
function do_sub_i(i) {
i = i|0;
var v = 0;
v = atomic_sub(i32a, i>>2, 148);
v = atomic_sub(i32a, i>>2, 148)|0;
return v|0;
}
// AND 0x33333333 into element 30
function do_and() {
var v = 0;
v = atomic_and(i32a, 30, 0x33333333);
v = atomic_and(i32a, 30, 0x33333333)|0;
return v|0;
}
@@ -92,14 +92,14 @@ function loadModule_int32(stdlib, foreign, heap) {
function do_and_i(i) {
i = i|0;
var v = 0;
v = atomic_and(i32a, i>>2, 0x33333333);
v = atomic_and(i32a, i>>2, 0x33333333)|0;
return v|0;
}
// OR 0x33333333 into element 40
function do_or() {
var v = 0;
v = atomic_or(i32a, 40, 0x33333333);
v = atomic_or(i32a, 40, 0x33333333)|0;
return v|0;
}
@@ -107,14 +107,14 @@ function loadModule_int32(stdlib, foreign, heap) {
function do_or_i(i) {
i = i|0;
var v = 0;
v = atomic_or(i32a, i>>2, 0x33333333);
v = atomic_or(i32a, i>>2, 0x33333333)|0;
return v|0;
}
// XOR 0x33333333 into element 50
function do_xor() {
var v = 0;
v = atomic_xor(i32a, 50, 0x33333333);
v = atomic_xor(i32a, 50, 0x33333333)|0;
return v|0;
}
@@ -122,21 +122,21 @@ function loadModule_int32(stdlib, foreign, heap) {
function do_xor_i(i) {
i = i|0;
var v = 0;
v = atomic_xor(i32a, i>>2, 0x33333333);
v = atomic_xor(i32a, i>>2, 0x33333333)|0;
return v|0;
}
// CAS element 100: 0 -> -1
function do_cas1() {
var v = 0;
v = atomic_cmpxchg(i32a, 100, 0, -1);
v = atomic_cmpxchg(i32a, 100, 0, -1)|0;
return v|0;
}
// CAS element 100: -1 -> 0x5A5A5A5A
function do_cas2() {
var v = 0;
v = atomic_cmpxchg(i32a, 100, -1, 0x5A5A5A5A);
v = atomic_cmpxchg(i32a, 100, -1, 0x5A5A5A5A)|0;
return v|0;
}
@@ -144,7 +144,7 @@ function loadModule_int32(stdlib, foreign, heap) {
function do_cas1_i(i) {
i = i|0;
var v = 0;
v = atomic_cmpxchg(i32a, i>>2, 0, -1);
v = atomic_cmpxchg(i32a, i>>2, 0, -1)|0;
return v|0;
}
@@ -152,7 +152,7 @@ function loadModule_int32(stdlib, foreign, heap) {
function do_cas2_i(i) {
i = i|0;
var v = 0;
v = atomic_cmpxchg(i32a, i>>2, -1, 0x5A5A5A5A);
v = atomic_cmpxchg(i32a, i>>2, -1, 0x5A5A5A5A)|0;
return v|0;
}
@@ -177,6 +177,9 @@ function loadModule_int32(stdlib, foreign, heap) {
cas2_i: do_cas2_i };
}
if (isAsmJSCompilationAvailable())
assertEq(isAsmJSModule(loadModule_int32), true);
function loadModule_int8(stdlib, foreign, heap) {
"use asm";
@@ -194,7 +197,7 @@ function loadModule_int8(stdlib, foreign, heap) {
// Load element 0
function do_load() {
var v = 0;
v = atomic_load(i8a, 0);
v = atomic_load(i8a, 0)|0;
return v|0;
}
@@ -202,14 +205,14 @@ function loadModule_int8(stdlib, foreign, heap) {
function do_load_i(i) {
i = i|0;
var v = 0;
v = atomic_load(i8a, i);
v = atomic_load(i8a, i)|0;
return v|0;
}
// Store 37 in element 0
function do_store() {
var v = 0;
v = atomic_store(i8a, 0, 37);
v = atomic_store(i8a, 0, 37)|0;
return v|0;
}
@@ -217,14 +220,14 @@ function loadModule_int8(stdlib, foreign, heap) {
function do_store_i(i) {
i = i|0;
var v = 0;
v = atomic_store(i8a, i, 37);
v = atomic_store(i8a, i, 37)|0;
return v|0;
}
// Add 37 to element 10
function do_add() {
var v = 0;
v = atomic_add(i8a, 10, 37);
v = atomic_add(i8a, 10, 37)|0;
return v|0;
}
@@ -232,14 +235,14 @@ function loadModule_int8(stdlib, foreign, heap) {
function do_add_i(i) {
i = i|0;
var v = 0;
v = atomic_add(i8a, i, 37);
v = atomic_add(i8a, i, 37)|0;
return v|0;
}
// Subtract 108 from element 20
function do_sub() {
var v = 0;
v = atomic_sub(i8a, 20, 108);
v = atomic_sub(i8a, 20, 108)|0;
return v|0;
}
@@ -247,14 +250,14 @@ function loadModule_int8(stdlib, foreign, heap) {
function do_sub_i(i) {
i = i|0;
var v = 0;
v = atomic_sub(i8a, i, 108);
v = atomic_sub(i8a, i, 108)|0;
return v|0;
}
// AND 0x33 into element 30
function do_and() {
var v = 0;
v = atomic_and(i8a, 30, 0x33);
v = atomic_and(i8a, 30, 0x33)|0;
return v|0;
}
@@ -262,14 +265,14 @@ function loadModule_int8(stdlib, foreign, heap) {
function do_and_i(i) {
i = i|0;
var v = 0;
v = atomic_and(i8a, i, 0x33);
v = atomic_and(i8a, i, 0x33)|0;
return v|0;
}
// OR 0x33 into element 40
function do_or() {
var v = 0;
v = atomic_or(i8a, 40, 0x33);
v = atomic_or(i8a, 40, 0x33)|0;
return v|0;
}
@@ -277,14 +280,14 @@ function loadModule_int8(stdlib, foreign, heap) {
function do_or_i(i) {
i = i|0;
var v = 0;
v = atomic_or(i8a, i, 0x33);
v = atomic_or(i8a, i, 0x33)|0;
return v|0;
}
// XOR 0x33 into element 50
function do_xor() {
var v = 0;
v = atomic_xor(i8a, 50, 0x33);
v = atomic_xor(i8a, 50, 0x33)|0;
return v|0;
}
@@ -292,21 +295,21 @@ function loadModule_int8(stdlib, foreign, heap) {
function do_xor_i(i) {
i = i|0;
var v = 0;
v = atomic_xor(i8a, i, 0x33);
v = atomic_xor(i8a, i, 0x33)|0;
return v|0;
}
// CAS element 100: 0 -> -1
function do_cas1() {
var v = 0;
v = atomic_cmpxchg(i8a, 100, 0, -1);
v = atomic_cmpxchg(i8a, 100, 0, -1)|0;
return v|0;
}
// CAS element 100: -1 -> 0x5A
function do_cas2() {
var v = 0;
v = atomic_cmpxchg(i8a, 100, -1, 0x5A);
v = atomic_cmpxchg(i8a, 100, -1, 0x5A)|0;
return v|0;
}
@@ -314,7 +317,7 @@ function loadModule_int8(stdlib, foreign, heap) {
function do_cas1_i(i) {
i = i|0;
var v = 0;
v = atomic_cmpxchg(i8a, i, 0, -1);
v = atomic_cmpxchg(i8a, i, 0, -1)|0;
return v|0;
}
@@ -322,7 +325,7 @@ function loadModule_int8(stdlib, foreign, heap) {
function do_cas2_i(i) {
i = i|0;
var v = 0;
v = atomic_cmpxchg(i8a, i, -1, 0x5A);
v = atomic_cmpxchg(i8a, i, -1, 0x5A)|0;
return v|0;
}
@@ -346,6 +349,9 @@ function loadModule_int8(stdlib, foreign, heap) {
cas2_i: do_cas2_i };
}
if (isAsmJSCompilationAvailable())
assertEq(isAsmJSModule(loadModule_int8), true);
// TODO: halfword arrays
// TODO: signed vs unsigned; negative results
@@ -6,7 +6,7 @@ if (typeof SIMD === 'undefined' || !isSimdAvailable()) {
(function(global) {
"use asm";
var frd = global.Math.fround;
var fx4 = global.SIMD.float32x4;
var fx4 = global.SIMD.Float32x4;
var fsp = fx4.splat;
function s(){}
function d(x){x=fx4(x);}
@@ -21,7 +21,7 @@ if (typeof SIMD === 'undefined' || !isSimdAvailable()) {
(function(m) {
"use asm"
var g = m.SIMD.int32x4
var g = m.SIMD.Int32x4
var h = g.select
function f() {
var x = g(0, 0, 0, 0)
@@ -34,7 +34,7 @@ if (typeof SIMD === 'undefined' || !isSimdAvailable()) {
t = (function(global) {
"use asm"
var toF = global.Math.fround
var f4 = global.SIMD.float32x4
var f4 = global.SIMD.Float32x4
function p(x, y, width, value, max_iterations) {
x = x | 0
y = y | 0
@@ -0,0 +1,49 @@
if (!this.SharedArrayBuffer || !isAsmJSCompilationAvailable())
quit(0);
// The way this is constructed, either the first module does not
// verify as asm.js (if the >>>0 is left off, which was legal prior to
// bug 1155176), or the results of the two modules have to be equal.
function m(stdlib, ffi, heap) {
"use asm";
var view = new stdlib.SharedUint32Array(heap);
var cas = stdlib.Atomics.compareExchange;
var hi = ffi.hi;
function run() {
hi(+(cas(view, 37, 0, 0)>>>0));
}
return run;
}
assertEq(isAsmJSModule(m), true);
function nonm(stdlib, ffi, heap) {
var view = new stdlib.SharedUint32Array(heap);
var cas = stdlib.Atomics.compareExchange;
var hi = ffi.hi;
function run() {
hi(+cas(view, 37, 0, 0));
}
return run;
}
var sab = new SharedArrayBuffer(65536);
var ua = new SharedUint32Array(sab);
var results = [];
var mrun = m(this, {hi: function (x) { results.push(x) }}, sab);
var nonmrun = nonm(this, {hi: function (x) { results.push(x) }}, sab);
ua[37] = 0x80000001;
mrun();
nonmrun();
assertEq(results[0], ua[37]);
assertEq(results[0], results[1]);
@@ -0,0 +1,23 @@
if (!this.SharedArrayBuffer)
quit(0);
function m(stdlib, ffi, heap) {
"use asm";
var HEAP32 = new stdlib.SharedInt32Array(heap);
var add = stdlib.Atomics.add;
var load = stdlib.Atomics.load;
function add_sharedEv(i1) {
i1 = i1 | 0;
load(HEAP32, i1 >> 2);
add(HEAP32, i1 >> 2, 1);
load(HEAP32, i1 >> 2);
}
return {add_sharedEv:add_sharedEv};
}
if (isAsmJSCompilationAvailable())
assertEq(isAsmJSModule(m), true);
var sab = new SharedArrayBuffer(65536);
var {add_sharedEv} = m(this, {}, sab);
add_sharedEv(sab.byteLength);
+1 -1
View File
@@ -168,7 +168,7 @@ assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[((
assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[((i32[i>>2]|0) + (g()|0)) >> 2] = 0 } function g() { return 0 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i >> 2] = (i32[i>>2]|0) + (g()|0) } function g() { return 0 } return f');
if (isSimdAvailable() && typeof SIMD !== 'undefined')
asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'var i4 = glob.SIMD.int32x4; var add = i4.add;' + CHANGE_FUN + 'function f(i) { i=i|0; i32[i4(i,1,2,i).x >> 2]; i32[add(i4(0,0,0,0),i4(1,1,1,1)).x >> 2]; } return f');
asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'var i4 = glob.SIMD.Int32x4; var add = i4.add;' + CHANGE_FUN + 'function f(i) { i=i|0; i32[i4(i,1,2,i).x >> 2]; i32[add(i4(0,0,0,0),i4(1,1,1,1)).x >> 2]; } return f');
// Tests for constant heap accesses when change-heap is used
@@ -31,7 +31,7 @@ function assertEqX4(real, expected, assertFunc) {
try {
// Load / Store
var IMPORTS = USE_ASM + 'var H=new glob.Uint8Array(heap); var i4=glob.SIMD.int32x4; var ci4=i4.check; var load=i4.load; var store=i4.store;';
var IMPORTS = USE_ASM + 'var H=new glob.Uint8Array(heap); var i4=glob.SIMD.Int32x4; var ci4=i4.check; var load=i4.load; var store=i4.store;';
// Bad number of args
assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){load();} return f");
@@ -45,7 +45,7 @@ assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){var i=0.;load(H
assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "var H2=new glob.Int32Array(heap); function f(){var i=0;load(H2, i)} return f");
assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "var H2=42; function f(){var i=0;load(H2, i)} return f");
assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){var i=0;load(H2, i)} return f");
assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "var f4=glob.SIMD.float32x4; function f(){var i=0;var vec=f4(1,2,3,4); store(H, i, vec)} return f");
assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "var f4=glob.SIMD.Float32x4; function f(){var i=0;var vec=f4(1,2,3,4); store(H, i, vec)} return f");
// Bad coercions of returned values
assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){var i=0;return load(H, i)|0;} return f");
@@ -77,12 +77,12 @@ var loadStoreCode = `
var H = new glob.Uint8Array(heap);
var i4 = glob.SIMD.int32x4;
var i4 = glob.SIMD.Int32x4;
var i4load = i4.load;
var i4store = i4.store;
var ci4 = i4.check;
var f4 = glob.SIMD.float32x4;
var f4 = glob.SIMD.Float32x4;
var f4load = f4.load;
var f4store = f4.store;
var cf4 = f4.check;
@@ -159,7 +159,7 @@ assertThrowsInstanceOf(() => f32l(SIZE - 3), RangeError);
var code = `
"use asm";
var f4 = glob.SIMD.float32x4;
var f4 = glob.SIMD.Float32x4;
var f4l = f4.load;
var u8 = new glob.Uint8Array(heap);
@@ -183,8 +183,8 @@ assertThrowsInstanceOf(() => asmLink(asmCompile('glob', 'ffi', 'heap', code), th
// Float32x4.store
function f32s(n, v) { return m.f32s((n|0) << 2 | 0, v); };
var vec = SIMD.float32x4(5,6,7,8);
var vec2 = SIMD.float32x4(0,1,2,3);
var vec = SIMD.Float32x4(5,6,7,8);
var vec2 = SIMD.Float32x4(0,1,2,3);
reset();
f32s(0, vec);
@@ -242,8 +242,8 @@ assertThrowsInstanceOf(() => i32(SIZE - 3), RangeError);
// Int32x4.store
function i32s(n, v) { return m.i32s((n|0) << 2 | 0, v); };
var vec = SIMD.int32x4(5,6,7,8);
var vec2 = SIMD.int32x4(0,1,2,3);
var vec = SIMD.Int32x4(5,6,7,8);
var vec2 = SIMD.Int32x4(0,1,2,3);
reset();
i32s(0, vec);
@@ -488,26 +488,26 @@ function TestPartialStores(m, typedArray, typeName, x, y, z, w) {
}
var f32 = new Float32Array(SIZE);
var mfloat32x4 = asmLink(asmCompile('glob', 'ffi', 'heap', MakeCodeFor('float32x4')), this, null, f32.buffer);
var mFloat32x4 = asmLink(asmCompile('glob', 'ffi', 'heap', MakeCodeFor('Float32x4')), this, null, f32.buffer);
TestPartialLoads(mfloat32x4, f32,
TestPartialLoads(mFloat32x4, f32,
(i) => i + 1,
(i) => Math.fround(13.37),
(i) => Math.fround(1/i),
(i) => Math.fround(Math.sqrt(0x2000 - i)));
TestPartialStores(mfloat32x4, f32, 'float32x4', 42, -0, NaN, 0.1337);
TestPartialStores(mFloat32x4, f32, 'Float32x4', 42, -0, NaN, 0.1337);
var i32 = new Int32Array(f32.buffer);
var mint32x4 = asmLink(asmCompile('glob', 'ffi', 'heap', MakeCodeFor('int32x4')), this, null, i32.buffer);
var mInt32x4 = asmLink(asmCompile('glob', 'ffi', 'heap', MakeCodeFor('Int32x4')), this, null, i32.buffer);
TestPartialLoads(mint32x4, i32,
TestPartialLoads(mInt32x4, i32,
(i) => i + 1 | 0,
(i) => -i | 0,
(i) => i * 2 | 0,
(i) => 42);
TestPartialStores(mint32x4, i32, 'int32x4', 42, -3, 13, 37);
TestPartialStores(mInt32x4, i32, 'Int32x4', 42, -3, 13, 37);
})();
+123 -121
View File
@@ -1,4 +1,5 @@
load(libdir + "asm.js");
load(libdir + "asserts.js");
var heap = new ArrayBuffer(0x10000);
// Set to true to see more JS debugging spew
@@ -9,12 +10,12 @@ if (!isSimdAvailable() || typeof SIMD === 'undefined') {
quit(0);
}
const I32 = 'var i4 = glob.SIMD.int32x4;'
const I32 = 'var i4 = glob.SIMD.Int32x4;'
const CI32 = 'var ci4 = i4.check;'
const I32A = 'var i4a = i4.add;'
const I32S = 'var i4s = i4.sub;'
const I32M = 'var i4m = i4.mul;'
const F32 = 'var f4 = glob.SIMD.float32x4;'
const F32 = 'var f4 = glob.SIMD.Float32x4;'
const CF32 = 'var cf4 = f4.check;'
const F32A = 'var f4a = f4.add;'
const F32S = 'var f4s = f4.sub;'
@@ -56,10 +57,10 @@ try {
// 1. Constructors
// 1.1 Compilation
assertAsmTypeFail('glob', USE_ASM + "var i4 = int32x4 ; return {}") ;
assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.int32x4 ; return {}") ;
assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.globglob.int32x4 ; return {}") ;
assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.Math.int32x4 ; return {}") ;
assertAsmTypeFail('glob', USE_ASM + "var i4 = Int32x4 ; return {}") ;
assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.Int32x4 ; return {}") ;
assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.globglob.Int32x4 ; return {}") ;
assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.Math.Int32x4 ; return {}") ;
assertAsmTypeFail('glob', USE_ASM + "var herd = glob.SIMD.ponyX4 ; return {}") ;
// 1.2 Linking
@@ -67,22 +68,22 @@ assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: 42});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: Math.fround});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: 42}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: Math.fround}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: new Array}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: SIMD.float32x4}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {Int32x4: 42}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {Int32x4: Math.fround}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {Int32x4: new Array}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {Int32x4: SIMD.Float32x4}});
[Type, int32] = [TypedObject.StructType, TypedObject.int32];
var MyStruct = new Type({'x': int32, 'y': int32, 'z': int32, 'w': int32});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: MyStruct}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {int32x4: new MyStruct}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {Int32x4: MyStruct}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {Int32x4: new MyStruct}});
assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {} return f"), {SIMD:{int32x4: SIMD.int32x4}})(), undefined);
assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {} return f"), {SIMD:{Int32x4: SIMD.Int32x4}})(), undefined);
assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {float32x4: 42}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {float32x4: Math.fround}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {float32x4: new Array}});
assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {} return f"), {SIMD:{float32x4: SIMD.float32x4}})(), undefined);
assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {Float32x4: 42}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {Float32x4: Math.fround}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {Float32x4: new Array}});
assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {} return f"), {SIMD:{Float32x4: SIMD.Float32x4}})(), undefined);
// 1.3 Correctness
// 1.3.1 Local variables declarations
@@ -158,7 +159,7 @@ function CheckSignMask(innerBody, coerceBefore, coerceAfter, expected) {
var lanes = ['x', 'y', 'z', 'w'];
for (var i = 0; i < lanes.length; i++) {
var lane = lanes[i];
var laneCheckCode = `"use asm"; var i4=glob.SIMD.int32x4; var f4=glob.SIMD.float32x4; function f() {${innerBody}; return ${coerceBefore}x.${lane}${coerceAfter} } return f;`;
var laneCheckCode = `"use asm"; var i4=glob.SIMD.Int32x4; var f4=glob.SIMD.Float32x4; function f() {${innerBody}; return ${coerceBefore}x.${lane}${coerceAfter} } return f;`;
assertEq(asmLink(asmCompile('glob', laneCheckCode), this)(), expected[i]);
}
}
@@ -243,13 +244,13 @@ assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "function f() {var x=f4(1,2,3,4)
CheckF4('', 'var x=f4(1,2,3,4); var y=f4(4,3,2,1); x=3?y:x', [4, 3, 2, 1]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=x|0; var v=f4(1,2,3,4); var w=f4(5,6,7,8); return cf4(x?w:v);} return f"), this)(1), [5,6,7,8]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(v) {v=cf4(v); var w=f4(5,6,7,8); return cf4(4?w:v);} return f"), this)(SIMD.float32x4(1,2,3,4)), [5,6,7,8]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(v, x) {v=cf4(v); x=x|0; var w=f4(5,6,7,8); return cf4(x?w:v);} return f"), this)(SIMD.float32x4(1,2,3,4), 0), [1,2,3,4]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(v) {v=cf4(v); var w=f4(5,6,7,8); return cf4(4?w:v);} return f"), this)(SIMD.Float32x4(1,2,3,4)), [5,6,7,8]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(v, x) {v=cf4(v); x=x|0; var w=f4(5,6,7,8); return cf4(x?w:v);} return f"), this)(SIMD.Float32x4(1,2,3,4), 0), [1,2,3,4]);
CheckI4('', 'var x=i4(1,2,3,4); var y=i4(4,3,2,1); x=(x.x|0)?y:x', [4, 3, 2, 1]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=x|0; var v=i4(1,2,3,4); var w=i4(5,6,7,8); return ci4(x?w:v);} return f"), this)(1), [5,6,7,8]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(v) {v=ci4(v); var w=i4(5,6,7,8); return ci4(4?w:v);} return f"), this)(SIMD.int32x4(1,2,3,4)), [5,6,7,8]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(v, x) {v=ci4(v); x=x|0; var w=i4(5,6,7,8); return ci4(x?w:v);} return f"), this)(SIMD.int32x4(1,2,3,4), 0), [1,2,3,4]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(v) {v=ci4(v); var w=i4(5,6,7,8); return ci4(4?w:v);} return f"), this)(SIMD.Int32x4(1,2,3,4)), [5,6,7,8]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(v, x) {v=ci4(v); x=x|0; var w=i4(5,6,7,8); return ci4(x?w:v);} return f"), this)(SIMD.Int32x4(1,2,3,4), 0), [1,2,3,4]);
// 1.3.4 Return values
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {var x=1; return ci4(x)} return f");
@@ -270,7 +271,7 @@ assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + FROUND + "function f() {ci4(f32
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + F32 + CF32 + "function f(x) {x=cf4(x); ci4(x);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); return 1 + ci4(x) | 0;} return f");
var i32x4 = SIMD.int32x4(1, 3, 3, 7);
var i32x4 = SIMD.Int32x4(1, 3, 3, 7);
assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x)} return f"), this)(i32x4), undefined);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); return ci4(x);} return f"), this)(i32x4), [1,3,3,7]);
@@ -282,7 +283,7 @@ assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + FROUND + "function f() {cf4(f32
assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + F32 + CF32 + "function f(x) {x=cf4(x); cf4(x);} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); return 1 + cf4(x) | 0;} return f");
var f32x4 = SIMD.float32x4(13.37, 42.42, -0, NaN);
var f32x4 = SIMD.Float32x4(13.37, 42.42, -0, NaN);
assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x)} return f"), this)(f32x4), undefined);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); return cf4(x);} return f"), this)(f32x4), [13.37, 42.42, -0, NaN].map(Math.fround));
@@ -317,14 +318,14 @@ assertCaught(f);
assertCaught(f, 1);
assertCaught(f, {});
assertCaught(f, "I sincerely am a SIMD typed object.");
assertCaught(f, SIMD.int32x4(1,2,3,4));
assertCaught(f, SIMD.Int32x4(1,2,3,4));
var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); return ci4(x);} return f"), this);
assertCaught(f);
assertCaught(f, 1);
assertCaught(f, {});
assertCaught(f, "I sincerely am a SIMD typed object.");
assertCaught(f, SIMD.float32x4(4,3,2,1));
assertCaught(f, SIMD.Float32x4(4,3,2,1));
// 1.3.6 Globals
// 1.3.6.1 Local globals
@@ -377,40 +378,40 @@ CheckF4('var x=f4(0,0,0,0); var y=42; var z=3.9; var w=13.37', 'x=f4(1,2,3,4); y
// 1.3.6.2 Imported globals
// Read
var int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {return ci4(g)} return f"), this, {g: SIMD.int32x4(1,2,3,4)})();
assertEq(int32x4.x, 1);
assertEq(int32x4.y, 2);
assertEq(int32x4.z, 3);
assertEq(int32x4.w, 4);
var Int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {return ci4(g)} return f"), this, {g: SIMD.Int32x4(1,2,3,4)})();
assertEq(Int32x4.x, 1);
assertEq(Int32x4.y, 2);
assertEq(Int32x4.z, 3);
assertEq(Int32x4.w, 4);
for (var v of [1, {}, "totally legit SIMD variable", SIMD.float32x4(1,2,3,4)])
for (var v of [1, {}, "totally legit SIMD variable", SIMD.Float32x4(1,2,3,4)])
assertCaught(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {return ci4(g)} return f"), this, {g: v});
var float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {return cf4(g)} return f"), this, {g: SIMD.float32x4(1,2,3,4)})();
assertEq(float32x4.x, 1);
assertEq(float32x4.y, 2);
assertEq(float32x4.z, 3);
assertEq(float32x4.w, 4);
var Float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {return cf4(g)} return f"), this, {g: SIMD.Float32x4(1,2,3,4)})();
assertEq(Float32x4.x, 1);
assertEq(Float32x4.y, 2);
assertEq(Float32x4.z, 3);
assertEq(Float32x4.w, 4);
for (var v of [1, {}, "totally legit SIMD variable", SIMD.int32x4(1,2,3,4)])
for (var v of [1, {}, "totally legit SIMD variable", SIMD.Int32x4(1,2,3,4)])
assertCaught(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {return cf4(g)} return f"), this, {g: v});
// Write
var int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {g=i4(4,5,6,7); return ci4(g)} return f"), this, {g: SIMD.int32x4(1,2,3,4)})();
assertEq(int32x4.x, 4);
assertEq(int32x4.y, 5);
assertEq(int32x4.z, 6);
assertEq(int32x4.w, 7);
var Int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {g=i4(4,5,6,7); return ci4(g)} return f"), this, {g: SIMD.Int32x4(1,2,3,4)})();
assertEq(Int32x4.x, 4);
assertEq(Int32x4.y, 5);
assertEq(Int32x4.z, 6);
assertEq(Int32x4.w, 7);
var float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {g=f4(4.,5.,6.,7.); return cf4(g)} return f"), this, {g: SIMD.float32x4(1,2,3,4)})();
assertEq(float32x4.x, 4);
assertEq(float32x4.y, 5);
assertEq(float32x4.z, 6);
assertEq(float32x4.w, 7);
var Float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {g=f4(4.,5.,6.,7.); return cf4(g)} return f"), this, {g: SIMD.Float32x4(1,2,3,4)})();
assertEq(Float32x4.x, 4);
assertEq(Float32x4.y, 5);
assertEq(Float32x4.z, 6);
assertEq(Float32x4.w, 7);
// 2. SIMD operations
// 2.1 Compilation
assertAsmTypeFail('glob', USE_ASM + "var add = int32x4.add; return {}");
assertAsmTypeFail('glob', USE_ASM + "var add = Int32x4.add; return {}");
assertAsmTypeFail('glob', USE_ASM + I32A + I32 + "return {}");
assertAsmTypeFail('glob', USE_ASM + "var g = 3; var add = g.add; return {}");
assertAsmTypeFail('glob', USE_ASM + I32 + "var func = i4.doTheHarlemShake; return {}");
@@ -421,14 +422,14 @@ assertAsmTypeFail('glob', USE_ASM + "var f32 = glob.Math.fround; var i4a = f32.a
assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {});
assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {SIMD: Math.fround});
var oldInt32x4Add = SIMD.int32x4.add;
var oldInt32x4Add = SIMD.Int32x4.add;
var code = asmCompile('glob', USE_ASM + I32 + I32A + "return {}");
for (var v of [42, Math.fround, SIMD.float32x4.add, function(){}, SIMD.int32x4.mul]) {
SIMD.int32x4.add = v;
assertAsmLinkFail(code, {SIMD: {int32x4: SIMD.int32x4}});
for (var v of [42, Math.fround, SIMD.Float32x4.add, function(){}, SIMD.Int32x4.mul]) {
SIMD.Int32x4.add = v;
assertAsmLinkFail(code, {SIMD: {Int32x4: SIMD.Int32x4}});
}
SIMD.int32x4.add = oldInt32x4Add; // finally replace the add function with the original one
assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {SIMD: {int32x4: SIMD.int32x4}})(), undefined);
SIMD.Int32x4.add = oldInt32x4Add; // finally replace the add function with the original one
assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {SIMD: {Int32x4: SIMD.Int32x4}})(), undefined);
// 2.3. Binary arithmetic operations
// 2.3.1 Additions
@@ -495,23 +496,23 @@ CheckF4(F32M, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4m(x,y)', [4,6,15,8]);
CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4m(x,y)', [Math.fround(13.37) * 4,6,15,8]);
CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=cf4(f4m(x,y))', [Math.fround(13.37) * 4,6,15,8]);
var f32x4 = SIMD.float32x4(0, NaN, -0, NaN);
var another = SIMD.float32x4(NaN, -1, -0, NaN);
var f32x4 = SIMD.Float32x4(0, NaN, -0, NaN);
var another = SIMD.Float32x4(NaN, -1, -0, NaN);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32M + CF32 + "function f(x, y) {x=cf4(x); y=cf4(y); x=f4m(x,y); return cf4(x);} return f"), this)(f32x4, another), [NaN, NaN, 0, NaN]);
CheckF4(F32D, 'var x=f4(1,2,3,4); x=f4d(x,x)', [1,1,1,1]);
CheckF4(F32D, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4d(x,y)', [1/4,2/3,3/5,2]);
CheckF4(F32D, 'var x=f4(13.37,1,1,4); var y=f4(4,0,-0.,2); x=f4d(x,y)', [Math.fround(13.37) / 4,+Infinity,-Infinity,2]);
var f32x4 = SIMD.float32x4(0, 0, -0, NaN);
var another = SIMD.float32x4(0, -0, 0, 0);
var f32x4 = SIMD.Float32x4(0, 0, -0, NaN);
var another = SIMD.Float32x4(0, -0, 0, 0);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32D + CF32 + "function f(x,y) {x=cf4(x); y=cf4(y); x=f4d(x,y); return cf4(x);} return f"), this)(f32x4, another), [NaN, NaN, NaN, NaN]);
// Unary arithmetic operators
function CheckUnaryF4(op, checkFunc, assertFunc) {
var _ = asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + 'var op=f4.' + op + '; function f(x){x=cf4(x); return cf4(op(x)); } return f'), this);
return function(input) {
var simd = SIMD.float32x4(input[0], input[1], input[2], input[3]);
var simd = SIMD.Float32x4(input[0], input[1], input[2], input[3]);
var exp = input.map(Math.fround).map(checkFunc).map(Math.fround);
var obs = _(simd);
@@ -522,7 +523,7 @@ function CheckUnaryF4(op, checkFunc, assertFunc) {
function CheckUnaryI4(op, checkFunc) {
var _ = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + 'var op=i4.' + op + '; function f(x){x=ci4(x); return ci4(op(x)); } return f'), this);
return function(input) {
var simd = SIMD.int32x4(input[0], input[1], input[2], input[3]);
var simd = SIMD.Int32x4(input[0], input[1], input[2], input[3]);
assertEqX4(_(simd), input.map(checkFunc).map(function(x) { return x | 0}));
}
}
@@ -608,37 +609,34 @@ CheckF4(F32MAXNUM, 'var x=f4(0,0,-0,-0); var y=f4(0,-0,0,-0); x=max(x,y)', [0,0,
CheckF4(F32MAXNUM + FROUND + 'var NaN = glob.NaN;', 'var x=f4(0,0,0,0); var y=f4(0,0,0,0); var n=f32(0); n=f32(NaN); x=f4(n,0.,n,0.); y=f4(n,n,0.,0.); x=max(x,y)', [NaN, 0, 0, 0]);
// With
const WXF = 'var w = f4.withX;';
const WYF = 'var w = f4.withY;';
const WZF = 'var w = f4.withZ;';
const WWF = 'var w = f4.withW;';
const RLF = 'var r = f4.replaceLane;';
assertAsmTypeFail('glob', USE_ASM + F32 + WXF + "function f() {var x = f4(1,2,3,4); x = w(x, 1);} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + WXF + "function f() {var x = f4(1,2,3,4); x = w(x, x);} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); x = w(1, f32(1));} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); x = w(1., f32(1));} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); x = w(f32(1), f32(1));} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); var y = i4(1,2,3,4); x = w(y, f32(1));} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + RLF + "function f() {var x = f4(1,2,3,4); x = r(x, 0, 1);} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + RLF + "function f() {var x = f4(1,2,3,4); x = r(x, 0, x);} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(x, 4, f32(1));} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(x, f32(0), f32(1));} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(1, 0, f32(1));} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(1, 0., f32(1));} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(f32(1), 0, f32(1));} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); var l = 0; x = r(x, l, f32(1));} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); var y = i4(1,2,3,4); x = r(y, 0, f32(1));} return f");
CheckF4(WXF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [Math.fround(13.37), 2, 3, 4]);
CheckF4(WYF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [1, Math.fround(13.37), 3, 4]);
CheckF4(WZF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [1, 2, Math.fround(13.37), 4]);
CheckF4(WWF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [1, 2, 3, Math.fround(13.37)]);
CheckF4(WWF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37) + f32(6.63));', [1, 2, 3, Math.fround(Math.fround(13.37) + Math.fround(6.63))]);
CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 0, f32(13.37));', [Math.fround(13.37), 2, 3, 4]);
CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 1, f32(13.37));', [1, Math.fround(13.37), 3, 4]);
CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 2, f32(13.37));', [1, 2, Math.fround(13.37), 4]);
CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 3, f32(13.37));', [1, 2, 3, Math.fround(13.37)]);
CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 3, f32(13.37) + f32(6.63));', [1, 2, 3, Math.fround(Math.fround(13.37) + Math.fround(6.63))]);
CheckF4(WXF + FROUND, 'var x = f4(1,2,3,4); x = w(x, 13.37);', [Math.fround(13.37), 2, 3, 4]);
CheckF4(WYF + FROUND, 'var x = f4(1,2,3,4); x = w(x, 13.37);', [1, Math.fround(13.37), 3, 4]);
CheckF4(WZF + FROUND, 'var x = f4(1,2,3,4); x = w(x, 13.37);', [1, 2, Math.fround(13.37), 4]);
CheckF4(WWF + FROUND, 'var x = f4(1,2,3,4); x = w(x, 13.37);', [1, 2, 3, Math.fround(13.37)]);
CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 0, 13.37);', [Math.fround(13.37), 2, 3, 4]);
CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 1, 13.37);', [1, Math.fround(13.37), 3, 4]);
CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 2, 13.37);', [1, 2, Math.fround(13.37), 4]);
CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 3, 13.37);', [1, 2, 3, Math.fround(13.37)]);
const WXI = 'var w = i4.withX;';
const WYI = 'var w = i4.withY;';
const WZI = 'var w = i4.withZ;';
const WWI = 'var w = i4.withW;';
CheckI4(WXI, 'var x = i4(1,2,3,4); x = w(x, 42);', [42, 2, 3, 4]);
CheckI4(WYI, 'var x = i4(1,2,3,4); x = w(x, 42);', [1, 42, 3, 4]);
CheckI4(WZI, 'var x = i4(1,2,3,4); x = w(x, 42);', [1, 2, 42, 4]);
CheckI4(WWI, 'var x = i4(1,2,3,4); x = w(x, 42);', [1, 2, 3, 42]);
const RLI = 'var r = i4.replaceLane;';
CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 0, 42);', [42, 2, 3, 4]);
CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 1, 42);', [1, 42, 3, 4]);
CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 2, 42);', [1, 2, 42, 4]);
CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 3, 42);', [1, 2, 3, 42]);
// Comparisons
// True yields all bits set to 1 (i.e as an int32, 0xFFFFFFFF === -1), false
@@ -726,17 +724,22 @@ assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIF + "function f() {var x=i4(
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIF + "function f() {var x=f4(1,2,3,4); x=cvt(x);} return f");
var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + CI32 + CVTIF + 'function f(x){x=ci4(x); var y=f4(0,0,0,0); y=cvt(x); return cf4(y);} return f'), this);
assertEqX4(f(SIMD.int32x4(1,2,3,4)), [1, 2, 3, 4]);
assertEqX4(f(SIMD.int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, Math.fround(INT32_MIN), Math.fround(INT32_MAX), -1]);
assertEqX4(f(SIMD.Int32x4(1,2,3,4)), [1, 2, 3, 4]);
assertEqX4(f(SIMD.Int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, Math.fround(INT32_MIN), Math.fround(INT32_MAX), -1]);
// TODO amend tests once int32x4.fromFloat32x4 is fully specified, when float
// values can't be converted into an int32 without overflowing. In these
// tests, we assume x86/x64, so a conversion which failed will return the
// undefined int32 value. See also bug 1068028.
const UNDEFINED_INT32 = 0x80000000 | 0;
var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + F32 + CF32 + CVTFI + 'function f(x){x=cf4(x); var y=i4(0,0,0,0); y=cvt(x); return ci4(y);} return f'), this);
assertEqX4(f(SIMD.float32x4(1,2,3,4)), [1, 2, 3, 4]);
assertEqX4(f(SIMD.float32x4(NaN,Infinity,-Infinity,-0)), [UNDEFINED_INT32, UNDEFINED_INT32, UNDEFINED_INT32, 0]);
assertEqX4(f(SIMD.Float32x4(1,2,3,4)), [1, 2, 3, 4]);
// Test that INT32_MIN (exactly representable as an float32) and the first
// integer representable as an float32 can be converted.
assertEqX4(f(SIMD.Float32x4(INT32_MIN, INT32_MAX - 64, -0, 0)), [INT32_MIN, INT32_MAX - 64, 0, 0].map(Math.fround));
// Test boundaries: first integer less than INT32_MIN and representable as a float32
assertThrowsInstanceOf(() => f(SIMD.Float32x4(INT32_MIN - 129, 0, 0, 0)), RangeError);
// INT_MAX + 1
assertThrowsInstanceOf(() => f(SIMD.Float32x4(Math.pow(2, 31), 0, 0, 0)), RangeError);
// Special values
assertThrowsInstanceOf(() => f(SIMD.Float32x4(NaN, 0, 0, 0)), RangeError);
assertThrowsInstanceOf(() => f(SIMD.Float32x4(Infinity, 0, 0, 0)), RangeError);
assertThrowsInstanceOf(() => f(SIMD.Float32x4(-Infinity, 0, 0, 0)), RangeError);
// Cast operators
const CVTIFB = 'var cvt=f4.fromInt32x4Bits;';
@@ -768,20 +771,20 @@ assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIFB + "function f() {var x=i4
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIFB + "function f() {var x=f4(1,2,3,4); x=cvt(x);} return f");
var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTIFB + CF32 + CI32 + 'function f(x){x=ci4(x); var y=f4(0,0,0,0); y=cvt(x); return cf4(y);} return f'), this);
assertEqX4(f(SIMD.int32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromInt32Bits));
assertEqX4(f(SIMD.int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, INT32_MIN, INT32_MAX, -1].map(cast.fromInt32Bits));
assertEqX4(f(SIMD.Int32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromInt32Bits));
assertEqX4(f(SIMD.Int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, INT32_MIN, INT32_MAX, -1].map(cast.fromInt32Bits));
var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32A + CVTIFB + CF32 + CI32 + 'function f(x){x=ci4(x); var y=f4(0,0,0,0); var z=f4(1,1,1,1); y=cvt(x); y=f4a(y, z); return cf4(y)} return f'), this);
assertEqX4(f(SIMD.int32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromInt32Bits).map((x) => x+1));
assertEqX4(f(SIMD.int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, INT32_MIN, INT32_MAX, -1].map(cast.fromInt32Bits).map((x) => x+1));
assertEqX4(f(SIMD.Int32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromInt32Bits).map((x) => x+1));
assertEqX4(f(SIMD.Int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, INT32_MIN, INT32_MAX, -1].map(cast.fromInt32Bits).map((x) => x+1));
var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + F32 + CF32 + CVTFIB + 'function f(x){x=cf4(x); var y=i4(0,0,0,0); y=cvt(x); return ci4(y);} return f'), this);
assertEqX4(f(SIMD.float32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromFloat32Bits));
assertEqX4(f(SIMD.float32x4(-0,NaN,+Infinity,-Infinity)), [-0, NaN, +Infinity, -Infinity].map(cast.fromFloat32Bits));
assertEqX4(f(SIMD.Float32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromFloat32Bits));
assertEqX4(f(SIMD.Float32x4(-0,NaN,+Infinity,-Infinity)), [-0, NaN, +Infinity, -Infinity].map(cast.fromFloat32Bits));
var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + F32 + CF32 + I32A + CVTFIB + 'function f(x){x=cf4(x); var y=i4(0,0,0,0); var z=i4(1,1,1,1); y=cvt(x); y=i4a(y,z); return ci4(y);} return f'), this);
assertEqX4(f(SIMD.float32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromFloat32Bits).map((x) => x+1));
assertEqX4(f(SIMD.float32x4(-0,NaN,+Infinity,-Infinity)), [-0, NaN, +Infinity, -Infinity].map(cast.fromFloat32Bits).map((x) => x+1));
assertEqX4(f(SIMD.Float32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromFloat32Bits).map((x) => x+1));
assertEqX4(f(SIMD.Float32x4(-0,NaN,+Infinity,-Infinity)), [-0, NaN, +Infinity, -Infinity].map(cast.fromFloat32Bits).map((x) => x+1));
// Bitwise ops
const ANDI32 = 'var andd=i4.and;';
@@ -905,37 +908,37 @@ assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32BSEL + "fu
// Specific bitselect tests
var masks = [
SIMD.int32x4(1337, 0x1337, 0x42, 42),
SIMD.int32x4(0x00FF1CE, 0xBAADF00D, 0xDEADBEEF, 0xCAFED00D),
SIMD.int32x4(0xD15EA5E, 0xDEADC0DE, 0xFACEB00C, 0x4B1D4B1D)
SIMD.Int32x4(1337, 0x1337, 0x42, 42),
SIMD.Int32x4(0x00FF1CE, 0xBAADF00D, 0xDEADBEEF, 0xCAFED00D),
SIMD.Int32x4(0xD15EA5E, 0xDEADC0DE, 0xFACEB00C, 0x4B1D4B1D)
];
var simdToArray = (vec) => [vec.x, vec.y, vec.z, vec.w];
var inputs = [
[SIMD.int32x4(0,4,9,16), SIMD.int32x4(1,2,3,4)],
[SIMD.int32x4(-1, 2, INT32_MAX, INT32_MIN), SIMD.int32x4(INT32_MAX, -4, INT32_MIN, 42)]
[SIMD.Int32x4(0,4,9,16), SIMD.Int32x4(1,2,3,4)],
[SIMD.Int32x4(-1, 2, INT32_MAX, INT32_MIN), SIMD.Int32x4(INT32_MAX, -4, INT32_MIN, 42)]
];
var i32bsel = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32BSEL + "function f(mask, ifTrue, ifFalse) {mask=ci4(mask); ifTrue=ci4(ifTrue); ifFalse=ci4(ifFalse); return ci4(i4sel(mask,ifTrue,ifFalse)); } return f"), this)
for (var mask of masks) {
for (var [x, y] of inputs) {
assertEqX4(i32bsel(mask, x, y), simdToArray(SIMD.int32x4.bitselect(mask, x, y)));
assertEqX4(i32bsel(mask, x, y), simdToArray(SIMD.Int32x4.bitselect(mask, x, y)));
}
}
inputs = [
[SIMD.float32x4(0.125,4.25,9.75,16.125), SIMD.float32x4(1.5,2.75,3.25,4.5)],
[SIMD.float32x4(-1.5,-0,NaN,-Infinity), SIMD.float32x4(1,-2,13.37,3.13)],
[SIMD.float32x4(1.5,2.75,NaN,Infinity), SIMD.float32x4(-NaN,-Infinity,9.75,16.125)]
[SIMD.Float32x4(0.125,4.25,9.75,16.125), SIMD.Float32x4(1.5,2.75,3.25,4.5)],
[SIMD.Float32x4(-1.5,-0,NaN,-Infinity), SIMD.Float32x4(1,-2,13.37,3.13)],
[SIMD.Float32x4(1.5,2.75,NaN,Infinity), SIMD.Float32x4(-NaN,-Infinity,9.75,16.125)]
];
var f32bsel = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CI32 + CF32 + F32BSEL + "function f(mask, ifTrue, ifFalse) {mask=ci4(mask); ifTrue=cf4(ifTrue); ifFalse=cf4(ifFalse); return cf4(f4sel(mask,ifTrue,ifFalse)); } return f"), this)
for (var mask of masks)
for (var [x, y] of inputs)
assertEqX4(f32bsel(mask, x, y), simdToArray(SIMD.float32x4.bitselect(mask, x, y)));
assertEqX4(f32bsel(mask, x, y), simdToArray(SIMD.Float32x4.bitselect(mask, x, y)));
// Splat
const I32SPLAT = 'var splat=i4.splat;'
@@ -1114,7 +1117,7 @@ var code = USE_ASM + I32 + CI32 + I32A + `
return f;
`;
var v4 = SIMD.int32x4(1,2,3,4);
var v4 = SIMD.Int32x4(1,2,3,4);
function check(x, y, z, w) {
assertEq(x, 35);
assertEq(y, 35);
@@ -1165,7 +1168,7 @@ for (var i = 1; i < 10; ++i) {
// Stress-test for register spilling code and stack depth checks
var code = `
"use asm";
var i4 = glob.SIMD.int32x4;
var i4 = glob.SIMD.Int32x4;
var i4a = i4.add;
var assertEq = ffi.assertEq;
function g() {
@@ -1185,7 +1188,7 @@ asmLink(asmCompile('glob', 'ffi', code), this, assertEqFFI)();
(function() {
var code = `
"use asm";
var i4 = glob.SIMD.int32x4;
var i4 = glob.SIMD.Int32x4;
var i4a = i4.add;
var assertEq = ffi.assertEq;
var one = ffi.one;
@@ -1227,7 +1230,7 @@ asmLink(asmCompile('glob', 'ffi', code), this, assertEqFFI)();
(function() {
var code = `
"use asm";
var i4 = glob.SIMD.int32x4;
var i4 = glob.SIMD.Int32x4;
var ci4 = i4.check;
function h(
// In registers:
@@ -1285,7 +1288,7 @@ asmLink(asmCompile('glob', 'ffi', code), this, assertEqFFI)();
var iters = 2000000;
var code = `
"use asm";
var i4 = glob.SIMD.int32x4;
var i4 = glob.SIMD.Int32x4;
var i4a = i4.add;
var ci4 = i4.check;
function _() {
@@ -1313,4 +1316,3 @@ asmLink(asmCompile('glob', 'ffi', code), this, assertEqFFI)();
print('Error:', e)
throw e;
}
+2 -2
View File
@@ -209,10 +209,10 @@ function testSimdX4(ctor, shift, scale, disp, simdName, simdCtor) {
}
function testFloat32x4(ctor, shift, scale, disp) {
testSimdX4(ctor, shift, scale, disp, 'float32x4', SIMD.float32x4);
testSimdX4(ctor, shift, scale, disp, 'Float32x4', SIMD.Float32x4);
}
function testInt32x4(ctor, shift, scale, disp) {
testSimdX4(ctor, shift, scale, disp, 'int32x4', SIMD.int32x4);
testSimdX4(ctor, shift, scale, disp, 'Int32x4', SIMD.Int32x4);
}
function test(tester, ctor, shift) {
@@ -139,7 +139,7 @@ assertEq(a.y, 2);
// defaults are evaluated even if there is no binding
var evaled = false;
({a: {} = (evaled = true, null)}) = {};
({a: {} = (evaled = true, {})}) = {};
assertEq(evaled, true);
evaled = false;
assertThrowsInstanceOf(() => { [[] = (evaled = true, 2)] = [] }, TypeError);
@@ -0,0 +1,107 @@
load(libdir + 'asserts.js');
load(libdir + 'iteration.js');
function f(v)
{
if (v + "")
({} = v);
}
f(true);
f({});
assertThrowsInstanceOf(() => f(null), TypeError);
assertThrowsInstanceOf(() => f(undefined), TypeError);
function g(v)
{
if (v + "")
({} = v);
}
g(true);
g({});
assertThrowsInstanceOf(() => g(undefined), TypeError);
assertThrowsInstanceOf(() => g(null), TypeError);
function h(v)
{
if (v + "")
([] = v);
}
h([true]);
h("foo");
assertThrowsInstanceOf(() => h(undefined), TypeError);
assertThrowsInstanceOf(() => h(null), TypeError);
Object.defineProperty(Boolean.prototype, "v",
{ get() { "use strict"; return typeof this; },
enumerable: true,
configurable: true });
Object.defineProperty(Number.prototype, "v",
{ get() { "use strict"; return typeof this; },
enumerable: true,
configurable: true });
Object.defineProperty(String.prototype, "v",
{ get() { "use strict"; return typeof this; },
enumerable: true,
configurable: true });
Object.defineProperty(Symbol.prototype, "v",
{ get() { "use strict"; return typeof this; },
enumerable: true,
configurable: true });
function primitiveThisSupported()
{
return 3.14.custom === "number";
}
function primitiveThisTests()
{
function f(v)
{
var type = typeof v;
({ v } = v);
assertEq(v, type);
}
f(true);
f(3.14);
f(72);
f("ohai");
f(Symbol.iterator);
assertThrowsInstanceOf(() => f(undefined), TypeError);
assertThrowsInstanceOf(() => f(null), TypeError);
function g(v)
{
var type = typeof v;
({ v } = v);
assertEq(v, type);
}
g(true);
g(3.14);
g(72);
g("ohai");
g(Symbol.iterator);
assertThrowsInstanceOf(() => g(null), TypeError);
assertThrowsInstanceOf(() => g(undefined), TypeError);
}
if (primitiveThisSupported())
primitiveThisTests();
// Ensure the internal implementation of destructuring object pattern
// assignment -- using a self-hosted intrinsic function -- works even when lazy
// standard class initialization hasn't occurred. Unfortunately we can't use
// |newGlobal()| because that method eagerly initializes standard classes.
evalcx("({} = 1);", evalcx("lazy"));
@@ -101,12 +101,27 @@ check("o[- (o)]");
// A few one off tests
check_one("6", (function () { 6() }), " is not a function");
check_one("0", (function () { Array.prototype.reverse.call('123'); }), " is read-only");
check_one(`(intermediate value)[Symbol.iterator](...).next(...).value`,
function () { var [{ x }] = [null, {}]; }, " is null");
check_one(`(intermediate value)[Symbol.iterator](...).next(...).value`,
check_one("(intermediate value)[Symbol.iterator](...).next(...).value",
function () { ieval("{ let x; var [a, b, [c0, c1]] = [x, x, x]; }") }, " is undefined");
check_one("void 1", function() { (void 1)(); }, " is not a function");
check_one("void o[1]", function() { var o = []; (void o[1])() }, " is not a function");
// Manual testing for this case: the only way to trigger an error is *not* on
// an attempted property access during destructuring, and the error message
// invoking ToObject(null) is different: "can't convert {0} to object".
try
{
(function() {
var [{x}] = [null, {}];
})();
throw new Error("didn't throw");
}
catch (e)
{
assertEq(e instanceof TypeError, true,
"expected TypeError, got " + e);
assertEq(e.message, "can't convert null to object");
}
// Check fallback behavior
assertThrowsInstanceOf(function () { for (let x of undefined) {} }, TypeError);
@@ -76,7 +76,6 @@ test("new RegExp('1')", r => assertEq("a1".search(r), 1));
test("new RegExp('1')", r => assertEq("a1".match(r)[0], '1'));
test("new RegExp('1')", r => assertEq("a1".replace(r, 'A'), 'aA'));
test("new RegExp('1')", r => assertEq(String("a1b".split(r)), "a,b"));
test("new RegExp('1')", r => assertEq(r, RegExp(r)));
test("new RegExp('1')", r => assertEq(String(new RegExp(r)), String(r)));
test("new RegExp('1')", r => assertEq(String(/x/.compile(r)), String(r)));
test("new WeakMap()", w => WeakMap.prototype.has.call(w, {}));
@@ -5,22 +5,22 @@ var g = newGlobal();
var dbg = new Debugger(g);
g.eval(`
function withTypedArrayOnStack(f) {
function withAllocationMarkerOnStack(f) {
(function () {
var onStack = new Int8Array();
var onStack = allocationMarker();
f();
}())
}
`);
assertEq("Int8Array" in dbg.memory.takeCensus().objects, false,
"There shouldn't exist any typed arrays in the census.");
assertEq("AllocationMarker" in dbg.memory.takeCensus().objects, false,
"There shouldn't exist any allocation markers in the census.");
var typedArrayCount;
g.withTypedArrayOnStack(() => {
typedArrayCount = dbg.memory.takeCensus().objects.Int8Array.count;
var allocationMarkerCount;
g.withAllocationMarkerOnStack(() => {
allocationMarkerCount = dbg.memory.takeCensus().objects.AllocationMarker.count;
});
assertEq(typedArrayCount, 1,
"Should have one typed array in the census, because there " +
assertEq(allocationMarkerCount, 1,
"Should have one allocation marker in the census, because there " +
"was one on the stack.");
@@ -4,11 +4,11 @@
var g = newGlobal();
var dbg = new Debugger(g);
assertEq("Int8Array" in dbg.memory.takeCensus().objects, false,
"There shouldn't exist any typed arrays in the census.");
assertEq("AllocationMarker" in dbg.memory.takeCensus().objects, false,
"There shouldn't exist any allocation markers in the census.");
this.ccw = g.eval("new Int8Array()");
this.ccw = g.allocationMarker();
assertEq(dbg.memory.takeCensus().objects.Int8Array.count, 1,
"Should have one typed array in the census, because there " +
"is one cross-compartment wrapper.");
assertEq(dbg.memory.takeCensus().objects.AllocationMarker.count, 1,
"Should have one allocation marker in the census, because there " +
"is one cross-compartment wrapper referring to it.");
@@ -0,0 +1,117 @@
// Check Debugger.Memory.prototype.takeCensus handling of 'breakdown' argument.
load(libdir + 'match.js');
var Pattern = Match.Pattern;
var g = newGlobal();
var dbg = new Debugger(g);
Pattern({ count: Pattern.NATURAL,
bytes: Pattern.NATURAL })
.assert(dbg.memory.takeCensus({ breakdown: { by: 'count' } }));
let census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: false, bytes: false } });
assertEq('count' in census, false);
assertEq('bytes' in census, false);
let census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: true, bytes: false } });
assertEq('count' in census, true);
assertEq('bytes' in census, false);
let census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: false, bytes: true } });
assertEq('count' in census, false);
assertEq('bytes' in census, true);
let census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: true, bytes: true } });
assertEq('count' in census, true);
assertEq('bytes' in census, true);
// Pattern doesn't mind objects with extra properties, so we'll restrict this
// list to the object classes we're pretty sure are going to stick around for
// the forseeable future.
Pattern({
Function: { count: Pattern.NATURAL },
Object: { count: Pattern.NATURAL },
Debugger: { count: Pattern.NATURAL },
global: { count: Pattern.NATURAL },
// The below are all Debugger prototype objects.
Source: { count: Pattern.NATURAL },
Environment: { count: Pattern.NATURAL },
Script: { count: Pattern.NATURAL },
Memory: { count: Pattern.NATURAL },
Frame: { count: Pattern.NATURAL }
})
.assert(dbg.memory.takeCensus({ breakdown: { by: 'objectClass' } }));
Pattern({
objects: { count: Pattern.NATURAL },
scripts: { count: Pattern.NATURAL },
strings: { count: Pattern.NATURAL },
other: { count: Pattern.NATURAL }
})
.assert(dbg.memory.takeCensus({ breakdown: { by: 'coarseType' } }));
// As for { by: 'objectClass' }, restrict our pattern to the types
// we predict will stick around for a long time.
Pattern({
JSString: { count: Pattern.NATURAL },
'js::Shape': { count: Pattern.NATURAL },
JSObject: { count: Pattern.NATURAL },
JSScript: { count: Pattern.NATURAL }
})
.assert(dbg.memory.takeCensus({ breakdown: { by: 'internalType' } }));
// Nested breakdowns.
let coarse_type_pattern = {
objects: { count: Pattern.NATURAL },
scripts: { count: Pattern.NATURAL },
strings: { count: Pattern.NATURAL },
other: { count: Pattern.NATURAL }
};
Pattern({
JSString: coarse_type_pattern,
'js::Shape': coarse_type_pattern,
JSObject: coarse_type_pattern,
JSScript: coarse_type_pattern,
})
.assert(dbg.memory.takeCensus({
breakdown: { by: 'internalType',
then: { by: 'coarseType' }
}
}));
Pattern({
Function: { count: Pattern.NATURAL },
Object: { count: Pattern.NATURAL },
Debugger: { count: Pattern.NATURAL },
global: { count: Pattern.NATURAL },
other: coarse_type_pattern
})
.assert(dbg.memory.takeCensus({
breakdown: {
by: 'objectClass',
then: { by: 'count' },
other: { by: 'coarseType' }
}
}));
Pattern({
objects: { count: Pattern.NATURAL, label: "object" },
scripts: { count: Pattern.NATURAL, label: "scripts" },
strings: { count: Pattern.NATURAL, label: "strings" },
other: { count: Pattern.NATURAL, label: "other" }
})
.assert(dbg.memory.takeCensus({
breakdown: {
by: 'coarseType',
objects: { by: 'count', label: 'object' },
scripts: { by: 'count', label: 'scripts' },
strings: { by: 'count', label: 'strings' },
other: { by: 'count', label: 'other' }
}
}));
@@ -0,0 +1,75 @@
// Debugger.Memory.prototype.takeCensus breakdown: check error handling on
// property gets.
load(libdir + 'asserts.js');
var g = newGlobal();
var dbg = new Debugger(g);
assertThrowsValue(() => {
dbg.memory.takeCensus({
breakdown: { get by() { throw "ಠ_ಠ" } }
});
}, "ಠ_ಠ");
assertThrowsValue(() => {
dbg.memory.takeCensus({
breakdown: { by: 'count', get count() { throw "ಠ_ಠ" } }
});
}, "ಠ_ಠ");
assertThrowsValue(() => {
dbg.memory.takeCensus({
breakdown: { by: 'count', get bytes() { throw "ಠ_ಠ" } }
});
}, "ಠ_ಠ");
assertThrowsValue(() => {
dbg.memory.takeCensus({
breakdown: { by: 'objectClass', get then() { throw "ಠ_ಠ" } }
});
}, "ಠ_ಠ");
assertThrowsValue(() => {
dbg.memory.takeCensus({
breakdown: { by: 'objectClass', get other() { throw "ಠ_ಠ" } }
});
}, "ಠ_ಠ");
assertThrowsValue(() => {
dbg.memory.takeCensus({
breakdown: { by: 'coarseType', get objects() { throw "ಠ_ಠ" } }
});
}, "ಠ_ಠ");
assertThrowsValue(() => {
dbg.memory.takeCensus({
breakdown: { by: 'coarseType', get scripts() { throw "ಠ_ಠ" } }
});
}, "ಠ_ಠ");
assertThrowsValue(() => {
dbg.memory.takeCensus({
breakdown: { by: 'coarseType', get strings() { throw "ಠ_ಠ" } }
});
}, "ಠ_ಠ");
assertThrowsValue(() => {
dbg.memory.takeCensus({
breakdown: { by: 'coarseType', get other() { throw "ಠ_ಠ" } }
});
}, "ಠ_ಠ");
assertThrowsValue(() => {
dbg.memory.takeCensus({
breakdown: { by: 'internalType', get then() { throw "ಠ_ಠ" } }
});
}, "ಠ_ಠ");
@@ -0,0 +1,73 @@
// Debugger.Memory.prototype.takeCensus: test by: 'count' breakdown
let g = newGlobal();
let dbg = new Debugger(g);
g.eval(`
var stuff = [];
function add(n, c) {
for (let i = 0; i < n; i++)
stuff.push(c());
}
let count = 0;
function obj() { return { count: count++ }; }
obj.factor = 1;
// This creates a closure (a function JSObject) that has captured
// a Call object. So each call creates two items.
function fun() { let v = count; return () => { return v; } }
fun.factor = 2;
function str() { return 'perambulator' + count++; }
str.factor = 1;
// Eval a fresh text each time, allocating:
// - a fresh ScriptSourceObject
// - a new JSScripts, not an eval cache hits
// - a fresh prototype object
// - a fresh Call object, since the eval makes 'ev' heavyweight
// - the new function itself
function ev() {
return eval(\`(function () { return \${ count++ } })\`);
}
ev.factor = 5;
// A new object (1) with a new shape (2) with a new atom (3)
function shape() { return { [ 'theobroma' + count++ ]: count }; }
shape.factor = 3;
`);
let baseline = 0;
function countIncreasedByAtLeast(n) {
let oldBaseline = baseline;
// Since a census counts only reachable objects, one might assume that calling
// GC here would have no effect on the census results. But GC also throws away
// JIT code and any objects it might be holding (template objects, say);
// takeCensus reaches those. Shake everything loose that we can, to make the
// census approximate reachability a bit more closely, and make our results a
// bit more predictable.
gc(g, 'shrinking');
baseline = dbg.memory.takeCensus({ breakdown: { by: 'count' } }).count;
return baseline >= oldBaseline + n;
}
countIncreasedByAtLeast(0);
g.add(100, g.obj);
assertEq(countIncreasedByAtLeast(g.obj.factor * 100), true);
g.add(100, g.fun);
assertEq(countIncreasedByAtLeast(g.fun.factor * 100), true);
g.add(100, g.str);
assertEq(countIncreasedByAtLeast(g.str.factor * 100), true);
g.add(100, g.ev);
assertEq(countIncreasedByAtLeast(g.ev.factor * 100), true);
g.add(100, g.shape);
assertEq(countIncreasedByAtLeast(g.shape.factor * 100), true);
@@ -0,0 +1,74 @@
// Debugger.Memory.prototype.takeCensus: by: allocationStack breakdown
var g = newGlobal();
var dbg = new Debugger(g);
g.evaluate(`
var log = [];
function f() { log.push(allocationMarker()); }
function g() { f(); }
function h() { f(); }
`,
{ fileName: "Rockford", lineNumber: 1000 });
// Create one allocationMarker with tracking turned off,
// so it will have no associated stack.
g.f();
dbg.memory.allocationSamplingProbability = 1;
dbg.memory.trackingAllocationSites = true;
for ([f, n] of [[g.f, 20], [g.g, 10], [g.h, 5]])
for (let i = 0; i < n; i++)
f(); // all allocations of allocationMarker occur with this line as the
// oldest stack frame.
let census = dbg.memory.takeCensus({ breakdown: { by: 'objectClass',
then: { by: 'allocationStack',
then: { by: 'count',
label: 'haz stack'
},
noStack: { by: 'count',
label: 'no haz stack'
}
}
}
});
let map = census.AllocationMarker;
assertEq(map instanceof Map, true);
// Gather the stacks we are expecting to appear as keys, and
// check that there are no unexpected keys.
let stacks = { };
map.forEach((v, k) => {
if (k === 'noStack') {
// No need to save this key.
} else if (k.functionDisplayName === 'f' &&
k.parent.functionDisplayName === null) {
stacks.f = k;
} else if (k.functionDisplayName === 'f' &&
k.parent.functionDisplayName === 'g' &&
k.parent.parent.functionDisplayName === null) {
stacks.fg = k;
} else if (k.functionDisplayName === 'f' &&
k.parent.functionDisplayName === 'h' &&
k.parent.parent.functionDisplayName === null) {
stacks.fh = k;
} else {
assertEq(true, false);
}
});
assertEq(map.get('noStack').label, 'no haz stack');
assertEq(map.get('noStack').count, 1);
assertEq(map.get(stacks.f).label, 'haz stack');
assertEq(map.get(stacks.f).count, 20);
assertEq(map.get(stacks.fg).label, 'haz stack');
assertEq(map.get(stacks.fg).count, 10);
assertEq(map.get(stacks.fh).label, 'haz stack');
assertEq(map.get(stacks.fh).count, 5);
@@ -0,0 +1,57 @@
// Check byte counts produced by takeCensus.
let g = newGlobal();
let dbg = new Debugger(g);
let sizeOfAM = byteSize(allocationMarker());
// Allocate a single allocation marker, and check that we can find it.
g.eval('let hold = allocationMarker();');
let census = dbg.memory.takeCensus({ breakdown: { by: 'objectClass' } });
assertEq(census.AllocationMarker.count, 1);
assertEq(census.AllocationMarker.bytes, sizeOfAM);
g.evaluate(`
var objs = [];
function fnerd() {
objs.push(allocationMarker());
for (let i = 0; i < 10; i++)
objs.push(allocationMarker());
}
`,
{ fileName: 'J. Edgar Hoover', lineNumber: 2000 });
dbg.memory.allocationSamplingProbability = 1;
dbg.memory.trackingAllocationSites = true;
g.hold = null;
g.fnerd();
let census = dbg.memory.takeCensus({
breakdown: { by: 'objectClass',
then: { by: 'allocationStack' }
}
});
let seen = 0;
census.AllocationMarker.forEach((v, k) => {
assertEq(k.functionDisplayName, 'fnerd');
assertEq(k.source, 'J. Edgar Hoover');
switch (k.line) {
case 2003:
assertEq(v.count, 1);
assertEq(v.bytes, sizeOfAM);
seen++;
break;
case 2005:
assertEq(v.count, 10);
assertEq(v.bytes, 10 * sizeOfAM);
seen++;
break;
default: assertEq(true, false);
}
});
assertEq(seen, 2);
+57 -6
View File
@@ -7672,9 +7672,10 @@ IonBuilder::jsop_intrinsic(PropertyName* name)
return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
}
// Bake in the intrinsic. Make sure that TI agrees with us on the type.
Value vp;
JS_ALWAYS_TRUE(script()->global().maybeGetIntrinsicValue(name, &vp));
// Bake in the intrinsic, guaranteed to exist because a non-empty typeset
// means the intrinsic was successfully gotten in the VM call above.
// Assert that TI agrees with us on the type.
Value vp = script()->global().existingIntrinsicValue(name);
MOZ_ASSERT(types->hasType(TypeSet::GetValueType(vp)));
pushConstant(vp);
@@ -8482,6 +8483,43 @@ IonBuilder::getElemTryCache(bool* emitted, MDefinition* obj, MDefinition* index)
return true;
}
TemporaryTypeSet*
IonBuilder::computeHeapType(const TemporaryTypeSet* objTypes, const jsid id)
{
if (objTypes->unknownObject() || objTypes->getObjectCount() == 0)
return nullptr;
TemporaryTypeSet empty;
TemporaryTypeSet* acc = &empty;
LifoAlloc* lifoAlloc = alloc().lifoAlloc();
Vector<HeapTypeSetKey, 4, SystemAllocPolicy> properties;
if (!properties.reserve(objTypes->getObjectCount()))
return nullptr;
for (unsigned i = 0; i < objTypes->getObjectCount(); i++) {
TypeSet::ObjectKey* key = objTypes->getObject(i);
if (key->unknownProperties())
return nullptr;
HeapTypeSetKey property = key->property(id);
HeapTypeSet* currentSet = property.maybeTypes();
if (!currentSet || currentSet->unknown())
return nullptr;
properties.infallibleAppend(property);
acc = TypeSet::unionSets(acc, currentSet, lifoAlloc);
}
// Freeze all the properties associated with the refined type set.
for (HeapTypeSetKey* i = properties.begin(); i != properties.end(); i++)
i->freeze(constraints());
return acc;
}
bool
IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType unboxedType)
{
@@ -8527,12 +8565,21 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType
// If we can load the element as a definite double, make sure to check that
// the array has been converted to homogenous doubles first.
TemporaryTypeSet* objTypes = obj->resultTypeSet();
bool inBounds = !readOutOfBounds && !needsHoleCheck;
if (inBounds) {
TemporaryTypeSet* heapTypes = computeHeapType(objTypes, JSID_VOID);
if (heapTypes && heapTypes->isSubset(types)) {
knownType = heapTypes->getKnownMIRType();
types = heapTypes;
}
}
bool loadDouble =
unboxedType == JSVAL_TYPE_MAGIC &&
barrier == BarrierKind::NoBarrier &&
loopDepth_ &&
!readOutOfBounds &&
!needsHoleCheck &&
inBounds &&
knownType == MIRType_Double &&
objTypes &&
objTypes->convertDoubleElements(constraints()) == TemporaryTypeSet::AlwaysConvertToDoubles;
@@ -8568,8 +8615,10 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType
MOZ_ASSERT(knownType == MIRType_Value);
}
if (knownType != MIRType_Value)
if (knownType != MIRType_Value) {
load->setResultType(knownType);
load->setResultTypeSet(types);
}
current->push(load);
return pushTypeBarrier(load, types, barrier);
@@ -10324,6 +10373,8 @@ IonBuilder::SimdTypeDescrToMIRType(SimdTypeDescr::Type type)
switch (type) {
case SimdTypeDescr::Int32x4: return MIRType_Int32x4;
case SimdTypeDescr::Float32x4: return MIRType_Float32x4;
case SimdTypeDescr::Int8x16:
case SimdTypeDescr::Int16x8:
case SimdTypeDescr::Float64x2: return MIRType_Undefined;
}
MOZ_CRASH("unimplemented MIR type for a SimdTypeDescr::Type");
+12 -2
View File
@@ -587,6 +587,7 @@ class IonBuilder
TypedObjectPrediction objTypeReprs,
TypedObjectPrediction elemTypeReprs,
int32_t elemSize);
TemporaryTypeSet* computeHeapType(const TemporaryTypeSet* objTypes, const jsid id);
enum BoundsChecking { DoBoundsCheck, SkipBoundsCheck };
@@ -818,8 +819,10 @@ class IonBuilder
MSimdBinaryComp::Operation op, SimdTypeDescr::Type compType);
InliningStatus inlineUnarySimd(CallInfo& callInfo, JSNative native,
MSimdUnaryArith::Operation op, SimdTypeDescr::Type type);
InliningStatus inlineSimdWith(CallInfo& callInfo, JSNative native, SimdLane lane,
SimdTypeDescr::Type type);
InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native,
SimdTypeDescr::Type type);
InliningStatus inlineSimdReplaceLane(CallInfo& callInfo, JSNative native,
SimdTypeDescr::Type type);
InliningStatus inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type);
InliningStatus inlineSimdShuffle(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
unsigned numVectors, unsigned numLanes);
@@ -1325,6 +1328,13 @@ class CallInfo
return args_[i];
}
MDefinition* getArgWithDefault(uint32_t i, MDefinition* defaultValue) const {
if (i < argc())
return args_[i];
return defaultValue;
}
void setArg(uint32_t i, MDefinition* def) {
MOZ_ASSERT(i < argc());
args_[i] = def;
+66 -29
View File
@@ -25,8 +25,9 @@
using mozilla::ArrayLength;
using JS::TrackedStrategy;
using JS::DoubleNaNValue;
using JS::TrackedOutcome;
using JS::TrackedStrategy;
using JS::TrackedTypeSite;
namespace js {
@@ -316,17 +317,15 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
COMP_COMMONX4_TO_INT32X4_SIMD_OP(INLINE_SIMD_COMPARISON_)
#undef INLINE_SIMD_COMPARISON_
#define INLINE_SIMD_SETTER_(LANE) \
if (native == js::simd_int32x4_with##LANE) \
return inlineSimdWith(callInfo, native, SimdLane::Lane##LANE, SimdTypeDescr::Int32x4); \
if (native == js::simd_float32x4_with##LANE) \
return inlineSimdWith(callInfo, native, SimdLane::Lane##LANE, SimdTypeDescr::Float32x4);
if (native == js::simd_int32x4_extractLane)
return inlineSimdExtractLane(callInfo, native, SimdTypeDescr::Int32x4);
if (native == js::simd_float32x4_extractLane)
return inlineSimdExtractLane(callInfo, native, SimdTypeDescr::Float32x4);
INLINE_SIMD_SETTER_(X)
INLINE_SIMD_SETTER_(Y)
INLINE_SIMD_SETTER_(Z)
INLINE_SIMD_SETTER_(W)
#undef INLINE_SIMD_SETTER_
if (native == js::simd_int32x4_replaceLane)
return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Int32x4);
if (native == js::simd_float32x4_replaceLane)
return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Float32x4);
if (native == js::simd_int32x4_not)
return inlineUnarySimd(callInfo, native, MSimdUnaryArith::not_, SimdTypeDescr::Int32x4);
@@ -3135,21 +3134,13 @@ IonBuilder::inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* descr)
IonBuilder::InliningStatus
IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr)
{
if (callInfo.argc() == 1)
return InliningStatus_NotInlined;
// Generic constructor of SIMD valuesX4.
MIRType simdType = SimdTypeDescrToMIRType(descr->type());
// TODO Happens for Float64x2 (Bug 1124205)
// TODO Happens for Float64x2 (Bug 1124205) and Int8x16/Int16x8 (Bug 1136226)
if (simdType == MIRType_Undefined)
return InliningStatus_NotInlined;
// We do not inline SIMD constructors if the number of arguments does not
// match the number of lanes.
if (SimdTypeToLength(simdType) != callInfo.argc())
return InliningStatus_NotInlined;
// Take the templateObject out of Baseline ICs, such that we can box
// SIMD value type in the same kind of objects.
MOZ_ASSERT(size_t(descr->size(descr->type())) < InlineTypedObject::MaximumSize);
@@ -3162,9 +3153,24 @@ IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr)
InlineTypedObject* inlineTypedObject = &templateObject->as<InlineTypedObject>();
MOZ_ASSERT(&inlineTypedObject->typeDescr() == descr);
MSimdValueX4* values = MSimdValueX4::New(alloc(), simdType,
callInfo.getArg(0), callInfo.getArg(1),
callInfo.getArg(2), callInfo.getArg(3));
// When there are missing arguments, provide a default value
// containing the coercion of 'undefined' to the right type.
MConstant* defVal = nullptr;
if (callInfo.argc() < SimdTypeToLength(simdType)) {
MIRType scalarType = SimdTypeToScalarType(simdType);
if (scalarType == MIRType_Int32) {
defVal = constant(Int32Value(0));
} else {
MOZ_ASSERT(IsFloatingPointType(scalarType));
defVal = constant(DoubleNaNValue());
defVal->setResultType(scalarType);
}
}
MSimdValueX4* values =
MSimdValueX4::New(alloc(), simdType,
callInfo.getArgWithDefault(0, defVal), callInfo.getArgWithDefault(1, defVal),
callInfo.getArgWithDefault(2, defVal), callInfo.getArgWithDefault(3, defVal));
current->add(values);
MSimdBox* obj = MSimdBox::New(alloc(), constraints(), values, inlineTypedObject,
@@ -3271,17 +3277,49 @@ IonBuilder::inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdTypeDescr::
}
IonBuilder::InliningStatus
IonBuilder::inlineSimdWith(CallInfo& callInfo, JSNative native, SimdLane lane,
SimdTypeDescr::Type type)
IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 2, &templateObj))
return InliningStatus_NotInlined;
MDefinition* arg = callInfo.getArg(1);
if (!arg->isConstantValue() || arg->type() != MIRType_Int32)
return InliningStatus_NotInlined;
int32_t lane = callInfo.getArg(1)->constantValue().toInt32();
if (lane < 0 || lane >= 4)
return InliningStatus_NotInlined;
// See comment in inlineBinarySimd
MIRType vecType = SimdTypeDescrToMIRType(type);
MIRType scalarType = SimdTypeToScalarType(vecType);
MSimdExtractElement* ins = MSimdExtractElement::New(alloc(), callInfo.getArg(0),
vecType, scalarType, SimdLane(lane));
current->add(ins);
current->push(ins);
callInfo.setImplicitlyUsedUnchecked();
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 3, &templateObj))
return InliningStatus_NotInlined;
MDefinition* arg = callInfo.getArg(1);
if (!arg->isConstantValue() || arg->type() != MIRType_Int32)
return InliningStatus_NotInlined;
int32_t lane = arg->constantValue().toInt32();
if (lane < 0 || lane >= 4)
return InliningStatus_NotInlined;
// See comment in inlineBinarySimd
MIRType mirType = SimdTypeDescrToMIRType(type);
MSimdInsertElement* ins = MSimdInsertElement::New(alloc(), callInfo.getArg(0),
callInfo.getArg(1), mirType, lane);
callInfo.getArg(2), mirType, SimdLane(lane));
return boxSimd(callInfo, ins, templateObj);
}
@@ -3329,9 +3367,6 @@ IonBuilder::inlineSimdCheck(CallInfo& callInfo, JSNative native, SimdTypeDescr::
MIRType mirType = SimdTypeDescrToMIRType(type);
MSimdUnbox* unbox = MSimdUnbox::New(alloc(), callInfo.getArg(0), mirType);
// Make sure not to remove this unbox!
unbox->setGuard();
current->add(unbox);
current->push(callInfo.getArg(0));
@@ -3367,6 +3402,8 @@ SimdTypeToScalarType(SimdTypeDescr::Type type)
switch (type) {
case SimdTypeDescr::Float32x4: return Scalar::Float32x4;
case SimdTypeDescr::Int32x4: return Scalar::Int32x4;
case SimdTypeDescr::Int8x16:
case SimdTypeDescr::Int16x8:
case SimdTypeDescr::Float64x2: break;
}
MOZ_CRASH("unexpected simd type");
+18
View File
@@ -930,6 +930,24 @@ MSimdSplatX4::foldsTo(TempAllocator& alloc)
return MSimdConstant::New(alloc, cst, type());
}
MDefinition*
MSimdUnbox::foldsTo(TempAllocator &alloc)
{
MDefinition* in = input();
if (in->isSimdBox()) {
// If the operand is a MSimdBox, then we just reuse the operand of the
// MSimdBox as long as the type corresponds to what we are supposed to
// unbox.
in = in->toSimdBox()->input();
if (in->type() != type())
return this;
return in;
}
return this;
}
MDefinition*
MSimdSwizzle::foldsTo(TempAllocator& alloc)
{
+6
View File
@@ -3253,6 +3253,7 @@ class MSimdUnbox
: MUnaryInstruction(op)
{
MOZ_ASSERT(IsSimdType(type));
setGuard();
setMovable();
setResultType(type);
}
@@ -3266,6 +3267,11 @@ class MSimdUnbox
return new(alloc) MSimdUnbox(op, type);
}
MDefinition* foldsTo(TempAllocator& alloc) override;
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const override {
return AliasSet::None();
}
+6
View File
@@ -1342,6 +1342,12 @@ RSimdBox::recover(JSContext* cx, SnapshotIterator &iter) const
case SimdTypeDescr::Float64x2:
MOZ_CRASH("NYI, RSimdBox of Float64x2");
break;
case SimdTypeDescr::Int8x16:
MOZ_CRASH("NYI, RSimdBox of Int8x16");
break;
case SimdTypeDescr::Int16x8:
MOZ_CRASH("NYI, RSimdBox of Int16x8");
break;
}
if (!resultObject)
+8 -8
View File
@@ -112,7 +112,7 @@ class Registers
ra = r31,
invalid_reg
};
typedef RegisterID Code;
typedef uint8_t Code;
typedef RegisterID Encoding;
// Content spilled during bailouts.
@@ -120,22 +120,22 @@ class Registers
uintptr_t r;
};
static const char *GetName(Code code) {
static const char* GetName(Code code) {
MOZ_ASSERT(code < Total);
static const char * const Names[] = { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"};
return Names[code];
}
static const char *GetName(uint32_t i) {
MOZ_ASSERT(i < Total);
static const char* GetName(Encoding i) {
return GetName(Code(i));
}
static Code FromName(const char* name);
static const Code StackPointer = sp;
static const Code Invalid = invalid_reg;
static const Encoding StackPointer = sp;
static const Encoding Invalid = invalid_reg;
static const uint32_t Total = 32;
static const uint32_t Allocatable = 14;
@@ -277,7 +277,7 @@ class FloatRegisters
double d;
};
static const char *GetName(Code code) {
static const char* GetName(Code code) {
static const char * const Names[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13",
"f14", "f15", "f16", "f17", "f18", "f19",
@@ -285,7 +285,7 @@ class FloatRegisters
"f26", "f27", "f28", "f29", "f30", "f31"};
return Names[code];
}
static const char *GetName(uint32_t i) {
static const char* GetName(uint32_t i) {
MOZ_ASSERT(i < Total);
return GetName(Code(i % 32));
}
+1 -1
View File
@@ -1420,7 +1420,7 @@ void
Assembler::as_break(uint32_t code)
{
MOZ_ASSERT(code <= MAX_BREAK_CODE);
writeInst(op_special | code << RTShift | ff_break);
writeInst(op_special | code << FunctionBits | ff_break);
}
uint32_t
+15 -1
View File
@@ -641,6 +641,20 @@ PatchBackedge(CodeLocationJump& jump_, CodeLocationLabel label, JitRuntime::Back
class Assembler;
typedef js::jit::AssemblerBuffer<1024, Instruction> MIPSBuffer;
class MIPSBufferWithExecutableCopy : public MIPSBuffer
{
public:
void executableCopy(uint8_t* buffer) {
if (this->oom())
return;
for (Slice* cur = head; cur != nullptr; cur = cur->getNext()) {
memcpy(buffer, &cur->instructions, cur->length());
buffer += cur->length();
}
}
};
class Assembler : public AssemblerShared
{
public:
@@ -751,7 +765,7 @@ class Assembler : public AssemblerShared
CompactBufferWriter dataRelocations_;
CompactBufferWriter preBarriers_;
MIPSBuffer m_buffer;
MIPSBufferWithExecutableCopy m_buffer;
public:
Assembler()
+11 -33
View File
@@ -2028,44 +2028,15 @@ CodeGeneratorMIPS::visitAsmJSPassStackArg(LAsmJSPassStackArg* ins)
}
void
CodeGeneratorMIPS::visitUDiv(LUDiv* ins)
{
Register lhs = ToRegister(ins->lhs());
Register rhs = ToRegister(ins->rhs());
Register output = ToRegister(ins->output());
Label done;
if (ins->mir()->canBeDivideByZero()) {
if (ins->mir()->isTruncated()) {
Label notzero;
masm.ma_b(rhs, rhs, &notzero, Assembler::NonZero, ShortJump);
masm.move32(Imm32(0), output);
masm.ma_b(&done, ShortJump);
masm.bind(&notzero);
} else {
MOZ_ASSERT(ins->mir()->fallible());
bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot());
}
}
masm.as_divu(lhs, rhs);
masm.as_mflo(output);
if (!ins->mir()->isTruncated())
bailoutCmp32(Assembler::LessThan, output, Imm32(0), ins->snapshot());
masm.bind(&done);
}
void
CodeGeneratorMIPS::visitUMod(LUMod* ins)
CodeGeneratorMIPS::visitUDivOrMod(LUDivOrMod* ins)
{
Register lhs = ToRegister(ins->lhs());
Register rhs = ToRegister(ins->rhs());
Register output = ToRegister(ins->output());
Label done;
if (ins->mir()->canBeDivideByZero()) {
// Prevent divide by zero.
if (ins->canBeDivideByZero()) {
if (ins->mir()->isTruncated()) {
// Infinity|0 == 0
Label notzero;
@@ -2074,7 +2045,6 @@ CodeGeneratorMIPS::visitUMod(LUMod* ins)
masm.ma_b(&done, ShortJump);
masm.bind(&notzero);
} else {
MOZ_ASSERT(ins->mir()->fallible());
bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot());
}
}
@@ -2082,6 +2052,14 @@ CodeGeneratorMIPS::visitUMod(LUMod* ins)
masm.as_divu(lhs, rhs);
masm.as_mfhi(output);
// If the remainder is > 0, bailout since this must be a double.
if (ins->mir()->isDiv()) {
if (!ins->mir()->toDiv()->canTruncateRemainder())
bailoutCmp32(Assembler::NonZero, output, output, ins->snapshot());
// Get quotient
masm.as_mflo(output);
}
if (!ins->mir()->isTruncated())
bailoutCmp32(Assembler::LessThan, output, Imm32(0), ins->snapshot());
+1 -2
View File
@@ -249,8 +249,7 @@ class CodeGeneratorMIPS : public CodeGeneratorShared
protected:
void visitEffectiveAddress(LEffectiveAddress* ins);
void visitUDiv(LUDiv* ins);
void visitUMod(LUMod* ins);
void visitUDivOrMod(LUDivOrMod* ins);
public:
// Unimplemented SIMD instructions
+9 -12
View File
@@ -355,23 +355,20 @@ class LMulI : public LBinaryMath<0>
}
};
class LUDiv : public LBinaryMath<0>
class LUDivOrMod : public LBinaryMath<0>
{
public:
LIR_HEADER(UDiv);
LIR_HEADER(UDivOrMod);
MDiv* mir() {
return mir_->toDiv();
MBinaryArithInstruction* mir() const {
MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
return static_cast<MBinaryArithInstruction* >(mir_);
}
};
class LUMod : public LBinaryMath<0>
{
public:
LIR_HEADER(UMod);
MMod* mir() {
return mir_->toMod();
bool canBeDivideByZero() const {
if (mir_->isMod())
return mir_->toMod()->canBeDivideByZero();
return mir_->toDiv()->canBeDivideByZero();
}
};
+1 -2
View File
@@ -20,8 +20,7 @@
_(PowHalfD) \
_(AsmJSUInt32ToDouble) \
_(AsmJSUInt32ToFloat32) \
_(UDiv) \
_(UMod) \
_(UDivOrMod) \
_(AsmJSLoadFuncPtr)
#endif // jit_mips_LOpcodes_mips_h__
+2 -2
View File
@@ -419,7 +419,7 @@ LIRGeneratorMIPS::lowerUDiv(MDiv* div)
MDefinition* lhs = div->getOperand(0);
MDefinition* rhs = div->getOperand(1);
LUDiv* lir = new(alloc()) LUDiv;
LUDivOrMod* lir = new(alloc()) LUDivOrMod;
lir->setOperand(0, useRegister(lhs));
lir->setOperand(1, useRegister(rhs));
if (div->fallible())
@@ -434,7 +434,7 @@ LIRGeneratorMIPS::lowerUMod(MMod* mod)
MDefinition* lhs = mod->getOperand(0);
MDefinition* rhs = mod->getOperand(1);
LUMod* lir = new(alloc()) LUMod;
LUDivOrMod* lir = new(alloc()) LUDivOrMod;
lir->setOperand(0, useRegister(lhs));
lir->setOperand(1, useRegister(rhs));
if (mod->fallible())
+9
View File
@@ -234,6 +234,15 @@ class MacroAssemblerMIPS : public Assembler
ma_li(ScratchRegister, imm);
ma_b(lhs, ScratchRegister, l, c, jumpKind);
}
void ma_b(Register lhs, ImmWord imm, Label* l, Condition c, JumpKind jumpKind = LongJump)
{
ma_b(lhs, Imm32(uint32_t(imm.value)), l, c, jumpKind);
}
void ma_b(Address addr, ImmWord imm, Label* l, Condition c, JumpKind jumpKind = LongJump)
{
ma_b(addr, Imm32(uint32_t(imm.value)), l, c, jumpKind);
}
void ma_b(Register lhs, Address addr, Label* l, Condition c, JumpKind jumpKind = LongJump);
void ma_b(Address addr, Imm32 imm, Label* l, Condition c, JumpKind jumpKind = LongJump);
void ma_b(Address addr, ImmGCPtr imm, Label* l, Condition c, JumpKind jumpKind = LongJump);
+2 -2
View File
@@ -42,7 +42,7 @@
namespace js {
namespace jit {
static const Instr kCallRedirInstr = op_special | MAX_BREAK_CODE << RTShift | ff_break;
static const Instr kCallRedirInstr = op_special | MAX_BREAK_CODE << FunctionBits | ff_break;
// Utils functions.
static bool
@@ -3423,7 +3423,7 @@ Simulator::call(uint8_t* entry, int argument_count, ...)
else
entry_stack = entry_stack - kCArgsSlotsSize;
entry_stack &= ~ABIStackAlignment;
entry_stack &= ~(ABIStackAlignment - 1);
intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
+1 -1
View File
@@ -276,7 +276,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0),
&skipProfilingInstrumentation);
masm.ma_addu(realFramePtr, StackPointer, Imm32(sizeof(void*)));
masm.ma_addu(realFramePtr, framePtr, Imm32(sizeof(void*)));
masm.profilerEnterFrame(realFramePtr, scratch);
masm.bind(&skipProfilingInstrumentation);
}
+1
View File
@@ -846,6 +846,7 @@ enum AsmJSImmKind
AsmJSImm_ReportOverRecursed,
AsmJSImm_OnDetached,
AsmJSImm_OnOutOfBounds,
AsmJSImm_OnImpreciseConversion,
AsmJSImm_HandleExecutionInterrupt,
AsmJSImm_InvokeFromAsmJS_Ignore,
AsmJSImm_InvokeFromAsmJS_ToInt32,

Some files were not shown because too many files have changed in this diff Show More