Ignore:
Timestamp:
Apr 6, 2016, 5:50:44 PM (9 years ago)
Author:
[email protected]
Message:

[ES6] Add support for Symbol.isConcatSpreadable.
https://bugs.webkit.org/show_bug.cgi?id=155351

Reviewed by Saam Barati.

Source/JavaScriptCore:

This patch adds support for Symbol.isConcatSpreadable. In order to do so it was necessary to move the
Array.prototype.concat function to JS. A number of different optimizations were needed to make such the move to
a builtin performant. First, four new DFG intrinsics were added.

1) IsArrayObject (I would have called it IsArray but we use the same name for an IndexingType): an intrinsic of

the Array.isArray function.

2) IsJSArray: checks the first child is a JSArray object.
3) IsArrayConstructor: checks the first child is an instance of ArrayConstructor.
4) CallObjectConstructor: an intrinsic of the Object constructor.

IsActualObject, IsJSArray, and CallObjectConstructor can all be converted into constants in the abstract interpreter if
we are able to prove that the first child is an Array or for ToObject an Object.

In order to further improve the perfomance we also now cover more indexing types in our fast path memcpy
code. Before we would only memcpy Arrays if they had the same indexing type and did not have Array storage and
were not undecided. Now the memcpy code covers the following additional two cases: One array is undecided and
the other is a non-array storage and the case where one array is Int32 and the other is contiguous (we map this
into a contiguous array).

This patch also adds a new fast path for concat with more than one array argument by using memcpy to append
values onto the result array. This works roughly the same as the two array fast path using the same methodology
to decide if we can memcpy the other butterfly into the result butterfly.

Two new debugging tools are also added to the jsc cli. One is a version of the print function with a private
name so it can be used for debugging builtins. The other is dumpDataLog, which takes a JSValue and runs our
dataLog function on it.

Finally, this patch add a new constructor to JSValueRegsTemporary that allows it to reuse the the registers of a
JSValueOperand if the operand's use count is one.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • builtins/ArrayPrototype.js:

(concatSlowPath):
(concat):

  • bytecode/BytecodeIntrinsicRegistry.cpp:

(JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):

  • bytecode/BytecodeIntrinsicRegistry.h:
  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
(JSC::DFG::ByteCodeParser::handleConstantInternalFunction):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileCurrentBlock):
(JSC::DFG::SpeculativeJIT::compileIsJSArray):
(JSC::DFG::SpeculativeJIT::compileIsArrayObject):
(JSC::DFG::SpeculativeJIT::compileIsArrayConstructor):
(JSC::DFG::SpeculativeJIT::compileCallObjectConstructor):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileCallObjectConstructor):
(JSC::FTL::DFG::LowerDFGToB3::compileIsArrayObject):
(JSC::FTL::DFG::LowerDFGToB3::compileIsJSArray):
(JSC::FTL::DFG::LowerDFGToB3::compileIsArrayConstructor):
(JSC::FTL::DFG::LowerDFGToB3::isArray):

  • jit/JITOperations.h:
  • jsc.cpp:

(WTF::RuntimeArray::createStructure):
(GlobalObject::finishCreation):
(functionDebug):
(functionDataLogValue):

  • runtime/ArrayConstructor.cpp:

(JSC::ArrayConstructor::finishCreation):
(JSC::arrayConstructorPrivateFuncIsArrayConstructor):

  • runtime/ArrayConstructor.h:

(JSC::isArrayConstructor):

  • runtime/ArrayPrototype.cpp:

(JSC::ArrayPrototype::finishCreation):
(JSC::arrayProtoPrivateFuncIsJSArray):
(JSC::moveElements):
(JSC::arrayProtoPrivateFuncConcatMemcpy):
(JSC::arrayProtoPrivateFuncAppendMemcpy):
(JSC::arrayProtoFuncConcat): Deleted.

  • runtime/ArrayPrototype.h:

(JSC::ArrayPrototype::createStructure):

  • runtime/CommonIdentifiers.h:
  • runtime/Intrinsic.h:
  • runtime/JSArray.cpp:

(JSC::JSArray::appendMemcpy):
(JSC::JSArray::fastConcatWith): Deleted.

  • runtime/JSArray.h:

(JSC::JSArray::createStructure):
(JSC::JSArray::fastConcatType): Deleted.

  • runtime/JSArrayInlines.h: Added.

