JavascriptFunction.h 16 KB

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