BOOL NullTypeHandlerBase::AddProperty(DynamicObject* instance, PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags, SideEffects possibleSideEffects) { if (this->isPrototype && (ChangeTypeOnProto() || (GetIsShared() && IsolatePrototypes()))) { ScriptContext* scriptContext = instance->GetScriptContext(); return ConvertToSimpleDictionaryType(instance)->AddProperty(instance, scriptContext->GetPropertyName(propertyId), value, attributes, info, flags, possibleSideEffects); } else { return ConvertToSimpleType(instance)->AddProperty(instance, propertyId, value, attributes, info, flags, possibleSideEffects); } }
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 JavascriptReflect::EntryDefineProperty(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); Var undefinedValue = scriptContext->GetLibrary()->GetUndefined(); AUTO_TAG_NATIVE_LIBRARY_ENTRY(function, callInfo, _u("Reflect.defineProperty")); AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'"); if (args.Info.Flags & CallFlags_New) { JavascriptError::ThrowTypeError(scriptContext, JSERR_ErrorOnNew, _u("Reflect.defineProperty")); } Var propertyKey, attributes; if (args.Info.Count < 2 || !JavascriptOperators::IsObject(args[1])) { JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_NeedObject, _u("Reflect.defineProperty")); } Var target = args[1]; propertyKey = args.Info.Count > 2 ? args[2] : undefinedValue; PropertyRecord const * propertyRecord; JavascriptConversion::ToPropertyKey(propertyKey, scriptContext, &propertyRecord); attributes = args.Info.Count > 3 ? args[3] : undefinedValue; PropertyDescriptor propertyDescriptor; if (!JavascriptOperators::ToPropertyDescriptor(attributes, &propertyDescriptor, scriptContext)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_PropertyDescriptor_Invalid, scriptContext->GetPropertyName(propertyRecord->GetPropertyId())->GetBuffer()); } // If the object is HostDispatch try to invoke the operation remotely BOOL defineResult; if (JavascriptOperators::GetTypeId(target) == TypeIds_HostDispatch) { defineResult = RecyclableObject::FromVar(target)->InvokeBuiltInOperationRemotely(EntryDefineProperty, args, nullptr); } else { defineResult = JavascriptObject::DefineOwnPropertyHelper(RecyclableObject::FromVar(target), propertyRecord->GetPropertyId(), propertyDescriptor, scriptContext, false); } return scriptContext->GetLibrary()->GetTrueOrFalse(defineResult); }
BOOL JavascriptVariantDate::SetProperty(Js::PropertyId propertyId, Js::Var value, Js::PropertyOperationFlags flags, PropertyValueInfo* info) { ScriptContext* scriptContext = this->GetScriptContext(); JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_VarDate, scriptContext->GetPropertyName(propertyId)->GetBuffer()); };
// // Load persisted scope info. // void ScopeInfo::GetScopeInfo(Parser *parser, ByteCodeGenerator* byteCodeGenerator, FuncInfo* funcInfo, Scope* scope) { ScriptContext* scriptContext; ArenaAllocator* alloc; // Load scope attributes and push onto scope stack. scope->SetIsDynamic(this->isDynamic); if (this->isObject) { scope->SetIsObject(); } scope->SetMustInstantiate(this->mustInstantiate); if (!this->GetCanMergeWithBodyScope()) { scope->SetCannotMergeWithBodyScope(); } scope->SetHasOwnLocalInClosure(this->hasLocalInClosure); if (parser) { scriptContext = parser->GetScriptContext(); alloc = parser->GetAllocator(); } else { TRACE_BYTECODE(_u("\nRestore ScopeInfo: %s #symbols: %d %s\n"), funcInfo->name, symbolCount, isObject ? _u("isObject") : _u("")); Assert(!this->isCached || scope == funcInfo->GetBodyScope()); funcInfo->SetHasCachedScope(this->isCached); byteCodeGenerator->PushScope(scope); // The scope is already populated, so we're done. return; } // Load scope symbols // On first access to the scopeinfo, replace the ID's with PropertyRecord*'s to save the dictionary lookup // on later accesses. Replace them all before allocating Symbol's to prevent inconsistency on OOM. if (!this->areNamesCached && !PHASE_OFF1(Js::CacheScopeInfoNamesPhase)) { for (int i = 0; i < symbolCount; i++) { PropertyId propertyId = GetSymbolId(i); if (propertyId != 0) // There may be empty slots, e.g. "arguments" may have no slot { PropertyRecord const* name = scriptContext->GetPropertyName(propertyId); this->SetPropertyName(i, name); } } this->areNamesCached = true; } for (int i = 0; i < symbolCount; i++) { PropertyRecord const* name = nullptr; if (this->areNamesCached) { name = this->GetPropertyName(i); } else { PropertyId propertyId = GetSymbolId(i); if (propertyId != 0) // There may be empty slots, e.g. "arguments" may have no slot { name = scriptContext->GetPropertyName(propertyId); } } if (name != nullptr) { SymbolType symbolType = GetSymbolType(i); SymbolName symName(name->GetBuffer(), name->GetLength()); Symbol *sym = Anew(alloc, Symbol, symName, nullptr, symbolType); sym->SetScopeSlot(static_cast<PropertyId>(i)); sym->SetIsBlockVar(GetIsBlockVariable(i)); if (GetHasFuncAssignment(i)) { sym->RestoreHasFuncAssignment(); } scope->AddNewSymbol(sym); if (parser) { parser->RestorePidRefForSym(sym); } TRACE_BYTECODE(_u("%12s %d\n"), sym->GetName().GetBuffer(), sym->GetScopeSlot()); } } this->scope = scope; DebugOnly(scope->isRestored = true); }