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 |