Compare commits

...
101 Commits
Author SHA1 Message Date
Basilisk-Dev 00084ea49c Cherry-pick upstream libvpx fix
Backport of https://hg.mozilla.org/releases/mozilla-esr115/rev/5241232a3292943bd59ff1704eab60fee3cbc9d1
Addresses CVE-2023-5217
2023-09-28 16:18:01 +02:00
Moonchild b6fae24296 [network] Refactor TransactionObserver::OnDataAvailable() 2023-09-27 21:55:28 +02:00
André Bargull 13c6b7422d [js] Handle dead wrappers 2023-09-27 21:55:19 +02:00
Moonchild 24f2e663cd Restore incorrect SIMD Op removals. 2023-09-25 10:48:42 +02:00
Brian Smith f96b155988 Issue #2313 - Implement WebAssembly sign extension opcodes. (uplift) 2023-09-25 10:46:25 +02:00
Brian Smith d5cc24e916 Issue #2308 & #1240 Follow-up - Fill in missing JSOP_INC/DEC cases for Doubles in Ion. 2023-09-20 03:34:06 +02:00
Brian Smith 8eba271c5f Issue #2308 & #1240 Follow-up - Replace JSOP_POS in ++/-- with JSOP_TONUMERIC.
https://bugzilla.mozilla.org/show_bug.cgi?id=1519135
2023-09-20 03:33:57 +02:00
Brian Smith 19955c82b3 Issue #2308 & #1240 Follow-up - Fill in missing JSOP_INC/DEC cases for Ion on Intel32/64. 2023-09-20 03:33:50 +02:00
Brian Smith 80ae8aec7c Issue #2308 & #1240 Follow-up - Add BigInt support to JSOP_INC and JSOP_DEC.
https://bugzilla.mozilla.org/show_bug.cgi?id=1526309
2023-09-20 03:33:41 +02:00
Brian Smith d8441d7c81 Issue #2308 & #1240 Follow-up - Introduce new increment and decrement operations.
https://bugzilla.mozilla.org/show_bug.cgi?id=1508521
2023-09-20 03:33:33 +02:00
Brian Smith c2446f2478 Issue #2308 - Fix JSON BigInt regressions.
https://bugzilla.mozilla.org/show_bug.cgi?id=1522433
2023-09-20 03:33:23 +02:00
Brian Smith 6efb7a1904 Issue #2282 - Performance observer safety checks.
Both fixes from later revisions, without the Dispatch API changes.
2023-09-20 03:33:14 +02:00
Brian Smith fa0b03a10f Issue #2026 Follow-up: Fill in missing BigInt64 cases in js::IsTypedArrayConstructor().
Hopefully fixes RSA errors on ProtonMail.
2023-09-20 03:32:41 +02:00
Moonchild 3ae2972950 Issue #2309 - Cherry-pick upstream libwebp fix.
Backport of: https://chromium.googlesource.com/webm/libwebp.git/+/2af26267cdfcb63a88e5c74a85927a12d6ca1d76

Resolves #2309
2023-09-13 10:22:50 +02:00
Moonchild 2d48de9998 Merge branch 'master' into release 2023-09-01 15:44:29 +02:00
Moonchild 3b029cdfe4 Merge branch 'master' into release 2023-07-15 16:01:39 +02:00
Moonchild ea9077a8a5 Merge branch 'master' into release 2023-07-07 19:41:06 +02:00
Moonchild b4af6b6265 No issue - Set the default for incremental cycle collector to be off.
Negative performance impact if enabled.
2023-06-05 21:17:24 +02:00
Moonchild ae1d53ceb1 Issue #2257 - Remove rematerialized frames after bailouts and exceptions.
This ensures that rematerialized frames used by the devtools debugger
are properly removed so that no stale data is used during bailouts.
2023-06-05 21:17:13 +02:00
Brian Smith c3f4709d5e Issue #2252 - Prevent crash when attempting to load a script with execution disallowed.
This issue is due to the ExecutionContext added in Issue #1691 not handling GetScript()
in a context where script execution is not allowed.  This expressed itself in crashes when
playing MP4s with the NoScript extension installed and enabled.
2023-06-05 21:16:57 +02:00
FranklinDM a7bb3fc175 Issue #1592 - Follow-up: Ensure topmost scope marker is cleaned up 2023-06-05 21:16:43 +02:00
FranklinDM 6a0203f25f Issue #2250 - Part 2: Ignore the ancestor filter assertion if rule matching is restricted or if the current element is under a shadow host
This only affects debug builds.
2023-06-05 21:16:31 +02:00
FranklinDM b0dfcb147f Issue #2250 - Part 1: Return early if the element being tested for is likely an ancestor and does not have an assigned slot 2023-06-05 21:16:22 +02:00
Job Bautista 06fd4c9357 Issue #2221 - Follow-up: Simplify jit_ioncheck{1|2|3}_deunified_sources assignment. 2023-06-05 21:15:52 +02:00
Job Bautista b9ea7fd9ee Issue #2221 - Follow-up: Ensure jit_ioncheck{1|2|3}_deunified_sources is defined.
Should fix build bustage in armhf, as well as prevent bustage in mips32.
2023-06-05 21:15:33 +02:00
Moonchild 58308a5c7a Merge branch 'master' into release
# Conflicts:
#	python/mozbuild/mozpack/dmg.py
2023-05-11 17:35:14 +02:00
Brian Smith 88c7d54975 No Issue - Fix FreeBSD build failure with WebRTC enabled. (release uplift)
Tag #2227
2023-05-01 22:12:11 +02:00
Timothy Valldeperas eadb5678b3 Issue #2175 - Fix build bustage in WebRTC. (release uplift)
Resolves #2227
2023-05-01 19:04:57 +02:00
Moonchild 54e3e60796 Revert "[devtools] Don't allow sourcemap URLs to redirect"
This reverts commit 2a05494abe.
2023-04-17 10:25:45 +02:00
Moonchild 2a05494abe [devtools] Don't allow sourcemap URLs to redirect 2023-04-13 10:54:34 +02:00
Moonchild bc89e58def [network] Improve checks while parsing MIME parameters. 2023-04-13 10:54:27 +02:00
Moonchild 3a009b97f6 Issue #1911 - Follow-up: Filter out illegal characters in more locations. 2023-04-13 10:54:10 +02:00
Moonchild a105f6d5e9 No issue - Fix off-by-one of kLargeDatasetSize 2023-04-13 10:54:02 +02:00
Sandra 5db241c0c0 Increase size of data over which we write the data to disk rather than keep it around in memory 2023-04-13 10:53:53 +02:00
Sandra d38dca10e5 Use nsAnonymousTemporaryFile for clipboard cache
Base on https://github.com/mozilla/gecko-dev/commit/ecc04a9245b409d7eed7df63ba733cd2073180de
2023-04-13 10:53:14 +02:00
Moonchild 54fc723126 Issue #2180 - Follow-up: Move sentinel check up a bit. 2023-04-02 15:39:05 +02:00
Moonchild 9b8ca17ee4 Issue #2180 - Add pref to control NSS TLS 1.3 protocol downgrade sentinel 2023-04-02 15:38:57 +02:00
Moonchild cddc95b39b Issue #2176 - Don't reconstruct the parent when tearing down
display:contents nodes with pseudo-elements.

We need to use StyleChildrenIterator which iterates over them, instead.
This is a bit of a hack but we can't always have our cake.

We need to be a bit careful though, since ::before and ::after are owned
by their own frame, and thus could be unbound from the tree or even dead
after removing the frame.

This basically ports bugs 1435566 and 1438467
2023-04-02 15:38:31 +02:00
Moonchild 5676529793 Issue #2171 - Skip over shadow nodes that don't have an owning node.
Resolves #2171
2023-04-02 15:37:44 +02:00
Moonchild ce68156cf4 Revert "[widget] Linux GTK3: Detach accessible from moz_container before it's deleted"
This reverts commit 465a18f342.
Resolves #2168
2023-03-18 19:57:56 +01:00
Moonchild 5032ad9593 Issue #2117 - Follow-up: Run precomplete cmd during package staging
We rely on this for all OSes except Mac where precomplete should not
be in the root (it uses Mozilla's fallback packaging that places it in
$RESPATH)
2023-03-17 22:11:30 +01:00
Moonchild b55f765f2e Issue #1911 - Follow-up: Filter out illegal file extensions also.
We already did this for file names, just not extensions.
2023-03-17 12:02:55 +01:00
Moonchild 856078d435 [widget] Linux GTK3: Detach accessible from moz_container before it's deleted 2023-03-17 12:02:46 +01:00
Moonchild c74c262d2f [GFX] Add some sanity checks and clamps to SurfaceData calculations. 2023-03-17 12:02:38 +01:00
Moonchild 787e29e374 No Issue - Ensure more OsiSpace
ensureOsiSpace(); was very much under-used. This adds more instances
where it makes sense to ensure Osi space before placing masm calls.
2023-03-17 12:02:31 +01:00
FranklinDM e439896c9b Issue #2148 - Shrink Vector from (usually) four pointers in size to three
when no inline storage is used.

See Bug 1338374
2023-03-17 12:02:20 +01:00
FranklinDM 15b508f1fb Issue #2148 - Make Vector not use AlignedStorage for its inline element storage
See Bug 1338374 1/2
2023-03-17 12:02:12 +01:00
Job Bautista 5651ebfc76 Issue #2148 - Discard RegExpShared data tables when discarding regexp JIT code.
Based on Mozilla bug 1378736's part 2.
Should fix the double-free.
Follow-up for #2083
2023-03-17 12:02:04 +01:00
Job Bautista 593bfc1ce8 Issue #2148 - Don't null out RegExpObject -> RegExpShared pointer on GC.
Follow-up for issue #2083.
Taken from Mozilla bug 1378736.
2023-03-17 12:01:50 +01:00
Brian Smith 28953cda7a Issue #2160 - Initial support for notarizing during DMG package.
Added --with-macbundle-idenity configure option to set a codesign identity.
If no identity is set or cross-compiling from Linux no codesigning will be
done. Currently doing a full deep bundle v2 sign, instead of limited v1.
2023-03-15 15:10:52 +01:00
Moonchild 516f3f545d Merge branch 'master' into release
# Conflicts:
#	CLOBBER
#	js/src/vm/RegExpObject.cpp
#	security/nss/lib/nss/nss.h
#	security/nss/lib/pkcs12/p12d.c
#	security/nss/lib/softoken/softkver.h
#	security/nss/lib/util/nssutil.h
2023-03-13 13:11:20 +01:00
Moonchild 83aff65a42 Force clobber 2023-02-19 17:53:31 +01:00
Moonchild 5bd97df957 [NSS] Update NSS to 3.52.9 to pick up fixes. 2023-02-19 17:51:26 +01:00
Moonchild 8772711181 [DOM] Check whether module load request was already cancelled when a load fails 2023-02-19 17:51:18 +01:00
Moonchild dc9526f4c6 [widget] Properly test for and handle errors in target-surface creation
and mapping.
2023-02-19 17:51:10 +01:00
Moonchild 9ab36e7ae0 Issue #2103 - Fix typo in RegExp Parser
This corrects the typo where the left-hand character would determine if
the right-hand character would be added or not.

Resolves #2103
2023-02-02 10:50:47 +01:00
Job Bautista e8d30841e7 Issue #2091 - Parse \p{Extended_Pictographic} too.
This is essentially a follow up to Issue #1286. We already have
 UCHAR_EXTENDED_PICTOGRAPHIC in our in-tree ICU, so there's no reason to comment
 this case out.
