void DebugManager::UpdateConsoleScope(DynamicObject* copyFromScope, ScriptContext* scriptContext) { Assert(copyFromScope != nullptr); DynamicObject* consoleScope = this->GetConsoleScope(scriptContext); Js::RecyclableObject* recyclableObject = Js::RecyclableObject::FromVar(copyFromScope); ulong newPropCount = recyclableObject->GetPropertyCount(); for (ulong i = 0; i < newPropCount; i++) { Js::PropertyId propertyId = recyclableObject->GetPropertyId((Js::PropertyIndex)i); // For deleted properties we won't have a property id if (propertyId != Js::Constants::NoProperty) { Js::PropertyValueInfo propertyValueInfo; Var propertyValue; BOOL gotPropertyValue = recyclableObject->GetProperty(recyclableObject, propertyId, &propertyValue, &propertyValueInfo, scriptContext); AssertMsg(gotPropertyValue, "DebugManager::UpdateConsoleScope Should have got valid value?"); OUTPUT_TRACE(Js::ConsoleScopePhase, _u("Adding property '%s'\n"), scriptContext->GetPropertyName(propertyId)->GetBuffer()); BOOL updateSuccess = consoleScope->SetPropertyWithAttributes(propertyId, propertyValue, propertyValueInfo.GetAttributes(), &propertyValueInfo); AssertMsg(updateSuccess, "DebugManager::UpdateConsoleScope Unable to update property value. Am I missing a scenario?"); } } OUTPUT_TRACE(Js::ConsoleScopePhase, _u("Number of properties on console scope object after update are %d\n"), consoleScope->GetPropertyCount()); }
void SnapshotExtractor::DoMarkWalk(const JsUtil::List<Js::Var, HeapAllocator>& roots, const JsUtil::List<Js::ScriptContext*, HeapAllocator>& ctxs, ThreadContext* threadContext) { TTDTimer timer; double startTime = timer.Now(); for(int32 i = 0; i < roots.Count(); ++i) { Js::Var root = roots.Item(i); this->MarkVisitVar(root); } while(!this->m_worklist.Empty()) { Js::RecyclableObject* nobj = this->m_worklist.Dequeue(); AssertMsg(JsSupport::IsVarComplexKind(nobj), "Should only be these two options"); this->MarkVisitStandardProperties(nobj); nobj->MarkVisitKindSpecificPtrs(this); } //Mark all of the well known objects/types for(int32 i = 0; i < ctxs.Count(); ++i) { ctxs.Item(i)->TTDWellKnownInfo->MarkWellKnownObjects_TTD(this->m_marks); } double endTime = timer.Now(); this->m_pendingSnap->MarkTime = (endTime - startTime) / 1000.0; }
Var JavascriptExternalFunction::StdCallExternalFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...) { RUNTIME_ARGUMENTS(args, callInfo); JavascriptExternalFunction* externalFunction = static_cast<JavascriptExternalFunction*>(function); externalFunction->PrepareExternalCall(&args); ScriptContext * scriptContext = externalFunction->type->GetScriptContext(); AnalysisAssert(scriptContext); Var result = NULL; BEGIN_LEAVE_SCRIPT(scriptContext) { result = externalFunction->stdCallNativeMethod(function, ((callInfo.Flags & CallFlags_New) != 0), args.Values, args.Info.Count, externalFunction->callbackState); } END_LEAVE_SCRIPT(scriptContext); if (result != nullptr && !Js::TaggedNumber::Is(result)) { if (!Js::RecyclableObject::Is(result)) { Js::Throw::InternalError(); } Js::RecyclableObject * obj = Js::RecyclableObject::FromVar(result); // For JSRT, we could get result marshalled in different context. bool isJSRT = !(scriptContext->GetThreadContext()->GetIsThreadBound()); if (!isJSRT && obj->GetScriptContext() != scriptContext) { Js::Throw::InternalError(); } } if (scriptContext->HasRecordedException()) { bool considerPassingToDebugger = false; JavascriptExceptionObject* recordedException = scriptContext->GetAndClearRecordedException(&considerPassingToDebugger); if (recordedException != nullptr) { // If this is script termination, then throw ScriptAbortExceptio, else throw normal Exception object. if (recordedException == scriptContext->GetThreadContext()->GetPendingTerminatedErrorObject()) { throw Js::ScriptAbortException(); } else { JavascriptExceptionOperators::RethrowExceptionObject(recordedException, scriptContext, considerPassingToDebugger); } } } return externalFunction->FinishExternalCall(result); }
// static Var CrossSite::MarshalVar(ScriptContext* scriptContext, Var value, bool fRequestWrapper) { // value might be null from disable implicit call if (value == nullptr || Js::TaggedNumber::Is(value)) { return value; } Js::RecyclableObject* object = RecyclableObject::UnsafeFromVar(value); if (fRequestWrapper || scriptContext != object->GetScriptContext()) { return MarshalVarInner(scriptContext, object, fRequestWrapper); } return value; }
void SnapshotExtractor::MarkVisitVar(Js::Var var) { AssertMsg(var != nullptr, "I don't think this should happen but not 100% sure."); AssertMsg(Js::JavascriptOperators::GetTypeId(var) < Js::TypeIds_Limit || Js::RecyclableObject::FromVar(var)->CanHaveInterceptors(), "Not cool."); //We don't need to visit tagged things if(JsSupport::IsVarTaggedInline(var)) { return; } if(JsSupport::IsVarPrimitiveKind(var)) { if(this->m_marks.MarkAndTestAddr<MarkTableTag::PrimitiveObjectTag>(var)) { Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(var); this->MarkVisitType(obj->GetType()); } } else { AssertMsg(JsSupport::IsVarComplexKind(var), "Shouldn't be anything else"); if(this->m_marks.MarkAndTestAddr<MarkTableTag::CompoundObjectTag>(var)) { Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(var); //do this here instead of in mark visit type as it wants the dynamic object as well if(Js::DynamicType::Is(obj->GetTypeId())) { Js::DynamicObject* dynObj = Js::DynamicObject::FromVar(obj); if(dynObj->GetDynamicType()->GetTypeHandler()->IsDeferredTypeHandler()) { dynObj->GetDynamicType()->GetTypeHandler()->EnsureObjectReady(dynObj); } } this->MarkVisitType(obj->GetType()); this->m_worklist.Enqueue(obj); } } }
Var JavascriptExternalFunction::StdCallExternalFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...) { ARGUMENTS(args, callInfo); JavascriptExternalFunction* externalFunction = static_cast<JavascriptExternalFunction*>(function); externalFunction->PrepareExternalCall(&args); ScriptContext * scriptContext = externalFunction->type->GetScriptContext(); AnalysisAssert(scriptContext); if (args.Info.Count > USHORT_MAX) { // Due to compat reasons, stdcall external functions expect a ushort count of args. // To support more than this we will need a new API. Js::JavascriptError::ThrowTypeError(scriptContext, JSERR_ArgListTooLarge); } Var result = nullptr; Assert(callInfo.Count > 0); StdCallJavascriptMethodInfo info = { args[0], args.HasNewTarget() ? args.GetNewTarget() : args.IsNewCall() ? function : scriptContext->GetLibrary()->GetUndefined(), args.IsNewCall() }; #if ENABLE_TTD if(scriptContext->ShouldPerformRecordOrReplayAction()) { result = JavascriptExternalFunction::HandleRecordReplayExternalFunction_StdThunk(function, callInfo, args, scriptContext); } else { BEGIN_LEAVE_SCRIPT(scriptContext) { result = externalFunction->stdCallNativeMethod(function, args.Values, static_cast<USHORT>(args.Info.Count), &info, externalFunction->callbackState); } END_LEAVE_SCRIPT(scriptContext); } #else BEGIN_LEAVE_SCRIPT(scriptContext) { result = externalFunction->stdCallNativeMethod(function, args.Values, static_cast<USHORT>(args.Info.Count), &info, externalFunction->callbackState); } END_LEAVE_SCRIPT(scriptContext); #endif bool marshallingMayBeNeeded = false; if (result != nullptr) { marshallingMayBeNeeded = Js::RecyclableObject::Is(result); if (marshallingMayBeNeeded) { Js::RecyclableObject * obj = Js::RecyclableObject::FromVar(result); // For JSRT, we could get result marshalled in different context. bool isJSRT = scriptContext->GetThreadContext()->IsJSRT(); marshallingMayBeNeeded = obj->GetScriptContext() != scriptContext; if (!isJSRT && marshallingMayBeNeeded) { Js::Throw::InternalError(); } } } if (scriptContext->HasRecordedException()) { bool considerPassingToDebugger = false; JavascriptExceptionObject* recordedException = scriptContext->GetAndClearRecordedException(&considerPassingToDebugger); if (recordedException != nullptr) { // If this is script termination, then throw ScriptAbortExceptio, else throw normal Exception object. if (recordedException == scriptContext->GetThreadContext()->GetPendingTerminatedErrorObject()) { throw Js::ScriptAbortException(); } else { JavascriptExceptionOperators::RethrowExceptionObject(recordedException, scriptContext, considerPassingToDebugger); } } } if (result == nullptr) { result = scriptContext->GetLibrary()->GetUndefined(); } else if (marshallingMayBeNeeded) { result = CrossSite::MarshalVar(scriptContext, result); } return result; }
void RuntimeContextInfo::GatherKnownObjectToPathMap(Js::ScriptContext* ctx) { JsUtil::List<const Js::PropertyRecord*, HeapAllocator> propertyRecordList(&HeapAllocator::Instance); this->EnqueueRootPathObject(_u("global"), ctx->GetGlobalObject()); this->EnqueueRootPathObject(_u("null"), ctx->GetLibrary()->GetNull()); this->EnqueueRootPathObject(_u("undeclBlockVar"), Js::RecyclableObject::FromVar(ctx->GetLibrary()->GetUndeclBlockVar())); this->EnqueueRootPathObject(_u("_defaultAccessor"), ctx->GetLibrary()->GetDefaultAccessorFunction()); if(ctx->GetConfig()->IsErrorStackTraceEnabled()) { this->EnqueueRootPathObject(_u("_stackTraceAccessor"), ctx->GetLibrary()->GetStackTraceAccessorFunction()); } this->EnqueueRootPathObject(_u("_throwTypeErrorRestrictedPropertyAccessor"), ctx->GetLibrary()->GetThrowTypeErrorRestrictedPropertyAccessorFunction()); if(ctx->GetConfig()->IsES6PromiseEnabled()) { this->EnqueueRootPathObject(_u("_identityFunction"), ctx->GetLibrary()->GetIdentityFunction()); this->EnqueueRootPathObject(_u("_throwerFunction"), ctx->GetLibrary()->GetThrowerFunction()); } // ArrayIteratorPrototype is not created when we have JsBuiltins, it it created on-demand only #ifdef ENABLE_JS_BUILTINS if (ctx->IsJsBuiltInEnabled()) { ctx->GetLibrary()->EnsureBuiltInEngineIsReady(); } #endif this->EnqueueRootPathObject(_u("_arrayIteratorPrototype"), ctx->GetLibrary()->GetArrayIteratorPrototype()); this->EnqueueRootPathObject(_u("_mapIteratorPrototype"), ctx->GetLibrary()->GetMapIteratorPrototype()); this->EnqueueRootPathObject(_u("_setIteratorPrototype"), ctx->GetLibrary()->GetSetIteratorPrototype()); this->EnqueueRootPathObject(_u("_stringIteratorPrototype"), ctx->GetLibrary()->GetStringIteratorPrototype()); this->EnqueueRootPathObject(_u("_generatorNextFunction"), ctx->GetLibrary()->EnsureGeneratorNextFunction()); this->EnqueueRootPathObject(_u("_generatorReturnFunction"), ctx->GetLibrary()->EnsureGeneratorReturnFunction()); this->EnqueueRootPathObject(_u("_generatorThrowFunction"), ctx->GetLibrary()->EnsureGeneratorThrowFunction()); this->EnqueueRootPathObject(_u("_generatorFunctionConstructor"), ctx->GetLibrary()->GetGeneratorFunctionConstructor()); this->EnqueueRootPathObject(_u("_asyncFunctionConstructor"), ctx->GetLibrary()->GetAsyncFunctionConstructor()); uint32 counter = 0; while(!this->m_worklist.Empty()) { Js::RecyclableObject* curr = this->m_worklist.Dequeue(); counter++; //// //Handle the standard properties for all object types //load propArray with all property names propertyRecordList.Clear(); LoadAndOrderPropertyNames(curr, propertyRecordList); //access each property and process the target objects as needed for(int32 i = 0; i < propertyRecordList.Count(); ++i) { const Js::PropertyRecord* precord = propertyRecordList.Item(i); Js::Var getter = nullptr; Js::Var setter = nullptr; if(curr->GetAccessors(precord->GetPropertyId(), &getter, &setter, ctx)) { if(getter != nullptr && !Js::JavascriptOperators::IsUndefinedObject(getter)) { TTDAssert(Js::JavascriptFunction::Is(getter), "The getter is not a function?"); this->EnqueueNewPathVarAsNeeded(curr, getter, precord, _u(">")); } if(setter != nullptr && !Js::JavascriptOperators::IsUndefinedObject(setter)) { TTDAssert(Js::JavascriptFunction::Is(setter), "The setter is not a function?"); this->EnqueueNewPathVarAsNeeded(curr, Js::RecyclableObject::FromVar(setter), precord, _u("<")); } } else { Js::Var pitem = nullptr; BOOL isproperty = Js::JavascriptOperators::GetOwnProperty(curr, precord->GetPropertyId(), &pitem, ctx, nullptr); TTDAssert(isproperty, "Not sure what went wrong."); this->EnqueueNewPathVarAsNeeded(curr, pitem, precord, nullptr); } } //shouldn't have any dynamic array valued properties if(Js::DynamicType::Is(curr->GetTypeId())) { Js::ArrayObject* parray = Js::DynamicObject::FromVar(curr)->GetObjectArray(); if(parray != nullptr) { this->EnqueueNewPathVarAsNeeded(curr, parray, _u("_object_array_")); } } Js::RecyclableObject* proto = curr->GetPrototype(); bool skipProto = (proto == nullptr) || Js::JavascriptOperators::IsUndefinedOrNullType(proto->GetTypeId()); if(!skipProto) { this->EnqueueNewPathVarAsNeeded(curr, proto, _u("_proto_")); } curr->ProcessCorePaths(); } SortDictIntoListOnNames<Js::RecyclableObject*>(this->m_coreObjToPathMap, this->m_sortedObjectList, this->m_nullString); SortDictIntoListOnNames<Js::FunctionBody*>(this->m_coreBodyToPathMap, this->m_sortedFunctionBodyList, this->m_nullString); SortDictIntoListOnNames<Js::DebuggerScope*>(this->m_coreDbgScopeToPathMap, this->m_sortedDbgScopeList, this->m_nullString); }
Var JavascriptExternalFunction::StdCallExternalFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...) { ARGUMENTS(args, callInfo); JavascriptExternalFunction* externalFunction = static_cast<JavascriptExternalFunction*>(function); externalFunction->PrepareExternalCall(&args); ScriptContext * scriptContext = externalFunction->type->GetScriptContext(); AnalysisAssert(scriptContext); Var result = NULL; #if ENABLE_TTD if(scriptContext->ShouldPerformRecordOrReplayAction()) { result = JavascriptExternalFunction::HandleRecordReplayExternalFunction_StdThunk(function, callInfo, args, scriptContext); } else { BEGIN_LEAVE_SCRIPT(scriptContext) { result = externalFunction->stdCallNativeMethod(function, ((callInfo.Flags & CallFlags_New) != 0), args.Values, args.Info.Count, externalFunction->callbackState); } END_LEAVE_SCRIPT(scriptContext); } #else BEGIN_LEAVE_SCRIPT(scriptContext) { result = externalFunction->stdCallNativeMethod(function, ((callInfo.Flags & CallFlags_New) != 0), args.Values, args.Info.Count, externalFunction->callbackState); } END_LEAVE_SCRIPT(scriptContext); #endif if (result != nullptr && !Js::TaggedNumber::Is(result)) { if (!Js::RecyclableObject::Is(result)) { Js::Throw::InternalError(); } Js::RecyclableObject * obj = Js::RecyclableObject::FromVar(result); // For JSRT, we could get result marshalled in different context. bool isJSRT = scriptContext->GetThreadContext()->IsJSRT(); if (!isJSRT && obj->GetScriptContext() != scriptContext) { Js::Throw::InternalError(); } } if (scriptContext->HasRecordedException()) { bool considerPassingToDebugger = false; JavascriptExceptionObject* recordedException = scriptContext->GetAndClearRecordedException(&considerPassingToDebugger); if (recordedException != nullptr) { // If this is script termination, then throw ScriptAbortExceptio, else throw normal Exception object. if (recordedException == scriptContext->GetThreadContext()->GetPendingTerminatedErrorObject()) { throw Js::ScriptAbortException(); } else { JavascriptExceptionOperators::RethrowExceptionObject(recordedException, scriptContext, considerPassingToDebugger); } } } if (result == nullptr) { result = scriptContext->GetLibrary()->GetUndefined(); } else { result = CrossSite::MarshalVar(scriptContext, result); } return result; }