@@ -76,10 +76,8 @@ namespace Js
7676 }
7777 }
7878
79- IndexType GetIndexType (Var indexVar, ScriptContext* scriptContext, uint32* index, PropertyRecord const ** propertyRecord, JavascriptString ** propertyNameString, bool createIfNotFound, bool preferJavascriptStringOverPropertyRecord)
79+ IndexType GetIndexTypeFromPrimitive (Var indexVar, ScriptContext* scriptContext, uint32* index, PropertyRecord const ** propertyRecord, JavascriptString ** propertyNameString, bool createIfNotFound, bool preferJavascriptStringOverPropertyRecord)
8080 {
81- indexVar = JavascriptConversion::ToPrimitive (indexVar, JavascriptHint::HintString, scriptContext);
82-
8381 // CONSIDER: Only OP_SetElementI and OP_GetElementI use and take advantage of the
8482 // IndexType_JavascriptString result. Consider modifying other callers of GetIndexType to take
8583 // advantage of non-interned property strings where appropriate.
@@ -142,7 +140,18 @@ namespace Js
142140 }
143141 }
144142
145- IndexType GetIndexType (Var indexVar, ScriptContext* scriptContext, uint32* index, PropertyRecord const ** propertyRecord, bool createIfNotFound)
143+ IndexType GetIndexTypeFromPrimitive (Var indexVar, ScriptContext* scriptContext, uint32* index, PropertyRecord const ** propertyRecord, bool createIfNotFound)
144+ {
145+ return GetIndexTypeFromPrimitive (indexVar, scriptContext, index, propertyRecord, nullptr , createIfNotFound, false );
146+ }
147+
148+ IndexType GetIndexType (Var& indexVar, ScriptContext* scriptContext, uint32* index, PropertyRecord const ** propertyRecord, JavascriptString ** propertyNameString, bool createIfNotFound, bool preferJavascriptStringOverPropertyRecord)
149+ {
150+ indexVar = JavascriptConversion::ToPrimitive (indexVar, JavascriptHint::HintString, scriptContext);
151+ return GetIndexTypeFromPrimitive (indexVar, scriptContext, index, propertyRecord, propertyNameString, createIfNotFound, preferJavascriptStringOverPropertyRecord);
152+ }
153+
154+ IndexType GetIndexType (Var& indexVar, ScriptContext* scriptContext, uint32* index, PropertyRecord const ** propertyRecord, bool createIfNotFound)
146155 {
147156 return GetIndexType (indexVar, scriptContext, index, propertyRecord, nullptr , createIfNotFound, false );
148157 }
@@ -434,11 +443,10 @@ namespace Js
434443 try
435444 {
436445 Js::JavascriptExceptionOperators::AutoCatchHandlerExists autoCatchHandlerExists (scriptContext);
446+ IndexType indexType = GetIndexType (index, scriptContext, &indexVal, &propertyRecord, false );
437447
438448 // For JS Objects, don't create the propertyId if not already added
439- bool createIfNotFound = !IsJsNativeObject (object) ||
440- (DynamicType::Is (object->GetTypeId ()) && static_cast <DynamicObject*>(object)->GetTypeHandler ()->IsStringTypeHandler ()) || JavascriptProxy::Is (object);
441- if (GetIndexType (index, scriptContext, &indexVal, &propertyRecord, createIfNotFound) == IndexType_Number)
449+ if (indexType == IndexType_Number)
442450 {
443451 // In edge mode, we don't need to worry about the special "unknown" behavior. If the item is not available from Get,
444452 // just return undefined.
@@ -450,26 +458,35 @@ namespace Js
450458 return scriptContext->GetLibrary ()->GetUndefinedDisplayString ();
451459 }
452460 }
453- else if (propertyRecord == nullptr )
461+ else
454462 {
455- Assert (IsJsNativeObject (object));
463+ Assert (indexType == IndexType_PropertyId);
464+ if (propertyRecord == nullptr && !JavascriptOperators::CanShortcutOnUnknownPropertyName (object))
465+ {
466+ indexType = GetIndexTypeFromPrimitive (index, scriptContext, &indexVal, &propertyRecord, true );
467+ Assert (indexType == IndexType_PropertyId);
468+ Assert (propertyRecord != nullptr );
469+ }
456470
471+ if (propertyRecord != nullptr )
472+ {
473+ if (!JavascriptOperators::GetProperty (instance, object, propertyRecord->GetPropertyId (), &member, scriptContext))
474+ {
475+ // If the instance doesn't have the property, typeof result is "undefined".
476+ threadContext->CheckAndResetImplicitCallAccessorFlag ();
477+ threadContext->AddImplicitCallFlags (savedImplicitCallFlags);
478+ return scriptContext->GetLibrary ()->GetUndefinedDisplayString ();
479+ }
480+ }
481+ else
482+ {
457483#if DBG
458- JavascriptString* indexStr = JavascriptConversion::ToString (index, scriptContext);
459- PropertyRecord const * debugPropertyRecord;
460- scriptContext->GetOrAddPropertyRecord (indexStr->GetString (), indexStr->GetLength (), &debugPropertyRecord);
461- AssertMsg (!JavascriptOperators::GetProperty (instance, object, debugPropertyRecord->GetPropertyId (), &member, scriptContext), " how did this property come? See OS Bug 2727708 if you see this come from the web" );
484+ JavascriptString* indexStr = JavascriptConversion::ToString (index, scriptContext);
485+ PropertyRecord const * debugPropertyRecord;
486+ scriptContext->GetOrAddPropertyRecord (indexStr->GetString (), indexStr->GetLength (), &debugPropertyRecord);
487+ AssertMsg (!JavascriptOperators::GetProperty (instance, object, debugPropertyRecord->GetPropertyId (), &member, scriptContext), " how did this property come? See OS Bug 2727708 if you see this come from the web" );
462488#endif
463489
464- // If the instance doesn't have the property, typeof result is "undefined".
465- threadContext->CheckAndResetImplicitCallAccessorFlag ();
466- threadContext->AddImplicitCallFlags (savedImplicitCallFlags);
467- return scriptContext->GetLibrary ()->GetUndefinedDisplayString ();
468- }
469- else
470- {
471- if (!JavascriptOperators::GetProperty (instance, object, propertyRecord->GetPropertyId (), &member, scriptContext))
472- {
473490 // If the instance doesn't have the property, typeof result is "undefined".
474491 threadContext->CheckAndResetImplicitCallAccessorFlag ();
475492 threadContext->AddImplicitCallFlags (savedImplicitCallFlags);
@@ -3118,29 +3135,37 @@ namespace Js
31183135
31193136 uint32 indexVal;
31203137 PropertyRecord const * propertyRecord;
3121- bool createIfNotFound = (DynamicType::Is (object->GetTypeId ()) &&
3122- static_cast <DynamicObject*>(object)->GetTypeHandler ()->IsStringTypeHandler ()) ||
3123- JavascriptProxy::Is (object);
3124- if (GetIndexType (index, scriptContext, &indexVal, &propertyRecord, createIfNotFound) == IndexType_Number)
3138+ IndexType indexType = GetIndexType (index, scriptContext, &indexVal, &propertyRecord, false );
3139+
3140+ if (indexType == IndexType_Number)
31253141 {
31263142 return HasItem (object, indexVal);
31273143 }
3128- else if (propertyRecord == nullptr )
3144+ else
31293145 {
3130- Assert (IsJsNativeObject (object));
3146+ Assert (indexType == IndexType_PropertyId);
3147+ if (propertyRecord == nullptr && !JavascriptOperators::CanShortcutOnUnknownPropertyName (object))
3148+ {
3149+ indexType = GetIndexTypeFromPrimitive (index, scriptContext, &indexVal, &propertyRecord, true );
3150+ Assert (indexType == IndexType_PropertyId);
3151+ Assert (propertyRecord != nullptr );
3152+ }
31313153
3154+ if (propertyRecord != nullptr )
3155+ {
3156+ return HasProperty (object, propertyRecord->GetPropertyId ());
3157+ }
3158+ else
3159+ {
31323160#if DBG
3133- JavascriptString* indexStr = JavascriptConversion::ToString (index, scriptContext);
3134- PropertyRecord const * debugPropertyRecord;
3135- scriptContext->GetOrAddPropertyRecord (indexStr->GetString (), indexStr->GetLength (), &debugPropertyRecord);
3136- AssertMsg (!JavascriptOperators::HasProperty (object, debugPropertyRecord->GetPropertyId ()), " how did this property come? See OS Bug 2727708 if you see this come from the web" );
3161+ JavascriptString* indexStr = JavascriptConversion::ToString (index, scriptContext);
3162+ PropertyRecord const * debugPropertyRecord;
3163+ scriptContext->GetOrAddPropertyRecord (indexStr->GetString (), indexStr->GetLength (), &debugPropertyRecord);
3164+ AssertMsg (!JavascriptOperators::HasProperty (object, debugPropertyRecord->GetPropertyId ()), " how did this property come? See OS Bug 2727708 if you see this come from the web" );
31373165#endif
31383166
3139- return FALSE ;
3140- }
3141- else
3142- {
3143- return HasProperty (object, propertyRecord->GetPropertyId ());
3167+ return FALSE ;
3168+ }
31443169 }
31453170 }
31463171
@@ -3700,9 +3725,7 @@ namespace Js
37003725 JavascriptString * propertyNameString;
37013726 Var value;
37023727
3703- bool createIfNotFound = !IsJsNativeObject (object);
3704-
3705- IndexType indexType = GetIndexType (index, scriptContext, &indexVal, &propertyRecord, &propertyNameString, createIfNotFound, true );
3728+ IndexType indexType = GetIndexType (index, scriptContext, &indexVal, &propertyRecord, &propertyNameString, false , true );
37063729
37073730 if (indexType == IndexType_Number)
37083731 {
@@ -3720,15 +3743,30 @@ namespace Js
37203743 }
37213744 else
37223745 {
3723- // We called GetIndexType with preferJavascriptString as true, so we mush have a propertyRecord
37243746 Assert (indexType == IndexType_PropertyId);
3747+ if (propertyRecord == nullptr && !JavascriptOperators::CanShortcutOnUnknownPropertyName (object))
3748+ {
3749+ indexType = GetIndexTypeFromPrimitive (index, scriptContext, &indexVal, &propertyRecord, &propertyNameString, true , true );
3750+ Assert (indexType == IndexType_PropertyId);
3751+ Assert (propertyRecord != nullptr );
3752+ }
37253753
3726- Assert (propertyRecord);
3727-
3728- if (JavascriptOperators::GetPropertyWPCache (receiver, object, propertyRecord->GetPropertyId (), &value, scriptContext, nullptr ))
3754+ if (propertyRecord != nullptr )
37293755 {
3730- return value;
3756+ if (JavascriptOperators::GetPropertyWPCache (receiver, object, propertyRecord->GetPropertyId (), &value, scriptContext, nullptr ))
3757+ {
3758+ return value;
3759+ }
3760+ }
3761+ #if DBG
3762+ else
3763+ {
3764+ JavascriptString* indexStr = JavascriptConversion::ToString (index, scriptContext);
3765+ PropertyRecord const * debugPropertyRecord;
3766+ scriptContext->GetOrAddPropertyRecord (indexStr->GetString (), indexStr->GetLength (), &debugPropertyRecord);
3767+ AssertMsg (!JavascriptOperators::GetProperty (receiver, object, debugPropertyRecord->GetPropertyId (), &value, scriptContext), " how did this property come? See OS Bug 2727708 if you see this come from the web" );
37313768 }
3769+ #endif
37323770 }
37333771
37343772 return scriptContext->GetMissingItemResult ();
@@ -3911,23 +3949,30 @@ namespace Js
39113949 PropertyRecord const * propertyRecord;
39123950 Var value = NULL ;
39133951 BOOL hasProperty = FALSE ;
3914- bool createIfNotFound = !IsJsNativeObject (object) ||
3915- (DynamicType::Is (object->GetTypeId ()) && static_cast <DynamicObject*>(object)->GetTypeHandler ()->IsStringTypeHandler ()) || JavascriptProxy::Is (object);
3952+ IndexType indexType = GetIndexType (index, scriptContext, &indexVal, &propertyRecord, false );
39163953
3917- if (GetIndexType (index, scriptContext, &indexVal, &propertyRecord, createIfNotFound) == IndexType_Number)
3954+ if (indexType == IndexType_Number)
39183955 {
39193956 hasProperty = JavascriptOperators::GetItemReference (instance, object, indexVal, &value, scriptContext);
39203957 }
39213958 else
39223959 {
3960+ Assert (indexType == IndexType_PropertyId);
3961+
3962+ if (propertyRecord == nullptr && !JavascriptOperators::CanShortcutOnUnknownPropertyName (object))
3963+ {
3964+ indexType = GetIndexTypeFromPrimitive (index, scriptContext, &indexVal, &propertyRecord, true );
3965+ Assert (indexType == IndexType_PropertyId);
3966+ Assert (propertyRecord != nullptr );
3967+ }
3968+
39233969 if (propertyRecord != nullptr )
39243970 {
39253971 hasProperty = JavascriptOperators::GetPropertyReference (instance, object, propertyRecord->GetPropertyId (), &value, scriptContext, NULL );
39263972 }
39273973#if DBG
39283974 else
39293975 {
3930- Assert (IsJsNativeObject (object));
39313976 JavascriptString* indexStr = JavascriptConversion::ToString (index, scriptContext);
39323977 PropertyRecord const * debugPropertyRecord;
39333978 scriptContext->GetOrAddPropertyRecord (indexStr->GetString (), indexStr->GetLength (), &debugPropertyRecord);
@@ -4765,24 +4810,30 @@ namespace Js
47654810 uint32 indexVal;
47664811 PropertyRecord const * propertyRecord;
47674812 BOOL result = TRUE ;
4813+ IndexType indexType = GetIndexType (index, scriptContext, &indexVal, &propertyRecord, false );
47684814
4769- bool createIfNotFound = !IsJsNativeObject (object) ||
4770- (DynamicType::Is (object->GetTypeId ()) && static_cast <DynamicObject*>(object)->GetTypeHandler ()->IsStringTypeHandler ()) || JavascriptProxy::Is (object);
4771-
4772- if (GetIndexType (index, scriptContext, &indexVal, &propertyRecord, createIfNotFound) == IndexType_Number)
4815+ if (indexType == IndexType_Number)
47734816 {
47744817 result = JavascriptOperators::DeleteItem (object, indexVal, propertyOperationFlags);
47754818 }
47764819 else
47774820 {
4778- if (propertyRecord)
4821+ Assert (indexType == IndexType_PropertyId);
4822+
4823+ if (propertyRecord == nullptr && !JavascriptOperators::CanShortcutOnUnknownPropertyName (object))
4824+ {
4825+ indexType = GetIndexTypeFromPrimitive (index, scriptContext, &indexVal, &propertyRecord, true );
4826+ Assert (indexType == IndexType_PropertyId);
4827+ Assert (propertyRecord != nullptr );
4828+ }
4829+
4830+ if (propertyRecord != nullptr )
47794831 {
47804832 result = JavascriptOperators::DeleteProperty (object, propertyRecord->GetPropertyId (), propertyOperationFlags);
47814833 }
47824834#if DBG
47834835 else
47844836 {
4785- Assert (IsJsNativeObject (object));
47864837 JavascriptString* indexStr = JavascriptConversion::ToString (index, scriptContext);
47874838 PropertyRecord const * debugPropertyRecord;
47884839 scriptContext->GetOrAddPropertyRecord (indexStr->GetString (), indexStr->GetLength (), &debugPropertyRecord);
@@ -4977,6 +5028,50 @@ namespace Js
49775028 }
49785029 }
49795030
5031+ bool JavascriptOperators::CanShortcutOnUnknownPropertyName (RecyclableObject *instance)
5032+ {
5033+ if (!CanShortcutInstanceOnUnknownPropertyName (instance))
5034+ {
5035+ return false ;
5036+ }
5037+ return CanShortcutPrototypeChainOnUnknownPropertyName (instance->GetPrototype ());
5038+ }
5039+
5040+ bool JavascriptOperators::CanShortcutInstanceOnUnknownPropertyName (RecyclableObject *instance)
5041+ {
5042+ if (PHASE_OFF1 (Js::OptUnknownElementNamePhase))
5043+ {
5044+ return false ;
5045+ }
5046+
5047+ if (JavascriptProxy::Is (instance) || instance->IsExternal ())
5048+ {
5049+ return false ;
5050+ }
5051+ if (DynamicType::Is (instance->GetTypeId ()) &&
5052+ static_cast <DynamicObject*>(instance)->GetTypeHandler ()->IsStringTypeHandler ())
5053+ {
5054+ return false ;
5055+ }
5056+ return !(instance->HasDeferredTypeHandler () &&
5057+ JavascriptFunction::Is (instance) &&
5058+ JavascriptFunction::FromVar (instance)->IsExternalFunction ());
5059+ }
5060+
5061+ bool JavascriptOperators::CanShortcutPrototypeChainOnUnknownPropertyName (RecyclableObject *prototype)
5062+ {
5063+ Assert (prototype);
5064+
5065+ for (; prototype->GetTypeId () != TypeIds_Null; prototype = prototype->GetPrototype ())
5066+ {
5067+ if (!CanShortcutInstanceOnUnknownPropertyName (prototype))
5068+ {
5069+ return false ;
5070+ }
5071+ }
5072+ return true ;
5073+ }
5074+
49805075 RecyclableObject* JavascriptOperators::GetPrototype (RecyclableObject* instance)
49815076 {
49825077 if (JavascriptOperators::GetTypeId (instance) == TypeIds_Null)
0 commit comments