namespace Microsoft.JScript {
- public class ArrayLiteral : AST {
+ public class ArrayLiteral : AST, ICanLookupPrototype {
internal ASTList elems;
int skip_count;
return r;
}
+ bool ICanLookupPrototype.ResolveFieldAccess (AST ast)
+ {
+ if (ast is Identifier) {
+ Identifier name = (Identifier) ast;
+ Type prototype = typeof (StringPrototype);
+ MemberInfo [] members = prototype.GetMember (name.name.Value);
+ return members.Length > 0;
+ } else
+ return false;
+ }
+
internal override void Emit (EmitContext ec)
{
int i = 0;
foreach (AST ast in exps) {
ig.Emit (OpCodes.Dup);
ig.Emit (OpCodes.Ldc_I4, i);
- if (ast != null)
+ if (ast != null) {
ast.Emit (ec);
- else
+ CodeGenerator.EmitBox (ig, ast);
+ } else
ig.Emit (OpCodes.Ldsfld, missing);
ig.Emit (OpCodes.Stelem_Ref);
i++;
+2005-08-19 Cesar Lopez Nataren <cnataren@novell.com>
+
+ * SemanticAnalyser.cs: Added ArrayLiteral, StringLiteral,
+ BooleanConstant, ByteConstant, ShortConstant, IntConstant,
+ LongConstant, FloatConstant, DoubleConstant to the
+ prototypes. Added methods IsNumericConstant, NeedsToBoolean.
+
+ * Parser.cs: Added methods InRangeOf, HasNoDecimals which help on
+ building the property AST node depending on how big and precise
+ the number is.
+
+ * CodeGenerator.cs: (emit_get_default_this) Receives an extra
+ argument which indicates if we are inside a method, use
+ load_engine. Added method EmitBox, EmitConv, GetBoxType
+
+ * Literal.cs: Add abstract class Constant. Renamed BooleanLiteral
+ to BooleanConstant. Delete NumericLiteral, handle the number code
+ generation properly categorizing in ByteConstant, ShortConstant,
+ IntConstant, LongConstant, FloatConstant and DoubleConstant which
+ inherit from NumericConstant. (ObjectLiteral) Handle boxing issue.
+
+ * Statement.cs, Relational.cs: (If) Handle boxing issue.
+
+ * VariableDeclaration.cs: Handle the boxing issue when
+ we have initializers.
+
+ * Equality.cs, StrictEquality.cs: Handle the boxing issue before invoking
+ EvaluateEquality, JScriptStrictEquals.
+
+ * ArrayLiteral.cs: Implement ICanLookupPrototype so we can
+ optimize access to methods through the prototype and not
+ generating IL code that uses late binding. Handle the boxing
+ issue.
+
+ * expression.cs: (Unary.Emit) Nuke emit_unary_op. Take care of
+ properly boxing the operands of methods that evaluate the unary
+ operators at runtime. Fix the minus logic for IL generation, add
+ method emit_non_numeric_unary. Optimize the numeric
+ cases. (Binary) Add LateBinding internal
+ property. (Binary.emit_late_get_or_set, emit_array_access,
+ Conditional.Emit, Call.Emit, emit_print_stm, emit_late_call,
+ setup_late_call_args, EmitBuiltInArgs, Identifier.Emit, Args.Emit,
+ Expression.Emit, Assign.Emit, New.Emit)
+ Take care of properly boxing the built in .NET
+ values. (force_strong_type) Change the type from ParameterInfo to
+ object, take care specifically. (Expression) Add Last internal
+ property. In general, the point is that value types like integers,
+ booleans, etc... do not have to generate a box operation, the user
+ of the arg must handle that.
+
2005-08-17 Florian Gross <flgr@ccan.de>
* ScriptObject.cs: Added settable _proto for __proto__. This isn't
ff_emit_relational (ec, last_exp, lbl);
else if (last_exp is Binary)
ff_binary_recursion (ec, last_exp, lbl);
- else if (last_exp is Identifier || last_exp is BooleanLiteral)
+ else if (last_exp is Identifier || last_exp is BooleanConstant)
emit_default_case (ec, last_exp, OpCodes.Brtrue, lbl);
else if (last_exp is Equality)
ff_emit_equality_cond (ec, last_exp, lbl);
Expression exp = ast as Expression;
int n = exp.exprs.Count - 1;
AST tmp = (AST) exp.exprs [n];
- if (tmp is Equality || tmp is Relational || tmp is BooleanLiteral)
+ if (tmp is Equality || tmp is Relational || tmp is BooleanConstant)
return false;
else
return true;
}
}
- internal static void emit_get_default_this (ILGenerator ig)
+ internal static void emit_get_default_this (ILGenerator ig, bool inFunction)
{
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
+ CodeGenerator.load_engine (inFunction, ig);
ig.Emit (OpCodes.Call, typeof (VsaEngine).GetMethod ("ScriptObjectStackTop"));
Type iact_obj = typeof (IActivationObject);
ig.Emit (OpCodes.Castclass, iact_obj);
ig.Emit (OpCodes.Call, typeof (ScriptObject).GetMethod ("GetParent"));
}
+ internal static void EmitBox (ILGenerator ig, object obj)
+ {
+ if (obj == null)
+ return;
+
+ Type box_type = GetBoxType (obj);
+
+ if (box_type == null)
+ ;
+ else
+ ig.Emit (OpCodes.Box, box_type);
+ }
+
+ internal static void EmitConv (ILGenerator ig, Type type)
+ {
+ TypeCode tc = Type.GetTypeCode (type);
+
+ switch (tc) {
+ case TypeCode.Double:
+ ig.Emit (OpCodes.Conv_R8);
+ break;
+
+ default:
+ throw new NotImplementedException ();
+ }
+ }
+
+ private static Type GetBoxType (object obj)
+ {
+ if (obj is ByteConstant || obj is ShortConstant || obj is IntConstant)
+ return typeof (int);
+ else if (obj is LongConstant)
+ return typeof (long);
+ else if (obj is FloatConstant || obj is DoubleConstant)
+ return typeof (double);
+ else if (obj is BooleanConstant || obj is StrictEquality || obj is Equality)
+ return typeof (bool);
+ else if (obj is Unary) {
+ Unary unary = (Unary) obj;
+ JSToken oper = unary.oper;
+ AST operand = unary.operand;
+
+ if (oper == JSToken.Minus || oper == JSToken.Plus ||
+ oper == JSToken.Increment || oper == JSToken.Decrement ||
+ oper == JSToken.BitwiseNot)
+ return GetBoxType (operand);
+ else if (oper == JSToken.LogicalNot)
+ return typeof (bool);
+ } else if (obj is Identifier) {
+ Identifier id = (Identifier) obj;
+ string name = id.name.Value;
+ if (name == "NaN" || name == "Infinity")
+ return typeof (double);
+ } else if (obj is Binary) {
+ Binary bin = obj as Binary;
+ if (bin.AccessField && !bin.LateBinding) {
+ MemberInfo binding = bin.Binding;
+ MemberTypes member_type = binding.MemberType;
+ if (member_type == MemberTypes.Property)
+ return ((PropertyInfo) binding).PropertyType;
+ }
+ }
+ return null;
+ }
+
internal static void emit_default_value (ILGenerator ig, ParameterInfo param)
{
Type param_type = param.ParameterType;
ig.Emit (OpCodes.Ldc_R8, GlobalObject.NaN);
else if (param_type == typeof (object))
ig.Emit (OpCodes.Ldsfld, typeof (Missing).GetField ("Value"));
- else {
- Console.WriteLine ("param_type = " + param_type);
+ else
throw new NotImplementedException ();
- }
}
}
}
ig.Emit (OpCodes.Ldloc, local_builder);
}
- if (left != null)
+ if (left != null) {
left.Emit (ec);
- if (right != null)
+ CodeGenerator.EmitBox (ig, left);
+ }
+ if (right != null) {
right.Emit (ec);
+ CodeGenerator.EmitBox (ig, right);
+ }
if (op == JSToken.Equal || op == JSToken.NotEqual) {
ig.Emit (OpCodes.Call, typeof (Equality).GetMethod ("EvaluateEquality"));
if (InFunction)
ec.ig.Emit (OpCodes.Ldarg_0);
else
- CodeGenerator.emit_get_default_this (ec.ig);
+ CodeGenerator.emit_get_default_this (ec.ig, InFunction);
}
}
- internal class BooleanLiteral : Exp {
+ internal abstract class Constant : Exp {
- internal bool val;
-
- internal BooleanLiteral (AST parent, bool val, Location location)
+ internal Constant (AST parent, Location location)
: base (parent, location)
{
- this.val = val;
}
- public override string ToString ()
+ internal override bool Resolve (IdentificationTable context)
{
- return val.ToString ();
+ return true;
}
- internal override bool Resolve (IdentificationTable context)
+ internal override bool Resolve (IdentificationTable context, bool no_effect)
{
- return true;
+ this.no_effect = no_effect;
+ return Resolve (context);
+ }
+ }
+
+ internal class BooleanConstant : Constant, ICanLookupPrototype {
+ internal bool Value;
+
+ internal BooleanConstant (AST parent, bool val, Location location)
+ : base (parent, location)
+ {
+ this.Value = val;
}
internal override bool Resolve (IdentificationTable context, bool no_effect)
{
ILGenerator ig = ec.ig;
- if (val)
+ if (Value)
ig.Emit (OpCodes.Ldc_I4_1);
else
ig.Emit (OpCodes.Ldc_I4_0);
-
- ig.Emit (OpCodes.Box, typeof (System.Boolean));
-
+
if (no_effect)
ig.Emit (OpCodes.Pop);
}
+
+ bool ICanLookupPrototype.ResolveFieldAccess (AST ast)
+ {
+ if (ast is Identifier) {
+ Identifier name = (Identifier) ast;
+ Type prototype = typeof (NumberPrototype);
+ MemberInfo [] members = prototype.GetMember (name.name.Value);
+ return members.Length > 0;
+ } else
+ return false;
+ }
}
- internal class NumericLiteral : Exp {
+ internal abstract class NumericConstant : Constant, ICanLookupPrototype {
+
+ internal NumericConstant (AST parent, Location location)
+ : base (parent, location)
+ {
+ }
- double val;
+ bool ICanLookupPrototype.ResolveFieldAccess (AST ast)
+ {
+ if (ast is Identifier) {
+ Identifier name = (Identifier) ast;
+ Type prototype = typeof (NumberPrototype);
+ MemberInfo [] members = prototype.GetMember (name.name.Value);
+ return members.Length > 0;
+ } else
+ return false;
+ }
+ }
- internal NumericLiteral (AST parent, double val, Location location)
+ internal class ByteConstant : NumericConstant {
+ byte Value;
+
+ internal ByteConstant (AST parent, byte v, Location location)
: base (parent, location)
{
- this.val = val;
+ Value = v;
}
- public override string ToString ()
+ internal override void Emit (EmitContext ec)
{
- return val.ToString ();
+ IntConstant.EmitInt (ec.ig, Value);
}
+ }
- internal override bool Resolve (IdentificationTable context)
+ internal class ShortConstant : NumericConstant {
+ short Value;
+
+ internal ShortConstant (AST parent, short v, Location location)
+ : base (parent, location)
{
- return true;
+ Value = v;
}
- internal override bool Resolve (IdentificationTable context, bool no_effect)
- {
- this.no_effect = no_effect;
- return Resolve (context);
+ internal override void Emit (EmitContext ec)
+ {
+ IntConstant.EmitInt (ec.ig, Value);
+ }
+ }
+
+ internal class IntConstant : NumericConstant {
+ int Value;
+
+ internal IntConstant (AST parent, int v, Location location)
+ : base (parent, location)
+ {
+ Value = v;
+ }
+
+ static public void EmitInt (ILGenerator ig, int i)
+ {
+ switch (i){
+ case -1:
+ ig.Emit (OpCodes.Ldc_I4_M1);
+ break;
+
+ case 0:
+ ig.Emit (OpCodes.Ldc_I4_0);
+ break;
+
+ case 1:
+ ig.Emit (OpCodes.Ldc_I4_1);
+ break;
+
+ case 2:
+ ig.Emit (OpCodes.Ldc_I4_2);
+ break;
+
+ case 3:
+ ig.Emit (OpCodes.Ldc_I4_3);
+ break;
+
+ case 4:
+ ig.Emit (OpCodes.Ldc_I4_4);
+ break;
+
+ case 5:
+ ig.Emit (OpCodes.Ldc_I4_5);
+ break;
+
+ case 6:
+ ig.Emit (OpCodes.Ldc_I4_6);
+ break;
+
+ case 7:
+ ig.Emit (OpCodes.Ldc_I4_7);
+ break;
+
+ case 8:
+ ig.Emit (OpCodes.Ldc_I4_8);
+ break;
+
+ default:
+ if (i >= -128 && i <= 127){
+ ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
+ } else
+ ig.Emit (OpCodes.Ldc_I4, i);
+ break;
+ }
}
internal override void Emit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
- if (parent is Unary && (parent as Unary).oper == JSToken.Minus)
- ig.Emit (OpCodes.Ldc_R8, (double) (val * -1));
- else
- ig.Emit (OpCodes.Ldc_R8, (double) val);
- ig.Emit (OpCodes.Box, typeof (System.Double));
- if (no_effect)
- ig.Emit (OpCodes.Pop);
+ EmitInt (ec.ig, Value);
}
}
+ internal class LongConstant : NumericConstant {
+ long Value;
+
+ internal LongConstant (AST parent, long v, Location location)
+ : base (parent, location)
+ {
+ Value = v;
+ }
+
+ internal override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ EmitLong (ig, Value);
+ }
+
+ static internal void EmitLong (ILGenerator ig, long l)
+ {
+ ig.Emit (OpCodes.Ldc_I8, l);
+ }
+ }
+
+ internal class FloatConstant : NumericConstant {
+ float Value;
+
+ internal FloatConstant (AST parent, float v, Location location)
+ : base (parent, location)
+ {
+ Value = v;
+ }
+
+ internal override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldc_R4, Value);
+ }
+ }
+
+
+ internal class DoubleConstant : NumericConstant {
+ double Value;
+
+ internal DoubleConstant (AST parent, double v, Location location)
+ : base (parent, location)
+ {
+ Value = v;
+ }
+
+ internal override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldc_R8, Value);
+ }
+ }
+
internal class ObjectLiteral : Exp {
internal ArrayList elems;
{
ec.ig.Emit (OpCodes.Ldstr, property_name);
exp.Emit (ec);
+ CodeGenerator.EmitBox (ec.ig, exp);
}
}
// Cesar Lopez Nataren (cesar@ciencias.unam.mx)
//
// (C) 2003, Cesar Lopez Nataren
+// Copyright (C) 2005, Novell Inc (http://novell.com)
//
//
public NumericUnary (int operatorTok)
: base (null, null)
{
- throw new NotImplementedException ();
+ oper = (JSToken) operatorTok;
}
[DebuggerStepThroughAttribute]
return new Decompiler ();
}
+ /// <summary>
+ /// Test if n is between the range stablished by min and max
+ /// </summary>
+ private bool InRangeOf (double n, double min, double max)
+ {
+ return min <= n && n <= max;
+ }
+
+ private bool HasNoDecimals (double v)
+ {
+ return Math.Round (v) == v;
+ }
+
/// <summary>
/// Build a parse tree from a given source_string
/// </summary>
} else if (tt == Token.NUMBER) {
double n = ts.GetNumber;
decompiler.AddNumber (n);
- return new NumericLiteral (parent, n, new Location (ts.SourceName, ts.LineNumber));
+
+ Location location = new Location (ts.SourceName, ts.LineNumber);
+
+ if (HasNoDecimals (n)) {
+ if (InRangeOf (n, Byte.MinValue, Byte.MaxValue))
+ return new ByteConstant (parent, (byte) n, location);
+ else if (InRangeOf (n, Int16.MinValue, Int16.MaxValue))
+ return new ShortConstant (parent, (short) n, location);
+ else if (InRangeOf (n, Int32.MinValue, Int32.MaxValue))
+ return new IntConstant (parent, (int) n, location);
+ else if (InRangeOf (n, Int64.MinValue, Int64.MaxValue))
+ return new LongConstant (parent, (long) n, location);
+ else
+ return new DoubleConstant (parent, n, location);
+ } else {
+ if (InRangeOf (n, Single.MinValue, Single.MaxValue))
+ return new FloatConstant (parent, (float) n, location);
+ else if (InRangeOf (n, Double.MinValue, Double.MaxValue))
+ return new DoubleConstant (parent, n, location);
+ else
+ return new DoubleConstant (parent, n, location);
+ }
} else if (tt == Token.STRING) {
string s = ts.GetString;
decompiler.AddString (s);
v = false;
else
v = true;
- return new BooleanLiteral (null, v, new Location (ts.SourceName, ts.LineNumber));
+ return new BooleanConstant (null, v, new Location (ts.SourceName, ts.LineNumber));
} else if (tt == Token.RESERVED) {
ReportError ("msg.reserved.id");
} else if (tt == Token.ERROR) {
left.Emit (ec);
return;
} else if (op == JSToken.Instanceof) {
- if (left != null)
+ if (left != null) {
left.Emit (ec);
- if (right != null)
+ CodeGenerator.EmitBox (ig, left);
+ }
+ if (right != null) {
right.Emit (ec);
+ CodeGenerator.EmitBox (ig, right);
+ }
ig.Emit (OpCodes.Call, typeof (Instanceof).GetMethod ("JScriptInstanceof"));
ig.Emit (OpCodes.Box, typeof (Boolean));
return;
ig.Emit (OpCodes.Stloc, loc);
ig.Emit (OpCodes.Ldloc, loc);
- if (left != null)
+ if (left != null) {
left.Emit (ec);
- if (right != null)
+ CodeGenerator.EmitBox (ig, left);
+ }
+ if (right != null) {
right.Emit (ec);
+ CodeGenerator.EmitBox (ig, right);
+ }
ig.Emit (OpCodes.Call, t.GetMethod ("EvaluateRelational"));
prototypes.Add (typeof (Closure), typeof (FunctionPrototype));
prototypes.Add (typeof (ArrayObject), typeof (ArrayPrototype));
prototypes.Add (typeof (StringObject), typeof (StringPrototype));
- prototypes.Add (typeof (StringLiteral), typeof (StringPrototype));
prototypes.Add (typeof (BooleanObject), typeof (BooleanPrototype));
prototypes.Add (typeof (NumberObject), typeof (NumberPrototype));
prototypes.Add (typeof (DateObject), typeof (DatePrototype));
prototypes.Add (typeof (SyntaxErrorObject), typeof (ErrorPrototype));
prototypes.Add (typeof (TypeErrorObject), typeof (ErrorPrototype));
prototypes.Add (typeof (URIErrorObject), typeof (ErrorPrototype));
+
+
+ // literals, used when accessing a method from the prototype
+ // through the literal
+ prototypes.Add (typeof (ArrayLiteral), typeof (ArrayPrototype));
+ prototypes.Add (typeof (StringLiteral), typeof (StringPrototype));
+ prototypes.Add (typeof (BooleanConstant), typeof (BooleanPrototype));
+
+ Type number_prototype = typeof (NumberPrototype);
+ prototypes.Add (typeof (ByteConstant), number_prototype);
+ prototypes.Add (typeof (ShortConstant), number_prototype);
+ prototypes.Add (typeof (IntConstant), number_prototype);
+ prototypes.Add (typeof (LongConstant), number_prototype);
+ prototypes.Add (typeof (FloatConstant), number_prototype);
+ prototypes.Add (typeof (DoubleConstant), number_prototype);
}
internal static string ImplementationName (string name)
obj = ((Identifier) left).name.Value;
prop_name = ((Identifier) right).name.Value;
target_type = SemanticAnalyser.map_to_ctr (obj);
- } else if (left is StringLiteral && right_is_identifier) {
+ } else if (left is ICanLookupPrototype && right_is_identifier) {
prop_name = ((Identifier) right).name.Value;
target_type = SemanticAnalyser.map_to_prototype (left);
}
return null;
}
+ internal static bool IsNumericConstant (object o)
+ {
+ return o is ByteConstant || o is ShortConstant ||
+ o is IntConstant || o is LongConstant ||
+ o is FloatConstant || o is DoubleConstant;
+ }
+
+ internal static bool NeedsToBoolean (AST ast)
+ {
+ if (ast is BooleanConstant || ast is StrictEquality)
+ return false;
+ else if (ast is Expression)
+ return NeedsToBoolean (((Expression) ast).Last);
+ else if (ast is Unary) {
+ Unary unary = (Unary) ast;
+ if (unary.oper != JSToken.LogicalNot)
+ return true;
+ return false;
+ } else if (ast is Call || ast is Identifier)
+ return true;
+ else {
+ Console.WriteLine ("ast.LineNumber = {0}", ast.Location.LineNumber);
+ throw new NotImplementedException ();
+ }
+ }
+
internal static bool Needs (JSFunctionAttributeEnum targetAttr, MethodInfo method)
{
JSFunctionAttribute [] custom_attrs = (JSFunctionAttribute [])
Label false_lbl = ig.DefineLabel ();
Label merge_lbl = ig.DefineLabel ();
CodeGenerator.fall_true (ec, cond, false_lbl);
+ CodeGenerator.EmitBox (ig, cond);
if (true_stm != null)
- true_stm.Emit (ec);
+ true_stm.Emit (ec);
ig.Emit (OpCodes.Br, merge_lbl);
ig.MarkLabel (false_lbl);
if (false_stm != null)
internal override void Emit (EmitContext ec)
{
- if (left != null)
+ if (left != null) {
left.Emit (ec);
- if (right != null)
+ CodeGenerator.EmitBox (ec.ig, left);
+ }
+ if (right != null) {
right.Emit (ec);
+ CodeGenerator.EmitBox (ec.ig, right);
+ }
ec.ig.Emit (OpCodes.Call, typeof (StrictEquality).GetMethod ("JScriptStrictEquals"));
}
}
&& parent.GetType () != typeof (FunctionExpression))) {
if (val != null) {
val.Emit (ec);
+ CodeGenerator.EmitBox (ig, val);
ig.Emit (OpCodes.Stsfld, field_info);
}
} else {
if (val != null) {
val.Emit (ec);
+ CodeGenerator.EmitBox (ig, val);
ig.Emit (OpCodes.Stloc, local_builder);
}
}
}
-
internal override bool Resolve (IdentificationTable context)
{
bool r = true;
internal override bool Resolve (IdentificationTable context)
{
bool r = false;
-
- if (operand is Exp)
+
+ if (operand is Exp) {
if (oper != JSToken.Increment && oper != JSToken.Decrement)
r = ((Exp) operand).Resolve (context, no_effect);
- r = ((AST) operand).Resolve (context);
+ } else
+ r = operand.Resolve (context);
return r;
}
}
internal override void Emit (EmitContext ec)
- {
- if (!(operand is NumericLiteral) || (oper != JSToken.Minus))
- emit_unary_op (ec);
- else
- operand.Emit (ec);
- }
-
- internal void emit_unary_op (EmitContext ec)
{
ILGenerator ig = ec.ig;
+
switch (oper) {
case JSToken.Void:
operand.Emit (ec);
case JSToken.Typeof:
operand.Emit (ec);
+ CodeGenerator.EmitBox (ig, operand);
ig.Emit (OpCodes.Call, typeof (Typeof).GetMethod ("JScriptTypeof"));
break;
case JSToken.Plus:
operand.Emit (ec);
ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToNumber", new Type [] { typeof (object) }));
- /* all clear */
+ //
+ // FIXME: investigate the real
+ // discriminate for generating this
+ // box.
+ if (!no_effect)
+ ig.Emit (OpCodes.Box, typeof (double));
break;
case JSToken.Minus:
- operand.Emit (ec);
- ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToNumber", new Type [] { typeof (object) }));
- ig.Emit (OpCodes.Neg);
+ if (SemanticAnalyser.IsNumericConstant (operand)) {
+ operand.Emit (ec);
+ ig.Emit (OpCodes.Neg);
+ } else if (operand is Identifier &&
+ ((Identifier) operand).name.Value == "Infinity")
+ ig.Emit (OpCodes.Ldc_R8, Double.NegativeInfinity);
+ else
+ emit_non_numeric_unary (ec, operand, (byte) 47);
break;
case JSToken.BitwiseNot:
- operand.Emit (ec);
- ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToInt32"));
- ig.Emit (OpCodes.Not);
+ if (SemanticAnalyser.IsNumericConstant (operand)) {
+ operand.Emit (ec);
+ ig.Emit (OpCodes.Not);
+ } else
+ emit_non_numeric_unary (ec, operand, (byte) 40);
break;
case JSToken.LogicalNot:
operand.Emit (ec);
- // FIXME: here we can infer the type
- // of the operand so that unneeded
- // ToBoolean can be avoided
- ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToBoolean", new Type [] { typeof (object) }));
- ig.Emit (OpCodes.Ldc_I4_1);
- ig.Emit (OpCodes.Sub);
+ if (SemanticAnalyser.NeedsToBoolean (operand)) {
+ CodeGenerator.EmitBox (ec.ig, operand);
+ ig.Emit (OpCodes.Ldc_I4_1);
+ ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToBoolean",
+ new Type [] { typeof (object), typeof (bool) }));
+ }
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Ceq);
break;
default:
throw new NotImplementedException ();
}
}
+
+ private void emit_non_numeric_unary (EmitContext ec, AST operand, byte oper)
+ {
+ ILGenerator ig = ec.ig;
+
+ Type unary_type = typeof (NumericUnary);
+ LocalBuilder unary_builder = ig.DeclareLocal (unary_type);
+
+ ig.Emit (OpCodes.Ldc_I4_S, oper);
+ ig.Emit (OpCodes.Newobj, unary_type.GetConstructor (new Type [] { typeof (int) }));
+ ig.Emit (OpCodes.Stloc, unary_builder);
+ ig.Emit (OpCodes.Ldloc, unary_builder);
+
+ operand.Emit (ec);
+
+ ig.Emit (OpCodes.Call, unary_type.GetMethod ("EvaluateUnary"));
+ }
}
internal class Binary : BinaryOp, IAssignable {
get { return op == JSToken.AccessField; }
}
+ internal bool LateBinding {
+ get { return late_bind; }
+ }
+
internal override bool Resolve (IdentificationTable context)
{
bool found = true;
emit_access (left, right, ec);
} else {
emit_operator (ig);
- if (left != null)
+ if (left != null) {
left.Emit (ec);
- if (right != null)
+ CodeGenerator.EmitBox (ig, left);
+ }
+ if (right != null) {
right.Emit (ec);
+ CodeGenerator.EmitBox (ig, right);
+ }
emit_op_eval (ig);
}
if (no_effect)
ig.Emit (OpCodes.Dup);
}
left.Emit (ec);
-
+
LocalBuilder local_literal = null;
//
right_side.Emit (ec);
else
ig.Emit (OpCodes.Ldloc, right_obj);
+ CodeGenerator.EmitBox (ig, right_side);
ig.Emit (OpCodes.Call, lb_type.GetMethod ("SetValue"));
} else
ig.Emit (OpCodes.Call, lb_type.GetMethod ("GetNonMissingValue"));
internal void get_default_this (ILGenerator ig)
{
- if (InFunction)
- ig.Emit (OpCodes.Ldarg_1);
- else {
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
- }
-
+ CodeGenerator.load_engine (InFunction, ig);
ig.Emit (OpCodes.Call, typeof (Microsoft.JScript.Vsa.VsaEngine).GetMethod ("ScriptObjectStackTop"));
Type iact_obj = typeof (IActivationObject);
ig.Emit (OpCodes.Castclass, iact_obj);
ig.Emit (OpCodes.Newarr, typeof (object));
ig.Emit (OpCodes.Dup);
ig.Emit (OpCodes.Ldc_I4_0);
- if (right != null)
+ if (right != null) {
right.Emit (ec);
+ CodeGenerator.EmitBox (ig, right);
+ }
ig.Emit (OpCodes.Stelem_Ref);
if (assign) {
- if (right_side != null)
+ if (right_side != null) {
right_side.Emit (ec);
+ CodeGenerator.EmitBox (ig, right_side);
+ }
else
ig.Emit (OpCodes.Ldloc, right_obj);
ig.Emit (OpCodes.Call, typeof (LateBinding).GetMethod ("SetIndexedPropertyValueStatic"));
} else {
ig.Emit (OpCodes.Ldc_I4_0);
ig.Emit (OpCodes.Ldc_I4_1);
-
- if (InFunction)
- ig.Emit (OpCodes.Ldarg_1);
- else {
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
- }
+ CodeGenerator.load_engine (InFunction, ig);
ig.Emit (OpCodes.Call, typeof (LateBinding).GetMethod ("CallValue"));
}
}
Label false_label = ig.DefineLabel ();
Label merge_label = ig.DefineLabel ();
CodeGenerator.fall_true (ec, cond_exp, false_label);
- if (true_exp != null)
+ if (true_exp != null) {
true_exp.Emit (ec);
+ CodeGenerator.EmitBox (ig, true_exp);
+ }
ig.Emit (OpCodes.Br, merge_label);
ig.MarkLabel (false_label);
- if (false_exp != null)
+ if (false_exp != null) {
false_exp.Emit (ec);
+ CodeGenerator.EmitBox (ig, false_exp);
+ }
ig.MarkLabel (merge_label);
if (no_effect)
ig.Emit (OpCodes.Pop);
if (member_type == MemberTypes.Method) {
if (member_exp is Binary) {
Binary bin = (Binary) member_exp;
- if (bin.left is StringLiteral && need_this)
+ if (bin.left is ICanLookupPrototype && need_this ) {
bin.left.Emit (ec);
+ CodeGenerator.EmitBox (ig, bin.left);
+ }
}
args.Emit (ec);
MethodInfo method = (MethodInfo) minfo;
for (int i = 0; i <= n; i++) {
ast = args.get_element (i);
ast.Emit (ec);
-
+ CodeGenerator.EmitBox (ig, ast);
+
if (ast is StringLiteral)
;
else {
Binary bin = member_exp as Binary;
if (SemanticAnalyser.IsLiteral (bin.left) != null) {
member_exp.Emit (ec);
+ CodeGenerator.EmitBox (ig, member_exp);
setup_late_call_args (ec);
ig.Emit (OpCodes.Call, typeof (LateBinding).GetMethod ("CallValue"));
} else if (bin.right is Identifier) {
ig.Emit (OpCodes.Call, typeof (LateBinding).GetMethod ("Call"));
} else {
bin.left.Emit (ec);
+ CodeGenerator.EmitBox (ig, bin.left);
+
member_exp.Emit (ec);
+ CodeGenerator.EmitBox (ig, member_exp);
+
setup_late_call_args (ec);
ig.Emit (OpCodes.Call, typeof (LateBinding).GetMethod ("CallValue"));
}
} else {
get_global_scope_or_this (ec.ig);
member_exp.Emit (ec);
+ CodeGenerator.EmitBox (ig, member_exp);
setup_late_call_args (ec);
ig.Emit (OpCodes.Call, typeof (LateBinding).GetMethod ("CallValue"));
}
AST left = (member_exp as Binary).left;
left.Emit (ec);
-
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
+
+ CodeGenerator.load_engine (InFunction, ig);
+
ig.Emit (OpCodes.Call , typeof (Convert).GetMethod ("ToObject"));
Type lb_type = typeof (LateBinding);
{
ILGenerator ig = ec.ig;
int n = args.Size;
+ AST ast = null;
ig.Emit (OpCodes.Ldc_I4, n);
ig.Emit (OpCodes.Newarr, typeof (object));
for (int i = 0; i < n; i++) {
ig.Emit (OpCodes.Dup);
ig.Emit (OpCodes.Ldc_I4, i);
- args.get_element (i).Emit (ec);
+ ast = args.get_element (i);
+ ast.Emit (ec);
+ CodeGenerator.EmitBox (ig, ast);
ig.Emit (OpCodes.Stelem_Ref);
}
ILGenerator ig = ec.ig;
int n = args.Size;
+ AST ast = null;
if (n >= 1 && (member_exp.ToString () == "String" || member_exp.ToString () == "Boolean" || member_exp.ToString () == "Number")) {
- args.get_element (0).Emit (ec);
+ ast = args.get_element (0);
+ ast.Emit (ec);
+ CodeGenerator.EmitBox (ig, ast);
return;
}
ig.Emit (OpCodes.Ldc_I4, n);
ig.Emit (OpCodes.Newarr, typeof (object));
+
for (int i = 0; i < n; i++) {
ig.Emit (OpCodes.Dup);
ig.Emit (OpCodes.Ldc_I4, i);
- args.get_element (i).Emit (ec);
+ ast = args.get_element (i);
+ ast.Emit (ec);
+ CodeGenerator.EmitBox (ig, ast);
ig.Emit (OpCodes.Stelem_Ref);
}
}
Console.WriteLine ("warning JS1135: Variable '" + name + "' has not been declared");
} else
throw new Exception (location.SourceName + "(" + location.LineNumber +
- ",0) : error JS1135: Variable '" + name + "' has not been declared");
+ ",0) : error JS1135: Variable '" + name + "' has not been declared");
return true;
}
{
ILGenerator ig = ec.ig;
- if (assign && right_side != null && !undeclared)
+ if (assign && right_side != null && !undeclared) {
right_side.Emit (ec);
+ CodeGenerator.EmitBox (ig, right_side);
+ }
if (binding is FormalParam) {
FormalParam f = binding as FormalParam;
if (assign)
get { return BoundToMethod is Function; }
}
+ private bool in_new = false;
+ internal bool InNew {
+ set { in_new = value; }
+ get { return in_new; }
+ }
+
private int expected_args = 0;
private bool has_this = false;
private bool var_args = false;
expected_args = method.GetParameters ().Length;
} else if (BoundToMethod is BuiltIn) {
BuiltIn built_in = (BuiltIn) BoundToMethod;
- if (built_in.IsConstructor)
- expected_args = elems.Count;
+ if (built_in.IsConstructor || InNew)
+ expected_args = (elems == null) ? 0 : elems.Count;
else
expected_args = ((BuiltIn) BoundToMethod).NumOfArgs;
}
- int n = Size;
+ if (elems == null)
+ return true;
+
+ int n = elems.Count;
for (int i = 0; i < n; i++) {
tmp = (AST) elems [i];
- r &= tmp.Resolve (context);
+ if (tmp != null)
+ r &= tmp.Resolve (context);
}
return r;
}
}
}
- if (strong_type)
+ if (BoundToMethod is MethodInfo)
parameters = ((MethodInfo) BoundToMethod).GetParameters ();
if (has_engine)
if (var_args) {
if (expected_args > 1)
emit_default_args_case (ec, expected_args, strong_type, parameters);
-
+
ILGenerator ig = ec.ig;
int remains = elems.Count - expected_args;
ig.Emit (OpCodes.Dup);
ig.Emit (OpCodes.Ldc_I4, k);
ast.Emit (ec);
+ CodeGenerator.EmitBox (ig, ast);
ig.Emit (OpCodes.Stelem_Ref);
}
}
ast.Emit (ec);
if (strong_type)
force_strong_type (ig, ast, parameters [j]);
+ else
+ CodeGenerator.EmitBox (ig, ast);
} else {
//
// ast was null and we need
}
}
- internal void force_strong_type (ILGenerator ig, AST ast, ParameterInfo pinfo)
+ internal void force_strong_type (ILGenerator ig, AST ast, object obj)
{
- Type param_type = pinfo.ParameterType;
- if (ast.GetType () == typeof (NumericLiteral)) {
- if (param_type == typeof (double)) {
- ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToNumber", new Type [] { typeof (object) }));
- //ig.Emit (OpCodes.Conv_R8);
- } else if (param_type == typeof (object))
- ;
- else {
- Console.WriteLine ("#1. ast.GetType = {0}, param_type = {1}", ast.GetType (), param_type);
- throw new NotImplementedException ();
- }
- } else {
+ Type param_type = null;
+ if (obj is ParameterInfo)
+ param_type = ((ParameterInfo) obj).ParameterType;
+ else
+ param_type = obj.GetType ();
+
+ if (SemanticAnalyser.IsNumericConstant (ast)) {
if (param_type == typeof (double))
- ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToNumber", new Type [] {typeof (object)}));
- else if (param_type == typeof (string)) {
- ig.Emit (OpCodes.Ldc_I4_1);
- ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToString", new Type [] {typeof (object), typeof (bool)}));
- } else if (param_type == typeof (object))
- ;
- else {
- Console.WriteLine ("#2. ast.GetType = {0}, param_type = {1}", ast.GetType (), param_type);
+ CodeGenerator.EmitConv (ig, param_type);
+ else if (param_type == typeof (object))
+ CodeGenerator.EmitBox (ig, ast);
+ else
throw new NotImplementedException ();
- }
+ } else {
+ if (ast is Unary) {
+ Unary unary = (Unary) ast;
+ force_strong_type (ig, unary.operand, obj);
+ } else if (param_type == typeof (double))
+ ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToNumber",
+ new Type [] { typeof (object) }));
}
}
}
exprs.Add (a);
}
+ internal AST Last {
+ get { return (AST) exprs [Size - 1]; }
+ }
+
public override string ToString ()
{
int size = exprs.Count;
for (i = 0; i < size; i++)
sb.Append (exprs [i].ToString ());
-
- sb.Append ("\n");
return sb.ToString ();
-
} else return String.Empty;
}
for (i = 0; i < n; i++) {
exp = (AST) exprs [i];
exp.Emit (ec);
+ CodeGenerator.EmitBox (ec.ig, exp);
}
}
}
ig.Emit (OpCodes.Stloc, aux);
ig.Emit (OpCodes.Ldloc, local);
ig.Emit (OpCodes.Ldloc, aux);
- if (right != null)
+ if (right != null) {
right.Emit (ec);
+ CodeGenerator.EmitBox (ig, right);
+ }
ig.Emit (OpCodes.Call, type.GetMethod ("EvaluatePlus"));
if (left is Identifier)
((Identifier) left).EmitStore (ec);
}
exp.Resolve (context);
- if (args != null)
+ if (args != null) {
+ args.InNew = true;
r &= args.Resolve (context);
+ }
return r;
}
ILGenerator ig = ec.ig;
if (exp != null) {
- if (late_bind) {
- CodeGenerator.emit_get_default_this (ec.ig);
+ if (late_bind) {
+ AST ast = null;
+ CodeGenerator.emit_get_default_this (ec.ig, InFunction);
exp.Emit (ec);
ig.Emit (OpCodes.Ldc_I4, args.Size);
for (int i = 0; i < args.Size; i++) {
ig.Emit (OpCodes.Dup);
ig.Emit (OpCodes.Ldc_I4, i);
- args.get_element (i).Emit (ec);
+ ast = args.get_element (i);
+ ast.Emit (ec);
+ CodeGenerator.EmitBox (ig, ast);
ig.Emit (OpCodes.Stelem_Ref);
}
-
+
ig.Emit (OpCodes.Ldc_I4_1);
ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
+ CodeGenerator.load_engine (InFunction, ig);
ig.Emit (OpCodes.Call, typeof (LateBinding).GetMethod ("CallValue"));
} else {
ig.Emit (OpCodes.Ldc_I4, args.Size);
ig.Emit (OpCodes.Newarr, typeof (object));
+ AST ast = null;
+
for (int i = 0; i < n; i++) {
ig.Emit (OpCodes.Dup);
ig.Emit (OpCodes.Ldc_I4, i);
- args.get_element (i).Emit (ec);
+ ast = args.get_element (i);
+ ast.Emit (ec);
+ CodeGenerator.EmitBox (ig, ast);
ig.Emit (OpCodes.Stelem_Ref);
}
}
/* value properties of the Global Object */
case "NaN":
ig.Emit (OpCodes.Ldc_R8, Double.NaN);
- ig.Emit (OpCodes.Box, typeof (Double));
break;
+
case "Infinity":
ig.Emit (OpCodes.Ldc_R8, Double.PositiveInfinity);
- // FIXME: research when not to generate the Boxing
- ig.Emit (OpCodes.Box, typeof (Double));
break;
+
case "undefined":
ig.Emit (OpCodes.Ldnull);
break;
+
case "null":
ig.Emit (OpCodes.Ldsfld, typeof (DBNull).GetField ("Value"));
break;
#endif
ig.Emit (OpCodes.Call, typeof (Eval).GetMethod ("JScriptEvaluate", method_args));
break;
+
case "parseInt":
ig.Emit (OpCodes.Call, go.GetMethod ("parseInt"));
ig.Emit (OpCodes.Box, typeof (Double));
break;
+
case "parseFloat":
ig.Emit (OpCodes.Call, go.GetMethod ("parseFloat"));
ig.Emit (OpCodes.Box, typeof (Double));
break;
+
case "isNaN":
ig.Emit (OpCodes.Call, go.GetMethod ("isNaN"));
ig.Emit (OpCodes.Box, typeof (bool));
break;
+
case "isFinite":
ig.Emit (OpCodes.Call, go.GetMethod ("isFinite"));
ig.Emit (OpCodes.Box, typeof (bool));
break;
+
case "decodeURI":
ig.Emit (OpCodes.Call, go.GetMethod ("decodeURI"));
break;
+
case "decodeURIComponent":
ig.Emit (OpCodes.Call, go.GetMethod ("decodeURIComponent"));
break;
+
case "encodeURI":
ig.Emit (OpCodes.Call, go.GetMethod ("encodeURI"));
break;
+
case "encodeURIComponent":
ig.Emit (OpCodes.Call, go.GetMethod ("encodeURIComponent"));
break;
+
case "escape":
ig.Emit (OpCodes.Call, go.GetMethod ("escape"));
break;
+
case "unescape":
ig.Emit (OpCodes.Call, go.GetMethod ("unescape"));
break;
+
/* constructor properties of the Global object */
case "Object":
ig.Emit (OpCodes.Call, go.GetProperty ("Object").GetGetMethod ());
break;
+
case "Function":
ig.Emit (OpCodes.Call, go.GetProperty ("Function").GetGetMethod ());
break;
+
case "Array":
ig.Emit (OpCodes.Call, go.GetProperty ("Array").GetGetMethod ());
break;
+
case "String":
ig.Emit (OpCodes.Call, go.GetProperty ("String").GetGetMethod ());
break;
+
case "Boolean":
ig.Emit (OpCodes.Call, go.GetProperty ("Boolean").GetGetMethod ());
break;
+
case "Number":
ig.Emit (OpCodes.Call, go.GetProperty ("Number").GetGetMethod ());
break;
+
case "Date":
ig.Emit (OpCodes.Call, go.GetProperty ("Date").GetGetMethod ());
break;
+
case "RegExp":
ig.Emit (OpCodes.Call, go.GetProperty ("RegExp").GetGetMethod ());
break;
+
case "Error":
ig.Emit (OpCodes.Call, go.GetProperty ("Error").GetGetMethod ());
break;
+
case "EvalError":
ig.Emit (OpCodes.Call, go.GetProperty ("EvalError").GetGetMethod ());
break;
+
case "RangeError":
ig.Emit (OpCodes.Call, go.GetProperty ("RangeError").GetGetMethod ());
break;