Var JavascriptGeneratorFunction::EntryGeneratorFunctionImplementation(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(stackArgs, callInfo); Assert(!(callInfo.Flags & CallFlags_New)); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptGeneratorFunction* generatorFunction = JavascriptGeneratorFunction::FromVar(function); // InterpreterStackFrame takes a pointer to the args, so copy them to the recycler heap // and use that buffer for this InterpreterStackFrame. Field(Var)* argsHeapCopy = RecyclerNewArray(scriptContext->GetRecycler(), Field(Var), stackArgs.Info.Count); CopyArray(argsHeapCopy, stackArgs.Info.Count, stackArgs.Values, stackArgs.Info.Count); Arguments heapArgs(callInfo, (Var*)argsHeapCopy); DynamicObject* prototype = scriptContext->GetLibrary()->CreateGeneratorConstructorPrototypeObject(); JavascriptGenerator* generator = scriptContext->GetLibrary()->CreateGenerator(heapArgs, generatorFunction->scriptFunction, prototype); // Set the prototype from constructor JavascriptOperators::OrdinaryCreateFromConstructor(function, generator, prototype, scriptContext); // Call a next on the generator to execute till the beginning of the body CALL_ENTRYPOINT(scriptContext->GetThreadContext(), generator->EntryNext, function, CallInfo(CallFlags_Value, 1), generator); return generator; }
Var JavascriptReflect::EntryEnumerate(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); AUTO_TAG_NATIVE_LIBRARY_ENTRY(function, callInfo, _u("Reflect.enumerate")); AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'"); if (args.Info.Flags & CallFlags_New) { JavascriptError::ThrowTypeError(scriptContext, JSERR_ErrorOnNew, _u("Reflect.enumerate")); } if (args.Info.Count < 2 || !JavascriptOperators::IsObject(args[1])) { JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_NeedObject, _u("Reflect.enumerate")); } Var target = args[1]; Var iterator = nullptr; Recycler* recycler = scriptContext->GetRecycler(); ForInObjectEnumeratorWrapper* forinEnumerator = RecyclerNew(recycler, Js::ForInObjectEnumeratorWrapper, RecyclableObject::FromVar(target), scriptContext); iterator = JavascriptEnumeratorIterator::Create(forinEnumerator, nullptr, scriptContext); return iterator; }
Var JavascriptGenerator::EntryThrow(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, L"Generator.prototype.throw"); if (!JavascriptGenerator::Is(args[0])) { JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, L"Generator.prototype.throw", L"Generator"); } JavascriptGenerator* generator = JavascriptGenerator::FromVar(args[0]); Var input = args.Info.Count > 1 ? args[1] : library->GetUndefined(); if (generator->IsSuspendedStart()) { generator->SetState(GeneratorState::Completed); } if (generator->IsCompleted()) { JavascriptExceptionOperators::OP_Throw(input, scriptContext); } ResumeYieldData yieldData(input, RecyclerNew(scriptContext->GetRecycler(), JavascriptExceptionObject, input, scriptContext, nullptr)); return generator->CallGenerator(&yieldData, L"Generator.prototype.throw"); }
// We will make sure the iterator will iterate through the exported properties in sorted order. // There is no such requirement for enumerator (forin). ListForListIterator* ModuleNamespace::EnsureSortedExportedNames() { if (sortedExportedNames == nullptr) { ExportedNames* exportedNames = moduleRecord->GetExportedNames(nullptr); ScriptContext* scriptContext = GetScriptContext(); sortedExportedNames = ListForListIterator::New(scriptContext->GetRecycler()); exportedNames->Map([&](PropertyId propertyId) { JavascriptString* propertyString = scriptContext->GetPropertyString(propertyId); sortedExportedNames->Add(propertyString); }); sortedExportedNames->Sort([](void* context, const void* left, const void* right) ->int { JavascriptString** leftString = (JavascriptString**) (left); JavascriptString** rightString = (JavascriptString**) (right); if (JavascriptString::LessThan(*leftString, *rightString)) { return -1; } if (JavascriptString::LessThan(*rightString, *leftString)) { return 1; } return 0; }, nullptr); } return sortedExportedNames; }
ScriptFunctionType * ScriptFunctionType::New(FunctionProxy * proxy, bool isShared) { Assert(proxy->GetFunctionProxy() == proxy); ScriptContext * scriptContext = proxy->GetScriptContext(); JavascriptLibrary * library = scriptContext->GetLibrary(); DynamicObject * functionPrototype = proxy->IsAsync() ? library->GetAsyncFunctionPrototype() : library->GetFunctionPrototype(); JavascriptMethod address = proxy->GetDefaultEntryPointInfo()->jsMethod; return RecyclerNew(scriptContext->GetRecycler(), ScriptFunctionType, scriptContext, functionPrototype, address, proxy->GetDefaultEntryPointInfo(), library->ScriptFunctionTypeHandler(proxy->IsLambda() || proxy->IsAsync() || proxy->IsClassMethod(), proxy->GetIsAnonymousFunction()), isShared, isShared); }
ModuleNamespace* ModuleNamespace::GetModuleNamespace(ModuleRecordBase* requestModule) { Assert(requestModule->IsSourceTextModuleRecord()); SourceTextModuleRecord* moduleRecord = SourceTextModuleRecord::FromHost(requestModule); ModuleNamespace* nsObject = moduleRecord->GetNamespace(); if (nsObject != nullptr) { return nsObject; } ScriptContext* scriptContext = moduleRecord->GetRealm()->GetScriptContext(); Recycler* recycler = scriptContext->GetRecycler(); nsObject = RecyclerNew(recycler, ModuleNamespace, moduleRecord, scriptContext->GetLibrary()->GetModuleNamespaceType()); nsObject->Initialize(); moduleRecord->SetNamespace(nsObject); return nsObject; }
Var JavascriptGeneratorFunction::EntryAsyncFunctionImplementation(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(stackArgs, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); RecyclableObject* prototype = scriptContext->GetLibrary()->GetNull(); // InterpreterStackFrame takes a pointer to the args, so copy them to the recycler heap // and use that buffer for this InterpreterStackFrame. Var* argsHeapCopy = RecyclerNewArray(scriptContext->GetRecycler(), Var, stackArgs.Info.Count); js_memcpy_s(argsHeapCopy, sizeof(Var) * stackArgs.Info.Count, stackArgs.Values, sizeof(Var) * stackArgs.Info.Count); Arguments heapArgs(callInfo, argsHeapCopy); JavascriptExceptionObject* e = nullptr; JavascriptPromiseResolveOrRejectFunction* resolve; JavascriptPromiseResolveOrRejectFunction* reject; JavascriptPromiseAsyncSpawnExecutorFunction* executor = library->CreatePromiseAsyncSpawnExecutorFunction( JavascriptPromise::EntryJavascriptPromiseAsyncSpawnExecutorFunction, scriptContext->GetLibrary()->CreateGenerator(heapArgs, JavascriptAsyncFunction::FromVar(function)->GetGeneratorVirtualScriptFunction(), prototype), stackArgs[0]); JavascriptPromise* promise = library->CreatePromise(); JavascriptPromise::InitializePromise(promise, &resolve, &reject, scriptContext); try { CALL_FUNCTION(executor, CallInfo(CallFlags_Value, 3), library->GetUndefined(), resolve, reject); } catch (JavascriptExceptionObject* ex) { e = ex; } if (e != nullptr) { JavascriptPromise::TryRejectWithExceptionObject(e, reject, scriptContext); } return promise; }
T* NullTypeHandlerBase::ConvertToTypeHandler(DynamicObject* instance) { ScriptContext* scriptContext = instance->GetScriptContext(); Recycler* recycler = scriptContext->GetRecycler(); T * newTypeHandler = RecyclerNew(recycler, T, recycler); Assert((newTypeHandler->GetFlags() & IsPrototypeFlag) == 0); // EnsureSlots before updating the type handler and instance, as EnsureSlots allocates and may throw. instance->EnsureSlots(0, newTypeHandler->GetSlotCapacity(), scriptContext, newTypeHandler); Assert(((this->GetFlags() & IsPrototypeFlag) != 0) == this->isPrototype); newTypeHandler->SetFlags(IsPrototypeFlag, this->GetFlags()); newTypeHandler->SetPropertyTypes(PropertyTypesWritableDataOnly | PropertyTypesWritableDataOnlyDetection | PropertyTypesInlineSlotCapacityLocked, this->GetPropertyTypes()); if (instance->HasReadOnlyPropertiesInvisibleToTypeHandler()) { newTypeHandler->ClearHasOnlyWritableDataProperties(); } newTypeHandler->SetInstanceTypeHandler(instance); return newTypeHandler; }
void DynamicObjectPropertyEnumerator::Reset() { if (this->object) { enumeratedCount = 0; initialType = object->GetDynamicType(); objectIndex = Constants::NoBigSlot; initialPropertyCount = GetSnapShotSemantics() ? this->object->GetPropertyCount() : Constants::NoBigSlot; // Create the appropriate enumerator object. if (GetSnapShotSemantics() && this->initialType->PrepareForTypeSnapshotEnumeration()) { ScriptContext* scriptContext = this->object->GetScriptContext(); ThreadContext * threadContext = scriptContext->GetThreadContext(); CachedData * data = (CachedData *)threadContext->GetDynamicObjectEnumeratorCache(this->initialType); if (data == nullptr || data->scriptContext != this->requestContext || data->enumNonEnumerable != GetEnumNonEnumerable() || data->enumSymbols != GetEnumSymbols()) { data = RecyclerNewStructPlus(scriptContext->GetRecycler(), this->initialPropertyCount * sizeof(PropertyString *) + this->initialPropertyCount * sizeof(BigPropertyIndex) + this->initialPropertyCount * sizeof(PropertyAttributes), CachedData); data->scriptContext = requestContext; data->cachedCount = 0; data->strings = (PropertyString **)(data + 1); data->indexes = (BigPropertyIndex *)(data->strings + this->initialPropertyCount); data->attributes = (PropertyAttributes*)(data->indexes + this->initialPropertyCount); data->completed = false; data->enumNonEnumerable = GetEnumNonEnumerable(); data->enumSymbols = GetEnumSymbols(); threadContext->AddDynamicObjectEnumeratorCache(this->initialType, data); } this->cachedData = data; this->cachedDataType = this->initialType; } else { this->cachedData = nullptr; this->cachedDataType = nullptr; } } }
Var JavascriptGeneratorFunction::EntryGeneratorFunctionImplementation(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(stackArgs, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptGeneratorFunction* generatorFunction = JavascriptGeneratorFunction::FromVar(function); // InterpreterStackFrame takes a pointer to the args, so copy them to the recycler heap // and use that buffer for this InterpreterStackFrame. Var* argsHeapCopy = RecyclerNewArray(scriptContext->GetRecycler(), Var, stackArgs.Info.Count); js_memcpy_s(argsHeapCopy, sizeof(Var) * stackArgs.Info.Count, stackArgs.Values, sizeof(Var) * stackArgs.Info.Count); Arguments heapArgs(callInfo, argsHeapCopy); DynamicObject* prototype = scriptContext->GetLibrary()->CreateGeneratorConstructorPrototypeObject(); JavascriptGenerator* generator = scriptContext->GetLibrary()->CreateGenerator(heapArgs, generatorFunction->scriptFunction, prototype); // Set the prototype from constructor JavascriptOperators::OrdinaryCreateFromConstructor(function, generator, prototype, scriptContext); Assert(!(callInfo.Flags & CallFlags_New)); return generator; }
Var WebAssemblyTable::EntryGrow(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); Assert(!(callInfo.Flags & CallFlags_New)); if (args.Info.Count == 0 || !WebAssemblyTable::Is(args[0])) { JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedTableObject); } WebAssemblyTable * table = WebAssemblyTable::FromVar(args[0]); uint32 oldLength = table->m_currentLength; Var deltaVar = args.Info.Count >= 2 ? args[1] : scriptContext->GetLibrary()->GetUndefined(); uint32 delta = WebAssembly::ToNonWrappingUint32(deltaVar, scriptContext); if (delta > 0) { uint32 newLength = 0; if (UInt32Math::Add(table->m_currentLength, delta, &newLength) || newLength > table->m_maxLength) { JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange); } Field(Var) * newValues = RecyclerNewArrayZ(scriptContext->GetRecycler(), Field(Var), newLength); CopyArray(newValues, newLength, table->m_values, table->m_currentLength); table->m_values = newValues; table->m_currentLength = newLength; } return JavascriptNumber::ToVar(oldLength, scriptContext); }
JavascriptString* CharStringCache::GetStringForCharW(char16 c) { Assert(!JavascriptString::IsASCII7BitChar(c)); JavascriptString* str; ScriptContext * scriptContext = JavascriptLibrary::FromCharStringCache(this)->GetScriptContext(); if (!scriptContext->IsClosed()) { if (charStringCache == nullptr) { Recycler * recycler = scriptContext->GetRecycler(); charStringCache = RecyclerNew(recycler, CharStringCacheMap, recycler, 17); } if (!charStringCache->TryGetValue(c, &str)) { str = SingleCharString::New(c, scriptContext); charStringCache->Add(c, str); } } else { str = SingleCharString::New(c, scriptContext); } return str; }
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 BoundFunction::NewInstance(RecyclableObject* function, CallInfo callInfo, ...) { RUNTIME_ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); if (args.Info.Count == 0) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction /* TODO-ERROR: get arg name - args[0] */); } BoundFunction *boundFunction = (BoundFunction *) function; Var targetFunction = boundFunction->targetFunction; // // var o = new boundFunction() // a new object should be created using the actual function object // Var newVarInstance = nullptr; if (callInfo.Flags & CallFlags_New) { if (JavascriptProxy::Is(targetFunction)) { JavascriptProxy* proxy = JavascriptProxy::FromVar(targetFunction); Arguments proxyArgs(CallInfo(CallFlags_New, 1), &targetFunction); args.Values[0] = newVarInstance = proxy->ConstructorTrap(proxyArgs, scriptContext, 0); } else { args.Values[0] = newVarInstance = JavascriptOperators::NewScObjectNoCtor(targetFunction, scriptContext); } } Js::Arguments actualArgs = args; if (boundFunction->count > 0) { BOOL isCrossSiteObject = boundFunction->IsCrossSiteObject(); // OACR thinks that this can change between here and the check in the for loop below const unsigned int argCount = args.Info.Count; if ((boundFunction->count + argCount) > CallInfo::kMaxCountArgs) { JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgListTooLarge); } Var *newValues = RecyclerNewArray(scriptContext->GetRecycler(), Var, boundFunction->count + argCount); uint index = 0; // // For [[Construct]] use the newly created var instance // For [[Call]] use the "this" to which bind bound it. // if (callInfo.Flags & CallFlags_New) { newValues[index++] = args[0]; } else { newValues[index++] = boundFunction->boundThis; } // Copy the bound args if (!isCrossSiteObject) { for (uint i = 0; i < boundFunction->count; i++) { newValues[index++] = boundFunction->boundArgs[i]; } } else { // it is possible that the bound arguments are not marshalled yet. for (uint i = 0; i < boundFunction->count; i++) { newValues[index++] = CrossSite::MarshalVar(scriptContext, boundFunction->boundArgs[i]); } } // Copy the extra args for (uint i=1; i<argCount; i++) { newValues[index++] = args[i]; } actualArgs = Arguments(args.Info, newValues); actualArgs.Info.Count = boundFunction->count + argCount; } else { if (!(callInfo.Flags & CallFlags_New)) { actualArgs.Values[0] = boundFunction->boundThis; } } RecyclableObject* actualFunction = RecyclableObject::FromVar(targetFunction); Var aReturnValue = JavascriptFunction::CallFunction<true>(actualFunction, actualFunction->GetEntryPoint(), actualArgs); // // [[Construct]] and call returned a non-object // return the newly created var instance // if ((callInfo.Flags & CallFlags_New) && !JavascriptOperators::IsObject(aReturnValue)) { aReturnValue = newVarInstance; } return aReturnValue; }
BoundFunction::BoundFunction(Arguments args, DynamicType * type) : JavascriptFunction(type, &functionInfo), count(0), boundArgs(nullptr) { DebugOnly(VerifyEntryPoint()); AssertMsg(args.Info.Count > 0, "wrong number of args in BoundFunction"); ScriptContext *scriptContext = this->GetScriptContext(); targetFunction = RecyclableObject::FromVar(args[0]); // Let proto be targetFunction.[[GetPrototypeOf]](). RecyclableObject* proto = JavascriptOperators::GetPrototype(targetFunction); if (proto != type->GetPrototype()) { if (type->GetIsShared()) { this->ChangeType(); type = this->GetDynamicType(); } type->SetPrototype(proto); } // If targetFunction is proxy, need to make sure that traps are called in right order as per 19.2.3.2 in RC#4 dated April 3rd 2015. // Here although we won't use value of length, this is just to make sure that we call traps involved with HasOwnProperty(Target, "length") and Get(Target, "length") if (JavascriptProxy::Is(targetFunction)) { if (JavascriptOperators::HasOwnProperty(targetFunction, PropertyIds::length, scriptContext) == TRUE) { int len = 0; Var varLength; if (targetFunction->GetProperty(targetFunction, PropertyIds::length, &varLength, nullptr, scriptContext)) { len = JavascriptConversion::ToInt32(varLength, scriptContext); } } GetTypeHandler()->EnsureObjectReady(this); } if (args.Info.Count > 1) { boundThis = args[1]; // function object and "this" arg const uint countAccountedFor = 2; count = args.Info.Count - countAccountedFor; // Store the args excluding function obj and "this" arg if (args.Info.Count > 2) { boundArgs = RecyclerNewArray(scriptContext->GetRecycler(), Var, count); for (uint i=0; i<count; i++) { boundArgs[i] = args[i+countAccountedFor]; } } } else { // If no "this" is passed, "undefined" is used boundThis = scriptContext->GetLibrary()->GetUndefined(); } }
void ModuleNamespace::Initialize() { ScriptContext* scriptContext = moduleRecord->GetRealm()->GetScriptContext(); Recycler* recycler = scriptContext->GetRecycler(); SourceTextModuleRecord* sourceTextModuleRecord = static_cast<SourceTextModuleRecord*>(moduleRecord); JavascriptLibrary* library = GetLibrary(); if (scriptContext->GetConfig()->IsES6ToStringTagEnabled()) { DynamicObject::SetPropertyWithAttributes(PropertyIds::_symbolToStringTag, library->GetModuleTypeDisplayString(), PropertyConfigurable, nullptr); } DynamicType* type = library->CreateFunctionWithLengthType(&EntryInfo::SymbolIterator); RuntimeFunction* iteratorFunction = RecyclerNewEnumClass(scriptContext->GetRecycler(), library->EnumFunctionClass, RuntimeFunction, type, &EntryInfo::SymbolIterator); DynamicObject::SetPropertyWithAttributes(PropertyIds::_symbolIterator, iteratorFunction, PropertyBuiltInMethodDefaults, nullptr); ModuleImportOrExportEntryList* localExportList = sourceTextModuleRecord->GetLocalExportEntryList(); // We don't have a type handler that can handle ModuleNamespace object. We have properties that could be aliased // like {export foo as foo1, foo2, foo3}, and external properties as reexport from current module. The problem with aliasing // is that multiple propertyId can be associated with one slotIndex. We need to build from PropertyMap directly here. // there is one instance of ModuleNamespace per module file; we can always use the BigPropertyIndex for security. propertyMap = RecyclerNew(recycler, SimplePropertyDescriptorMap, recycler, sourceTextModuleRecord->GetLocalExportCount()); if (localExportList != nullptr) { localExportList->Map([=](ModuleImportOrExportEntry exportEntry) { PropertyId exportNameId = exportEntry.exportName->GetPropertyId(); PropertyId localNameId = exportEntry.localName->GetPropertyId(); const Js::PropertyRecord* exportNameRecord = scriptContext->GetThreadContext()->GetPropertyName(exportNameId); ModuleNameRecord* importRecord = nullptr; AssertMsg(exportNameId != Js::Constants::NoProperty, "should have been initialized already"); // ignore local exports that are actually indirect exports. if (sourceTextModuleRecord->GetImportEntryList() == nullptr || (sourceTextModuleRecord->ResolveImport(localNameId, &importRecord) && importRecord == nullptr)) { BigPropertyIndex index = sourceTextModuleRecord->GetLocalExportSlotIndexByExportName(exportNameId); Assert((uint)index < sourceTextModuleRecord->GetLocalExportCount()); SimpleDictionaryPropertyDescriptor<BigPropertyIndex> propertyDescriptor = { index, PropertyModuleNamespaceDefault }; propertyMap->Add(exportNameRecord, propertyDescriptor); } }); } // update the local slot to use the storage for local exports. SetNSSlotsForModuleNS(sourceTextModuleRecord->GetLocalExportSlots()); // For items that are not in the local export list, we need to resolve them to get it ExportedNames* exportedNames = sourceTextModuleRecord->GetExportedNames(nullptr); ModuleNameRecord* moduleNameRecord = nullptr; #if DBG uint unresolvableExportsCount = 0; uint localExportCount = 0; #endif if (exportedNames != nullptr) { exportedNames->Map([&](PropertyId propertyId) { if (!moduleRecord->ResolveExport(propertyId, nullptr, nullptr, &moduleNameRecord)) { // ignore ambigious resolution. #if DBG unresolvableExportsCount++; #endif return; } // non-ambiguous resolution. if (moduleNameRecord == nullptr) { JavascriptError::ThrowSyntaxError(scriptContext, JSERR_ResolveExportFailed, scriptContext->GetPropertyName(propertyId)->GetBuffer()); } if (moduleNameRecord->module == moduleRecord) { // skip local exports as they are covered in the localExportSlots. #if DBG localExportCount++; #endif return; } Assert(moduleNameRecord->module != moduleRecord); this->AddUnambiguousNonLocalExport(propertyId, moduleNameRecord); }); } #if DBG uint totalExportCount = exportedNames != nullptr ? exportedNames->Count() : 0; uint unambiguousNonLocalCount = (this->GetUnambiguousNonLocalExports() != nullptr) ? this->GetUnambiguousNonLocalExports()->Count() : 0; Assert(totalExportCount == localExportCount + unambiguousNonLocalCount + unresolvableExportsCount); #endif BOOL result = this->PreventExtensions(); Assert(result); }
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; }