2023-01-27 05:01:53 +01:00
Martok 9faf29374e Issue #2093 - Trace HeapPtr<RegExpShared::groupsTemplate_> for GC move/compact events, regression from #2072 2023-01-26 20:11:28 +01:00
Moonchild 75e4818d36 Merge branch 'master' into release 2023-01-19 00:42:00 +01:00
Moonchild a65144e9e0 Fix merge conflicts. 2023-01-13 12:55:52 +01:00
Moonchild 4f29548526 Merge branch 'master' into release
# Conflicts:
#	image/decoders/nsJXLDecoder.cpp
#	js/src/irregexp/NativeRegExpMacroAssembler.cpp
#	js/src/irregexp/RegExpAST.h
#	js/src/irregexp/RegExpEngine.cpp
#	js/src/irregexp/RegExpParser.cpp
#	js/src/irregexp/RegExpParser.h
#	xpcom/io/nsLocalFileUnix.cpp
2023-01-13 12:11:56 +01:00
Moonchild 528db2cbd8 Issue #1818 - Remove obsolete path hack in widget code. 2022-12-16 09:13:48 +00:00
Moonchild 84e6bcc1e6 [network] Align cookie checks with RFC 6265 (bis) 2022-12-16 09:13:38 +00:00
Moonchild 0dc9ff518d [libjar] Add some extra sanity checks to our Zip reader. 2022-12-16 09:13:25 +00:00
Moonchild a2e3bd44aa [network] move some generic websocket code to the baseclass 2022-12-16 09:13:09 +00:00
Moonchild 163a0e7caf Revert "Issue #1279 - Implement regular expressions lookbehind (v2)"
This reverts commit d10e8a5b06.
2022-12-15 09:11:02 +00:00
Moonchild 49a86db5f3 Issue #2040 - Pre-multiply the alpha values in our JXL decode buffer. (uplift)
Using selective calculation (only if not opaque) and fast integer
math here should optimize well in compilers.
2022-12-15 09:09:19 +00:00
Moonchild 2640953d8b Issue #2019 - Follow-up: Make nsPluginInstanceOwner also listen to keypress events in the system event group.
nsPluginInstanceOwner only listens to keypress events in the default event group.
However, in our changed operating mode, keypress events are not fired in the
default event group if the key does not result in something printable.
This means that nsPluginInstanceOwner should also listen to keypress events
in the system event group and should handle each keypress that way, but
only once. I.e., if a printable keypress event is received in the system event
group, it should be ignored, since it would've already been handled in the
default event group in that case.
2022-11-26 18:18:09 +00:00
Moonchild 7eb7d67f7a Issue #2033 - Temporary fix of R<->B channel swap.
We have a BGR/RGB channel ordering mismatch here. to at least
provide proper display, a quick&dirty byte swap on the output
buffer will fix this for now, but we should look into seeing where
the surface mismatch is caused.
std::swap() should optimize pretty well in any of the used
compilers, but if necessary, a full buffer ASM routine can be
slotted in (although on current hardware I doubt this will be
even noticeable as it is)
2022-11-26 02:43:18 +00:00
Moonchild e28860ba7f Revert "[XPCOM] Deal with lstat potentially lying in nsLocalFileUnix."
This reverts commit c127f58ef3.
2022-11-20 14:14:48 +00:00
Moonchild 49a96b1d91 Merge branch 'master' into release 2022-11-19 20:15:23 +00:00
Moonchild 3130812693 Merge branch 'master' into release 2022-11-12 18:34:07 +00:00
Moonchild 71ae69aea8 [WebGL] Implement webgl.max-size-per-texture-mib 2022-10-26 14:50:05 +00:00
Moonchild 9e34d697c7 [XPCOM] Fix Base64 off-by-one issue and safeguard against this mistake in the future. 2022-10-26 14:49:55 +00:00
Moonchild 8fa9125d02 [No issue] Hold some strong references on nsRefreshDriver 2022-10-26 14:49:46 +00:00
Brian Smith 4b4488c3e4 Issue #2022 - Part 2 - Add Ventura version detection.
Also add Monterey and Ventura to the graphics driver blocklist.
2022-10-26 14:49:33 +00:00
Brian Smith 248db7d301 Issue #2022 - Part 1 - Fix transparent windows on MacOS 13 Ventura.
During the BaseWindow creation contenView is nil on Ventura...
So create a NSView with the requested dimensions and set is as the contenView.
2022-10-26 14:49:23 +00:00
Moonchild e199f2949b [No issue] Ensure LockImpl::Try() returns the correct bool value. 2022-10-26 14:45:39 +00:00
Moonchild 456b5450a4 Issue #2010 - Ensure raw tagnames are safe exiting internalEntityParser
This resolves #2010
2022-09-28 13:50:10 +00:00
Moonchild d8e629c4a3 Merge branch 'master' into release 2022-09-27 20:12:40 +00:00
Moonchild 4898c4f297 Merge branch 'master' into release 2022-09-24 12:16:59 +00:00
Moonchild 7cd578bbc6 Merge branch 'master' into release 2022-09-22 13:16:48 +00:00
Moonchild 1e91df628a Merge branch 'master' into release 2022-09-22 11:52:16 +00:00
Moonchild b110549cbd Merge branch 'master' into release 2022-07-27 06:07:45 +00:00
Moonchild 971047835a Merge branch 'master' into release
# Conflicts:
#	config/milestone.txt
#	toolkit/mozapps/extensions/internal/XPIProvider.jsm
2022-07-25 20:47:06 +00:00
Moonchild dd4d9eb032 [XPCOM] Crash safely when TArray replacements are OOB.
In the unlikely event of TArray element replacement calls are OOB, crash safely
with a debug breakpoint instead of corrupting memory.
2022-07-03 15:49:44 +00:00
Moonchild 8b94f1e480 [DOM] use the sanitizer to restrict href in svg:use to fragment-only URLs 2022-07-03 15:49:34 +00:00
Moonchild c89610a5c7 [network] Clear PAC loader when the load failed 2022-07-03 15:49:23 +00:00
Moonchild 217963cbed Update NSS to 3.52.7 2022-07-03 15:49:14 +00:00
Moonchild c4f4e18340 [DOM media] Remove potentially unsafe type accesses when debug logging 2022-07-03 15:49:04 +00:00
Moonchild 8a7c0e7345 [network] Clean up and update the list of external protocol handlers. 2022-07-03 15:48:54 +00:00
Moonchild 52e304d450 Issue #1053 - Follow-up: Correct conditional define on POSIX systems. (uplift)
This conditional was incorrectly changed when removing Android support.
This potentially causes issues on Linux systems by not using pthreads correctly,
which may lead to high idle CPU usage.
2022-06-28 13:28:20 +00:00
Moonchild cfc0eeca53 Revert "Issue #1909 - Guard against empty update manifest URL"
This reverts commit d7fadcdef9.
2022-06-07 11:59:07 +00:00
Moonchild ebd3dd9228 Merge branch 'master' into release 2022-06-03 21:50:44 +00:00
Moonchild cb40e4e7ef Merge branch 'master' into release 2022-06-01 13:54:11 +00:00
Moonchild 662dba55fd Merge branch 'master' into release 2022-05-29 11:13:44 +00:00
Moonchild 8760ce023c Issue #1895 - Implement queueMicroTask(callback()) (uplift) 2022-05-07 14:40:14 +00:00
Moonchild b86e148bb7 Roll back milestone version to release. 2022-05-06 12:43:43 +00:00
Moonchild 9e83721e5e Merge branch 'master' into release 2022-05-06 12:43:00 +00:00
Moonchild dc2d6c2e60 Revert "No Issue - Make content-type on JAR channels behave the same as HTTP channels."
This reverts commit 425677ada7.
2022-05-03 17:38:19 +00:00
Moonchild 4ada6f6762 Update 7zSD for v31 2022-05-03 17:38:12 +00:00
75 changed files with 1310 additions and 295 deletions

No files matched your search

