| 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 1378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2286 | 2307 |
| 2287 String getTargetName(ErroneousElement error, [String prefix]) { | 2308 String getTargetName(ErroneousElement error, [String prefix]) { |
| 2288 String result = error.name.slowToString(); | 2309 String result = error.name.slowToString(); |
| 2289 if (?prefix) { | 2310 if (?prefix) { |
| 2290 result = '$prefix $result'; | 2311 result = '$prefix $result'; |
| 2291 } | 2312 } |
| 2292 return result; | 2313 return result; |
| 2293 } | 2314 } |
| 2294 | 2315 |
| 2295 /** | 2316 /** |
| 2296 * Returns a set of interceptor classes that contain a member whose | 2317 * Returns a set of interceptor classes that contain the given |
| 2297 * signature matches the given [selector]. | 2318 * [selector]. |
| 2298 */ | 2319 */ |
| 2299 Set<ClassElement> getInterceptedClassesOn(Selector selector) { | |
| 2300 return backend.getInterceptedClassesOn(selector); | |
| 2301 } | |
| 2302 | |
| 2303 void generateInstanceGetterWithCompiledReceiver(Send send, | 2320 void generateInstanceGetterWithCompiledReceiver(Send send, |
| 2304 Selector selector, | 2321 Selector selector, |
| 2305 HInstruction receiver) { | 2322 HInstruction receiver) { |
| 2306 assert(Elements.isInstanceSend(send, elements)); | 2323 assert(Elements.isInstanceSend(send, elements)); |
| 2307 assert(selector.isGetter()); | 2324 assert(selector.isGetter()); |
| 2308 SourceString getterName = selector.name; | 2325 SourceString getterName = selector.name; |
| 2309 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 2326 Set<ClassElement> interceptedClasses = |
| 2327 backend.getInterceptedClassesOn(getterName); |
| 2310 | 2328 |
| 2311 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); | 2329 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); |
| 2312 HInstruction instruction; | 2330 HInstruction instruction; |
| 2313 if (interceptedClasses != null) { | 2331 if (interceptedClasses != null) { |
| 2314 // If we're using an interceptor class, emit a call to the | 2332 // If we're using an interceptor class, emit a call to the |
| 2315 // interceptor method and then the actual dynamic call on the | 2333 // interceptor method and then the actual dynamic call on the |
| 2316 // interceptor object. | 2334 // interceptor object. |
| 2317 instruction = | 2335 instruction = |
| 2318 invokeInterceptor(interceptedClasses, receiver, send); | 2336 invokeInterceptor(interceptedClasses, receiver, send); |
| 2319 instruction = new HInvokeDynamicGetter( | 2337 instruction = new HInvokeDynamicGetter( |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2375 } | 2393 } |
| 2376 | 2394 |
| 2377 void generateInstanceSetterWithCompiledReceiver(Send send, | 2395 void generateInstanceSetterWithCompiledReceiver(Send send, |
| 2378 HInstruction receiver, | 2396 HInstruction receiver, |
| 2379 HInstruction value) { | 2397 HInstruction value) { |
| 2380 assert(Elements.isInstanceSend(send, elements)); | 2398 assert(Elements.isInstanceSend(send, elements)); |
| 2381 Selector selector = elements.getSelector(send); | 2399 Selector selector = elements.getSelector(send); |
| 2382 assert(selector.isSetter()); | 2400 assert(selector.isSetter()); |
| 2383 SourceString setterName = selector.name; | 2401 SourceString setterName = selector.name; |
| 2384 bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); | 2402 bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); |
| 2385 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 2403 Set<ClassElement> interceptedClasses = |
| 2404 backend.getInterceptedClassesOn(setterName); |
| 2386 if (interceptedClasses != null) { | 2405 if (interceptedClasses != null) { |
| 2387 // If we're using an interceptor class, emit a call to the | 2406 // If we're using an interceptor class, emit a call to the |
| 2388 // getInterceptor method and then the actual dynamic call on the | 2407 // getInterceptor method and then the actual dynamic call on the |
| 2389 // interceptor object. | 2408 // interceptor object. |
| 2390 HInstruction instruction = | 2409 HInstruction instruction = |
| 2391 invokeInterceptor(interceptedClasses, receiver, send); | 2410 invokeInterceptor(interceptedClasses, receiver, send); |
| 2392 instruction = new HInvokeDynamicSetter( | 2411 instruction = new HInvokeDynamicSetter( |
| 2393 selector, null, instruction, receiver, !hasSetter); | 2412 selector, null, instruction, receiver, !hasSetter); |
| 2394 // Add the value as an argument to the setter call on the | 2413 // Add the value as an argument to the setter call on the |
| 2395 // interceptor. | 2414 // interceptor. |
| (...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3037 constantSystem.createInt(selector.invocationMirrorKind); | 3056 constantSystem.createInt(selector.invocationMirrorKind); |
| 3038 | 3057 |
| 3039 pushInvokeHelper5(createInvocationMirror, | 3058 pushInvokeHelper5(createInvocationMirror, |
| 3040 graph.addConstant(nameConstant), | 3059 graph.addConstant(nameConstant), |
| 3041 graph.addConstant(internalNameConstant), | 3060 graph.addConstant(internalNameConstant), |
| 3042 graph.addConstant(kindConstant), | 3061 graph.addConstant(kindConstant), |
| 3043 argumentsInstruction, | 3062 argumentsInstruction, |
| 3044 argumentNamesInstruction, | 3063 argumentNamesInstruction, |
| 3045 HType.UNKNOWN); | 3064 HType.UNKNOWN); |
| 3046 | 3065 |
| 3047 var inputs = <HInstruction>[ | 3066 var inputs = <HInstruction>[target, self]; |
| 3048 target, | 3067 if (backend.isInterceptedMethod(element)) { |
| 3049 self, | 3068 inputs.add(self); |
| 3050 pop()]; | 3069 } |
| 3070 inputs.add(pop()); |
| 3051 push(new HInvokeSuper(inputs)); | 3071 push(new HInvokeSuper(inputs)); |
| 3052 } | 3072 } |
| 3053 | 3073 |
| 3054 visitSend(Send node) { | 3074 visitSend(Send node) { |
| 3055 Element element = elements[node]; | 3075 Element element = elements[node]; |
| 3056 if (element != null && identical(element, currentElement)) { | 3076 if (element != null && identical(element, currentElement)) { |
| 3057 graph.isRecursiveMethod = true; | 3077 graph.isRecursiveMethod = true; |
| 3058 } | 3078 } |
| 3059 super.visitSend(node); | 3079 super.visitSend(node); |
| 3060 } | 3080 } |
| 3061 | 3081 |
| 3062 visitSuperSend(Send node) { | 3082 visitSuperSend(Send node) { |
| 3063 Selector selector = elements.getSelector(node); | 3083 Selector selector = elements.getSelector(node); |
| 3064 Element element = elements[node]; | 3084 Element element = elements[node]; |
| 3065 if (Elements.isUnresolved(element)) { | 3085 if (Elements.isUnresolved(element)) { |
| 3066 return generateSuperNoSuchMethodSend(node); | 3086 return generateSuperNoSuchMethodSend(node); |
| 3067 } | 3087 } |
| 3068 // TODO(5346): Try to avoid the need for calling [declaration] before | 3088 // TODO(5346): Try to avoid the need for calling [declaration] before |
| 3069 // creating an [HStatic]. | 3089 // creating an [HStatic]. |
| 3070 HInstruction target = new HStatic(element.declaration); | 3090 HInstruction target = new HStatic(element.declaration); |
| 3071 HInstruction context = localsHandler.readThis(); | 3091 HInstruction context = localsHandler.readThis(); |
| 3072 add(target); | 3092 add(target); |
| 3073 var inputs = <HInstruction>[target, context]; | 3093 var inputs = <HInstruction>[target, context]; |
| 3094 if (backend.isInterceptedMethod(element)) { |
| 3095 inputs.add(context); |
| 3096 } |
| 3074 if (node.isPropertyAccess) { | 3097 if (node.isPropertyAccess) { |
| 3075 push(new HInvokeSuper(inputs)); | 3098 push(new HInvokeSuper(inputs)); |
| 3076 } else if (element.isFunction() || element.isGenerativeConstructor()) { | 3099 } else if (element.isFunction() || element.isGenerativeConstructor()) { |
| 3077 // TODO(5347): Try to avoid the need for calling [implementation] before | 3100 // TODO(5347): Try to avoid the need for calling [implementation] before |
| 3078 // calling [addStaticSendArgumentsToList]. | 3101 // calling [addStaticSendArgumentsToList]. |
| 3079 FunctionElement function = element.implementation; | 3102 FunctionElement function = element.implementation; |
| 3080 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, | 3103 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
| 3081 function, inputs); | 3104 function, inputs); |
| 3082 if (!succeeded) { | 3105 if (!succeeded) { |
| 3083 generateWrongArgumentCountError(node, element, node.arguments); | 3106 generateWrongArgumentCountError(node, element, node.arguments); |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3503 visitNewSend(send, type); | 3526 visitNewSend(send, type); |
| 3504 } | 3527 } |
| 3505 } | 3528 } |
| 3506 } | 3529 } |
| 3507 } | 3530 } |
| 3508 | 3531 |
| 3509 HInvokeDynamicMethod buildInvokeDynamic(Node node, | 3532 HInvokeDynamicMethod buildInvokeDynamic(Node node, |
| 3510 Selector selector, | 3533 Selector selector, |
| 3511 HInstruction receiver, | 3534 HInstruction receiver, |
| 3512 List<HInstruction> arguments) { | 3535 List<HInstruction> arguments) { |
| 3513 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 3536 Set<ClassElement> interceptedClasses = |
| 3537 backend.getInterceptedClassesOn(selector.name); |
| 3514 List<HInstruction> inputs = <HInstruction>[]; | 3538 List<HInstruction> inputs = <HInstruction>[]; |
| 3515 bool isIntercepted = interceptedClasses != null; | 3539 bool isIntercepted = interceptedClasses != null; |
| 3516 if (isIntercepted) { | 3540 if (isIntercepted) { |
| 3517 assert(!interceptedClasses.isEmpty); | 3541 assert(!interceptedClasses.isEmpty); |
| 3518 inputs.add(invokeInterceptor(interceptedClasses, receiver, node)); | 3542 inputs.add(invokeInterceptor(interceptedClasses, receiver, node)); |
| 3519 } | 3543 } |
| 3520 inputs.add(receiver); | 3544 inputs.add(receiver); |
| 3521 inputs.addAll(arguments); | 3545 inputs.addAll(arguments); |
| 3522 return new HInvokeDynamicMethod(selector, inputs, isIntercepted); | 3546 return new HInvokeDynamicMethod(selector, inputs, isIntercepted); |
| 3523 } | 3547 } |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3861 // Iterator<E> $iter = <iterable>.iterator; | 3885 // Iterator<E> $iter = <iterable>.iterator; |
| 3862 // while ($iter.moveNext()) { | 3886 // while ($iter.moveNext()) { |
| 3863 // E <declaredIdentifier> = $iter.current; | 3887 // E <declaredIdentifier> = $iter.current; |
| 3864 // <body> | 3888 // <body> |
| 3865 // } | 3889 // } |
| 3866 | 3890 |
| 3867 // The iterator is shared between initializer, condition and body. | 3891 // The iterator is shared between initializer, condition and body. |
| 3868 HInstruction iterator; | 3892 HInstruction iterator; |
| 3869 void buildInitializer() { | 3893 void buildInitializer() { |
| 3870 Selector selector = elements.getIteratorSelector(node); | 3894 Selector selector = elements.getIteratorSelector(node); |
| 3871 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 3895 Set<ClassElement> interceptedClasses = |
| 3896 backend.getInterceptedClassesOn(selector.name); |
| 3872 visit(node.expression); | 3897 visit(node.expression); |
| 3873 HInstruction receiver = pop(); | 3898 HInstruction receiver = pop(); |
| 3874 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); | 3899 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); |
| 3875 if (interceptedClasses == null) { | 3900 if (interceptedClasses == null) { |
| 3876 iterator = | 3901 iterator = |
| 3877 new HInvokeDynamicGetter(selector, null, receiver, !hasGetter); | 3902 new HInvokeDynamicGetter(selector, null, receiver, !hasGetter); |
| 3878 } else { | 3903 } else { |
| 3879 HInterceptor interceptor = | 3904 HInterceptor interceptor = |
| 3880 invokeInterceptor(interceptedClasses, receiver, null); | 3905 invokeInterceptor(interceptedClasses, receiver, null); |
| 3881 iterator = | 3906 iterator = |
| (...skipping 1095 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4977 new HSubGraphBlockInformation(elseBranch.graph)); | 5002 new HSubGraphBlockInformation(elseBranch.graph)); |
| 4978 | 5003 |
| 4979 HBasicBlock conditionStartBlock = conditionBranch.block; | 5004 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 4980 conditionStartBlock.setBlockFlow(info, joinBlock); | 5005 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 4981 SubGraph conditionGraph = conditionBranch.graph; | 5006 SubGraph conditionGraph = conditionBranch.graph; |
| 4982 HIf branch = conditionGraph.end.last; | 5007 HIf branch = conditionGraph.end.last; |
| 4983 assert(branch is HIf); | 5008 assert(branch is HIf); |
| 4984 branch.blockInformation = conditionStartBlock.blockFlow; | 5009 branch.blockInformation = conditionStartBlock.blockFlow; |
| 4985 } | 5010 } |
| 4986 } | 5011 } |
| OLD | NEW |