Changeset 191215 in webkit


Ignore:
Timestamp:
Oct 16, 2015, 3:18:42 PM (10 years ago)
Author:
[email protected]
Message:

Add Intrinsic Getters and use them to fix performance on the getters of TypedArray properties.
https://bugs.webkit.org/show_bug.cgi?id=149687

Patch by Keith Miller <[email protected]> on 2015-10-16
Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Add the ability to create intrinsic getters in both the inline cache and the DFG/FTL. When the
getter fetched by a GetById has an intrinsic we know about we add a new intrinsic access case.
Once we get to the DFG, we observe that the access case was an intrinsic and add an appropriate
GetByIdVariant. We then parse the intrinsic into an appropriate DFG node.

The first intrinsics are the new TypedArray prototype getters length, byteLength, and byteOffset.

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/GetByIdStatus.cpp:

(JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
(JSC::GetByIdStatus::computeFor):

  • bytecode/GetByIdVariant.cpp:

(JSC::GetByIdVariant::GetByIdVariant):
(JSC::GetByIdVariant::operator=):
(JSC::GetByIdVariant::canMergeIntrinsicStructures):
(JSC::GetByIdVariant::attemptToMerge):
(JSC::GetByIdVariant::dumpInContext):

  • bytecode/GetByIdVariant.h:

(JSC::GetByIdVariant::intrinsicFunction):
(JSC::GetByIdVariant::intrinsic):
(JSC::GetByIdVariant::callLinkStatus): Deleted.

  • bytecode/PolymorphicAccess.cpp:

(JSC::AccessGenerationState::addWatchpoint):
(JSC::AccessGenerationState::restoreScratch):
(JSC::AccessGenerationState::succeed):
(JSC::AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling):
(JSC::AccessGenerationState::preserveLiveRegistersToStackForCall):
(JSC::AccessGenerationState::restoreLiveRegistersFromStackForCall):
(JSC::AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException):
(JSC::AccessGenerationState::callSiteIndexForExceptionHandlingOrOriginal):
(JSC::AccessGenerationState::originalExceptionHandler):
(JSC::AccessGenerationState::originalCallSiteIndex):
(JSC::AccessCase::getIntrinsic):
(JSC::AccessCase::clone):
(JSC::AccessCase::visitWeak):
(JSC::AccessCase::generate):
(WTF::printInternal):
(JSC::AccessCase::AccessCase): Deleted.
(JSC::AccessCase::get): Deleted.
(JSC::AccessCase::replace): Deleted.
(JSC::AccessCase::transition): Deleted.

  • bytecode/PolymorphicAccess.h:

(JSC::AccessCase::isGet):
(JSC::AccessCase::isPut):
(JSC::AccessCase::isIn):
(JSC::AccessCase::intrinsicFunction):
(JSC::AccessCase::intrinsic):
(JSC::AccessGenerationState::AccessGenerationState):
(JSC::AccessGenerationState::liveRegistersForCall):
(JSC::AccessGenerationState::callSiteIndexForExceptionHandling):
(JSC::AccessGenerationState::numberOfStackBytesUsedForRegisterPreservation):
(JSC::AccessGenerationState::needsToRestoreRegistersIfException):
(JSC::AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite):

  • bytecode/PutByIdVariant.h:

(JSC::PutByIdVariant::intrinsic):

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGArrayMode.cpp:

(JSC::DFG::ArrayMode::alreadyChecked):
(JSC::DFG::arrayTypeToString):
(JSC::DFG::toTypedArrayType):
(JSC::DFG::refineTypedArrayType):
(JSC::DFG::permitsBoundsCheckLowering):

  • dfg/DFGArrayMode.h:

(JSC::DFG::ArrayMode::supportsLength):
(JSC::DFG::ArrayMode::isSomeTypedArrayView):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::attemptToInlineCall):
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
(JSC::DFG::ByteCodeParser::handleIntrinsicGetter):
(JSC::DFG::ByteCodeParser::load):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::presenceLike): Deleted.
(JSC::DFG::ByteCodeParser::store): Deleted.

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::convertToGetArrayLength): Deleted.
(JSC::DFG::FixupPhase::prependGetArrayLength): Deleted.
(JSC::DFG::FixupPhase::fixupChecksInBlock): Deleted.

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::tryGetFoldableView):

  • dfg/DFGPredictionPropagationPhase.cpp:

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

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::checkArray):
(JSC::DFG::SpeculativeJIT::compileGetArrayLength):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::DFG::LowerDFGToLLVM::compileGetArrayLength):

  • jit/IntrinsicEmitter.cpp: Added.

(JSC::AccessCase::canEmitIntrinsicGetter):
(JSC::AccessCase::emitIntrinsicGetter):

  • jit/Repatch.cpp:

(JSC::tryCacheGetByID):

  • runtime/Intrinsic.h:
  • runtime/JSArrayBufferView.cpp:

(JSC::JSArrayBufferView::put):
(JSC::JSArrayBufferView::defineOwnProperty):
(JSC::JSArrayBufferView::deleteProperty):
(JSC::JSArrayBufferView::getOwnNonIndexPropertyNames):
(JSC::JSArrayBufferView::getOwnPropertySlot): Deleted.
(JSC::JSArrayBufferView::finalize): Deleted.

  • runtime/JSDataView.cpp:

(JSC::JSDataView::getOwnPropertySlot):
(JSC::JSDataView::put):
(JSC::JSDataView::defineOwnProperty):
(JSC::JSDataView::deleteProperty):
(JSC::JSDataView::getOwnNonIndexPropertyNames):

  • runtime/JSDataView.h:
  • runtime/JSFunction.h:
  • runtime/JSFunctionInlines.h:

(JSC::JSFunction::intrinsic):

  • runtime/JSGenericTypedArrayView.h:
  • runtime/JSGenericTypedArrayViewInlines.h:

(JSC::JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot):
(JSC::JSGenericTypedArrayView<Adaptor>::defineOwnProperty):
(JSC::JSGenericTypedArrayView<Adaptor>::deleteProperty):
(JSC::JSGenericTypedArrayView<Adaptor>::getOwnPropertySlotByIndex): Deleted.
(JSC::JSGenericTypedArrayView<Adaptor>::visitChildren): Deleted.

  • runtime/JSObject.cpp:

(JSC::JSObject::putDirectNativeIntrinsicGetter):

  • runtime/JSObject.h:
  • runtime/JSTypedArrayViewPrototype.cpp:

(JSC::JSTypedArrayViewPrototype::finishCreation):

  • tests/stress/typedarray-add-property-to-base-object.js: Added.

(body.foo):
(body):

  • tests/stress/typedarray-bad-getter.js: Added.

(body.foo):
(body.get Bar):
(body):

  • tests/stress/typedarray-getter-on-self.js: Added.

(body.foo):
(body.bar):
(body.baz):
(body.get for):
(body):

  • tests/stress/typedarray-intrinsic-getters-change-prototype.js: Added.

(body.foo):
(body.bar):
(body.baz):
(body):

LayoutTests:

Fix test since typedarrays no longer have length as a own property.

  • js/dom/getOwnPropertyDescriptor-expected.txt:
  • js/resources/getOwnPropertyDescriptor.js:
