Changeset 238861 in webkit


Ignore:
Timestamp:
Dec 4, 2018 10:55:27 AM (5 years ago)
Author:
Caio Lima
Message:

[ESNext][BigInt] Support logic operations
https://bugs.webkit.org/show_bug.cgi?id=179903

Reviewed by Yusuke Suzuki.

JSTests:

  • stress/big-int-branch-usage.js: Added.
  • stress/big-int-logical-and.js: Added.
  • stress/big-int-logical-not.js: Added.
  • stress/big-int-logical-or.js: Added.

Source/JavaScriptCore:

We are introducing in this patch the ToBoolean support for JSBigInt.
With this change, we can implement the correct behavior of BigInt as
operand of logical opertions. During JIT genertion into DFG and FTL,
we are using JSBigInt::m_length to verify if the number is 0n or not,
following the same approach used by JSString. This is also safe in the case
of BigInt, because only 0n has m_length == 0.

We are not including BigInt speculation into Branch nodes in this
patch, but the plan is to implement it in further patches.

  • ftl/FTLAbstractHeapRepository.h:
  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::boolify):
(JSC::FTL::DFG::LowerDFGToB3::isBigInt):

  • jit/AssemblyHelpers.cpp:

(JSC::AssemblyHelpers::emitConvertValueToBoolean):
(JSC::AssemblyHelpers::branchIfValue):

  • runtime/JSBigInt.cpp:

(JSC::JSBigInt::isZero const):
(JSC::JSBigInt::offsetOfLength):
(JSC::JSBigInt::toBoolean const):
(JSC::JSBigInt::isZero): Deleted.

  • runtime/JSBigInt.h:
  • runtime/JSCellInlines.h:

(JSC::JSCell::toBoolean const):
(JSC::JSCell::pureToBoolean const):

