aboutsummaryrefslogtreecommitdiffstats
path: root/src/3rdparty
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty')
-rw-r--r--src/3rdparty/double-conversion/README6
-rw-r--r--src/3rdparty/double-conversion/bignum-dtoa.cc641
-rw-r--r--src/3rdparty/double-conversion/bignum-dtoa.h84
-rw-r--r--src/3rdparty/double-conversion/bignum.cc766
-rw-r--r--src/3rdparty/double-conversion/bignum.h145
-rw-r--r--src/3rdparty/double-conversion/cached-powers.cc178
-rw-r--r--src/3rdparty/double-conversion/cached-powers.h64
-rw-r--r--src/3rdparty/double-conversion/diy-fp.cc57
-rw-r--r--src/3rdparty/double-conversion/diy-fp.h118
-rw-r--r--src/3rdparty/double-conversion/double-conversion.cc975
-rw-r--r--src/3rdparty/double-conversion/double-conversion.h543
-rw-r--r--src/3rdparty/double-conversion/double-conversion.pri24
-rw-r--r--src/3rdparty/double-conversion/fast-dtoa.cc665
-rw-r--r--src/3rdparty/double-conversion/fast-dtoa.h88
-rw-r--r--src/3rdparty/double-conversion/fixed-dtoa.cc404
-rw-r--r--src/3rdparty/double-conversion/fixed-dtoa.h56
-rw-r--r--src/3rdparty/double-conversion/ieee.h402
-rw-r--r--src/3rdparty/double-conversion/strtod.cc555
-rw-r--r--src/3rdparty/double-conversion/strtod.h45
-rw-r--r--src/3rdparty/double-conversion/utils.h330
-rw-r--r--src/3rdparty/masm/WeakRandom.h34
-rw-r--r--src/3rdparty/masm/assembler/ARM64Assembler.h3772
-rw-r--r--src/3rdparty/masm/assembler/ARMv7Assembler.h1
-rw-r--r--src/3rdparty/masm/assembler/AbstractMacroAssembler.h52
-rw-r--r--src/3rdparty/masm/assembler/MacroAssembler.h12
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARM64.h3455
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARMv7.h2
-rw-r--r--src/3rdparty/masm/config.h34
-rw-r--r--src/3rdparty/masm/disassembler/ARM64/A64DOpcode.cpp1202
-rw-r--r--src/3rdparty/masm/disassembler/ARM64/A64DOpcode.h708
-rw-r--r--src/3rdparty/masm/disassembler/ARM64Disassembler.cpp72
-rw-r--r--src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp2
-rw-r--r--src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h2
-rw-r--r--src/3rdparty/masm/disassembler/ARMv7Disassembler.cpp2
-rw-r--r--src/3rdparty/masm/masm-defs.pri9
-rw-r--r--src/3rdparty/masm/masm.pri3
-rw-r--r--src/3rdparty/masm/stubs/ExecutableAllocator.h117
-rw-r--r--src/3rdparty/masm/stubs/JSGlobalData.h34
-rw-r--r--src/3rdparty/masm/stubs/Options.cpp34
-rw-r--r--src/3rdparty/masm/stubs/Options.h34
-rw-r--r--src/3rdparty/masm/stubs/WTFStubs.cpp41
-rw-r--r--src/3rdparty/masm/stubs/WTFStubs.h34
-rw-r--r--src/3rdparty/masm/stubs/compat/stdint.h34
-rw-r--r--src/3rdparty/masm/stubs/wtf/FastAllocBase.h34
-rw-r--r--src/3rdparty/masm/stubs/wtf/FastMalloc.h34
-rw-r--r--src/3rdparty/masm/stubs/wtf/Noncopyable.h34
-rw-r--r--src/3rdparty/masm/stubs/wtf/OwnPtr.h34
-rw-r--r--src/3rdparty/masm/stubs/wtf/PassOwnPtr.h38
-rw-r--r--src/3rdparty/masm/stubs/wtf/PassRefPtr.h37
-rw-r--r--src/3rdparty/masm/stubs/wtf/RefCounted.h34
-rw-r--r--src/3rdparty/masm/stubs/wtf/RefPtr.h34
-rw-r--r--src/3rdparty/masm/stubs/wtf/TypeTraits.h34
-rw-r--r--src/3rdparty/masm/stubs/wtf/UnusedParam.h34
-rw-r--r--src/3rdparty/masm/stubs/wtf/Vector.h34
-rw-r--r--src/3rdparty/masm/stubs/wtf/text/CString.h34
-rw-r--r--src/3rdparty/masm/stubs/wtf/text/WTFString.h34
-rw-r--r--src/3rdparty/masm/stubs/wtf/unicode/Unicode.h34
-rw-r--r--src/3rdparty/masm/wtf/OSAllocator.h2
-rw-r--r--src/3rdparty/masm/wtf/OSAllocatorPosix.cpp5
-rw-r--r--src/3rdparty/masm/wtf/OSAllocatorWin.cpp5
-rw-r--r--src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp104
-rw-r--r--src/3rdparty/masm/wtf/Platform.h19
-rw-r--r--src/3rdparty/masm/yarr/YarrJIT.cpp11
63 files changed, 9945 insertions, 6520 deletions
diff --git a/src/3rdparty/double-conversion/README b/src/3rdparty/double-conversion/README
deleted file mode 100644
index 3a9733d795..0000000000
--- a/src/3rdparty/double-conversion/README
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a copy of the library for binary-decimal and decimal-binary conversion routines for IEEE doubles, taken
-from
-
- http://code.google.com/p/double-conversion/
-
-commit 2fb03de56faa32bbba5e02222528e7b760f71d77
diff --git a/src/3rdparty/double-conversion/bignum-dtoa.cc b/src/3rdparty/double-conversion/bignum-dtoa.cc
deleted file mode 100644
index f1ad7a5ae8..0000000000
--- a/src/3rdparty/double-conversion/bignum-dtoa.cc
+++ /dev/null
@@ -1,641 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <math.h>
-
-#include "bignum-dtoa.h"
-
-#include "bignum.h"
-#include "ieee.h"
-
-namespace double_conversion {
-
-static int NormalizedExponent(uint64_t significand, int exponent) {
- ASSERT(significand != 0);
- while ((significand & Double::kHiddenBit) == 0) {
- significand = significand << 1;
- exponent = exponent - 1;
- }
- return exponent;
-}
-
-
-// Forward declarations:
-// Returns an estimation of k such that 10^(k-1) <= v < 10^k.
-static int EstimatePower(int exponent);
-// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
-// and denominator.
-static void InitialScaledStartValues(uint64_t significand,
- int exponent,
- bool lower_boundary_is_closer,
- int estimated_power,
- bool need_boundary_deltas,
- Bignum* numerator,
- Bignum* denominator,
- Bignum* delta_minus,
- Bignum* delta_plus);
-// Multiplies numerator/denominator so that its values lies in the range 1-10.
-// Returns decimal_point s.t.
-// v = numerator'/denominator' * 10^(decimal_point-1)
-// where numerator' and denominator' are the values of numerator and
-// denominator after the call to this function.
-static void FixupMultiply10(int estimated_power, bool is_even,
- int* decimal_point,
- Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus);
-// Generates digits from the left to the right and stops when the generated
-// digits yield the shortest decimal representation of v.
-static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus,
- bool is_even,
- Vector<char> buffer, int* length);
-// Generates 'requested_digits' after the decimal point.
-static void BignumToFixed(int requested_digits, int* decimal_point,
- Bignum* numerator, Bignum* denominator,
- Vector<char>(buffer), int* length);
-// Generates 'count' digits of numerator/denominator.
-// Once 'count' digits have been produced rounds the result depending on the
-// remainder (remainders of exactly .5 round upwards). Might update the
-// decimal_point when rounding up (for example for 0.9999).
-static void GenerateCountedDigits(int count, int* decimal_point,
- Bignum* numerator, Bignum* denominator,
- Vector<char>(buffer), int* length);
-
-
-void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
- Vector<char> buffer, int* length, int* decimal_point) {
- ASSERT(v > 0);
- ASSERT(!Double(v).IsSpecial());
- uint64_t significand;
- int exponent;
- bool lower_boundary_is_closer;
- if (mode == BIGNUM_DTOA_SHORTEST_SINGLE) {
- float f = static_cast<float>(v);
- ASSERT(f == v);
- significand = Single(f).Significand();
- exponent = Single(f).Exponent();
- lower_boundary_is_closer = Single(f).LowerBoundaryIsCloser();
- } else {
- significand = Double(v).Significand();
- exponent = Double(v).Exponent();
- lower_boundary_is_closer = Double(v).LowerBoundaryIsCloser();
- }
- bool need_boundary_deltas =
- (mode == BIGNUM_DTOA_SHORTEST || mode == BIGNUM_DTOA_SHORTEST_SINGLE);
-
- bool is_even = (significand & 1) == 0;
- int normalized_exponent = NormalizedExponent(significand, exponent);
- // estimated_power might be too low by 1.
- int estimated_power = EstimatePower(normalized_exponent);
-
- // Shortcut for Fixed.
- // The requested digits correspond to the digits after the point. If the
- // number is much too small, then there is no need in trying to get any
- // digits.
- if (mode == BIGNUM_DTOA_FIXED && -estimated_power - 1 > requested_digits) {
- buffer[0] = '\0';
- *length = 0;
- // Set decimal-point to -requested_digits. This is what Gay does.
- // Note that it should not have any effect anyways since the string is
- // empty.
- *decimal_point = -requested_digits;
- return;
- }
-
- Bignum numerator;
- Bignum denominator;
- Bignum delta_minus;
- Bignum delta_plus;
- // Make sure the bignum can grow large enough. The smallest double equals
- // 4e-324. In this case the denominator needs fewer than 324*4 binary digits.
- // The maximum double is 1.7976931348623157e308 which needs fewer than
- // 308*4 binary digits.
- ASSERT(Bignum::kMaxSignificantBits >= 324*4);
- InitialScaledStartValues(significand, exponent, lower_boundary_is_closer,
- estimated_power, need_boundary_deltas,
- &numerator, &denominator,
- &delta_minus, &delta_plus);
- // We now have v = (numerator / denominator) * 10^estimated_power.
- FixupMultiply10(estimated_power, is_even, decimal_point,
- &numerator, &denominator,
- &delta_minus, &delta_plus);
- // We now have v = (numerator / denominator) * 10^(decimal_point-1), and
- // 1 <= (numerator + delta_plus) / denominator < 10
- switch (mode) {
- case BIGNUM_DTOA_SHORTEST:
- case BIGNUM_DTOA_SHORTEST_SINGLE:
- GenerateShortestDigits(&numerator, &denominator,
- &delta_minus, &delta_plus,
- is_even, buffer, length);
- break;
- case BIGNUM_DTOA_FIXED:
- BignumToFixed(requested_digits, decimal_point,
- &numerator, &denominator,
- buffer, length);
- break;
- case BIGNUM_DTOA_PRECISION:
- GenerateCountedDigits(requested_digits, decimal_point,
- &numerator, &denominator,
- buffer, length);
- break;
- default:
- UNREACHABLE();
- }
- buffer[*length] = '\0';
-}
-
-
-// The procedure starts generating digits from the left to the right and stops
-// when the generated digits yield the shortest decimal representation of v. A
-// decimal representation of v is a number lying closer to v than to any other
-// double, so it converts to v when read.
-//
-// This is true if d, the decimal representation, is between m- and m+, the
-// upper and lower boundaries. d must be strictly between them if !is_even.
-// m- := (numerator - delta_minus) / denominator
-// m+ := (numerator + delta_plus) / denominator
-//
-// Precondition: 0 <= (numerator+delta_plus) / denominator < 10.
-// If 1 <= (numerator+delta_plus) / denominator < 10 then no leading 0 digit
-// will be produced. This should be the standard precondition.
-static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus,
- bool is_even,
- Vector<char> buffer, int* length) {
- // Small optimization: if delta_minus and delta_plus are the same just reuse
- // one of the two bignums.
- if (Bignum::Equal(*delta_minus, *delta_plus)) {
- delta_plus = delta_minus;
- }
- *length = 0;
- for (;;) {
- uint16_t digit;
- digit = numerator->DivideModuloIntBignum(*denominator);
- ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive.
- // digit = numerator / denominator (integer division).
- // numerator = numerator % denominator.
- buffer[(*length)++] = static_cast<char>(digit + '0');
-
- // Can we stop already?
- // If the remainder of the division is less than the distance to the lower
- // boundary we can stop. In this case we simply round down (discarding the
- // remainder).
- // Similarly we test if we can round up (using the upper boundary).
- bool in_delta_room_minus;
- bool in_delta_room_plus;
- if (is_even) {
- in_delta_room_minus = Bignum::LessEqual(*numerator, *delta_minus);
- } else {
- in_delta_room_minus = Bignum::Less(*numerator, *delta_minus);
- }
- if (is_even) {
- in_delta_room_plus =
- Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
- } else {
- in_delta_room_plus =
- Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
- }
- if (!in_delta_room_minus && !in_delta_room_plus) {
- // Prepare for next iteration.
- numerator->Times10();
- delta_minus->Times10();
- // We optimized delta_plus to be equal to delta_minus (if they share the
- // same value). So don't multiply delta_plus if they point to the same
- // object.
- if (delta_minus != delta_plus) {
- delta_plus->Times10();
- }
- } else if (in_delta_room_minus && in_delta_room_plus) {
- // Let's see if 2*numerator < denominator.
- // If yes, then the next digit would be < 5 and we can round down.
- int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator);
- if (compare < 0) {
- // Remaining digits are less than .5. -> Round down (== do nothing).
- } else if (compare > 0) {
- // Remaining digits are more than .5 of denominator. -> Round up.
- // Note that the last digit could not be a '9' as otherwise the whole
- // loop would have stopped earlier.
- // We still have an assert here in case the preconditions were not
- // satisfied.
- ASSERT(buffer[(*length) - 1] != '9');
- buffer[(*length) - 1]++;
- } else {
- // Halfway case.
- // TODO(floitsch): need a way to solve half-way cases.
- // For now let's round towards even (since this is what Gay seems to
- // do).
-
- if ((buffer[(*length) - 1] - '0') % 2 == 0) {
- // Round down => Do nothing.
- } else {
- ASSERT(buffer[(*length) - 1] != '9');
- buffer[(*length) - 1]++;
- }
- }
- return;
- } else if (in_delta_room_minus) {
- // Round down (== do nothing).
- return;
- } else { // in_delta_room_plus
- // Round up.
- // Note again that the last digit could not be '9' since this would have
- // stopped the loop earlier.
- // We still have an ASSERT here, in case the preconditions were not
- // satisfied.
- ASSERT(buffer[(*length) -1] != '9');
- buffer[(*length) - 1]++;
- return;
- }
- }
-}
-
-
-// Let v = numerator / denominator < 10.
-// Then we generate 'count' digits of d = x.xxxxx... (without the decimal point)
-// from left to right. Once 'count' digits have been produced we decide wether
-// to round up or down. Remainders of exactly .5 round upwards. Numbers such
-// as 9.999999 propagate a carry all the way, and change the
-// exponent (decimal_point), when rounding upwards.
-static void GenerateCountedDigits(int count, int* decimal_point,
- Bignum* numerator, Bignum* denominator,
- Vector<char> buffer, int* length) {
- ASSERT(count >= 0);
- for (int i = 0; i < count - 1; ++i) {
- uint16_t digit;
- digit = numerator->DivideModuloIntBignum(*denominator);
- ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive.
- // digit = numerator / denominator (integer division).
- // numerator = numerator % denominator.
- buffer[i] = static_cast<char>(digit + '0');
- // Prepare for next iteration.
- numerator->Times10();
- }
- // Generate the last digit.
- uint16_t digit;
- digit = numerator->DivideModuloIntBignum(*denominator);
- if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
- digit++;
- }
- ASSERT(digit <= 10);
- buffer[count - 1] = static_cast<char>(digit + '0');
- // Correct bad digits (in case we had a sequence of '9's). Propagate the
- // carry until we hat a non-'9' or til we reach the first digit.
- for (int i = count - 1; i > 0; --i) {
- if (buffer[i] != '0' + 10) break;
- buffer[i] = '0';
- buffer[i - 1]++;
- }
- if (buffer[0] == '0' + 10) {
- // Propagate a carry past the top place.
- buffer[0] = '1';
- (*decimal_point)++;
- }
- *length = count;
-}
-
-
-// Generates 'requested_digits' after the decimal point. It might omit
-// trailing '0's. If the input number is too small then no digits at all are
-// generated (ex.: 2 fixed digits for 0.00001).
-//
-// Input verifies: 1 <= (numerator + delta) / denominator < 10.
-static void BignumToFixed(int requested_digits, int* decimal_point,
- Bignum* numerator, Bignum* denominator,
- Vector<char>(buffer), int* length) {
- // Note that we have to look at more than just the requested_digits, since
- // a number could be rounded up. Example: v=0.5 with requested_digits=0.
- // Even though the power of v equals 0 we can't just stop here.
- if (-(*decimal_point) > requested_digits) {
- // The number is definitively too small.
- // Ex: 0.001 with requested_digits == 1.
- // Set decimal-point to -requested_digits. This is what Gay does.
- // Note that it should not have any effect anyways since the string is
- // empty.
- *decimal_point = -requested_digits;
- *length = 0;
- return;
- } else if (-(*decimal_point) == requested_digits) {
- // We only need to verify if the number rounds down or up.
- // Ex: 0.04 and 0.06 with requested_digits == 1.
- ASSERT(*decimal_point == -requested_digits);
- // Initially the fraction lies in range (1, 10]. Multiply the denominator
- // by 10 so that we can compare more easily.
- denominator->Times10();
- if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
- // If the fraction is >= 0.5 then we have to include the rounded
- // digit.
- buffer[0] = '1';
- *length = 1;
- (*decimal_point)++;
- } else {
- // Note that we caught most of similar cases earlier.
- *length = 0;
- }
- return;
- } else {
- // The requested digits correspond to the digits after the point.
- // The variable 'needed_digits' includes the digits before the point.
- int needed_digits = (*decimal_point) + requested_digits;
- GenerateCountedDigits(needed_digits, decimal_point,
- numerator, denominator,
- buffer, length);
- }
-}
-
-
-// Returns an estimation of k such that 10^(k-1) <= v < 10^k where
-// v = f * 2^exponent and 2^52 <= f < 2^53.
-// v is hence a normalized double with the given exponent. The output is an
-// approximation for the exponent of the decimal approimation .digits * 10^k.
-//
-// The result might undershoot by 1 in which case 10^k <= v < 10^k+1.
-// Note: this property holds for v's upper boundary m+ too.
-// 10^k <= m+ < 10^k+1.
-// (see explanation below).
-//
-// Examples:
-// EstimatePower(0) => 16
-// EstimatePower(-52) => 0
-//
-// Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0.
-static int EstimatePower(int exponent) {
- // This function estimates log10 of v where v = f*2^e (with e == exponent).
- // Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)).
- // Note that f is bounded by its container size. Let p = 53 (the double's
- // significand size). Then 2^(p-1) <= f < 2^p.
- //
- // Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close
- // to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)).
- // The computed number undershoots by less than 0.631 (when we compute log3
- // and not log10).
- //
- // Optimization: since we only need an approximated result this computation
- // can be performed on 64 bit integers. On x86/x64 architecture the speedup is
- // not really measurable, though.
- //
- // Since we want to avoid overshooting we decrement by 1e10 so that
- // floating-point imprecisions don't affect us.
- //
- // Explanation for v's boundary m+: the computation takes advantage of
- // the fact that 2^(p-1) <= f < 2^p. Boundaries still satisfy this requirement
- // (even for denormals where the delta can be much more important).
-
- const double k1Log10 = 0.30102999566398114; // 1/lg(10)
-
- // For doubles len(f) == 53 (don't forget the hidden bit).
- const int kSignificandSize = Double::kSignificandSize;
- double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10);
- return static_cast<int>(estimate);
-}
-
-
-// See comments for InitialScaledStartValues.
-static void InitialScaledStartValuesPositiveExponent(
- uint64_t significand, int exponent,
- int estimated_power, bool need_boundary_deltas,
- Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus) {
- // A positive exponent implies a positive power.
- ASSERT(estimated_power >= 0);
- // Since the estimated_power is positive we simply multiply the denominator
- // by 10^estimated_power.
-
- // numerator = v.
- numerator->AssignUInt64(significand);
- numerator->ShiftLeft(exponent);
- // denominator = 10^estimated_power.
- denominator->AssignPowerUInt16(10, estimated_power);
-
- if (need_boundary_deltas) {
- // Introduce a common denominator so that the deltas to the boundaries are
- // integers.
- denominator->ShiftLeft(1);
- numerator->ShiftLeft(1);
- // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
- // denominator (of 2) delta_plus equals 2^e.
- delta_plus->AssignUInt16(1);
- delta_plus->ShiftLeft(exponent);
- // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
- delta_minus->AssignUInt16(1);
- delta_minus->ShiftLeft(exponent);
- }
-}
-
-
-// See comments for InitialScaledStartValues
-static void InitialScaledStartValuesNegativeExponentPositivePower(
- uint64_t significand, int exponent,
- int estimated_power, bool need_boundary_deltas,
- Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus) {
- // v = f * 2^e with e < 0, and with estimated_power >= 0.
- // This means that e is close to 0 (have a look at how estimated_power is
- // computed).
-
- // numerator = significand
- // since v = significand * 2^exponent this is equivalent to
- // numerator = v * / 2^-exponent
- numerator->AssignUInt64(significand);
- // denominator = 10^estimated_power * 2^-exponent (with exponent < 0)
- denominator->AssignPowerUInt16(10, estimated_power);
- denominator->ShiftLeft(-exponent);
-
- if (need_boundary_deltas) {
- // Introduce a common denominator so that the deltas to the boundaries are
- // integers.
- denominator->ShiftLeft(1);
- numerator->ShiftLeft(1);
- // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
- // denominator (of 2) delta_plus equals 2^e.
- // Given that the denominator already includes v's exponent the distance
- // to the boundaries is simply 1.
- delta_plus->AssignUInt16(1);
- // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
- delta_minus->AssignUInt16(1);
- }
-}
-
-
-// See comments for InitialScaledStartValues
-static void InitialScaledStartValuesNegativeExponentNegativePower(
- uint64_t significand, int exponent,
- int estimated_power, bool need_boundary_deltas,
- Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus) {
- // Instead of multiplying the denominator with 10^estimated_power we
- // multiply all values (numerator and deltas) by 10^-estimated_power.
-
- // Use numerator as temporary container for power_ten.
- Bignum* power_ten = numerator;
- power_ten->AssignPowerUInt16(10, -estimated_power);
-
- if (need_boundary_deltas) {
- // Since power_ten == numerator we must make a copy of 10^estimated_power
- // before we complete the computation of the numerator.
- // delta_plus = delta_minus = 10^estimated_power
- delta_plus->AssignBignum(*power_ten);
- delta_minus->AssignBignum(*power_ten);
- }
-
- // numerator = significand * 2 * 10^-estimated_power
- // since v = significand * 2^exponent this is equivalent to
- // numerator = v * 10^-estimated_power * 2 * 2^-exponent.
- // Remember: numerator has been abused as power_ten. So no need to assign it
- // to itself.
- ASSERT(numerator == power_ten);
- numerator->MultiplyByUInt64(significand);
-
- // denominator = 2 * 2^-exponent with exponent < 0.
- denominator->AssignUInt16(1);
- denominator->ShiftLeft(-exponent);
-
- if (need_boundary_deltas) {
- // Introduce a common denominator so that the deltas to the boundaries are
- // integers.
- numerator->ShiftLeft(1);
- denominator->ShiftLeft(1);
- // With this shift the boundaries have their correct value, since
- // delta_plus = 10^-estimated_power, and
- // delta_minus = 10^-estimated_power.
- // These assignments have been done earlier.
- // The adjustments if f == 2^p-1 (lower boundary is closer) are done later.
- }
-}
-
-
-// Let v = significand * 2^exponent.
-// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
-// and denominator. The functions GenerateShortestDigits and
-// GenerateCountedDigits will then convert this ratio to its decimal
-// representation d, with the required accuracy.
-// Then d * 10^estimated_power is the representation of v.
-// (Note: the fraction and the estimated_power might get adjusted before
-// generating the decimal representation.)
-//
-// The initial start values consist of:
-// - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power.
-// - a scaled (common) denominator.
-// optionally (used by GenerateShortestDigits to decide if it has the shortest
-// decimal converting back to v):
-// - v - m-: the distance to the lower boundary.
-// - m+ - v: the distance to the upper boundary.
-//
-// v, m+, m-, and therefore v - m- and m+ - v all share the same denominator.
-//
-// Let ep == estimated_power, then the returned values will satisfy:
-// v / 10^ep = numerator / denominator.
-// v's boundarys m- and m+:
-// m- / 10^ep == v / 10^ep - delta_minus / denominator
-// m+ / 10^ep == v / 10^ep + delta_plus / denominator
-// Or in other words:
-// m- == v - delta_minus * 10^ep / denominator;
-// m+ == v + delta_plus * 10^ep / denominator;
-//
-// Since 10^(k-1) <= v < 10^k (with k == estimated_power)
-// or 10^k <= v < 10^(k+1)
-// we then have 0.1 <= numerator/denominator < 1
-// or 1 <= numerator/denominator < 10
-//
-// It is then easy to kickstart the digit-generation routine.
-//
-// The boundary-deltas are only filled if the mode equals BIGNUM_DTOA_SHORTEST
-// or BIGNUM_DTOA_SHORTEST_SINGLE.
-
-static void InitialScaledStartValues(uint64_t significand,
- int exponent,
- bool lower_boundary_is_closer,
- int estimated_power,
- bool need_boundary_deltas,
- Bignum* numerator,
- Bignum* denominator,
- Bignum* delta_minus,
- Bignum* delta_plus) {
- if (exponent >= 0) {
- InitialScaledStartValuesPositiveExponent(
- significand, exponent, estimated_power, need_boundary_deltas,
- numerator, denominator, delta_minus, delta_plus);
- } else if (estimated_power >= 0) {
- InitialScaledStartValuesNegativeExponentPositivePower(
- significand, exponent, estimated_power, need_boundary_deltas,
- numerator, denominator, delta_minus, delta_plus);
- } else {
- InitialScaledStartValuesNegativeExponentNegativePower(
- significand, exponent, estimated_power, need_boundary_deltas,
- numerator, denominator, delta_minus, delta_plus);
- }
-
- if (need_boundary_deltas && lower_boundary_is_closer) {
- // The lower boundary is closer at half the distance of "normal" numbers.
- // Increase the common denominator and adapt all but the delta_minus.
- denominator->ShiftLeft(1); // *2
- numerator->ShiftLeft(1); // *2
- delta_plus->ShiftLeft(1); // *2
- }
-}
-
-
-// This routine multiplies numerator/denominator so that its values lies in the
-// range 1-10. That is after a call to this function we have:
-// 1 <= (numerator + delta_plus) /denominator < 10.
-// Let numerator the input before modification and numerator' the argument
-// after modification, then the output-parameter decimal_point is such that
-// numerator / denominator * 10^estimated_power ==
-// numerator' / denominator' * 10^(decimal_point - 1)
-// In some cases estimated_power was too low, and this is already the case. We
-// then simply adjust the power so that 10^(k-1) <= v < 10^k (with k ==
-// estimated_power) but do not touch the numerator or denominator.
-// Otherwise the routine multiplies the numerator and the deltas by 10.
-static void FixupMultiply10(int estimated_power, bool is_even,
- int* decimal_point,
- Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus) {
- bool in_range;
- if (is_even) {
- // For IEEE doubles half-way cases (in decimal system numbers ending with 5)
- // are rounded to the closest floating-point number with even significand.
- in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
- } else {
- in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
- }
- if (in_range) {
- // Since numerator + delta_plus >= denominator we already have
- // 1 <= numerator/denominator < 10. Simply update the estimated_power.
- *decimal_point = estimated_power + 1;
- } else {
- *decimal_point = estimated_power;
- numerator->Times10();
- if (Bignum::Equal(*delta_minus, *delta_plus)) {
- delta_minus->Times10();
- delta_plus->AssignBignum(*delta_minus);
- } else {
- delta_minus->Times10();
- delta_plus->Times10();
- }
- }
-}
-
-} // namespace double_conversion
diff --git a/src/3rdparty/double-conversion/bignum-dtoa.h b/src/3rdparty/double-conversion/bignum-dtoa.h
deleted file mode 100644
index 34b961992d..0000000000
--- a/src/3rdparty/double-conversion/bignum-dtoa.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef DOUBLE_CONVERSION_BIGNUM_DTOA_H_
-#define DOUBLE_CONVERSION_BIGNUM_DTOA_H_
-
-#include "utils.h"
-
-namespace double_conversion {
-
-enum BignumDtoaMode {
- // Return the shortest correct representation.
- // For example the output of 0.299999999999999988897 is (the less accurate but
- // correct) 0.3.
- BIGNUM_DTOA_SHORTEST,
- // Same as BIGNUM_DTOA_SHORTEST but for single-precision floats.
- BIGNUM_DTOA_SHORTEST_SINGLE,
- // Return a fixed number of digits after the decimal point.
- // For instance fixed(0.1, 4) becomes 0.1000
- // If the input number is big, the output will be big.
- BIGNUM_DTOA_FIXED,
- // Return a fixed number of digits, no matter what the exponent is.
- BIGNUM_DTOA_PRECISION
-};
-
-// Converts the given double 'v' to ascii.
-// The result should be interpreted as buffer * 10^(point-length).
-// The buffer will be null-terminated.
-//
-// The input v must be > 0 and different from NaN, and Infinity.
-//
-// The output depends on the given mode:
-// - SHORTEST: produce the least amount of digits for which the internal
-// identity requirement is still satisfied. If the digits are printed
-// (together with the correct exponent) then reading this number will give
-// 'v' again. The buffer will choose the representation that is closest to
-// 'v'. If there are two at the same distance, than the number is round up.
-// In this mode the 'requested_digits' parameter is ignored.
-// - FIXED: produces digits necessary to print a given number with
-// 'requested_digits' digits after the decimal point. The produced digits
-// might be too short in which case the caller has to fill the gaps with '0's.
-// Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
-// Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns
-// buffer="2", point=0.
-// Note: the length of the returned buffer has no meaning wrt the significance
-// of its digits. That is, just because it contains '0's does not mean that
-// any other digit would not satisfy the internal identity requirement.
-// - PRECISION: produces 'requested_digits' where the first digit is not '0'.
-// Even though the length of produced digits usually equals
-// 'requested_digits', the function is allowed to return fewer digits, in
-// which case the caller has to fill the missing digits with '0's.
-// Halfway cases are again rounded up.
-// 'BignumDtoa' expects the given buffer to be big enough to hold all digits
-// and a terminating null-character.
-void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
- Vector<char> buffer, int* length, int* point);
-
-} // namespace double_conversion
-
-#endif // DOUBLE_CONVERSION_BIGNUM_DTOA_H_
diff --git a/src/3rdparty/double-conversion/bignum.cc b/src/3rdparty/double-conversion/bignum.cc
deleted file mode 100644
index 2743d67e8d..0000000000
--- a/src/3rdparty/double-conversion/bignum.cc
+++ /dev/null
@@ -1,766 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "bignum.h"
-#include "utils.h"
-
-namespace double_conversion {
-
-Bignum::Bignum()
- : bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) {
- for (int i = 0; i < kBigitCapacity; ++i) {
- bigits_[i] = 0;
- }
-}
-
-
-template<typename S>
-static int BitSize(S value) {
- (void) value; // Mark variable as used.
- return 8 * sizeof(value);
-}
-
-// Guaranteed to lie in one Bigit.
-void Bignum::AssignUInt16(uint16_t value) {
- ASSERT(kBigitSize >= BitSize(value));
- Zero();
- if (value == 0) return;
-
- EnsureCapacity(1);
- bigits_[0] = value;
- used_digits_ = 1;
-}
-
-
-void Bignum::AssignUInt64(uint64_t value) {
- const int kUInt64Size = 64;
-
- Zero();
- if (value == 0) return;
-
- int needed_bigits = kUInt64Size / kBigitSize + 1;
- EnsureCapacity(needed_bigits);
- for (int i = 0; i < needed_bigits; ++i) {
- bigits_[i] = value & kBigitMask;
- value = value >> kBigitSize;
- }
- used_digits_ = needed_bigits;
- Clamp();
-}
-
-
-void Bignum::AssignBignum(const Bignum& other) {
- exponent_ = other.exponent_;
- for (int i = 0; i < other.used_digits_; ++i) {
- bigits_[i] = other.bigits_[i];
- }
- // Clear the excess digits (if there were any).
- for (int i = other.used_digits_; i < used_digits_; ++i) {
- bigits_[i] = 0;
- }
- used_digits_ = other.used_digits_;
-}
-
-
-static uint64_t ReadUInt64(Vector<const char> buffer,
- int from,
- int digits_to_read) {
- uint64_t result = 0;
- for (int i = from; i < from + digits_to_read; ++i) {
- int digit = buffer[i] - '0';
- ASSERT(0 <= digit && digit <= 9);
- result = result * 10 + digit;
- }
- return result;
-}
-
-
-void Bignum::AssignDecimalString(Vector<const char> value) {
- // 2^64 = 18446744073709551616 > 10^19
- const int kMaxUint64DecimalDigits = 19;
- Zero();
- int length = value.length();
- int pos = 0;
- // Let's just say that each digit needs 4 bits.
- while (length >= kMaxUint64DecimalDigits) {
- uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits);
- pos += kMaxUint64DecimalDigits;
- length -= kMaxUint64DecimalDigits;
- MultiplyByPowerOfTen(kMaxUint64DecimalDigits);
- AddUInt64(digits);
- }
- uint64_t digits = ReadUInt64(value, pos, length);
- MultiplyByPowerOfTen(length);
- AddUInt64(digits);
- Clamp();
-}
-
-
-static int HexCharValue(char c) {
- if ('0' <= c && c <= '9') return c - '0';
- if ('a' <= c && c <= 'f') return 10 + c - 'a';
- ASSERT('A' <= c && c <= 'F');
- return 10 + c - 'A';
-}
-
-
-void Bignum::AssignHexString(Vector<const char> value) {
- Zero();
- int length = value.length();
-
- int needed_bigits = length * 4 / kBigitSize + 1;
- EnsureCapacity(needed_bigits);
- int string_index = length - 1;
- for (int i = 0; i < needed_bigits - 1; ++i) {
- // These bigits are guaranteed to be "full".
- Chunk current_bigit = 0;
- for (int j = 0; j < kBigitSize / 4; j++) {
- current_bigit += HexCharValue(value[string_index--]) << (j * 4);
- }
- bigits_[i] = current_bigit;
- }
- used_digits_ = needed_bigits - 1;
-
- Chunk most_significant_bigit = 0; // Could be = 0;
- for (int j = 0; j <= string_index; ++j) {
- most_significant_bigit <<= 4;
- most_significant_bigit += HexCharValue(value[j]);
- }
- if (most_significant_bigit != 0) {
- bigits_[used_digits_] = most_significant_bigit;
- used_digits_++;
- }
- Clamp();
-}
-
-
-void Bignum::AddUInt64(uint64_t operand) {
- if (operand == 0) return;
- Bignum other;
- other.AssignUInt64(operand);
- AddBignum(other);
-}
-
-
-void Bignum::AddBignum(const Bignum& other) {
- ASSERT(IsClamped());
- ASSERT(other.IsClamped());
-
- // If this has a greater exponent than other append zero-bigits to this.
- // After this call exponent_ <= other.exponent_.
- Align(other);
-
- // There are two possibilities:
- // aaaaaaaaaaa 0000 (where the 0s represent a's exponent)
- // bbbbb 00000000
- // ----------------
- // ccccccccccc 0000
- // or
- // aaaaaaaaaa 0000
- // bbbbbbbbb 0000000
- // -----------------
- // cccccccccccc 0000
- // In both cases we might need a carry bigit.
-
- EnsureCapacity(1 + Max(BigitLength(), other.BigitLength()) - exponent_);
- Chunk carry = 0;
- int bigit_pos = other.exponent_ - exponent_;
- ASSERT(bigit_pos >= 0);
- for (int i = 0; i < other.used_digits_; ++i) {
- Chunk sum = bigits_[bigit_pos] + other.bigits_[i] + carry;
- bigits_[bigit_pos] = sum & kBigitMask;
- carry = sum >> kBigitSize;
- bigit_pos++;
- }
-
- while (carry != 0) {
- Chunk sum = bigits_[bigit_pos] + carry;
- bigits_[bigit_pos] = sum & kBigitMask;
- carry = sum >> kBigitSize;
- bigit_pos++;
- }
- used_digits_ = Max(bigit_pos, used_digits_);
- ASSERT(IsClamped());
-}
-
-
-void Bignum::SubtractBignum(const Bignum& other) {
- ASSERT(IsClamped());
- ASSERT(other.IsClamped());
- // We require this to be bigger than other.
- ASSERT(LessEqual(other, *this));
-
- Align(other);
-
- int offset = other.exponent_ - exponent_;
- Chunk borrow = 0;
- int i;
- for (i = 0; i < other.used_digits_; ++i) {
- ASSERT((borrow == 0) || (borrow == 1));
- Chunk difference = bigits_[i + offset] - other.bigits_[i] - borrow;
- bigits_[i + offset] = difference & kBigitMask;
- borrow = difference >> (kChunkSize - 1);
- }
- while (borrow != 0) {
- Chunk difference = bigits_[i + offset] - borrow;
- bigits_[i + offset] = difference & kBigitMask;
- borrow = difference >> (kChunkSize - 1);
- ++i;
- }
- Clamp();
-}
-
-
-void Bignum::ShiftLeft(int shift_amount) {
- if (used_digits_ == 0) return;
- exponent_ += shift_amount / kBigitSize;
- int local_shift = shift_amount % kBigitSize;
- EnsureCapacity(used_digits_ + 1);
- BigitsShiftLeft(local_shift);
-}
-
-
-void Bignum::MultiplyByUInt32(uint32_t factor) {
- if (factor == 1) return;
- if (factor == 0) {
- Zero();
- return;
- }
- if (used_digits_ == 0) return;
-
- // The product of a bigit with the factor is of size kBigitSize + 32.
- // Assert that this number + 1 (for the carry) fits into double chunk.
- ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1);
- DoubleChunk carry = 0;
- for (int i = 0; i < used_digits_; ++i) {
- DoubleChunk product = static_cast<DoubleChunk>(factor) * bigits_[i] + carry;
- bigits_[i] = static_cast<Chunk>(product & kBigitMask);
- carry = (product >> kBigitSize);
- }
- while (carry != 0) {
- EnsureCapacity(used_digits_ + 1);
- bigits_[used_digits_] = carry & kBigitMask;
- used_digits_++;
- carry >>= kBigitSize;
- }
-}
-
-
-void Bignum::MultiplyByUInt64(uint64_t factor) {
- if (factor == 1) return;
- if (factor == 0) {
- Zero();
- return;
- }
- ASSERT(kBigitSize < 32);
- uint64_t carry = 0;
- uint64_t low = factor & 0xFFFFFFFF;
- uint64_t high = factor >> 32;
- for (int i = 0; i < used_digits_; ++i) {
- uint64_t product_low = low * bigits_[i];
- uint64_t product_high = high * bigits_[i];
- uint64_t tmp = (carry & kBigitMask) + product_low;
- bigits_[i] = tmp & kBigitMask;
- carry = (carry >> kBigitSize) + (tmp >> kBigitSize) +
- (product_high << (32 - kBigitSize));
- }
- while (carry != 0) {
- EnsureCapacity(used_digits_ + 1);
- bigits_[used_digits_] = carry & kBigitMask;
- used_digits_++;
- carry >>= kBigitSize;
- }
-}
-
-
-void Bignum::MultiplyByPowerOfTen(int exponent) {
- const uint64_t kFive27 = UINT64_2PART_C(0x6765c793, fa10079d);
- const uint16_t kFive1 = 5;
- const uint16_t kFive2 = kFive1 * 5;
- const uint16_t kFive3 = kFive2 * 5;
- const uint16_t kFive4 = kFive3 * 5;
- const uint16_t kFive5 = kFive4 * 5;
- const uint16_t kFive6 = kFive5 * 5;
- const uint32_t kFive7 = kFive6 * 5;
- const uint32_t kFive8 = kFive7 * 5;
- const uint32_t kFive9 = kFive8 * 5;
- const uint32_t kFive10 = kFive9 * 5;
- const uint32_t kFive11 = kFive10 * 5;
- const uint32_t kFive12 = kFive11 * 5;
- const uint32_t kFive13 = kFive12 * 5;
- const uint32_t kFive1_to_12[] =
- { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6,
- kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 };
-
- ASSERT(exponent >= 0);
- if (exponent == 0) return;
- if (used_digits_ == 0) return;
-
- // We shift by exponent at the end just before returning.
- int remaining_exponent = exponent;
- while (remaining_exponent >= 27) {
- MultiplyByUInt64(kFive27);
- remaining_exponent -= 27;
- }
- while (remaining_exponent >= 13) {
- MultiplyByUInt32(kFive13);
- remaining_exponent -= 13;
- }
- if (remaining_exponent > 0) {
- MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]);
- }
- ShiftLeft(exponent);
-}
-
-
-void Bignum::Square() {
- ASSERT(IsClamped());
- int product_length = 2 * used_digits_;
- EnsureCapacity(product_length);
-
- // Comba multiplication: compute each column separately.
- // Example: r = a2a1a0 * b2b1b0.
- // r = 1 * a0b0 +
- // 10 * (a1b0 + a0b1) +
- // 100 * (a2b0 + a1b1 + a0b2) +
- // 1000 * (a2b1 + a1b2) +
- // 10000 * a2b2
- //
- // In the worst case we have to accumulate nb-digits products of digit*digit.
- //
- // Assert that the additional number of bits in a DoubleChunk are enough to
- // sum up used_digits of Bigit*Bigit.
- if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_digits_) {
- UNIMPLEMENTED();
- }
- DoubleChunk accumulator = 0;
- // First shift the digits so we don't overwrite them.
- int copy_offset = used_digits_;
- for (int i = 0; i < used_digits_; ++i) {
- bigits_[copy_offset + i] = bigits_[i];
- }
- // We have two loops to avoid some 'if's in the loop.
- for (int i = 0; i < used_digits_; ++i) {
- // Process temporary digit i with power i.
- // The sum of the two indices must be equal to i.
- int bigit_index1 = i;
- int bigit_index2 = 0;
- // Sum all of the sub-products.
- while (bigit_index1 >= 0) {
- Chunk chunk1 = bigits_[copy_offset + bigit_index1];
- Chunk chunk2 = bigits_[copy_offset + bigit_index2];
- accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
- bigit_index1--;
- bigit_index2++;
- }
- bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;
- accumulator >>= kBigitSize;
- }
- for (int i = used_digits_; i < product_length; ++i) {
- int bigit_index1 = used_digits_ - 1;
- int bigit_index2 = i - bigit_index1;
- // Invariant: sum of both indices is again equal to i.
- // Inner loop runs 0 times on last iteration, emptying accumulator.
- while (bigit_index2 < used_digits_) {
- Chunk chunk1 = bigits_[copy_offset + bigit_index1];
- Chunk chunk2 = bigits_[copy_offset + bigit_index2];
- accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
- bigit_index1--;
- bigit_index2++;
- }
- // The overwritten bigits_[i] will never be read in further loop iterations,
- // because bigit_index1 and bigit_index2 are always greater
- // than i - used_digits_.
- bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;
- accumulator >>= kBigitSize;
- }
- // Since the result was guaranteed to lie inside the number the
- // accumulator must be 0 now.
- ASSERT(accumulator == 0);
-
- // Don't forget to update the used_digits and the exponent.
- used_digits_ = product_length;
- exponent_ *= 2;
- Clamp();
-}
-
-
-void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) {
- ASSERT(base != 0);
- ASSERT(power_exponent >= 0);
- if (power_exponent == 0) {
- AssignUInt16(1);
- return;
- }
- Zero();
- int shifts = 0;
- // We expect base to be in range 2-32, and most often to be 10.
- // It does not make much sense to implement different algorithms for counting
- // the bits.
- while ((base & 1) == 0) {
- base >>= 1;
- shifts++;
- }
- int bit_size = 0;
- int tmp_base = base;
- while (tmp_base != 0) {
- tmp_base >>= 1;
- bit_size++;
- }
- int final_size = bit_size * power_exponent;
- // 1 extra bigit for the shifting, and one for rounded final_size.
- EnsureCapacity(final_size / kBigitSize + 2);
-
- // Left to Right exponentiation.
- int mask = 1;
- while (power_exponent >= mask) mask <<= 1;
-
- // The mask is now pointing to the bit above the most significant 1-bit of
- // power_exponent.
- // Get rid of first 1-bit;
- mask >>= 2;
- uint64_t this_value = base;
-
- bool delayed_multipliciation = false;
- const uint64_t max_32bits = 0xFFFFFFFF;
- while (mask != 0 && this_value <= max_32bits) {
- this_value = this_value * this_value;
- // Verify that there is enough space in this_value to perform the
- // multiplication. The first bit_size bits must be 0.
- if ((power_exponent & mask) != 0) {
- uint64_t base_bits_mask =
- ~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);
- bool high_bits_zero = (this_value & base_bits_mask) == 0;
- if (high_bits_zero) {
- this_value *= base;
- } else {
- delayed_multipliciation = true;
- }
- }
- mask >>= 1;
- }
- AssignUInt64(this_value);
- if (delayed_multipliciation) {
- MultiplyByUInt32(base);
- }
-
- // Now do the same thing as a bignum.
- while (mask != 0) {
- Square();
- if ((power_exponent & mask) != 0) {
- MultiplyByUInt32(base);
- }
- mask >>= 1;
- }
-
- // And finally add the saved shifts.
- ShiftLeft(shifts * power_exponent);
-}
-
-
-// Precondition: this/other < 16bit.
-uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) {
- ASSERT(IsClamped());
- ASSERT(other.IsClamped());
- ASSERT(other.used_digits_ > 0);
-
- // Easy case: if we have less digits than the divisor than the result is 0.
- // Note: this handles the case where this == 0, too.
- if (BigitLength() < other.BigitLength()) {
- return 0;
- }
-
- Align(other);
-
- uint16_t result = 0;
-
- // Start by removing multiples of 'other' until both numbers have the same
- // number of digits.
- while (BigitLength() > other.BigitLength()) {
- // This naive approach is extremely inefficient if `this` divided by other
- // is big. This function is implemented for doubleToString where
- // the result should be small (less than 10).
- ASSERT(other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16));
- ASSERT(bigits_[used_digits_ - 1] < 0x10000);
- // Remove the multiples of the first digit.
- // Example this = 23 and other equals 9. -> Remove 2 multiples.
- result += static_cast<uint16_t>(bigits_[used_digits_ - 1]);
- SubtractTimes(other, bigits_[used_digits_ - 1]);
- }
-
- ASSERT(BigitLength() == other.BigitLength());
-
- // Both bignums are at the same length now.
- // Since other has more than 0 digits we know that the access to
- // bigits_[used_digits_ - 1] is safe.
- Chunk this_bigit = bigits_[used_digits_ - 1];
- Chunk other_bigit = other.bigits_[other.used_digits_ - 1];
-
- if (other.used_digits_ == 1) {
- // Shortcut for easy (and common) case.
- int quotient = this_bigit / other_bigit;
- bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient;
- ASSERT(quotient < 0x10000);
- result += static_cast<uint16_t>(quotient);
- Clamp();
- return result;
- }
-
- int division_estimate = this_bigit / (other_bigit + 1);
- ASSERT(division_estimate < 0x10000);
- result += static_cast<uint16_t>(division_estimate);
- SubtractTimes(other, division_estimate);
-
- if (other_bigit * (division_estimate + 1) > this_bigit) {
- // No need to even try to subtract. Even if other's remaining digits were 0
- // another subtraction would be too much.
- return result;
- }
-
- while (LessEqual(other, *this)) {
- SubtractBignum(other);
- result++;
- }
- return result;
-}
-
-
-template<typename S>
-static int SizeInHexChars(S number) {
- ASSERT(number > 0);
- int result = 0;
- while (number != 0) {
- number >>= 4;
- result++;
- }
- return result;
-}
-
-
-static char HexCharOfValue(int value) {
- ASSERT(0 <= value && value <= 16);
- if (value < 10) return static_cast<char>(value + '0');
- return static_cast<char>(value - 10 + 'A');
-}
-
-
-bool Bignum::ToHexString(char* buffer, int buffer_size) const {
- ASSERT(IsClamped());
- // Each bigit must be printable as separate hex-character.
- ASSERT(kBigitSize % 4 == 0);
- const int kHexCharsPerBigit = kBigitSize / 4;
-
- if (used_digits_ == 0) {
- if (buffer_size < 2) return false;
- buffer[0] = '0';
- buffer[1] = '\0';
- return true;
- }
- // We add 1 for the terminating '\0' character.
- int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit +
- SizeInHexChars(bigits_[used_digits_ - 1]) + 1;
- if (needed_chars > buffer_size) return false;
- int string_index = needed_chars - 1;
- buffer[string_index--] = '\0';
- for (int i = 0; i < exponent_; ++i) {
- for (int j = 0; j < kHexCharsPerBigit; ++j) {
- buffer[string_index--] = '0';
- }
- }
- for (int i = 0; i < used_digits_ - 1; ++i) {
- Chunk current_bigit = bigits_[i];
- for (int j = 0; j < kHexCharsPerBigit; ++j) {
- buffer[string_index--] = HexCharOfValue(current_bigit & 0xF);
- current_bigit >>= 4;
- }
- }
- // And finally the last bigit.
- Chunk most_significant_bigit = bigits_[used_digits_ - 1];
- while (most_significant_bigit != 0) {
- buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF);
- most_significant_bigit >>= 4;
- }
- return true;
-}
-
-
-Bignum::Chunk Bignum::BigitAt(int index) const {
- if (index >= BigitLength()) return 0;
- if (index < exponent_) return 0;
- return bigits_[index - exponent_];
-}
-
-
-int Bignum::Compare(const Bignum& a, const Bignum& b) {
- ASSERT(a.IsClamped());
- ASSERT(b.IsClamped());
- int bigit_length_a = a.BigitLength();
- int bigit_length_b = b.BigitLength();
- if (bigit_length_a < bigit_length_b) return -1;
- if (bigit_length_a > bigit_length_b) return +1;
- for (int i = bigit_length_a - 1; i >= Min(a.exponent_, b.exponent_); --i) {
- Chunk bigit_a = a.BigitAt(i);
- Chunk bigit_b = b.BigitAt(i);
- if (bigit_a < bigit_b) return -1;
- if (bigit_a > bigit_b) return +1;
- // Otherwise they are equal up to this digit. Try the next digit.
- }
- return 0;
-}
-
-
-int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) {
- ASSERT(a.IsClamped());
- ASSERT(b.IsClamped());
- ASSERT(c.IsClamped());
- if (a.BigitLength() < b.BigitLength()) {
- return PlusCompare(b, a, c);
- }
- if (a.BigitLength() + 1 < c.BigitLength()) return -1;
- if (a.BigitLength() > c.BigitLength()) return +1;
- // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than
- // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one
- // of 'a'.
- if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) {
- return -1;
- }
-
- Chunk borrow = 0;
- // Starting at min_exponent all digits are == 0. So no need to compare them.
- int min_exponent = Min(Min(a.exponent_, b.exponent_), c.exponent_);
- for (int i = c.BigitLength() - 1; i >= min_exponent; --i) {
- Chunk chunk_a = a.BigitAt(i);
- Chunk chunk_b = b.BigitAt(i);
- Chunk chunk_c = c.BigitAt(i);
- Chunk sum = chunk_a + chunk_b;
- if (sum > chunk_c + borrow) {
- return +1;
- } else {
- borrow = chunk_c + borrow - sum;
- if (borrow > 1) return -1;
- borrow <<= kBigitSize;
- }
- }
- if (borrow == 0) return 0;
- return -1;
-}
-
-
-void Bignum::Clamp() {
- while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) {
- used_digits_--;
- }
- if (used_digits_ == 0) {
- // Zero.
- exponent_ = 0;
- }
-}
-
-
-bool Bignum::IsClamped() const {
- return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0;
-}
-
-
-void Bignum::Zero() {
- for (int i = 0; i < used_digits_; ++i) {
- bigits_[i] = 0;
- }
- used_digits_ = 0;
- exponent_ = 0;
-}
-
-
-void Bignum::Align(const Bignum& other) {
- if (exponent_ > other.exponent_) {
- // If "X" represents a "hidden" digit (by the exponent) then we are in the
- // following case (a == this, b == other):
- // a: aaaaaaXXXX or a: aaaaaXXX
- // b: bbbbbbX b: bbbbbbbbXX
- // We replace some of the hidden digits (X) of a with 0 digits.
- // a: aaaaaa000X or a: aaaaa0XX
- int zero_digits = exponent_ - other.exponent_;
- EnsureCapacity(used_digits_ + zero_digits);
- for (int i = used_digits_ - 1; i >= 0; --i) {
- bigits_[i + zero_digits] = bigits_[i];
- }
- for (int i = 0; i < zero_digits; ++i) {
- bigits_[i] = 0;
- }
- used_digits_ += zero_digits;
- exponent_ -= zero_digits;
- ASSERT(used_digits_ >= 0);
- ASSERT(exponent_ >= 0);
- }
-}
-
-
-void Bignum::BigitsShiftLeft(int shift_amount) {
- ASSERT(shift_amount < kBigitSize);
- ASSERT(shift_amount >= 0);
- Chunk carry = 0;
- for (int i = 0; i < used_digits_; ++i) {
- Chunk new_carry = bigits_[i] >> (kBigitSize - shift_amount);
- bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask;
- carry = new_carry;
- }
- if (carry != 0) {
- bigits_[used_digits_] = carry;
- used_digits_++;
- }
-}
-
-
-void Bignum::SubtractTimes(const Bignum& other, int factor) {
- ASSERT(exponent_ <= other.exponent_);
- if (factor < 3) {
- for (int i = 0; i < factor; ++i) {
- SubtractBignum(other);
- }
- return;
- }
- Chunk borrow = 0;
- int exponent_diff = other.exponent_ - exponent_;
- for (int i = 0; i < other.used_digits_; ++i) {
- DoubleChunk product = static_cast<DoubleChunk>(factor) * other.bigits_[i];
- DoubleChunk remove = borrow + product;
- Chunk difference = bigits_[i + exponent_diff] - (remove & kBigitMask);
- bigits_[i + exponent_diff] = difference & kBigitMask;
- borrow = static_cast<Chunk>((difference >> (kChunkSize - 1)) +
- (remove >> kBigitSize));
- }
- for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) {
- if (borrow == 0) return;
- Chunk difference = bigits_[i] - borrow;
- bigits_[i] = difference & kBigitMask;
- borrow = difference >> (kChunkSize - 1);
- }
- Clamp();
-}
-
-
-} // namespace double_conversion
diff --git a/src/3rdparty/double-conversion/bignum.h b/src/3rdparty/double-conversion/bignum.h
deleted file mode 100644
index 5ec3544f57..0000000000
--- a/src/3rdparty/double-conversion/bignum.h
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef DOUBLE_CONVERSION_BIGNUM_H_
-#define DOUBLE_CONVERSION_BIGNUM_H_
-
-#include "utils.h"
-
-namespace double_conversion {
-
-class Bignum {
- public:
- // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately.
- // This bignum can encode much bigger numbers, since it contains an
- // exponent.
- static const int kMaxSignificantBits = 3584;
-
- Bignum();
- void AssignUInt16(uint16_t value);
- void AssignUInt64(uint64_t value);
- void AssignBignum(const Bignum& other);
-
- void AssignDecimalString(Vector<const char> value);
- void AssignHexString(Vector<const char> value);
-
- void AssignPowerUInt16(uint16_t base, int exponent);
-
- void AddUInt16(uint16_t operand);
- void AddUInt64(uint64_t operand);
- void AddBignum(const Bignum& other);
- // Precondition: this >= other.
- void SubtractBignum(const Bignum& other);
-
- void Square();
- void ShiftLeft(int shift_amount);
- void MultiplyByUInt32(uint32_t factor);
- void MultiplyByUInt64(uint64_t factor);
- void MultiplyByPowerOfTen(int exponent);
- void Times10() { return MultiplyByUInt32(10); }
- // Pseudocode:
- // int result = this / other;
- // this = this % other;
- // In the worst case this function is in O(this/other).
- uint16_t DivideModuloIntBignum(const Bignum& other);
-
- bool ToHexString(char* buffer, int buffer_size) const;
-
- // Returns
- // -1 if a < b,
- // 0 if a == b, and
- // +1 if a > b.
- static int Compare(const Bignum& a, const Bignum& b);
- static bool Equal(const Bignum& a, const Bignum& b) {
- return Compare(a, b) == 0;
- }
- static bool LessEqual(const Bignum& a, const Bignum& b) {
- return Compare(a, b) <= 0;
- }
- static bool Less(const Bignum& a, const Bignum& b) {
- return Compare(a, b) < 0;
- }
- // Returns Compare(a + b, c);
- static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c);
- // Returns a + b == c
- static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
- return PlusCompare(a, b, c) == 0;
- }
- // Returns a + b <= c
- static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
- return PlusCompare(a, b, c) <= 0;
- }
- // Returns a + b < c
- static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) {
- return PlusCompare(a, b, c) < 0;
- }
- private:
- typedef uint32_t Chunk;
- typedef uint64_t DoubleChunk;
-
- static const int kChunkSize = sizeof(Chunk) * 8;
- static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8;
- // With bigit size of 28 we loose some bits, but a double still fits easily
- // into two chunks, and more importantly we can use the Comba multiplication.
- static const int kBigitSize = 28;
- static const Chunk kBigitMask = (1 << kBigitSize) - 1;
- // Every instance allocates kBigitLength chunks on the stack. Bignums cannot
- // grow. There are no checks if the stack-allocated space is sufficient.
- static const int kBigitCapacity = kMaxSignificantBits / kBigitSize;
-
- void EnsureCapacity(int size) {
- if (size > kBigitCapacity) {
- UNREACHABLE();
- }
- }
- void Align(const Bignum& other);
- void Clamp();
- bool IsClamped() const;
- void Zero();
- // Requires this to have enough capacity (no tests done).
- // Updates used_digits_ if necessary.
- // shift_amount must be < kBigitSize.
- void BigitsShiftLeft(int shift_amount);
- // BigitLength includes the "hidden" digits encoded in the exponent.
- int BigitLength() const { return used_digits_ + exponent_; }
- Chunk BigitAt(int index) const;
- void SubtractTimes(const Bignum& other, int factor);
-
- Chunk bigits_buffer_[kBigitCapacity];
- // A vector backed by bigits_buffer_. This way accesses to the array are
- // checked for out-of-bounds errors.
- Vector<Chunk> bigits_;
- int used_digits_;
- // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize).
- int exponent_;
-
- DISALLOW_COPY_AND_ASSIGN(Bignum);
-};
-
-} // namespace double_conversion
-
-#endif // DOUBLE_CONVERSION_BIGNUM_H_
diff --git a/src/3rdparty/double-conversion/cached-powers.cc b/src/3rdparty/double-conversion/cached-powers.cc
deleted file mode 100644
index 9536f26927..0000000000
--- a/src/3rdparty/double-conversion/cached-powers.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <stdarg.h>
-#include <limits.h>
-#include <math.h>
-
-#include "utils.h"
-
-#include "cached-powers.h"
-
-namespace double_conversion {
-
-struct CachedPower {
- uint64_t significand;
- int16_t binary_exponent;
- int16_t decimal_exponent;
-};
-
-static const CachedPower kCachedPowers[] = {
- {UINT64_2PART_C(0xfa8fd5a0, 081c0288), -1220, -348},
- {UINT64_2PART_C(0xbaaee17f, a23ebf76), -1193, -340},
- {UINT64_2PART_C(0x8b16fb20, 3055ac76), -1166, -332},
- {UINT64_2PART_C(0xcf42894a, 5dce35ea), -1140, -324},
- {UINT64_2PART_C(0x9a6bb0aa, 55653b2d), -1113, -316},
- {UINT64_2PART_C(0xe61acf03, 3d1a45df), -1087, -308},
- {UINT64_2PART_C(0xab70fe17, c79ac6ca), -1060, -300},
- {UINT64_2PART_C(0xff77b1fc, bebcdc4f), -1034, -292},
- {UINT64_2PART_C(0xbe5691ef, 416bd60c), -1007, -284},
- {UINT64_2PART_C(0x8dd01fad, 907ffc3c), -980, -276},
- {UINT64_2PART_C(0xd3515c28, 31559a83), -954, -268},
- {UINT64_2PART_C(0x9d71ac8f, ada6c9b5), -927, -260},
- {UINT64_2PART_C(0xea9c2277, 23ee8bcb), -901, -252},
- {UINT64_2PART_C(0xaecc4991, 4078536d), -874, -244},
- {UINT64_2PART_C(0x823c1279, 5db6ce57), -847, -236},
- {UINT64_2PART_C(0xc2109436, 4dfb5637), -821, -228},
- {UINT64_2PART_C(0x9096ea6f, 3848984f), -794, -220},
- {UINT64_2PART_C(0xd77485cb, 25823ac7), -768, -212},
- {UINT64_2PART_C(0xa086cfcd, 97bf97f4), -741, -204},
- {UINT64_2PART_C(0xef340a98, 172aace5), -715, -196},
- {UINT64_2PART_C(0xb23867fb, 2a35b28e), -688, -188},
- {UINT64_2PART_C(0x84c8d4df, d2c63f3b), -661, -180},
- {UINT64_2PART_C(0xc5dd4427, 1ad3cdba), -635, -172},
- {UINT64_2PART_C(0x936b9fce, bb25c996), -608, -164},
- {UINT64_2PART_C(0xdbac6c24, 7d62a584), -582, -156},
- {UINT64_2PART_C(0xa3ab6658, 0d5fdaf6), -555, -148},
- {UINT64_2PART_C(0xf3e2f893, dec3f126), -529, -140},
- {UINT64_2PART_C(0xb5b5ada8, aaff80b8), -502, -132},
- {UINT64_2PART_C(0x87625f05, 6c7c4a8b), -475, -124},
- {UINT64_2PART_C(0xc9bcff60, 34c13053), -449, -116},
- {UINT64_2PART_C(0x964e858c, 91ba2655), -422, -108},
- {UINT64_2PART_C(0xdff97724, 70297ebd), -396, -100},
- {UINT64_2PART_C(0xa6dfbd9f, b8e5b88f), -369, -92},
- {UINT64_2PART_C(0xf8a95fcf, 88747d94), -343, -84},
- {UINT64_2PART_C(0xb9447093, 8fa89bcf), -316, -76},
- {UINT64_2PART_C(0x8a08f0f8, bf0f156b), -289, -68},
- {UINT64_2PART_C(0xcdb02555, 653131b6), -263, -60},
- {UINT64_2PART_C(0x993fe2c6, d07b7fac), -236, -52},
- {UINT64_2PART_C(0xe45c10c4, 2a2b3b06), -210, -44},
- {UINT64_2PART_C(0xaa242499, 697392d3), -183, -36},
- {UINT64_2PART_C(0xfd87b5f2, 8300ca0e), -157, -28},
- {UINT64_2PART_C(0xbce50864, 92111aeb), -130, -20},
- {UINT64_2PART_C(0x8cbccc09, 6f5088cc), -103, -12},
- {UINT64_2PART_C(0xd1b71758, e219652c), -77, -4},
- {UINT64_2PART_C(0x9c400000, 00000000), -50, 4},
- {UINT64_2PART_C(0xe8d4a510, 00000000), -24, 12},
- {UINT64_2PART_C(0xad78ebc5, ac620000), 3, 20},
- {UINT64_2PART_C(0x813f3978, f8940984), 30, 28},
- {UINT64_2PART_C(0xc097ce7b, c90715b3), 56, 36},
- {UINT64_2PART_C(0x8f7e32ce, 7bea5c70), 83, 44},
- {UINT64_2PART_C(0xd5d238a4, abe98068), 109, 52},
- {UINT64_2PART_C(0x9f4f2726, 179a2245), 136, 60},
- {UINT64_2PART_C(0xed63a231, d4c4fb27), 162, 68},
- {UINT64_2PART_C(0xb0de6538, 8cc8ada8), 189, 76},
- {UINT64_2PART_C(0x83c7088e, 1aab65db), 216, 84},
- {UINT64_2PART_C(0xc45d1df9, 42711d9a), 242, 92},
- {UINT64_2PART_C(0x924d692c, a61be758), 269, 100},
- {UINT64_2PART_C(0xda01ee64, 1a708dea), 295, 108},
- {UINT64_2PART_C(0xa26da399, 9aef774a), 322, 116},
- {UINT64_2PART_C(0xf209787b, b47d6b85), 348, 124},
- {UINT64_2PART_C(0xb454e4a1, 79dd1877), 375, 132},
- {UINT64_2PART_C(0x865b8692, 5b9bc5c2), 402, 140},
- {UINT64_2PART_C(0xc83553c5, c8965d3d), 428, 148},
- {UINT64_2PART_C(0x952ab45c, fa97a0b3), 455, 156},
- {UINT64_2PART_C(0xde469fbd, 99a05fe3), 481, 164},
- {UINT64_2PART_C(0xa59bc234, db398c25), 508, 172},
- {UINT64_2PART_C(0xf6c69a72, a3989f5c), 534, 180},
- {UINT64_2PART_C(0xb7dcbf53, 54e9bece), 561, 188},
- {UINT64_2PART_C(0x88fcf317, f22241e2), 588, 196},
- {UINT64_2PART_C(0xcc20ce9b, d35c78a5), 614, 204},
- {UINT64_2PART_C(0x98165af3, 7b2153df), 641, 212},
- {UINT64_2PART_C(0xe2a0b5dc, 971f303a), 667, 220},
- {UINT64_2PART_C(0xa8d9d153, 5ce3b396), 694, 228},
- {UINT64_2PART_C(0xfb9b7cd9, a4a7443c), 720, 236},
- {UINT64_2PART_C(0xbb764c4c, a7a44410), 747, 244},
- {UINT64_2PART_C(0x8bab8eef, b6409c1a), 774, 252},
- {UINT64_2PART_C(0xd01fef10, a657842c), 800, 260},
- {UINT64_2PART_C(0x9b10a4e5, e9913129), 827, 268},
- {UINT64_2PART_C(0xe7109bfb, a19c0c9d), 853, 276},
- {UINT64_2PART_C(0xac2820d9, 623bf429), 880, 284},
- {UINT64_2PART_C(0x80444b5e, 7aa7cf85), 907, 292},
- {UINT64_2PART_C(0xbf21e440, 03acdd2d), 933, 300},
- {UINT64_2PART_C(0x8e679c2f, 5e44ff8f), 960, 308},
- {UINT64_2PART_C(0xd433179d, 9c8cb841), 986, 316},
- {UINT64_2PART_C(0x9e19db92, b4e31ba9), 1013, 324},
- {UINT64_2PART_C(0xeb96bf6e, badf77d9), 1039, 332},
- {UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340},
-};
-
-static const int kCachedPowersLength = ARRAY_SIZE(kCachedPowers);
-static const int kCachedPowersOffset = 348; // -1 * the first decimal_exponent.
-static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10)
-// Difference between the decimal exponents in the table above.
-const int PowersOfTenCache::kDecimalExponentDistance = 8;
-const int PowersOfTenCache::kMinDecimalExponent = -348;
-const int PowersOfTenCache::kMaxDecimalExponent = 340;
-
-void PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
- int min_exponent,
- int max_exponent,
- DiyFp* power,
- int* decimal_exponent) {
- (void)max_exponent; // Silence unused parameter warning in release builds
- (void)kCachedPowersLength; // Silence unused parameter warning in release builds
- int kQ = DiyFp::kSignificandSize;
- double k = ceil((min_exponent + kQ - 1) * kD_1_LOG2_10);
- int foo = kCachedPowersOffset;
- int index =
- (foo + static_cast<int>(k) - 1) / kDecimalExponentDistance + 1;
- ASSERT(0 <= index && index < kCachedPowersLength);
- CachedPower cached_power = kCachedPowers[index];
- ASSERT(min_exponent <= cached_power.binary_exponent);
- (void) max_exponent; // Mark variable as used.
- ASSERT(cached_power.binary_exponent <= max_exponent);
- *decimal_exponent = cached_power.decimal_exponent;
- *power = DiyFp(cached_power.significand, cached_power.binary_exponent);
-}
-
-
-void PowersOfTenCache::GetCachedPowerForDecimalExponent(int requested_exponent,
- DiyFp* power,
- int* found_exponent) {
- ASSERT(kMinDecimalExponent <= requested_exponent);
- ASSERT(requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance);
- int index =
- (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance;
- CachedPower cached_power = kCachedPowers[index];
- *power = DiyFp(cached_power.significand, cached_power.binary_exponent);
- *found_exponent = cached_power.decimal_exponent;
- ASSERT(*found_exponent <= requested_exponent);
- ASSERT(requested_exponent < *found_exponent + kDecimalExponentDistance);
-}
-
-} // namespace double_conversion
diff --git a/src/3rdparty/double-conversion/cached-powers.h b/src/3rdparty/double-conversion/cached-powers.h
deleted file mode 100644
index 61a50614cf..0000000000
--- a/src/3rdparty/double-conversion/cached-powers.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef DOUBLE_CONVERSION_CACHED_POWERS_H_
-#define DOUBLE_CONVERSION_CACHED_POWERS_H_
-
-#include "diy-fp.h"
-
-namespace double_conversion {
-
-class PowersOfTenCache {
- public:
-
- // Not all powers of ten are cached. The decimal exponent of two neighboring
- // cached numbers will differ by kDecimalExponentDistance.
- static const int kDecimalExponentDistance;
-
- static const int kMinDecimalExponent;
- static const int kMaxDecimalExponent;
-
- // Returns a cached power-of-ten with a binary exponent in the range
- // [min_exponent; max_exponent] (boundaries included).
- static void GetCachedPowerForBinaryExponentRange(int min_exponent,
- int max_exponent,
- DiyFp* power,
- int* decimal_exponent);
-
- // Returns a cached power of ten x ~= 10^k such that
- // k <= decimal_exponent < k + kCachedPowersDecimalDistance.
- // The given decimal_exponent must satisfy
- // kMinDecimalExponent <= requested_exponent, and
- // requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance.
- static void GetCachedPowerForDecimalExponent(int requested_exponent,
- DiyFp* power,
- int* found_exponent);
-};
-
-} // namespace double_conversion
-
-#endif // DOUBLE_CONVERSION_CACHED_POWERS_H_
diff --git a/src/3rdparty/double-conversion/diy-fp.cc b/src/3rdparty/double-conversion/diy-fp.cc
deleted file mode 100644
index ddd1891b16..0000000000
--- a/src/3rdparty/double-conversion/diy-fp.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-#include "diy-fp.h"
-#include "utils.h"
-
-namespace double_conversion {
-
-void DiyFp::Multiply(const DiyFp& other) {
- // Simply "emulates" a 128 bit multiplication.
- // However: the resulting number only contains 64 bits. The least
- // significant 64 bits are only used for rounding the most significant 64
- // bits.
- const uint64_t kM32 = 0xFFFFFFFFU;
- uint64_t a = f_ >> 32;
- uint64_t b = f_ & kM32;
- uint64_t c = other.f_ >> 32;
- uint64_t d = other.f_ & kM32;
- uint64_t ac = a * c;
- uint64_t bc = b * c;
- uint64_t ad = a * d;
- uint64_t bd = b * d;
- uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32);
- // By adding 1U << 31 to tmp we round the final result.
- // Halfway cases will be round up.
- tmp += 1U << 31;
- uint64_t result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
- e_ += other.e_ + 64;
- f_ = result_f;
-}
-
-} // namespace double_conversion
diff --git a/src/3rdparty/double-conversion/diy-fp.h b/src/3rdparty/double-conversion/diy-fp.h
deleted file mode 100644
index 9dcf8fbdba..0000000000
--- a/src/3rdparty/double-conversion/diy-fp.h
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef DOUBLE_CONVERSION_DIY_FP_H_
-#define DOUBLE_CONVERSION_DIY_FP_H_
-
-#include "utils.h"
-
-namespace double_conversion {
-
-// This "Do It Yourself Floating Point" class implements a floating-point number
-// with a uint64 significand and an int exponent. Normalized DiyFp numbers will
-// have the most significant bit of the significand set.
-// Multiplication and Subtraction do not normalize their results.
-// DiyFp are not designed to contain special doubles (NaN and Infinity).
-class DiyFp {
- public:
- static const int kSignificandSize = 64;
-
- DiyFp() : f_(0), e_(0) {}
- DiyFp(uint64_t f, int e) : f_(f), e_(e) {}
-
- // this = this - other.
- // The exponents of both numbers must be the same and the significand of this
- // must be bigger than the significand of other.
- // The result will not be normalized.
- void Subtract(const DiyFp& other) {
- ASSERT(e_ == other.e_);
- ASSERT(f_ >= other.f_);
- f_ -= other.f_;
- }
-
- // Returns a - b.
- // The exponents of both numbers must be the same and this must be bigger
- // than other. The result will not be normalized.
- static DiyFp Minus(const DiyFp& a, const DiyFp& b) {
- DiyFp result = a;
- result.Subtract(b);
- return result;
- }
-
-
- // this = this * other.
- void Multiply(const DiyFp& other);
-
- // returns a * b;
- static DiyFp Times(const DiyFp& a, const DiyFp& b) {
- DiyFp result = a;
- result.Multiply(b);
- return result;
- }
-
- void Normalize() {
- ASSERT(f_ != 0);
- uint64_t f = f_;
- int e = e_;
-
- // This method is mainly called for normalizing boundaries. In general
- // boundaries need to be shifted by 10 bits. We thus optimize for this case.
- const uint64_t k10MSBits = UINT64_2PART_C(0xFFC00000, 00000000);
- while ((f & k10MSBits) == 0) {
- f <<= 10;
- e -= 10;
- }
- while ((f & kUint64MSB) == 0) {
- f <<= 1;
- e--;
- }
- f_ = f;
- e_ = e;
- }
-
- static DiyFp Normalize(const DiyFp& a) {
- DiyFp result = a;
- result.Normalize();
- return result;
- }
-
- uint64_t f() const { return f_; }
- int e() const { return e_; }
-
- void set_f(uint64_t new_value) { f_ = new_value; }
- void set_e(int new_value) { e_ = new_value; }
-
- private:
- static const uint64_t kUint64MSB = UINT64_2PART_C(0x80000000, 00000000);
-
- uint64_t f_;
- int e_;
-};
-
-} // namespace double_conversion
-
-#endif // DOUBLE_CONVERSION_DIY_FP_H_
diff --git a/src/3rdparty/double-conversion/double-conversion.cc b/src/3rdparty/double-conversion/double-conversion.cc
deleted file mode 100644
index 909985be82..0000000000
--- a/src/3rdparty/double-conversion/double-conversion.cc
+++ /dev/null
@@ -1,975 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <limits.h>
-#include <math.h>
-
-#include "double-conversion.h"
-
-#include "bignum-dtoa.h"
-#include "fast-dtoa.h"
-#include "fixed-dtoa.h"
-#include "ieee.h"
-#include "strtod.h"
-#include "utils.h"
-
-namespace double_conversion {
-
-const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() {
- int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN;
- static DoubleToStringConverter converter(flags,
- "Infinity",
- "NaN",
- 'e',
- -6, 21,
- 6, 0);
- return converter;
-}
-
-
-bool DoubleToStringConverter::HandleSpecialValues(
- double value,
- StringBuilder* result_builder) const {
- Double double_inspect(value);
- if (double_inspect.IsInfinite()) {
- if (infinity_symbol_ == NULL) return false;
- if (value < 0) {
- result_builder->AddCharacter('-');
- }
- result_builder->AddString(infinity_symbol_);
- return true;
- }
- if (double_inspect.IsNan()) {
- if (nan_symbol_ == NULL) return false;
- result_builder->AddString(nan_symbol_);
- return true;
- }
- return false;
-}
-
-
-void DoubleToStringConverter::CreateExponentialRepresentation(
- const char* decimal_digits,
- int length,
- int exponent,
- StringBuilder* result_builder) const {
- ASSERT(length != 0);
- result_builder->AddCharacter(decimal_digits[0]);
- if (length != 1) {
- result_builder->AddCharacter('.');
- result_builder->AddSubstring(&decimal_digits[1], length-1);
- }
- result_builder->AddCharacter(exponent_character_);
- if (exponent < 0) {
- result_builder->AddCharacter('-');
- exponent = -exponent;
- } else {
- if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) {
- result_builder->AddCharacter('+');
- }
- }
- if (exponent == 0) {
- result_builder->AddCharacter('0');
- return;
- }
- ASSERT(exponent < 1e4);
- const int kMaxExponentLength = 5;
- char buffer[kMaxExponentLength + 1];
- buffer[kMaxExponentLength] = '\0';
- int first_char_pos = kMaxExponentLength;
- while (exponent > 0) {
- buffer[--first_char_pos] = '0' + (exponent % 10);
- exponent /= 10;
- }
- result_builder->AddSubstring(&buffer[first_char_pos],
- kMaxExponentLength - first_char_pos);
-}
-
-
-void DoubleToStringConverter::CreateDecimalRepresentation(
- const char* decimal_digits,
- int length,
- int decimal_point,
- int digits_after_point,
- StringBuilder* result_builder) const {
- // Create a representation that is padded with zeros if needed.
- if (decimal_point <= 0) {
- // "0.00000decimal_rep".
- result_builder->AddCharacter('0');
- if (digits_after_point > 0) {
- result_builder->AddCharacter('.');
- result_builder->AddPadding('0', -decimal_point);
- ASSERT(length <= digits_after_point - (-decimal_point));
- result_builder->AddSubstring(decimal_digits, length);
- int remaining_digits = digits_after_point - (-decimal_point) - length;
- result_builder->AddPadding('0', remaining_digits);
- }
- } else if (decimal_point >= length) {
- // "decimal_rep0000.00000" or "decimal_rep.0000"
- result_builder->AddSubstring(decimal_digits, length);
- result_builder->AddPadding('0', decimal_point - length);
- if (digits_after_point > 0) {
- result_builder->AddCharacter('.');
- result_builder->AddPadding('0', digits_after_point);
- }
- } else {
- // "decima.l_rep000"
- ASSERT(digits_after_point > 0);
- result_builder->AddSubstring(decimal_digits, decimal_point);
- result_builder->AddCharacter('.');
- ASSERT(length - decimal_point <= digits_after_point);
- result_builder->AddSubstring(&decimal_digits[decimal_point],
- length - decimal_point);
- int remaining_digits = digits_after_point - (length - decimal_point);
- result_builder->AddPadding('0', remaining_digits);
- }
- if (digits_after_point == 0) {
- if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) {
- result_builder->AddCharacter('.');
- }
- if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) {
- result_builder->AddCharacter('0');
- }
- }
-}
-
-
-bool DoubleToStringConverter::ToShortestIeeeNumber(
- double value,
- StringBuilder* result_builder,
- DoubleToStringConverter::DtoaMode mode) const {
- ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE);
- if (Double(value).IsSpecial()) {
- return HandleSpecialValues(value, result_builder);
- }
-
- int decimal_point;
- bool sign;
- const int kDecimalRepCapacity = kBase10MaximalLength + 1;
- char decimal_rep[kDecimalRepCapacity];
- int decimal_rep_length;
-
- DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity,
- &sign, &decimal_rep_length, &decimal_point);
-
- bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
- if (sign && (value != 0.0 || !unique_zero)) {
- result_builder->AddCharacter('-');
- }
-
- int exponent = decimal_point - 1;
- if ((decimal_in_shortest_low_ <= exponent) &&
- (exponent < decimal_in_shortest_high_)) {
- CreateDecimalRepresentation(decimal_rep, decimal_rep_length,
- decimal_point,
- Max(0, decimal_rep_length - decimal_point),
- result_builder);
- } else {
- CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent,
- result_builder);
- }
- return true;
-}
-
-
-bool DoubleToStringConverter::ToFixed(double value,
- int requested_digits,
- StringBuilder* result_builder) const {
- ASSERT(kMaxFixedDigitsBeforePoint == 60);
- const double kFirstNonFixed = 1e60;
-
- if (Double(value).IsSpecial()) {
- return HandleSpecialValues(value, result_builder);
- }
-
- if (requested_digits > kMaxFixedDigitsAfterPoint) return false;
- if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false;
-
- // Find a sufficiently precise decimal representation of n.
- int decimal_point;
- bool sign;
- // Add space for the '\0' byte.
- const int kDecimalRepCapacity =
- kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1;
- char decimal_rep[kDecimalRepCapacity];
- int decimal_rep_length;
- DoubleToAscii(value, FIXED, requested_digits,
- decimal_rep, kDecimalRepCapacity,
- &sign, &decimal_rep_length, &decimal_point);
-
- bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
- if (sign && (value != 0.0 || !unique_zero)) {
- result_builder->AddCharacter('-');
- }
-
- CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
- requested_digits, result_builder);
- return true;
-}
-
-
-bool DoubleToStringConverter::ToExponential(
- double value,
- int requested_digits,
- StringBuilder* result_builder) const {
- if (Double(value).IsSpecial()) {
- return HandleSpecialValues(value, result_builder);
- }
-
- if (requested_digits < -1) return false;
- if (requested_digits > kMaxExponentialDigits) return false;
-
- int decimal_point;
- bool sign;
- // Add space for digit before the decimal point and the '\0' character.
- const int kDecimalRepCapacity = kMaxExponentialDigits + 2;
- ASSERT(kDecimalRepCapacity > kBase10MaximalLength);
- char decimal_rep[kDecimalRepCapacity];
- int decimal_rep_length;
-
- if (requested_digits == -1) {
- DoubleToAscii(value, SHORTEST, 0,
- decimal_rep, kDecimalRepCapacity,
- &sign, &decimal_rep_length, &decimal_point);
- } else {
- DoubleToAscii(value, PRECISION, requested_digits + 1,
- decimal_rep, kDecimalRepCapacity,
- &sign, &decimal_rep_length, &decimal_point);
- ASSERT(decimal_rep_length <= requested_digits + 1);
-
- for (int i = decimal_rep_length; i < requested_digits + 1; ++i) {
- decimal_rep[i] = '0';
- }
- decimal_rep_length = requested_digits + 1;
- }
-
- bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
- if (sign && (value != 0.0 || !unique_zero)) {
- result_builder->AddCharacter('-');
- }
-
- int exponent = decimal_point - 1;
- CreateExponentialRepresentation(decimal_rep,
- decimal_rep_length,
- exponent,
- result_builder);
- return true;
-}
-
-
-bool DoubleToStringConverter::ToPrecision(double value,
- int precision,
- StringBuilder* result_builder) const {
- if (Double(value).IsSpecial()) {
- return HandleSpecialValues(value, result_builder);
- }
-
- if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) {
- return false;
- }
-
- // Find a sufficiently precise decimal representation of n.
- int decimal_point;
- bool sign;
- // Add one for the terminating null character.
- const int kDecimalRepCapacity = kMaxPrecisionDigits + 1;
- char decimal_rep[kDecimalRepCapacity];
- int decimal_rep_length;
-
- DoubleToAscii(value, PRECISION, precision,
- decimal_rep, kDecimalRepCapacity,
- &sign, &decimal_rep_length, &decimal_point);
- ASSERT(decimal_rep_length <= precision);
-
- bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
- if (sign && (value != 0.0 || !unique_zero)) {
- result_builder->AddCharacter('-');
- }
-
- // The exponent if we print the number as x.xxeyyy. That is with the
- // decimal point after the first digit.
- int exponent = decimal_point - 1;
-
- int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
- if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
- (decimal_point - precision + extra_zero >
- max_trailing_padding_zeroes_in_precision_mode_)) {
- // Fill buffer to contain 'precision' digits.
- // Usually the buffer is already at the correct length, but 'DoubleToAscii'
- // is allowed to return less characters.
- for (int i = decimal_rep_length; i < precision; ++i) {
- decimal_rep[i] = '0';
- }
-
- CreateExponentialRepresentation(decimal_rep,
- precision,
- exponent,
- result_builder);
- } else {
- CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
- Max(0, precision - decimal_point),
- result_builder);
- }
- return true;
-}
-
-
-static BignumDtoaMode DtoaToBignumDtoaMode(
- DoubleToStringConverter::DtoaMode dtoa_mode) {
- switch (dtoa_mode) {
- case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST;
- case DoubleToStringConverter::SHORTEST_SINGLE:
- return BIGNUM_DTOA_SHORTEST_SINGLE;
- case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED;
- case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION;
- default:
- UNREACHABLE();
- }
-}
-
-
-void DoubleToStringConverter::DoubleToAscii(double v,
- DtoaMode mode,
- int requested_digits,
- char* buffer,
- int buffer_length,
- bool* sign,
- int* length,
- int* point) {
- Vector<char> vector(buffer, buffer_length);
- ASSERT(!Double(v).IsSpecial());
- ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0);
-
- if (Double(v).Sign() < 0) {
- *sign = true;
- v = -v;
- } else {
- *sign = false;
- }
-
- if (mode == PRECISION && requested_digits == 0) {
- vector[0] = '\0';
- *length = 0;
- return;
- }
-
- if (v == 0) {
- vector[0] = '0';
- vector[1] = '\0';
- *length = 1;
- *point = 1;
- return;
- }
-
- bool fast_worked;
- switch (mode) {
- case SHORTEST:
- fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
- break;
- case SHORTEST_SINGLE:
- fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0,
- vector, length, point);
- break;
- case FIXED:
- fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
- break;
- case PRECISION:
- fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
- vector, length, point);
- break;
- default:
- fast_worked = false;
- UNREACHABLE();
- }
- if (fast_worked) return;
-
- // If the fast dtoa didn't succeed use the slower bignum version.
- BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);
- BignumDtoa(v, bignum_mode, requested_digits, vector, length, point);
- vector[*length] = '\0';
-}
-
-
-// Consumes the given substring from the iterator.
-// Returns false, if the substring does not match.
-template <class Iterator>
-static bool ConsumeSubString(Iterator* current,
- Iterator end,
- const char* substring) {
- ASSERT(**current == *substring);
- for (substring++; *substring != '\0'; substring++) {
- ++*current;
- if (*current == end || **current != *substring) return false;
- }
- ++*current;
- return true;
-}
-
-
-// Maximum number of significant digits in decimal representation.
-// The longest possible double in decimal representation is
-// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
-// (768 digits). If we parse a number whose first digits are equal to a
-// mean of 2 adjacent doubles (that could have up to 769 digits) the result
-// must be rounded to the bigger one unless the tail consists of zeros, so
-// we don't need to preserve all the digits.
-const int kMaxSignificantDigits = 772;
-
-
-static const char kWhitespaceTable7[] = { 32, 13, 10, 9, 11, 12 };
-static const int kWhitespaceTable7Length = ARRAY_SIZE(kWhitespaceTable7);
-
-
-static const uc16 kWhitespaceTable16[] = {
- 160, 8232, 8233, 5760, 6158, 8192, 8193, 8194, 8195,
- 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8239, 8287, 12288, 65279
-};
-static const int kWhitespaceTable16Length = ARRAY_SIZE(kWhitespaceTable16);
-
-
-static bool isWhitespace(int x) {
- if (x < 128) {
- for (int i = 0; i < kWhitespaceTable7Length; i++) {
- if (kWhitespaceTable7[i] == x) return true;
- }
- } else {
- for (int i = 0; i < kWhitespaceTable16Length; i++) {
- if (kWhitespaceTable16[i] == x) return true;
- }
- }
- return false;
-}
-
-
-// Returns true if a nonspace found and false if the end has reached.
-template <class Iterator>
-static inline bool AdvanceToNonspace(Iterator* current, Iterator end) {
- while (*current != end) {
- if (!isWhitespace(**current)) return true;
- ++*current;
- }
- return false;
-}
-
-
-static bool isDigit(int x, int radix) {
- return (x >= '0' && x <= '9' && x < '0' + radix)
- || (radix > 10 && x >= 'a' && x < 'a' + radix - 10)
- || (radix > 10 && x >= 'A' && x < 'A' + radix - 10);
-}
-
-
-static double SignedZero(bool sign) {
- return sign ? -0.0 : 0.0;
-}
-
-
-// Returns true if 'c' is a decimal digit that is valid for the given radix.
-//
-// The function is small and could be inlined, but VS2012 emitted a warning
-// because it constant-propagated the radix and concluded that the last
-// condition was always true. By moving it into a separate function the
-// compiler wouldn't warn anymore.
-static bool IsDecimalDigitForRadix(int c, int radix) {
- return '0' <= c && c <= '9' && (c - '0') < radix;
-}
-
-// Returns true if 'c' is a character digit that is valid for the given radix.
-// The 'a_character' should be 'a' or 'A'.
-//
-// The function is small and could be inlined, but VS2012 emitted a warning
-// because it constant-propagated the radix and concluded that the first
-// condition was always false. By moving it into a separate function the
-// compiler wouldn't warn anymore.
-static bool IsCharacterDigitForRadix(int c, int radix, char a_character) {
- return radix > 10 && c >= a_character && c < a_character + radix - 10;
-}
-
-
-// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
-template <int radix_log_2, class Iterator>
-static double RadixStringToIeee(Iterator* current,
- Iterator end,
- bool sign,
- bool allow_trailing_junk,
- double junk_string_value,
- bool read_as_double,
- bool* result_is_junk) {
- ASSERT(*current != end);
-
- const int kDoubleSize = Double::kSignificandSize;
- const int kSingleSize = Single::kSignificandSize;
- const int kSignificandSize = read_as_double? kDoubleSize: kSingleSize;
-
- *result_is_junk = true;
-
- // Skip leading 0s.
- while (**current == '0') {
- ++(*current);
- if (*current == end) {
- *result_is_junk = false;
- return SignedZero(sign);
- }
- }
-
- int64_t number = 0;
- int exponent = 0;
- const int radix = (1 << radix_log_2);
-
- do {
- int digit;
- if (IsDecimalDigitForRadix(**current, radix)) {
- digit = static_cast<char>(**current) - '0';
- } else if (IsCharacterDigitForRadix(**current, radix, 'a')) {
- digit = static_cast<char>(**current) - 'a' + 10;
- } else if (IsCharacterDigitForRadix(**current, radix, 'A')) {
- digit = static_cast<char>(**current) - 'A' + 10;
- } else {
- if (allow_trailing_junk || !AdvanceToNonspace(current, end)) {
- break;
- } else {
- return junk_string_value;
- }
- }
-
- number = number * radix + digit;
- int overflow = static_cast<int>(number >> kSignificandSize);
- if (overflow != 0) {
- // Overflow occurred. Need to determine which direction to round the
- // result.
- int overflow_bits_count = 1;
- while (overflow > 1) {
- overflow_bits_count++;
- overflow >>= 1;
- }
-
- int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
- int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
- number >>= overflow_bits_count;
- exponent = overflow_bits_count;
-
- bool zero_tail = true;
- for (;;) {
- ++(*current);
- if (*current == end || !isDigit(**current, radix)) break;
- zero_tail = zero_tail && **current == '0';
- exponent += radix_log_2;
- }
-
- if (!allow_trailing_junk && AdvanceToNonspace(current, end)) {
- return junk_string_value;
- }
-
- int middle_value = (1 << (overflow_bits_count - 1));
- if (dropped_bits > middle_value) {
- number++; // Rounding up.
- } else if (dropped_bits == middle_value) {
- // Rounding to even to consistency with decimals: half-way case rounds
- // up if significant part is odd and down otherwise.
- if ((number & 1) != 0 || !zero_tail) {
- number++; // Rounding up.
- }
- }
-
- // Rounding up may cause overflow.
- if ((number & ((int64_t)1 << kSignificandSize)) != 0) {
- exponent++;
- number >>= 1;
- }
- break;
- }
- ++(*current);
- } while (*current != end);
-
- ASSERT(number < ((int64_t)1 << kSignificandSize));
- ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);
-
- *result_is_junk = false;
-
- if (exponent == 0) {
- if (sign) {
- if (number == 0) return -0.0;
- number = -number;
- }
- return static_cast<double>(number);
- }
-
- ASSERT(number != 0);
- return Double(DiyFp(number, exponent)).value();
-}
-
-
-template <class Iterator>
-double StringToDoubleConverter::StringToIeee(
- Iterator input,
- int length,
- bool read_as_double,
- int* processed_characters_count) const {
- Iterator current = input;
- Iterator end = input + length;
-
- *processed_characters_count = 0;
-
- const bool allow_trailing_junk = (flags_ & ALLOW_TRAILING_JUNK) != 0;
- const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0;
- const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0;
- const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0;
-
- // To make sure that iterator dereferencing is valid the following
- // convention is used:
- // 1. Each '++current' statement is followed by check for equality to 'end'.
- // 2. If AdvanceToNonspace returned false then current == end.
- // 3. If 'current' becomes equal to 'end' the function returns or goes to
- // 'parsing_done'.
- // 4. 'current' is not dereferenced after the 'parsing_done' label.
- // 5. Code before 'parsing_done' may rely on 'current != end'.
- if (current == end) return empty_string_value_;
-
- if (allow_leading_spaces || allow_trailing_spaces) {
- if (!AdvanceToNonspace(&current, end)) {
- *processed_characters_count = static_cast<int>(current - input);
- return empty_string_value_;
- }
- if (!allow_leading_spaces && (input != current)) {
- // No leading spaces allowed, but AdvanceToNonspace moved forward.
- return junk_string_value_;
- }
- }
-
- // The longest form of simplified number is: "-<significant digits>.1eXXX\0".
- const int kBufferSize = kMaxSignificantDigits + 10;
- char buffer[kBufferSize]; // NOLINT: size is known at compile time.
- int buffer_pos = 0;
-
- // Exponent will be adjusted if insignificant digits of the integer part
- // or insignificant leading zeros of the fractional part are dropped.
- int exponent = 0;
- int significant_digits = 0;
- int insignificant_digits = 0;
- bool nonzero_digit_dropped = false;
-
- bool sign = false;
-
- if (*current == '+' || *current == '-') {
- sign = (*current == '-');
- ++current;
- Iterator next_non_space = current;
- // Skip following spaces (if allowed).
- if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_;
- if (!allow_spaces_after_sign && (current != next_non_space)) {
- return junk_string_value_;
- }
- current = next_non_space;
- }
-
- if (infinity_symbol_ != NULL) {
- if (*current == infinity_symbol_[0]) {
- if (!ConsumeSubString(&current, end, infinity_symbol_)) {
- return junk_string_value_;
- }
-
- if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
- return junk_string_value_;
- }
- if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
- return junk_string_value_;
- }
-
- ASSERT(buffer_pos == 0);
- *processed_characters_count = static_cast<int>(current - input);
- return sign ? -Double::Infinity() : Double::Infinity();
- }
- }
-
- if (nan_symbol_ != NULL) {
- if (*current == nan_symbol_[0]) {
- if (!ConsumeSubString(&current, end, nan_symbol_)) {
- return junk_string_value_;
- }
-
- if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
- return junk_string_value_;
- }
- if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
- return junk_string_value_;
- }
-
- ASSERT(buffer_pos == 0);
- *processed_characters_count = static_cast<int>(current - input);
- return sign ? -Double::NaN() : Double::NaN();
- }
- }
-
- bool leading_zero = false;
- if (*current == '0') {
- ++current;
- if (current == end) {
- *processed_characters_count = static_cast<int>(current - input);
- return SignedZero(sign);
- }
-
- leading_zero = true;
-
- // It could be hexadecimal value.
- if ((flags_ & ALLOW_HEX) && (*current == 'x' || *current == 'X')) {
- ++current;
- if (current == end || !isDigit(*current, 16)) {
- return junk_string_value_; // "0x".
- }
-
- bool result_is_junk;
- double result = RadixStringToIeee<4>(&current,
- end,
- sign,
- allow_trailing_junk,
- junk_string_value_,
- read_as_double,
- &result_is_junk);
- if (!result_is_junk) {
- if (allow_trailing_spaces) AdvanceToNonspace(&current, end);
- *processed_characters_count = static_cast<int>(current - input);
- }
- return result;
- }
-
- // Ignore leading zeros in the integer part.
- while (*current == '0') {
- ++current;
- if (current == end) {
- *processed_characters_count = static_cast<int>(current - input);
- return SignedZero(sign);
- }
- }
- }
-
- bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0;
-
- // Copy significant digits of the integer part (if any) to the buffer.
- while (*current >= '0' && *current <= '9') {
- if (significant_digits < kMaxSignificantDigits) {
- ASSERT(buffer_pos < kBufferSize);
- buffer[buffer_pos++] = static_cast<char>(*current);
- significant_digits++;
- // Will later check if it's an octal in the buffer.
- } else {
- insignificant_digits++; // Move the digit into the exponential part.
- nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
- }
- octal = octal && *current < '8';
- ++current;
- if (current == end) goto parsing_done;
- }
-
- if (significant_digits == 0) {
- octal = false;
- }
-
- if (*current == '.') {
- if (octal && !allow_trailing_junk) return junk_string_value_;
- if (octal) goto parsing_done;
-
- ++current;
- if (current == end) {
- if (significant_digits == 0 && !leading_zero) {
- return junk_string_value_;
- } else {
- goto parsing_done;
- }
- }
-
- if (significant_digits == 0) {
- // octal = false;
- // Integer part consists of 0 or is absent. Significant digits start after
- // leading zeros (if any).
- while (*current == '0') {
- ++current;
- if (current == end) {
- *processed_characters_count = static_cast<int>(current - input);
- return SignedZero(sign);
- }
- exponent--; // Move this 0 into the exponent.
- }
- }
-
- // There is a fractional part.
- // We don't emit a '.', but adjust the exponent instead.
- while (*current >= '0' && *current <= '9') {
- if (significant_digits < kMaxSignificantDigits) {
- ASSERT(buffer_pos < kBufferSize);
- buffer[buffer_pos++] = static_cast<char>(*current);
- significant_digits++;
- exponent--;
- } else {
- // Ignore insignificant digits in the fractional part.
- nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
- }
- ++current;
- if (current == end) goto parsing_done;
- }
- }
-
- if (!leading_zero && exponent == 0 && significant_digits == 0) {
- // If leading_zeros is true then the string contains zeros.
- // If exponent < 0 then string was [+-]\.0*...
- // If significant_digits != 0 the string is not equal to 0.
- // Otherwise there are no digits in the string.
- return junk_string_value_;
- }
-
- // Parse exponential part.
- if (*current == 'e' || *current == 'E') {
- if (octal && !allow_trailing_junk) return junk_string_value_;
- if (octal) goto parsing_done;
- ++current;
- if (current == end) {
- if (allow_trailing_junk) {
- goto parsing_done;
- } else {
- return junk_string_value_;
- }
- }
- char sign = '+';
- if (*current == '+' || *current == '-') {
- sign = static_cast<char>(*current);
- ++current;
- if (current == end) {
- if (allow_trailing_junk) {
- goto parsing_done;
- } else {
- return junk_string_value_;
- }
- }
- }
-
- if (current == end || *current < '0' || *current > '9') {
- if (allow_trailing_junk) {
- goto parsing_done;
- } else {
- return junk_string_value_;
- }
- }
-
- const int max_exponent = INT_MAX / 2;
- ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);
- int num = 0;
- do {
- // Check overflow.
- int digit = *current - '0';
- if (num >= max_exponent / 10
- && !(num == max_exponent / 10 && digit <= max_exponent % 10)) {
- num = max_exponent;
- } else {
- num = num * 10 + digit;
- }
- ++current;
- } while (current != end && *current >= '0' && *current <= '9');
-
- exponent += (sign == '-' ? -num : num);
- }
-
- if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
- return junk_string_value_;
- }
- if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
- return junk_string_value_;
- }
- if (allow_trailing_spaces) {
- AdvanceToNonspace(&current, end);
- }
-
- parsing_done:
- exponent += insignificant_digits;
-
- if (octal) {
- double result;
- bool result_is_junk;
- char* start = buffer;
- result = RadixStringToIeee<3>(&start,
- buffer + buffer_pos,
- sign,
- allow_trailing_junk,
- junk_string_value_,
- read_as_double,
- &result_is_junk);
- ASSERT(!result_is_junk);
- *processed_characters_count = static_cast<int>(current - input);
- return result;
- }
-
- if (nonzero_digit_dropped) {
- buffer[buffer_pos++] = '1';
- exponent--;
- }
-
- ASSERT(buffer_pos < kBufferSize);
- buffer[buffer_pos] = '\0';
-
- double converted;
- if (read_as_double) {
- converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
- } else {
- converted = Strtof(Vector<const char>(buffer, buffer_pos), exponent);
- }
- *processed_characters_count = static_cast<int>(current - input);
- return sign? -converted: converted;
-}
-
-
-double StringToDoubleConverter::StringToDouble(
- const char* buffer,
- int length,
- int* processed_characters_count) const {
- return StringToIeee(buffer, length, true, processed_characters_count);
-}
-
-
-double StringToDoubleConverter::StringToDouble(
- const uc16* buffer,
- int length,
- int* processed_characters_count) const {
- return StringToIeee(buffer, length, true, processed_characters_count);
-}
-
-
-float StringToDoubleConverter::StringToFloat(
- const char* buffer,
- int length,
- int* processed_characters_count) const {
- return static_cast<float>(StringToIeee(buffer, length, false,
- processed_characters_count));
-}
-
-
-float StringToDoubleConverter::StringToFloat(
- const uc16* buffer,
- int length,
- int* processed_characters_count) const {
- return static_cast<float>(StringToIeee(buffer, length, false,
- processed_characters_count));
-}
-
-} // namespace double_conversion
diff --git a/src/3rdparty/double-conversion/double-conversion.h b/src/3rdparty/double-conversion/double-conversion.h
deleted file mode 100644
index 6bdfa8d25d..0000000000
--- a/src/3rdparty/double-conversion/double-conversion.h
+++ /dev/null
@@ -1,543 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
-#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
-
-#include "utils.h"
-
-namespace double_conversion {
-
-class DoubleToStringConverter {
- public:
- // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint
- // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the
- // function returns false.
- static const int kMaxFixedDigitsBeforePoint = 60;
- static const int kMaxFixedDigitsAfterPoint = 60;
-
- // When calling ToExponential with a requested_digits
- // parameter > kMaxExponentialDigits then the function returns false.
- static const int kMaxExponentialDigits = 120;
-
- // When calling ToPrecision with a requested_digits
- // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits
- // then the function returns false.
- static const int kMinPrecisionDigits = 1;
- static const int kMaxPrecisionDigits = 120;
-
- enum Flags {
- NO_FLAGS = 0,
- EMIT_POSITIVE_EXPONENT_SIGN = 1,
- EMIT_TRAILING_DECIMAL_POINT = 2,
- EMIT_TRAILING_ZERO_AFTER_POINT = 4,
- UNIQUE_ZERO = 8
- };
-
- // Flags should be a bit-or combination of the possible Flags-enum.
- // - NO_FLAGS: no special flags.
- // - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent
- // form, emits a '+' for positive exponents. Example: 1.2e+2.
- // - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is
- // converted into decimal format then a trailing decimal point is appended.
- // Example: 2345.0 is converted to "2345.".
- // - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point
- // emits a trailing '0'-character. This flag requires the
- // EXMIT_TRAILING_DECIMAL_POINT flag.
- // Example: 2345.0 is converted to "2345.0".
- // - UNIQUE_ZERO: "-0.0" is converted to "0.0".
- //
- // Infinity symbol and nan_symbol provide the string representation for these
- // special values. If the string is NULL and the special value is encountered
- // then the conversion functions return false.
- //
- // The exponent_character is used in exponential representations. It is
- // usually 'e' or 'E'.
- //
- // When converting to the shortest representation the converter will
- // represent input numbers in decimal format if they are in the interval
- // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[
- // (lower boundary included, greater boundary excluded).
- // Example: with decimal_in_shortest_low = -6 and
- // decimal_in_shortest_high = 21:
- // ToShortest(0.000001) -> "0.000001"
- // ToShortest(0.0000001) -> "1e-7"
- // ToShortest(111111111111111111111.0) -> "111111111111111110000"
- // ToShortest(100000000000000000000.0) -> "100000000000000000000"
- // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"
- //
- // When converting to precision mode the converter may add
- // max_leading_padding_zeroes before returning the number in exponential
- // format.
- // Example with max_leading_padding_zeroes_in_precision_mode = 6.
- // ToPrecision(0.0000012345, 2) -> "0.0000012"
- // ToPrecision(0.00000012345, 2) -> "1.2e-7"
- // Similarily the converter may add up to
- // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
- // returning an exponential representation. A zero added by the
- // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
- // Examples for max_trailing_padding_zeroes_in_precision_mode = 1:
- // ToPrecision(230.0, 2) -> "230"
- // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.
- // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
- DoubleToStringConverter(int flags,
- const char* infinity_symbol,
- const char* nan_symbol,
- char exponent_character,
- int decimal_in_shortest_low,
- int decimal_in_shortest_high,
- int max_leading_padding_zeroes_in_precision_mode,
- int max_trailing_padding_zeroes_in_precision_mode)
- : flags_(flags),
- infinity_symbol_(infinity_symbol),
- nan_symbol_(nan_symbol),
- exponent_character_(exponent_character),
- decimal_in_shortest_low_(decimal_in_shortest_low),
- decimal_in_shortest_high_(decimal_in_shortest_high),
- max_leading_padding_zeroes_in_precision_mode_(
- max_leading_padding_zeroes_in_precision_mode),
- max_trailing_padding_zeroes_in_precision_mode_(
- max_trailing_padding_zeroes_in_precision_mode) {
- // When 'trailing zero after the point' is set, then 'trailing point'
- // must be set too.
- ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) ||
- !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0));
- }
-
- // Returns a converter following the EcmaScript specification.
- static const DoubleToStringConverter& EcmaScriptConverter();
-
- // Computes the shortest string of digits that correctly represent the input
- // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high
- // (see constructor) it then either returns a decimal representation, or an
- // exponential representation.
- // Example with decimal_in_shortest_low = -6,
- // decimal_in_shortest_high = 21,
- // EMIT_POSITIVE_EXPONENT_SIGN activated, and
- // EMIT_TRAILING_DECIMAL_POINT deactived:
- // ToShortest(0.000001) -> "0.000001"
- // ToShortest(0.0000001) -> "1e-7"
- // ToShortest(111111111111111111111.0) -> "111111111111111110000"
- // ToShortest(100000000000000000000.0) -> "100000000000000000000"
- // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"
- //
- // Note: the conversion may round the output if the returned string
- // is accurate enough to uniquely identify the input-number.
- // For example the most precise representation of the double 9e59 equals
- // "899999999999999918767229449717619953810131273674690656206848", but
- // the converter will return the shorter (but still correct) "9e59".
- //
- // Returns true if the conversion succeeds. The conversion always succeeds
- // except when the input value is special and no infinity_symbol or
- // nan_symbol has been given to the constructor.
- bool ToShortest(double value, StringBuilder* result_builder) const {
- return ToShortestIeeeNumber(value, result_builder, SHORTEST);
- }
-
- // Same as ToShortest, but for single-precision floats.
- bool ToShortestSingle(float value, StringBuilder* result_builder) const {
- return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE);
- }
-
-
- // Computes a decimal representation with a fixed number of digits after the
- // decimal point. The last emitted digit is rounded.
- //
- // Examples:
- // ToFixed(3.12, 1) -> "3.1"
- // ToFixed(3.1415, 3) -> "3.142"
- // ToFixed(1234.56789, 4) -> "1234.5679"
- // ToFixed(1.23, 5) -> "1.23000"
- // ToFixed(0.1, 4) -> "0.1000"
- // ToFixed(1e30, 2) -> "1000000000000000019884624838656.00"
- // ToFixed(0.1, 30) -> "0.100000000000000005551115123126"
- // ToFixed(0.1, 17) -> "0.10000000000000001"
- //
- // If requested_digits equals 0, then the tail of the result depends on
- // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT.
- // Examples, for requested_digits == 0,
- // let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be
- // - false and false: then 123.45 -> 123
- // 0.678 -> 1
- // - true and false: then 123.45 -> 123.
- // 0.678 -> 1.
- // - true and true: then 123.45 -> 123.0
- // 0.678 -> 1.0
- //
- // Returns true if the conversion succeeds. The conversion always succeeds
- // except for the following cases:
- // - the input value is special and no infinity_symbol or nan_symbol has
- // been provided to the constructor,
- // - 'value' > 10^kMaxFixedDigitsBeforePoint, or
- // - 'requested_digits' > kMaxFixedDigitsAfterPoint.
- // The last two conditions imply that the result will never contain more than
- // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters
- // (one additional character for the sign, and one for the decimal point).
- bool ToFixed(double value,
- int requested_digits,
- StringBuilder* result_builder) const;
-
- // Computes a representation in exponential format with requested_digits
- // after the decimal point. The last emitted digit is rounded.
- // If requested_digits equals -1, then the shortest exponential representation
- // is computed.
- //
- // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and
- // exponent_character set to 'e'.
- // ToExponential(3.12, 1) -> "3.1e0"
- // ToExponential(5.0, 3) -> "5.000e0"
- // ToExponential(0.001, 2) -> "1.00e-3"
- // ToExponential(3.1415, -1) -> "3.1415e0"
- // ToExponential(3.1415, 4) -> "3.1415e0"
- // ToExponential(3.1415, 3) -> "3.142e0"
- // ToExponential(123456789000000, 3) -> "1.235e14"
- // ToExponential(1000000000000000019884624838656.0, -1) -> "1e30"
- // ToExponential(1000000000000000019884624838656.0, 32) ->
- // "1.00000000000000001988462483865600e30"
- // ToExponential(1234, 0) -> "1e3"
- //
- // Returns true if the conversion succeeds. The conversion always succeeds
- // except for the following cases:
- // - the input value is special and no infinity_symbol or nan_symbol has
- // been provided to the constructor,
- // - 'requested_digits' > kMaxExponentialDigits.
- // The last condition implies that the result will never contain more than
- // kMaxExponentialDigits + 8 characters (the sign, the digit before the
- // decimal point, the decimal point, the exponent character, the
- // exponent's sign, and at most 3 exponent digits).
- bool ToExponential(double value,
- int requested_digits,
- StringBuilder* result_builder) const;
-
- // Computes 'precision' leading digits of the given 'value' and returns them
- // either in exponential or decimal format, depending on
- // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the
- // constructor).
- // The last computed digit is rounded.
- //
- // Example with max_leading_padding_zeroes_in_precision_mode = 6.
- // ToPrecision(0.0000012345, 2) -> "0.0000012"
- // ToPrecision(0.00000012345, 2) -> "1.2e-7"
- // Similarily the converter may add up to
- // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
- // returning an exponential representation. A zero added by the
- // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
- // Examples for max_trailing_padding_zeroes_in_precision_mode = 1:
- // ToPrecision(230.0, 2) -> "230"
- // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.
- // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
- // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no
- // EMIT_TRAILING_ZERO_AFTER_POINT:
- // ToPrecision(123450.0, 6) -> "123450"
- // ToPrecision(123450.0, 5) -> "123450"
- // ToPrecision(123450.0, 4) -> "123500"
- // ToPrecision(123450.0, 3) -> "123000"
- // ToPrecision(123450.0, 2) -> "1.2e5"
- //
- // Returns true if the conversion succeeds. The conversion always succeeds
- // except for the following cases:
- // - the input value is special and no infinity_symbol or nan_symbol has
- // been provided to the constructor,
- // - precision < kMinPericisionDigits
- // - precision > kMaxPrecisionDigits
- // The last condition implies that the result will never contain more than
- // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the
- // exponent character, the exponent's sign, and at most 3 exponent digits).
- bool ToPrecision(double value,
- int precision,
- StringBuilder* result_builder) const;
-
- enum DtoaMode {
- // Produce the shortest correct representation.
- // For example the output of 0.299999999999999988897 is (the less accurate
- // but correct) 0.3.
- SHORTEST,
- // Same as SHORTEST, but for single-precision floats.
- SHORTEST_SINGLE,
- // Produce a fixed number of digits after the decimal point.
- // For instance fixed(0.1, 4) becomes 0.1000
- // If the input number is big, the output will be big.
- FIXED,
- // Fixed number of digits (independent of the decimal point).
- PRECISION
- };
-
- // The maximal number of digits that are needed to emit a double in base 10.
- // A higher precision can be achieved by using more digits, but the shortest
- // accurate representation of any double will never use more digits than
- // kBase10MaximalLength.
- // Note that DoubleToAscii null-terminates its input. So the given buffer
- // should be at least kBase10MaximalLength + 1 characters long.
- static const int kBase10MaximalLength = 17;
-
- // Converts the given double 'v' to ascii. 'v' must not be NaN, +Infinity, or
- // -Infinity. In SHORTEST_SINGLE-mode this restriction also applies to 'v'
- // after it has been casted to a single-precision float. That is, in this
- // mode static_cast<float>(v) must not be NaN, +Infinity or -Infinity.
- //
- // The result should be interpreted as buffer * 10^(point-length).
- //
- // The output depends on the given mode:
- // - SHORTEST: produce the least amount of digits for which the internal
- // identity requirement is still satisfied. If the digits are printed
- // (together with the correct exponent) then reading this number will give
- // 'v' again. The buffer will choose the representation that is closest to
- // 'v'. If there are two at the same distance, than the one farther away
- // from 0 is chosen (halfway cases - ending with 5 - are rounded up).
- // In this mode the 'requested_digits' parameter is ignored.
- // - SHORTEST_SINGLE: same as SHORTEST but with single-precision.
- // - FIXED: produces digits necessary to print a given number with
- // 'requested_digits' digits after the decimal point. The produced digits
- // might be too short in which case the caller has to fill the remainder
- // with '0's.
- // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
- // Halfway cases are rounded towards +/-Infinity (away from 0). The call
- // toFixed(0.15, 2) thus returns buffer="2", point=0.
- // The returned buffer may contain digits that would be truncated from the
- // shortest representation of the input.
- // - PRECISION: produces 'requested_digits' where the first digit is not '0'.
- // Even though the length of produced digits usually equals
- // 'requested_digits', the function is allowed to return fewer digits, in
- // which case the caller has to fill the missing digits with '0's.
- // Halfway cases are again rounded away from 0.
- // DoubleToAscii expects the given buffer to be big enough to hold all
- // digits and a terminating null-character. In SHORTEST-mode it expects a
- // buffer of at least kBase10MaximalLength + 1. In all other modes the
- // requested_digits parameter and the padding-zeroes limit the size of the
- // output. Don't forget the decimal point, the exponent character and the
- // terminating null-character when computing the maximal output size.
- // The given length is only used in debug mode to ensure the buffer is big
- // enough.
- static void DoubleToAscii(double v,
- DtoaMode mode,
- int requested_digits,
- char* buffer,
- int buffer_length,
- bool* sign,
- int* length,
- int* point);
-
- private:
- // Implementation for ToShortest and ToShortestSingle.
- bool ToShortestIeeeNumber(double value,
- StringBuilder* result_builder,
- DtoaMode mode) const;
-
- // If the value is a special value (NaN or Infinity) constructs the
- // corresponding string using the configured infinity/nan-symbol.
- // If either of them is NULL or the value is not special then the
- // function returns false.
- bool HandleSpecialValues(double value, StringBuilder* result_builder) const;
- // Constructs an exponential representation (i.e. 1.234e56).
- // The given exponent assumes a decimal point after the first decimal digit.
- void CreateExponentialRepresentation(const char* decimal_digits,
- int length,
- int exponent,
- StringBuilder* result_builder) const;
- // Creates a decimal representation (i.e 1234.5678).
- void CreateDecimalRepresentation(const char* decimal_digits,
- int length,
- int decimal_point,
- int digits_after_point,
- StringBuilder* result_builder) const;
-
- const int flags_;
- const char* const infinity_symbol_;
- const char* const nan_symbol_;
- const char exponent_character_;
- const int decimal_in_shortest_low_;
- const int decimal_in_shortest_high_;
- const int max_leading_padding_zeroes_in_precision_mode_;
- const int max_trailing_padding_zeroes_in_precision_mode_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter);
-};
-
-
-class StringToDoubleConverter {
- public:
- // Enumeration for allowing octals and ignoring junk when converting
- // strings to numbers.
- enum Flags {
- NO_FLAGS = 0,
- ALLOW_HEX = 1,
- ALLOW_OCTALS = 2,
- ALLOW_TRAILING_JUNK = 4,
- ALLOW_LEADING_SPACES = 8,
- ALLOW_TRAILING_SPACES = 16,
- ALLOW_SPACES_AFTER_SIGN = 32
- };
-
- // Flags should be a bit-or combination of the possible Flags-enum.
- // - NO_FLAGS: no special flags.
- // - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers.
- // Ex: StringToDouble("0x1234") -> 4660.0
- // In StringToDouble("0x1234.56") the characters ".56" are trailing
- // junk. The result of the call is hence dependent on
- // the ALLOW_TRAILING_JUNK flag and/or the junk value.
- // With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK,
- // the string will not be parsed as "0" followed by junk.
- //
- // - ALLOW_OCTALS: recognizes the prefix "0" for octals:
- // If a sequence of octal digits starts with '0', then the number is
- // read as octal integer. Octal numbers may only be integers.
- // Ex: StringToDouble("01234") -> 668.0
- // StringToDouble("012349") -> 12349.0 // Not a sequence of octal
- // // digits.
- // In StringToDouble("01234.56") the characters ".56" are trailing
- // junk. The result of the call is hence dependent on
- // the ALLOW_TRAILING_JUNK flag and/or the junk value.
- // In StringToDouble("01234e56") the characters "e56" are trailing
- // junk, too.
- // - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of
- // a double literal.
- // - ALLOW_LEADING_SPACES: skip over leading whitespace, including spaces,
- // new-lines, and tabs.
- // - ALLOW_TRAILING_SPACES: ignore trailing whitespace.
- // - ALLOW_SPACES_AFTER_SIGN: ignore whitespace after the sign.
- // Ex: StringToDouble("- 123.2") -> -123.2.
- // StringToDouble("+ 123.2") -> 123.2
- //
- // empty_string_value is returned when an empty string is given as input.
- // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string
- // containing only spaces is converted to the 'empty_string_value', too.
- //
- // junk_string_value is returned when
- // a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not
- // part of a double-literal) is found.
- // b) ALLOW_TRAILING_JUNK is set, but the string does not start with a
- // double literal.
- //
- // infinity_symbol and nan_symbol are strings that are used to detect
- // inputs that represent infinity and NaN. They can be null, in which case
- // they are ignored.
- // The conversion routine first reads any possible signs. Then it compares the
- // following character of the input-string with the first character of
- // the infinity, and nan-symbol. If either matches, the function assumes, that
- // a match has been found, and expects the following input characters to match
- // the remaining characters of the special-value symbol.
- // This means that the following restrictions apply to special-value symbols:
- // - they must not start with signs ('+', or '-'),
- // - they must not have the same first character.
- // - they must not start with digits.
- //
- // Examples:
- // flags = ALLOW_HEX | ALLOW_TRAILING_JUNK,
- // empty_string_value = 0.0,
- // junk_string_value = NaN,
- // infinity_symbol = "infinity",
- // nan_symbol = "nan":
- // StringToDouble("0x1234") -> 4660.0.
- // StringToDouble("0x1234K") -> 4660.0.
- // StringToDouble("") -> 0.0 // empty_string_value.
- // StringToDouble(" ") -> NaN // junk_string_value.
- // StringToDouble(" 1") -> NaN // junk_string_value.
- // StringToDouble("0x") -> NaN // junk_string_value.
- // StringToDouble("-123.45") -> -123.45.
- // StringToDouble("--123.45") -> NaN // junk_string_value.
- // StringToDouble("123e45") -> 123e45.
- // StringToDouble("123E45") -> 123e45.
- // StringToDouble("123e+45") -> 123e45.
- // StringToDouble("123E-45") -> 123e-45.
- // StringToDouble("123e") -> 123.0 // trailing junk ignored.
- // StringToDouble("123e-") -> 123.0 // trailing junk ignored.
- // StringToDouble("+NaN") -> NaN // NaN string literal.
- // StringToDouble("-infinity") -> -inf. // infinity literal.
- // StringToDouble("Infinity") -> NaN // junk_string_value.
- //
- // flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES,
- // empty_string_value = 0.0,
- // junk_string_value = NaN,
- // infinity_symbol = NULL,
- // nan_symbol = NULL:
- // StringToDouble("0x1234") -> NaN // junk_string_value.
- // StringToDouble("01234") -> 668.0.
- // StringToDouble("") -> 0.0 // empty_string_value.
- // StringToDouble(" ") -> 0.0 // empty_string_value.
- // StringToDouble(" 1") -> 1.0
- // StringToDouble("0x") -> NaN // junk_string_value.
- // StringToDouble("0123e45") -> NaN // junk_string_value.
- // StringToDouble("01239E45") -> 1239e45.
- // StringToDouble("-infinity") -> NaN // junk_string_value.
- // StringToDouble("NaN") -> NaN // junk_string_value.
- StringToDoubleConverter(int flags,
- double empty_string_value,
- double junk_string_value,
- const char* infinity_symbol,
- const char* nan_symbol)
- : flags_(flags),
- empty_string_value_(empty_string_value),
- junk_string_value_(junk_string_value),
- infinity_symbol_(infinity_symbol),
- nan_symbol_(nan_symbol) {
- }
-
- // Performs the conversion.
- // The output parameter 'processed_characters_count' is set to the number
- // of characters that have been processed to read the number.
- // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included
- // in the 'processed_characters_count'. Trailing junk is never included.
- double StringToDouble(const char* buffer,
- int length,
- int* processed_characters_count) const;
-
- // Same as StringToDouble above but for 16 bit characters.
- double StringToDouble(const uc16* buffer,
- int length,
- int* processed_characters_count) const;
-
- // Same as StringToDouble but reads a float.
- // Note that this is not equivalent to static_cast<float>(StringToDouble(...))
- // due to potential double-rounding.
- float StringToFloat(const char* buffer,
- int length,
- int* processed_characters_count) const;
-
- // Same as StringToFloat above but for 16 bit characters.
- float StringToFloat(const uc16* buffer,
- int length,
- int* processed_characters_count) const;
-
- private:
- const int flags_;
- const double empty_string_value_;
- const double junk_string_value_;
- const char* const infinity_symbol_;
- const char* const nan_symbol_;
-
- template <class Iterator>
- double StringToIeee(Iterator start_pointer,
- int length,
- bool read_as_double,
- int* processed_characters_count) const;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
-};
-
-} // namespace double_conversion
-
-#endif // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
diff --git a/src/3rdparty/double-conversion/double-conversion.pri b/src/3rdparty/double-conversion/double-conversion.pri
deleted file mode 100644
index 1597aca33e..0000000000
--- a/src/3rdparty/double-conversion/double-conversion.pri
+++ /dev/null
@@ -1,24 +0,0 @@
-INCLUDEPATH += $$PWD
-VPATH += $$PWD
-SOURCES += \
- $$PWD/bignum.cc \
- $$PWD/bignum-dtoa.cc \
- $$PWD/cached-powers.cc \
- $$PWD/diy-fp.cc \
- $$PWD/double-conversion.cc \
- $$PWD/fast-dtoa.cc \
- $$PWD/fixed-dtoa.cc \
- $$PWD/strtod.cc
-
-HEADERS += \
- $$PWD/bignum-dtoa.h \
- $$PWD/bignum.h \
- $$PWD/cached-powers.h \
- $$PWD/diy-fp.h \
- $$PWD/double-conversion.h \
- $$PWD/fast-dtoa.h \
- $$PWD/fixed-dtoa.h \
- $$PWD/ieee.h \
- $$PWD/strtod.h \
- $$PWD/utils.h
-
diff --git a/src/3rdparty/double-conversion/fast-dtoa.cc b/src/3rdparty/double-conversion/fast-dtoa.cc
deleted file mode 100644
index 61350383a9..0000000000
--- a/src/3rdparty/double-conversion/fast-dtoa.cc
+++ /dev/null
@@ -1,665 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "fast-dtoa.h"
-
-#include "cached-powers.h"
-#include "diy-fp.h"
-#include "ieee.h"
-
-namespace double_conversion {
-
-// The minimal and maximal target exponent define the range of w's binary
-// exponent, where 'w' is the result of multiplying the input by a cached power
-// of ten.
-//
-// A different range might be chosen on a different platform, to optimize digit
-// generation, but a smaller range requires more powers of ten to be cached.
-static const int kMinimalTargetExponent = -60;
-static const int kMaximalTargetExponent = -32;
-
-
-// Adjusts the last digit of the generated number, and screens out generated
-// solutions that may be inaccurate. A solution may be inaccurate if it is
-// outside the safe interval, or if we cannot prove that it is closer to the
-// input than a neighboring representation of the same length.
-//
-// Input: * buffer containing the digits of too_high / 10^kappa
-// * the buffer's length
-// * distance_too_high_w == (too_high - w).f() * unit
-// * unsafe_interval == (too_high - too_low).f() * unit
-// * rest = (too_high - buffer * 10^kappa).f() * unit
-// * ten_kappa = 10^kappa * unit
-// * unit = the common multiplier
-// Output: returns true if the buffer is guaranteed to contain the closest
-// representable number to the input.
-// Modifies the generated digits in the buffer to approach (round towards) w.
-static bool RoundWeed(Vector<char> buffer,
- int length,
- uint64_t distance_too_high_w,
- uint64_t unsafe_interval,
- uint64_t rest,
- uint64_t ten_kappa,
- uint64_t unit) {
- uint64_t small_distance = distance_too_high_w - unit;
- uint64_t big_distance = distance_too_high_w + unit;
- // Let w_low = too_high - big_distance, and
- // w_high = too_high - small_distance.
- // Note: w_low < w < w_high
- //
- // The real w (* unit) must lie somewhere inside the interval
- // ]w_low; w_high[ (often written as "(w_low; w_high)")
-
- // Basically the buffer currently contains a number in the unsafe interval
- // ]too_low; too_high[ with too_low < w < too_high
- //
- // too_high - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- // ^v 1 unit ^ ^ ^ ^
- // boundary_high --------------------- . . . .
- // ^v 1 unit . . . .
- // - - - - - - - - - - - - - - - - - - - + - - + - - - - - - . .
- // . . ^ . .
- // . big_distance . . .
- // . . . . rest
- // small_distance . . . .
- // v . . . .
- // w_high - - - - - - - - - - - - - - - - - - . . . .
- // ^v 1 unit . . . .
- // w ---------------------------------------- . . . .
- // ^v 1 unit v . . .
- // w_low - - - - - - - - - - - - - - - - - - - - - . . .
- // . . v
- // buffer --------------------------------------------------+-------+--------
- // . .
- // safe_interval .
- // v .
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .
- // ^v 1 unit .
- // boundary_low ------------------------- unsafe_interval
- // ^v 1 unit v
- // too_low - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- //
- //
- // Note that the value of buffer could lie anywhere inside the range too_low
- // to too_high.
- //
- // boundary_low, boundary_high and w are approximations of the real boundaries
- // and v (the input number). They are guaranteed to be precise up to one unit.
- // In fact the error is guaranteed to be strictly less than one unit.
- //
- // Anything that lies outside the unsafe interval is guaranteed not to round
- // to v when read again.
- // Anything that lies inside the safe interval is guaranteed to round to v
- // when read again.
- // If the number inside the buffer lies inside the unsafe interval but not
- // inside the safe interval then we simply do not know and bail out (returning
- // false).
- //
- // Similarly we have to take into account the imprecision of 'w' when finding
- // the closest representation of 'w'. If we have two potential
- // representations, and one is closer to both w_low and w_high, then we know
- // it is closer to the actual value v.
- //
- // By generating the digits of too_high we got the largest (closest to
- // too_high) buffer that is still in the unsafe interval. In the case where
- // w_high < buffer < too_high we try to decrement the buffer.
- // This way the buffer approaches (rounds towards) w.
- // There are 3 conditions that stop the decrementation process:
- // 1) the buffer is already below w_high
- // 2) decrementing the buffer would make it leave the unsafe interval
- // 3) decrementing the buffer would yield a number below w_high and farther
- // away than the current number. In other words:
- // (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high
- // Instead of using the buffer directly we use its distance to too_high.
- // Conceptually rest ~= too_high - buffer
- // We need to do the following tests in this order to avoid over- and
- // underflows.
- ASSERT(rest <= unsafe_interval);
- while (rest < small_distance && // Negated condition 1
- unsafe_interval - rest >= ten_kappa && // Negated condition 2
- (rest + ten_kappa < small_distance || // buffer{-1} > w_high
- small_distance - rest >= rest + ten_kappa - small_distance)) {
- buffer[length - 1]--;
- rest += ten_kappa;
- }
-
- // We have approached w+ as much as possible. We now test if approaching w-
- // would require changing the buffer. If yes, then we have two possible
- // representations close to w, but we cannot decide which one is closer.
- if (rest < big_distance &&
- unsafe_interval - rest >= ten_kappa &&
- (rest + ten_kappa < big_distance ||
- big_distance - rest > rest + ten_kappa - big_distance)) {
- return false;
- }
-
- // Weeding test.
- // The safe interval is [too_low + 2 ulp; too_high - 2 ulp]
- // Since too_low = too_high - unsafe_interval this is equivalent to
- // [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp]
- // Conceptually we have: rest ~= too_high - buffer
- return (2 * unit <= rest) && (rest <= unsafe_interval - 4 * unit);
-}
-
-
-// Rounds the buffer upwards if the result is closer to v by possibly adding
-// 1 to the buffer. If the precision of the calculation is not sufficient to
-// round correctly, return false.
-// The rounding might shift the whole buffer in which case the kappa is
-// adjusted. For example "99", kappa = 3 might become "10", kappa = 4.
-//
-// If 2*rest > ten_kappa then the buffer needs to be round up.
-// rest can have an error of +/- 1 unit. This function accounts for the
-// imprecision and returns false, if the rounding direction cannot be
-// unambiguously determined.
-//
-// Precondition: rest < ten_kappa.
-static bool RoundWeedCounted(Vector<char> buffer,
- int length,
- uint64_t rest,
- uint64_t ten_kappa,
- uint64_t unit,
- int* kappa) {
- ASSERT(rest < ten_kappa);
- // The following tests are done in a specific order to avoid overflows. They
- // will work correctly with any uint64 values of rest < ten_kappa and unit.
- //
- // If the unit is too big, then we don't know which way to round. For example
- // a unit of 50 means that the real number lies within rest +/- 50. If
- // 10^kappa == 40 then there is no way to tell which way to round.
- if (unit >= ten_kappa) return false;
- // Even if unit is just half the size of 10^kappa we are already completely
- // lost. (And after the previous test we know that the expression will not
- // over/underflow.)
- if (ten_kappa - unit <= unit) return false;
- // If 2 * (rest + unit) <= 10^kappa we can safely round down.
- if ((ten_kappa - rest > rest) && (ten_kappa - 2 * rest >= 2 * unit)) {
- return true;
- }
- // If 2 * (rest - unit) >= 10^kappa, then we can safely round up.
- if ((rest > unit) && (ten_kappa - (rest - unit) <= (rest - unit))) {
- // Increment the last digit recursively until we find a non '9' digit.
- buffer[length - 1]++;
- for (int i = length - 1; i > 0; --i) {
- if (buffer[i] != '0' + 10) break;
- buffer[i] = '0';
- buffer[i - 1]++;
- }
- // If the first digit is now '0'+ 10 we had a buffer with all '9's. With the
- // exception of the first digit all digits are now '0'. Simply switch the
- // first digit to '1' and adjust the kappa. Example: "99" becomes "10" and
- // the power (the kappa) is increased.
- if (buffer[0] == '0' + 10) {
- buffer[0] = '1';
- (*kappa) += 1;
- }
- return true;
- }
- return false;
-}
-
-// Returns the biggest power of ten that is less than or equal to the given
-// number. We furthermore receive the maximum number of bits 'number' has.
-//
-// Returns power == 10^(exponent_plus_one-1) such that
-// power <= number < power * 10.
-// If number_bits == 0 then 0^(0-1) is returned.
-// The number of bits must be <= 32.
-// Precondition: number < (1 << (number_bits + 1)).
-
-// Inspired by the method for finding an integer log base 10 from here:
-// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
-static unsigned int const kSmallPowersOfTen[] =
- {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
- 1000000000};
-
-static void BiggestPowerTen(uint32_t number,
- int number_bits,
- uint32_t* power,
- int* exponent_plus_one) {
- ASSERT(number < (1u << (number_bits + 1)));
- // 1233/4096 is approximately 1/lg(10).
- int exponent_plus_one_guess = ((number_bits + 1) * 1233 >> 12);
- // We increment to skip over the first entry in the kPowersOf10 table.
- // Note: kPowersOf10[i] == 10^(i-1).
- exponent_plus_one_guess++;
- // We don't have any guarantees that 2^number_bits <= number.
- if (number < kSmallPowersOfTen[exponent_plus_one_guess]) {
- exponent_plus_one_guess--;
- }
- *power = kSmallPowersOfTen[exponent_plus_one_guess];
- *exponent_plus_one = exponent_plus_one_guess;
-}
-
-// Generates the digits of input number w.
-// w is a floating-point number (DiyFp), consisting of a significand and an
-// exponent. Its exponent is bounded by kMinimalTargetExponent and
-// kMaximalTargetExponent.
-// Hence -60 <= w.e() <= -32.
-//
-// Returns false if it fails, in which case the generated digits in the buffer
-// should not be used.
-// Preconditions:
-// * low, w and high are correct up to 1 ulp (unit in the last place). That
-// is, their error must be less than a unit of their last digits.
-// * low.e() == w.e() == high.e()
-// * low < w < high, and taking into account their error: low~ <= high~
-// * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
-// Postconditions: returns false if procedure fails.
-// otherwise:
-// * buffer is not null-terminated, but len contains the number of digits.
-// * buffer contains the shortest possible decimal digit-sequence
-// such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the
-// correct values of low and high (without their error).
-// * if more than one decimal representation gives the minimal number of
-// decimal digits then the one closest to W (where W is the correct value
-// of w) is chosen.
-// Remark: this procedure takes into account the imprecision of its input
-// numbers. If the precision is not enough to guarantee all the postconditions
-// then false is returned. This usually happens rarely (~0.5%).
-//
-// Say, for the sake of example, that
-// w.e() == -48, and w.f() == 0x1234567890abcdef
-// w's value can be computed by w.f() * 2^w.e()
-// We can obtain w's integral digits by simply shifting w.f() by -w.e().
-// -> w's integral part is 0x1234
-// w's fractional part is therefore 0x567890abcdef.
-// Printing w's integral part is easy (simply print 0x1234 in decimal).
-// In order to print its fraction we repeatedly multiply the fraction by 10 and
-// get each digit. Example the first digit after the point would be computed by
-// (0x567890abcdef * 10) >> 48. -> 3
-// The whole thing becomes slightly more complicated because we want to stop
-// once we have enough digits. That is, once the digits inside the buffer
-// represent 'w' we can stop. Everything inside the interval low - high
-// represents w. However we have to pay attention to low, high and w's
-// imprecision.
-static bool DigitGen(DiyFp low,
- DiyFp w,
- DiyFp high,
- Vector<char> buffer,
- int* length,
- int* kappa) {
- ASSERT(low.e() == w.e() && w.e() == high.e());
- ASSERT(low.f() + 1 <= high.f() - 1);
- ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
- // low, w and high are imprecise, but by less than one ulp (unit in the last
- // place).
- // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that
- // the new numbers are outside of the interval we want the final
- // representation to lie in.
- // Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield
- // numbers that are certain to lie in the interval. We will use this fact
- // later on.
- // We will now start by generating the digits within the uncertain
- // interval. Later we will weed out representations that lie outside the safe
- // interval and thus _might_ lie outside the correct interval.
- uint64_t unit = 1;
- DiyFp too_low = DiyFp(low.f() - unit, low.e());
- DiyFp too_high = DiyFp(high.f() + unit, high.e());
- // too_low and too_high are guaranteed to lie outside the interval we want the
- // generated number in.
- DiyFp unsafe_interval = DiyFp::Minus(too_high, too_low);
- // We now cut the input number into two parts: the integral digits and the
- // fractionals. We will not write any decimal separator though, but adapt
- // kappa instead.
- // Reminder: we are currently computing the digits (stored inside the buffer)
- // such that: too_low < buffer * 10^kappa < too_high
- // We use too_high for the digit_generation and stop as soon as possible.
- // If we stop early we effectively round down.
- DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());
- // Division by one is a shift.
- uint32_t integrals = static_cast<uint32_t>(too_high.f() >> -one.e());
- // Modulo by one is an and.
- uint64_t fractionals = too_high.f() & (one.f() - 1);
- uint32_t divisor;
- int divisor_exponent_plus_one;
- BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),
- &divisor, &divisor_exponent_plus_one);
- *kappa = divisor_exponent_plus_one;
- *length = 0;
- // Loop invariant: buffer = too_high / 10^kappa (integer division)
- // The invariant holds for the first iteration: kappa has been initialized
- // with the divisor exponent + 1. And the divisor is the biggest power of ten
- // that is smaller than integrals.
- while (*kappa > 0) {
- int digit = integrals / divisor;
- ASSERT(digit <= 9);
- buffer[*length] = static_cast<char>('0' + digit);
- (*length)++;
- integrals %= divisor;
- (*kappa)--;
- // Note that kappa now equals the exponent of the divisor and that the
- // invariant thus holds again.
- uint64_t rest =
- (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;
- // Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e())
- // Reminder: unsafe_interval.e() == one.e()
- if (rest < unsafe_interval.f()) {
- // Rounding down (by not emitting the remaining digits) yields a number
- // that lies within the unsafe interval.
- return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f(),
- unsafe_interval.f(), rest,
- static_cast<uint64_t>(divisor) << -one.e(), unit);
- }
- divisor /= 10;
- }
-
- // The integrals have been generated. We are at the point of the decimal
- // separator. In the following loop we simply multiply the remaining digits by
- // 10 and divide by one. We just need to pay attention to multiply associated
- // data (like the interval or 'unit'), too.
- // Note that the multiplication by 10 does not overflow, because w.e >= -60
- // and thus one.e >= -60.
- ASSERT(one.e() >= -60);
- ASSERT(fractionals < one.f());
- ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f());
- for (;;) {
- fractionals *= 10;
- unit *= 10;
- unsafe_interval.set_f(unsafe_interval.f() * 10);
- // Integer division by one.
- int digit = static_cast<int>(fractionals >> -one.e());
- ASSERT(digit <= 9);
- buffer[*length] = static_cast<char>('0' + digit);
- (*length)++;
- fractionals &= one.f() - 1; // Modulo by one.
- (*kappa)--;
- if (fractionals < unsafe_interval.f()) {
- return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f() * unit,
- unsafe_interval.f(), fractionals, one.f(), unit);
- }
- }
-}
-
-
-
-// Generates (at most) requested_digits digits of input number w.
-// w is a floating-point number (DiyFp), consisting of a significand and an
-// exponent. Its exponent is bounded by kMinimalTargetExponent and
-// kMaximalTargetExponent.
-// Hence -60 <= w.e() <= -32.
-//
-// Returns false if it fails, in which case the generated digits in the buffer
-// should not be used.
-// Preconditions:
-// * w is correct up to 1 ulp (unit in the last place). That
-// is, its error must be strictly less than a unit of its last digit.
-// * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
-//
-// Postconditions: returns false if procedure fails.
-// otherwise:
-// * buffer is not null-terminated, but length contains the number of
-// digits.
-// * the representation in buffer is the most precise representation of
-// requested_digits digits.
-// * buffer contains at most requested_digits digits of w. If there are less
-// than requested_digits digits then some trailing '0's have been removed.
-// * kappa is such that
-// w = buffer * 10^kappa + eps with |eps| < 10^kappa / 2.
-//
-// Remark: This procedure takes into account the imprecision of its input
-// numbers. If the precision is not enough to guarantee all the postconditions
-// then false is returned. This usually happens rarely, but the failure-rate
-// increases with higher requested_digits.
-static bool DigitGenCounted(DiyFp w,
- int requested_digits,
- Vector<char> buffer,
- int* length,
- int* kappa) {
- ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
- ASSERT(kMinimalTargetExponent >= -60);
- ASSERT(kMaximalTargetExponent <= -32);
- // w is assumed to have an error less than 1 unit. Whenever w is scaled we
- // also scale its error.
- uint64_t w_error = 1;
- // We cut the input number into two parts: the integral digits and the
- // fractional digits. We don't emit any decimal separator, but adapt kappa
- // instead. Example: instead of writing "1.2" we put "12" into the buffer and
- // increase kappa by 1.
- DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());
- // Division by one is a shift.
- uint32_t integrals = static_cast<uint32_t>(w.f() >> -one.e());
- // Modulo by one is an and.
- uint64_t fractionals = w.f() & (one.f() - 1);
- uint32_t divisor;
- int divisor_exponent_plus_one;
- BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),
- &divisor, &divisor_exponent_plus_one);
- *kappa = divisor_exponent_plus_one;
- *length = 0;
-
- // Loop invariant: buffer = w / 10^kappa (integer division)
- // The invariant holds for the first iteration: kappa has been initialized
- // with the divisor exponent + 1. And the divisor is the biggest power of ten
- // that is smaller than 'integrals'.
- while (*kappa > 0) {
- int digit = integrals / divisor;
- ASSERT(digit <= 9);
- buffer[*length] = static_cast<char>('0' + digit);
- (*length)++;
- requested_digits--;
- integrals %= divisor;
- (*kappa)--;
- // Note that kappa now equals the exponent of the divisor and that the
- // invariant thus holds again.
- if (requested_digits == 0) break;
- divisor /= 10;
- }
-
- if (requested_digits == 0) {
- uint64_t rest =
- (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;
- return RoundWeedCounted(buffer, *length, rest,
- static_cast<uint64_t>(divisor) << -one.e(), w_error,
- kappa);
- }
-
- // The integrals have been generated. We are at the point of the decimal
- // separator. In the following loop we simply multiply the remaining digits by
- // 10 and divide by one. We just need to pay attention to multiply associated
- // data (the 'unit'), too.
- // Note that the multiplication by 10 does not overflow, because w.e >= -60
- // and thus one.e >= -60.
- ASSERT(one.e() >= -60);
- ASSERT(fractionals < one.f());
- ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f());
- while (requested_digits > 0 && fractionals > w_error) {
- fractionals *= 10;
- w_error *= 10;
- // Integer division by one.
- int digit = static_cast<int>(fractionals >> -one.e());
- ASSERT(digit <= 9);
- buffer[*length] = static_cast<char>('0' + digit);
- (*length)++;
- requested_digits--;
- fractionals &= one.f() - 1; // Modulo by one.
- (*kappa)--;
- }
- if (requested_digits != 0) return false;
- return RoundWeedCounted(buffer, *length, fractionals, one.f(), w_error,
- kappa);
-}
-
-
-// Provides a decimal representation of v.
-// Returns true if it succeeds, otherwise the result cannot be trusted.
-// There will be *length digits inside the buffer (not null-terminated).
-// If the function returns true then
-// v == (double) (buffer * 10^decimal_exponent).
-// The digits in the buffer are the shortest representation possible: no
-// 0.09999999999999999 instead of 0.1. The shorter representation will even be
-// chosen even if the longer one would be closer to v.
-// The last digit will be closest to the actual v. That is, even if several
-// digits might correctly yield 'v' when read again, the closest will be
-// computed.
-static bool Grisu3(double v,
- FastDtoaMode mode,
- Vector<char> buffer,
- int* length,
- int* decimal_exponent) {
- DiyFp w = Double(v).AsNormalizedDiyFp();
- // boundary_minus and boundary_plus are the boundaries between v and its
- // closest floating-point neighbors. Any number strictly between
- // boundary_minus and boundary_plus will round to v when convert to a double.
- // Grisu3 will never output representations that lie exactly on a boundary.
- DiyFp boundary_minus, boundary_plus;
- if (mode == FAST_DTOA_SHORTEST) {
- Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
- } else {
- ASSERT(mode == FAST_DTOA_SHORTEST_SINGLE);
- float single_v = static_cast<float>(v);
- Single(single_v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
- }
- ASSERT(boundary_plus.e() == w.e());
- DiyFp ten_mk; // Cached power of ten: 10^-k
- int mk; // -k
- int ten_mk_minimal_binary_exponent =
- kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize);
- int ten_mk_maximal_binary_exponent =
- kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize);
- PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
- ten_mk_minimal_binary_exponent,
- ten_mk_maximal_binary_exponent,
- &ten_mk, &mk);
- ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() +
- DiyFp::kSignificandSize) &&
- (kMaximalTargetExponent >= w.e() + ten_mk.e() +
- DiyFp::kSignificandSize));
- // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
- // 64 bit significand and ten_mk is thus only precise up to 64 bits.
-
- // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
- // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
- // off by a small amount.
- // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
- // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
- // (f-1) * 2^e < w*10^k < (f+1) * 2^e
- DiyFp scaled_w = DiyFp::Times(w, ten_mk);
- ASSERT(scaled_w.e() ==
- boundary_plus.e() + ten_mk.e() + DiyFp::kSignificandSize);
- // In theory it would be possible to avoid some recomputations by computing
- // the difference between w and boundary_minus/plus (a power of 2) and to
- // compute scaled_boundary_minus/plus by subtracting/adding from
- // scaled_w. However the code becomes much less readable and the speed
- // enhancements are not terriffic.
- DiyFp scaled_boundary_minus = DiyFp::Times(boundary_minus, ten_mk);
- DiyFp scaled_boundary_plus = DiyFp::Times(boundary_plus, ten_mk);
-
- // DigitGen will generate the digits of scaled_w. Therefore we have
- // v == (double) (scaled_w * 10^-mk).
- // Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an
- // integer than it will be updated. For instance if scaled_w == 1.23 then
- // the buffer will be filled with "123" und the decimal_exponent will be
- // decreased by 2.
- int kappa;
- bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus,
- buffer, length, &kappa);
- *decimal_exponent = -mk + kappa;
- return result;
-}
-
-
-// The "counted" version of grisu3 (see above) only generates requested_digits
-// number of digits. This version does not generate the shortest representation,
-// and with enough requested digits 0.1 will at some point print as 0.9999999...
-// Grisu3 is too imprecise for real halfway cases (1.5 will not work) and
-// therefore the rounding strategy for halfway cases is irrelevant.
-static bool Grisu3Counted(double v,
- int requested_digits,
- Vector<char> buffer,
- int* length,
- int* decimal_exponent) {
- DiyFp w = Double(v).AsNormalizedDiyFp();
- DiyFp ten_mk; // Cached power of ten: 10^-k
- int mk; // -k
- int ten_mk_minimal_binary_exponent =
- kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize);
- int ten_mk_maximal_binary_exponent =
- kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize);
- PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
- ten_mk_minimal_binary_exponent,
- ten_mk_maximal_binary_exponent,
- &ten_mk, &mk);
- ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() +
- DiyFp::kSignificandSize) &&
- (kMaximalTargetExponent >= w.e() + ten_mk.e() +
- DiyFp::kSignificandSize));
- // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
- // 64 bit significand and ten_mk is thus only precise up to 64 bits.
-
- // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
- // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
- // off by a small amount.
- // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
- // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
- // (f-1) * 2^e < w*10^k < (f+1) * 2^e
- DiyFp scaled_w = DiyFp::Times(w, ten_mk);
-
- // We now have (double) (scaled_w * 10^-mk).
- // DigitGen will generate the first requested_digits digits of scaled_w and
- // return together with a kappa such that scaled_w ~= buffer * 10^kappa. (It
- // will not always be exactly the same since DigitGenCounted only produces a
- // limited number of digits.)
- int kappa;
- bool result = DigitGenCounted(scaled_w, requested_digits,
- buffer, length, &kappa);
- *decimal_exponent = -mk + kappa;
- return result;
-}
-
-
-bool FastDtoa(double v,
- FastDtoaMode mode,
- int requested_digits,
- Vector<char> buffer,
- int* length,
- int* decimal_point) {
- ASSERT(v > 0);
- ASSERT(!Double(v).IsSpecial());
-
- bool result = false;
- int decimal_exponent = 0;
- switch (mode) {
- case FAST_DTOA_SHORTEST:
- case FAST_DTOA_SHORTEST_SINGLE:
- result = Grisu3(v, mode, buffer, length, &decimal_exponent);
- break;
- case FAST_DTOA_PRECISION:
- result = Grisu3Counted(v, requested_digits,
- buffer, length, &decimal_exponent);
- break;
- default:
- UNREACHABLE();
- }
- if (result) {
- *decimal_point = *length + decimal_exponent;
- buffer[*length] = '\0';
- }
- return result;
-}
-
-} // namespace double_conversion
diff --git a/src/3rdparty/double-conversion/fast-dtoa.h b/src/3rdparty/double-conversion/fast-dtoa.h
deleted file mode 100644
index 5f1e8eee5e..0000000000
--- a/src/3rdparty/double-conversion/fast-dtoa.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef DOUBLE_CONVERSION_FAST_DTOA_H_
-#define DOUBLE_CONVERSION_FAST_DTOA_H_
-
-#include "utils.h"
-
-namespace double_conversion {
-
-enum FastDtoaMode {
- // Computes the shortest representation of the given input. The returned
- // result will be the most accurate number of this length. Longer
- // representations might be more accurate.
- FAST_DTOA_SHORTEST,
- // Same as FAST_DTOA_SHORTEST but for single-precision floats.
- FAST_DTOA_SHORTEST_SINGLE,
- // Computes a representation where the precision (number of digits) is
- // given as input. The precision is independent of the decimal point.
- FAST_DTOA_PRECISION
-};
-
-// FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not
-// include the terminating '\0' character.
-static const int kFastDtoaMaximalLength = 17;
-// Same for single-precision numbers.
-static const int kFastDtoaMaximalSingleLength = 9;
-
-// Provides a decimal representation of v.
-// The result should be interpreted as buffer * 10^(point - length).
-//
-// Precondition:
-// * v must be a strictly positive finite double.
-//
-// Returns true if it succeeds, otherwise the result can not be trusted.
-// There will be *length digits inside the buffer followed by a null terminator.
-// If the function returns true and mode equals
-// - FAST_DTOA_SHORTEST, then
-// the parameter requested_digits is ignored.
-// The result satisfies
-// v == (double) (buffer * 10^(point - length)).
-// The digits in the buffer are the shortest representation possible. E.g.
-// if 0.099999999999 and 0.1 represent the same double then "1" is returned
-// with point = 0.
-// The last digit will be closest to the actual v. That is, even if several
-// digits might correctly yield 'v' when read again, the buffer will contain
-// the one closest to v.
-// - FAST_DTOA_PRECISION, then
-// the buffer contains requested_digits digits.
-// the difference v - (buffer * 10^(point-length)) is closest to zero for
-// all possible representations of requested_digits digits.
-// If there are two values that are equally close, then FastDtoa returns
-// false.
-// For both modes the buffer must be large enough to hold the result.
-bool FastDtoa(double d,
- FastDtoaMode mode,
- int requested_digits,
- Vector<char> buffer,
- int* length,
- int* decimal_point);
-
-} // namespace double_conversion
-
-#endif // DOUBLE_CONVERSION_FAST_DTOA_H_
diff --git a/src/3rdparty/double-conversion/fixed-dtoa.cc b/src/3rdparty/double-conversion/fixed-dtoa.cc
deleted file mode 100644
index aef65fdc21..0000000000
--- a/src/3rdparty/double-conversion/fixed-dtoa.cc
+++ /dev/null
@@ -1,404 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <math.h>
-
-#include "fixed-dtoa.h"
-#include "ieee.h"
-
-namespace double_conversion {
-
-// Represents a 128bit type. This class should be replaced by a native type on
-// platforms that support 128bit integers.
-class UInt128 {
- public:
- UInt128() : high_bits_(0), low_bits_(0) { }
- UInt128(uint64_t high, uint64_t low) : high_bits_(high), low_bits_(low) { }
-
- void Multiply(uint32_t multiplicand) {
- uint64_t accumulator;
-
- accumulator = (low_bits_ & kMask32) * multiplicand;
- uint32_t part = static_cast<uint32_t>(accumulator & kMask32);
- accumulator >>= 32;
- accumulator = accumulator + (low_bits_ >> 32) * multiplicand;
- low_bits_ = (accumulator << 32) + part;
- accumulator >>= 32;
- accumulator = accumulator + (high_bits_ & kMask32) * multiplicand;
- part = static_cast<uint32_t>(accumulator & kMask32);
- accumulator >>= 32;
- accumulator = accumulator + (high_bits_ >> 32) * multiplicand;
- high_bits_ = (accumulator << 32) + part;
- ASSERT((accumulator >> 32) == 0);
- }
-
- void Shift(int shift_amount) {
- ASSERT(-64 <= shift_amount && shift_amount <= 64);
- if (shift_amount == 0) {
- return;
- } else if (shift_amount == -64) {
- high_bits_ = low_bits_;
- low_bits_ = 0;
- } else if (shift_amount == 64) {
- low_bits_ = high_bits_;
- high_bits_ = 0;
- } else if (shift_amount <= 0) {
- high_bits_ <<= -shift_amount;
- high_bits_ += low_bits_ >> (64 + shift_amount);
- low_bits_ <<= -shift_amount;
- } else {
- low_bits_ >>= shift_amount;
- low_bits_ += high_bits_ << (64 - shift_amount);
- high_bits_ >>= shift_amount;
- }
- }
-
- // Modifies *this to *this MOD (2^power).
- // Returns *this DIV (2^power).
- int DivModPowerOf2(int power) {
- if (power >= 64) {
- int result = static_cast<int>(high_bits_ >> (power - 64));
- high_bits_ -= static_cast<uint64_t>(result) << (power - 64);
- return result;
- } else {
- uint64_t part_low = low_bits_ >> power;
- uint64_t part_high = high_bits_ << (64 - power);
- int result = static_cast<int>(part_low + part_high);
- high_bits_ = 0;
- low_bits_ -= part_low << power;
- return result;
- }
- }
-
- bool IsZero() const {
- return high_bits_ == 0 && low_bits_ == 0;
- }
-
- int BitAt(int position) {
- if (position >= 64) {
- return static_cast<int>(high_bits_ >> (position - 64)) & 1;
- } else {
- return static_cast<int>(low_bits_ >> position) & 1;
- }
- }
-
- private:
- static const uint64_t kMask32 = 0xFFFFFFFF;
- // Value == (high_bits_ << 64) + low_bits_
- uint64_t high_bits_;
- uint64_t low_bits_;
-};
-
-
-static const int kDoubleSignificandSize = 53; // Includes the hidden bit.
-
-
-static void FillDigits32FixedLength(uint32_t number, int requested_length,
- Vector<char> buffer, int* length) {
- for (int i = requested_length - 1; i >= 0; --i) {
- buffer[(*length) + i] = '0' + number % 10;
- number /= 10;
- }
- *length += requested_length;
-}
-
-
-static void FillDigits32(uint32_t number, Vector<char> buffer, int* length) {
- int number_length = 0;
- // We fill the digits in reverse order and exchange them afterwards.
- while (number != 0) {
- int digit = number % 10;
- number /= 10;
- buffer[(*length) + number_length] = static_cast<char>('0' + digit);
- number_length++;
- }
- // Exchange the digits.
- int i = *length;
- int j = *length + number_length - 1;
- while (i < j) {
- char tmp = buffer[i];
- buffer[i] = buffer[j];
- buffer[j] = tmp;
- i++;
- j--;
- }
- *length += number_length;
-}
-
-
-static void FillDigits64FixedLength(uint64_t number,
- Vector<char> buffer, int* length) {
- const uint32_t kTen7 = 10000000;
- // For efficiency cut the number into 3 uint32_t parts, and print those.
- uint32_t part2 = static_cast<uint32_t>(number % kTen7);
- number /= kTen7;
- uint32_t part1 = static_cast<uint32_t>(number % kTen7);
- uint32_t part0 = static_cast<uint32_t>(number / kTen7);
-
- FillDigits32FixedLength(part0, 3, buffer, length);
- FillDigits32FixedLength(part1, 7, buffer, length);
- FillDigits32FixedLength(part2, 7, buffer, length);
-}
-
-
-static void FillDigits64(uint64_t number, Vector<char> buffer, int* length) {
- const uint32_t kTen7 = 10000000;
- // For efficiency cut the number into 3 uint32_t parts, and print those.
- uint32_t part2 = static_cast<uint32_t>(number % kTen7);
- number /= kTen7;
- uint32_t part1 = static_cast<uint32_t>(number % kTen7);
- uint32_t part0 = static_cast<uint32_t>(number / kTen7);
-
- if (part0 != 0) {
- FillDigits32(part0, buffer, length);
- FillDigits32FixedLength(part1, 7, buffer, length);
- FillDigits32FixedLength(part2, 7, buffer, length);
- } else if (part1 != 0) {
- FillDigits32(part1, buffer, length);
- FillDigits32FixedLength(part2, 7, buffer, length);
- } else {
- FillDigits32(part2, buffer, length);
- }
-}
-
-
-static void RoundUp(Vector<char> buffer, int* length, int* decimal_point) {
- // An empty buffer represents 0.
- if (*length == 0) {
- buffer[0] = '1';
- *decimal_point = 1;
- *length = 1;
- return;
- }
- // Round the last digit until we either have a digit that was not '9' or until
- // we reached the first digit.
- buffer[(*length) - 1]++;
- for (int i = (*length) - 1; i > 0; --i) {
- if (buffer[i] != '0' + 10) {
- return;
- }
- buffer[i] = '0';
- buffer[i - 1]++;
- }
- // If the first digit is now '0' + 10, we would need to set it to '0' and add
- // a '1' in front. However we reach the first digit only if all following
- // digits had been '9' before rounding up. Now all trailing digits are '0' and
- // we simply switch the first digit to '1' and update the decimal-point
- // (indicating that the point is now one digit to the right).
- if (buffer[0] == '0' + 10) {
- buffer[0] = '1';
- (*decimal_point)++;
- }
-}
-
-
-// The given fractionals number represents a fixed-point number with binary
-// point at bit (-exponent).
-// Preconditions:
-// -128 <= exponent <= 0.
-// 0 <= fractionals * 2^exponent < 1
-// The buffer holds the result.
-// The function will round its result. During the rounding-process digits not
-// generated by this function might be updated, and the decimal-point variable
-// might be updated. If this function generates the digits 99 and the buffer
-// already contained "199" (thus yielding a buffer of "19999") then a
-// rounding-up will change the contents of the buffer to "20000".
-static void FillFractionals(uint64_t fractionals, int exponent,
- int fractional_count, Vector<char> buffer,
- int* length, int* decimal_point) {
- ASSERT(-128 <= exponent && exponent <= 0);
- // 'fractionals' is a fixed-point number, with binary point at bit
- // (-exponent). Inside the function the non-converted remainder of fractionals
- // is a fixed-point number, with binary point at bit 'point'.
- if (-exponent <= 64) {
- // One 64 bit number is sufficient.
- ASSERT(fractionals >> 56 == 0);
- int point = -exponent;
- for (int i = 0; i < fractional_count; ++i) {
- if (fractionals == 0) break;
- // Instead of multiplying by 10 we multiply by 5 and adjust the point
- // location. This way the fractionals variable will not overflow.
- // Invariant at the beginning of the loop: fractionals < 2^point.
- // Initially we have: point <= 64 and fractionals < 2^56
- // After each iteration the point is decremented by one.
- // Note that 5^3 = 125 < 128 = 2^7.
- // Therefore three iterations of this loop will not overflow fractionals
- // (even without the subtraction at the end of the loop body). At this
- // time point will satisfy point <= 61 and therefore fractionals < 2^point
- // and any further multiplication of fractionals by 5 will not overflow.
- fractionals *= 5;
- point--;
- int digit = static_cast<int>(fractionals >> point);
- ASSERT(digit <= 9);
- buffer[*length] = static_cast<char>('0' + digit);
- (*length)++;
- fractionals -= static_cast<uint64_t>(digit) << point;
- }
- // If the first bit after the point is set we have to round up.
- if (((fractionals >> (point - 1)) & 1) == 1) {
- RoundUp(buffer, length, decimal_point);
- }
- } else { // We need 128 bits.
- ASSERT(64 < -exponent && -exponent <= 128);
- UInt128 fractionals128 = UInt128(fractionals, 0);
- fractionals128.Shift(-exponent - 64);
- int point = 128;
- for (int i = 0; i < fractional_count; ++i) {
- if (fractionals128.IsZero()) break;
- // As before: instead of multiplying by 10 we multiply by 5 and adjust the
- // point location.
- // This multiplication will not overflow for the same reasons as before.
- fractionals128.Multiply(5);
- point--;
- int digit = fractionals128.DivModPowerOf2(point);
- ASSERT(digit <= 9);
- buffer[*length] = static_cast<char>('0' + digit);
- (*length)++;
- }
- if (fractionals128.BitAt(point - 1) == 1) {
- RoundUp(buffer, length, decimal_point);
- }
- }
-}
-
-
-// Removes leading and trailing zeros.
-// If leading zeros are removed then the decimal point position is adjusted.
-static void TrimZeros(Vector<char> buffer, int* length, int* decimal_point) {
- while (*length > 0 && buffer[(*length) - 1] == '0') {
- (*length)--;
- }
- int first_non_zero = 0;
- while (first_non_zero < *length && buffer[first_non_zero] == '0') {
- first_non_zero++;
- }
- if (first_non_zero != 0) {
- for (int i = first_non_zero; i < *length; ++i) {
- buffer[i - first_non_zero] = buffer[i];
- }
- *length -= first_non_zero;
- *decimal_point -= first_non_zero;
- }
-}
-
-
-bool FastFixedDtoa(double v,
- int fractional_count,
- Vector<char> buffer,
- int* length,
- int* decimal_point) {
- const uint32_t kMaxUInt32 = 0xFFFFFFFF;
- uint64_t significand = Double(v).Significand();
- int exponent = Double(v).Exponent();
- // v = significand * 2^exponent (with significand a 53bit integer).
- // If the exponent is larger than 20 (i.e. we may have a 73bit number) then we
- // don't know how to compute the representation. 2^73 ~= 9.5*10^21.
- // If necessary this limit could probably be increased, but we don't need
- // more.
- if (exponent > 20) return false;
- if (fractional_count > 20) return false;
- *length = 0;
- // At most kDoubleSignificandSize bits of the significand are non-zero.
- // Given a 64 bit integer we have 11 0s followed by 53 potentially non-zero
- // bits: 0..11*..0xxx..53*..xx
- if (exponent + kDoubleSignificandSize > 64) {
- // The exponent must be > 11.
- //
- // We know that v = significand * 2^exponent.
- // And the exponent > 11.
- // We simplify the task by dividing v by 10^17.
- // The quotient delivers the first digits, and the remainder fits into a 64
- // bit number.
- // Dividing by 10^17 is equivalent to dividing by 5^17*2^17.
- const uint64_t kFive17 = UINT64_2PART_C(0xB1, A2BC2EC5); // 5^17
- uint64_t divisor = kFive17;
- int divisor_power = 17;
- uint64_t dividend = significand;
- uint32_t quotient;
- uint64_t remainder;
- // Let v = f * 2^e with f == significand and e == exponent.
- // Then need q (quotient) and r (remainder) as follows:
- // v = q * 10^17 + r
- // f * 2^e = q * 10^17 + r
- // f * 2^e = q * 5^17 * 2^17 + r
- // If e > 17 then
- // f * 2^(e-17) = q * 5^17 + r/2^17
- // else
- // f = q * 5^17 * 2^(17-e) + r/2^e
- if (exponent > divisor_power) {
- // We only allow exponents of up to 20 and therefore (17 - e) <= 3
- dividend <<= exponent - divisor_power;
- quotient = static_cast<uint32_t>(dividend / divisor);
- remainder = (dividend % divisor) << divisor_power;
- } else {
- divisor <<= divisor_power - exponent;
- quotient = static_cast<uint32_t>(dividend / divisor);
- remainder = (dividend % divisor) << exponent;
- }
- FillDigits32(quotient, buffer, length);
- FillDigits64FixedLength(remainder, buffer, length);
- *decimal_point = *length;
- } else if (exponent >= 0) {
- // 0 <= exponent <= 11
- significand <<= exponent;
- FillDigits64(significand, buffer, length);
- *decimal_point = *length;
- } else if (exponent > -kDoubleSignificandSize) {
- // We have to cut the number.
- uint64_t integrals = significand >> -exponent;
- uint64_t fractionals = significand - (integrals << -exponent);
- if (integrals > kMaxUInt32) {
- FillDigits64(integrals, buffer, length);
- } else {
- FillDigits32(static_cast<uint32_t>(integrals), buffer, length);
- }
- *decimal_point = *length;
- FillFractionals(fractionals, exponent, fractional_count,
- buffer, length, decimal_point);
- } else if (exponent < -128) {
- // This configuration (with at most 20 digits) means that all digits must be
- // 0.
- ASSERT(fractional_count <= 20);
- buffer[0] = '\0';
- *length = 0;
- *decimal_point = -fractional_count;
- } else {
- *decimal_point = 0;
- FillFractionals(significand, exponent, fractional_count,
- buffer, length, decimal_point);
- }
- TrimZeros(buffer, length, decimal_point);
- buffer[*length] = '\0';
- if ((*length) == 0) {
- // The string is empty and the decimal_point thus has no importance. Mimick
- // Gay's dtoa and and set it to -fractional_count.
- *decimal_point = -fractional_count;
- }
- return true;
-}
-
-} // namespace double_conversion
diff --git a/src/3rdparty/double-conversion/fixed-dtoa.h b/src/3rdparty/double-conversion/fixed-dtoa.h
deleted file mode 100644
index 3bdd08e21f..0000000000
--- a/src/3rdparty/double-conversion/fixed-dtoa.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef DOUBLE_CONVERSION_FIXED_DTOA_H_
-#define DOUBLE_CONVERSION_FIXED_DTOA_H_
-
-#include "utils.h"
-
-namespace double_conversion {
-
-// Produces digits necessary to print a given number with
-// 'fractional_count' digits after the decimal point.
-// The buffer must be big enough to hold the result plus one terminating null
-// character.
-//
-// The produced digits might be too short in which case the caller has to fill
-// the gaps with '0's.
-// Example: FastFixedDtoa(0.001, 5, ...) is allowed to return buffer = "1", and
-// decimal_point = -2.
-// Halfway cases are rounded towards +/-Infinity (away from 0). The call
-// FastFixedDtoa(0.15, 2, ...) thus returns buffer = "2", decimal_point = 0.
-// The returned buffer may contain digits that would be truncated from the
-// shortest representation of the input.
-//
-// This method only works for some parameters. If it can't handle the input it
-// returns false. The output is null-terminated when the function succeeds.
-bool FastFixedDtoa(double v, int fractional_count,
- Vector<char> buffer, int* length, int* decimal_point);
-
-} // namespace double_conversion
-
-#endif // DOUBLE_CONVERSION_FIXED_DTOA_H_
diff --git a/src/3rdparty/double-conversion/ieee.h b/src/3rdparty/double-conversion/ieee.h
deleted file mode 100644
index 661141d1a8..0000000000
--- a/src/3rdparty/double-conversion/ieee.h
+++ /dev/null
@@ -1,402 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef DOUBLE_CONVERSION_DOUBLE_H_
-#define DOUBLE_CONVERSION_DOUBLE_H_
-
-#include "diy-fp.h"
-
-namespace double_conversion {
-
-// We assume that doubles and uint64_t have the same endianness.
-static uint64_t double_to_uint64(double d) { return BitCast<uint64_t>(d); }
-static double uint64_to_double(uint64_t d64) { return BitCast<double>(d64); }
-static uint32_t float_to_uint32(float f) { return BitCast<uint32_t>(f); }
-static float uint32_to_float(uint32_t d32) { return BitCast<float>(d32); }
-
-// Helper functions for doubles.
-class Double {
- public:
- static const uint64_t kSignMask = UINT64_2PART_C(0x80000000, 00000000);
- static const uint64_t kExponentMask = UINT64_2PART_C(0x7FF00000, 00000000);
- static const uint64_t kSignificandMask = UINT64_2PART_C(0x000FFFFF, FFFFFFFF);
- static const uint64_t kHiddenBit = UINT64_2PART_C(0x00100000, 00000000);
- static const int kPhysicalSignificandSize = 52; // Excludes the hidden bit.
- static const int kSignificandSize = 53;
-
- Double() : d64_(0) {}
- explicit Double(double d) : d64_(double_to_uint64(d)) {}
- explicit Double(uint64_t d64) : d64_(d64) {}
- explicit Double(DiyFp diy_fp)
- : d64_(DiyFpToUint64(diy_fp)) {}
-
- // The value encoded by this Double must be greater or equal to +0.0.
- // It must not be special (infinity, or NaN).
- DiyFp AsDiyFp() const {
- ASSERT(Sign() > 0);
- ASSERT(!IsSpecial());
- return DiyFp(Significand(), Exponent());
- }
-
- // The value encoded by this Double must be strictly greater than 0.
- DiyFp AsNormalizedDiyFp() const {
- ASSERT(value() > 0.0);
- uint64_t f = Significand();
- int e = Exponent();
-
- // The current double could be a denormal.
- while ((f & kHiddenBit) == 0) {
- f <<= 1;
- e--;
- }
- // Do the final shifts in one go.
- f <<= DiyFp::kSignificandSize - kSignificandSize;
- e -= DiyFp::kSignificandSize - kSignificandSize;
- return DiyFp(f, e);
- }
-
- // Returns the double's bit as uint64.
- uint64_t AsUint64() const {
- return d64_;
- }
-
- // Returns the next greater double. Returns +infinity on input +infinity.
- double NextDouble() const {
- if (d64_ == kInfinity) return Double(kInfinity).value();
- if (Sign() < 0 && Significand() == 0) {
- // -0.0
- return 0.0;
- }
- if (Sign() < 0) {
- return Double(d64_ - 1).value();
- } else {
- return Double(d64_ + 1).value();
- }
- }
-
- double PreviousDouble() const {
- if (d64_ == (kInfinity | kSignMask)) return -Double::Infinity();
- if (Sign() < 0) {
- return Double(d64_ + 1).value();
- } else {
- if (Significand() == 0) return -0.0;
- return Double(d64_ - 1).value();
- }
- }
-
- int Exponent() const {
- if (IsDenormal()) return kDenormalExponent;
-
- uint64_t d64 = AsUint64();
- int biased_e =
- static_cast<int>((d64 & kExponentMask) >> kPhysicalSignificandSize);
- return biased_e - kExponentBias;
- }
-
- uint64_t Significand() const {
- uint64_t d64 = AsUint64();
- uint64_t significand = d64 & kSignificandMask;
- if (!IsDenormal()) {
- return significand + kHiddenBit;
- } else {
- return significand;
- }
- }
-
- // Returns true if the double is a denormal.
- bool IsDenormal() const {
- uint64_t d64 = AsUint64();
- return (d64 & kExponentMask) == 0;
- }
-
- // We consider denormals not to be special.
- // Hence only Infinity and NaN are special.
- bool IsSpecial() const {
- uint64_t d64 = AsUint64();
- return (d64 & kExponentMask) == kExponentMask;
- }
-
- bool IsNan() const {
- uint64_t d64 = AsUint64();
- return ((d64 & kExponentMask) == kExponentMask) &&
- ((d64 & kSignificandMask) != 0);
- }
-
- bool IsInfinite() const {
- uint64_t d64 = AsUint64();
- return ((d64 & kExponentMask) == kExponentMask) &&
- ((d64 & kSignificandMask) == 0);
- }
-
- int Sign() const {
- uint64_t d64 = AsUint64();
- return (d64 & kSignMask) == 0? 1: -1;
- }
-
- // Precondition: the value encoded by this Double must be greater or equal
- // than +0.0.
- DiyFp UpperBoundary() const {
- ASSERT(Sign() > 0);
- return DiyFp(Significand() * 2 + 1, Exponent() - 1);
- }
-
- // Computes the two boundaries of this.
- // The bigger boundary (m_plus) is normalized. The lower boundary has the same
- // exponent as m_plus.
- // Precondition: the value encoded by this Double must be greater than 0.
- void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
- ASSERT(value() > 0.0);
- DiyFp v = this->AsDiyFp();
- DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
- DiyFp m_minus;
- if (LowerBoundaryIsCloser()) {
- m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
- } else {
- m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
- }
- m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
- m_minus.set_e(m_plus.e());
- *out_m_plus = m_plus;
- *out_m_minus = m_minus;
- }
-
- bool LowerBoundaryIsCloser() const {
- // The boundary is closer if the significand is of the form f == 2^p-1 then
- // the lower boundary is closer.
- // Think of v = 1000e10 and v- = 9999e9.
- // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
- // at a distance of 1e8.
- // The only exception is for the smallest normal: the largest denormal is
- // at the same distance as its successor.
- // Note: denormals have the same exponent as the smallest normals.
- bool physical_significand_is_zero = ((AsUint64() & kSignificandMask) == 0);
- return physical_significand_is_zero && (Exponent() != kDenormalExponent);
- }
-
- double value() const { return uint64_to_double(d64_); }
-
- // Returns the significand size for a given order of magnitude.
- // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude.
- // This function returns the number of significant binary digits v will have
- // once it's encoded into a double. In almost all cases this is equal to
- // kSignificandSize. The only exceptions are denormals. They start with
- // leading zeroes and their effective significand-size is hence smaller.
- static int SignificandSizeForOrderOfMagnitude(int order) {
- if (order >= (kDenormalExponent + kSignificandSize)) {
- return kSignificandSize;
- }
- if (order <= kDenormalExponent) return 0;
- return order - kDenormalExponent;
- }
-
- static double Infinity() {
- return Double(kInfinity).value();
- }
-
- static double NaN() {
- return Double(kNaN).value();
- }
-
- private:
- static const int kExponentBias = 0x3FF + kPhysicalSignificandSize;
- static const int kDenormalExponent = -kExponentBias + 1;
- static const int kMaxExponent = 0x7FF - kExponentBias;
- static const uint64_t kInfinity = UINT64_2PART_C(0x7FF00000, 00000000);
- static const uint64_t kNaN = UINT64_2PART_C(0x7FF80000, 00000000);
-
- const uint64_t d64_;
-
- static uint64_t DiyFpToUint64(DiyFp diy_fp) {
- uint64_t significand = diy_fp.f();
- int exponent = diy_fp.e();
- while (significand > kHiddenBit + kSignificandMask) {
- significand >>= 1;
- exponent++;
- }
- if (exponent >= kMaxExponent) {
- return kInfinity;
- }
- if (exponent < kDenormalExponent) {
- return 0;
- }
- while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) {
- significand <<= 1;
- exponent--;
- }
- uint64_t biased_exponent;
- if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) {
- biased_exponent = 0;
- } else {
- biased_exponent = static_cast<uint64_t>(exponent + kExponentBias);
- }
- return (significand & kSignificandMask) |
- (biased_exponent << kPhysicalSignificandSize);
- }
-
- DISALLOW_COPY_AND_ASSIGN(Double);
-};
-
-class Single {
- public:
- static const uint32_t kSignMask = 0x80000000;
- static const uint32_t kExponentMask = 0x7F800000;
- static const uint32_t kSignificandMask = 0x007FFFFF;
- static const uint32_t kHiddenBit = 0x00800000;
- static const int kPhysicalSignificandSize = 23; // Excludes the hidden bit.
- static const int kSignificandSize = 24;
-
- Single() : d32_(0) {}
- explicit Single(float f) : d32_(float_to_uint32(f)) {}
- explicit Single(uint32_t d32) : d32_(d32) {}
-
- // The value encoded by this Single must be greater or equal to +0.0.
- // It must not be special (infinity, or NaN).
- DiyFp AsDiyFp() const {
- ASSERT(Sign() > 0);
- ASSERT(!IsSpecial());
- return DiyFp(Significand(), Exponent());
- }
-
- // Returns the single's bit as uint64.
- uint32_t AsUint32() const {
- return d32_;
- }
-
- int Exponent() const {
- if (IsDenormal()) return kDenormalExponent;
-
- uint32_t d32 = AsUint32();
- int biased_e =
- static_cast<int>((d32 & kExponentMask) >> kPhysicalSignificandSize);
- return biased_e - kExponentBias;
- }
-
- uint32_t Significand() const {
- uint32_t d32 = AsUint32();
- uint32_t significand = d32 & kSignificandMask;
- if (!IsDenormal()) {
- return significand + kHiddenBit;
- } else {
- return significand;
- }
- }
-
- // Returns true if the single is a denormal.
- bool IsDenormal() const {
- uint32_t d32 = AsUint32();
- return (d32 & kExponentMask) == 0;
- }
-
- // We consider denormals not to be special.
- // Hence only Infinity and NaN are special.
- bool IsSpecial() const {
- uint32_t d32 = AsUint32();
- return (d32 & kExponentMask) == kExponentMask;
- }
-
- bool IsNan() const {
- uint32_t d32 = AsUint32();
- return ((d32 & kExponentMask) == kExponentMask) &&
- ((d32 & kSignificandMask) != 0);
- }
-
- bool IsInfinite() const {
- uint32_t d32 = AsUint32();
- return ((d32 & kExponentMask) == kExponentMask) &&
- ((d32 & kSignificandMask) == 0);
- }
-
- int Sign() const {
- uint32_t d32 = AsUint32();
- return (d32 & kSignMask) == 0? 1: -1;
- }
-
- // Computes the two boundaries of this.
- // The bigger boundary (m_plus) is normalized. The lower boundary has the same
- // exponent as m_plus.
- // Precondition: the value encoded by this Single must be greater than 0.
- void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
- ASSERT(value() > 0.0);
- DiyFp v = this->AsDiyFp();
- DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
- DiyFp m_minus;
- if (LowerBoundaryIsCloser()) {
- m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
- } else {
- m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
- }
- m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
- m_minus.set_e(m_plus.e());
- *out_m_plus = m_plus;
- *out_m_minus = m_minus;
- }
-
- // Precondition: the value encoded by this Single must be greater or equal
- // than +0.0.
- DiyFp UpperBoundary() const {
- ASSERT(Sign() > 0);
- return DiyFp(Significand() * 2 + 1, Exponent() - 1);
- }
-
- bool LowerBoundaryIsCloser() const {
- // The boundary is closer if the significand is of the form f == 2^p-1 then
- // the lower boundary is closer.
- // Think of v = 1000e10 and v- = 9999e9.
- // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
- // at a distance of 1e8.
- // The only exception is for the smallest normal: the largest denormal is
- // at the same distance as its successor.
- // Note: denormals have the same exponent as the smallest normals.
- bool physical_significand_is_zero = ((AsUint32() & kSignificandMask) == 0);
- return physical_significand_is_zero && (Exponent() != kDenormalExponent);
- }
-
- float value() const { return uint32_to_float(d32_); }
-
- static float Infinity() {
- return Single(kInfinity).value();
- }
-
- static float NaN() {
- return Single(kNaN).value();
- }
-
- private:
- static const int kExponentBias = 0x7F + kPhysicalSignificandSize;
- static const int kDenormalExponent = -kExponentBias + 1;
- static const int kMaxExponent = 0xFF - kExponentBias;
- static const uint32_t kInfinity = 0x7F800000;
- static const uint32_t kNaN = 0x7FC00000;
-
- const uint32_t d32_;
-
- DISALLOW_COPY_AND_ASSIGN(Single);
-};
-
-} // namespace double_conversion
-
-#endif // DOUBLE_CONVERSION_DOUBLE_H_
diff --git a/src/3rdparty/double-conversion/strtod.cc b/src/3rdparty/double-conversion/strtod.cc
deleted file mode 100644
index 34717562bd..0000000000
--- a/src/3rdparty/double-conversion/strtod.cc
+++ /dev/null
@@ -1,555 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <stdarg.h>
-#include <limits.h>
-
-#include "strtod.h"
-#include "bignum.h"
-#include "cached-powers.h"
-#include "ieee.h"
-
-namespace double_conversion {
-
-// 2^53 = 9007199254740992.
-// Any integer with at most 15 decimal digits will hence fit into a double
-// (which has a 53bit significand) without loss of precision.
-static const int kMaxExactDoubleIntegerDecimalDigits = 15;
-// 2^64 = 18446744073709551616 > 10^19
-static const int kMaxUint64DecimalDigits = 19;
-
-// Max double: 1.7976931348623157 x 10^308
-// Min non-zero double: 4.9406564584124654 x 10^-324
-// Any x >= 10^309 is interpreted as +infinity.
-// Any x <= 10^-324 is interpreted as 0.
-// Note that 2.5e-324 (despite being smaller than the min double) will be read
-// as non-zero (equal to the min non-zero double).
-static const int kMaxDecimalPower = 309;
-static const int kMinDecimalPower = -324;
-
-// 2^64 = 18446744073709551616
-static const uint64_t kMaxUint64 = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF);
-
-
-static const double exact_powers_of_ten[] = {
- 1.0, // 10^0
- 10.0,
- 100.0,
- 1000.0,
- 10000.0,
- 100000.0,
- 1000000.0,
- 10000000.0,
- 100000000.0,
- 1000000000.0,
- 10000000000.0, // 10^10
- 100000000000.0,
- 1000000000000.0,
- 10000000000000.0,
- 100000000000000.0,
- 1000000000000000.0,
- 10000000000000000.0,
- 100000000000000000.0,
- 1000000000000000000.0,
- 10000000000000000000.0,
- 100000000000000000000.0, // 10^20
- 1000000000000000000000.0,
- // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22
- 10000000000000000000000.0
-};
-static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten);
-
-// Maximum number of significant digits in the decimal representation.
-// In fact the value is 772 (see conversions.cc), but to give us some margin
-// we round up to 780.
-static const int kMaxSignificantDecimalDigits = 780;
-
-static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) {
- for (int i = 0; i < buffer.length(); i++) {
- if (buffer[i] != '0') {
- return buffer.SubVector(i, buffer.length());
- }
- }
- return Vector<const char>(buffer.start(), 0);
-}
-
-
-static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
- for (int i = buffer.length() - 1; i >= 0; --i) {
- if (buffer[i] != '0') {
- return buffer.SubVector(0, i + 1);
- }
- }
- return Vector<const char>(buffer.start(), 0);
-}
-
-
-static void CutToMaxSignificantDigits(Vector<const char> buffer,
- int exponent,
- char* significant_buffer,
- int* significant_exponent) {
- for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) {
- significant_buffer[i] = buffer[i];
- }
- // The input buffer has been trimmed. Therefore the last digit must be
- // different from '0'.
- ASSERT(buffer[buffer.length() - 1] != '0');
- // Set the last digit to be non-zero. This is sufficient to guarantee
- // correct rounding.
- significant_buffer[kMaxSignificantDecimalDigits - 1] = '1';
- *significant_exponent =
- exponent + (buffer.length() - kMaxSignificantDecimalDigits);
-}
-
-
-// Trims the buffer and cuts it to at most kMaxSignificantDecimalDigits.
-// If possible the input-buffer is reused, but if the buffer needs to be
-// modified (due to cutting), then the input needs to be copied into the
-// buffer_copy_space.
-static void TrimAndCut(Vector<const char> buffer, int exponent,
- char* buffer_copy_space, int space_size,
- Vector<const char>* trimmed, int* updated_exponent) {
- Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
- Vector<const char> right_trimmed = TrimTrailingZeros(left_trimmed);
- exponent += left_trimmed.length() - right_trimmed.length();
- if (right_trimmed.length() > kMaxSignificantDecimalDigits) {
- (void) space_size; // Mark variable as used.
- ASSERT(space_size >= kMaxSignificantDecimalDigits);
- CutToMaxSignificantDigits(right_trimmed, exponent,
- buffer_copy_space, updated_exponent);
- *trimmed = Vector<const char>(buffer_copy_space,
- kMaxSignificantDecimalDigits);
- } else {
- *trimmed = right_trimmed;
- *updated_exponent = exponent;
- }
-}
-
-
-// Reads digits from the buffer and converts them to a uint64.
-// Reads in as many digits as fit into a uint64.
-// When the string starts with "1844674407370955161" no further digit is read.
-// Since 2^64 = 18446744073709551616 it would still be possible read another
-// digit if it was less or equal than 6, but this would complicate the code.
-static uint64_t ReadUint64(Vector<const char> buffer,
- int* number_of_read_digits) {
- uint64_t result = 0;
- int i = 0;
- while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) {
- int digit = buffer[i++] - '0';
- ASSERT(0 <= digit && digit <= 9);
- result = 10 * result + digit;
- }
- *number_of_read_digits = i;
- return result;
-}
-
-
-// Reads a DiyFp from the buffer.
-// The returned DiyFp is not necessarily normalized.
-// If remaining_decimals is zero then the returned DiyFp is accurate.
-// Otherwise it has been rounded and has error of at most 1/2 ulp.
-static void ReadDiyFp(Vector<const char> buffer,
- DiyFp* result,
- int* remaining_decimals) {
- int read_digits;
- uint64_t significand = ReadUint64(buffer, &read_digits);
- if (buffer.length() == read_digits) {
- *result = DiyFp(significand, 0);
- *remaining_decimals = 0;
- } else {
- // Round the significand.
- if (buffer[read_digits] >= '5') {
- significand++;
- }
- // Compute the binary exponent.
- int exponent = 0;
- *result = DiyFp(significand, exponent);
- *remaining_decimals = buffer.length() - read_digits;
- }
-}
-
-
-static bool DoubleStrtod(Vector<const char> trimmed,
- int exponent,
- double* result) {
-#if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
- // On x86 the floating-point stack can be 64 or 80 bits wide. If it is
- // 80 bits wide (as is the case on Linux) then double-rounding occurs and the
- // result is not accurate.
- // We know that Windows32 uses 64 bits and is therefore accurate.
- // Note that the ARM simulator is compiled for 32bits. It therefore exhibits
- // the same problem.
- return false;
-#endif
- if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) {
- int read_digits;
- // The trimmed input fits into a double.
- // If the 10^exponent (resp. 10^-exponent) fits into a double too then we
- // can compute the result-double simply by multiplying (resp. dividing) the
- // two numbers.
- // This is possible because IEEE guarantees that floating-point operations
- // return the best possible approximation.
- if (exponent < 0 && -exponent < kExactPowersOfTenSize) {
- // 10^-exponent fits into a double.
- *result = static_cast<double>(ReadUint64(trimmed, &read_digits));
- ASSERT(read_digits == trimmed.length());
- *result /= exact_powers_of_ten[-exponent];
- return true;
- }
- if (0 <= exponent && exponent < kExactPowersOfTenSize) {
- // 10^exponent fits into a double.
- *result = static_cast<double>(ReadUint64(trimmed, &read_digits));
- ASSERT(read_digits == trimmed.length());
- *result *= exact_powers_of_ten[exponent];
- return true;
- }
- int remaining_digits =
- kMaxExactDoubleIntegerDecimalDigits - trimmed.length();
- if ((0 <= exponent) &&
- (exponent - remaining_digits < kExactPowersOfTenSize)) {
- // The trimmed string was short and we can multiply it with
- // 10^remaining_digits. As a result the remaining exponent now fits
- // into a double too.
- *result = static_cast<double>(ReadUint64(trimmed, &read_digits));
- ASSERT(read_digits == trimmed.length());
- *result *= exact_powers_of_ten[remaining_digits];
- *result *= exact_powers_of_ten[exponent - remaining_digits];
- return true;
- }
- }
- return false;
-}
-
-
-// Returns 10^exponent as an exact DiyFp.
-// The given exponent must be in the range [1; kDecimalExponentDistance[.
-static DiyFp AdjustmentPowerOfTen(int exponent) {
- ASSERT(0 < exponent);
- ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance);
- // Simply hardcode the remaining powers for the given decimal exponent
- // distance.
- ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8);
- switch (exponent) {
- case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60);
- case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57);
- case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54);
- case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50);
- case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47);
- case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44);
- case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40);
- default:
- UNREACHABLE();
- }
-}
-
-
-// If the function returns true then the result is the correct double.
-// Otherwise it is either the correct double or the double that is just below
-// the correct double.
-static bool DiyFpStrtod(Vector<const char> buffer,
- int exponent,
- double* result) {
- DiyFp input;
- int remaining_decimals;
- ReadDiyFp(buffer, &input, &remaining_decimals);
- // Since we may have dropped some digits the input is not accurate.
- // If remaining_decimals is different than 0 than the error is at most
- // .5 ulp (unit in the last place).
- // We don't want to deal with fractions and therefore keep a common
- // denominator.
- const int kDenominatorLog = 3;
- const int kDenominator = 1 << kDenominatorLog;
- // Move the remaining decimals into the exponent.
- exponent += remaining_decimals;
- int error = (remaining_decimals == 0 ? 0 : kDenominator / 2);
-
- int old_e = input.e();
- input.Normalize();
- error <<= old_e - input.e();
-
- ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent);
- if (exponent < PowersOfTenCache::kMinDecimalExponent) {
- *result = 0.0;
- return true;
- }
- DiyFp cached_power;
- int cached_decimal_exponent;
- PowersOfTenCache::GetCachedPowerForDecimalExponent(exponent,
- &cached_power,
- &cached_decimal_exponent);
-
- if (cached_decimal_exponent != exponent) {
- int adjustment_exponent = exponent - cached_decimal_exponent;
- DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent);
- input.Multiply(adjustment_power);
- if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) {
- // The product of input with the adjustment power fits into a 64 bit
- // integer.
- ASSERT(DiyFp::kSignificandSize == 64);
- } else {
- // The adjustment power is exact. There is hence only an error of 0.5.
- error += kDenominator / 2;
- }
- }
-
- input.Multiply(cached_power);
- // The error introduced by a multiplication of a*b equals
- // error_a + error_b + error_a*error_b/2^64 + 0.5
- // Substituting a with 'input' and b with 'cached_power' we have
- // error_b = 0.5 (all cached powers have an error of less than 0.5 ulp),
- // error_ab = 0 or 1 / kDenominator > error_a*error_b/ 2^64
- int error_b = kDenominator / 2;
- int error_ab = (error == 0 ? 0 : 1); // We round up to 1.
- int fixed_error = kDenominator / 2;
- error += error_b + error_ab + fixed_error;
-
- old_e = input.e();
- input.Normalize();
- error <<= old_e - input.e();
-
- // See if the double's significand changes if we add/subtract the error.
- int order_of_magnitude = DiyFp::kSignificandSize + input.e();
- int effective_significand_size =
- Double::SignificandSizeForOrderOfMagnitude(order_of_magnitude);
- int precision_digits_count =
- DiyFp::kSignificandSize - effective_significand_size;
- if (precision_digits_count + kDenominatorLog >= DiyFp::kSignificandSize) {
- // This can only happen for very small denormals. In this case the
- // half-way multiplied by the denominator exceeds the range of an uint64.
- // Simply shift everything to the right.
- int shift_amount = (precision_digits_count + kDenominatorLog) -
- DiyFp::kSignificandSize + 1;
- input.set_f(input.f() >> shift_amount);
- input.set_e(input.e() + shift_amount);
- // We add 1 for the lost precision of error, and kDenominator for
- // the lost precision of input.f().
- error = (error >> shift_amount) + 1 + kDenominator;
- precision_digits_count -= shift_amount;
- }
- // We use uint64_ts now. This only works if the DiyFp uses uint64_ts too.
- ASSERT(DiyFp::kSignificandSize == 64);
- ASSERT(precision_digits_count < 64);
- uint64_t one64 = 1;
- uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1;
- uint64_t precision_bits = input.f() & precision_bits_mask;
- uint64_t half_way = one64 << (precision_digits_count - 1);
- precision_bits *= kDenominator;
- half_way *= kDenominator;
- DiyFp rounded_input(input.f() >> precision_digits_count,
- input.e() + precision_digits_count);
- if (precision_bits >= half_way + error) {
- rounded_input.set_f(rounded_input.f() + 1);
- }
- // If the last_bits are too close to the half-way case than we are too
- // inaccurate and round down. In this case we return false so that we can
- // fall back to a more precise algorithm.
-
- *result = Double(rounded_input).value();
- if (half_way - error < precision_bits && precision_bits < half_way + error) {
- // Too imprecise. The caller will have to fall back to a slower version.
- // However the returned number is guaranteed to be either the correct
- // double, or the next-lower double.
- return false;
- } else {
- return true;
- }
-}
-
-
-// Returns
-// - -1 if buffer*10^exponent < diy_fp.
-// - 0 if buffer*10^exponent == diy_fp.
-// - +1 if buffer*10^exponent > diy_fp.
-// Preconditions:
-// buffer.length() + exponent <= kMaxDecimalPower + 1
-// buffer.length() + exponent > kMinDecimalPower
-// buffer.length() <= kMaxDecimalSignificantDigits
-static int CompareBufferWithDiyFp(Vector<const char> buffer,
- int exponent,
- DiyFp diy_fp) {
- ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);
- ASSERT(buffer.length() + exponent > kMinDecimalPower);
- ASSERT(buffer.length() <= kMaxSignificantDecimalDigits);
- // Make sure that the Bignum will be able to hold all our numbers.
- // Our Bignum implementation has a separate field for exponents. Shifts will
- // consume at most one bigit (< 64 bits).
- // ln(10) == 3.3219...
- ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits);
- Bignum buffer_bignum;
- Bignum diy_fp_bignum;
- buffer_bignum.AssignDecimalString(buffer);
- diy_fp_bignum.AssignUInt64(diy_fp.f());
- if (exponent >= 0) {
- buffer_bignum.MultiplyByPowerOfTen(exponent);
- } else {
- diy_fp_bignum.MultiplyByPowerOfTen(-exponent);
- }
- if (diy_fp.e() > 0) {
- diy_fp_bignum.ShiftLeft(diy_fp.e());
- } else {
- buffer_bignum.ShiftLeft(-diy_fp.e());
- }
- return Bignum::Compare(buffer_bignum, diy_fp_bignum);
-}
-
-
-// Returns true if the guess is the correct double.
-// Returns false, when guess is either correct or the next-lower double.
-static bool ComputeGuess(Vector<const char> trimmed, int exponent,
- double* guess) {
- if (trimmed.length() == 0) {
- *guess = 0.0;
- return true;
- }
- if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) {
- *guess = Double::Infinity();
- return true;
- }
- if (exponent + trimmed.length() <= kMinDecimalPower) {
- *guess = 0.0;
- return true;
- }
-
- if (DoubleStrtod(trimmed, exponent, guess) ||
- DiyFpStrtod(trimmed, exponent, guess)) {
- return true;
- }
- if (*guess == Double::Infinity()) {
- return true;
- }
- return false;
-}
-
-double Strtod(Vector<const char> buffer, int exponent) {
- char copy_buffer[kMaxSignificantDecimalDigits];
- Vector<const char> trimmed;
- int updated_exponent;
- TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
- &trimmed, &updated_exponent);
- exponent = updated_exponent;
-
- double guess;
- bool is_correct = ComputeGuess(trimmed, exponent, &guess);
- if (is_correct) return guess;
-
- DiyFp upper_boundary = Double(guess).UpperBoundary();
- int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
- if (comparison < 0) {
- return guess;
- } else if (comparison > 0) {
- return Double(guess).NextDouble();
- } else if ((Double(guess).Significand() & 1) == 0) {
- // Round towards even.
- return guess;
- } else {
- return Double(guess).NextDouble();
- }
-}
-
-float Strtof(Vector<const char> buffer, int exponent) {
- char copy_buffer[kMaxSignificantDecimalDigits];
- Vector<const char> trimmed;
- int updated_exponent;
- TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
- &trimmed, &updated_exponent);
- exponent = updated_exponent;
-
- double double_guess;
- bool is_correct = ComputeGuess(trimmed, exponent, &double_guess);
-
- float float_guess = static_cast<float>(double_guess);
- if (float_guess == double_guess) {
- // This shortcut triggers for integer values.
- return float_guess;
- }
-
- // We must catch double-rounding. Say the double has been rounded up, and is
- // now a boundary of a float, and rounds up again. This is why we have to
- // look at previous too.
- // Example (in decimal numbers):
- // input: 12349
- // high-precision (4 digits): 1235
- // low-precision (3 digits):
- // when read from input: 123
- // when rounded from high precision: 124.
- // To do this we simply look at the neigbors of the correct result and see
- // if they would round to the same float. If the guess is not correct we have
- // to look at four values (since two different doubles could be the correct
- // double).
-
- double double_next = Double(double_guess).NextDouble();
- double double_previous = Double(double_guess).PreviousDouble();
-
- float f1 = static_cast<float>(double_previous);
- float f2 = float_guess;
- float f3 = static_cast<float>(double_next);
- float f4;
- if (is_correct) {
- f4 = f3;
- } else {
- double double_next2 = Double(double_next).NextDouble();
- f4 = static_cast<float>(double_next2);
- }
- (void) f2; // Mark variable as used.
- ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4);
-
- // If the guess doesn't lie near a single-precision boundary we can simply
- // return its float-value.
- if (f1 == f4) {
- return float_guess;
- }
-
- ASSERT((f1 != f2 && f2 == f3 && f3 == f4) ||
- (f1 == f2 && f2 != f3 && f3 == f4) ||
- (f1 == f2 && f2 == f3 && f3 != f4));
-
- // guess and next are the two possible canditates (in the same way that
- // double_guess was the lower candidate for a double-precision guess).
- float guess = f1;
- float next = f4;
- DiyFp upper_boundary;
- if (guess == 0.0f) {
- float min_float = 1e-45f;
- upper_boundary = Double(static_cast<double>(min_float) / 2).AsDiyFp();
- } else {
- upper_boundary = Single(guess).UpperBoundary();
- }
- int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
- if (comparison < 0) {
- return guess;
- } else if (comparison > 0) {
- return next;
- } else if ((Single(guess).Significand() & 1) == 0) {
- // Round towards even.
- return guess;
- } else {
- return next;
- }
-}
-
-} // namespace double_conversion
diff --git a/src/3rdparty/double-conversion/strtod.h b/src/3rdparty/double-conversion/strtod.h
deleted file mode 100644
index ed0293b8f5..0000000000
--- a/src/3rdparty/double-conversion/strtod.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef DOUBLE_CONVERSION_STRTOD_H_
-#define DOUBLE_CONVERSION_STRTOD_H_
-
-#include "utils.h"
-
-namespace double_conversion {
-
-// The buffer must only contain digits in the range [0-9]. It must not
-// contain a dot or a sign. It must not start with '0', and must not be empty.
-double Strtod(Vector<const char> buffer, int exponent);
-
-// The buffer must only contain digits in the range [0-9]. It must not
-// contain a dot or a sign. It must not start with '0', and must not be empty.
-float Strtof(Vector<const char> buffer, int exponent);
-
-} // namespace double_conversion
-
-#endif // DOUBLE_CONVERSION_STRTOD_H_
diff --git a/src/3rdparty/double-conversion/utils.h b/src/3rdparty/double-conversion/utils.h
deleted file mode 100644
index 53eec64282..0000000000
--- a/src/3rdparty/double-conversion/utils.h
+++ /dev/null
@@ -1,330 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef DOUBLE_CONVERSION_UTILS_H_
-#define DOUBLE_CONVERSION_UTILS_H_
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <assert.h>
-#ifndef ASSERT
-# if defined(WINCE) || defined(_WIN32_WCE)
-# define ASSERT(condition)
-# else
-# define ASSERT(condition) \
- assert(condition);
-# endif
-#endif
-#ifndef UNIMPLEMENTED
-# define UNIMPLEMENTED() (exit(-1))
-#endif
-#ifndef UNREACHABLE
-# define UNREACHABLE() (exit(-1))
-#endif
-
-// Double operations detection based on target architecture.
-// Linux uses a 80bit wide floating point stack on x86. This induces double
-// rounding, which in turn leads to wrong results.
-// An easy way to test if the floating-point operations are correct is to
-// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then
-// the result is equal to 89255e-22.
-// The best way to test this, is to create a division-function and to compare
-// the output of the division with the expected result. (Inlining must be
-// disabled.)
-// On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
-#if defined(_M_X64) || defined(__x86_64__) || \
- defined(__ARMEL__) || defined(__avr32__) || _M_ARM_FP || \
- defined(__hppa__) || defined(__ia64__) || \
- defined(__mips__) || \
- defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
- defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
- defined(__SH4__) || defined(__alpha__) || \
- defined(_MIPS_ARCH_MIPS32R2) || \
- defined(__AARCH64EL__)
-#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
-#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
-#if defined(_WIN32)
-// Windows uses a 64bit wide floating point stack.
-#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
-#else
-#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
-#endif // _WIN32
-#elif defined(WINCE) || defined(_WIN32_WCE)
-#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
-#else
-#error Target architecture was not detected as supported by Double-Conversion.
-#endif
-
-#if defined(__GNUC__)
-#define DOUBLE_CONVERSION_UNUSED __attribute__((unused))
-#else
-#define DOUBLE_CONVERSION_UNUSED
-#endif
-
-#if defined(_WIN32) && !defined(__MINGW32__)
-
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef short int16_t; // NOLINT
-typedef unsigned short uint16_t; // NOLINT
-typedef int int32_t;
-typedef unsigned int uint32_t;
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-// intptr_t and friends are defined in crtdefs.h through stdio.h.
-
-#else
-
-#include <stdint.h>
-
-#endif
-
-typedef uint16_t uc16;
-
-// The following macro works on both 32 and 64-bit platforms.
-// Usage: instead of writing 0x1234567890123456
-// write UINT64_2PART_C(0x12345678,90123456);
-#define UINT64_2PART_C(a, b) (((static_cast<uint64_t>(a) << 32) + 0x##b##u))
-
-
-// The expression ARRAY_SIZE(a) is a compile-time constant of type
-// size_t which represents the number of elements of the given
-// array. You should only use ARRAY_SIZE on statically allocated
-// arrays.
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(a) \
- ((sizeof(a) / sizeof(*(a))) / \
- static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
-#endif
-
-// A macro to disallow the evil copy constructor and operator= functions
-// This should be used in the private: declarations for a class
-#ifndef DISALLOW_COPY_AND_ASSIGN
-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
- TypeName(const TypeName&); \
- void operator=(const TypeName&)
-#endif
-
-// A macro to disallow all the implicit constructors, namely the
-// default constructor, copy constructor and operator= functions.
-//
-// This should be used in the private: declarations for a class
-// that wants to prevent anyone from instantiating it. This is
-// especially useful for classes containing only static methods.
-#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS
-#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
- TypeName(); \
- DISALLOW_COPY_AND_ASSIGN(TypeName)
-#endif
-
-namespace double_conversion {
-
-static const int kCharSize = sizeof(char);
-
-// Returns the maximum of the two parameters.
-template <typename T>
-static T Max(T a, T b) {
- return a < b ? b : a;
-}
-
-
-// Returns the minimum of the two parameters.
-template <typename T>
-static T Min(T a, T b) {
- return a < b ? a : b;
-}
-
-
-inline int StrLength(const char* string) {
- size_t length = strlen(string);
- ASSERT(length == static_cast<size_t>(static_cast<int>(length)));
- return static_cast<int>(length);
-}
-
-// This is a simplified version of V8's Vector class.
-template <typename T>
-class Vector {
- public:
- Vector() : start_(NULL), length_(0) {}
- Vector(T* data, int length) : start_(data), length_(length) {
- ASSERT(length == 0 || (length > 0 && data != NULL));
- }
-
- // Returns a vector using the same backing storage as this one,
- // spanning from and including 'from', to but not including 'to'.
- Vector<T> SubVector(int from, int to) {
- ASSERT(to <= length_);
- ASSERT(from < to);
- ASSERT(0 <= from);
- return Vector<T>(start() + from, to - from);
- }
-
- // Returns the length of the vector.
- int length() const { return length_; }
-
- // Returns whether or not the vector is empty.
- bool is_empty() const { return length_ == 0; }
-
- // Returns the pointer to the start of the data in the vector.
- T* start() const { return start_; }
-
- // Access individual vector elements - checks bounds in debug mode.
- T& operator[](int index) const {
- ASSERT(0 <= index && index < length_);
- return start_[index];
- }
-
- T& first() { return start_[0]; }
-
- T& last() { return start_[length_ - 1]; }
-
- private:
- T* start_;
- int length_;
-};
-
-
-// Helper class for building result strings in a character buffer. The
-// purpose of the class is to use safe operations that checks the
-// buffer bounds on all operations in debug mode.
-class StringBuilder {
- public:
- StringBuilder(char* buffer, int size)
- : buffer_(buffer, size), position_(0) { }
-
- ~StringBuilder() { if (!is_finalized()) Finalize(); }
-
- int size() const { return buffer_.length(); }
-
- // Get the current position in the builder.
- int position() const {
- ASSERT(!is_finalized());
- return position_;
- }
-
- // Reset the position.
- void Reset() { position_ = 0; }
-
- // Add a single character to the builder. It is not allowed to add
- // 0-characters; use the Finalize() method to terminate the string
- // instead.
- void AddCharacter(char c) {
- ASSERT(c != '\0');
- ASSERT(!is_finalized() && position_ < buffer_.length());
- buffer_[position_++] = c;
- }
-
- // Add an entire string to the builder. Uses strlen() internally to
- // compute the length of the input string.
- void AddString(const char* s) {
- AddSubstring(s, StrLength(s));
- }
-
- // Add the first 'n' characters of the given string 's' to the
- // builder. The input string must have enough characters.
- void AddSubstring(const char* s, int n) {
- ASSERT(!is_finalized() && position_ + n < buffer_.length());
- ASSERT(static_cast<size_t>(n) <= strlen(s));
- memmove(&buffer_[position_], s, n * kCharSize);
- position_ += n;
- }
-
-
- // Add character padding to the builder. If count is non-positive,
- // nothing is added to the builder.
- void AddPadding(char c, int count) {
- for (int i = 0; i < count; i++) {
- AddCharacter(c);
- }
- }
-
- // Finalize the string by 0-terminating it and returning the buffer.
- char* Finalize() {
- ASSERT(!is_finalized() && position_ < buffer_.length());
- buffer_[position_] = '\0';
- // Make sure nobody managed to add a 0-character to the
- // buffer while building the string.
- ASSERT(strlen(buffer_.start()) == static_cast<size_t>(position_));
- position_ = -1;
- ASSERT(is_finalized());
- return buffer_.start();
- }
-
- private:
- Vector<char> buffer_;
- int position_;
-
- bool is_finalized() const { return position_ < 0; }
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
-};
-
-// The type-based aliasing rule allows the compiler to assume that pointers of
-// different types (for some definition of different) never alias each other.
-// Thus the following code does not work:
-//
-// float f = foo();
-// int fbits = *(int*)(&f);
-//
-// The compiler 'knows' that the int pointer can't refer to f since the types
-// don't match, so the compiler may cache f in a register, leaving random data
-// in fbits. Using C++ style casts makes no difference, however a pointer to
-// char data is assumed to alias any other pointer. This is the 'memcpy
-// exception'.
-//
-// Bit_cast uses the memcpy exception to move the bits from a variable of one
-// type of a variable of another type. Of course the end result is likely to
-// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005)
-// will completely optimize BitCast away.
-//
-// There is an additional use for BitCast.
-// Recent gccs will warn when they see casts that may result in breakage due to
-// the type-based aliasing rule. If you have checked that there is no breakage
-// you can use BitCast to cast one pointer type to another. This confuses gcc
-// enough that it can no longer see that you have cast one pointer type to
-// another thus avoiding the warning.
-template <class Dest, class Source>
-inline Dest BitCast(const Source& source) {
- // Compile time assertion: sizeof(Dest) == sizeof(Source)
- // A compile error here means your Dest and Source have different sizes.
- DOUBLE_CONVERSION_UNUSED
- typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
-
- Dest dest;
- memmove(&dest, &source, sizeof(dest));
- return dest;
-}
-
-template <class Dest, class Source>
-inline Dest BitCast(Source* source) {
- return BitCast<Dest>(reinterpret_cast<uintptr_t>(source));
-}
-
-} // namespace double_conversion
-
-#endif // DOUBLE_CONVERSION_UTILS_H_
diff --git a/src/3rdparty/masm/WeakRandom.h b/src/3rdparty/masm/WeakRandom.h
index bf5d20e360..924bac00c4 100644
--- a/src/3rdparty/masm/WeakRandom.h
+++ b/src/3rdparty/masm/WeakRandom.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/assembler/ARM64Assembler.h b/src/3rdparty/masm/assembler/ARM64Assembler.h
new file mode 100644
index 0000000000..ad5acdbb85
--- /dev/null
+++ b/src/3rdparty/masm/assembler/ARM64Assembler.h
@@ -0,0 +1,3772 @@
+/*
+ * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ARM64Assembler_h
+#define ARM64Assembler_h
+
+#if ENABLE(ASSEMBLER) && CPU(ARM64)
+
+#include "AssemblerBuffer.h"
+#include <limits.h>
+#include <wtf/Assertions.h>
+#include <wtf/Vector.h>
+#include <stdint.h>
+
+#if OS(IOS)
+#include <libkern/OSCacheControl.h>
+#endif
+
+#define CHECK_DATASIZE_OF(datasize) ASSERT(datasize == 32 || datasize == 64)
+#define DATASIZE_OF(datasize) ((datasize == 64) ? Datasize_64 : Datasize_32)
+#define MEMOPSIZE_OF(datasize) ((datasize == 8 || datasize == 128) ? MemOpSize_8_or_128 : (datasize == 16) ? MemOpSize_16 : (datasize == 32) ? MemOpSize_32 : MemOpSize_64)
+#define CHECK_DATASIZE() CHECK_DATASIZE_OF(datasize)
+#define CHECK_VECTOR_DATASIZE() ASSERT(datasize == 64 || datasize == 128)
+#define DATASIZE DATASIZE_OF(datasize)
+#define MEMOPSIZE MEMOPSIZE_OF(datasize)
+#define CHECK_FP_MEMOP_DATASIZE() ASSERT(datasize == 8 || datasize == 16 || datasize == 32 || datasize == 64 || datasize == 128)
+#define MEMPAIROPSIZE_INT(datasize) ((datasize == 64) ? MemPairOp_64 : MemPairOp_32)
+#define MEMPAIROPSIZE_FP(datasize) ((datasize == 128) ? MemPairOp_V128 : (datasize == 64) ? MemPairOp_V64 : MemPairOp_32)
+
+namespace JSC {
+
+ALWAYS_INLINE bool isInt9(int32_t value)
+{
+ return value == ((value << 23) >> 23);
+}
+
+template<typename Type>
+ALWAYS_INLINE bool isUInt12(Type value)
+{
+ return !(value & ~static_cast<Type>(0xfff));
+}
+
+template<int datasize>
+ALWAYS_INLINE bool isValidScaledUImm12(int32_t offset)
+{
+ int32_t maxPImm = 4095 * (datasize / 8);
+ if (offset < 0)
+ return false;
+ if (offset > maxPImm)
+ return false;
+ if (offset & ((datasize / 8) - 1))
+ return false;
+ return true;
+}
+
+ALWAYS_INLINE bool isValidSignedImm9(int32_t value)
+{
+ return isInt9(value);
+}
+
+ALWAYS_INLINE bool isInt7(int32_t value)
+{
+ return value == ((value << 25) >> 25);
+}
+
+ALWAYS_INLINE bool isInt11(int32_t value)
+{
+ return value == ((value << 21) >> 21);
+}
+
+ALWAYS_INLINE bool isUInt5(int32_t value)
+{
+ return !(value & ~0x1f);
+}
+
+class UInt5 {
+public:
+ explicit UInt5(int value)
+ : m_value(value)
+ {
+ ASSERT(isUInt5(value));
+ }
+
+ operator int() { return m_value; }
+
+private:
+ int m_value;
+};
+
+class UInt12 {
+public:
+ explicit UInt12(int value)
+ : m_value(value)
+ {
+ ASSERT(isUInt12(value));
+ }
+
+ operator int() { return m_value; }
+
+private:
+ int m_value;
+};
+
+class PostIndex {
+public:
+ explicit PostIndex(int value)
+ : m_value(value)
+ {
+ ASSERT(isInt9(value));
+ }
+
+ operator int() { return m_value; }
+
+private:
+ int m_value;
+};
+
+class PreIndex {
+public:
+ explicit PreIndex(int value)
+ : m_value(value)
+ {
+ ASSERT(isInt9(value));
+ }
+
+ operator int() { return m_value; }
+
+private:
+ int m_value;
+};
+
+class PairPostIndex {
+public:
+ explicit PairPostIndex(int value)
+ : m_value(value)
+ {
+ ASSERT(isInt11(value));
+ }
+
+ operator int() { return m_value; }
+
+private:
+ int m_value;
+};
+
+class PairPreIndex {
+public:
+ explicit PairPreIndex(int value)
+ : m_value(value)
+ {
+ ASSERT(isInt11(value));
+ }
+
+ operator int() { return m_value; }
+
+private:
+ int m_value;
+};
+
+class LogicalImmediate {
+public:
+ static LogicalImmediate create32(uint32_t value)
+ {
+ // Check for 0, -1 - these cannot be encoded.
+ if (!value || !~value)
+ return InvalidLogicalImmediate;
+
+ // First look for a 32-bit pattern, then for repeating 16-bit
+ // patterns, 8-bit, 4-bit, and finally 2-bit.
+
+ unsigned hsb, lsb;
+ bool inverted;
+ if (findBitRange<32>(value, hsb, lsb, inverted))
+ return encodeLogicalImmediate<32>(hsb, lsb, inverted);
+
+ if ((value & 0xffff) != (value >> 16))
+ return InvalidLogicalImmediate;
+ value &= 0xffff;
+
+ if (findBitRange<16>(value, hsb, lsb, inverted))
+ return encodeLogicalImmediate<16>(hsb, lsb, inverted);
+
+ if ((value & 0xff) != (value >> 8))
+ return InvalidLogicalImmediate;
+ value &= 0xff;
+
+ if (findBitRange<8>(value, hsb, lsb, inverted))
+ return encodeLogicalImmediate<8>(hsb, lsb, inverted);
+
+ if ((value & 0xf) != (value >> 4))
+ return InvalidLogicalImmediate;
+ value &= 0xf;
+
+ if (findBitRange<4>(value, hsb, lsb, inverted))
+ return encodeLogicalImmediate<4>(hsb, lsb, inverted);
+
+ if ((value & 0x3) != (value >> 2))
+ return InvalidLogicalImmediate;
+ value &= 0x3;
+
+ if (findBitRange<2>(value, hsb, lsb, inverted))
+ return encodeLogicalImmediate<2>(hsb, lsb, inverted);
+
+ return InvalidLogicalImmediate;
+ }
+
+ static LogicalImmediate create64(uint64_t value)
+ {
+ // Check for 0, -1 - these cannot be encoded.
+ if (!value || !~value)
+ return InvalidLogicalImmediate;
+
+ // Look for a contiguous bit range.
+ unsigned hsb, lsb;
+ bool inverted;
+ if (findBitRange<64>(value, hsb, lsb, inverted))
+ return encodeLogicalImmediate<64>(hsb, lsb, inverted);
+
+ // If the high & low 32 bits are equal, we can try for a 32-bit (or narrower) pattern.
+ if (static_cast<uint32_t>(value) == static_cast<uint32_t>(value >> 32))
+ return create32(static_cast<uint32_t>(value));
+ return InvalidLogicalImmediate;
+ }
+
+ int value() const
+ {
+ ASSERT(isValid());
+ return m_value;
+ }
+
+ bool isValid() const
+ {
+ return m_value != InvalidLogicalImmediate;
+ }
+
+ bool is64bit() const
+ {
+ return m_value & (1 << 12);
+ }
+
+private:
+ LogicalImmediate(int value)
+ : m_value(value)
+ {
+ }
+
+ // Generate a mask with bits in the range hsb..0 set, for example:
+ // hsb:63 = 0xffffffffffffffff
+ // hsb:42 = 0x000007ffffffffff
+ // hsb: 0 = 0x0000000000000001
+ static uint64_t mask(unsigned hsb)
+ {
+ ASSERT(hsb < 64);
+ return 0xffffffffffffffffull >> (63 - hsb);
+ }
+
+ template<unsigned N>
+ static void partialHSB(uint64_t& value, unsigned&result)
+ {
+ if (value & (0xffffffffffffffffull << N)) {
+ result += N;
+ value >>= N;
+ }
+ }
+
+ // Find the bit number of the highest bit set in a non-zero value, for example:
+ // 0x8080808080808080 = hsb:63
+ // 0x0000000000000001 = hsb: 0
+ // 0x000007ffffe00000 = hsb:42
+ static unsigned highestSetBit(uint64_t value)
+ {
+ ASSERT(value);
+ unsigned hsb = 0;
+ partialHSB<32>(value, hsb);
+ partialHSB<16>(value, hsb);
+ partialHSB<8>(value, hsb);
+ partialHSB<4>(value, hsb);
+ partialHSB<2>(value, hsb);
+ partialHSB<1>(value, hsb);
+ return hsb;
+ }
+
+ // This function takes a value and a bit width, where value obeys the following constraints:
+ // * bits outside of the width of the value must be zero.
+ // * bits within the width of value must neither be all clear or all set.
+ // The input is inspected to detect values that consist of either two or three contiguous
+ // ranges of bits. The output range hsb..lsb will describe the second range of the value.
+ // if the range is set, inverted will be false, and if the range is clear, inverted will
+ // be true. For example (with width 8):
+ // 00001111 = hsb:3, lsb:0, inverted:false
+ // 11110000 = hsb:3, lsb:0, inverted:true
+ // 00111100 = hsb:5, lsb:2, inverted:false
+ // 11000011 = hsb:5, lsb:2, inverted:true
+ template<unsigned width>
+ static bool findBitRange(uint64_t value, unsigned& hsb, unsigned& lsb, bool& inverted)
+ {
+ ASSERT(value & mask(width - 1));
+ ASSERT(value != mask(width - 1));
+ ASSERT(!(value & ~mask(width - 1)));
+
+ // Detect cases where the top bit is set; if so, flip all the bits & set invert.
+ // This halves the number of patterns we need to look for.
+ const uint64_t msb = 1ull << (width - 1);
+ if ((inverted = (value & msb)))
+ value ^= mask(width - 1);
+
+ // Find the highest set bit in value, generate a corresponding mask & flip all
+ // bits under it.
+ hsb = highestSetBit(value);
+ value ^= mask(hsb);
+ if (!value) {
+ // If this cleared the value, then the range hsb..0 was all set.
+ lsb = 0;
+ return true;
+ }
+
+ // Try making one more mask, and flipping the bits!
+ lsb = highestSetBit(value);
+ value ^= mask(lsb);
+ if (!value) {
+ // Success - but lsb actually points to the hsb of a third range - add one
+ // to get to the lsb of the mid range.
+ ++lsb;
+ return true;
+ }
+
+ return false;
+ }
+
+ // Encodes the set of immN:immr:imms fields found in a logical immediate.
+ template<unsigned width>
+ static int encodeLogicalImmediate(unsigned hsb, unsigned lsb, bool inverted)
+ {
+ // Check width is a power of 2!
+ ASSERT(!(width & (width -1)));
+ ASSERT(width <= 64 && width >= 2);
+ ASSERT(hsb >= lsb);
+ ASSERT(hsb < width);
+
+ int immN = 0;
+ int imms = 0;
+ int immr = 0;
+
+ // For 64-bit values this is easy - just set immN to true, and imms just
+ // contains the bit number of the highest set bit of the set range. For
+ // values with narrower widths, these are encoded by a leading set of
+ // one bits, followed by a zero bit, followed by the remaining set of bits
+ // being the high bit of the range. For a 32-bit immediate there are no
+ // leading one bits, just a zero followed by a five bit number. For a
+ // 16-bit immediate there is one one bit, a zero bit, and then a four bit
+ // bit-position, etc.
+ if (width == 64)
+ immN = 1;
+ else
+ imms = 63 & ~(width + width - 1);
+
+ if (inverted) {
+ // if width is 64 & hsb is 62, then we have a value something like:
+ // 0x80000000ffffffff (in this case with lsb 32).
+ // The ror should be by 1, imms (effectively set width minus 1) is
+ // 32. Set width is full width minus cleared width.
+ immr = (width - 1) - hsb;
+ imms |= (width - ((hsb - lsb) + 1)) - 1;
+ } else {
+ // if width is 64 & hsb is 62, then we have a value something like:
+ // 0x7fffffff00000000 (in this case with lsb 32).
+ // The value is effectively rol'ed by lsb, which is equivalent to
+ // a ror by width - lsb (or 0, in the case where lsb is 0). imms
+ // is hsb - lsb.
+ immr = (width - lsb) & (width - 1);
+ imms |= hsb - lsb;
+ }
+
+ return immN << 12 | immr << 6 | imms;
+ }
+
+ static const int InvalidLogicalImmediate = -1;
+
+ int m_value;
+};
+
+inline uint16_t getHalfword(uint64_t value, int which)
+{
+ return value >> (which << 4);
+}
+
+namespace ARM64Registers {
+
+#define FOR_EACH_CPU_REGISTER(V) \
+ FOR_EACH_CPU_GPREGISTER(V) \
+ FOR_EACH_CPU_SPECIAL_REGISTER(V) \
+ FOR_EACH_CPU_FPREGISTER(V)
+
+// The following are defined as pairs of the following value:
+// 1. type of the storage needed to save the register value by the JIT probe.
+// 2. name of the register.
+#define FOR_EACH_CPU_GPREGISTER(V) \
+ /* Parameter/result registers */ \
+ V(void*, x0) \
+ V(void*, x1) \
+ V(void*, x2) \
+ V(void*, x3) \
+ V(void*, x4) \
+ V(void*, x5) \
+ V(void*, x6) \
+ V(void*, x7) \
+ /* Indirect result location register */ \
+ V(void*, x8) \
+ /* Temporary registers */ \
+ V(void*, x9) \
+ V(void*, x10) \
+ V(void*, x11) \
+ V(void*, x12) \
+ V(void*, x13) \
+ V(void*, x14) \
+ V(void*, x15) \
+ /* Intra-procedure-call scratch registers (temporary) */ \
+ V(void*, x16) \
+ V(void*, x17) \
+ /* Platform Register (temporary) */ \
+ V(void*, x18) \
+ /* Callee-saved */ \
+ V(void*, x19) \
+ V(void*, x20) \
+ V(void*, x21) \
+ V(void*, x22) \
+ V(void*, x23) \
+ V(void*, x24) \
+ V(void*, x25) \
+ V(void*, x26) \
+ V(void*, x27) \
+ V(void*, x28) \
+ /* Special */ \
+ V(void*, fp) \
+ V(void*, lr) \
+ V(void*, sp)
+
+#define FOR_EACH_CPU_SPECIAL_REGISTER(V) \
+ V(void*, pc) \
+ V(void*, nzcv) \
+ V(void*, fpsr) \
+
+// ARM64 always has 32 FPU registers 128-bits each. See http://llvm.org/devmtg/2012-11/Northover-AArch64.pdf
+// and Section 5.1.2 in http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf.
+// However, we only use them for 64-bit doubles.
+#define FOR_EACH_CPU_FPREGISTER(V) \
+ /* Parameter/result registers */ \
+ V(double, q0) \
+ V(double, q1) \
+ V(double, q2) \
+ V(double, q3) \
+ V(double, q4) \
+ V(double, q5) \
+ V(double, q6) \
+ V(double, q7) \
+ /* Callee-saved (up to 64-bits only!) */ \
+ V(double, q8) \
+ V(double, q9) \
+ V(double, q10) \
+ V(double, q11) \
+ V(double, q12) \
+ V(double, q13) \
+ V(double, q14) \
+ V(double, q15) \
+ /* Temporary registers */ \
+ V(double, q16) \
+ V(double, q17) \
+ V(double, q18) \
+ V(double, q19) \
+ V(double, q20) \
+ V(double, q21) \
+ V(double, q22) \
+ V(double, q23) \
+ V(double, q24) \
+ V(double, q25) \
+ V(double, q26) \
+ V(double, q27) \
+ V(double, q28) \
+ V(double, q29) \
+ V(double, q30) \
+ V(double, q31)
+
+typedef enum {
+ #define DECLARE_REGISTER(_type, _regName) _regName,
+ FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER)
+ #undef DECLARE_REGISTER
+
+ ip0 = x16,
+ ip1 = x17,
+ x29 = fp,
+ x30 = lr,
+ zr = 0x3f,
+} RegisterID;
+
+typedef enum {
+ #define DECLARE_REGISTER(_type, _regName) _regName,
+ FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER)
+ #undef DECLARE_REGISTER
+} FPRegisterID;
+
+static constexpr bool isSp(RegisterID reg) { return reg == sp; }
+static constexpr bool isZr(RegisterID reg) { return reg == zr; }
+
+} // namespace ARM64Registers
+
+class ARM64Assembler {
+public:
+ typedef ARM64Registers::RegisterID RegisterID;
+ typedef ARM64Registers::FPRegisterID FPRegisterID;
+
+ static constexpr RegisterID firstRegister() { return ARM64Registers::x0; }
+ static constexpr RegisterID lastRegister() { return ARM64Registers::sp; }
+
+ static constexpr FPRegisterID firstFPRegister() { return ARM64Registers::q0; }
+ static constexpr FPRegisterID lastFPRegister() { return ARM64Registers::q31; }
+
+private:
+ static constexpr bool isSp(RegisterID reg) { return ARM64Registers::isSp(reg); }
+ static constexpr bool isZr(RegisterID reg) { return ARM64Registers::isZr(reg); }
+
+public:
+ ARM64Assembler()
+ : m_indexOfLastWatchpoint(INT_MIN)
+ , m_indexOfTailOfLastWatchpoint(INT_MIN)
+ {
+ }
+
+ AssemblerBuffer& buffer() { return m_buffer; }
+
+ // (HS, LO, HI, LS) -> (AE, B, A, BE)
+ // (VS, VC) -> (O, NO)
+ typedef enum {
+ ConditionEQ,
+ ConditionNE,
+ ConditionHS, ConditionCS = ConditionHS,
+ ConditionLO, ConditionCC = ConditionLO,
+ ConditionMI,
+ ConditionPL,
+ ConditionVS,
+ ConditionVC,
+ ConditionHI,
+ ConditionLS,
+ ConditionGE,
+ ConditionLT,
+ ConditionGT,
+ ConditionLE,
+ ConditionAL,
+ ConditionInvalid
+ } Condition;
+
+ static Condition invert(Condition cond)
+ {
+ return static_cast<Condition>(cond ^ 1);
+ }
+
+ typedef enum {
+ LSL,
+ LSR,
+ ASR,
+ ROR
+ } ShiftType;
+
+ typedef enum {
+ UXTB,
+ UXTH,
+ UXTW,
+ UXTX,
+ SXTB,
+ SXTH,
+ SXTW,
+ SXTX
+ } ExtendType;
+
+ enum SetFlags {
+ DontSetFlags,
+ S
+ };
+
+#define JUMP_ENUM_WITH_SIZE(index, value) (((value) << 4) | (index))
+#define JUMP_ENUM_SIZE(jump) ((jump) >> 4)
+ enum JumpType { JumpFixed = JUMP_ENUM_WITH_SIZE(0, 0),
+ JumpNoCondition = JUMP_ENUM_WITH_SIZE(1, 1 * sizeof(uint32_t)),
+ JumpCondition = JUMP_ENUM_WITH_SIZE(2, 2 * sizeof(uint32_t)),
+ JumpCompareAndBranch = JUMP_ENUM_WITH_SIZE(3, 2 * sizeof(uint32_t)),
+ JumpTestBit = JUMP_ENUM_WITH_SIZE(4, 2 * sizeof(uint32_t)),
+ JumpNoConditionFixedSize = JUMP_ENUM_WITH_SIZE(5, 1 * sizeof(uint32_t)),
+ JumpConditionFixedSize = JUMP_ENUM_WITH_SIZE(6, 2 * sizeof(uint32_t)),
+ JumpCompareAndBranchFixedSize = JUMP_ENUM_WITH_SIZE(7, 2 * sizeof(uint32_t)),
+ JumpTestBitFixedSize = JUMP_ENUM_WITH_SIZE(8, 2 * sizeof(uint32_t)),
+ };
+ enum JumpLinkType {
+ LinkInvalid = JUMP_ENUM_WITH_SIZE(0, 0),
+ LinkJumpNoCondition = JUMP_ENUM_WITH_SIZE(1, 1 * sizeof(uint32_t)),
+ LinkJumpConditionDirect = JUMP_ENUM_WITH_SIZE(2, 1 * sizeof(uint32_t)),
+ LinkJumpCondition = JUMP_ENUM_WITH_SIZE(3, 2 * sizeof(uint32_t)),
+ LinkJumpCompareAndBranch = JUMP_ENUM_WITH_SIZE(4, 2 * sizeof(uint32_t)),
+ LinkJumpCompareAndBranchDirect = JUMP_ENUM_WITH_SIZE(5, 1 * sizeof(uint32_t)),
+ LinkJumpTestBit = JUMP_ENUM_WITH_SIZE(6, 2 * sizeof(uint32_t)),
+ LinkJumpTestBitDirect = JUMP_ENUM_WITH_SIZE(7, 1 * sizeof(uint32_t)),
+ };
+
+ class LinkRecord {
+ public:
+ LinkRecord(intptr_t from, intptr_t to, JumpType type, Condition condition)
+ {
+ data.realTypes.m_from = from;
+ data.realTypes.m_to = to;
+ data.realTypes.m_type = type;
+ data.realTypes.m_linkType = LinkInvalid;
+ data.realTypes.m_condition = condition;
+ }
+ LinkRecord(intptr_t from, intptr_t to, JumpType type, Condition condition, bool is64Bit, RegisterID compareRegister)
+ {
+ data.realTypes.m_from = from;
+ data.realTypes.m_to = to;
+ data.realTypes.m_type = type;
+ data.realTypes.m_linkType = LinkInvalid;
+ data.realTypes.m_condition = condition;
+ data.realTypes.m_is64Bit = is64Bit;
+ data.realTypes.m_compareRegister = compareRegister;
+ }
+ LinkRecord(intptr_t from, intptr_t to, JumpType type, Condition condition, unsigned bitNumber, RegisterID compareRegister)
+ {
+ data.realTypes.m_from = from;
+ data.realTypes.m_to = to;
+ data.realTypes.m_type = type;
+ data.realTypes.m_linkType = LinkInvalid;
+ data.realTypes.m_condition = condition;
+ data.realTypes.m_bitNumber = bitNumber;
+ data.realTypes.m_compareRegister = compareRegister;
+ }
+ void operator=(const LinkRecord& other)
+ {
+ data.copyTypes.content[0] = other.data.copyTypes.content[0];
+ data.copyTypes.content[1] = other.data.copyTypes.content[1];
+ data.copyTypes.content[2] = other.data.copyTypes.content[2];
+ }
+ intptr_t from() const { return data.realTypes.m_from; }
+ void setFrom(intptr_t from) { data.realTypes.m_from = from; }
+ intptr_t to() const { return data.realTypes.m_to; }
+ JumpType type() const { return data.realTypes.m_type; }
+ JumpLinkType linkType() const { return data.realTypes.m_linkType; }
+ void setLinkType(JumpLinkType linkType) { ASSERT(data.realTypes.m_linkType == LinkInvalid); data.realTypes.m_linkType = linkType; }
+ Condition condition() const { return data.realTypes.m_condition; }
+ bool is64Bit() const { return data.realTypes.m_is64Bit; }
+ unsigned bitNumber() const { return data.realTypes.m_bitNumber; }
+ RegisterID compareRegister() const { return data.realTypes.m_compareRegister; }
+
+ private:
+ union {
+ struct RealTypes {
+ intptr_t m_from : 48;
+ intptr_t m_to : 48;
+ JumpType m_type : 8;
+ JumpLinkType m_linkType : 8;
+ Condition m_condition : 4;
+ unsigned m_bitNumber : 6;
+ RegisterID m_compareRegister : 6;
+ bool m_is64Bit : 1;
+ } realTypes;
+ struct CopyTypes {
+ uint64_t content[3];
+ } copyTypes;
+ COMPILE_ASSERT(sizeof(RealTypes) == sizeof(CopyTypes), LinkRecordCopyStructSizeEqualsRealStruct);
+ } data;
+ };
+
+ // bits(N) VFPExpandImm(bits(8) imm8);
+ //
+ // Encoding of floating point immediates is a litte complicated. Here's a
+ // high level description:
+ // +/-m*2-n where m and n are integers, 16 <= m <= 31, 0 <= n <= 7
+ // and the algirithm for expanding to a single precision float:
+ // return imm8<7>:NOT(imm8<6>):Replicate(imm8<6>,5):imm8<5:0>:Zeros(19);
+ //
+ // The trickiest bit is how the exponent is handled. The following table
+ // may help clarify things a little:
+ // 654
+ // 100 01111100 124 -3 1020 01111111100
+ // 101 01111101 125 -2 1021 01111111101
+ // 110 01111110 126 -1 1022 01111111110
+ // 111 01111111 127 0 1023 01111111111
+ // 000 10000000 128 1 1024 10000000000
+ // 001 10000001 129 2 1025 10000000001
+ // 010 10000010 130 3 1026 10000000010
+ // 011 10000011 131 4 1027 10000000011
+ // The first column shows the bit pattern stored in bits 6-4 of the arm
+ // encoded immediate. The second column shows the 8-bit IEEE 754 single
+ // -precision exponent in binary, the third column shows the raw decimal
+ // value. IEEE 754 single-precision numbers are stored with a bias of 127
+ // to the exponent, so the fourth column shows the resulting exponent.
+ // From this was can see that the exponent can be in the range -3..4,
+ // which agrees with the high level description given above. The fifth
+ // and sixth columns shows the value stored in a IEEE 754 double-precision
+ // number to represent these exponents in decimal and binary, given the
+ // bias of 1023.
+ //
+ // Ultimately, detecting doubles that can be encoded as immediates on arm
+ // and encoding doubles is actually not too bad. A floating point value can
+ // be encoded by retaining the sign bit, the low three bits of the exponent
+ // and the high 4 bits of the mantissa. To validly be able to encode an
+ // immediate the remainder of the mantissa must be zero, and the high part
+ // of the exponent must match the top bit retained, bar the highest bit
+ // which must be its inverse.
+ static bool canEncodeFPImm(double d)
+ {
+ // Discard the sign bit, the low two bits of the exponent & the highest
+ // four bits of the mantissa.
+ uint64_t masked = bitwise_cast<uint64_t>(d) & 0x7fc0ffffffffffffull;
+ return (masked == 0x3fc0000000000000ull) || (masked == 0x4000000000000000ull);
+ }
+
+ template<int datasize>
+ static bool canEncodePImmOffset(int32_t offset)
+ {
+ return isValidScaledUImm12<datasize>(offset);
+ }
+
+ static bool canEncodeSImmOffset(int32_t offset)
+ {
+ return isValidSignedImm9(offset);
+ }
+
+private:
+ int encodeFPImm(double d)
+ {
+ ASSERT(canEncodeFPImm(d));
+ uint64_t u64 = bitwise_cast<uint64_t>(d);
+ return (static_cast<int>(u64 >> 56) & 0x80) | (static_cast<int>(u64 >> 48) & 0x7f);
+ }
+
+ template<int datasize>
+ int encodeShiftAmount(int amount)
+ {
+ ASSERT(!amount || datasize == (8 << amount));
+ return amount;
+ }
+
+ template<int datasize>
+ static int encodePositiveImmediate(unsigned pimm)
+ {
+ ASSERT(!(pimm & ((datasize / 8) - 1)));
+ return pimm / (datasize / 8);
+ }
+
+ enum Datasize {
+ Datasize_32,
+ Datasize_64,
+ Datasize_64_top,
+ Datasize_16
+ };
+
+ enum MemOpSize {
+ MemOpSize_8_or_128,
+ MemOpSize_16,
+ MemOpSize_32,
+ MemOpSize_64,
+ };
+
+ enum BranchType {
+ BranchType_JMP,
+ BranchType_CALL,
+ BranchType_RET
+ };
+
+ enum AddOp {
+ AddOp_ADD,
+ AddOp_SUB
+ };
+
+ enum BitfieldOp {
+ BitfieldOp_SBFM,
+ BitfieldOp_BFM,
+ BitfieldOp_UBFM
+ };
+
+ enum DataOp1Source {
+ DataOp_RBIT,
+ DataOp_REV16,
+ DataOp_REV32,
+ DataOp_REV64,
+ DataOp_CLZ,
+ DataOp_CLS
+ };
+
+ enum DataOp2Source {
+ DataOp_UDIV = 2,
+ DataOp_SDIV = 3,
+ DataOp_LSLV = 8,
+ DataOp_LSRV = 9,
+ DataOp_ASRV = 10,
+ DataOp_RORV = 11
+ };
+
+ enum DataOp3Source {
+ DataOp_MADD = 0,
+ DataOp_MSUB = 1,
+ DataOp_SMADDL = 2,
+ DataOp_SMSUBL = 3,
+ DataOp_SMULH = 4,
+ DataOp_UMADDL = 10,
+ DataOp_UMSUBL = 11,
+ DataOp_UMULH = 12
+ };
+
+ enum ExcepnOp {
+ ExcepnOp_EXCEPTION = 0,
+ ExcepnOp_BREAKPOINT = 1,
+ ExcepnOp_HALT = 2,
+ ExcepnOp_DCPS = 5
+ };
+
+ enum FPCmpOp {
+ FPCmpOp_FCMP = 0x00,
+ FPCmpOp_FCMP0 = 0x08,
+ FPCmpOp_FCMPE = 0x10,
+ FPCmpOp_FCMPE0 = 0x18
+ };
+
+ enum FPCondCmpOp {
+ FPCondCmpOp_FCMP,
+ FPCondCmpOp_FCMPE
+ };
+
+ enum FPDataOp1Source {
+ FPDataOp_FMOV = 0,
+ FPDataOp_FABS = 1,
+ FPDataOp_FNEG = 2,
+ FPDataOp_FSQRT = 3,
+ FPDataOp_FCVT_toSingle = 4,
+ FPDataOp_FCVT_toDouble = 5,
+ FPDataOp_FCVT_toHalf = 7,
+ FPDataOp_FRINTN = 8,
+ FPDataOp_FRINTP = 9,
+ FPDataOp_FRINTM = 10,
+ FPDataOp_FRINTZ = 11,
+ FPDataOp_FRINTA = 12,
+ FPDataOp_FRINTX = 14,
+ FPDataOp_FRINTI = 15
+ };
+
+ enum FPDataOp2Source {
+ FPDataOp_FMUL,
+ FPDataOp_FDIV,
+ FPDataOp_FADD,
+ FPDataOp_FSUB,
+ FPDataOp_FMAX,
+ FPDataOp_FMIN,
+ FPDataOp_FMAXNM,
+ FPDataOp_FMINNM,
+ FPDataOp_FNMUL
+ };
+
+ enum SIMD3Same {
+ SIMD_LogicalOp_AND = 0x03
+ };
+
+ enum FPIntConvOp {
+ FPIntConvOp_FCVTNS = 0x00,
+ FPIntConvOp_FCVTNU = 0x01,
+ FPIntConvOp_SCVTF = 0x02,
+ FPIntConvOp_UCVTF = 0x03,
+ FPIntConvOp_FCVTAS = 0x04,
+ FPIntConvOp_FCVTAU = 0x05,
+ FPIntConvOp_FMOV_QtoX = 0x06,
+ FPIntConvOp_FMOV_XtoQ = 0x07,
+ FPIntConvOp_FCVTPS = 0x08,
+ FPIntConvOp_FCVTPU = 0x09,
+ FPIntConvOp_FMOV_QtoX_top = 0x0e,
+ FPIntConvOp_FMOV_XtoQ_top = 0x0f,
+ FPIntConvOp_FCVTMS = 0x10,
+ FPIntConvOp_FCVTMU = 0x11,
+ FPIntConvOp_FCVTZS = 0x18,
+ FPIntConvOp_FCVTZU = 0x19,
+ };
+
+ enum LogicalOp {
+ LogicalOp_AND,
+ LogicalOp_ORR,
+ LogicalOp_EOR,
+ LogicalOp_ANDS
+ };
+
+ enum MemOp {
+ MemOp_STORE,
+ MemOp_LOAD,
+ MemOp_STORE_V128,
+ MemOp_LOAD_V128,
+ MemOp_PREFETCH = 2, // size must be 3
+ MemOp_LOAD_signed64 = 2, // size may be 0, 1 or 2
+ MemOp_LOAD_signed32 = 3 // size may be 0 or 1
+ };
+
+ enum MemPairOpSize {
+ MemPairOp_32 = 0,
+ MemPairOp_LoadSigned_32 = 1,
+ MemPairOp_64 = 2,
+
+ MemPairOp_V32 = MemPairOp_32,
+ MemPairOp_V64 = 1,
+ MemPairOp_V128 = 2
+ };
+
+ enum MoveWideOp {
+ MoveWideOp_N = 0,
+ MoveWideOp_Z = 2,
+ MoveWideOp_K = 3
+ };
+
+ enum LdrLiteralOp {
+ LdrLiteralOp_32BIT = 0,
+ LdrLiteralOp_64BIT = 1,
+ LdrLiteralOp_LDRSW = 2,
+ LdrLiteralOp_128BIT = 2
+ };
+
+ static unsigned memPairOffsetShift(bool V, MemPairOpSize size)
+ {
+ // return the log2 of the size in bytes, e.g. 64 bit size returns 3
+ if (V)
+ return size + 2;
+ return (size >> 1) + 2;
+ }
+
+public:
+ // Integer Instructions:
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void adc(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ CHECK_DATASIZE();
+ insn(addSubtractWithCarry(DATASIZE, AddOp_ADD, setFlags, rm, rn, rd));
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, UInt12 imm12, int shift = 0)
+ {
+ CHECK_DATASIZE();
+ ASSERT(!shift || shift == 12);
+ insn(addSubtractImmediate(DATASIZE, AddOp_ADD, setFlags, shift == 12, imm12, rn, rd));
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ add<datasize, setFlags>(rd, rn, rm, LSL, 0);
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ CHECK_DATASIZE();
+ insn(addSubtractExtendedRegister(DATASIZE, AddOp_ADD, setFlags, rm, extend, amount, rn, rd));
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
+ {
+ CHECK_DATASIZE();
+ if (isSp(rd) || isSp(rn)) {
+ ASSERT(shift == LSL);
+ ASSERT(!isSp(rm));
+ add<datasize, setFlags>(rd, rn, rm, UXTX, amount);
+ } else
+ insn(addSubtractShiftedRegister(DATASIZE, AddOp_ADD, setFlags, shift, rm, amount, rn, rd));
+ }
+
+ ALWAYS_INLINE void adr(RegisterID rd, int offset)
+ {
+ insn(pcRelative(false, offset, rd));
+ }
+
+ ALWAYS_INLINE void adrp(RegisterID rd, int offset)
+ {
+ ASSERT(!(offset & 0xfff));
+ insn(pcRelative(true, offset >> 12, rd));
+ nopCortexA53Fix843419();
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void and_(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ and_<datasize, setFlags>(rd, rn, rm, LSL, 0);
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void and_(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
+ {
+ CHECK_DATASIZE();
+ insn(logicalShiftedRegister(DATASIZE, setFlags ? LogicalOp_ANDS : LogicalOp_AND, shift, false, rm, amount, rn, rd));
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void and_(RegisterID rd, RegisterID rn, LogicalImmediate imm)
+ {
+ CHECK_DATASIZE();
+ insn(logicalImmediate(DATASIZE, setFlags ? LogicalOp_ANDS : LogicalOp_AND, imm.value(), rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void asr(RegisterID rd, RegisterID rn, int shift)
+ {
+ ASSERT(shift < datasize);
+ sbfm<datasize>(rd, rn, shift, datasize - 1);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void asr(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ asrv<datasize>(rd, rn, rm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void asrv(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ CHECK_DATASIZE();
+ insn(dataProcessing2Source(DATASIZE, rm, DataOp_ASRV, rn, rd));
+ }
+
+ ALWAYS_INLINE void b(int32_t offset = 0)
+ {
+ ASSERT(!(offset & 3));
+ offset >>= 2;
+ ASSERT(offset == (offset << 6) >> 6);
+ insn(unconditionalBranchImmediate(false, offset));
+ }
+
+ ALWAYS_INLINE void b_cond(Condition cond, int32_t offset = 0)
+ {
+ ASSERT(!(offset & 3));
+ offset >>= 2;
+ ASSERT(offset == (offset << 13) >> 13);
+ insn(conditionalBranchImmediate(offset, cond));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void bfi(RegisterID rd, RegisterID rn, int lsb, int width)
+ {
+ bfm<datasize>(rd, rn, (datasize - lsb) & (datasize - 1), width - 1);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void bfm(RegisterID rd, RegisterID rn, int immr, int imms)
+ {
+ CHECK_DATASIZE();
+ insn(bitfield(DATASIZE, BitfieldOp_BFM, immr, imms, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void bfxil(RegisterID rd, RegisterID rn, int lsb, int width)
+ {
+ bfm<datasize>(rd, rn, lsb, lsb + width - 1);
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void bic(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ bic<datasize, setFlags>(rd, rn, rm, LSL, 0);
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void bic(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
+ {
+ CHECK_DATASIZE();
+ insn(logicalShiftedRegister(DATASIZE, setFlags ? LogicalOp_ANDS : LogicalOp_AND, shift, true, rm, amount, rn, rd));
+ }
+
+ ALWAYS_INLINE void bl(int32_t offset = 0)
+ {
+ ASSERT(!(offset & 3));
+ offset >>= 2;
+ insn(unconditionalBranchImmediate(true, offset));
+ }
+
+ ALWAYS_INLINE void blr(RegisterID rn)
+ {
+ insn(unconditionalBranchRegister(BranchType_CALL, rn));
+ }
+
+ ALWAYS_INLINE void br(RegisterID rn)
+ {
+ insn(unconditionalBranchRegister(BranchType_JMP, rn));
+ }
+
+ ALWAYS_INLINE void brk(uint16_t imm)
+ {
+ insn(excepnGeneration(ExcepnOp_BREAKPOINT, imm, 0));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cbnz(RegisterID rt, int32_t offset = 0)
+ {
+ CHECK_DATASIZE();
+ ASSERT(!(offset & 3));
+ offset >>= 2;
+ insn(compareAndBranchImmediate(DATASIZE, true, offset, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cbz(RegisterID rt, int32_t offset = 0)
+ {
+ CHECK_DATASIZE();
+ ASSERT(!(offset & 3));
+ offset >>= 2;
+ insn(compareAndBranchImmediate(DATASIZE, false, offset, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ccmn(RegisterID rn, RegisterID rm, int nzcv, Condition cond)
+ {
+ CHECK_DATASIZE();
+ insn(conditionalCompareRegister(DATASIZE, AddOp_ADD, rm, cond, rn, nzcv));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ccmn(RegisterID rn, UInt5 imm, int nzcv, Condition cond)
+ {
+ CHECK_DATASIZE();
+ insn(conditionalCompareImmediate(DATASIZE, AddOp_ADD, imm, cond, rn, nzcv));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ccmp(RegisterID rn, RegisterID rm, int nzcv, Condition cond)
+ {
+ CHECK_DATASIZE();
+ insn(conditionalCompareRegister(DATASIZE, AddOp_SUB, rm, cond, rn, nzcv));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ccmp(RegisterID rn, UInt5 imm, int nzcv, Condition cond)
+ {
+ CHECK_DATASIZE();
+ insn(conditionalCompareImmediate(DATASIZE, AddOp_SUB, imm, cond, rn, nzcv));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cinc(RegisterID rd, RegisterID rn, Condition cond)
+ {
+ csinc<datasize>(rd, rn, rn, invert(cond));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cinv(RegisterID rd, RegisterID rn, Condition cond)
+ {
+ csinv<datasize>(rd, rn, rn, invert(cond));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cls(RegisterID rd, RegisterID rn)
+ {
+ CHECK_DATASIZE();
+ insn(dataProcessing1Source(DATASIZE, DataOp_CLS, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void clz(RegisterID rd, RegisterID rn)
+ {
+ CHECK_DATASIZE();
+ insn(dataProcessing1Source(DATASIZE, DataOp_CLZ, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cmn(RegisterID rn, UInt12 imm12, int shift = 0)
+ {
+ add<datasize, S>(ARM64Registers::zr, rn, imm12, shift);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cmn(RegisterID rn, RegisterID rm)
+ {
+ add<datasize, S>(ARM64Registers::zr, rn, rm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cmn(RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ add<datasize, S>(ARM64Registers::zr, rn, rm, extend, amount);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cmn(RegisterID rn, RegisterID rm, ShiftType shift, int amount)
+ {
+ add<datasize, S>(ARM64Registers::zr, rn, rm, shift, amount);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cmp(RegisterID rn, UInt12 imm12, int shift = 0)
+ {
+ sub<datasize, S>(ARM64Registers::zr, rn, imm12, shift);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm)
+ {
+ sub<datasize, S>(ARM64Registers::zr, rn, rm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ sub<datasize, S>(ARM64Registers::zr, rn, rm, extend, amount);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm, ShiftType shift, int amount)
+ {
+ sub<datasize, S>(ARM64Registers::zr, rn, rm, shift, amount);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cneg(RegisterID rd, RegisterID rn, Condition cond)
+ {
+ csneg<datasize>(rd, rn, rn, invert(cond));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void csel(RegisterID rd, RegisterID rn, RegisterID rm, Condition cond)
+ {
+ CHECK_DATASIZE();
+ insn(conditionalSelect(DATASIZE, false, rm, cond, false, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void cset(RegisterID rd, Condition cond)
+ {
+ csinc<datasize>(rd, ARM64Registers::zr, ARM64Registers::zr, invert(cond));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void csetm(RegisterID rd, Condition cond)
+ {
+ csinv<datasize>(rd, ARM64Registers::zr, ARM64Registers::zr, invert(cond));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void csinc(RegisterID rd, RegisterID rn, RegisterID rm, Condition cond)
+ {
+ CHECK_DATASIZE();
+ insn(conditionalSelect(DATASIZE, false, rm, cond, true, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void csinv(RegisterID rd, RegisterID rn, RegisterID rm, Condition cond)
+ {
+ CHECK_DATASIZE();
+ insn(conditionalSelect(DATASIZE, true, rm, cond, false, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void csneg(RegisterID rd, RegisterID rn, RegisterID rm, Condition cond)
+ {
+ CHECK_DATASIZE();
+ insn(conditionalSelect(DATASIZE, true, rm, cond, true, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void eon(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ eon<datasize>(rd, rn, rm, LSL, 0);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void eon(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
+ {
+ CHECK_DATASIZE();
+ insn(logicalShiftedRegister(DATASIZE, LogicalOp_EOR, shift, true, rm, amount, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ eor<datasize>(rd, rn, rm, LSL, 0);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
+ {
+ CHECK_DATASIZE();
+ insn(logicalShiftedRegister(DATASIZE, LogicalOp_EOR, shift, false, rm, amount, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, LogicalImmediate imm)
+ {
+ CHECK_DATASIZE();
+ insn(logicalImmediate(DATASIZE, LogicalOp_EOR, imm.value(), rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void extr(RegisterID rd, RegisterID rn, RegisterID rm, int lsb)
+ {
+ CHECK_DATASIZE();
+ insn(extract(DATASIZE, rm, lsb, rn, rd));
+ }
+
+ ALWAYS_INLINE void hint(int imm)
+ {
+ insn(hintPseudo(imm));
+ }
+
+ ALWAYS_INLINE void hlt(uint16_t imm)
+ {
+ insn(excepnGeneration(ExcepnOp_HALT, imm, 0));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldp(RegisterID rt, RegisterID rt2, RegisterID rn, PairPostIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPairPostIndex(MEMPAIROPSIZE_INT(datasize), false, MemOp_LOAD, simm, rn, rt, rt2));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldp(RegisterID rt, RegisterID rt2, RegisterID rn, PairPreIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPairPreIndex(MEMPAIROPSIZE_INT(datasize), false, MemOp_LOAD, simm, rn, rt, rt2));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, RegisterID rm)
+ {
+ ldr<datasize>(rt, rn, rm, UXTX, 0);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterRegisterOffset(MEMOPSIZE, false, MemOp_LOAD, rm, extend, encodeShiftAmount<datasize>(amount), rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterUnsignedImmediate(MEMOPSIZE, false, MemOp_LOAD, encodePositiveImmediate<datasize>(pimm), rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, PostIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPostIndex(MEMOPSIZE, false, MemOp_LOAD, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, PreIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPreIndex(MEMOPSIZE, false, MemOp_LOAD, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldr_literal(RegisterID rt, int offset = 0)
+ {
+ CHECK_DATASIZE();
+ ASSERT(!(offset & 3));
+ insn(loadRegisterLiteral(datasize == 64 ? LdrLiteralOp_64BIT : LdrLiteralOp_32BIT, false, offset >> 2, rt));
+ }
+
+ ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, RegisterID rm)
+ {
+ // Not calling the 5 argument form of ldrb, since is amount is ommitted S is false.
+ insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, MemOp_LOAD, rm, UXTX, false, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ ASSERT_UNUSED(amount, !amount);
+ insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, MemOp_LOAD, rm, extend, true, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ insn(loadStoreRegisterUnsignedImmediate(MemOpSize_8_or_128, false, MemOp_LOAD, encodePositiveImmediate<8>(pimm), rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, PostIndex simm)
+ {
+ insn(loadStoreRegisterPostIndex(MemOpSize_8_or_128, false, MemOp_LOAD, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, PreIndex simm)
+ {
+ insn(loadStoreRegisterPreIndex(MemOpSize_8_or_128, false, MemOp_LOAD, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, RegisterID rm)
+ {
+ ldrh(rt, rn, rm, UXTX, 0);
+ }
+
+ ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ ASSERT(!amount || amount == 1);
+ insn(loadStoreRegisterRegisterOffset(MemOpSize_16, false, MemOp_LOAD, rm, extend, amount == 1, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ insn(loadStoreRegisterUnsignedImmediate(MemOpSize_16, false, MemOp_LOAD, encodePositiveImmediate<16>(pimm), rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, PostIndex simm)
+ {
+ insn(loadStoreRegisterPostIndex(MemOpSize_16, false, MemOp_LOAD, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, PreIndex simm)
+ {
+ insn(loadStoreRegisterPreIndex(MemOpSize_16, false, MemOp_LOAD, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldrsb(RegisterID rt, RegisterID rn, RegisterID rm)
+ {
+ CHECK_DATASIZE();
+ // Not calling the 5 argument form of ldrsb, since is amount is ommitted S is false.
+ insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, rm, UXTX, false, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldrsb(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ CHECK_DATASIZE();
+ ASSERT_UNUSED(amount, !amount);
+ insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, rm, extend, true, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldrsb(RegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterUnsignedImmediate(MemOpSize_8_or_128, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, encodePositiveImmediate<8>(pimm), rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldrsb(RegisterID rt, RegisterID rn, PostIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPostIndex(MemOpSize_8_or_128, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldrsb(RegisterID rt, RegisterID rn, PreIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPreIndex(MemOpSize_8_or_128, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldrsh(RegisterID rt, RegisterID rn, RegisterID rm)
+ {
+ ldrsh<datasize>(rt, rn, rm, UXTX, 0);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldrsh(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ CHECK_DATASIZE();
+ ASSERT(!amount || amount == 1);
+ insn(loadStoreRegisterRegisterOffset(MemOpSize_16, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, rm, extend, amount == 1, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldrsh(RegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterUnsignedImmediate(MemOpSize_16, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, encodePositiveImmediate<16>(pimm), rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldrsh(RegisterID rt, RegisterID rn, PostIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPostIndex(MemOpSize_16, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldrsh(RegisterID rt, RegisterID rn, PreIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPreIndex(MemOpSize_16, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrsw(RegisterID rt, RegisterID rn, RegisterID rm)
+ {
+ ldrsw(rt, rn, rm, UXTX, 0);
+ }
+
+ ALWAYS_INLINE void ldrsw(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ ASSERT(!amount || amount == 2);
+ insn(loadStoreRegisterRegisterOffset(MemOpSize_32, false, MemOp_LOAD_signed64, rm, extend, amount == 2, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrsw(RegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ insn(loadStoreRegisterUnsignedImmediate(MemOpSize_32, false, MemOp_LOAD_signed64, encodePositiveImmediate<32>(pimm), rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrsw(RegisterID rt, RegisterID rn, PostIndex simm)
+ {
+ insn(loadStoreRegisterPostIndex(MemOpSize_32, false, MemOp_LOAD_signed64, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrsw(RegisterID rt, RegisterID rn, PreIndex simm)
+ {
+ insn(loadStoreRegisterPreIndex(MemOpSize_32, false, MemOp_LOAD_signed64, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldrsw_literal(RegisterID rt, int offset = 0)
+ {
+ ASSERT(!(offset & 3));
+ insn(loadRegisterLiteral(LdrLiteralOp_LDRSW, false, offset >> 2, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldur(RegisterID rt, RegisterID rn, int simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterUnscaledImmediate(MEMOPSIZE, false, MemOp_LOAD, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldurb(RegisterID rt, RegisterID rn, int simm)
+ {
+ insn(loadStoreRegisterUnscaledImmediate(MemOpSize_8_or_128, false, MemOp_LOAD, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldurh(RegisterID rt, RegisterID rn, int simm)
+ {
+ insn(loadStoreRegisterUnscaledImmediate(MemOpSize_16, false, MemOp_LOAD, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldursb(RegisterID rt, RegisterID rn, int simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterUnscaledImmediate(MemOpSize_8_or_128, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldursh(RegisterID rt, RegisterID rn, int simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterUnscaledImmediate(MemOpSize_16, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void ldursw(RegisterID rt, RegisterID rn, int simm)
+ {
+ insn(loadStoreRegisterUnscaledImmediate(MemOpSize_32, false, MemOp_LOAD_signed64, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void lsl(RegisterID rd, RegisterID rn, int shift)
+ {
+ ASSERT(shift < datasize);
+ ubfm<datasize>(rd, rn, (datasize - shift) & (datasize - 1), datasize - 1 - shift);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void lsl(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ lslv<datasize>(rd, rn, rm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void lslv(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ CHECK_DATASIZE();
+ insn(dataProcessing2Source(DATASIZE, rm, DataOp_LSLV, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void lsr(RegisterID rd, RegisterID rn, int shift)
+ {
+ ASSERT(shift < datasize);
+ ubfm<datasize>(rd, rn, shift, datasize - 1);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void lsr(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ lsrv<datasize>(rd, rn, rm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void lsrv(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ CHECK_DATASIZE();
+ insn(dataProcessing2Source(DATASIZE, rm, DataOp_LSRV, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void madd(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
+ {
+ CHECK_DATASIZE();
+ nopCortexA53Fix835769<datasize>();
+ insn(dataProcessing3Source(DATASIZE, DataOp_MADD, rm, ra, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void mneg(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ msub<datasize>(rd, rn, rm, ARM64Registers::zr);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void mov(RegisterID rd, RegisterID rm)
+ {
+ if (isSp(rd) || isSp(rm))
+ add<datasize>(rd, rm, UInt12(0));
+ else
+ orr<datasize>(rd, ARM64Registers::zr, rm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void movi(RegisterID rd, LogicalImmediate imm)
+ {
+ orr<datasize>(rd, ARM64Registers::zr, imm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void movk(RegisterID rd, uint16_t value, int shift = 0)
+ {
+ CHECK_DATASIZE();
+ ASSERT(!(shift & 0xf));
+ insn(moveWideImediate(DATASIZE, MoveWideOp_K, shift >> 4, value, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void movn(RegisterID rd, uint16_t value, int shift = 0)
+ {
+ CHECK_DATASIZE();
+ ASSERT(!(shift & 0xf));
+ insn(moveWideImediate(DATASIZE, MoveWideOp_N, shift >> 4, value, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void movz(RegisterID rd, uint16_t value, int shift = 0)
+ {
+ CHECK_DATASIZE();
+ ASSERT(!(shift & 0xf));
+ insn(moveWideImediate(DATASIZE, MoveWideOp_Z, shift >> 4, value, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void msub(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
+ {
+ CHECK_DATASIZE();
+ nopCortexA53Fix835769<datasize>();
+ insn(dataProcessing3Source(DATASIZE, DataOp_MSUB, rm, ra, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void mul(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ madd<datasize>(rd, rn, rm, ARM64Registers::zr);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void mvn(RegisterID rd, RegisterID rm)
+ {
+ orn<datasize>(rd, ARM64Registers::zr, rm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void mvn(RegisterID rd, RegisterID rm, ShiftType shift, int amount)
+ {
+ orn<datasize>(rd, ARM64Registers::zr, rm, shift, amount);
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void neg(RegisterID rd, RegisterID rm)
+ {
+ sub<datasize, setFlags>(rd, ARM64Registers::zr, rm);
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void neg(RegisterID rd, RegisterID rm, ShiftType shift, int amount)
+ {
+ sub<datasize, setFlags>(rd, ARM64Registers::zr, rm, shift, amount);
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void ngc(RegisterID rd, RegisterID rm)
+ {
+ sbc<datasize, setFlags>(rd, ARM64Registers::zr, rm);
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void ngc(RegisterID rd, RegisterID rm, ShiftType shift, int amount)
+ {
+ sbc<datasize, setFlags>(rd, ARM64Registers::zr, rm, shift, amount);
+ }
+
+ ALWAYS_INLINE void nop()
+ {
+ insn(nopPseudo());
+ }
+
+ static void fillNops(void* base, size_t size)
+ {
+ RELEASE_ASSERT(!(size % sizeof(int32_t)));
+ size_t n = size / sizeof(int32_t);
+ for (int32_t* ptr = static_cast<int32_t*>(base); n--;)
+ *ptr++ = nopPseudo();
+ }
+
+ ALWAYS_INLINE void dmbSY()
+ {
+ insn(0xd5033fbf);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void orn(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ orn<datasize>(rd, rn, rm, LSL, 0);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void orn(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
+ {
+ CHECK_DATASIZE();
+ insn(logicalShiftedRegister(DATASIZE, LogicalOp_ORR, shift, true, rm, amount, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ orr<datasize>(rd, rn, rm, LSL, 0);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
+ {
+ CHECK_DATASIZE();
+ insn(logicalShiftedRegister(DATASIZE, LogicalOp_ORR, shift, false, rm, amount, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, LogicalImmediate imm)
+ {
+ CHECK_DATASIZE();
+ insn(logicalImmediate(DATASIZE, LogicalOp_ORR, imm.value(), rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void rbit(RegisterID rd, RegisterID rn)
+ {
+ CHECK_DATASIZE();
+ insn(dataProcessing1Source(DATASIZE, DataOp_RBIT, rn, rd));
+ }
+
+ ALWAYS_INLINE void ret(RegisterID rn = ARM64Registers::lr)
+ {
+ insn(unconditionalBranchRegister(BranchType_RET, rn));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void rev(RegisterID rd, RegisterID rn)
+ {
+ CHECK_DATASIZE();
+ if (datasize == 32) // 'rev' mnemonic means REV32 or REV64 depending on the operand width.
+ insn(dataProcessing1Source(Datasize_32, DataOp_REV32, rn, rd));
+ else
+ insn(dataProcessing1Source(Datasize_64, DataOp_REV64, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void rev16(RegisterID rd, RegisterID rn)
+ {
+ CHECK_DATASIZE();
+ insn(dataProcessing1Source(DATASIZE, DataOp_REV16, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void rev32(RegisterID rd, RegisterID rn)
+ {
+ ASSERT(datasize == 64); // 'rev32' only valid with 64-bit operands.
+ insn(dataProcessing1Source(Datasize_64, DataOp_REV32, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ror(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ rorv<datasize>(rd, rn, rm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ror(RegisterID rd, RegisterID rs, int shift)
+ {
+ extr<datasize>(rd, rs, rs, shift);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void rorv(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ CHECK_DATASIZE();
+ insn(dataProcessing2Source(DATASIZE, rm, DataOp_RORV, rn, rd));
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void sbc(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ CHECK_DATASIZE();
+ insn(addSubtractWithCarry(DATASIZE, AddOp_SUB, setFlags, rm, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void sbfiz(RegisterID rd, RegisterID rn, int lsb, int width)
+ {
+ sbfm<datasize>(rd, rn, (datasize - lsb) & (datasize - 1), width - 1);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void sbfm(RegisterID rd, RegisterID rn, int immr, int imms)
+ {
+ CHECK_DATASIZE();
+ insn(bitfield(DATASIZE, BitfieldOp_SBFM, immr, imms, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void sbfx(RegisterID rd, RegisterID rn, int lsb, int width)
+ {
+ sbfm<datasize>(rd, rn, lsb, lsb + width - 1);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void sdiv(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ CHECK_DATASIZE();
+ insn(dataProcessing2Source(DATASIZE, rm, DataOp_SDIV, rn, rd));
+ }
+
+ ALWAYS_INLINE void smaddl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
+ {
+ nopCortexA53Fix835769<64>();
+ insn(dataProcessing3Source(Datasize_64, DataOp_SMADDL, rm, ra, rn, rd));
+ }
+
+ ALWAYS_INLINE void smnegl(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ smsubl(rd, rn, rm, ARM64Registers::zr);
+ }
+
+ ALWAYS_INLINE void smsubl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
+ {
+ nopCortexA53Fix835769<64>();
+ insn(dataProcessing3Source(Datasize_64, DataOp_SMSUBL, rm, ra, rn, rd));
+ }
+
+ ALWAYS_INLINE void smulh(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ insn(dataProcessing3Source(Datasize_64, DataOp_SMULH, rm, ARM64Registers::zr, rn, rd));
+ }
+
+ ALWAYS_INLINE void smull(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ smaddl(rd, rn, rm, ARM64Registers::zr);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void stp(RegisterID rt, RegisterID rt2, RegisterID rn, PairPostIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPairPostIndex(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, simm, rn, rt, rt2));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void stp(RegisterID rt, RegisterID rt2, RegisterID rn, PairPreIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPairPreIndex(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, simm, rn, rt, rt2));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, RegisterID rm)
+ {
+ str<datasize>(rt, rn, rm, UXTX, 0);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterRegisterOffset(MEMOPSIZE, false, MemOp_STORE, rm, extend, encodeShiftAmount<datasize>(amount), rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterUnsignedImmediate(MEMOPSIZE, false, MemOp_STORE, encodePositiveImmediate<datasize>(pimm), rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, PostIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPostIndex(MEMOPSIZE, false, MemOp_STORE, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, PreIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPreIndex(MEMOPSIZE, false, MemOp_STORE, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, RegisterID rm)
+ {
+ // Not calling the 5 argument form of strb, since is amount is ommitted S is false.
+ insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, MemOp_STORE, rm, UXTX, false, rn, rt));
+ }
+
+ ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ ASSERT_UNUSED(amount, !amount);
+ insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, MemOp_STORE, rm, extend, true, rn, rt));
+ }
+
+ ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ insn(loadStoreRegisterUnsignedImmediate(MemOpSize_8_or_128, false, MemOp_STORE, encodePositiveImmediate<8>(pimm), rn, rt));
+ }
+
+ ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, PostIndex simm)
+ {
+ insn(loadStoreRegisterPostIndex(MemOpSize_8_or_128, false, MemOp_STORE, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, PreIndex simm)
+ {
+ insn(loadStoreRegisterPreIndex(MemOpSize_8_or_128, false, MemOp_STORE, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, RegisterID rm)
+ {
+ strh(rt, rn, rm, UXTX, 0);
+ }
+
+ ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ ASSERT(!amount || amount == 1);
+ insn(loadStoreRegisterRegisterOffset(MemOpSize_16, false, MemOp_STORE, rm, extend, amount == 1, rn, rt));
+ }
+
+ ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ insn(loadStoreRegisterUnsignedImmediate(MemOpSize_16, false, MemOp_STORE, encodePositiveImmediate<16>(pimm), rn, rt));
+ }
+
+ ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, PostIndex simm)
+ {
+ insn(loadStoreRegisterPostIndex(MemOpSize_16, false, MemOp_STORE, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, PreIndex simm)
+ {
+ insn(loadStoreRegisterPreIndex(MemOpSize_16, false, MemOp_STORE, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void stur(RegisterID rt, RegisterID rn, int simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterUnscaledImmediate(MEMOPSIZE, false, MemOp_STORE, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void sturb(RegisterID rt, RegisterID rn, int simm)
+ {
+ insn(loadStoreRegisterUnscaledImmediate(MemOpSize_8_or_128, false, MemOp_STORE, simm, rn, rt));
+ }
+
+ ALWAYS_INLINE void sturh(RegisterID rt, RegisterID rn, int simm)
+ {
+ insn(loadStoreRegisterUnscaledImmediate(MemOpSize_16, false, MemOp_STORE, simm, rn, rt));
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, UInt12 imm12, int shift = 0)
+ {
+ CHECK_DATASIZE();
+ ASSERT(!shift || shift == 12);
+ insn(addSubtractImmediate(DATASIZE, AddOp_SUB, setFlags, shift == 12, imm12, rn, rd));
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ ASSERT_WITH_MESSAGE(!isSp(rd) || setFlags == DontSetFlags, "SUBS with shifted register does not support SP for Xd, it uses XZR for the register 31. SUBS with extended register support SP for Xd, but only if SetFlag is not used, otherwise register 31 is Xd.");
+ ASSERT_WITH_MESSAGE(!isSp(rm), "No encoding of SUBS supports SP for the third operand.");
+
+ if (isSp(rd) || isSp(rn))
+ sub<datasize, setFlags>(rd, rn, rm, UXTX, 0);
+ else
+ sub<datasize, setFlags>(rd, rn, rm, LSL, 0);
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ CHECK_DATASIZE();
+ insn(addSubtractExtendedRegister(DATASIZE, AddOp_SUB, setFlags, rm, extend, amount, rn, rd));
+ }
+
+ template<int datasize, SetFlags setFlags = DontSetFlags>
+ ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
+ {
+ CHECK_DATASIZE();
+ ASSERT(!isSp(rd) && !isSp(rn) && !isSp(rm));
+ insn(addSubtractShiftedRegister(DATASIZE, AddOp_SUB, setFlags, shift, rm, amount, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void sxtb(RegisterID rd, RegisterID rn)
+ {
+ sbfm<datasize>(rd, rn, 0, 7);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void sxth(RegisterID rd, RegisterID rn)
+ {
+ sbfm<datasize>(rd, rn, 0, 15);
+ }
+
+ ALWAYS_INLINE void sxtw(RegisterID rd, RegisterID rn)
+ {
+ sbfm<64>(rd, rn, 0, 31);
+ }
+
+ ALWAYS_INLINE void tbz(RegisterID rt, int imm, int offset = 0)
+ {
+ ASSERT(!(offset & 3));
+ offset >>= 2;
+ insn(testAndBranchImmediate(false, imm, offset, rt));
+ }
+
+ ALWAYS_INLINE void tbnz(RegisterID rt, int imm, int offset = 0)
+ {
+ ASSERT(!(offset & 3));
+ offset >>= 2;
+ insn(testAndBranchImmediate(true, imm, offset, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm)
+ {
+ and_<datasize, S>(ARM64Registers::zr, rn, rm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm, ShiftType shift, int amount)
+ {
+ and_<datasize, S>(ARM64Registers::zr, rn, rm, shift, amount);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void tst(RegisterID rn, LogicalImmediate imm)
+ {
+ and_<datasize, S>(ARM64Registers::zr, rn, imm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ubfiz(RegisterID rd, RegisterID rn, int lsb, int width)
+ {
+ ubfm<datasize>(rd, rn, (datasize - lsb) & (datasize - 1), width - 1);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ubfm(RegisterID rd, RegisterID rn, int immr, int imms)
+ {
+ CHECK_DATASIZE();
+ insn(bitfield(DATASIZE, BitfieldOp_UBFM, immr, imms, rn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ubfx(RegisterID rd, RegisterID rn, int lsb, int width)
+ {
+ ubfm<datasize>(rd, rn, lsb, lsb + width - 1);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void udiv(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ CHECK_DATASIZE();
+ insn(dataProcessing2Source(DATASIZE, rm, DataOp_UDIV, rn, rd));
+ }
+
+ ALWAYS_INLINE void umaddl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
+ {
+ nopCortexA53Fix835769<64>();
+ insn(dataProcessing3Source(Datasize_64, DataOp_UMADDL, rm, ra, rn, rd));
+ }
+
+ ALWAYS_INLINE void umnegl(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ umsubl(rd, rn, rm, ARM64Registers::zr);
+ }
+
+ ALWAYS_INLINE void umsubl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
+ {
+ nopCortexA53Fix835769<64>();
+ insn(dataProcessing3Source(Datasize_64, DataOp_UMSUBL, rm, ra, rn, rd));
+ }
+
+ ALWAYS_INLINE void umulh(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ insn(dataProcessing3Source(Datasize_64, DataOp_UMULH, rm, ARM64Registers::zr, rn, rd));
+ }
+
+ ALWAYS_INLINE void umull(RegisterID rd, RegisterID rn, RegisterID rm)
+ {
+ umaddl(rd, rn, rm, ARM64Registers::zr);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void uxtb(RegisterID rd, RegisterID rn)
+ {
+ ubfm<datasize>(rd, rn, 0, 7);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void uxth(RegisterID rd, RegisterID rn)
+ {
+ ubfm<datasize>(rd, rn, 0, 15);
+ }
+
+ ALWAYS_INLINE void uxtw(RegisterID rd, RegisterID rn)
+ {
+ ubfm<64>(rd, rn, 0, 31);
+ }
+
+ // Floating Point Instructions:
+
+ template<int datasize>
+ ALWAYS_INLINE void fabs(FPRegisterID vd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FABS, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fadd(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FADD, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fccmp(FPRegisterID vn, FPRegisterID vm, int nzcv, Condition cond)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointConditionalCompare(DATASIZE, vm, cond, vn, FPCondCmpOp_FCMP, nzcv));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fccmpe(FPRegisterID vn, FPRegisterID vm, int nzcv, Condition cond)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointConditionalCompare(DATASIZE, vm, cond, vn, FPCondCmpOp_FCMPE, nzcv));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fcmp(FPRegisterID vn, FPRegisterID vm)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointCompare(DATASIZE, vm, vn, FPCmpOp_FCMP));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fcmp_0(FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointCompare(DATASIZE, static_cast<FPRegisterID>(0), vn, FPCmpOp_FCMP0));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fcmpe(FPRegisterID vn, FPRegisterID vm)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointCompare(DATASIZE, vm, vn, FPCmpOp_FCMPE));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fcmpe_0(FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointCompare(DATASIZE, static_cast<FPRegisterID>(0), vn, FPCmpOp_FCMPE0));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fcsel(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, Condition cond)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointConditionalSelect(DATASIZE, vm, cond, vn, vd));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void fcvt(FPRegisterID vd, FPRegisterID vn)
+ {
+ ASSERT(dstsize == 16 || dstsize == 32 || dstsize == 64);
+ ASSERT(srcsize == 16 || srcsize == 32 || srcsize == 64);
+ ASSERT(dstsize != srcsize);
+ Datasize type = (srcsize == 64) ? Datasize_64 : (srcsize == 32) ? Datasize_32 : Datasize_16;
+ FPDataOp1Source opcode = (dstsize == 64) ? FPDataOp_FCVT_toDouble : (dstsize == 32) ? FPDataOp_FCVT_toSingle : FPDataOp_FCVT_toHalf;
+ insn(floatingPointDataProcessing1Source(type, opcode, vn, vd));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void fcvtas(RegisterID rd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE_OF(dstsize);
+ CHECK_DATASIZE_OF(srcsize);
+ insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTAS, vn, rd));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void fcvtau(RegisterID rd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE_OF(dstsize);
+ CHECK_DATASIZE_OF(srcsize);
+ insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTAU, vn, rd));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void fcvtms(RegisterID rd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE_OF(dstsize);
+ CHECK_DATASIZE_OF(srcsize);
+ insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTMS, vn, rd));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void fcvtmu(RegisterID rd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE_OF(dstsize);
+ CHECK_DATASIZE_OF(srcsize);
+ insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTMU, vn, rd));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void fcvtns(RegisterID rd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE_OF(dstsize);
+ CHECK_DATASIZE_OF(srcsize);
+ insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTNS, vn, rd));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void fcvtnu(RegisterID rd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE_OF(dstsize);
+ CHECK_DATASIZE_OF(srcsize);
+ insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTNU, vn, rd));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void fcvtps(RegisterID rd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE_OF(dstsize);
+ CHECK_DATASIZE_OF(srcsize);
+ insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTPS, vn, rd));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void fcvtpu(RegisterID rd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE_OF(dstsize);
+ CHECK_DATASIZE_OF(srcsize);
+ insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTPU, vn, rd));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void fcvtzs(RegisterID rd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE_OF(dstsize);
+ CHECK_DATASIZE_OF(srcsize);
+ insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTZS, vn, rd));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void fcvtzu(RegisterID rd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE_OF(dstsize);
+ CHECK_DATASIZE_OF(srcsize);
+ insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTZU, vn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fdiv(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FDIV, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fmadd(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, FPRegisterID va)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing3Source(DATASIZE, false, vm, AddOp_ADD, va, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fmax(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMAX, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fmaxnm(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMAXNM, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fmin(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMIN, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fminnm(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMINNM, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fmov(FPRegisterID vd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FMOV, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fmov(FPRegisterID vd, RegisterID rn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointIntegerConversions(DATASIZE, DATASIZE, FPIntConvOp_FMOV_XtoQ, rn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fmov(RegisterID rd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointIntegerConversions(DATASIZE, DATASIZE, FPIntConvOp_FMOV_QtoX, vn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fmov(FPRegisterID vd, double imm)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointImmediate(DATASIZE, encodeFPImm(imm), vd));
+ }
+
+ ALWAYS_INLINE void fmov_top(FPRegisterID vd, RegisterID rn)
+ {
+ insn(floatingPointIntegerConversions(Datasize_64, Datasize_64, FPIntConvOp_FMOV_XtoQ_top, rn, vd));
+ }
+
+ ALWAYS_INLINE void fmov_top(RegisterID rd, FPRegisterID vn)
+ {
+ insn(floatingPointIntegerConversions(Datasize_64, Datasize_64, FPIntConvOp_FMOV_QtoX_top, vn, rd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fmsub(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, FPRegisterID va)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing3Source(DATASIZE, false, vm, AddOp_SUB, va, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fmul(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMUL, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fneg(FPRegisterID vd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FNEG, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fnmadd(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, FPRegisterID va)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing3Source(DATASIZE, true, vm, AddOp_ADD, va, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fnmsub(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, FPRegisterID va)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing3Source(DATASIZE, true, vm, AddOp_SUB, va, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fnmul(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FNMUL, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void vand(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
+ {
+ CHECK_VECTOR_DATASIZE();
+ insn(vectorDataProcessing2Source(SIMD_LogicalOp_AND, vm, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void frinta(FPRegisterID vd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTA, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void frinti(FPRegisterID vd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTI, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void frintm(FPRegisterID vd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTM, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void frintn(FPRegisterID vd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTN, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void frintp(FPRegisterID vd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTP, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void frintx(FPRegisterID vd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTX, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void frintz(FPRegisterID vd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTZ, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fsqrt(FPRegisterID vd, FPRegisterID vn)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FSQRT, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void fsub(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
+ {
+ CHECK_DATASIZE();
+ insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FSUB, vn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, RegisterID rm)
+ {
+ ldr<datasize>(rt, rn, rm, UXTX, 0);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ CHECK_FP_MEMOP_DATASIZE();
+ insn(loadStoreRegisterRegisterOffset(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, rm, extend, encodeShiftAmount<datasize>(amount), rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ CHECK_FP_MEMOP_DATASIZE();
+ insn(loadStoreRegisterUnsignedImmediate(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, encodePositiveImmediate<datasize>(pimm), rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, PostIndex simm)
+ {
+ CHECK_FP_MEMOP_DATASIZE();
+ insn(loadStoreRegisterPostIndex(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, PreIndex simm)
+ {
+ CHECK_FP_MEMOP_DATASIZE();
+ insn(loadStoreRegisterPreIndex(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldr_literal(FPRegisterID rt, int offset = 0)
+ {
+ CHECK_FP_MEMOP_DATASIZE();
+ ASSERT(datasize >= 32);
+ ASSERT(!(offset & 3));
+ insn(loadRegisterLiteral(datasize == 128 ? LdrLiteralOp_128BIT : datasize == 64 ? LdrLiteralOp_64BIT : LdrLiteralOp_32BIT, true, offset >> 2, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldur(FPRegisterID rt, RegisterID rn, int simm)
+ {
+ CHECK_FP_MEMOP_DATASIZE();
+ insn(loadStoreRegisterUnscaledImmediate(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, simm, rn, rt));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void scvtf(FPRegisterID vd, RegisterID rn)
+ {
+ CHECK_DATASIZE_OF(dstsize);
+ CHECK_DATASIZE_OF(srcsize);
+ insn(floatingPointIntegerConversions(DATASIZE_OF(srcsize), DATASIZE_OF(dstsize), FPIntConvOp_SCVTF, rn, vd));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, RegisterID rm)
+ {
+ str<datasize>(rt, rn, rm, UXTX, 0);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
+ {
+ CHECK_FP_MEMOP_DATASIZE();
+ insn(loadStoreRegisterRegisterOffset(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, rm, extend, encodeShiftAmount<datasize>(amount), rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ CHECK_FP_MEMOP_DATASIZE();
+ insn(loadStoreRegisterUnsignedImmediate(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, encodePositiveImmediate<datasize>(pimm), rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, PostIndex simm)
+ {
+ CHECK_FP_MEMOP_DATASIZE();
+ insn(loadStoreRegisterPostIndex(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, PreIndex simm)
+ {
+ CHECK_FP_MEMOP_DATASIZE();
+ insn(loadStoreRegisterPreIndex(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, simm, rn, rt));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void stur(FPRegisterID rt, RegisterID rn, int simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterUnscaledImmediate(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, simm, rn, rt));
+ }
+
+ template<int dstsize, int srcsize>
+ ALWAYS_INLINE void ucvtf(FPRegisterID vd, RegisterID rn)
+ {
+ CHECK_DATASIZE_OF(dstsize);
+ CHECK_DATASIZE_OF(srcsize);
+ insn(floatingPointIntegerConversions(DATASIZE_OF(srcsize), DATASIZE_OF(dstsize), FPIntConvOp_UCVTF, rn, vd));
+ }
+
+ // Admin methods:
+
+ AssemblerLabel labelIgnoringWatchpoints()
+ {
+ return m_buffer.label();
+ }
+
+ AssemblerLabel labelForWatchpoint()
+ {
+ AssemblerLabel result = m_buffer.label();
+ if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint)
+ result = label();
+ m_indexOfLastWatchpoint = result.m_offset;
+ m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
+ return result;
+ }
+
+ AssemblerLabel label()
+ {
+ AssemblerLabel result = m_buffer.label();
+ while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) {
+ nop();
+ result = m_buffer.label();
+ }
+ return result;
+ }
+
+ AssemblerLabel align(int alignment)
+ {
+ ASSERT(!(alignment & 3));
+ while (!m_buffer.isAligned(alignment))
+ brk(0);
+ return label();
+ }
+
+ static void* getRelocatedAddress(void* code, AssemblerLabel label)
+ {
+ ASSERT(label.isSet());
+ return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + label.m_offset);
+ }
+
+ static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
+ {
+ return b.m_offset - a.m_offset;
+ }
+
+ void* unlinkedCode() { return m_buffer.data(); }
+ size_t codeSize() const { return m_buffer.codeSize(); }
+
+ static unsigned getCallReturnOffset(AssemblerLabel call)
+ {
+ ASSERT(call.isSet());
+ return call.m_offset;
+ }
+
+ // Linking & patching:
+ //
+ // 'link' and 'patch' methods are for use on unprotected code - such as the code
+ // within the AssemblerBuffer, and code being patched by the patch buffer. Once
+ // code has been finalized it is (platform support permitting) within a non-
+ // writable region of memory; to modify the code in an execute-only execuable
+ // pool the 'repatch' and 'relink' methods should be used.
+
+ void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition)
+ {
+ ASSERT(to.isSet());
+ ASSERT(from.isSet());
+ m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition));
+ }
+
+ void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition, bool is64Bit, RegisterID compareRegister)
+ {
+ ASSERT(to.isSet());
+ ASSERT(from.isSet());
+ m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition, is64Bit, compareRegister));
+ }
+
+ void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition, unsigned bitNumber, RegisterID compareRegister)
+ {
+ ASSERT(to.isSet());
+ ASSERT(from.isSet());
+ m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition, bitNumber, compareRegister));
+ }
+
+ void linkJump(AssemblerLabel from, AssemblerLabel to)
+ {
+ ASSERT(from.isSet());
+ ASSERT(to.isSet());
+ relinkJumpOrCall<false>(addressOf(from), addressOf(to));
+ }
+
+ static void linkJump(void* code, AssemblerLabel from, void* to)
+ {
+ ASSERT(from.isSet());
+ relinkJumpOrCall<false>(addressOf(code, from), to);
+ }
+
+ static void linkCall(void* code, AssemblerLabel from, void* to)
+ {
+ ASSERT(from.isSet());
+ linkJumpOrCall<true>(addressOf(code, from) - 1, to);
+ }
+
+ static void linkPointer(void* code, AssemblerLabel where, void* valuePtr)
+ {
+ linkPointer(addressOf(code, where), valuePtr);
+ }
+
+ static void replaceWithJump(void* where, void* to)
+ {
+ intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(where)) >> 2;
+ ASSERT(static_cast<int>(offset) == offset);
+ *static_cast<int*>(where) = unconditionalBranchImmediate(false, static_cast<int>(offset));
+ cacheFlush(where, sizeof(int));
+ }
+
+ static ptrdiff_t maxJumpReplacementSize()
+ {
+ return 4;
+ }
+
+ static void replaceWithLoad(void* where)
+ {
+ Datasize sf;
+ AddOp op;
+ SetFlags S;
+ int shift;
+ int imm12;
+ RegisterID rn;
+ RegisterID rd;
+ if (disassembleAddSubtractImmediate(where, sf, op, S, shift, imm12, rn, rd)) {
+ ASSERT(sf == Datasize_64);
+ ASSERT(op == AddOp_ADD);
+ ASSERT(!S);
+ ASSERT(!shift);
+ ASSERT(!(imm12 & ~0xff8));
+ *static_cast<int*>(where) = loadStoreRegisterUnsignedImmediate(MemOpSize_64, false, MemOp_LOAD, encodePositiveImmediate<64>(imm12), rn, rd);
+ cacheFlush(where, sizeof(int));
+ }
+#if !ASSERT_DISABLED
+ else {
+ MemOpSize size;
+ bool V;
+ MemOp opc;
+ int imm12;
+ RegisterID rn;
+ RegisterID rt;
+ ASSERT(disassembleLoadStoreRegisterUnsignedImmediate(where, size, V, opc, imm12, rn, rt));
+ ASSERT(size == MemOpSize_64);
+ ASSERT(!V);
+ ASSERT(opc == MemOp_LOAD);
+ ASSERT(!(imm12 & ~0x1ff));
+ }
+#endif
+ }
+
+ static void replaceWithAddressComputation(void* where)
+ {
+ MemOpSize size;
+ bool V;
+ MemOp opc;
+ int imm12;
+ RegisterID rn;
+ RegisterID rt;
+ if (disassembleLoadStoreRegisterUnsignedImmediate(where, size, V, opc, imm12, rn, rt)) {
+ ASSERT(size == MemOpSize_64);
+ ASSERT(!V);
+ ASSERT(opc == MemOp_LOAD);
+ ASSERT(!(imm12 & ~0x1ff));
+ *static_cast<int*>(where) = addSubtractImmediate(Datasize_64, AddOp_ADD, DontSetFlags, 0, imm12 * sizeof(void*), rn, rt);
+ cacheFlush(where, sizeof(int));
+ }
+#if !ASSERT_DISABLED
+ else {
+ Datasize sf;
+ AddOp op;
+ SetFlags S;
+ int shift;
+ int imm12;
+ RegisterID rn;
+ RegisterID rd;
+ ASSERT(disassembleAddSubtractImmediate(where, sf, op, S, shift, imm12, rn, rd));
+ ASSERT(sf == Datasize_64);
+ ASSERT(op == AddOp_ADD);
+ ASSERT(!S);
+ ASSERT(!shift);
+ ASSERT(!(imm12 & ~0xff8));
+ }
+#endif
+ }
+
+ static void repatchPointer(void* where, void* valuePtr)
+ {
+ linkPointer(static_cast<int*>(where), valuePtr, true);
+ }
+
+ static void setPointer(int* address, void* valuePtr, RegisterID rd, bool flush)
+ {
+ uintptr_t value = reinterpret_cast<uintptr_t>(valuePtr);
+ address[0] = moveWideImediate(Datasize_64, MoveWideOp_Z, 0, getHalfword(value, 0), rd);
+ address[1] = moveWideImediate(Datasize_64, MoveWideOp_K, 1, getHalfword(value, 1), rd);
+ address[2] = moveWideImediate(Datasize_64, MoveWideOp_K, 2, getHalfword(value, 2), rd);
+
+ if (flush)
+ cacheFlush(address, sizeof(int) * 3);
+ }
+
+ static void repatchInt32(void* where, int32_t value)
+ {
+ int* address = static_cast<int*>(where);
+
+ Datasize sf;
+ MoveWideOp opc;
+ int hw;
+ uint16_t imm16;
+ RegisterID rd;
+ bool expected = disassembleMoveWideImediate(address, sf, opc, hw, imm16, rd);
+ ASSERT_UNUSED(expected, expected && !sf && (opc == MoveWideOp_Z || opc == MoveWideOp_N) && !hw);
+ ASSERT(checkMovk<Datasize_32>(address[1], 1, rd));
+
+ if (value >= 0) {
+ address[0] = moveWideImediate(Datasize_32, MoveWideOp_Z, 0, getHalfword(value, 0), rd);
+ address[1] = moveWideImediate(Datasize_32, MoveWideOp_K, 1, getHalfword(value, 1), rd);
+ } else {
+ address[0] = moveWideImediate(Datasize_32, MoveWideOp_N, 0, ~getHalfword(value, 0), rd);
+ address[1] = moveWideImediate(Datasize_32, MoveWideOp_K, 1, getHalfword(value, 1), rd);
+ }
+
+ cacheFlush(where, sizeof(int) * 2);
+ }
+
+ static void* readPointer(void* where)
+ {
+ int* address = static_cast<int*>(where);
+
+ Datasize sf;
+ MoveWideOp opc;
+ int hw;
+ uint16_t imm16;
+ RegisterID rdFirst, rd;
+
+ bool expected = disassembleMoveWideImediate(address, sf, opc, hw, imm16, rdFirst);
+ ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_Z && !hw);
+ uintptr_t result = imm16;
+
+ expected = disassembleMoveWideImediate(address + 1, sf, opc, hw, imm16, rd);
+ ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 1 && rd == rdFirst);
+ result |= static_cast<uintptr_t>(imm16) << 16;
+
+ expected = disassembleMoveWideImediate(address + 2, sf, opc, hw, imm16, rd);
+ ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 2 && rd == rdFirst);
+ result |= static_cast<uintptr_t>(imm16) << 32;
+
+ return reinterpret_cast<void*>(result);
+ }
+
+ static void* readCallTarget(void* from)
+ {
+ return readPointer(reinterpret_cast<int*>(from) - 4);
+ }
+
+ static void relinkJump(void* from, void* to)
+ {
+ relinkJumpOrCall<false>(reinterpret_cast<int*>(from), to);
+ cacheFlush(from, sizeof(int));
+ }
+
+ static void relinkCall(void* from, void* to)
+ {
+ relinkJumpOrCall<true>(reinterpret_cast<int*>(from) - 1, to);
+ cacheFlush(reinterpret_cast<int*>(from) - 1, sizeof(int));
+ }
+
+ static void repatchCompact(void* where, int32_t value)
+ {
+ ASSERT(!(value & ~0x3ff8));
+
+ MemOpSize size;
+ bool V;
+ MemOp opc;
+ int imm12;
+ RegisterID rn;
+ RegisterID rt;
+ bool expected = disassembleLoadStoreRegisterUnsignedImmediate(where, size, V, opc, imm12, rn, rt);
+ ASSERT_UNUSED(expected, expected && size >= MemOpSize_32 && !V && opc == MemOp_LOAD); // expect 32/64 bit load to GPR.
+
+ if (size == MemOpSize_32)
+ imm12 = encodePositiveImmediate<32>(value);
+ else
+ imm12 = encodePositiveImmediate<64>(value);
+ *static_cast<int*>(where) = loadStoreRegisterUnsignedImmediate(size, V, opc, imm12, rn, rt);
+
+ cacheFlush(where, sizeof(int));
+ }
+
+ unsigned debugOffset() { return m_buffer.debugOffset(); }
+
+ void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset)
+ {
+ int32_t ptr = regionStart / sizeof(int32_t);
+ const int32_t end = regionEnd / sizeof(int32_t);
+ int32_t* offsets = static_cast<int32_t*>(m_buffer.data());
+ while (ptr < end)
+ offsets[ptr++] = offset;
+ }
+
+ int executableOffsetFor(int location)
+ {
+ if (!location)
+ return 0;
+ return static_cast<int32_t*>(m_buffer.data())[location / sizeof(int32_t) - 1];
+ }
+
+#if OS(LINUX)
+ static inline void linuxPageFlush(uintptr_t begin, uintptr_t end)
+ {
+ __builtin___clear_cache(reinterpret_cast<char*>(begin), reinterpret_cast<char*>(end));
+ }
+#endif
+
+ static void cacheFlush(void* code, size_t size)
+ {
+#if OS(IOS)
+ sys_cache_control(kCacheFunctionPrepareForExecution, code, size);
+#elif OS(LINUX)
+ size_t page = pageSize();
+ uintptr_t current = reinterpret_cast<uintptr_t>(code);
+ uintptr_t end = current + size;
+ uintptr_t firstPageEnd = (current & ~(page - 1)) + page;
+
+ if (end <= firstPageEnd) {
+ linuxPageFlush(current, end);
+ return;
+ }
+
+ linuxPageFlush(current, firstPageEnd);
+
+ for (current = firstPageEnd; current + page < end; current += page)
+ linuxPageFlush(current, current + page);
+
+ linuxPageFlush(current, end);
+#else
+#error "The cacheFlush support is missing on this platform."
+#endif
+ }
+
+ // Assembler admin methods:
+
+ static int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return JUMP_ENUM_SIZE(jumpType) - JUMP_ENUM_SIZE(jumpLinkType); }
+
+ static ALWAYS_INLINE bool linkRecordSourceComparator(const LinkRecord& a, const LinkRecord& b)
+ {
+ return a.from() < b.from();
+ }
+
+ static bool canCompact(JumpType jumpType)
+ {
+ // Fixed jumps cannot be compacted
+ return (jumpType == JumpNoCondition) || (jumpType == JumpCondition) || (jumpType == JumpCompareAndBranch) || (jumpType == JumpTestBit);
+ }
+
+ static JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to)
+ {
+ switch (jumpType) {
+ case JumpFixed:
+ return LinkInvalid;
+ case JumpNoConditionFixedSize:
+ return LinkJumpNoCondition;
+ case JumpConditionFixedSize:
+ return LinkJumpCondition;
+ case JumpCompareAndBranchFixedSize:
+ return LinkJumpCompareAndBranch;
+ case JumpTestBitFixedSize:
+ return LinkJumpTestBit;
+ case JumpNoCondition:
+ return LinkJumpNoCondition;
+ case JumpCondition: {
+ ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
+ ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
+ intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
+
+ if (((relative << 43) >> 43) == relative)
+ return LinkJumpConditionDirect;
+
+ return LinkJumpCondition;
+ }
+ case JumpCompareAndBranch: {
+ ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
+ ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
+ intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
+
+ if (((relative << 43) >> 43) == relative)
+ return LinkJumpCompareAndBranchDirect;
+
+ return LinkJumpCompareAndBranch;
+ }
+ case JumpTestBit: {
+ ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
+ ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
+ intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
+
+ if (((relative << 50) >> 50) == relative)
+ return LinkJumpTestBitDirect;
+
+ return LinkJumpTestBit;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return LinkJumpNoCondition;
+ }
+
+ static JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to)
+ {
+ JumpLinkType linkType = computeJumpType(record.type(), from, to);
+ record.setLinkType(linkType);
+ return linkType;
+ }
+
+ Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink()
+ {
+ std::sort(m_jumpsToLink.begin(), m_jumpsToLink.end(), linkRecordSourceComparator);
+ return m_jumpsToLink;
+ }
+
+ static void ALWAYS_INLINE link(LinkRecord& record, uint8_t* from, uint8_t* to)
+ {
+ switch (record.linkType()) {
+ case LinkJumpNoCondition:
+ linkJumpOrCall<false>(reinterpret_cast<int*>(from), to);
+ break;
+ case LinkJumpConditionDirect:
+ linkConditionalBranch<true>(record.condition(), reinterpret_cast<int*>(from), to);
+ break;
+ case LinkJumpCondition:
+ linkConditionalBranch<false>(record.condition(), reinterpret_cast<int*>(from) - 1, to);
+ break;
+ case LinkJumpCompareAndBranchDirect:
+ linkCompareAndBranch<true>(record.condition(), record.is64Bit(), record.compareRegister(), reinterpret_cast<int*>(from), to);
+ break;
+ case LinkJumpCompareAndBranch:
+ linkCompareAndBranch<false>(record.condition(), record.is64Bit(), record.compareRegister(), reinterpret_cast<int*>(from) - 1, to);
+ break;
+ case LinkJumpTestBitDirect:
+ linkTestAndBranch<true>(record.condition(), record.bitNumber(), record.compareRegister(), reinterpret_cast<int*>(from), to);
+ break;
+ case LinkJumpTestBit:
+ linkTestAndBranch<false>(record.condition(), record.bitNumber(), record.compareRegister(), reinterpret_cast<int*>(from) - 1, to);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
+private:
+ template<Datasize size>
+ static bool checkMovk(int insn, int _hw, RegisterID _rd)
+ {
+ Datasize sf;
+ MoveWideOp opc;
+ int hw;
+ uint16_t imm16;
+ RegisterID rd;
+ bool expected = disassembleMoveWideImediate(&insn, sf, opc, hw, imm16, rd);
+
+ return expected
+ && sf == size
+ && opc == MoveWideOp_K
+ && hw == _hw
+ && rd == _rd;
+ }
+
+ static void linkPointer(int* address, void* valuePtr, bool flush = false)
+ {
+ Datasize sf;
+ MoveWideOp opc;
+ int hw;
+ uint16_t imm16;
+ RegisterID rd;
+ bool expected = disassembleMoveWideImediate(address, sf, opc, hw, imm16, rd);
+ ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_Z && !hw);
+ ASSERT(checkMovk<Datasize_64>(address[1], 1, rd));
+ ASSERT(checkMovk<Datasize_64>(address[2], 2, rd));
+
+ setPointer(address, valuePtr, rd, flush);
+ }
+
+ template<bool isCall>
+ static void linkJumpOrCall(int* from, void* to)
+ {
+ bool link;
+ int imm26;
+ bool isUnconditionalBranchImmediateOrNop = disassembleUnconditionalBranchImmediate(from, link, imm26) || disassembleNop(from);
+
+ ASSERT_UNUSED(isUnconditionalBranchImmediateOrNop, isUnconditionalBranchImmediateOrNop);
+ ASSERT_UNUSED(isCall, (link == isCall) || disassembleNop(from));
+ ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
+ ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
+ intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
+ ASSERT(static_cast<int>(offset) == offset);
+
+ *from = unconditionalBranchImmediate(isCall, static_cast<int>(offset));
+ }
+
+ template<bool isDirect>
+ static void linkCompareAndBranch(Condition condition, bool is64Bit, RegisterID rt, int* from, void* to)
+ {
+ ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
+ ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
+ intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
+ ASSERT(((offset << 38) >> 38) == offset);
+
+ bool useDirect = ((offset << 45) >> 45) == offset; // Fits in 19 bits
+ ASSERT(!isDirect || useDirect);
+
+ if (useDirect || isDirect) {
+ *from = compareAndBranchImmediate(is64Bit ? Datasize_64 : Datasize_32, condition == ConditionNE, static_cast<int>(offset), rt);
+ if (!isDirect)
+ *(from + 1) = nopPseudo();
+ } else {
+ *from = compareAndBranchImmediate(is64Bit ? Datasize_64 : Datasize_32, invert(condition) == ConditionNE, 2, rt);
+ linkJumpOrCall<false>(from + 1, to);
+ }
+ }
+
+ template<bool isDirect>
+ static void linkConditionalBranch(Condition condition, int* from, void* to)
+ {
+ ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
+ ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
+ intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
+ ASSERT(((offset << 38) >> 38) == offset);
+
+ bool useDirect = ((offset << 45) >> 45) == offset; // Fits in 19 bits
+ ASSERT(!isDirect || useDirect);
+
+ if (useDirect || isDirect) {
+ *from = conditionalBranchImmediate(static_cast<int>(offset), condition);
+ if (!isDirect)
+ *(from + 1) = nopPseudo();
+ } else {
+ *from = conditionalBranchImmediate(2, invert(condition));
+ linkJumpOrCall<false>(from + 1, to);
+ }
+ }
+
+ template<bool isDirect>
+ static void linkTestAndBranch(Condition condition, unsigned bitNumber, RegisterID rt, int* from, void* to)
+ {
+ ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
+ ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
+ intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
+ ASSERT(static_cast<int>(offset) == offset);
+ ASSERT(((offset << 38) >> 38) == offset);
+
+ bool useDirect = ((offset << 50) >> 50) == offset; // Fits in 14 bits
+ ASSERT(!isDirect || useDirect);
+
+ if (useDirect || isDirect) {
+ *from = testAndBranchImmediate(condition == ConditionNE, static_cast<int>(bitNumber), static_cast<int>(offset), rt);
+ if (!isDirect)
+ *(from + 1) = nopPseudo();
+ } else {
+ *from = testAndBranchImmediate(invert(condition) == ConditionNE, static_cast<int>(bitNumber), 2, rt);
+ linkJumpOrCall<false>(from + 1, to);
+ }
+ }
+
+ template<bool isCall>
+ static void relinkJumpOrCall(int* from, void* to)
+ {
+ if (!isCall && disassembleNop(from)) {
+ unsigned op01;
+ int imm19;
+ Condition condition;
+ bool isConditionalBranchImmediate = disassembleConditionalBranchImmediate(from - 1, op01, imm19, condition);
+
+ if (isConditionalBranchImmediate) {
+ ASSERT_UNUSED(op01, !op01);
+ ASSERT_UNUSED(isCall, !isCall);
+
+ if (imm19 == 8)
+ condition = invert(condition);
+
+ linkConditionalBranch<false>(condition, from - 1, to);
+ return;
+ }
+
+ Datasize opSize;
+ bool op;
+ RegisterID rt;
+ bool isCompareAndBranchImmediate = disassembleCompareAndBranchImmediate(from - 1, opSize, op, imm19, rt);
+
+ if (isCompareAndBranchImmediate) {
+ if (imm19 == 8)
+ op = !op;
+
+ linkCompareAndBranch<false>(op ? ConditionNE : ConditionEQ, opSize == Datasize_64, rt, from - 1, to);
+ return;
+ }
+
+ int imm14;
+ unsigned bitNumber;
+ bool isTestAndBranchImmediate = disassembleTestAndBranchImmediate(from - 1, op, bitNumber, imm14, rt);
+
+ if (isTestAndBranchImmediate) {
+ if (imm14 == 8)
+ op = !op;
+
+ linkTestAndBranch<false>(op ? ConditionNE : ConditionEQ, bitNumber, rt, from - 1, to);
+ return;
+ }
+ }
+
+ linkJumpOrCall<isCall>(from, to);
+ }
+
+ static int* addressOf(void* code, AssemblerLabel label)
+ {
+ return reinterpret_cast<int*>(static_cast<char*>(code) + label.m_offset);
+ }
+
+ int* addressOf(AssemblerLabel label)
+ {
+ return addressOf(m_buffer.data(), label);
+ }
+
+ static RegisterID disassembleXOrSp(int reg) { return reg == 31 ? ARM64Registers::sp : static_cast<RegisterID>(reg); }
+ static RegisterID disassembleXOrZr(int reg) { return reg == 31 ? ARM64Registers::zr : static_cast<RegisterID>(reg); }
+ static RegisterID disassembleXOrZrOrSp(bool useZr, int reg) { return reg == 31 ? (useZr ? ARM64Registers::zr : ARM64Registers::sp) : static_cast<RegisterID>(reg); }
+
+ static bool disassembleAddSubtractImmediate(void* address, Datasize& sf, AddOp& op, SetFlags& S, int& shift, int& imm12, RegisterID& rn, RegisterID& rd)
+ {
+ int insn = *static_cast<int*>(address);
+ sf = static_cast<Datasize>((insn >> 31) & 1);
+ op = static_cast<AddOp>((insn >> 30) & 1);
+ S = static_cast<SetFlags>((insn >> 29) & 1);
+ shift = (insn >> 22) & 3;
+ imm12 = (insn >> 10) & 0x3ff;
+ rn = disassembleXOrSp((insn >> 5) & 0x1f);
+ rd = disassembleXOrZrOrSp(S, insn & 0x1f);
+ return (insn & 0x1f000000) == 0x11000000;
+ }
+
+ static bool disassembleLoadStoreRegisterUnsignedImmediate(void* address, MemOpSize& size, bool& V, MemOp& opc, int& imm12, RegisterID& rn, RegisterID& rt)
+ {
+ int insn = *static_cast<int*>(address);
+ size = static_cast<MemOpSize>((insn >> 30) & 3);
+ V = (insn >> 26) & 1;
+ opc = static_cast<MemOp>((insn >> 22) & 3);
+ imm12 = (insn >> 10) & 0xfff;
+ rn = disassembleXOrSp((insn >> 5) & 0x1f);
+ rt = disassembleXOrZr(insn & 0x1f);
+ return (insn & 0x3b000000) == 0x39000000;
+ }
+
+ static bool disassembleMoveWideImediate(void* address, Datasize& sf, MoveWideOp& opc, int& hw, uint16_t& imm16, RegisterID& rd)
+ {
+ int insn = *static_cast<int*>(address);
+ sf = static_cast<Datasize>((insn >> 31) & 1);
+ opc = static_cast<MoveWideOp>((insn >> 29) & 3);
+ hw = (insn >> 21) & 3;
+ imm16 = insn >> 5;
+ rd = disassembleXOrZr(insn & 0x1f);
+ return (insn & 0x1f800000) == 0x12800000;
+ }
+
+ static bool disassembleNop(void* address)
+ {
+ unsigned insn = *static_cast<unsigned*>(address);
+ return insn == 0xd503201f;
+ }
+
+ static bool disassembleCompareAndBranchImmediate(void* address, Datasize& sf, bool& op, int& imm19, RegisterID& rt)
+ {
+ int insn = *static_cast<int*>(address);
+ sf = static_cast<Datasize>((insn >> 31) & 1);
+ op = (insn >> 24) & 0x1;
+ imm19 = (insn << 8) >> 13;
+ rt = static_cast<RegisterID>(insn & 0x1f);
+ return (insn & 0x7e000000) == 0x34000000;
+
+ }
+
+ static bool disassembleConditionalBranchImmediate(void* address, unsigned& op01, int& imm19, Condition &condition)
+ {
+ int insn = *static_cast<int*>(address);
+ op01 = ((insn >> 23) & 0x2) | ((insn >> 4) & 0x1);
+ imm19 = (insn << 8) >> 13;
+ condition = static_cast<Condition>(insn & 0xf);
+ return (insn & 0xfe000000) == 0x54000000;
+ }
+
+ static bool disassembleTestAndBranchImmediate(void* address, bool& op, unsigned& bitNumber, int& imm14, RegisterID& rt)
+ {
+ int insn = *static_cast<int*>(address);
+ op = (insn >> 24) & 0x1;
+ imm14 = (insn << 13) >> 18;
+ bitNumber = static_cast<unsigned>((((insn >> 26) & 0x20)) | ((insn >> 19) & 0x1f));
+ rt = static_cast<RegisterID>(insn & 0x1f);
+ return (insn & 0x7e000000) == 0x36000000;
+
+ }
+
+ static bool disassembleUnconditionalBranchImmediate(void* address, bool& op, int& imm26)
+ {
+ int insn = *static_cast<int*>(address);
+ op = (insn >> 31) & 1;
+ imm26 = (insn << 6) >> 6;
+ return (insn & 0x7c000000) == 0x14000000;
+ }
+
+ static int xOrSp(RegisterID reg) { ASSERT(!isZr(reg)); return reg; }
+ static int xOrZr(RegisterID reg) { ASSERT(!isSp(reg)); return reg & 31; }
+ static FPRegisterID xOrZrAsFPR(RegisterID reg) { return static_cast<FPRegisterID>(xOrZr(reg)); }
+ static int xOrZrOrSp(bool useZr, RegisterID reg) { return useZr ? xOrZr(reg) : xOrSp(reg); }
+
+ ALWAYS_INLINE void insn(int instruction)
+ {
+ m_buffer.putInt(instruction);
+ }
+
+ ALWAYS_INLINE static int addSubtractExtendedRegister(Datasize sf, AddOp op, SetFlags S, RegisterID rm, ExtendType option, int imm3, RegisterID rn, RegisterID rd)
+ {
+ ASSERT(imm3 < 5);
+ // The only allocated values for opt is 0.
+ const int opt = 0;
+ return (0x0b200000 | sf << 31 | op << 30 | S << 29 | opt << 22 | xOrZr(rm) << 16 | option << 13 | (imm3 & 0x7) << 10 | xOrSp(rn) << 5 | xOrZrOrSp(S, rd));
+ }
+
+ ALWAYS_INLINE static int addSubtractImmediate(Datasize sf, AddOp op, SetFlags S, int shift, int imm12, RegisterID rn, RegisterID rd)
+ {
+ ASSERT(shift < 2);
+ ASSERT(isUInt12(imm12));
+ return (0x11000000 | sf << 31 | op << 30 | S << 29 | shift << 22 | (imm12 & 0xfff) << 10 | xOrSp(rn) << 5 | xOrZrOrSp(S, rd));
+ }
+
+ ALWAYS_INLINE static int addSubtractShiftedRegister(Datasize sf, AddOp op, SetFlags S, ShiftType shift, RegisterID rm, int imm6, RegisterID rn, RegisterID rd)
+ {
+ ASSERT(shift < 3);
+ ASSERT(!(imm6 & (sf ? ~63 : ~31)));
+ return (0x0b000000 | sf << 31 | op << 30 | S << 29 | shift << 22 | xOrZr(rm) << 16 | (imm6 & 0x3f) << 10 | xOrZr(rn) << 5 | xOrZr(rd));
+ }
+
+ ALWAYS_INLINE static int addSubtractWithCarry(Datasize sf, AddOp op, SetFlags S, RegisterID rm, RegisterID rn, RegisterID rd)
+ {
+ const int opcode2 = 0;
+ return (0x1a000000 | sf << 31 | op << 30 | S << 29 | xOrZr(rm) << 16 | opcode2 << 10 | xOrZr(rn) << 5 | xOrZr(rd));
+ }
+
+ ALWAYS_INLINE static int bitfield(Datasize sf, BitfieldOp opc, int immr, int imms, RegisterID rn, RegisterID rd)
+ {
+ ASSERT(immr < (sf ? 64 : 32));
+ ASSERT(imms < (sf ? 64 : 32));
+ const int N = sf;
+ return (0x13000000 | sf << 31 | opc << 29 | N << 22 | immr << 16 | imms << 10 | xOrZr(rn) << 5 | xOrZr(rd));
+ }
+
+ // 'op' means negate
+ ALWAYS_INLINE static int compareAndBranchImmediate(Datasize sf, bool op, int32_t imm19, RegisterID rt)
+ {
+ ASSERT(imm19 == (imm19 << 13) >> 13);
+ return (0x34000000 | sf << 31 | op << 24 | (imm19 & 0x7ffff) << 5 | xOrZr(rt));
+ }
+
+ ALWAYS_INLINE static int conditionalBranchImmediate(int32_t imm19, Condition cond)
+ {
+ ASSERT(imm19 == (imm19 << 13) >> 13);
+ ASSERT(!(cond & ~15));
+ // The only allocated values for o1 & o0 are 0.
+ const int o1 = 0;
+ const int o0 = 0;
+ return (0x54000000 | o1 << 24 | (imm19 & 0x7ffff) << 5 | o0 << 4 | cond);
+ }
+
+ ALWAYS_INLINE static int conditionalCompareImmediate(Datasize sf, AddOp op, int imm5, Condition cond, RegisterID rn, int nzcv)
+ {
+ ASSERT(!(imm5 & ~0x1f));
+ ASSERT(nzcv < 16);
+ const int S = 1;
+ const int o2 = 0;
+ const int o3 = 0;
+ return (0x1a400800 | sf << 31 | op << 30 | S << 29 | (imm5 & 0x1f) << 16 | cond << 12 | o2 << 10 | xOrZr(rn) << 5 | o3 << 4 | nzcv);
+ }
+
+ ALWAYS_INLINE static int conditionalCompareRegister(Datasize sf, AddOp op, RegisterID rm, Condition cond, RegisterID rn, int nzcv)
+ {
+ ASSERT(nzcv < 16);
+ const int S = 1;
+ const int o2 = 0;
+ const int o3 = 0;
+ return (0x1a400000 | sf << 31 | op << 30 | S << 29 | xOrZr(rm) << 16 | cond << 12 | o2 << 10 | xOrZr(rn) << 5 | o3 << 4 | nzcv);
+ }
+
+ // 'op' means negate
+ // 'op2' means increment
+ ALWAYS_INLINE static int conditionalSelect(Datasize sf, bool op, RegisterID rm, Condition cond, bool op2, RegisterID rn, RegisterID rd)
+ {
+ const int S = 0;
+ return (0x1a800000 | sf << 31 | op << 30 | S << 29 | xOrZr(rm) << 16 | cond << 12 | op2 << 10 | xOrZr(rn) << 5 | xOrZr(rd));
+ }
+
+ ALWAYS_INLINE static int dataProcessing1Source(Datasize sf, DataOp1Source opcode, RegisterID rn, RegisterID rd)
+ {
+ const int S = 0;
+ const int opcode2 = 0;
+ return (0x5ac00000 | sf << 31 | S << 29 | opcode2 << 16 | opcode << 10 | xOrZr(rn) << 5 | xOrZr(rd));
+ }
+
+ ALWAYS_INLINE static int dataProcessing2Source(Datasize sf, RegisterID rm, DataOp2Source opcode, RegisterID rn, RegisterID rd)
+ {
+ const int S = 0;
+ return (0x1ac00000 | sf << 31 | S << 29 | xOrZr(rm) << 16 | opcode << 10 | xOrZr(rn) << 5 | xOrZr(rd));
+ }
+
+ ALWAYS_INLINE static int dataProcessing3Source(Datasize sf, DataOp3Source opcode, RegisterID rm, RegisterID ra, RegisterID rn, RegisterID rd)
+ {
+ int op54 = opcode >> 4;
+ int op31 = (opcode >> 1) & 7;
+ int op0 = opcode & 1;
+ return (0x1b000000 | sf << 31 | op54 << 29 | op31 << 21 | xOrZr(rm) << 16 | op0 << 15 | xOrZr(ra) << 10 | xOrZr(rn) << 5 | xOrZr(rd));
+ }
+
+ ALWAYS_INLINE static int excepnGeneration(ExcepnOp opc, uint16_t imm16, int LL)
+ {
+ ASSERT((opc == ExcepnOp_BREAKPOINT || opc == ExcepnOp_HALT) ? !LL : (LL && (LL < 4)));
+ const int op2 = 0;
+ return (0xd4000000 | opc << 21 | imm16 << 5 | op2 << 2 | LL);
+ }
+
+ ALWAYS_INLINE static int extract(Datasize sf, RegisterID rm, int imms, RegisterID rn, RegisterID rd)
+ {
+ ASSERT(imms < (sf ? 64 : 32));
+ const int op21 = 0;
+ const int N = sf;
+ const int o0 = 0;
+ return (0x13800000 | sf << 31 | op21 << 29 | N << 22 | o0 << 21 | xOrZr(rm) << 16 | imms << 10 | xOrZr(rn) << 5 | xOrZr(rd));
+ }
+
+ ALWAYS_INLINE static int floatingPointCompare(Datasize type, FPRegisterID rm, FPRegisterID rn, FPCmpOp opcode2)
+ {
+ const int M = 0;
+ const int S = 0;
+ const int op = 0;
+ return (0x1e202000 | M << 31 | S << 29 | type << 22 | rm << 16 | op << 14 | rn << 5 | opcode2);
+ }
+
+ ALWAYS_INLINE static int floatingPointConditionalCompare(Datasize type, FPRegisterID rm, Condition cond, FPRegisterID rn, FPCondCmpOp op, int nzcv)
+ {
+ ASSERT(nzcv < 16);
+ const int M = 0;
+ const int S = 0;
+ return (0x1e200400 | M << 31 | S << 29 | type << 22 | rm << 16 | cond << 12 | rn << 5 | op << 4 | nzcv);
+ }
+
+ ALWAYS_INLINE static int floatingPointConditionalSelect(Datasize type, FPRegisterID rm, Condition cond, FPRegisterID rn, FPRegisterID rd)
+ {
+ const int M = 0;
+ const int S = 0;
+ return (0x1e200c00 | M << 31 | S << 29 | type << 22 | rm << 16 | cond << 12 | rn << 5 | rd);
+ }
+
+ ALWAYS_INLINE static int floatingPointImmediate(Datasize type, int imm8, FPRegisterID rd)
+ {
+ const int M = 0;
+ const int S = 0;
+ const int imm5 = 0;
+ return (0x1e201000 | M << 31 | S << 29 | type << 22 | (imm8 & 0xff) << 13 | imm5 << 5 | rd);
+ }
+
+ ALWAYS_INLINE static int floatingPointIntegerConversions(Datasize sf, Datasize type, FPIntConvOp rmodeOpcode, FPRegisterID rn, FPRegisterID rd)
+ {
+ const int S = 0;
+ return (0x1e200000 | sf << 31 | S << 29 | type << 22 | rmodeOpcode << 16 | rn << 5 | rd);
+ }
+
+ ALWAYS_INLINE static int floatingPointIntegerConversions(Datasize sf, Datasize type, FPIntConvOp rmodeOpcode, FPRegisterID rn, RegisterID rd)
+ {
+ return floatingPointIntegerConversions(sf, type, rmodeOpcode, rn, xOrZrAsFPR(rd));
+ }
+
+ ALWAYS_INLINE static int floatingPointIntegerConversions(Datasize sf, Datasize type, FPIntConvOp rmodeOpcode, RegisterID rn, FPRegisterID rd)
+ {
+ return floatingPointIntegerConversions(sf, type, rmodeOpcode, xOrZrAsFPR(rn), rd);
+ }
+
+ ALWAYS_INLINE static int floatingPointDataProcessing1Source(Datasize type, FPDataOp1Source opcode, FPRegisterID rn, FPRegisterID rd)
+ {
+ const int M = 0;
+ const int S = 0;
+ return (0x1e204000 | M << 31 | S << 29 | type << 22 | opcode << 15 | rn << 5 | rd);
+ }
+
+ ALWAYS_INLINE static int floatingPointDataProcessing2Source(Datasize type, FPRegisterID rm, FPDataOp2Source opcode, FPRegisterID rn, FPRegisterID rd)
+ {
+ const int M = 0;
+ const int S = 0;
+ return (0x1e200800 | M << 31 | S << 29 | type << 22 | rm << 16 | opcode << 12 | rn << 5 | rd);
+ }
+
+ ALWAYS_INLINE static int vectorDataProcessing2Source(SIMD3Same opcode, unsigned size, FPRegisterID vm, FPRegisterID vn, FPRegisterID vd)
+ {
+ const int Q = 0;
+ return (0xe201c00 | Q << 30 | size << 22 | vm << 16 | opcode << 11 | vn << 5 | vd);
+ }
+
+ ALWAYS_INLINE static int vectorDataProcessing2Source(SIMD3Same opcode, FPRegisterID vm, FPRegisterID vn, FPRegisterID vd)
+ {
+ return vectorDataProcessing2Source(opcode, 0, vm, vn, vd);
+ }
+
+
+ // 'o1' means negate
+ ALWAYS_INLINE static int floatingPointDataProcessing3Source(Datasize type, bool o1, FPRegisterID rm, AddOp o2, FPRegisterID ra, FPRegisterID rn, FPRegisterID rd)
+ {
+ const int M = 0;
+ const int S = 0;
+ return (0x1f000000 | M << 31 | S << 29 | type << 22 | o1 << 21 | rm << 16 | o2 << 15 | ra << 10 | rn << 5 | rd);
+ }
+
+ // 'V' means vector
+ ALWAYS_INLINE static int loadRegisterLiteral(LdrLiteralOp opc, bool V, int imm19, FPRegisterID rt)
+ {
+ ASSERT(((imm19 << 13) >> 13) == imm19);
+ return (0x18000000 | opc << 30 | V << 26 | (imm19 & 0x7ffff) << 5 | rt);
+ }
+
+ ALWAYS_INLINE static int loadRegisterLiteral(LdrLiteralOp opc, bool V, int imm19, RegisterID rt)
+ {
+ return loadRegisterLiteral(opc, V, imm19, xOrZrAsFPR(rt));
+ }
+
+ // 'V' means vector
+ ALWAYS_INLINE static int loadStoreRegisterPostIndex(MemOpSize size, bool V, MemOp opc, int imm9, RegisterID rn, FPRegisterID rt)
+ {
+ ASSERT(!(size && V && (opc & 2))); // Maximum vector size is 128 bits.
+ ASSERT(!((size & 2) && !V && (opc == 3))); // signed 32-bit load must be extending from 8/16 bits.
+ ASSERT(isInt9(imm9));
+ return (0x38000400 | size << 30 | V << 26 | opc << 22 | (imm9 & 0x1ff) << 12 | xOrSp(rn) << 5 | rt);
+ }
+
+ ALWAYS_INLINE static int loadStoreRegisterPostIndex(MemOpSize size, bool V, MemOp opc, int imm9, RegisterID rn, RegisterID rt)
+ {
+ return loadStoreRegisterPostIndex(size, V, opc, imm9, rn, xOrZrAsFPR(rt));
+ }
+
+ // 'V' means vector
+ ALWAYS_INLINE static int loadStoreRegisterPairPostIndex(MemPairOpSize size, bool V, MemOp opc, int immediate, RegisterID rn, FPRegisterID rt, FPRegisterID rt2)
+ {
+ ASSERT(size < 3);
+ ASSERT(opc == (opc & 1)); // Only load or store, load signed 64 is handled via size.
+ ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
+ unsigned immedShiftAmount = memPairOffsetShift(V, size);
+ int imm7 = immediate >> immedShiftAmount;
+ ASSERT((imm7 << immedShiftAmount) == immediate && isInt7(imm7));
+ return (0x28800000 | size << 30 | V << 26 | opc << 22 | (imm7 & 0x7f) << 15 | rt2 << 10 | xOrSp(rn) << 5 | rt);
+ }
+
+ ALWAYS_INLINE static int loadStoreRegisterPairPostIndex(MemPairOpSize size, bool V, MemOp opc, int immediate, RegisterID rn, RegisterID rt, RegisterID rt2)
+ {
+ return loadStoreRegisterPairPostIndex(size, V, opc, immediate, rn, xOrZrAsFPR(rt), xOrZrAsFPR(rt2));
+ }
+
+ // 'V' means vector
+ ALWAYS_INLINE static int loadStoreRegisterPreIndex(MemOpSize size, bool V, MemOp opc, int imm9, RegisterID rn, FPRegisterID rt)
+ {
+ ASSERT(!(size && V && (opc & 2))); // Maximum vector size is 128 bits.
+ ASSERT(!((size & 2) && !V && (opc == 3))); // signed 32-bit load must be extending from 8/16 bits.
+ ASSERT(isInt9(imm9));
+ return (0x38000c00 | size << 30 | V << 26 | opc << 22 | (imm9 & 0x1ff) << 12 | xOrSp(rn) << 5 | rt);
+ }
+
+ ALWAYS_INLINE static int loadStoreRegisterPreIndex(MemOpSize size, bool V, MemOp opc, int imm9, RegisterID rn, RegisterID rt)
+ {
+ return loadStoreRegisterPreIndex(size, V, opc, imm9, rn, xOrZrAsFPR(rt));
+ }
+
+ // 'V' means vector
+ ALWAYS_INLINE static int loadStoreRegisterPairPreIndex(MemPairOpSize size, bool V, MemOp opc, int immediate, RegisterID rn, FPRegisterID rt, FPRegisterID rt2)
+ {
+ ASSERT(size < 3);
+ ASSERT(opc == (opc & 1)); // Only load or store, load signed 64 is handled via size.
+ ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
+ unsigned immedShiftAmount = memPairOffsetShift(V, size);
+ int imm7 = immediate >> immedShiftAmount;
+ ASSERT((imm7 << immedShiftAmount) == immediate && isInt7(imm7));
+ return (0x29800000 | size << 30 | V << 26 | opc << 22 | (imm7 & 0x7f) << 15 | rt2 << 10 | xOrSp(rn) << 5 | rt);
+ }
+
+ ALWAYS_INLINE static int loadStoreRegisterPairPreIndex(MemPairOpSize size, bool V, MemOp opc, int immediate, RegisterID rn, RegisterID rt, RegisterID rt2)
+ {
+ return loadStoreRegisterPairPreIndex(size, V, opc, immediate, rn, xOrZrAsFPR(rt), xOrZrAsFPR(rt2));
+ }
+
+ // 'V' means vector
+ // 'S' means shift rm
+ ALWAYS_INLINE static int loadStoreRegisterRegisterOffset(MemOpSize size, bool V, MemOp opc, RegisterID rm, ExtendType option, bool S, RegisterID rn, FPRegisterID rt)
+ {
+ ASSERT(!(size && V && (opc & 2))); // Maximum vector size is 128 bits.
+ ASSERT(!((size & 2) && !V && (opc == 3))); // signed 32-bit load must be extending from 8/16 bits.
+ ASSERT(option & 2); // The ExtendType for the address must be 32/64 bit, signed or unsigned - not 8/16bit.
+ return (0x38200800 | size << 30 | V << 26 | opc << 22 | xOrZr(rm) << 16 | option << 13 | S << 12 | xOrSp(rn) << 5 | rt);
+ }
+
+ ALWAYS_INLINE static int loadStoreRegisterRegisterOffset(MemOpSize size, bool V, MemOp opc, RegisterID rm, ExtendType option, bool S, RegisterID rn, RegisterID rt)
+ {
+ return loadStoreRegisterRegisterOffset(size, V, opc, rm, option, S, rn, xOrZrAsFPR(rt));
+ }
+
+ // 'V' means vector
+ ALWAYS_INLINE static int loadStoreRegisterUnscaledImmediate(MemOpSize size, bool V, MemOp opc, int imm9, RegisterID rn, FPRegisterID rt)
+ {
+ ASSERT(!(size && V && (opc & 2))); // Maximum vector size is 128 bits.
+ ASSERT(!((size & 2) && !V && (opc == 3))); // signed 32-bit load must be extending from 8/16 bits.
+ ASSERT(isInt9(imm9));
+ return (0x38000000 | size << 30 | V << 26 | opc << 22 | (imm9 & 0x1ff) << 12 | xOrSp(rn) << 5 | rt);
+ }
+
+ ALWAYS_INLINE static int loadStoreRegisterUnscaledImmediate(MemOpSize size, bool V, MemOp opc, int imm9, RegisterID rn, RegisterID rt)
+ {
+ ASSERT(isInt9(imm9));
+ return loadStoreRegisterUnscaledImmediate(size, V, opc, imm9, rn, xOrZrAsFPR(rt));
+ }
+
+ // 'V' means vector
+ ALWAYS_INLINE static int loadStoreRegisterUnsignedImmediate(MemOpSize size, bool V, MemOp opc, int imm12, RegisterID rn, FPRegisterID rt)
+ {
+ ASSERT(!(size && V && (opc & 2))); // Maximum vector size is 128 bits.
+ ASSERT(!((size & 2) && !V && (opc == 3))); // signed 32-bit load must be extending from 8/16 bits.
+ ASSERT(isUInt12(imm12));
+ return (0x39000000 | size << 30 | V << 26 | opc << 22 | (imm12 & 0xfff) << 10 | xOrSp(rn) << 5 | rt);
+ }
+
+ ALWAYS_INLINE static int loadStoreRegisterUnsignedImmediate(MemOpSize size, bool V, MemOp opc, int imm12, RegisterID rn, RegisterID rt)
+ {
+ return loadStoreRegisterUnsignedImmediate(size, V, opc, imm12, rn, xOrZrAsFPR(rt));
+ }
+
+ ALWAYS_INLINE static int logicalImmediate(Datasize sf, LogicalOp opc, int N_immr_imms, RegisterID rn, RegisterID rd)
+ {
+ ASSERT(!(N_immr_imms & (sf ? ~0x1fff : ~0xfff)));
+ return (0x12000000 | sf << 31 | opc << 29 | N_immr_imms << 10 | xOrZr(rn) << 5 | xOrZrOrSp(opc == LogicalOp_ANDS, rd));
+ }
+
+ // 'N' means negate rm
+ ALWAYS_INLINE static int logicalShiftedRegister(Datasize sf, LogicalOp opc, ShiftType shift, bool N, RegisterID rm, int imm6, RegisterID rn, RegisterID rd)
+ {
+ ASSERT(!(imm6 & (sf ? ~63 : ~31)));
+ return (0x0a000000 | sf << 31 | opc << 29 | shift << 22 | N << 21 | xOrZr(rm) << 16 | (imm6 & 0x3f) << 10 | xOrZr(rn) << 5 | xOrZr(rd));
+ }
+
+ ALWAYS_INLINE static int moveWideImediate(Datasize sf, MoveWideOp opc, int hw, uint16_t imm16, RegisterID rd)
+ {
+ ASSERT(hw < (sf ? 4 : 2));
+ return (0x12800000 | sf << 31 | opc << 29 | hw << 21 | (int)imm16 << 5 | xOrZr(rd));
+ }
+
+ // 'op' means link
+ ALWAYS_INLINE static int unconditionalBranchImmediate(bool op, int32_t imm26)
+ {
+ ASSERT(imm26 == (imm26 << 6) >> 6);
+ return (0x14000000 | op << 31 | (imm26 & 0x3ffffff));
+ }
+
+ // 'op' means page
+ ALWAYS_INLINE static int pcRelative(bool op, int32_t imm21, RegisterID rd)
+ {
+ ASSERT(imm21 == (imm21 << 11) >> 11);
+ int32_t immlo = imm21 & 3;
+ int32_t immhi = (imm21 >> 2) & 0x7ffff;
+ return (0x10000000 | op << 31 | immlo << 29 | immhi << 5 | xOrZr(rd));
+ }
+
+ ALWAYS_INLINE static int system(bool L, int op0, int op1, int crn, int crm, int op2, RegisterID rt)
+ {
+ return (0xd5000000 | L << 21 | op0 << 19 | op1 << 16 | crn << 12 | crm << 8 | op2 << 5 | xOrZr(rt));
+ }
+
+ ALWAYS_INLINE static int hintPseudo(int imm)
+ {
+ ASSERT(!(imm & ~0x7f));
+ return system(0, 0, 3, 2, (imm >> 3) & 0xf, imm & 0x7, ARM64Registers::zr);
+ }
+
+ ALWAYS_INLINE static int nopPseudo()
+ {
+ return hintPseudo(0);
+ }
+
+ // 'op' means negate
+ ALWAYS_INLINE static int testAndBranchImmediate(bool op, int b50, int imm14, RegisterID rt)
+ {
+ ASSERT(!(b50 & ~0x3f));
+ ASSERT(imm14 == (imm14 << 18) >> 18);
+ int b5 = b50 >> 5;
+ int b40 = b50 & 0x1f;
+ return (0x36000000 | b5 << 31 | op << 24 | b40 << 19 | (imm14 & 0x3fff) << 5 | xOrZr(rt));
+ }
+
+ ALWAYS_INLINE static int unconditionalBranchRegister(BranchType opc, RegisterID rn)
+ {
+ // The only allocated values for op2 is 0x1f, for op3 & op4 are 0.
+ const int op2 = 0x1f;
+ const int op3 = 0;
+ const int op4 = 0;
+ return (0xd6000000 | opc << 21 | op2 << 16 | op3 << 10 | xOrZr(rn) << 5 | op4);
+ }
+
+ // Workaround for Cortex-A53 erratum (835769). Emit an extra nop if the
+ // last instruction in the buffer is a load, store or prefetch. Needed
+ // before 64-bit multiply-accumulate instructions.
+ template<int datasize>
+ ALWAYS_INLINE void nopCortexA53Fix835769()
+ {
+#if CPU(ARM64_CORTEXA53)
+ CHECK_DATASIZE();
+ if (datasize == 64) {
+ if (LIKELY(m_buffer.codeSize() >= sizeof(int32_t))) {
+ // From ARMv8 Reference Manual, Section C4.1: the encoding of the
+ // instructions in the Loads and stores instruction group is:
+ // ---- 1-0- ---- ---- ---- ---- ---- ----
+ if (UNLIKELY((*reinterpret_cast_ptr<int32_t*>(reinterpret_cast_ptr<char*>(m_buffer.data()) + m_buffer.codeSize() - sizeof(int32_t)) & 0x0a000000) == 0x08000000))
+ nop();
+ }
+ }
+#endif
+ }
+
+ // Workaround for Cortex-A53 erratum (843419). Emit extra nops to avoid
+ // wrong address access after ADRP instruction.
+ ALWAYS_INLINE void nopCortexA53Fix843419()
+ {
+#if CPU(ARM64_CORTEXA53)
+ nop();
+ nop();
+ nop();
+#endif
+ }
+
+ AssemblerBuffer m_buffer;
+ Vector<LinkRecord, 0, UnsafeVectorOverflow> m_jumpsToLink;
+ int m_indexOfLastWatchpoint;
+ int m_indexOfTailOfLastWatchpoint;
+};
+
+} // namespace JSC
+
+#undef CHECK_DATASIZE_OF
+#undef DATASIZE_OF
+#undef MEMOPSIZE_OF
+#undef CHECK_DATASIZE
+#undef DATASIZE
+#undef MEMOPSIZE
+#undef CHECK_FP_MEMOP_DATASIZE
+
+#endif // ENABLE(ASSEMBLER) && CPU(ARM64)
+
+#endif // ARM64Assembler_h
diff --git a/src/3rdparty/masm/assembler/ARMv7Assembler.h b/src/3rdparty/masm/assembler/ARMv7Assembler.h
index 236d55883d..f0fa07a1bf 100644
--- a/src/3rdparty/masm/assembler/ARMv7Assembler.h
+++ b/src/3rdparty/masm/assembler/ARMv7Assembler.h
@@ -423,6 +423,7 @@ public:
typedef ARMRegisters::FPSingleRegisterID FPSingleRegisterID;
typedef ARMRegisters::FPDoubleRegisterID FPDoubleRegisterID;
typedef ARMRegisters::FPQuadRegisterID FPQuadRegisterID;
+ typedef ARMRegisters::FPDoubleRegisterID FPRegisterID;
// (HS, LO, HI, LS) -> (AE, B, A, BE)
// (VS, VC) -> (O, NO)
diff --git a/src/3rdparty/masm/assembler/AbstractMacroAssembler.h b/src/3rdparty/masm/assembler/AbstractMacroAssembler.h
index 95eaf7d99d..e90dd235c6 100644
--- a/src/3rdparty/masm/assembler/AbstractMacroAssembler.h
+++ b/src/3rdparty/masm/assembler/AbstractMacroAssembler.h
@@ -66,6 +66,7 @@ public:
class Jump;
typedef typename AssemblerType::RegisterID RegisterID;
+ typedef typename AssemblerType::FPRegisterID FPRegisterID;
// Section 1: MacroAssembler operand types
//
@@ -275,7 +276,7 @@ public:
{
}
-#if CPU(X86_64)
+#if CPU(X86_64) || CPU(ARM64)
explicit TrustedImm64(TrustedImmPtr ptr)
: m_value(ptr.asIntptr())
{
@@ -296,7 +297,7 @@ public:
: TrustedImm64(value)
{
}
-#if CPU(X86_64)
+#if CPU(X86_64) || CPU(ARM64)
explicit Imm64(TrustedImmPtr ptr)
: TrustedImm64(ptr)
{
@@ -516,6 +517,33 @@ public:
, m_condition(condition)
{
}
+#elif CPU(ARM64)
+ Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type = ARM64Assembler::JumpNoCondition, ARM64Assembler::Condition condition = ARM64Assembler::ConditionInvalid)
+ : m_label(jmp)
+ , m_type(type)
+ , m_condition(condition)
+ {
+ }
+
+ Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type, ARM64Assembler::Condition condition, bool is64Bit, ARM64Assembler::RegisterID compareRegister)
+ : m_label(jmp)
+ , m_type(type)
+ , m_condition(condition)
+ , m_is64Bit(is64Bit)
+ , m_compareRegister(compareRegister)
+ {
+ ASSERT((type == ARM64Assembler::JumpCompareAndBranch) || (type == ARM64Assembler::JumpCompareAndBranchFixedSize));
+ }
+
+ Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type, ARM64Assembler::Condition condition, unsigned bitNumber, ARM64Assembler::RegisterID compareRegister)
+ : m_label(jmp)
+ , m_type(type)
+ , m_condition(condition)
+ , m_bitNumber(bitNumber)
+ , m_compareRegister(compareRegister)
+ {
+ ASSERT((type == ARM64Assembler::JumpTestBit) || (type == ARM64Assembler::JumpTestBitFixedSize));
+ }
#elif CPU(SH4)
Jump(AssemblerLabel jmp, SH4Assembler::JumpType type = SH4Assembler::JumpFar)
: m_label(jmp)
@@ -544,6 +572,13 @@ public:
#if CPU(ARM_THUMB2)
masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
+#elif CPU(ARM64)
+ if ((m_type == ARM64Assembler::JumpCompareAndBranch) || (m_type == ARM64Assembler::JumpCompareAndBranchFixedSize))
+ masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition, m_is64Bit, m_compareRegister);
+ else if ((m_type == ARM64Assembler::JumpTestBit) || (m_type == ARM64Assembler::JumpTestBitFixedSize))
+ masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition, m_bitNumber, m_compareRegister);
+ else
+ masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
#elif CPU(SH4)
masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type);
#else
@@ -559,6 +594,13 @@ public:
#if CPU(ARM_THUMB2)
masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition);
+#elif CPU(ARM64)
+ if ((m_type == ARM64Assembler::JumpCompareAndBranch) || (m_type == ARM64Assembler::JumpCompareAndBranchFixedSize))
+ masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition, m_is64Bit, m_compareRegister);
+ else if ((m_type == ARM64Assembler::JumpTestBit) || (m_type == ARM64Assembler::JumpTestBitFixedSize))
+ masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition, m_bitNumber, m_compareRegister);
+ else
+ masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition);
#else
masm->m_assembler.linkJump(m_label, label.m_label);
#endif
@@ -571,6 +613,12 @@ public:
#if CPU(ARM_THUMB2)
ARMv7Assembler::JumpType m_type;
ARMv7Assembler::Condition m_condition;
+#elif CPU(ARM64)
+ ARM64Assembler::JumpType m_type;
+ ARM64Assembler::Condition m_condition;
+ bool m_is64Bit;
+ unsigned m_bitNumber;
+ ARM64Assembler::RegisterID m_compareRegister;
#endif
#if CPU(SH4)
SH4Assembler::JumpType m_type;
diff --git a/src/3rdparty/masm/assembler/MacroAssembler.h b/src/3rdparty/masm/assembler/MacroAssembler.h
index 0c95bc7ca1..e122e2f3ae 100644
--- a/src/3rdparty/masm/assembler/MacroAssembler.h
+++ b/src/3rdparty/masm/assembler/MacroAssembler.h
@@ -34,6 +34,10 @@
#include "MacroAssemblerARMv7.h"
namespace JSC { typedef MacroAssemblerARMv7 MacroAssemblerBase; };
+#elif CPU(ARM64)
+#include "MacroAssemblerARM64.h"
+namespace JSC { typedef MacroAssemblerARM64 MacroAssemblerBase; };
+
#elif CPU(ARM_TRADITIONAL)
#include "MacroAssemblerARM.h"
namespace JSC { typedef MacroAssemblerARM MacroAssemblerBase; };
@@ -183,7 +187,7 @@ public:
storePtr(imm, addressForPoke(index));
}
-#if CPU(X86_64)
+#if CPU(X86_64) || CPU(ARM64)
void peek64(RegisterID dest, int index = 0)
{
load64(Address(stackPointerRegister, (index * sizeof(void*))), dest);
@@ -253,7 +257,7 @@ public:
branchTestPtr(cond, reg).linkTo(target, this);
}
-#if !CPU(ARM_THUMB2)
+#if !CPU(ARM_THUMB2) && !CPU(ARM64)
PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right = TrustedImmPtr(0))
{
return PatchableJump(branchPtr(cond, left, right));
@@ -273,7 +277,7 @@ public:
{
return PatchableJump(branchTest32(cond, reg, mask));
}
-#endif // !CPU(ARM_THUMB2)
+#endif // !CPU(ARM_THUMB2) && !CPU(ARM64)
#if !CPU(ARM)
PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm)
@@ -325,7 +329,7 @@ public:
// Ptr methods
// On 32-bit platforms (i.e. x86), these methods directly map onto their 32-bit equivalents.
// FIXME: should this use a test for 32-bitness instead of this specific exception?
-#if !CPU(X86_64)
+#if !CPU(X86_64) && !CPU(ARM64)
void addPtr(Address src, RegisterID dest)
{
add32(src, dest);
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h
new file mode 100644
index 0000000000..bd85b6b2c1
--- /dev/null
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h
@@ -0,0 +1,3455 @@
+/*
+ * Copyright (C) 2012, 2014, 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MacroAssemblerARM64_h
+#define MacroAssemblerARM64_h
+
+#if ENABLE(ASSEMBLER)
+
+#include "ARM64Assembler.h"
+#include "AbstractMacroAssembler.h"
+#include <wtf/MathExtras.h>
+
+namespace JSC {
+
+class MacroAssemblerARM64 : public AbstractMacroAssembler<ARM64Assembler> {
+#define COPIED_FROM_AbstractAssembler_H 1
+#ifdef COPIED_FROM_AbstractAssembler_H
+ typedef MacroAssemblerARM64 AbstractMacroAssemblerType;
+ class CachedTempRegister {
+ friend class DataLabelPtr;
+ friend class DataLabel32;
+ friend class DataLabelCompact;
+ friend class Jump;
+ friend class Label;
+
+ public:
+ CachedTempRegister(AbstractMacroAssemblerType* masm, RegisterID registerID)
+ : m_masm(masm)
+ , m_registerID(registerID)
+ , m_value(0)
+ , m_validBit(1 << static_cast<unsigned>(registerID))
+ {
+ ASSERT(static_cast<unsigned>(registerID) < (sizeof(unsigned) * 8));
+ }
+
+ ALWAYS_INLINE RegisterID registerIDInvalidate() { invalidate(); return m_registerID; }
+
+ ALWAYS_INLINE RegisterID registerIDNoInvalidate() { return m_registerID; }
+
+ bool value(intptr_t& value)
+ {
+ value = m_value;
+ return m_masm->isTempRegisterValid(m_validBit);
+ }
+
+ void setValue(intptr_t value)
+ {
+ m_value = value;
+ m_masm->setTempRegisterValid(m_validBit);
+ }
+
+ ALWAYS_INLINE void invalidate() { m_masm->clearTempRegisterValid(m_validBit); }
+
+ private:
+ AbstractMacroAssemblerType* m_masm;
+ RegisterID m_registerID;
+ intptr_t m_value;
+ unsigned m_validBit;
+ };
+
+ ALWAYS_INLINE void invalidateAllTempRegisters()
+ {
+ m_tempRegistersValidBits = 0;
+ }
+
+ ALWAYS_INLINE bool isTempRegisterValid(unsigned registerMask)
+ {
+ return (m_tempRegistersValidBits & registerMask);
+ }
+
+ ALWAYS_INLINE void clearTempRegisterValid(unsigned registerMask)
+ {
+ m_tempRegistersValidBits &= ~registerMask;
+ }
+
+ ALWAYS_INLINE void setTempRegisterValid(unsigned registerMask)
+ {
+ m_tempRegistersValidBits |= registerMask;
+ }
+
+ friend class AllowMacroScratchRegisterUsage;
+ friend class DisallowMacroScratchRegisterUsage;
+ unsigned m_tempRegistersValidBits;
+#endif // COPIED_FROM_AbstractAssembler_H
+public:
+ static const RegisterID dataTempRegister = ARM64Registers::ip0;
+ static const RegisterID memoryTempRegister = ARM64Registers::ip1;
+
+#if 0
+ RegisterID scratchRegister()
+ {
+ RELEASE_ASSERT(m_allowScratchRegister);
+ return getCachedDataTempRegisterIDAndInvalidate();
+ }
+#endif
+
+private:
+ static const ARM64Registers::FPRegisterID fpTempRegister = ARM64Registers::q31;
+ static const ARM64Assembler::SetFlags S = ARM64Assembler::S;
+ static const intptr_t maskHalfWord0 = 0xffffl;
+ static const intptr_t maskHalfWord1 = 0xffff0000l;
+ static const intptr_t maskUpperWord = 0xffffffff00000000l;
+
+ // 4 instructions - 3 to load the function pointer, + blr.
+ static const ptrdiff_t REPATCH_OFFSET_CALL_TO_POINTER = -16;
+
+public:
+ MacroAssemblerARM64()
+ : m_dataMemoryTempRegister(this, dataTempRegister)
+ , m_cachedMemoryTempRegister(this, memoryTempRegister)
+ , m_makeJumpPatchable(false)
+ {
+ }
+
+ typedef ARM64Assembler::LinkRecord LinkRecord;
+ typedef ARM64Assembler::JumpType JumpType;
+ typedef ARM64Assembler::JumpLinkType JumpLinkType;
+ typedef ARM64Assembler::Condition Condition;
+
+ static const ARM64Assembler::Condition DefaultCondition = ARM64Assembler::ConditionInvalid;
+ static const ARM64Assembler::JumpType DefaultJump = ARM64Assembler::JumpNoConditionFixedSize;
+
+ Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink() { return m_assembler.jumpsToLink(); }
+ void* unlinkedCode() { return m_assembler.unlinkedCode(); }
+ static bool canCompact(JumpType jumpType) { return ARM64Assembler::canCompact(jumpType); }
+ static JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return ARM64Assembler::computeJumpType(jumpType, from, to); }
+ static JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return ARM64Assembler::computeJumpType(record, from, to); }
+ static int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return ARM64Assembler::jumpSizeDelta(jumpType, jumpLinkType); }
+ static void link(LinkRecord& record, uint8_t* from, uint8_t* to) { return ARM64Assembler::link(record, from, to); }
+
+ static const Scale ScalePtr = TimesEight;
+
+ static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
+ {
+ // This is the largest 32-bit access allowed, aligned to 64-bit boundary.
+ return !(value & ~0x3ff8);
+ }
+
+ enum RelationalCondition {
+ Equal = ARM64Assembler::ConditionEQ,
+ NotEqual = ARM64Assembler::ConditionNE,
+ Above = ARM64Assembler::ConditionHI,
+ AboveOrEqual = ARM64Assembler::ConditionHS,
+ Below = ARM64Assembler::ConditionLO,
+ BelowOrEqual = ARM64Assembler::ConditionLS,
+ GreaterThan = ARM64Assembler::ConditionGT,
+ GreaterThanOrEqual = ARM64Assembler::ConditionGE,
+ LessThan = ARM64Assembler::ConditionLT,
+ LessThanOrEqual = ARM64Assembler::ConditionLE
+ };
+
+ enum ResultCondition {
+ Overflow = ARM64Assembler::ConditionVS,
+ Signed = ARM64Assembler::ConditionMI,
+ PositiveOrZero = ARM64Assembler::ConditionPL,
+ Zero = ARM64Assembler::ConditionEQ,
+ NonZero = ARM64Assembler::ConditionNE
+ };
+
+ enum ZeroCondition {
+ IsZero = ARM64Assembler::ConditionEQ,
+ IsNonZero = ARM64Assembler::ConditionNE
+ };
+
+ enum DoubleCondition {
+ // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
+ DoubleEqual = ARM64Assembler::ConditionEQ,
+ DoubleNotEqual = ARM64Assembler::ConditionVC, // Not the right flag! check for this & handle differently.
+ DoubleGreaterThan = ARM64Assembler::ConditionGT,
+ DoubleGreaterThanOrEqual = ARM64Assembler::ConditionGE,
+ DoubleLessThan = ARM64Assembler::ConditionLO,
+ DoubleLessThanOrEqual = ARM64Assembler::ConditionLS,
+ // If either operand is NaN, these conditions always evaluate to true.
+ DoubleEqualOrUnordered = ARM64Assembler::ConditionVS, // Not the right flag! check for this & handle differently.
+ DoubleNotEqualOrUnordered = ARM64Assembler::ConditionNE,
+ DoubleGreaterThanOrUnordered = ARM64Assembler::ConditionHI,
+ DoubleGreaterThanOrEqualOrUnordered = ARM64Assembler::ConditionHS,
+ DoubleLessThanOrUnordered = ARM64Assembler::ConditionLT,
+ DoubleLessThanOrEqualOrUnordered = ARM64Assembler::ConditionLE,
+ };
+
+ static const RegisterID stackPointerRegister = ARM64Registers::sp;
+ static const RegisterID framePointerRegister = ARM64Registers::fp;
+ static const RegisterID linkRegister = ARM64Registers::lr;
+
+ // FIXME: Get reasonable implementations for these
+ static bool shouldBlindForSpecificArch(uint32_t value) { return value >= 0x00ffffff; }
+ static bool shouldBlindForSpecificArch(uint64_t value) { return value >= 0x00ffffff; }
+
+ // Integer operations:
+
+ void add32(RegisterID a, RegisterID b, RegisterID dest)
+ {
+ ASSERT(a != ARM64Registers::sp && b != ARM64Registers::sp);
+ m_assembler.add<32>(dest, a, b);
+ }
+
+ void add32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.add<32>(dest, dest, src);
+ }
+
+ void add32(TrustedImm32 imm, RegisterID dest)
+ {
+ if (!imm.m_value)
+ return;
+
+ add32(imm, dest, dest);
+ }
+
+ void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ if (!imm.m_value) {
+ move(src, dest);
+ return;
+ }
+
+ if (isUInt12(imm.m_value))
+ m_assembler.add<32>(dest, src, UInt12(imm.m_value));
+ else if (isUInt12(-imm.m_value))
+ m_assembler.sub<32>(dest, src, UInt12(-imm.m_value));
+ else {
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.add<32>(dest, src, dataTempRegister);
+ }
+ }
+
+ void add32(TrustedImm32 imm, Address address)
+ {
+ if (!imm.m_value)
+ return;
+
+ load32(address, getCachedDataTempRegisterIDAndInvalidate());
+
+ if (isUInt12(imm.m_value))
+ m_assembler.add<32>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
+ else if (isUInt12(-imm.m_value))
+ m_assembler.sub<32>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
+ else {
+ move(imm, getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<32>(dataTempRegister, dataTempRegister, memoryTempRegister);
+ }
+
+ store32(dataTempRegister, address);
+ }
+
+ void add32(TrustedImm32 imm, AbsoluteAddress address)
+ {
+ if (!imm.m_value)
+ return;
+
+ load32(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
+
+ if (isUInt12(imm.m_value)) {
+ m_assembler.add<32>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
+ store32(dataTempRegister, address.m_ptr);
+ return;
+ }
+
+ if (isUInt12(-imm.m_value)) {
+ m_assembler.sub<32>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
+ store32(dataTempRegister, address.m_ptr);
+ return;
+ }
+
+ move(imm, getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<32>(dataTempRegister, dataTempRegister, memoryTempRegister);
+ store32(dataTempRegister, address.m_ptr);
+ }
+
+ void add32(Address src, RegisterID dest)
+ {
+ load32(src, getCachedDataTempRegisterIDAndInvalidate());
+ add32(dataTempRegister, dest);
+ }
+
+ void add64(RegisterID a, RegisterID b, RegisterID dest)
+ {
+ ASSERT(a != ARM64Registers::sp || b != ARM64Registers::sp);
+ if (b == ARM64Registers::sp)
+ std::swap(a, b);
+ m_assembler.add<64>(dest, a, b);
+ }
+
+ void add64(RegisterID src, RegisterID dest)
+ {
+ if (src == ARM64Registers::sp)
+ m_assembler.add<64>(dest, src, dest);
+ else
+ m_assembler.add<64>(dest, dest, src);
+ }
+
+ void add64(TrustedImm32 imm, RegisterID dest)
+ {
+ if (!imm.m_value)
+ return;
+
+ if (isUInt12(imm.m_value)) {
+ m_assembler.add<64>(dest, dest, UInt12(imm.m_value));
+ return;
+ }
+ if (isUInt12(-imm.m_value)) {
+ m_assembler.sub<64>(dest, dest, UInt12(-imm.m_value));
+ return;
+ }
+
+ signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(dest, dest, dataTempRegister);
+ }
+
+ void add64(TrustedImm64 imm, RegisterID dest)
+ {
+ intptr_t immediate = imm.m_value;
+ if (!immediate)
+ return;
+
+ if (isUInt12(immediate)) {
+ m_assembler.add<64>(dest, dest, UInt12(static_cast<int32_t>(immediate)));
+ return;
+ }
+ if (isUInt12(-immediate)) {
+ m_assembler.sub<64>(dest, dest, UInt12(static_cast<int32_t>(-immediate)));
+ return;
+ }
+
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(dest, dest, dataTempRegister);
+ }
+
+ void add64(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ if (!imm.m_value) {
+ move(src, dest);
+ return;
+ }
+
+ if (isUInt12(imm.m_value)) {
+ m_assembler.add<64>(dest, src, UInt12(imm.m_value));
+ return;
+ }
+ if (isUInt12(-imm.m_value)) {
+ m_assembler.sub<64>(dest, src, UInt12(-imm.m_value));
+ return;
+ }
+
+ signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(dest, src, dataTempRegister);
+ }
+
+ void add64(TrustedImm32 imm, Address address)
+ {
+ if (!imm.m_value)
+ return;
+
+ load64(address, getCachedDataTempRegisterIDAndInvalidate());
+
+ if (isUInt12(imm.m_value))
+ m_assembler.add<64>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
+ else if (isUInt12(-imm.m_value))
+ m_assembler.sub<64>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
+ else {
+ signExtend32ToPtr(imm, getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(dataTempRegister, dataTempRegister, memoryTempRegister);
+ }
+
+ store64(dataTempRegister, address);
+ }
+
+ void add64(TrustedImm32 imm, AbsoluteAddress address)
+ {
+ if (!imm.m_value)
+ return;
+
+ load64(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
+
+ if (isUInt12(imm.m_value)) {
+ m_assembler.add<64>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
+ store64(dataTempRegister, address.m_ptr);
+ return;
+ }
+
+ if (isUInt12(-imm.m_value)) {
+ m_assembler.sub<64>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
+ store64(dataTempRegister, address.m_ptr);
+ return;
+ }
+
+ signExtend32ToPtr(imm, getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(dataTempRegister, dataTempRegister, memoryTempRegister);
+ store64(dataTempRegister, address.m_ptr);
+ }
+
+ void addPtrNoFlags(TrustedImm32 imm, RegisterID srcDest)
+ {
+ add64(imm, srcDest);
+ }
+
+ void add64(Address src, RegisterID dest)
+ {
+ load64(src, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(dest, dest, dataTempRegister);
+ }
+
+ void add64(AbsoluteAddress src, RegisterID dest)
+ {
+ load64(src.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(dest, dest, dataTempRegister);
+ }
+
+ void and32(RegisterID src, RegisterID dest)
+ {
+ and32(dest, src, dest);
+ }
+
+ void and32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.and_<32>(dest, op1, op2);
+ }
+
+ void and32(TrustedImm32 imm, RegisterID dest)
+ {
+ and32(imm, dest, dest);
+ }
+
+ void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ LogicalImmediate logicalImm = LogicalImmediate::create32(imm.m_value);
+
+ if (logicalImm.isValid()) {
+ m_assembler.and_<32>(dest, src, logicalImm);
+ return;
+ }
+
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.and_<32>(dest, src, dataTempRegister);
+ }
+
+ void and32(Address src, RegisterID dest)
+ {
+ load32(src, dataTempRegister);
+ and32(dataTempRegister, dest);
+ }
+
+ void and64(RegisterID src, RegisterID dest)
+ {
+ m_assembler.and_<64>(dest, dest, src);
+ }
+
+ void and64(TrustedImm32 imm, RegisterID dest)
+ {
+ LogicalImmediate logicalImm = LogicalImmediate::create64(static_cast<intptr_t>(static_cast<int64_t>(imm.m_value)));
+
+ if (logicalImm.isValid()) {
+ m_assembler.and_<64>(dest, dest, logicalImm);
+ return;
+ }
+
+ signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.and_<64>(dest, dest, dataTempRegister);
+ }
+
+ void and64(TrustedImmPtr imm, RegisterID dest)
+ {
+ LogicalImmediate logicalImm = LogicalImmediate::create64(reinterpret_cast<uint64_t>(imm.m_value));
+
+ if (logicalImm.isValid()) {
+ m_assembler.and_<64>(dest, dest, logicalImm);
+ return;
+ }
+
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.and_<64>(dest, dest, dataTempRegister);
+ }
+
+ void countLeadingZeros32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.clz<32>(dest, src);
+ }
+
+ void countLeadingZeros64(RegisterID src, RegisterID dest)
+ {
+ m_assembler.clz<64>(dest, src);
+ }
+
+ void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.lsl<32>(dest, src, shiftAmount);
+ }
+
+ void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.lsl<32>(dest, src, imm.m_value & 0x1f);
+ }
+
+ void lshift32(RegisterID shiftAmount, RegisterID dest)
+ {
+ lshift32(dest, shiftAmount, dest);
+ }
+
+ void lshift32(TrustedImm32 imm, RegisterID dest)
+ {
+ lshift32(dest, imm, dest);
+ }
+
+ void lshift64(RegisterID src, RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.lsl<64>(dest, src, shiftAmount);
+ }
+
+ void lshift64(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.lsl<64>(dest, src, imm.m_value & 0x3f);
+ }
+
+ void lshift64(RegisterID shiftAmount, RegisterID dest)
+ {
+ lshift64(dest, shiftAmount, dest);
+ }
+
+ void lshift64(TrustedImm32 imm, RegisterID dest)
+ {
+ lshift64(dest, imm, dest);
+ }
+
+ void mul32(RegisterID left, RegisterID right, RegisterID dest)
+ {
+ m_assembler.mul<32>(dest, left, right);
+ }
+
+ void mul32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.mul<32>(dest, dest, src);
+ }
+
+ void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.mul<32>(dest, src, dataTempRegister);
+ }
+
+ void mul32(Address src, RegisterID dest)
+ {
+ load32(src, dataTempRegister);
+ mul32(dataTempRegister, dest);
+ }
+
+ void mul64(RegisterID src, RegisterID dest)
+ {
+ m_assembler.mul<64>(dest, dest, src);
+ }
+
+ void mul64(RegisterID left, RegisterID right, RegisterID dest)
+ {
+ m_assembler.mul<64>(dest, left, right);
+ }
+
+ void div32(RegisterID dividend, RegisterID divisor, RegisterID dest)
+ {
+ m_assembler.sdiv<32>(dest, dividend, divisor);
+ }
+
+ void div64(RegisterID dividend, RegisterID divisor, RegisterID dest)
+ {
+ m_assembler.sdiv<64>(dest, dividend, divisor);
+ }
+
+ void neg32(RegisterID dest)
+ {
+ m_assembler.neg<32>(dest, dest);
+ }
+
+ void neg64(RegisterID dest)
+ {
+ m_assembler.neg<64>(dest, dest);
+ }
+
+ void or32(RegisterID src, RegisterID dest)
+ {
+ or32(dest, src, dest);
+ }
+
+ void or32(Address src, RegisterID dest)
+ {
+ load32(src, dataTempRegister);
+ or32(dataTempRegister, dest);
+ }
+
+ void or32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.orr<32>(dest, op1, op2);
+ }
+
+ void or32(TrustedImm32 imm, RegisterID dest)
+ {
+ or32(imm, dest, dest);
+ }
+
+ void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ LogicalImmediate logicalImm = LogicalImmediate::create32(imm.m_value);
+
+ if (logicalImm.isValid()) {
+ m_assembler.orr<32>(dest, src, logicalImm);
+ return;
+ }
+
+ ASSERT(src != dataTempRegister);
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.orr<32>(dest, src, dataTempRegister);
+ }
+
+ void or32(RegisterID src, AbsoluteAddress address)
+ {
+ load32(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.orr<32>(dataTempRegister, dataTempRegister, src);
+ store32(dataTempRegister, address.m_ptr);
+ }
+
+ void or32(TrustedImm32 imm, AbsoluteAddress address)
+ {
+ LogicalImmediate logicalImm = LogicalImmediate::create32(imm.m_value);
+ if (logicalImm.isValid()) {
+ load32(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.orr<32>(dataTempRegister, dataTempRegister, logicalImm);
+ store32(dataTempRegister, address.m_ptr);
+ } else {
+ load32(address.m_ptr, getCachedMemoryTempRegisterIDAndInvalidate());
+ or32(imm, memoryTempRegister, getCachedDataTempRegisterIDAndInvalidate());
+ store32(dataTempRegister, address.m_ptr);
+ }
+ }
+
+ void or32(TrustedImm32 imm, Address address)
+ {
+ load32(address, getCachedDataTempRegisterIDAndInvalidate());
+ or32(imm, dataTempRegister, dataTempRegister);
+ store32(dataTempRegister, address);
+ }
+
+ void or64(RegisterID src, RegisterID dest)
+ {
+ or64(dest, src, dest);
+ }
+
+ void or64(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.orr<64>(dest, op1, op2);
+ }
+
+ void or64(TrustedImm32 imm, RegisterID dest)
+ {
+ or64(imm, dest, dest);
+ }
+
+ void or64(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ LogicalImmediate logicalImm = LogicalImmediate::create64(static_cast<intptr_t>(static_cast<int64_t>(imm.m_value)));
+
+ if (logicalImm.isValid()) {
+ m_assembler.orr<64>(dest, src, logicalImm);
+ return;
+ }
+
+ signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.orr<64>(dest, src, dataTempRegister);
+ }
+
+ void or64(TrustedImm64 imm, RegisterID dest)
+ {
+ LogicalImmediate logicalImm = LogicalImmediate::create64(static_cast<intptr_t>(static_cast<int64_t>(imm.m_value)));
+
+ if (logicalImm.isValid()) {
+ m_assembler.orr<64>(dest, dest, logicalImm);
+ return;
+ }
+
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.orr<64>(dest, dest, dataTempRegister);
+ }
+
+ void rotateRight64(TrustedImm32 imm, RegisterID srcDst)
+ {
+ m_assembler.ror<64>(srcDst, srcDst, imm.m_value & 63);
+ }
+
+ void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.asr<32>(dest, src, shiftAmount);
+ }
+
+ void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.asr<32>(dest, src, imm.m_value & 0x1f);
+ }
+
+ void rshift32(RegisterID shiftAmount, RegisterID dest)
+ {
+ rshift32(dest, shiftAmount, dest);
+ }
+
+ void rshift32(TrustedImm32 imm, RegisterID dest)
+ {
+ rshift32(dest, imm, dest);
+ }
+
+ void rshift64(RegisterID src, RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.asr<64>(dest, src, shiftAmount);
+ }
+
+ void rshift64(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.asr<64>(dest, src, imm.m_value & 0x3f);
+ }
+
+ void rshift64(RegisterID shiftAmount, RegisterID dest)
+ {
+ rshift64(dest, shiftAmount, dest);
+ }
+
+ void rshift64(TrustedImm32 imm, RegisterID dest)
+ {
+ rshift64(dest, imm, dest);
+ }
+
+ void sub32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.sub<32>(dest, dest, src);
+ }
+
+ void sub32(TrustedImm32 imm, RegisterID dest)
+ {
+ if (isUInt12(imm.m_value)) {
+ m_assembler.sub<32>(dest, dest, UInt12(imm.m_value));
+ return;
+ }
+ if (isUInt12(-imm.m_value)) {
+ m_assembler.add<32>(dest, dest, UInt12(-imm.m_value));
+ return;
+ }
+
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.sub<32>(dest, dest, dataTempRegister);
+ }
+
+ void sub32(TrustedImm32 imm, Address address)
+ {
+ load32(address, getCachedDataTempRegisterIDAndInvalidate());
+
+ if (isUInt12(imm.m_value))
+ m_assembler.sub<32>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
+ else if (isUInt12(-imm.m_value))
+ m_assembler.add<32>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
+ else {
+ move(imm, getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.sub<32>(dataTempRegister, dataTempRegister, memoryTempRegister);
+ }
+
+ store32(dataTempRegister, address);
+ }
+
+ void sub32(TrustedImm32 imm, AbsoluteAddress address)
+ {
+ load32(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
+
+ if (isUInt12(imm.m_value)) {
+ m_assembler.sub<32>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
+ store32(dataTempRegister, address.m_ptr);
+ return;
+ }
+
+ if (isUInt12(-imm.m_value)) {
+ m_assembler.add<32>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
+ store32(dataTempRegister, address.m_ptr);
+ return;
+ }
+
+ move(imm, getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.sub<32>(dataTempRegister, dataTempRegister, memoryTempRegister);
+ store32(dataTempRegister, address.m_ptr);
+ }
+
+ void sub32(Address src, RegisterID dest)
+ {
+ load32(src, getCachedDataTempRegisterIDAndInvalidate());
+ sub32(dataTempRegister, dest);
+ }
+
+ void sub64(RegisterID src, RegisterID dest)
+ {
+ m_assembler.sub<64>(dest, dest, src);
+ }
+
+ void sub64(TrustedImm32 imm, RegisterID dest)
+ {
+ if (isUInt12(imm.m_value)) {
+ m_assembler.sub<64>(dest, dest, UInt12(imm.m_value));
+ return;
+ }
+ if (isUInt12(-imm.m_value)) {
+ m_assembler.add<64>(dest, dest, UInt12(-imm.m_value));
+ return;
+ }
+
+ signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.sub<64>(dest, dest, dataTempRegister);
+ }
+
+ void sub64(TrustedImm64 imm, RegisterID dest)
+ {
+ intptr_t immediate = imm.m_value;
+
+ if (isUInt12(immediate)) {
+ m_assembler.sub<64>(dest, dest, UInt12(static_cast<int32_t>(immediate)));
+ return;
+ }
+ if (isUInt12(-immediate)) {
+ m_assembler.add<64>(dest, dest, UInt12(static_cast<int32_t>(-immediate)));
+ return;
+ }
+
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.sub<64>(dest, dest, dataTempRegister);
+ }
+
+ void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.lsr<32>(dest, src, shiftAmount);
+ }
+
+ void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.lsr<32>(dest, src, imm.m_value & 0x1f);
+ }
+
+ void urshift32(RegisterID shiftAmount, RegisterID dest)
+ {
+ urshift32(dest, shiftAmount, dest);
+ }
+
+ void urshift32(TrustedImm32 imm, RegisterID dest)
+ {
+ urshift32(dest, imm, dest);
+ }
+
+ void urshift64(RegisterID src, RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.lsr<64>(dest, src, shiftAmount);
+ }
+
+ void urshift64(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.lsr<64>(dest, src, imm.m_value & 0x3f);
+ }
+
+ void urshift64(RegisterID shiftAmount, RegisterID dest)
+ {
+ urshift64(dest, shiftAmount, dest);
+ }
+
+ void urshift64(TrustedImm32 imm, RegisterID dest)
+ {
+ urshift64(dest, imm, dest);
+ }
+
+ void xor32(Address src, RegisterID dest)
+ {
+ load32(src, dataTempRegister);
+ xor32(dataTempRegister, dest);
+ }
+
+ void xor32(RegisterID src, RegisterID dest)
+ {
+ xor32(dest, src, dest);
+ }
+
+ void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.eor<32>(dest, op1, op2);
+ }
+
+ void xor32(TrustedImm32 imm, RegisterID dest)
+ {
+ xor32(imm, dest, dest);
+ }
+
+ void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ if (imm.m_value == -1)
+ m_assembler.mvn<32>(dest, src);
+ else {
+ LogicalImmediate logicalImm = LogicalImmediate::create32(imm.m_value);
+
+ if (logicalImm.isValid()) {
+ m_assembler.eor<32>(dest, src, logicalImm);
+ return;
+ }
+
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.eor<32>(dest, src, dataTempRegister);
+ }
+ }
+
+ void xor64(RegisterID src, Address address)
+ {
+ load64(address, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.eor<64>(dataTempRegister, dataTempRegister, src);
+ store64(dataTempRegister, address);
+ }
+
+ void xor64(RegisterID src, RegisterID dest)
+ {
+ xor64(dest, src, dest);
+ }
+
+ void xor64(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.eor<64>(dest, op1, op2);
+ }
+
+ void xor64(TrustedImm32 imm, RegisterID dest)
+ {
+ xor64(imm, dest, dest);
+ }
+
+ void xor64(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ if (imm.m_value == -1)
+ m_assembler.mvn<64>(dest, src);
+ else {
+ LogicalImmediate logicalImm = LogicalImmediate::create64(static_cast<intptr_t>(static_cast<int64_t>(imm.m_value)));
+
+ if (logicalImm.isValid()) {
+ m_assembler.eor<64>(dest, src, logicalImm);
+ return;
+ }
+
+ signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.eor<64>(dest, src, dataTempRegister);
+ }
+ }
+
+ void not32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.mvn<32>(dest, src);
+ }
+
+ void not64(RegisterID src, RegisterID dest)
+ {
+ m_assembler.mvn<64>(dest, src);
+ }
+
+ // Memory access operations:
+
+ void load64(ImplicitAddress address, RegisterID dest)
+ {
+ if (tryLoadWithOffset<64>(dest, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.ldr<64>(dest, address.base, memoryTempRegister);
+ }
+
+ void load64(BaseIndex address, RegisterID dest)
+ {
+ if (!address.offset && (!address.scale || address.scale == 3)) {
+ m_assembler.ldr<64>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.ldr<64>(dest, address.base, memoryTempRegister);
+ }
+
+ void load64(const void* address, RegisterID dest)
+ {
+ load<64>(address, dest);
+ }
+
+ DataLabel32 load64WithAddressOffsetPatch(Address address, RegisterID dest)
+ {
+ DataLabel32 label(this);
+ signExtend32ToPtrWithFixedWidth(address.offset, getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.ldr<64>(dest, address.base, memoryTempRegister, ARM64Assembler::SXTW, 0);
+ return label;
+ }
+
+ DataLabelCompact load64WithCompactAddressOffsetPatch(Address address, RegisterID dest)
+ {
+ ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
+ DataLabelCompact label(this);
+ m_assembler.ldr<64>(dest, address.base, address.offset);
+ return label;
+ }
+
+ ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
+ {
+ ConvertibleLoadLabel result(this);
+ ASSERT(!(address.offset & ~0xff8));
+ m_assembler.ldr<64>(dest, address.base, address.offset);
+ return result;
+ }
+
+ void load32(ImplicitAddress address, RegisterID dest)
+ {
+ if (tryLoadWithOffset<32>(dest, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.ldr<32>(dest, address.base, memoryTempRegister);
+ }
+
+ void load32(BaseIndex address, RegisterID dest)
+ {
+ if (!address.offset && (!address.scale || address.scale == 2)) {
+ m_assembler.ldr<32>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.ldr<32>(dest, address.base, memoryTempRegister);
+ }
+
+ void load32(const void* address, RegisterID dest)
+ {
+ load<32>(address, dest);
+ }
+
+ DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
+ {
+ DataLabel32 label(this);
+ signExtend32ToPtrWithFixedWidth(address.offset, getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.ldr<32>(dest, address.base, memoryTempRegister, ARM64Assembler::SXTW, 0);
+ return label;
+ }
+
+ DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
+ {
+ ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
+ DataLabelCompact label(this);
+ m_assembler.ldr<32>(dest, address.base, address.offset);
+ return label;
+ }
+
+ void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
+ {
+ load32(address, dest);
+ }
+
+ void load16(ImplicitAddress address, RegisterID dest)
+ {
+ if (tryLoadWithOffset<16>(dest, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.ldrh(dest, address.base, memoryTempRegister);
+ }
+
+ void load16(BaseIndex address, RegisterID dest)
+ {
+ if (!address.offset && (!address.scale || address.scale == 1)) {
+ m_assembler.ldrh(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.ldrh(dest, address.base, memoryTempRegister);
+ }
+
+ void load16Unaligned(BaseIndex address, RegisterID dest)
+ {
+ load16(address, dest);
+ }
+
+ void load16SignedExtendTo32(ImplicitAddress address, RegisterID dest)
+ {
+ if (tryLoadSignedWithOffset<16>(dest, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.ldrsh<32>(dest, address.base, memoryTempRegister);
+ }
+
+ void load16SignedExtendTo32(BaseIndex address, RegisterID dest)
+ {
+ if (!address.offset && (!address.scale || address.scale == 1)) {
+ m_assembler.ldrsh<32>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.ldrsh<32>(dest, address.base, memoryTempRegister);
+ }
+
+ void zeroExtend16To32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.uxth<64>(dest, src);
+ }
+
+ void signExtend16To32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.sxth<64>(dest, src);
+ }
+
+ void load8(ImplicitAddress address, RegisterID dest)
+ {
+ if (tryLoadWithOffset<8>(dest, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.ldrb(dest, address.base, memoryTempRegister);
+ }
+
+ void load8(BaseIndex address, RegisterID dest)
+ {
+ if (!address.offset && !address.scale) {
+ m_assembler.ldrb(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.ldrb(dest, address.base, memoryTempRegister);
+ }
+
+ void load8(const void* address, RegisterID dest)
+ {
+ moveToCachedReg(TrustedImmPtr(address), m_cachedMemoryTempRegister);
+ m_assembler.ldrb(dest, memoryTempRegister, ARM64Registers::zr);
+ if (dest == memoryTempRegister)
+ m_cachedMemoryTempRegister.invalidate();
+ }
+
+ void load8SignedExtendTo32(ImplicitAddress address, RegisterID dest)
+ {
+ if (tryLoadSignedWithOffset<8>(dest, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.ldrsb<32>(dest, address.base, memoryTempRegister);
+ }
+
+ void load8SignedExtendTo32(BaseIndex address, RegisterID dest)
+ {
+ if (!address.offset && !address.scale) {
+ m_assembler.ldrsb<32>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.ldrsb<32>(dest, address.base, memoryTempRegister);
+ }
+
+ void zeroExtend8To32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.uxtb<64>(dest, src);
+ }
+
+ void signExtend8To32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.sxtb<64>(dest, src);
+ }
+
+ void store64(RegisterID src, ImplicitAddress address)
+ {
+ if (tryStoreWithOffset<64>(src, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.str<64>(src, address.base, memoryTempRegister);
+ }
+
+ void store64(RegisterID src, BaseIndex address)
+ {
+ if (!address.offset && (!address.scale || address.scale == 3)) {
+ m_assembler.str<64>(src, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.str<64>(src, address.base, memoryTempRegister);
+ }
+
+ void store64(RegisterID src, const void* address)
+ {
+ store<64>(src, address);
+ }
+
+ void store64(TrustedImm32 imm, ImplicitAddress address)
+ {
+ store64(TrustedImm64(imm.m_value), address);
+ }
+
+ void store64(TrustedImm64 imm, ImplicitAddress address)
+ {
+ if (!imm.m_value) {
+ store64(ARM64Registers::zr, address);
+ return;
+ }
+
+ moveToCachedReg(imm, m_dataMemoryTempRegister);
+ store64(dataTempRegister, address);
+ }
+
+ void store64(TrustedImm64 imm, BaseIndex address)
+ {
+ if (!imm.m_value) {
+ store64(ARM64Registers::zr, address);
+ return;
+ }
+
+ moveToCachedReg(imm, m_dataMemoryTempRegister);
+ store64(dataTempRegister, address);
+ }
+
+ DataLabel32 store64WithAddressOffsetPatch(RegisterID src, Address address)
+ {
+ DataLabel32 label(this);
+ signExtend32ToPtrWithFixedWidth(address.offset, getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.str<64>(src, address.base, memoryTempRegister, ARM64Assembler::SXTW, 0);
+ return label;
+ }
+
+ void store32(RegisterID src, ImplicitAddress address)
+ {
+ if (tryStoreWithOffset<32>(src, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.str<32>(src, address.base, memoryTempRegister);
+ }
+
+ void store32(RegisterID src, BaseIndex address)
+ {
+ if (!address.offset && (!address.scale || address.scale == 2)) {
+ m_assembler.str<32>(src, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.str<32>(src, address.base, memoryTempRegister);
+ }
+
+ void store32(RegisterID src, const void* address)
+ {
+ store<32>(src, address);
+ }
+
+ void store32(TrustedImm32 imm, ImplicitAddress address)
+ {
+ if (!imm.m_value) {
+ store32(ARM64Registers::zr, address);
+ return;
+ }
+
+ moveToCachedReg(imm, m_dataMemoryTempRegister);
+ store32(dataTempRegister, address);
+ }
+
+ void store32(TrustedImm32 imm, BaseIndex address)
+ {
+ if (!imm.m_value) {
+ store32(ARM64Registers::zr, address);
+ return;
+ }
+
+ moveToCachedReg(imm, m_dataMemoryTempRegister);
+ store32(dataTempRegister, address);
+ }
+
+ void store32(TrustedImm32 imm, const void* address)
+ {
+ if (!imm.m_value) {
+ store32(ARM64Registers::zr, address);
+ return;
+ }
+
+ moveToCachedReg(imm, m_dataMemoryTempRegister);
+ store32(dataTempRegister, address);
+ }
+
+ DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
+ {
+ DataLabel32 label(this);
+ signExtend32ToPtrWithFixedWidth(address.offset, getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.str<32>(src, address.base, memoryTempRegister, ARM64Assembler::SXTW, 0);
+ return label;
+ }
+
+ void store16(RegisterID src, ImplicitAddress address)
+ {
+ if (tryStoreWithOffset<16>(src, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.str<16>(src, address.base, memoryTempRegister);
+ }
+
+ void store16(RegisterID src, BaseIndex address)
+ {
+ if (!address.offset && (!address.scale || address.scale == 1)) {
+ m_assembler.strh(src, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.strh(src, address.base, memoryTempRegister);
+ }
+
+ void store8(RegisterID src, BaseIndex address)
+ {
+ if (!address.offset && !address.scale) {
+ m_assembler.strb(src, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.strb(src, address.base, memoryTempRegister);
+ }
+
+ void store8(RegisterID src, void* address)
+ {
+ move(TrustedImmPtr(address), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.strb(src, memoryTempRegister, 0);
+ }
+
+ void store8(RegisterID src, ImplicitAddress address)
+ {
+ if (tryStoreWithOffset<8>(src, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.str<8>(src, address.base, memoryTempRegister);
+ }
+
+ void store8(TrustedImm32 imm, void* address)
+ {
+ if (!imm.m_value) {
+ store8(ARM64Registers::zr, address);
+ return;
+ }
+
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ store8(dataTempRegister, address);
+ }
+
+ void store8(TrustedImm32 imm, ImplicitAddress address)
+ {
+ if (!imm.m_value) {
+ store8(ARM64Registers::zr, address);
+ return;
+ }
+
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ store8(dataTempRegister, address);
+ }
+
+ // Floating-point operations:
+
+ static bool supportsFloatingPoint() { return true; }
+ static bool supportsFloatingPointTruncate() { return true; }
+ static bool supportsFloatingPointSqrt() { return true; }
+ static bool supportsFloatingPointAbs() { return true; }
+ static bool supportsFloatingPointCeil() { return true; }
+
+ enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
+
+ void absDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.fabs<64>(dest, src);
+ }
+
+ void absFloat(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.fabs<32>(dest, src);
+ }
+
+ void addDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ addDouble(dest, src, dest);
+ }
+
+ void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.fadd<64>(dest, op1, op2);
+ }
+
+ void addDouble(Address src, FPRegisterID dest)
+ {
+ loadDouble(src, fpTempRegister);
+ addDouble(fpTempRegister, dest);
+ }
+
+ void addDouble(AbsoluteAddress address, FPRegisterID dest)
+ {
+ loadDouble(TrustedImmPtr(address.m_ptr), fpTempRegister);
+ addDouble(fpTempRegister, dest);
+ }
+
+ void addFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.fadd<32>(dest, op1, op2);
+ }
+
+ void ceilDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.frintp<64>(dest, src);
+ }
+
+ void ceilFloat(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.frintp<32>(dest, src);
+ }
+
+ void floorDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.frintm<64>(dest, src);
+ }
+
+ // Convert 'src' to an integer, and places the resulting 'dest'.
+ // If the result is not representable as a 32 bit value, branch.
+ // May also branch for some values that are representable in 32 bits
+ // (specifically, in this case, 0).
+ void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID, bool negZeroCheck = true)
+ {
+ m_assembler.fcvtns<32, 64>(dest, src);
+
+ // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
+ m_assembler.scvtf<64, 32>(fpTempRegister, dest);
+ failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
+
+ // Test for negative zero.
+ if (negZeroCheck) {
+ Jump valueIsNonZero = branchTest32(NonZero, dest);
+ RegisterID scratch = getCachedMemoryTempRegisterIDAndInvalidate();
+ m_assembler.fmov<64>(scratch, src);
+ failureCases.append(makeTestBitAndBranch(scratch, 63, IsNonZero));
+ valueIsNonZero.link(this);
+ }
+ }
+
+ Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
+ {
+ m_assembler.fcmp<64>(left, right);
+ return jumpAfterFloatingPointCompare(cond);
+ }
+
+ Jump branchFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
+ {
+ m_assembler.fcmp<32>(left, right);
+ return jumpAfterFloatingPointCompare(cond);
+ }
+
+ Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
+ {
+ m_assembler.fcmp_0<64>(reg);
+ Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
+ Jump result = makeBranch(ARM64Assembler::ConditionNE);
+ unordered.link(this);
+ return result;
+ }
+
+ Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
+ {
+ m_assembler.fcmp_0<64>(reg);
+ Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
+ Jump notEqual = makeBranch(ARM64Assembler::ConditionNE);
+ unordered.link(this);
+ // We get here if either unordered or equal.
+ Jump result = jump();
+ notEqual.link(this);
+ return result;
+ }
+
+ Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
+ {
+ // Truncate to a 64-bit integer in dataTempRegister, copy the low 32-bit to dest.
+ m_assembler.fcvtzs<64, 64>(getCachedDataTempRegisterIDAndInvalidate(), src);
+ zeroExtend32ToPtr(dataTempRegister, dest);
+ // Check thlow 32-bits sign extend to be equal to the full value.
+ m_assembler.cmp<64>(dataTempRegister, dataTempRegister, ARM64Assembler::SXTW, 0);
+ return Jump(makeBranch(branchType == BranchIfTruncateSuccessful ? Equal : NotEqual));
+ }
+
+ Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
+ {
+ // Truncate to a 64-bit unsigned integer in dataTempRegister, copy the low 32-bit to dest.
+ m_assembler.fcvtzu<64, 64>(getCachedDataTempRegisterIDAndInvalidate(), src);
+ zeroExtend32ToPtr(dataTempRegister, dest);
+ // Check thlow 32-bits sign extend to be equal to the full value.
+ m_assembler.cmp<64>(dataTempRegister, dataTempRegister, ARM64Assembler::SXTW, 0);
+ return Jump(makeBranch(branchType == BranchIfTruncateSuccessful ? Equal : NotEqual));
+ }
+
+ void convertDoubleToFloat(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.fcvt<32, 64>(dest, src);
+ }
+
+ void convertFloatToDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.fcvt<64, 32>(dest, src);
+ }
+
+ void convertInt32ToDouble(TrustedImm32 imm, FPRegisterID dest)
+ {
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ convertInt32ToDouble(dataTempRegister, dest);
+ }
+
+ void convertUInt32ToDouble(RegisterID src, FPRegisterID dest, RegisterID /*scratch*/)
+ {
+ m_assembler.ucvtf<64, 32>(dest, src);
+ }
+
+ void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
+ {
+ m_assembler.scvtf<64, 32>(dest, src);
+ }
+
+ void convertInt32ToDouble(Address address, FPRegisterID dest)
+ {
+ load32(address, getCachedDataTempRegisterIDAndInvalidate());
+ convertInt32ToDouble(dataTempRegister, dest);
+ }
+
+ void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
+ {
+ load32(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
+ convertInt32ToDouble(dataTempRegister, dest);
+ }
+
+ void convertInt64ToDouble(RegisterID src, FPRegisterID dest)
+ {
+ m_assembler.scvtf<64, 64>(dest, src);
+ }
+
+ void divDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ divDouble(dest, src, dest);
+ }
+
+ void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.fdiv<64>(dest, op1, op2);
+ }
+
+ void divFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.fdiv<32>(dest, op1, op2);
+ }
+
+ void loadDouble(ImplicitAddress address, FPRegisterID dest)
+ {
+ if (tryLoadWithOffset<64>(dest, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.ldr<64>(dest, address.base, memoryTempRegister);
+ }
+
+ void loadDouble(BaseIndex address, FPRegisterID dest)
+ {
+ if (!address.offset && (!address.scale || address.scale == 3)) {
+ m_assembler.ldr<64>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.ldr<64>(dest, address.base, memoryTempRegister);
+ }
+
+ void loadDouble(TrustedImmPtr address, FPRegisterID dest)
+ {
+ moveToCachedReg(address, m_cachedMemoryTempRegister);
+ m_assembler.ldr<64>(dest, memoryTempRegister, ARM64Registers::zr);
+ }
+
+ void loadFloat(ImplicitAddress address, FPRegisterID dest)
+ {
+ if (tryLoadWithOffset<32>(dest, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.ldr<32>(dest, address.base, memoryTempRegister);
+ }
+
+ void loadFloat(BaseIndex address, FPRegisterID dest)
+ {
+ if (!address.offset && (!address.scale || address.scale == 2)) {
+ m_assembler.ldr<32>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.ldr<32>(dest, address.base, memoryTempRegister);
+ }
+
+ void moveDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.fmov<64>(dest, src);
+ }
+
+ void moveZeroToDouble(FPRegisterID reg)
+ {
+ m_assembler.fmov<64>(reg, ARM64Registers::zr);
+ }
+
+ void moveDoubleTo64(FPRegisterID src, RegisterID dest)
+ {
+ m_assembler.fmov<64>(dest, src);
+ }
+
+ void moveFloatTo32(FPRegisterID src, RegisterID dest)
+ {
+ m_assembler.fmov<32>(dest, src);
+ }
+
+ void move64ToDouble(RegisterID src, FPRegisterID dest)
+ {
+ m_assembler.fmov<64>(dest, src);
+ }
+
+ void move32ToFloat(RegisterID src, FPRegisterID dest)
+ {
+ m_assembler.fmov<32>(dest, src);
+ }
+
+ void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
+ {
+ m_assembler.fcmp<64>(left, right);
+ moveConditionallyAfterFloatingPointCompare<64>(cond, src, dest);
+ }
+
+ void moveConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
+ {
+ m_assembler.fcmp<32>(left, right);
+ moveConditionallyAfterFloatingPointCompare<64>(cond, src, dest);
+ }
+
+ template<int datasize>
+ void moveConditionallyAfterFloatingPointCompare(DoubleCondition cond, RegisterID src, RegisterID dest)
+ {
+ if (cond == DoubleNotEqual) {
+ Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
+ m_assembler.csel<datasize>(dest, src, dest, ARM64Assembler::ConditionNE);
+ unordered.link(this);
+ return;
+ }
+ if (cond == DoubleEqualOrUnordered) {
+ // If the compare is unordered, src is copied to dest and the
+ // next csel has all arguments equal to src.
+ // If the compare is ordered, dest is unchanged and EQ decides
+ // what value to set.
+ m_assembler.csel<datasize>(dest, src, dest, ARM64Assembler::ConditionVS);
+ m_assembler.csel<datasize>(dest, src, dest, ARM64Assembler::ConditionEQ);
+ return;
+ }
+ m_assembler.csel<datasize>(dest, src, dest, ARM64Condition(cond));
+ }
+
+ void mulDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ mulDouble(dest, src, dest);
+ }
+
+ void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.fmul<64>(dest, op1, op2);
+ }
+
+ void mulDouble(Address src, FPRegisterID dest)
+ {
+ loadDouble(src, fpTempRegister);
+ mulDouble(fpTempRegister, dest);
+ }
+
+ void mulFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.fmul<32>(dest, op1, op2);
+ }
+
+ void andDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.vand<64>(dest, op1, op2);
+ }
+
+ void andFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ andDouble(op1, op2, dest);
+ }
+
+ void negateDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.fneg<64>(dest, src);
+ }
+
+ void sqrtDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.fsqrt<64>(dest, src);
+ }
+
+ void sqrtFloat(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.fsqrt<32>(dest, src);
+ }
+
+ void storeDouble(FPRegisterID src, ImplicitAddress address)
+ {
+ if (tryStoreWithOffset<64>(src, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.str<64>(src, address.base, memoryTempRegister);
+ }
+
+ void storeDouble(FPRegisterID src, TrustedImmPtr address)
+ {
+ moveToCachedReg(address, m_cachedMemoryTempRegister);
+ m_assembler.str<64>(src, memoryTempRegister, ARM64Registers::zr);
+ }
+
+ void storeDouble(FPRegisterID src, BaseIndex address)
+ {
+ if (!address.offset && (!address.scale || address.scale == 3)) {
+ m_assembler.str<64>(src, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.str<64>(src, address.base, memoryTempRegister);
+ }
+
+ void storeFloat(FPRegisterID src, ImplicitAddress address)
+ {
+ if (tryStoreWithOffset<32>(src, address.base, address.offset))
+ return;
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.str<32>(src, address.base, memoryTempRegister);
+ }
+
+ void storeFloat(FPRegisterID src, BaseIndex address)
+ {
+ if (!address.offset && (!address.scale || address.scale == 2)) {
+ m_assembler.str<32>(src, address.base, address.index, ARM64Assembler::UXTX, address.scale);
+ return;
+ }
+
+ signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
+ m_assembler.str<32>(src, address.base, memoryTempRegister);
+ }
+
+ void subDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ subDouble(dest, src, dest);
+ }
+
+ void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.fsub<64>(dest, op1, op2);
+ }
+
+ void subDouble(Address src, FPRegisterID dest)
+ {
+ loadDouble(src, fpTempRegister);
+ subDouble(fpTempRegister, dest);
+ }
+
+ void subFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.fsub<32>(dest, op1, op2);
+ }
+
+ // Result is undefined if the value is outside of the integer range.
+ void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
+ {
+ m_assembler.fcvtzs<32, 64>(dest, src);
+ }
+
+ void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
+ {
+ m_assembler.fcvtzu<32, 64>(dest, src);
+ }
+
+
+ // Stack manipulation operations:
+ //
+ // The ABI is assumed to provide a stack abstraction to memory,
+ // containing machine word sized units of data. Push and pop
+ // operations add and remove a single register sized unit of data
+ // to or from the stack. These operations are not supported on
+ // ARM64. Peek and poke operations read or write values on the
+ // stack, without moving the current stack position. Additionally,
+ // there are popToRestore and pushToSave operations, which are
+ // designed just for quick-and-dirty saving and restoring of
+ // temporary values. These operations don't claim to have any
+ // ABI compatibility.
+
+ void pop(RegisterID) NO_RETURN_DUE_TO_CRASH
+ {
+ CRASH();
+ }
+
+ void push(RegisterID) NO_RETURN_DUE_TO_CRASH
+ {
+ CRASH();
+ }
+
+ void push(Address) NO_RETURN_DUE_TO_CRASH
+ {
+ CRASH();
+ }
+
+ void push(TrustedImm32) NO_RETURN_DUE_TO_CRASH
+ {
+ CRASH();
+ }
+
+ void popPair(RegisterID dest1, RegisterID dest2)
+ {
+ m_assembler.ldp<64>(dest1, dest2, ARM64Registers::sp, PairPostIndex(16));
+ }
+
+ void pushPair(RegisterID src1, RegisterID src2)
+ {
+ m_assembler.stp<64>(src1, src2, ARM64Registers::sp, PairPreIndex(-16));
+ }
+
+ void popToRestore(RegisterID dest)
+ {
+ m_assembler.ldr<64>(dest, ARM64Registers::sp, PostIndex(16));
+ }
+
+ void pushToSave(RegisterID src)
+ {
+ m_assembler.str<64>(src, ARM64Registers::sp, PreIndex(-16));
+ }
+
+ void pushToSaveImmediateWithoutTouchingRegisters(TrustedImm32 imm)
+ {
+ RegisterID reg = dataTempRegister;
+ pushPair(reg, reg);
+ move(imm, reg);
+ store64(reg, stackPointerRegister);
+ load64(Address(stackPointerRegister, 8), reg);
+ }
+
+ void pushToSave(Address address)
+ {
+ load32(address, getCachedDataTempRegisterIDAndInvalidate());
+ pushToSave(dataTempRegister);
+ }
+
+ void pushToSave(TrustedImm32 imm)
+ {
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ pushToSave(dataTempRegister);
+ }
+
+ void popToRestore(FPRegisterID dest)
+ {
+ loadDouble(stackPointerRegister, dest);
+ add64(TrustedImm32(16), stackPointerRegister);
+ }
+
+ void pushToSave(FPRegisterID src)
+ {
+ sub64(TrustedImm32(16), stackPointerRegister);
+ storeDouble(src, stackPointerRegister);
+ }
+
+ static ptrdiff_t pushToSaveByteOffset() { return 16; }
+
+ // Register move operations:
+
+ void move(RegisterID src, RegisterID dest)
+ {
+ if (src != dest)
+ m_assembler.mov<64>(dest, src);
+ }
+
+ void move(TrustedImm32 imm, RegisterID dest)
+ {
+ moveInternal<TrustedImm32, int32_t>(imm, dest);
+ }
+
+ void move(TrustedImmPtr imm, RegisterID dest)
+ {
+ moveInternal<TrustedImmPtr, intptr_t>(imm, dest);
+ }
+
+ void move(TrustedImm64 imm, RegisterID dest)
+ {
+ moveInternal<TrustedImm64, int64_t>(imm, dest);
+ }
+
+ void swap(RegisterID reg1, RegisterID reg2)
+ {
+ move(reg1, getCachedDataTempRegisterIDAndInvalidate());
+ move(reg2, reg1);
+ move(dataTempRegister, reg2);
+ }
+
+ void signExtend32ToPtr(TrustedImm32 imm, RegisterID dest)
+ {
+ move(TrustedImmPtr(reinterpret_cast<void*>(static_cast<intptr_t>(imm.m_value))), dest);
+ }
+
+ void signExtend32ToPtr(RegisterID src, RegisterID dest)
+ {
+ m_assembler.sxtw(dest, src);
+ }
+
+ void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
+ {
+ m_assembler.uxtw(dest, src);
+ }
+
+ void moveConditionally32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
+ {
+ m_assembler.cmp<32>(left, right);
+ m_assembler.csel<32>(dest, src, dest, ARM64Condition(cond));
+ }
+
+ void moveConditionally64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
+ {
+ m_assembler.cmp<64>(left, right);
+ m_assembler.csel<64>(dest, src, dest, ARM64Condition(cond));
+ }
+
+ void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
+ {
+ m_assembler.tst<32>(testReg, mask);
+ m_assembler.csel<32>(dest, src, dest, ARM64Condition(cond));
+ }
+
+ void moveConditionallyTest64(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
+ {
+ m_assembler.tst<64>(testReg, mask);
+ m_assembler.csel<64>(dest, src, dest, ARM64Condition(cond));
+ }
+
+ // Forwards / external control flow operations:
+ //
+ // This set of jump and conditional branch operations return a Jump
+ // object which may linked at a later point, allow forwards jump,
+ // or jumps that will require external linkage (after the code has been
+ // relocated).
+ //
+ // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
+ // respecitvely, for unsigned comparisons the names b, a, be, and ae are
+ // used (representing the names 'below' and 'above').
+ //
+ // Operands to the comparision are provided in the expected order, e.g.
+ // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
+ // treated as a signed 32bit value, is less than or equal to 5.
+ //
+ // jz and jnz test whether the first operand is equal to zero, and take
+ // an optional second operand of a mask under which to perform the test.
+
+ Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
+ {
+ m_assembler.cmp<32>(left, right);
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
+ {
+ if (isUInt12(right.m_value))
+ m_assembler.cmp<32>(left, UInt12(right.m_value));
+ else if (isUInt12(-right.m_value))
+ m_assembler.cmn<32>(left, UInt12(-right.m_value));
+ else {
+ moveToCachedReg(right, m_dataMemoryTempRegister);
+ m_assembler.cmp<32>(left, dataTempRegister);
+ }
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branch32(RelationalCondition cond, RegisterID left, Address right)
+ {
+ load32(right, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch32(cond, left, memoryTempRegister);
+ }
+
+ Jump branch32(RelationalCondition cond, Address left, RegisterID right)
+ {
+ load32(left, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch32(cond, memoryTempRegister, right);
+ }
+
+ Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
+ {
+ load32(left, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch32(cond, memoryTempRegister, right);
+ }
+
+ Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
+ {
+ load32(left, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch32(cond, memoryTempRegister, right);
+ }
+
+ Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
+ {
+ load32(left.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
+ return branch32(cond, dataTempRegister, right);
+ }
+
+ Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
+ {
+ load32(left.m_ptr, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch32(cond, memoryTempRegister, right);
+ }
+
+ Jump branch64(RelationalCondition cond, RegisterID left, RegisterID right)
+ {
+ if (right == ARM64Registers::sp) {
+ if (cond == Equal && left != ARM64Registers::sp) {
+ // CMP can only use SP for the left argument, since we are testing for equality, the order
+ // does not matter here.
+ std::swap(left, right);
+ } else {
+ move(right, getCachedDataTempRegisterIDAndInvalidate());
+ right = dataTempRegister;
+ }
+ }
+ m_assembler.cmp<64>(left, right);
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branch64(RelationalCondition cond, RegisterID left, TrustedImm64 right)
+ {
+ intptr_t immediate = right.m_value;
+ if (isUInt12(immediate))
+ m_assembler.cmp<64>(left, UInt12(static_cast<int32_t>(immediate)));
+ else if (isUInt12(-immediate))
+ m_assembler.cmn<64>(left, UInt12(static_cast<int32_t>(-immediate)));
+ else {
+ moveToCachedReg(right, m_dataMemoryTempRegister);
+ m_assembler.cmp<64>(left, dataTempRegister);
+ }
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branch64(RelationalCondition cond, RegisterID left, Address right)
+ {
+ load64(right, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch64(cond, left, memoryTempRegister);
+ }
+
+ Jump branch64(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
+ {
+ load64(left.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
+ return branch64(cond, dataTempRegister, right);
+ }
+
+ Jump branch64(RelationalCondition cond, Address left, RegisterID right)
+ {
+ load64(left, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch64(cond, memoryTempRegister, right);
+ }
+
+ Jump branch64(RelationalCondition cond, Address left, TrustedImm64 right)
+ {
+ load64(left, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch64(cond, memoryTempRegister, right);
+ }
+
+ Jump branchPtr(RelationalCondition cond, BaseIndex left, RegisterID right)
+ {
+ load64(left, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch64(cond, memoryTempRegister, right);
+ }
+
+ Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
+ {
+ ASSERT(!(0xffffff00 & right.m_value));
+ load8(left, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch32(cond, memoryTempRegister, right);
+ }
+
+ Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
+ {
+ ASSERT(!(0xffffff00 & right.m_value));
+ load8(left, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch32(cond, memoryTempRegister, right);
+ }
+
+ Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
+ {
+ ASSERT(!(0xffffff00 & right.m_value));
+ load8(left.m_ptr, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch32(cond, memoryTempRegister, right);
+ }
+
+ Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
+ {
+ m_assembler.tst<32>(reg, mask);
+ return Jump(makeBranch(cond));
+ }
+
+ void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ if (mask.m_value == -1)
+ m_assembler.tst<32>(reg, reg);
+ else {
+ bool testedWithImmediate = false;
+ if ((cond == Zero) || (cond == NonZero)) {
+ LogicalImmediate logicalImm = LogicalImmediate::create32(mask.m_value);
+
+ if (logicalImm.isValid()) {
+ m_assembler.tst<32>(reg, logicalImm);
+ testedWithImmediate = true;
+ }
+ }
+ if (!testedWithImmediate) {
+ move(mask, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.tst<32>(reg, dataTempRegister);
+ }
+ }
+ }
+
+ Jump branch(ResultCondition cond)
+ {
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ if (mask.m_value == -1) {
+ if ((cond == Zero) || (cond == NonZero))
+ return Jump(makeCompareAndBranch<32>(static_cast<ZeroCondition>(cond), reg));
+ m_assembler.tst<32>(reg, reg);
+ } else if (hasOneBitSet(mask.m_value) && ((cond == Zero) || (cond == NonZero)))
+ return Jump(makeTestBitAndBranch(reg, getLSBSet(mask.m_value), static_cast<ZeroCondition>(cond)));
+ else {
+ if ((cond == Zero) || (cond == NonZero)) {
+ LogicalImmediate logicalImm = LogicalImmediate::create32(mask.m_value);
+
+ if (logicalImm.isValid()) {
+ m_assembler.tst<32>(reg, logicalImm);
+ return Jump(makeBranch(cond));
+ }
+ }
+
+ move(mask, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.tst<32>(reg, dataTempRegister);
+ }
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ load32(address, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branchTest32(cond, memoryTempRegister, mask);
+ }
+
+ Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ load32(address, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branchTest32(cond, memoryTempRegister, mask);
+ }
+
+ Jump branchTest64(ResultCondition cond, RegisterID reg, RegisterID mask)
+ {
+ m_assembler.tst<64>(reg, mask);
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branchTest64(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ if (mask.m_value == -1) {
+ if ((cond == Zero) || (cond == NonZero))
+ return Jump(makeCompareAndBranch<64>(static_cast<ZeroCondition>(cond), reg));
+ m_assembler.tst<64>(reg, reg);
+ } else if (hasOneBitSet(mask.m_value) && ((cond == Zero) || (cond == NonZero)))
+ return Jump(makeTestBitAndBranch(reg, getLSBSet(mask.m_value), static_cast<ZeroCondition>(cond)));
+ else {
+ if ((cond == Zero) || (cond == NonZero)) {
+ LogicalImmediate logicalImm = LogicalImmediate::create64(mask.m_value);
+
+ if (logicalImm.isValid()) {
+ m_assembler.tst<64>(reg, logicalImm);
+ return Jump(makeBranch(cond));
+ }
+ }
+
+ signExtend32ToPtr(mask, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.tst<64>(reg, dataTempRegister);
+ }
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branchTest64(ResultCondition cond, RegisterID reg, TrustedImm64 mask)
+ {
+ move(mask, getCachedDataTempRegisterIDAndInvalidate());
+ return branchTest64(cond, reg, dataTempRegister);
+ }
+
+ Jump branchTest64(ResultCondition cond, Address address, RegisterID mask)
+ {
+ load64(address, getCachedDataTempRegisterIDAndInvalidate());
+ return branchTest64(cond, dataTempRegister, mask);
+ }
+
+ Jump branchTest64(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ load64(address, getCachedDataTempRegisterIDAndInvalidate());
+ return branchTest64(cond, dataTempRegister, mask);
+ }
+
+ Jump branchTest64(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ load64(address, getCachedDataTempRegisterIDAndInvalidate());
+ return branchTest64(cond, dataTempRegister, mask);
+ }
+
+ Jump branchTest64(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ load64(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
+ return branchTest64(cond, dataTempRegister, mask);
+ }
+
+ Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ load8(address, getCachedDataTempRegisterIDAndInvalidate());
+ return branchTest32(cond, dataTempRegister, mask);
+ }
+
+ Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ load8(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
+ return branchTest32(cond, dataTempRegister, mask);
+ }
+
+ Jump branchTest8(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ move(TrustedImmPtr(reinterpret_cast<void*>(address.offset)), getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.ldrb(dataTempRegister, address.base, dataTempRegister);
+ return branchTest32(cond, dataTempRegister, mask);
+ }
+
+ Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ load8(address, getCachedDataTempRegisterIDAndInvalidate());
+ return branchTest32(cond, dataTempRegister, mask);
+ }
+
+ Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
+ {
+ return branch32(cond, left, right);
+ }
+
+
+ // Arithmetic control flow operations:
+ //
+ // This set of conditional branch operations branch based
+ // on the result of an arithmetic operation. The operation
+ // is performed as normal, storing the result.
+ //
+ // * jz operations branch if the result is zero.
+ // * jo operations branch if the (signed) arithmetic
+ // operation caused an overflow to occur.
+
+ Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.add<32, S>(dest, op1, op2);
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
+ {
+ if (isUInt12(imm.m_value)) {
+ m_assembler.add<32, S>(dest, op1, UInt12(imm.m_value));
+ return Jump(makeBranch(cond));
+ }
+ if (isUInt12(-imm.m_value)) {
+ m_assembler.sub<32, S>(dest, op1, UInt12(-imm.m_value));
+ return Jump(makeBranch(cond));
+ }
+
+ signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
+ return branchAdd32(cond, op1, dataTempRegister, dest);
+ }
+
+ Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest)
+ {
+ load32(src, getCachedDataTempRegisterIDAndInvalidate());
+ return branchAdd32(cond, dest, dataTempRegister, dest);
+ }
+
+ Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
+ {
+ return branchAdd32(cond, dest, src, dest);
+ }
+
+ Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
+ {
+ return branchAdd32(cond, dest, imm, dest);
+ }
+
+ Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress address)
+ {
+ load32(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
+
+ if (isUInt12(imm.m_value)) {
+ m_assembler.add<32, S>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
+ store32(dataTempRegister, address.m_ptr);
+ } else if (isUInt12(-imm.m_value)) {
+ m_assembler.sub<32, S>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
+ store32(dataTempRegister, address.m_ptr);
+ } else {
+ move(imm, getCachedMemoryTempRegisterIDAndInvalidate());
+ m_assembler.add<32, S>(dataTempRegister, dataTempRegister, memoryTempRegister);
+ store32(dataTempRegister, address.m_ptr);
+ }
+
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branchAdd64(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.add<64, S>(dest, op1, op2);
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branchAdd64(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
+ {
+ if (isUInt12(imm.m_value)) {
+ m_assembler.add<64, S>(dest, op1, UInt12(imm.m_value));
+ return Jump(makeBranch(cond));
+ }
+ if (isUInt12(-imm.m_value)) {
+ m_assembler.sub<64, S>(dest, op1, UInt12(-imm.m_value));
+ return Jump(makeBranch(cond));
+ }
+
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ return branchAdd64(cond, op1, dataTempRegister, dest);
+ }
+
+ Jump branchAdd64(ResultCondition cond, RegisterID src, RegisterID dest)
+ {
+ return branchAdd64(cond, dest, src, dest);
+ }
+
+ Jump branchAdd64(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
+ {
+ return branchAdd64(cond, dest, imm, dest);
+ }
+
+ Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID scratch1, RegisterID scratch2, RegisterID dest)
+ {
+ ASSERT(cond != Signed);
+
+ if (cond != Overflow) {
+ m_assembler.mul<32>(dest, src1, src2);
+ return branchTest32(cond, dest);
+ }
+
+ // This is a signed multiple of two 32-bit values, producing a 64-bit result.
+ m_assembler.smull(dest, src1, src2);
+ // Copy bits 63..32 of the result to bits 31..0 of scratch1.
+ m_assembler.asr<64>(scratch1, dest, 32);
+ // Splat bit 31 of the result to bits 31..0 of scratch2.
+ m_assembler.asr<32>(scratch2, dest, 31);
+ // After a mul32 the top 32 bits of the register should be clear.
+ zeroExtend32ToPtr(dest, dest);
+ // Check that bits 31..63 of the original result were all equal.
+ return branch32(NotEqual, scratch2, scratch1);
+ }
+
+ Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
+ {
+ return branchMul32(cond, src1, src2, getCachedDataTempRegisterIDAndInvalidate(), getCachedMemoryTempRegisterIDAndInvalidate(), dest);
+ }
+
+ Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
+ {
+ return branchMul32(cond, dest, src, dest);
+ }
+
+ Jump branchMul32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ return branchMul32(cond, dataTempRegister, src, dest);
+ }
+
+ Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ move(imm, dataTempRegister);
+ return branchMul32(cond, dataTempRegister, src, dest);
+ }
+
+ Jump branchMul64(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID scratch1, RegisterID scratch2, RegisterID dest)
+ {
+ ASSERT(cond != Signed);
+
+ // This is a signed multiple of two 64-bit values, producing a 64-bit result.
+ m_assembler.mul<64>(dest, src1, src2);
+
+ if (cond != Overflow)
+ return branchTest64(cond, dest);
+
+ // Compute bits 127..64 of the result into scratch1.
+ m_assembler.smulh(scratch1, src1, src2);
+ // Splat bit 63 of the result to bits 63..0 of scratch2.
+ m_assembler.asr<64>(scratch2, dest, 63);
+ // Check that bits 31..63 of the original result were all equal.
+ return branch64(NotEqual, scratch2, scratch1);
+ }
+
+ Jump branchMul64(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
+ {
+ return branchMul64(cond, src1, src2, getCachedDataTempRegisterIDAndInvalidate(), getCachedMemoryTempRegisterIDAndInvalidate(), dest);
+ }
+
+ Jump branchMul64(ResultCondition cond, RegisterID src, RegisterID dest)
+ {
+ return branchMul64(cond, dest, src, dest);
+ }
+
+ Jump branchNeg32(ResultCondition cond, RegisterID dest)
+ {
+ m_assembler.neg<32, S>(dest, dest);
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branchNeg64(ResultCondition cond, RegisterID srcDest)
+ {
+ m_assembler.neg<64, S>(srcDest, srcDest);
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branchSub32(ResultCondition cond, RegisterID dest)
+ {
+ m_assembler.neg<32, S>(dest, dest);
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.sub<32, S>(dest, op1, op2);
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
+ {
+ if (isUInt12(imm.m_value)) {
+ m_assembler.sub<32, S>(dest, op1, UInt12(imm.m_value));
+ return Jump(makeBranch(cond));
+ }
+ if (isUInt12(-imm.m_value)) {
+ m_assembler.add<32, S>(dest, op1, UInt12(-imm.m_value));
+ return Jump(makeBranch(cond));
+ }
+
+ signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
+ return branchSub32(cond, op1, dataTempRegister, dest);
+ }
+
+ Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
+ {
+ return branchSub32(cond, dest, src, dest);
+ }
+
+ Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
+ {
+ return branchSub32(cond, dest, imm, dest);
+ }
+
+ Jump branchSub64(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.sub<64, S>(dest, op1, op2);
+ return Jump(makeBranch(cond));
+ }
+
+ Jump branchSub64(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
+ {
+ if (isUInt12(imm.m_value)) {
+ m_assembler.sub<64, S>(dest, op1, UInt12(imm.m_value));
+ return Jump(makeBranch(cond));
+ }
+ if (isUInt12(-imm.m_value)) {
+ m_assembler.add<64, S>(dest, op1, UInt12(-imm.m_value));
+ return Jump(makeBranch(cond));
+ }
+
+ move(imm, getCachedDataTempRegisterIDAndInvalidate());
+ return branchSub64(cond, op1, dataTempRegister, dest);
+ }
+
+ Jump branchSub64(ResultCondition cond, RegisterID src, RegisterID dest)
+ {
+ return branchSub64(cond, dest, src, dest);
+ }
+
+ Jump branchSub64(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
+ {
+ return branchSub64(cond, dest, imm, dest);
+ }
+
+
+ // Jumps, calls, returns
+
+ ALWAYS_INLINE Call call()
+ {
+ AssemblerLabel pointerLabel = m_assembler.label();
+ moveWithFixedWidth(TrustedImmPtr(0), getCachedDataTempRegisterIDAndInvalidate());
+ invalidateAllTempRegisters();
+ m_assembler.blr(dataTempRegister);
+ AssemblerLabel callLabel = m_assembler.label();
+ ASSERT_UNUSED(pointerLabel, ARM64Assembler::getDifferenceBetweenLabels(callLabel, pointerLabel) == REPATCH_OFFSET_CALL_TO_POINTER);
+ return Call(callLabel, Call::Linkable);
+ }
+
+ ALWAYS_INLINE Call call(RegisterID target)
+ {
+ invalidateAllTempRegisters();
+ m_assembler.blr(target);
+ return Call(m_assembler.label(), Call::None);
+ }
+
+ ALWAYS_INLINE Call call(Address address)
+ {
+ load64(address, getCachedDataTempRegisterIDAndInvalidate());
+ return call(dataTempRegister);
+ }
+
+ ALWAYS_INLINE Jump jump()
+ {
+ AssemblerLabel label = m_assembler.label();
+ m_assembler.b();
+ return Jump(label, m_makeJumpPatchable ? ARM64Assembler::JumpNoConditionFixedSize : ARM64Assembler::JumpNoCondition);
+ }
+
+ void jump(RegisterID target)
+ {
+ m_assembler.br(target);
+ }
+
+ void jump(Address address)
+ {
+ load64(address, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.br(dataTempRegister);
+ }
+
+ void jump(AbsoluteAddress address)
+ {
+ move(TrustedImmPtr(address.m_ptr), getCachedDataTempRegisterIDAndInvalidate());
+ load64(Address(dataTempRegister), dataTempRegister);
+ m_assembler.br(dataTempRegister);
+ }
+
+ ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
+ {
+ oldJump.link(this);
+ return tailRecursiveCall();
+ }
+
+ ALWAYS_INLINE Call nearCall()
+ {
+ m_assembler.bl();
+ return Call(m_assembler.label(), Call::LinkableNear);
+ }
+
+#if 0
+ ALWAYS_INLINE Call nearTailCall()
+ {
+ AssemblerLabel label = m_assembler.label();
+ m_assembler.b();
+ return Call(label, Call::LinkableNearTail);
+ }
+#endif
+
+ ALWAYS_INLINE void ret()
+ {
+ m_assembler.ret();
+ }
+
+ ALWAYS_INLINE Call tailRecursiveCall()
+ {
+ // Like a normal call, but don't link.
+ AssemblerLabel pointerLabel = m_assembler.label();
+ moveWithFixedWidth(TrustedImmPtr(0), getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.br(dataTempRegister);
+ AssemblerLabel callLabel = m_assembler.label();
+ ASSERT_UNUSED(pointerLabel, ARM64Assembler::getDifferenceBetweenLabels(callLabel, pointerLabel) == REPATCH_OFFSET_CALL_TO_POINTER);
+ return Call(callLabel, Call::Linkable);
+ }
+
+
+ // Comparisons operations
+
+ void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
+ {
+ m_assembler.cmp<32>(left, right);
+ m_assembler.cset<32>(dest, ARM64Condition(cond));
+ }
+
+ void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
+ {
+ load32(left, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.cmp<32>(dataTempRegister, right);
+ m_assembler.cset<32>(dest, ARM64Condition(cond));
+ }
+
+ void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
+ {
+ move(right, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.cmp<32>(left, dataTempRegister);
+ m_assembler.cset<32>(dest, ARM64Condition(cond));
+ }
+
+ void compare64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
+ {
+ m_assembler.cmp<64>(left, right);
+ m_assembler.cset<32>(dest, ARM64Condition(cond));
+ }
+
+ void compare64(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
+ {
+ signExtend32ToPtr(right, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.cmp<64>(left, dataTempRegister);
+ m_assembler.cset<32>(dest, ARM64Condition(cond));
+ }
+
+ void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
+ {
+ load8(left, getCachedMemoryTempRegisterIDAndInvalidate());
+ move(right, getCachedDataTempRegisterIDAndInvalidate());
+ compare32(cond, memoryTempRegister, dataTempRegister, dest);
+ }
+
+ void test32(ResultCondition cond, RegisterID src, RegisterID mask, RegisterID dest)
+ {
+ m_assembler.tst<32>(src, mask);
+ m_assembler.cset<32>(dest, ARM64Condition(cond));
+ }
+
+ void test32(ResultCondition cond, RegisterID src, TrustedImm32 mask, RegisterID dest)
+ {
+ if (mask.m_value == -1)
+ m_assembler.tst<32>(src, src);
+ else {
+ signExtend32ToPtr(mask, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.tst<32>(src, dataTempRegister);
+ }
+ m_assembler.cset<32>(dest, ARM64Condition(cond));
+ }
+
+ void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
+ {
+ load32(address, getCachedMemoryTempRegisterIDAndInvalidate());
+ test32(cond, memoryTempRegister, mask, dest);
+ }
+
+ void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
+ {
+ load8(address, getCachedMemoryTempRegisterIDAndInvalidate());
+ test32(cond, memoryTempRegister, mask, dest);
+ }
+
+ void test64(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.tst<64>(op1, op2);
+ m_assembler.cset<32>(dest, ARM64Condition(cond));
+ }
+
+ void test64(ResultCondition cond, RegisterID src, TrustedImm32 mask, RegisterID dest)
+ {
+ if (mask.m_value == -1)
+ m_assembler.tst<64>(src, src);
+ else {
+ signExtend32ToPtr(mask, getCachedDataTempRegisterIDAndInvalidate());
+ m_assembler.tst<64>(src, dataTempRegister);
+ }
+ m_assembler.cset<32>(dest, ARM64Condition(cond));
+ }
+
+ void setCarry(RegisterID dest)
+ {
+ m_assembler.cset<32>(dest, ARM64Assembler::ConditionCS);
+ }
+
+ // Patchable operations
+
+ ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dest)
+ {
+ DataLabel32 label(this);
+ moveWithFixedWidth(imm, dest);
+ return label;
+ }
+
+ ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dest)
+ {
+ DataLabelPtr label(this);
+ moveWithFixedWidth(imm, dest);
+ return label;
+ }
+
+ ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
+ {
+ dataLabel = DataLabelPtr(this);
+ moveWithPatch(initialRightValue, getCachedDataTempRegisterIDAndInvalidate());
+ return branch64(cond, left, dataTempRegister);
+ }
+
+ ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
+ {
+ dataLabel = DataLabelPtr(this);
+ moveWithPatch(initialRightValue, getCachedDataTempRegisterIDAndInvalidate());
+ return branch64(cond, left, dataTempRegister);
+ }
+
+ ALWAYS_INLINE Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
+ {
+ dataLabel = DataLabel32(this);
+ moveWithPatch(initialRightValue, getCachedDataTempRegisterIDAndInvalidate());
+ return branch32(cond, left, dataTempRegister);
+ }
+
+ PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right)
+ {
+ m_makeJumpPatchable = true;
+ Jump result = branch64(cond, left, TrustedImm64(right));
+ m_makeJumpPatchable = false;
+ return PatchableJump(result);
+ }
+
+ PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ m_makeJumpPatchable = true;
+ Jump result = branchTest32(cond, reg, mask);
+ m_makeJumpPatchable = false;
+ return PatchableJump(result);
+ }
+
+ PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm)
+ {
+ m_makeJumpPatchable = true;
+ Jump result = branch32(cond, reg, imm);
+ m_makeJumpPatchable = false;
+ return PatchableJump(result);
+ }
+
+ PatchableJump patchableBranch64(RelationalCondition cond, RegisterID reg, TrustedImm64 imm)
+ {
+ m_makeJumpPatchable = true;
+ Jump result = branch64(cond, reg, imm);
+ m_makeJumpPatchable = false;
+ return PatchableJump(result);
+ }
+
+ PatchableJump patchableBranch64(RelationalCondition cond, RegisterID left, RegisterID right)
+ {
+ m_makeJumpPatchable = true;
+ Jump result = branch64(cond, left, right);
+ m_makeJumpPatchable = false;
+ return PatchableJump(result);
+ }
+
+ PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
+ {
+ m_makeJumpPatchable = true;
+ Jump result = branchPtrWithPatch(cond, left, dataLabel, initialRightValue);
+ m_makeJumpPatchable = false;
+ return PatchableJump(result);
+ }
+
+ PatchableJump patchableBranch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
+ {
+ m_makeJumpPatchable = true;
+ Jump result = branch32WithPatch(cond, left, dataLabel, initialRightValue);
+ m_makeJumpPatchable = false;
+ return PatchableJump(result);
+ }
+
+ PatchableJump patchableJump()
+ {
+ m_makeJumpPatchable = true;
+ Jump result = jump();
+ m_makeJumpPatchable = false;
+ return PatchableJump(result);
+ }
+
+ ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+ {
+ DataLabelPtr label(this);
+ moveWithFixedWidth(initialValue, getCachedDataTempRegisterIDAndInvalidate());
+ store64(dataTempRegister, address);
+ return label;
+ }
+
+ ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address)
+ {
+ return storePtrWithPatch(TrustedImmPtr(0), address);
+ }
+
+ static void reemitInitialMoveWithPatch(void* address, void* value)
+ {
+ ARM64Assembler::setPointer(static_cast<int*>(address), value, dataTempRegister, true);
+ }
+
+ // Miscellaneous operations:
+
+ void breakpoint(uint16_t imm = 0)
+ {
+ m_assembler.brk(imm);
+ }
+
+ void nop()
+ {
+ m_assembler.nop();
+ }
+
+ void memoryFence()
+ {
+ m_assembler.dmbSY();
+ }
+
+
+ // Misc helper functions.
+
+ // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
+ static RelationalCondition invert(RelationalCondition cond)
+ {
+ return static_cast<RelationalCondition>(ARM64Assembler::invert(static_cast<ARM64Assembler::Condition>(cond)));
+ }
+
+ static FunctionPtr readCallTarget(CodeLocationCall call)
+ {
+ return FunctionPtr(reinterpret_cast<void(*)()>(ARM64Assembler::readCallTarget(call.dataLocation())));
+ }
+
+ static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
+ {
+ ARM64Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
+ }
+
+ static ptrdiff_t maxJumpReplacementSize()
+ {
+ return ARM64Assembler::maxJumpReplacementSize();
+ }
+
+ RegisterID scratchRegisterForBlinding()
+ {
+ // We *do not* have a scratch register for blinding.
+ RELEASE_ASSERT_NOT_REACHED();
+ return getCachedDataTempRegisterIDAndInvalidate();
+ }
+
+ static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
+ static bool canJumpReplacePatchableBranch32WithPatch() { return false; }
+
+ static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
+ {
+ return label.labelAtOffset(0);
+ }
+
+ static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
+ {
+ UNREACHABLE_FOR_PLATFORM();
+ return CodeLocationLabel();
+ }
+
+ static CodeLocationLabel startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32)
+ {
+ UNREACHABLE_FOR_PLATFORM();
+ return CodeLocationLabel();
+ }
+
+ static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID, void* initialValue)
+ {
+ reemitInitialMoveWithPatch(instructionStart.dataLocation(), initialValue);
+ }
+
+ static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*)
+ {
+ UNREACHABLE_FOR_PLATFORM();
+ }
+
+ static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel, Address, int32_t)
+ {
+ UNREACHABLE_FOR_PLATFORM();
+ }
+
+ static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
+ {
+ ARM64Assembler::repatchPointer(call.dataLabelPtrAtOffset(REPATCH_OFFSET_CALL_TO_POINTER).dataLocation(), destination.executableAddress());
+ }
+
+ static void repatchCall(CodeLocationCall call, FunctionPtr destination)
+ {
+ ARM64Assembler::repatchPointer(call.dataLabelPtrAtOffset(REPATCH_OFFSET_CALL_TO_POINTER).dataLocation(), destination.executableAddress());
+ }
+
+#if ENABLE(MASM_PROBE)
+ void probe(ProbeFunction, void* arg1, void* arg2);
+#endif // ENABLE(MASM_PROBE)
+
+protected:
+ ALWAYS_INLINE Jump makeBranch(ARM64Assembler::Condition cond)
+ {
+ m_assembler.b_cond(cond);
+ AssemblerLabel label = m_assembler.label();
+ m_assembler.nop();
+ return Jump(label, m_makeJumpPatchable ? ARM64Assembler::JumpConditionFixedSize : ARM64Assembler::JumpCondition, cond);
+ }
+ ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(ARM64Condition(cond)); }
+ ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(ARM64Condition(cond)); }
+ ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(ARM64Condition(cond)); }
+
+ template <int dataSize>
+ ALWAYS_INLINE Jump makeCompareAndBranch(ZeroCondition cond, RegisterID reg)
+ {
+ if (cond == IsZero)
+ m_assembler.cbz<dataSize>(reg);
+ else
+ m_assembler.cbnz<dataSize>(reg);
+ AssemblerLabel label = m_assembler.label();
+ m_assembler.nop();
+ return Jump(label, m_makeJumpPatchable ? ARM64Assembler::JumpCompareAndBranchFixedSize : ARM64Assembler::JumpCompareAndBranch, static_cast<ARM64Assembler::Condition>(cond), dataSize == 64, reg);
+ }
+
+ ALWAYS_INLINE Jump makeTestBitAndBranch(RegisterID reg, unsigned bit, ZeroCondition cond)
+ {
+ ASSERT(bit < 64);
+ bit &= 0x3f;
+ if (cond == IsZero)
+ m_assembler.tbz(reg, bit);
+ else
+ m_assembler.tbnz(reg, bit);
+ AssemblerLabel label = m_assembler.label();
+ m_assembler.nop();
+ return Jump(label, m_makeJumpPatchable ? ARM64Assembler::JumpTestBitFixedSize : ARM64Assembler::JumpTestBit, static_cast<ARM64Assembler::Condition>(cond), bit, reg);
+ }
+
+ ARM64Assembler::Condition ARM64Condition(RelationalCondition cond)
+ {
+ return static_cast<ARM64Assembler::Condition>(cond);
+ }
+
+ ARM64Assembler::Condition ARM64Condition(ResultCondition cond)
+ {
+ return static_cast<ARM64Assembler::Condition>(cond);
+ }
+
+ ARM64Assembler::Condition ARM64Condition(DoubleCondition cond)
+ {
+ return static_cast<ARM64Assembler::Condition>(cond);
+ }
+
+private:
+ ALWAYS_INLINE RegisterID getCachedDataTempRegisterIDAndInvalidate()
+ {
+ RELEASE_ASSERT(m_allowScratchRegister);
+ return m_dataMemoryTempRegister.registerIDInvalidate();
+ }
+ ALWAYS_INLINE RegisterID getCachedMemoryTempRegisterIDAndInvalidate()
+ {
+ RELEASE_ASSERT(m_allowScratchRegister);
+ return m_cachedMemoryTempRegister.registerIDInvalidate();
+ }
+
+ ALWAYS_INLINE bool isInIntRange(intptr_t value)
+ {
+ return value == ((value << 32) >> 32);
+ }
+
+ template<typename ImmediateType, typename rawType>
+ void moveInternal(ImmediateType imm, RegisterID dest)
+ {
+ const int dataSize = sizeof(rawType) * 8;
+ const int numberHalfWords = dataSize / 16;
+ rawType value = bitwise_cast<rawType>(imm.m_value);
+ uint16_t halfword[numberHalfWords];
+
+ // Handle 0 and ~0 here to simplify code below
+ if (!value) {
+ m_assembler.movz<dataSize>(dest, 0);
+ return;
+ }
+ if (!~value) {
+ m_assembler.movn<dataSize>(dest, 0);
+ return;
+ }
+
+ LogicalImmediate logicalImm = dataSize == 64 ? LogicalImmediate::create64(static_cast<uint64_t>(value)) : LogicalImmediate::create32(static_cast<uint32_t>(value));
+
+ if (logicalImm.isValid()) {
+ m_assembler.movi<dataSize>(dest, logicalImm);
+ return;
+ }
+
+ // Figure out how many halfwords are 0 or FFFF, then choose movz or movn accordingly.
+ int zeroOrNegateVote = 0;
+ for (int i = 0; i < numberHalfWords; ++i) {
+ halfword[i] = getHalfword(value, i);
+ if (!halfword[i])
+ zeroOrNegateVote++;
+ else if (halfword[i] == 0xffff)
+ zeroOrNegateVote--;
+ }
+
+ bool needToClearRegister = true;
+ if (zeroOrNegateVote >= 0) {
+ for (int i = 0; i < numberHalfWords; i++) {
+ if (halfword[i]) {
+ if (needToClearRegister) {
+ m_assembler.movz<dataSize>(dest, halfword[i], 16*i);
+ needToClearRegister = false;
+ } else
+ m_assembler.movk<dataSize>(dest, halfword[i], 16*i);
+ }
+ }
+ } else {
+ for (int i = 0; i < numberHalfWords; i++) {
+ if (halfword[i] != 0xffff) {
+ if (needToClearRegister) {
+ m_assembler.movn<dataSize>(dest, ~halfword[i], 16*i);
+ needToClearRegister = false;
+ } else
+ m_assembler.movk<dataSize>(dest, halfword[i], 16*i);
+ }
+ }
+ }
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void loadUnsignedImmediate(RegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ m_assembler.ldr<datasize>(rt, rn, pimm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void loadUnscaledImmediate(RegisterID rt, RegisterID rn, int simm)
+ {
+ m_assembler.ldur<datasize>(rt, rn, simm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void loadSignedAddressedByUnsignedImmediate(RegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ loadUnsignedImmediate<datasize>(rt, rn, pimm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void loadSignedAddressedByUnscaledImmediate(RegisterID rt, RegisterID rn, int simm)
+ {
+ loadUnscaledImmediate<datasize>(rt, rn, simm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void storeUnsignedImmediate(RegisterID rt, RegisterID rn, unsigned pimm)
+ {
+ m_assembler.str<datasize>(rt, rn, pimm);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void storeUnscaledImmediate(RegisterID rt, RegisterID rn, int simm)
+ {
+ m_assembler.stur<datasize>(rt, rn, simm);
+ }
+
+ void moveWithFixedWidth(TrustedImm32 imm, RegisterID dest)
+ {
+ int32_t value = imm.m_value;
+ m_assembler.movz<32>(dest, getHalfword(value, 0));
+ m_assembler.movk<32>(dest, getHalfword(value, 1), 16);
+ }
+
+ void moveWithFixedWidth(TrustedImmPtr imm, RegisterID dest)
+ {
+ intptr_t value = reinterpret_cast<intptr_t>(imm.m_value);
+ m_assembler.movz<64>(dest, getHalfword(value, 0));
+ m_assembler.movk<64>(dest, getHalfword(value, 1), 16);
+ m_assembler.movk<64>(dest, getHalfword(value, 2), 32);
+ }
+
+ void signExtend32ToPtrWithFixedWidth(int32_t value, RegisterID dest)
+ {
+ if (value >= 0) {
+ m_assembler.movz<32>(dest, getHalfword(value, 0));
+ m_assembler.movk<32>(dest, getHalfword(value, 1), 16);
+ } else {
+ m_assembler.movn<32>(dest, ~getHalfword(value, 0));
+ m_assembler.movk<32>(dest, getHalfword(value, 1), 16);
+ }
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void load(const void* address, RegisterID dest)
+ {
+ intptr_t currentRegisterContents;
+ if (m_cachedMemoryTempRegister.value(currentRegisterContents)) {
+ intptr_t addressAsInt = reinterpret_cast<intptr_t>(address);
+ intptr_t addressDelta = addressAsInt - currentRegisterContents;
+
+ if (dest == memoryTempRegister)
+ m_cachedMemoryTempRegister.invalidate();
+
+ if (isInIntRange(addressDelta)) {
+ if (ARM64Assembler::canEncodeSImmOffset(addressDelta)) {
+ m_assembler.ldur<datasize>(dest, memoryTempRegister, addressDelta);
+ return;
+ }
+
+ if (ARM64Assembler::canEncodePImmOffset<datasize>(addressDelta)) {
+ m_assembler.ldr<datasize>(dest, memoryTempRegister, addressDelta);
+ return;
+ }
+ }
+
+ if ((addressAsInt & (~maskHalfWord0)) == (currentRegisterContents & (~maskHalfWord0))) {
+ m_assembler.movk<64>(memoryTempRegister, addressAsInt & maskHalfWord0, 0);
+ m_cachedMemoryTempRegister.setValue(reinterpret_cast<intptr_t>(address));
+ m_assembler.ldr<datasize>(dest, memoryTempRegister, ARM64Registers::zr);
+ return;
+ }
+ }
+
+ move(TrustedImmPtr(address), memoryTempRegister);
+ if (dest == memoryTempRegister)
+ m_cachedMemoryTempRegister.invalidate();
+ else
+ m_cachedMemoryTempRegister.setValue(reinterpret_cast<intptr_t>(address));
+ m_assembler.ldr<datasize>(dest, memoryTempRegister, ARM64Registers::zr);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void store(RegisterID src, const void* address)
+ {
+ ASSERT(src != memoryTempRegister);
+ intptr_t currentRegisterContents;
+ if (m_cachedMemoryTempRegister.value(currentRegisterContents)) {
+ intptr_t addressAsInt = reinterpret_cast<intptr_t>(address);
+ intptr_t addressDelta = addressAsInt - currentRegisterContents;
+
+ if (isInIntRange(addressDelta)) {
+ if (ARM64Assembler::canEncodeSImmOffset(addressDelta)) {
+ m_assembler.stur<datasize>(src, memoryTempRegister, addressDelta);
+ return;
+ }
+
+ if (ARM64Assembler::canEncodePImmOffset<datasize>(addressDelta)) {
+ m_assembler.str<datasize>(src, memoryTempRegister, addressDelta);
+ return;
+ }
+ }
+
+ if ((addressAsInt & (~maskHalfWord0)) == (currentRegisterContents & (~maskHalfWord0))) {
+ m_assembler.movk<64>(memoryTempRegister, addressAsInt & maskHalfWord0, 0);
+ m_cachedMemoryTempRegister.setValue(reinterpret_cast<intptr_t>(address));
+ m_assembler.str<datasize>(src, memoryTempRegister, ARM64Registers::zr);
+ return;
+ }
+ }
+
+ move(TrustedImmPtr(address), memoryTempRegister);
+ m_cachedMemoryTempRegister.setValue(reinterpret_cast<intptr_t>(address));
+ m_assembler.str<datasize>(src, memoryTempRegister, ARM64Registers::zr);
+ }
+
+ template <int dataSize>
+ ALWAYS_INLINE bool tryMoveUsingCacheRegisterContents(intptr_t immediate, CachedTempRegister& dest)
+ {
+#if 1
+ Q_UNUSED(immediate);
+ Q_UNUSED(dest)
+#else
+ intptr_t currentRegisterContents;
+ if (dest.value(currentRegisterContents)) {
+ if (currentRegisterContents == immediate)
+ return true;
+
+ LogicalImmediate logicalImm = dataSize == 64 ? LogicalImmediate::create64(static_cast<uint64_t>(immediate)) : LogicalImmediate::create32(static_cast<uint32_t>(immediate));
+
+ if (logicalImm.isValid()) {
+ m_assembler.movi<dataSize>(dest.registerIDNoInvalidate(), logicalImm);
+ dest.setValue(immediate);
+ return true;
+ }
+
+ if ((immediate & maskUpperWord) == (currentRegisterContents & maskUpperWord)) {
+ if ((immediate & maskHalfWord1) != (currentRegisterContents & maskHalfWord1))
+ m_assembler.movk<dataSize>(dest.registerIDNoInvalidate(), (immediate & maskHalfWord1) >> 16, 16);
+
+ if ((immediate & maskHalfWord0) != (currentRegisterContents & maskHalfWord0))
+ m_assembler.movk<dataSize>(dest.registerIDNoInvalidate(), immediate & maskHalfWord0, 0);
+
+ dest.setValue(immediate);
+ return true;
+ }
+ }
+#endif
+
+ return false;
+ }
+
+ void moveToCachedReg(TrustedImm32 imm, CachedTempRegister& dest)
+ {
+ if (tryMoveUsingCacheRegisterContents<32>(static_cast<intptr_t>(imm.m_value), dest))
+ return;
+
+ moveInternal<TrustedImm32, int32_t>(imm, dest.registerIDNoInvalidate());
+ dest.setValue(imm.m_value);
+ }
+
+ void moveToCachedReg(TrustedImmPtr imm, CachedTempRegister& dest)
+ {
+ if (tryMoveUsingCacheRegisterContents<64>(imm.asIntptr(), dest))
+ return;
+
+ moveInternal<TrustedImmPtr, intptr_t>(imm, dest.registerIDNoInvalidate());
+ dest.setValue(imm.asIntptr());
+ }
+
+ void moveToCachedReg(TrustedImm64 imm, CachedTempRegister& dest)
+ {
+ if (tryMoveUsingCacheRegisterContents<64>(static_cast<intptr_t>(imm.m_value), dest))
+ return;
+
+ moveInternal<TrustedImm64, int64_t>(imm, dest.registerIDNoInvalidate());
+ dest.setValue(imm.m_value);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE bool tryLoadWithOffset(RegisterID rt, RegisterID rn, int32_t offset)
+ {
+ if (ARM64Assembler::canEncodeSImmOffset(offset)) {
+ loadUnscaledImmediate<datasize>(rt, rn, offset);
+ return true;
+ }
+ if (ARM64Assembler::canEncodePImmOffset<datasize>(offset)) {
+ loadUnsignedImmediate<datasize>(rt, rn, static_cast<unsigned>(offset));
+ return true;
+ }
+ return false;
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE bool tryLoadSignedWithOffset(RegisterID rt, RegisterID rn, int32_t offset)
+ {
+ if (ARM64Assembler::canEncodeSImmOffset(offset)) {
+ loadSignedAddressedByUnscaledImmediate<datasize>(rt, rn, offset);
+ return true;
+ }
+ if (ARM64Assembler::canEncodePImmOffset<datasize>(offset)) {
+ loadSignedAddressedByUnsignedImmediate<datasize>(rt, rn, static_cast<unsigned>(offset));
+ return true;
+ }
+ return false;
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE bool tryLoadWithOffset(FPRegisterID rt, RegisterID rn, int32_t offset)
+ {
+ if (ARM64Assembler::canEncodeSImmOffset(offset)) {
+ m_assembler.ldur<datasize>(rt, rn, offset);
+ return true;
+ }
+ if (ARM64Assembler::canEncodePImmOffset<datasize>(offset)) {
+ m_assembler.ldr<datasize>(rt, rn, static_cast<unsigned>(offset));
+ return true;
+ }
+ return false;
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE bool tryStoreWithOffset(RegisterID rt, RegisterID rn, int32_t offset)
+ {
+ if (ARM64Assembler::canEncodeSImmOffset(offset)) {
+ storeUnscaledImmediate<datasize>(rt, rn, offset);
+ return true;
+ }
+ if (ARM64Assembler::canEncodePImmOffset<datasize>(offset)) {
+ storeUnsignedImmediate<datasize>(rt, rn, static_cast<unsigned>(offset));
+ return true;
+ }
+ return false;
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE bool tryStoreWithOffset(FPRegisterID rt, RegisterID rn, int32_t offset)
+ {
+ if (ARM64Assembler::canEncodeSImmOffset(offset)) {
+ m_assembler.stur<datasize>(rt, rn, offset);
+ return true;
+ }
+ if (ARM64Assembler::canEncodePImmOffset<datasize>(offset)) {
+ m_assembler.str<datasize>(rt, rn, static_cast<unsigned>(offset));
+ return true;
+ }
+ return false;
+ }
+
+ Jump jumpAfterFloatingPointCompare(DoubleCondition cond)
+ {
+ if (cond == DoubleNotEqual) {
+ // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
+ Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
+ Jump result = makeBranch(ARM64Assembler::ConditionNE);
+ unordered.link(this);
+ return result;
+ }
+ if (cond == DoubleEqualOrUnordered) {
+ Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
+ Jump notEqual = makeBranch(ARM64Assembler::ConditionNE);
+ unordered.link(this);
+ // We get here if either unordered or equal.
+ Jump result = jump();
+ notEqual.link(this);
+ return result;
+ }
+ return makeBranch(cond);
+ }
+
+ friend class LinkBuffer;
+ void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset) {return m_assembler.recordLinkOffsets(regionStart, regionEnd, offset); }
+ int executableOffsetFor(int location) { return m_assembler.executableOffsetFor(location); }
+
+ static void linkCall(void* code, Call call, FunctionPtr function)
+ {
+ if (!call.isFlagSet(Call::Near))
+ ARM64Assembler::linkPointer(code, call.m_label.labelAtOffset(REPATCH_OFFSET_CALL_TO_POINTER), function.value());
+#if 0
+ else if (call.isFlagSet(Call::Tail))
+ ARM64Assembler::linkJump(code, call.m_label, function.value());
+#endif
+ else
+ ARM64Assembler::linkCall(code, call.m_label, function.value());
+ }
+
+ CachedTempRegister m_dataMemoryTempRegister;
+ CachedTempRegister m_cachedMemoryTempRegister;
+ bool m_makeJumpPatchable;
+ bool m_allowScratchRegister = true;
+};
+
+// Extend the {load,store}{Unsigned,Unscaled}Immediate templated general register methods to cover all load/store sizes
+template<>
+ALWAYS_INLINE void MacroAssemblerARM64::loadUnsignedImmediate<8>(RegisterID rt, RegisterID rn, unsigned pimm)
+{
+ m_assembler.ldrb(rt, rn, pimm);
+}
+
+template<>
+ALWAYS_INLINE void MacroAssemblerARM64::loadUnsignedImmediate<16>(RegisterID rt, RegisterID rn, unsigned pimm)
+{
+ m_assembler.ldrh(rt, rn, pimm);
+}
+
+template<>
+ALWAYS_INLINE void MacroAssemblerARM64::loadSignedAddressedByUnsignedImmediate<8>(RegisterID rt, RegisterID rn, unsigned pimm)
+{
+ m_assembler.ldrsb<64>(rt, rn, pimm);
+}
+
+template<>
+ALWAYS_INLINE void MacroAssemblerARM64::loadSignedAddressedByUnsignedImmediate<16>(RegisterID rt, RegisterID rn, unsigned pimm)
+{
+ m_assembler.ldrsh<64>(rt, rn, pimm);
+}
+
+template<>
+ALWAYS_INLINE void MacroAssemblerARM64::loadUnscaledImmediate<8>(RegisterID rt, RegisterID rn, int simm)
+{
+ m_assembler.ldurb(rt, rn, simm);
+}
+
+template<>
+ALWAYS_INLINE void MacroAssemblerARM64::loadUnscaledImmediate<16>(RegisterID rt, RegisterID rn, int simm)
+{
+ m_assembler.ldurh(rt, rn, simm);
+}
+
+template<>
+ALWAYS_INLINE void MacroAssemblerARM64::loadSignedAddressedByUnscaledImmediate<8>(RegisterID rt, RegisterID rn, int simm)
+{
+ m_assembler.ldursb<64>(rt, rn, simm);
+}
+
+template<>
+ALWAYS_INLINE void MacroAssemblerARM64::loadSignedAddressedByUnscaledImmediate<16>(RegisterID rt, RegisterID rn, int simm)
+{
+ m_assembler.ldursh<64>(rt, rn, simm);
+}
+
+template<>
+ALWAYS_INLINE void MacroAssemblerARM64::storeUnsignedImmediate<8>(RegisterID rt, RegisterID rn, unsigned pimm)
+{
+ m_assembler.strb(rt, rn, pimm);
+}
+
+template<>
+ALWAYS_INLINE void MacroAssemblerARM64::storeUnsignedImmediate<16>(RegisterID rt, RegisterID rn, unsigned pimm)
+{
+ m_assembler.strh(rt, rn, pimm);
+}
+
+template<>
+ALWAYS_INLINE void MacroAssemblerARM64::storeUnscaledImmediate<8>(RegisterID rt, RegisterID rn, int simm)
+{
+ m_assembler.sturb(rt, rn, simm);
+}
+
+template<>
+ALWAYS_INLINE void MacroAssemblerARM64::storeUnscaledImmediate<16>(RegisterID rt, RegisterID rn, int simm)
+{
+ m_assembler.sturh(rt, rn, simm);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(ASSEMBLER)
+
+#endif // MacroAssemblerARM64_h
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
index 85cd6c27b9..0938383513 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
@@ -27,7 +27,7 @@
#ifndef MacroAssemblerARMv7_h
#define MacroAssemblerARMv7_h
-#if ENABLE(ASSEMBLER)
+#if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
#include "ARMv7Assembler.h"
#include "AbstractMacroAssembler.h"
diff --git a/src/3rdparty/masm/config.h b/src/3rdparty/masm/config.h
index 224b7d09e2..72035f6a6a 100644
--- a/src/3rdparty/masm/config.h
+++ b/src/3rdparty/masm/config.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/disassembler/ARM64/A64DOpcode.cpp b/src/3rdparty/masm/disassembler/ARM64/A64DOpcode.cpp
new file mode 100644
index 0000000000..52a92c669c
--- /dev/null
+++ b/src/3rdparty/masm/disassembler/ARM64/A64DOpcode.cpp
@@ -0,0 +1,1202 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __STDC_FORMAT_MACROS
+#include "config.h"
+
+#if USE(ARM64_DISASSEMBLER)
+
+#include "A64DOpcode.h"
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+
+namespace JSC { namespace ARM64Disassembler {
+
+A64DOpcode::OpcodeGroup* A64DOpcode::opcodeTable[32];
+
+const char* const A64DOpcode::s_conditionNames[16] = {
+ "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
+ "hi", "ls", "ge", "lt", "gt", "le", "al", "ne"
+};
+
+const char* const A64DOpcode::s_optionName[8] = {
+ "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx"
+};
+
+const char* const A64DOpcode::s_shiftNames[4] = {
+ "lsl", "lsr", "asl", "ror"
+};
+
+const char A64DOpcode::s_FPRegisterPrefix[5] = {
+ 'b', 'h', 's', 'd', 'q'
+};
+
+struct OpcodeGroupInitializer {
+ unsigned m_opcodeGroupNumber;
+ uint32_t m_mask;
+ uint32_t m_pattern;
+ const char* (*m_format)(A64DOpcode*);
+};
+
+#define OPCODE_GROUP_ENTRY(groupIndex, groupClass) \
+{ groupIndex, groupClass::mask, groupClass::pattern, groupClass::format }
+
+static OpcodeGroupInitializer opcodeGroupList[] = {
+ OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreRegisterPair),
+ OPCODE_GROUP_ENTRY(0x09, A64DOpcodeLoadStoreRegisterPair),
+ OPCODE_GROUP_ENTRY(0x0a, A64DOpcodeLogicalShiftedRegister),
+ OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractExtendedRegister),
+ OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractShiftedRegister),
+ OPCODE_GROUP_ENTRY(0x11, A64DOpcodeAddSubtractImmediate),
+ OPCODE_GROUP_ENTRY(0x12, A64DOpcodeMoveWide),
+ OPCODE_GROUP_ENTRY(0x12, A64DOpcodeLogicalImmediate),
+ OPCODE_GROUP_ENTRY(0x13, A64DOpcodeBitfield),
+ OPCODE_GROUP_ENTRY(0x13, A64DOpcodeExtract),
+ OPCODE_GROUP_ENTRY(0x14, A64DOpcodeUnconditionalBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x14, A64DOpcodeConditionalBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x14, A64DOpcodeCompareAndBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x14, A64OpcodeExceptionGeneration),
+ OPCODE_GROUP_ENTRY(0x15, A64DOpcodeUnconditionalBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x15, A64DOpcodeConditionalBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x15, A64DOpcodeCompareAndBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x15, A64DOpcodeHint),
+ OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchRegister),
+ OPCODE_GROUP_ENTRY(0x16, A64DOpcodeTestAndBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchRegister),
+ OPCODE_GROUP_ENTRY(0x17, A64DOpcodeTestAndBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreImmediate),
+ OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreRegisterOffset),
+ OPCODE_GROUP_ENTRY(0x19, A64DOpcodeLoadStoreUnsignedImmediate),
+ OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeConditionalSelect),
+ OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing2Source),
+ OPCODE_GROUP_ENTRY(0x1b, A64DOpcodeDataProcessing3Source),
+ OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreImmediate),
+ OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreRegisterOffset),
+ OPCODE_GROUP_ENTRY(0x1d, A64DOpcodeLoadStoreUnsignedImmediate),
+ OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointCompare),
+ OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing2Source),
+ OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing1Source),
+ OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingFixedPointConversions),
+ OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointIntegerConversions),
+};
+
+bool A64DOpcode::s_initialized = false;
+
+void A64DOpcode::init()
+{
+ if (s_initialized)
+ return;
+
+ OpcodeGroup* lastGroups[32];
+
+ for (unsigned i = 0; i < 32; i++) {
+ opcodeTable[i] = 0;
+ lastGroups[i] = 0;
+ }
+
+ for (unsigned i = 0; i < sizeof(opcodeGroupList) / sizeof(struct OpcodeGroupInitializer); i++) {
+ OpcodeGroup* newOpcodeGroup = new OpcodeGroup(opcodeGroupList[i].m_mask, opcodeGroupList[i].m_pattern, opcodeGroupList[i].m_format);
+ uint32_t opcodeGroupNumber = opcodeGroupList[i].m_opcodeGroupNumber;
+
+ if (!opcodeTable[opcodeGroupNumber])
+ opcodeTable[opcodeGroupNumber] = newOpcodeGroup;
+ else
+ lastGroups[opcodeGroupNumber]->setNext(newOpcodeGroup);
+ lastGroups[opcodeGroupNumber] = newOpcodeGroup;
+ }
+
+ s_initialized = true;
+}
+
+void A64DOpcode::setPCAndOpcode(uint32_t* newPC, uint32_t newOpcode)
+{
+ m_currentPC = newPC;
+ m_opcode = newOpcode;
+ m_bufferOffset = 0;
+ m_formatBuffer[0] = '\0';
+}
+
+const char* A64DOpcode::disassemble(uint32_t* currentPC)
+{
+ setPCAndOpcode(currentPC, *currentPC);
+
+ OpcodeGroup* opGroup = opcodeTable[opcodeGroupNumber(m_opcode)];
+
+ while (opGroup) {
+ if (opGroup->matches(m_opcode))
+ return opGroup->format(this);
+ opGroup = opGroup->next();
+ }
+
+ return A64DOpcode::format();
+}
+
+void A64DOpcode::bufferPrintf(const char* format, ...)
+{
+ if (m_bufferOffset >= bufferSize)
+ return;
+
+ va_list argList;
+ va_start(argList, format);
+
+ m_bufferOffset += vsnprintf(m_formatBuffer + m_bufferOffset, bufferSize - m_bufferOffset, format, argList);
+
+ va_end(argList);
+}
+
+const char* A64DOpcode::format()
+{
+ bufferPrintf(" .long %08x", m_opcode);
+ return m_formatBuffer;
+}
+
+void A64DOpcode::appendRegisterName(unsigned registerNumber, bool is64Bit)
+{
+ if (registerNumber == 29) {
+ bufferPrintf(is64Bit ? "fp" : "wfp");
+ return;
+ }
+
+ if (registerNumber == 30) {
+ bufferPrintf(is64Bit ? "lr" : "wlr");
+ return;
+ }
+
+ bufferPrintf("%c%u", is64Bit ? 'x' : 'w', registerNumber);
+}
+
+void A64DOpcode::appendFPRegisterName(unsigned registerNumber, unsigned registerSize)
+{
+ bufferPrintf("%c%u", FPRegisterPrefix(registerSize), registerNumber);
+}
+
+const char* const A64DOpcodeAddSubtract::s_opNames[4] = { "add", "adds", "sub", "subs" };
+
+const char* A64DOpcodeAddSubtractImmediate::format()
+{
+ if (isCMP())
+ appendInstructionName(cmpName());
+ else {
+ if (isMovSP())
+ appendInstructionName("mov");
+ else
+ appendInstructionName(opName());
+ appendSPOrRegisterName(rd(), is64Bit());
+ appendSeparator();
+ }
+ appendSPOrRegisterName(rn(), is64Bit());
+
+ if (!isMovSP()) {
+ appendSeparator();
+ appendUnsignedImmediate(immed12());
+ if (shift()) {
+ appendSeparator();
+ appendString(shift() == 1 ? "lsl" : "reserved");
+ }
+ }
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeAddSubtractExtendedRegister::format()
+{
+ if (immediate3() > 4)
+ return A64DOpcode::format();
+
+ if (isCMP())
+ appendInstructionName(cmpName());
+ else {
+ appendInstructionName(opName());
+ appendSPOrRegisterName(rd(), is64Bit());
+ appendSeparator();
+ }
+ appendSPOrRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendZROrRegisterName(rm(), is64Bit() && ((option() & 0x3) == 0x3));
+ appendSeparator();
+ if (option() == 0x2 && ((rd() == 31) || (rn() == 31)))
+ appendString("lsl");
+ else
+ appendString(optionName());
+ if (immediate3()) {
+ appendCharacter(' ');
+ appendUnsignedImmediate(immediate3());
+ }
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeAddSubtractShiftedRegister::format()
+{
+ if (!is64Bit() && immediate6() & 0x20)
+ return A64DOpcode::format();
+
+ if (shift() == 0x3)
+ return A64DOpcode::format();
+
+ if (isCMP())
+ appendInstructionName(cmpName());
+ else {
+ if (isNeg())
+ appendInstructionName(cmpName());
+ else
+ appendInstructionName(opName());
+ appendSPOrRegisterName(rd(), is64Bit());
+ appendSeparator();
+ }
+ if (!isNeg()) {
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ }
+ appendZROrRegisterName(rm(), is64Bit());
+ if (immediate6()) {
+ appendSeparator();
+ appendShiftType(shift());
+ appendUnsignedImmediate(immediate6());
+ }
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeBitfield::s_opNames[3] = { "sbfm", "bfm", "ubfm" };
+const char* const A64DOpcodeBitfield::s_extendPseudoOpNames[3][3] = {
+ { "sxtb", "sxth", "sxtw" }, { 0, 0, 0} , { "uxtb", "uxth", "uxtw" } };
+const char* const A64DOpcodeBitfield::s_insertOpNames[3] = { "sbfiz", "bfi", "ubfiz" };
+const char* const A64DOpcodeBitfield::s_extractOpNames[3] = { "sbfx", "bf", "ubfx" };
+
+const char* A64DOpcodeBitfield::format()
+{
+ if (opc() == 0x3)
+ return A64DOpcode::format();
+
+ if (is64Bit() != nBit())
+ return A64DOpcode::format();
+
+ if (!is64Bit() && ((immediateR() & 0x20) || (immediateS() & 0x20)))
+ return A64DOpcode::format();
+
+ if (!(opc() & 0x1) && !immediateR()) {
+ // [un]signed {btye,half-word,word} extend
+ bool isSTXType = false;
+ if (immediateS() == 7) {
+ appendInstructionName(extendPseudoOpNames(0));
+ isSTXType = true;
+ } else if (immediateS() == 15) {
+ appendInstructionName(extendPseudoOpNames(1));
+ isSTXType = true;
+ } else if (immediateS() == 31 && is64Bit()) {
+ appendInstructionName(extendPseudoOpNames(2));
+ isSTXType = true;
+ }
+
+ if (isSTXType) {
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), false);
+
+ return m_formatBuffer;
+ }
+ }
+
+ if (opc() == 0x2 && immediateS() == (immediateR() + 1)) {
+ // lsl
+ appendInstructionName("lsl");
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate((is64Bit() ? 63u : 31u) - immediateR());
+
+ return m_formatBuffer;
+ } else if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) {
+ // asr/lsr
+ appendInstructionName(!opc() ? "ars" : "lsr");
+
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate(immediateR());
+
+ return m_formatBuffer;
+ } else if (immediateS() < immediateR()) {
+ // bit field insert
+ appendInstructionName(insertOpNames());
+
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR());
+ appendSeparator();
+ appendUnsignedImmediate(immediateS() + 1);
+
+ return m_formatBuffer;
+ } else {
+ // bit field extract
+ appendInstructionName(extractOpNames());
+
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate(immediateR());
+ appendSeparator();
+ appendUnsignedImmediate(immediateS() - immediateR() + 1);
+
+ return m_formatBuffer;
+ }
+
+ appendInstructionName(opName());
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate(immediateR());
+ appendSeparator();
+ appendUnsignedImmediate(immediateS());
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeCompareAndBranchImmediate::format()
+{
+ appendInstructionName(opBit() ? "cbnz" : "cbz");
+ appendRegisterName(rt(), is64Bit());
+ appendSeparator();
+ appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate19()));
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeConditionalBranchImmediate::format()
+{
+ bufferPrintf(" b.%-5.5s", conditionName(condition()));
+ appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate19()));
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeConditionalSelect::s_opNames[4] = {
+ "csel", "csinc", "csinv", "csneg"
+};
+
+const char* A64DOpcodeConditionalSelect::format()
+{
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (op2() & 0x2)
+ return A64DOpcode::format();
+
+ if (rn() == rm() && (opNum() == 1 || opNum() == 2)) {
+ if (rn() == 31) {
+ appendInstructionName((opNum() == 1) ? "cset" : "csetm");
+ appendRegisterName(rd(), is64Bit());
+ } else {
+ appendInstructionName((opNum() == 1) ? "cinc" : "cinv");
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendZROrRegisterName(rn(), is64Bit());
+ }
+ appendSeparator();
+ appendString(conditionName(condition() ^ 0x1));
+
+ return m_formatBuffer;
+ }
+
+ appendInstructionName(opName());
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendZROrRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendZROrRegisterName(rm(), is64Bit());
+ appendSeparator();
+ appendString(conditionName(condition()));
+
+ return m_formatBuffer;
+
+}
+
+const char* const A64DOpcodeDataProcessing2Source::s_opNames[8] = {
+ 0, 0, "udiv", "sdiv", "lsl", "lsr", "asr", "ror" // We use the pseudo-op names for the shift/rotate instructions
+};
+
+const char* A64DOpcodeDataProcessing2Source::format()
+{
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (!(opCode() & 0x3e))
+ return A64DOpcode::format();
+
+ if (opCode() & 0x30)
+ return A64DOpcode::format();
+
+ if ((opCode() & 0x34) == 0x4)
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rm(), is64Bit());
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeDataProcessing3Source::s_opNames[16] = {
+ "madd", "msub", "smaddl", "smsubl", "smulh", 0, 0, 0,
+ 0, 0, "umaddl", "umsubl", "umulh", 0, 0, 0
+};
+
+const char* const A64DOpcodeDataProcessing3Source::s_pseudoOpNames[16] = {
+ "mul", "mneg", "smull", "smnegl", "smulh", 0, 0, 0,
+ 0, 0, "umull", "umnegl", "umulh", 0, 0, 0
+};
+
+const char* A64DOpcodeDataProcessing3Source::format()
+{
+ if (op54())
+ return A64DOpcode::format();
+
+ if (opNum() > 12)
+ return A64DOpcode::format();
+
+ if (!is64Bit() && opNum() > 1)
+ return A64DOpcode::format();
+
+ if (!opName())
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ bool srcOneAndTwoAre64Bit = is64Bit() & !(opNum() & 0x2);
+ appendRegisterName(rn(), srcOneAndTwoAre64Bit);
+ appendSeparator();
+ appendRegisterName(rm(), srcOneAndTwoAre64Bit);
+
+ if ((ra() != 31) || !(opNum() & 0x4)) {
+ appendSeparator();
+ appendRegisterName(ra(), is64Bit());
+ }
+
+ return m_formatBuffer;
+}
+
+const char* A64OpcodeExceptionGeneration::format()
+{
+ const char* opname = 0;
+ if (!op2()) {
+ switch (opc()) {
+ case 0x0: // SVC, HVC & SMC
+ switch (ll()) {
+ case 0x1:
+ opname = "svc";
+ break;
+ case 0x2:
+ opname = "hvc";
+ break;
+ case 0x3:
+ opname = "smc";
+ break;
+ }
+ break;
+ case 0x1: // BRK
+ if (!ll())
+ opname = "brk";
+ break;
+ case 0x2: // HLT
+ if (!ll())
+ opname = "hlt";
+ break;
+ case 0x5: // DPCS1-3
+ switch (ll()) {
+ case 0x1:
+ opname = "dpcs1";
+ break;
+ case 0x2:
+ opname = "dpcs2";
+ break;
+ case 0x3:
+ opname = "dpcs3";
+ break;
+ }
+ break;
+ }
+ }
+
+ if (!opname)
+ return A64DOpcode::format();
+
+ appendInstructionName(opname);
+ appendUnsignedImmediate(immediate16());
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeExtract::format()
+{
+ if (!op21() || !o0Bit())
+ return A64DOpcode::format();
+
+ if (is64Bit() != nBit())
+ return A64DOpcode::format();
+
+ if (is64Bit() && (immediateS() & 0x20))
+ return A64DOpcode::format();
+
+ const char* opName = (rn() == rm()) ? "ror" : "extr";
+
+ appendInstructionName(opName);
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rm(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate(immediateS());
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeFloatingPointCompare::format()
+{
+ if (mBit())
+ return A64DOpcode::format();
+
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (type() & 0x2)
+ return A64DOpcode::format();
+
+ if (op())
+ return A64DOpcode::format();
+
+ if (opCode2() & 0x7)
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ unsigned registerSize = type() + 2;
+ appendFPRegisterName(rn(), registerSize);
+ appendSeparator();
+ if (opCode2() & 0x8)
+ bufferPrintf("#0.0");
+ else
+ appendFPRegisterName(rm(), registerSize);
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeFloatingPointDataProcessing1Source::s_opNames[16] = {
+ "fmov", "fabs", "fneg", "fsqrt", "fcvt", "fcvt", 0, "fcvt",
+ "frintn", "frintp", "frintm", "frintz", "frinta", 0, "frintx", "frinti"
+};
+
+const char* A64DOpcodeFloatingPointDataProcessing1Source::format()
+{
+ if (mBit())
+ return A64DOpcode::format();
+
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (opNum() > 16)
+ return A64DOpcode::format();
+
+ switch (type()) {
+ case 0:
+ if ((opNum() == 0x4) || (opNum() == 0x6) || (opNum() == 0xd))
+ return A64DOpcode::format();
+ break;
+ case 1:
+ if ((opNum() == 0x5) || (opNum() == 0x6) || (opNum() == 0xd))
+ return A64DOpcode::format();
+ break;
+ case 2:
+ return A64DOpcode::format();
+ case 3:
+ if ((opNum() < 0x4) || (opNum() > 0x5))
+ return A64DOpcode::format();
+ break;
+ }
+
+ appendInstructionName(opName());
+ if ((opNum() >= 0x4) && (opNum() <= 0x7)) {
+ unsigned srcRegisterSize = type() ^ 0x2; // 0:s, 1:d & 3:h
+ unsigned destRegisterSize = (opNum() & 0x3) ^ 0x2;
+ appendFPRegisterName(rd(), destRegisterSize);
+ appendSeparator();
+ appendFPRegisterName(rn(), srcRegisterSize);
+ } else {
+ unsigned registerSize = type() + 2;
+ appendFPRegisterName(rd(), registerSize);
+ appendSeparator();
+ appendFPRegisterName(rn(), registerSize);
+ }
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeFloatingPointDataProcessing2Source::s_opNames[16] = {
+ "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul"
+};
+
+const char* A64DOpcodeFloatingPointDataProcessing2Source::format()
+{
+ if (mBit())
+ return A64DOpcode::format();
+
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (type() & 0x2)
+ return A64DOpcode::format();
+
+ if (opNum() > 8)
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ unsigned registerSize = type() + 2;
+ appendFPRegisterName(rd(), registerSize);
+ appendSeparator();
+ appendFPRegisterName(rn(), registerSize);
+ appendSeparator();
+ appendFPRegisterName(rm(), registerSize);
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeFloatingFixedPointConversions::s_opNames[4] = {
+ "fcvtzs", "fcvtzu", "scvtf", "ucvtf"
+};
+
+const char* A64DOpcodeFloatingFixedPointConversions::format()
+{
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (type() & 0x2)
+ return A64DOpcode::format();
+
+ if (opcode() & 0x4)
+ return A64DOpcode::format();
+
+ if (!(rmode() & 0x1) && !(opcode() & 0x6))
+ return A64DOpcode::format();
+
+ if ((rmode() & 0x1) && (opcode() & 0x6) == 0x2)
+ return A64DOpcode::format();
+
+ if (!(rmode() & 0x2) && !(opcode() & 0x6))
+ return A64DOpcode::format();
+
+ if ((rmode() & 0x2) && (opcode() & 0x6) == 0x2)
+ return A64DOpcode::format();
+
+ if (!is64Bit() && scale() >= 32)
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ unsigned FPRegisterSize = type() + 2;
+ bool destIsFP = !rmode();
+
+ if (destIsFP) {
+ appendFPRegisterName(rd(), FPRegisterSize);
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ } else {
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendFPRegisterName(rn(), FPRegisterSize);
+ }
+ appendSeparator();
+ appendUnsignedImmediate(64 - scale());
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeFloatingPointIntegerConversions::s_opNames[32] = {
+ "fcvtns", "fcvtnu", "scvtf", "ucvtf", "fcvtas", "fcvtau", "fmov", "fmov",
+ "fcvtps", "fcvtpu", 0, 0, 0, 0, "fmov", "fmov",
+ "fcvtms", "fcvtmu", 0, 0, 0, 0, 0, 0,
+ "fcvtzs", "fcvtzu", 0, 0, 0, 0, 0, 0
+};
+
+const char* A64DOpcodeFloatingPointIntegerConversions::format()
+{
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (type() == 0x3)
+ return A64DOpcode::format();
+
+ if (((rmode() & 0x1) || (rmode() & 0x2)) && (((opcode() & 0x6) == 0x2) || ((opcode() & 0x6) == 0x4)))
+ return A64DOpcode::format();
+
+ if ((type() == 0x2) && (!(opcode() & 0x4) || ((opcode() & 0x6) == 0x4)))
+ return A64DOpcode::format();
+
+ if (!type() && (rmode() & 0x1) && ((opcode() & 0x6) == 0x6))
+ return A64DOpcode::format();
+
+ if (is64Bit() && type() == 0x2 && ((opNum() & 0xe) == 0x6))
+ return A64DOpcode::format();
+
+ if (!opName())
+ return A64DOpcode::format();
+
+ if ((opNum() & 0x1e) == 0xe) {
+ // Handle fmov to/from upper half of quad separately
+ if (!is64Bit() || (type() != 0x2))
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ if (opcode() & 0x1) {
+ // fmov Vd.D[1], Xn
+ bufferPrintf("V%u.D[1]", rd());
+ appendSeparator();
+ appendRegisterName(rn());
+ } else {
+ // fmov Xd, Vn.D[1]
+ appendRegisterName(rd());
+ appendSeparator();
+ bufferPrintf("V%u.D[1]", rn());
+ }
+
+ return m_formatBuffer;
+ }
+
+ appendInstructionName(opName());
+ unsigned FPRegisterSize = type() + 2;
+ bool destIsFP = ((opNum() == 2) || (opNum() == 3) || (opNum() == 7));
+
+ if (destIsFP) {
+ appendFPRegisterName(rd(), FPRegisterSize);
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ } else {
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendFPRegisterName(rn(), FPRegisterSize);
+ }
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeHint::s_opNames[6] = {
+ "nop", "yield", "wfe", "wfi", "sev", "sevl"
+};
+
+const char* A64DOpcodeHint::format()
+{
+ appendInstructionName(opName());
+
+ if (immediate7() > 5)
+ appendUnsignedImmediate(immediate7());
+
+ return m_formatBuffer;
+}
+
+// A zero in an entry of the table means the instruction is Unallocated
+const char* const A64DOpcodeLoadStore::s_opNames[32] = {
+ "strb", "ldrb", "ldrsb", "ldrsb", "str", "ldr", "str", "ldr",
+ "strh", "ldrh", "ldrsh", "ldrsh", "str", "ldr", 0, 0,
+ "str", "ldr", "ldrsw", 0, "str", "ldr", 0, 0,
+ "str", "ldr", 0, 0, "str", "ldr", 0, 0
+};
+
+// A zero in an entry of the table means the instruction is Unallocated
+const char* const A64DOpcodeLoadStoreImmediate::s_unprivilegedOpNames[32] = {
+ "sttrb", "ldtrb", "ldtrsb", "ldtrsb", 0, 0, 0, 0,
+ "sttrh", "ldtrh", "ldtrsh", "ldtrsh", 0, 0, 0, 0,
+ "sttr", "ldtr", "ldtrsw", 0, 0, 0, 0, 0,
+ "sttr", "ldtr", 0, 0, 0, 0, 0, 0
+};
+
+// A zero in an entry of the table means the instruction is Unallocated
+const char* const A64DOpcodeLoadStoreImmediate::s_unscaledOpNames[32] = {
+ "sturb", "ldurb", "ldursb", "ldursb", "stur", "ldur", "stur", "ldur",
+ "sturh", "ldurh", "ldursh", "ldursh", "stur", "ldur", 0, 0,
+ "stur", "ldur", "ldursw", 0, "stur", "ldur", 0, 0,
+ "stur", "ldur", "prfum", 0, "stur", "ldur", 0, 0
+};
+
+const char* A64DOpcodeLoadStoreImmediate::format()
+{
+ const char* thisOpName;
+
+ if (type() & 0x1)
+ thisOpName = opName();
+ else if (!type())
+ thisOpName = unscaledOpName();
+ else
+ thisOpName = unprivilegedOpName();
+
+ if (!thisOpName)
+ return A64DOpcode::format();
+
+ appendInstructionName(thisOpName);
+ if (vBit())
+ appendFPRegisterName(rt(), size());
+ else
+ appendRegisterName(rt(), is64BitRT());
+ appendSeparator();
+ appendCharacter('[');
+ appendSPOrRegisterName(rn());
+
+ switch (type()) {
+ case 0: // Unscaled Immediate
+ if (immediate9()) {
+ appendSeparator();
+ appendSignedImmediate(immediate9());
+ }
+ appendCharacter(']');
+ break;
+ case 1: // Immediate Post-Indexed
+ appendCharacter(']');
+ if (immediate9()) {
+ appendSeparator();
+ appendSignedImmediate(immediate9());
+ }
+ break;
+ case 2: // Unprivileged
+ if (immediate9()) {
+ appendSeparator();
+ appendSignedImmediate(immediate9());
+ }
+ appendCharacter(']');
+ break;
+ case 3: // Immediate Pre-Indexed
+ if (immediate9()) {
+ appendSeparator();
+ appendSignedImmediate(immediate9());
+ }
+ appendCharacter(']');
+ appendCharacter('!');
+ break;
+ }
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeLoadStoreRegisterOffset::format()
+{
+ const char* thisOpName = opName();
+
+ if (!thisOpName)
+ return A64DOpcode::format();
+
+ if (!(option() & 0x2))
+ return A64DOpcode::format();
+
+ appendInstructionName(thisOpName);
+ unsigned scale;
+ if (vBit()) {
+ appendFPRegisterName(rt(), size());
+ scale = ((opc() & 2)<<1) | size();
+ } else {
+ appendRegisterName(rt(), is64BitRT());
+ scale = size();
+ }
+ appendSeparator();
+ appendCharacter('[');
+ appendSPOrRegisterName(rn());
+ appendSeparator();
+ appendZROrRegisterName(rm(), (option() & 0x3) == 0x3);
+
+ unsigned shift = sBit() ? scale : 0;
+
+ if (option() == 0x3) {
+ if (shift) {
+ appendSeparator();
+ appendString("lsl ");
+ appendUnsignedImmediate(shift);
+ }
+ } else {
+ appendSeparator();
+ appendString(optionName());
+ if (shift)
+ appendUnsignedImmediate(shift);
+ }
+
+ appendCharacter(']');
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeLoadStoreRegisterPair::opName()
+{
+ if (!vBit() && lBit() && size() == 0x1)
+ return "ldpsw";
+ if (lBit())
+ return "ldp";
+ return "stp";
+}
+
+const char* A64DOpcodeLoadStoreRegisterPair::format()
+{
+ const char* thisOpName = opName();
+
+ if (size() == 0x3)
+ return A64DOpcode::format();
+
+ if ((offsetMode() < 0x1) || (offsetMode() > 0x3))
+ return A64DOpcode::format();
+
+ if ((offsetMode() == 0x1) && !vBit() && !lBit())
+ return A64DOpcode::format();
+
+ appendInstructionName(thisOpName);
+ unsigned offsetShift;
+ if (vBit()) {
+ appendFPRegisterName(rt(), size());
+ appendSeparator();
+ appendFPRegisterName(rt2(), size());
+ offsetShift = size() + 2;
+ } else {
+ appendRegisterName(rt(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rt2(), is64Bit());
+ offsetShift = (size() >> 1) + 2;
+ }
+
+ appendSeparator();
+ appendCharacter('[');
+ appendSPOrRegisterName(rn());
+
+ int offset = immediate7() << offsetShift;
+
+ if (offsetMode() == 1) {
+ appendCharacter(']');
+ appendSeparator();
+ appendSignedImmediate(offset);
+ } else {
+ appendSeparator();
+ appendSignedImmediate(offset);
+ appendCharacter(']');
+ if (offsetMode() == 0x3)
+ appendCharacter('!');
+ }
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeLoadStoreUnsignedImmediate::format()
+{
+ const char* thisOpName = opName();
+
+ if (!thisOpName)
+ return A64DOpcode::format();
+
+ appendInstructionName(thisOpName);
+ unsigned scale;
+ if (vBit()) {
+ appendFPRegisterName(rt(), size());
+ scale = ((opc() & 2)<<1) | size();
+ } else {
+ appendRegisterName(rt(), is64BitRT());
+ scale = size();
+ }
+ appendSeparator();
+ appendCharacter('[');
+ appendSPOrRegisterName(rn());
+
+ if (immediate12()) {
+ appendSeparator();
+ appendUnsignedImmediate(immediate12() << scale);
+ }
+
+ appendCharacter(']');
+
+ return m_formatBuffer;
+}
+
+// A zero in an entry of the table means the instruction is Unallocated
+const char* const A64DOpcodeLogical::s_opNames[8] = {
+ "and", "bic", "orr", "orn", "eor", "eon", "ands", "bics"
+};
+
+const char* A64DOpcodeLogicalShiftedRegister::format()
+{
+ if (!is64Bit() && immediate6() & 0x20)
+ return A64DOpcode::format();
+
+ if (isTst())
+ appendInstructionName("tst");
+ else {
+ if (isMov())
+ appendInstructionName("mov");
+ else
+ appendInstructionName(opName(opNumber()));
+ appendSPOrRegisterName(rd(), is64Bit());
+ appendSeparator();
+ }
+
+ if (!isMov()) {
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ }
+
+ appendZROrRegisterName(rm(), is64Bit());
+ if (immediate6()) {
+ appendSeparator();
+ appendShiftType(shift());
+ appendUnsignedImmediate(immediate6());
+ }
+
+ return m_formatBuffer;
+}
+
+static unsigned highestBitSet(unsigned value)
+{
+ unsigned result = 0;
+
+ while (value >>= 1)
+ result++;
+
+ return result;
+}
+
+static uint64_t rotateRight(uint64_t value, unsigned width, unsigned shift)
+{
+ uint64_t result = value;
+
+ if (shift)
+ result = (value >> (shift % width)) | (value << (width - shift));
+
+ return result;
+}
+
+static uint64_t replicate(uint64_t value, unsigned width)
+{
+ uint64_t result = 0;
+
+ for (unsigned totalBits = 0; totalBits < 64; totalBits += width)
+ result = (result << width) | value;
+
+ return result;
+}
+
+const char* A64DOpcodeLogicalImmediate::format()
+{
+ if (!is64Bit() && nBit())
+ return A64DOpcode::format();
+
+ unsigned len = highestBitSet(nBit() << 6 | (immediateS() ^ 0x3f));
+ unsigned levels = (1 << len) - 1; // len number of 1 bits starting at LSB
+
+ if ((immediateS() & levels) == levels)
+ return A64DOpcode::format();
+
+ unsigned r = immediateR() & levels;
+ unsigned s = immediateS() & levels;
+ unsigned eSize = 1 << len;
+ uint64_t pattern = rotateRight((1ull << (s + 1)) - 1, eSize, r);
+
+ uint64_t immediate = replicate(pattern, eSize);
+
+ if (!is64Bit())
+ immediate &= 0xffffffffull;
+
+ if (isTst())
+ appendInstructionName("tst");
+ else {
+ if (isMov())
+ appendInstructionName("mov");
+ else
+ appendInstructionName(opName(opNumber()));
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ }
+ if (!isMov()) {
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ }
+ appendUnsignedImmediate64(immediate);
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeMoveWide::s_opNames[4] = { "movn", "", "movz", "movk" };
+
+const char* A64DOpcodeMoveWide::format()
+{
+ if (opc() == 1)
+ return A64DOpcode::format();
+ if (!size() && hw() >= 2)
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate(immediate16());
+ if (hw()) {
+ appendSeparator();
+ appendShiftAmount(hw());
+ }
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeTestAndBranchImmediate::format()
+{
+ appendInstructionName(opBit() ? "tbnz" : "tbz");
+ appendRegisterName(rt());
+ appendSeparator();
+ appendUnsignedImmediate(bitNumber());
+ appendSeparator();
+ appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate14()));
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeUnconditionalBranchImmediate::format()
+{
+ appendInstructionName(op() ? "bl" : "b");
+ appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate26()));
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeUnconditionalBranchRegister::s_opNames[8] = { "br", "blr", "ret", "", "eret", "drps", "", "" };
+
+const char* A64DOpcodeUnconditionalBranchRegister::format()
+{
+ unsigned opcValue = opc();
+ if (opcValue == 3 || opcValue > 5)
+ return A64DOpcode::format();
+ if (((opcValue & 0xe) == 0x4) && rn() != 0x1f)
+ return A64DOpcode::format();
+ appendInstructionName(opName());
+ if (opcValue <= 2)
+ appendRegisterName(rn());
+ return m_formatBuffer;
+}
+
+} } // namespace JSC::ARM64Disassembler
+
+#endif // USE(ARM64_DISASSEMBLER)
diff --git a/src/3rdparty/masm/disassembler/ARM64/A64DOpcode.h b/src/3rdparty/masm/disassembler/ARM64/A64DOpcode.h
new file mode 100644
index 0000000000..5bb7db9f12
--- /dev/null
+++ b/src/3rdparty/masm/disassembler/ARM64/A64DOpcode.h
@@ -0,0 +1,708 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef A64DOpcode_h
+#define A64DOpcode_h
+
+#include <wtf/Assertions.h>
+#include <stdint.h>
+
+namespace JSC { namespace ARM64Disassembler {
+
+class A64DOpcode {
+private:
+ class OpcodeGroup {
+ public:
+ OpcodeGroup(uint32_t opcodeMask, uint32_t opcodePattern, const char* (*format)(A64DOpcode*))
+ : m_opcodeMask(opcodeMask)
+ , m_opcodePattern(opcodePattern)
+ , m_format(format)
+ , m_next(0)
+ {
+ }
+
+ void setNext(OpcodeGroup* next)
+ {
+ m_next = next;
+ }
+
+ OpcodeGroup* next()
+ {
+ return m_next;
+ }
+
+ bool matches(uint32_t opcode)
+ {
+ return (opcode & m_opcodeMask) == m_opcodePattern;
+ }
+
+ const char* format(A64DOpcode* thisObj)
+ {
+ return m_format(thisObj);
+ }
+
+ private:
+ uint32_t m_opcodeMask;
+ uint32_t m_opcodePattern;
+ const char* (*m_format)(A64DOpcode*);
+ OpcodeGroup* m_next;
+ };
+
+public:
+ static void init();
+
+ A64DOpcode()
+ : m_opcode(0)
+ , m_bufferOffset(0)
+ {
+ init();
+ m_formatBuffer[0] = '\0';
+ }
+
+ const char* disassemble(uint32_t* currentPC);
+
+protected:
+ void setPCAndOpcode(uint32_t*, uint32_t);
+ const char* format();
+
+ static const char* const s_conditionNames[16];
+ static const char* const s_shiftNames[4];
+ static const char* const s_optionName[8];
+ static const char s_FPRegisterPrefix[5];
+
+ static const char* conditionName(unsigned condition) { return s_conditionNames[condition & 0xf]; }
+ static const char* shiftName(unsigned shiftValue) { return s_shiftNames[shiftValue & 0x3]; }
+ const char* optionName() { return s_optionName[option()]; }
+ static char FPRegisterPrefix(unsigned FPRegisterSize)
+ {
+ if (FPRegisterSize > 4)
+ FPRegisterSize = 4;
+ return s_FPRegisterPrefix[FPRegisterSize];
+ }
+
+ unsigned opcodeGroupNumber(uint32_t opcode) { return (opcode >> 24) & 0x1f; }
+
+ bool is64Bit() { return m_opcode & 0x80000000; }
+ unsigned size() { return m_opcode >> 30; }
+ unsigned option() { return (m_opcode >> 13) & 0x7; }
+ unsigned rd() { return m_opcode & 0x1f; }
+ unsigned rt() { return m_opcode & 0x1f; }
+ unsigned rn() { return (m_opcode >> 5) & 0x1f; }
+ unsigned rm() { return (m_opcode >> 16) & 0x1f; }
+
+ void bufferPrintf(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
+
+ void appendInstructionName(const char* instructionName)
+ {
+ bufferPrintf(" %-7.7s", instructionName);
+ }
+
+ void appendRegisterName(unsigned registerNumber, bool is64Bit = true);
+ void appendSPOrRegisterName(unsigned registerNumber, bool is64Bit = true)
+ {
+ if (registerNumber == 31) {
+ bufferPrintf(is64Bit ? "sp" : "wsp");
+ return;
+ }
+ appendRegisterName(registerNumber, is64Bit);
+ }
+
+ void appendZROrRegisterName(unsigned registerNumber, bool is64Bit = true)
+ {
+ if (registerNumber == 31) {
+ bufferPrintf(is64Bit ? "xzr" : "wzr");
+ return;
+ }
+ appendRegisterName(registerNumber, is64Bit);
+ }
+
+ void appendFPRegisterName(unsigned registerNumber, unsigned registerSize);
+
+ void appendSeparator()
+ {
+ bufferPrintf(", ");
+ }
+
+ void appendCharacter(const char c)
+ {
+ bufferPrintf("%c", c);
+ }
+
+ void appendString(const char* string)
+ {
+ bufferPrintf("%s", string);
+ }
+
+ void appendShiftType(unsigned shiftValue)
+ {
+ bufferPrintf("%s ", shiftName(shiftValue));
+ }
+
+ void appendSignedImmediate(int immediate)
+ {
+ bufferPrintf("#%d", immediate);
+ }
+
+ void appendUnsignedImmediate(unsigned immediate)
+ {
+ bufferPrintf("#%u", immediate);
+ }
+
+ void appendUnsignedImmediate64(uint64_t immediate)
+ {
+ bufferPrintf("#0x%" PRIx64, immediate);
+ }
+
+ void appendPCRelativeOffset(uint32_t* pc, int32_t immediate)
+ {
+ bufferPrintf("0x%" PRIx64, reinterpret_cast<uint64_t>(pc + immediate));
+ }
+
+ void appendShiftAmount(unsigned amount)
+ {
+ bufferPrintf("lsl #%u", 16 * amount);
+ }
+
+ static const int bufferSize = 81;
+
+ char m_formatBuffer[bufferSize];
+ uint32_t* m_currentPC;
+ uint32_t m_opcode;
+ int m_bufferOffset;
+
+private:
+ static OpcodeGroup* opcodeTable[32];
+
+ static bool s_initialized;
+};
+
+#define DEFINE_STATIC_FORMAT(klass, thisObj) \
+ static const char* format(A64DOpcode* thisObj) { return reinterpret_cast< klass *>(thisObj)->format(); }
+
+class A64DOpcodeAddSubtract : public A64DOpcode {
+private:
+ static const char* const s_opNames[4];
+
+public:
+ const char* opName() { return s_opNames[opAndS()]; }
+ const char* cmpName() { return op() ? "cmp" : "cmn"; }
+
+ bool isCMP() { return (sBit() && rd() == 31); }
+ unsigned op() { return (m_opcode >> 30) & 0x1; }
+ unsigned sBit() { return (m_opcode >> 29) & 0x1; }
+ unsigned opAndS() { return (m_opcode >> 29) & 0x3; }
+};
+
+class A64DOpcodeAddSubtractImmediate : public A64DOpcodeAddSubtract {
+public:
+ static const uint32_t mask = 0x1f000000;
+ static const uint32_t pattern = 0x11000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractImmediate, thisObj);
+
+ const char* format();
+
+ bool isMovSP() { return (!opAndS() && !immed12() && ((rd() == 31) || rn() == 31)); }
+ unsigned shift() { return (m_opcode >> 22) & 0x3; }
+ unsigned immed12() { return (m_opcode >> 10) & 0xfff; }
+};
+
+class A64DOpcodeAddSubtractExtendedRegister : public A64DOpcodeAddSubtract {
+public:
+ static const uint32_t mask = 0x1fe00000;
+ static const uint32_t pattern = 0x0b200000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractExtendedRegister, thisObj);
+
+ const char* format();
+
+ unsigned immediate3() { return (m_opcode >> 10) & 0x7; }
+};
+
+class A64DOpcodeAddSubtractShiftedRegister : public A64DOpcodeAddSubtract {
+public:
+ static const uint32_t mask = 0x1f200000;
+ static const uint32_t pattern = 0x0b000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractShiftedRegister, thisObj);
+
+ const char* format();
+
+ bool isNeg() { return (op() && rn() == 31); }
+ const char* negName() { return sBit() ? "negs" : "neg"; }
+ unsigned shift() { return (m_opcode >> 22) & 0x3; }
+ int immediate6() { return (static_cast<int>((m_opcode >> 10) & 0x3f) << 26) >> 26; }
+};
+
+class A64DOpcodeBitfield : public A64DOpcode {
+private:
+ static const char* const s_opNames[3];
+ static const char* const s_extendPseudoOpNames[3][3];
+ static const char* const s_insertOpNames[3];
+ static const char* const s_extractOpNames[3];
+
+public:
+ static const uint32_t mask = 0x1f800000;
+ static const uint32_t pattern = 0x13000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeBitfield, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opc()]; }
+ const char* extendPseudoOpNames(unsigned opSize) { return s_extendPseudoOpNames[opc()][opSize]; }
+ const char* insertOpNames() { return s_insertOpNames[opc()]; }
+ const char* extractOpNames() { return s_extractOpNames[opc()]; }
+
+ unsigned opc() { return (m_opcode >> 29) & 0x3; }
+ unsigned nBit() { return (m_opcode >> 22) & 0x1; }
+ unsigned immediateR() { return (m_opcode >> 16) & 0x3f; }
+ unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
+};
+
+class A64DOpcodeCompareAndBranchImmediate : public A64DOpcode {
+public:
+ static const uint32_t mask = 0x7e000000;
+ static const uint32_t pattern = 0x34000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeCompareAndBranchImmediate, thisObj);
+
+ const char* format();
+
+ unsigned opBit() { return (m_opcode >> 24) & 0x1; }
+ int immediate19() { return (static_cast<int>((m_opcode >> 5) & 0x7ffff) << 13) >> 13; }
+};
+
+class A64DOpcodeConditionalBranchImmediate : public A64DOpcode {
+public:
+ static const uint32_t mask = 0xff000010;
+ static const uint32_t pattern = 0x54000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeConditionalBranchImmediate, thisObj);
+
+ const char* format();
+
+ unsigned condition() { return m_opcode & 0xf; }
+ int immediate19() { return (static_cast<int>((m_opcode >> 5) & 0x7ffff) << 13) >> 13; }
+};
+
+class A64DOpcodeConditionalSelect : public A64DOpcode {
+private:
+ static const char* const s_opNames[4];
+
+public:
+ static const uint32_t mask = 0x1fe00010;
+ static const uint32_t pattern = 0x1a800000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeConditionalSelect, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+ unsigned opNum() { return (op() << 1 | (op2() & 0x1)); }
+ unsigned op() { return (m_opcode >> 30) & 0x1; }
+ unsigned sBit() { return (m_opcode >> 29) & 0x1; }
+ unsigned condition() { return (m_opcode >> 12) & 0xf; }
+ unsigned op2() { return (m_opcode >> 10) & 0x3; }
+};
+
+class A64DOpcodeDataProcessing2Source : public A64DOpcode {
+private:
+ static const char* const s_opNames[8];
+
+public:
+ static const uint32_t mask = 0x5fe00000;
+ static const uint32_t pattern = 0x1ac00000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing2Source, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNameIndex()]; }
+ unsigned sBit() { return (m_opcode >> 29) & 0x1; }
+ unsigned opCode() { return (m_opcode >> 10) & 0x3f; }
+ unsigned opNameIndex() { return ((m_opcode >> 11) & 0x4) | ((m_opcode >> 10) & 0x3); }
+};
+
+class A64DOpcodeDataProcessing3Source : public A64DOpcode {
+private:
+ static const char* const s_opNames[16];
+ static const char* const s_pseudoOpNames[16];
+
+public:
+ static const uint32_t mask = 0x1f000000;
+ static const uint32_t pattern = 0x1b000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing3Source, thisObj);
+
+ const char* format();
+
+ const char* opName() { return ra() == 31 ? s_opNames[opNum() & 0xf] : s_pseudoOpNames[opNum() & 0xf]; }
+ unsigned ra() { return (m_opcode >> 10) & 0x1f; }
+ unsigned op54() { return (m_opcode >> 29) & 0x3; }
+ unsigned op31() { return (m_opcode >> 21) & 0x7; }
+ unsigned op0() { return (m_opcode >> 15) & 0x1; }
+ unsigned opNum() { return ((m_opcode >> 25) & 0x30) | ((m_opcode >> 20) & 0xe) | ((m_opcode >> 15) & 0x1); }
+};
+
+class A64OpcodeExceptionGeneration : public A64DOpcode {
+public:
+ static const uint32_t mask = 0xff000010;
+ static const uint32_t pattern = 0xd4000000;
+
+ DEFINE_STATIC_FORMAT(A64OpcodeExceptionGeneration, thisObj);
+
+ const char* format();
+
+ unsigned opc() { return (m_opcode>>21) & 0x7; }
+ unsigned op2() { return (m_opcode>>2) & 0x7; }
+ unsigned ll() { return m_opcode & 0x3; }
+ int immediate16() { return (static_cast<int>((m_opcode >> 5) & 0xffff) << 16) >> 16; }
+};
+
+class A64DOpcodeExtract : public A64DOpcode {
+public:
+ static const uint32_t mask = 0x1f800000;
+ static const uint32_t pattern = 0x13800000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeExtract, thisObj);
+
+ const char* format();
+
+ unsigned op21() { return (m_opcode >> 29) & 0x3; }
+ unsigned nBit() { return (m_opcode >> 22) & 0x1; }
+ unsigned o0Bit() { return (m_opcode >> 21) & 0x1; }
+ unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
+};
+
+class A64DOpcodeFloatingPointOps : public A64DOpcode {
+public:
+ unsigned mBit() { return (m_opcode >> 31) & 0x1; }
+ unsigned sBit() { return (m_opcode >> 29) & 0x1; }
+ unsigned type() { return (m_opcode >> 22) & 0x3; }
+};
+
+class A64DOpcodeFloatingPointCompare : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[16];
+
+public:
+ static const uint32_t mask = 0x5f203c00;
+ static const uint32_t pattern = 0x1e202000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointCompare, thisObj);
+
+ const char* format();
+
+ const char* opName() { return (opNum() & 0x2) ? "fcmpe" : "fcmp"; }
+
+ unsigned op() { return (m_opcode >> 14) & 0x3; }
+ unsigned opCode2() { return m_opcode & 0x1f; }
+ unsigned opNum() { return (m_opcode >> 3) & 0x3; }
+};
+
+class A64DOpcodeFloatingPointDataProcessing1Source : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[16];
+
+public:
+ static const uint32_t mask = 0x5f207c00;
+ static const uint32_t pattern = 0x1e204000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointDataProcessing1Source, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+
+ unsigned opNum() { return (m_opcode >> 15) & 0x3f; }
+};
+
+class A64DOpcodeFloatingPointDataProcessing2Source : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[16];
+
+public:
+ static const uint32_t mask = 0x5f200800;
+ static const uint32_t pattern = 0x1e200800;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointDataProcessing2Source, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+
+ unsigned opNum() { return (m_opcode >> 12) & 0xf; }
+};
+
+class A64DOpcodeFloatingFixedPointConversions : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[4];
+
+public:
+ static const uint32_t mask = 0x5f200000;
+ static const uint32_t pattern = 0x1e000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingFixedPointConversions, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+ unsigned rmode() { return (m_opcode >> 19) & 0x3; }
+ unsigned opcode() { return (m_opcode >> 16) & 0x7; }
+ unsigned scale() { return (m_opcode >> 10) & 0x3f; }
+ unsigned opNum() { return (m_opcode >> 16) & 0x3; }
+};
+
+class A64DOpcodeFloatingPointIntegerConversions : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[32];
+
+public:
+ static const uint32_t mask = 0x5f20fc00;
+ static const uint32_t pattern = 0x1e200000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointIntegerConversions, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+ unsigned rmode() { return (m_opcode >> 19) & 0x3; }
+ unsigned opcode() { return (m_opcode >> 16) & 0x7; }
+ unsigned opNum() { return (m_opcode >> 16) & 0x1f; }
+};
+
+class A64DOpcodeHint : public A64DOpcode {
+private:
+ static const char* const s_opNames[6];
+
+public:
+ static const uint32_t mask = 0xfffff01f;
+ static const uint32_t pattern = 0xd503201f;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeHint, thisObj);
+
+ const char* format();
+
+ const char* opName() { return immediate7() <= 5 ? s_opNames[immediate7()] : "hint"; }
+ unsigned immediate7() { return (m_opcode >> 5) & 0x7f; }
+};
+
+class A64DOpcodeLoadStore : public A64DOpcode {
+private:
+ static const char* const s_opNames[32];
+
+protected:
+ const char* opName()
+ {
+ return s_opNames[opNumber()];
+ }
+
+ unsigned size() { return (m_opcode >> 30) & 0x3; }
+ unsigned vBit() { return (m_opcode >> 26) & 0x1; }
+ unsigned opc() { return (m_opcode >> 22) & 0x3; }
+ unsigned opNumber() { return (size() <<3 ) | (vBit() << 2) | opc(); }
+ bool is64BitRT() { return ((opNumber() & 0x17) == 0x02) || ((opNumber() & 0x1e) == 0x18); }
+};
+
+class A64DOpcodeLoadStoreImmediate : public A64DOpcodeLoadStore {
+private:
+ static const char* const s_unprivilegedOpNames[32];
+ static const char* const s_unscaledOpNames[32];
+
+public:
+ static const uint32_t mask = 0x3b200000;
+ static const uint32_t pattern = 0x38000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreImmediate, thisObj);
+
+ const char* format();
+
+ const char* unprivilegedOpName()
+ {
+ return s_unprivilegedOpNames[opNumber()];
+ }
+ const char* unscaledOpName()
+ {
+ return s_unscaledOpNames[opNumber()];
+ }
+ unsigned type() { return (m_opcode >> 10) & 0x3; }
+ int immediate9() { return (static_cast<int>((m_opcode >> 12) & 0x1ff) << 23) >> 23; }
+};
+
+class A64DOpcodeLoadStoreRegisterOffset : public A64DOpcodeLoadStore {
+public:
+ static const uint32_t mask = 0x3b200c00;
+ static const uint32_t pattern = 0x38200800;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterOffset, thisObj);
+
+ const char* format();
+
+ unsigned option() { return (m_opcode >> 13) & 0x7; }
+ int sBit() { return (m_opcode >> 12) & 0x1; }
+};
+
+class A64DOpcodeLoadStoreRegisterPair : public A64DOpcodeLoadStore {
+public:
+ static const uint32_t mask = 0x3a000000;
+ static const uint32_t pattern = 0x28000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterPair, thisObj);
+
+ const char* format();
+ const char* opName();
+
+ unsigned rt2() { return (m_opcode >> 10) & 0x1f; }
+ int immediate7() { return (static_cast<int>((m_opcode >> 15) & 0x7f) << 25) >> 25; }
+ unsigned offsetMode() { return (m_opcode >> 23) & 0x7; }
+ int lBit() { return (m_opcode >> 22) & 0x1; }
+};
+
+class A64DOpcodeLoadStoreUnsignedImmediate : public A64DOpcodeLoadStore {
+public:
+ static const uint32_t mask = 0x3b000000;
+ static const uint32_t pattern = 0x39000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreUnsignedImmediate, thisObj);
+
+ const char* format();
+
+ unsigned immediate12() { return (m_opcode >> 10) & 0xfff; }
+};
+
+class A64DOpcodeLogical : public A64DOpcode {
+private:
+ static const char* const s_opNames[8];
+
+public:
+ const char* opName(unsigned opNumber)
+ {
+ return s_opNames[opNumber & 0x7];
+ }
+
+ unsigned opc() { return (m_opcode >> 29) & 0x3; }
+ unsigned nBit() { return (m_opcode >> 21) & 0x1; }
+};
+
+class A64DOpcodeLogicalImmediate : public A64DOpcodeLogical {
+public:
+ static const uint32_t mask = 0x1f800000;
+ static const uint32_t pattern = 0x12000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLogicalImmediate, thisObj);
+
+ const char* format();
+
+ bool isTst() { return ((opNumber() == 6) && (rd() == 31)); }
+ bool isMov() { return ((opNumber() == 2) && (rn() == 31)); }
+ unsigned opNumber() { return opc() << 1; }
+ unsigned nBit() { return (m_opcode >> 22) & 0x1; }
+ unsigned immediateR() { return (m_opcode >> 16) & 0x3f; }
+ unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
+};
+
+class A64DOpcodeLogicalShiftedRegister : public A64DOpcodeLogical {
+public:
+ static const uint32_t mask = 0x1f000000;
+ static const uint32_t pattern = 0x0a000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLogicalShiftedRegister, thisObj);
+
+ const char* format();
+
+ bool isTst() { return ((opNumber() == 6) && (rd() == 31)); }
+ bool isMov() { return ((opNumber() == 2) && (rn() == 31)); }
+ unsigned opNumber() { return (opc() << 1) | nBit(); }
+ unsigned shift() { return (m_opcode >> 22) & 0x3; }
+ int immediate6() { return (static_cast<int>((m_opcode >> 10) & 0x3f) << 26) >> 26; }
+};
+
+class A64DOpcodeMoveWide : public A64DOpcode {
+private:
+ static const char* const s_opNames[4];
+
+public:
+ static const uint32_t mask = 0x1f800000;
+ static const uint32_t pattern = 0x12800000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeMoveWide, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opc()]; }
+ unsigned opc() { return (m_opcode >> 29) & 0x3; }
+ unsigned hw() { return (m_opcode >> 21) & 0x3; }
+ unsigned immediate16() { return (m_opcode >> 5) & 0xffff; }
+};
+
+class A64DOpcodeTestAndBranchImmediate : public A64DOpcode {
+public:
+ static const uint32_t mask = 0x7e000000;
+ static const uint32_t pattern = 0x36000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeTestAndBranchImmediate, thisObj);
+
+ const char* format();
+
+ unsigned bitNumber() { return ((m_opcode >> 26) & 0x20) | ((m_opcode >> 19) & 0x1f); }
+ unsigned opBit() { return (m_opcode >> 24) & 0x1; }
+ int immediate14() { return (static_cast<int>((m_opcode >> 5) & 0x3fff) << 18) >> 18; }
+};
+
+class A64DOpcodeUnconditionalBranchImmediate : public A64DOpcode {
+public:
+ static const uint32_t mask = 0x7c000000;
+ static const uint32_t pattern = 0x14000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeUnconditionalBranchImmediate, thisObj);
+
+ const char* format();
+
+ unsigned op() { return (m_opcode >> 31) & 0x1; }
+ int immediate26() { return (static_cast<int>(m_opcode & 0x3ffffff) << 6) >> 6; }
+};
+
+class A64DOpcodeUnconditionalBranchRegister : public A64DOpcode {
+private:
+ static const char* const s_opNames[8];
+
+public:
+ static const uint32_t mask = 0xfe1ffc1f;
+ static const uint32_t pattern = 0xd61f0000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeUnconditionalBranchRegister, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opc()]; }
+ unsigned opc() { return (m_opcode >> 21) & 0xf; }
+};
+
+} } // namespace JSC::ARM64Disassembler
+
+using JSC::ARM64Disassembler::A64DOpcode;
+
+#endif // A64DOpcode_h
diff --git a/src/3rdparty/masm/disassembler/ARM64Disassembler.cpp b/src/3rdparty/masm/disassembler/ARM64Disassembler.cpp
new file mode 100644
index 0000000000..27ae4b96d0
--- /dev/null
+++ b/src/3rdparty/masm/disassembler/ARM64Disassembler.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __STDC_FORMAT_MACROS
+#include "config.h"
+#include "Disassembler.h"
+
+#if USE(ARM64_DISASSEMBLER) && CPU(ARM64)
+
+#include "ARM64/A64DOpcode.h"
+#include "MacroAssemblerCodeRef.h"
+
+namespace JSC {
+
+bool tryToDisassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out)
+{
+ A64DOpcode arm64Opcode;
+
+ uint32_t* currentPC = reinterpret_cast<uint32_t*>(codePtr.executableAddress());
+ size_t byteCount = size;
+
+ while (byteCount) {
+ char pcString[20];
+ snprintf(pcString, sizeof(pcString), "0x%lx", reinterpret_cast<unsigned long>(currentPC));
+ out.printf("%s%16s: %s\n", prefix, pcString, arm64Opcode.disassemble(currentPC));
+ currentPC++;
+ byteCount -= sizeof(uint32_t);
+ }
+
+ return true;
+}
+
+} // namespace JSC
+
+#endif // USE(ARM64_DISASSEMBLER)
+
+#if USE(LLVM_DISASSEMBLER) && CPU(ARM64)
+
+#include "LLVMDisassembler.h"
+
+namespace JSC {
+
+bool tryToDisassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out, InstructionSubsetHint hint)
+{
+ return tryToDisassembleWithLLVM(codePtr, size, prefix, out, hint);
+}
+
+} // namespace JSC
+
+#endif // USE(LLVM_DISASSEMBLER) && CPU(ARM64)
diff --git a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
index d9afdd447a..6af71e523b 100644
--- a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
+++ b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
@@ -1623,6 +1623,8 @@ const char* ARMv7DOpcodeVCVT::format()
default:
n1 = "vcvt.?";
n2 = ".?";
+ dregPrefix = '?';
+ mregPrefix = '?';
break;
}
diff --git a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
index 051d05525a..03e0ba21c4 100644
--- a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
+++ b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
@@ -127,7 +127,7 @@ protected:
void appendPCRelativeOffset(int32_t immediate)
{
- bufferPrintf("0x%x", reinterpret_cast<uint32_t>(m_currentPC + immediate));
+ bufferPrintf("%p", m_currentPC + immediate);
}
void appendShiftAmount(unsigned amount)
diff --git a/src/3rdparty/masm/disassembler/ARMv7Disassembler.cpp b/src/3rdparty/masm/disassembler/ARMv7Disassembler.cpp
index bfb48953c0..dee017525d 100644
--- a/src/3rdparty/masm/disassembler/ARMv7Disassembler.cpp
+++ b/src/3rdparty/masm/disassembler/ARMv7Disassembler.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "Disassembler.h"
-#if USE(ARMV7_DISASSEMBLER)
+#if USE(ARMV7_DISASSEMBLER) && CPU(ARM_THUMB2)
#include "ARMv7/ARMv7DOpcode.h"
#include "MacroAssemblerCodeRef.h"
diff --git a/src/3rdparty/masm/masm-defs.pri b/src/3rdparty/masm/masm-defs.pri
index f09a8329c9..c4c7d3ce9a 100644
--- a/src/3rdparty/masm/masm-defs.pri
+++ b/src/3rdparty/masm/masm-defs.pri
@@ -1,6 +1,5 @@
-
-
DEFINES += WTF_EXPORT_PRIVATE="" JS_EXPORT_PRIVATE=""
+DEFINES += ENABLE_ASSEMBLER_WX_EXCLUSIVE=1
# Avoid symbol clashes with QtScript during static linking
DEFINES += WTFReportAssertionFailure=qmlWTFReportAssertionFailure
@@ -25,12 +24,16 @@ INCLUDEPATH += $$PWD
disassembler {
if(isEqual(QT_ARCH, "i386")|isEqual(QT_ARCH, "x86_64")): DEFINES += WTF_USE_UDIS86=1
- if(isEqual(QT_ARCH, "arm")): DEFINES += WTF_USE_ARMV7_DISASSEMBLER=1
+ if(isEqual(QT_ARCH, "arm")): DEFINES += WTF_USE_ARMV7_DISASSEMBLER=1 WTF_USE_ARM64_DISASSEMBLER=1
if(isEqual(QT_ARCH, "mips")): DEFINES += WTF_USE_MIPS32_DISASSEMBLER=1
} else {
DEFINES += WTF_USE_UDIS86=0
}
+force-compile-jit {
+ DEFINES += V4_FORCE_COMPILE_JIT
+}
+
INCLUDEPATH += $$PWD/disassembler
INCLUDEPATH += $$PWD/disassembler/udis86
INCLUDEPATH += $$_OUT_PWD
diff --git a/src/3rdparty/masm/masm.pri b/src/3rdparty/masm/masm.pri
index 04548fe8a3..afa1438974 100644
--- a/src/3rdparty/masm/masm.pri
+++ b/src/3rdparty/masm/masm.pri
@@ -62,6 +62,9 @@ HEADERS += $$PWD/disassembler/ARMv7/ARMv7DOpcode.h
SOURCES += $$PWD/disassembler/Mips32Disassembler.cpp
SOURCES += $$PWD/disassembler/mips32/Mips32Opcode.cpp
HEADERS += $$PWD/disassembler/mips32/Mips32Opcode.h
+SOURCES += $$PWD/disassembler/ARM64Disassembler.cpp
+SOURCES += $$PWD/disassembler/ARM64/A64DOpcode.cpp
+HEADERS += $$PWD/disassembler/ARM64/A64DOpcode.h
SOURCES += $$PWD/yarr/*.cpp
HEADERS += $$PWD/yarr/*.h
diff --git a/src/3rdparty/masm/stubs/ExecutableAllocator.h b/src/3rdparty/masm/stubs/ExecutableAllocator.h
index 5f7d5678ab..5a3939b7b2 100644
--- a/src/3rdparty/masm/stubs/ExecutableAllocator.h
+++ b/src/3rdparty/masm/stubs/ExecutableAllocator.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -33,6 +39,11 @@
#ifndef MASM_EXECUTABLEALLOCATOR_H
#define MASM_EXECUTABLEALLOCATOR_H
+// Defined via mkspec
+#if _MSC_VER >= 1900
+#include <windows.h>
+#endif
+
#include <RefPtr.h>
#include <RefCounted.h>
#include <wtf/PageBlock.h>
@@ -46,6 +57,10 @@
#include <unistd.h>
#endif
+#ifdef __QNXNTO__
+using std::perror;
+#endif
+
namespace JSC {
class JSGlobalData;
@@ -89,15 +104,34 @@ struct ExecutableAllocator {
return adoptRef(new ExecutableMemoryHandle(realAllocator, size));
}
- static void makeWritable(void* addr, int size)
+ static void makeWritable(void* addr, size_t size)
{
-#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
- size_t pageSize = WTF::pageSize();
- size_t iaddr = reinterpret_cast<size_t>(addr);
- size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
+ quintptr pageSize = WTF::pageSize();
+ quintptr iaddr = reinterpret_cast<quintptr>(addr);
+ quintptr roundAddr = iaddr & ~(pageSize - 1);
+ size = size + (iaddr - roundAddr);
+ addr = reinterpret_cast<void*>(roundAddr);
+#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
+# if OS(WINDOWS)
+ DWORD oldProtect;
+# if !OS(WINRT)
+ VirtualProtect(addr, size, PAGE_READWRITE, &oldProtect);
+# elif _MSC_VER >= 1900
+ bool hr = VirtualProtectFromApp(addr, size, PAGE_READWRITE, &oldProtect);
+ if (!hr) {
+ Q_UNREACHABLE();
+ }
+# else
+ (void)oldProtect;
+# endif
+# else
int mode = PROT_READ | PROT_WRITE;
- mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode);
+ if (mprotect(addr, size, mode) != 0) {
+ perror("mprotect failed in ExecutableAllocator::makeWritable");
+ Q_UNREACHABLE();
+ }
+# endif
#else
// We assume we already have RWX
(void)addr; // suppress unused parameter warning
@@ -105,25 +139,36 @@ struct ExecutableAllocator {
#endif
}
- static void makeExecutable(void* addr, int size)
+ static void makeExecutable(void* addr, size_t size)
{
- size_t pageSize = WTF::pageSize();
- size_t iaddr = reinterpret_cast<size_t>(addr);
- size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
-#if OS(WINDOWS)
-#if !OS(WINRT)
+ quintptr pageSize = WTF::pageSize();
+ quintptr iaddr = reinterpret_cast<quintptr>(addr);
+ quintptr roundAddr = iaddr & ~(pageSize - 1);
+ size = size + (iaddr - roundAddr);
+ addr = reinterpret_cast<void*>(roundAddr);
+
+#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
+# if OS(WINDOWS)
DWORD oldProtect;
- VirtualProtect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), PAGE_EXECUTE_READWRITE, &oldProtect);
-#else
- (void)size; // suppress unused parameter warning
- (void)roundAddr; // suppress unused parameter warning
-#endif
-#else
+# if !OS(WINRT)
+ VirtualProtect(addr, size, PAGE_EXECUTE_READ, &oldProtect);
+# elif _MSC_VER >= 1900
+ bool hr = VirtualProtectFromApp(addr, size, PAGE_EXECUTE_READ, &oldProtect);
+ if (!hr) {
+ Q_UNREACHABLE();
+ }
+# else
+ (void)oldProtect;
+# endif
+# else
int mode = PROT_READ | PROT_EXEC;
-#if !ENABLE(ASSEMBLER_WX_EXCLUSIVE)
- mode |= PROT_WRITE;
-#endif
- mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode);
+ if (mprotect(addr, size, mode) != 0) {
+ perror("mprotect failed in ExecutableAllocator::makeExecutable");
+ Q_UNREACHABLE();
+ }
+# endif
+#else
+# error "Only W^X is supported"
#endif
}
diff --git a/src/3rdparty/masm/stubs/JSGlobalData.h b/src/3rdparty/masm/stubs/JSGlobalData.h
index cac2aa6b6a..14c238acfb 100644
--- a/src/3rdparty/masm/stubs/JSGlobalData.h
+++ b/src/3rdparty/masm/stubs/JSGlobalData.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/Options.cpp b/src/3rdparty/masm/stubs/Options.cpp
index 76da55c387..6689aca383 100644
--- a/src/3rdparty/masm/stubs/Options.cpp
+++ b/src/3rdparty/masm/stubs/Options.cpp
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/Options.h b/src/3rdparty/masm/stubs/Options.h
index b0590f1a77..e03cc67690 100644
--- a/src/3rdparty/masm/stubs/Options.h
+++ b/src/3rdparty/masm/stubs/Options.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/WTFStubs.cpp b/src/3rdparty/masm/stubs/WTFStubs.cpp
index 828712b29a..610b632baf 100644
--- a/src/3rdparty/masm/stubs/WTFStubs.cpp
+++ b/src/3rdparty/masm/stubs/WTFStubs.cpp
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -112,6 +118,13 @@ void WTFReportAssertionFailure(const char* file, int line, const char* function,
fprintf(stderr, "WTF failing assertion in %s, line %d, function %s: %s\n", file, line, function, assertion);
}
+void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...)
+{
+ // TODO: show the message, or remove this function completely. (The latter would probably be best.)
+ Q_UNUSED(format);
+ fprintf(stderr, "WTF failing assertion in %s, line %d, function %s: %s\n", file, line, function, assertion);
+}
+
void WTFReportBacktrace()
{
}
diff --git a/src/3rdparty/masm/stubs/WTFStubs.h b/src/3rdparty/masm/stubs/WTFStubs.h
index 3b6acc7224..91b8838558 100644
--- a/src/3rdparty/masm/stubs/WTFStubs.h
+++ b/src/3rdparty/masm/stubs/WTFStubs.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/compat/stdint.h b/src/3rdparty/masm/stubs/compat/stdint.h
index 94a80b7839..394a3d824f 100644
--- a/src/3rdparty/masm/stubs/compat/stdint.h
+++ b/src/3rdparty/masm/stubs/compat/stdint.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/wtf/FastAllocBase.h b/src/3rdparty/masm/stubs/wtf/FastAllocBase.h
index 49fc89ce26..c7f99a30a5 100644
--- a/src/3rdparty/masm/stubs/wtf/FastAllocBase.h
+++ b/src/3rdparty/masm/stubs/wtf/FastAllocBase.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/wtf/FastMalloc.h b/src/3rdparty/masm/stubs/wtf/FastMalloc.h
index c4b0d4ebcc..7d6f86b32d 100644
--- a/src/3rdparty/masm/stubs/wtf/FastMalloc.h
+++ b/src/3rdparty/masm/stubs/wtf/FastMalloc.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/wtf/Noncopyable.h b/src/3rdparty/masm/stubs/wtf/Noncopyable.h
index 658375c3f5..2d4de9cd83 100644
--- a/src/3rdparty/masm/stubs/wtf/Noncopyable.h
+++ b/src/3rdparty/masm/stubs/wtf/Noncopyable.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/wtf/OwnPtr.h b/src/3rdparty/masm/stubs/wtf/OwnPtr.h
index 7c99077d18..eee828bb68 100644
--- a/src/3rdparty/masm/stubs/wtf/OwnPtr.h
+++ b/src/3rdparty/masm/stubs/wtf/OwnPtr.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/wtf/PassOwnPtr.h b/src/3rdparty/masm/stubs/wtf/PassOwnPtr.h
index aabd05060c..0e18132f77 100644
--- a/src/3rdparty/masm/stubs/wtf/PassOwnPtr.h
+++ b/src/3rdparty/masm/stubs/wtf/PassOwnPtr.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -95,8 +101,8 @@ public:
private:
template <typename PtrType> friend PassOwnPtr<PtrType> adoptPtr(PtrType*);
- PassOwnPtr<T>& operator=(const PassOwnPtr<T>&)
- {}
+ PassOwnPtr<T>& operator=(const PassOwnPtr<T>& t);
+
mutable QScopedPointer<T> m_ptr;
};
diff --git a/src/3rdparty/masm/stubs/wtf/PassRefPtr.h b/src/3rdparty/masm/stubs/wtf/PassRefPtr.h
index 5353b1680c..f072e70dd7 100644
--- a/src/3rdparty/masm/stubs/wtf/PassRefPtr.h
+++ b/src/3rdparty/masm/stubs/wtf/PassRefPtr.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -75,8 +81,7 @@ public:
}
private:
- PassRefPtr<T>& operator=(const PassRefPtr<T>&)
- {}
+ PassRefPtr<T>& operator=(const PassRefPtr<T>& t);
template <typename PtrType> friend PassRefPtr<PtrType> adoptRef(PtrType*);
mutable T* m_ptr;
diff --git a/src/3rdparty/masm/stubs/wtf/RefCounted.h b/src/3rdparty/masm/stubs/wtf/RefCounted.h
index 2624c4218a..332ef301aa 100644
--- a/src/3rdparty/masm/stubs/wtf/RefCounted.h
+++ b/src/3rdparty/masm/stubs/wtf/RefCounted.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/wtf/RefPtr.h b/src/3rdparty/masm/stubs/wtf/RefPtr.h
index 7e63511bca..e7e918649f 100644
--- a/src/3rdparty/masm/stubs/wtf/RefPtr.h
+++ b/src/3rdparty/masm/stubs/wtf/RefPtr.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/wtf/TypeTraits.h b/src/3rdparty/masm/stubs/wtf/TypeTraits.h
index 406fdcb3e3..04c2608a4d 100644
--- a/src/3rdparty/masm/stubs/wtf/TypeTraits.h
+++ b/src/3rdparty/masm/stubs/wtf/TypeTraits.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/wtf/UnusedParam.h b/src/3rdparty/masm/stubs/wtf/UnusedParam.h
index da4b8e0cc7..6d80b5a90b 100644
--- a/src/3rdparty/masm/stubs/wtf/UnusedParam.h
+++ b/src/3rdparty/masm/stubs/wtf/UnusedParam.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/wtf/Vector.h b/src/3rdparty/masm/stubs/wtf/Vector.h
index 22922ff27c..2025acf8a9 100644
--- a/src/3rdparty/masm/stubs/wtf/Vector.h
+++ b/src/3rdparty/masm/stubs/wtf/Vector.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/wtf/text/CString.h b/src/3rdparty/masm/stubs/wtf/text/CString.h
index cfbfd27c6d..26f74f7593 100644
--- a/src/3rdparty/masm/stubs/wtf/text/CString.h
+++ b/src/3rdparty/masm/stubs/wtf/text/CString.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/wtf/text/WTFString.h b/src/3rdparty/masm/stubs/wtf/text/WTFString.h
index 17bd466951..928c684fdb 100644
--- a/src/3rdparty/masm/stubs/wtf/text/WTFString.h
+++ b/src/3rdparty/masm/stubs/wtf/text/WTFString.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/stubs/wtf/unicode/Unicode.h b/src/3rdparty/masm/stubs/wtf/unicode/Unicode.h
index ce25561f52..d61cec5c4e 100644
--- a/src/3rdparty/masm/stubs/wtf/unicode/Unicode.h
+++ b/src/3rdparty/masm/stubs/wtf/unicode/Unicode.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/3rdparty/masm/wtf/OSAllocator.h b/src/3rdparty/masm/wtf/OSAllocator.h
index 494f8bc3c7..933b3cda0a 100644
--- a/src/3rdparty/masm/wtf/OSAllocator.h
+++ b/src/3rdparty/masm/wtf/OSAllocator.h
@@ -71,6 +71,8 @@ public:
// This interface is provided since it may be possible to optimize this operation on some platforms.
template<typename T>
static T* reallocateCommitted(T*, size_t oldSize, size_t newSize, Usage = UnknownUsage, bool writable = true, bool executable = false);
+
+ static bool canAllocateExecutableMemory();
};
inline void* OSAllocator::reserveAndCommit(size_t reserveSize, size_t commitSize, Usage usage, bool writable, bool executable)
diff --git a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
index f52c22f7fa..bbf11e4488 100644
--- a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
+++ b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
@@ -189,6 +189,11 @@ void OSAllocator::releaseDecommitted(void* address, size_t bytes)
CRASH();
}
+bool OSAllocator::canAllocateExecutableMemory()
+{
+ return true;
+}
+
} // namespace WTF
#endif // OS(UNIX)
diff --git a/src/3rdparty/masm/wtf/OSAllocatorWin.cpp b/src/3rdparty/masm/wtf/OSAllocatorWin.cpp
index 259fc67324..bb934264ab 100644
--- a/src/3rdparty/masm/wtf/OSAllocatorWin.cpp
+++ b/src/3rdparty/masm/wtf/OSAllocatorWin.cpp
@@ -90,6 +90,11 @@ void OSAllocator::releaseDecommitted(void* address, size_t bytes)
CRASH();
}
+bool OSAllocator::canAllocateExecutableMemory()
+{
+ return true;
+}
+
} // namespace WTF
#endif // OS(WINDOWS)
diff --git a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp
index d684367ec6..b7ad723f07 100644
--- a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp
+++ b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp
@@ -25,12 +25,27 @@
#include "config.h"
#include "OSAllocator.h"
+#include "PageBlock.h"
#if OS(WINRT)
#include "windows.h"
#include <wtf/Assertions.h>
+#if _MSC_VER >= 1900
+// Try to use JIT by default and fallback to non-JIT on first error
+static bool qt_winrt_use_jit = true;
+#else // _MSC_VER < 1900
+# define PAGE_EXECUTE 0x10
+# define PAGE_EXECUTE_READ 0x20
+# define PAGE_EXECUTE_READWRITE 0x40
+# define MEM_RELEASE 0x8000
+inline void* VirtualAllocFromApp(void*, size_t, int, int) { return 0; }
+inline bool VirtualProtectFromApp(void *, size_t, int, DWORD*) { return false; }
+inline bool VirtualFree(void *, size_t, DWORD) { return false; }
+static bool qt_winrt_use_jit = false;
+#endif // _MSC_VER < 1900
+
namespace WTF {
inline size_t getPageSize()
@@ -40,19 +55,58 @@ inline size_t getPageSize()
return info.dwPageSize;
}
-void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool, bool)
+static inline DWORD protection(bool writable, bool executable)
{
- static const size_t pageSize = getPageSize();
- void* result = _aligned_malloc(bytes, pageSize);
- if (!result)
- CRASH();
- memset(result, 0, bytes);
+ if (writable && executable)
+ qFatal("read/write executable areas are not allowed on WinRT");
+ return executable ?
+ (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) :
+ (writable ? PAGE_READWRITE : PAGE_READONLY);
+}
+
+void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable)
+{
+ void *result;
+ if (qt_winrt_use_jit) {
+ result = VirtualAllocFromApp(0, bytes, MEM_RESERVE, protection(writable, executable));
+ if (!result) {
+ qt_winrt_use_jit = false;
+ return reserveUncommitted(bytes, UnknownUsage, writable, executable);
+ }
+ } else {
+ static const size_t pageSize = getPageSize();
+ result = _aligned_malloc(bytes, pageSize);
+ if (!result)
+ CRASH();
+ memset(result, 0, bytes);
+ }
return result;
}
-void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool)
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
{
- return reserveUncommitted(bytes, usage, writable, executable);
+ void *result;
+ if (qt_winrt_use_jit) {
+ result = VirtualAllocFromApp(0, bytes, MEM_RESERVE | MEM_COMMIT,
+ protection(writable, executable));
+ if (!result) {
+ qt_winrt_use_jit = false;
+ return reserveAndCommit(bytes, usage, writable, executable, includesGuardPages);
+ }
+
+ if (includesGuardPages) {
+ size_t guardSize = pageSize();
+ DWORD oldProtect;
+ if (!VirtualProtectFromApp(result, guardSize, protection(false, false), &oldProtect) ||
+ !VirtualProtectFromApp(static_cast<char*>(result) + bytes - guardSize, guardSize,
+ protection(false, false), &oldProtect)) {
+ CRASH();
+ }
+ }
+ } else {
+ result = reserveUncommitted(bytes, usage, writable, executable);
+ }
+ return result;
}
void OSAllocator::commit(void*, size_t, bool, bool)
@@ -62,14 +116,44 @@ void OSAllocator::commit(void*, size_t, bool, bool)
void OSAllocator::decommit(void* address, size_t)
{
- _aligned_free(address);
+ if (qt_winrt_use_jit)
+ Q_UNREACHABLE();
+ else
+ _aligned_free(address);
}
void OSAllocator::releaseDecommitted(void* address, size_t bytes)
{
- decommit(address, bytes);
+ if (qt_winrt_use_jit) {
+ bool result = VirtualFree(address, 0, MEM_RELEASE);
+ if (!result)
+ CRASH();
+ } else {
+ decommit(address, bytes);
+ }
}
+bool OSAllocator::canAllocateExecutableMemory()
+{
+ if (qt_winrt_use_jit) {
+ // For WinRT we first check if code generation is enabled. If successful
+ // we allow to use JIT, otherwise fallback to the interpreter
+ const size_t pageSize = getPageSize();
+ void *all = VirtualAllocFromApp(0, pageSize, MEM_RESERVE | MEM_COMMIT,
+ protection(true, false));
+ DWORD oldProtect;
+ bool res = VirtualProtectFromApp(all, pageSize, PAGE_EXECUTE, &oldProtect);
+ VirtualFree(all, 0, MEM_RELEASE);
+ if (!res) {
+ qt_winrt_use_jit = false;
+ qWarning("Could not enable JIT, fallback to interpreter mode. "
+ "Consider setting the code-generation capability");
+ }
+ }
+ return qt_winrt_use_jit;
+}
+
+
} // namespace WTF
#endif // OS(WINRT)
diff --git a/src/3rdparty/masm/wtf/Platform.h b/src/3rdparty/masm/wtf/Platform.h
index f0612fe50e..3f480d344a 100644
--- a/src/3rdparty/masm/wtf/Platform.h
+++ b/src/3rdparty/masm/wtf/Platform.h
@@ -166,6 +166,11 @@
#define WTF_CPU_X86_64 1
#endif
+/* CPU(ARM64) - Apple */
+#if (defined(__arm64__) && defined(__APPLE__)) || defined(__aarch64__)
+#define WTF_CPU_ARM64 1
+#endif
+
/* CPU(ARM) - ARM, any version*/
#define WTF_ARM_ARCH_AT_LEAST(N) (CPU(ARM) && WTF_ARM_ARCH_VERSION >= N)
@@ -348,6 +353,11 @@
|| (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) \
|| (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR))
#define WTF_OS_IOS 1
+#elif OS(DARWIN) && ((defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) \
+ || (defined(TARGET_OS_APPLETV) && TARGET_OS_APPLETV) \
+ || (defined(TARGET_APPLETV_SIMULATOR) && TARGET_APPLETV_SIMULATOR))
+#define WTF_OS_IOS 1
+#define WTF_OS_TVOS 1
#elif OS(DARWIN) && defined(TARGET_OS_MAC) && TARGET_OS_MAC
#define WTF_OS_MAC_OS_X 1
@@ -700,6 +710,7 @@
#if (CPU(X86_64) && (OS(UNIX) || OS(WINDOWS))) \
|| (CPU(IA64) && !CPU(IA64_32)) \
|| CPU(ALPHA) \
+ || CPU(ARM64) \
|| CPU(SPARC64) \
|| CPU(S390X) \
|| CPU(PPC64)
@@ -720,7 +731,7 @@
/* The JIT is enabled by default on all x86, x86-64, ARM & MIPS platforms. */
#if !defined(ENABLE_JIT) \
- && (CPU(X86) || CPU(X86_64) || CPU(ARM) || CPU(MIPS)) \
+ && (CPU(X86) || CPU(X86_64) || CPU(ARM) || CPU(MIPS) || CPU(ARM64)) \
&& (OS(DARWIN) || !COMPILER(GCC) || GCC_VERSION_AT_LEAST(4, 1, 0)) \
&& !OS(WINCE) \
&& !(OS(QNX) && !PLATFORM(QT)) /* We use JIT in QNX Qt */
@@ -735,7 +746,7 @@
#define WTF_USE_UDIS86 1
#endif
-#if !defined(ENABLE_DISASSEMBLER) && (USE(UDIS86) || USE(ARMV7_DISASSEMBLER) || USE(MIPS32_DISASSEMBLER))
+#if !defined(ENABLE_DISASSEMBLER) && (USE(UDIS86) || USE(ARMV7_DISASSEMBLER) || USE(ARM64_DISASSEMBLER) || USE(MIPS32_DISASSEMBLER))
#define ENABLE_DISASSEMBLER 1
#endif
@@ -869,7 +880,7 @@
/* Pick which allocator to use; we only need an executable allocator if the assembler is compiled in.
On x86-64 we use a single fixed mmap, on other platforms we mmap on demand. */
#if ENABLE(ASSEMBLER)
-#if CPU(X86_64) && !OS(WINDOWS) || PLATFORM(IOS)
+#if CPU(X86_64) && !OS(WINDOWS) || PLATFORM(IOS) || CPU(ARM64)
#define ENABLE_EXECUTABLE_ALLOCATOR_FIXED 1
#else
#define ENABLE_EXECUTABLE_ALLOCATOR_DEMAND 1
@@ -928,7 +939,7 @@
#define WTF_USE_ACCESSIBILITY_CONTEXT_MENUS 1
#endif
-#if CPU(ARM_THUMB2)
+#if CPU(ARM_THUMB2) || CPU(ARM64)
#define ENABLE_BRANCH_COMPACTION 1
#endif
diff --git a/src/3rdparty/masm/yarr/YarrJIT.cpp b/src/3rdparty/masm/yarr/YarrJIT.cpp
index ce18b3ab4f..5664c585b9 100644
--- a/src/3rdparty/masm/yarr/YarrJIT.cpp
+++ b/src/3rdparty/masm/yarr/YarrJIT.cpp
@@ -53,6 +53,17 @@ class YarrGenerator : private MacroAssembler {
static const RegisterID returnRegister = ARMRegisters::r0;
static const RegisterID returnRegister2 = ARMRegisters::r1;
+#elif CPU(ARM64)
+ static const RegisterID input = ARM64Registers::x0;
+ static const RegisterID index = ARM64Registers::x1;
+ static const RegisterID length = ARM64Registers::x2;
+ static const RegisterID output = ARM64Registers::x3;
+
+ static const RegisterID regT0 = ARM64Registers::x4;
+ static const RegisterID regT1 = ARM64Registers::x5;
+
+ static const RegisterID returnRegister = ARM64Registers::x0;
+ static const RegisterID returnRegister2 = ARM64Registers::x1;
#elif CPU(MIPS)
static const RegisterID input = MIPSRegisters::a0;
static const RegisterID index = MIPSRegisters::a1;