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 |