Var JavascriptSet::NewInstance(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); AUTO_TAG_NATIVE_LIBRARY_ENTRY(function, callInfo, _u("Set")); Var newTarget = callInfo.Flags & CallFlags_NewTarget ? args.Values[args.Info.Count] : args[0]; bool isCtorSuperCall = (callInfo.Flags & CallFlags_New) && newTarget != nullptr && !JavascriptOperators::IsUndefined(newTarget); Assert(isCtorSuperCall || !(callInfo.Flags & CallFlags_New) || args[0] == nullptr); CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(SetCount); JavascriptSet* setObject = nullptr; if (callInfo.Flags & CallFlags_New) { setObject = library->CreateSet(); } else { JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("Set"), _u("Set")); } Assert(setObject != nullptr); Var iterable = (args.Info.Count > 1) ? args[1] : library->GetUndefined(); RecyclableObject* iter = nullptr; RecyclableObject* adder = nullptr; if (JavascriptConversion::CheckObjectCoercible(iterable, scriptContext)) { iter = JavascriptOperators::GetIterator(iterable, scriptContext); Var adderVar = JavascriptOperators::GetProperty(setObject, PropertyIds::add, scriptContext); if (!JavascriptConversion::IsCallable(adderVar)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction); } adder = RecyclableObject::FromVar(adderVar); } if (setObject->set != nullptr) { JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_ObjectIsAlreadyInitialized, _u("Set"), _u("Set")); } setObject->set = RecyclerNew(scriptContext->GetRecycler(), SetDataSet, scriptContext->GetRecycler()); if (iter != nullptr) { JavascriptOperators::DoIteratorStepAndValue(iter, scriptContext, [&](Var nextItem) { CALL_FUNCTION(adder, CallInfo(CallFlags_Value, 2), setObject, nextItem); }); } return isCtorSuperCall ? JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), setObject, nullptr, scriptContext) : setObject; }
Var JavascriptWeakMap::NewInstance(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); Var newTarget = callInfo.Flags & CallFlags_NewTarget ? args.Values[args.Info.Count] : args[0]; bool isCtorSuperCall = (callInfo.Flags & CallFlags_New) && newTarget != nullptr && RecyclableObject::Is(newTarget); Assert(isCtorSuperCall || !(callInfo.Flags & CallFlags_New) || args[0] == nullptr); CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(WeakMapCount); JavascriptWeakMap* weakMapObject = nullptr; if (callInfo.Flags & CallFlags_New) { weakMapObject = library->CreateWeakMap(); } else { JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("WeakMap"), _u("WeakMap")); } Assert(weakMapObject != nullptr); Var iterable = (args.Info.Count > 1) ? args[1] : library->GetUndefined(); RecyclableObject* iter = nullptr; RecyclableObject* adder = nullptr; if (JavascriptConversion::CheckObjectCoercible(iterable, scriptContext)) { iter = JavascriptOperators::GetIterator(iterable, scriptContext); Var adderVar = JavascriptOperators::GetProperty(weakMapObject, PropertyIds::set, scriptContext); if (!JavascriptConversion::IsCallable(adderVar)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction); } adder = RecyclableObject::FromVar(adderVar); } if (iter != nullptr) { Var nextItem; Var undefined = library->GetUndefined(); while (JavascriptOperators::IteratorStepAndValue(iter, scriptContext, &nextItem)) { if (!JavascriptOperators::IsObject(nextItem)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject); } RecyclableObject* obj = RecyclableObject::FromVar(nextItem); Var key, value; if (!JavascriptOperators::GetItem(obj, 0u, &key, scriptContext)) { key = undefined; } if (!JavascriptOperators::GetItem(obj, 1u, &value, scriptContext)) { value = undefined; } adder->GetEntryPoint()(adder, CallInfo(CallFlags_Value, 3), weakMapObject, key, value); } } return isCtorSuperCall ? JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), weakMapObject, nullptr, scriptContext) : weakMapObject; }
Var JavascriptMap::NewInstance(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); AUTO_TAG_NATIVE_LIBRARY_ENTRY(function, callInfo, _u("Map")); Var newTarget = callInfo.Flags & CallFlags_NewTarget ? args.Values[args.Info.Count] : args[0]; bool isCtorSuperCall = (callInfo.Flags & CallFlags_New) && newTarget != nullptr && !JavascriptOperators::IsUndefined(newTarget); Assert(isCtorSuperCall || !(callInfo.Flags & CallFlags_New) || args[0] == nullptr); CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(MapCount); JavascriptMap* mapObject = nullptr; if (callInfo.Flags & CallFlags_New) { mapObject = library->CreateMap(); } else { JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("Map"), _u("Map")); } Assert(mapObject != nullptr); Var iterable = (args.Info.Count > 1) ? args[1] : library->GetUndefined(); RecyclableObject* iter = nullptr; RecyclableObject* adder = nullptr; if (JavascriptConversion::CheckObjectCoercible(iterable, scriptContext)) { iter = JavascriptOperators::GetIterator(iterable, scriptContext); Var adderVar = JavascriptOperators::GetProperty(mapObject, PropertyIds::set, scriptContext); if (!JavascriptConversion::IsCallable(adderVar)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction); } adder = RecyclableObject::FromVar(adderVar); } if (mapObject->map != nullptr) { JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_ObjectIsAlreadyInitialized, _u("Map"), _u("Map")); } mapObject->map = RecyclerNew(scriptContext->GetRecycler(), MapDataMap, scriptContext->GetRecycler()); if (iter != nullptr) { Var undefined = library->GetUndefined(); JavascriptOperators::DoIteratorStepAndValue(iter, scriptContext, [&](Var nextItem) { if (!JavascriptOperators::IsObject(nextItem)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject); } RecyclableObject* obj = RecyclableObject::FromVar(nextItem); Var key, value; if (!JavascriptOperators::GetItem(obj, 0u, &key, scriptContext)) { key = undefined; } if (!JavascriptOperators::GetItem(obj, 1u, &value, scriptContext)) { value = undefined; } // CONSIDER: if adder is the default built-in, fast path it and skip the JS call? CALL_FUNCTION(adder, CallInfo(CallFlags_Value, 3), mapObject, key, value); }); } return isCtorSuperCall ? JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), mapObject, nullptr, scriptContext) : mapObject; }