CrossSite.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeBasePch.h"
  6. #include "Library/JavascriptProxy.h"
  7. #include "Library/HostObjectBase.h"
  8. #include "Types/UnscopablesWrapperObject.h"
  9. #if ENABLE_CROSSSITE_TRACE
  10. #define TTD_XSITE_LOG(CTX, MSG, VAR) if((CTX)->ShouldPerformRecordOrReplayAction()) \
  11. { \
  12. (CTX)->GetThreadContext()->TTDExecutionInfo->GetTraceLogger()->WriteLiteralMsg(" -XS- "); \
  13. (CTX)->GetThreadContext()->TTDExecutionInfo->GetTraceLogger()->WriteLiteralMsg(MSG); \
  14. (CTX)->GetThreadContext()->TTDExecutionInfo->GetTraceLogger()->WriteVar(VAR); \
  15. (CTX)->GetThreadContext()->TTDExecutionInfo->GetTraceLogger()->WriteLiteralMsg("\n"); \
  16. }
  17. #else
  18. #define TTD_XSITE_LOG(CTX, MSG, VAR)
  19. #endif
  20. namespace Js
  21. {
  22. BOOL CrossSite::NeedMarshalVar(Var instance, ScriptContext * requestContext)
  23. {
  24. if (TaggedNumber::Is(instance))
  25. {
  26. return FALSE;
  27. }
  28. RecyclableObject * object = UnsafeVarTo<RecyclableObject>(instance);
  29. if (object->GetScriptContext() == requestContext)
  30. {
  31. return FALSE;
  32. }
  33. if (PHASE_TRACE1(Js::Phase::MarshalPhase))
  34. {
  35. Output::Print(_u("NeedMarshalVar: %p (var sc: %p, request sc: %p)\n"), instance, object->GetScriptContext(), requestContext);
  36. }
  37. if (DynamicType::Is(object->GetTypeId()))
  38. {
  39. return !UnsafeVarTo<DynamicObject>(object)->IsCrossSiteObject() && !object->IsExternal();
  40. }
  41. return TRUE;
  42. }
  43. void CrossSite::MarshalDynamicObject(ScriptContext * scriptContext, DynamicObject * object)
  44. {
  45. Assert(!object->IsExternal() && !object->IsCrossSiteObject());
  46. TTD_XSITE_LOG(scriptContext, "MarshalDynamicObject", object);
  47. object->MarshalToScriptContext(scriptContext);
  48. if (object->GetTypeId() == TypeIds_Function)
  49. {
  50. AssertMsg(object != object->GetScriptContext()->GetLibrary()->GetDefaultAccessorFunction(), "default accessor marshalled");
  51. JavascriptFunction * function = VarTo<JavascriptFunction>(object);
  52. //TODO: this may be too aggressive and create x-site thunks that are't technically needed -- see uglify-2js test.
  53. // See if this function is one that the host needs to handle
  54. HostScriptContext * hostScriptContext = scriptContext->GetHostScriptContext();
  55. if (!hostScriptContext || !hostScriptContext->SetCrossSiteForFunctionType(function))
  56. {
  57. if (function->GetDynamicType()->GetIsLocked())
  58. {
  59. TTD_XSITE_LOG(scriptContext, "SetCrossSiteForLockedFunctionType ", object);
  60. function->GetLibrary()->SetCrossSiteForLockedFunctionType(function);
  61. }
  62. else
  63. {
  64. TTD_XSITE_LOG(scriptContext, "setEntryPoint->CurrentCrossSiteThunk ", object);
  65. function->SetEntryPoint(function->GetScriptContext()->CurrentCrossSiteThunk);
  66. }
  67. }
  68. }
  69. else if (object->GetTypeId() == TypeIds_Proxy)
  70. {
  71. RecyclableObject * target = VarTo<JavascriptProxy>(object)->GetTarget();
  72. if (JavascriptConversion::IsCallable(target))
  73. {
  74. Assert(JavascriptProxy::FunctionCallTrap == object->GetEntryPoint());
  75. TTD_XSITE_LOG(scriptContext, "setEntryPoint->CrossSiteProxyCallTrap ", object);
  76. object->GetDynamicType()->SetEntryPoint(CrossSite::CrossSiteProxyCallTrap);
  77. }
  78. }
  79. }
  80. void CrossSite::MarshalPrototypeChain(ScriptContext* scriptContext, DynamicObject * object)
  81. {
  82. RecyclableObject * prototype = object->GetPrototype();
  83. while (prototype->GetTypeId() != TypeIds_Null && prototype->GetTypeId() != TypeIds_HostDispatch)
  84. {
  85. // We should not see any static type or host dispatch here
  86. DynamicObject * prototypeObject = VarTo<DynamicObject>(prototype);
  87. if (prototypeObject->IsCrossSiteObject())
  88. {
  89. break;
  90. }
  91. if (scriptContext != prototypeObject->GetScriptContext() && !prototypeObject->IsExternal())
  92. {
  93. MarshalDynamicObject(scriptContext, prototypeObject);
  94. }
  95. if (VarIs<JavascriptProxy>(prototypeObject))
  96. {
  97. // Fetching prototype of proxy can invoke trap - which we don't want during the marshalling time.
  98. break;
  99. }
  100. prototype = prototypeObject->GetPrototype();
  101. }
  102. }
  103. void CrossSite::MarshalDynamicObjectAndPrototype(ScriptContext* scriptContext, DynamicObject * object)
  104. {
  105. MarshalDynamicObject(scriptContext, object);
  106. MarshalPrototypeChain(scriptContext, object);
  107. }
  108. Var CrossSite::MarshalFrameDisplay(ScriptContext* scriptContext, FrameDisplay *display)
  109. {
  110. TTD_XSITE_LOG(scriptContext, "MarshalFrameDisplay", nullptr);
  111. uint16 length = display->GetLength();
  112. FrameDisplay *newDisplay =
  113. RecyclerNewPlus(scriptContext->GetRecycler(), length * sizeof(Var), FrameDisplay, length);
  114. for (uint16 i = 0; i < length; i++)
  115. {
  116. Var value = display->GetItem(i);
  117. if (UnscopablesWrapperObject::Is(value))
  118. {
  119. // Here we are marshalling the wrappedObject and then ReWrapping th object in the new context.
  120. RecyclableObject* wrappedObject = UnscopablesWrapperObject::FromVar(value)->GetWrappedObject();
  121. ScriptContext* wrappedObjectScriptContext = wrappedObject->GetScriptContext();
  122. value = JavascriptOperators::ToUnscopablesWrapperObject(CrossSite::MarshalVar(scriptContext,
  123. wrappedObject, wrappedObjectScriptContext), scriptContext);
  124. }
  125. else
  126. {
  127. value = CrossSite::MarshalVar(scriptContext, value);
  128. }
  129. newDisplay->SetItem(i, value);
  130. }
  131. return (Var)newDisplay;
  132. }
  133. // static
  134. Var CrossSite::MarshalVar(ScriptContext* scriptContext, Var value, ScriptContext* objectScriptContext)
  135. {
  136. if (scriptContext != objectScriptContext)
  137. {
  138. if (value == nullptr || Js::TaggedNumber::Is(value))
  139. {
  140. return value;
  141. }
  142. return MarshalVarInner(scriptContext, VarTo<RecyclableObject>(value), false);
  143. }
  144. return value;
  145. }
  146. // static
  147. Var CrossSite::MarshalVar(ScriptContext* scriptContext, Var value, bool fRequestWrapper)
  148. {
  149. // value might be null from disable implicit call
  150. if (value == nullptr || Js::TaggedNumber::Is(value))
  151. {
  152. return value;
  153. }
  154. Js::RecyclableObject* object = UnsafeVarTo<RecyclableObject>(value);
  155. if (fRequestWrapper || scriptContext != object->GetScriptContext())
  156. {
  157. if (PHASE_TRACE1(Js::Phase::MarshalPhase))
  158. {
  159. Output::Print(_u("MarshalVar: %p (var sc: %p, request sc: %p, requestWrapper: %d)\n"), object, object->GetScriptContext(), scriptContext, fRequestWrapper);
  160. }
  161. // Do not allow marshaling if a callable object is being marshalled into a high privileged
  162. // script context.
  163. if (JavascriptConversion::IsCallable(object))
  164. {
  165. ScriptContext* objectScriptContext = object->GetScriptContext();
  166. if (scriptContext->GetPrivilegeLevel() < objectScriptContext->GetPrivilegeLevel())
  167. {
  168. return scriptContext->GetLibrary()->GetUndefined();
  169. }
  170. }
  171. return MarshalVarInner(scriptContext, object, fRequestWrapper);
  172. }
  173. return value;
  174. }
  175. bool CrossSite::DoRequestWrapper(Js::RecyclableObject* object, bool fRequestWrapper)
  176. {
  177. return fRequestWrapper && VarIs<JavascriptFunction>(object) && VarTo<JavascriptFunction>(object)->IsExternalFunction();
  178. }
  179. #if ENABLE_TTD
  180. void CrossSite::MarshalCrossSite_TTDInflate(DynamicObject* obj)
  181. {
  182. obj->MarshalCrossSite_TTDInflate();
  183. if(obj->GetTypeId() == TypeIds_Function)
  184. {
  185. AssertMsg(obj != obj->GetScriptContext()->GetLibrary()->GetDefaultAccessorFunction(), "default accessor marshalled -- I don't think this should ever happen as it is marshalled in a special case?");
  186. JavascriptFunction * function = VarTo<JavascriptFunction>(obj);
  187. //
  188. //TODO: what happens if the gaurd in marshal (MarshalDynamicObject) isn't true?
  189. //
  190. if(function->GetTypeHandler()->GetIsLocked())
  191. {
  192. function->GetLibrary()->SetCrossSiteForLockedFunctionType(function);
  193. }
  194. else
  195. {
  196. function->SetEntryPoint(function->GetScriptContext()->CurrentCrossSiteThunk);
  197. }
  198. }
  199. }
  200. #endif
  201. Var CrossSite::MarshalVarInner(ScriptContext* scriptContext, __in Js::RecyclableObject* object, bool fRequestWrapper)
  202. {
  203. if (scriptContext == object->GetScriptContext())
  204. {
  205. if (DoRequestWrapper(object, fRequestWrapper))
  206. {
  207. // If we get here then we need to either wrap in the caller's type system or we need to return undefined.
  208. // VBScript will pass in the scriptContext (requestContext) from the JavascriptDispatch and this will be the
  209. // same as the object's script context and so we have to safely pretend this value doesn't exist.
  210. return scriptContext->GetLibrary()->GetUndefined();
  211. }
  212. return object;
  213. }
  214. AssertMsg(scriptContext->GetThreadContext() == object->GetScriptContext()->GetThreadContext(), "ScriptContexts should belong to same threadcontext for marshalling.");
  215. // In heapenum, we are traversing through the object graph to dump out the content of recyclable objects. The content
  216. // of the objects are duplicated to the heapenum result, and we are not storing/changing the object graph during heap enum.
  217. // We don't actually need to do cross site thunk here.
  218. if (scriptContext->GetRecycler()->IsHeapEnumInProgress())
  219. {
  220. return object;
  221. }
  222. #if ENABLE_TTD
  223. if (scriptContext->IsTTDSnapshotOrInflateInProgress())
  224. {
  225. return object;
  226. }
  227. #endif
  228. // Marshaling should not cause any re-entrancy.
  229. JS_REENTRANCY_LOCK(jsReentLock, scriptContext->GetThreadContext());
  230. #if ENABLE_COPYONACCESS_ARRAY
  231. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(object);
  232. #endif
  233. TypeId typeId = object->GetTypeId();
  234. AssertMsg(typeId != TypeIds_Enumerator, "enumerator shouldn't be marshalled here");
  235. // At the moment the mental model for UnscopablesWrapperObject Marshaling is this:
  236. // Are we trying to marshal a UnscopablesWrapperObject in the Frame Display? - then 1) unwrap in MarshalFrameDisplay,
  237. // 2) marshal the wrapped object, 3) Create a new UnscopablesWrapperObject in the current scriptContext and re-wrap.
  238. // We can avoid copying the UnscopablesWrapperObject because it has no properties and never should.
  239. // Thus creating a new UnscopablesWrapperObject per context in MarshalFrameDisplay should be kosher.
  240. // If it is not a FrameDisplay then we should not marshal. We can wrap cross context objects with a
  241. // UnscopablesWrapperObject in a different context. When we unwrap for property lookups and the wrapped object
  242. // is cross context, then we marshal the wrapped object into the current scriptContext, thus avoiding
  243. // the need to copy the UnscopablesWrapperObject itself. Thus We don't have to handle marshaling the UnscopablesWrapperObject
  244. // in non-FrameDisplay cases.
  245. AssertMsg(typeId != TypeIds_UnscopablesWrapperObject, "UnscopablesWrapperObject shouldn't be marshalled here");
  246. if (StaticType::Is(typeId))
  247. {
  248. TTD_XSITE_LOG(object->GetScriptContext(), "CloneToScriptContext", object);
  249. return object->CloneToScriptContext(scriptContext);
  250. }
  251. if (typeId == TypeIds_ModuleRoot)
  252. {
  253. RootObjectBase *moduleRoot = static_cast<RootObjectBase*>(object);
  254. HostObjectBase * hostObject = moduleRoot->GetHostObject();
  255. // When marshaling module root, all we need is the host object.
  256. // So, if the module root which is being marshaled has host object, marshal it.
  257. if (hostObject)
  258. {
  259. TTD_XSITE_LOG(object->GetScriptContext(), "hostObject", hostObject);
  260. Var hostDispatch = hostObject->GetHostDispatchVar();
  261. return CrossSite::MarshalVar(scriptContext, hostDispatch);
  262. }
  263. }
  264. if (typeId == TypeIds_Function)
  265. {
  266. if (object == object->GetScriptContext()->GetLibrary()->GetDefaultAccessorFunction() )
  267. {
  268. TTD_XSITE_LOG(object->GetScriptContext(), "DefaultAccessorFunction", object);
  269. return scriptContext->GetLibrary()->GetDefaultAccessorFunction();
  270. }
  271. if (DoRequestWrapper(object, fRequestWrapper))
  272. {
  273. TTD_XSITE_LOG(object->GetScriptContext(), "CreateWrappedExternalFunction", object);
  274. // Marshal as a cross-site thunk if necessary before re-wrapping in an external function thunk.
  275. MarshalVarInner(scriptContext, object, false);
  276. return scriptContext->GetLibrary()->CreateWrappedExternalFunction(static_cast<JavascriptExternalFunction*>(object));
  277. }
  278. }
  279. // We have an object marshaled, we need to keep track of the related script context
  280. // so optimization overrides can be updated as a group
  281. scriptContext->optimizationOverrides.Merge(&object->GetScriptContext()->optimizationOverrides);
  282. DynamicObject * dynamicObject = VarTo<DynamicObject>(object);
  283. if (!dynamicObject->IsExternal())
  284. {
  285. if (!dynamicObject->IsCrossSiteObject())
  286. {
  287. if (VarIs<JavascriptProxy>(dynamicObject))
  288. {
  289. // We don't need to marshal the prototype chain in the case of Proxy. Otherwise we will go to the user code.
  290. TTD_XSITE_LOG(object->GetScriptContext(), "MarshalDynamicObject", object);
  291. MarshalDynamicObject(scriptContext, dynamicObject);
  292. }
  293. else
  294. {
  295. TTD_XSITE_LOG(object->GetScriptContext(), "MarshalDynamicObjectAndPrototype", object);
  296. MarshalDynamicObjectAndPrototype(scriptContext, dynamicObject);
  297. }
  298. }
  299. }
  300. else
  301. {
  302. MarshalPrototypeChain(scriptContext, dynamicObject);
  303. if (Js::JavascriptConversion::IsCallable(dynamicObject))
  304. {
  305. TTD_XSITE_LOG(object->GetScriptContext(), "MarshalToScriptContext", object);
  306. dynamicObject->MarshalToScriptContext(scriptContext);
  307. }
  308. }
  309. return dynamicObject;
  310. }
  311. bool CrossSite::IsThunk(JavascriptMethod thunk)
  312. {
  313. #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
  314. return (thunk == CrossSite::ProfileThunk || thunk == CrossSite::DefaultThunk);
  315. #else
  316. return (thunk == CrossSite::DefaultThunk);
  317. #endif
  318. }
  319. #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
  320. Var CrossSite::ProfileThunk(RecyclableObject* callable, CallInfo callInfo, ...)
  321. {
  322. JavascriptFunction* function = VarTo<JavascriptFunction>(callable);
  323. Assert(function->GetTypeId() == TypeIds_Function);
  324. Assert(function->GetEntryPoint() == CrossSite::ProfileThunk);
  325. RUNTIME_ARGUMENTS(args, callInfo);
  326. ScriptContext * scriptContext = function->GetScriptContext();
  327. // It is not safe to access the function body if the script context is not alive.
  328. scriptContext->VerifyAliveWithHostContext(!function->IsExternal(),
  329. scriptContext->GetThreadContext()->GetPreviousHostScriptContext());
  330. JavascriptMethod entryPoint;
  331. FunctionInfo *funcInfo = function->GetFunctionInfo();
  332. TTD_XSITE_LOG(callable->GetScriptContext(), "DefaultOrProfileThunk", callable);
  333. #ifdef ENABLE_WASM
  334. if (VarIs<WasmScriptFunction>(function))
  335. {
  336. entryPoint = Js::AsmJsExternalEntryPoint;
  337. } else
  338. #endif
  339. if (funcInfo->HasBody())
  340. {
  341. #if ENABLE_DEBUG_CONFIG_OPTIONS
  342. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  343. #endif
  344. entryPoint = VarTo<ScriptFunction>(function)->GetEntryPointInfo()->jsMethod;
  345. if (funcInfo->IsDeferred() && scriptContext->IsProfiling())
  346. {
  347. // if the current entrypoint is deferred parse we need to update it appropriately for the profiler mode.
  348. entryPoint = Js::ScriptContext::GetProfileModeThunk(entryPoint);
  349. }
  350. OUTPUT_TRACE(Js::ScriptProfilerPhase, _u("CrossSite::ProfileThunk FunctionNumber : %s, Entrypoint : 0x%08X\n"), funcInfo->GetFunctionProxy()->GetDebugNumberSet(debugStringBuffer), entryPoint);
  351. }
  352. else
  353. {
  354. entryPoint = ProfileEntryThunk;
  355. }
  356. return CommonThunk(function, entryPoint, args);
  357. }
  358. #endif
  359. Var CrossSite::DefaultThunk(RecyclableObject* callable, CallInfo callInfo, ...)
  360. {
  361. JavascriptFunction* function = VarTo<JavascriptFunction>(callable);
  362. Assert(function->GetTypeId() == TypeIds_Function);
  363. Assert(function->GetEntryPoint() == CrossSite::DefaultThunk);
  364. RUNTIME_ARGUMENTS(args, callInfo);
  365. // It is not safe to access the function body if the script context is not alive.
  366. function->GetScriptContext()->VerifyAliveWithHostContext(!function->IsExternal(),
  367. ThreadContext::GetContextForCurrentThread()->GetPreviousHostScriptContext());
  368. JavascriptMethod entryPoint;
  369. FunctionInfo *funcInfo = function->GetFunctionInfo();
  370. TTD_XSITE_LOG(callable->GetScriptContext(), "DefaultOrProfileThunk", callable);
  371. if (funcInfo->HasBody())
  372. {
  373. #ifdef ASMJS_PLAT
  374. if (funcInfo->GetFunctionProxy()->IsFunctionBody() &&
  375. funcInfo->GetFunctionBody()->GetIsAsmJsFunction())
  376. {
  377. entryPoint = Js::AsmJsExternalEntryPoint;
  378. }
  379. else
  380. #endif
  381. {
  382. entryPoint = VarTo<ScriptFunction>(function)->GetEntryPointInfo()->jsMethod;
  383. }
  384. }
  385. else
  386. {
  387. entryPoint = funcInfo->GetOriginalEntryPoint();
  388. }
  389. return CommonThunk(function, entryPoint, args);
  390. }
  391. Var CrossSite::CrossSiteProxyCallTrap(RecyclableObject* function, CallInfo callInfo, ...)
  392. {
  393. RUNTIME_ARGUMENTS(args, callInfo);
  394. Assert(VarIs<JavascriptProxy>(function));
  395. return CrossSite::CommonThunk(function, JavascriptProxy::FunctionCallTrap, args);
  396. }
  397. Var CrossSite::CommonThunk(RecyclableObject* recyclableObject, JavascriptMethod entryPoint, Arguments args)
  398. {
  399. DynamicObject* function = VarTo<DynamicObject>(recyclableObject);
  400. FunctionInfo * functionInfo = (VarIs<JavascriptFunction>(function) ? VarTo<JavascriptFunction>(function)->GetFunctionInfo() : nullptr);
  401. AutoDisableRedeferral autoDisableRedeferral(functionInfo);
  402. ScriptContext* targetScriptContext = function->GetScriptContext();
  403. Assert(!targetScriptContext->IsClosed());
  404. Assert(function->IsExternal() || function->IsCrossSiteObject());
  405. Assert(targetScriptContext->GetThreadContext()->IsScriptActive());
  406. HostScriptContext* calleeHostScriptContext = targetScriptContext->GetHostScriptContext();
  407. HostScriptContext* callerHostScriptContext = targetScriptContext->GetThreadContext()->GetPreviousHostScriptContext();
  408. if (callerHostScriptContext == calleeHostScriptContext || (callerHostScriptContext == nullptr && !calleeHostScriptContext->HasCaller()))
  409. {
  410. BEGIN_SAFE_REENTRANT_CALL(targetScriptContext->GetThreadContext())
  411. {
  412. return JavascriptFunction::CallFunction<true>(function, entryPoint, args, true /*useLargeArgCount*/);
  413. }
  414. END_SAFE_REENTRANT_CALL
  415. }
  416. #if DBG_DUMP || defined(PROFILE_EXEC) || defined(PROFILE_MEM)
  417. calleeHostScriptContext->EnsureParentInfo(callerHostScriptContext->GetScriptContext());
  418. #endif
  419. TTD_XSITE_LOG(recyclableObject->GetScriptContext(), "CommonThunk -- Pass Through", recyclableObject);
  420. uint i = 0;
  421. if (args.Values[0] == nullptr)
  422. {
  423. i = 1;
  424. Assert(args.IsNewCall());
  425. Assert(VarIs<JavascriptProxy>(function) || (VarIs<JavascriptFunction>(function) && VarTo<JavascriptFunction>(function)->GetFunctionInfo()->GetAttributes() & FunctionInfo::SkipDefaultNewObject));
  426. }
  427. uint count = args.Info.Count;
  428. for (; i < count; i++)
  429. {
  430. args.Values[i] = CrossSite::MarshalVar(targetScriptContext, args.Values[i]);
  431. }
  432. if (args.HasNewTarget())
  433. {
  434. // Last value is new.target
  435. args.Values[count] = CrossSite::MarshalVar(targetScriptContext, args.GetNewTarget());
  436. }
  437. else if (args.HasExtraArg())
  438. {
  439. // The final eval arg is a frame display that needs to be marshaled specially.
  440. args.Values[count] = CrossSite::MarshalFrameDisplay(targetScriptContext, args.GetFrameDisplay());
  441. }
  442. #if ENABLE_NATIVE_CODEGEN
  443. CheckCodeGenFunction checkCodeGenFunction = GetCheckCodeGenFunction(entryPoint);
  444. if (checkCodeGenFunction != nullptr)
  445. {
  446. ScriptFunction* callFunc = VarTo<ScriptFunction>(function);
  447. entryPoint = checkCodeGenFunction(callFunc);
  448. Assert(CrossSite::IsThunk(function->GetEntryPoint()));
  449. }
  450. #endif
  451. // We need to setup the caller chain when we go across script site boundary. Property access
  452. // is OK, and we need to let host know who the caller is when a call is from another script site.
  453. // CrossSiteObject is the natural place but it is in the target site. We build up the site
  454. // chain through PushDispatchExCaller/PopDispatchExCaller, and we call SetCaller in the target site
  455. // to indicate who the caller is. We first need to get the site from the previously pushed site
  456. // and set that as the caller for current call, and push a new DispatchExCaller for future calls
  457. // off this site. GetDispatchExCaller and ReleaseDispatchExCaller is used to get the current caller.
  458. // currentDispatchExCaller is cached to avoid multiple allocations.
  459. IUnknown* sourceCaller = nullptr, *previousSourceCaller = nullptr;
  460. HRESULT hr = NOERROR;
  461. Var result = nullptr;
  462. BOOL wasDispatchExCallerPushed = FALSE, wasCallerSet = FALSE;
  463. TryFinally([&]()
  464. {
  465. hr = callerHostScriptContext->GetDispatchExCaller((void**)&sourceCaller);
  466. if (SUCCEEDED(hr))
  467. {
  468. hr = calleeHostScriptContext->SetCaller((IUnknown*)sourceCaller, (IUnknown**)&previousSourceCaller);
  469. }
  470. if (SUCCEEDED(hr))
  471. {
  472. wasCallerSet = TRUE;
  473. hr = calleeHostScriptContext->PushHostScriptContext();
  474. }
  475. if (FAILED(hr))
  476. {
  477. // CONSIDER: Should this be callerScriptContext if we failed?
  478. JavascriptError::MapAndThrowError(targetScriptContext, hr);
  479. }
  480. wasDispatchExCallerPushed = TRUE;
  481. BEGIN_SAFE_REENTRANT_CALL(targetScriptContext->GetThreadContext())
  482. {
  483. result = JavascriptFunction::CallFunction<true>(function, entryPoint, args, true /*useLargeArgCount*/);
  484. }
  485. END_SAFE_REENTRANT_CALL
  486. ScriptContext* callerScriptContext = callerHostScriptContext->GetScriptContext();
  487. result = CrossSite::MarshalVar(callerScriptContext, result);
  488. },
  489. [&](bool hasException)
  490. {
  491. if (sourceCaller != nullptr)
  492. {
  493. callerHostScriptContext->ReleaseDispatchExCaller(sourceCaller);
  494. }
  495. IUnknown* originalCaller = nullptr;
  496. if (wasDispatchExCallerPushed)
  497. {
  498. calleeHostScriptContext->PopHostScriptContext();
  499. }
  500. if (wasCallerSet)
  501. {
  502. calleeHostScriptContext->SetCaller(previousSourceCaller, &originalCaller);
  503. if (previousSourceCaller)
  504. {
  505. previousSourceCaller->Release();
  506. }
  507. if (originalCaller)
  508. {
  509. originalCaller->Release();
  510. }
  511. }
  512. });
  513. Assert(result != nullptr);
  514. return result;
  515. }
  516. // For prototype chain to install cross-site thunk.
  517. // When we change prototype using __proto__, those prototypes might not have cross-site thunks
  518. // installed even though the CEO is accessed from a different context. During ChangePrototype time
  519. // we don't really know where the requestContext is.
  520. // Force installing cross-site thunk for all prototype changes. It's a relatively less frequently used
  521. // scenario.
  522. void CrossSite::ForceCrossSiteThunkOnPrototypeChain(RecyclableObject* object)
  523. {
  524. if (TaggedNumber::Is(object))
  525. {
  526. return;
  527. }
  528. while (DynamicType::Is(object->GetTypeId()) && !VarIs<JavascriptProxy>(object))
  529. {
  530. DynamicObject* dynamicObject = UnsafeVarTo<DynamicObject>(object);
  531. if (!dynamicObject->IsCrossSiteObject() && !dynamicObject->IsExternal())
  532. {
  533. // force to install cross-site thunk on prototype objects.
  534. dynamicObject->MarshalToScriptContext(nullptr);
  535. }
  536. object = object->GetPrototype();
  537. }
  538. return;
  539. }
  540. };