Browse Source

perf: Improve internal type discovery and getProperty

 - Fast path for IsNull / IsUndefined (in case the argument is
    recyclableObject, or we know for sure object's context). Especially
NullCheck was pretty common within the internal loops

    - Introduce internal GetProperty calls by introducing
    GetPropertyNoCache that serves only for RecyclableObject+ and when
info == nullptr.

 - Improve logic in related places. (i.e. use less GetTypeId calls,
GetPropertyName calls...)
Oguz Bastemur 8 years ago
parent
commit
a745c465fb

+ 3 - 14
lib/Runtime/Language/JavascriptConversion.cpp

@@ -22,12 +22,7 @@ namespace Js
     // construct the message string before knowing whether or not the object is coercible.
     BOOL JavascriptConversion::CheckObjectCoercible(Var aValue, ScriptContext* scriptContext)
     {
-        TypeId typeId = JavascriptOperators::GetTypeId(aValue);
-        if (typeId == TypeIds_Null || typeId == TypeIds_Undefined)
-        {
-            return FALSE;
-        }
-        return TRUE;
+        return !JavascriptOperators::IsUndefinedOrNull(aValue);
     }
 
     //ES5 9.11  Undefined, Null, Boolean, Number, String - return false
@@ -63,15 +58,9 @@ namespace Js
         TypeId leftType = JavascriptOperators::GetTypeId(aLeft);
         TypeId rightType = JavascriptOperators::GetTypeId(aRight);
 
-        //Check for undefined and null type;
-        if (leftType == TypeIds_Undefined )
-        {
-            return rightType == TypeIds_Undefined;
-        }
-
-        if (leftType == TypeIds_Null)
+        if (JavascriptOperators::IsUndefinedOrNullType(leftType))
         {
-            return rightType == TypeIds_Null;
+            return leftType == rightType;
         }
 
         double dblLeft, dblRight;

+ 1 - 1
lib/Runtime/Language/JavascriptExceptionOperators.cpp

@@ -1452,7 +1452,7 @@ namespace Js
             }
 
             Var var = nullptr;
