JavascriptFunction.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. #if DBG
  7. EXTERN_C Js::JavascriptMethod checkCodeGenThunk;
  8. #endif
  9. namespace Js
  10. {
  11. #if _M_X64
  12. extern "C" Var amd64_CallFunction(RecyclableObject *function, JavascriptMethod entryPoint, CallInfo callInfo, uint argc, Var *argv);
  13. #endif
  14. class JavascriptFunction : public DynamicObject
  15. {
  16. private:
  17. static PropertyId const specialPropertyIds[];
  18. // Need a constructor cache on every function (script and native) to avoid extra checks on the fast path, if the function isn't fixed.
  19. ConstructorCache* constructorCache;
  20. protected:
  21. FunctionInfo * functionInfo; // Underlying function
  22. DEFINE_VTABLE_CTOR(JavascriptFunction, DynamicObject);
  23. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptFunction);
  24. private:
  25. // noinline, we want to use own stack frame.
  26. __declspec(noinline) JavascriptFunction* FindCaller(BOOL* foundThis, JavascriptFunction* nullValue, ScriptContext* requestContext);
  27. BOOL GetCallerProperty(Var originalInstance, Var* value, ScriptContext* requestContext);
  28. BOOL GetArgumentsProperty(Var originalInstance, Var* value, ScriptContext* requestContext);
  29. bool GetPropertyBuiltIns(Var originalInstance, PropertyId propertyId, Var* value, ScriptContext* requestContext, BOOL* result);
  30. bool GetSetterBuiltIns(PropertyId propertyId, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext, DescriptorFlags* descriptorFlags);
  31. void InvalidateConstructorCacheOnPrototypeChange();
  32. bool GetSourceStringName(JavascriptString** name) const;
  33. static const charcount_t DIAG_MAX_FUNCTION_STRING = 256;
  34. protected:
  35. enum class FunctionKind { Normal, Generator, Async };
  36. static Var NewInstanceHelper(ScriptContext *scriptContext, RecyclableObject* function, CallInfo callInfo, Js::ArgumentReader& args, FunctionKind functionKind = FunctionKind::Normal);
  37. JavascriptFunction(DynamicType * type);
  38. public:
  39. JavascriptFunction(DynamicType * type, FunctionInfo * functionInfo);
  40. JavascriptFunction(DynamicType * type, FunctionInfo * functionInfo, ConstructorCache* cache);
  41. class EntryInfo
  42. {
  43. public:
  44. static FunctionInfo NewInstance;
  45. static FunctionInfo PrototypeEntryPoint;
  46. static FunctionInfo Apply;
  47. static FunctionInfo Bind;
  48. static FunctionInfo Call;
  49. static FunctionInfo ToString;
  50. static FunctionInfo SymbolHasInstance;
  51. static FunctionInfo NewAsyncFunctionInstance;
  52. };
  53. static const int numberLinesPrependedToAnonymousFunction = 1;
  54. static DWORD GetFunctionInfoOffset() { return offsetof(JavascriptFunction, functionInfo); }
  55. static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  56. static Var NewInstanceRestrictedMode(RecyclableObject* function, CallInfo callInfo, ...);
  57. static Var PrototypeEntryPoint(RecyclableObject* function, CallInfo callInfo, ...);
  58. static Var EntryApply(RecyclableObject* function, CallInfo callInfo, ...);
  59. static Var EntryBind(RecyclableObject* function, CallInfo callInfo, ...);
  60. static Var EntryCall(RecyclableObject* function, CallInfo callInfo, ...);
  61. static Var EntryToString(RecyclableObject* function, CallInfo callInfo, ...);
  62. static Var EntrySymbolHasInstance(RecyclableObject* function, CallInfo callInfo, ...);
  63. static Var NewAsyncFunctionInstance(RecyclableObject* function, CallInfo callInfo, ...);
  64. static bool Is(Var aValue);
  65. static JavascriptFunction* FromVar(Var aValue);
  66. Var CallFunction(Arguments args);
  67. Var CallRootFunction(Arguments args, ScriptContext * scriptContext, bool inScript);
  68. Var CallRootFunctionInternal(Arguments args, ScriptContext * scriptContext, bool inScript);
  69. template <typename T>
  70. static T CallAsmJsFunction(RecyclableObject * function, void* entryPoint, uint argc, Var * argv);
  71. template <bool isConstruct>
  72. static Var CalloutHelper(RecyclableObject* function, Var thisArg, Var overridingNewTarget, Var argArray, ScriptContext* scriptContext);
  73. static Var ApplyHelper(RecyclableObject* function, Var thisArg, Var argArray, ScriptContext* scriptContext);
  74. static Var ConstructHelper(RecyclableObject* function, Var thisArg, Var overridingNewTarget, Var argArray, ScriptContext* scriptContext);
  75. static Var CallRootFunctionInScript(JavascriptFunction* func, Arguments args);
  76. static Var CallAsConstructor(Var v, Var overridingNewTarget, Arguments args, ScriptContext* scriptContext, const Js::AuxArray<uint32> *spreadIndices = nullptr);
  77. static Var FinishConstructor(const Var constructorReturnValue, Var newObject, JavascriptFunction *const function);
  78. #if DBG
  79. static void CheckValidDebugThunk(ScriptContext* scriptContext, RecyclableObject *function);
  80. #endif
  81. template <bool doStackProbe>
  82. static Var CallFunction(RecyclableObject* obj, JavascriptMethod entryPoint, Arguments args);
  83. static Var CallSpreadFunction(RecyclableObject* obj, JavascriptMethod entryPoint, Arguments args, const Js::AuxArray<uint32> *spreadIndices);
  84. static uint32 GetSpreadSize(const Arguments args, const Js::AuxArray<uint32> *spreadIndices, ScriptContext *scriptContext);
  85. static void SpreadArgs(const Arguments args, Arguments& destArgs, const Js::AuxArray<uint32> *spreadIndices, ScriptContext *scriptContext);
  86. static Var EntrySpreadCall(const Js::AuxArray<uint32> *spreadIndices, RecyclableObject* function, CallInfo callInfo, ...);
  87. static void CheckAlignment();
  88. static BOOL IsNativeAddress(ScriptContext * scriptContext, void * codeAddr);
  89. static Var DeferredParsingThunk(RecyclableObject* function, CallInfo callInfo, ...);
  90. static JavascriptMethod DeferredParse(ScriptFunction** function);
  91. static JavascriptMethod DeferredParseCore(ScriptFunction** function, BOOL &fParsed);
  92. static void ReparseAsmJsModule(ScriptFunction ** function);
  93. static Var DeferredDeserializeThunk(RecyclableObject* function, CallInfo callInfo, ...);
  94. static JavascriptMethod DeferredDeserialize(ScriptFunction* function);
  95. static BYTE GetOffsetOfFunctionInfo()
  96. {
  97. CompileAssert(offsetof(JavascriptFunction, functionInfo) <= UCHAR_MAX);
  98. return offsetof(JavascriptFunction, functionInfo);
  99. }
  100. static uint32 GetOffsetOfConstructorCache() { return offsetof(JavascriptFunction, constructorCache); };
  101. static JavascriptString* GetNativeFunctionDisplayString(ScriptContext *scriptContext, JavascriptString *name);
  102. static JavascriptString* GetLibraryCodeDisplayString(ScriptContext* scriptContext, PCWSTR displayName);
  103. template <class StringHelper, class String, class ScriptContext>
  104. static String GetNativeFunctionDisplayStringCommon(ScriptContext* scriptContext, String name);
  105. template <class StringHelper, class String, class ScriptContext>
  106. static String GetLibraryCodeDisplayStringCommon(ScriptContext* scriptContext, PCWSTR displayName);
  107. FunctionInfo * GetFunctionInfo() const { return functionInfo; }
  108. void SetFunctionInfo(FunctionInfo *info) { functionInfo = info; }
  109. FunctionProxy * GetFunctionProxy() const;
  110. ParseableFunctionInfo * GetParseableFunctionInfo() const;
  111. DeferDeserializeFunctionInfo * GetDeferDeserializeFunctionInfo() const;
  112. FunctionBody * GetFunctionBody() const;
  113. virtual JavascriptString* GetDisplayNameImpl() const;
  114. JavascriptString* DisplayNameHelper(const wchar_t* name, charcount_t length) const;
  115. JavascriptString* GetDisplayName() const;
  116. bool GetFunctionName(JavascriptString** name) const;
  117. bool IsLibraryCode() const;
  118. BOOL IsScriptFunction() const;
  119. virtual Var GetSourceString() const { return nullptr; }
  120. virtual Var EnsureSourceString();
  121. virtual BOOL IsExternalFunction() { return FALSE; }
  122. virtual BOOL IsWinRTFunction() { return FALSE; }
  123. BOOL IsStrictMode() const;
  124. BOOL IsLambda() const;
  125. virtual inline BOOL IsConstructor() const;
  126. bool HasRestrictedProperties() const;
  127. ConstructorCache* GetConstructorCache() { Assert(this->constructorCache != nullptr); return this->constructorCache; }
  128. ConstructorCache* EnsureValidConstructorCache();
  129. void ResetConstructorCacheToDefault();
  130. virtual bool HasReadOnlyPropertiesInvisibleToTypeHandler() override { return true; }
  131. virtual BOOL HasProperty(PropertyId propertyId) override;
  132. virtual BOOL GetProperty(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  133. virtual BOOL GetProperty(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  134. virtual BOOL GetPropertyReference(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  135. virtual BOOL SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) override;
  136. virtual BOOL SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) override;
  137. virtual BOOL SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags = PropertyOperation_None, SideEffects possibleSideEffects = SideEffects_Any) override;
  138. virtual BOOL GetAccessors(PropertyId propertyId, Var *getter, Var *setter, ScriptContext * requestContext) override;
  139. virtual DescriptorFlags GetSetter(PropertyId propertyId, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext) override;
  140. virtual DescriptorFlags GetSetter(JavascriptString* propertyNameString, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext) override;
  141. virtual BOOL IsConfigurable(PropertyId propertyId) override;
  142. virtual BOOL IsEnumerable(PropertyId propertyId) override;
  143. virtual BOOL IsWritable(PropertyId propertyId) override;
  144. virtual BOOL GetSpecialPropertyName(uint32 index, Var *propertyName, ScriptContext * requestContext) override;
  145. virtual uint GetSpecialPropertyCount() const override;
  146. virtual PropertyId const * GetSpecialPropertyIds() const override;
  147. virtual BOOL DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags) override;
  148. virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  149. virtual BOOL GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  150. virtual Var GetTypeOfString(ScriptContext * requestContext) override;
  151. virtual BOOL HasInstance(Var instance, ScriptContext* scriptContext, IsInstInlineCache* inlineCache = NULL);
  152. static BOOL HasInstance(Var funcPrototype, Var instance, ScriptContext* scriptContext, IsInstInlineCache* inlineCache, JavascriptFunction* function);
  153. // This will be overridden for the BoundFunction
  154. virtual bool IsBoundFunction() const { return false; }
  155. virtual bool IsGeneratorFunction() const { return false; }
  156. BOOL IsThrowTypeErrorFunction();
  157. void SetEntryPoint(JavascriptMethod method);
  158. #if DBG
  159. void VerifyEntryPoint();
  160. static bool IsBuiltinProperty(Var objectWithProperty, PropertyIds propertyId);
  161. #endif
  162. private:
  163. static int ResumeForOutOfBoundsArrayRefs(int exceptionCode, PEXCEPTION_POINTERS exceptionInfo);
  164. };
  165. class ArrayAccessDecoder
  166. {
  167. public:
  168. struct InstructionData
  169. {
  170. public:
  171. bool isLoad : 1;
  172. bool isFloat32 : 1;
  173. bool isFloat64 : 1;
  174. bool isSimd : 1;
  175. bool isInvalidInstr : 1;
  176. BYTE bufferReg = 0;
  177. BYTE dstReg = 0;
  178. uint instrSizeInByte = 0;
  179. uint64 bufferValue = 0;
  180. InstructionData() :isLoad(0), isFloat32(0), isFloat64(0), isSimd(0), isInvalidInstr(0){}
  181. };
  182. struct RexByteValue
  183. {
  184. public:
  185. bool isR : 1;
  186. bool isX : 1;
  187. bool isW : 1;
  188. bool isB : 1;
  189. uint rexValue;
  190. RexByteValue() :isR(0), isX(0), isW(0), isB(0), rexValue(0){}
  191. };
  192. static InstructionData CheckValidInstr(BYTE* &pc, PEXCEPTION_POINTERS exceptionInfo, FunctionBody* funcBody);
  193. };
  194. //
  195. // ---- implementation shared with diagnostics ----
  196. //
  197. template <class StringHelper, class String, class ScriptContext>
  198. String JavascriptFunction::GetNativeFunctionDisplayStringCommon(ScriptContext* scriptContext, String name)
  199. {
  200. auto library = scriptContext->GetLibrary();
  201. String sourceString;
  202. sourceString = library->CreateStringFromCppLiteral(JS_DISPLAY_STRING_FUNCTION_HEADER); //L"function "
  203. sourceString = StringHelper::Concat(sourceString, name);
  204. sourceString = StringHelper::Concat(sourceString, library->CreateStringFromCppLiteral(JS_DISPLAY_STRING_FUNCTION_BODY)); //L"() { [native code] }"
  205. return sourceString;
  206. }
  207. template <class StringHelper, class String, class ScriptContext>
  208. String JavascriptFunction::GetLibraryCodeDisplayStringCommon(ScriptContext* scriptContext, PCWSTR displayName)
  209. {
  210. String sourceString;
  211. if(wcscmp(displayName, Js::Constants::AnonymousFunction) == 0)
  212. {
  213. sourceString = scriptContext->GetLibrary()->GetFunctionDisplayString();
  214. }
  215. else
  216. {
  217. sourceString = GetNativeFunctionDisplayStringCommon<StringHelper>(scriptContext, StringHelper::NewCopySz(displayName, scriptContext));
  218. }
  219. return sourceString;
  220. }
  221. } // namespace Js