Chromium Code Reviews| Index: pkg/kernel/lib/interpreter/interpreter.dart |
| diff --git a/pkg/kernel/lib/interpreter/interpreter.dart b/pkg/kernel/lib/interpreter/interpreter.dart |
| index 6741928fa9ff7753c95d631e6446171560f27145..9f3b525e25414c0426ad33f8465032d3db06f9d9 100644 |
| --- a/pkg/kernel/lib/interpreter/interpreter.dart |
| +++ b/pkg/kernel/lib/interpreter/interpreter.dart |
| @@ -21,6 +21,8 @@ class Interpreter { |
| Program program; |
| StatementExecuter visitor = new StatementExecuter(); |
| + static MainEnvironment mainEnvironment = new MainEnvironment(); |
| + |
| Interpreter(this.program); |
| void run() { |
| @@ -57,6 +59,25 @@ class Binding { |
| Binding(this.variable, this.location); |
| } |
| +class MainEnvironment { |
| + Map<Member, Location> _staticFields = <Member, Location>{}; |
| + |
| + bool contains(Member member) => _staticFields[member] != null; |
| + |
| + Value lookup(Member member) { |
| + assert(contains(member)); |
| + return _staticFields[member].value; |
| + } |
| + |
| + void update(Member member, Value value) { |
|
Dmitry Stefantsov
2017/08/16 08:25:39
I would add a comment that [MainEnvironment] insta
|
| + if (_staticFields[member] == null) { |
| + _staticFields[member] = new Location(value); |
| + } else { |
| + _staticFields[member].value = value; |
| + } |
| + } |
| +} |
| + |
| class Environment { |
| final List<Binding> bindings = <Binding>[]; |
| final Environment parent; |
| @@ -174,10 +195,64 @@ class Evaluator extends ExpressionVisitor1<Configuration, EvalConfiguration> { |
| node.receiver, config.environment, config.exceptionComponents, cont); |
| } |
| - Configuration visitStaticGet(StaticGet node, EvalConfiguration config) => |
| - defaultExpression(node, config); |
| - Configuration visitStaticSet(StaticSet node, EvalConfiguration config) => |
| - defaultExpression(node, config); |
| + Configuration visitStaticGet(StaticGet node, EvalConfiguration config) { |
| + Member member = node.target; |
| + |
| + if (member is Procedure && !member.isAccessor) { |
| + // Create a closure for the method tear off. |
| + var v = new FunctionValue( |
| + member.function, new EnvironmentLocation(new Environment.empty())); |
| + return new ValuePassingConfiguration(config.continuation, v); |
| + } |
| + |
| + if (member is Procedure && member.isGetter) { |
| + // Execute the body of the getter. |
| + var state = new State.initial() |
| + .withReturnContinuation(config.continuation) |
| + .withContinuation(new ExitSK(config.continuation, Value.nullInstance)) |
| + .withException(config.exceptionComponents); |
| + return new ExecConfiguration( |
| + member.function.body, new Environment.empty(), state); |
| + } |
| + |
| + assert(member is Field); |
| + if (Interpreter.mainEnvironment.contains(member)) { |
|
Dmitry Stefantsov
2017/08/16 08:25:39
I would use a special value to indicate that the s
|
| + // Read the value for the member in the main environment. |
| + return new ValuePassingConfiguration( |
| + config.continuation, Interpreter.mainEnvironment.lookup(member)); |
| + } |
| + |
| + // Otherwise, the static field is accessed for the first time. |
| + // We store `Value.nullInstance` if there the field doesn't have an |
| + // initializer. |
| + if ((member as Field).initializer == null) { |
| + Interpreter.mainEnvironment.update(member, Value.nullInstance); |
|
Dmitry Stefantsov
2017/08/16 08:25:39
If the special value for uninitialized variables h
|
| + return new ValuePassingConfiguration( |
| + config.continuation, Value.nullInstance); |
| + } |
| + |
| + // The initializer expression is evaluated otherwise. |
| + var cont = new StaticSetEK(member, config.continuation); |
| + return new EvalConfiguration((member as Field).initializer, |
| + new Environment.empty(), config.exceptionComponents, cont); |
| + } |
| + |
| + Configuration visitStaticSet(StaticSet node, EvalConfiguration config) { |
| + Member member = node.target; |
| + ExpressionContinuation cont; |
| + |
| + if (member is Procedure) { |
| + assert(member.isSetter); |
| + cont = new StaticSetterEK( |
| + member.function, config.exceptionComponents, config.continuation); |
| + } else { |
| + assert(member is Field); |
| + cont = new StaticSetEK(member, config.continuation); |
| + } |
| + |
| + return new EvalConfiguration( |
| + node.value, config.environment, config.exceptionComponents, cont); |
| + } |
| Configuration visitStaticInvocation( |
| StaticInvocation node, EvalConfiguration config) { |
| @@ -429,8 +504,9 @@ class ExecConfiguration extends Configuration { |
| ExecConfiguration(this.currentStatement, this.environment, this.state); |
| - Configuration step(StatementExecuter executer) => |
| - executer.exec(currentStatement, this); |
| + Configuration step(StatementExecuter executer) { |
| + return executer.exec(currentStatement, this); |
| + } |
| } |
| /// Configuration for applying a [StatementContinuation] to an [Environment]. |
| @@ -1003,6 +1079,39 @@ class SetterEK extends ExpressionContinuation { |
| } |
| } |
| +class StaticSetEK extends ExpressionContinuation { |
| + final Member member; |
| + final ExpressionContinuation continuation; |
| + |
| + StaticSetEK(this.member, this.continuation); |
| + |
| + Configuration call(Value v) { |
| + Interpreter.mainEnvironment.update(member, v); |
| + return new ValuePassingConfiguration(continuation, v); |
| + } |
| +} |
| + |
| +class StaticSetterEK extends ExpressionContinuation { |
| + final FunctionNode setter; |
| + final ExceptionComponents exceptionComponents; |
| + final ExpressionContinuation expressionContinuation; |
| + |
| + StaticSetterEK( |
| + this.setter, this.exceptionComponents, this.expressionContinuation); |
| + |
| + Configuration call(Value v) { |
| + VariableDeclaration arg = setter.positionalParameters.first; |
| + var env = new Environment.empty().extend(arg, v); |
| + var state = new State.initial() |
| + .withException(exceptionComponents) |
| + .withReturnContinuation(expressionContinuation) |
| + .withContinuation( |
| + new ExitSK(expressionContinuation, Value.nullInstance)); |
| + |
| + return new ExecConfiguration(setter.body, env, state); |
| + } |
| +} |
| + |
| /// Represents a continuation to be called after the evaluation of an actual |
| /// argument for function invocation. |
| class ExpressionListEK extends ExpressionContinuation { |
| @@ -1541,10 +1650,9 @@ class StatementExecuter |
| conf.state.continuation, conf.environment); |
| } |
| - var env = new Environment(conf.environment); |
| var cont = new BlockSK.fromConfig(node.statements.skip(1).toList(), conf); |
| - return new ExecConfiguration( |
| - node.statements.first, env, conf.state.withContinuation(cont)); |
| + return new ExecConfiguration(node.statements.first, conf.environment, |
| + conf.state.withContinuation(cont)); |
| } |
| Configuration visitEmptyStatement( |