public override void EmitSetValue(BoundExpression expression) { // Push the closure onto the stack. Scope.EmitLoadClosure(_field.Closure); // Push the value onto the stack. Generator.EmitCast(Generator.EmitExpression(expression), Type.Type); // Set the closure field. IL.Emit(OpCodes.Stfld, _field.Builder.Field); }
private bool? ToBoolean(BoundExpression node) { // This method tests whether the expression evaluates to a constant // expression. This depends on a constant folding phase for // correct results (which we don't have, so currently it just // checks for a true/false constant). var constant = node as BoundConstant; if (constant != null && constant.Value is bool) return (bool)constant.Value; return null; }
public ReadState(BoundExpression expression, int writeCount) { Expression = expression; WriteCount = writeCount; }
private void EmitSetMember(BoundExpression expression, BoundExpression index, BoundExpression value) { EmitPop(EmitOperationCall(Operation.SetMember, expression, index, value)); }
public void Join(IList<Branch> branches) { // If there aren't any branches, there is no work. if (branches.Count == 0) return; // If we just have a single branch, we can just copy all // assignments. if (branches.Count == 1) { var branch = branches[0]; if (branch._assigned != null) MergeAssigned(branch._assigned); // And move the expressions. Expressions = branch.Expressions; return; } // If we don't have a single branch, we have to merge // the expressions from all branches. BoundExpression[] expressions = null; foreach (var branch in branches) { if (expressions == null) { // If we don't have expressions yet, just move them // from the branch. expressions = branch.Expressions; } else if (branch.Expressions != null) { // Otherwise, concatenate the two arrays. var a = expressions; var b = branch.Expressions; var result = new BoundExpression[a.Length + b.Length]; Array.Copy(a, result, a.Length); Array.Copy(b, 0, result, a.Length, b.Length); expressions = result; } } Expressions = expressions; // If we have an empty branch, we don't have to do // any work, because nothing will be definitely assigned. if (branches.Any(p => p._assigned == null)) return; // Otherwise, we need to get the intersection of all // branches. var assigned = new List<BoundVariable>(branches[0]._assigned); for (int i = 1; i < branches.Count; i++) { var branchAssigned = branches[i]._assigned; for (int j = assigned.Count - 1; j >= 0; j--) { // If the branch does not contain an assignment // for the variable in our current collection, // remove it from our current collection. if (!branchAssigned.Contains(assigned[j])) assigned.RemoveAt(j); } // Stop processing when we don't have any variables // left. if (assigned.Count == 0) break; } // Add the assigned variables to our list. if (assigned.Count > 0) MergeAssigned(assigned); }
private BoundValueType EmitOperationCall(Operation operation, BoundExpression left, BoundExpression right) { var leftType = left.ValueType; var rightType = right.ValueType; var method = FindOperationMethod(operation, leftType, rightType); var builder = FindOperationBuilder(operation, leftType, rightType); bool boxLeft = false; bool boxRight = false; if (method == null && builder == null) { method = FindOperationMethod(operation, leftType, BoundValueType.Unknown); builder = FindOperationBuilder(operation, leftType, BoundValueType.Unknown); if (method != null || builder != null) boxRight = true; } if (method == null && builder == null) { method = FindOperationMethod(operation, BoundValueType.Unknown, rightType); builder = FindOperationBuilder(operation, BoundValueType.Unknown, rightType); if (method != null || builder != null) boxLeft = true; } if (method == null && builder == null) { method = FindOperationMethod(operation, BoundValueType.Unknown, BoundValueType.Unknown); builder = FindOperationBuilder(operation, BoundValueType.Unknown, BoundValueType.Unknown); boxLeft = true; boxRight = true; } if (builder != null) return builder(this, new[] { left, right }); if (!method.IsStatic) _scope.EmitLoad(SpecialLocal.Runtime); EmitExpression(left); if (boxLeft) EmitBox(leftType); EmitExpression(right); if (boxRight) EmitBox(rightType); return IL.EmitCall(method); }
protected bool TryGetCacheSlot(BoundExpression expression, BoundConstant constant, out int index, out FieldInfo cacheSlot) { cacheSlot = null; index = 0; string name = constant.Value as string; if (name != null) index = Generator._identifierManager.ResolveIdentifier(name); if (name == null && constant.ValueType == BoundValueType.Number) { double number = (double)constant.Value; index = (int)number; if (index != number || index < 0) return false; name = index.ToString(); } cacheSlot = Generator.ResolveCacheSlot(expression, name); return cacheSlot != null; }
public override void EmitSetValue(BoundExpression expression) { // Push the value onto the stack. Generator.EmitCast(Generator.EmitExpression(expression), Type.Type); // Store into the local. IL.Emit(OpCodes.Stloc, Local); }
private BoundValueType EmitGetMember(BoundExpression expression, int index) { if (expression.ValueType != BoundValueType.Object) _scope.EmitLoad(SpecialLocal.Runtime); EmitBox(EmitExpression(expression)); IL.EmitConstant(index); if (expression.ValueType == BoundValueType.Object) { var cacheSlot = ResolveCacheSlot(expression, _identifierManager.GetIdentifier(index)); if (cacheSlot != null) { IL.Emit(OpCodes.Ldsflda, cacheSlot); return IL.EmitCall(_objectGetPropertyCached); } return IL.EmitCall(_objectGetProperty); } return IL.EmitCall(_runtimeGetMemberByIndex); }
private BoundValueType EmitExpression(BoundExpression node) { switch (node.Kind) { case BoundKind.Binary: return EmitBinary((BoundBinary)node); case BoundKind.Call: return EmitCall((BoundCall)node); case BoundKind.Constant: return EmitConstant((BoundConstant)node); case BoundKind.CreateFunction: return EmitCreateFunction((BoundCreateFunction)node); case BoundKind.DeleteMember: return EmitDeleteMember((BoundDeleteMember)node); case BoundKind.ExpressionBlock: return EmitExpressionBlock((BoundExpressionBlock)node); case BoundKind.GetMember: return EmitGetMember((BoundGetMember)node); case BoundKind.GetVariable: return EmitGetVariable((BoundGetVariable)node); case BoundKind.HasMember: return EmitHasMember((BoundHasMember)node); case BoundKind.New: return EmitNew((BoundNew)node); case BoundKind.NewBuiltIn: return EmitNewBuiltIn((BoundNewBuiltIn)node); case BoundKind.RegEx: return EmitRegEx((BoundRegEx)node); case BoundKind.Unary: return EmitUnary((BoundUnary)node); case BoundKind.Emit: return EmitEmit((BoundEmitExpression)node); default: throw new InvalidOperationException(); } }
private FieldInfo ResolveCacheSlot(BoundExpression expression, string member) { var getVariable = expression as BoundGetVariable; if (getVariable != null) { var variable = getVariable.Variable; if (variable.Kind == BoundVariableKind.Argument) variable = GetMappedArgument((BoundArgument)variable); if (variable.Kind == BoundVariableKind.Temporary) return ResolveCacheSlot("<>Temporary" + ((BoundTemporary)variable).Index, member); if (variable.Kind == BoundVariableKind.Local) return ResolveCacheSlot(((BoundLocal)variable).Name, member); if (variable.Kind == BoundVariableKind.ClosureField) return ResolveCacheSlot(((BoundClosureField)variable).Name, member); if (variable.Kind == BoundVariableKind.Magic) return ResolveCacheSlot(((BoundMagicVariable)variable).VariableType.ToString(), member); } return null; }
private ValueEmitter GetEmitter(BoundExpression expression) { var getVariable = expression as BoundGetVariable; if (getVariable == null) return null; var emitter = _scope.GetEmitter(getVariable.Variable); if (emitter != null) return emitter; if (getVariable.Variable.Kind == BoundVariableKind.Argument) { var mappedArgument = GetMappedArgument((BoundArgument)getVariable.Variable); if (mappedArgument != null) return _scope.GetEmitter(mappedArgument); } return null; }
private void EmitTest(BoundExpression test, Label target, bool inverse) { // TODO: This should be optimized. E.g. the compare expressions // could be changed to e.g. a Bgt. var type = EmitExpression(test); EmitCast(type, BoundValueType.Boolean); IL.Emit(inverse ? OpCodes.Brfalse : OpCodes.Brtrue, target); }
private void EmitTest(BoundExpression test, Label target) { EmitTest(test, target, false); }
private void EmitSetVariable(IBoundWritable variable, BoundExpression value) { switch (variable.Kind) { case BoundVariableKind.Global: _scope.GlobalScopeEmitter.EmitSetMember(new BoundSetMember( new BoundGetVariable(BoundMagicVariable.Global), BoundConstant.Create(((BoundGlobal)variable).Name), value, SourceLocation.Missing )); break; case BoundVariableKind.Local: case BoundVariableKind.Temporary: case BoundVariableKind.ClosureField: _scope.GetEmitter(variable).EmitSetValue(value); break; case BoundVariableKind.Argument: var argument = (BoundArgument)variable; // Check whether the argument is mapped to a local or closure // field. var scope = argument.Closure == null ? _scope : _scope.FindScope(argument.Closure); var mappedArgument = scope.GetMappedArgument(argument); if (mappedArgument != null) { EmitSetVariable(mappedArgument, value); return; } BoundGetVariable getVariable; if (scope.ArgumentsClosureField != null) getVariable = new BoundGetVariable(scope.ArgumentsClosureField); else getVariable = new BoundGetVariable(BoundMagicVariable.Arguments); EmitSetMember(new BoundSetMember( getVariable, BoundConstant.Create((double)argument.Index), value, SourceLocation.Missing )); return; default: throw new InvalidOperationException(); } }
private BoundValueType EmitGetMember(BoundExpression expression, BoundExpression index) { return EmitOperationCall(Operation.Member, expression, index); }
public override void EmitSetValue(BoundExpression expression) { // Load the reference to the local. IL.Emit(OpCodes.Ldloca, Local); // Push the value onto the stack. Generator.EmitCast(Generator.EmitExpression(expression), Type.Type); // Call set_Value. IL.EmitCall(_setValue); }
private BoundExpression BuildGetMember(BoundExpression expression, BoundExpression index) { return new BoundGetMember( expression, index ); }
public abstract void EmitSetValue(BoundExpression expression);
private BoundStatement BuildSet(SyntaxNode syntax, BoundExpression value) { switch (syntax.Type) { case SyntaxType.Identifier: var identifier = ((IdentifierSyntax)syntax).Identifier; if (identifier.Type == IdentifierType.Global) _scope.IsGlobalScopeReferenced = true; return BuildSet(identifier, value); case SyntaxType.Property: var property = (PropertySyntax)syntax; return BuildSetMember( BuildExpression(property.Expression), BoundConstant.Create(property.Name), value ); case SyntaxType.Indexer: var indexer = (IndexerSyntax)syntax; return BuildSetMember( BuildGet(indexer.Expression), BuildExpression(indexer.Index), value ); default: throw new InvalidOperationException(); } }
private BoundValueType EmitOperationCall(Operation operation, BoundExpression obj, BoundExpression index, BoundExpression value) { var indexType = index.ValueType; bool boxIndex = false; var method = FindOperationMethod(operation, BoundValueType.Unknown, indexType, BoundValueType.Unknown); var builder = FindOperationBuilder(operation, BoundValueType.Unknown, indexType, BoundValueType.Unknown); if (method == null && builder == null) { method = FindOperationMethod(operation, BoundValueType.Unknown, BoundValueType.Unknown, BoundValueType.Unknown); builder = FindOperationBuilder(operation, BoundValueType.Unknown, BoundValueType.Unknown, BoundValueType.Unknown); boxIndex = true; } if (builder != null) return builder(this, new[] { obj, index, value }); if (!method.IsStatic) _scope.EmitLoad(SpecialLocal.Runtime); EmitBox(EmitExpression(obj)); EmitExpression(index); if (boxIndex) EmitBox(indexType); EmitBox(EmitExpression(value)); return IL.EmitCall(method); }
private BoundStatement BuildSet(IIdentifier identifier, BoundExpression value) { switch (identifier.Type) { case IdentifierType.Parameter: return new BoundSetVariable( _scope.GetArgument(identifier), value, SourceLocation.Missing ); case IdentifierType.Scoped: var builder = new BlockBuilder(this); var valueTemporary = builder.CreateTemporary(); builder.Add(new BoundSetVariable( valueTemporary, value, SourceLocation.Missing )); builder.Add(BuildSetWithScope(builder, identifier.WithScope, identifier.Fallback, valueTemporary)); return builder.BuildBlock(SourceLocation.Missing); case IdentifierType.Local: case IdentifierType.Global: if (identifier.Type == IdentifierType.Global) _scope.IsGlobalScopeReferenced = true; if (identifier.Closure == null) return new BoundSetVariable(_scope.GetLocal(identifier), value, SourceLocation.Missing); return new BoundSetVariable( _scope.GetClosureField(identifier), value, SourceLocation.Missing ); /* // These are handled upstream. case IdentifierType.This: case IdentifierType.Null: case IdentifierType.Undefined: case IdentifierType.Arguments: */ default: throw new InvalidOperationException("Cannot find variable of argument"); } }
private BoundValueType EmitOperationCall(Operation operation, BoundExpression operand) { var operandType = operand.ValueType; var method = FindOperationMethod(operation, operandType); var builder = FindOperationBuilder(operation, operandType); bool boxOperand = false; if (method == null && builder == null) { method = FindOperationMethod(operation, BoundValueType.Unknown); builder = FindOperationBuilder(operation, BoundValueType.Unknown); boxOperand = true; } if (builder != null) return builder(this, new[] { operand }); if (!method.IsStatic) _scope.EmitLoad(SpecialLocal.Runtime); EmitExpression(operand); if (boxOperand) EmitBox(operandType); return IL.EmitCall(method); }
private BoundSetMember BuildSetMember(BoundExpression expression, BoundExpression index, BoundExpression value) { return new BoundSetMember( expression, index, value, SourceLocation.Missing ); }
public void MarkExpression(BoundExpression expression) { Expressions = new[] { expression }; }
private void EmitSetMember(BoundExpression expression, int index, BoundExpression value) { EmitBox(EmitExpression(expression)); IL.EmitConstant(index); EmitBox(EmitExpression(value)); if (expression.ValueType == BoundValueType.Object) { var cacheSlot = ResolveCacheSlot(expression, _identifierManager.GetIdentifier(index)); if (cacheSlot != null) { IL.Emit(OpCodes.Ldsflda, cacheSlot); IL.EmitCall(_objectSetPropertyCached, BoundValueType.Unset); } else { IL.EmitCall(_objectSetProperty, BoundValueType.Unset); } } else { IL.EmitCall(_runtimeSetMemberByIndex, BoundValueType.Unset); } }