mirror of
https://github.com/SSCLI/sscli_20021101
synced 2026-06-08 12:28:57 +00:00
9fa3874800
Moved the original file to the archive subfolder.
1366 lines
56 KiB
C#
1366 lines
56 KiB
C#
// ==++==
|
|
//
|
|
//
|
|
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
|
|
//
|
|
// The use and distribution terms for this software are contained in the file
|
|
// named license.txt, which can be found in the root of this distribution.
|
|
// By using this software in any fashion, you are agreeing to be bound by the
|
|
// terms of this license.
|
|
//
|
|
// You must not remove this notice, or any other, from this software.
|
|
//
|
|
//
|
|
// ==--==
|
|
namespace Microsoft.JScript.Vsa
|
|
{
|
|
|
|
using Microsoft.JScript;
|
|
using Microsoft.Vsa;
|
|
using System;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using System.Globalization;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
using System.Resources;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Runtime.Remoting.Messaging;
|
|
|
|
public class VsaEngine : BaseVsaEngine, IRedirectOutput{
|
|
internal bool alwaysGenerateIL;
|
|
private bool autoRef;
|
|
private Hashtable Defines;
|
|
internal bool doCRS;
|
|
internal bool doFast;
|
|
internal bool doPrint;
|
|
internal bool doSaveAfterCompile;
|
|
private bool doWarnAsError;
|
|
private int nWarningLevel;
|
|
internal bool genStartupClass;
|
|
internal bool isCLSCompliant;
|
|
internal bool versionSafe;
|
|
private String PEFileName;
|
|
internal PEFileKinds PEFileKind;
|
|
private Version versionInfo;
|
|
|
|
private CultureInfo errorCultureInfo;
|
|
|
|
|
|
//In appdomain used to executing JScript debugger expression evaluator
|
|
static internal bool executeForJSEE = false;
|
|
|
|
private String libpath;
|
|
private String[] libpathList;
|
|
|
|
private bool isCompilerSet;
|
|
|
|
internal VsaScriptScope globalScope;
|
|
private ArrayList packages;
|
|
private ArrayList scopes;
|
|
private ArrayList implicitAssemblies;
|
|
private SimpleHashtable implicitAssemblyCache;
|
|
private ICollection managedResources;
|
|
private string debugDirectory;
|
|
private Random randomNumberGenerator;
|
|
private string cachedPEFileName;
|
|
internal int classCounter;
|
|
|
|
private SimpleHashtable cachedTypeLookups;
|
|
|
|
internal Thread runningThread;
|
|
private CompilerGlobals compilerGlobals;
|
|
private Globals globals;
|
|
|
|
// Used only during VsaEngine.Compile. It is reset at the beginning of the
|
|
// function. It is incremented as errors are reported via OnCompilerError.
|
|
private int numberOfErrors;
|
|
|
|
private String runtimeDirectory;
|
|
private static readonly Version CurrentProjectVersion = new Version("1.0");
|
|
|
|
private Hashtable typenameTable; // for checking CLS compliance
|
|
|
|
public VsaEngine()
|
|
:this(true){
|
|
}
|
|
|
|
public VsaEngine(bool fast) : base("JScript", "7.0.3300.0", true){
|
|
this.alwaysGenerateIL = false;
|
|
this.autoRef = false;
|
|
this.doCRS = false;
|
|
this.doFast = fast;
|
|
this.cachedPEFileName = "";
|
|
this.genDebugInfo = false;
|
|
this.genStartupClass = true;
|
|
this.doPrint = false;
|
|
this.doWarnAsError = false;
|
|
this.nWarningLevel = 4;
|
|
this.isCLSCompliant = false;
|
|
this.versionSafe = false;
|
|
this.PEFileName = null;
|
|
this.PEFileKind = PEFileKinds.Dll;
|
|
this.errorCultureInfo = null;
|
|
this.libpath = null;
|
|
this.libpathList = null;
|
|
|
|
this.globalScope = null;
|
|
this.vsaItems = new VsaItems(this);
|
|
this.packages = null;
|
|
this.scopes = null;
|
|
this.classCounter = 0;
|
|
this.implicitAssemblies = null;
|
|
this.implicitAssemblyCache = null;
|
|
this.cachedTypeLookups = null;
|
|
|
|
this.isEngineRunning = false;
|
|
this.isEngineCompiled = false;
|
|
this.isCompilerSet = false;
|
|
this.isClosed = false;
|
|
|
|
this.runningThread = null;
|
|
this.compilerGlobals = null;
|
|
this.globals = null;
|
|
this.runtimeDirectory = null;
|
|
Globals.contextEngine = this;
|
|
this.runtimeAssembly = null;
|
|
this.typenameTable = null;
|
|
}
|
|
|
|
private Assembly runtimeAssembly;
|
|
private static Hashtable assemblyReferencesTable = null;
|
|
// This constructor is called at run time to instantiate an engine for a given assembly
|
|
private VsaEngine(Assembly runtimeAssembly) : this(true){
|
|
this.runtimeAssembly = runtimeAssembly;
|
|
}
|
|
|
|
|
|
internal void AddPackage(PackageScope pscope){
|
|
if (this.packages == null)
|
|
this.packages = new ArrayList(8);
|
|
IEnumerator e = this.packages.GetEnumerator();
|
|
while (e.MoveNext()){
|
|
PackageScope cps = (PackageScope)e.Current;
|
|
if (cps.name.Equals(pscope.name)){
|
|
cps.owner.MergeWith(pscope.owner);
|
|
return;
|
|
}
|
|
}
|
|
this.packages.Add(pscope);
|
|
}
|
|
|
|
internal void CheckForErrors(){
|
|
if (!this.isClosed && !this.isEngineCompiled){
|
|
SetUpCompilerEnvironment();
|
|
Globals.ScopeStack.Push(this.GetGlobalScope().GetObject());
|
|
try{
|
|
foreach (Object item in this.vsaItems){
|
|
if (item is VsaReference)
|
|
((VsaReference)item).Compile(); //Load the assembly into memory.
|
|
}
|
|
if (this.vsaItems.Count > 0)
|
|
this.SetEnclosingContext(new WrappedNamespace("", this)); //Provide a way to find types that are not inside of a name space
|
|
foreach (Object item in this.vsaItems){
|
|
if (!(item is VsaReference))
|
|
((VsaItem)item).CheckForErrors();
|
|
}
|
|
if (null != this.globalScope)
|
|
this.globalScope.CheckForErrors(); //In case the host added items to the global scope.
|
|
}finally{
|
|
Globals.ScopeStack.Pop();
|
|
}
|
|
}
|
|
this.globalScope = null;
|
|
}
|
|
|
|
public virtual IVsaEngine Clone(AppDomain domain){
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public virtual bool CompileEmpty(){
|
|
this.TryObtainLock();
|
|
try{
|
|
return this.DoCompile();
|
|
}finally{
|
|
this.ReleaseLock();
|
|
}
|
|
}
|
|
|
|
|
|
public virtual void ConnectEvents(){
|
|
}
|
|
|
|
internal CompilerGlobals CompilerGlobals{
|
|
get{
|
|
if (this.compilerGlobals == null)
|
|
this.compilerGlobals = new CompilerGlobals(this.Name, this.PEFileName, this.PEFileKind,
|
|
this.doSaveAfterCompile || this.genStartupClass, !this.doSaveAfterCompile || this.genStartupClass, this.genDebugInfo, this.isCLSCompliant,
|
|
this.versionInfo, this.globals);
|
|
return this.compilerGlobals;
|
|
}
|
|
}
|
|
|
|
public static GlobalScope CreateEngineAndGetGlobalScope(bool fast, String[] assemblyNames){
|
|
VsaEngine engine = new VsaEngine(fast);
|
|
engine.InitVsaEngine("JScript.Vsa.VsaEngine://Microsoft.JScript.VsaEngine.Vsa", new DefaultVsaSite());
|
|
engine.doPrint = true;
|
|
engine.SetEnclosingContext(new WrappedNamespace("", engine));
|
|
foreach (String assemblyName in assemblyNames){
|
|
VsaReference r = (VsaReference)engine.vsaItems.CreateItem(assemblyName, VsaItemType.Reference, VsaItemFlag.None);
|
|
r.AssemblyName = assemblyName;
|
|
}
|
|
VsaEngine.exeEngine = engine;
|
|
GlobalScope scope = (GlobalScope)engine.GetGlobalScope().GetObject();
|
|
scope.globalObject = engine.Globals.globalObject;
|
|
return scope;
|
|
}
|
|
|
|
public static GlobalScope CreateEngineAndGetGlobalScopeWithType(bool fast, String[] assemblyNames, RuntimeTypeHandle callingTypeHandle){
|
|
VsaEngine engine = new VsaEngine(fast);
|
|
engine.InitVsaEngine("JScript.Vsa.VsaEngine://Microsoft.JScript.VsaEngine.Vsa", new DefaultVsaSite());
|
|
engine.doPrint = true;
|
|
engine.SetEnclosingContext(new WrappedNamespace("", engine));
|
|
foreach (String assemblyName in assemblyNames){
|
|
VsaReference r = (VsaReference)engine.vsaItems.CreateItem(assemblyName, VsaItemType.Reference, VsaItemFlag.None);
|
|
r.AssemblyName = assemblyName;
|
|
}
|
|
// Put the engine in the CallContext so that calls to CreateEngineWithType will return this engine
|
|
Type callingType = Type.GetTypeFromHandle(callingTypeHandle);
|
|
Assembly callingAssembly = callingType.Assembly;
|
|
System.Runtime.Remoting.Messaging.CallContext.SetData("JScript:" + callingAssembly.FullName, engine);
|
|
// Get and return the global scope
|
|
GlobalScope scope = (GlobalScope)engine.GetGlobalScope().GetObject();
|
|
scope.globalObject = engine.Globals.globalObject;
|
|
return scope;
|
|
}
|
|
|
|
private static volatile VsaEngine exeEngine; // Instance of VsaEngine used by JScript EXEs
|
|
|
|
// This factory method is called by EXE code only
|
|
public static VsaEngine CreateEngine(){
|
|
if (VsaEngine.exeEngine == null){
|
|
VsaEngine e = new VsaEngine(true);
|
|
e.InitVsaEngine("JScript.Vsa.VsaEngine://Microsoft.JScript.VsaEngine.Vsa", new DefaultVsaSite());
|
|
VsaEngine.exeEngine = e;
|
|
}
|
|
return VsaEngine.exeEngine;
|
|
}
|
|
|
|
internal static VsaEngine CreateEngineForDebugger(){
|
|
VsaEngine engine = new VsaEngine(true);
|
|
engine.InitVsaEngine("JScript.Vsa.VsaEngine://Microsoft.JScript.VsaEngine.Vsa", new DefaultVsaSite());
|
|
GlobalScope scope = (GlobalScope)engine.GetGlobalScope().GetObject();
|
|
scope.globalObject = engine.Globals.globalObject;
|
|
return engine;
|
|
}
|
|
|
|
// This factory method is called by DLL code only
|
|
public static VsaEngine CreateEngineWithType(RuntimeTypeHandle callingTypeHandle){
|
|
Type callingType = Type.GetTypeFromHandle(callingTypeHandle);
|
|
Assembly callingAssembly = callingType.Assembly;
|
|
Object o = System.Runtime.Remoting.Messaging.CallContext.GetData("JScript:" + callingAssembly.FullName);
|
|
if (o != null){
|
|
VsaEngine e = o as VsaEngine;
|
|
if (e != null)
|
|
return e;
|
|
}
|
|
|
|
VsaEngine engine = new VsaEngine(callingAssembly);
|
|
engine.InitVsaEngine("JScript.Vsa.VsaEngine://Microsoft.JScript.VsaEngine.Vsa", new DefaultVsaSite());
|
|
|
|
GlobalScope scope = (GlobalScope)engine.GetGlobalScope().GetObject();
|
|
scope.globalObject = engine.Globals.globalObject;
|
|
|
|
// for every global class generated in this assembly make an instance and call the global code method
|
|
int i = 0;
|
|
Type globalClassType = null;
|
|
do{
|
|
String globalClassName = "JScript " + i.ToString();
|
|
globalClassType = callingAssembly.GetType(globalClassName, false);
|
|
if (globalClassType != null){
|
|
engine.SetEnclosingContext(new WrappedNamespace("", engine));
|
|
ConstructorInfo globalScopeConstructor = globalClassType.GetConstructor(new Type[]{typeof(GlobalScope)});
|
|
MethodInfo globalCode = globalClassType.GetMethod("Global Code");
|
|
Object globalClassInstance = globalScopeConstructor.Invoke(new Object[]{scope});
|
|
globalCode.Invoke(globalClassInstance, new Object[0]);
|
|
}
|
|
i++;
|
|
}while (globalClassType != null);
|
|
|
|
if (o == null)
|
|
System.Runtime.Remoting.Messaging.CallContext.SetData("JScript:" + callingAssembly.FullName, engine);
|
|
return engine;
|
|
}
|
|
|
|
private void AddReferences(){
|
|
if (VsaEngine.assemblyReferencesTable == null) {
|
|
// Create the cache
|
|
Hashtable h = new Hashtable();
|
|
VsaEngine.assemblyReferencesTable = Hashtable.Synchronized(h);
|
|
}
|
|
|
|
String[] references = VsaEngine.assemblyReferencesTable[this.runtimeAssembly.FullName] as String[];
|
|
if (references != null){
|
|
for (int i = 0; i < references.Length; i++){
|
|
VsaReference r = (VsaReference)this.vsaItems.CreateItem(references[i], VsaItemType.Reference, VsaItemFlag.None);
|
|
r.AssemblyName = references[i];
|
|
}
|
|
}else{
|
|
// Read the references from the custom attribute on the assembly and create VsaReferences for each
|
|
// of them.
|
|
Object[] attrs = this.runtimeAssembly.GetCustomAttributes(Typeob.ReferenceAttribute, false);
|
|
String[] references1 = new String[attrs.Length];
|
|
for (int i = 0; i < attrs.Length; i++){
|
|
String assemblyName = ((ReferenceAttribute)attrs[i]).reference;
|
|
VsaReference r = (VsaReference)this.vsaItems.CreateItem(assemblyName, VsaItemType.Reference, VsaItemFlag.None);
|
|
r.AssemblyName = assemblyName;
|
|
references1[i] = assemblyName;
|
|
}
|
|
VsaEngine.assemblyReferencesTable[this.runtimeAssembly.FullName] = references1;
|
|
}
|
|
}
|
|
|
|
private void EmitReferences()
|
|
{
|
|
SimpleHashtable emitted = new SimpleHashtable((uint)this.vsaItems.Count + (this.implicitAssemblies == null ? 0 : (uint)this.implicitAssemblies.Count));
|
|
foreach (Object item in this.vsaItems){
|
|
if (item is VsaReference){
|
|
String referenceName = ((VsaReference)item).Assembly.GetName().FullName;
|
|
// do not write duplicate assemblies
|
|
if (emitted[referenceName] == null){
|
|
CustomAttributeBuilder cab = new CustomAttributeBuilder(CompilerGlobals.referenceAttributeConstructor, new Object[1] {referenceName});
|
|
this.CompilerGlobals.assemblyBuilder.SetCustomAttribute(cab);
|
|
emitted[referenceName] = item;
|
|
}
|
|
}
|
|
}
|
|
if (this.implicitAssemblies != null){
|
|
foreach (Object item in this.implicitAssemblies){
|
|
Assembly a = item as Assembly;
|
|
if (a != null){
|
|
String referenceName = a.GetName().FullName;
|
|
// do not write duplicate assemblies
|
|
if (emitted[referenceName] == null){
|
|
CustomAttributeBuilder cab = new CustomAttributeBuilder(CompilerGlobals.referenceAttributeConstructor, new Object[1] {referenceName});
|
|
this.CompilerGlobals.assemblyBuilder.SetCustomAttribute(cab);
|
|
emitted[referenceName] = item;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CreateMain(){
|
|
// define a class that will hold the main method
|
|
TypeBuilder mainClass = this.CompilerGlobals.module.DefineType("JScript Main", TypeAttributes.Public);
|
|
|
|
// create a function with the following signature void Main(String[] args)
|
|
MethodBuilder main = mainClass.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, Typeob.Void, new Type[]{typeof(String[])});
|
|
ILGenerator il = main.GetILGenerator();
|
|
|
|
// emit code for main method
|
|
this.CreateEntryPointIL(il, null /* site */);
|
|
|
|
// cook method and class
|
|
mainClass.CreateType();
|
|
// define the Main() method as the entry point for the exe
|
|
this.CompilerGlobals.assemblyBuilder.SetEntryPoint(main, this.PEFileKind);
|
|
}
|
|
|
|
private void CreateStartupClass(){
|
|
// define _Startup class for VSA (in the RootNamespace)
|
|
Debug.Assert(this.rootNamespace != null && this.rootNamespace.Length > 0);
|
|
TypeBuilder startupClass = this.CompilerGlobals.module.DefineType(this.rootNamespace + "._Startup", TypeAttributes.Public, typeof(BaseVsaStartup));
|
|
FieldInfo site = typeof(BaseVsaStartup).GetField("site", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
// create a function with the following signature: public virtual void Startup()
|
|
MethodBuilder startup = startupClass.DefineMethod("Startup", MethodAttributes.Public | MethodAttributes.Virtual, Typeob.Void, Type.EmptyTypes);
|
|
this.CreateEntryPointIL(startup.GetILGenerator(), site, startupClass);
|
|
// create a function with the following signature: public virtual void Shutdown()
|
|
MethodBuilder shutdown = startupClass.DefineMethod("Shutdown", MethodAttributes.Public | MethodAttributes.Virtual, Typeob.Void, Type.EmptyTypes);
|
|
this.CreateShutdownIL(shutdown.GetILGenerator());
|
|
|
|
// cook method and class
|
|
startupClass.CreateType();
|
|
}
|
|
|
|
void CreateEntryPointIL(ILGenerator il, FieldInfo site){
|
|
this.CreateEntryPointIL(il, site, null);
|
|
}
|
|
|
|
void CreateEntryPointIL(ILGenerator il, FieldInfo site, TypeBuilder startupClass){
|
|
LocalBuilder globalScope = il.DeclareLocal(typeof(GlobalScope));
|
|
|
|
//Emit code to create an engine. We do this explicitly so that we can control fast mode.
|
|
if (this.doFast)
|
|
il.Emit(OpCodes.Ldc_I4_1);
|
|
else
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
//Run through the list of references and emit code to create an array of strings representing them
|
|
//but do not emit duplicates.
|
|
SimpleHashtable uniqueReferences = new SimpleHashtable((uint)this.vsaItems.Count);
|
|
ArrayList references = new ArrayList();
|
|
foreach (Object item in this.vsaItems){
|
|
if (item is VsaReference){
|
|
string assemblyName = ((VsaReference)item).Assembly.GetName().FullName;
|
|
if (uniqueReferences[assemblyName] == null){
|
|
references.Add(assemblyName);
|
|
uniqueReferences[assemblyName] = item;
|
|
}
|
|
}
|
|
}
|
|
if (this.implicitAssemblies != null){
|
|
foreach (Object item in this.implicitAssemblies){
|
|
Assembly a = item as Assembly;
|
|
if (a != null){
|
|
String assemblyName = a.GetName().FullName;
|
|
if (uniqueReferences[assemblyName] == null){
|
|
references.Add(assemblyName);
|
|
uniqueReferences[assemblyName] = item;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ConstantWrapper.TranslateToILInt(il, references.Count);
|
|
il.Emit(OpCodes.Newarr, Typeob.String);
|
|
int num = 0;
|
|
foreach (string referenceName in references){
|
|
il.Emit(OpCodes.Dup);
|
|
ConstantWrapper.TranslateToILInt(il, num++);
|
|
il.Emit(OpCodes.Ldstr, referenceName);
|
|
il.Emit(OpCodes.Stelem_Ref);
|
|
}
|
|
if (startupClass != null){
|
|
MethodInfo createEngineAndGetGlobalScopeWithType = this.GetType().GetMethod("CreateEngineAndGetGlobalScopeWithType");
|
|
il.Emit(OpCodes.Ldtoken, startupClass);
|
|
il.Emit(OpCodes.Call, createEngineAndGetGlobalScopeWithType);
|
|
}else{
|
|
MethodInfo createEngineAndGetGlobalScope = this.GetType().GetMethod("CreateEngineAndGetGlobalScope");
|
|
il.Emit(OpCodes.Call, createEngineAndGetGlobalScope);
|
|
}
|
|
il.Emit(OpCodes.Stloc, globalScope);
|
|
|
|
// get global object instances and event source instances (CreateStartupClass scenario only)
|
|
if (site != null) this.CreateHostCallbackIL(il, site);
|
|
|
|
bool setUserEntryPoint = this.genDebugInfo;
|
|
// for every generated class make an instance and call the main routine method
|
|
foreach (Object item in this.vsaItems){
|
|
Type compiledType = ((VsaItem)item).GetCompiledType();
|
|
if (null != compiledType){
|
|
ConstructorInfo globalScopeConstructor = compiledType.GetConstructor(new Type[]{typeof(GlobalScope)});
|
|
MethodInfo globalCode = compiledType.GetMethod("Global Code");
|
|
if (setUserEntryPoint){
|
|
//Set the Global Code method of the first code item to be the place where the debugger breaks for the first step into
|
|
this.CompilerGlobals.module.SetUserEntryPoint(globalCode);
|
|
setUserEntryPoint = false; //Do it once only
|
|
}
|
|
il.Emit(OpCodes.Ldloc, globalScope);
|
|
il.Emit(OpCodes.Newobj, globalScopeConstructor);
|
|
il.Emit(OpCodes.Call, globalCode);
|
|
il.Emit(OpCodes.Pop);
|
|
}
|
|
}
|
|
// a method needs a return opcode
|
|
il.Emit(OpCodes.Ret);
|
|
}
|
|
|
|
private void CreateHostCallbackIL(ILGenerator il, FieldInfo site){
|
|
// Do callbacks to the host for global object instances
|
|
MethodInfo getGlobalInstance = site.FieldType.GetMethod("GetGlobalInstance");
|
|
MethodInfo getEventSourceInstance = site.FieldType.GetMethod("GetEventSourceInstance");
|
|
foreach (Object item in this.vsaItems){
|
|
if (item is VsaHostObject){
|
|
VsaHostObject hostObject = (VsaHostObject)item;
|
|
// get global item instance from site
|
|
il.Emit(OpCodes.Ldarg_0);
|
|
il.Emit(OpCodes.Ldfld, site);
|
|
il.Emit(OpCodes.Ldstr, hostObject.Name);
|
|
il.Emit(OpCodes.Callvirt, getGlobalInstance);
|
|
// cast instance to the correct type and store into the global field
|
|
Type target_type = hostObject.Field.FieldType;
|
|
il.Emit(OpCodes.Ldtoken, target_type);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
|
|
ConstantWrapper.TranslateToILInt(il, 0);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.coerceTMethod);
|
|
if (target_type.IsValueType)
|
|
Microsoft.JScript.Convert.EmitUnbox(il, target_type, Type.GetTypeCode(target_type));
|
|
else
|
|
il.Emit(OpCodes.Castclass, target_type);
|
|
il.Emit(OpCodes.Stsfld, hostObject.Field);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CreateShutdownIL(ILGenerator il){
|
|
// release references to global instances
|
|
foreach (Object item in this.vsaItems){
|
|
if (item is VsaHostObject){
|
|
il.Emit(OpCodes.Ldnull);
|
|
il.Emit(OpCodes.Stsfld, ((VsaHostObject)item).Field);
|
|
}
|
|
}
|
|
il.Emit(OpCodes.Ret);
|
|
}
|
|
|
|
private void DeleteCachedCompiledState(){
|
|
if (this.cachedPEFileName.Length > 0){
|
|
try{
|
|
if (File.Exists(this.cachedPEFileName))
|
|
File.Delete(this.cachedPEFileName);
|
|
string debugFileName = Path.ChangeExtension(this.cachedPEFileName, ".ildb");
|
|
if (File.Exists(debugFileName))
|
|
File.Delete(debugFileName);
|
|
}catch(Exception){
|
|
// swallow exceptions
|
|
}
|
|
this.cachedPEFileName = "";
|
|
}
|
|
}
|
|
|
|
public virtual void DisconnectEvents(){
|
|
}
|
|
|
|
protected override void DoClose(){
|
|
((VsaItems)this.vsaItems).Close();
|
|
if (null != this.globalScope)
|
|
this.globalScope.Close();
|
|
this.vsaItems = null;
|
|
this.engineSite = null;
|
|
this.globalScope = null;
|
|
this.runningThread = null;
|
|
this.compilerGlobals = null;
|
|
this.globals = null;
|
|
ScriptStream.Out = Console.Out;
|
|
ScriptStream.Error = Console.Error;
|
|
this.DeleteCachedCompiledState();
|
|
this.isClosed = true;
|
|
|
|
// The following calls ensure that all pointers to unmanaged objects get properly released
|
|
// and avoid memory leaks on shutdown. GC.Collect() should be enough by itself when COM+
|
|
// takes care of the second automatically.
|
|
GC.Collect();
|
|
}
|
|
|
|
protected override bool DoCompile(){
|
|
if (!this.isClosed && !this.isEngineCompiled){
|
|
this.SetUpCompilerEnvironment();
|
|
if (this.PEFileName == null){
|
|
// we use random default names to avoid overwriting cached assembly files when debugging VSA
|
|
this.PEFileName = this.GenerateRandomPEFileName();
|
|
}
|
|
this.SaveSourceForDebugging(); // Save sources needed for debugging (does nothing if no debug info)
|
|
this.numberOfErrors = 0; // Records number of errors during compilation.
|
|
this.isEngineCompiled = true; // OnCompilerError sets to false if it encounters an unrecoverable error.
|
|
Globals.ScopeStack.Push(this.GetGlobalScope().GetObject());
|
|
try{
|
|
try{
|
|
foreach (Object item in this.vsaItems){
|
|
Debug.Assert(item is VsaReference || item is VsaStaticCode || item is VsaHostObject);
|
|
if (item is VsaReference)
|
|
((VsaReference)item).Compile(); //Load the assembly into memory.
|
|
}
|
|
if (this.vsaItems.Count > 0)
|
|
this.SetEnclosingContext(new WrappedNamespace("", this)); //Provide a way to find types that are not inside of a name space
|
|
// Add VSA global items to the global scope
|
|
foreach (Object item in this.vsaItems){
|
|
if (item is VsaHostObject)
|
|
((VsaHostObject)item).Compile();
|
|
}
|
|
foreach (Object item in this.vsaItems){
|
|
if (item is VsaStaticCode)
|
|
((VsaStaticCode)item).Parse();
|
|
}
|
|
foreach (Object item in this.vsaItems){
|
|
if (item is VsaStaticCode)
|
|
((VsaStaticCode)item).ProcessAssemblyAttributeLists();
|
|
}
|
|
foreach (Object item in this.vsaItems){
|
|
if (item is VsaStaticCode)
|
|
((VsaStaticCode)item).PartiallyEvaluate();
|
|
}
|
|
foreach (Object item in this.vsaItems){
|
|
if (item is VsaStaticCode)
|
|
((VsaStaticCode)item).TranslateToIL();
|
|
}
|
|
foreach (Object item in this.vsaItems){
|
|
if (item is VsaStaticCode)
|
|
((VsaStaticCode)item).GetCompiledType();
|
|
}
|
|
if (null != this.globalScope)
|
|
this.globalScope.Compile(); //In case the host added items to the global scope
|
|
}catch(JScriptException se){
|
|
// It's a bit strange because we may be capturing an exception
|
|
// thrown by VsaEngine.OnCompilerError (in the case where
|
|
// this.engineSite is null. This is fine though. All we end up doing
|
|
// is capturing and then rethrowing the same error.
|
|
this.OnCompilerError(se);
|
|
}catch(System.IO.FileLoadException e){
|
|
JScriptException se = new JScriptException(JSError.ImplicitlyReferencedAssemblyNotFound);
|
|
se.value = e.FileName;
|
|
this.OnCompilerError(se);
|
|
this.isEngineCompiled = false;
|
|
}catch(EndOfFile){
|
|
// an error was reported during PartiallyEvaluate and the host decided to abort
|
|
// swallow the exception and keep going
|
|
}catch(Exception){
|
|
// internal compiler error -- make sure we don't claim to have compiled, then rethrow
|
|
this.isEngineCompiled = false;
|
|
throw;
|
|
}
|
|
}finally{
|
|
Globals.ScopeStack.Pop();
|
|
}
|
|
if (this.isEngineCompiled){
|
|
// there were no unrecoverable errors, but we want to return true only if there is IL
|
|
this.isEngineCompiled = (this.numberOfErrors == 0 || this.alwaysGenerateIL);
|
|
}
|
|
}
|
|
|
|
if (this.managedResources != null){
|
|
foreach (ResInfo managedResource in this.managedResources){
|
|
if (managedResource.isLinked){
|
|
this.CompilerGlobals.assemblyBuilder.AddResourceFile(managedResource.name,
|
|
Path.GetFileName(managedResource.filename),
|
|
managedResource.isPublic?
|
|
ResourceAttributes.Public:
|
|
ResourceAttributes.Private);
|
|
}else{
|
|
ResourceReader reader = null;
|
|
try{
|
|
reader = new ResourceReader(managedResource.filename);
|
|
}catch(System.ArgumentException){
|
|
JScriptException se = new JScriptException(JSError.InvalidResource);
|
|
se.value = managedResource.filename;
|
|
this.OnCompilerError(se);
|
|
this.isEngineCompiled = false;
|
|
return false;
|
|
}
|
|
IResourceWriter writer = this.CompilerGlobals.module.DefineResource(managedResource.name,
|
|
managedResource.filename,
|
|
managedResource.isPublic?
|
|
ResourceAttributes.Public:
|
|
ResourceAttributes.Private);
|
|
foreach (DictionaryEntry resource in reader)
|
|
writer.AddResource((string)resource.Key, resource.Value);
|
|
reader.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this.isEngineCompiled)
|
|
this.EmitReferences();
|
|
|
|
// Save things out to a local PE file when doSaveAfterCompile is set; this is set when an
|
|
// output name is given (allows JSC to avoid IVsaEngine.SaveCompiledState). The proper
|
|
// values for VSA are doSaveAfterCompile == false and genStartupClass == true. We allow
|
|
// genStartupClass to be false for scenarios like JSTest and the Debugger
|
|
if (this.isEngineCompiled){
|
|
if (this.doSaveAfterCompile){
|
|
if (this.PEFileKind != PEFileKinds.Dll)
|
|
this.CreateMain();
|
|
try {
|
|
// After executing this code path, it is an error to call SaveCompiledState (until the engine is recompiled)
|
|
compilerGlobals.assemblyBuilder.Save(Path.GetFileName(this.PEFileName));
|
|
}catch(Exception e){
|
|
throw new VsaException(VsaError.SaveCompiledStateFailed, e.Message, e);
|
|
}
|
|
}else if (this.genStartupClass){
|
|
// this is generated for VSA hosting
|
|
this.CreateStartupClass();
|
|
}
|
|
}
|
|
return this.isEngineCompiled;
|
|
}
|
|
|
|
internal CultureInfo ErrorCultureInfo{
|
|
get{
|
|
if (this.errorCultureInfo == null || this.errorCultureInfo.LCID != this.errorLocale)
|
|
this.errorCultureInfo = new CultureInfo(this.errorLocale);
|
|
return this.errorCultureInfo;
|
|
}
|
|
}
|
|
|
|
private string GenerateRandomPEFileName(){
|
|
if (this.randomNumberGenerator == null)
|
|
this.randomNumberGenerator = new Random((int)System.DateTime.Now.ToFileTime());
|
|
string filename = "tmp" + this.randomNumberGenerator.Next() + (this.PEFileKind == PEFileKinds.Dll? ".dll": ".exe");
|
|
return System.IO.Path.GetTempPath() + filename;
|
|
}
|
|
|
|
public virtual Assembly GetAssembly(){
|
|
this.TryObtainLock();
|
|
try{
|
|
if (null != this.PEFileName)
|
|
return Assembly.LoadFrom(this.PEFileName);
|
|
else
|
|
return compilerGlobals.assemblyBuilder;
|
|
}finally{
|
|
this.ReleaseLock();
|
|
}
|
|
}
|
|
|
|
internal ClassScope GetClass(String className){
|
|
if (this.packages != null)
|
|
for (int i = 0, n = this.packages.Count; i < n; i++){
|
|
PackageScope pscope = (PackageScope)this.packages[i];
|
|
Object pval = pscope.GetMemberValue(className, 1);
|
|
if (!(pval is Microsoft.JScript.Missing)){
|
|
ClassScope csc = (ClassScope)pval;
|
|
return csc;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual IVsaScriptScope GetGlobalScope(){
|
|
if (null == this.globalScope){
|
|
this.globalScope = new VsaScriptScope(this, "Global", null);
|
|
GlobalScope scope = (GlobalScope)this.globalScope.GetObject();
|
|
scope.globalObject = this.Globals.globalObject;
|
|
scope.fast = this.doFast;
|
|
scope.isKnownAtCompileTime = this.doFast;
|
|
}
|
|
return this.globalScope;
|
|
}
|
|
|
|
// Called by the debugger to get hold of the global scope from within a class method
|
|
public virtual GlobalScope GetMainScope(){
|
|
ScriptObject o = ScriptObjectStackTop();
|
|
while (o != null && !(o is GlobalScope))
|
|
o = o.GetParent();
|
|
return (GlobalScope)o;
|
|
}
|
|
|
|
public virtual Module GetModule(){
|
|
if (null != this.PEFileName){
|
|
Assembly a = GetAssembly();
|
|
Module[] modules = a.GetModules();
|
|
return modules[0];
|
|
}else
|
|
return this.CompilerGlobals.module;
|
|
}
|
|
|
|
public ArrayConstructor GetOriginalArrayConstructor(){
|
|
return this.Globals.globalObject.originalArray;
|
|
}
|
|
|
|
public ObjectConstructor GetOriginalObjectConstructor(){
|
|
return this.Globals.globalObject.originalObject;
|
|
}
|
|
|
|
public RegExpConstructor GetOriginalRegExpConstructor(){
|
|
return this.Globals.globalObject.originalRegExp;
|
|
}
|
|
|
|
protected override Object GetCustomOption(String name){
|
|
if (String.Compare(name, "CLSCompliant", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.isCLSCompliant;
|
|
else if (String.Compare(name, "fast", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.doFast;
|
|
else if (String.Compare(name, "output", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.PEFileName;
|
|
else if (String.Compare(name, "PEFileKind", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.PEFileKind;
|
|
else if (String.Compare(name, "print", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.doPrint;
|
|
else if (String.Compare(name, "UseContextRelativeStatics", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.doCRS;
|
|
// the next two are needed because of the ICompiler interface. They should not fail even though they may not do anything
|
|
else if (String.Compare(name, "optimize", true, CultureInfo.InvariantCulture) == 0)
|
|
return null;
|
|
else if (String.Compare(name, "define", true, CultureInfo.InvariantCulture) == 0)
|
|
return null;
|
|
else if (String.Compare(name, "defines", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.Defines;
|
|
else if (String.Compare(name, "ee", true, CultureInfo.InvariantCulture) == 0)
|
|
return VsaEngine.executeForJSEE;
|
|
else if (String.Compare(name, "version", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.versionInfo;
|
|
else if (String.Compare(name, "VersionSafe", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.versionSafe;
|
|
else if (String.Compare(name, "warnaserror", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.doWarnAsError;
|
|
else if (String.Compare(name, "WarningLevel", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.nWarningLevel;
|
|
else if (String.Compare(name, "managedResources", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.managedResources;
|
|
else if (String.Compare(name, "alwaysGenerateIL", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.alwaysGenerateIL;
|
|
else if (String.Compare(name, "DebugDirectory", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.debugDirectory;
|
|
else if (String.Compare(name, "AutoRef", true, CultureInfo.InvariantCulture) == 0)
|
|
return this.autoRef;
|
|
else
|
|
throw new VsaException(VsaError.OptionNotSupported);
|
|
}
|
|
|
|
internal int GetStaticCodeBlockCount(){
|
|
return ((VsaItems)this.vsaItems).staticCodeBlockCount;
|
|
}
|
|
|
|
internal Type GetType(String typeName){
|
|
if (this.cachedTypeLookups == null)
|
|
this.cachedTypeLookups = new SimpleHashtable(1000);
|
|
object cacheResult = this.cachedTypeLookups[typeName];
|
|
if (cacheResult == null){
|
|
// proceed with lookup
|
|
for (int i = 0, n = this.Scopes.Count; i < n; i++){
|
|
GlobalScope scope = (GlobalScope)this.scopes[i];
|
|
Type result = scope.GetType().Module.Assembly.GetType(typeName, false);
|
|
if (result != null){
|
|
this.cachedTypeLookups[typeName] = result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
if (this.runtimeAssembly != null) {
|
|
this.AddReferences();
|
|
this.runtimeAssembly = null;
|
|
}
|
|
|
|
for (int i = 0, n = this.vsaItems.Count; i < n; i++){
|
|
object item = this.vsaItems[i];
|
|
if (item is VsaReference){
|
|
Type result = ((VsaReference)item).GetType(typeName);
|
|
if (result != null){
|
|
this.cachedTypeLookups[typeName] = result;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
if (this.implicitAssemblies == null){
|
|
this.cachedTypeLookups[typeName] = false;
|
|
return null;
|
|
}
|
|
for (int i = 0, n = this.implicitAssemblies.Count; i < n; i++){
|
|
Assembly assembly = (Assembly)this.implicitAssemblies[i];
|
|
Type result = assembly.GetType(typeName, false);
|
|
if (result != null){
|
|
if (!result.IsPublic || result.IsDefined(typeof(System.Runtime.CompilerServices.RequiredAttributeAttribute), true))
|
|
result = null; //Suppress the type if it is not public or if it is a funky C++ type.
|
|
else{
|
|
this.cachedTypeLookups[typeName] = result;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
this.cachedTypeLookups[typeName] = false;
|
|
return null;
|
|
}
|
|
return (cacheResult as Type);
|
|
}
|
|
|
|
internal Globals Globals{
|
|
get{
|
|
if (this.globals == null)
|
|
this.globals = new Globals(this.doFast, this);
|
|
return this.globals;
|
|
}
|
|
}
|
|
|
|
internal bool HasErrors{
|
|
get{
|
|
return this.numberOfErrors != 0;
|
|
}
|
|
}
|
|
|
|
// GetScannerInstance is used by IsValidNamespaceName and IsValidIdentifier to validate names.
|
|
// We return an instance of the scanner only if there is no whitespace in the name text, since
|
|
// we do not want to allow, say, "not. valid" to be a valid namespace name even though that
|
|
// would produce a valid sequence of tokens.
|
|
private JSScanner GetScannerInstance(string name){
|
|
// make sure there's no whitespace in the name (values copied from documentation on String.Trim())
|
|
char[] anyWhiteSpace = {
|
|
(char)0x0009, (char)0x000A, (char)0x000B, (char)0x000C, (char)0x000D, (char)0x0020, (char)0x00A0,
|
|
(char)0x2000, (char)0x2001, (char)0x2002, (char)0x2003, (char)0x2004, (char)0x2005, (char)0x2006,
|
|
(char)0x2007, (char)0x2008, (char)0x2009, (char)0x200A, (char)0x200B, (char)0x3000, (char)0xFEFF
|
|
};
|
|
if (name == null || name.IndexOfAny(anyWhiteSpace) > -1)
|
|
return null;
|
|
// Create a code item whose source is the given text
|
|
VsaItem item = new VsaStaticCode(this, "itemName", VsaItemFlag.None);
|
|
Context context = new Context(new DocumentContext(item), name);
|
|
context.errorReported = -1;
|
|
JSScanner scanner = new JSScanner(); //Use this constructor to avoid allocating a Globals instance
|
|
scanner.SetSource(context);
|
|
return scanner;
|
|
}
|
|
|
|
// Use this method to initialize the engine for non-VSA use. This includes JSC, JSTest, and the JSEE.
|
|
public void InitVsaEngine(string rootMoniker, IVsaSite site){
|
|
this.genStartupClass = false;
|
|
this.engineMoniker = rootMoniker;
|
|
this.engineSite = site;
|
|
this.isEngineInitialized = true;
|
|
this.rootNamespace = "JScript.DefaultNamespace";
|
|
this.isEngineDirty = true;
|
|
this.isEngineCompiled = false;
|
|
}
|
|
|
|
public virtual void Interrupt(){
|
|
if (this.runningThread != null){
|
|
this.runningThread.Abort();
|
|
this.runningThread = null;
|
|
}
|
|
}
|
|
|
|
protected override bool IsValidNamespaceName(string name){
|
|
JSScanner scanner = this.GetScannerInstance(name);
|
|
if (scanner == null)
|
|
return false;
|
|
while(true){
|
|
if (scanner.PeekToken() != JSToken.Identifier)
|
|
return false;
|
|
scanner.GetNextToken();
|
|
if (scanner.PeekToken() == JSToken.EndOfFile)
|
|
break;
|
|
if (scanner.PeekToken() != JSToken.AccessField)
|
|
return false;
|
|
scanner.GetNextToken();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override bool IsValidIdentifier(string ident){
|
|
JSScanner scanner = this.GetScannerInstance(ident);
|
|
if (scanner == null)
|
|
return false;
|
|
if (scanner.PeekToken() != JSToken.Identifier)
|
|
return false;
|
|
scanner.GetNextToken();
|
|
if (scanner.PeekToken() != JSToken.EndOfFile)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
public LenientGlobalObject LenientGlobalObject{
|
|
get{
|
|
return (LenientGlobalObject)this.Globals.globalObject;
|
|
}
|
|
}
|
|
|
|
protected override Assembly LoadCompiledState(){
|
|
Debug.Assert(this.haveCompiledState);
|
|
byte[] pe;
|
|
byte[] pdb;
|
|
if (!this.genDebugInfo)
|
|
return this.compilerGlobals.assemblyBuilder;
|
|
// we need to save/reload to properly associate debug symbols with the assembly
|
|
this.DoSaveCompiledState(out pe, out pdb);
|
|
return Assembly.Load(pe, pdb, this.executionEvidence);
|
|
}
|
|
|
|
protected override void DoLoadSourceState(IVsaPersistSite site){
|
|
}
|
|
|
|
|
|
internal bool OnCompilerError(JScriptException se){
|
|
if (se.Severity == 0 || (this.doWarnAsError && se.Severity <= this.nWarningLevel))
|
|
this.numberOfErrors++;
|
|
bool canRecover = this.engineSite.OnCompilerError(se); //true means carry on with compilation.
|
|
if (!canRecover)
|
|
this.isEngineCompiled = false;
|
|
return canRecover;
|
|
}
|
|
|
|
public ScriptObject PopScriptObject(){
|
|
return (ScriptObject)this.Globals.ScopeStack.Pop();
|
|
}
|
|
|
|
public void PushScriptObject(ScriptObject obj){
|
|
this.Globals.ScopeStack.Push(obj);
|
|
}
|
|
|
|
public virtual void RegisterEventSource(String name){
|
|
}
|
|
|
|
public override void Reset(){
|
|
if (this.genStartupClass)
|
|
base.Reset();
|
|
else
|
|
this.ResetCompiledState();
|
|
}
|
|
|
|
protected override void ResetCompiledState(){
|
|
if (this.globalScope != null){
|
|
this.globalScope.Reset();
|
|
this.globalScope = null;
|
|
}
|
|
this.classCounter = 0;
|
|
this.haveCompiledState = false;
|
|
this.failedCompilation = true;
|
|
this.compiledRootNamespace = null;
|
|
this.startupClass = null;
|
|
this.compilerGlobals = null;
|
|
this.globals = null;
|
|
foreach (Object item in this.vsaItems)
|
|
((VsaItem)item).Reset();
|
|
this.implicitAssemblies = null;
|
|
this.implicitAssemblyCache = null;
|
|
this.cachedTypeLookups = null;
|
|
this.isEngineCompiled = false;
|
|
this.isEngineRunning = false;
|
|
this.isCompilerSet = false;
|
|
this.packages = null;
|
|
this.DeleteCachedCompiledState();
|
|
}
|
|
|
|
// the debugger restart the engine to run different expression evaluation
|
|
public virtual void Restart(){
|
|
this.TryObtainLock();
|
|
try{
|
|
((VsaItems)this.vsaItems).Close();
|
|
if (null != this.globalScope)
|
|
this.globalScope.Close();
|
|
this.globalScope = null;
|
|
this.vsaItems = new VsaItems(this);
|
|
this.isEngineRunning = false;
|
|
this.isEngineCompiled = false;
|
|
this.isCompilerSet = false;
|
|
this.isClosed = false;
|
|
this.runningThread = null;
|
|
this.globals = null;
|
|
|
|
// These are the same as the calls in Close(). Ideally, they should be necessary only in Close(),
|
|
// but actually the debugger leaks memory on shutdown if they are not present at both places.
|
|
GC.Collect();
|
|
}finally{
|
|
this.ReleaseLock();
|
|
}
|
|
}
|
|
|
|
public virtual void RunEmpty(){
|
|
this.TryObtainLock();
|
|
try{
|
|
Preconditions(Pre.EngineNotClosed | Pre.RootMonikerSet | Pre.SiteSet);
|
|
this.isEngineRunning = true;
|
|
// save the current thread so it can be interrupted
|
|
this.runningThread = Thread.CurrentThread;
|
|
if (null != this.globalScope)
|
|
this.globalScope.Run();
|
|
foreach (Object item in this.vsaItems)
|
|
((VsaItem)item).Run();
|
|
}finally{
|
|
this.runningThread = null;
|
|
this.ReleaseLock();
|
|
}
|
|
}
|
|
|
|
public virtual void Run(AppDomain domain){
|
|
// managed engines are not supporting Run in user-provided AppDomains
|
|
throw new System.NotImplementedException();
|
|
}
|
|
|
|
protected override void DoSaveCompiledState(out byte[] pe, out byte[] pdb){
|
|
pe = null;
|
|
pdb = null;
|
|
try{
|
|
// Save things out to a local PE file, then read back into memory
|
|
// PEFileName was set in the Compile method and we must have compiled in order to be calling this
|
|
string tempAssemblyName = this.PEFileName;
|
|
if (this.cachedPEFileName.Length == 0){
|
|
this.compilerGlobals.assemblyBuilder.Save(Path.GetFileName(tempAssemblyName));
|
|
}else
|
|
tempAssemblyName = this.cachedPEFileName;
|
|
FileStream stream = new FileStream(this.PEFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
|
pe = new byte[(int)stream.Length];
|
|
stream.Read(pe, 0, pe.Length);
|
|
stream.Close();
|
|
this.cachedPEFileName = tempAssemblyName;
|
|
if (this.genDebugInfo){
|
|
string tempPDBName = Path.ChangeExtension(tempAssemblyName, ".pdb");
|
|
// genDebugInfo could have been changed since we compiled, so check to make sure the symbols are there
|
|
if (File.Exists(tempPDBName)){
|
|
stream = new FileStream(tempPDBName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
|
try{
|
|
pdb = new byte[(int)stream.Length];
|
|
stream.Read(pdb, 0, pdb.Length);
|
|
}finally{
|
|
stream.Close();
|
|
}
|
|
}
|
|
}
|
|
}catch(Exception e){
|
|
throw new VsaException(VsaError.SaveCompiledStateFailed, e.ToString(), e);
|
|
}
|
|
}
|
|
|
|
protected override void DoSaveSourceState(IVsaPersistSite site){
|
|
}
|
|
|
|
private void SaveSourceForDebugging(){
|
|
if (!this.GenerateDebugInfo || this.debugDirectory == null || !this.isEngineDirty)
|
|
return;
|
|
foreach (VsaItem item in this.vsaItems){
|
|
if (item is VsaStaticCode){
|
|
string fileName = this.debugDirectory + item.Name + ".js";
|
|
try{
|
|
FileStream file = new FileStream(fileName, FileMode.Create, FileAccess.Write);
|
|
try{
|
|
StreamWriter sw = new StreamWriter(file);
|
|
sw.Write(((VsaStaticCode)item).SourceText);
|
|
sw.Close();
|
|
item.SetOption("codebase", fileName);
|
|
}finally{
|
|
file.Close();
|
|
}
|
|
}catch(Exception){
|
|
// swallow any file creation exceptions
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
internal ArrayList Scopes{
|
|
get{
|
|
if (this.scopes == null)
|
|
this.scopes = new ArrayList(8);
|
|
return this.scopes;
|
|
}
|
|
}
|
|
|
|
public ScriptObject ScriptObjectStackTop(){
|
|
return (ScriptObject)this.Globals.ScopeStack.Peek();
|
|
}
|
|
|
|
internal void SetEnclosingContext(ScriptObject ob){
|
|
ScriptObject s = this.Globals.ScopeStack.Peek();
|
|
while (s.GetParent() != null)
|
|
s = s.GetParent();
|
|
s.SetParent(ob);
|
|
}
|
|
|
|
public virtual void SetOutputStream(IMessageReceiver output){
|
|
COMCharStream stream = new COMCharStream(output);
|
|
System.IO.StreamWriter writer = new System.IO.StreamWriter(stream, Encoding.Default);
|
|
writer.AutoFlush = true;
|
|
ScriptStream.Out = writer;
|
|
ScriptStream.Error = writer;
|
|
}
|
|
|
|
protected override void SetCustomOption(String name, Object value){
|
|
try{
|
|
if (String.Compare(name, "CLSCompliant", true, CultureInfo.InvariantCulture) == 0)
|
|
this.isCLSCompliant = (bool)value;
|
|
else if (String.Compare(name, "fast", true, CultureInfo.InvariantCulture) == 0)
|
|
this.doFast = (bool)value;
|
|
else if (String.Compare(name, "output", true, CultureInfo.InvariantCulture) == 0){
|
|
if (value is String){
|
|
this.PEFileName = (String)value;
|
|
this.doSaveAfterCompile = true;
|
|
}
|
|
}else if (String.Compare(name, "PEFileKind", true, CultureInfo.InvariantCulture) == 0)
|
|
this.PEFileKind = (PEFileKinds)value;
|
|
else if (String.Compare(name, "print", true, CultureInfo.InvariantCulture) == 0)
|
|
this.doPrint = (bool)value;
|
|
else if (String.Compare(name, "UseContextRelativeStatics", true, CultureInfo.InvariantCulture) == 0)
|
|
this.doCRS = (bool)value;
|
|
// the next two are needed because of the ICompiler interface. They should not fail even though they may not do anything
|
|
else if (String.Compare(name, "optimize", true, CultureInfo.InvariantCulture) == 0)
|
|
return;
|
|
else if (String.Compare(name, "define", true, CultureInfo.InvariantCulture) == 0)
|
|
return;
|
|
else if (String.Compare(name, "defines", true, CultureInfo.InvariantCulture) == 0)
|
|
this.Defines = (Hashtable)value;
|
|
else if (String.Compare(name, "ee", true, CultureInfo.InvariantCulture) == 0)
|
|
VsaEngine.executeForJSEE = (Boolean)value;
|
|
else if (String.Compare(name, "version", true, CultureInfo.InvariantCulture) == 0)
|
|
this.versionInfo = (Version)value;
|
|
else if (String.Compare(name, "VersionSafe", true, CultureInfo.InvariantCulture) == 0)
|
|
this.versionSafe = (Boolean)value;
|
|
else if (String.Compare(name, "libpath", true, CultureInfo.InvariantCulture) == 0)
|
|
this.libpath = (String)value;
|
|
else if (String.Compare(name, "warnaserror", true, CultureInfo.InvariantCulture) == 0)
|
|
this.doWarnAsError = (bool)value;
|
|
else if (String.Compare(name, "WarningLevel", true, CultureInfo.InvariantCulture) == 0)
|
|
this.nWarningLevel = (int)value;
|
|
else if (String.Compare(name, "managedResources", true, CultureInfo.InvariantCulture) == 0)
|
|
this.managedResources = (ICollection)value;
|
|
else if (String.Compare(name, "alwaysGenerateIL", true, CultureInfo.InvariantCulture) == 0)
|
|
this.alwaysGenerateIL = (bool)value;
|
|
else if (String.Compare(name, "DebugDirectory", true, CultureInfo.InvariantCulture) == 0){
|
|
// use null to turn off SaveSourceState source generation
|
|
if (value == null){
|
|
this.debugDirectory = null;
|
|
return;
|
|
}
|
|
string dir = value as string;
|
|
if (dir == null)
|
|
throw new VsaException(VsaError.OptionInvalid);
|
|
try{
|
|
dir = Path.GetFullPath(dir + Path.DirectorySeparatorChar);
|
|
if (!Directory.Exists(dir))
|
|
Directory.CreateDirectory(dir);
|
|
}catch(Exception e){
|
|
// we couldn't create the specified directory
|
|
throw new VsaException(VsaError.OptionInvalid, "", e);
|
|
}
|
|
this.debugDirectory = dir;
|
|
}else if (String.Compare(name, "AutoRef", true, CultureInfo.InvariantCulture) == 0)
|
|
this.autoRef = (bool)value;
|
|
else
|
|
throw new VsaException(VsaError.OptionNotSupported);
|
|
}catch(VsaException){
|
|
throw;
|
|
}catch(Exception){
|
|
throw new VsaException(VsaError.OptionInvalid);
|
|
}
|
|
}
|
|
|
|
internal void SetUpCompilerEnvironment(){
|
|
if (!this.isCompilerSet){
|
|
this.globals = this.Globals;
|
|
this.isCompilerSet = true;
|
|
}
|
|
}
|
|
|
|
internal void TryToAddImplicitAssemblyReference(String name){
|
|
if (!this.autoRef) return;
|
|
|
|
String key;
|
|
SimpleHashtable implictAssemblyCache = this.implicitAssemblyCache;
|
|
if (implicitAssemblyCache == null) {
|
|
//Populate cache with things that should not be autoref'd. Canonical form is lower case without extension.
|
|
implicitAssemblyCache = new SimpleHashtable(50);
|
|
|
|
//PEFileName always includes an extension and is never NULL.
|
|
implicitAssemblyCache[Path.GetFileNameWithoutExtension(this.PEFileName).ToLower(CultureInfo.InvariantCulture)] = true;
|
|
|
|
foreach (Object item in this.vsaItems){
|
|
VsaReference assemblyReference = item as VsaReference;
|
|
if (assemblyReference == null || assemblyReference.AssemblyName == null) continue;
|
|
key = Path.GetFileName(assemblyReference.AssemblyName).ToLower(CultureInfo.InvariantCulture);
|
|
if (key.EndsWith(".dll"))
|
|
key = key.Substring(0, key.Length-4);
|
|
implicitAssemblyCache[key] = true;
|
|
}
|
|
this.implicitAssemblyCache = implicitAssemblyCache;
|
|
}
|
|
|
|
key = name.ToLower(CultureInfo.InvariantCulture);
|
|
if (implicitAssemblyCache[key] != null) return;
|
|
implicitAssemblyCache[key] = true;
|
|
|
|
try{
|
|
VsaReference assemblyReference = new VsaReference(this, name + ".dll");
|
|
if (assemblyReference.Compile(false)){
|
|
ArrayList implicitAssemblies = this.implicitAssemblies;
|
|
if (implicitAssemblies == null) {
|
|
implicitAssemblies = new ArrayList();
|
|
this.implicitAssemblies = implicitAssemblies;
|
|
}
|
|
implicitAssemblies.Add(assemblyReference.Assembly);
|
|
}
|
|
}catch(VsaException){
|
|
}
|
|
}
|
|
|
|
internal String RuntimeDirectory{
|
|
get{
|
|
if (this.runtimeDirectory == null){
|
|
//Get the path to mscorlib.dll
|
|
String s = typeof(Object).Module.FullyQualifiedName;
|
|
//Remove the file part to get the directory
|
|
this.runtimeDirectory = Path.GetDirectoryName(s);
|
|
}
|
|
return this.runtimeDirectory;
|
|
}
|
|
}
|
|
|
|
internal String[] LibpathList{
|
|
get{
|
|
if (this.libpathList == null){
|
|
if (this.libpath == null)
|
|
this.libpathList = new String[]{Typeob.Object.Module.Assembly.Location};
|
|
else
|
|
this.libpathList = this.libpath.Split(new Char[] {Path.PathSeparator});
|
|
}
|
|
return this.libpathList;
|
|
}
|
|
}
|
|
|
|
internal String FindAssembly(String name){
|
|
String path = name;
|
|
if (Path.GetFileName(name) == name){ // just the filename, no path
|
|
// Look in current directory
|
|
if (!File.Exists(name)){
|
|
// Look in COM+ runtime directory
|
|
String path1 = this.RuntimeDirectory + Path.DirectorySeparatorChar + name;
|
|
if (File.Exists(path1))
|
|
path = path1;
|
|
else{
|
|
// Look on the LIBPATH
|
|
String[] libpathList = this.LibpathList;
|
|
foreach( String l in libpathList ){
|
|
if (l.Length > 0){
|
|
path1 = l + Path.DirectorySeparatorChar + name;
|
|
if (File.Exists(path1)){
|
|
path = path1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!File.Exists(path))
|
|
return null;
|
|
return path;
|
|
}
|
|
|
|
protected override void ValidateRootMoniker(string rootMoniker){
|
|
// We override this method to avoid reading the registry in a non-VSA scenario
|
|
if (this.genStartupClass)
|
|
base.ValidateRootMoniker(rootMoniker);
|
|
else if (rootMoniker == null || rootMoniker.Length == 0)
|
|
throw new VsaException(VsaError.RootMonikerInvalid);
|
|
}
|
|
|
|
internal static bool CheckIdentifierForCLSCompliance(String name){
|
|
if (name[0] == '_')
|
|
return false;
|
|
for (int i = 0; i < name.Length; i++){
|
|
if (name[i] == '$')
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
internal void CheckTypeNameForCLSCompliance(String name, String fullname, Context context){
|
|
if (!this.isCLSCompliant)
|
|
return;
|
|
if (name[0] == '_'){
|
|
context.HandleError(JSError.NonCLSCompliantType);
|
|
return;
|
|
}
|
|
if (!VsaEngine.CheckIdentifierForCLSCompliance(fullname)){
|
|
context.HandleError(JSError.NonCLSCompliantType);
|
|
return;
|
|
}
|
|
if (this.typenameTable == null)
|
|
this.typenameTable = new Hashtable(new CaseInsensitiveHashCodeProvider(CultureInfo.InvariantCulture), new CaseInsensitiveComparer(CultureInfo.InvariantCulture));
|
|
if (this.typenameTable[fullname] == null)
|
|
this.typenameTable[fullname] = fullname;
|
|
else
|
|
context.HandleError(JSError.NonCLSCompliantType);
|
|
}
|
|
}
|
|
|
|
// The VSA spec requires that every IVsaEngine has a host property that is non-null.
|
|
// Since every assembly that we generate creates an engine (see CreateEngineAndGetGlobalScope)
|
|
// we must provide a default site for it.
|
|
|
|
class DefaultVsaSite: BaseVsaSite{
|
|
public override bool OnCompilerError(IVsaError error){
|
|
// We expect only JScriptExceptions here, and we throw them to be caught by the host
|
|
throw (JScriptException)error;
|
|
}
|
|
}
|
|
}
|