(JSC::JSArray::memCopyWithIndexingType):
(JSC::JSArray::canFastCopy):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):

  • runtime/JSType.h:
  • runtime/ObjectConstructor.h:

(JSC::constructObject):

  • tests/es6.yaml:
  • tests/stress/array-concat-spread-object.js: Added.

(arrayEq):

  • tests/stress/array-concat-spread-proxy-exception-check.js: Added.

(arrayEq):

  • tests/stress/array-concat-spread-proxy.js: Added.

(arrayEq):

  • tests/stress/array-concat-with-slow-indexingtypes.js: Added.

(arrayEq):

  • tests/stress/array-species-config-array-constructor.js:

Source/WebCore:

Makes runtime arrays have the new ArrayType

  • bridge/runtime_array.h:

(JSC::RuntimeArray::createStructure):

LayoutTests:

Fix tests for Symbol.isConcatSpreadable on the Symbol object.

  • js/Object-getOwnPropertyNames-expected.txt:
  • js/dom/array-prototype-properties-expected.txt:
  • js/script-tests/Object-getOwnPropertyNames.js:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/builtins/ArrayPrototype.js

    r198844 r199128  
    647647}
    648648
     649function concatSlowPath()
     650{
     651    "use strict";
     652
     653    var argCount = arguments.length;
     654    var result = new this.species(0);
     655    var resultIsArray = @isJSArray(result);
     656
     657    var currentElement = this.array;
     658    var resultIndex = 0;
     659    var argIndex = 0;
     660
     661    do {
     662        var spreadable = @isObject(currentElement) && currentElement[@symbolIsConcatSpreadable];
     663        if ((spreadable == @undefined && @isArray(currentElement)) || spreadable) {
     664            var length = @toLength(currentElement.length);
     665            if (resultIsArray && @isJSArray(currentElement)
     666                && @appendMemcpy(result, currentElement)) {
     667
     668                resultIndex += length;
     669            } else {
     670                if (length + resultIndex > @MAX_SAFE_INTEGER)
     671                    throw @TypeError("length exceeded the maximum safe integer");
     672                for (var i = 0; i < length; i++) {
     673                    if (i in currentElement)
     674                        @putByValDirect(result, resultIndex, currentElement[i]);
     675                    resultIndex++;
     676                }
     677            }
     678        } else {
     679            if (resultIndex >= @MAX_SAFE_INTEGER)
     680                throw @TypeError("length exceeded the maximum safe integer");
     681            @putByValDirect(result, resultIndex++, currentElement);
     682        }
     683        currentElement = arguments[argIndex];
     684    } while (argIndex++ < argCount);
     685
     686    result.length = resultIndex;
     687    return result;
     688}
     689
     690function concat(first)
     691{
     692    "use strict";
     693
     694    if (this == null) {
     695        if (this === null)
     696            throw new @TypeError("Array.prototype.concat requires that |this| not be null");
     697        throw new @TypeError("Array.prototype.concat requires that |this| not be undefined");
     698    }
     699
     700    var array = @Object(this);
     701
     702    var constructor;
     703    if (@isArray(array)) {
     704        constructor = array.constructor;
     705        // We have this check so that if some array from a different global object
     706        // calls this map they don't get an array with the Array.prototype of the
     707        // other global object.
     708        if (@isArrayConstructor(constructor) && @Array !== constructor)
     709            constructor = @undefined;
     710        if (@isObject(constructor)) {
     711            constructor = constructor[@symbolSpecies];
     712            if (constructor === null)
     713                constructor = @Array;
     714        }
     715    }
     716    if (constructor === @undefined)
     717        constructor = @Array;
     718
     719    var result;
     720    if (arguments.length === 1
     721        && constructor === @Array
     722        && @isJSArray(array)
     723        && @isJSArray(first)
     724        // FIXME: these get_by_ids should be "in"s but using "in" here is a 10% regression.
     725        // https://bugs.webkit.org/show_bug.cgi?id=155590
     726        && array[@symbolIsConcatSpreadable] == @undefined
     727        && first[@symbolIsConcatSpreadable] == @undefined) {
     728
     729        result = @concatMemcpy(array, first);
     730        if (result !== null)
     731            return result;
     732    }
     733
     734    return @concatSlowPath.@apply({ array: array, species: constructor }, arguments);
     735}
     736
    649737function copyWithin(target, start /*, end */)
    650738{
Note: See TracChangeset for help on using the changeset viewer.