Location:
trunk
Files:
4 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r238835 r238861  
     12018-12-04  Caio Lima  <ticaiolima@gmail.com>
     2
     3        [ESNext][BigInt] Support logic operations
     4        https://bugs.webkit.org/show_bug.cgi?id=179903
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        * stress/big-int-branch-usage.js: Added.
     9        * stress/big-int-logical-and.js: Added.
     10        * stress/big-int-logical-not.js: Added.
     11        * stress/big-int-logical-or.js: Added.
     12
    1132018-12-03  Ryan Haddad  <ryanhaddad@apple.com>
    214
  • trunk/Source/JavaScriptCore/ChangeLog

    r238850 r238861  
     12018-12-04  Caio Lima  <ticaiolima@gmail.com>
     2
     3        [ESNext][BigInt] Support logic operations
     4        https://bugs.webkit.org/show_bug.cgi?id=179903
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        We are introducing in this patch the ToBoolean support for JSBigInt.
     9        With this change, we can implement the correct behavior of BigInt as
     10        operand of logical opertions. During JIT genertion into DFG and FTL,
     11        we are using JSBigInt::m_length to verify if the number is 0n or not,
     12        following the same approach used by JSString. This is also safe in the case
     13        of BigInt, because only 0n has m_length == 0.
     14
     15        We are not including BigInt speculation into Branch nodes in this
     16        patch, but the plan is to implement it in further patches.
     17
     18        * ftl/FTLAbstractHeapRepository.h:
     19        * ftl/FTLLowerDFGToB3.cpp:
     20        (JSC::FTL::DFG::LowerDFGToB3::boolify):
     21        (JSC::FTL::DFG::LowerDFGToB3::isBigInt):
     22        * jit/AssemblyHelpers.cpp:
     23        (JSC::AssemblyHelpers::emitConvertValueToBoolean):
     24        (JSC::AssemblyHelpers::branchIfValue):
     25        * runtime/JSBigInt.cpp:
     26        (JSC::JSBigInt::isZero const):
     27        (JSC::JSBigInt::offsetOfLength):
     28        (JSC::JSBigInt::toBoolean const):
     29        (JSC::JSBigInt::isZero): Deleted.
     30        * runtime/JSBigInt.h:
     31        * runtime/JSCellInlines.h:
     32        (JSC::JSCell::toBoolean const):
     33        (JSC::JSCell::pureToBoolean const):
     34
    1352018-12-04  Devin Rousso  <drousso@apple.com>
    236
  • trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h

    r238835 r238861  
    8686    macro(JSString_length, JSString::offsetOfLength()) \
    8787    macro(JSString_value, JSString::offsetOfValue()) \
     88    macro(JSBigInt_length, JSBigInt::offsetOfLength()) \
    8889    macro(JSSymbolTableObject_symbolTable, JSSymbolTableObject::offsetOfSymbolTable()) \
    8990    macro(JSWrapperObject_internalValue, JSWrapperObject::internalValueOffset()) \
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r238835 r238861  
    1357913579            // Implements the following control flow structure:
    1358013580            // if (value is cell) {
    13581             //     if (value is string)
     13581            //     if (value is string or value is BigInt)
    1358213582            //         result = !!value->length
    1358313583            //     else {
     
    1359613596            LBasicBlock stringCase = m_out.newBlock();
    1359713597            LBasicBlock notStringCase = m_out.newBlock();
     13598            LBasicBlock bigIntCase = m_out.newBlock();
     13599            LBasicBlock notBigIntCase = m_out.newBlock();
    1359813600            LBasicBlock notCellCase = m_out.newBlock();
    1359913601            LBasicBlock int32Case = m_out.newBlock();
     
    1361713619            results.append(m_out.anchor(nonEmptyString));
    1361813620            m_out.jump(continuation);
    13619            
    13620             m_out.appendTo(notStringCase, notCellCase);
     13621
     13622            m_out.appendTo(notStringCase, bigIntCase);
     13623            m_out.branch(
     13624                isBigInt(value, provenType(edge) & SpecCell),
     13625                unsure(bigIntCase), unsure(notBigIntCase));
     13626
     13627            m_out.appendTo(bigIntCase, notBigIntCase);
     13628            LValue nonZeroBigInt = m_out.notZero32(
     13629                m_out.load32NonNegative(value, m_heaps.JSBigInt_length));
     13630            results.append(m_out.anchor(nonZeroBigInt));
     13631            m_out.jump(continuation);
     13632           
     13633            m_out.appendTo(notBigIntCase, notCellCase);
    1362113634            LValue isTruthyObject;
    1362213635            if (masqueradesAsUndefinedWatchpointIsStillValid())
     
    1561215625    }
    1561315626
     15627    LValue isBigInt(LValue cell, SpeculatedType type = SpecFullTop)
     15628    {
     15629        if (LValue proven = isProvenValue(type & SpecCell, SpecBigInt))
     15630            return proven;
     15631        return m_out.equal(
     15632            m_out.load32(cell, m_heaps.JSCell_structureID),
     15633            m_out.constInt32(vm().bigIntStructure->id()));
     15634    }
     15635
    1561415636    LValue isArrayTypeForArrayify(LValue cell, ArrayMode arrayMode)
    1561515637    {
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp

    r238835 r238861  
    759759    // Implements the following control flow structure:
    760760    // if (value is cell) {
    761     //     if (value is string)
     761    //     if (value is string or value is BigInt)
    762762    //         result = !!value->length
    763763    //     else {
     
    782782
    783783    isCellButNotString.link(this);
     784    auto isCellButNotBigIntOrString = branchIfNotBigInt(value.payloadGPR());
     785    load32(Address(value.payloadGPR(), JSBigInt::offsetOfLength()), result);
     786    compare32(invert ? Equal : NotEqual, result, TrustedImm32(0), result);
     787    done.append(jump());
     788
     789    isCellButNotBigIntOrString.link(this);
    784790    if (shouldCheckMasqueradesAsUndefined) {
    785791        ASSERT(scratchIfShouldCheckMasqueradesAsUndefined != InvalidGPRReg);
     
    832838    // Implements the following control flow structure:
    833839    // if (value is cell) {
    834     //     if (value is string)
     840    //     if (value is string or value is BigInt)
    835841    //         result = !!value->length
    836842    //     else {
     
    853859    truthy.append(branchTest32(invert ? Zero : NonZero, Address(value.payloadGPR(), JSString::offsetOfLength())));
    854860    done.append(jump());
     861    isCellButNotString.link(this);
     862    auto isCellButNotBigIntOrString = branchIfNotBigInt(value.payloadGPR());
     863    truthy.append(branchTest32(invert ? Zero : NonZero, Address(value.payloadGPR(), JSBigInt::offsetOfLength())));
     864    done.append(jump());
    855865
    856866    if (shouldCheckMasqueradesAsUndefined) {
    857         isCellButNotString.link(this);
     867        isCellButNotBigIntOrString.link(this);
    858868        ASSERT(scratchIfShouldCheckMasqueradesAsUndefined != InvalidGPRReg);
    859869        JumpList isNotMasqueradesAsUndefined;
     
    875885    } else {
    876886        if (invert)
    877             done.append(isCellButNotString);
     887            done.append(isCellButNotBigIntOrString);
    878888        else
    879             truthy.append(isCellButNotString);
     889            truthy.append(isCellButNotBigIntOrString);
    880890    }
    881891
  • trunk/Source/JavaScriptCore/runtime/JSBigInt.cpp

    r238835 r238861  
    233233}
    234234
    235 inline bool JSBigInt::isZero()
    236 {
    237     ASSERT(length() || !sign());
    238     return length() == 0;
    239 }
    240 
    241235// Multiplies {this} with {factor} and adds {summand} to the result.
    242236void JSBigInt::inplaceMultiplyAdd(Digit factor, Digit summand)
     
    17011695}
    17021696
     1697size_t JSBigInt::offsetOfLength()
     1698{
     1699    return OBJECT_OFFSETOF(JSBigInt, m_length);
     1700}
     1701
    17031702template <typename CharType>
    17041703JSBigInt* JSBigInt::parseInt(ExecState* exec, CharType*  data, unsigned length, ErrorParseMode errorParseMode)
     
    18191818    dataStorage()[n] = value;
    18201819}
     1820
    18211821JSObject* JSBigInt::toObject(ExecState* exec, JSGlobalObject* globalObject) const
    18221822{
  • trunk/Source/JavaScriptCore/runtime/JSBigInt.h

    r238835 r238861  
    2929#include "ExceptionHelpers.h"
    3030#include "JSObject.h"
    31 #include "ParseInt.h"
    3231#include <wtf/CagedPtr.h>
    3332#include <wtf/text/StringBuilder.h>
     
    5958    static JSBigInt* createFrom(VM&, int64_t value);
    6059    static JSBigInt* createFrom(VM&, bool value);
     60
     61    static size_t offsetOfLength();
    6162
    6263    DECLARE_EXPORT_INFO;
     
    105106
    106107    JSObject* toObject(ExecState*, JSGlobalObject*) const;
     108    inline bool toBoolean() const { return !isZero(); }
    107109
    108110    static JSBigInt* multiply(ExecState*, JSBigInt* x, JSBigInt* y);
     
    195197    static String toStringGeneric(ExecState*, JSBigInt*, unsigned radix);
    196198
    197     bool isZero();
     199    inline bool isZero() const
     200    {
     201        ASSERT(length() || !sign());
     202        return length() == 0;
     203    }
    198204
    199205    template <typename CharType>
  • trunk/Source/JavaScriptCore/runtime/JSCellInlines.h

    r238835 r238861  
    3434#include "Handle.h"
    3535#include "IsoSubspaceInlines.h"
     36#include "JSBigInt.h"
    3637#include "JSCast.h"
    3738#include "JSDestructibleObject.h"
     
    340341    if (isString())
    341342        return static_cast<const JSString*>(this)->toBoolean();
     343    if (isBigInt())
     344        return static_cast<const JSBigInt*>(this)->toBoolean();
    342345    return !structure(exec->vm())->masqueradesAsUndefined(exec->lexicalGlobalObject());
    343346}
     
    347350    if (isString())
    348351        return static_cast<const JSString*>(this)->toBoolean() ? TrueTriState : FalseTriState;
     352    if (isBigInt())
     353        return static_cast<const JSBigInt*>(this)->toBoolean() ? TrueTriState : FalseTriState;
    349354    if (isSymbol())
    350355        return TrueTriState;
Note: See TracChangeset for help on using the changeset viewer.