JsBuiltInEngineInterfaceExtensionObject.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
  4. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  5. //-------------------------------------------------------------------------------------------------------
  6. #include "RuntimeLibraryPch.h"
  7. #include "EngineInterfaceObject.h"
  8. #include "JsBuiltInEngineInterfaceExtensionObject.h"
  9. #include "Types/DeferredTypeHandler.h"
  10. #ifdef ENABLE_JS_BUILTINS
  11. #include "ByteCode/ByteCodeSerializer.h"
  12. #include "errstr.h"
  13. #include "ByteCode/ByteCodeDumper.h"
  14. #define IfFailAssertMsgAndThrowHr(op, msg) \
  15. if (FAILED(hr=(op))) \
  16. { \
  17. AssertMsg(false, msg); \
  18. JavascriptError::MapAndThrowError(scriptContext, hr); \
  19. } \
  20. enum class IsTypeStatic : bool
  21. {
  22. prototype = false,
  23. constructor = true,
  24. object = true
  25. };
  26. namespace Js
  27. {
  28. JsBuiltInEngineInterfaceExtensionObject::JsBuiltInEngineInterfaceExtensionObject(ScriptContext * scriptContext) :
  29. EngineExtensionObjectBase(EngineInterfaceExtensionKind_JsBuiltIn, scriptContext)
  30. {
  31. }
  32. NoProfileFunctionInfo JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_RegisterFunction(FORCE_NO_WRITE_BARRIER_TAG(JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_RegisterFunction));
  33. NoProfileFunctionInfo JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_RegisterChakraLibraryFunction(FORCE_NO_WRITE_BARRIER_TAG(JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_RegisterChakraLibraryFunction));
  34. NoProfileFunctionInfo JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_GetLength(FORCE_NO_WRITE_BARRIER_TAG(JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_GetLength));
  35. NoProfileFunctionInfo JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_GetIteratorPrototype(FORCE_NO_WRITE_BARRIER_TAG(JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_GetIteratorPrototype));
  36. NoProfileFunctionInfo JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_InitInternalProperties(FORCE_NO_WRITE_BARRIER_TAG(JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_InitInternalProperties));
  37. NoProfileFunctionInfo JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_ToLengthFunction(FORCE_NO_WRITE_BARRIER_TAG(JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_ToLengthFunction));
  38. NoProfileFunctionInfo JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_ToIntegerFunction(FORCE_NO_WRITE_BARRIER_TAG(JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_ToIntegerFunction));
  39. NoProfileFunctionInfo JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_ArraySpeciesCreate(FORCE_NO_WRITE_BARRIER_TAG(JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_ArraySpeciesCreate));
  40. NoProfileFunctionInfo JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_ArrayCreateDataPropertyOrThrow(FORCE_NO_WRITE_BARRIER_TAG(JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_ArrayCreateDataPropertyOrThrow));
  41. void JsBuiltInEngineInterfaceExtensionObject::Initialize()
  42. {
  43. if (wasInitialized)
  44. {
  45. return;
  46. }
  47. JavascriptLibrary* library = scriptContext->GetLibrary();
  48. DynamicObject* commonObject = library->GetEngineInterfaceObject()->GetCommonNativeInterfaces();
  49. if (scriptContext->IsJsBuiltInEnabled())
  50. {
  51. Assert(library->GetEngineInterfaceObject() != nullptr);
  52. builtInNativeInterfaces = DynamicObject::New(library->GetRecycler(),
  53. DynamicType::New(scriptContext, TypeIds_Object, commonObject, nullptr,
  54. DeferredTypeHandler<InitializeJsBuiltInNativeInterfaces>::GetDefaultInstance()));
  55. library->AddMember(library->GetEngineInterfaceObject(), Js::PropertyIds::JsBuiltIn, builtInNativeInterfaces);
  56. }
  57. wasInitialized = true;
  58. }
  59. void JsBuiltInEngineInterfaceExtensionObject::InitializePrototypes(ScriptContext * scriptContext)
  60. {
  61. JavascriptLibrary* library = scriptContext->GetLibrary();
  62. JavascriptString * methodName = JavascriptString::NewWithSz(_u("ArrayIterator"), scriptContext);
  63. auto arrayIterator = JavascriptOperators::GetProperty(library->GetChakraLib(), JavascriptOperators::GetPropertyId(methodName, scriptContext), scriptContext);
  64. library->arrayIteratorPrototype = VarTo<DynamicObject>(JavascriptOperators::GetProperty(VarTo<DynamicObject>(arrayIterator), PropertyIds::prototype, scriptContext));
  65. library->arrayIteratorPrototypeBuiltinNextFunction = VarTo<JavascriptFunction>(JavascriptOperators::GetProperty(library->arrayIteratorPrototype, PropertyIds::next, scriptContext));
  66. }
  67. void JsBuiltInEngineInterfaceExtensionObject::InjectJsBuiltInLibraryCode(ScriptContext * scriptContext, JsBuiltInFile file)
  68. {
  69. JavascriptExceptionObject *pExceptionObject = nullptr;
  70. FunctionBody* jsBuiltInByteCode = nullptr;
  71. switch (file)
  72. {
  73. #define jsBuiltInByteCodeCase(class, type, obj) \
  74. case (JsBuiltInFile::class##_##type): \
  75. { \
  76. if (jsBuiltIn##class##_##type##Bytecode != nullptr) \
  77. return; \
  78. EnsureSourceInfo(); \
  79. uint32 flags = fscrJsBuiltIn | (CONFIG_FLAG(CreateFunctionProxy) && !scriptContext->IsProfiling() ? fscrAllowFunctionProxy : 0); \
  80. SRCINFO* hsi = sourceInfo; \
  81. Js::ByteCodeSerializer::DeserializeFromBuffer(scriptContext, flags, (LPCUTF8)nullptr, hsi, (byte*)js::Library_Bytecode_##class##_##type, nullptr, &jsBuiltIn##class##_##type##Bytecode); \
  82. jsBuiltInByteCode = jsBuiltIn##class##_##type##Bytecode; \
  83. break; \
  84. }
  85. JsBuiltIns(jsBuiltInByteCodeCase)
  86. #undef jsBuiltInByteCodeCase
  87. }
  88. this->SetHasBytecode();
  89. try {
  90. AssertOrFailFast(jsBuiltInByteCode != nullptr);
  91. Js::ScriptFunction *functionGlobal = scriptContext->GetLibrary()->CreateScriptFunction(jsBuiltInByteCode);
  92. // If we are in the debugger and doing a GetProperty of arguments, then Js Builtins code will be injected on-demand
  93. // Since it is a cross site call, we marshall not only functionGlobal but also its entire prototype chain
  94. // The prototype of functionGlobal will be shared by a normal Js function,
  95. // so marshalling will inadvertently transition the entrypoint of the prototype to a crosssite entrypoint
  96. // So we set the prototype to null here
  97. functionGlobal->SetPrototype(scriptContext->GetLibrary()->nullValue);
  98. #ifdef ENABLE_SCRIPT_PROFILING
  99. // If we are profiling, we need to register the script to the profiler callback, so the script compiled event will be sent.
  100. if (scriptContext->IsProfiling())
  101. {
  102. scriptContext->RegisterScript(functionGlobal->GetFunctionProxy());
  103. }
  104. #endif
  105. #ifdef ENABLE_SCRIPT_DEBUGGING
  106. // Mark we are profiling library code already, so that any initialization library code called here won't be reported to profiler.
  107. // Also tell the debugger not to record events during intialization so that we don't leak information about initialization.
  108. AutoInitLibraryCodeScope autoInitLibraryCodeScope(scriptContext);
  109. #endif
  110. Js::Var args[] = { scriptContext->GetLibrary()->GetUndefined(), scriptContext->GetLibrary()->GetEngineInterfaceObject() };
  111. Js::CallInfo callInfo(Js::CallFlags_Value, _countof(args));
  112. #if ENABLE_JS_REENTRANCY_CHECK
  113. // Create a Reentrancy lock to make sure we correctly restore the lock at the end of BuiltIns initialization
  114. JsReentLock lock(scriptContext->GetThreadContext());
  115. // Clear ReentrancyLock bit as initialization code doesn't have any side effect
  116. scriptContext->GetThreadContext()->SetNoJsReentrancy(false);
  117. #endif
  118. // Clear disable implicit call bit as initialization code doesn't have any side effect
  119. {
  120. ThreadContext::AutoRestoreImplicitFlags autoRestoreImplicitFlags(scriptContext->GetThreadContext(), scriptContext->GetThreadContext()->GetImplicitCallFlags(), scriptContext->GetThreadContext()->GetDisableImplicitFlags());
  121. scriptContext->GetThreadContext()->ClearDisableImplicitFlags();
  122. JavascriptFunction::CallRootFunctionInScript(functionGlobal, Js::Arguments(callInfo, args));
  123. }
  124. Js::ScriptFunction *functionBuiltins = scriptContext->GetLibrary()->CreateScriptFunction(jsBuiltInByteCode->GetNestedFunctionForExecution(0));
  125. functionBuiltins->SetPrototype(scriptContext->GetLibrary()->nullValue);
  126. current = file;
  127. // Clear disable implicit call bit as initialization code doesn't have any side effect
  128. {
  129. ThreadContext::AutoRestoreImplicitFlags autoRestoreImplicitFlags(scriptContext->GetThreadContext(), scriptContext->GetThreadContext()->GetImplicitCallFlags(), scriptContext->GetThreadContext()->GetDisableImplicitFlags());
  130. scriptContext->GetThreadContext()->ClearDisableImplicitFlags();
  131. JavascriptFunction::CallRootFunctionInScript(functionBuiltins, Js::Arguments(callInfo, args));
  132. }
  133. if (file == JsBuiltInFile::Array_prototype)
  134. {
  135. InitializePrototypes(scriptContext);
  136. }
  137. #if DBG_DUMP
  138. if (PHASE_DUMP(Js::ByteCodePhase, functionGlobal->GetFunctionProxy()) && Js::Configuration::Global.flags.Verbose)
  139. {
  140. DumpByteCode();
  141. }
  142. #endif
  143. }
  144. catch (const JavascriptException& err)
  145. {
  146. pExceptionObject = err.GetAndClear();
  147. }
  148. if (pExceptionObject)
  149. {
  150. switch (file)
  151. {
  152. #define clearJsBuiltInByteCodeCase(class, type, obj) \
  153. case (JsBuiltInFile::class##_##type): \
  154. jsBuiltIn##class##_##type##Bytecode = nullptr;
  155. break;
  156. JsBuiltIns(clearJsBuiltInByteCodeCase)
  157. #undef clearJsBuiltInByteCodeCase
  158. }
  159. jsBuiltInByteCode = nullptr;
  160. if (pExceptionObject == ThreadContext::GetContextForCurrentThread()->GetPendingSOErrorObject())
  161. {
  162. JavascriptExceptionOperators::DoThrowCheckClone(pExceptionObject, scriptContext);
  163. }
  164. Js::Throw::FatalJsBuiltInError();
  165. }
  166. }
  167. bool JsBuiltInEngineInterfaceExtensionObject::InitializeJsBuiltInNativeInterfaces(DynamicObject * builtInNativeInterfaces, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode)
  168. {
  169. int initSlotCapacity = 5; // for register{ChakraLibrary}Function, POSITIVE_INFINITY, NEGATIVE_INFINITY, and GetIteratorPrototype
  170. typeHandler->Convert(builtInNativeInterfaces, mode, initSlotCapacity);
  171. ScriptContext* scriptContext = builtInNativeInterfaces->GetScriptContext();
  172. JavascriptLibrary* library = scriptContext->GetLibrary();
  173. library->AddMember(builtInNativeInterfaces, PropertyIds::POSITIVE_INFINITY, library->GetPositiveInfinite());
  174. library->AddMember(builtInNativeInterfaces, PropertyIds::NEGATIVE_INFINITY, library->GetNegativeInfinite());
  175. library->AddFunctionToLibraryObject(builtInNativeInterfaces, Js::PropertyIds::registerChakraLibraryFunction, &JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_RegisterChakraLibraryFunction, 2);
  176. library->AddFunctionToLibraryObject(builtInNativeInterfaces, Js::PropertyIds::registerFunction, &JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_RegisterFunction, 2);
  177. library->AddFunctionToLibraryObject(builtInNativeInterfaces, Js::PropertyIds::GetIteratorPrototype, &JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_GetIteratorPrototype, 1);
  178. builtInNativeInterfaces->SetHasNoEnumerableProperties(true);
  179. return true;
  180. }
  181. #if DBG
  182. void JsBuiltInEngineInterfaceExtensionObject::DumpByteCode(JsBuiltInFile file)
  183. {
  184. Output::Print(_u("Dumping JS Built Ins Byte Code:\n"));
  185. switch (file)
  186. {
  187. #define fileCase(class, type, obj) \
  188. case class##_##type: \
  189. Assert(this->jsBuiltIn##class##_##type##Bytecode != nullptr); \
  190. Js::ByteCodeDumper::DumpRecursively(this->jsBuiltIn##class##_##type##Bytecode); \
  191. break;
  192. JsBuiltIns(fileCase)
  193. #undef fileCase
  194. }
  195. }
  196. void JsBuiltInEngineInterfaceExtensionObject::DumpByteCode()
  197. {
  198. Output::Print(_u("Dumping JS Built Ins Byte Code:\n"));
  199. #define dumpOne(class, type, obj) \
  200. if (this->jsBuiltIn##class##_##type##Bytecode != nullptr) \
  201. { \
  202. DumpByteCode(JsBuiltInFile::class##_##type); \
  203. }
  204. JsBuiltIns(dumpOne)
  205. #undef dumpOne
  206. }
  207. #endif // DBG
  208. void JsBuiltInEngineInterfaceExtensionObject::EnsureSourceInfo()
  209. {
  210. if (sourceInfo == nullptr)
  211. {
  212. SourceContextInfo* sourceContextInfo = RecyclerNewStructZ(scriptContext->GetRecycler(), SourceContextInfo);
  213. sourceContextInfo->dwHostSourceContext = Js::Constants::JsBuiltInSourceContext;
  214. sourceContextInfo->isHostDynamicDocument = true;
  215. sourceContextInfo->sourceContextId = Js::Constants::JsBuiltInSourceContextId;
  216. Assert(sourceContextInfo != nullptr);
  217. SRCINFO si;
  218. memset(&si, 0, sizeof(si));
  219. si.sourceContextInfo = sourceContextInfo;
  220. sourceInfo = scriptContext->AddHostSrcInfo(&si);
  221. }
  222. }
  223. Var JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_RegisterChakraLibraryFunction(RecyclableObject* function, CallInfo callInfo, ...)
  224. {
  225. EngineInterfaceObject_CommonFunctionProlog(function, callInfo);
  226. AssertOrFailFast(args.Info.Count >= 3 && VarIs<JavascriptString>(args.Values[1]) && VarIs<ScriptFunction>(args.Values[2]));
  227. JavascriptLibrary * library = scriptContext->GetLibrary();
  228. JavascriptString* methodName = UnsafeVarTo<JavascriptString>(args.Values[1]);
  229. // chakra library functions, since they aren't public, can be constructors (__chakraLibrary.ArrayIterator is one)
  230. ScriptFunction* func = EngineInterfaceObject::CreateLibraryCodeScriptFunction(
  231. UnsafeVarTo<ScriptFunction>(args.Values[2]),
  232. methodName,
  233. true /* isConstructor */,
  234. true /* isJsBuiltIn */,
  235. false /* isPublic */
  236. );
  237. PropertyIds functionIdentifier = JavascriptOperators::GetPropertyId(methodName, scriptContext);
  238. library->AddMember(library->GetChakraLib(), functionIdentifier, func);
  239. //Don't need to return anything
  240. return library->GetUndefined();
  241. }
  242. Var JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_RegisterFunction(RecyclableObject* function, CallInfo callInfo, ...)
  243. {
  244. EngineInterfaceObject_CommonFunctionProlog(function, callInfo);
  245. AssertOrFailFast(args.Info.Count == 3 && VarIs<ScriptFunction>(args.Values[2]));
  246. JavascriptLibrary * library = scriptContext->GetLibrary();
  247. // process function name and get property ID
  248. JavascriptString* methodString = VarTo<JavascriptString>(args.Values[1]);
  249. PropertyRecord* methodPropertyRecord = nullptr;
  250. methodString->GetPropertyRecord((PropertyRecord const **) &methodPropertyRecord, false);
  251. PropertyId methodPropID = methodPropertyRecord->GetPropertyId();
  252. DynamicObject *installTarget = nullptr;
  253. bool isStatic = false;
  254. PropertyString *classPropString = nullptr;
  255. JavascriptString *fullName = nullptr;
  256. JavascriptString *dot = library->GetDotString();
  257. JsBuiltInFile current = (static_cast<JsBuiltInEngineInterfaceExtensionObject*>(scriptContext->GetLibrary()
  258. ->GetEngineInterfaceObject()->GetEngineExtension(EngineInterfaceExtensionKind_JsBuiltIn)))->current;
  259. // determine what object this function is being added too
  260. switch (current)
  261. {
  262. #define file(class, type, obj) \
  263. case class##_##type: \
  264. isStatic = static_cast<bool>(IsTypeStatic::##type); \
  265. installTarget = library->Get##obj##(); \
  266. classPropString = scriptContext->GetPropertyString(PropertyIds::class); \
  267. break;
  268. JsBuiltIns(file)
  269. }
  270. Assert(methodString && classPropString && installTarget && methodPropID != PropertyIds::_none);
  271. if (isStatic)
  272. {
  273. fullName = JavascriptString::Concat3(classPropString, dot, methodString);
  274. }
  275. else
  276. {
  277. JavascriptString *dotPrototypeDot = JavascriptString::Concat3(dot, scriptContext->GetPropertyString(PropertyIds::prototype), dot);
  278. fullName = JavascriptString::Concat3(classPropString, dotPrototypeDot, methodString);
  279. }
  280. ScriptFunction *func = EngineInterfaceObject::CreateLibraryCodeScriptFunction(
  281. UnsafeVarTo<ScriptFunction>(args.Values[2]),
  282. fullName,
  283. false /* isConstructor */,
  284. true /* isJsBuiltIn */,
  285. true /* isPublic */
  286. );
  287. library->AddMember(installTarget, methodPropID, func);
  288. // Make function available to other internal facilities that need it
  289. // applicable for specific functions only - this may need review upon moving other functions into JsBuiltins
  290. if (current == JsBuiltInFile::Array_prototype)
  291. {
  292. switch (methodPropID)
  293. {
  294. case PropertyIds::entries:
  295. library->arrayPrototypeEntriesFunction = func;
  296. break;
  297. case PropertyIds::values:
  298. library->arrayPrototypeValuesFunction = func;
  299. library->AddMember(installTarget, PropertyIds::_symbolIterator, func);
  300. break;
  301. case PropertyIds::keys:
  302. library->arrayPrototypeKeysFunction = func;
  303. break;
  304. case PropertyIds::forEach:
  305. library->AddMember(scriptContext->GetLibrary()->GetEngineInterfaceObject()->GetCommonNativeInterfaces(), PropertyIds::builtInArray_prototype_forEach, func);
  306. break;
  307. case PropertyIds::filter:
  308. library->AddMember(scriptContext->GetLibrary()->GetEngineInterfaceObject()->GetCommonNativeInterfaces(), PropertyIds::builtInArray_prototype_filter, func);
  309. break;
  310. case PropertyIds::indexOf:
  311. library->AddMember(scriptContext->GetLibrary()->GetEngineInterfaceObject()->GetCommonNativeInterfaces(), PropertyIds::builtInArray_prototype_indexOf, func);
  312. break;
  313. case PropertyIds::reduce:
  314. library->AddMember(scriptContext->GetLibrary()->GetEngineInterfaceObject()->GetCommonNativeInterfaces(), PropertyIds::builtInArray_prototype_reduce, func);
  315. break;
  316. }
  317. }
  318. else if (current == JsBuiltInFile::Math_object)
  319. {
  320. switch (methodPropID)
  321. {
  322. case PropertyIds::max:
  323. library->mathMax = func;
  324. library->AddMember(scriptContext->GetLibrary()->GetEngineInterfaceObject()->GetCommonNativeInterfaces(), PropertyIds::builtInMath_object_max, func);
  325. break;
  326. case PropertyIds::min:
  327. library->mathMin = func;
  328. library->AddMember(scriptContext->GetLibrary()->GetEngineInterfaceObject()->GetCommonNativeInterfaces(), PropertyIds::builtInMath_object_min, func);
  329. break;
  330. }
  331. }
  332. //Don't need to return anything
  333. return library->GetUndefined();
  334. }
  335. Var JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_ToLengthFunction(RecyclableObject * function, CallInfo callInfo, ...)
  336. {
  337. EngineInterfaceObject_CommonFunctionProlog(function, callInfo);
  338. Assert(args.Info.Count == 2);
  339. return JavascriptNumber::ToVar(JavascriptConversion::ToLength(args.Values[1], scriptContext), scriptContext);
  340. }
  341. Var JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_ToIntegerFunction(RecyclableObject * function, CallInfo callInfo, ...)
  342. {
  343. EngineInterfaceObject_CommonFunctionProlog(function, callInfo);
  344. Assert(args.Info.Count == 2);
  345. Var value = args.Values[1];
  346. if (JavascriptOperators::IsUndefinedOrNull(value))
  347. {
  348. return TaggedInt::ToVarUnchecked(0);
  349. }
  350. else if (TaggedInt::Is(value))
  351. {
  352. return value;
  353. }
  354. return JavascriptNumber::ToVarIntCheck(JavascriptConversion::ToInteger(value, scriptContext), scriptContext);
  355. }
  356. Var JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_GetLength(RecyclableObject *function, CallInfo callInfo, ...)
  357. {
  358. EngineInterfaceObject_CommonFunctionProlog(function, callInfo);
  359. Assert(callInfo.Count == 2);
  360. int64 length;
  361. Var iterable = args.Values[1];
  362. TypedArrayBase *typedArrayBase = nullptr;
  363. Assert(!JavascriptArray::IsNonES5Array(iterable));
  364. if (VarIs<TypedArrayBase>(iterable))
  365. {
  366. typedArrayBase = VarTo<TypedArrayBase>(iterable);
  367. if (typedArrayBase->IsDetachedBuffer())
  368. {
  369. JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray);
  370. }
  371. length = typedArrayBase->GetLength();
  372. }
  373. else
  374. {
  375. length = JavascriptConversion::ToLength(JavascriptOperators::OP_GetLength(iterable, scriptContext), scriptContext);
  376. }
  377. return JavascriptNumber::ToVar(length, scriptContext);
  378. }
  379. Var JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_GetIteratorPrototype(RecyclableObject *function, CallInfo callInfo, ...)
  380. {
  381. EngineInterfaceObject_CommonFunctionProlog(function, callInfo);
  382. Assert(callInfo.Count == 1);
  383. return scriptContext->GetLibrary()->iteratorPrototype;
  384. }
  385. Var JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_InitInternalProperties(RecyclableObject *function, CallInfo callInfo, ...)
  386. {
  387. EngineInterfaceObject_CommonFunctionProlog(function, callInfo);
  388. DynamicObject* obj = VarTo<DynamicObject>(args.Values[1]);
  389. unsigned propCount = TaggedInt::ToUInt32(args.Values[2]);
  390. Assert(callInfo.Count == 3 + propCount);
  391. for (unsigned i = 0; i < propCount; i++)
  392. {
  393. JavascriptString *propName = VarTo<JavascriptString>(args.Values[i + 3]);
  394. obj->SetPropertyWithAttributes(JavascriptOperators::GetPropertyId(propName, scriptContext), scriptContext->GetLibrary()->GetNull(), PropertyWritable, nullptr);
  395. }
  396. return obj;
  397. }
  398. Var JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_ArraySpeciesCreate(RecyclableObject *function, CallInfo callInfo, ...)
  399. {
  400. EngineInterfaceObject_CommonFunctionProlog(function, callInfo);
  401. AssertOrFailFast(args.Info.Count == 3);
  402. int64 length64 = JavascriptConversion::ToLength(args.Values[2], scriptContext);
  403. if (length64 > UINT_MAX)
  404. {
  405. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArrayLengthConstructIncorrect);
  406. }
  407. uint32 length = static_cast<uint32>(length64);
  408. bool isBuiltinArrayCtor = true;
  409. RecyclableObject * newObj = JavascriptArray::ArraySpeciesCreate(args.Values[1], length, scriptContext, nullptr, nullptr, &isBuiltinArrayCtor);
  410. nullptr;
  411. if (newObj == nullptr)
  412. {
  413. newObj = scriptContext->GetLibrary()->CreateArray(length);
  414. }
  415. else
  416. {
  417. #if ENABLE_COPYONACCESS_ARRAY
  418. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(newObj);
  419. #endif
  420. }
  421. return newObj;
  422. }
  423. Var JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_ArrayCreateDataPropertyOrThrow(RecyclableObject *function, CallInfo callInfo, ...)
  424. {
  425. EngineInterfaceObject_CommonFunctionProlog(function, callInfo);
  426. AssertOrFailFast(args.Info.Count == 4);
  427. RecyclableObject * obj = VarTo<RecyclableObject>(args.Values[1]);
  428. double index = JavascriptConversion::ToInteger(args.Values[2], scriptContext);
  429. AssertOrFailFast(index >= 0);
  430. JavascriptArray::BigIndex bigIndex(static_cast<uint64>(index));
  431. Var item = args.Values[3];
  432. JavascriptArray::CreateDataPropertyOrThrow(obj, bigIndex, item, scriptContext);
  433. return scriptContext->GetLibrary()->GetTrue();
  434. }
  435. }
  436. #endif // ENABLE_JS_BUILTINS