WebKit Bugzilla
Attachment 340539 Details for
Bug 185702
: REGRESSION(r231845): it is breaking Apple High Sierra 32-bit JSC bot (Requested by caiolima on #webkit).
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
ROLLOUT of r231845
bug-185702-20180516193602.patch (text/plain), 38.30 KB, created by
WebKit Commit Bot
on 2018-05-16 16:36:02 PDT
(
hide
)
Description:
ROLLOUT of r231845
Filename:
MIME Type:
Creator:
WebKit Commit Bot
Created:
2018-05-16 16:36:02 PDT
Size:
38.30 KB
patch
obsolete
>Subversion Revision: 231877 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index f30732e453839b81c73344fe69dffbad892f2695..0a3d07768fec9d3e266888be82970ab2e4158129 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,17 @@ >+2018-05-16 Commit Queue <commit-queue@webkit.org> >+ >+ Unreviewed, rolling out r231845. >+ https://bugs.webkit.org/show_bug.cgi?id=185702 >+ >+ it is breaking Apple High Sierra 32-bit JSC bot (Requested by >+ caiolima on #webkit). >+ >+ Reverted changeset: >+ >+ "[ESNext][BigInt] Implement support for "/" operation" >+ https://bugs.webkit.org/show_bug.cgi?id=183996 >+ https://trac.webkit.org/changeset/231845 >+ > 2018-05-16 Filip Pizlo <fpizlo@apple.com> > > DFG models InstanceOf incorrectly >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp >index b5815fd1738559bafdb6cef719219a06b09d0786..5b0947e3d5f5bd8e6250bd9ec549e8b966eb80fc 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -75,7 +75,6 @@ > #include "TypedArrayInlines.h" > #include "VMInlines.h" > #include <wtf/InlineASM.h> >-#include <wtf/Variant.h> > > #if ENABLE(JIT) > #if ENABLE(DFG_JIT) >@@ -425,25 +424,10 @@ EncodedJSValue JIT_OPERATION operationValueDiv(ExecState* exec, EncodedJSValue e > JSValue op1 = JSValue::decode(encodedOp1); > JSValue op2 = JSValue::decode(encodedOp2); > >- auto leftNumeric = op1.toNumeric(exec); >- RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- auto rightNumeric = op2.toNumeric(exec); >+ double a = op1.toNumber(exec); > RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- >- if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >- if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >- JSBigInt* result = JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); >- RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- return JSValue::encode(result); >- } >- >- return throwVMTypeError(exec, scope, "Invalid operand in BigInt operation."); >- } >- > scope.release(); >- >- double a = WTF::get<double>(leftNumeric); >- double b = WTF::get<double>(rightNumeric); >+ double b = op2.toNumber(exec); > return JSValue::encode(jsNumber(a / b)); > } > >diff --git a/Source/JavaScriptCore/runtime/BigIntPrototype.cpp b/Source/JavaScriptCore/runtime/BigIntPrototype.cpp >index 32d9d1487ee5543e1a33a29a37968dd38841379a..4498158e338cb1f03cc3b241e5b7769ac5febb3d 100644 >--- a/Source/JavaScriptCore/runtime/BigIntPrototype.cpp >+++ b/Source/JavaScriptCore/runtime/BigIntPrototype.cpp >@@ -103,7 +103,7 @@ EncodedJSValue JSC_HOST_CALL bigIntProtoFuncToString(ExecState* state) > int32_t radix = extractToStringRadixArgument(state, state->argument(0), scope); > RETURN_IF_EXCEPTION(scope, encodedJSValue()); > >- String resultString = value->toString(state, radix); >+ String resultString = value->toString(*state, radix); > RETURN_IF_EXCEPTION(scope, encodedJSValue()); > scope.release(); > if (resultString.length() == 1) >diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >index 84dd3d2a4516a188f0f98a01d501004cdc725663..a8a5681dc96e8802ebad812af9a075af9a61763f 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -516,25 +516,12 @@ SLOW_PATH_DECL(slow_path_div) > BEGIN(); > JSValue left = OP_C(2).jsValue(); > JSValue right = OP_C(3).jsValue(); >- auto leftNumeric = left.toNumeric(exec); >- CHECK_EXCEPTION(); >- auto rightNumeric = right.toNumeric(exec); >- CHECK_EXCEPTION(); >- >- if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >- if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >- JSValue result(JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric))); >- CHECK_EXCEPTION(); >- RETURN_WITH_PROFILING(result, { >- updateArithProfileForBinaryArithOp(exec, pc, result, left, right); >- }); >- } >- >- THROW(createTypeError(exec, "Invalid mix of BigInt and other type in division.")); >- } >- >- double a = WTF::get<double>(leftNumeric); >- double b = WTF::get<double>(rightNumeric); >+ double a = left.toNumber(exec); >+ if (UNLIKELY(throwScope.exception())) >+ RETURN(JSValue()); >+ double b = right.toNumber(exec); >+ if (UNLIKELY(throwScope.exception())) >+ RETURN(JSValue()); > JSValue result = jsNumber(a / b); > RETURN_WITH_PROFILING(result, { > updateArithProfileForBinaryArithOp(exec, pc, result, left, right); >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.cpp b/Source/JavaScriptCore/runtime/JSBigInt.cpp >index 222a2acd740dd1cf9cedf6f437f69e7840ec8259..fd8e9af2a1d40213b62dafe048047823d6c59e4e 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp >+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp >@@ -227,10 +227,10 @@ JSBigInt* JSBigInt::stringToBigInt(ExecState* state, StringView s) > return parseInt(state, s, ErrorParseMode::IgnoreExceptions); > } > >-String JSBigInt::toString(ExecState* state, unsigned radix) >+String JSBigInt::toString(ExecState& state, unsigned radix) > { > if (this->isZero()) >- return state->vm().smallStrings.singleCharacterStringRep('0'); >+ return state.vm().smallStrings.singleCharacterStringRep('0'); > > return toStringGeneric(state, this, radix); > } >@@ -270,59 +270,6 @@ JSBigInt* JSBigInt::multiply(ExecState* state, JSBigInt* x, JSBigInt* y) > return result->rightTrim(vm); > } > >-JSBigInt* JSBigInt::divide(ExecState* state, JSBigInt* x, JSBigInt* y) >-{ >- // 1. If y is 0n, throw a RangeError exception. >- VM& vm = state->vm(); >- auto scope = DECLARE_THROW_SCOPE(vm); >- >- if (y->isZero()) { >- throwRangeError(state, scope, ASCIILiteral("0 is an invalid divisor value.")); >- return nullptr; >- } >- >- // 2. Let quotient be the mathematical value of x divided by y. >- // 3. Return a BigInt representing quotient rounded towards 0 to the next >- // integral value. >- if (absoluteCompare(x, y) == ComparisonResult::LessThan) >- return createZero(vm); >- >- JSBigInt* quotient = nullptr; >- bool resultSign = x->sign() != y->sign(); >- if (y->length() == 1) { >- Digit divisor = y->digit(0); >- if (divisor == 1) >- return resultSign == x->sign() ? x : unaryMinus(vm, x); >- >- Digit remainder; >- absoluteDivWithDigitDivisor(vm, x, divisor, "ient, remainder); >- } else >- absoluteDivWithBigIntDivisor(vm, x, y, "ient, nullptr); >- >- quotient->setSign(resultSign); >- return quotient->rightTrim(vm); >-} >- >-JSBigInt* JSBigInt::copy(VM& vm, JSBigInt* x) >-{ >- ASSERT(!x->isZero()); >- >- JSBigInt* result = JSBigInt::createWithLength(vm, x->length()); >- std::copy(x->dataStorage(), x->dataStorage() + x->length(), result->dataStorage()); >- result->setSign(x->sign()); >- return result; >-} >- >-JSBigInt* JSBigInt::unaryMinus(VM& vm, JSBigInt* x) >-{ >- if (x->isZero()) >- return x; >- >- JSBigInt* result = copy(vm, x); >- result->setSign(!x->sign()); >- return result; >-} >- > #if USE(JSVALUE32_64) > #define HAVE_TWO_DIGIT 1 > typedef uint64_t TwoDigit; >@@ -575,25 +522,6 @@ bool JSBigInt::equals(JSBigInt* x, JSBigInt* y) > return true; > } > >-inline JSBigInt::ComparisonResult JSBigInt::absoluteCompare(JSBigInt* x, JSBigInt* y) >-{ >- ASSERT(!x->length() || x->digit(0)); >- ASSERT(!y->length() || y->digit(0)); >- >- int diff = x->length() - y->length(); >- if (diff) >- return diff < 0 ? ComparisonResult::LessThan : ComparisonResult::GreaterThan; >- >- int i = x->length() - 1; >- while (i >= 0 && x->digit(i) == y->digit(i)) >- i--; >- >- if (i < 0) >- return ComparisonResult::Equal; >- >- return x->digit(i) > y->digit(i) ? ComparisonResult::GreaterThan : ComparisonResult::LessThan; >-} >- > // Divides {x} by {divisor}, returning the result in {quotient} and {remainder}. > // Mathematically, the contract is: > // quotient = (x - remainder) / divisor, with 0 <= remainder < divisor. >@@ -601,10 +529,11 @@ inline JSBigInt::ComparisonResult JSBigInt::absoluteCompare(JSBigInt* x, JSBigIn > // allocated for it; otherwise the caller must ensure that it is big enough. > // {quotient} can be the same as {x} for an in-place division. {quotient} can > // also be nullptr if the caller is only interested in the remainder. >-void JSBigInt::absoluteDivWithDigitDivisor(VM& vm, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder) >+void JSBigInt::absoluteDivSmall(ExecState& state, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder) > { > ASSERT(divisor); > >+ VM& vm = state.vm(); > ASSERT(!x->isZero()); > remainder = 0; > if (divisor == 1) { >@@ -628,209 +557,6 @@ void JSBigInt::absoluteDivWithDigitDivisor(VM& vm, JSBigInt* x, Digit divisor, J > } > } > >-// Divides {dividend} by {divisor}, returning the result in {quotient} and >-// {remainder}. Mathematically, the contract is: >-// quotient = (dividend - remainder) / divisor, with 0 <= remainder < divisor. >-// Both {quotient} and {remainder} are optional, for callers that are only >-// interested in one of them. >-// See Knuth, Volume 2, section 4.3.1, Algorithm D. >-void JSBigInt::absoluteDivWithBigIntDivisor(VM& vm, JSBigInt* dividend, JSBigInt* divisor, JSBigInt** quotient, JSBigInt** remainder) >-{ >- ASSERT(divisor->length() >= 2); >- ASSERT(dividend->length() >= divisor->length()); >- >- // The unusual variable names inside this function are consistent with >- // Knuth's book, as well as with Go's implementation of this algorithm. >- // Maintaining this consistency is probably more useful than trying to >- // come up with more descriptive names for them. >- unsigned n = divisor->length(); >- unsigned m = dividend->length() - n; >- >- // The quotient to be computed. >- JSBigInt* q = nullptr; >- if (quotient != nullptr) >- q = createWithLength(vm, m + 1); >- >- // In each iteration, {qhatv} holds {divisor} * {current quotient digit}. >- // "v" is the book's name for {divisor}, "qhat" the current quotient digit. >- JSBigInt* qhatv = createWithLength(vm, m + 1); >- >- // D1. >- // Left-shift inputs so that the divisor's MSB is set. This is necessary >- // to prevent the digit-wise divisions (see digit_div call below) from >- // overflowing (they take a two digits wide input, and return a one digit >- // result). >- Digit lastDigit = divisor->digit(n - 1); >- unsigned shift = sizeof(lastDigit) == 8 ? clz64(lastDigit) : clz32(lastDigit); >- >- if (shift > 0) >- divisor = absoluteLeftShiftAlwaysCopy(vm, divisor, shift, LeftShiftMode::SameSizeResult); >- >- // Holds the (continuously updated) remaining part of the dividend, which >- // eventually becomes the remainder. >- JSBigInt* u = absoluteLeftShiftAlwaysCopy(vm, dividend, shift, LeftShiftMode::AlwaysAddOneDigit); >- >- // D2. >- // Iterate over the dividend's digit (like the "grad school" algorithm). >- // {vn1} is the divisor's most significant digit. >- Digit vn1 = divisor->digit(n - 1); >- for (int j = m; j >= 0; j--) { >- // D3. >- // Estimate the current iteration's quotient digit (see Knuth for details). >- // {qhat} is the current quotient digit. >- Digit qhat = std::numeric_limits<Digit>::max(); >- >- // {ujn} is the dividend's most significant remaining digit. >- Digit ujn = u->digit(j + n); >- if (ujn != vn1) { >- // {rhat} is the current iteration's remainder. >- Digit rhat = 0; >- // Estimate the current quotient digit by dividing the most significant >- // digits of dividend and divisor. The result will not be too small, >- // but could be a bit too large. >- qhat = digitDiv(ujn, u->digit(j + n - 1), vn1, rhat); >- >- // Decrement the quotient estimate as needed by looking at the next >- // digit, i.e. by testing whether >- // qhat * v_{n-2} > (rhat << digitBits) + u_{j+n-2}. >- Digit vn2 = divisor->digit(n - 2); >- Digit ujn2 = u->digit(j + n - 2); >- while (productGreaterThan(qhat, vn2, rhat, ujn2)) { >- qhat--; >- Digit prevRhat = rhat; >- rhat += vn1; >- // v[n-1] >= 0, so this tests for overflow. >- if (rhat < prevRhat) >- break; >- } >- } >- >- // D4. >- // Multiply the divisor with the current quotient digit, and subtract >- // it from the dividend. If there was "borrow", then the quotient digit >- // was one too high, so we must correct it and undo one subtraction of >- // the (shifted) divisor. >- internalMultiplyAdd(divisor, qhat, 0, n, qhatv); >- Digit c = u->absoluteInplaceSub(qhatv, j); >- if (c) { >- c = u->absoluteInplaceAdd(divisor, j); >- u->setDigit(j + n, u->digit(j + n) + c); >- qhat--; >- } >- >- if (quotient != nullptr) >- q->setDigit(j, qhat); >- } >- >- if (quotient != nullptr) { >- // Caller will right-trim. >- *quotient = q; >- } >- >- if (remainder != nullptr) { >- u->inplaceRightShift(shift); >- *remainder = u; >- } >-} >- >-// Returns whether (factor1 * factor2) > (high << kDigitBits) + low. >-inline bool JSBigInt::productGreaterThan(Digit factor1, Digit factor2, Digit high, Digit low) >-{ >- Digit resultHigh; >- Digit resultLow = digitMul(factor1, factor2, resultHigh); >- return resultHigh > high || (resultHigh == high && resultLow > low); >-} >- >-// Adds {summand} onto {this}, starting with {summand}'s 0th digit >-// at {this}'s {startIndex}'th digit. Returns the "carry" (0 or 1). >-JSBigInt::Digit JSBigInt::absoluteInplaceAdd(JSBigInt* summand, unsigned startIndex) >-{ >- Digit carry = 0; >- unsigned n = summand->length(); >- ASSERT(length() >= startIndex + n); >- for (unsigned i = 0; i < n; i++) { >- Digit newCarry = 0; >- Digit sum = digitAdd(digit(startIndex + i), summand->digit(i), newCarry); >- sum = digitAdd(sum, carry, newCarry); >- setDigit(startIndex + i, sum); >- carry = newCarry; >- } >- >- return carry; >-} >- >-// Subtracts {subtrahend} from {this}, starting with {subtrahend}'s 0th digit >-// at {this}'s {startIndex}-th digit. Returns the "borrow" (0 or 1). >-JSBigInt::Digit JSBigInt::absoluteInplaceSub(JSBigInt* subtrahend, unsigned startIndex) >-{ >- Digit borrow = 0; >- unsigned n = subtrahend->length(); >- ASSERT(length() >= startIndex + n); >- for (unsigned i = 0; i < n; i++) { >- Digit newBorrow = 0; >- Digit difference = digitSub(digit(startIndex + i), subtrahend->digit(i), newBorrow); >- difference = digitSub(difference, borrow, newBorrow); >- setDigit(startIndex + i, difference); >- borrow = newBorrow; >- } >- >- return borrow; >-} >- >-void JSBigInt::inplaceRightShift(unsigned shift) >-{ >- ASSERT(shift < digitBits); >- ASSERT(!(digit(0) & ((static_cast<Digit>(1) << shift) - 1))); >- >- if (!shift) >- return; >- >- Digit carry = digit(0) >> shift; >- unsigned last = length() - 1; >- for (unsigned i = 0; i < last; i++) { >- Digit d = digit(i + 1); >- setDigit(i, (d << (digitBits - shift)) | carry); >- carry = d >> shift; >- } >- setDigit(last, carry); >-} >- >-// Always copies the input, even when {shift} == 0. >-JSBigInt* JSBigInt::absoluteLeftShiftAlwaysCopy(VM& vm, JSBigInt* x, unsigned shift, LeftShiftMode mode) >-{ >- ASSERT(shift < digitBits); >- ASSERT(!x->isZero()); >- >- unsigned n = x->length(); >- unsigned resultLength = mode == LeftShiftMode::AlwaysAddOneDigit ? n + 1 : n; >- JSBigInt* result = createWithLength(vm, resultLength); >- >- if (!shift) { >- for (unsigned i = 0; i < n; i++) >- result->setDigit(i, x->digit(i)); >- if (mode == LeftShiftMode::AlwaysAddOneDigit) >- result->setDigit(n, 0); >- >- return result; >- } >- >- Digit carry = 0; >- for (unsigned i = 0; i < n; i++) { >- Digit d = x->digit(i); >- result->setDigit(i, (d << shift) | carry); >- carry = d >> (digitBits - shift); >- } >- >- if (mode == LeftShiftMode::AlwaysAddOneDigit) >- result->setDigit(n, carry); >- else { >- ASSERT(mode == LeftShiftMode::SameSizeResult); >- ASSERT(!carry); >- } >- >- return result; >-} >- > // Lookup table for the maximum number of bits required per character of a > // base-N string representation of a number. To increase accuracy, the array > // value is the actual value multiplied by 32. To generate this table: >@@ -878,14 +604,12 @@ uint64_t JSBigInt::calculateMaximumCharactersRequired(unsigned length, unsigned > return maximumCharactersRequired; > } > >-String JSBigInt::toStringGeneric(ExecState* state, JSBigInt* x, unsigned radix) >+String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, unsigned radix) > { > // FIXME: [JSC] Revisit usage of Vector into JSBigInt::toString > // https://bugs.webkit.org/show_bug.cgi?id=18067 > Vector<LChar> resultString; > >- VM& vm = state->vm(); >- > ASSERT(radix >= 2 && radix <= 36); > ASSERT(!x->isZero()); > >@@ -896,8 +620,8 @@ String JSBigInt::toStringGeneric(ExecState* state, JSBigInt* x, unsigned radix) > uint64_t maximumCharactersRequired = calculateMaximumCharactersRequired(length, radix, x->digit(length - 1), sign); > > if (maximumCharactersRequired > JSString::MaxLength) { >- auto scope = DECLARE_THROW_SCOPE(vm); >- throwOutOfMemoryError(state, scope); >+ auto scope = DECLARE_THROW_SCOPE(state.vm()); >+ throwOutOfMemoryError(&state, scope); > return String(); > } > >@@ -922,7 +646,7 @@ String JSBigInt::toStringGeneric(ExecState* state, JSBigInt* x, unsigned radix) > JSBigInt** dividend = &x; > do { > Digit chunk; >- absoluteDivWithDigitDivisor(vm, *dividend, chunkDivisor, &rest, chunk); >+ absoluteDivSmall(state, *dividend, chunkDivisor, &rest, chunk); > ASSERT(rest); > > dividend = &rest; >@@ -970,11 +694,13 @@ JSBigInt* JSBigInt::rightTrim(VM& vm) > if (isZero()) > return this; > >- unsigned nonZeroIndex = m_length - 1; >- while (!digit(nonZeroIndex)) >+ ASSERT(m_length); >+ >+ int nonZeroIndex = m_length - 1; >+ while (nonZeroIndex >= 0 && !digit(nonZeroIndex)) > nonZeroIndex--; > >- if (nonZeroIndex == m_length - 1) >+ if (nonZeroIndex == static_cast<int>(m_length - 1)) > return this; > > unsigned newLength = nonZeroIndex + 1; >@@ -1148,15 +874,15 @@ inline JSBigInt::Digit* JSBigInt::dataStorage() > return reinterpret_cast<Digit*>(reinterpret_cast<char*>(this) + offsetOfData()); > } > >-inline JSBigInt::Digit JSBigInt::digit(unsigned n) >+JSBigInt::Digit JSBigInt::digit(unsigned n) > { >- ASSERT(n < length()); >+ ASSERT(n >= 0 && n < length()); > return dataStorage()[n]; > } > >-inline void JSBigInt::setDigit(unsigned n, Digit value) >+void JSBigInt::setDigit(unsigned n, Digit value) > { >- ASSERT(n < length()); >+ ASSERT(n >= 0 && n < length()); > dataStorage()[n] = value; > } > JSObject* JSBigInt::toObject(ExecState* exec, JSGlobalObject* globalObject) const >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.h b/Source/JavaScriptCore/runtime/JSBigInt.h >index 67650fc2f368b58fdee550c677e2c628476b7200..0244cbb4954c8efe49809638873d1a7fc1f65dd7 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.h >+++ b/Source/JavaScriptCore/runtime/JSBigInt.h >@@ -82,7 +82,7 @@ public: > static JSBigInt* stringToBigInt(ExecState*, StringView); > > std::optional<uint8_t> singleDigitValueForString(); >- String toString(ExecState*, unsigned radix); >+ String toString(ExecState&, unsigned radix); > > JS_EXPORT_PRIVATE static bool equals(JSBigInt*, JSBigInt*); > bool equalsToNumber(JSValue); >@@ -94,12 +94,9 @@ public: > > static JSBigInt* multiply(ExecState*, JSBigInt* x, JSBigInt* y); > >- static JSBigInt* divide(ExecState*, JSBigInt* x, JSBigInt* y); >- static JSBigInt* unaryMinus(VM&, JSBigInt* x); >- > private: > >- enum class ComparisonResult { >+ enum ComparisonResult { > Equal, > Undefined, > GreaterThan, >@@ -121,23 +118,9 @@ private: > > static uint64_t calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign); > >- static ComparisonResult absoluteCompare(JSBigInt* x, JSBigInt* y); >- static void absoluteDivWithDigitDivisor(VM&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder); >+ static void absoluteDivSmall(ExecState&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder); > static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned, JSBigInt* result); > static void multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex); >- static void absoluteDivWithBigIntDivisor(VM&, JSBigInt* dividend, JSBigInt* divisor, JSBigInt** quotient, JSBigInt** remainder); >- >- enum class LeftShiftMode { >- SameSizeResult, >- AlwaysAddOneDigit >- }; >- >- static JSBigInt* absoluteLeftShiftAlwaysCopy(VM&, JSBigInt* x, unsigned shift, LeftShiftMode); >- static bool productGreaterThan(Digit factor1, Digit factor2, Digit high, Digit low); >- >- Digit absoluteInplaceAdd(JSBigInt* summand, unsigned startIndex); >- Digit absoluteInplaceSub(JSBigInt* subtrahend, unsigned startIndex); >- void inplaceRightShift(unsigned shift); > > // Digit arithmetic helpers. > static Digit digitAdd(Digit a, Digit b, Digit& carry); >@@ -146,7 +129,7 @@ private: > static Digit digitDiv(Digit high, Digit low, Digit divisor, Digit& remainder); > static Digit digitPow(Digit base, Digit exponent); > >- static String toStringGeneric(ExecState*, JSBigInt*, unsigned radix); >+ static String toStringGeneric(ExecState&, JSBigInt*, unsigned radix); > > bool isZero(); > >@@ -160,7 +143,6 @@ private: > > static JSBigInt* allocateFor(ExecState*, VM&, unsigned radix, unsigned charcount); > >- static JSBigInt* copy(VM&, JSBigInt* x); > JSBigInt* rightTrim(VM&); > > void inplaceMultiplyAdd(Digit multiplier, Digit part); >diff --git a/Source/JavaScriptCore/runtime/JSCJSValue.cpp b/Source/JavaScriptCore/runtime/JSCJSValue.cpp >index 9edc6019df3df1f7f627f2ee648c33e5038179c0..b5f77be59749fe386cf33ca1ec9447d24ccbbe5e 100644 >--- a/Source/JavaScriptCore/runtime/JSCJSValue.cpp >+++ b/Source/JavaScriptCore/runtime/JSCJSValue.cpp >@@ -382,7 +382,7 @@ JSString* JSValue::toStringSlowCase(ExecState* exec, bool returnEmptyStringOnErr > JSBigInt* bigInt = asBigInt(*this); > if (auto digit = bigInt->singleDigitValueForString()) > return vm.smallStrings.singleCharacterString(*digit + '0'); >- JSString* returnString = jsNontrivialString(&vm, bigInt->toString(exec, 10)); >+ JSString* returnString = jsNontrivialString(&vm, bigInt->toString(*exec, 10)); > RETURN_IF_EXCEPTION(scope, errorValue()); > return returnString; > } >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index b04b7053c9f25434d21f93e24c3ed766d9c704a9..da542537fe19d29d90e15ed083d9d968980c4f6a 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,17 @@ >+2018-05-16 Commit Queue <commit-queue@webkit.org> >+ >+ Unreviewed, rolling out r231845. >+ https://bugs.webkit.org/show_bug.cgi?id=185702 >+ >+ it is breaking Apple High Sierra 32-bit JSC bot (Requested by >+ caiolima on #webkit). >+ >+ Reverted changeset: >+ >+ "[ESNext][BigInt] Implement support for "/" operation" >+ https://bugs.webkit.org/show_bug.cgi?id=183996 >+ https://trac.webkit.org/changeset/231845 >+ > 2018-05-16 Filip Pizlo <fpizlo@apple.com> > > DFG models InstanceOf incorrectly >diff --git a/JSTests/bigIntTests.yaml b/JSTests/bigIntTests.yaml >index 4ff994ff5096e519da2caf1eec41318b727a44b0..e947dc2945adf90d077fc837d5583a1d08e3bc91 100644 >--- a/JSTests/bigIntTests.yaml >+++ b/JSTests/bigIntTests.yaml >@@ -118,20 +118,3 @@ > - path: stress/big-int-multiply-memory-stress.js > cmd: runBigIntEnabled > >-- path: stress/big-int-div-jit.js >- cmd: runBigIntEnabled >- >-- path: stress/big-int-div-memory-stress.js >- cmd: runBigIntEnabled >- >-- path: stress/big-int-div-to-primitive.js >- cmd: runBigIntEnabled >- >-- path: stress/big-int-div-type-error.js >- cmd: runBigIntEnabled >- >-- path: stress/big-int-div-wrapped-value.js >- cmd: runBigIntEnabled >- >-- path: stress/big-int-division.js >- cmd: runBigIntEnabled >diff --git a/JSTests/stress/big-int-div-jit.js b/JSTests/stress/big-int-div-jit.js >deleted file mode 100644 >index 0e217e8307e39d4f40c15a2ad0708448266a904f..0000000000000000000000000000000000000000 >--- a/JSTests/stress/big-int-div-jit.js >+++ /dev/null >@@ -1,19 +0,0 @@ >-//@ runBigIntEnabled >- >-let assert = { >- sameValue: function(i, e, m) { >- if (i !== e) >- throw new Error(m); >- } >-} >- >-function bigIntDiv(x, y) { >- return x / y; >-} >-noInline(bigIntDiv); >- >-for (let i = 0; i < 10000; i++) { >- let r = bigIntDiv(30n, 10n); >- assert.sameValue(r, 3n, 30n + " / " + 10n + " = " + r); >-} >- >diff --git a/JSTests/stress/big-int-div-memory-stress.js b/JSTests/stress/big-int-div-memory-stress.js >deleted file mode 100644 >index 0cf0b9b6faf3ef85c5f59d3ba9bf4a974f73f6f4..0000000000000000000000000000000000000000 >--- a/JSTests/stress/big-int-div-memory-stress.js >+++ /dev/null >@@ -1,15 +0,0 @@ >-//@ runBigIntEnabled >- >-function assert(a) { >- if (!a) >- throw new Error("Bad assertion"); >-} >- >-let a = 0n; >-let b = 30n; >-for (let i = 0; i < 1000000; i++) { >- a = b / 2n; >-} >- >-assert(a === 15n); >- >diff --git a/JSTests/stress/big-int-div-to-primitive.js b/JSTests/stress/big-int-div-to-primitive.js >deleted file mode 100644 >index a2973447ea4258262252eafdaae0d62ef1821c88..0000000000000000000000000000000000000000 >--- a/JSTests/stress/big-int-div-to-primitive.js >+++ /dev/null >@@ -1,34 +0,0 @@ >-//@ runBigIntEnabled >- >-function assert(a) { >- if (!a) >- throw new Error("Bad assertion"); >-} >- >-assert.sameValue = function (input, expected, message) { >- if (input !== expected) >- throw new Error(message); >-} >- >-function testDiv(x, y, z) { >- assert.sameValue(x / y, z, x + " / " + y + " = " + z); >-} >- >-let o = { >- [Symbol.toPrimitive]: function () { return 300000000000n; } >-} >- >-testDiv(500000000000438n, o, 1666n); >- >-o.valueOf = function () { >- throw new Error("Should never execute it"); >-}; >- >-testDiv(700000000000438n, o, 2333n); >- >-o.toString = function () { >- throw new Error("Should never execute it"); >-}; >- >-testDiv(700000000000438n, o, 2333n); >- >diff --git a/JSTests/stress/big-int-div-type-error.js b/JSTests/stress/big-int-div-type-error.js >deleted file mode 100644 >index 27982cd78e030150eafaa4f9346e4f667d5e661b..0000000000000000000000000000000000000000 >--- a/JSTests/stress/big-int-div-type-error.js >+++ /dev/null >@@ -1,106 +0,0 @@ >-//@ runBigIntEnabled >- >-function assert(a, message) { >- if (!a) >- throw new Error(message); >-} >- >-function assertThrowTypeError(a, b, message) { >- try { >- let n = a / b; >- assert(false, message + ": Should throw TypeError, but executed without exception"); >- } catch (e) { >- assert(e instanceof TypeError, message + ": expected TypeError, got: " + e); >- } >-} >- >-assertThrowTypeError(30n, "foo", "BigInt / String"); >-assertThrowTypeError("bar", 18757382984821n, "String / BigInt"); >-assertThrowTypeError(30n, Symbol("foo"), "BigInt / Symbol"); >-assertThrowTypeError(Symbol("bar"), 18757382984821n, "Symbol / BigInt"); >-assertThrowTypeError(30n, 3320, "BigInt / Int32"); >-assertThrowTypeError(33256, 18757382984821n, "Int32 / BigInt"); >-assertThrowTypeError(30n, 0.543, "BigInt / Double"); >-assertThrowTypeError(230.19293, 18757382984821n, "Double / BigInt"); >-assertThrowTypeError(30n, NaN, "BigInt / NaN"); >-assertThrowTypeError(NaN, 18757382984821n, "NaN / BigInt"); >-assertThrowTypeError(30n, NaN, "BigInt / NaN"); >-assertThrowTypeError(NaN, 18757382984821n, "NaN / BigInt"); >-assertThrowTypeError(30n, +Infinity, "BigInt / NaN"); >-assertThrowTypeError(+Infinity, 18757382984821n, "NaN / BigInt"); >-assertThrowTypeError(30n, -Infinity, "BigInt / -Infinity"); >-assertThrowTypeError(-Infinity, 18757382984821n, "-Infinity / BigInt"); >-assertThrowTypeError(30n, null, "BigInt / null"); >-assertThrowTypeError(null, 18757382984821n, "null / BigInt"); >-assertThrowTypeError(30n, undefined, "BigInt / undefined"); >-assertThrowTypeError(undefined, 18757382984821n, "undefined / BigInt"); >-assertThrowTypeError(30n, true, "BigInt * true"); >-assertThrowTypeError(true, 18757382984821n, "true / BigInt"); >-assertThrowTypeError(30n, false, "BigInt / false"); >-assertThrowTypeError(false, 18757382984821n, "false / BigInt"); >- >-// Error when returning from object >- >-let o = { >- valueOf: function () { return Symbol("Foo"); } >-}; >- >-assertThrowTypeError(30n, o, "BigInt / Object.valueOf returning Symbol"); >-assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Symbol / BigInt"); >- >-o = { >- valueOf: function () { return 33256; } >-}; >- >-assertThrowTypeError(30n, o, "BigInt / Object.valueOf returning Int32"); >-assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Int32 / BigInt"); >- >-o = { >- valueOf: function () { return 0.453; } >-}; >- >-assertThrowTypeError(30n, o, "BigInt / Object.valueOf returning Double"); >-assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Double / BigInt"); >- >-o = { >- toString: function () { return Symbol("Foo"); } >-}; >- >-assertThrowTypeError(30n, o, "BigInt / Object.toString returning Symbol"); >-assertThrowTypeError(o, 18757382984821n, "Object.toString returning Symbol / BigInt"); >- >-o = { >- toString: function () { return 33256; } >-}; >- >-assertThrowTypeError(30n, o, "BigInt / Object.toString returning Int32"); >-assertThrowTypeError(o, 18757382984821n, "Object.toString returning Int32 / BigInt"); >- >-o = { >- toString: function () { return 0.453; } >-}; >- >-assertThrowTypeError(30n, o, "BigInt / Object.toString returning Double"); >-assertThrowTypeError(o, 18757382984821n, "Object.toString returning Double / BigInt"); >- >-o = { >- [Symbol.toPrimitive]: function () { return Symbol("Foo"); } >-}; >- >-assertThrowTypeError(30n, o, "BigInt / Object.@@toPrimitive returning Symbol"); >-assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Symbol / BigInt"); >- >-o = { >- [Symbol.toPrimitive]: function () { return 33256; } >-}; >- >-assertThrowTypeError(30n, o, "BigInt / Object.@@toPrimitive returning Int32"); >-assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Int32 / BigInt"); >- >-o = { >- [Symbol.toPrimitive]: function () { return 0.453; } >-}; >- >-assertThrowTypeError(30n, o, "BigInt / Object.@@toPrimitive returning Double"); >-assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Double / BigInt"); >- >diff --git a/JSTests/stress/big-int-div-wrapped-value.js b/JSTests/stress/big-int-div-wrapped-value.js >deleted file mode 100644 >index 9bb9aee983af0c0e09758e772384f5eb3c46dc90..0000000000000000000000000000000000000000 >--- a/JSTests/stress/big-int-div-wrapped-value.js >+++ /dev/null >@@ -1,46 +0,0 @@ >-//@ runBigIntEnabled >- >-assert = { >- sameValue: function (input, expected, message) { >- if (input !== expected) >- throw new Error(message); >- } >-}; >- >-function testDiv(x, y, z, message) { >- assert.sameValue(x / y, z, message); >-} >- >-testDiv(Object(2n), 1n, 2n, "ToPrimitive: unbox object with internal slot"); >- >-let o = { >- [Symbol.toPrimitive]: function() { >- return 2n; >- } >-}; >-testDiv(o, 1n, 2n, "ToPrimitive: @@toPrimitive"); >- >-o = { >- valueOf: function() { >- return 2n; >- } >-}; >-testDiv(o, 1n, 2n, "ToPrimitive: valueOf"); >- >-o = { >- toString: function() { >- return 2n; >- } >-} >-testDiv(o, 1n, 2n, "ToPrimitive: toString"); >- >-o = { >- valueOf: function() { >- return 2n; >- }, >- toString: function () { >- throw new Error("Should never execute it"); >- } >-}; >-testDiv(o, 1n, 2n, "ToPrimitive: valueOf"); >- >diff --git a/JSTests/stress/big-int-division.js b/JSTests/stress/big-int-division.js >deleted file mode 100644 >index 401890ad6316cece7a9b2cad020aab0f5db2991a..0000000000000000000000000000000000000000 >--- a/JSTests/stress/big-int-division.js >+++ /dev/null >@@ -1,131 +0,0 @@ >-//@ runBigIntEnabled >- >-// Copyright (C) 2017 Robin Templeton. All rights reserved. >-// This code is governed by the BSD license found in the LICENSE file. >- >-function assert(a) { >- if (!a) >- throw new Error("Bad assertion"); >-} >- >-assert.sameValue = function (input, expected, message) { >- if (input !== expected) >- throw new Error(message); >-} >- >-function testDiv(x, y, z) { >- assert.sameValue(x / y, z, x + " / " + y + " = " + z); >-} >- >-testDiv(0xFEDCBA9876543210n, 0xFEDCBA9876543210n, 0x1n); >-testDiv(0xFEDCBA9876543210n, 0xFEDCBA987654320Fn, 0x1n); >-testDiv(0xFEDCBA9876543210n, 0xFEDCBA98n, 0x100000000n); >-testDiv(0xFEDCBA9876543210n, 0xFEDCBA97n, 0x100000001n); >-testDiv(0xFEDCBA9876543210n, 0x1234n, 0xE0042813BE5DCn); >-testDiv(0xFEDCBA9876543210n, 0x3n, 0x54F43E32D21C10B0n); >-testDiv(0xFEDCBA9876543210n, 0x2n, 0x7F6E5D4C3B2A1908n); >-testDiv(0xFEDCBA9876543210n, 0x1n, 0xFEDCBA9876543210n); >-testDiv(0xFEDCBA9876543210n, BigInt("-1"), BigInt("-18364758544493064720")); >-testDiv(0xFEDCBA9876543210n, BigInt("-2"), BigInt("-9182379272246532360")); >-testDiv(0xFEDCBA9876543210n, BigInt("-3"), BigInt("-6121586181497688240")); >-testDiv(0xFEDCBA9876543210n, BigInt("-4275878551"), BigInt("-4294967297")); >-testDiv(0xFEDCBA9876543210n, BigInt("-18364758544493064719"), BigInt("-1")); >-testDiv(0xFEDCBA987654320Fn, 0xFEDCBA9876543210n, 0x0n); >-testDiv(0xFEDCBA987654320Fn, 0xFEDCBA987654320Fn, 0x1n); >-testDiv(0xFEDCBA987654320Fn, 0xFEDCBA98n, 0x100000000n); >-testDiv(0xFEDCBA987654320Fn, 0xFEDCBA97n, 0x100000001n); >-testDiv(0xFEDCBA987654320Fn, 0x1234n, 0xE0042813BE5DCn); >-testDiv(0xFEDCBA987654320Fn, 0x3n, 0x54F43E32D21C10AFn); >-testDiv(0xFEDCBA987654320Fn, 0x2n, 0x7F6E5D4C3B2A1907n); >-testDiv(0xFEDCBA987654320Fn, 0x1n, 0xFEDCBA987654320Fn); >-testDiv(0xFEDCBA98n, 0xFEDCBA9876543210n, 0x0n); >-testDiv(0xFEDCBA98n, 0xFEDCBA987654320Fn, 0x0n); >-testDiv(0xFEDCBA98n, 0xFEDCBA98n, 0x1n); >-testDiv(0xFEDCBA98n, 0xFEDCBA97n, 0x1n); >-testDiv(0xFEDCBA98n, 0x1234n, 0xE0042n); >-testDiv(0xFEDCBA98n, 0x3n, 0x54F43E32n); >-testDiv(0xFEDCBA98n, 0x2n, 0x7F6E5D4Cn); >-testDiv(0xFEDCBA98n, 0x1n, 0xFEDCBA98n); >-testDiv(0xFEDCBA98n, BigInt("-1"), BigInt("-4275878552")); >-testDiv(0xFEDCBA98n, BigInt("-2"), BigInt("-2137939276")); >-testDiv(0xFEDCBA98n, BigInt("-3"), BigInt("-1425292850")); >-testDiv(0xFEDCBA98n, BigInt("-4275878551"), BigInt("-1")); >-testDiv(0xFEDCBA98n, BigInt("-18364758544493064719"), 0x0n); >-testDiv(0xFEDCBA97n, 0xFEDCBA9876543210n, 0x0n); >-testDiv(0xFEDCBA97n, 0xFEDCBA987654320Fn, 0x0n); >-testDiv(0xFEDCBA97n, 0xFEDCBA98n, 0x0n); >-testDiv(0xFEDCBA97n, 0xFEDCBA97n, 0x1n); >-testDiv(0xFEDCBA97n, 0x1234n, 0xE0042n); >-testDiv(0xFEDCBA97n, 0x3n, 0x54F43E32n); >-testDiv(0xFEDCBA97n, 0x2n, 0x7F6E5D4Bn); >-testDiv(0xFEDCBA97n, 0x1n, 0xFEDCBA97n); >-testDiv(0x3n, 0xFEDCBA9876543210n, 0x0n); >-testDiv(0x3n, 0xFEDCBA98n, 0x0n); >-testDiv(0x3n, 0x1234n, 0x0n); >-testDiv(0x3n, 0x3n, 0x1n); >-testDiv(0x3n, 0x2n, 0x1n); >-testDiv(0x3n, 0x1n, 0x3n); >-testDiv(0x3n, BigInt("-2"), BigInt("-1")); >-testDiv(0x3n, BigInt("-3"), BigInt("-1")); >-testDiv(0x3n, BigInt("-4275878551"), 0x0n); >-testDiv(0x3n, BigInt("-18364758544493064719"), 0x0n); >-testDiv(0x2n, 0xFEDCBA98n, 0x0n); >-testDiv(0x2n, 0xFEDCBA97n, 0x0n); >-testDiv(0x2n, 0x3n, 0x0n); >-testDiv(0x2n, 0x1n, 0x2n); >-testDiv(0x2n, BigInt("-1"), BigInt("-2")); >-testDiv(0x2n, BigInt("-2"), BigInt("-1")); >-testDiv(0x2n, BigInt("-3"), 0x0n); >-testDiv(0x1n, 0x1234n, 0x0n); >-testDiv(0x1n, 0x3n, 0x0n); >-testDiv(0x1n, 0x2n, 0x0n); >-testDiv(0x1n, 0x1n, 0x1n); >-testDiv(0x1n, BigInt("-1"), BigInt("-1")); >-testDiv(0x1n, BigInt("-3"), 0x0n); >-testDiv(0x1n, BigInt("-4660"), 0x0n); >-testDiv(0x1n, BigInt("-18364758544493064719"), 0x0n); >-testDiv(BigInt("-1"), 0xFEDCBA9876543210n, 0x0n); >-testDiv(BigInt("-1"), 0xFEDCBA987654320Fn, 0x0n); >-testDiv(BigInt("-1"), 0xFEDCBA98n, 0x0n); >-testDiv(BigInt("-1"), 0xFEDCBA97n, 0x0n); >-testDiv(BigInt("-1"), 0x3n, 0x0n); >-testDiv(BigInt("-1"), 0x1n, BigInt("-1")); >-testDiv(BigInt("-1"), BigInt("-3"), 0x0n); >-testDiv(BigInt("-1"), BigInt("-4660"), 0x0n); >-testDiv(BigInt("-1"), BigInt("-18364758544493064719"), 0x0n); >-testDiv(BigInt("-2"), 0xFEDCBA9876543210n, 0x0n); >-testDiv(BigInt("-3"), 0x3n, BigInt("-1")); >-testDiv(BigInt("-3"), 0x2n, BigInt("-1")); >-testDiv(BigInt("-3"), BigInt("-1"), 0x3n); >-testDiv(BigInt("-3"), BigInt("-3"), 0x1n); >-testDiv(BigInt("-3"), BigInt("-4660"), 0x0n); >-testDiv(BigInt("-3"), BigInt("-4275878551"), 0x0n); >-testDiv(BigInt("-3"), BigInt("-4275878552"), 0x0n); >-testDiv(BigInt("-3"), BigInt("-18364758544493064720"), 0x0n); >-testDiv(BigInt("-18364758544493064719"), 0xFEDCBA97n, BigInt("-4294967297")); >-testDiv(BigInt("-18364758544493064719"), 0x1234n, BigInt("-3940935309977052")); >-testDiv(BigInt("-18364758544493064719"), 0x3n, BigInt("-6121586181497688239")); >-testDiv(BigInt("-18364758544493064719"), 0x2n, BigInt("-9182379272246532359")); >-testDiv(BigInt("-18364758544493064719"), 0x1n, BigInt("-18364758544493064719")); >-testDiv(BigInt("-18364758544493064719"), BigInt("-1"), 0xFEDCBA987654320Fn); >-testDiv(BigInt("-18364758544493064719"), BigInt("-4275878551"), 0x100000001n); >-testDiv(BigInt("-18364758544493064719"), BigInt("-18364758544493064719"), 0x1n); >-testDiv(BigInt("-18364758544493064720"), 0xFEDCBA9876543210n, BigInt("-1")); >-testDiv(BigInt("-18364758544493064720"), 0x1234n, BigInt("-3940935309977052")); >-testDiv(BigInt("-18364758544493064720"), 0x3n, BigInt("-6121586181497688240")); >-testDiv(BigInt("-18364758544493064720"), 0x2n, BigInt("-9182379272246532360")); >-testDiv(BigInt("-18364758544493064720"), 0x1n, BigInt("-18364758544493064720")); >-testDiv(BigInt("-18364758544493064720"), BigInt("-1"), 0xFEDCBA9876543210n); >-testDiv(BigInt("-18364758544493064720"), BigInt("-3"), 0x54F43E32D21C10B0n); >-testDiv(BigInt("-18364758544493064720"), BigInt("-4660"), 0xE0042813BE5DCn); >-testDiv(BigInt("-18364758544493064720"), BigInt("-4275878552"), 0x100000000n); >-testDiv(BigInt("-18364758544493064720"), BigInt("-18364758544493064720"), 0x1n); >- >-// Test division by 0 >-try { >- let a = 102122311n / 0n; >-} catch (e) { >- assert(e instanceof RangeError); >- assert(e.message == "0 is an invalid divisor value."); >-} >-
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 185702
: 340539