Przeglądaj źródła

Use builtin `@@hasInstance` from prototype in `instanceOf` (#6861)

* Don't ignore build-in hasInstance (from prototype) - removing invalid optimisation

* Remove `IsES6HasInstanceEnabled` switch

Fixes #6507
Lukas Kurz 3 lat temu
rodzic
commit
fd6908097f

+ 1 - 3
lib/Common/ConfigFlagsList.h

@@ -1,6 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
-// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 
@@ -695,7 +695,6 @@ PHASE(All)
 #else
     #define DEFAULT_CONFIG_ES6RegExSymbols         (false)
 #endif
-#define DEFAULT_CONFIG_ES6HasInstance          (true)
 #define DEFAULT_CONFIG_ES7AsyncAwait           (true)
 #define DEFAULT_CONFIG_ES7ExponentionOperator  (true)
 #define DEFAULT_CONFIG_ES7TrailingComma        (true)
@@ -1180,7 +1179,6 @@ FLAGPR_REGOVR_EXP(Boolean, ES6, ES6RegExPrototypeProperties, "Enable ES6 propert
 // Also, the corresponding helpers in JnHelperMethodList.h should be marked as being reentrant
 FLAGPR_REGOVR_EXP(Boolean, ES6, ES6RegExSymbols        , "Enable ES6 RegExp symbols"                                , DEFAULT_CONFIG_ES6RegExSymbols)
 
-FLAGPR           (Boolean, ES6, ES6HasInstance         , "Enable ES6 @@hasInstance symbol"                          , DEFAULT_CONFIG_ES6HasInstance)
 FLAGPR           (Boolean, ES6, ES6Verbose             , "Enable ES6 verbose trace"                                 , DEFAULT_CONFIG_ES6Verbose)
 FLAGPR           (Boolean, ES6, ESObjectGetOwnPropertyDescriptors, "Enable Object.getOwnPropertyDescriptors"        , DEFAULT_CONFIG_ESObjectGetOwnPropertyDescriptors)
 

+ 1 - 2
lib/Runtime/Base/ThreadConfigFlagsList.h

@@ -1,6 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
-// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 
@@ -35,7 +35,6 @@ FLAG_RELEASE(IsES6RegExStickyEnabled, ES6RegExSticky)
 FLAG_RELEASE(IsES2018RegExDotAllEnabled, ES2018RegExDotAll)
 FLAG_RELEASE(IsES6RegExPrototypePropertiesEnabled, ES6RegExPrototypeProperties)
 FLAG_RELEASE(IsES6RegExSymbolsEnabled, ES6RegExSymbols)
-FLAG_RELEASE(IsES6HasInstanceEnabled, ES6HasInstance)
 FLAG_RELEASE(SkipSplitOnNoResult, SkipSplitOnNoResult)
 FLAG_RELEASE(IsES7AsyncAndAwaitEnabled, ES7AsyncAwait)
 FLAG_RELEASE(IsESObjectGetOwnPropertyDescriptorsEnabled, ESObjectGetOwnPropertyDescriptors)

+ 24 - 32
lib/Runtime/Language/JavascriptOperators.cpp

@@ -7716,45 +7716,37 @@ SetElementIHelper_INDEX_TYPE_IS_NUMBER:
         }
 
         RecyclableObject* constructor = VarTo<RecyclableObject>(aClass);
-        if (scriptContext->GetConfig()->IsES6HasInstanceEnabled())
+        if (VarIs<JavascriptFunction>(constructor))
         {
-            if (VarIs<JavascriptFunction>(constructor))
+            JavascriptFunction* func = VarTo<JavascriptFunction>(constructor);
+            if (func->IsBoundFunction())
             {
-                JavascriptFunction* func = VarTo<JavascriptFunction>(constructor);
-                if (func->IsBoundFunction())
-                {
-                    BoundFunction* boundFunc = (BoundFunction*)func;
-                    constructor = boundFunc->GetTargetFunction();
-                }
+                BoundFunction* boundFunc = (BoundFunction*)func;
+                constructor = boundFunc->GetTargetFunction();
             }
-
-            Var instOfHandler = JavascriptOperators::GetPropertyNoCache(constructor,
-              PropertyIds::_symbolHasInstance, scriptContext);
-            if (JavascriptOperators::IsUndefinedObject(instOfHandler)
-                || instOfHandler == scriptContext->GetBuiltInLibraryFunction(JavascriptFunction::EntryInfo::SymbolHasInstance.GetOriginalEntryPoint()))
+        }
+            
+        Var instOfHandler = JavascriptOperators::GetPropertyNoCache(constructor,
+            PropertyIds::_symbolHasInstance, scriptContext);
+        if (JavascriptOperators::IsUndefinedObject(instOfHandler))
+        {
+            return JavascriptBoolean::ToVar(constructor->HasInstance(instance, scriptContext, inlineCache), scriptContext);
+        }
+        else
+        {
+            if (!JavascriptConversion::IsCallable(instOfHandler))
             {
-                return JavascriptBoolean::ToVar(constructor->HasInstance(instance, scriptContext, inlineCache), scriptContext);
+                JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction, _u("Symbol[Symbol.hasInstance]"));
             }
-            else
-            {
-                if (!JavascriptConversion::IsCallable(instOfHandler))
-                {
-                    JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction, _u("Symbol[Symbol.hasInstance]"));
-                }
 
-                ThreadContext * threadContext = scriptContext->GetThreadContext();
-                RecyclableObject *instFunc = VarTo<RecyclableObject>(instOfHandler);
-                Var result = threadContext->ExecuteImplicitCall(instFunc, ImplicitCall_Accessor, [=]()->Js::Var
-                {
-                    return CALL_FUNCTION(scriptContext->GetThreadContext(), instFunc, CallInfo(CallFlags_Value, 2), constructor, instance);
-                });
+            ThreadContext * threadContext = scriptContext->GetThreadContext();
+            RecyclableObject *instFunc = VarTo<RecyclableObject>(instOfHandler);
+            Var result = threadContext->ExecuteImplicitCall(instFunc, ImplicitCall_Accessor, [=]()->Js::Var
+            {
+                return CALL_FUNCTION(scriptContext->GetThreadContext(), instFunc, CallInfo(CallFlags_Value, 2), constructor, instance);
+            });
 
-                return  JavascriptBoolean::ToVar(JavascriptConversion::ToBoolean(result, scriptContext) ? TRUE : FALSE, scriptContext);
-            }
-        }
-        else
-        {
-            return JavascriptBoolean::ToVar(constructor->HasInstance(instance, scriptContext, inlineCache), scriptContext);
+            return  JavascriptBoolean::ToVar(JavascriptConversion::ToBoolean(result, scriptContext) ? TRUE : FALSE, scriptContext);
         }
         JIT_HELPER_END(ScrObj_OP_IsInst);
     }

