aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2009-11-03 19:11:09 +0000
committerJustin Clark-Casey (justincc)2009-11-03 19:11:09 +0000
commitaf0e5d097480de264e7501e7d5d35328be5640bb (patch)
tree4ca5cd796ed9618dc9134a6e5eee1f7e7912bee4 /OpenSim/Region/ScriptEngine
parentminor: remove some mono compiler warnings (diff)
parentFixed a couple of NREs in corner cases. (diff)
downloadopensim-SC-af0e5d097480de264e7501e7d5d35328be5640bb.zip
opensim-SC-af0e5d097480de264e7501e7d5d35328be5640bb.tar.gz
opensim-SC-af0e5d097480de264e7501e7d5d35328be5640bb.tar.bz2
opensim-SC-af0e5d097480de264e7501e7d5d35328be5640bb.tar.xz
Merge branch 'master' of ssh://justincc@opensimulator.org/var/git/opensim
Diffstat (limited to 'OpenSim/Region/ScriptEngine')
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs5
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs191
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs54
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs118
6 files changed, 182 insertions, 192 deletions
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs b/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs
index f8af902..e4ca635 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs
@@ -34,9 +34,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
34{ 34{
35 public interface ICompiler 35 public interface ICompiler
36 { 36 {
37 object PerformScriptCompile(string source, string asset, UUID ownerID); 37 void PerformScriptCompile(string source, string asset, UUID ownerID, out string assembly, out Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap);
38 string[] GetWarnings(); 38 string[] GetWarnings();
39 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>
40 LineMap();
41 } 39 }
42} 40}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 3849558..0ea62d7 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -2163,7 +2163,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2163 public LSL_Vector llGetOmega() 2163 public LSL_Vector llGetOmega()
2164 { 2164 {
2165 m_host.AddScriptLPS(1); 2165 m_host.AddScriptLPS(1);
2166 return new LSL_Vector(m_host.RotationalVelocity.X, m_host.RotationalVelocity.Y, m_host.RotationalVelocity.Z); 2166 return new LSL_Vector(m_host.AngularVelocity.X, m_host.AngularVelocity.Y, m_host.AngularVelocity.Z);
2167 } 2167 }
2168 2168
2169 public LSL_Float llGetTimeOfDay() 2169 public LSL_Float llGetTimeOfDay()
@@ -3159,7 +3159,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3159 public void llTargetOmega(LSL_Vector axis, double spinrate, double gain) 3159 public void llTargetOmega(LSL_Vector axis, double spinrate, double gain)
3160 { 3160 {
3161 m_host.AddScriptLPS(1); 3161 m_host.AddScriptLPS(1);
3162 m_host.RotationalVelocity = new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate));
3163 m_host.AngularVelocity = new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate)); 3162 m_host.AngularVelocity = new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate));
3164 m_host.ScheduleTerseUpdate(); 3163 m_host.ScheduleTerseUpdate();
3165 m_host.SendTerseUpdateToAllClients(); 3164 m_host.SendTerseUpdateToAllClients();
@@ -3817,7 +3816,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3817 { 3816 {
3818 case 1: // DATA_ONLINE (0|1) 3817 case 1: // DATA_ONLINE (0|1)
3819 // TODO: implement fetching of this information 3818 // TODO: implement fetching of this information
3820 if (userProfile.CurrentAgent.AgentOnline) 3819 if (userProfile.CurrentAgent!=null && userProfile.CurrentAgent.AgentOnline)
3821 reply = "1"; 3820 reply = "1";
3822 else 3821 else
3823 reply = "0"; 3822 reply = "0";
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs
index 917ca44..121159c 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs
@@ -113,7 +113,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
113 return; 113 return;
114 114
115 //ILease lease = (ILease)RemotingServices.GetLifetimeService(data as MarshalByRefObject); 115 //ILease lease = (ILease)RemotingServices.GetLifetimeService(data as MarshalByRefObject);
116 RemotingServices.GetLifetimeService(data as MarshalByRefObject); 116 //RemotingServices.GetLifetimeService(data as MarshalByRefObject);
117// lease.Register(m_sponser); 117// lease.Register(m_sponser);
118 118
119 MethodInfo mi = inits[api]; 119 MethodInfo mi = inits[api];
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs
index fe26429..3080c71 100644
--- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs
@@ -74,7 +74,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
74 private string FilePrefix; 74 private string FilePrefix;
75 private string ScriptEnginesPath = "ScriptEngines"; 75 private string ScriptEnginesPath = "ScriptEngines";
76 // mapping between LSL and C# line/column numbers 76 // mapping between LSL and C# line/column numbers
77 private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> m_positionMap;
78 private ICodeConverter LSL_Converter; 77 private ICodeConverter LSL_Converter;
79 78
80 private List<string> m_warnings = new List<string>(); 79 private List<string> m_warnings = new List<string>();
@@ -91,6 +90,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
91 private static UInt64 scriptCompileCounter = 0; // And a counter 90 private static UInt64 scriptCompileCounter = 0; // And a counter
92 91
93 public IScriptEngine m_scriptEngine; 92 public IScriptEngine m_scriptEngine;
93 private Dictionary<string, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>> m_lineMaps =
94 new Dictionary<string, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>>();
95
94 public Compiler(IScriptEngine scriptEngine) 96 public Compiler(IScriptEngine scriptEngine)
95 { 97 {
96 m_scriptEngine = scriptEngine; 98 m_scriptEngine = scriptEngine;
@@ -172,8 +174,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
172 else 174 else
173 { 175 {
174#if DEBUG 176#if DEBUG
175// m_log.Debug("[Compiler]: " + 177 // m_log.Debug("[Compiler]: " +
176// "Config OK. Default language \"" + defaultCompileLanguage + "\" specified in \"DefaultCompileLanguage\" is recognized as a valid language."); 178 // "Config OK. Default language \"" + defaultCompileLanguage + "\" specified in \"DefaultCompileLanguage\" is recognized as a valid language.");
177#endif 179#endif
178 // LANGUAGE IS IN ALLOW-LIST 180 // LANGUAGE IS IN ALLOW-LIST
179 DefaultCompileLanguage = LanguageMapping[defaultCompileLanguage]; 181 DefaultCompileLanguage = LanguageMapping[defaultCompileLanguage];
@@ -212,12 +214,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
212 catch (Exception ex) 214 catch (Exception ex)
213 { 215 {
214 m_log.Error("[Compiler]: Exception trying to create ScriptEngine directory \"" + Path.Combine(ScriptEnginesPath, 216 m_log.Error("[Compiler]: Exception trying to create ScriptEngine directory \"" + Path.Combine(ScriptEnginesPath,
215 m_scriptEngine.World.RegionInfo.RegionID.ToString())+ "\": " + ex.ToString()); 217 m_scriptEngine.World.RegionInfo.RegionID.ToString()) + "\": " + ex.ToString());
216 } 218 }
217 } 219 }
218 220
219 foreach (string file in Directory.GetFiles(Path.Combine(ScriptEnginesPath, 221 foreach (string file in Directory.GetFiles(Path.Combine(ScriptEnginesPath,
220 m_scriptEngine.World.RegionInfo.RegionID.ToString()),FilePrefix + "_compiled*")) 222 m_scriptEngine.World.RegionInfo.RegionID.ToString()), FilePrefix + "_compiled*"))
221 { 223 {
222 try 224 try
223 { 225 {
@@ -271,16 +273,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
271 /// </summary> 273 /// </summary>
272 /// <param name="Script">LSL script</param> 274 /// <param name="Script">LSL script</param>
273 /// <returns>Filename to .dll assembly</returns> 275 /// <returns>Filename to .dll assembly</returns>
274 public object PerformScriptCompile(string Script, string asset, UUID ownerUUID) 276 public void PerformScriptCompile(string Script, string asset, UUID ownerUUID,
277 out string assembly, out Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap)
275 { 278 {
276 m_positionMap = null; 279 linemap = null;
277 m_warnings.Clear(); 280 m_warnings.Clear();
278 281
279 string OutFile = Path.Combine(ScriptEnginesPath, Path.Combine( 282 assembly = Path.Combine(ScriptEnginesPath, Path.Combine(
280 m_scriptEngine.World.RegionInfo.RegionID.ToString(), 283 m_scriptEngine.World.RegionInfo.RegionID.ToString(),
281 FilePrefix + "_compiled_" + asset + ".dll")); 284 FilePrefix + "_compiled_" + asset + ".dll"));
282// string OutFile = Path.Combine(ScriptEnginesPath,
283// FilePrefix + "_compiled_" + asset + ".dll");
284 285
285 if (!Directory.Exists(ScriptEnginesPath)) 286 if (!Directory.Exists(ScriptEnginesPath))
286 { 287 {
@@ -305,60 +306,63 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
305 } 306 }
306 } 307 }
307 308
308 if (Script == String.Empty) 309 // Don't recompile if we already have it
310 // Performing 3 file exists tests for every script can still be slow
311 if (File.Exists(assembly) && File.Exists(assembly + ".text") && File.Exists(assembly + ".map"))
309 { 312 {
310 if (File.Exists(OutFile)) 313 // If we have already read this linemap file, then it will be in our dictionary.
311 return OutFile; 314 // Don't build another copy of the dictionary (saves memory) and certainly
312 315 // don't keep reading the same file from disk multiple times.
313 throw new Exception("Cannot find script assembly and no script text present"); 316 if (!m_lineMaps.ContainsKey(assembly))
317 m_lineMaps[assembly] = ReadMapFile(assembly + ".map");
318 linemap = m_lineMaps[assembly];
319 return;
314 } 320 }
315 321
316 // Don't recompile if we already have it 322 if (Script == String.Empty)
317 //
318 if (File.Exists(OutFile) && File.Exists(OutFile+".text") && File.Exists(OutFile+".map"))
319 { 323 {
320 ReadMapFile(OutFile+".map"); 324 throw new Exception("Cannot find script assembly and no script text present");
321 return OutFile;
322 } 325 }
323 326
324 enumCompileType l = DefaultCompileLanguage; 327 enumCompileType language = DefaultCompileLanguage;
325 328
326 if (Script.StartsWith("//c#", true, CultureInfo.InvariantCulture)) 329 if (Script.StartsWith("//c#", true, CultureInfo.InvariantCulture))
327 l = enumCompileType.cs; 330 language = enumCompileType.cs;
328 if (Script.StartsWith("//vb", true, CultureInfo.InvariantCulture)) 331 if (Script.StartsWith("//vb", true, CultureInfo.InvariantCulture))
329 { 332 {
330 l = enumCompileType.vb; 333 language = enumCompileType.vb;
331 // We need to remove //vb, it won't compile with that 334 // We need to remove //vb, it won't compile with that
332 335
333 Script = Script.Substring(4, Script.Length - 4); 336 Script = Script.Substring(4, Script.Length - 4);
334 } 337 }
335 if (Script.StartsWith("//lsl", true, CultureInfo.InvariantCulture)) 338 if (Script.StartsWith("//lsl", true, CultureInfo.InvariantCulture))
336 l = enumCompileType.lsl; 339 language = enumCompileType.lsl;
337 340
338 if (Script.StartsWith("//js", true, CultureInfo.InvariantCulture)) 341 if (Script.StartsWith("//js", true, CultureInfo.InvariantCulture))
339 l = enumCompileType.js; 342 language = enumCompileType.js;
340 343
341 if (Script.StartsWith("//yp", true, CultureInfo.InvariantCulture)) 344 if (Script.StartsWith("//yp", true, CultureInfo.InvariantCulture))
342 l = enumCompileType.yp; 345 language = enumCompileType.yp;
343 346
344 if (!AllowedCompilers.ContainsKey(l.ToString())) 347 if (!AllowedCompilers.ContainsKey(language.ToString()))
345 { 348 {
346 // Not allowed to compile to this language! 349 // Not allowed to compile to this language!
347 string errtext = String.Empty; 350 string errtext = String.Empty;
348 errtext += "The compiler for language \"" + l.ToString() + "\" is not in list of allowed compilers. Script will not be executed!"; 351 errtext += "The compiler for language \"" + language.ToString() + "\" is not in list of allowed compilers. Script will not be executed!";
349 throw new Exception(errtext); 352 throw new Exception(errtext);
350 } 353 }
351 354
352 if (m_scriptEngine.World.Permissions.CanCompileScript(ownerUUID, (int)l) == false) { 355 if (m_scriptEngine.World.Permissions.CanCompileScript(ownerUUID, (int)language) == false)
356 {
353 // Not allowed to compile to this language! 357 // Not allowed to compile to this language!
354 string errtext = String.Empty; 358 string errtext = String.Empty;
355 errtext += ownerUUID + " is not in list of allowed users for this scripting language. Script will not be executed!"; 359 errtext += ownerUUID + " is not in list of allowed users for this scripting language. Script will not be executed!";
356 throw new Exception(errtext); 360 throw new Exception(errtext);
357 } 361 }
358 362
359 string compileScript = Script; 363 string compileScript = Script;
360 364
361 if (l == enumCompileType.lsl) 365 if (language == enumCompileType.lsl)
362 { 366 {
363 // Its LSL, convert it to C# 367 // Its LSL, convert it to C#
364 LSL_Converter = (ICodeConverter)new CSCodeGenerator(); 368 LSL_Converter = (ICodeConverter)new CSCodeGenerator();
@@ -370,16 +374,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
370 AddWarning(warning); 374 AddWarning(warning);
371 } 375 }
372 376
373 m_positionMap = ((CSCodeGenerator) LSL_Converter).PositionMap; 377 linemap = ((CSCodeGenerator)LSL_Converter).PositionMap;
378 // Write the linemap to a file and save it in our dictionary for next time.
379 m_lineMaps[assembly] = linemap;
380 WriteMapFile(assembly + ".map", linemap);
374 } 381 }
375 382
376 if (l == enumCompileType.yp) 383 if (language == enumCompileType.yp)
377 { 384 {
378 // Its YP, convert it to C# 385 // Its YP, convert it to C#
379 compileScript = YP_Converter.Convert(Script); 386 compileScript = YP_Converter.Convert(Script);
380 } 387 }
381 388
382 switch (l) 389 switch (language)
383 { 390 {
384 case enumCompileType.cs: 391 case enumCompileType.cs:
385 case enumCompileType.lsl: 392 case enumCompileType.lsl:
@@ -396,7 +403,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
396 break; 403 break;
397 } 404 }
398 405
399 return CompileFromDotNetText(compileScript, l, asset); 406 assembly = CompileFromDotNetText(compileScript, language, asset, assembly);
407 return;
400 } 408 }
401 409
402 public string[] GetWarnings() 410 public string[] GetWarnings()
@@ -468,22 +476,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
468 /// </summary> 476 /// </summary>
469 /// <param name="Script">CS script</param> 477 /// <param name="Script">CS script</param>
470 /// <returns>Filename to .dll assembly</returns> 478 /// <returns>Filename to .dll assembly</returns>
471 internal string CompileFromDotNetText(string Script, enumCompileType lang, string asset) 479 internal string CompileFromDotNetText(string Script, enumCompileType lang, string asset, string assembly)
472 { 480 {
473 string ext = "." + lang.ToString(); 481 string ext = "." + lang.ToString();
474 482
475 // Output assembly name 483 // Output assembly name
476 scriptCompileCounter++; 484 scriptCompileCounter++;
477 string OutFile = Path.Combine(ScriptEnginesPath, Path.Combine(
478 m_scriptEngine.World.RegionInfo.RegionID.ToString(),
479 FilePrefix + "_compiled_" + asset + ".dll"));
480 try 485 try
481 { 486 {
482 File.Delete(OutFile); 487 File.Delete(assembly);
483 } 488 }
484 catch (Exception e) // NOTLEGIT - Should be just FileIOException 489 catch (Exception e) // NOTLEGIT - Should be just FileIOException
485 { 490 {
486 throw new Exception("Unable to delete old existing "+ 491 throw new Exception("Unable to delete old existing " +
487 "script-file before writing new. Compile aborted: " + 492 "script-file before writing new. Compile aborted: " +
488 e.ToString()); 493 e.ToString());
489 } 494 }
@@ -492,7 +497,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
492 if (WriteScriptSourceToDebugFile) 497 if (WriteScriptSourceToDebugFile)
493 { 498 {
494 string srcFileName = FilePrefix + "_source_" + 499 string srcFileName = FilePrefix + "_source_" +
495 Path.GetFileNameWithoutExtension(OutFile) + ext; 500 Path.GetFileNameWithoutExtension(assembly) + ext;
496 try 501 try
497 { 502 {
498 File.WriteAllText(Path.Combine(Path.Combine( 503 File.WriteAllText(Path.Combine(Path.Combine(
@@ -502,7 +507,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
502 } 507 }
503 catch (Exception ex) //NOTLEGIT - Should be just FileIOException 508 catch (Exception ex) //NOTLEGIT - Should be just FileIOException
504 { 509 {
505 m_log.Error("[Compiler]: Exception while "+ 510 m_log.Error("[Compiler]: Exception while " +
506 "trying to write script source to file \"" + 511 "trying to write script source to file \"" +
507 srcFileName + "\": " + ex.ToString()); 512 srcFileName + "\": " + ex.ToString());
508 } 513 }
@@ -528,7 +533,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
528 } 533 }
529 534
530 parameters.GenerateExecutable = false; 535 parameters.GenerateExecutable = false;
531 parameters.OutputAssembly = OutFile; 536 parameters.OutputAssembly = assembly;
532 parameters.IncludeDebugInformation = CompileWithDebugInformation; 537 parameters.IncludeDebugInformation = CompileWithDebugInformation;
533 //parameters.WarningLevel = 1; // Should be 4? 538 //parameters.WarningLevel = 1; // Should be 4?
534 parameters.TreatWarningsAsErrors = false; 539 parameters.TreatWarningsAsErrors = false;
@@ -543,7 +548,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
543 case enumCompileType.cs: 548 case enumCompileType.cs:
544 case enumCompileType.lsl: 549 case enumCompileType.lsl:
545 bool complete = false; 550 bool complete = false;
546 bool retried = false; 551 bool retried = false;
547 do 552 do
548 { 553 {
549 lock (CScodeProvider) 554 lock (CScodeProvider)
@@ -584,7 +589,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
584 parameters, Script); 589 parameters, Script);
585 break; 590 break;
586 default: 591 default:
587 throw new Exception("Compiler is not able to recongnize "+ 592 throw new Exception("Compiler is not able to recongnize " +
588 "language type \"" + lang.ToString() + "\""); 593 "language type \"" + lang.ToString() + "\"");
589 } 594 }
590 595
@@ -609,7 +614,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
609 614
610 if (severity == "Error") 615 if (severity == "Error")
611 { 616 {
612 lslPos = FindErrorPosition(CompErr.Line, CompErr.Column); 617 lslPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]);
613 string text = CompErr.ErrorText; 618 string text = CompErr.ErrorText;
614 619
615 // Use LSL type names 620 // Use LSL type names
@@ -635,14 +640,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
635 // the compile may not be immediately apparent. Wait a 640 // the compile may not be immediately apparent. Wait a
636 // reasonable amount of time before giving up on it. 641 // reasonable amount of time before giving up on it.
637 642
638 if (!File.Exists(OutFile)) 643 if (!File.Exists(assembly))
639 { 644 {
640 for (int i=0; i<20 && !File.Exists(OutFile); i++) 645 for (int i = 0; i < 20 && !File.Exists(assembly); i++)
641 { 646 {
642 System.Threading.Thread.Sleep(250); 647 System.Threading.Thread.Sleep(250);
643 } 648 }
644 // One final chance... 649 // One final chance...
645 if (!File.Exists(OutFile)) 650 if (!File.Exists(assembly))
646 { 651 {
647 errtext = String.Empty; 652 errtext = String.Empty;
648 errtext += "No compile error. But not able to locate compiled file."; 653 errtext += "No compile error. But not able to locate compiled file.";
@@ -650,15 +655,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
650 } 655 }
651 } 656 }
652 657
653// m_log.DebugFormat("[Compiler] Compiled new assembly "+ 658 // m_log.DebugFormat("[Compiler] Compiled new assembly "+
654// "for {0}", asset); 659 // "for {0}", asset);
655 660
656 // Because windows likes to perform exclusive locks, we simply 661 // Because windows likes to perform exclusive locks, we simply
657 // write out a textual representation of the file here 662 // write out a textual representation of the file here
658 // 663 //
659 // Read the binary file into a buffer 664 // Read the binary file into a buffer
660 // 665 //
661 FileInfo fi = new FileInfo(OutFile); 666 FileInfo fi = new FileInfo(assembly);
662 667
663 if (fi == null) 668 if (fi == null)
664 { 669 {
@@ -671,7 +676,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
671 676
672 try 677 try
673 { 678 {
674 FileStream fs = File.Open(OutFile, FileMode.Open, FileAccess.Read); 679 FileStream fs = File.Open(assembly, FileMode.Open, FileAccess.Read);
675 fs.Read(data, 0, data.Length); 680 fs.Read(data, 0, data.Length);
676 fs.Close(); 681 fs.Close();
677 } 682 }
@@ -690,40 +695,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
690 695
691 Byte[] buf = enc.GetBytes(filetext); 696 Byte[] buf = enc.GetBytes(filetext);
692 697
693 FileStream sfs = File.Create(OutFile+".text"); 698 FileStream sfs = File.Create(assembly + ".text");
694 sfs.Write(buf, 0, buf.Length); 699 sfs.Write(buf, 0, buf.Length);
695 sfs.Close(); 700 sfs.Close();
696 701
697 string posmap = String.Empty; 702 return assembly;
698 if (m_positionMap != null)
699 {
700 foreach (KeyValuePair<KeyValuePair<int, int>, KeyValuePair<int, int>> kvp in m_positionMap)
701 {
702 KeyValuePair<int, int> k = kvp.Key;
703 KeyValuePair<int, int> v = kvp.Value;
704 posmap += String.Format("{0},{1},{2},{3}\n",
705 k.Key, k.Value, v.Key, v.Value);
706 }
707 }
708
709 buf = enc.GetBytes(posmap);
710
711 FileStream mfs = File.Create(OutFile+".map");
712 mfs.Write(buf, 0, buf.Length);
713 mfs.Close();
714
715 return OutFile;
716 }
717
718 public KeyValuePair<int, int> FindErrorPosition(int line, int col)
719 {
720 return FindErrorPosition(line, col, m_positionMap);
721 } 703 }
722 704
723 private class kvpSorter : IComparer<KeyValuePair<int,int>> 705 private class kvpSorter : IComparer<KeyValuePair<int, int>>
724 { 706 {
725 public int Compare(KeyValuePair<int,int> a, 707 public int Compare(KeyValuePair<int, int> a,
726 KeyValuePair<int,int> b) 708 KeyValuePair<int, int> b)
727 { 709 {
728 return a.Key.CompareTo(b.Key); 710 return a.Key.CompareTo(b.Key);
729 } 711 }
@@ -742,8 +724,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
742 out ret)) 724 out ret))
743 return ret; 725 return ret;
744 726
745 List<KeyValuePair<int,int>> sorted = 727 List<KeyValuePair<int, int>> sorted =
746 new List<KeyValuePair<int,int>>(positionMap.Keys); 728 new List<KeyValuePair<int, int>>(positionMap.Keys);
747 729
748 sorted.Sort(new kvpSorter()); 730 sorted.Sort(new kvpSorter());
749 731
@@ -791,32 +773,37 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
791 return message; 773 return message;
792 } 774 }
793 775
794 public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap() 776
777 private static void WriteMapFile(string filename, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap)
795 { 778 {
796 if (m_positionMap == null) 779 string mapstring = String.Empty;
797 return null; 780 foreach (KeyValuePair<KeyValuePair<int, int>, KeyValuePair<int, int>> kvp in linemap)
798 781 {
799 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> ret = 782 KeyValuePair<int, int> k = kvp.Key;
800 new Dictionary<KeyValuePair<int,int>, KeyValuePair<int, int>>(); 783 KeyValuePair<int, int> v = kvp.Value;
801 784 mapstring += String.Format("{0},{1},{2},{3}\n", k.Key, k.Value, v.Key, v.Value);
802 foreach (KeyValuePair<int, int> kvp in m_positionMap.Keys) 785 }
803 ret.Add(kvp, m_positionMap[kvp]); 786
804 787 System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
805 return ret; 788 Byte[] mapbytes = enc.GetBytes(mapstring);
789 FileStream mfs = File.Create(filename);
790 mfs.Write(mapbytes, 0, mapbytes.Length);
791 mfs.Close();
806 } 792 }
807 793
808 private void ReadMapFile(string filename) 794
795 private static Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> ReadMapFile(string filename)
809 { 796 {
797 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
810 try 798 try
811 { 799 {
812 StreamReader r = File.OpenText(filename); 800 StreamReader r = File.OpenText(filename);
801 linemap = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>();
813 802
814 m_positionMap = new Dictionary<KeyValuePair<int,int>, KeyValuePair<int, int>>();
815
816 string line; 803 string line;
817 while ((line = r.ReadLine()) != null) 804 while ((line = r.ReadLine()) != null)
818 { 805 {
819 String[] parts = line.Split(new Char[] {','}); 806 String[] parts = line.Split(new Char[] { ',' });
820 int kk = System.Convert.ToInt32(parts[0]); 807 int kk = System.Convert.ToInt32(parts[0]);
821 int kv = System.Convert.ToInt32(parts[1]); 808 int kv = System.Convert.ToInt32(parts[1]);
822 int vk = System.Convert.ToInt32(parts[2]); 809 int vk = System.Convert.ToInt32(parts[2]);
@@ -825,12 +812,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
825 KeyValuePair<int, int> k = new KeyValuePair<int, int>(kk, kv); 812 KeyValuePair<int, int> k = new KeyValuePair<int, int>(kk, kv);
826 KeyValuePair<int, int> v = new KeyValuePair<int, int>(vk, vv); 813 KeyValuePair<int, int> v = new KeyValuePair<int, int>(vk, vv);
827 814
828 m_positionMap[k] = v; 815 linemap[k] = v;
829 } 816 }
830 } 817 }
831 catch 818 catch
832 { 819 {
820 linemap = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>();
833 } 821 }
822 return linemap;
834 } 823 }
835 } 824 }
836} 825}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 2b858ec..549c038 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -74,27 +74,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
74 private string m_PrimName; 74 private string m_PrimName;
75 private string m_ScriptName; 75 private string m_ScriptName;
76 private string m_Assembly; 76 private string m_Assembly;
77 private int m_StartParam = 0; 77 private int m_StartParam;
78 private string m_CurrentEvent = String.Empty; 78 private string m_CurrentEvent = String.Empty;
79 private bool m_InSelfDelete = false; 79 private bool m_InSelfDelete;
80 private int m_MaxScriptQueue; 80 private int m_MaxScriptQueue;
81 private bool m_SaveState = true; 81 private bool m_SaveState = true;
82 private bool m_ShuttingDown = false; 82 private bool m_ShuttingDown;
83 private int m_ControlEventsInQueue = 0; 83 private int m_ControlEventsInQueue;
84 private int m_LastControlLevel = 0; 84 private int m_LastControlLevel;
85 private bool m_CollisionInQueue = false; 85 private bool m_CollisionInQueue;
86 private TaskInventoryItem m_thisScriptTask; 86 private TaskInventoryItem m_thisScriptTask;
87 // The following is for setting a minimum delay between events 87 // The following is for setting a minimum delay between events
88 private double m_minEventDelay = 0; 88 private double m_minEventDelay;
89 private long m_eventDelayTicks = 0; 89 private long m_eventDelayTicks;
90 private long m_nextEventTimeTicks = 0; 90 private long m_nextEventTimeTicks;
91 private bool m_startOnInit = true; 91 private bool m_startOnInit = true;
92 private UUID m_AttachedAvatar = UUID.Zero; 92 private UUID m_AttachedAvatar;
93 private StateSource m_stateSource; 93 private StateSource m_stateSource;
94 private bool m_postOnRez; 94 private bool m_postOnRez;
95 private bool m_startedFromSavedState = false; 95 private bool m_startedFromSavedState;
96 private string m_CurrentState = String.Empty; 96 private UUID m_CurrentStateHash;
97 private UUID m_RegionID = UUID.Zero; 97 private UUID m_RegionID;
98 98
99 private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> 99 private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>
100 m_LineMap; 100 m_LineMap;
@@ -252,16 +252,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
252 { 252 {
253 m_Apis[api] = am.CreateApi(api); 253 m_Apis[api] = am.CreateApi(api);
254 m_Apis[api].Initialize(engine, part, m_LocalID, itemID); 254 m_Apis[api].Initialize(engine, part, m_LocalID, itemID);
255 } 255 }
256
257 try
258 {
259 if (dom != System.AppDomain.CurrentDomain)
260 m_Script = (IScript)dom.CreateInstanceAndUnwrap(
261 Path.GetFileNameWithoutExtension(assembly),
262 "SecondLife.Script");
263 else
264 m_Script = (IScript)Assembly.Load(
265 Path.GetFileNameWithoutExtension(assembly)).CreateInstance(
266 "SecondLife.Script");
256 267
257 try
258 {
259 m_Script = (IScript)dom.CreateInstanceAndUnwrap(
260 Path.GetFileNameWithoutExtension(assembly),
261 "SecondLife.Script");
262 268
263 //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); 269 //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
264 RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); 270 //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
265// lease.Register(this); 271// lease.Register(this);
266 } 272 }
267 catch (Exception) 273 catch (Exception)
@@ -893,7 +899,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
893 899
894 string xml = ScriptSerializer.Serialize(this); 900 string xml = ScriptSerializer.Serialize(this);
895 901
896 if (m_CurrentState != xml) 902 // Compare hash of the state we just just created with the state last written to disk
903 // If the state is different, update the disk file.
904 UUID hash = UUID.Parse(Utils.MD5String(xml));
905
906 if(hash != m_CurrentStateHash)
897 { 907 {
898 try 908 try
899 { 909 {
@@ -911,7 +921,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
911 //{ 921 //{
912 // throw new Exception("Completed persistence save, but no file was created"); 922 // throw new Exception("Completed persistence save, but no file was created");
913 //} 923 //}
914 m_CurrentState = xml; 924 m_CurrentStateHash = hash;
915 } 925 }
916 } 926 }
917 927
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 7b19ce3..b0fce75 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -50,6 +50,9 @@ using OpenSim.Region.ScriptEngine.Shared.CodeTools;
50using OpenSim.Region.ScriptEngine.Shared.Instance; 50using OpenSim.Region.ScriptEngine.Shared.Instance;
51using OpenSim.Region.ScriptEngine.Interfaces; 51using OpenSim.Region.ScriptEngine.Interfaces;
52 52
53using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>;
54using Parallel = OpenSim.Framework.Parallel;
55
53namespace OpenSim.Region.ScriptEngine.XEngine 56namespace OpenSim.Region.ScriptEngine.XEngine
54{ 57{
55 public class XEngine : INonSharedRegionModule, IScriptModule, IScriptEngine 58 public class XEngine : INonSharedRegionModule, IScriptModule, IScriptEngine
@@ -73,9 +76,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
73 private bool m_InitialStartup = true; 76 private bool m_InitialStartup = true;
74 private int m_ScriptFailCount; // Number of script fails since compile queue was last empty 77 private int m_ScriptFailCount; // Number of script fails since compile queue was last empty
75 private string m_ScriptErrorMessage; 78 private string m_ScriptErrorMessage;
79 private Dictionary<string, string> m_uniqueScripts = new Dictionary<string, string>();
80 private bool m_AppDomainLoading;
76 81
77// disable warning: need to keep a reference to XEngine.EventManager 82 // disable warning: need to keep a reference to XEngine.EventManager
78// alive to avoid it being garbage collected 83 // alive to avoid it being garbage collected
79#pragma warning disable 414 84#pragma warning disable 414
80 private EventManager m_EventManager; 85 private EventManager m_EventManager;
81#pragma warning restore 414 86#pragma warning restore 414
@@ -114,7 +119,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
114 private Dictionary<UUID, List<UUID> > m_DomainScripts = 119 private Dictionary<UUID, List<UUID> > m_DomainScripts =
115 new Dictionary<UUID, List<UUID> >(); 120 new Dictionary<UUID, List<UUID> >();
116 121
117 private Queue m_CompileQueue = new Queue(100); 122 private ScriptCompileQueue m_CompileQueue = new ScriptCompileQueue();
118 IWorkItemResult m_CurrentCompile = null; 123 IWorkItemResult m_CurrentCompile = null;
119 124
120 public string ScriptEngineName 125 public string ScriptEngineName
@@ -201,6 +206,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
201 m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300); 206 m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300);
202 m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144); 207 m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144);
203 m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000; 208 m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000;
209 m_AppDomainLoading = m_ScriptConfig.GetBoolean("AppDomainLoading", true);
204 210
205 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); 211 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
206 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); 212 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
@@ -470,6 +476,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
470 if (engine != ScriptEngineName) 476 if (engine != ScriptEngineName)
471 return; 477 return;
472 478
479 // If we've seen this exact script text before, use that reference instead
480 if (m_uniqueScripts.ContainsKey(script))
481 script = m_uniqueScripts[script];
482 else
483 m_uniqueScripts[script] = script;
484
473 Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource}; 485 Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource};
474 486
475 if (stateSource == (int)StateSource.ScriptedRez) 487 if (stateSource == (int)StateSource.ScriptedRez)
@@ -478,16 +490,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
478 } 490 }
479 else 491 else
480 { 492 {
481 lock (m_CompileQueue) 493 m_CompileQueue.Enqueue(parms);
482 {
483 m_CompileQueue.Enqueue(parms);
484 494
485 if (m_CurrentCompile == null) 495 if (m_CurrentCompile == null)
486 { 496 {
487 m_CurrentCompile = m_ThreadPool.QueueWorkItem( 497 m_CurrentCompile = m_ThreadPool.QueueWorkItem(DoOnRezScriptQueue, null);
488 new WorkItemCallback(this.DoOnRezScriptQueue),
489 new Object[0]);
490 }
491 } 498 }
492 } 499 }
493 } 500 }
@@ -498,50 +505,35 @@ namespace OpenSim.Region.ScriptEngine.XEngine
498 { 505 {
499 m_InitialStartup = false; 506 m_InitialStartup = false;
500 System.Threading.Thread.Sleep(15000); 507 System.Threading.Thread.Sleep(15000);
501 lock (m_CompileQueue) 508
509 if (m_CompileQueue.Count == 0)
502 { 510 {
503 if (m_CompileQueue.Count==0) 511 // No scripts on region, so won't get triggered later
504 // No scripts on region, so won't get triggered later 512 // by the queue becoming empty so we trigger it here
505 // by the queue becoming empty so we trigger it here 513 m_Scene.EventManager.TriggerEmptyScriptCompileQueue(0, String.Empty);
506 m_Scene.EventManager.TriggerEmptyScriptCompileQueue(0, String.Empty);
507 } 514 }
508 } 515 }
509 516
510 Object o; 517 List<object[]> compiles = new List<object[]>();
511 lock (m_CompileQueue) 518 object[] o;
519 while (m_CompileQueue.Dequeue(out o))
512 { 520 {
513 o = m_CompileQueue.Dequeue(); 521 compiles.Add(o);
514 if (o == null)
515 {
516 m_CurrentCompile = null;
517 return null;
518 }
519 } 522 }
520 523
521 DoOnRezScript(o); 524 Parallel.For(0, compiles.Count, delegate(int i) { DoOnRezScript(compiles[i]); });
525
526 m_CurrentCompile = null;
527 m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount,
528 m_ScriptErrorMessage);
529 m_ScriptFailCount = 0;
522 530
523 lock (m_CompileQueue)
524 {
525 if (m_CompileQueue.Count > 0)
526 {
527 m_CurrentCompile = m_ThreadPool.QueueWorkItem(
528 new WorkItemCallback(this.DoOnRezScriptQueue),
529 new Object[0]);
530 }
531 else
532 {
533 m_CurrentCompile = null;
534 m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount,
535 m_ScriptErrorMessage);
536 m_ScriptFailCount = 0;
537 }
538 }
539 return null; 531 return null;
540 } 532 }
541 533
542 private bool DoOnRezScript(object parm) 534 private bool DoOnRezScript(object[] parms)
543 { 535 {
544 Object[] p = (Object[])parm; 536 Object[] p = parms;
545 uint localID = (uint)p[0]; 537 uint localID = (uint)p[0];
546 UUID itemID = (UUID)p[1]; 538 UUID itemID = (UUID)p[1];
547 string script =(string)p[2]; 539 string script =(string)p[2];
@@ -590,14 +582,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
590 { 582 {
591 lock (m_AddingAssemblies) 583 lock (m_AddingAssemblies)
592 { 584 {
593 assembly = (string)m_Compiler.PerformScriptCompile(script, 585 m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap);
594 assetID.ToString(), item.OwnerID);
595 if (!m_AddingAssemblies.ContainsKey(assembly)) { 586 if (!m_AddingAssemblies.ContainsKey(assembly)) {
596 m_AddingAssemblies[assembly] = 1; 587 m_AddingAssemblies[assembly] = 1;
597 } else { 588 } else {
598 m_AddingAssemblies[assembly]++; 589 m_AddingAssemblies[assembly]++;
599 } 590 }
600 linemap = m_Compiler.LineMap();
601 } 591 }
602 592
603 string[] warnings = m_Compiler.GetWarnings(); 593 string[] warnings = m_Compiler.GetWarnings();
@@ -696,19 +686,22 @@ namespace OpenSim.Region.ScriptEngine.XEngine
696 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence; 686 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
697 Evidence evidence = new Evidence(baseEvidence); 687 Evidence evidence = new Evidence(baseEvidence);
698 688
699 AppDomain sandbox = 689 AppDomain sandbox;
700 AppDomain.CreateDomain( 690 if (m_AppDomainLoading)
701 m_Scene.RegionInfo.RegionID.ToString(), 691 sandbox = AppDomain.CreateDomain(
702 evidence, appSetup); 692 m_Scene.RegionInfo.RegionID.ToString(),
703/* 693 evidence, appSetup);
704 PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); 694 else
705 AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); 695 sandbox = AppDomain.CurrentDomain;
706 PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet"); 696
707 PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet); 697 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel();
708 CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement); 698 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition();
709 sandboxPolicy.RootCodeGroup = sandboxCodeGroup; 699 //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet");
710 sandbox.SetAppDomainPolicy(sandboxPolicy); 700 //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet);
711*/ 701 //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement);
702 //sandboxPolicy.RootCodeGroup = sandboxCodeGroup;
703 //sandbox.SetAppDomainPolicy(sandboxPolicy);
704
712 m_AppDomains[appDomain] = sandbox; 705 m_AppDomains[appDomain] = sandbox;
713 706
714 m_AppDomains[appDomain].AssemblyResolve += 707 m_AppDomains[appDomain].AssemblyResolve +=
@@ -905,9 +898,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
905 AppDomain domain = m_AppDomains[id]; 898 AppDomain domain = m_AppDomains[id];
906 m_AppDomains.Remove(id); 899 m_AppDomains.Remove(id);
907 900
908 AppDomain.Unload(domain); 901 if (domain != AppDomain.CurrentDomain)
902 AppDomain.Unload(domain);
909 domain = null; 903 domain = null;
910// m_log.DebugFormat("[XEngine] Unloaded app domain {0}", id.ToString()); 904 // m_log.DebugFormat("[XEngine] Unloaded app domain {0}", id.ToString());
911 } 905 }
912 } 906 }
913 907