+8 -2
View File
@@ -676,7 +676,8 @@ public:
NS_IMETHOD Run() override
{
MOZ_ASSERT(mPerformance);
mPerformance->NotifyObservers();
RefPtr<Performance> performance(mPerformance);
performance->NotifyObservers();
return NS_OK;
}
@@ -700,7 +701,12 @@ Performance::RunNotificationObserversTask()
{
mPendingNotificationObserversTask = true;
nsCOMPtr<nsIRunnable> task = new NotifyObserversTask(this);
nsresult rv = NS_DispatchToCurrentThread(task);
nsresult rv;
if (NS_IsMainThread()) {
rv = NS_DispatchToCurrentThread(task);
} else {
rv = NS_DispatchToMainThread(task);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
mPendingNotificationObserversTask = false;
}
+5
View File
@@ -57,6 +57,10 @@ namespace JS {
_(BinaryArith_SharedCache) \
_(BinaryArith_Call) \
\
_(UnaryArith_SpecializedTypes) \
_(UnaryArith_SpecializedOnBaselineTypes) \
_(UnaryArith_InlineCache) \
\
_(InlineCache_OptimizedStub) \
\
_(Call_Inline)
@@ -112,6 +116,7 @@ namespace JS {
_(GetElemStringNotCached) \
_(NonNativeReceiver) \
_(IndexType) \
_(SpeculationOnInputTypesFailed) \
_(SetElemNonDenseNonTANotCached) \
_(NoSimdJitSupport) \
_(SimdTypeNotOptimized) \
+6 -2
View File
@@ -537,8 +537,12 @@ JSObject*
PromiseObject::resolutionSite()
{
auto debugInfo = PromiseDebugInfo::FromPromise(this);
if (debugInfo)
return debugInfo->resolutionSite();
if (debugInfo) {
JSObject* site = debugInfo->resolutionSite();
if (site && !JS_IsDeadWrapper(site)) {
return site;
}
}
return nullptr;
}
+1 -1
View File
@@ -2057,7 +2057,7 @@ BytecodeEmitter::emitCallIncDec(UnaryNode* incDec)
MOZ_ASSERT(call->isKind(PNK_CALL));
if (!emitTree(call)) // CALLRESULT
return false;
if (!emit1(JSOP_POS)) // N
if (!emit1(JSOP_TONUMERIC)) // N
return false;
// The increment/decrement has no side effects, so proceed to throw for
+3 -6
View File
@@ -233,8 +233,8 @@ ElemOpEmitter::emitIncDec()
MOZ_ASSERT(state_ == State::Get);
JSOp binOp = isInc() ? JSOP_ADD : JSOP_SUB;
if (!bce_->emit1(JSOP_POS)) { // ... N
JSOp incOp = isInc() ? JSOP_INC : JSOP_DEC;
if (!bce_->emit1(JSOP_TONUMERIC)) { // ... N
return false;
}
if (isPostIncDec()) {
@@ -242,10 +242,7 @@ ElemOpEmitter::emitIncDec()
return false;
}
}
if (!bce_->emit1(JSOP_ONE)) { // ... N? N 1
return false;
}
if (!bce_->emit1(binOp)) { // ... N? N+1
if (!bce_->emit1(incOp)) { // ... N? N+1
return false;
}
if (isPostIncDec()) {
+3 -6
View File
@@ -339,11 +339,11 @@ NameOpEmitter::emitIncDec()
{
MOZ_ASSERT(state_ == State::Start);
JSOp binOp = isInc() ? JSOP_ADD : JSOP_SUB;
JSOp incOp = isInc() ? JSOP_INC : JSOP_DEC;
if (!prepareForRhs()) { // ENV? V
return false;
}
if (!bce_->emit1(JSOP_POS)) { // ENV? N
if (!bce_->emit1(JSOP_TONUMERIC)) { // ENV? N
return false;
}
if (isPostIncDec()) {
@@ -351,10 +351,7 @@ NameOpEmitter::emitIncDec()
return false;
}
}
if (!bce_->emit1(JSOP_ONE)) { // ENV? N? N 1
return false;
}
if (!bce_->emit1(binOp)) { // ENV? N? N+1
if (!bce_->emit1(incOp)) { // ENV? N? N+1
return false;
}
if (isPostIncDec() && emittedBindOp()) {
+3 -6
View File
@@ -217,9 +217,9 @@ PropOpEmitter::emitIncDec(JSAtom* prop)
MOZ_ASSERT(state_ == State::Get);
JSOp binOp = isInc() ? JSOP_ADD : JSOP_SUB;
JSOp incOp = isInc() ? JSOP_INC : JSOP_DEC;
if (!bce_->emit1(JSOP_POS)) { // ... N
if (!bce_->emit1(JSOP_TONUMERIC)) { // ... N
return false;
}
if (isPostIncDec()) {
@@ -227,10 +227,7 @@ PropOpEmitter::emitIncDec(JSAtom* prop)
return false;
}
}
if (!bce_->emit1(JSOP_ONE)) { // ... N? N 1
return false;
}
if (!bce_->emit1(binOp)) { // ... N? N+1
if (!bce_->emit1(incOp)) { // ... N? N+1
return false;
}
if (isPostIncDec()) {
+2
View File
@@ -84,6 +84,8 @@ const I64TruncUF32Code = 0xaf;
const I64TruncSF64Code = 0xb0;
const I64TruncUF64Code = 0xb1;
const FirstInvalidOpcode = 0xc5;
// DefinitionKind
const FunctionCode = 0x00;
const TableCode = 0x01;
+39 -4
View File
@@ -1322,14 +1322,37 @@ BaselineCompiler::emit_JSOP_POS()
// Keep top stack value in R0.
frame.popRegsAndSync(1);
// Inline path for int32 and double.
// Inline path for int32 and double; otherwise call VM.
Label done;
masm.branchTestNumber(Assembler::Equal, R0, &done);
// Call IC.
ICToNumber_Fallback::Compiler stubCompiler(cx);
if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
prepareVMCall();
pushArg(R0);
if (!callVM(ToNumberInfo)) {
return false;
}
masm.bind(&done);
frame.push(R0);
return true;
}
bool
BaselineCompiler::emit_JSOP_TONUMERIC()
{
// Keep top stack value in R0.
frame.popRegsAndSync(1);
// Inline path for int32 and double; otherwise call VM.
Label done;
masm.branchTestNumber(Assembler::Equal, R0, &done);
prepareVMCall();
pushArg(R0);
if (!callVM(ToNumericInfo)) {
return false;
}
masm.bind(&done);
frame.push(R0);
@@ -1939,6 +1962,18 @@ BaselineCompiler::emit_JSOP_NEG()
return emitUnaryArith();
}
bool
BaselineCompiler::emit_JSOP_INC()
{
return emitUnaryArith();
}
bool
BaselineCompiler::emit_JSOP_DEC()
{
return emitUnaryArith();
}
bool
BaselineCompiler::emit_JSOP_LT()
{
+6 -3
View File
@@ -50,6 +50,7 @@ namespace jit {
_(JSOP_OR) \
_(JSOP_NOT) \
_(JSOP_POS) \
_(JSOP_TONUMERIC) \
_(JSOP_LOOPHEAD) \
_(JSOP_LOOPENTRY) \
_(JSOP_VOID) \
@@ -242,8 +243,10 @@ namespace jit {
_(JSOP_JUMPTARGET) \
_(JSOP_IS_CONSTRUCTING) \
_(JSOP_TRY_DESTRUCTURING_ITERCLOSE) \
_(JSOP_IMPORTMETA) \
_(JSOP_DYNAMIC_IMPORT)
_(JSOP_IMPORTMETA) \
_(JSOP_DYNAMIC_IMPORT) \
_(JSOP_INC) \
_(JSOP_DEC)
class BaselineCompiler : public BaselineCompilerSpecific
{
@@ -327,7 +330,7 @@ class BaselineCompiler : public BaselineCompilerSpecific
OPCODE_LIST(EMIT_OP)
#undef EMIT_OP
// JSOP_NEG, JSOP_BITNOT
// JSOP_NEG, JSOP_BITNOT, JSOP_INC, JSOP_DEC
MOZ_MUST_USE bool emitUnaryArith();
// JSOP_BITXOR, JSOP_LSH, JSOP_ADD etc.
-36
View File
@@ -694,42 +694,6 @@ ICToBool_Object::Compiler::generateStubCode(MacroAssembler& masm)
return true;
}
//
// ToNumber_Fallback
//
static bool
DoToNumberFallback(JSContext* cx, ICToNumber_Fallback* stub, HandleValue arg, MutableHandleValue ret)
{
FallbackICSpew(cx, stub, "ToNumber");
ret.set(arg);
return ToNumber(cx, ret);
}
typedef bool (*DoToNumberFallbackFn)(JSContext*, ICToNumber_Fallback*, HandleValue, MutableHandleValue);
static const VMFunction DoToNumberFallbackInfo =
FunctionInfo<DoToNumberFallbackFn>(DoToNumberFallback, "DoToNumberFallback", TailCall,
PopValues(1));
bool
ICToNumber_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
{
MOZ_ASSERT(engine_ == Engine::Baseline);
MOZ_ASSERT(R0 == JSReturnOperand);
// Restore the tail call register.
EmitRestoreTailCallReg(masm);
// Ensure stack is fully synced for the expression decompiler.
masm.pushValue(R0);
// Push arguments.
masm.pushValue(R0);
masm.push(ICStubReg);
return tailCallVM(DoToNumberFallbackInfo, masm);
}
//
// GetElem_Fallback
//
-26
View File
@@ -333,32 +333,6 @@ class ICToBool_Object : public ICStub
};
};
// ToNumber
// JSOP_POS
class ICToNumber_Fallback : public ICFallbackStub
{
friend class ICStubSpace;
explicit ICToNumber_Fallback(JitCode* stubCode)
: ICFallbackStub(ICStub::ToNumber_Fallback, stubCode) {}
public:
// Compiler for this stub kind.
class Compiler : public ICStubCompiler {
protected:
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
public:
explicit Compiler(JSContext* cx)
: ICStubCompiler(cx, ICStub::ToNumber_Fallback, Engine::Baseline) {}
ICStub* getStub(ICStubSpace* space) {
return newStub<ICToNumber_Fallback>(space, getStubCode());
}
};
};
// GetElem
// JSOP_GETELEM
-2
View File
@@ -34,8 +34,6 @@ namespace jit {
_(ToBool_Double) \
_(ToBool_Object) \
\
_(ToNumber_Fallback) \
\
_(Call_Fallback) \
_(Call_Scripted) \
_(Call_AnyScripted) \
+5
View File
@@ -408,6 +408,11 @@ BaselineInspector::expectedBinaryArithSpecialization(jsbytecode* pc)
MIRType result;
ICStub* stubs[2];
if (JSOp(*pc) == JSOP_POS) {
// +x expanding to x*1, but no corresponding IC.
return MIRType::None;
}
const ICEntry& entry = icEntryFromPC(pc);
ICStub* stub = entry.fallbackStub();
if (stub->isBinaryArith_Fallback() &&
+47 -3
View File
@@ -2378,6 +2378,8 @@ CodeGenerator::visitUnarySharedStub(LUnarySharedStub* lir)
switch (jsop) {
case JSOP_BITNOT:
case JSOP_NEG:
case JSOP_INC:
case JSOP_DEC:
emitSharedStub(ICStub::Kind::UnaryArith_Fallback, lir);
break;
case JSOP_CALLPROP:
@@ -3413,6 +3415,48 @@ CodeGenerator::visitLoadUnboxedExpando(LLoadUnboxedExpando* lir)
masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), result);
}
void
CodeGenerator::visitToNumeric(LToNumeric* lir)
{
ValueOperand operand = ToValue(lir, LToNumeric::Input);
ValueOperand output = ToOutValue(lir);
bool maybeInt32 = lir->mir()->mightBeType(MIRType::Int32);
bool maybeDouble = lir->mir()->mightBeType(MIRType::Double);
bool maybeNumber = maybeInt32 || maybeDouble;
bool maybeBigInt = lir->mir()->mightBeType(MIRType::BigInt);
int checks = int(maybeNumber) + int(maybeBigInt);
OutOfLineCode* ool = oolCallVM(ToNumericInfo, lir, ArgList(operand), StoreValueTo(output));
if (checks == 0) {
masm.jump(ool->entry());
} else {
Label done;
using Condition = Assembler::Condition;
constexpr Condition Equal = Assembler::Equal;
constexpr Condition NotEqual = Assembler::NotEqual;
if (maybeNumber) {
checks--;
Condition cond = checks ? Equal : NotEqual;
Label* target = checks ? &done : ool->entry();
masm.branchTestNumber(cond, operand, target);
}
if (maybeBigInt) {
checks--;
Condition cond = checks ? Equal : NotEqual;
Label* target = checks ? &done : ool->entry();
masm.branchTestBigInt(cond, operand, target);
}
MOZ_ASSERT(checks == 0);
masm.bind(&done);
masm.moveValue(operand, output);
}
masm.bind(ool->rejoin());
}
void
CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir)
{
@@ -12205,16 +12249,16 @@ CodeGenerator::visitRandom(LRandom* ins)
}
void
CodeGenerator::visitSignExtend(LSignExtend* ins)
CodeGenerator::visitSignExtendInt32(LSignExtendInt32* ins)
{
Register input = ToRegister(ins->input());
Register output = ToRegister(ins->output());
switch (ins->mode()) {
case MSignExtend::Byte:
case MSignExtendInt32::Byte:
masm.move8SignExtend(input, output);
break;
case MSignExtend::Half:
case MSignExtendInt32::Half:
masm.move16SignExtend(input, output);
break;
}
+2 -1
View File
@@ -149,6 +149,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir);
void visitGuardUnboxedExpando(LGuardUnboxedExpando* lir);
void visitLoadUnboxedExpando(LLoadUnboxedExpando* lir);
void visitToNumeric(LToNumeric* lir);
void visitTypeBarrierV(LTypeBarrierV* lir);
void visitTypeBarrierO(LTypeBarrierO* lir);
void visitMonitorTypes(LMonitorTypes* lir);
@@ -441,7 +442,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitRotate(LRotate* ins);
void visitRandom(LRandom* ins);
void visitSignExtend(LSignExtend* ins);
void visitSignExtendInt32(LSignExtendInt32* ins);
void visitModuleMetadata(LModuleMetadata* lir);
void visitDynamicImport(LDynamicImport* lir);
+214 -24
View File
@@ -636,7 +636,7 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod
MPhi* phi = entry->getSlot(slot)->toPhi();
if (*last == JSOP_POS)
if (*last == JSOP_POS || *last == JSOP_TONUMERIC)
last = earlier;
if (CodeSpec[*last].format & JOF_TYPESET) {
@@ -719,6 +719,8 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod
case JSOP_DIV:
case JSOP_MOD:
case JSOP_NEG:
case JSOP_INC:
case JSOP_DEC:
type = inspector->expectedResultType(last);
break;
case JSOP_BIGINT:
@@ -1584,6 +1586,7 @@ IonBuilder::traverseBytecode()
break;
case JSOP_POS:
case JSOP_TONUMERIC:
case JSOP_TOID:
case JSOP_TOSTRING:
// These ops may leave their input on the stack without setting
@@ -1737,9 +1740,16 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_POS:
return jsop_pos();
case JSOP_TONUMERIC:
return jsop_tonumeric();
case JSOP_NEG:
return jsop_neg();
case JSOP_INC:
case JSOP_DEC:
return jsop_inc_or_dec(op);
case JSOP_TOSTRING:
return jsop_tostring();
@@ -4852,7 +4862,7 @@ IonBuilder::jsop_bitop(JSOp op)
}
MDefinition::Opcode
JSOpToMDefinition(JSOp op)
BinaryJSOpToMDefinition(JSOp op)
{
switch (op) {
case JSOP_ADD:
@@ -4953,6 +4963,40 @@ IonBuilder::powTrySpecialized(bool* emitted, MDefinition* base, MDefinition* pow
return true;
}
MIRType
IonBuilder::binaryArithNumberSpecialization(MDefinition* left, MDefinition* right)
{
// Try to specialize as int32.
if (left->type() == MIRType::Int32 && right->type() == MIRType::Int32 &&
!inspector->hasSeenDoubleResult(pc)) {
return MIRType::Int32;
}
return MIRType::Double;
}
MBinaryArithInstruction*
IonBuilder::binaryArithEmitSpecialized(MDefinition::Opcode op, MIRType specialization,
MDefinition* left, MDefinition* right)
{
MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), op, left, right);
ins->setSpecialization(specialization);
if (op == MDefinition::Op_Add || op == MDefinition::Op_Mul) {
ins->setCommutative();
}
current->add(ins);
current->push(ins);
MOZ_ASSERT(!ins->isEffectful());
if(!maybeInsertResume()) {
return nullptr;
}
return ins;
}
static inline bool
SimpleArithOperand(MDefinition* op)
{
@@ -4986,19 +5030,20 @@ IonBuilder::binaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* left,
return true;
}
MDefinition::Opcode defOp = JSOpToMDefinition(op);
MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), defOp, left, right);
ins->setNumberSpecialization(alloc(), inspector, pc);
MDefinition::Opcode defOp = BinaryJSOpToMDefinition(op);
MIRType specialization = binaryArithNumberSpecialization(left, right);
MBinaryArithInstruction* ins = binaryArithEmitSpecialized(defOp, specialization, left, right);
if (op == JSOP_ADD || op == JSOP_MUL)
ins->setCommutative();
current->add(ins);
current->push(ins);
MOZ_ASSERT(!ins->isEffectful());
if (!maybeInsertResume())
if(!ins) {
return false;
}
// Relax int32 to double if, despite the fact that we have int32 operands and
// we've never seen a double result, we know the result may overflow or be a
// double.
if (specialization == MIRType::Int32 && ins->constantDoubleResult(alloc())) {
ins->setSpecialization(MIRType::Double);
}
trackOptimizationSuccess();
*emitted = true;
@@ -5022,16 +5067,10 @@ IonBuilder::binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op,
return true;
}
MDefinition::Opcode def_op = JSOpToMDefinition(op);
MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), def_op, left, right);
ins->setSpecialization(specialization);
current->add(ins);
current->push(ins);
MOZ_ASSERT(!ins->isEffectful());
if (!maybeInsertResume())
MDefinition::Opcode defOp = BinaryJSOpToMDefinition(op);
if(!binaryArithEmitSpecialized(defOp, specialization, left, right)) {
return false;
}
trackOptimizationSuccess();
*emitted = true;
@@ -5124,8 +5163,8 @@ IonBuilder::jsop_binary_arith(JSOp op, MDefinition* left, MDefinition* right)
trackOptimizationAttempt(TrackedStrategy::BinaryArith_Call);
trackOptimizationSuccess();
MDefinition::Opcode def_op = JSOpToMDefinition(op);
MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), def_op, left, right);
MDefinition::Opcode defOp = BinaryJSOpToMDefinition(op);
MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), defOp, left, right);
// Decrease type from 'any type' to 'empty type' when one of the operands
// is 'empty typed'.
@@ -5202,6 +5241,157 @@ IonBuilder::jsop_neg()
return jsop_binary_arith(JSOP_MUL, negator, right);
}
MDefinition*
IonBuilder::unaryArithConvertToBinary(JSOp op, MDefinition::Opcode* defOp)
{
switch (op) {
case JSOP_INC: {
*defOp = MDefinition::Op_Add;
MConstant* right = MConstant::New(alloc(), Int32Value(1));
current->add(right);
return right;
}
case JSOP_DEC: {
*defOp = MDefinition::Op_Sub;
MConstant* right = MConstant::New(alloc(), Int32Value(1));
current->add(right);
return right;
}
default:
MOZ_CRASH("unexpected unary opcode");
}
}
bool
IonBuilder::unaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* value)
{
MOZ_ASSERT(*emitted == false);
// Try to convert Inc(x) or Dec(x) to Add(x,1) or Sub(x,1) if the operand is a
// number.
trackOptimizationAttempt(TrackedStrategy::UnaryArith_SpecializedTypes);
if (!IsNumberType(value->type())) {
trackOptimizationOutcome(TrackedOutcome::OperandNotNumber);
return true;
}
MDefinition::Opcode defOp;
MDefinition* rhs = unaryArithConvertToBinary(op, &defOp);
MIRType specialization = binaryArithNumberSpecialization(value, rhs);
if (!binaryArithEmitSpecialized(defOp, specialization, value, rhs)) {
return false;
}
trackOptimizationSuccess();
*emitted = true;
return true;
}
bool
IonBuilder::unaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* value)
{
MOZ_ASSERT(*emitted == false);
// Try to emit a specialized binary instruction speculating the
// type using the baseline caches.
trackOptimizationAttempt(TrackedStrategy::UnaryArith_SpecializedOnBaselineTypes);
MIRType specialization = inspector->expectedBinaryArithSpecialization(pc);
if (specialization == MIRType::None) {
trackOptimizationOutcome(TrackedOutcome::SpeculationOnInputTypesFailed);
return true;
}
MDefinition::Opcode defOp;
MDefinition* rhs = unaryArithConvertToBinary(op, &defOp);
if (!binaryArithEmitSpecialized(defOp, specialization, value, rhs)) {
return false;
}
trackOptimizationSuccess();
*emitted = true;
return true;
}
bool
IonBuilder::jsop_tonumeric()
{
MDefinition* peeked = current->peek(-1);
if (IsNumericType(peeked->type())) {
// Elide the ToNumeric as we already unboxed the value.
peeked->setImplicitlyUsedUnchecked();
return true;
}
LifoAlloc* lifoAlloc = alloc().lifoAlloc();
TemporaryTypeSet* types = lifoAlloc->new_<TemporaryTypeSet>();
if (!types) {
return false;
}
types->addType(TypeSet::Int32Type(), lifoAlloc);
types->addType(TypeSet::DoubleType(), lifoAlloc);
types->addType(TypeSet::BigIntType(), lifoAlloc);
if (peeked->type() == MIRType::Value && peeked->resultTypeSet() &&
peeked->resultTypeSet()->isSubset(types)) {
// Elide the ToNumeric because the arg is already a boxed numeric.
peeked->setImplicitlyUsedUnchecked();
return true;
}
// Otherwise, pop the value and add an MToNumeric.
MDefinition* popped = current->pop();
MToNumeric* ins = MToNumeric::New(alloc(), popped, types);
current->add(ins);
current->push(ins);
// toValue() is effectful, so add a resume point.
return resumeAfter(ins);
}
bool
IonBuilder::jsop_inc_or_dec(JSOp op)
{
bool emitted = false;
MDefinition* value = current->pop();
startTrackingOptimizations();
trackTypeInfo(TrackedTypeSite::Operand, value->type(), value->resultTypeSet());
if (!unaryArithTrySpecialized(&emitted, op, value)) {
return false;
}
if (emitted) {
return true;
}
if (!unaryArithTrySpecializedOnBaselineInspector(&emitted, op, value)) {
return false;
}
if (emitted) {
return true;
}
trackOptimizationAttempt(TrackedStrategy::UnaryArith_InlineCache);
trackOptimizationSuccess();
MInstruction* stub = MUnarySharedStub::New(alloc(), value);
current->add(stub);
current->push(stub);
// Decrease type from 'any type' to 'empty type' when one of the operands
// is 'empty typed'.
maybeMarkEmpty(stub);
return resumeAfter(stub);
}
bool
IonBuilder::jsop_tostring()
{
+13
View File
@@ -497,8 +497,13 @@ class IonBuilder
// jsop_binary_arith helpers.
MBinaryArithInstruction* binaryArithInstruction(JSOp op, MDefinition* left, MDefinition* right);
MIRType binaryArithNumberSpecialization(MDefinition* left, MDefinition* right);
MOZ_MUST_USE bool binaryArithTryConcat(bool* emitted, JSOp op, MDefinition* left,
MDefinition* right);
MOZ_MUST_USE MBinaryArithInstruction* binaryArithEmitSpecialized(MDefinition::Opcode op,
MIRType specialization,
MDefinition* left,
MDefinition* right);
MOZ_MUST_USE bool binaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* left,
MDefinition* right);
MOZ_MUST_USE bool binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op,
@@ -510,6 +515,12 @@ class IonBuilder
// jsop_bitnot helpers.
MOZ_MUST_USE bool bitnotTrySpecialized(bool* emitted, MDefinition* input);
// jsop_inc_or_dec helpers.
MDefinition* unaryArithConvertToBinary(JSOp op, MDefinition::Opcode* defOp);
MOZ_MUST_USE bool unaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* value);
MOZ_MUST_USE bool unaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op,
MDefinition* value);
// jsop_pow helpers.
MOZ_MUST_USE bool powTrySpecialized(bool* emitted, MDefinition* base, MDefinition* power,
MIRType outputType);
@@ -692,6 +703,8 @@ class IonBuilder
MOZ_MUST_USE bool jsop_pow();
MOZ_MUST_USE bool jsop_pos();
MOZ_MUST_USE bool jsop_neg();
MOZ_MUST_USE bool jsop_tonumeric();
MOZ_MUST_USE bool jsop_inc_or_dec(JSOp op);
MOZ_MUST_USE bool jsop_tostring();
MOZ_MUST_USE bool jsop_setarg(uint32_t arg);
MOZ_MUST_USE bool jsop_defvar(uint32_t index);
+4
View File
@@ -644,6 +644,10 @@ IsNumberType(MIRType type)
type == MIRType::Int64;
}
static inline bool IsNumericType(MIRType type) {
return IsNumberType(type) || type == MIRType::BigInt;
}
static inline bool
IsTypeRepresentableAsDouble(MIRType type)
{
+13 -4
View File
@@ -1328,14 +1328,14 @@ LIRGenerator::visitUrsh(MUrsh* ins)
}
void
LIRGenerator::visitSignExtend(MSignExtend* ins)
LIRGenerator::visitSignExtendInt32(MSignExtendInt32* ins)
{
LInstructionHelper<1, 1, 0>* lir;
if (ins->mode() == MSignExtend::Byte)
lir = new(alloc()) LSignExtend(useByteOpRegisterAtStart(ins->input()), ins->mode());
if (ins->mode() == MSignExtendInt32::Byte)
lir = new(alloc()) LSignExtendInt32(useByteOpRegisterAtStart(ins->input()), ins->mode());
else
lir = new(alloc()) LSignExtend(useRegisterAtStart(ins->input()), ins->mode());
lir = new(alloc()) LSignExtendInt32(useRegisterAtStart(ins->input()), ins->mode());
define(lir, ins);
}
@@ -2165,6 +2165,15 @@ LIRGenerator::visitToInt32(MToInt32* convert)
}
}
void
LIRGenerator::visitToNumeric(MToNumeric* ins)
{
MOZ_ASSERT(ins->input()->type() == MIRType::Value);
LToNumeric* lir = new (alloc()) LToNumeric(useBoxAtStart(ins->input()));
defineBox(lir, ins);
assignSafepoint(lir, ins);
}
void
LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate)
{
+2 -1
View File
@@ -130,7 +130,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitLsh(MLsh* ins);
void visitRsh(MRsh* ins);
void visitUrsh(MUrsh* ins);
void visitSignExtend(MSignExtend* ins);
void visitSignExtendInt32(MSignExtendInt32* ins);
void visitRotate(MRotate* ins);
void visitFloor(MFloor* ins);
void visitCeil(MCeil* ins);
@@ -336,6 +336,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins);
void visitModuleMetadata(MModuleMetadata* ins);
void visitDynamicImport(MDynamicImport* ins);
void visitToNumeric(MToNumeric* ins);
};
} // namespace jit
+54 -19
View File
@@ -3110,23 +3110,6 @@ MBinaryArithInstruction::New(TempAllocator& alloc, Opcode op,
}
}
void
MBinaryArithInstruction::setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector,
jsbytecode* pc)
{
setSpecialization(MIRType::Double);
// Try to specialize as int32.
if (getOperand(0)->type() == MIRType::Int32 && getOperand(1)->type() == MIRType::Int32) {
bool seenDouble = inspector->hasSeenDoubleResult(pc);
// Use int32 specialization if the operation doesn't overflow on its
// constant operands and if the operation has never overflowed.
if (!seenDouble && !constantDoubleResult(alloc))
setInt32Specialization();
}
}
bool
MBinaryArithInstruction::constantDoubleResult(TempAllocator& alloc)
{
@@ -3159,9 +3142,9 @@ MRsh::foldsTo(TempAllocator& alloc)
switch (shift) {
case 16:
return MSignExtend::New(alloc, lhs->getOperand(0), MSignExtend::Half);
return MSignExtendInt32::New(alloc, lhs->getOperand(0), MSignExtendInt32::Half);
case 24:
return MSignExtend::New(alloc, lhs->getOperand(0), MSignExtend::Byte);
return MSignExtendInt32::New(alloc, lhs->getOperand(0), MSignExtendInt32::Byte);
}
return this;
@@ -4189,6 +4172,23 @@ MResumePoint::isRecoverableOperand(MUse* u) const
return block()->info().isRecoverableOperand(indexOf(u));
}
MDefinition*
MToNumeric::foldsTo(TempAllocator& alloc)
{
MDefinition* input = getOperand(0);
if (input->isBox()) {
MDefinition* unboxed = input->getOperand(0);
if (IsNumericType(unboxed->type())) {
// If the argument is an MBox and we can see that it boxes a numeric
// value, ToNumeric can be elided.
return input;
}
}
return this;
}
MDefinition*
MToInt32::foldsTo(TempAllocator& alloc)
{
@@ -4326,6 +4326,41 @@ MExtendInt32ToInt64::foldsTo(TempAllocator& alloc)
return this;
}
MDefinition*
MSignExtendInt32::foldsTo(TempAllocator& alloc)
{
MDefinition* input = this->input();
if (input->isConstant()) {
int32_t c = input->toConstant()->toInt32();
int32_t res;
switch (mode_) {
case Byte: res = int32_t(int8_t(c & 0xFF)); break;
case Half: res = int32_t(int16_t(c & 0xFFFF)); break;
}
return MConstant::New(alloc, Int32Value(res));
}
return this;
}
MDefinition*
MSignExtendInt64::foldsTo(TempAllocator& alloc)
{
MDefinition* input = this->input();
if (input->isConstant()) {
int64_t c = input->toConstant()->toInt64();
int64_t res;
switch (mode_) {
case Byte: res = int64_t(int8_t(c & 0xFF)); break;
case Half: res = int64_t(int16_t(c & 0xFFFF)); break;
case Word: res = int64_t(int32_t(c & 0xFFFFFFFFU)); break;
}
return MConstant::NewInt64(alloc, res);
}
return this;
}
MDefinition*
MToDouble::foldsTo(TempAllocator& alloc)
{
+92 -6
View File
@@ -5534,6 +5534,43 @@ class MInt64ToFloatingPoint
}
};
// Takes a boxed Value and returns a Value containing either a Number or a
// BigInt. Usually this will be the value itself, but it may be an object that
// has a @@toPrimitive, valueOf, or toString method.
class MToNumeric : public MUnaryInstruction, public BoxInputsPolicy::Data
{
MToNumeric(MDefinition* arg, TemporaryTypeSet* types)
: MUnaryInstruction(arg)
{
MOZ_ASSERT(!IsNumericType(arg->type()),
"Unboxable definitions don't need ToNumeric");
setResultType(MIRType::Value);
// Although `types' is always Int32|Double|BigInt, we have to compute it in
// IonBuilder to know whether emitting an MToNumeric is needed, so we just
// pass it through as an argument instead of recomputing it here.
setResultTypeSet(types);
setGuard();
setMovable();
}
public:
INSTRUCTION_HEADER(ToNumeric)
TRIVIAL_NEW_WRAPPERS
static MToNumeric* New(TempAllocator& alloc, MDefinition* arg,
TemporaryTypeSet* types) {
return new (alloc) MToNumeric(arg, types);
}
void computeRange(TempAllocator& alloc) override;
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins);
}
MDefinition* foldsTo(TempAllocator& alloc) override;
ALLOW_CLONE(MToNumeric)
};
// Converts a primitive (either typed or untyped) to an int32. If the input is
// not primitive at runtime, a bailout occurs. If the input cannot be converted
// to an int32 without loss (i.e. "5.5" or undefined) then a bailout occurs.
@@ -6135,7 +6172,7 @@ class MUrsh : public MShiftInstruction
ALLOW_CLONE(MUrsh)
};
class MSignExtend
class MSignExtendInt32
: public MUnaryInstruction,
public NoTypePolicy::Data
{
@@ -6148,7 +6185,7 @@ class MSignExtend
private:
Mode mode_;
MSignExtend(MDefinition* op, Mode mode)
MSignExtendInt32(MDefinition* op, Mode mode)
: MUnaryInstruction(op), mode_(mode)
{
setResultType(MIRType::Int32);
@@ -6156,17 +6193,67 @@ class MSignExtend
}
public:
INSTRUCTION_HEADER(SignExtend)
INSTRUCTION_HEADER(SignExtendInt32)
TRIVIAL_NEW_WRAPPERS
Mode mode() { return mode_; }
Mode mode() const { return mode_; }
MDefinition* foldsTo(TempAllocator& alloc) override;
bool congruentTo(const MDefinition* ins) const override {
if (!congruentIfOperandsEqual(ins))
return false;
return ins->isSignExtendInt32() && ins->toSignExtendInt32()->mode_ == mode_;
}
AliasSet getAliasSet() const override {
return AliasSet::None();
}
MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
bool canRecoverOnBailout() const override {
return true;
}
ALLOW_CLONE(MSignExtend)
ALLOW_CLONE(MSignExtendInt32)
};
class MSignExtendInt64
: public MUnaryInstruction,
public NoTypePolicy::Data
{
public:
enum Mode {
Byte,
Half,
Word
};
private:
Mode mode_;
MSignExtendInt64(MDefinition* op, Mode mode)
: MUnaryInstruction(op), mode_(mode)
{
setResultType(MIRType::Int64);
setMovable();
}
public:
INSTRUCTION_HEADER(SignExtendInt64)
TRIVIAL_NEW_WRAPPERS
Mode mode() const { return mode_; }
MDefinition* foldsTo(TempAllocator& alloc) override;
bool congruentTo(const MDefinition* ins) const override {
if (!congruentIfOperandsEqual(ins))
return false;
return ins->isSignExtendInt64() && ins->toSignExtendInt64()->mode_ == mode_;
}
AliasSet getAliasSet() const override {
return AliasSet::None();
}
ALLOW_CLONE(MSignExtendInt64)
};
class MBinaryArithInstruction
@@ -6219,7 +6306,6 @@ class MBinaryArithInstruction
specialization_ = MIRType::Int32;
setResultType(MIRType::Int32);
}
void setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector, jsbytecode* pc);
virtual void trySpecializeFloat32(TempAllocator& alloc) override;
+3 -1
View File
@@ -87,7 +87,8 @@ namespace jit {
_(Lsh) \
_(Rsh) \
_(Ursh) \
_(SignExtend) \
_(SignExtendInt32) \
_(SignExtendInt64) \
_(MinMax) \
_(Abs) \
_(Clz) \
@@ -123,6 +124,7 @@ namespace jit {
_(ToDouble) \
_(ToFloat32) \
_(ToInt32) \
_(ToNumeric) \
_(TruncateToInt32) \
_(WrapInt64ToInt32) \
_(ExtendInt32ToInt64) \
+6
View File
@@ -1741,6 +1741,12 @@ MTruncateToInt32::computeRange(TempAllocator& alloc)
setRange(output);
}
void
MToNumeric::computeRange(TempAllocator& alloc)
{
setRange(new (alloc) Range(getOperand(0)));
}
void
MToInt32::computeRange(TempAllocator& alloc)
{
+7 -7
View File
@@ -336,32 +336,32 @@ RUrsh::recover(JSContext* cx, SnapshotIterator& iter) const
}
bool
MSignExtend::writeRecoverData(CompactBufferWriter& writer) const
MSignExtendInt32::writeRecoverData(CompactBufferWriter& writer) const
{
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_SignExtend));
writer.writeUnsigned(uint32_t(RInstruction::Recover_SignExtendInt32));
MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_);
writer.writeByte(uint8_t(mode_));
return true;
}
RSignExtend::RSignExtend(CompactBufferReader& reader)
RSignExtendInt32::RSignExtendInt32(CompactBufferReader& reader)
{
mode_ = reader.readByte();
}
bool
RSignExtend::recover(JSContext* cx, SnapshotIterator& iter) const
RSignExtendInt32::recover(JSContext* cx, SnapshotIterator& iter) const
{
RootedValue operand(cx, iter.read());
int32_t result;
switch (MSignExtend::Mode(mode_)) {
case MSignExtend::Byte:
switch (MSignExtendInt32::Mode(mode_)) {
case MSignExtendInt32::Byte:
if (!js::SignExtendOperation<int8_t>(cx, operand, &result))
return false;
break;
case MSignExtend::Half:
case MSignExtendInt32::Half:
if (!js::SignExtendOperation<int16_t>(cx, operand, &result))
return false;
break;
+3 -3
View File
@@ -64,7 +64,7 @@ namespace jit {
_(Lsh) \
_(Rsh) \
_(Ursh) \
_(SignExtend) \
_(SignExtendInt32) \
_(Add) \
_(Sub) \
_(Mul) \
@@ -255,13 +255,13 @@ class RUrsh final : public RInstruction
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override;
};
class RSignExtend final : public RInstruction
class RSignExtendInt32 final : public RInstruction
{
private:
uint8_t mode_;
public:
RINSTRUCTION_HEADER_NUM_OP_(SignExtend, 1)
RINSTRUCTION_HEADER_NUM_OP_(SignExtendInt32, 1)
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override;
};
+36 -10
View File
@@ -1469,21 +1469,33 @@ DoUnaryArithFallback(JSContext* cx, void* payload, ICUnaryArith_Fallback* stub_,
JSOp op = JSOp(*pc);
FallbackICSpew(cx, stub, "UnaryArith(%s)", CodeName[op]);
// The unary operations take a copied val because the original value is needed
// below.
RootedValue valCopy(cx, val);
switch (op) {
case JSOP_BITNOT: {
RootedValue valCopy(cx, val);
if (!BitNot(cx, &valCopy, res)) {
return false;
}
break;
}
case JSOP_NEG: {
// We copy val here because the original value is needed below.
RootedValue valCopy(cx, val);
if (!NegOperation(cx, script, pc, &valCopy, res))
if (!NegOperation(cx, script, pc, &valCopy, res))
return false;
break;
}
case JSOP_INC: {
if (!IncOperation(cx, &valCopy, res)) {
return false;
}
break;
}
case JSOP_DEC: {
if (!DecOperation(cx, &valCopy, res)) {
return false;
}
break;
}
default:
MOZ_CRASH("Unexpected op");
}
@@ -1558,12 +1570,8 @@ ICUnaryArith_Double::Compiler::generateStubCode(MacroAssembler& masm)
Label failure;
masm.ensureDouble(R0, FloatReg0, &failure);
MOZ_ASSERT(op == JSOP_NEG || op == JSOP_BITNOT);
if (op == JSOP_NEG) {
masm.negateDouble(FloatReg0);
masm.boxDouble(FloatReg0, R0);
} else {
switch (op) {
case JSOP_BITNOT: {
// Truncate the double to an int32.
Register scratchReg = R1.scratchReg();
@@ -1581,6 +1589,24 @@ ICUnaryArith_Double::Compiler::generateStubCode(MacroAssembler& masm)
masm.bind(&doneTruncate);
masm.not32(scratchReg);
masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
break;
}
case JSOP_NEG:
masm.negateDouble(FloatReg0);
masm.boxDouble(FloatReg0, R0);
break;
case JSOP_INC:
case JSOP_DEC:
masm.loadConstantDouble(1.0, ScratchDoubleReg);
if (op == JSOP_INC) {
masm.addDouble(ScratchDoubleReg, FloatReg0);
} else {
masm.subDouble(ScratchDoubleReg, FloatReg0);
}
masm.boxDouble(FloatReg0, R0);
break;
default:
MOZ_CRASH("Unexpected op");
}
EmitReturnFromIC(masm);
+2
View File
@@ -1855,6 +1855,8 @@ class ICBinaryArith_DoubleWithInt32 : public ICStub
// UnaryArith
// JSOP_BITNOT
// JSOP_NEG
// JSOP_INC
// JSOP_DEC
class ICUnaryArith_Fallback : public ICFallbackStub
{
+1 -1
View File
@@ -1186,6 +1186,7 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
// Lists of all TypePolicy specializations which are used by MIR Instructions.
#define TYPE_POLICY_LIST(_) \
_(AllDoublePolicy) \
_(ArithPolicy) \
_(BitwisePolicy) \
_(BoxInputsPolicy) \
@@ -1204,7 +1205,6 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
_(StoreUnboxedScalarPolicy) \
_(StoreUnboxedObjectOrNullPolicy) \
_(TestPolicy) \
_(AllDoublePolicy) \
_(ToDoublePolicy) \
_(ToInt32Policy) \
_(ToStringPolicy) \
+14
View File
@@ -1357,5 +1357,19 @@ CheckIsCallable(JSContext* cx, HandleValue v, CheckIsCallableKind kind)
return true;
}
template <bool allowBigInt = false>
static bool DoToNumeric(JSContext* cx, HandleValue arg, MutableHandleValue ret)
{
ret.set(arg);
if (allowBigInt) {
return ToNumeric(cx, ret);
}
return ToNumber(cx, ret);
}
typedef bool (*ToNumericFn)(JSContext*, HandleValue, MutableHandleValue);
const VMFunction ToNumberInfo = FunctionInfo<ToNumericFn>(DoToNumeric, "ToNumber");
const VMFunction ToNumericInfo = FunctionInfo<ToNumericFn>(DoToNumeric<true>, "ToNumeric");
} // namespace jit
} // namespace js
+3
View File
@@ -803,6 +803,9 @@ BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue
MOZ_MUST_USE bool
CheckIsCallable(JSContext* cx, HandleValue v, CheckIsCallableKind kind);
extern const VMFunction ToNumberInfo;
extern const VMFunction ToNumericInfo;
} // namespace jit
} // namespace js
+18
View File
@@ -3364,6 +3364,24 @@ CodeGeneratorARM::visitExtendInt32ToInt64(LExtendInt32ToInt64* lir)
masm.ma_asr(Imm32(31), output.low, output.high);
}
void
CodeGeneratorARM::visitSignExtendInt64(LSignExtendInt64* lir)
{
Register64 input = ToRegister64(lir->getInt64Operand(0));
Register64 output = ToOutRegister64(lir);
switch (lir->mode()) {
case MSignExtendInt64::Byte:
masm.move8SignExtend(input.low, output.low);
break;
case MSignExtendInt64::Half:
masm.move16SignExtend(input.low, output.low);
break;
case MSignExtendInt64::Word:
break;
}
masm.ma_asr(Imm32(31), output.low, output.high);
}
void
CodeGeneratorARM::visitDivOrModI64(LDivOrModI64* lir)
{
+1
View File
@@ -168,6 +168,7 @@ class CodeGeneratorARM : public CodeGeneratorShared
virtual void visitWrapInt64ToInt32(LWrapInt64ToInt32* lir);
virtual void visitExtendInt32ToInt64(LExtendInt32ToInt64* lir);
virtual void visitSignExtendInt64(LSignExtendInt64* ins);
virtual void visitAddI64(LAddI64* lir);
virtual void visitSubI64(LSubI64* lir);
virtual void visitMulI64(LMulI64* lir);
+6
View File
@@ -1028,3 +1028,9 @@ LIRGeneratorARM::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
lir->setDef(0, def);
}
void
LIRGeneratorARM::visitSignExtendInt64(MSignExtendInt64* ins)
{
defineInt64(new(alloc()) LSignExtendInt64(useInt64RegisterAtStart(ins->input())), ins);
}
+1
View File
@@ -121,6 +121,7 @@ class LIRGeneratorARM : public LIRGeneratorShared
void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
void visitCopySign(MCopySign* ins);
void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
void visitSignExtendInt64(MSignExtendInt64* ins);
};
typedef LIRGeneratorARM LIRGeneratorSpecific;
+6
View File
@@ -366,3 +366,9 @@ LIRGeneratorARM64::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
{
MOZ_CRASH("NYI");
}
void
LIRGeneratorARM64::visitSignExtendInt64(MSignExtendInt64* ins)
{
MOZ_CRASH("NYI");
}
+1
View File
@@ -121,6 +121,7 @@ class LIRGeneratorARM64 : public LIRGeneratorShared
void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
void visitCopySign(MCopySign* ins);
void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
void visitSignExtendInt64(MSignExtendInt64* ins);
};
typedef LIRGeneratorARM64 LIRGeneratorSpecific;
+1
View File
@@ -107,6 +107,7 @@ class LIRGeneratorNone : public LIRGeneratorShared
void visitWasmTruncateToInt64(MWasmTruncateToInt64*) { MOZ_CRASH(); }
void visitInt64ToFloatingPoint(MInt64ToFloatingPoint*) { MOZ_CRASH(); }
void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) { MOZ_CRASH(); }
void visitSignExtendInt64(MSignExtendInt64* ins) { MOZ_CRASH(); }
};
typedef LIRGeneratorNone LIRGeneratorSpecific;
+35 -5
View File
@@ -3351,19 +3351,34 @@ class LShiftI64 : public LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0>
};
// Sign extension
class LSignExtend : public LInstructionHelper<1, 1, 0>
class LSignExtendInt32 : public LInstructionHelper<1, 1, 0>
{
MSignExtend::Mode mode_;
MSignExtendInt32::Mode mode_;
public:
LIR_HEADER(SignExtend);
explicit LSignExtend(const LAllocation& num, MSignExtend::Mode mode)
LIR_HEADER(SignExtendInt32);
explicit LSignExtendInt32(const LAllocation& num, MSignExtendInt32::Mode mode)
: mode_(mode)
{
setOperand(0, num);
}
MSignExtend::Mode mode() { return mode_; }
MSignExtendInt32::Mode mode() { return mode_; }
};
class LSignExtendInt64 : public LInstructionHelper<INT64_PIECES, INT64_PIECES, 0>
{
public:
LIR_HEADER(SignExtendInt64)
explicit LSignExtendInt64(const LInt64Allocation& input) {
setInt64Operand(0, input);
}
const MSignExtendInt64* mir() const {
return mir_->toSignExtendInt64();
}
MSignExtendInt64::Mode mode() const { return mir()->mode(); }
};
class LUrshD : public LBinaryMath<1>
@@ -7494,6 +7509,21 @@ class LLoadUnboxedExpando : public LInstructionHelper<1, 1, 0>
}
};
// Ensure that a value is numeric, possibly via a VM call-out that invokes
// valueOf().
class LToNumeric : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 0> {
public:
LIR_HEADER(ToNumeric)
explicit LToNumeric(const LBoxAllocation& input) {
setBoxOperand(Input, input);
}
static const size_t Input = 0;
const MToNumeric* mir() const { return mir_->toToNumeric(); }
};
// Guard that a value is in a TypeSet.
class LTypeBarrierV : public LInstructionHelper<0, BOX_PIECES, 1>
{
+3 -1
View File
@@ -111,7 +111,8 @@
_(BitOpV) \
_(ShiftI) \
_(ShiftI64) \
_(SignExtend) \
_(SignExtendInt32) \
_(SignExtendInt64) \
_(UrshD) \
_(Return) \
_(Throw) \
@@ -258,6 +259,7 @@
_(GuardClass) \
_(GuardUnboxedExpando) \
_(LoadUnboxedExpando) \
_(ToNumeric) \
_(TypeBarrierV) \
_(TypeBarrierO) \
_(MonitorTypes) \
+6
View File
@@ -470,6 +470,9 @@ class Assembler : public AssemblerX86Shared
void movsbq(const Operand& src, Register dest) {
switch (src.kind()) {
case Operand::REG:
masm.movsbq_rr(src.reg(), dest.encoding());
break;
case Operand::MEM_REG_DISP:
masm.movsbq_mr(src.disp(), src.base(), dest.encoding());
break;
@@ -489,6 +492,9 @@ class Assembler : public AssemblerX86Shared
void movswq(const Operand& src, Register dest) {
switch (src.kind()) {
case Operand::REG:
masm.movswq_rr(src.reg(), dest.encoding());
break;
case Operand::MEM_REG_DISP:
masm.movswq_mr(src.disp(), src.base(), dest.encoding());
break;
+10
View File
@@ -652,6 +652,11 @@ class BaseAssemblerX64 : public BaseAssembler
m_formatter.immediate64(imm);
}
void movsbq_rr(RegisterID src, RegisterID dst)
{
spew("movsbq %s, %s", GPReg32Name(src), GPReg64Name(dst));
m_formatter.twoByteOp64(OP2_MOVSX_GvEb, src, dst);
}
void movsbq_mr(int32_t offset, RegisterID base, RegisterID dst)
{
spew("movsbq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst));
@@ -663,6 +668,11 @@ class BaseAssemblerX64 : public BaseAssembler
m_formatter.twoByteOp64(OP2_MOVSX_GvEb, offset, base, index, scale, dst);
}
void movswq_rr(RegisterID src, RegisterID dst)
{
spew("movswq %s, %s", GPReg32Name(src), GPReg64Name(dst));
m_formatter.twoByteOp64(OP2_MOVSX_GvEw, src, dst);
}
void movswq_mr(int32_t offset, RegisterID base, RegisterID dst)
{
spew("movswq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst));
+18
View File
@@ -802,6 +802,24 @@ CodeGeneratorX64::visitExtendInt32ToInt64(LExtendInt32ToInt64* lir)
masm.movslq(ToOperand(input), output);
}
void
CodeGeneratorX64::visitSignExtendInt64(LSignExtendInt64* ins)
{
Register64 input = ToRegister64(ins->getInt64Operand(0));
Register64 output = ToOutRegister64(ins);
switch (ins->mode()) {
case MSignExtendInt64::Byte:
masm.movsbq(Operand(input.reg), output.reg);
break;
case MSignExtendInt64::Half:
masm.movswq(Operand(input.reg), output.reg);
break;
case MSignExtendInt64::Word:
masm.movslq(Operand(input.reg), output.reg);
break;
}
}
void
CodeGeneratorX64::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir)
{
+1
View File
@@ -52,6 +52,7 @@ class CodeGeneratorX64 : public CodeGeneratorX86Shared
void visitTruncateFToInt32(LTruncateFToInt32* ins);
void visitWrapInt64ToInt32(LWrapInt64ToInt32* lir);
void visitExtendInt32ToInt64(LExtendInt32ToInt64* lir);
void visitSignExtendInt64(LSignExtendInt64* ins);
void visitWasmTruncateToInt64(LWasmTruncateToInt64* lir);
void visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir);
void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins);
+7
View File
@@ -494,3 +494,10 @@ LIRGeneratorX64::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
{
defineInt64(new(alloc()) LExtendInt32ToInt64(useAtStart(ins->input())), ins);
}
void
LIRGeneratorX64::visitSignExtendInt64(MSignExtendInt64* ins)
{
defineInt64(new(alloc()) LSignExtendInt64(useInt64RegisterAtStart(ins->input())), ins);
}
+1
View File
@@ -69,6 +69,7 @@ class LIRGeneratorX64 : public LIRGeneratorX86Shared
void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins);
void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
void visitSignExtendInt64(MSignExtendInt64* ins);
};
typedef LIRGeneratorX64 LIRGeneratorSpecific;
+10
View File
@@ -216,6 +216,16 @@ ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
masm.branchTest32(Assembler::Zero, R0.valueReg(), Imm32(0x7fffffff), &failure);
masm.negl(R0.valueReg());
break;
case JSOP_INC: {
RegisterOrInt32Constant rval = RegisterOrInt32Constant(R0.valueReg());
masm.inc32(&rval);
break;
}
case JSOP_DEC: {
RegisterOrInt32Constant rval = RegisterOrInt32Constant(R0.valueReg());
masm.dec32(&rval);
break;
}
default:
MOZ_CRASH("Unexpected op");
}
@@ -4937,7 +4937,7 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off
void twoByteOp8(TwoByteOpcodeID opcode, RegisterID rm, RegisterID reg)
{
m_buffer.ensureSpace(MaxInstructionSize);
emitRexIf(byteRegRequiresRex(reg)|byteRegRequiresRex(rm), reg, 0, rm);
emitRexIf(byteRegRequiresRex(reg)||byteRegRequiresRex(rm), reg, 0, rm);
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
m_buffer.putByteUnchecked(opcode);
registerModRM(rm, reg);
@@ -4946,7 +4946,7 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off
void twoByteOp8(TwoByteOpcodeID opcode, int32_t offset, RegisterID base, RegisterID reg)
{
m_buffer.ensureSpace(MaxInstructionSize);
emitRexIf(byteRegRequiresRex(reg)|regRequiresRex(base), reg, 0, base);
emitRexIf(byteRegRequiresRex(reg)||regRequiresRex(base), reg, 0, base);
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
m_buffer.putByteUnchecked(opcode);
memoryModRM(offset, base, reg);
@@ -4956,7 +4956,7 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off
int scale, RegisterID reg)
{
m_buffer.ensureSpace(MaxInstructionSize);
emitRexIf(byteRegRequiresRex(reg)|regRequiresRex(base)|regRequiresRex(index),
emitRexIf(byteRegRequiresRex(reg)||regRequiresRex(base)||regRequiresRex(index),
reg, index, base);
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
m_buffer.putByteUnchecked(opcode);
@@ -4970,7 +4970,7 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off
void twoByteOp8_movx(TwoByteOpcodeID opcode, RegisterID rm, RegisterID reg)
{
m_buffer.ensureSpace(MaxInstructionSize);
emitRexIf(regRequiresRex(reg)|byteRegRequiresRex(rm), reg, 0, rm);
emitRexIf(regRequiresRex(reg)||byteRegRequiresRex(rm), reg, 0, rm);
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
m_buffer.putByteUnchecked(opcode);
registerModRM(rm, reg);
+22
View File
@@ -1182,6 +1182,28 @@ CodeGeneratorX86::visitExtendInt32ToInt64(LExtendInt32ToInt64* lir)
}
}
void
CodeGeneratorX86::visitSignExtendInt64(LSignExtendInt64* lir)
{
Register64 input = ToRegister64(lir->getInt64Operand(0));
Register64 output = ToOutRegister64(lir);
MOZ_ASSERT(input.low == eax);
MOZ_ASSERT(output.low == eax);
MOZ_ASSERT(input.high == edx);
MOZ_ASSERT(output.high == edx);
switch (lir->mode()) {
case MSignExtendInt64::Byte:
masm.move8SignExtend(eax, eax);
break;
case MSignExtendInt64::Half:
masm.move16SignExtend(eax, eax);
break;
case MSignExtendInt64::Word:
break;
}
masm.cdq();
}
void
CodeGeneratorX86::visitWrapInt64ToInt32(LWrapInt64ToInt32* lir)
{
+1
View File
@@ -77,6 +77,7 @@ class CodeGeneratorX86 : public CodeGeneratorX86Shared
void visitWasmReinterpretFromI64(LWasmReinterpretFromI64* lir);
void visitWasmReinterpretToI64(LWasmReinterpretToI64* lir);
void visitExtendInt32ToInt64(LExtendInt32ToInt64* lir);
void visitSignExtendInt64(LSignExtendInt64* ins);
void visitWrapInt64ToInt32(LWrapInt64ToInt32* lir);
void visitClzI64(LClzI64* lir);
void visitCtzI64(LCtzI64* lir);
+11
View File
@@ -657,3 +657,14 @@ LIRGeneratorX86::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
LAllocation(AnyRegister(eax))));
}
}
void
LIRGeneratorX86::visitSignExtendInt64(MSignExtendInt64* ins)
{
// Here we'll end up using cdq which requires input and output in (edx,eax).
LSignExtendInt64* lir =
new(alloc()) LSignExtendInt64(useInt64RegisterAtStart(ins->input()));
defineInt64Fixed(lir, ins, LInt64Allocation(LAllocation(AnyRegister(edx)),
LAllocation(AnyRegister(eax))));
}
+1
View File
@@ -76,6 +76,7 @@ class LIRGeneratorX86 : public LIRGeneratorX86Shared
void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins);
void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
void visitSignExtendInt64(MSignExtendInt64* ins);
void lowerPhi(MPhi* phi);
static bool allowTypedElementHoleCheck() {
+11
View File
@@ -226,6 +226,17 @@ ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(0x7fffffff), &failure);
masm.negl(R0.payloadReg());
break;
case JSOP_INC: {
RegisterOrInt32Constant rval = RegisterOrInt32Constant(R0.payloadReg());
masm.inc32(&rval);
break;
}
case JSOP_DEC: {
RegisterOrInt32Constant rval = RegisterOrInt32Constant(R0.payloadReg());
masm.dec32(&rval);
break;
}
default:
MOZ_CRASH("Unexpected op");
}
+8 -3
View File
@@ -277,10 +277,15 @@ PreprocessValue(JSContext* cx, HandleObject holder, KeyType key, MutableHandleVa
RootedString keyStr(cx);
/* Step 2. */
if (vp.isObject()) {
// Step 2. Modified by BigInt spec 6.1 to check for a toJSON method on the
// BigInt prototype when the value is a BigInt.
if (vp.isObject() || vp.isBigInt()) {
RootedValue toJSON(cx);
RootedObject obj(cx, &vp.toObject());
RootedObject obj(cx, JS::ToObject(cx, vp));
if (!obj) {
return false;
}
if (!GetProperty(cx, obj, obj, cx->names().toJSON, &toJSON))
return false;
+88 -55
View File
@@ -185,16 +185,21 @@ BigInt* BigInt::zero(ExclusiveContext* cx) {
return createUninitialized(cx, 0, false);
}
BigInt* BigInt::one(ExclusiveContext* cx) {
BigInt* ret = createUninitialized(cx, 1, false);
if (!ret) {
BigInt* BigInt::createFromDigit(ExclusiveContext* cx, Digit d, bool isNegative) {
MOZ_ASSERT(d != 0);
BigInt* res = createUninitialized(cx, 1, isNegative);
if (!res) {
return nullptr;
}
ret->setDigit(0, 1);
res->setDigit(0, d);
return res;
}
return ret;
BigInt* BigInt::one(ExclusiveContext* cx) { return createFromDigit(cx, 1, false); }
BigInt* BigInt::negativeOne(ExclusiveContext* cx) {
return createFromDigit(cx, 1, true);
}
BigInt* BigInt::neg(ExclusiveContext* cx, HandleBigInt x) {
@@ -977,21 +982,26 @@ BigInt* BigInt::absoluteAddOne(ExclusiveContext* cx, HandleBigInt x,
return destructivelyTrimHighZeroDigits(cx, result);
}
// Like the above, but you can specify that the allocated result should have
// length `resultLength`, which must be at least as large as `x->digitLength()`.
// The result will be unsigned.
BigInt* BigInt::absoluteSubOne(ExclusiveContext* cx, HandleBigInt x,
unsigned resultLength) {
bool resultNegative) {
MOZ_ASSERT(!x->isZero());
MOZ_ASSERT(resultLength >= x->digitLength());
bool resultNegative = false;
RootedBigInt result(cx,
createUninitialized(cx, resultLength, resultNegative));
unsigned length = x->digitLength();
if (length == 1) {
Digit d = x->digit(0);
if (d == 1) {
// Ignore resultNegative.
return zero(cx);
}
return createFromDigit(cx, d - 1, resultNegative);
}
RootedBigInt result(cx, createUninitialized(cx, length, resultNegative));
if (!result) {
return nullptr;
}
unsigned length = x->digitLength();
Digit borrow = 1;
for (unsigned i = 0; i < length; i++) {
Digit newBorrow = 0;
@@ -999,13 +1009,36 @@ BigInt* BigInt::absoluteSubOne(ExclusiveContext* cx, HandleBigInt x,
borrow = newBorrow;
}
MOZ_ASSERT(!borrow);
for (unsigned i = length; i < resultLength; i++) {
result->setDigit(i, 0);
}
return destructivelyTrimHighZeroDigits(cx, result);
}
BigInt* BigInt::inc(ExclusiveContext* cx, HandleBigInt x) {
if (x->isZero()) {
return one(cx);
}
bool isNegative = x->isNegative();
if (isNegative) {
return absoluteSubOne(cx, x, isNegative);
}
return absoluteAddOne(cx, x, isNegative);
}
BigInt* BigInt::dec(ExclusiveContext* cx, HandleBigInt x) {
if (x->isZero()) {
return negativeOne(cx);
}
bool isNegative = x->isNegative();
if (isNegative) {
return absoluteAddOne(cx, x, isNegative);
}
return absoluteSubOne(cx, x, isNegative);
}
// Lookup table for the maximum number of bits required per character of a
// base-N string representation of a number. To increase accuracy, the array
// value is the actual value multiplied by 32. To generate this table:
@@ -1569,13 +1602,7 @@ BigInt* BigInt::createFromUint64(ExclusiveContext* cx, uint64_t n) {
return res;
}
BigInt* res = createUninitialized(cx, 1, isNegative);
if (!res) {
return nullptr;
}
res->setDigit(0, n);
return res;
return createFromDigit(cx, n, isNegative);
}
BigInt* BigInt::createFromInt64(ExclusiveContext* cx, int64_t n) {
@@ -1770,12 +1797,7 @@ BigInt* BigInt::mod(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) {
return zero(cx);
}
BigInt* remainder = createUninitialized(cx, 1, x->isNegative());
if (!remainder) {
return nullptr;
}
remainder->setDigit(0, remainderDigit);
return remainder;
return createFromDigit(cx, remainderDigit, x->isNegative());
} else {
RootedBigInt remainder(cx);
if (!absoluteDivWithBigIntDivisor(cx, x, y, Nothing(), Some(&remainder),
@@ -1930,15 +1952,7 @@ BigInt* BigInt::lshByAbsolute(ExclusiveContext* cx, HandleBigInt x, HandleBigInt
}
BigInt* BigInt::rshByMaximum(ExclusiveContext* cx, bool isNegative) {
if (isNegative) {
RootedBigInt negativeOne(cx, createUninitialized(cx, 1, isNegative));
if (!negativeOne) {
return nullptr;
}
negativeOne->setDigit(0, 1);
return negativeOne;
}
return zero(cx);
return isNegative ? negativeOne(cx) : zero(cx);
}
BigInt* BigInt::rshByAbsolute(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) {
@@ -2049,14 +2063,13 @@ BigInt* BigInt::bitAnd(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) {
}
if (x->isNegative() && y->isNegative()) {
int resultLength = std::max(x->digitLength(), y->digitLength()) + 1;
// (-x) & (-y) == ~(x-1) & ~(y-1) == ~((x-1) | (y-1))
// == -(((x-1) | (y-1)) + 1)
RootedBigInt x1(cx, absoluteSubOne(cx, x, resultLength));
RootedBigInt x1(cx, absoluteSubOne(cx, x));
if (!x1) {
return nullptr;
}
RootedBigInt y1(cx, absoluteSubOne(cx, y, y->digitLength()));
RootedBigInt y1(cx, absoluteSubOne(cx, y));
if (!y1) {
return nullptr;
}
@@ -2072,7 +2085,7 @@ BigInt* BigInt::bitAnd(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) {
HandleBigInt& pos = x->isNegative() ? y : x;
HandleBigInt& neg = x->isNegative() ? x : y;
RootedBigInt neg1(cx, absoluteSubOne(cx, neg, neg->digitLength()));
RootedBigInt neg1(cx, absoluteSubOne(cx, neg));
if (!neg1) {
return nullptr;
}
@@ -2096,27 +2109,24 @@ BigInt* BigInt::bitXor(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) {
}
if (x->isNegative() && y->isNegative()) {
int resultLength = std::max(x->digitLength(), y->digitLength());
// (-x) ^ (-y) == ~(x-1) ^ ~(y-1) == (x-1) ^ (y-1)
RootedBigInt x1(cx, absoluteSubOne(cx, x, resultLength));
RootedBigInt x1(cx, absoluteSubOne(cx, x));
if (!x1) {
return nullptr;
}
RootedBigInt y1(cx, absoluteSubOne(cx, y, y->digitLength()));
RootedBigInt y1(cx, absoluteSubOne(cx, y));
if (!y1) {
return nullptr;
}
return absoluteXor(cx, x1, y1);
}
MOZ_ASSERT(x->isNegative() != y->isNegative());
int resultLength = std::max(x->digitLength(), y->digitLength()) + 1;
HandleBigInt& pos = x->isNegative() ? y : x;
HandleBigInt& neg = x->isNegative() ? x : y;
// x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
RootedBigInt result(cx, absoluteSubOne(cx, neg, resultLength));
RootedBigInt result(cx, absoluteSubOne(cx, neg));
if (!result) {
return nullptr;
}
@@ -2138,7 +2148,6 @@ BigInt* BigInt::bitOr(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) {
return x;
}
unsigned resultLength = std::max(x->digitLength(), y->digitLength());
bool resultNegative = x->isNegative() || y->isNegative();
if (!resultNegative) {
@@ -2148,11 +2157,11 @@ BigInt* BigInt::bitOr(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) {
if (x->isNegative() && y->isNegative()) {
// (-x) | (-y) == ~(x-1) | ~(y-1) == ~((x-1) & (y-1))
// == -(((x-1) & (y-1)) + 1)
RootedBigInt result(cx, absoluteSubOne(cx, x, resultLength));
RootedBigInt result(cx, absoluteSubOne(cx, x));
if (!result) {
return nullptr;
}
RootedBigInt y1(cx, absoluteSubOne(cx, y, y->digitLength()));
RootedBigInt y1(cx, absoluteSubOne(cx, y));
if (!y1) {
return nullptr;
}
@@ -2168,7 +2177,7 @@ BigInt* BigInt::bitOr(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) {
HandleBigInt& neg = x->isNegative() ? x : y;
// x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(((y-1) &~ x) + 1)
RootedBigInt result(cx, absoluteSubOne(cx, neg, resultLength));
RootedBigInt result(cx, absoluteSubOne(cx, neg));
if (!result) {
return nullptr;
}
@@ -2183,7 +2192,7 @@ BigInt* BigInt::bitOr(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) {
BigInt* BigInt::bitNot(ExclusiveContext* cx, HandleBigInt x) {
if (x->isNegative()) {
// ~(-x) == ~(~(x-1)) == x-1
return absoluteSubOne(cx, x, x->digitLength());
return absoluteSubOne(cx, x);
} else {
// ~x == -x-1 == -(x+1)
bool resultNegative = true;
@@ -2535,6 +2544,30 @@ bool BigInt::neg(ExclusiveContext* cx, HandleValue operand, MutableHandleValue r
return true;
}
bool BigInt::inc(ExclusiveContext* cx, HandleValue operand, MutableHandleValue res) {
MOZ_ASSERT(operand.isBigInt());
RootedBigInt operandBigInt(cx, operand.toBigInt());
BigInt* resBigInt = BigInt::inc(cx, operandBigInt);
if (!resBigInt) {
return false;
}
res.setBigInt(resBigInt);
return true;
}
bool BigInt::dec(ExclusiveContext* cx, HandleValue operand, MutableHandleValue res) {
MOZ_ASSERT(operand.isBigInt());
RootedBigInt operandBigInt(cx, operand.toBigInt());
BigInt* resBigInt = BigInt::dec(cx, operandBigInt);
if (!resBigInt) {
return false;
}
res.setBigInt(resBigInt);
return true;
}
bool BigInt::lsh(ExclusiveContext* cx, HandleValue lhs, HandleValue rhs,
MutableHandleValue res) {
if (!ValidBigIntOperands(cx, lhs, rhs)) {
+9 -1
View File
@@ -97,9 +97,11 @@ class BigInt final : public js::gc::TenuredCell {
static BigInt* createFromDouble(js::ExclusiveContext* cx, double d);
static BigInt* createFromUint64(js::ExclusiveContext* cx, uint64_t n);
static BigInt* createFromInt64(js::ExclusiveContext* cx, int64_t n);
static BigInt* createFromDigit(js::ExclusiveContext* cx, Digit d, bool isNegative);
// FIXME: Cache these values.
static BigInt* zero(js::ExclusiveContext* cx);
static BigInt* one(js::ExclusiveContext* cx);
static BigInt* negativeOne(js::ExclusiveContext* cx);
static BigInt* copy(js::ExclusiveContext* cx, Handle<BigInt*> x);
static BigInt* add(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
@@ -109,6 +111,8 @@ class BigInt final : public js::gc::TenuredCell {
static BigInt* mod(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
static BigInt* pow(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
static BigInt* neg(js::ExclusiveContext* cx, Handle<BigInt*> x);
static BigInt* inc(js::ExclusiveContext* cx, Handle<BigInt*> x);
static BigInt* dec(js::ExclusiveContext* cx, Handle<BigInt*> x);
static BigInt* lsh(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
static BigInt* rsh(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
static BigInt* bitAnd(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
@@ -145,6 +149,10 @@ class BigInt final : public js::gc::TenuredCell {
MutableHandle<Value> res);
static bool neg(js::ExclusiveContext* cx, Handle<Value> operand,
MutableHandle<Value> res);
static bool inc(js::ExclusiveContext* cx, Handle<Value> operand,
MutableHandle<Value> res);
static bool dec(js::ExclusiveContext* cx, Handle<Value> operand,
MutableHandle<Value> res);
static bool lsh(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
MutableHandle<Value> res);
static bool rsh(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
@@ -288,7 +296,7 @@ class BigInt final : public js::gc::TenuredCell {
// Return `(|x| - 1) * (resultNegative ? -1 : +1)`, with the precondition that
// |x| != 0.
static BigInt* absoluteSubOne(js::ExclusiveContext* cx, Handle<BigInt*> x,
unsigned resultLength);
bool resultNegative = false);
// Return `a + b`, incrementing `*carry` if the addition overflows.
static inline Digit digitAdd(Digit a, Digit b, Digit* carry) {
+40
View File
@@ -416,6 +416,46 @@ NegOperation(JSContext* cx, HandleScript script, jsbytecode* pc, MutableHandleVa
return true;
}
static MOZ_ALWAYS_INLINE bool
IncOperation(JSContext* cx,
MutableHandleValue val,
MutableHandleValue res)
{
int32_t i;
if (val.isInt32() && (i = val.toInt32()) != INT32_MAX) {
res.setInt32(i + 1);
return true;
}
if (val.isNumber()) {
res.setNumber(val.toNumber() + 1);
return true;
}
MOZ_ASSERT(val.isBigInt(), "+1 only callable on result of JSOP_TONUMERIC");
return BigInt::inc(cx, val, res);
}
static MOZ_ALWAYS_INLINE bool
DecOperation(JSContext* cx,
MutableHandleValue val,
MutableHandleValue res)
{
int32_t i;
if (val.isInt32() && (i = val.toInt32()) != INT32_MIN) {
res.setInt32(i - 1);
return true;
}
if (val.isNumber()) {
res.setNumber(val.toNumber() - 1);
return true;
}
MOZ_ASSERT(val.isBigInt(), "-1 only callable on result of JSOP_TONUMERIC");
return BigInt::dec(cx, val, res);
}
static MOZ_ALWAYS_INLINE bool
ToIdOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue idval,
MutableHandleValue res)
+28
View File
@@ -4176,6 +4176,34 @@ CASE(JSOP_IS_CONSTRUCTING)
PUSH_MAGIC(JS_IS_CONSTRUCTING);
END_CASE(JSOP_IS_CONSTRUCTING)
CASE(JSOP_INC)
{
ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
MutableHandleValue res = REGS.stackHandleAt(-1);
if (!IncOperation(cx, &val, res)) {
goto error;
}
}
END_CASE(JSOP_INC)
CASE(JSOP_DEC)
{
ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
MutableHandleValue res = REGS.stackHandleAt(-1);
if (!DecOperation(cx, &val, res)) {
goto error;
}
}
END_CASE(JSOP_DEC)
CASE(JSOP_TONUMERIC)
{
if (!ToNumeric(cx, REGS.stackHandleAt(-1))) {
goto error;
}
}
END_CASE(JSOP_TONUMERIC)
CASE(JSOP_BIGINT)
{
PUSH_COPY(script->getConst(GET_UINT32_INDEX(REGS.pc)));
+28 -5
View File
@@ -2357,7 +2357,33 @@
* Operands:
* Stack: arg => rval
*/ \
macro(JSOP_DYNAMIC_IMPORT, 234, "call-import", NULL, 1, 1, 1, JOF_BYTE) \
macro(JSOP_DYNAMIC_IMPORT, 234, "call-import", NULL, 1, 1, 1, JOF_BYTE) \
/*
* Pops the numeric value 'val' from the stack, then pushes 'val + 1'.
*
* Category: Operators
* Type: Arithmetic Operators
* Operands:
* Stack: val => (val + 1)
*/ \
macro(JSOP_INC, 235, "inc", NULL, 1, 1, 1, JOF_BYTE) \
/*
* Pops the numeric value 'val' from the stack, then pushes 'val - 1'.
*
* Category: Operators
* Type: Arithmetic Operators
* Operands:
* Stack: val => (val - 1)
*/ \
macro(JSOP_DEC, 236, "dec", NULL, 1, 1, 1, JOF_BYTE) \
/*
* Pop 'val' from the stack, then push the result of 'ToNumeric(val)'.
* Category: Operators
* Type: Arithmetic Operators
* Operands:
* Stack: val => ToNumeric(val)
*/ \
macro(JSOP_TONUMERIC, 237, "tonumeric", NULL, 1, 1, 1, JOF_BYTE) \
/*
* Pushes a BigInt constant onto the stack.
* Category: Literals
@@ -2365,15 +2391,12 @@
* Operands: uint32_t constIndex
* Stack: => val
*/ \
macro(JSOP_BIGINT, 235, "bigint", NULL, 5, 0, 1, JOF_BIGINT)
macro(JSOP_BIGINT, 238, "bigint", NULL, 5, 0, 1, JOF_BIGINT)
/*
* In certain circumstances it may be useful to "pad out" the opcode space to
* a power of two. Use this macro to do so.
*/
#define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \
macro(236) \
macro(237) \
macro(238) \
macro(239) \
macro(240) \
macro(241) \
+4
View File
@@ -3245,6 +3245,10 @@ js::IsTypedArrayConstructor(HandleValue v, uint32_t type)
return IsNativeFunction(v, Int32Array::class_constructor);
case Scalar::Uint32:
return IsNativeFunction(v, Uint32Array::class_constructor);
case Scalar::BigInt64:
return IsNativeFunction(v, BigInt64Array::class_constructor);
case Scalar::BigUint64:
return IsNativeFunction(v, BigUint64Array::class_constructor);
case Scalar::Float32:
return IsNativeFunction(v, Float32Array::class_constructor);
case Scalar::Float64:
+91
View File
@@ -2719,6 +2719,38 @@ class BaseCompiler
return x0;
}
RegI64 popI64ForSignExtendI64() {
#if defined(JS_CODEGEN_X86)
need2xI32(specific_edx, specific_eax);
// Low on top, high underneath
return popI64ToSpecific(RegI64(Register64(specific_edx.reg, specific_eax.reg)));
#else
return popI64();
#endif
}
void signExtendI64_8(RegI64 r) {
#if defined(JS_CODEGEN_X64)
masm.movsbq(Operand(r.reg.reg), r.reg.reg);
#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
masm.move8SignExtend(r.reg.low, r.reg.low);
signExtendI32ToI64(RegI32(r.reg.low), r);
#else
MOZ_CRASH("Basecompiler platform hook: signExtendI64_8");
#endif
}
void signExtendI64_16(RegI64 r) {
#if defined(JS_CODEGEN_X64)
masm.movswq(Operand(r.reg.reg), r.reg.reg);
#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
masm.move16SignExtend(r.reg.low, r.reg.low);
signExtendI32ToI64(RegI32(r.reg.low), r);
#else
MOZ_CRASH("Basecompiler platform hook: signExtendI64_16");
#endif
}
void signExtendI32ToI64(RegI32 src, RegI64 dest) {
#if defined(JS_CODEGEN_X64)
masm.movslq(src.reg, dest.reg.reg);
@@ -3707,6 +3739,11 @@ class BaseCompiler
template<bool isUnsigned> MOZ_MUST_USE bool emitTruncateF64ToI64();
#endif
void emitWrapI64ToI32();
void emitExtendI32_8();
void emitExtendI32_16();
void emitExtendI64_8();
void emitExtendI64_16();
void emitExtendI64_32();
void emitExtendI32ToI64();
void emitExtendU32ToI64();
void emitReinterpretF32AsI32();
@@ -4597,6 +4634,48 @@ BaseCompiler::emitWrapI64ToI32()
pushI32(i0);
}
void
BaseCompiler::emitExtendI32_8()
{
RegI32 r = popI32();
masm.move8SignExtend(r.reg, r.reg);
pushI32(r);
}
void
BaseCompiler::emitExtendI32_16()
{
RegI32 r = popI32();
masm.move16SignExtend(r.reg, r.reg);
pushI32(r);
}
void
BaseCompiler::emitExtendI64_8()
{
RegI64 r = popI64ForSignExtendI64();
signExtendI64_8(r);
pushI64(r);
}
void
BaseCompiler::emitExtendI64_16()
{
RegI64 r = popI64ForSignExtendI64();
signExtendI64_16(r);
pushI64(r);
}
void
BaseCompiler::emitExtendI64_32()
{
RegI64 x0 = popI64ForSignExtendI64();
RegI32 r0 = RegI32(lowPart(x0));
signExtendI32ToI64(r0, x0);
pushI64(x0);
// Note: no need to free r0, since it is part of x0
}
void
BaseCompiler::emitExtendI32ToI64()
{
@@ -7166,6 +7245,18 @@ BaseCompiler::emitBody()
case uint16_t(Op::I32AtomicsExchange):
MOZ_CRASH("Unimplemented Atomics");
// Sign extensions
case uint16_t(Op::I32Extend8S):
CHECK_NEXT(emitConversion(emitExtendI32_8, ValType::I32, ValType::I32));
case uint16_t(Op::I32Extend16S):
CHECK_NEXT(emitConversion(emitExtendI32_16, ValType::I32, ValType::I32));
case uint16_t(Op::I64Extend8S):
CHECK_NEXT(emitConversion(emitExtendI64_8, ValType::I64, ValType::I64));
case uint16_t(Op::I64Extend16S):
CHECK_NEXT(emitConversion(emitExtendI64_16, ValType::I64, ValType::I64));
case uint16_t(Op::I64Extend32S):
CHECK_NEXT(emitConversion(emitExtendI64_32, ValType::I64, ValType::I64));
// Memory Related
case uint16_t(Op::GrowMemory):
CHECK_NEXT(emitGrowMemory());
+7
View File
@@ -310,6 +310,13 @@ enum class Op
F32ReinterpretI32 = 0xbe,
F64ReinterpretI64 = 0xbf,
// Sign extension
I32Extend8S = 0xc0,
I32Extend16S = 0xc1,
I64Extend8S = 0xc2,
I64Extend16S = 0xc3,
I64Extend32S = 0xc4,
// ------------------------------------------------------------------------
// The rest of these operators are currently only emitted internally when
// compiling asm.js and are rejected by wasm validation.
+5
View File
@@ -279,6 +279,11 @@ wasm::Classify(Op op)
case Op::F32x4fromInt8x16Bits:
case Op::F32x4fromInt16x8Bits:
case Op::F32x4fromInt32x4Bits:
case Op::I32Extend8S:
case Op::I32Extend16S:
case Op::I64Extend8S:
case Op::I64Extend16S:
case Op::I64Extend32S:
return OpKind::Conversion;
case Op::I32Load8S:
case Op::I32Load8U:
+11
View File
@@ -1300,6 +1300,17 @@ AstDecodeExpr(AstDecodeContext& c)
if (!AstDecodeConversion(c, ValType::F32, ValType::F64, Op(op)))
return false;
break;
case uint16_t(Op::I32Extend8S):
case uint16_t(Op::I32Extend16S):
if (!AstDecodeConversion(c, ValType::I32, ValType::I32, Op(op)))
return false;
break;
case uint16_t(Op::I64Extend8S):
case uint16_t(Op::I64Extend16S):
case uint16_t(Op::I64Extend32S):
if (!AstDecodeConversion(c, ValType::I64, ValType::I64, Op(op)))
return false;
break;
case uint16_t(Op::I32Load8S):
case uint16_t(Op::I32Load8U):
if (!AstDecodeLoad(c, ValType::I32, 1, Op(op)))
+5
View File
@@ -713,6 +713,11 @@ RenderConversionOperator(WasmRenderContext& c, AstConversionOperator& conv)
case Op::F64ConvertUI64: opStr = "f64.convert_u/i64"; break;
case Op::F64ReinterpretI64: opStr = "f64.reinterpret/i64"; break;
case Op::F64PromoteF32: opStr = "f64.promote/f32"; break;
case Op::I32Extend8S: opStr = "i32.extend8_s"; break;
case Op::I32Extend16S: opStr = "i32.extend16_s"; break;
case Op::I64Extend8S: opStr = "i64.extend8_s"; break;
case Op::I64Extend16S: opStr = "i64.extend16_s"; break;
case Op::I64Extend32S: opStr = "i64.extend32_s"; break;
case Op::I32Eqz: opStr = "i32.eqz"; break;
case Op::I64Eqz: opStr = "i64.eqz"; break;
default: return Fail(c, "unexpected conversion operator");
+7
View File
@@ -347,6 +347,13 @@ DecodeFunctionBodyExprs(FunctionDecoder& f)
CHECK(f.iter().readConversion(ValType::I64, ValType::F64, nullptr));
case uint16_t(Op::F64PromoteF32):
CHECK(f.iter().readConversion(ValType::F32, ValType::F64, nullptr));
case uint16_t(Op::I32Extend8S):
case uint16_t(Op::I32Extend16S):
CHECK(f.iter().readConversion(ValType::I32, ValType::I32, nullptr));
case uint16_t(Op::I64Extend8S):
case uint16_t(Op::I64Extend16S):
case uint16_t(Op::I64Extend32S):
CHECK(f.iter().readConversion(ValType::I64, ValType::I64, nullptr));
case uint16_t(Op::I32Load8S):
case uint16_t(Op::I32Load8U):
CHECK(f.checkHasMemory() && f.iter().readLoad(ValType::I32, 1, nullptr));
+59
View File
@@ -666,6 +666,41 @@ class FunctionCompiler
return ins;
}
MDefinition* signExtend(MDefinition* op, uint32_t srcSize, uint32_t targetSize)
{
if (inDeadCode())
return nullptr;
MInstruction* ins;
switch (targetSize) {
case 4: {
MSignExtendInt32::Mode mode;
switch (srcSize) {
case 1: mode = MSignExtendInt32::Byte; break;
case 2: mode = MSignExtendInt32::Half; break;
default: MOZ_CRASH("Bad sign extension");
}
ins = MSignExtendInt32::New(alloc(), op, mode);
break;
}
case 8: {
MSignExtendInt64::Mode mode;
switch (srcSize) {
case 1: mode = MSignExtendInt64::Byte; break;
case 2: mode = MSignExtendInt64::Half; break;
case 4: mode = MSignExtendInt64::Word; break;
default: MOZ_CRASH("Bad sign extension");
}
ins = MSignExtendInt64::New(alloc(), op, mode);
break;
}
default: {
MOZ_CRASH("Bad sign extension");
}
}
curBlock_->add(ins);
return ins;
}
MDefinition* convertI64ToFloatingPoint(MDefinition* op, MIRType type, bool isUnsigned)
{
if (inDeadCode())
@@ -2181,6 +2216,18 @@ EmitTruncate(FunctionCompiler& f, ValType operandType, ValType resultType,
return true;
}
static bool
EmitSignExtend(FunctionCompiler& f, uint32_t srcSize, uint32_t targetSize)
{
MDefinition* input;
ValType type = targetSize == 4 ? ValType::I32 : ValType::I64;
if (!f.iter().readConversion(type, type, &input))
return false;
f.iter().setResult(f.signExtend(input, srcSize, targetSize));
return true;
}
static bool
EmitExtendI32(FunctionCompiler& f, bool isUnsigned)
{
@@ -3480,6 +3527,18 @@ EmitExpr(FunctionCompiler& f)
case Op::F64ReinterpretI64:
return EmitReinterpret(f, ValType::F64, ValType::I64, MIRType::Double);
// Sign extensions
case Op::I32Extend8S:
return EmitSignExtend(f, 1, 4);
case Op::I32Extend16S:
return EmitSignExtend(f, 2, 4);
case Op::I64Extend8S:
return EmitSignExtend(f, 1, 8);
case Op::I64Extend16S:
return EmitSignExtend(f, 2, 8);
case Op::I64Extend32S:
return EmitSignExtend(f, 4, 8);
// Comparisons
case Op::I32Eq:
return EmitComparison(f, ValType::I32, JSOP_EQ, MCompare::Compare_Int32);
+10
View File
@@ -925,6 +925,16 @@ WasmTokenStream::next()
case 'e':
if (consume(u"eq"))
return WasmToken(WasmToken::ComparisonOpcode, Op::F32Eq, begin, cur_);
if (consume(u"extend8_s"))
return WasmToken(WasmToken::ConversionOpcode, Op::I32Extend8S, begin, cur_);
if (consume(u"extend16_s"))
return WasmToken(WasmToken::ConversionOpcode, Op::I32Extend16S, begin, cur_);
if (consume(u"extend8_s"))
return WasmToken(WasmToken::ConversionOpcode, Op::I64Extend8S, begin, cur_);
if (consume(u"extend16_s"))
return WasmToken(WasmToken::ConversionOpcode, Op::I64Extend16S, begin, cur_);
if (consume(u"extend32_s"))
return WasmToken(WasmToken::ConversionOpcode, Op::I64Extend32S, begin, cur_);
break;
case 'f':
if (consume(u"floor"))
+4
View File
@@ -1557,6 +1557,10 @@ void vp8_change_config(VP8_COMP *cpi, VP8_CONFIG *oxcf)
last_h = cpi->oxcf.Height;
prev_number_of_layers = cpi->oxcf.number_of_layers;
if (cpi->initial_width) {
oxcf->multi_threaded = cpi->oxcf.multi_threaded;
}
cpi->oxcf = *oxcf;
switch (cpi->oxcf.Mode)
+25 -21
View File
@@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths(
int symbol;
int max_symbol;
int prev_code_len = DEFAULT_CODE_LENGTH;
HuffmanCode table[1 << LENGTHS_TABLE_BITS];
HuffmanTables tables;
if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS,
code_length_code_lengths,
NUM_CODE_LENGTH_CODES)) {
if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) ||
!VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS,
code_length_code_lengths, NUM_CODE_LENGTH_CODES)) {
goto End;
}
@@ -277,7 +277,7 @@ static int ReadHuffmanCodeLengths(
int code_len;
if (max_symbol-- == 0) break;
VP8LFillBitWindow(br);
p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
VP8LSetBitPos(br, br->bit_pos_ + p->bits);
code_len = p->value;
if (code_len < kCodeLengthLiterals) {
@@ -300,6 +300,7 @@ static int ReadHuffmanCodeLengths(
ok = 1;
End:
VP8LHuffmanTablesDeallocate(&tables);
if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
return ok;
}
@@ -307,7 +308,8 @@ static int ReadHuffmanCodeLengths(
// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
// tree.
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
int* const code_lengths, HuffmanCode* const table) {
int* const code_lengths,
HuffmanTables* const table) {
int ok = 0;
int size = 0;
VP8LBitReader* const br = &dec->br_;
@@ -362,8 +364,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL;
HTreeGroup* htree_groups = NULL;
HuffmanCode* huffman_tables = NULL;
HuffmanCode* huffman_table = NULL;
HuffmanTables* huffman_tables = &hdr->huffman_tables_;
int num_htree_groups = 1;
int num_htree_groups_max = 1;
int max_alphabet_size = 0;
@@ -372,6 +373,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int* mapping = NULL;
int ok = 0;
// Check the table has been 0 initialized (through InitMetadata).
assert(huffman_tables->root.start == NULL);
assert(huffman_tables->curr_segment == NULL);
if (allow_recursion && VP8LReadBits(br, 1)) {
// use meta Huffman codes.
const int huffman_precision = VP8LReadBits(br, 3) + 2;
@@ -434,16 +439,15 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
sizeof(*code_lengths));
huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
sizeof(*huffman_tables));
htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
if (htree_groups == NULL || code_lengths == NULL ||
!VP8LHuffmanTablesAllocate(num_htree_groups * table_size,
huffman_tables)) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error;
}
huffman_table = huffman_tables;
for (i = 0; i < num_htree_groups_max; ++i) {
// If the index "i" is unused in the Huffman image, just make sure the
// coefficients are valid but do not store them.
@@ -468,19 +472,20 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int max_bits = 0;
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
int alphabet_size = kAlphabetSize[j];
htrees[j] = huffman_table;
if (j == 0 && color_cache_bits > 0) {
alphabet_size += (1 << color_cache_bits);
}
size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table);
size =
ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables);
htrees[j] = huffman_tables->curr_segment->curr_table;
if (size == 0) {
goto Error;
}
if (is_trivial_literal && kLiteralMap[j] == 1) {
is_trivial_literal = (huffman_table->bits == 0);
is_trivial_literal = (htrees[j]->bits == 0);
}
total_size += huffman_table->bits;
huffman_table += size;
total_size += htrees[j]->bits;
huffman_tables->curr_segment->curr_table += size;
if (j <= ALPHA) {
int local_max_bits = code_lengths[0];
int k;
@@ -515,14 +520,13 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
hdr->huffman_image_ = huffman_image;
hdr->num_htree_groups_ = num_htree_groups;
hdr->htree_groups_ = htree_groups;
hdr->huffman_tables_ = huffman_tables;
Error:
WebPSafeFree(code_lengths);
WebPSafeFree(mapping);
if (!ok) {
WebPSafeFree(huffman_image);
WebPSafeFree(huffman_tables);
VP8LHuffmanTablesDeallocate(huffman_tables);
VP8LHtreeGroupsFree(htree_groups);
}
return ok;
@@ -1358,7 +1362,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
assert(hdr != NULL);
WebPSafeFree(hdr->huffman_image_);
WebPSafeFree(hdr->huffman_tables_);
VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_);
VP8LHtreeGroupsFree(hdr->htree_groups_);
VP8LColorCacheClear(&hdr->color_cache_);
VP8LColorCacheClear(&hdr->saved_color_cache_);
@@ -1673,7 +1677,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
if (dec == NULL) return 0;
assert(dec->hdr_.huffman_tables_ != NULL);
assert(dec->hdr_.huffman_tables_.root.start != NULL);
assert(dec->hdr_.htree_groups_ != NULL);
assert(dec->hdr_.num_htree_groups_ > 0);
+1 -1
View File
@@ -51,7 +51,7 @@ typedef struct {
uint32_t* huffman_image_;
int num_htree_groups_;
HTreeGroup* htree_groups_;
HuffmanCode* huffman_tables_;
HuffmanTables huffman_tables_;
} VP8LMetadata;
typedef struct VP8LDecoder VP8LDecoder;
+79 -18
View File
@@ -177,21 +177,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
if (num_open < 0) {
return 0;
}
if (root_table == NULL) continue;
for (; count[len] > 0; --count[len]) {
HuffmanCode code;
if ((key & mask) != low) {
table += table_size;
if (root_table != NULL) table += table_size;
table_bits = NextTableBitSize(count, len, root_bits);
table_size = 1 << table_bits;
total_size += table_size;
low = key & mask;
root_table[low].bits = (uint8_t)(table_bits + root_bits);
root_table[low].value = (uint16_t)((table - root_table) - low);
if (root_table != NULL) {
root_table[low].bits = (uint8_t)(table_bits + root_bits);
root_table[low].value = (uint16_t)((table - root_table) - low);
}
}
if (root_table != NULL) {
code.bits = (uint8_t)(len - root_bits);
code.value = (uint16_t)sorted[symbol++];
ReplicateValue(&table[key >> root_bits], step, table_size, code);
}
code.bits = (uint8_t)(len - root_bits);
code.value = (uint16_t)sorted[symbol++];
ReplicateValue(&table[key >> root_bits], step, table_size, code);
key = GetNextKey(key, len);
}
}
@@ -211,25 +214,83 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
((1 << MAX_CACHE_BITS) + NUM_LITERAL_CODES + NUM_LENGTH_CODES)
// Cut-off value for switching between heap and stack allocation.
#define SORTED_SIZE_CUTOFF 512
int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
const int code_lengths[], int code_lengths_size) {
int total_size;
const int total_size =
BuildHuffmanTable(NULL, root_bits, code_lengths, code_lengths_size, NULL);
assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE);
if (root_table == NULL) {
total_size = BuildHuffmanTable(NULL, root_bits,
code_lengths, code_lengths_size, NULL);
} else if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
if (total_size == 0 || root_table == NULL) return total_size;
if (root_table->curr_segment->curr_table + total_size >=
root_table->curr_segment->start + root_table->curr_segment->size) {
// If 'root_table' does not have enough memory, allocate a new segment.
// The available part of root_table->curr_segment is left unused because we
// need a contiguous buffer.
const int segment_size = root_table->curr_segment->size;
struct HuffmanTablesSegment* next =
(HuffmanTablesSegment*)WebPSafeMalloc(1, sizeof(*next));
if (next == NULL) return 0;
// Fill the new segment.
// We need at least 'total_size' but if that value is small, it is better to
// allocate a big chunk to prevent more allocations later. 'segment_size' is
// therefore chosen (any other arbitrary value could be chosen).
next->size = total_size > segment_size ? total_size : segment_size;
next->start =
(HuffmanCode*)WebPSafeMalloc(next->size, sizeof(*next->start));
if (next->start == NULL) {
WebPSafeFree(next);
return 0;
}
next->curr_table = next->start;
next->next = NULL;
// Point to the new segment.
root_table->curr_segment->next = next;
root_table->curr_segment = next;
}
if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
// use local stack-allocated array.
uint16_t sorted[SORTED_SIZE_CUTOFF];
total_size = BuildHuffmanTable(root_table, root_bits,
code_lengths, code_lengths_size, sorted);
} else { // rare case. Use heap allocation.
BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
code_lengths, code_lengths_size, sorted);
} else { // rare case. Use heap allocation.
uint16_t* const sorted =
(uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted));
if (sorted == NULL) return 0;
total_size = BuildHuffmanTable(root_table, root_bits,
code_lengths, code_lengths_size, sorted);
BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
code_lengths, code_lengths_size, sorted);
WebPSafeFree(sorted);
}
return total_size;
}
int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) {
// Have 'segment' point to the first segment for now, 'root'.
HuffmanTablesSegment* const root = &huffman_tables->root;
huffman_tables->curr_segment = root;
// Allocate root.
root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start));
if (root->start == NULL) return 0;
root->curr_table = root->start;
root->next = NULL;
root->size = size;
return 1;
}
void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables) {
HuffmanTablesSegment *current, *next;
if (huffman_tables == NULL) return;
// Free the root node.
current = &huffman_tables->root;
next = current->next;
WebPSafeFree(current->start);
current->start = NULL;
current->next = NULL;
current = next;
// Free the following nodes.
while (current != NULL) {
next = current->next;
WebPSafeFree(current->start);
WebPSafeFree(current);
current = next;
}
}
+24 -3
View File
@@ -43,6 +43,29 @@ typedef struct {
// or non-literal symbol otherwise
} HuffmanCode32;
// Contiguous memory segment of HuffmanCodes.
typedef struct HuffmanTablesSegment {
HuffmanCode* start;
// Pointer to where we are writing into the segment. Starts at 'start' and
// cannot go beyond 'start' + 'size'.
HuffmanCode* curr_table;
// Pointer to the next segment in the chain.
struct HuffmanTablesSegment* next;
int size;
} HuffmanTablesSegment;
// Chained memory segments of HuffmanCodes.
typedef struct HuffmanTables {
HuffmanTablesSegment root;
// Currently processed segment. At first, this is 'root'.
HuffmanTablesSegment* curr_segment;
} HuffmanTables;
// Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on
// memory allocation error, 1 otherwise.
int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables);
void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables);
#define HUFFMAN_PACKED_BITS 6
#define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS)
@@ -78,9 +101,7 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
// the huffman table.
// Returns built table size or 0 in case of error (invalid tree or
// memory error).
// If root_table is NULL, it returns 0 if a lookup cannot be built, something
// > 0 otherwise (but not the table size).
int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
const int code_lengths[], int code_lengths_size);
#ifdef __cplusplus
+5 -4
View File
@@ -755,13 +755,14 @@ TransactionObserver::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext
nsIInputStream *aStream, uint64_t aOffset, uint32_t aCount)
{
MOZ_ASSERT(NS_IsMainThread());
uint64_t newLen = aCount + mWKResponse.Length();
uint64_t oldLen = static_cast<uint64_t>(mWKResponse.Length());
uint64_t newLen = static_cast<uint64_t>(aCount) + oldLen;
if (newLen < MAX_WK) {
char *startByte = reinterpret_cast<char *>(mWKResponse.BeginWriting()) + mWKResponse.Length();
char *startByte = reinterpret_cast<char *>(mWKResponse.BeginWriting()) + oldLen;
uint32_t amtRead;
if (NS_SUCCEEDED(aStream->Read(startByte, aCount, &amtRead))) {
MOZ_ASSERT(mWKResponse.Length() + amtRead < MAX_WK);
mWKResponse.SetLength(mWKResponse.Length() + amtRead);
MOZ_ASSERT(oldLen + amtRead < MAX_WK);
mWKResponse.SetLength(oldLen + amtRead);
LOG(("TransactionObserver onDataAvailable %p read %d of .wk [%d]\n",
this, amtRead, mWKResponse.Length()));
} else {