Location:
trunk
Files:
5 added
35 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r191211 r191215  
     12015-10-16  Keith Miller  <[email protected]>
     2
     3        Add Intrinsic Getters and use them to fix performance on the getters of TypedArray properties.
     4        https://bugs.webkit.org/show_bug.cgi?id=149687
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Fix test since typedarrays no longer have length as a own property.
     9
     10        * js/dom/getOwnPropertyDescriptor-expected.txt:
     11        * js/resources/getOwnPropertyDescriptor.js:
     12
    1132015-10-16  Brent Fulgham  <[email protected]>
    214
  • trunk/LayoutTests/js/dom/getOwnPropertyDescriptor-expected.txt

    r185370 r191215  
    158158PASS Object.getOwnPropertyDescriptor(document.getElementsByClassName('pass'), 'length').enumerable is true
    159159PASS Object.getOwnPropertyDescriptor(document.getElementsByClassName('pass'), 'length').configurable is false
    160 PASS Object.getOwnPropertyDescriptor(canvasPixelArray, 'length').value is canvasPixelArray.length
    161 PASS Object.getOwnPropertyDescriptor(canvasPixelArray, 'length').hasOwnProperty('get') is false
    162 PASS Object.getOwnPropertyDescriptor(canvasPixelArray, 'length').hasOwnProperty('set') is false
    163 PASS Object.getOwnPropertyDescriptor(canvasPixelArray, 'length').enumerable is true
    164 PASS Object.getOwnPropertyDescriptor(canvasPixelArray, 'length').configurable is false
    165160PASS Object.getOwnPropertyDescriptor(canvasPixelArray, 0).value is canvasPixelArray[0]
    166161PASS Object.getOwnPropertyDescriptor(canvasPixelArray, 0).hasOwnProperty('get') is false
  • trunk/LayoutTests/js/resources/getOwnPropertyDescriptor.js

    r185370 r191215  
    5252var canvas = document.createElement("canvas");
    5353var canvasPixelArray = canvas.getContext("2d").createImageData(10,10).data;
    54 descriptorShouldBe("canvasPixelArray", "'length'", {writable: false, enumerable: true, configurable: false, value:"canvasPixelArray.length"});
    5554descriptorShouldBe("canvasPixelArray", "0", {writable: true, enumerable: true, configurable: false, value:"canvasPixelArray[0]"});
    5655var select = document.createElement("select");
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r191191 r191215  
    374374    jit/GCAwareJITStubRoutine.cpp
    375375    jit/HostCallReturnValue.cpp
     376    jit/IntrinsicEmitter.cpp
    376377    jit/JIT.cpp
    377378    jit/JITArithmetic.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r191212 r191215  
     12015-10-16  Keith Miller  <[email protected]>
     2
     3        Add Intrinsic Getters and use them to fix performance on the getters of TypedArray properties.
     4        https://bugs.webkit.org/show_bug.cgi?id=149687
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Add the ability to create intrinsic getters in both the inline cache and the DFG/FTL. When the
     9        getter fetched by a GetById has an intrinsic we know about we add a new intrinsic access case.
     10        Once we get to the DFG, we observe that the access case was an intrinsic and add an appropriate
     11        GetByIdVariant. We then parse the intrinsic into an appropriate DFG node.
     12
     13        The first intrinsics are the new TypedArray prototype getters length, byteLength, and byteOffset.
     14
     15        * CMakeLists.txt:
     16        * JavaScriptCore.xcodeproj/project.pbxproj:
     17        * bytecode/GetByIdStatus.cpp:
     18        (JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
     19        (JSC::GetByIdStatus::computeFor):
     20        * bytecode/GetByIdVariant.cpp:
     21        (JSC::GetByIdVariant::GetByIdVariant):
     22        (JSC::GetByIdVariant::operator=):
     23        (JSC::GetByIdVariant::canMergeIntrinsicStructures):
     24        (JSC::GetByIdVariant::attemptToMerge):
     25        (JSC::GetByIdVariant::dumpInContext):
     26        * bytecode/GetByIdVariant.h:
     27        (JSC::GetByIdVariant::intrinsicFunction):
     28        (JSC::GetByIdVariant::intrinsic):
     29        (JSC::GetByIdVariant::callLinkStatus): Deleted.
     30        * bytecode/PolymorphicAccess.cpp:
     31        (JSC::AccessGenerationState::addWatchpoint):
     32        (JSC::AccessGenerationState::restoreScratch):
     33        (JSC::AccessGenerationState::succeed):
     34        (JSC::AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling):
     35        (JSC::AccessGenerationState::preserveLiveRegistersToStackForCall):
     36        (JSC::AccessGenerationState::restoreLiveRegistersFromStackForCall):
     37        (JSC::AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException):
     38        (JSC::AccessGenerationState::callSiteIndexForExceptionHandlingOrOriginal):
     39        (JSC::AccessGenerationState::originalExceptionHandler):
     40        (JSC::AccessGenerationState::originalCallSiteIndex):
     41        (JSC::AccessCase::getIntrinsic):
     42        (JSC::AccessCase::clone):
     43        (JSC::AccessCase::visitWeak):
     44        (JSC::AccessCase::generate):
     45        (WTF::printInternal):
     46        (JSC::AccessCase::AccessCase): Deleted.
     47        (JSC::AccessCase::get): Deleted.
     48        (JSC::AccessCase::replace): Deleted.
     49        (JSC::AccessCase::transition): Deleted.
     50        * bytecode/PolymorphicAccess.h:
     51        (JSC::AccessCase::isGet):
     52        (JSC::AccessCase::isPut):
     53        (JSC::AccessCase::isIn):
     54        (JSC::AccessCase::intrinsicFunction):
     55        (JSC::AccessCase::intrinsic):
     56        (JSC::AccessGenerationState::AccessGenerationState):
     57        (JSC::AccessGenerationState::liveRegistersForCall):
     58        (JSC::AccessGenerationState::callSiteIndexForExceptionHandling):
     59        (JSC::AccessGenerationState::numberOfStackBytesUsedForRegisterPreservation):
     60        (JSC::AccessGenerationState::needsToRestoreRegistersIfException):
     61        (JSC::AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite):
     62        * bytecode/PutByIdVariant.h:
     63        (JSC::PutByIdVariant::intrinsic):
     64        * dfg/DFGAbstractInterpreterInlines.h:
     65        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     66        * dfg/DFGArrayMode.cpp:
     67        (JSC::DFG::ArrayMode::alreadyChecked):
     68        (JSC::DFG::arrayTypeToString):
     69        (JSC::DFG::toTypedArrayType):
     70        (JSC::DFG::refineTypedArrayType):
     71        (JSC::DFG::permitsBoundsCheckLowering):
     72        * dfg/DFGArrayMode.h:
     73        (JSC::DFG::ArrayMode::supportsLength):
     74        (JSC::DFG::ArrayMode::isSomeTypedArrayView):
     75        * dfg/DFGByteCodeParser.cpp:
     76        (JSC::DFG::ByteCodeParser::attemptToInlineCall):
     77        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
     78        (JSC::DFG::ByteCodeParser::handleIntrinsicGetter):
     79        (JSC::DFG::ByteCodeParser::load):
     80        (JSC::DFG::ByteCodeParser::handleGetById):
     81        (JSC::DFG::ByteCodeParser::presenceLike): Deleted.
     82        (JSC::DFG::ByteCodeParser::store): Deleted.
     83        * dfg/DFGClobberize.h:
     84        (JSC::DFG::clobberize):
     85        * dfg/DFGFixupPhase.cpp:
     86        (JSC::DFG::FixupPhase::fixupNode):
     87        (JSC::DFG::FixupPhase::convertToGetArrayLength): Deleted.
     88        (JSC::DFG::FixupPhase::prependGetArrayLength): Deleted.
     89        (JSC::DFG::FixupPhase::fixupChecksInBlock): Deleted.
     90        * dfg/DFGGraph.cpp:
     91        (JSC::DFG::Graph::tryGetFoldableView):
     92        * dfg/DFGPredictionPropagationPhase.cpp:
     93        (JSC::DFG::PredictionPropagationPhase::propagate):
     94        * dfg/DFGSpeculativeJIT.cpp:
     95        (JSC::DFG::SpeculativeJIT::checkArray):
     96        (JSC::DFG::SpeculativeJIT::compileGetArrayLength):
     97        * ftl/FTLCapabilities.cpp:
     98        (JSC::FTL::canCompile):
     99        * ftl/FTLLowerDFGToLLVM.cpp:
     100        (JSC::FTL::DFG::LowerDFGToLLVM::compileGetArrayLength):
     101        * jit/IntrinsicEmitter.cpp: Added.
     102        (JSC::AccessCase::canEmitIntrinsicGetter):
     103        (JSC::AccessCase::emitIntrinsicGetter):
     104        * jit/Repatch.cpp:
     105        (JSC::tryCacheGetByID):
     106        * runtime/Intrinsic.h:
     107        * runtime/JSArrayBufferView.cpp:
     108        (JSC::JSArrayBufferView::put):
     109        (JSC::JSArrayBufferView::defineOwnProperty):
     110        (JSC::JSArrayBufferView::deleteProperty):
     111        (JSC::JSArrayBufferView::getOwnNonIndexPropertyNames):
     112        (JSC::JSArrayBufferView::getOwnPropertySlot): Deleted.
     113        (JSC::JSArrayBufferView::finalize): Deleted.
     114        * runtime/JSDataView.cpp:
     115        (JSC::JSDataView::getOwnPropertySlot):
     116        (JSC::JSDataView::put):
     117        (JSC::JSDataView::defineOwnProperty):
     118        (JSC::JSDataView::deleteProperty):
     119        (JSC::JSDataView::getOwnNonIndexPropertyNames):
     120        * runtime/JSDataView.h:
     121        * runtime/JSFunction.h:
     122        * runtime/JSFunctionInlines.h:
     123        (JSC::JSFunction::intrinsic):
     124        * runtime/JSGenericTypedArrayView.h:
     125        * runtime/JSGenericTypedArrayViewInlines.h:
     126        (JSC::JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot):
     127        (JSC::JSGenericTypedArrayView<Adaptor>::defineOwnProperty):
     128        (JSC::JSGenericTypedArrayView<Adaptor>::deleteProperty):
     129        (JSC::JSGenericTypedArrayView<Adaptor>::getOwnPropertySlotByIndex): Deleted.
     130        (JSC::JSGenericTypedArrayView<Adaptor>::visitChildren): Deleted.
     131        * runtime/JSObject.cpp:
     132        (JSC::JSObject::putDirectNativeIntrinsicGetter):
     133        * runtime/JSObject.h:
     134        * runtime/JSTypedArrayViewPrototype.cpp:
     135        (JSC::JSTypedArrayViewPrototype::finishCreation):
     136        * tests/stress/typedarray-add-property-to-base-object.js: Added.
     137        (body.foo):
     138        (body):
     139        * tests/stress/typedarray-bad-getter.js: Added.
     140        (body.foo):
     141        (body.get Bar):
     142        (body):
     143        * tests/stress/typedarray-getter-on-self.js: Added.
     144        (body.foo):
     145        (body.bar):
     146        (body.baz):
     147        (body.get for):
     148        (body):
     149        * tests/stress/typedarray-intrinsic-getters-change-prototype.js: Added.
     150        (body.foo):
     151        (body.bar):
     152        (body.baz):
     153        (body):
     154
    11552015-10-16  Keith Miller  <[email protected]>
    2156
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r191191 r191215  
    17251725                C4F4B6F61A05C984005CAB76 /* objc_generator_templates.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D81A05C76F005CAB76 /* objc_generator_templates.py */; settings = {ATTRIBUTES = (Private, ); }; };
    17261726                DC00039319D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h in Headers */ = {isa = PBXBuildFile; fileRef = DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */; };
     1727                DE5A0A001BA3AC3E003D4424 /* IntrinsicEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE5A09FF1BA3AC3E003D4424 /* IntrinsicEmitter.cpp */; };
    17271728                DEA7E2441BBC677200D78440 /* JSTypedArrayViewPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53F256E11B87E28000B4B768 /* JSTypedArrayViewPrototype.cpp */; };
    17281729                DEA7E2451BBC677F00D78440 /* JSTypedArrayViewPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 53917E7C1B791106000EBD33 /* JSTypedArrayViewPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    36183619                D21202290AD4310C00ED79B6 /* DateConversion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DateConversion.h; sourceTree = "<group>"; };
    36193620                DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPreciseLocalClobberize.h; path = dfg/DFGPreciseLocalClobberize.h; sourceTree = "<group>"; };
     3621                DE5A09FF1BA3AC3E003D4424 /* IntrinsicEmitter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntrinsicEmitter.cpp; sourceTree = "<group>"; };
    36203622                E124A8F50E555775003091F1 /* OpaqueJSString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpaqueJSString.h; sourceTree = "<group>"; };
    36213623                E124A8F60E555775003091F1 /* OpaqueJSString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpaqueJSString.cpp; sourceTree = "<group>"; };
     
    41724174                                0F4680D014BBC5F800BFE272 /* HostCallReturnValue.cpp */,
    41734175                                0F4680D114BBC5F800BFE272 /* HostCallReturnValue.h */,
     4176                                DE5A09FF1BA3AC3E003D4424 /* IntrinsicEmitter.cpp */,
    41744177                                1429D92D0ED22D7000B89619 /* JIT.cpp */,
    41754178                                1429D92E0ED22D7000B89619 /* JIT.h */,
     
    75077510                                0F8F9446166764F100D61971 /* CodeOrigin.cpp in Sources */,
    75087511                                86B5826714D2796C00A9C306 /* CodeProfile.cpp in Sources */,
     7512                                DE5A0A001BA3AC3E003D4424 /* IntrinsicEmitter.cpp in Sources */,
    75097513                                86B5826914D2797000A9C306 /* CodeProfiling.cpp in Sources */,
    75107514                                0F8F943C1667631300D61971 /* CodeSpecializationKind.cpp in Sources */,
  • trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp

    r190561 r191215  
    208208            case ComplexGetStatus::Inlineable: {
    209209                std::unique_ptr<CallLinkStatus> callLinkStatus;
     210                JSFunction* intrinsicFunction = nullptr;
     211
    210212                switch (access.type()) {
    211213                case AccessCase::Load: {
     214                    break;
     215                }
     216                case AccessCase::IntrinsicGetter: {
     217                    intrinsicFunction = access.intrinsicFunction();
    212218                    break;
    213219                }
     
    228234                GetByIdVariant variant(
    229235                    StructureSet(structure), complexGetStatus.offset(),
    230                     complexGetStatus.conditionSet(), WTF::move(callLinkStatus));
    231                  
     236                    complexGetStatus.conditionSet(), WTF::move(callLinkStatus),
     237                    intrinsicFunction);
     238
    232239                if (!result.appendVariant(variant))
    233240                    return GetByIdStatus(slowPathState, true);
     
    315322            return GetByIdStatus(TakesSlowPath); // It's probably a prototype lookup. Give up on life for now, even though we could totally be way smarter about it.
    316323        if (attributes & Accessor)
    317             return GetByIdStatus(MakesCalls); // We could be smarter here, like strenght-reducing this to a Call.
     324            return GetByIdStatus(MakesCalls); // We could be smarter here, like strength-reducing this to a Call.
    318325       
    319326        if (!result.appendVariant(GetByIdVariant(structure, offset)))
  • trunk/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp

    r187780 r191215  
    3636    const StructureSet& structureSet, PropertyOffset offset,
    3737    const ObjectPropertyConditionSet& conditionSet,
    38     std::unique_ptr<CallLinkStatus> callLinkStatus)
     38    std::unique_ptr<CallLinkStatus> callLinkStatus,
     39    JSFunction* intrinsicFunction)
    3940    : m_structureSet(structureSet)
    4041    , m_conditionSet(conditionSet)
    4142    , m_offset(offset)
    4243    , m_callLinkStatus(WTF::move(callLinkStatus))
     44    , m_intrinsicFunction(intrinsicFunction)
    4345{
    4446    if (!structureSet.size()) {
     
    4648        ASSERT(conditionSet.isEmpty());
    4749    }
     50    if (intrinsicFunction)
     51        ASSERT(intrinsic() != NoIntrinsic);
    4852}
    4953                     
     
    6165    m_conditionSet = other.m_conditionSet;
    6266    m_offset = other.m_offset;
     67    m_intrinsicFunction = other.m_intrinsicFunction;
    6368    if (other.m_callLinkStatus)
    6469        m_callLinkStatus = std::make_unique<CallLinkStatus>(*other.m_callLinkStatus);
     
    6873}
    6974
     75inline bool GetByIdVariant::canMergeIntrinsicStructures(const GetByIdVariant& other) const
     76{
     77    if (m_intrinsicFunction != other.m_intrinsicFunction)
     78        return false;
     79    switch (intrinsic()) {
     80    case TypedArrayByteLengthIntrinsic: {
     81        // We can merge these sets as long as the element size of the two sets is the same.
     82        TypedArrayType thisType = (*m_structureSet.begin())->classInfo()->typedArrayStorageType;
     83        TypedArrayType otherType = (*other.m_structureSet.begin())->classInfo()->typedArrayStorageType;
     84
     85        ASSERT(isTypedView(thisType) && isTypedView(otherType));
     86
     87        return logElementSize(thisType) == logElementSize(otherType);
     88    }
     89
     90    default:
     91        return true;
     92    }
     93    RELEASE_ASSERT_NOT_REACHED();
     94}
     95
    7096bool GetByIdVariant::attemptToMerge(const GetByIdVariant& other)
    7197{
     
    7399        return false;
    74100    if (m_callLinkStatus || other.m_callLinkStatus)
     101        return false;
     102
     103    if (!canMergeIntrinsicStructures(other))
    75104        return false;
    76105
     
    108137    if (m_callLinkStatus)
    109138        out.print(", call = ", *m_callLinkStatus);
     139    if (m_intrinsicFunction)
     140        out.print(", intrinsic = ", *m_intrinsicFunction);
    110141    out.print(">");
    111142}
  • trunk/Source/JavaScriptCore/bytecode/GetByIdVariant.h

    r187780 r191215  
    4444        const StructureSet& structureSet = StructureSet(), PropertyOffset offset = invalidOffset,
    4545        const ObjectPropertyConditionSet& = ObjectPropertyConditionSet(),
    46         std::unique_ptr<CallLinkStatus> callLinkStatus = nullptr);
    47    
     46        std::unique_ptr<CallLinkStatus> = nullptr,
     47        JSFunction* = nullptr);
     48
    4849    ~GetByIdVariant();
    4950   
     
    6162    PropertyOffset offset() const { return m_offset; }
    6263    CallLinkStatus* callLinkStatus() const { return m_callLinkStatus.get(); }
    63    
     64    JSFunction* intrinsicFunction() const { return m_intrinsicFunction; }
     65    Intrinsic intrinsic() const { return m_intrinsicFunction ? m_intrinsicFunction->intrinsic() : NoIntrinsic; }
     66
    6467    bool attemptToMerge(const GetByIdVariant& other);
    6568   
     
    6972private:
    7073    friend class GetByIdStatus;
     74
     75    bool canMergeIntrinsicStructures(const GetByIdVariant&) const;
    7176   
    7277    StructureSet m_structureSet;
     
    7479    PropertyOffset m_offset;
    7580    std::unique_ptr<CallLinkStatus> m_callLinkStatus;
     81    JSFunction* m_intrinsicFunction;
    7682};
    7783
  • trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp

    r191016 r191215  
    4848static const bool verbose = false;
    4949
    50 struct AccessGenerationState {
    51     AccessGenerationState()
    52         : m_calculatedRegistersForCallAndExceptionHandling(false)
    53         , m_needsToRestoreRegistersIfException(false)
    54         , m_calculatedCallSiteIndex(false)
    55     {
    56     }
    57     CCallHelpers* jit { nullptr };
    58     ScratchRegisterAllocator* allocator;
    59     unsigned numberOfBytesUsedToPreserveReusedRegisters { 0 };
    60     PolymorphicAccess* access { nullptr };
    61     StructureStubInfo* stubInfo { nullptr };
    62     CCallHelpers::JumpList success;
    63     CCallHelpers::JumpList failAndRepatch;
    64     CCallHelpers::JumpList failAndIgnore;
    65     GPRReg baseGPR { InvalidGPRReg };
    66     JSValueRegs valueRegs;
    67     GPRReg scratchGPR { InvalidGPRReg };
    68     Vector<std::function<void(LinkBuffer&)>> callbacks;
    69     const Identifier* ident;
    70     std::unique_ptr<WatchpointsOnStructureStubInfo> watchpoints;
    71     Vector<WriteBarrier<JSCell>> weakReferences;
    72 
    73     Watchpoint* addWatchpoint(const ObjectPropertyCondition& condition = ObjectPropertyCondition())
    74     {
    75         return WatchpointsOnStructureStubInfo::ensureReferenceAndAddWatchpoint(
    76             watchpoints, jit->codeBlock(), stubInfo, condition);
    77     }
    78 
    79     void restoreScratch()
    80     {
    81         allocator->restoreReusedRegistersByPopping(*jit, numberOfBytesUsedToPreserveReusedRegisters);
    82     }
    83 
    84     void succeed()
    85     {
    86         restoreScratch();
    87         success.append(jit->jump());
    88     }
    89 
    90     void calculateLiveRegistersForCallAndExceptionHandling()
    91     {
    92         if (!m_calculatedRegistersForCallAndExceptionHandling) {
    93             m_calculatedRegistersForCallAndExceptionHandling = true;
    94 
    95             m_liveRegistersToPreserveAtExceptionHandlingCallSite = jit->codeBlock()->jitCode()->liveRegistersToPreserveAtExceptionHandlingCallSite(jit->codeBlock(), stubInfo->callSiteIndex);
    96             m_needsToRestoreRegistersIfException = m_liveRegistersToPreserveAtExceptionHandlingCallSite.numberOfSetRegisters() > 0;
    97             if (m_needsToRestoreRegistersIfException)
    98                 RELEASE_ASSERT(JITCode::isOptimizingJIT(jit->codeBlock()->jitType()));
    99 
    100             m_liveRegistersForCall = RegisterSet(m_liveRegistersToPreserveAtExceptionHandlingCallSite, allocator->usedRegisters());
    101             m_liveRegistersForCall.exclude(RegisterSet::registersToNotSaveForCall());
    102         }
    103     }
    104 
    105     void preserveLiveRegistersToStackForCall()
    106     {
    107         unsigned extraStackPadding = 0;
    108         unsigned numberOfStackBytesUsedForRegisterPreservation = ScratchRegisterAllocator::preserveRegistersToStackForCall(*jit, liveRegistersForCall(), extraStackPadding);
    109         if (m_numberOfStackBytesUsedForRegisterPreservation != std::numeric_limits<unsigned>::max())
    110             RELEASE_ASSERT(numberOfStackBytesUsedForRegisterPreservation == m_numberOfStackBytesUsedForRegisterPreservation);
    111         m_numberOfStackBytesUsedForRegisterPreservation = numberOfStackBytesUsedForRegisterPreservation;
    112     }
    113 
    114     void restoreLiveRegistersFromStackForCall(bool isGetter)
    115     {
    116         RegisterSet dontRestore;
    117         if (isGetter) {
    118             // This is the result value. We don't want to overwrite the result with what we stored to the stack.
    119             // We sometimes have to store it to the stack just in case we throw an exception and need the original value.
    120             dontRestore.set(valueRegs);
    121         }
    122         restoreLiveRegistersFromStackForCall(dontRestore);
    123     }
    124 
    125     void restoreLiveRegistersFromStackForCallWithThrownException()
    126     {
    127         // Even if we're a getter, we don't want to ignore the result value like we normally do
    128         // because the getter threw, and therefore, didn't return a value that means anything.
    129         // Instead, we want to restore that register to what it was upon entering the getter
    130         // inline cache. The subtlety here is if the base and the result are the same register,
    131         // and the getter threw, we want OSR exit to see the original base value, not the result
    132         // of the getter call.
    133         RegisterSet dontRestore = liveRegistersForCall();
    134         // As an optimization here, we only need to restore what is live for exception handling.
    135         // We can construct the dontRestore set to accomplish this goal by having it contain only
    136         // what is live for call but not live for exception handling. By ignoring things that are
    137         // only live at the call but not the exception handler, we will only restore things live
    138         // at the exception handler.
    139         dontRestore.exclude(liveRegistersToPreserveAtExceptionHandlingCallSite());
    140         restoreLiveRegistersFromStackForCall(dontRestore);
    141     }
    142 
    143     void restoreLiveRegistersFromStackForCall(const RegisterSet& dontRestore)
    144     {
    145         unsigned extraStackPadding = 0;
    146         ScratchRegisterAllocator::restoreRegistersFromStackForCall(*jit, liveRegistersForCall(), dontRestore, m_numberOfStackBytesUsedForRegisterPreservation, extraStackPadding);
    147     }
    148 
    149     const RegisterSet& liveRegistersForCall()
    150     {
    151         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
    152         return m_liveRegistersForCall;
    153     }
    154 
    155     CallSiteIndex callSiteIndexForExceptionHandlingOrOriginal()
    156     {
    157         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
    158 
    159         if (!m_calculatedCallSiteIndex) {
    160             m_calculatedCallSiteIndex = true;
    161 
    162             if (m_needsToRestoreRegistersIfException)
    163                 m_callSiteIndex = jit->codeBlock()->newExceptionHandlingCallSiteIndex(stubInfo->callSiteIndex);
    164             else
    165                 m_callSiteIndex = originalCallSiteIndex();
    166         }
    167 
    168         return m_callSiteIndex;
    169     }
    170 
    171     CallSiteIndex callSiteIndexForExceptionHandling()
    172     {
    173         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
    174         RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
    175         RELEASE_ASSERT(m_calculatedCallSiteIndex);
    176         return m_callSiteIndex;
    177     }
    178 
    179     const HandlerInfo& originalExceptionHandler() const
    180     {
    181         RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
    182         HandlerInfo* exceptionHandler = jit->codeBlock()->handlerForIndex(stubInfo->callSiteIndex.bits());
    183         RELEASE_ASSERT(exceptionHandler);
    184         return *exceptionHandler;
    185     }
    186 
    187     unsigned numberOfStackBytesUsedForRegisterPreservation() const
    188     {
    189         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
    190         return m_numberOfStackBytesUsedForRegisterPreservation;
    191     }
    192 
    193     bool needsToRestoreRegistersIfException() const { return m_needsToRestoreRegistersIfException; }
    194     CallSiteIndex originalCallSiteIndex() const { return stubInfo->callSiteIndex; }
    195 
    196 private:
    197     const RegisterSet& liveRegistersToPreserveAtExceptionHandlingCallSite()
    198     {
    199         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
    200         return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
    201     }
    202    
    203     RegisterSet m_liveRegistersToPreserveAtExceptionHandlingCallSite;
    204     RegisterSet m_liveRegistersForCall;
    205     CallSiteIndex m_callSiteIndex { CallSiteIndex(std::numeric_limits<unsigned>::max()) };
    206     unsigned m_numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits<unsigned>::max() };
    207     bool m_calculatedRegistersForCallAndExceptionHandling : 1;
    208     bool m_needsToRestoreRegistersIfException : 1;
    209     bool m_calculatedCallSiteIndex : 1;
    210 };
     50Watchpoint* AccessGenerationState::addWatchpoint(const ObjectPropertyCondition& condition)
     51{
     52    return WatchpointsOnStructureStubInfo::ensureReferenceAndAddWatchpoint(
     53        watchpoints, jit->codeBlock(), stubInfo, condition);
     54}
     55
     56void AccessGenerationState::restoreScratch()
     57{
     58    allocator->restoreReusedRegistersByPopping(*jit, numberOfBytesUsedToPreserveReusedRegisters);
     59}
     60
     61void AccessGenerationState::succeed()
     62{
     63    restoreScratch();
     64    success.append(jit->jump());
     65}
     66
     67void AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling()
     68{
     69    if (!m_calculatedRegistersForCallAndExceptionHandling) {
     70        m_calculatedRegistersForCallAndExceptionHandling = true;
     71
     72        m_liveRegistersToPreserveAtExceptionHandlingCallSite = jit->codeBlock()->jitCode()->liveRegistersToPreserveAtExceptionHandlingCallSite(jit->codeBlock(), stubInfo->callSiteIndex);
     73        m_needsToRestoreRegistersIfException = m_liveRegistersToPreserveAtExceptionHandlingCallSite.numberOfSetRegisters() > 0;
     74        if (m_needsToRestoreRegistersIfException)
     75            RELEASE_ASSERT(JITCode::isOptimizingJIT(jit->codeBlock()->jitType()));
     76
     77        m_liveRegistersForCall = RegisterSet(m_liveRegistersToPreserveAtExceptionHandlingCallSite, allocator->usedRegisters());
     78        m_liveRegistersForCall.exclude(RegisterSet::registersToNotSaveForCall());
     79    }
     80}
     81
     82void AccessGenerationState::preserveLiveRegistersToStackForCall()
     83{
     84    unsigned extraStackPadding = 0;
     85    unsigned numberOfStackBytesUsedForRegisterPreservation = ScratchRegisterAllocator::preserveRegistersToStackForCall(*jit, liveRegistersForCall(), extraStackPadding);
     86    if (m_numberOfStackBytesUsedForRegisterPreservation != std::numeric_limits<unsigned>::max())
     87        RELEASE_ASSERT(numberOfStackBytesUsedForRegisterPreservation == m_numberOfStackBytesUsedForRegisterPreservation);
     88    m_numberOfStackBytesUsedForRegisterPreservation = numberOfStackBytesUsedForRegisterPreservation;
     89}
     90
     91void AccessGenerationState::restoreLiveRegistersFromStackForCall(bool isGetter)
     92{
     93    RegisterSet dontRestore;
     94    if (isGetter) {
     95        // This is the result value. We don't want to overwrite the result with what we stored to the stack.
     96        // We sometimes have to store it to the stack just in case we throw an exception and need the original value.
     97        dontRestore.set(valueRegs);
     98    }
     99    restoreLiveRegistersFromStackForCall(dontRestore);
     100}
     101
     102void AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException()
     103{
     104    // Even if we're a getter, we don't want to ignore the result value like we normally do
     105    // because the getter threw, and therefore, didn't return a value that means anything.
     106    // Instead, we want to restore that register to what it was upon entering the getter
     107    // inline cache. The subtlety here is if the base and the result are the same register,
     108    // and the getter threw, we want OSR exit to see the original base value, not the result
     109    // of the getter call.
     110    RegisterSet dontRestore = liveRegistersForCall();
     111    // As an optimization here, we only need to restore what is live for exception handling.
     112    // We can construct the dontRestore set to accomplish this goal by having it contain only
     113    // what is live for call but not live for exception handling. By ignoring things that are
     114    // only live at the call but not the exception handler, we will only restore things live
     115    // at the exception handler.
     116    dontRestore.exclude(liveRegistersToPreserveAtExceptionHandlingCallSite());
     117    restoreLiveRegistersFromStackForCall(dontRestore);
     118}
     119
     120void AccessGenerationState::restoreLiveRegistersFromStackForCall(const RegisterSet& dontRestore)
     121{
     122    unsigned extraStackPadding = 0;
     123    ScratchRegisterAllocator::restoreRegistersFromStackForCall(*jit, liveRegistersForCall(), dontRestore, m_numberOfStackBytesUsedForRegisterPreservation, extraStackPadding);
     124}
     125
     126CallSiteIndex AccessGenerationState::callSiteIndexForExceptionHandlingOrOriginal()
     127{
     128    RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
     129
     130    if (!m_calculatedCallSiteIndex) {
     131        m_calculatedCallSiteIndex = true;
     132
     133        if (m_needsToRestoreRegistersIfException)
     134            m_callSiteIndex = jit->codeBlock()->newExceptionHandlingCallSiteIndex(stubInfo->callSiteIndex);
     135        else
     136            m_callSiteIndex = originalCallSiteIndex();
     137    }
     138
     139    return m_callSiteIndex;
     140}
     141
     142const HandlerInfo& AccessGenerationState::originalExceptionHandler() const
     143{
     144    RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
     145    HandlerInfo* exceptionHandler = jit->codeBlock()->handlerForIndex(stubInfo->callSiteIndex.bits());
     146    RELEASE_ASSERT(exceptionHandler);
     147    return *exceptionHandler;
     148}
     149
     150CallSiteIndex AccessGenerationState::originalCallSiteIndex() const { return stubInfo->callSiteIndex; }
    211151
    212152AccessCase::AccessCase()
     
    316256
    317257    result->m_type = type;
     258
     259    return result;
     260}
     261
     262std::unique_ptr<AccessCase> AccessCase::getIntrinsic(
     263    VM& vm, JSCell* owner, JSFunction* getter, PropertyOffset offset,
     264    Structure* structure, const ObjectPropertyConditionSet& conditionSet)
     265{
     266    std::unique_ptr<AccessCase> result(new AccessCase());
     267
     268    result->m_type = IntrinsicGetter;
     269    result->m_structure.set(vm, owner, structure);
     270    result->m_conditionSet = conditionSet;
     271    result->m_offset = offset;
     272
     273    result->m_rareData = std::make_unique<RareData>();
     274    result->m_rareData->intrinsicFunction.set(vm, owner, getter);
    318275
    319276    return result;
     
    356313        result->m_rareData->customAccessor.opaque = rareData->customAccessor.opaque;
    357314        result->m_rareData->customSlotBase = rareData->customSlotBase;
     315        result->m_rareData->intrinsicFunction = rareData->intrinsicFunction;
    358316    }
    359317    return result;
     
    440398            m_rareData->callLinkInfo->visitWeak(vm);
    441399        if (m_rareData->customSlotBase && !Heap::isMarked(m_rareData->customSlotBase.get()))
     400            return false;
     401        if (m_rareData->intrinsicFunction && !Heap::isMarked(m_rareData->intrinsicFunction.get()))
    442402            return false;
    443403    }
     
    11071067        state.succeed();
    11081068        return;
     1069    }
     1070
     1071    case IntrinsicGetter: {
     1072        RELEASE_ASSERT(isValidOffset(offset()));
     1073
     1074        // We need to ensure the getter value does not move from under us. Note that GetterSetters
     1075        // are immutable so we just need to watch the property not any value inside it.
     1076        Structure* currStructure;
     1077        if (m_conditionSet.isEmpty())
     1078            currStructure = structure();
     1079        else
     1080            currStructure = m_conditionSet.slotBaseCondition().object()->structure();
     1081        currStructure->startWatchingPropertyForReplacements(vm, offset());
     1082
     1083        emitIntrinsicGetter(state);
     1084        return;
    11091085    } }
    11101086   
     
    14421418        out.print("CustomSetter");
    14431419        return;
     1420    case AccessCase::IntrinsicGetter:
     1421        out.print("IntrinsicGetter");
     1422        return;
    14441423    case AccessCase::InHit:
    14451424        out.print("InHit");
  • trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h

    r190735 r191215  
    3030
    3131#include "CodeOrigin.h"
     32#include "JSFunctionInlines.h"
    3233#include "MacroAssembler.h"
    3334#include "ObjectPropertyConditionSet.h"
     
    4243class StructureStubInfo;
    4344class WatchpointsOnStructureStubInfo;
     45class ScratchRegisterAllocator;
    4446
    4547struct AccessGenerationState;
     
    5860        CustomGetter,
    5961        CustomSetter,
     62        IntrinsicGetter,
    6063        InHit,
    6164        InMiss,
     
    7881        case Getter:
    7982        case CustomGetter:
     83        case IntrinsicGetter:
    8084        case ArrayLength:
    8185        case StringLength:
     
    9195        case Getter:
    9296        case CustomGetter:
     97        case IntrinsicGetter:
    9398        case InHit:
    9499        case InMiss:
     
    111116        case Getter:
    112117        case CustomGetter:
     118        case IntrinsicGetter:
    113119        case Transition:
    114120        case Replace:
     
    148154
    149155    static std::unique_ptr<AccessCase> getLength(VM&, JSCell* owner, AccessType);
     156    static std::unique_ptr<AccessCase> getIntrinsic(VM&, JSCell* owner, JSFunction* intrinsic, PropertyOffset, Structure*, const ObjectPropertyConditionSet&);
    150157   
    151158    static std::unique_ptr<AccessCase> fromStructureStubInfo(VM&, JSCell* owner, StructureStubInfo&);
     
    174181   
    175182    ObjectPropertyConditionSet conditionSet() const { return m_conditionSet; }
     183    JSFunction* intrinsicFunction() const
     184    {
     185        ASSERT(type() == IntrinsicGetter && m_rareData);
     186        return m_rareData->intrinsicFunction.get();
     187    }
     188    Intrinsic intrinsic() const
     189    {
     190        return intrinsicFunction()->intrinsic();
     191    }
    176192
    177193    WatchpointSet* additionalSet() const
     
    221237    bool couldStillSucceed() const;
    222238
     239    static bool canEmitIntrinsicGetter(JSFunction*, Structure*);
     240
    223241    // If this method returns true, then it's a good idea to remove 'other' from the access once 'this'
    224242    // is added. This method assumes that in case of contradictions, 'this' represents a newer, and so
     
    243261    // Fall through on success, add a jump to the failure list on failure.
    244262    void generate(AccessGenerationState&);
     263    void emitIntrinsicGetter(AccessGenerationState&);
    245264   
    246265    AccessType m_type { Load };
     
    272291        } customAccessor;
    273292        WriteBarrier<JSObject> customSlotBase;
     293        WriteBarrier<JSFunction> intrinsicFunction;
    274294    };
    275295
     
    321341};
    322342
     343struct AccessGenerationState {
     344    AccessGenerationState()
     345    : m_calculatedRegistersForCallAndExceptionHandling(false)
     346    , m_needsToRestoreRegistersIfException(false)
     347    , m_calculatedCallSiteIndex(false)
     348    {
     349    }
     350    CCallHelpers* jit { nullptr };
     351    ScratchRegisterAllocator* allocator;
     352    unsigned numberOfBytesUsedToPreserveReusedRegisters { 0 };
     353    PolymorphicAccess* access { nullptr };
     354    StructureStubInfo* stubInfo { nullptr };
     355    MacroAssembler::JumpList success;
     356    MacroAssembler::JumpList failAndRepatch;
     357    MacroAssembler::JumpList failAndIgnore;
     358    GPRReg baseGPR { InvalidGPRReg };
     359    JSValueRegs valueRegs;
     360    GPRReg scratchGPR { InvalidGPRReg };
     361    Vector<std::function<void(LinkBuffer&)>> callbacks;
     362    const Identifier* ident;
     363    std::unique_ptr<WatchpointsOnStructureStubInfo> watchpoints;
     364    Vector<WriteBarrier<JSCell>> weakReferences;
     365
     366    Watchpoint* addWatchpoint(const ObjectPropertyCondition& = ObjectPropertyCondition());
     367
     368    void restoreScratch();
     369    void succeed();
     370
     371    void calculateLiveRegistersForCallAndExceptionHandling();
     372
     373    void preserveLiveRegistersToStackForCall();
     374
     375    void restoreLiveRegistersFromStackForCall(bool isGetter);
     376    void restoreLiveRegistersFromStackForCallWithThrownException();
     377    void restoreLiveRegistersFromStackForCall(const RegisterSet& dontRestore);
     378
     379    const RegisterSet& liveRegistersForCall()
     380    {
     381        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
     382        return m_liveRegistersForCall;
     383    }
     384
     385    CallSiteIndex callSiteIndexForExceptionHandlingOrOriginal();
     386    CallSiteIndex callSiteIndexForExceptionHandling()
     387    {
     388        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
     389        RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
     390        RELEASE_ASSERT(m_calculatedCallSiteIndex);
     391        return m_callSiteIndex;
     392    }
     393
     394    const HandlerInfo& originalExceptionHandler() const;
     395    unsigned numberOfStackBytesUsedForRegisterPreservation() const
     396    {
     397        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
     398        return m_numberOfStackBytesUsedForRegisterPreservation;
     399    }
     400
     401    bool needsToRestoreRegistersIfException() const { return m_needsToRestoreRegistersIfException; }
     402    CallSiteIndex originalCallSiteIndex() const;
     403   
     404private:
     405    const RegisterSet& liveRegistersToPreserveAtExceptionHandlingCallSite()
     406    {
     407        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
     408        return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
     409    }
     410   
     411    RegisterSet m_liveRegistersToPreserveAtExceptionHandlingCallSite;
     412    RegisterSet m_liveRegistersForCall;
     413    CallSiteIndex m_callSiteIndex { CallSiteIndex(std::numeric_limits<unsigned>::max()) };
     414    unsigned m_numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits<unsigned>::max() };
     415    bool m_calculatedRegistersForCallAndExceptionHandling : 1;
     416    bool m_needsToRestoreRegistersIfException : 1;
     417    bool m_calculatedCallSiteIndex : 1;
     418};
     419
    323420} // namespace JSC
    324421
  • trunk/Source/JavaScriptCore/bytecode/PutByIdVariant.h

    r190076 r191215  
    111111    const ObjectPropertyConditionSet& conditionSet() const { return m_conditionSet; }
    112112   
     113    // We don't support intrinsics for Setters (it would be sweet if we did) but we need this for templated helpers.
     114    Intrinsic intrinsic() const { return NoIntrinsic; }
     115   
    113116    PropertyOffset offset() const
    114117    {
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r190896 r191215  
    20222022        case Array::Float64Array:
    20232023            filter(node->child1(), SpecFloat64Array);
     2024            break;
     2025        case Array::AnyTypedArray:
     2026            filter(node->child1(), SpecTypedArrayView);
    20242027            break;
    20252028        default:
  • trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp

    r188432 r191215  
    486486    case Array::Float64Array:
    487487        return speculationChecked(value.m_type, SpecFloat64Array);
    488        
     488
     489    case Array::AnyTypedArray:
     490        return speculationChecked(value.m_type, SpecTypedArrayView);
     491
    489492    case Array::SelectUsingPredictions:
    490493    case Array::Unprofiled:
     
    546549    case Array::Float64Array:
    547550        return "Float64Array";
     551    case Array::AnyTypedArray:
     552        return "AnyTypedArray";
    548553    default:
    549554        // Better to return something then it is to crash. Remember, this method
     
    640645    case Array::Float64Array:
    641646        return TypeFloat64;
     647    case Array::AnyTypedArray:
     648        RELEASE_ASSERT_NOT_REACHED();
     649        return NotTypedArray;
    642650    default:
    643651        return NotTypedArray;
     
    671679}
    672680
     681Array::Type refineTypedArrayType(Array::Type oldType, TypedArrayType newType)
     682{
     683    if (oldType == Array::Generic)
     684        return oldType;
     685    Array::Type newArrayType = toArrayType(newType);
     686    if (newArrayType == Array::Generic)
     687        return newArrayType;
     688
     689    if (oldType != newArrayType)
     690        return Array::AnyTypedArray;
     691    return oldType;
     692}
     693
    673694bool permitsBoundsCheckLowering(Array::Type type)
    674695{
     
    686707    case Array::Float32Array:
    687708    case Array::Float64Array:
     709    case Array::AnyTypedArray:
    688710        return true;
    689711    default:
  • trunk/Source/JavaScriptCore/dfg/DFGArrayMode.h

    r188432 r191215  
    7878    Uint32Array,
    7979    Float32Array,
    80     Float64Array
     80    Float64Array,
     81    AnyTypedArray
    8182};
    8283
     
    111112TypedArrayType toTypedArrayType(Array::Type);
    112113Array::Type toArrayType(TypedArrayType);
     114Array::Type refineTypedArrayType(Array::Type, TypedArrayType);
    113115
    114116bool permitsBoundsCheckLowering(Array::Type);
     
    355357        case Array::ForceExit:
    356358        case Array::Generic:
     359        // TypedArrays do not have a self length property as of ES6.
     360        case Array::Int8Array:
     361        case Array::Int16Array:
     362        case Array::Int32Array:
     363        case Array::Uint8Array:
     364        case Array::Uint8ClampedArray:
     365        case Array::Uint16Array:
     366        case Array::Uint32Array:
     367        case Array::Float32Array:
     368        case Array::Float64Array:
    357369            return false;
    358370        case Array::Int32:
     
    431443        return toTypedArrayType(type());
    432444    }
     445
     446    bool isSomeTypedArrayView() const
     447    {
     448        return type() == Array::AnyTypedArray || isTypedView(typedArrayType());
     449    }
    433450   
    434451    bool operator==(const ArrayMode& other) const
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r191058 r191215  
    202202    // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call.
    203203    template<typename ChecksFunctor>
    204     bool handleIntrinsic(int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks);
     204    bool handleIntrinsicCall(int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks);
     205    template<typename ChecksFunctor>
     206    bool handleIntrinsicGetter(int resultOperand, const GetByIdVariant& intrinsicVariant, Node* thisNode, const ChecksFunctor& insertChecks);
    205207    template<typename ChecksFunctor>
    206208    bool handleTypedArrayConstructor(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType, const ChecksFunctor& insertChecks);
     
    15911593        Intrinsic intrinsic = callee.intrinsicFor(specializationKind);
    15921594        if (intrinsic != NoIntrinsic) {
    1593             if (handleIntrinsic(resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction, insertChecksWithAccounting)) {
     1595            if (handleIntrinsicCall(resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction, insertChecksWithAccounting)) {
    15941596                RELEASE_ASSERT(didInsertChecks);
    15951597                addToGraph(Phantom, callTargetNode);
     
    19811983
    19821984template<typename ChecksFunctor>
    1983 bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks)
     1985bool ByteCodeParser::handleIntrinsicCall(int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks)
    19841986{
    19851987    switch (intrinsic) {
     1988
     1989    // Intrinsic Functions:
     1990
    19861991    case AbsIntrinsic: {
    19871992        if (argumentCountIncludingThis == 1) { // Math.abs()
     
    22672272        return false;
    22682273    }
     2274}
     2275
     2276template<typename ChecksFunctor>
     2277bool ByteCodeParser::handleIntrinsicGetter(int resultOperand, const GetByIdVariant& variant, Node* thisNode, const ChecksFunctor& insertChecks)
     2278{
     2279    switch (variant.intrinsic()) {
     2280    case TypedArrayByteLengthIntrinsic: {
     2281        insertChecks();
     2282
     2283        TypedArrayType type = (*variant.structureSet().begin())->classInfo()->typedArrayStorageType;
     2284        Array::Type arrayType = toArrayType(type);
     2285        size_t logSize = logElementSize(type);
     2286
     2287        variant.structureSet().forEach([&] (Structure* structure) {
     2288            TypedArrayType curType = structure->classInfo()->typedArrayStorageType;
     2289            ASSERT(logSize == logElementSize(curType));
     2290            arrayType = refineTypedArrayType(arrayType, curType);
     2291            ASSERT(arrayType != Array::Generic);
     2292        });
     2293
     2294        Node* lengthNode = addToGraph(GetArrayLength, OpInfo(ArrayMode(arrayType).asWord()), thisNode);
     2295
     2296        if (!logSize) {
     2297            set(VirtualRegister(resultOperand), lengthNode);
     2298            return true;
     2299        }
     2300
     2301        // We can use a BitLShift here because typed arrays will never have a byteLength
     2302        // that overflows int32.
     2303        Node* shiftNode = jsConstant(jsNumber(logSize));
     2304        set(VirtualRegister(resultOperand), addToGraph(BitLShift, lengthNode, shiftNode));
     2305
     2306        return true;
     2307    }
     2308
     2309    case TypedArrayLengthIntrinsic: {
     2310        insertChecks();
     2311
     2312        TypedArrayType type = (*variant.structureSet().begin())->classInfo()->typedArrayStorageType;
     2313        Array::Type arrayType = toArrayType(type);
     2314
     2315        variant.structureSet().forEach([&] (Structure* structure) {
     2316            TypedArrayType curType = structure->classInfo()->typedArrayStorageType;
     2317            arrayType = refineTypedArrayType(arrayType, curType);
     2318            ASSERT(arrayType != Array::Generic);
     2319        });
     2320
     2321        set(VirtualRegister(resultOperand), addToGraph(GetArrayLength, OpInfo(ArrayMode(arrayType).asWord()), thisNode));
     2322
     2323        return true;
     2324
     2325    }
     2326
     2327    case TypedArrayByteOffsetIntrinsic: {
     2328        insertChecks();
     2329
     2330        TypedArrayType type = (*variant.structureSet().begin())->classInfo()->typedArrayStorageType;
     2331        Array::Type arrayType = toArrayType(type);
     2332
     2333        variant.structureSet().forEach([&] (Structure* structure) {
     2334            TypedArrayType curType = structure->classInfo()->typedArrayStorageType;
     2335            arrayType = refineTypedArrayType(arrayType, curType);
     2336            ASSERT(arrayType != Array::Generic);
     2337        });
     2338
     2339        set(VirtualRegister(resultOperand), addToGraph(GetTypedArrayByteOffset, OpInfo(ArrayMode(arrayType).asWord()), thisNode));
     2340
     2341        return true;
     2342    }
     2343
     2344    default:
     2345        return false;
     2346    }
     2347    RELEASE_ASSERT_NOT_REACHED();
    22692348}
    22702349
     
    26932772    SpeculatedType loadPrediction;
    26942773    NodeType loadOp;
    2695     if (variant.callLinkStatus()) {
     2774    if (variant.callLinkStatus() || variant.intrinsic() != NoIntrinsic) {
    26962775        loadPrediction = SpecCellOther;
    26972776        loadOp = GetGetterSetterByOffset;
     
    27642843        //    of checks and those checks are not watchpointable.
    27652844        for (const GetByIdVariant& variant : getByIdStatus.variants()) {
     2845            if (variant.intrinsic() != NoIntrinsic) {
     2846                set(VirtualRegister(destinationOperand),
     2847                    addToGraph(getById, OpInfo(identifierNumber), OpInfo(prediction), base));
     2848                return;
     2849            }
     2850
    27662851            if (variant.conditionSet().isEmpty()) {
    27672852                cases.append(
     
    28062891    if (m_graph.compilation())
    28072892        m_graph.compilation()->noticeInlinedGetById();
    2808    
    2809     if (!variant.callLinkStatus()) {
     2893
     2894    if (!variant.callLinkStatus() && variant.intrinsic() == NoIntrinsic) {
    28102895        set(VirtualRegister(destinationOperand), loadedValue);
    28112896        return;
     
    28132898   
    28142899    Node* getter = addToGraph(GetGetter, loadedValue);
    2815    
     2900
     2901    if (handleIntrinsicGetter(destinationOperand, variant, base,
     2902            [&] () {
     2903                addToGraph(CheckCell, OpInfo(m_graph.freeze(variant.intrinsicFunction())), getter, base);
     2904            })) {
     2905        addToGraph(Phantom, getter);
     2906        return;
     2907    }
     2908
     2909    if (variant.intrinsic() != NoIntrinsic)
     2910        ASSERT(variant.intrinsic() == NoIntrinsic);
     2911
    28162912    // Make a call. We don't try to get fancy with using the smallest operand number because
    28172913    // the stack layout phase should compress the stack anyway.
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r190896 r191215  
    576576            def(HeapLocation(IndexedPropertyLoc, TypedArrayProperties, node->child1(), node->child2()), LazyNode(node));
    577577            return;
     578        // We should not get an AnyTypedArray in a GetByVal as AnyTypedArray is only created from intrinsics, which
     579        // are only added from Inline Caching a GetById.
     580        case Array::AnyTypedArray:
     581            DFG_CRASH(graph, node, "impossible array mode for get");
     582            return;
    578583        }
    579584        RELEASE_ASSERT_NOT_REACHED();
     
    680685            // https://bugs.webkit.org/show_bug.cgi?id=134737
    681686            return;
     687        case Array::AnyTypedArray:
    682688        case Array::String:
    683689        case Array::DirectArguments:
     
    819825            def(PureValue(node, mode.asWord()));
    820826            return;
    821            
     827
    822828        case Array::DirectArguments:
    823829        case Array::ScopedArguments:
     
    825831            def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
    826832            return;
    827            
     833
    828834        default:
    829             ASSERT(mode.typedArrayType() != NotTypedArray);
     835            ASSERT(mode.isSomeTypedArrayView());
    830836            read(MiscFields);
    831837            def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r190896 r191215  
    10371037                    break;
    10381038                }
    1039                 if (uid == vm().propertyNames->byteLength.impl()) {
    1040                     attemptToMakeGetTypedArrayByteLength(node);
    1041                     break;
    1042                 }
    1043                 if (uid == vm().propertyNames->byteOffset.impl()) {
    1044                     attemptToMakeGetTypedArrayByteOffset(node);
    1045                     break;
    1046                 }
    10471039            }
    10481040            fixEdge<CellUse>(node->child1());
     
    11641156        }
    11651157
    1166         case GetArrayLength:
     1158        case GetArrayLength: {
     1159            fixEdge<KnownCellUse>(node->child1());
     1160            break;
     1161        }
     1162
     1163        case GetTypedArrayByteOffset: {
     1164            fixEdge<KnownCellUse>(node->child1());
     1165            break;
     1166        }
     1167
    11671168        case Phi:
    11681169        case Upsilon:
    11691170        case GetIndexedPropertyStorage:
    1170         case GetTypedArrayByteOffset:
    11711171        case LastNodeType:
    11721172        case CheckTierUpInLoop:
     
    20652065        return true;
    20662066    }
    2067    
    2068     bool attemptToMakeGetTypedArrayByteLength(Node* node)
    2069     {
    2070         if (!isInt32Speculation(node->prediction()))
    2071             return false;
    2072        
    2073         TypedArrayType type = typedArrayTypeFromSpeculation(node->child1()->prediction());
    2074         if (!isTypedView(type))
    2075             return false;
    2076        
    2077         if (elementSize(type) == 1) {
    2078             convertToGetArrayLength(node, ArrayMode(toArrayType(type)));
    2079             return true;
    2080         }
    2081        
    2082         Node* length = prependGetArrayLength(
    2083             node->origin, node->child1().node(), ArrayMode(toArrayType(type)));
    2084        
    2085         Node* shiftAmount = m_insertionSet.insertNode(
    2086             m_indexInBlock, SpecInt32, JSConstant, node->origin,
    2087             OpInfo(m_graph.freeze(jsNumber(logElementSize(type)))));
    2088        
    2089         // We can use a BitLShift here because typed arrays will never have a byteLength
    2090         // that overflows int32.
    2091         node->setOp(BitLShift);
    2092         node->clearFlags(NodeMustGenerate);
    2093         observeUseKindOnNode(length, Int32Use);
    2094         observeUseKindOnNode(shiftAmount, Int32Use);
    2095         node->child1() = Edge(length, Int32Use);
    2096         node->child2() = Edge(shiftAmount, Int32Use);
    2097         return true;
    2098     }
    2099    
     2067
    21002068    void convertToGetArrayLength(Node* node, ArrayMode arrayMode)
    21012069    {
     
    21182086            m_indexInBlock, SpecInt32, GetArrayLength, origin,
    21192087            OpInfo(arrayMode.asWord()), Edge(child, KnownCellUse), Edge(storage));
    2120     }
    2121    
    2122     bool attemptToMakeGetTypedArrayByteOffset(Node* node)
    2123     {
    2124         if (!isInt32Speculation(node->prediction()))
    2125             return false;
    2126        
    2127         TypedArrayType type = typedArrayTypeFromSpeculation(node->child1()->prediction());
    2128         if (!isTypedView(type))
    2129             return false;
    2130        
    2131         checkArray(
    2132             ArrayMode(toArrayType(type)), node->origin, node->child1().node(),
    2133             0, neverNeedsStorage);
    2134        
    2135         node->setOp(GetTypedArrayByteOffset);
    2136         node->clearFlags(NodeMustGenerate);
    2137         fixEdge<KnownCellUse>(node->child1());
    2138         return true;
    21392088    }
    21402089   
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r190827 r191215  
    12161216JSArrayBufferView* Graph::tryGetFoldableView(JSValue value, ArrayMode arrayMode)
    12171217{
    1218     if (arrayMode.typedArrayType() == NotTypedArray)
     1218    if (arrayMode.type() != Array::AnyTypedArray && arrayMode.typedArrayType() == NotTypedArray)
    12191219        return nullptr;
    12201220    return tryGetFoldableView(value);
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r190896 r191215  
    231231        }
    232232
     233        case GetTypedArrayByteOffset:
     234        case GetArrayLength: {
     235            changed |= setPrediction(SpecInt32);
     236            break;
     237        }
     238
    233239        case StringCharCodeAt: {
    234240            changed |= setPrediction(SpecInt32);
     
    541547
    542548        case PutByValAlias:
    543         case GetArrayLength:
    544         case GetTypedArrayByteOffset:
    545549        case DoubleAsInt32:
    546550        case GetLocalUnlinked:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r191058 r191215  
    768768   
    769769    switch (node->arrayMode().type()) {
     770    case Array::AnyTypedArray:
    770771    case Array::String:
    771772        RELEASE_ASSERT_NOT_REACHED(); // Should have been a Phantom(String:)
     
    46664667    }
    46674668    default: {
    4668         ASSERT(isTypedView(node->arrayMode().typedArrayType()));
     4669        ASSERT(node->arrayMode().isSomeTypedArrayView());
    46694670        SpeculateCellOperand base(this, node->child1());
    46704671        GPRTemporary result(this, Reuse, base);
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r190896 r191215  
    252252            break;
    253253        default:
    254             if (isTypedView(node->arrayMode().typedArrayType()))
     254            if (node->arrayMode().isSomeTypedArrayView())
    255255                break;
    256256            return CannotCompile;
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp

    r191175 r191215  
    24112411           
    24122412        default:
    2413             if (isTypedView(m_node->arrayMode().typedArrayType())) {
     2413            if (m_node->arrayMode().isSomeTypedArrayView()) {
    24142414                setInt32(
    24152415                    m_out.load32NonNegative(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_length));
  • trunk/Source/JavaScriptCore/jit/Repatch.cpp

    r191058 r191215  
    225225
    226226    std::unique_ptr<AccessCase> newCase;
     227    JSFunction* getter = nullptr;
     228    ObjectPropertyConditionSet conditionSet;
     229    JSCell* baseCell = baseValue.asCell();
     230    Structure* structure = baseCell->structure(vm);
     231
     232    if (slot.isCacheableGetter())
     233        getter = jsDynamicCast<JSFunction*>(slot.getterSetter()->getter());
    227234
    228235    if (isJSArray(baseValue) && propertyName == exec->propertyNames().length)
     
    230237    else if (isJSString(baseValue) && propertyName == exec->propertyNames().length)
    231238        newCase = AccessCase::getLength(vm, codeBlock, AccessCase::StringLength);
    232     else {
     239    else if (getter && AccessCase::canEmitIntrinsicGetter(getter, structure)) {
     240        if (slot.slotBase() != baseValue) {
     241            conditionSet = generateConditionsForPrototypePropertyHit(vm, codeBlock->ownerExecutable(), exec, structure, slot.slotBase(), propertyName.impl());
     242            if (!conditionSet.isValid())
     243                return GiveUpOnCache;
     244        }
     245
     246        newCase = AccessCase::getIntrinsic(vm, codeBlock, getter, slot.cachedOffset(), structure, conditionSet);
     247
     248    } else {
    233249        if (!slot.isCacheable() && !slot.isUnset())
    234250            return GiveUpOnCache;
    235 
    236         JSCell* baseCell = baseValue.asCell();
    237         Structure* structure = baseCell->structure(vm);
    238251
    239252        bool loadTargetFromProxy = false;
     
    266279
    267280        PropertyOffset offset = slot.isUnset() ? invalidOffset : slot.cachedOffset();
    268        
    269         ObjectPropertyConditionSet conditionSet;
     281
    270282        if (slot.isUnset() || slot.slotBase() != baseValue) {
    271283            if (structure->typeInfo().prohibitsPropertyCaching() || structure->isDictionary())
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.h

    r184260 r191215  
    3030
    3131enum Intrinsic {
     32    // Call intrinsics.
    3233    NoIntrinsic,
    3334    AbsIntrinsic,
     
    5556    FRoundIntrinsic,
    5657
     58    // Getter intrinsics.
     59    TypedArrayLengthIntrinsic,
     60    TypedArrayByteLengthIntrinsic,
     61    TypedArrayByteOffsetIntrinsic,
     62
    5763    // Debugging intrinsics. These are meant to be used as testing hacks within
    5864    // jsc.cpp and should never be exposed to users.
  • trunk/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp

    r190896 r191215  
    141141{
    142142    JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object);
    143     if (propertyName == exec->propertyNames().byteOffset) {
    144         slot.setValue(thisObject, DontDelete | ReadOnly, jsNumber(thisObject->byteOffset()));
    145         return true;
    146     }
    147143   
    148144    if (propertyName == exec->propertyNames().buffer) {
     
    161157{
    162158    JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(cell);
    163     if (propertyName == exec->propertyNames().byteLength
    164         || propertyName == exec->propertyNames().byteOffset
    165         || propertyName == exec->propertyNames().buffer) {
     159    if (propertyName == exec->propertyNames().buffer) {
    166160        reject(exec, slot.isStrictMode(), "Attempting to write to read-only typed array property.");
    167161        return;
     
    176170{
    177171    JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object);
    178     if (propertyName == exec->propertyNames().byteLength
    179         || propertyName == exec->propertyNames().byteOffset
    180         || propertyName == exec->propertyNames().buffer)
     172    if (propertyName == exec->propertyNames().buffer)
    181173        return reject(exec, shouldThrow, "Attempting to define read-only typed array property.");
    182174   
     
    188180{
    189181    JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(cell);
    190     if (propertyName == exec->propertyNames().byteLength
    191         || propertyName == exec->propertyNames().byteOffset
    192         || propertyName == exec->propertyNames().buffer)
     182    if (propertyName == exec->propertyNames().buffer)
    193183        return false;
    194184   
     
    201191    JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object);
    202192   
    203     // length/byteOffset/byteLength are DontEnum, at least in Firefox.
    204     if (mode.includeDontEnumProperties()) {
    205         array.add(exec->propertyNames().byteOffset);
    206         array.add(exec->propertyNames().byteLength);
     193    if (mode.includeDontEnumProperties())
    207194        array.add(exec->propertyNames().buffer);
    208     }
     195
    209196   
    210197    Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode);
  • trunk/Source/JavaScriptCore/runtime/JSDataView.cpp

    r191059 r191215  
    3131#include "Error.h"
    3232#include "JSCInlines.h"
     33#include "Reject.h"
    3334
    3435namespace JSC {
     
    103104        return true;
    104105    }
     106    if (propertyName == exec->propertyNames().byteOffset) {
     107        slot.setValue(thisObject, DontEnum | ReadOnly, jsNumber(thisObject->byteOffset()));
     108        return true;
     109    }
     110
     111    return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
     112}
     113
     114void JSDataView::put(
     115    JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value,
     116    PutPropertySlot& slot)
     117{
     118    JSDataView* thisObject = jsCast<JSDataView*>(cell);
     119    if (propertyName == exec->propertyNames().byteLength
     120        || propertyName == exec->propertyNames().byteOffset) {
     121        reject(exec, slot.isStrictMode(), "Attempting to write to read-only typed array property.");
     122        return;
     123    }
     124
     125    Base::put(thisObject, exec, propertyName, value, slot);
     126}
     127
     128bool JSDataView::defineOwnProperty(
     129    JSObject* object, ExecState* exec, PropertyName propertyName,
     130    const PropertyDescriptor& descriptor, bool shouldThrow)
     131{
     132    JSDataView* thisObject = jsCast<JSDataView*>(object);
     133    if (propertyName == exec->propertyNames().byteLength
     134        || propertyName == exec->propertyNames().byteOffset)
     135        return reject(exec, shouldThrow, "Attempting to define read-only typed array property.");
     136
     137    return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
     138}
     139
     140bool JSDataView::deleteProperty(
     141    JSCell* cell, ExecState* exec, PropertyName propertyName)
     142{
     143    JSDataView* thisObject = jsCast<JSDataView*>(cell);
     144    if (propertyName == exec->propertyNames().byteLength
     145        || propertyName == exec->propertyNames().byteOffset)
     146        return false;
     147
     148    return Base::deleteProperty(thisObject, exec, propertyName);
     149}
     150
     151void JSDataView::getOwnNonIndexPropertyNames(
     152    JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode)
     153{
     154    JSDataView* thisObject = jsCast<JSDataView*>(object);
    105155   
    106     return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
     156    if (mode.includeDontEnumProperties()) {
     157        array.add(exec->propertyNames().byteOffset);
     158        array.add(exec->propertyNames().byteLength);
     159    }
     160   
     161    Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode);
    107162}
    108163
  • trunk/Source/JavaScriptCore/runtime/JSDataView.h

    r191059 r191215  
    6060protected:
    6161    static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
     62    static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
     63    static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
     64    static bool deleteProperty(JSCell*, ExecState*, PropertyName);
     65
     66    static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
    6267
    6368    static ArrayBuffer* slowDownAndWasteMemory(JSArrayBufferView*);
  • trunk/Source/JavaScriptCore/runtime/JSFunction.h

    r190198 r191215  
    8585    ExecutableBase* executable() const { return m_executable.get(); }
    8686
    87     // To call either of these methods include Executable.h
     87    // To call any of these methods include JSFunctionInlines.h
    8888    bool isHostFunction() const;
    8989    FunctionExecutable* jsExecutable() const;
     90    Intrinsic intrinsic() const;
    9091
    9192    JS_EXPORT_PRIVATE const SourceCode* sourceCode() const;
  • trunk/Source/JavaScriptCore/runtime/JSFunctionInlines.h

    r189123 r191215  
    7474}
    7575
     76inline Intrinsic JSFunction::intrinsic() const
     77{
     78    return executable()->intrinsic();
     79}
     80
    7681inline bool JSFunction::isBuiltinFunction() const
    7782{
  • trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h

    r191059 r191215  
    278278    static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
    279279   
    280     static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
    281280    static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
    282281   
  • trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h

    r190896 r191215  
    294294{
    295295    JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
    296     if (propertyName == exec->propertyNames().length) {
    297         slot.setValue(thisObject, DontDelete | ReadOnly, jsNumber(thisObject->length()));
    298         return true;
    299     }
    300    
    301     if (propertyName == exec->propertyNames().byteLength) {
    302         slot.setValue(thisObject, DontDelete | ReadOnly, jsNumber(thisObject->byteLength()));
    303         return true;
    304     }
    305    
     296
    306297    Optional<uint32_t> index = parseIndex(propertyName);
    307298    if (index && thisObject->canGetIndexQuickly(index.value())) {
     
    320311    JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
    321312   
    322     if (propertyName == exec->propertyNames().length) {
    323         // Firefox appears to simply ignore attempts to store to the length property.
    324         // Even in strict mode. I will do the same.
    325         return;
    326     }
    327    
    328313    if (Optional<uint32_t> index = parseIndex(propertyName)) {
    329314        putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode());
     
    344329    // defineOwnProperty for indexed properties on typed arrays, even if they're out
    345330    // of bounds.
    346     if (propertyName == exec->propertyNames().length || parseIndex(propertyName))
     331    if (parseIndex(propertyName))
    347332        return reject(exec, shouldThrow, "Attempting to write to a read-only typed array property.");
    348333   
     
    356341    JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
    357342   
    358     if (propertyName == exec->propertyNames().length || parseIndex(propertyName))
     343    if (parseIndex(propertyName))
    359344        return false;
    360345   
     
    406391   
    407392    return false;
    408 }
    409 
    410 template<typename Adaptor>
    411 void JSGenericTypedArrayView<Adaptor>::getOwnNonIndexPropertyNames(
    412     JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode)
    413 {
    414     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
    415    
    416     if (mode.includeDontEnumProperties())
    417         array.add(exec->propertyNames().length);
    418    
    419     Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode);
    420393}
    421394
  • trunk/Source/JavaScriptCore/runtime/JSObject.cpp

    r190904 r191215  
    22882288}
    22892289
     2290void JSObject::putDirectNativeIntrinsicGetter(VM& vm, JSGlobalObject* globalObject, Identifier name, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
     2291{
     2292    GetterSetter* accessor = GetterSetter::create(vm, globalObject);
     2293    JSFunction* function = JSFunction::create(vm, globalObject, 0, name.string(), nativeFunction, intrinsic);
     2294    accessor->setGetter(vm, globalObject, function);
     2295    putDirectNonIndexAccessor(vm, name, accessor, attributes);
     2296}
     2297
    22902298void JSObject::putDirectNativeFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
    22912299{
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r190896 r191215  
    596596    void putDirectUndefined(PropertyOffset offset) { locationForOffset(offset)->setUndefined(); }
    597597
     598    JS_EXPORT_PRIVATE void putDirectNativeIntrinsicGetter(VM&, JSGlobalObject*, Identifier, NativeFunction, Intrinsic, unsigned attributes);
    598599    JS_EXPORT_PRIVATE void putDirectNativeFunction(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
    599600    JS_EXPORT_PRIVATE JSFunction* putDirectBuiltinFunction(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
     
    14721473
    14731474// Helper for defining native getters on properties.
    1474 #define JSC_NATIVE_GETTER(jsName, cppName, attributes, length) do { \
    1475         Identifier ident = makeIdentifier(vm, (jsName)); \
    1476         GetterSetter* accessor = GetterSetter::create(vm, globalObject); \
    1477         JSFunction* function = JSFunction::create(vm, globalObject, (length), ident.string(), (cppName)); \
    1478         accessor->setGetter(vm, globalObject, function); \
    1479         putDirectNonIndexAccessor(vm, ident, accessor, (attributes) | Accessor); \
    1480     } while (false)
     1475#define JSC_NATIVE_INTRINSIC_GETTER(jsName, cppName, attributes, intrinsic) \
     1476    putDirectNativeIntrinsicGetter(\
     1477        vm, globalObject, makeIdentifier(vm, (jsName)), (cppName), \
     1478        (intrinsic), ((attributes) | Accessor))
     1479
     1480#define JSC_NATIVE_GETTER(jsName, cppName, attributes) \
     1481    JSC_NATIVE_INTRINSIC_GETTER((jsName), (cppName), (attributes), NoIntrinsic)
    14811482
    14821483
  • trunk/Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp

    r191059 r191215  
    214214    ASSERT(inherits(info()));
    215215
    216     JSC_NATIVE_GETTER(vm.propertyNames->byteLength, typedArrayViewProtoGetterFuncByteLength, DontEnum | ReadOnly | DontDelete, 0);
    217     JSC_NATIVE_GETTER(vm.propertyNames->byteOffset, typedArrayViewProtoGetterFuncByteOffset, DontEnum | ReadOnly | DontDelete, 0);
     216    JSC_NATIVE_INTRINSIC_GETTER(vm.propertyNames->byteLength, typedArrayViewProtoGetterFuncByteLength, DontEnum | ReadOnly | DontDelete, TypedArrayByteLengthIntrinsic);
     217    JSC_NATIVE_INTRINSIC_GETTER(vm.propertyNames->byteOffset, typedArrayViewProtoGetterFuncByteOffset, DontEnum | ReadOnly | DontDelete, TypedArrayByteOffsetIntrinsic);
    218218    JSC_NATIVE_FUNCTION("copyWithin", typedArrayViewProtoFuncCopyWithin, DontEnum, 2);
    219219    JSC_BUILTIN_FUNCTION("every", typedArrayPrototypeEveryCodeGenerator, DontEnum);
     
    229229    JSC_NATIVE_FUNCTION(vm.propertyNames->keys, typedArrayViewProtoFuncKeys, DontEnum, 0);
    230230    JSC_NATIVE_FUNCTION("lastIndexOf", typedArrayViewProtoFuncLastIndexOf, DontEnum, 1);
    231     JSC_NATIVE_GETTER(vm.propertyNames->length, typedArrayViewProtoGetterFuncLength, DontEnum | ReadOnly | DontDelete, 0);
     231    JSC_NATIVE_INTRINSIC_GETTER(vm.propertyNames->length, typedArrayViewProtoGetterFuncLength, DontEnum | ReadOnly | DontDelete, TypedArrayLengthIntrinsic);
    232232    JSC_BUILTIN_FUNCTION("map", typedArrayPrototypeMapCodeGenerator, DontEnum);
    233233    JSC_BUILTIN_FUNCTION("reduce", typedArrayPrototypeReduceCodeGenerator, DontEnum);
Note: See TracChangeset for help on using the changeset viewer.