| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A special element for the extra parameter taken by intercepted | 8 * A special element for the extra parameter taken by intercepted |
| 9 * methods. We need to override [Element.computeType] because our | 9 * methods. We need to override [Element.computeType] because our |
| 10 * optimizers may look at its declared type. | 10 * optimizers may look at its declared type. |
| 11 */ | 11 */ |
| 12 class InterceptedElement extends ElementX { | 12 class InterceptedElement extends ElementX { |
| 13 final HType ssaType; | 13 final HType ssaType; |
| 14 InterceptedElement(this.ssaType, Element enclosing) | 14 InterceptedElement(this.ssaType, SourceString name, Element enclosing) |
| 15 : super(const SourceString('receiver'), | 15 : super(name, ElementKind.PARAMETER, enclosing); |
| 16 ElementKind.PARAMETER, | |
| 17 enclosing); | |
| 18 | 16 |
| 19 DartType computeType(Compiler compiler) => ssaType.computeType(compiler); | 17 DartType computeType(Compiler compiler) => ssaType.computeType(compiler); |
| 20 } | 18 } |
| 21 | 19 |
| 22 class SsaBuilderTask extends CompilerTask { | 20 class SsaBuilderTask extends CompilerTask { |
| 23 final CodeEmitterTask emitter; | 21 final CodeEmitterTask emitter; |
| 24 final JavaScriptBackend backend; | 22 final JavaScriptBackend backend; |
| 25 | 23 |
| 26 String get name => 'SSA builder'; | 24 String get name => 'SSA builder'; |
| 27 | 25 |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 // not have any thisElement if the closure was created inside a static | 316 // not have any thisElement if the closure was created inside a static |
| 319 // context. | 317 // context. |
| 320 HThis thisInstruction = new HThis( | 318 HThis thisInstruction = new HThis( |
| 321 closureData.thisElement, getTypeOfThis()); | 319 closureData.thisElement, getTypeOfThis()); |
| 322 builder.graph.thisInstruction = thisInstruction; | 320 builder.graph.thisInstruction = thisInstruction; |
| 323 builder.graph.entry.addAtEntry(thisInstruction); | 321 builder.graph.entry.addAtEntry(thisInstruction); |
| 324 directLocals[closureData.thisElement] = thisInstruction; | 322 directLocals[closureData.thisElement] = thisInstruction; |
| 325 } | 323 } |
| 326 | 324 |
| 327 // If this method is an intercepted method, add the extra | 325 // If this method is an intercepted method, add the extra |
| 328 // parameter to it, that is the actual receiver. | 326 // parameter to it, that is the actual receiver for intercepted |
| 327 // classes, or the same as [:this:] for non-intercepted classes. |
| 329 ClassElement cls = element.getEnclosingClass(); | 328 ClassElement cls = element.getEnclosingClass(); |
| 330 if (builder.backend.isInterceptorClass(cls)) { | 329 if (builder.backend.isInterceptedMethod(element)) { |
| 331 HType type = HType.UNKNOWN; | 330 HType type = HType.UNKNOWN; |
| 331 SourceString name = const SourceString('receiver'); |
| 332 if (cls == builder.backend.jsArrayClass) { | 332 if (cls == builder.backend.jsArrayClass) { |
| 333 type = HType.READABLE_ARRAY; | 333 type = HType.READABLE_ARRAY; |
| 334 } else if (cls == builder.backend.jsStringClass) { | 334 } else if (cls == builder.backend.jsStringClass) { |
| 335 type = HType.STRING; | 335 type = HType.STRING; |
| 336 } else if (cls == builder.backend.jsNumberClass) { | 336 } else if (cls == builder.backend.jsNumberClass) { |
| 337 type = HType.NUMBER; | 337 type = HType.NUMBER; |
| 338 } else if (cls == builder.backend.jsIntClass) { | 338 } else if (cls == builder.backend.jsIntClass) { |
| 339 type = HType.INTEGER; | 339 type = HType.INTEGER; |
| 340 } else if (cls == builder.backend.jsDoubleClass) { | 340 } else if (cls == builder.backend.jsDoubleClass) { |
| 341 type = HType.DOUBLE; | 341 type = HType.DOUBLE; |
| 342 } else if (cls == builder.backend.jsNullClass) { | 342 } else if (cls == builder.backend.jsNullClass) { |
| 343 type = HType.NULL; | 343 type = HType.NULL; |
| 344 } else if (cls == builder.backend.jsBoolClass) { | 344 } else if (cls == builder.backend.jsBoolClass) { |
| 345 type = HType.BOOLEAN; | 345 type = HType.BOOLEAN; |
| 346 } else if (cls == builder.backend.jsFunctionClass) { |
| 347 type = HType.UNKNOWN; |
| 348 } else if (cls != compiler.objectClass) { |
| 349 JavaScriptBackend backend = compiler.backend; |
| 350 assert(!backend.isInterceptorClass(cls)); |
| 351 name = const SourceString('_'); |
| 346 } | 352 } |
| 347 Element parameter = new InterceptedElement(type, element); | 353 Element parameter = new InterceptedElement(type, name, element); |
| 348 HParameterValue value = new HParameterValue(parameter); | 354 HParameterValue value = new HParameterValue(parameter); |
| 349 builder.graph.entry.addAfter( | 355 builder.graph.entry.addAfter( |
| 350 directLocals[closureData.thisElement], value); | 356 directLocals[closureData.thisElement], value); |
| 351 directLocals[closureData.thisElement] = value; | 357 if (builder.backend.isInterceptorClass(cls.declaration)) { |
| 358 // Only use the extra parameter in intercepted classes. |
| 359 directLocals[closureData.thisElement] = value; |
| 360 } |
| 352 value.instructionType = type; | 361 value.instructionType = type; |
| 353 } | 362 } |
| 354 } | 363 } |
| 355 | 364 |
| 356 bool hasValueForDirectLocal(Element element) { | 365 bool hasValueForDirectLocal(Element element) { |
| 357 assert(element != null); | 366 assert(element != null); |
| 358 assert(isAccessedDirectly(element)); | 367 assert(isAccessedDirectly(element)); |
| 359 return directLocals[element] != null; | 368 return directLocals[element] != null; |
| 360 } | 369 } |
| 361 | 370 |
| (...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 888 FunctionExpression function = functionElement.parseNode(compiler); | 897 FunctionExpression function = functionElement.parseNode(compiler); |
| 889 assert(function != null); | 898 assert(function != null); |
| 890 assert(!function.modifiers.isExternal()); | 899 assert(!function.modifiers.isExternal()); |
| 891 assert(elements[function] != null); | 900 assert(elements[function] != null); |
| 892 openFunction(functionElement, function); | 901 openFunction(functionElement, function); |
| 893 SourceString name = functionElement.name; | 902 SourceString name = functionElement.name; |
| 894 // If [functionElement] is operator== we explicitely add a null | 903 // If [functionElement] is operator== we explicitely add a null |
| 895 // check at the beginning of the method. This is to avoid having | 904 // check at the beginning of the method. This is to avoid having |
| 896 // call sites do the null check. | 905 // call sites do the null check. |
| 897 if (name == const SourceString('==')) { | 906 if (name == const SourceString('==')) { |
| 907 if (functionElement.getEnclosingClass() == compiler.objectClass) { |
| 908 // We special case [Object.operator==] because we know the |
| 909 // receiver is not null and therefore can just do an identity |
| 910 // check on [:this:]. The interceptor classes have their own |
| 911 // synthesized [:operator==:] method. |
| 912 HInstruction parameter = parameters.values.first; |
| 913 HIdentity identity = new HIdentity(graph.thisInstruction, parameter); |
| 914 add(identity); |
| 915 HReturn ret = new HReturn(identity); |
| 916 close(ret).addSuccessor(graph.exit); |
| 917 return closeFunction(); |
| 918 } |
| 898 handleIf( | 919 handleIf( |
| 899 function, | 920 function, |
| 900 () { | 921 () { |
| 901 HParameterValue parameter = parameters.values.first; | 922 HParameterValue parameter = parameters.values.first; |
| 902 push(new HIdentity( | 923 push(new HIdentity( |
| 903 parameter, graph.addConstantNull(constantSystem))); | 924 parameter, graph.addConstantNull(constantSystem))); |
| 904 }, | 925 }, |
| 905 () { | 926 () { |
| 906 HReturn ret = new HReturn( | 927 HReturn ret = new HReturn( |
| 907 graph.addConstantBool(false, constantSystem)); | 928 graph.addConstantBool(false, constantSystem)); |
| (...skipping 1377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2285 | 2306 |
| 2286 String getTargetName(ErroneousElement error, [String prefix]) { | 2307 String getTargetName(ErroneousElement error, [String prefix]) { |
| 2287 String result = error.name.slowToString(); | 2308 String result = error.name.slowToString(); |
| 2288 if (?prefix) { | 2309 if (?prefix) { |
| 2289 result = '$prefix $result'; | 2310 result = '$prefix $result'; |
| 2290 } | 2311 } |
| 2291 return result; | 2312 return result; |
| 2292 } | 2313 } |
| 2293 | 2314 |
| 2294 /** | 2315 /** |
| 2295 * Returns a set of interceptor classes that contain a member whose | 2316 * Returns a set of interceptor classes that contain the given |
| 2296 * signature matches the given [selector]. | 2317 * [selector]. |
| 2297 */ | 2318 */ |
| 2298 Set<ClassElement> getInterceptedClassesOn(Selector selector) { | |
| 2299 return backend.getInterceptedClassesOn(selector); | |
| 2300 } | |
| 2301 | |
| 2302 void generateInstanceGetterWithCompiledReceiver(Send send, | 2319 void generateInstanceGetterWithCompiledReceiver(Send send, |
| 2303 Selector selector, | 2320 Selector selector, |
| 2304 HInstruction receiver) { | 2321 HInstruction receiver) { |
| 2305 assert(Elements.isInstanceSend(send, elements)); | 2322 assert(Elements.isInstanceSend(send, elements)); |
| 2306 assert(selector.isGetter()); | 2323 assert(selector.isGetter()); |
| 2307 SourceString getterName = selector.name; | 2324 SourceString getterName = selector.name; |
| 2308 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 2325 Set<ClassElement> interceptedClasses = |
| 2326 backend.getInterceptedClassesOn(getterName); |
| 2309 | 2327 |
| 2310 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); | 2328 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); |
| 2311 HInstruction instruction; | 2329 HInstruction instruction; |
| 2312 if (interceptedClasses != null) { | 2330 if (interceptedClasses != null) { |
| 2313 // If we're using an interceptor class, emit a call to the | 2331 // If we're using an interceptor class, emit a call to the |
| 2314 // interceptor method and then the actual dynamic call on the | 2332 // interceptor method and then the actual dynamic call on the |
| 2315 // interceptor object. | 2333 // interceptor object. |
| 2316 instruction = | 2334 instruction = |
| 2317 invokeInterceptor(interceptedClasses, receiver, send); | 2335 invokeInterceptor(interceptedClasses, receiver, send); |
| 2318 instruction = new HInvokeDynamicGetter( | 2336 instruction = new HInvokeDynamicGetter( |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2374 } | 2392 } |
| 2375 | 2393 |
| 2376 void generateInstanceSetterWithCompiledReceiver(Send send, | 2394 void generateInstanceSetterWithCompiledReceiver(Send send, |
| 2377 HInstruction receiver, | 2395 HInstruction receiver, |
| 2378 HInstruction value) { | 2396 HInstruction value) { |
| 2379 assert(Elements.isInstanceSend(send, elements)); | 2397 assert(Elements.isInstanceSend(send, elements)); |
| 2380 Selector selector = elements.getSelector(send); | 2398 Selector selector = elements.getSelector(send); |
| 2381 assert(selector.isSetter()); | 2399 assert(selector.isSetter()); |
| 2382 SourceString setterName = selector.name; | 2400 SourceString setterName = selector.name; |
| 2383 bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); | 2401 bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); |
| 2384 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 2402 Set<ClassElement> interceptedClasses = |
| 2403 backend.getInterceptedClassesOn(setterName); |
| 2385 if (interceptedClasses != null) { | 2404 if (interceptedClasses != null) { |
| 2386 // If we're using an interceptor class, emit a call to the | 2405 // If we're using an interceptor class, emit a call to the |
| 2387 // getInterceptor method and then the actual dynamic call on the | 2406 // getInterceptor method and then the actual dynamic call on the |
| 2388 // interceptor object. | 2407 // interceptor object. |
| 2389 HInstruction instruction = | 2408 HInstruction instruction = |
| 2390 invokeInterceptor(interceptedClasses, receiver, send); | 2409 invokeInterceptor(interceptedClasses, receiver, send); |
| 2391 instruction = new HInvokeDynamicSetter( | 2410 instruction = new HInvokeDynamicSetter( |
| 2392 selector, null, instruction, receiver, !hasSetter); | 2411 selector, null, instruction, receiver, !hasSetter); |
| 2393 // Add the value as an argument to the setter call on the | 2412 // Add the value as an argument to the setter call on the |
| 2394 // interceptor. | 2413 // interceptor. |
| (...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3031 constantSystem.createInt(selector.invocationMirrorKind); | 3050 constantSystem.createInt(selector.invocationMirrorKind); |
| 3032 | 3051 |
| 3033 pushInvokeHelper5(createInvocationMirror, | 3052 pushInvokeHelper5(createInvocationMirror, |
| 3034 graph.addConstant(nameConstant), | 3053 graph.addConstant(nameConstant), |
| 3035 graph.addConstant(internalNameConstant), | 3054 graph.addConstant(internalNameConstant), |
| 3036 graph.addConstant(kindConstant), | 3055 graph.addConstant(kindConstant), |
| 3037 argumentsInstruction, | 3056 argumentsInstruction, |
| 3038 argumentNamesInstruction, | 3057 argumentNamesInstruction, |
| 3039 HType.UNKNOWN); | 3058 HType.UNKNOWN); |
| 3040 | 3059 |
| 3041 var inputs = <HInstruction>[ | 3060 var inputs = <HInstruction>[target, self]; |
| 3042 target, | 3061 if (backend.isInterceptedMethod(element)) { |
| 3043 self, | 3062 inputs.add(self); |
| 3044 pop()]; | 3063 } |
| 3064 inputs.add(pop()); |
| 3045 push(new HInvokeSuper(inputs)); | 3065 push(new HInvokeSuper(inputs)); |
| 3046 } | 3066 } |
| 3047 | 3067 |
| 3048 visitSend(Send node) { | 3068 visitSend(Send node) { |
| 3049 Element element = elements[node]; | 3069 Element element = elements[node]; |
| 3050 if (element != null && identical(element, currentElement)) { | 3070 if (element != null && identical(element, currentElement)) { |
| 3051 graph.isRecursiveMethod = true; | 3071 graph.isRecursiveMethod = true; |
| 3052 } | 3072 } |
| 3053 super.visitSend(node); | 3073 super.visitSend(node); |
| 3054 } | 3074 } |
| 3055 | 3075 |
| 3056 visitSuperSend(Send node) { | 3076 visitSuperSend(Send node) { |
| 3057 Selector selector = elements.getSelector(node); | 3077 Selector selector = elements.getSelector(node); |
| 3058 Element element = elements[node]; | 3078 Element element = elements[node]; |
| 3059 if (Elements.isUnresolved(element)) { | 3079 if (Elements.isUnresolved(element)) { |
| 3060 return generateSuperNoSuchMethodSend(node); | 3080 return generateSuperNoSuchMethodSend(node); |
| 3061 } | 3081 } |
| 3062 // TODO(5346): Try to avoid the need for calling [declaration] before | 3082 // TODO(5346): Try to avoid the need for calling [declaration] before |
| 3063 // creating an [HStatic]. | 3083 // creating an [HStatic]. |
| 3064 HInstruction target = new HStatic(element.declaration); | 3084 HInstruction target = new HStatic(element.declaration); |
| 3065 HInstruction context = localsHandler.readThis(); | 3085 HInstruction context = localsHandler.readThis(); |
| 3066 add(target); | 3086 add(target); |
| 3067 var inputs = <HInstruction>[target, context]; | 3087 var inputs = <HInstruction>[target, context]; |
| 3088 if (backend.isInterceptedMethod(element)) { |
| 3089 inputs.add(context); |
| 3090 } |
| 3068 if (node.isPropertyAccess) { | 3091 if (node.isPropertyAccess) { |
| 3069 push(new HInvokeSuper(inputs)); | 3092 push(new HInvokeSuper(inputs)); |
| 3070 } else if (element.isFunction() || element.isGenerativeConstructor()) { | 3093 } else if (element.isFunction() || element.isGenerativeConstructor()) { |
| 3071 // TODO(5347): Try to avoid the need for calling [implementation] before | 3094 // TODO(5347): Try to avoid the need for calling [implementation] before |
| 3072 // calling [addStaticSendArgumentsToList]. | 3095 // calling [addStaticSendArgumentsToList]. |
| 3073 FunctionElement function = element.implementation; | 3096 FunctionElement function = element.implementation; |
| 3074 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, | 3097 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
| 3075 function, inputs); | 3098 function, inputs); |
| 3076 if (!succeeded) { | 3099 if (!succeeded) { |
| 3077 generateWrongArgumentCountError(node, element, node.arguments); | 3100 generateWrongArgumentCountError(node, element, node.arguments); |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3497 visitNewSend(send, type); | 3520 visitNewSend(send, type); |
| 3498 } | 3521 } |
| 3499 } | 3522 } |
| 3500 } | 3523 } |
| 3501 } | 3524 } |
| 3502 | 3525 |
| 3503 HInvokeDynamicMethod buildInvokeDynamic(Node node, | 3526 HInvokeDynamicMethod buildInvokeDynamic(Node node, |
| 3504 Selector selector, | 3527 Selector selector, |
| 3505 HInstruction receiver, | 3528 HInstruction receiver, |
| 3506 List<HInstruction> arguments) { | 3529 List<HInstruction> arguments) { |
| 3507 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 3530 Set<ClassElement> interceptedClasses = |
| 3531 backend.getInterceptedClassesOn(selector.name); |
| 3508 List<HInstruction> inputs = <HInstruction>[]; | 3532 List<HInstruction> inputs = <HInstruction>[]; |
| 3509 bool isIntercepted = interceptedClasses != null; | 3533 bool isIntercepted = interceptedClasses != null; |
| 3510 if (isIntercepted) { | 3534 if (isIntercepted) { |
| 3511 assert(!interceptedClasses.isEmpty); | 3535 assert(!interceptedClasses.isEmpty); |
| 3512 inputs.add(invokeInterceptor(interceptedClasses, receiver, node)); | 3536 inputs.add(invokeInterceptor(interceptedClasses, receiver, node)); |
| 3513 } | 3537 } |
| 3514 inputs.add(receiver); | 3538 inputs.add(receiver); |
| 3515 inputs.addAll(arguments); | 3539 inputs.addAll(arguments); |
| 3516 return new HInvokeDynamicMethod(selector, inputs, isIntercepted); | 3540 return new HInvokeDynamicMethod(selector, inputs, isIntercepted); |
| 3517 } | 3541 } |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3855 // Iterator<E> $iter = <iterable>.iterator; | 3879 // Iterator<E> $iter = <iterable>.iterator; |
| 3856 // while ($iter.moveNext()) { | 3880 // while ($iter.moveNext()) { |
| 3857 // E <declaredIdentifier> = $iter.current; | 3881 // E <declaredIdentifier> = $iter.current; |
| 3858 // <body> | 3882 // <body> |
| 3859 // } | 3883 // } |
| 3860 | 3884 |
| 3861 // The iterator is shared between initializer, condition and body. | 3885 // The iterator is shared between initializer, condition and body. |
| 3862 HInstruction iterator; | 3886 HInstruction iterator; |
| 3863 void buildInitializer() { | 3887 void buildInitializer() { |
| 3864 Selector selector = elements.getIteratorSelector(node); | 3888 Selector selector = elements.getIteratorSelector(node); |
| 3865 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 3889 Set<ClassElement> interceptedClasses = |
| 3890 backend.getInterceptedClassesOn(selector.name); |
| 3866 visit(node.expression); | 3891 visit(node.expression); |
| 3867 HInstruction receiver = pop(); | 3892 HInstruction receiver = pop(); |
| 3868 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); | 3893 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); |
| 3869 if (interceptedClasses == null) { | 3894 if (interceptedClasses == null) { |
| 3870 iterator = | 3895 iterator = |
| 3871 new HInvokeDynamicGetter(selector, null, receiver, !hasGetter); | 3896 new HInvokeDynamicGetter(selector, null, receiver, !hasGetter); |
| 3872 } else { | 3897 } else { |
| 3873 HInterceptor interceptor = | 3898 HInterceptor interceptor = |
| 3874 invokeInterceptor(interceptedClasses, receiver, null); | 3899 invokeInterceptor(interceptedClasses, receiver, null); |
| 3875 iterator = | 3900 iterator = |
| (...skipping 1095 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4971 new HSubGraphBlockInformation(elseBranch.graph)); | 4996 new HSubGraphBlockInformation(elseBranch.graph)); |
| 4972 | 4997 |
| 4973 HBasicBlock conditionStartBlock = conditionBranch.block; | 4998 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 4974 conditionStartBlock.setBlockFlow(info, joinBlock); | 4999 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 4975 SubGraph conditionGraph = conditionBranch.graph; | 5000 SubGraph conditionGraph = conditionBranch.graph; |
| 4976 HIf branch = conditionGraph.end.last; | 5001 HIf branch = conditionGraph.end.last; |
| 4977 assert(branch is HIf); | 5002 assert(branch is HIf); |
| 4978 branch.blockInformation = conditionStartBlock.blockFlow; | 5003 branch.blockInformation = conditionStartBlock.blockFlow; |
| 4979 } | 5004 } |
| 4980 } | 5005 } |
| OLD | NEW |