private BoundExpression BuildGet(ExpressionSyntax syntax, BoundTemporary withTarget) { switch (syntax.Type) { case SyntaxType.Identifier: var identifier = ((IdentifierSyntax)syntax).Identifier; if (identifier.Type == IdentifierType.Global) _scope.IsGlobalScopeReferenced = true; return BuildGet(identifier, withTarget); case SyntaxType.Property: var property = (PropertySyntax)syntax; return BuildGetMember( BuildExpression(property.Expression), BoundConstant.Create(property.Name) ); case SyntaxType.Indexer: var indexer = (IndexerSyntax)syntax; return BuildGetMember( BuildGet(indexer.Expression, withTarget), BuildExpression(indexer.Index) ); default: return BuildExpression(syntax); } }
public Rewriter(IEnumerable<BoundExpression> resultExpressions, BoundTypeManager typeManager) { _typeManager = typeManager; _resultExpressions = new HashSet<BoundExpression>(resultExpressions); _resultTemporary = new BoundTemporary( --_lastTemporaryIndex, typeManager.CreateType(null, BoundTypeKind.Temporary) ); }
public override BoundNode Visit(BoundNode node) { var expression = node as BoundExpression; if (expression != null && _resultExpressions.Contains(expression)) { // Create a temporary to hold the result. var temporary = new BoundTemporary( --_lastTemporaryIndex, _typeManager.CreateType(null, BoundTypeKind.Temporary) ); var nodes = new ReadOnlyArray<BoundStatement>.Builder(); // Initialize the temporary with the expression. nodes.Add(new BoundSetVariable( temporary, expression, SourceLocation.Missing )); // Copy the temporary to the result. nodes.Add(new BoundSetVariable( _resultTemporary, new BoundGetVariable(temporary), SourceLocation.Missing )); // Return an expression block. return new BoundExpressionBlock( temporary, new BoundBlock( ReadOnlyArray<BoundTemporary>.CreateFrom(temporary), nodes.ToReadOnly(), SourceLocation.Missing ) ); } return base.Visit(node); }
private void MarkRead(BoundTemporary temporary) { // Check if the local is still valid. If this temporary is // only written to from a local, it is eligible for replacement. // However, we can only do this when the local hasn't been // changed before we read the temporary. This is what is // checked below. var statistics = GetStatistic(temporary); if (statistics.WriteState == WriteType.Local && statistics.Value != null) { var getVariable = statistics.Value.Expression as BoundGetVariable; if (getVariable != null) { var local = getVariable.Variable as BoundLocal; if (local != null) { int writeCount; _variableWriteCount.TryGetValue(local, out writeCount); if (writeCount != statistics.Value.WriteCount) statistics.WriteState = WriteType.DoNotRemove; } } } statistics.Reads++; }
private Statistics GetStatistic(BoundTemporary temporary) { Statistics statistics; if (!_statistics.TryGetValue(temporary, out statistics)) { statistics = new Statistics(); _statistics.Add(temporary, statistics); } return statistics; }
public BoundTemporary CreateTemporary() { var result = new BoundTemporary( _visitor._scope.GetNextTemporaryIndex(), _visitor._scope.TypeManager.CreateType(null, BoundTypeKind.Temporary) ); if (_temporaries == null) _temporaries = new ReadOnlyArray<BoundTemporary>.Builder(); _temporaries.Add(result); return result; }
public BoundExpression BuildExpression(BoundTemporary result, SourceLocation location) { return new BoundExpressionBlock( result, new BoundBlock( _temporaries == null ? ReadOnlyArray<BoundTemporary>.Empty : _temporaries.ToReadOnly(), _nodes == null ? ReadOnlyArray<BoundStatement>.Empty : _nodes.ToReadOnly(), location ) ); }
private BoundIf BuildSetWithScope(BlockBuilder builder, WithScope withScope, IIdentifier fallback, BoundTemporary value) { var withLocal = builder.CreateTemporary(); builder.Add(new BoundSetVariable( withLocal, new BoundGetVariable(_withIdentifiers[withScope.Identifier]), SourceLocation.Missing )); var setter = new BoundSetMember( new BoundGetVariable(withLocal), BoundConstant.Create(fallback.Name), new BoundGetVariable(value), SourceLocation.Missing ); BoundBlock @else; if (withScope.Parent == null) { @else = BuildBlock(BuildSet( fallback, new BoundGetVariable(value) )); } else { @else = BuildBlock(BuildSetWithScope( builder, withScope.Parent, fallback, value )); } return new BoundIf( new BoundHasMember( new BoundGetVariable(withLocal), fallback.Name ), BuildBlock(setter), @else, SourceLocation.Missing ); }
private BoundIf BuildGetWithScope(BlockBuilder builder, WithScope withScope, IIdentifier fallback, BoundTemporary result, BoundTemporary withTarget) { var withLocal = builder.CreateTemporary(); builder.Add(new BoundSetVariable( withLocal, new BoundGetVariable(_withIdentifiers[withScope.Identifier]), SourceLocation.Missing )); var getter = new BlockBuilder(this); if (withTarget != null) { getter.Add(new BoundSetVariable( withTarget, new BoundGetVariable(withLocal), SourceLocation.Missing )); } getter.Add(new BoundSetVariable( result, BuildGetMember( new BoundGetVariable(withLocal), BoundConstant.Create(fallback.Name) ), SourceLocation.Missing )); BoundBlock @else; if (withScope.Parent == null) { @else = BuildBlock(new BoundSetVariable( result, BuildGet( fallback, null ), SourceLocation.Missing )); } else { @else = BuildBlock(BuildGetWithScope( builder, withScope.Parent, fallback, result, withTarget )); } return new BoundIf( new BoundHasMember( new BoundGetVariable(withLocal), fallback.Name ), getter.BuildBlock(SourceLocation.Missing), @else, SourceLocation.Missing ); }
private BoundExpression BuildGet(IIdentifier identifier, BoundTemporary withTarget) { switch (identifier.Type) { case IdentifierType.Null: return new BoundGetVariable(BoundMagicVariable.Null); case IdentifierType.Undefined: return new BoundGetVariable(BoundMagicVariable.Undefined); case IdentifierType.This: _scope.IsThisReferenced = true; return new BoundGetVariable(BoundMagicVariable.This); case IdentifierType.Arguments: _scope.IsArgumentsReferenced = true; return new BoundGetVariable(BoundMagicVariable.Arguments); case IdentifierType.Parameter: return new BoundGetVariable(_scope.GetArgument(identifier)); case IdentifierType.Scoped: var builder = new BlockBuilder(this); var result = builder.CreateTemporary(); builder.Add( BuildGetWithScope(builder, identifier.WithScope, identifier.Fallback, result, withTarget) ); return builder.BuildExpression(result, SourceLocation.Missing); case IdentifierType.Local: case IdentifierType.Global: if (identifier.Closure != null) return new BoundGetVariable(_scope.GetClosureField(identifier)); return new BoundGetVariable(_scope.GetLocal(identifier)); default: throw new InvalidOperationException("Cannot find variable of argument"); } }