+ 7 - 13
lib/Runtime/Library/JavascriptLibrary.cpp

@@ -1,6 +1,6 @@
 //-------------------------------------------------------------------------------------------------------
 // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
-// Copyright (c) 2022 ChakraCore Project Contributors. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 
@@ -2599,10 +2599,7 @@ namespace Js
         library->AddMember(symbolConstructor, PropertyIds::length, TaggedInt::ToVarUnchecked(0), PropertyConfigurable);
         library->AddMember(symbolConstructor, PropertyIds::prototype, library->symbolPrototype, PropertyNone);
         library->AddMember(symbolConstructor, PropertyIds::name, scriptContext->GetPropertyString(PropertyIds::Symbol), PropertyConfigurable);
-        if (scriptContext->GetConfig()->IsES6HasInstanceEnabled())
-        {
-            library->AddMember(symbolConstructor, PropertyIds::hasInstance, library->GetSymbolHasInstance(), PropertyNone);
-        }
+        library->AddMember(symbolConstructor, PropertyIds::hasInstance, library->GetSymbolHasInstance(), PropertyNone);
         if (scriptContext->GetConfig()->IsES6IsConcatSpreadableEnabled())
         {
             library->AddMember(symbolConstructor, PropertyIds::isConcatSpreadable, library->GetSymbolIsConcatSpreadable(), PropertyNone);
@@ -3197,14 +3194,11 @@ namespace Js
         builtinFuncs[BuiltinFunction::JavascriptFunction_Call] = func;
         library->AddFunctionToLibraryObject(functionPrototype, PropertyIds::toString, &JavascriptFunction::EntryInfo::ToString, 0);
 
-        if (scriptContext->GetConfig()->IsES6HasInstanceEnabled())
-        {
-            scriptContext->SetBuiltInLibraryFunction(JavascriptFunction::EntryInfo::SymbolHasInstance.GetOriginalEntryPoint(),
-                                                     library->AddFunctionToLibraryObjectWithName(functionPrototype, PropertyIds::_symbolHasInstance, PropertyIds::_RuntimeFunctionNameId_hasInstance,
-                                                                                                 &JavascriptFunction::EntryInfo::SymbolHasInstance, 1));
-            functionPrototype->SetWritable(PropertyIds::_symbolHasInstance, false);
-            functionPrototype->SetConfigurable(PropertyIds::_symbolHasInstance, false);
-        }
+        scriptContext->SetBuiltInLibraryFunction(JavascriptFunction::EntryInfo::SymbolHasInstance.GetOriginalEntryPoint(),
+                                                    library->AddFunctionToLibraryObjectWithName(functionPrototype, PropertyIds::_symbolHasInstance, PropertyIds::_RuntimeFunctionNameId_hasInstance,
+                                                                                                &JavascriptFunction::EntryInfo::SymbolHasInstance, 1));
+        functionPrototype->SetWritable(PropertyIds::_symbolHasInstance, false);
+        functionPrototype->SetConfigurable(PropertyIds::_symbolHasInstance, false);
 
         functionPrototype->DynamicObject::SetAccessors(PropertyIds::caller, library->throwTypeErrorRestrictedPropertyAccessorFunction, library->throwTypeErrorRestrictedPropertyAccessorFunction);
         functionPrototype->SetEnumerable(PropertyIds::caller, false);

+ 23 - 0
test/es6/instanceOfProto.js

@@ -0,0 +1,23 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Copyright (c) ChakraCore Project Contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+// @ts-check
+/// <reference path="..\UnitTestFramework\UnitTestFramework.js" />
+WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
+
+const tests = [
+    {
+        name: "Issue #6507 : Use @@hasInstance of built-in prototype",
+        body() {
+            const obj = { __proto__: String };
+            const testFn = () => "hello" instanceof obj;
+            assert.doesNotThrow(testFn, "instanceof should not throw");
+            assert.areEqual(false, testFn(), "instanceof should return false");
+        }
+    }
+]
+
+testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

+ 6 - 0
test/es6/rlexe.xml

@@ -1,5 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <regress-exe>
+  <test>
+    <default>
+      <files>instanceOfProto.js</files>
+      <compile-flags>-args summary -endargs</compile-flags>
+    </default>
+  </test>
   <test>
     <default>
       <files>bug_issue_2747.js</files>