-            if (JavascriptOperators::GetProperty(error, PropertyIds::stackTraceLimit, &var, scriptContext))
+            if (JavascriptOperators::GetPropertyNoCache(error, PropertyIds::stackTraceLimit, &var, scriptContext))
             {
                 // Only accept the value if it is a "Number". Avoid potential valueOf() call.
                 switch (JavascriptOperators::GetTypeId(var))

+ 138 - 52
lib/Runtime/Language/JavascriptOperators.cpp

@@ -1483,7 +1483,7 @@ CommonNumber:
 
     BOOL JavascriptOperators::HasProperty(RecyclableObject* instance, PropertyId propertyId)
     {
-        while (JavascriptOperators::GetTypeId(instance) != TypeIds_Null)
+        while (!JavascriptOperators::IsNull(instance))
         {
             PropertyQueryFlags result = instance->HasPropertyQuery(propertyId);
             if (result != PropertyQueryFlags::Property_NotFound)
@@ -1675,6 +1675,36 @@ CommonNumber:
         return GetProperty_Internal<false>(instance, RecyclableObject::FromVar(instance), true, propertyId, value, requestContext, info);
     }
 
+    BOOL JavascriptOperators::GetProperty_InternalSimple(Var instance, RecyclableObject* object, PropertyId propertyId, _Outptr_result_maybenull_ Var* value, ScriptContext* requestContext)
+    {
+        BOOL foundProperty = FALSE;
+        Assert(value != nullptr);
+
+        while (!JavascriptOperators::IsNull(object))
+        {
+            PropertyQueryFlags result = object->GetPropertyQuery(instance, propertyId, value, nullptr, requestContext);
+            if (result != PropertyQueryFlags::Property_NotFound)
+            {
+                foundProperty = JavascriptConversion::PropertyQueryFlagsToBoolean(result);
+                break;
+            }
+
+            if (object->SkipsPrototype())
+            {
+                break;
+            }
+
+            object = JavascriptOperators::GetPrototypeNoTrap(object);
+        }
+
+        if (!foundProperty)
+        {
+            *value = requestContext->GetMissingPropertyResult();
+        }
+
+        return foundProperty;
+    }
+
     template <bool unscopables>
     BOOL JavascriptOperators::GetProperty_Internal(Var instance, RecyclableObject* propertyObject, const bool isRoot, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info)
     {
@@ -1692,7 +1722,7 @@ CommonNumber:
             foundProperty = rootObject->GetRootProperty(instance, propertyId, value, info, requestContext);
         }
 
-        while (!foundProperty && JavascriptOperators::GetTypeId(object) != TypeIds_Null)
+        while (!foundProperty && !JavascriptOperators::IsNull(object))
         {
             if (unscopables && IsPropertyUnscopable(object, propertyId))
             {
@@ -1795,7 +1825,7 @@ CommonNumber:
     BOOL JavascriptOperators::GetPropertyWPCache(Var instance, RecyclableObject* propertyObject, PropertyKeyType propertyKey, Var* value, ScriptContext* requestContext, _Inout_ PropertyValueInfo * info)
     {
         RecyclableObject* object = propertyObject;
-        while (JavascriptOperators::GetTypeId(object) != TypeIds_Null)
+        while (!JavascriptOperators::IsNull(object))
         {
             PropertyQueryFlags result = object->GetPropertyQuery(instance, propertyKey, value, info, requestContext);
             if (result != PropertyQueryFlags::Property_NotFound)
@@ -1832,9 +1862,8 @@ CommonNumber:
             return TRUE;
         }
         RecyclableObject* object = RecyclableObject::FromVar(instance);
-        TypeId typeId = object->GetTypeId();
         *propertyObject = object;
-        if (typeId == TypeIds_Null || typeId == TypeIds_Undefined)
+        if (JavascriptOperators::IsUndefinedOrNull(object))
         {
             return FALSE;
         }
@@ -1864,7 +1893,7 @@ CommonNumber:
             }
         }
 
-        Var result = JavascriptOperators::GetProperty(instance, object, propertyId, scriptContext);
+        Var result = JavascriptOperators::GetPropertyNoCache(instance, object, propertyId, scriptContext);
         AssertMsg(result != nullptr, "result null in OP_GetProperty");
         return result;
     }
@@ -1998,7 +2027,7 @@ CommonNumber:
     {
         BOOL foundProperty = false;
         RecyclableObject* object = *propertyObject;
-        while (!foundProperty && JavascriptOperators::GetTypeId(object) != TypeIds_Null)
+        while (!foundProperty && !JavascriptOperators::IsNull(object))
         {
             if (unscopables && JavascriptOperators::IsPropertyUnscopable(object, propertyId))
             {
@@ -2085,16 +2114,14 @@ CommonNumber:
     {
         DescriptorFlags flags = None;
         RecyclableObject* object = instance;
-        while (flags == None && JavascriptOperators::GetTypeId(object) != TypeIds_Null)
+        while (flags == None && !JavascriptOperators::IsNull(object))
         {
-
             if (unscopable && IsPropertyUnscopable(object, propertyKey))
             {
                 break;
             }
             else
             {
-
                 flags = object->GetSetter(propertyKey, setterValue, info, scriptContext);
                 if (flags != None)
                 {
@@ -2144,7 +2171,7 @@ CommonNumber:
         }
 
         RecyclableObject* object = instance;
-        while (JavascriptOperators::GetTypeId(object) != TypeIds_Null)
+        while (!JavascriptOperators::IsNull(object))
         {
             *flags = object->GetItemSetter(index, setterValue, scriptContext);
             if (*flags != None || skipPrototypeCheck)
@@ -2468,7 +2495,7 @@ CommonNumber:
             else
             {
                 RecyclableObject* instanceObject = RecyclableObject::FromVar(receiver);
-                while (JavascriptOperators::GetTypeId(instanceObject) != TypeIds_Null)
+                while (!JavascriptOperators::IsNull(instanceObject))
                 {
                     if (unscopables && JavascriptOperators::IsPropertyUnscopable(instanceObject, propertyId))
                     {
@@ -2532,8 +2559,7 @@ CommonNumber:
     BOOL JavascriptOperators::GetAccessors(RecyclableObject* instance, PropertyId propertyId, ScriptContext* requestContext, Var* getter, Var* setter)
     {
         RecyclableObject* object = instance;
-
-        while (JavascriptOperators::GetTypeId(object) != TypeIds_Null)
+        while (!JavascriptOperators::IsNull(object))
         {
             if (object->GetAccessors(propertyId, getter, setter, requestContext))
             {
@@ -2566,7 +2592,7 @@ CommonNumber:
         }
         TypeId typeId = JavascriptOperators::GetTypeId(thisInstance);
 
-        if (typeId == TypeIds_Null || typeId == TypeIds_Undefined)
+        if (JavascriptOperators::IsUndefinedOrNullType(typeId))
         {
             if (scriptContext->GetThreadContext()->RecordImplicitException())
             {
@@ -2774,15 +2800,13 @@ CommonNumber:
             return scriptContext->GetLibrary()->GetTrue();
         }
 
-        TypeId typeId = JavascriptOperators::GetTypeId(instance);
-        if (typeId == TypeIds_Null || typeId == TypeIds_Undefined)
+        RecyclableObject* recyclableObject = RecyclableObject::FromVar(instance);
+        if (JavascriptOperators::IsUndefinedOrNull(recyclableObject))
         {
             JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotDelete_NullOrUndefined,
                 scriptContext->GetPropertyName(propertyId)->GetBuffer());
         }
 
-        RecyclableObject *recyclableObject = RecyclableObject::FromVar(instance);
-
         return scriptContext->GetLibrary()->CreateBoolean(
             JavascriptOperators::DeleteProperty(recyclableObject, propertyId, propertyOperationFlags));
     }
@@ -3066,7 +3090,7 @@ CommonNumber:
 #if ENABLE_COPYONACCESS_ARRAY
         JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(object);
 #endif
-        while (JavascriptOperators::GetTypeId(object) != TypeIds_Null)
+        while (!JavascriptOperators::IsNull(object))
         {
             PropertyQueryFlags result;
             if ((result = object->HasItemQuery(index)) != PropertyQueryFlags::Property_NotFound)
@@ -3088,7 +3112,7 @@ CommonNumber:
     BOOL JavascriptOperators::GetItem(Var instance, RecyclableObject* propertyObject, uint32 index, Var* value, ScriptContext* requestContext)
     {
         RecyclableObject* object = propertyObject;
-        while (JavascriptOperators::GetTypeId(object) != TypeIds_Null)
+        while (!JavascriptOperators::IsNull(object))
         {
             PropertyQueryFlags result;
             if ((result = object->GetItemQuery(instance, index, value, requestContext)) != PropertyQueryFlags::Property_NotFound)
@@ -3108,7 +3132,7 @@ CommonNumber:
     BOOL JavascriptOperators::GetItemReference(Var instance, RecyclableObject* propertyObject, uint32 index, Var* value, ScriptContext* requestContext)
     {
         RecyclableObject* object = propertyObject;
-        while (JavascriptOperators::GetTypeId(object) != TypeIds_Null)
+        while (!JavascriptOperators::IsNull(object))
         {
             PropertyQueryFlags result;
             if ((result = object->GetItemReferenceQuery(instance, index, value, requestContext)) != PropertyQueryFlags::Property_NotFound)
@@ -4886,14 +4910,12 @@ CommonNumber:
 #if ENABLE_COPYONACCESS_ARRAY
         JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
 #endif
-        TypeId typeId = JavascriptOperators::GetTypeId(instance);
-        if (typeId == TypeIds_Null || typeId == TypeIds_Undefined)
+        RecyclableObject* object = RecyclableObject::FromVar(instance);
+        if (JavascriptOperators::IsUndefinedOrNull(object))
         {
             JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotDelete_NullOrUndefined, GetPropertyDisplayNameForError(index, scriptContext));
         }
 
-        RecyclableObject* object = RecyclableObject::FromVar(instance);
-
         uint32 indexVal;
         PropertyRecord const * propertyRecord = nullptr;
         JavascriptString * propertyNameString = nullptr;
@@ -5165,8 +5187,7 @@ CommonNumber:
     bool JavascriptOperators::CanShortcutPrototypeChainOnUnknownPropertyName(RecyclableObject *prototype)
     {
         Assert(prototype);
-
-        for (; prototype->GetTypeId() != TypeIds_Null; prototype = prototype->GetPrototype())
+        for (; !JavascriptOperators::IsNull(prototype); prototype = prototype->GetPrototype())
         {
             if (!CanShortcutInstanceOnUnknownPropertyName(prototype))
             {
@@ -5191,13 +5212,15 @@ CommonNumber:
         {
             return scriptContext->GetLibrary()->GetNumberPrototype();
         }
-        else if (JavascriptOperators::GetTypeId(instance) != TypeIds_Null)
-        {
-            return JavascriptOperators::GetPrototype(RecyclableObject::FromVar(instance));
-        }
         else
         {
-            return scriptContext->GetLibrary()->GetNull();
+            RecyclableObject* object = RecyclableObject::FromVar(instance);
+            if (JavascriptOperators::IsNull(object))
+            {
+                return object;
+            }
+
+            return JavascriptOperators::GetPrototype(object);
         }
     }
 
@@ -7018,7 +7041,8 @@ CommonNumber:
         RecyclableObject* constructor = RecyclableObject::FromVar(aClass);
         if (scriptContext->GetConfig()->IsES6HasInstanceEnabled())
         {
-            Var instOfHandler = JavascriptOperators::GetProperty(constructor, PropertyIds::_symbolHasInstance, scriptContext);
+            Var instOfHandler = JavascriptOperators::GetPropertyNoCache(constructor,
+              PropertyIds::_symbolHasInstance, scriptContext);
             if (JavascriptOperators::IsUndefinedObject(instOfHandler)
                 || instOfHandler == scriptContext->GetBuiltInLibraryFunction(JavascriptFunction::EntryInfo::SymbolHasInstance.GetOriginalEntryPoint()))
             {
@@ -7098,14 +7122,14 @@ CommonNumber:
                         JavascriptError::ThrowTypeError(scriptContext, JSERR_InvalidPrototype);
                     }
 
-                    Var extendsProto = JavascriptOperators::GetProperty(extends, extendsObj, Js::PropertyIds::prototype, scriptContext);
+                    Var extendsProto = JavascriptOperators::GetPropertyNoCache(extends, extendsObj, Js::PropertyIds::prototype, scriptContext);
                     uint extendsProtoTypeId = JavascriptOperators::GetTypeId(extendsProto);
                     if (extendsProtoTypeId <= Js::TypeId::TypeIds_LastJavascriptPrimitiveType && extendsProtoTypeId != Js::TypeId::TypeIds_Null)
                     {
                         JavascriptError::ThrowTypeError(scriptContext, JSERR_InvalidPrototype);
                     }
 
-                    Var ctorProto = JavascriptOperators::GetProperty(constructor, ctor, Js::PropertyIds::prototype, scriptContext);
+                    Var ctorProto = JavascriptOperators::GetPropertyNoCache(constructor, ctor, Js::PropertyIds::prototype, scriptContext);
                     RecyclableObject * ctorProtoObj = RecyclableObject::FromVar(ctorProto);
 
                     ctorProtoObj->SetPrototype(RecyclableObject::FromVar(extendsProto));
@@ -7113,7 +7137,7 @@ CommonNumber:
                     ctorProtoObj->EnsureProperty(Js::PropertyIds::constructor);
                     ctorProtoObj->SetEnumerable(Js::PropertyIds::constructor, FALSE);
 
-                    Var protoCtor = JavascriptOperators::GetProperty(ctorProto, ctorProtoObj, Js::PropertyIds::constructor, scriptContext);
+                    Var protoCtor = JavascriptOperators::GetPropertyNoCache(ctorProto, ctorProtoObj, Js::PropertyIds::constructor, scriptContext);
                     RecyclableObject * protoCtorObj = RecyclableObject::FromVar(protoCtor);
                     protoCtorObj->SetPrototype(extendsObj);
 
@@ -8994,27 +9018,27 @@ CommonNumber:
         Var value;
         RecyclableObject* propertySpecObj = RecyclableObject::FromVar(propertySpec);
 
-        if (JavascriptOperators::GetProperty(propertySpecObj, PropertyIds::enumerable, &value, scriptContext))
+        if (JavascriptOperators::GetPropertyNoCache(propertySpecObj, PropertyIds::enumerable, &value, scriptContext))
         {
             descriptor->SetEnumerable(JavascriptConversion::ToBoolean(value, scriptContext) ? true : false);
         }
 
-        if (JavascriptOperators::GetProperty(propertySpecObj, PropertyIds::configurable, &value, scriptContext))
+        if (JavascriptOperators::GetPropertyNoCache(propertySpecObj, PropertyIds::configurable, &value, scriptContext))
         {
             descriptor->SetConfigurable(JavascriptConversion::ToBoolean(value, scriptContext) ? true : false);
         }
 
-        if (JavascriptOperators::GetProperty(propertySpecObj, PropertyIds::value, &value, scriptContext))
+        if (JavascriptOperators::GetPropertyNoCache(propertySpecObj, PropertyIds::value, &value, scriptContext))
         {
             descriptor->SetValue(value);
         }
 
-        if (JavascriptOperators::GetProperty(propertySpecObj, PropertyIds::writable, &value, scriptContext))
+        if (JavascriptOperators::GetPropertyNoCache(propertySpecObj, PropertyIds::writable, &value, scriptContext))
         {
             descriptor->SetWritable(JavascriptConversion::ToBoolean(value, scriptContext) ? true : false);
         }
 
-        if (JavascriptOperators::GetProperty(propertySpecObj, PropertyIds::get, &value, scriptContext))
+        if (JavascriptOperators::GetPropertyNoCache(propertySpecObj, PropertyIds::get, &value, scriptContext))
         {
             if (JavascriptOperators::GetTypeId(value) != TypeIds_Undefined && (false == JavascriptConversion::IsCallable(value)))
             {
@@ -9023,7 +9047,7 @@ CommonNumber:
             descriptor->SetGetter(value);
         }
 
-        if (JavascriptOperators::GetProperty(propertySpecObj, PropertyIds::set, &value, scriptContext))
+        if (JavascriptOperators::GetPropertyNoCache(propertySpecObj, PropertyIds::set, &value, scriptContext))
         {
             if (JavascriptOperators::GetTypeId(value) != TypeIds_Undefined && (false == JavascriptConversion::IsCallable(value)))
             {
@@ -10060,7 +10084,8 @@ CommonNumber:
             //6.Let S be Get(C, @@species).
             //7.ReturnIfAbrupt(S).
             Var species = nullptr;
-            if (!JavascriptOperators::GetProperty(RecyclableObject::FromVar(constructor), PropertyIds::_symbolSpecies, &species, scriptContext)
+            if (!JavascriptOperators::GetProperty(RecyclableObject::FromVar(constructor),
+                PropertyIds::_symbolSpecies, &species, scriptContext)
                 || JavascriptOperators::IsUndefinedOrNull(species))
             {
                 //8.If S is either undefined or null, return defaultConstructor.
@@ -10423,11 +10448,43 @@ CommonNumber:
         return IsUndefinedOrNullType(JavascriptOperators::GetTypeId(instance));
     }
 
+    BOOL JavascriptOperators::IsUndefinedOrNull(RecyclableObject* instance)
+    {
+        return JavascriptOperators::IsUndefinedOrNullType(instance->GetTypeId());
+    }
+
+    BOOL JavascriptOperators::IsUndefinedOrNull(Var instance, ScriptContext* scriptContext)
+    {
+        JavascriptLibrary* library = scriptContext->GetLibrary();
+        return IsUndefinedObject(instance, library) || IsNull(instance, library);
+    }
+
+    BOOL JavascriptOperators::IsUndefinedOrNull(Var instance, JavascriptLibrary* library)
+    {
+        return IsUndefinedObject(instance, library) || IsNull(instance, library);
+    }
+
     BOOL JavascriptOperators::IsNull(Var instance)
     {
         return JavascriptOperators::GetTypeId(instance) == TypeIds_Null;
     }
 
+    BOOL JavascriptOperators::IsNull(Var instance, ScriptContext* scriptContext)
+    {
+        return JavascriptOperators::IsNull(instance, scriptContext->GetLibrary());
+    }
+
+    BOOL JavascriptOperators::IsNull(Var instance, JavascriptLibrary* library)
+    {
+        Assert(!RecyclableObject::Is(instance) ? TRUE : ((RecyclableObject*)instance)->GetScriptContext()->GetLibrary() == library );
+        return library->GetNull() == instance;
+    }
+
+    BOOL JavascriptOperators::IsNull(RecyclableObject* instance)
+    {
+        return instance->GetType()->GetTypeId() == TypeIds_Null;
+    }
+
     BOOL JavascriptOperators::IsSpecialObjectType(TypeId typeId)
     {
         return typeId > TypeIds_LastTrueJavascriptObjectType;
@@ -10438,20 +10495,27 @@ CommonNumber:
         return JavascriptOperators::GetTypeId(instance) == TypeIds_Undefined;
     }
 
-    BOOL JavascriptOperators::IsUndefinedObject(Var instance, RecyclableObject *libraryUndefined)
+    BOOL JavascriptOperators::IsUndefinedObject(RecyclableObject* instance)
     {
-        Assert(JavascriptOperators::IsUndefinedObject(libraryUndefined));
+        return instance->GetType()->GetTypeId() == TypeIds_Undefined;
+    }
 
+    BOOL JavascriptOperators::IsUndefinedObject(Var instance, RecyclableObject* libraryUndefined)
+    {
+        Assert(JavascriptOperators::IsUndefinedObject(libraryUndefined));
+        AssertMsg((instance == libraryUndefined)
+          == JavascriptOperators::IsUndefinedObject(instance), "Wrong ScriptContext?");
         return instance == libraryUndefined;
     }
 
     BOOL JavascriptOperators::IsUndefinedObject(Var instance, ScriptContext *scriptContext)
     {
-        return JavascriptOperators::IsUndefinedObject(instance, scriptContext->GetLibrary()->GetUndefined());
+        return JavascriptOperators::IsUndefinedObject(instance, scriptContext->GetLibrary());
     }
 
     BOOL JavascriptOperators::IsUndefinedObject(Var instance, JavascriptLibrary* library)
     {
+        Assert(!RecyclableObject::Is(instance) ? TRUE : ((RecyclableObject*)instance)->GetScriptContext()->GetLibrary() == library );
         return JavascriptOperators::IsUndefinedObject(instance, library->GetUndefined());
     }
 
@@ -10476,7 +10540,7 @@ CommonNumber:
 
     RecyclableObject* JavascriptOperators::GetIteratorFunction(RecyclableObject* instance, ScriptContext * scriptContext, bool optional)
     {
-        Var func = JavascriptOperators::GetProperty(instance, PropertyIds::_symbolIterator, scriptContext);
+        Var func = JavascriptOperators::GetPropertyNoCache(instance, PropertyIds::_symbolIterator, scriptContext);
 
         if (optional && JavascriptOperators::IsUndefinedOrNull(func))
         {
@@ -10537,7 +10601,7 @@ CommonNumber:
     // IteratorNext as described in ES6.0 (draft 22) Section 7.4.2
     RecyclableObject* JavascriptOperators::IteratorNext(RecyclableObject* iterator, ScriptContext* scriptContext, Var value)
     {
-        Var func = JavascriptOperators::GetProperty(iterator, PropertyIds::next, scriptContext);
+        Var func = JavascriptOperators::GetPropertyNoCache(iterator, PropertyIds::next, scriptContext);
 
         ThreadContext *threadContext = scriptContext->GetThreadContext();
         if (!JavascriptConversion::IsCallable(func))
@@ -10572,7 +10636,7 @@ CommonNumber:
     // IteratorComplete as described in ES6.0 (draft 22) Section 7.4.3
     bool JavascriptOperators::IteratorComplete(RecyclableObject* iterResult, ScriptContext* scriptContext)
     {
-        Var done = JavascriptOperators::GetProperty(iterResult, Js::PropertyIds::done, scriptContext);
+        Var done = JavascriptOperators::GetPropertyNoCache(iterResult, Js::PropertyIds::done, scriptContext);
 
         return JavascriptConversion::ToBool(done, scriptContext);
     }
@@ -10580,7 +10644,7 @@ CommonNumber:
     // IteratorValue as described in ES6.0 (draft 22) Section 7.4.4
     Var JavascriptOperators::IteratorValue(RecyclableObject* iterResult, ScriptContext* scriptContext)
     {
-        return JavascriptOperators::GetProperty(iterResult, Js::PropertyIds::value, scriptContext);
+        return JavascriptOperators::GetPropertyNoCache(iterResult, Js::PropertyIds::value, scriptContext);
     }
 
     // IteratorStep as described in ES6.0 (draft 22) Section 7.4.5
@@ -10617,7 +10681,7 @@ CommonNumber:
         // There isn't a good way for us to add internal properties to objects in Chakra.
         // Thus, caller should take care to create obj with the correct internal properties.
 
-        Var proto = JavascriptOperators::GetProperty(constructor, Js::PropertyIds::prototype, scriptContext);
+        Var proto = JavascriptOperators::GetPropertyNoCache(constructor, Js::PropertyIds::prototype, scriptContext);
 
         // If constructor.prototype is an object, we should use that as the [[Prototype]] for our obj.
         // Else, we set the [[Prototype]] internal slot of obj to %intrinsicProto% - which should be the default.
@@ -10650,6 +10714,28 @@ CommonNumber:
         return requestContext->GetMissingPropertyResult();
     }
 
+    Var JavascriptOperators::GetPropertyNoCache(RecyclableObject* instance, PropertyId propertyId, ScriptContext* requestContext)
+    {
+        return JavascriptOperators::GetPropertyNoCache(instance, instance, propertyId, requestContext);
+    }
+
+    Var JavascriptOperators::GetPropertyNoCache(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, ScriptContext* requestContext)
+    {
+        Var value;
+        JavascriptOperators::GetProperty_InternalSimple(instance, propertyObject, propertyId, &value, requestContext);
+        return value;
+    }
+
+    BOOL JavascriptOperators::GetPropertyNoCache(RecyclableObject* instance, PropertyId propertyId, Var* value, ScriptContext* requestContext)
+    {
+        return JavascriptOperators::GetPropertyNoCache(instance, instance, propertyId, value, requestContext);
+    }
+
+    BOOL JavascriptOperators::GetPropertyNoCache(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, Var* value, ScriptContext* requestContext)
+    {
+        return JavascriptOperators::GetProperty_InternalSimple(instance, propertyObject, propertyId, value, requestContext);
+    }
+
     Var JavascriptOperators::GetRootProperty(RecyclableObject* instance, PropertyId propertyId, ScriptContext* requestContext, PropertyValueInfo* info)
     {
         Var value;

+ 20 - 3
lib/Runtime/Language/JavascriptOperators.h

@@ -179,6 +179,12 @@ namespace Js
         static Var  GetProperty(RecyclableObject* instance, PropertyId propertyId, ScriptContext* requestContext, PropertyValueInfo* info = NULL);
         static BOOL GetProperty(RecyclableObject* instance, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info = NULL);
         static Var  GetProperty(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, ScriptContext* requestContext, PropertyValueInfo* info = NULL);
+
+        static Var  GetPropertyNoCache(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, ScriptContext* requestContext);
+        static Var  GetPropertyNoCache(RecyclableObject* instance, PropertyId propertyId, ScriptContext* requestContext);
+        static BOOL GetPropertyNoCache(RecyclableObject* instance, PropertyId propertyId, Var* value, ScriptContext* requestContext);
+        static BOOL GetPropertyNoCache(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, Var* value, ScriptContext* requestContext);
+
         static BOOL GetProperty(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info = NULL);
         static BOOL GetPropertyObject(Var instance, ScriptContext * scriptContext, RecyclableObject** propertyObject);
         static BOOL GetRootProperty(Var instance, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info = NULL);
@@ -209,19 +215,28 @@ namespace Js
         static BOOL IsObjectType(TypeId typeId);
         static BOOL IsObjectOrNull(Var instance);
         static BOOL IsUndefined(Var instance);
+        static BOOL IsUndefinedObject(RecyclableObject* instance);
         static BOOL IsUndefinedOrNullType(TypeId);
         static BOOL IsUndefinedOrNull(Var instance);
+        static BOOL IsUndefinedOrNull(RecyclableObject* instance);
         static BOOL IsNull(Var instance);
+        static BOOL IsNull(RecyclableObject* instance);
         static BOOL IsSpecialObjectType(TypeId typeId);
         static BOOL IsJsNativeObject(Var instance);
         static BOOL IsUndefinedObject(Var instance);
-        static BOOL IsUndefinedObject(Var instance, ScriptContext *scriptContext);
-        static BOOL IsUndefinedObject(Var instance, RecyclableObject *libraryUndefined);
-        static BOOL IsUndefinedObject(Var instance, JavascriptLibrary* library);
         static BOOL IsAnyNumberValue(Var instance);
         static BOOL IsClassConstructor(Var instance);
         static BOOL IsBaseConstructorKind(Var instance);
 
+        // careful using the versions below. (instance's scriptContext better be === scriptContext)
+        static BOOL IsUndefinedOrNull(Var instance, JavascriptLibrary* library);
+        static BOOL IsUndefinedOrNull(Var instance, ScriptContext* scriptContext);
+        static BOOL IsNull(Var instance, ScriptContext* scriptContext);
+        static BOOL IsNull(Var instance, JavascriptLibrary* library);
+        static BOOL IsUndefinedObject(Var instance, ScriptContext* scriptContext);
+        static BOOL IsUndefinedObject(Var instance, RecyclableObject* libraryUndefined);
+        static BOOL IsUndefinedObject(Var instance, JavascriptLibrary* library);
+
         static bool CanShortcutOnUnknownPropertyName(RecyclableObject * instance);
         static bool CanShortcutInstanceOnUnknownPropertyName(RecyclableObject *instance);
         static bool CanShortcutPrototypeChainOnUnknownPropertyName(RecyclableObject *instance);
@@ -643,6 +658,8 @@ namespace Js
         static void BuildHandlerScope(Var argThis, RecyclableObject * hostObject, FrameDisplay * pScopes, ScriptContext * scriptContext);
         static void TryLoadRoot(Var& thisVar, TypeId typeId, int moduleID, ScriptContextInfo* scriptContext);
 
+        static BOOL GetProperty_InternalSimple(Var instance, RecyclableObject* object, PropertyId propertyId, _Outptr_result_maybenull_ Var* value, ScriptContext* requestContext);
+
         template <bool unscopables>
         static BOOL GetProperty_Internal(Var instance, RecyclableObject* propertyObject, const bool isRoot, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info);
 

+ 1 - 1
lib/Runtime/Library/BoundFunction.cpp

@@ -275,7 +275,7 @@ namespace Js
         JavascriptString* displayName = GetLibrary()->GetEmptyString();
         if (targetFunction != nullptr)
         {
-            Var value = JavascriptOperators::GetProperty(targetFunction, PropertyIds::name, targetFunction->GetScriptContext());
+            Var value = JavascriptOperators::GetPropertyNoCache(targetFunction, PropertyIds::name, targetFunction->GetScriptContext());
             if (JavascriptString::Is(value))
             {
                 displayName = JavascriptString::FromVar(value);

+ 6 - 8
lib/Runtime/Library/JavascriptArray.cpp

@@ -825,7 +825,7 @@ namespace Js
     void JavascriptArray::InternalFillFromPrototype(JavascriptArray *dstArray, uint32 dstIndex, JavascriptArray *srcArray, uint32 start, uint32 end, uint32 count)
     {
         RecyclableObject* prototype = srcArray->GetPrototype();
-        while (start + count != end && JavascriptOperators::GetTypeId(prototype) != TypeIds_Null)
+        while (start + count != end && !JavascriptOperators::IsNull(prototype))
         {
             ForEachOwnMissingArrayIndexOfObject(srcArray, dstArray, prototype, start, end, dstIndex, [&](uint32 index, Var value) {
                 uint32 n = dstIndex + (index - start);
@@ -4336,7 +4336,7 @@ namespace Js
     JavascriptString* JavascriptArray::JoinToString(Var value, ScriptContext* scriptContext)
     {
         TypeId typeId = JavascriptOperators::GetTypeId(value);
-        if (typeId == TypeIds_Null || typeId == TypeIds_Undefined)
+        if (typeId <= TypeIds_UndefinedOrNull)
         {
             return scriptContext->GetLibrary()->GetEmptyString();
         }
@@ -5334,8 +5334,7 @@ Case0:
         if (forceCheckProtoChain || arr->IsFillFromPrototypes())
         {
             RecyclableObject* prototype = arr->GetPrototype();
-
-            while (JavascriptOperators::GetTypeId(prototype) != TypeIds_Null)
+            while (!JavascriptOperators::IsNull(prototype))
             {
                 RecyclableObject* protoObj = prototype;
 
@@ -8018,7 +8017,7 @@ Case0:
         }
 
         // In ES5 we could be calling a user defined join, even on array. We must [[Get]] join at runtime.
-        JS_REENTRANT(jsReentLock, Var join = JavascriptOperators::GetProperty(obj, PropertyIds::join, scriptContext));
+        JS_REENTRANT(jsReentLock, Var join = JavascriptOperators::GetPropertyNoCache(obj, PropertyIds::join, scriptContext));
         if (JavascriptConversion::IsCallable(join))
         {
             RecyclableObject* func = RecyclableObject::FromVar(join);
@@ -10451,7 +10450,7 @@ Case0:
     JavascriptString* JavascriptArray::ToLocaleStringHelper(Var value, ScriptContext* scriptContext)
     {
         TypeId typeId = JavascriptOperators::GetTypeId(value);
-        if (typeId == TypeIds_Null || typeId == TypeIds_Undefined)
+        if (typeId <= TypeIds_UndefinedOrNull)
         {
             return scriptContext->GetLibrary()->GetEmptyString();
         }
@@ -10491,9 +10490,8 @@ Case0:
         }
 
         RecyclableObject* prototype = this->GetPrototype();
-
         // Fill all missing values by walking through prototype
-        while (JavascriptOperators::GetTypeId(prototype) != TypeIds_Null)
+        while (!JavascriptOperators::IsNull(prototype))
         {
             ForEachOwnMissingArrayIndexOfObject(this, nullptr, prototype, startIndex, limitIndex,0, [this](uint32 index, Var value) {
                 this->SetItem(index, value, PropertyOperation_None);

+ 3 - 3
lib/Runtime/Library/JavascriptError.cpp

@@ -186,7 +186,7 @@ namespace Js
         JavascriptString *outputStr, *message;
 
         // get error.name
-        BOOL hasName = JavascriptOperators::GetProperty(thisError, PropertyIds::name, &value, scriptContext, NULL) &&
+        BOOL hasName = JavascriptOperators::GetPropertyNoCache(thisError, PropertyIds::name, &value, scriptContext) &&
             JavascriptOperators::GetTypeId(value) != TypeIds_Undefined;
 
         if (hasName)
@@ -199,7 +199,7 @@ namespace Js
         }
 
         // get error.message
-        if (JavascriptOperators::GetProperty(thisError, PropertyIds::message, &value, scriptContext, NULL)
+        if (JavascriptOperators::GetPropertyNoCache(thisError, PropertyIds::message, &value, scriptContext)
             && JavascriptOperators::GetTypeId(value) != TypeIds_Undefined)
         {
             message = JavascriptConversion::ToString(value, scriptContext);
@@ -527,7 +527,7 @@ namespace Js
         // This version needs to be called in script.
         Assert(scriptContext->GetThreadContext()->IsScriptActive());
 
-        Var number = JavascriptOperators::GetProperty(errorObject, Js::PropertyIds::number, scriptContext, NULL);
+        Var number = JavascriptOperators::GetPropertyNoCache(errorObject, Js::PropertyIds::number, scriptContext);
         if (TaggedInt::Is(number))
         {
             hr = TaggedInt::ToInt32(number);

+ 1 - 1
lib/Runtime/Library/JavascriptExternalFunction.cpp

@@ -249,7 +249,7 @@ namespace Js
     Var JavascriptExternalFunction::DefaultExternalFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...)
     {
         TypeId typeId = function->GetTypeId();
-        rtErrors err = typeId == TypeIds_Undefined || typeId == TypeIds_Null ? JSERR_NeedObject : JSERR_NeedFunction;
+        rtErrors err = typeId <= TypeIds_UndefinedOrNull ? JSERR_NeedObject : JSERR_NeedFunction;
         JavascriptError::ThrowTypeError(function->GetScriptContext(), err);
     }
 

+ 5 - 4
lib/Runtime/Library/JavascriptFunction.cpp

@@ -469,7 +469,7 @@ namespace Js
         {
             bool isArray = JavascriptArray::Is(argArray);
             TypeId typeId = JavascriptOperators::GetTypeId(argArray);
-            bool isNullOrUndefined = (typeId == TypeIds_Null || typeId == TypeIds_Undefined);
+            bool isNullOrUndefined = typeId <= TypeIds_UndefinedOrNull;
 
             if (!isNullOrUndefined && !JavascriptOperators::IsObject(argArray)) // ES5: throw if Type(argArray) is not Object
             {
@@ -3348,7 +3348,7 @@ LABEL1:
         }
         else
         {
-            funcPrototype = JavascriptOperators::GetProperty(this, PropertyIds::prototype, scriptContext, nullptr);
+            funcPrototype = JavascriptOperators::GetPropertyNoCache(this, PropertyIds::prototype, scriptContext);
         }
         funcPrototype = CrossSite::MarshalVar(scriptContext, funcPrototype);
         return JavascriptFunction::HasInstance(funcPrototype, instance, scriptContext, inlineCache, this);
@@ -3416,7 +3416,8 @@ LABEL1:
         // However, object o's type (even if it is of the same "shape" as before, and even if o is the very same object) will be different,
         // because the object types are permanently bound and unique to the script context from which they were created.
 
-        Var prototype = JavascriptOperators::GetPrototype(RecyclableObject::FromVar(instance));
+        RecyclableObject* instanceObject = RecyclableObject::FromVar(instance);
+        Var prototype = JavascriptOperators::GetPrototype(instanceObject);
 
         if (!JavascriptOperators::IsObject(funcPrototype))
         {
@@ -3425,7 +3426,7 @@ LABEL1:
 
         // Since we missed the cache, we must now walk the prototype chain of the object to check if the given function's prototype is somewhere in
         // that chain. If it is, we return true. Otherwise (i.e., we hit the end of the chain before finding the function's prototype) we return false.
-        while (JavascriptOperators::GetTypeId(prototype) != TypeIds_Null)
+        while (!JavascriptOperators::IsNull(prototype))
         {
             if (prototype == funcPrototype)
             {

+ 1 - 1
lib/Runtime/Library/JavascriptLibrary.cpp

@@ -4021,7 +4021,7 @@ namespace Js
     {
         Var arrayIteratorPrototypeNext = nullptr;
         ImplicitCallFlags flags = scriptContext->GetThreadContext()->TryWithDisabledImplicitCall(
-            [&]() { arrayIteratorPrototypeNext = JavascriptOperators::GetProperty(scriptContext->GetLibrary()->GetArrayIteratorPrototype(), PropertyIds::next, scriptContext); });
+            [&]() { arrayIteratorPrototypeNext = JavascriptOperators::GetPropertyNoCache(scriptContext->GetLibrary()->GetArrayIteratorPrototype(), PropertyIds::next, scriptContext); });
 
         return (flags != ImplicitCall_None) || arrayIteratorPrototypeNext != scriptContext->GetLibrary()->GetArrayIteratorPrototypeBuiltinNextFunction();
     }

+ 1 - 1
lib/Runtime/Library/JavascriptMap.cpp

@@ -80,7 +80,7 @@ namespace Js
         if (JavascriptConversion::CheckObjectCoercible(iterable, scriptContext))
         {
             iter = JavascriptOperators::GetIterator(iterable, scriptContext);
-            Var adderVar = JavascriptOperators::GetProperty(mapObject, PropertyIds::set, scriptContext);
+            Var adderVar = JavascriptOperators::GetPropertyNoCache(mapObject, PropertyIds::set, scriptContext);
             if (!JavascriptConversion::IsCallable(adderVar))
             {
                 JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction);

+ 5 - 5
lib/Runtime/Library/JavascriptNumber.cpp

@@ -997,22 +997,22 @@ namespace Js
     {
         TypeId typeId = JavascriptOperators::GetTypeId(aValue);
 
-        if (typeId == TypeIds_Null || typeId == TypeIds_Undefined)
+        if (typeId <= TypeIds_UndefinedOrNull)
         {
             return FALSE;
         }
 
-        if (TaggedInt::Is(aValue))
+        if (typeId == TypeIds_Integer)
         {
             *pDouble = TaggedInt::ToDouble(aValue);
             return TRUE;
         }
-        else if (Js::JavascriptOperators::GetTypeId(aValue) == TypeIds_Int64Number)
+        else if (typeId == TypeIds_Int64Number)
         {
             *pDouble = (double)JavascriptInt64Number::FromVar(aValue)->GetValue();
             return TRUE;
         }
-        else if (Js::JavascriptOperators::GetTypeId(aValue) == TypeIds_UInt64Number)
+        else if (typeId == TypeIds_UInt64Number)
         {
             *pDouble = (double)JavascriptUInt64Number::FromVar(aValue)->GetValue();
             return TRUE;
@@ -1022,7 +1022,7 @@ namespace Js
             *pDouble = JavascriptNumber::GetValue(aValue);
             return TRUE;
         }
-        else if (JavascriptNumberObject::Is(aValue))
+        else if (typeId == TypeIds_NumberObject)
         {
             JavascriptNumberObject* obj = JavascriptNumberObject::FromVar(aValue);
             *pDouble = obj->GetValue();

+ 13 - 16
lib/Runtime/Library/JavascriptObject.cpp

@@ -304,7 +304,7 @@ namespace Js
             dynamicObject = RecyclableObject::FromVar(static_cast<Js::GlobalObject*>(dynamicObject)->ToThis());
         }
 
-        while (JavascriptOperators::GetTypeId(value) != TypeIds_Null)
+        while (!JavascriptOperators::IsNull(value))
         {
             value = JavascriptOperators::GetPrototype(value);
             if (dynamicObject == value)
@@ -376,12 +376,8 @@ namespace Js
         // 3. Let O be ToObject(this value).
         RecyclableObject *thisArgAsObject = RecyclableObject::FromVar(JavascriptOperators::ToObject(thisArg, scriptContext));
 
-        // 4. Let isArray be ? IsArray(O).
-        // There is an implicit check for a null proxy handler in IsArray, so use the operator.
-        BOOL isArray = JavascriptOperators::IsArray(thisArgAsObject);
-
         // 15. Let tag be ? Get(O, @@toStringTag).
-        Var tag = JavascriptOperators::GetProperty(thisArgAsObject, PropertyIds::_symbolToStringTag, scriptContext); // Let tag be the result of Get(O, @@toStringTag).
+        Var tag = JavascriptOperators::GetPropertyNoCache(thisArgAsObject, PropertyIds::_symbolToStringTag, scriptContext); // Let tag be the result of Get(O, @@toStringTag).
 
         // 17. Return the String that is the result of concatenating "[object ", tag, and "]".
         auto buildToString = [&scriptContext](Var tag) {
@@ -402,6 +398,10 @@ namespace Js
             return buildToString(tag);
         }
 
+        // 4. Let isArray be ? IsArray(O).
+        // There is an implicit check for a null proxy handler in IsArray, so use the operator.
+        BOOL isArray = JavascriptOperators::IsArray(thisArgAsObject);
+
         // If we don't have a tag or it's not a string, use the 'built in tag'.
         if (isArray)
         {
@@ -536,11 +536,8 @@ namespace Js
 
         AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
 
-        TypeId argType = JavascriptOperators::GetTypeId(args[0]);
-
         // throw a TypeError if TypeId is null or undefined, and apply ToObject to the 'this' value otherwise.
-
-        if ((argType == TypeIds_Null) || (argType == TypeIds_Undefined))
+        if (JavascriptOperators::IsUndefinedOrNull(args[0]))
         {
             JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NullOrUndefined, _u("Object.prototype.valueOf"));
         }
@@ -1487,14 +1484,14 @@ namespace Js
             //          ii.ReturnIfAbrupt(from).
             //          iii.Let keys be from.[[OwnPropertyKeys]]().
             //          iv.ReturnIfAbrupt(keys).
-            if (JavascriptOperators::IsUndefinedOrNull(args[i]))
-            {
-                continue;
-            }
 
             RecyclableObject* from = nullptr;
             if (!JavascriptConversion::ToObject(args[i], scriptContext, &from))
             {
+                if (JavascriptOperators::IsUndefinedOrNull(args[i]))
+                {
+                    continue;
+                }
                 JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_NeedObject, _u("Object.assign"));
             }
 
@@ -1695,7 +1692,7 @@ namespace Js
             }
             else
             {
-                propertyRecord = scriptContext->GetPropertyName(propId);
+                propertyRecord = ((PropertyString*)propertyName)->GetPropertyRecord();
             }
 
             if (descCount == descSize)
@@ -1712,7 +1709,7 @@ namespace Js
                 descriptors = temp;
             }
 
-            Var tempVar = JavascriptOperators::GetProperty(props, propId, scriptContext);
+            Var tempVar = JavascriptOperators::GetPropertyNoCache(props, propId, scriptContext);
 
             AnalysisAssert(descCount < descSize);
             if (!JavascriptOperators::ToPropertyDescriptor(tempVar, &descriptors[descCount].descriptor, scriptContext))

+ 1 - 1
lib/Runtime/Library/JavascriptPromise.cpp

@@ -622,7 +622,7 @@ namespace Js
                 try
                 {
                     RecyclableObject* thenable = RecyclableObject::FromVar(resolution);
-                    Var then = JavascriptOperators::GetProperty(thenable, Js::PropertyIds::then, scriptContext);
+                    Var then = JavascriptOperators::GetPropertyNoCache(thenable, Js::PropertyIds::then, scriptContext);
 
                     if (JavascriptConversion::IsCallable(then))
                     {

+ 1 - 1
lib/Runtime/Library/JavascriptSet.cpp

@@ -77,7 +77,7 @@ namespace Js
         if (JavascriptConversion::CheckObjectCoercible(iterable, scriptContext))
         {
             iter = JavascriptOperators::GetIterator(iterable, scriptContext);
-            Var adderVar = JavascriptOperators::GetProperty(setObject, PropertyIds::add, scriptContext);
+            Var adderVar = JavascriptOperators::GetPropertyNoCache(setObject, PropertyIds::add, scriptContext);
             if (!JavascriptConversion::IsCallable(adderVar))
             {
                 JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction);

+ 1 - 1
lib/Runtime/Library/JavascriptString.cpp

@@ -1758,7 +1758,7 @@ case_2:
 
     Var JavascriptString::GetRegExSymbolFunction(Var regExp, PropertyId propertyId, ScriptContext* scriptContext)
     {
-        return JavascriptOperators::GetProperty(
+        return JavascriptOperators::GetPropertyNoCache(
             RecyclableObject::FromVar(JavascriptOperators::ToObject(regExp, scriptContext)),
             propertyId,
             scriptContext);

+ 12 - 14
lib/Runtime/Library/TypedArray.cpp

@@ -671,18 +671,17 @@ namespace Js
 
     PropertyQueryFlags TypedArrayBase::GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
     {
-        uint32 index = 0;
-        if (GetScriptContext()->IsNumericPropertyId(propertyId, &index))
+        const Js::PropertyRecord* propertyRecord = requestContext->GetPropertyName(propertyId);
+        if (propertyRecord->IsNumeric())
         {
-            *value = this->DirectGetItem(index);
+            *value = this->DirectGetItem(propertyRecord->GetNumericValue());
             if (JavascriptOperators::GetTypeId(*value) == Js::TypeIds_Undefined)
             {
                 return PropertyQueryFlags::Property_NotFound;
             }
             return PropertyQueryFlags::Property_Found;
         }
-
-        if (!requestContext->GetPropertyName(propertyId)->IsSymbol() && CanonicalNumericIndexString(propertyId, requestContext))
+        if (!propertyRecord->IsSymbol() && CanonicalNumericIndexString(propertyId, requestContext))
         {
             *value = requestContext->GetLibrary()->GetUndefined();
             return PropertyQueryFlags::Property_NotFound_NoProto;
@@ -734,16 +733,16 @@ namespace Js
 
     BOOL TypedArrayBase::SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
     {
-        uint32 index;
         ScriptContext *scriptContext = GetScriptContext();
 
-        if (GetScriptContext()->IsNumericPropertyId(propertyId, &index))
+        const PropertyRecord* propertyRecord = scriptContext->GetPropertyName(propertyId);
+        if (propertyRecord->IsNumeric())
         {
-            this->DirectSetItem(index, value);
+            this->DirectSetItem(propertyRecord->GetNumericValue(), value);
             return true;
         }
 
-        if (!scriptContext->GetPropertyName(propertyId)->IsSymbol() && CanonicalNumericIndexString(propertyId, scriptContext))
+        if (!propertyRecord->IsSymbol() && CanonicalNumericIndexString(propertyId, scriptContext))
         {
             return FALSE;
         }
@@ -947,15 +946,14 @@ namespace Js
     {
         ScriptContext* scriptContext = GetScriptContext();
 
-        uint32 index;
-
-        if (scriptContext->IsNumericPropertyId(propertyId, &index))
+        const PropertyRecord* propertyRecord = scriptContext->GetPropertyName(propertyId);
+        if (propertyRecord->IsNumeric())
         {
             VerifySetItemAttributes(propertyId, attributes);
-            return SetItem(index, value);
+            return SetItem(propertyRecord->GetNumericValue(), value);
         }
 
-        if (!scriptContext->GetPropertyName(propertyId)->IsSymbol() && CanonicalNumericIndexString(propertyId, scriptContext))
+        if (!propertyRecord->IsSymbol() && CanonicalNumericIndexString(propertyId, scriptContext))
         {
             return FALSE;
         }