Var JavascriptGenerator::EntryNext(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.next"); if (!JavascriptGenerator::Is(args[0])) { JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, L"Generator.prototype.next", L"Generator"); } JavascriptGenerator* generator = JavascriptGenerator::FromVar(args[0]); Var input = args.Info.Count > 1 ? args[1] : library->GetUndefined(); if (generator->IsCompleted()) { return library->CreateIteratorResultObjectUndefinedTrue(); } ResumeYieldData yieldData(input, nullptr); return generator->CallGenerator(&yieldData, L"Generator.prototype.next"); }
Var JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_RegisterChakraLibraryFunction(RecyclableObject* function, CallInfo callInfo, ...) { EngineInterfaceObject_CommonFunctionProlog(function, callInfo); AssertOrFailFast(args.Info.Count >= 3 && JavascriptString::Is(args.Values[1]) && JavascriptFunction::Is(args.Values[2])); JavascriptLibrary * library = scriptContext->GetLibrary(); // retrieves arguments JavascriptString* methodName = JavascriptString::FromVar(args.Values[1]); JavascriptFunction* func = JavascriptFunction::FromVar(args.Values[2]); // Set the function's display name, as the function we pass in argument are anonym. func->GetFunctionProxy()->SetIsPublicLibraryCode(); func->GetFunctionProxy()->EnsureDeserialized()->SetDisplayName(methodName->GetString(), methodName->GetLength(), 0); DynamicObject* chakraLibraryObject = GetPrototypeFromName(PropertyIds::__chakraLibrary, scriptContext); PropertyIds functionIdentifier = JavascriptOperators::GetPropertyId(methodName, scriptContext); // Link the function to __chakraLibrary. ScriptFunction* scriptFunction = library->CreateScriptFunction(func->GetFunctionProxy()); scriptFunction->GetFunctionProxy()->SetIsJsBuiltInCode(); Assert(scriptFunction->HasFunctionBody()); scriptFunction->GetFunctionBody()->SetJsBuiltInForceInline(); scriptFunction->SetPropertyWithAttributes(PropertyIds::name, methodName, PropertyConfigurable, nullptr); library->AddMember(chakraLibraryObject, functionIdentifier, scriptFunction); //Don't need to return anything return library->GetUndefined(); }
JavascriptString * RuntimeFunction::EnsureSourceString() { JavascriptLibrary* library = this->GetLibrary(); ScriptContext * scriptContext = library->GetScriptContext(); JavascriptString * retStr = nullptr; if (this->functionNameId == nullptr) { retStr = library->GetFunctionDisplayString(); this->functionNameId = retStr; } else { if (TaggedInt::Is(this->functionNameId)) { if (this->GetTypeHandler()->IsDeferredTypeHandler()) { JavascriptString* functionName = nullptr; DebugOnly(bool status = ) this->GetFunctionName(&functionName); Assert(status); this->SetPropertyWithAttributes(PropertyIds::name, functionName, PropertyConfigurable, nullptr); } // This has a side-effect where any other code (such as debugger) that uses functionNameId value will now get the value like "function foo() { native code }" // instead of just "foo". Alternative ways will need to be devised; if it's not desirable to use this full display name value in those cases. retStr = GetNativeFunctionDisplayString(scriptContext, scriptContext->GetPropertyString(TaggedInt::ToInt32(this->functionNameId))); this->functionNameId = retStr; } else {
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"); }
RecyclableObject* ThrowErrorObject::CreateThrowErrorObject(CreateErrorFunc createError, ScriptContext* scriptContext, int32 hCode, PCWSTR varName) { JavascriptLibrary* library = scriptContext->GetLibrary(); JavascriptError *pError = (library->*createError)(); JavascriptError::SetErrorMessage(pError, hCode, varName, scriptContext); return library->CreateThrowErrorObject(pError); }
// Symbol.keyFor as described in ES 2015 Var JavascriptSymbol::EntryKeyFor(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); AssertMsg(args.Info.Count, "Should always have implicit 'this'."); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); Assert(!(callInfo.Flags & CallFlags_New)); if (args.Info.Count < 2 || !JavascriptSymbol::Is(args[1])) { JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedSymbol, _u("Symbol.keyFor")); } JavascriptSymbol* sym = JavascriptSymbol::FromVar(args[1]); const char16* key = sym->GetValue()->GetBuffer(); // Search the global symbol registration map for a key equal to the description of the symbol passed into Symbol.keyFor. // Symbol.for creates a new symbol with description equal to the key and uses that key as a mapping to the new symbol. // There will only be one symbol in the map with that string key value. const Js::PropertyRecord* propertyRecord = scriptContext->GetThreadContext()->GetSymbolFromRegistrationMap(key); // If we found a PropertyRecord in the map, make sure it is the same symbol that was passed to Symbol.keyFor. // If the two are different, it means the symbol passed to keyFor has the same description as a symbol registered via // Symbol.for _but_ is not the symbol returned from Symbol.for. if (propertyRecord != nullptr && propertyRecord == sym->GetValue()) { return JavascriptString::NewCopyBuffer(key, sym->GetValue()->GetLength(), scriptContext); } return library->GetUndefined(); }
void JsBuiltInEngineInterfaceExtensionObject::InitializePrototypes(ScriptContext * scriptContext) { JavascriptLibrary* library = scriptContext->GetLibrary(); JavascriptString * methodName = JavascriptString::NewWithSz(_u("ArrayIterator"), scriptContext); auto arrayIterator = JavascriptOperators::GetProperty(library->GetChakraLib(), JavascriptOperators::GetPropertyId(methodName, scriptContext), scriptContext); library->arrayIteratorPrototype = DynamicObject::FromVar(JavascriptOperators::GetProperty(DynamicObject::FromVar(arrayIterator), PropertyIds::prototype, scriptContext)); library->arrayIteratorPrototypeBuiltinNextFunction = JavascriptFunction::FromVar(JavascriptOperators::GetProperty(library->arrayIteratorPrototype, PropertyIds::next, scriptContext)); }
Var JavascriptWeakSet::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 && !JavascriptOperators::IsUndefined(newTarget); Assert(isCtorSuperCall || !(callInfo.Flags & CallFlags_New) || args[0] == nullptr); CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(WeakSetCount); JavascriptWeakSet* weakSetObject = nullptr; if (callInfo.Flags & CallFlags_New) { weakSetObject = library->CreateWeakSet(); } else { JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("WeakSet"), _u("WeakSet")); } Assert(weakSetObject != 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(weakSetObject, PropertyIds::add, scriptContext); if (!JavascriptConversion::IsCallable(adderVar)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction); } adder = RecyclableObject::FromVar(adderVar); } if (iter != nullptr) { Var nextItem; while (JavascriptOperators::IteratorStepAndValue(iter, scriptContext, &nextItem)) { CALL_FUNCTION(adder, CallInfo(CallFlags_Value, 2), weakSetObject, nextItem); } } return isCtorSuperCall ? JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), weakSetObject, nullptr, scriptContext) : weakSetObject; }
Var JavascriptStringIterator::EntryNext(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); Assert(!(callInfo.Flags & CallFlags_New)); Var thisObj = args[0]; if (!JavascriptStringIterator::Is(thisObj)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedStringIterator, L"String Iterator.prototype.next"); } JavascriptStringIterator* iterator = JavascriptStringIterator::FromVar(thisObj); JavascriptString* string = iterator->m_string; if (string == nullptr) { return library->CreateIteratorResultObjectUndefinedTrue(); } charcount_t length = string->GetLength(); charcount_t index = iterator->m_nextIndex; if (index >= length) { // Nulling out the m_string field is important so that the iterator // does not keep the string alive after iteration is completed. iterator->m_string = nullptr; return library->CreateIteratorResultObjectUndefinedTrue(); } wchar_t chFirst = string->GetItem(index); Var result; if (index + 1 == string->GetLength() || !NumberUtilities::IsSurrogateLowerPart(chFirst) || !NumberUtilities::IsSurrogateUpperPart(string->GetItem(index + 1))) { result = scriptContext->GetLibrary()->GetCharStringCache().GetStringForChar(chFirst); iterator->m_nextIndex += 1; } else { result = JavascriptString::SubstringCore(string, index, 2, scriptContext); iterator->m_nextIndex += 2; } return library->CreateIteratorResultObjectValueFalse(result); }
bool JsBuiltInEngineInterfaceExtensionObject::InitializeJsBuiltInNativeInterfaces(DynamicObject * builtInNativeInterfaces, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode) { typeHandler->Convert(builtInNativeInterfaces, mode, 16); ScriptContext* scriptContext = builtInNativeInterfaces->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); library->AddFunctionToLibraryObject(builtInNativeInterfaces, Js::PropertyIds::registerChakraLibraryFunction, &JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_RegisterChakraLibraryFunction, 2); library->AddFunctionToLibraryObject(builtInNativeInterfaces, Js::PropertyIds::registerFunction, &JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_RegisterFunction, 2); library->AddFunctionToLibraryObject(builtInNativeInterfaces, Js::PropertyIds::GetIteratorPrototype, &JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_GetIteratorPrototype, 1); builtInNativeInterfaces->SetHasNoEnumerableProperties(true); return true; }
Var JavascriptMapIterator::EntryNext(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); Assert(!(callInfo.Flags & CallFlags_New)); Var thisObj = args[0]; if (!JavascriptMapIterator::Is(thisObj)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedMapIterator, L"Map Iterator.prototype.next"); } JavascriptMapIterator* iterator = JavascriptMapIterator::FromVar(thisObj); JavascriptMap* map = iterator->m_map; auto& mapIterator = iterator->m_mapIterator; if (map == nullptr || !mapIterator.Next()) { iterator->m_map = nullptr; return library->CreateIteratorResultObjectUndefinedTrue(); } auto entry = mapIterator.Current(); Var result; if (iterator->m_kind == JavascriptMapIteratorKind::KeyAndValue) { JavascriptArray* keyValueTuple = library->CreateArray(2); keyValueTuple->SetItem(0, entry.Key(), PropertyOperation_None); keyValueTuple->SetItem(1, entry.Value(), PropertyOperation_None); result = keyValueTuple; } else if (iterator->m_kind == JavascriptMapIteratorKind::Key) { result = entry.Key(); } else { Assert(iterator->m_kind == JavascriptMapIteratorKind::Value); result = entry.Value(); } return library->CreateIteratorResultObjectValueFalse(result); }
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); }
JavascriptString* CharStringCache::GetStringForCharA(char c) { AssertMsg(JavascriptString::IsASCII7BitChar(c), "GetStringForCharA must be called with ASCII 7bit chars only"); PropertyString * str = charStringCacheA[(int)c]; if (str == nullptr) { PropertyRecord const * propertyRecord; char16 wc = c; JavascriptLibrary * javascriptLibrary = JavascriptLibrary::FromCharStringCache(this); javascriptLibrary->GetScriptContext()->GetOrAddPropertyRecord(&wc, 1, &propertyRecord); str = javascriptLibrary->CreatePropertyString(propertyRecord); charStringCacheA[(int)c] = str; } return str; }
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; }
DynamicObject* JsBuiltInEngineInterfaceExtensionObject::GetPrototypeFromName(Js::PropertyIds propertyId, ScriptContext* scriptContext) { JavascriptLibrary* library = scriptContext->GetLibrary(); switch (propertyId) { case PropertyIds::Array: return library->arrayPrototype; case PropertyIds::String: return library->stringPrototype; case PropertyIds::__chakraLibrary: return library->GetChakraLib(); default: AssertMsg(false, "Unable to find a prototype that match with this className."); return nullptr; } }
void EngineInterfaceObject::Initialize() { Recycler* recycler = this->GetRecycler(); ScriptContext* scriptContext = this->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); // CommonNativeInterfaces is used as a prototype for the other native interface objects // to share the common APIs without requiring everyone to access EngineInterfaceObject.Common. this->commonNativeInterfaces = DynamicObject::New(recycler, DynamicType::New(scriptContext, TypeIds_Object, library->GetObjectPrototype(), nullptr, DeferredTypeHandler<InitializeCommonNativeInterfaces>::GetDefaultInstance())); library->AddMember(this, Js::PropertyIds::Common, this->commonNativeInterfaces); for (uint i = 0; i <= MaxEngineInterfaceExtensionKind; i++) { if (engineExtensions[i] != nullptr) { engineExtensions[i]->Initialize(); } } }
// Symbol.for as described in ES 2015 Var JavascriptSymbol::EntryFor(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); AssertMsg(args.Info.Count, "Should always have implicit 'this'."); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); Assert(!(callInfo.Flags & CallFlags_New)); JavascriptString* key; if (args.Info.Count > 1) { key = JavascriptConversion::ToString(args[1], scriptContext); } else { key = library->GetUndefinedDisplayString(); } // Search the global symbol registration map for a symbol with description equal to the string key. // The map can only have one symbol with that description so if we found a symbol, that is the registered // symbol for the string key. const Js::PropertyRecord* propertyRecord = scriptContext->GetThreadContext()->GetSymbolFromRegistrationMap(key->GetString(), key->GetLength()); // If we didn't find a PropertyRecord in the map, we'll create a new symbol with description equal to the key string. // This is the only place we add new PropertyRecords to the map, so we should never have multiple PropertyRecords in the // map with the same string key value (since we would return the one we found above instead of creating a new one). if (propertyRecord == nullptr) { propertyRecord = scriptContext->GetThreadContext()->AddSymbolToRegistrationMap(key->GetString(), key->GetLength()); } Assert(propertyRecord != nullptr); return library->CreateSymbol(propertyRecord); }
Var RuntimeFunction::EnsureSourceString() { JavascriptLibrary* library = this->GetLibrary(); ScriptContext * scriptContext = library->GetScriptContext(); if (this->functionNameId == nullptr) { this->functionNameId = library->GetFunctionDisplayString(); } else { if (TaggedInt::Is(this->functionNameId)) { if (this->GetScriptContext()->GetConfig()->IsES6FunctionNameEnabled() && this->GetTypeHandler()->IsDeferredTypeHandler()) { JavascriptString* functionName = nullptr; DebugOnly(bool status = ) this->GetFunctionName(&functionName); Assert(status); this->SetPropertyWithAttributes(PropertyIds::name, functionName, PropertyConfigurable, nullptr); } this->functionNameId = GetNativeFunctionDisplayString(scriptContext, scriptContext->GetPropertyString(TaggedInt::ToInt32(this->functionNameId))); } }
void EngineInterfaceObject::InitializeCommonNativeInterfaces(DynamicObject* commonNativeInterfaces, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode) { typeHandler->Convert(commonNativeInterfaces, mode, 38); ScriptContext* scriptContext = commonNativeInterfaces->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); #ifndef GlobalBuiltIn #define GlobalBuiltIn(global, method) \ library->AddFunctionToLibraryObject(commonNativeInterfaces, Js::PropertyIds::builtIn##global##method, &EngineInterfaceObject::EntryInfo::Intl_BuiltIn_##global##_##method##, 1); \ #define GlobalBuiltInConstructor(global) SetPropertyOn(commonNativeInterfaces, Js::PropertyIds::##global##, library->Get##global##Constructor()); #define BuiltInRaiseException(exceptionType, exceptionID) \ library->AddFunctionToLibraryObject(commonNativeInterfaces, Js::PropertyIds::raise##exceptionID, &EngineInterfaceObject::EntryInfo::Intl_BuiltIn_raise##exceptionID, 1); \ #define BuiltInRaiseException1(exceptionType, exceptionID) BuiltInRaiseException(exceptionType, exceptionID) #define BuiltInRaiseException2(exceptionType, exceptionID) BuiltInRaiseException(exceptionType, exceptionID) #define BuiltInRaiseException3(exceptionType, exceptionID) BuiltInRaiseException(exceptionType, exceptionID##_3) #include "EngineInterfaceObjectBuiltIns.h" #undef BuiltInRaiseException #undef BuiltInRaiseException1 #undef BuiltInRaiseException2 #undef BuiltInRaiseException3 #undef GlobalBuiltIn #undef GlobalBuiltInConstructor #endif library->AddFunctionToLibraryObject(commonNativeInterfaces, Js::PropertyIds::builtInJavascriptObjectCreate, &JavascriptObject::EntryInfo::Create, 1); library->AddFunctionToLibraryObject(commonNativeInterfaces, Js::PropertyIds::builtInJavascriptObjectPreventExtensions, &JavascriptObject::EntryInfo::PreventExtensions, 1); library->AddFunctionToLibraryObject(commonNativeInterfaces, Js::PropertyIds::builtInJavascriptObjectGetOwnPropertyDescriptor, &JavascriptObject::EntryInfo::GetOwnPropertyDescriptor, 1); library->AddFunctionToLibraryObject(commonNativeInterfaces, Js::PropertyIds::builtInGlobalObjectEval, &GlobalObject::EntryInfo::Eval, 2); library->AddFunctionToLibraryObject(commonNativeInterfaces, Js::PropertyIds::getErrorMessage, &EngineInterfaceObject::EntryInfo::GetErrorMessage, 1); library->AddFunctionToLibraryObject(commonNativeInterfaces, Js::PropertyIds::logDebugMessage, &EngineInterfaceObject::EntryInfo::LogDebugMessage, 1); library->AddFunctionToLibraryObject(commonNativeInterfaces, Js::PropertyIds::tagPublicLibraryCode, &EngineInterfaceObject::EntryInfo::TagPublicLibraryCode, 1); commonNativeInterfaces->SetHasNoEnumerableProperties(true); }
void JsBuiltInEngineInterfaceExtensionObject::Initialize() { if (wasInitialized) { return; } JavascriptLibrary* library = scriptContext->GetLibrary(); DynamicObject* commonObject = library->GetEngineInterfaceObject()->GetCommonNativeInterfaces(); if (scriptContext->IsJsBuiltInEnabled()) { Assert(library->GetEngineInterfaceObject() != nullptr); builtInNativeInterfaces = DynamicObject::New(library->GetRecycler(), DynamicType::New(scriptContext, TypeIds_Object, commonObject, nullptr, DeferredTypeHandler<InitializeJsBuiltInNativeInterfaces>::GetDefaultInstance())); library->AddMember(library->GetEngineInterfaceObject(), Js::PropertyIds::JsBuiltIn, builtInNativeInterfaces); } wasInitialized = true; }
Var JavascriptGenerator::CallGenerator(ResumeYieldData* yieldData, const wchar_t* apiNameForErrorMessage) { ScriptContext* scriptContext = this->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); Var result = nullptr; if (this->IsExecuting()) { JavascriptError::ThrowTypeError(scriptContext, JSERR_GeneratorAlreadyExecuting, apiNameForErrorMessage); } { // RAII helper to set the state of the generator to completed if an exception is thrown // or if the save state InterpreterStackFrame is never created implying the generator // is JITed and returned without ever yielding. class GeneratorStateHelper { JavascriptGenerator* g; bool didThrow; public: GeneratorStateHelper(JavascriptGenerator* g) : g(g), didThrow(true) { g->SetState(GeneratorState::Executing); } ~GeneratorStateHelper() { g->SetState(didThrow || g->frame == nullptr ? GeneratorState::Completed : GeneratorState::Suspended); } void DidNotThrow() { didThrow = false; } } helper(this); Var thunkArgs[] = { this, yieldData }; Arguments arguments(_countof(thunkArgs), thunkArgs); try { result = JavascriptFunction::CallFunction<1>(this->scriptFunction, this->scriptFunction->GetEntryPoint(), arguments); helper.DidNotThrow(); } catch (Js::JavascriptExceptionObject* exceptionObj) { if (!exceptionObj->IsGeneratorReturnException()) { throw exceptionObj; } result = exceptionObj->GetThrownObject(nullptr); } } if (this->IsCompleted()) { result = library->CreateIteratorResultObject(result, library->GetTrue()); } else { int nextOffset = this->frame->GetReader()->GetCurrentOffset(); int endOffset = this->frame->GetFunctionBody()->GetByteCode()->GetLength(); if (nextOffset != endOffset - 1) { result = library->CreateIteratorResultObjectValueFalse(result); } else { result = library->CreateIteratorResultObject(result, library->GetTrue()); this->SetState(GeneratorState::Completed); } } return result; }
// SharedArrayBuffer.prototype.slice Var SharedArrayBuffer::EntrySlice(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'"); Assert(!(callInfo.Flags & CallFlags_New)); if (!SharedArrayBuffer::Is(args[0])) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedSharedArrayBufferObject); } JavascriptLibrary* library = scriptContext->GetLibrary(); SharedArrayBuffer* currentBuffer = SharedArrayBuffer::FromVar(args[0]); int64 currentLen = (int64)currentBuffer->GetByteLength(); int64 start = 0, end = 0; int64 newLen = 0; // If no start or end arguments, use the entire length if (args.Info.Count < 2) { newLen = currentLen; } else { start = JavascriptArray::GetIndexFromVar(args[1], currentLen, scriptContext); // If no end argument, use length as the end if (args.Info.Count < 3 || args[2] == library->GetUndefined()) { end = currentLen; } else { end = JavascriptArray::GetIndexFromVar(args[2], currentLen, scriptContext); } newLen = end > start ? end - start : 0; } // We can't have allocated an SharedArrayBuffer with byteLength > MaxArrayBufferLength. // start and end are clamped to valid indices, so the new length also cannot exceed MaxArrayBufferLength. // Therefore, should be safe to cast down newLen to uint32. Assert(newLen < MaxSharedArrayBufferLength); uint32 newbyteLength = static_cast<uint32>(newLen); SharedArrayBuffer* newBuffer = nullptr; if (scriptContext->GetConfig()->IsES6SpeciesEnabled()) { Var constructorVar = JavascriptOperators::SpeciesConstructor(currentBuffer, scriptContext->GetLibrary()->GetSharedArrayBufferConstructor(), scriptContext); JavascriptFunction* constructor = JavascriptFunction::FromVar(constructorVar); Js::Var constructorArgs[] = { constructor, JavascriptNumber::ToVar(newbyteLength, scriptContext) }; Js::CallInfo constructorCallInfo(Js::CallFlags_New, _countof(constructorArgs)); Js::Var newVar = JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext); if (!SharedArrayBuffer::Is(newVar)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedSharedArrayBufferObject); } newBuffer = SharedArrayBuffer::FromVar(newVar); if (newBuffer == currentBuffer) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedSharedArrayBufferObject); } if (newBuffer->GetByteLength() < newbyteLength) { JavascriptError::ThrowTypeError(scriptContext, JSERR_ArgumentOutOfRange, _u("SharedArrayBuffer.prototype.slice")); } } else { newBuffer = library->CreateSharedArrayBuffer(newbyteLength); } Assert(newBuffer); Assert(newBuffer->GetByteLength() >= newbyteLength); // Don't bother doing memcpy if we aren't copying any elements if (newbyteLength > 0) { AssertMsg(currentBuffer->GetBuffer() != nullptr, "buffer must not be null when we copy from it"); js_memcpy_s(newBuffer->GetBuffer(), newbyteLength, currentBuffer->GetBuffer() + start, newbyteLength); } return newBuffer; }
Var JavascriptArrayIterator::EntryNext(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); Assert(!(callInfo.Flags & CallFlags_New)); Var thisObj = args[0]; if (!JavascriptArrayIterator::Is(thisObj)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedArrayIterator, _u("Array Iterator.prototype.next")); } JavascriptArrayIterator* iterator = JavascriptArrayIterator::FromVar(thisObj); Var iterable = iterator->m_iterableObject; if (iterable == nullptr) { return library->CreateIteratorResultObjectUndefinedTrue(); } int64 length; bool bArray = false; JavascriptArray* pArr = nullptr; if (DynamicObject::IsAnyArray(iterable) && !JavascriptArray::FromAnyArray(iterable)->IsCrossSiteObject()) { #if ENABLE_COPYONACCESS_ARRAY JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(iterable); #endif pArr = JavascriptArray::FromAnyArray(iterable); length = pArr->GetLength(); bArray = true; } else { length = JavascriptConversion::ToLength(JavascriptOperators::OP_GetLength(iterable, scriptContext), scriptContext); } int64 index = iterator->m_nextIndex; if (index >= length) { // Nulling out the m_iterableObject field is important so that the iterator // does not keep the iterable object alive after iteration is completed. iterator->m_iterableObject = nullptr; return library->CreateIteratorResultObjectUndefinedTrue(); } iterator->m_nextIndex += 1; if (iterator->m_kind == JavascriptArrayIteratorKind::Key) { return library->CreateIteratorResultObjectValueFalse(JavascriptNumber::ToVar(index, scriptContext)); } Var value; if (index <= UINT_MAX) { if (bArray) { if (JavascriptArray::Is(pArr)) { value = pArr->DirectGetItem((uint32)index); } else { if (!JavascriptOperators::GetOwnItem(pArr, (uint32) index, &value, scriptContext)) { value = library->GetUndefined(); } } } else { value = JavascriptOperators::OP_GetElementI_UInt32(iterable, (uint32)index, scriptContext); } } else { value = JavascriptOperators::OP_GetElementI(iterable, JavascriptNumber::ToVar(index, scriptContext), scriptContext); } if (iterator->m_kind == JavascriptArrayIteratorKind::Value) { return library->CreateIteratorResultObjectValueFalse(value); } Assert(iterator->m_kind == JavascriptArrayIteratorKind::KeyAndValue); JavascriptArray* keyValueTuple = library->CreateArray(2); keyValueTuple->SetItem(0, JavascriptNumber::ToVar(index, scriptContext), PropertyOperation_None); keyValueTuple->SetItem(1, value, PropertyOperation_None); return library->CreateIteratorResultObjectValueFalse(keyValueTuple); }
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; }
Var JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_RegisterFunction(RecyclableObject* function, CallInfo callInfo, ...) { EngineInterfaceObject_CommonFunctionProlog(function, callInfo); AssertOrFailFast(args.Info.Count >= 3 && JavascriptObject::Is(args.Values[1]) && JavascriptFunction::Is(args.Values[2])); JavascriptLibrary * library = scriptContext->GetLibrary(); // retrieves arguments RecyclableObject* funcInfo = nullptr; if (!JavascriptConversion::ToObject(args.Values[1], scriptContext, &funcInfo)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_NeedObject, _u("Object.assign")); } Var classNameProperty = JavascriptOperators::OP_GetProperty(funcInfo, Js::PropertyIds::className, scriptContext); Var methodNameProperty = JavascriptOperators::OP_GetProperty(funcInfo, Js::PropertyIds::methodName, scriptContext); Var argumentsCountProperty = JavascriptOperators::OP_GetProperty(funcInfo, Js::PropertyIds::argumentsCount, scriptContext); Var forceInlineProperty = JavascriptOperators::OP_GetProperty(funcInfo, Js::PropertyIds::forceInline, scriptContext); Var aliasProperty = JavascriptOperators::OP_GetProperty(funcInfo, Js::PropertyIds::alias, scriptContext); Assert(JavascriptString::Is(classNameProperty)); Assert(JavascriptString::Is(methodNameProperty)); Assert(TaggedInt::Is(argumentsCountProperty)); JavascriptString* className = JavascriptString::FromVar(classNameProperty); JavascriptString* methodName = JavascriptString::FromVar(methodNameProperty); int argumentsCount = TaggedInt::ToInt32(argumentsCountProperty); BOOL forceInline = JavascriptConversion::ToBoolean(forceInlineProperty, scriptContext); JavascriptFunction* func = JavascriptFunction::FromVar(args.Values[2]); // Set the function's display name, as the function we pass in argument are anonym. func->GetFunctionProxy()->SetIsPublicLibraryCode(); func->GetFunctionProxy()->EnsureDeserialized()->SetDisplayName(methodName->GetString(), methodName->GetLength(), 0); DynamicObject* prototype = GetPrototypeFromName(JavascriptOperators::GetPropertyId(className, scriptContext), scriptContext); PropertyIds functionIdentifier = methodName->BufferEquals(_u("Symbol.iterator"), 15)? PropertyIds::_symbolIterator : JavascriptOperators::GetPropertyId(methodName, scriptContext); // Link the function to the prototype. ScriptFunction* scriptFunction = library->CreateScriptFunction(func->GetFunctionProxy()); scriptFunction->GetFunctionProxy()->SetIsJsBuiltInCode(); if (forceInline) { Assert(scriptFunction->HasFunctionBody()); scriptFunction->GetFunctionBody()->SetJsBuiltInForceInline(); } scriptFunction->SetPropertyWithAttributes(PropertyIds::length, TaggedInt::ToVarUnchecked(argumentsCount), PropertyConfigurable, nullptr); scriptFunction->SetConfigurable(PropertyIds::prototype, true); scriptFunction->DeleteProperty(PropertyIds::prototype, Js::PropertyOperationFlags::PropertyOperation_None); scriptFunction->SetPropertyWithAttributes(PropertyIds::name, methodName, PropertyConfigurable, nullptr); library->AddMember(prototype, functionIdentifier, scriptFunction); RecordCommonNativeInterfaceBuiltIns(functionIdentifier, scriptContext, scriptFunction); if (!JavascriptOperators::IsUndefinedOrNull(aliasProperty)) { JavascriptString * alias = JavascriptConversion::ToString(aliasProperty, scriptContext); // Cannot do a string to property id search here, Symbol.* have different hashing mechanism, so resort to this str compare PropertyIds aliasFunctionIdentifier = alias->BufferEquals(_u("Symbol.iterator"), 15) ? PropertyIds::_symbolIterator : JavascriptOperators::GetPropertyId(alias, scriptContext); library->AddMember(prototype, aliasFunctionIdentifier, scriptFunction); } if (prototype == library->arrayPrototype) { RecordDefaultIteratorFunctions(functionIdentifier, scriptContext, scriptFunction); } //Don't need to return anything return library->GetUndefined(); }