OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dart2js.ir_builder; | 5 library dart2js.ir_builder; |
6 | 6 |
7 import '../constants/constant_system.dart'; | 7 import '../constants/constant_system.dart'; |
8 import '../constants/expressions.dart'; | 8 import '../constants/expressions.dart'; |
9 import '../constants/values.dart' show PrimitiveConstantValue; | 9 import '../constants/values.dart' show PrimitiveConstantValue; |
10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
388 final List<JumpCollector> continueCollectors = <JumpCollector>[]; | 388 final List<JumpCollector> continueCollectors = <JumpCollector>[]; |
389 | 389 |
390 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; | 390 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; |
391 | 391 |
392 final ExecutableElement currentElement; | 392 final ExecutableElement currentElement; |
393 | 393 |
394 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); | 394 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); |
395 ir.Parameter _thisParameter; | 395 ir.Parameter _thisParameter; |
396 ir.Parameter enclosingMethodThisParameter; | 396 ir.Parameter enclosingMethodThisParameter; |
397 | 397 |
398 final List<ir.Definition> functionParameters = <ir.Definition>[]; | 398 final List<ir.Parameter> functionParameters = <ir.Parameter>[]; |
399 | 399 |
400 IrBuilderSharedState(this.constantSystem, this.currentElement); | 400 IrBuilderSharedState(this.constantSystem, this.currentElement); |
401 | 401 |
402 ir.Parameter get thisParameter => _thisParameter; | 402 ir.Parameter get thisParameter => _thisParameter; |
403 void set thisParameter(ir.Parameter value) { | 403 void set thisParameter(ir.Parameter value) { |
404 assert(_thisParameter == null); | 404 assert(_thisParameter == null); |
405 _thisParameter = value; | 405 _thisParameter = value; |
406 } | 406 } |
407 } | 407 } |
408 | 408 |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
558 /// variables to their values. If an optional environment argument is | 558 /// variables to their values. If an optional environment argument is |
559 /// supplied, it is used as the builder's initial environment. Otherwise | 559 /// supplied, it is used as the builder's initial environment. Otherwise |
560 /// the environment is initially a copy of the parent builder's environment. | 560 /// the environment is initially a copy of the parent builder's environment. |
561 IrBuilder makeDelimitedBuilder([Environment env = null]) { | 561 IrBuilder makeDelimitedBuilder([Environment env = null]) { |
562 return _makeInstance() | 562 return _makeInstance() |
563 ..state = state | 563 ..state = state |
564 ..environment = env != null ? env : new Environment.from(environment) | 564 ..environment = env != null ? env : new Environment.from(environment) |
565 ..mutableVariables = mutableVariables; | 565 ..mutableVariables = mutableVariables; |
566 } | 566 } |
567 | 567 |
568 /// Construct a builder for making constructor field initializers. | |
569 IrBuilder makeInitializerBuilder() { | |
570 return _makeInstance() | |
571 ..state = new IrBuilderSharedState(state.constantSystem, | |
572 state.currentElement) | |
573 ..environment = new Environment.from(environment) | |
574 ..mutableVariables = mutableVariables; | |
575 } | |
576 | |
577 /// Construct a builder for an inner function. | |
578 IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) { | |
579 IrBuilderSharedState innerState = | |
580 new IrBuilderSharedState(state.constantSystem, currentElement) | |
581 ..enclosingMethodThisParameter = state.enclosingMethodThisParameter; | |
582 return _makeInstance() | |
583 ..state = innerState | |
584 ..environment = new Environment.empty() | |
585 ..mutableVariables = | |
586 new Map<Local, ir.MutableVariable>.from(mutableVariables); | |
587 } | |
588 | |
589 bool get isOpen => _root == null || _current != null; | 568 bool get isOpen => _root == null || _current != null; |
590 | 569 |
591 | |
592 void buildFieldInitializerHeader({ClosureScope closureScope}) { | |
593 _enterScope(closureScope); | |
594 } | |
595 | |
596 List<ir.Primitive> buildFunctionHeader(Iterable<Local> parameters, | 570 List<ir.Primitive> buildFunctionHeader(Iterable<Local> parameters, |
597 {ClosureScope closureScope, | 571 {ClosureScope closureScope, |
598 ClosureEnvironment env}) { | 572 ClosureEnvironment env}) { |
599 _createThisParameter(); | 573 _createThisParameter(); |
600 _enterClosureEnvironment(env); | 574 _enterClosureEnvironment(env); |
601 _enterScope(closureScope); | 575 _enterScope(closureScope); |
602 parameters.forEach(_createFunctionParameter); | 576 parameters.forEach(_createFunctionParameter); |
603 return _parameters; | 577 return _parameters; |
604 } | 578 } |
605 | 579 |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
825 * statement on each branch. This includes functions with an empty body, | 799 * statement on each branch. This includes functions with an empty body, |
826 * such as `foo(){ }`. | 800 * such as `foo(){ }`. |
827 */ | 801 */ |
828 void _ensureReturn() { | 802 void _ensureReturn() { |
829 if (!isOpen) return; | 803 if (!isOpen) return; |
830 ir.Constant constant = buildNullConstant(); | 804 ir.Constant constant = buildNullConstant(); |
831 add(new ir.InvokeContinuation(state.returnContinuation, [constant])); | 805 add(new ir.InvokeContinuation(state.returnContinuation, [constant])); |
832 _current = null; | 806 _current = null; |
833 } | 807 } |
834 | 808 |
835 ir.SuperInitializer makeSuperInitializer(ConstructorElement target, | 809 /// Create a [ir.FunctionDefinition] using [_root] as the body. |
836 List<ir.Body> arguments, | |
837 Selector selector) { | |
838 return new ir.SuperInitializer(target, arguments, selector); | |
839 } | |
840 | |
841 ir.FieldInitializer makeFieldInitializer(FieldElement element, | |
842 ir.Body body) { | |
843 return new ir.FieldInitializer(element, body); | |
844 } | |
845 | |
846 /// Create a [ir.FieldDefinition] for the current [Element] using [_root] as | |
847 /// the body using [initializer] as the initial value. | |
848 ir.FieldDefinition makeFieldDefinition(ir.Primitive initializer) { | |
849 if (initializer == null) { | |
850 return new ir.FieldDefinition.withoutInitializer(state.currentElement); | |
851 } else { | |
852 ir.Body body = makeBody(initializer); | |
853 return new ir.FieldDefinition(state.currentElement, body); | |
854 } | |
855 } | |
856 | |
857 ir.Body makeBody([ir.Primitive value]) { | |
858 if (value == null) { | |
859 _ensureReturn(); | |
860 } else { | |
861 buildReturn(value); | |
862 } | |
863 return new ir.Body(_root, state.returnContinuation); | |
864 } | |
865 | |
866 /// Create a [ir.FunctionDefinition] for [element] using [_root] as the body. | |
867 /// | 810 /// |
868 /// Parameters must be created before the construction of the body using | 811 /// The protocol for building a function is: |
869 /// [createFunctionParameter]. | 812 /// 1. Call [buildFunctionHeader]. |
870 ir.FunctionDefinition makeFunctionDefinition( | 813 /// 2. Call `buildXXX` methods to build the body. |
871 List<ConstantExpression> defaults) { | 814 /// 3. Call [makeFunctionDefinition] to finish. |
872 FunctionElement element = state.currentElement; | 815 ir.FunctionDefinition makeFunctionDefinition() { |
873 if (element.isAbstract || element.isExternal) { | 816 _ensureReturn(); |
874 assert(invariant(element, _root == null, | 817 return new ir.FunctionDefinition( |
875 message: "Non-empty body for abstract method $element: $_root")); | 818 state.currentElement, |
876 assert(invariant(element, state.localConstants.isEmpty, | 819 state.thisParameter, |
877 message: "Local constants for abstract method $element: " | 820 state.functionParameters, |
878 "${state.localConstants}")); | 821 state.returnContinuation, |
879 return new ir.FunctionDefinition.abstract( | 822 _root); |
880 element, state.functionParameters, defaults); | |
881 } else { | |
882 ir.Body body = makeBody(); | |
883 return new ir.FunctionDefinition( | |
884 element, state.thisParameter, state.functionParameters, body, | |
885 state.localConstants, defaults); | |
886 } | |
887 } | |
888 | |
889 /// Create a constructor definition without a body, for representing | |
890 /// external constructors declarations. | |
891 ir.ConstructorDefinition makeAbstractConstructorDefinition( | |
892 List<ConstantExpression> defaults) { | |
893 FunctionElement element = state.currentElement; | |
894 assert(invariant(element, _root == null, | |
895 message: "Non-empty body for external constructor $element: $_root")); | |
896 assert(invariant(element, state.localConstants.isEmpty, | |
897 message: "Local constants for external constructor $element: " | |
898 "${state.localConstants}")); | |
899 return new ir.ConstructorDefinition.abstract( | |
900 element, state.functionParameters, defaults); | |
901 } | |
902 | |
903 ir.ConstructorDefinition makeConstructorDefinition( | |
904 List<ConstantExpression> defaults, List<ir.Initializer> initializers) { | |
905 FunctionElement element = state.currentElement; | |
906 ir.Body body = makeBody(); | |
907 return new ir.ConstructorDefinition( | |
908 element, state.thisParameter, state.functionParameters, body, initialize
rs, | |
909 state.localConstants, defaults); | |
910 } | |
911 | |
912 ir.FunctionDefinition makeLazyFieldInitializer() { | |
913 ir.Body body = makeBody(); | |
914 FieldElement element = state.currentElement; | |
915 return new ir.FunctionDefinition(element, null, [], body, [], []); | |
916 } | 823 } |
917 | 824 |
918 /// Create a invocation of the [method] on the super class where the call | 825 /// Create a invocation of the [method] on the super class where the call |
919 /// structure is defined [callStructure] and the argument values are defined | 826 /// structure is defined [callStructure] and the argument values are defined |
920 /// by [arguments]. | 827 /// by [arguments]. |
921 ir.Primitive buildSuperMethodInvocation(MethodElement method, | 828 ir.Primitive buildSuperMethodInvocation(MethodElement method, |
922 CallStructure callStructure, | 829 CallStructure callStructure, |
923 List<ir.Primitive> arguments) { | 830 List<ir.Primitive> arguments) { |
924 // TODO(johnniwinther): This shouldn't be necessary. | 831 // TODO(johnniwinther): This shouldn't be necessary. |
925 SelectorKind kind = Elements.isOperatorName(method.name) | 832 SelectorKind kind = Elements.isOperatorName(method.name) |
(...skipping 1170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2096 leftTrueContinuation, | 2003 leftTrueContinuation, |
2097 leftFalseContinuation)))); | 2004 leftFalseContinuation)))); |
2098 environment = join.environment; | 2005 environment = join.environment; |
2099 environment.discard(1); | 2006 environment.discard(1); |
2100 // There is always a join parameter for the result value, because it | 2007 // There is always a join parameter for the result value, because it |
2101 // is different on at least two paths. | 2008 // is different on at least two paths. |
2102 return join.continuation.parameters.last; | 2009 return join.continuation.parameters.last; |
2103 } | 2010 } |
2104 } | 2011 } |
2105 | 2012 |
2106 /// Shared state between DartIrBuilders within the same method. | |
2107 class DartIrBuilderSharedState { | |
2108 /// [MutableVariable]s that should temporarily be treated as registers. | |
2109 final Set<Local> registerizedMutableVariables = new Set<Local>(); | |
2110 } | |
2111 | |
2112 /// Dart-specific subclass of [IrBuilder]. | |
2113 /// | |
2114 /// Inner functions are represented by a [FunctionDefinition] with the | |
2115 /// IR for the inner function nested inside. | |
2116 /// | |
2117 /// Captured variables are translated to ref cells (see [MutableVariable]) | |
2118 /// using [GetMutableVariable] and [SetMutableVariable]. | |
2119 class DartIrBuilder extends IrBuilder { | |
2120 final DartIrBuilderSharedState dartState; | |
2121 | |
2122 IrBuilder _makeInstance() => new DartIrBuilder._blank(dartState); | |
2123 DartIrBuilder._blank(this.dartState); | |
2124 | |
2125 DartIrBuilder(ConstantSystem constantSystem, | |
2126 ExecutableElement currentElement, | |
2127 Set<Local> capturedVariables) | |
2128 : dartState = new DartIrBuilderSharedState() { | |
2129 _init(constantSystem, currentElement); | |
2130 capturedVariables.forEach(makeMutableVariable); | |
2131 } | |
2132 | |
2133 @override | |
2134 bool isInMutableVariable(Local local) { | |
2135 return mutableVariables.containsKey(local) && | |
2136 !dartState.registerizedMutableVariables.contains(local); | |
2137 } | |
2138 | |
2139 void _enterScope(ClosureScope scope) { | |
2140 assert(scope == null); | |
2141 } | |
2142 | |
2143 void _enterClosureEnvironment(ClosureEnvironment env) { | |
2144 assert(env == null); | |
2145 } | |
2146 | |
2147 void _enterForLoopInitializer(ClosureScope scope, | |
2148 List<LocalElement> loopVariables) { | |
2149 assert(scope == null); | |
2150 for (LocalElement loopVariable in loopVariables) { | |
2151 if (mutableVariables.containsKey(loopVariable)) { | |
2152 // Temporarily keep the loop variable in a primitive. | |
2153 // The loop variable will be added to environment when | |
2154 // [declareLocalVariable] is called. | |
2155 dartState.registerizedMutableVariables.add(loopVariable); | |
2156 } | |
2157 } | |
2158 } | |
2159 | |
2160 void _enterForLoopBody(ClosureScope scope, | |
2161 List<LocalElement> loopVariables) { | |
2162 assert(scope == null); | |
2163 for (LocalElement loopVariable in loopVariables) { | |
2164 if (mutableVariables.containsKey(loopVariable)) { | |
2165 // Move from [Primitive] into [MutableVariable]. | |
2166 dartState.registerizedMutableVariables.remove(loopVariable); | |
2167 add(new ir.LetMutable(getMutableVariable(loopVariable), | |
2168 environment.lookup(loopVariable))); | |
2169 } | |
2170 } | |
2171 } | |
2172 | |
2173 void _enterForLoopUpdate(ClosureScope scope, | |
2174 List<LocalElement> loopVariables) { | |
2175 assert(scope == null); | |
2176 // Move captured loop variables back into the local environment. | |
2177 // The update expression will use the values we put in the environment, | |
2178 // and then the environments for the initializer and update will be | |
2179 // joined at the head of the body. | |
2180 for (LocalElement loopVariable in loopVariables) { | |
2181 if (isInMutableVariable(loopVariable)) { | |
2182 ir.MutableVariable mutableVariable = getMutableVariable(loopVariable); | |
2183 ir.Primitive value = | |
2184 addPrimitive(new ir.GetMutableVariable(mutableVariable)); | |
2185 environment.update(loopVariable, value); | |
2186 dartState.registerizedMutableVariables.add(loopVariable); | |
2187 } | |
2188 } | |
2189 } | |
2190 | |
2191 void _createFunctionParameter(Local parameterElement) { | |
2192 ir.Parameter parameter = new ir.Parameter(parameterElement); | |
2193 _parameters.add(parameter); | |
2194 if (isInMutableVariable(parameterElement)) { | |
2195 state.functionParameters.add(getMutableVariable(parameterElement)); | |
2196 } else { | |
2197 state.functionParameters.add(parameter); | |
2198 environment.extend(parameterElement, parameter); | |
2199 } | |
2200 } | |
2201 | |
2202 void _createThisParameter() { | |
2203 void create() { | |
2204 ir.Parameter thisParameter = | |
2205 new ir.Parameter(new ThisParameterLocal(state.currentElement)); | |
2206 state.thisParameter = thisParameter; | |
2207 state.enclosingMethodThisParameter = thisParameter; | |
2208 } | |
2209 if (state.currentElement.isLocal) return; | |
2210 if (state.currentElement.isStatic) return; | |
2211 if (state.currentElement.isGenerativeConstructor) { | |
2212 create(); | |
2213 return; | |
2214 } | |
2215 if (state.currentElement.isStatic) return; | |
2216 if (state.currentElement.isInstanceMember) { | |
2217 create(); | |
2218 return; | |
2219 } | |
2220 } | |
2221 | |
2222 void declareLocalVariable(LocalVariableElement variableElement, | |
2223 {ir.Primitive initialValue}) { | |
2224 assert(isOpen); | |
2225 if (initialValue == null) { | |
2226 initialValue = buildNullConstant(); | |
2227 } | |
2228 if (isInMutableVariable(variableElement)) { | |
2229 add(new ir.LetMutable(getMutableVariable(variableElement), | |
2230 initialValue)); | |
2231 } else { | |
2232 initialValue.useElementAsHint(variableElement); | |
2233 environment.extend(variableElement, initialValue); | |
2234 } | |
2235 } | |
2236 | |
2237 /// Add [functionElement] to the environment with provided [definition]. | |
2238 void declareLocalFunction(LocalFunctionElement functionElement, | |
2239 ir.FunctionDefinition definition) { | |
2240 assert(isOpen); | |
2241 if (isInMutableVariable(functionElement)) { | |
2242 ir.MutableVariable variable = getMutableVariable(functionElement); | |
2243 add(new ir.DeclareFunction(variable, definition)); | |
2244 } else { | |
2245 ir.CreateFunction prim = addPrimitive(new ir.CreateFunction(definition)); | |
2246 environment.extend(functionElement, prim); | |
2247 prim.useElementAsHint(functionElement); | |
2248 } | |
2249 } | |
2250 | |
2251 /// Create a function expression from [definition]. | |
2252 ir.Primitive buildFunctionExpression(ir.FunctionDefinition definition) { | |
2253 return addPrimitive(new ir.CreateFunction(definition)); | |
2254 } | |
2255 | |
2256 /// Create a read access of [local]. | |
2257 @override | |
2258 ir.Primitive _buildLocalGet(LocalElement local) { | |
2259 assert(isOpen); | |
2260 if (isInMutableVariable(local)) { | |
2261 // Do not use [local] as a hint on [result]. The variable should always | |
2262 // be inlined, but the hint prevents it. | |
2263 return addPrimitive(new ir.GetMutableVariable(getMutableVariable(local))); | |
2264 } else { | |
2265 return environment.lookup(local); | |
2266 } | |
2267 } | |
2268 | |
2269 /// Create a write access to [local] with the provided [value]. | |
2270 @override | |
2271 ir.Primitive buildLocalVariableSet(LocalElement local, ir.Primitive value) { | |
2272 assert(isOpen); | |
2273 if (isInMutableVariable(local)) { | |
2274 add(new ir.SetMutableVariable(getMutableVariable(local), value)); | |
2275 } else { | |
2276 value.useElementAsHint(local); | |
2277 environment.update(local, value); | |
2278 } | |
2279 return value; | |
2280 } | |
2281 | |
2282 ir.Primitive buildThis() { | |
2283 return state.enclosingMethodThisParameter; | |
2284 } | |
2285 | |
2286 @override | |
2287 ir.Primitive buildConstructorInvocation(ConstructorElement element, | |
2288 CallStructure callStructure, | |
2289 DartType type, | |
2290 List<ir.Primitive> arguments) { | |
2291 assert(isOpen); | |
2292 Selector selector = | |
2293 new Selector(SelectorKind.CALL, element.memberName, callStructure); | |
2294 return _continueWithExpression( | |
2295 (k) => new ir.InvokeConstructor(type, element, selector, | |
2296 arguments, k)); | |
2297 } | |
2298 | |
2299 @override | |
2300 ir.Primitive buildReifyTypeVariable(TypeVariableType variable) { | |
2301 return addPrimitive(new ir.ReifyTypeVar(variable.element)); | |
2302 } | |
2303 | |
2304 @override | |
2305 ir.Primitive buildTypeOperator(ir.Primitive value, | |
2306 DartType type, | |
2307 {bool isTypeTest}) { | |
2308 assert(isOpen); | |
2309 assert(isTypeTest != null); | |
2310 ir.Primitive check = _continueWithExpression( | |
2311 (k) => new ir.TypeOperator(value, type, | |
2312 const <ir.Primitive>[], k, isTypeTest: isTypeTest)); | |
2313 return check; | |
2314 } | |
2315 } | |
2316 | |
2317 /// State shared between JsIrBuilders within the same function. | 2013 /// State shared between JsIrBuilders within the same function. |
2318 /// | 2014 /// |
2319 /// Note that this is not shared between builders of nested functions. | 2015 /// Note that this is not shared between builders of nested functions. |
2320 class JsIrBuilderSharedState { | 2016 class JsIrBuilderSharedState { |
2321 /// Maps boxed locals to their location. These locals are not part of | 2017 /// Maps boxed locals to their location. These locals are not part of |
2322 /// the environment. | 2018 /// the environment. |
2323 final Map<Local, ClosureLocation> boxedVariables = {}; | 2019 final Map<Local, ClosureLocation> boxedVariables = {}; |
2324 | 2020 |
2325 /// If non-null, this refers to the receiver (`this`) in the enclosing method. | 2021 /// If non-null, this refers to the receiver (`this`) in the enclosing method. |
2326 ir.Primitive receiver; | 2022 ir.Primitive receiver; |
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2765 final DartType type; | 2461 final DartType type; |
2766 final LocalVariableElement exceptionVariable; | 2462 final LocalVariableElement exceptionVariable; |
2767 final LocalVariableElement stackTraceVariable; | 2463 final LocalVariableElement stackTraceVariable; |
2768 final SubbuildFunction buildCatchBlock; | 2464 final SubbuildFunction buildCatchBlock; |
2769 | 2465 |
2770 CatchClauseInfo({this.type, | 2466 CatchClauseInfo({this.type, |
2771 this.exceptionVariable, | 2467 this.exceptionVariable, |
2772 this.stackTraceVariable, | 2468 this.stackTraceVariable, |
2773 this.buildCatchBlock}); | 2469 this.buildCatchBlock}); |
2774 } | 2470 } |
OLD | NEW |