2017-08-12 16:48:01 +00:00
/*
2022-10-23 02:55:20 +00:00
* Copyright ( C ) 2012 - 2020 Apple Inc . All rights reserved .
2017-08-12 16:48:01 +00:00
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC . ` ` AS IS ' ' AND ANY
* EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL APPLE INC . OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL ,
* EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO ,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR
* PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "config.h"
2022-10-23 02:55:20 +00:00
# include "GetByStatus.h"
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
# include "BytecodeStructs.h"
2022-10-23 02:55:20 +00:00
# include "CacheableIdentifierInlines.h"
2017-08-12 16:48:01 +00:00
# include "CodeBlock.h"
# include "ComplexGetStatus.h"
2018-01-03 05:16:05 +00:00
# include "GetterSetterAccessCase.h"
2020-08-29 13:27:11 +00:00
# include "ICStatusUtils.h"
2018-01-03 05:16:05 +00:00
# include "IntrinsicGetterAccessCase.h"
# include "ModuleNamespaceAccessCase.h"
2017-08-12 16:48:01 +00:00
# include "PolymorphicAccess.h"
# include "StructureStubInfo.h"
# include <wtf/ListDump.h>
namespace JSC {
2022-10-23 02:55:20 +00:00
bool GetByStatus : : appendVariant ( const GetByIdVariant & variant )
2017-08-12 16:48:01 +00:00
{
2020-08-29 13:27:11 +00:00
return appendICStatusVariant ( m_variants , variant ) ;
2017-08-12 16:48:01 +00:00
}
2022-10-23 02:55:20 +00:00
GetByStatus GetByStatus : : computeFromLLInt ( CodeBlock * profiledBlock , BytecodeIndex bytecodeIndex )
2017-08-12 16:48:01 +00:00
{
2022-10-23 02:55:20 +00:00
VM & vm = profiledBlock - > vm ( ) ;
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
auto instruction = profiledBlock - > instructions ( ) . at ( bytecodeIndex . offset ( ) ) ;
2020-08-29 13:27:11 +00:00
StructureID structureID ;
2022-10-23 02:55:20 +00:00
const Identifier * identifier = nullptr ;
2020-08-29 13:27:11 +00:00
switch ( instruction - > opcodeID ( ) ) {
case op_get_by_id : {
auto & metadata = instruction - > as < OpGetById > ( ) . metadata ( profiledBlock ) ;
// FIXME: We should not just bail if we see a get_by_id_proto_load.
// https://bugs.webkit.org/show_bug.cgi?id=158039
if ( metadata . m_modeMetadata . mode ! = GetByIdMode : : Default )
2022-10-23 02:55:20 +00:00
return GetByStatus ( NoInformation , false ) ;
2020-08-29 13:27:11 +00:00
structureID = metadata . m_modeMetadata . defaultMode . structureID ;
2022-10-23 02:55:20 +00:00
identifier = & ( profiledBlock - > identifier ( instruction - > as < OpGetById > ( ) . m_property ) ) ;
2020-08-29 13:27:11 +00:00
break ;
}
case op_get_by_id_direct :
structureID = instruction - > as < OpGetByIdDirect > ( ) . metadata ( profiledBlock ) . m_structureID ;
2022-10-23 02:55:20 +00:00
identifier = & ( profiledBlock - > identifier ( instruction - > as < OpGetByIdDirect > ( ) . m_property ) ) ;
2020-08-29 13:27:11 +00:00
break ;
case op_try_get_by_id : {
// FIXME: We should not just bail if we see a try_get_by_id.
// https://bugs.webkit.org/show_bug.cgi?id=158039
2022-10-23 02:55:20 +00:00
return GetByStatus ( NoInformation , false ) ;
}
case op_get_by_val :
return GetByStatus ( NoInformation , false ) ;
case op_iterator_open : {
ASSERT ( bytecodeIndex . checkpoint ( ) = = OpIteratorOpen : : getNext ) ;
auto & metadata = instruction - > as < OpIteratorOpen > ( ) . metadata ( profiledBlock ) ;
// FIXME: We should not just bail if we see a get_by_id_proto_load.
// https://bugs.webkit.org/show_bug.cgi?id=158039
if ( metadata . m_modeMetadata . mode ! = GetByIdMode : : Default )
return GetByStatus ( NoInformation , false ) ;
structureID = metadata . m_modeMetadata . defaultMode . structureID ;
identifier = & vm . propertyNames - > next ;
break ;
2020-08-29 13:27:11 +00:00
}
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
case op_iterator_next : {
auto & metadata = instruction - > as < OpIteratorNext > ( ) . metadata ( profiledBlock ) ;
if ( bytecodeIndex . checkpoint ( ) = = OpIteratorNext : : getDone ) {
if ( metadata . m_doneModeMetadata . mode ! = GetByIdMode : : Default )
return GetByStatus ( NoInformation , false ) ;
structureID = metadata . m_doneModeMetadata . defaultMode . structureID ;
identifier = & vm . propertyNames - > done ;
} else {
ASSERT ( bytecodeIndex . checkpoint ( ) = = OpIteratorNext : : getValue ) ;
if ( metadata . m_valueModeMetadata . mode ! = GetByIdMode : : Default )
return GetByStatus ( NoInformation , false ) ;
structureID = metadata . m_valueModeMetadata . defaultMode . structureID ;
identifier = & vm . propertyNames - > value ;
}
break ;
}
case op_get_private_name :
// FIXME: Consider using LLInt caches or IC information to populate GetByStatus
// https://bugs.webkit.org/show_bug.cgi?id=217245
return GetByStatus ( NoInformation , false ) ;
2020-08-29 13:27:11 +00:00
default : {
ASSERT_NOT_REACHED ( ) ;
2022-10-23 02:55:20 +00:00
return GetByStatus ( NoInformation , false ) ;
2020-08-29 13:27:11 +00:00
}
}
2017-08-12 16:48:01 +00:00
if ( ! structureID )
2022-10-23 02:55:20 +00:00
return GetByStatus ( NoInformation , false ) ;
2017-08-12 16:48:01 +00:00
Structure * structure = vm . heap . structureIDTable ( ) . get ( structureID ) ;
if ( structure - > takesSlowPathInDFGForImpureProperty ( ) )
2022-10-23 02:55:20 +00:00
return GetByStatus ( NoInformation , false ) ;
2017-08-12 16:48:01 +00:00
unsigned attributes ;
2022-10-23 02:55:20 +00:00
PropertyOffset offset = structure - > getConcurrently ( identifier - > impl ( ) , attributes ) ;
2017-08-12 16:48:01 +00:00
if ( ! isValidOffset ( offset ) )
2022-10-23 02:55:20 +00:00
return GetByStatus ( NoInformation , false ) ;
2020-08-29 13:27:11 +00:00
if ( attributes & PropertyAttribute : : CustomAccessorOrValue )
2022-10-23 02:55:20 +00:00
return GetByStatus ( NoInformation , false ) ;
2020-08-29 13:27:11 +00:00
2022-10-23 02:55:20 +00:00
GetByStatus result ( Simple , false ) ;
result . appendVariant ( GetByIdVariant ( nullptr , StructureSet ( structure ) , offset ) ) ;
return result ;
2017-08-12 16:48:01 +00:00
}
2022-10-23 02:55:20 +00:00
GetByStatus GetByStatus : : computeFor ( CodeBlock * profiledBlock , ICStatusMap & map , BytecodeIndex bytecodeIndex , ExitFlag didExit , CallLinkStatus : : ExitSiteData callExitSiteData )
2017-08-12 16:48:01 +00:00
{
ConcurrentJSLocker locker ( profiledBlock - > m_lock ) ;
2022-10-23 02:55:20 +00:00
GetByStatus result ;
2017-08-12 16:48:01 +00:00
# if ENABLE(DFG_JIT)
result = computeForStubInfoWithoutExitSiteFeedback (
2022-10-23 02:55:20 +00:00
locker , profiledBlock , map . get ( CodeOrigin ( bytecodeIndex ) ) . stubInfo , callExitSiteData ) ;
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
if ( didExit )
return result . slowVersion ( ) ;
2017-08-12 16:48:01 +00:00
# else
UNUSED_PARAM ( map ) ;
2020-08-29 13:27:11 +00:00
UNUSED_PARAM ( didExit ) ;
UNUSED_PARAM ( callExitSiteData ) ;
2017-08-12 16:48:01 +00:00
# endif
if ( ! result )
2022-10-23 02:55:20 +00:00
return computeFromLLInt ( profiledBlock , bytecodeIndex ) ;
2017-08-12 16:48:01 +00:00
return result ;
}
2022-10-23 02:55:20 +00:00
# if ENABLE(JIT)
GetByStatus : : GetByStatus ( StubInfoSummary summary , StructureStubInfo & stubInfo )
: m_wasSeenInJIT ( true )
2017-08-12 16:48:01 +00:00
{
2022-10-23 02:55:20 +00:00
switch ( summary ) {
case StubInfoSummary : : NoInformation :
m_state = NoInformation ;
return ;
case StubInfoSummary : : Simple :
case StubInfoSummary : : MakesCalls :
RELEASE_ASSERT_NOT_REACHED ( ) ;
return ;
case StubInfoSummary : : TakesSlowPath :
m_state = stubInfo . tookSlowPath ? ObservedTakesSlowPath : LikelyTakesSlowPath ;
return ;
case StubInfoSummary : : TakesSlowPathAndMakesCalls :
m_state = stubInfo . tookSlowPath ? ObservedSlowPathAndMakesCalls : MakesCalls ;
return ;
}
RELEASE_ASSERT_NOT_REACHED ( ) ;
2017-08-12 16:48:01 +00:00
}
2022-10-23 02:55:20 +00:00
GetByStatus : : GetByStatus ( const ModuleNamespaceAccessCase & accessCase )
: m_moduleNamespaceData ( Box < ModuleNamespaceData > : : create ( ModuleNamespaceData { accessCase . moduleNamespaceObject ( ) , accessCase . moduleEnvironment ( ) , accessCase . scopeOffset ( ) , accessCase . identifier ( ) } ) )
2020-08-29 13:27:11 +00:00
, m_state ( ModuleNamespace )
, m_wasSeenInJIT ( true )
2018-01-03 05:16:05 +00:00
{
}
2022-10-23 02:55:20 +00:00
GetByStatus GetByStatus : : computeForStubInfoWithoutExitSiteFeedback (
const ConcurrentJSLocker & locker , CodeBlock * profiledBlock , StructureStubInfo * stubInfo , CallLinkStatus : : ExitSiteData callExitSiteData )
2017-08-12 16:48:01 +00:00
{
2022-10-23 02:55:20 +00:00
StubInfoSummary summary = StructureStubInfo : : summary ( profiledBlock - > vm ( ) , stubInfo ) ;
2020-08-29 13:27:11 +00:00
if ( ! isInlineable ( summary ) )
2022-10-23 02:55:20 +00:00
return GetByStatus ( summary , * stubInfo ) ;
2017-08-12 16:48:01 +00:00
// Finally figure out if we can derive an access strategy.
2022-10-23 02:55:20 +00:00
GetByStatus result ;
2017-08-12 16:48:01 +00:00
result . m_state = Simple ;
result . m_wasSeenInJIT = true ; // This is interesting for bytecode dumping only.
2022-10-23 02:55:20 +00:00
switch ( stubInfo - > cacheType ( ) ) {
2017-08-12 16:48:01 +00:00
case CacheType : : Unset :
2022-10-23 02:55:20 +00:00
return GetByStatus ( NoInformation ) ;
2017-08-12 16:48:01 +00:00
case CacheType : : GetByIdSelf : {
Structure * structure = stubInfo - > u . byIdSelf . baseObjectStructure . get ( ) ;
if ( structure - > takesSlowPathInDFGForImpureProperty ( ) )
2022-10-23 02:55:20 +00:00
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
CacheableIdentifier identifier = stubInfo - > identifier ( ) ;
UniquedStringImpl * uid = identifier . uid ( ) ;
RELEASE_ASSERT ( uid ) ;
GetByIdVariant variant ( WTFMove ( identifier ) ) ;
2017-08-12 16:48:01 +00:00
unsigned attributes ;
variant . m_offset = structure - > getConcurrently ( uid , attributes ) ;
if ( ! isValidOffset ( variant . m_offset ) )
2022-10-23 02:55:20 +00:00
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
2020-08-29 13:27:11 +00:00
if ( attributes & PropertyAttribute : : CustomAccessorOrValue )
2022-10-23 02:55:20 +00:00
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
2017-08-12 16:48:01 +00:00
variant . m_structureSet . add ( structure ) ;
bool didAppend = result . appendVariant ( variant ) ;
ASSERT_UNUSED ( didAppend , didAppend ) ;
return result ;
}
case CacheType : : Stub : {
2020-08-29 13:27:11 +00:00
PolymorphicAccess * list = stubInfo - > u . stub ;
2018-01-03 05:16:05 +00:00
if ( list - > size ( ) = = 1 ) {
const AccessCase & access = list - > at ( 0 ) ;
switch ( access . type ( ) ) {
case AccessCase : : ModuleNamespaceLoad :
2022-10-23 02:55:20 +00:00
return GetByStatus ( access . as < ModuleNamespaceAccessCase > ( ) ) ;
2018-01-03 05:16:05 +00:00
default :
break ;
}
}
2017-08-12 16:48:01 +00:00
for ( unsigned listIndex = 0 ; listIndex < list - > size ( ) ; + + listIndex ) {
const AccessCase & access = list - > at ( listIndex ) ;
if ( access . viaProxy ( ) )
2022-10-23 02:55:20 +00:00
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
2020-08-29 13:27:11 +00:00
if ( access . usesPolyProto ( ) )
2022-10-23 02:55:20 +00:00
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
if ( ! access . requiresIdentifierNameMatch ( ) ) {
// FIXME: We could use this for indexed loads in the future. This is pretty solid profiling
// information, and probably better than ArrayProfile when it's available.
// https://bugs.webkit.org/show_bug.cgi?id=204215
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
}
2017-08-12 16:48:01 +00:00
Structure * structure = access . structure ( ) ;
if ( ! structure ) {
// The null structure cases arise due to array.length and string.length. We have no way
// of creating a GetByIdVariant for those, and we don't really have to since the DFG
// handles those cases in FixupPhase using value profiling. That's a bit awkward - we
// shouldn't have to use value profiling to discover something that the AccessCase
// could have told us. But, it works well enough. So, our only concern here is to not
// crash on null structure.
2022-10-23 02:55:20 +00:00
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
2017-08-12 16:48:01 +00:00
}
ComplexGetStatus complexGetStatus = ComplexGetStatus : : computeFor (
2022-10-23 02:55:20 +00:00
structure , access . conditionSet ( ) , access . uid ( ) ) ;
2017-08-12 16:48:01 +00:00
switch ( complexGetStatus . kind ( ) ) {
case ComplexGetStatus : : ShouldSkip :
continue ;
case ComplexGetStatus : : TakesSlowPath :
2022-10-23 02:55:20 +00:00
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
2017-08-12 16:48:01 +00:00
case ComplexGetStatus : : Inlineable : {
std : : unique_ptr < CallLinkStatus > callLinkStatus ;
JSFunction * intrinsicFunction = nullptr ;
2022-10-23 02:55:20 +00:00
FunctionPtr < CustomAccessorPtrTag > customAccessorGetter ;
std : : unique_ptr < DOMAttributeAnnotation > domAttribute ;
bool haveDOMAttribute = false ;
2017-08-12 16:48:01 +00:00
switch ( access . type ( ) ) {
case AccessCase : : Load :
case AccessCase : : GetGetter :
case AccessCase : : Miss : {
break ;
}
case AccessCase : : IntrinsicGetter : {
2018-01-03 05:16:05 +00:00
intrinsicFunction = access . as < IntrinsicGetterAccessCase > ( ) . intrinsicFunction ( ) ;
2017-08-12 16:48:01 +00:00
break ;
}
case AccessCase : : Getter : {
2022-10-23 02:55:20 +00:00
callLinkStatus = makeUnique < CallLinkStatus > ( ) ;
2018-01-03 05:16:05 +00:00
if ( CallLinkInfo * callLinkInfo = access . as < GetterSetterAccessCase > ( ) . callLinkInfo ( ) ) {
2017-08-12 16:48:01 +00:00
* callLinkStatus = CallLinkStatus : : computeFor (
locker , profiledBlock , * callLinkInfo , callExitSiteData ) ;
}
break ;
}
case AccessCase : : CustomAccessorGetter : {
2020-08-29 13:27:11 +00:00
customAccessorGetter = access . as < GetterSetterAccessCase > ( ) . customAccessor ( ) ;
2022-10-23 02:55:20 +00:00
if ( ! access . as < GetterSetterAccessCase > ( ) . domAttribute ( ) )
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
domAttribute = WTF : : makeUnique < DOMAttributeAnnotation > ( * access . as < GetterSetterAccessCase > ( ) . domAttribute ( ) ) ;
haveDOMAttribute = true ;
2017-08-12 16:48:01 +00:00
result . m_state = Custom ;
break ;
}
default : {
// FIXME: It would be totally sweet to support more of these at some point in the
// future. https://bugs.webkit.org/show_bug.cgi?id=133052
2022-10-23 02:55:20 +00:00
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
2017-08-12 16:48:01 +00:00
} }
2022-10-23 02:55:20 +00:00
ASSERT ( ( AccessCase : : Miss = = access . type ( ) | | access . isCustom ( ) ) = = ( access . offset ( ) = = invalidOffset ) ) ;
GetByIdVariant variant ( access . identifier ( ) , StructureSet ( structure ) , complexGetStatus . offset ( ) ,
2017-08-12 16:48:01 +00:00
complexGetStatus . conditionSet ( ) , WTFMove ( callLinkStatus ) ,
intrinsicFunction ,
2020-08-29 13:27:11 +00:00
customAccessorGetter ,
2022-10-23 02:55:20 +00:00
WTFMove ( domAttribute ) ) ;
2017-08-12 16:48:01 +00:00
if ( ! result . appendVariant ( variant ) )
2022-10-23 02:55:20 +00:00
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
if ( haveDOMAttribute ) {
2020-08-29 13:27:11 +00:00
// Give up when custom accesses are not merged into one.
2017-08-12 16:48:01 +00:00
if ( result . numVariants ( ) ! = 1 )
2022-10-23 02:55:20 +00:00
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
2017-08-12 16:48:01 +00:00
} else {
// Give up when custom access and simple access are mixed.
if ( result . m_state = = Custom )
2022-10-23 02:55:20 +00:00
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
2017-08-12 16:48:01 +00:00
}
break ;
} }
}
return result ;
}
default :
2022-10-23 02:55:20 +00:00
return GetByStatus ( JSC : : slowVersion ( summary ) , * stubInfo ) ;
2017-08-12 16:48:01 +00:00
}
RELEASE_ASSERT_NOT_REACHED ( ) ;
2022-10-23 02:55:20 +00:00
return GetByStatus ( ) ;
2017-08-12 16:48:01 +00:00
}
2022-10-23 02:55:20 +00:00
GetByStatus GetByStatus : : computeFor (
2020-08-29 13:27:11 +00:00
CodeBlock * profiledBlock , ICStatusMap & baselineMap ,
2022-10-23 02:55:20 +00:00
ICStatusContextStack & icContextStack , CodeOrigin codeOrigin )
2017-08-12 16:48:01 +00:00
{
2022-10-23 02:55:20 +00:00
BytecodeIndex bytecodeIndex = codeOrigin . bytecodeIndex ( ) ;
2020-08-29 13:27:11 +00:00
CallLinkStatus : : ExitSiteData callExitSiteData = CallLinkStatus : : computeExitSiteData ( profiledBlock , bytecodeIndex ) ;
ExitFlag didExit = hasBadCacheExitSite ( profiledBlock , bytecodeIndex ) ;
2022-10-23 02:55:20 +00:00
2020-08-29 13:27:11 +00:00
for ( ICStatusContext * context : icContextStack ) {
ICStatus status = context - > get ( codeOrigin ) ;
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
auto bless = [ & ] ( const GetByStatus & result ) - > GetByStatus {
2020-08-29 13:27:11 +00:00
if ( ! context - > isInlined ( codeOrigin ) ) {
// Merge with baseline result, which also happens to contain exit data for both
// inlined and not-inlined.
2022-10-23 02:55:20 +00:00
GetByStatus baselineResult = computeFor (
profiledBlock , baselineMap , bytecodeIndex , didExit ,
2020-08-29 13:27:11 +00:00
callExitSiteData ) ;
baselineResult . merge ( result ) ;
return baselineResult ;
}
if ( didExit . isSet ( ExitFromInlined ) )
return result . slowVersion ( ) ;
2017-08-12 16:48:01 +00:00
return result ;
2020-08-29 13:27:11 +00:00
} ;
if ( status . stubInfo ) {
2022-10-23 02:55:20 +00:00
GetByStatus result ;
2020-08-29 13:27:11 +00:00
{
ConcurrentJSLocker locker ( context - > optimizedCodeBlock - > m_lock ) ;
result = computeForStubInfoWithoutExitSiteFeedback (
2022-10-23 02:55:20 +00:00
locker , context - > optimizedCodeBlock , status . stubInfo , callExitSiteData ) ;
2020-08-29 13:27:11 +00:00
}
if ( result . isSet ( ) )
return bless ( result ) ;
2017-08-12 16:48:01 +00:00
}
2020-08-29 13:27:11 +00:00
if ( status . getStatus )
return bless ( * status . getStatus ) ;
2017-08-12 16:48:01 +00:00
}
2020-08-29 13:27:11 +00:00
2022-10-23 02:55:20 +00:00
return computeFor ( profiledBlock , baselineMap , bytecodeIndex , didExit , callExitSiteData ) ;
2017-08-12 16:48:01 +00:00
}
2022-10-23 02:55:20 +00:00
GetByStatus GetByStatus : : computeFor ( const StructureSet & set , UniquedStringImpl * uid )
2017-08-12 16:48:01 +00:00
{
// For now we only handle the super simple self access case. We could handle the
// prototype case in the future.
2020-08-29 13:27:11 +00:00
//
// Note that this code is also used for GetByIdDirect since this function only looks
// into direct properties. When supporting prototype chains, we should split this for
// GetById and GetByIdDirect.
2017-08-12 16:48:01 +00:00
if ( set . isEmpty ( ) )
2022-10-23 02:55:20 +00:00
return GetByStatus ( ) ;
2017-08-12 16:48:01 +00:00
if ( parseIndex ( * uid ) )
2022-10-23 02:55:20 +00:00
return GetByStatus ( LikelyTakesSlowPath ) ;
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
GetByStatus result ;
2017-08-12 16:48:01 +00:00
result . m_state = Simple ;
result . m_wasSeenInJIT = false ;
for ( unsigned i = 0 ; i < set . size ( ) ; + + i ) {
Structure * structure = set [ i ] ;
if ( structure - > typeInfo ( ) . overridesGetOwnPropertySlot ( ) & & structure - > typeInfo ( ) . type ( ) ! = GlobalObjectType )
2022-10-23 02:55:20 +00:00
return GetByStatus ( LikelyTakesSlowPath ) ;
2017-08-12 16:48:01 +00:00
if ( ! structure - > propertyAccessesAreCacheable ( ) )
2022-10-23 02:55:20 +00:00
return GetByStatus ( LikelyTakesSlowPath ) ;
2017-08-12 16:48:01 +00:00
unsigned attributes ;
PropertyOffset offset = structure - > getConcurrently ( uid , attributes ) ;
if ( ! isValidOffset ( offset ) )
2022-10-23 02:55:20 +00:00
return GetByStatus ( LikelyTakesSlowPath ) ; // It's probably a prototype lookup. Give up on life for now, even though we could totally be way smarter about it.
2020-08-29 13:27:11 +00:00
if ( attributes & PropertyAttribute : : Accessor )
2022-10-23 02:55:20 +00:00
return GetByStatus ( MakesCalls ) ; // We could be smarter here, like strength-reducing this to a Call.
2020-08-29 13:27:11 +00:00
if ( attributes & PropertyAttribute : : CustomAccessorOrValue )
2022-10-23 02:55:20 +00:00
return GetByStatus ( LikelyTakesSlowPath ) ;
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
if ( ! result . appendVariant ( GetByIdVariant ( nullptr , structure , offset ) ) )
return GetByStatus ( LikelyTakesSlowPath ) ;
2017-08-12 16:48:01 +00:00
}
return result ;
}
2020-08-29 13:27:11 +00:00
# endif // ENABLE(JIT)
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
bool GetByStatus : : makesCalls ( ) const
2017-08-12 16:48:01 +00:00
{
switch ( m_state ) {
case NoInformation :
2022-10-23 02:55:20 +00:00
case LikelyTakesSlowPath :
case ObservedTakesSlowPath :
2017-08-12 16:48:01 +00:00
case Custom :
2018-01-03 05:16:05 +00:00
case ModuleNamespace :
2017-08-12 16:48:01 +00:00
return false ;
case Simple :
for ( unsigned i = m_variants . size ( ) ; i - - ; ) {
if ( m_variants [ i ] . callLinkStatus ( ) )
return true ;
}
return false ;
case MakesCalls :
2022-10-23 02:55:20 +00:00
case ObservedSlowPathAndMakesCalls :
2017-08-12 16:48:01 +00:00
return true ;
}
RELEASE_ASSERT_NOT_REACHED ( ) ;
return false ;
}
2022-10-23 02:55:20 +00:00
GetByStatus GetByStatus : : slowVersion ( ) const
2017-08-12 16:48:01 +00:00
{
2022-10-23 02:55:20 +00:00
if ( observedStructureStubInfoSlowPath ( ) )
return GetByStatus ( makesCalls ( ) ? ObservedSlowPathAndMakesCalls : ObservedTakesSlowPath , wasSeenInJIT ( ) ) ;
return GetByStatus ( makesCalls ( ) ? MakesCalls : LikelyTakesSlowPath , wasSeenInJIT ( ) ) ;
2020-08-29 13:27:11 +00:00
}
2022-10-23 02:55:20 +00:00
void GetByStatus : : merge ( const GetByStatus & other )
2020-08-29 13:27:11 +00:00
{
if ( other . m_state = = NoInformation )
2017-08-12 16:48:01 +00:00
return ;
2020-08-29 13:27:11 +00:00
auto mergeSlow = [ & ] ( ) {
2022-10-23 02:55:20 +00:00
if ( observedStructureStubInfoSlowPath ( ) | | other . observedStructureStubInfoSlowPath ( ) )
* this = GetByStatus ( ( makesCalls ( ) | | other . makesCalls ( ) ) ? ObservedSlowPathAndMakesCalls : ObservedTakesSlowPath ) ;
else
* this = GetByStatus ( ( makesCalls ( ) | | other . makesCalls ( ) ) ? MakesCalls : LikelyTakesSlowPath ) ;
2020-08-29 13:27:11 +00:00
} ;
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
switch ( m_state ) {
case NoInformation :
* this = other ;
return ;
case Simple :
case Custom :
if ( m_state ! = other . m_state )
return mergeSlow ( ) ;
for ( const GetByIdVariant & otherVariant : other . m_variants ) {
if ( ! appendVariant ( otherVariant ) )
return mergeSlow ( ) ;
}
return ;
case ModuleNamespace :
if ( other . m_state ! = ModuleNamespace )
return mergeSlow ( ) ;
2022-10-23 02:55:20 +00:00
if ( m_moduleNamespaceData - > m_moduleNamespaceObject ! = other . m_moduleNamespaceData - > m_moduleNamespaceObject )
2020-08-29 13:27:11 +00:00
return mergeSlow ( ) ;
2022-10-23 02:55:20 +00:00
if ( m_moduleNamespaceData - > m_moduleEnvironment ! = other . m_moduleNamespaceData - > m_moduleEnvironment )
2020-08-29 13:27:11 +00:00
return mergeSlow ( ) ;
2022-10-23 02:55:20 +00:00
if ( m_moduleNamespaceData - > m_scopeOffset ! = other . m_moduleNamespaceData - > m_scopeOffset )
2020-08-29 13:27:11 +00:00
return mergeSlow ( ) ;
return ;
2022-10-23 02:55:20 +00:00
case LikelyTakesSlowPath :
case ObservedTakesSlowPath :
2020-08-29 13:27:11 +00:00
case MakesCalls :
2022-10-23 02:55:20 +00:00
case ObservedSlowPathAndMakesCalls :
2020-08-29 13:27:11 +00:00
return mergeSlow ( ) ;
}
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
RELEASE_ASSERT_NOT_REACHED ( ) ;
}
2022-10-23 02:55:20 +00:00
void GetByStatus : : filter ( const StructureSet & set )
2020-08-29 13:27:11 +00:00
{
if ( m_state ! = Simple )
return ;
filterICStatusVariants ( m_variants , set ) ;
2017-08-12 16:48:01 +00:00
if ( m_variants . isEmpty ( ) )
m_state = NoInformation ;
}
2022-10-23 02:55:20 +00:00
void GetByStatus : : visitAggregate ( SlotVisitor & visitor )
{
if ( isModuleNamespace ( ) )
m_moduleNamespaceData - > m_identifier . visitAggregate ( visitor ) ;
for ( GetByIdVariant & variant : m_variants )
variant . visitAggregate ( visitor ) ;
}
void GetByStatus : : markIfCheap ( SlotVisitor & visitor )
2020-08-29 13:27:11 +00:00
{
for ( GetByIdVariant & variant : m_variants )
variant . markIfCheap ( visitor ) ;
}
2022-10-23 02:55:20 +00:00
bool GetByStatus : : finalize ( VM & vm )
2020-08-29 13:27:11 +00:00
{
for ( GetByIdVariant & variant : m_variants ) {
if ( ! variant . finalize ( vm ) )
return false ;
}
2022-10-23 02:55:20 +00:00
if ( isModuleNamespace ( ) ) {
if ( m_moduleNamespaceData - > m_moduleNamespaceObject & & ! vm . heap . isMarked ( m_moduleNamespaceData - > m_moduleNamespaceObject ) )
return false ;
if ( m_moduleNamespaceData - > m_moduleEnvironment & & ! vm . heap . isMarked ( m_moduleNamespaceData - > m_moduleEnvironment ) )
return false ;
}
2020-08-29 13:27:11 +00:00
return true ;
}
2022-10-23 02:55:20 +00:00
CacheableIdentifier GetByStatus : : singleIdentifier ( ) const
{
if ( isModuleNamespace ( ) )
return m_moduleNamespaceData - > m_identifier ;
if ( m_variants . isEmpty ( ) )
return nullptr ;
CacheableIdentifier result = m_variants . first ( ) . identifier ( ) ;
if ( ! result )
return nullptr ;
for ( size_t i = 1 ; i < m_variants . size ( ) ; + + i ) {
CacheableIdentifier identifier = m_variants [ i ] . identifier ( ) ;
if ( ! identifier )
return nullptr ;
if ( identifier ! = result )
return nullptr ;
}
return result ;
}
void GetByStatus : : dump ( PrintStream & out ) const
2017-08-12 16:48:01 +00:00
{
out . print ( " ( " ) ;
switch ( m_state ) {
case NoInformation :
out . print ( " NoInformation " ) ;
break ;
case Simple :
out . print ( " Simple " ) ;
break ;
case Custom :
out . print ( " Custom " ) ;
break ;
2018-01-03 05:16:05 +00:00
case ModuleNamespace :
out . print ( " ModuleNamespace " ) ;
break ;
2022-10-23 02:55:20 +00:00
case LikelyTakesSlowPath :
out . print ( " LikelyTakesSlowPath " ) ;
break ;
case ObservedTakesSlowPath :
out . print ( " ObservedTakesSlowPath " ) ;
2017-08-12 16:48:01 +00:00
break ;
case MakesCalls :
out . print ( " MakesCalls " ) ;
break ;
2022-10-23 02:55:20 +00:00
case ObservedSlowPathAndMakesCalls :
out . print ( " ObservedSlowPathAndMakesCalls " ) ;
break ;
2017-08-12 16:48:01 +00:00
}
out . print ( " , " , listDump ( m_variants ) , " , seenInJIT = " , m_wasSeenInJIT , " ) " ) ;
}
} // namespace JSC