Chromium Code Reviews| 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, Element enclosing) |
| 15 : super(const SourceString('receiver'), | 15 : super(const SourceString('receiver'), |
|
ngeoffray
2013/02/28 10:39:42
Changed the name to '_' in case of a non-intercept
| |
| 16 ElementKind.PARAMETER, | 16 ElementKind.PARAMETER, |
| 17 enclosing); | 17 enclosing); |
| 18 | 18 |
| 19 DartType computeType(Compiler compiler) => ssaType.computeType(compiler); | 19 DartType computeType(Compiler compiler) => ssaType.computeType(compiler); |
| 20 } | 20 } |
| 21 | 21 |
| 22 class SsaBuilderTask extends CompilerTask { | 22 class SsaBuilderTask extends CompilerTask { |
| 23 final CodeEmitterTask emitter; | 23 final CodeEmitterTask emitter; |
| 24 final JavaScriptBackend backend; | 24 final JavaScriptBackend backend; |
| 25 | 25 |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 318 // not have any thisElement if the closure was created inside a static | 318 // not have any thisElement if the closure was created inside a static |
| 319 // context. | 319 // context. |
| 320 HThis thisInstruction = new HThis( | 320 HThis thisInstruction = new HThis( |
| 321 closureData.thisElement, getTypeOfThis()); | 321 closureData.thisElement, getTypeOfThis()); |
| 322 builder.graph.thisInstruction = thisInstruction; | 322 builder.graph.thisInstruction = thisInstruction; |
| 323 builder.graph.entry.addAtEntry(thisInstruction); | 323 builder.graph.entry.addAtEntry(thisInstruction); |
| 324 directLocals[closureData.thisElement] = thisInstruction; | 324 directLocals[closureData.thisElement] = thisInstruction; |
| 325 } | 325 } |
| 326 | 326 |
| 327 // If this method is an intercepted method, add the extra | 327 // If this method is an intercepted method, add the extra |
| 328 // parameter to it, that is the actual receiver. | 328 // parameter to it, that is the actual receiver for intercepted |
| 329 // classes, or the same as [:this:] for non-intercepted classes. | |
| 329 ClassElement cls = element.getEnclosingClass(); | 330 ClassElement cls = element.getEnclosingClass(); |
| 330 if (builder.backend.isInterceptorClass(cls)) { | 331 if (builder.backend.isInterceptedMethod(element)) { |
| 331 HType type = HType.UNKNOWN; | 332 HType type = HType.UNKNOWN; |
| 332 if (cls == builder.backend.jsArrayClass) { | 333 if (cls == builder.backend.jsArrayClass) { |
| 333 type = HType.READABLE_ARRAY; | 334 type = HType.READABLE_ARRAY; |
| 334 } else if (cls == builder.backend.jsStringClass) { | 335 } else if (cls == builder.backend.jsStringClass) { |
| 335 type = HType.STRING; | 336 type = HType.STRING; |
| 336 } else if (cls == builder.backend.jsNumberClass) { | 337 } else if (cls == builder.backend.jsNumberClass) { |
| 337 type = HType.NUMBER; | 338 type = HType.NUMBER; |
| 338 } else if (cls == builder.backend.jsIntClass) { | 339 } else if (cls == builder.backend.jsIntClass) { |
| 339 type = HType.INTEGER; | 340 type = HType.INTEGER; |
| 340 } else if (cls == builder.backend.jsDoubleClass) { | 341 } else if (cls == builder.backend.jsDoubleClass) { |
| 341 type = HType.DOUBLE; | 342 type = HType.DOUBLE; |
| 342 } else if (cls == builder.backend.jsNullClass) { | 343 } else if (cls == builder.backend.jsNullClass) { |
| 343 type = HType.NULL; | 344 type = HType.NULL; |
| 344 } else if (cls == builder.backend.jsBoolClass) { | 345 } else if (cls == builder.backend.jsBoolClass) { |
| 345 type = HType.BOOLEAN; | 346 type = HType.BOOLEAN; |
| 346 } | 347 } |
| 347 Element parameter = new InterceptedElement(type, element); | 348 Element parameter = new InterceptedElement(type, element); |
| 348 HParameterValue value = new HParameterValue(parameter); | 349 HParameterValue value = new HParameterValue(parameter); |
| 349 builder.graph.entry.addAfter( | 350 builder.graph.entry.addAfter( |
| 350 directLocals[closureData.thisElement], value); | 351 directLocals[closureData.thisElement], value); |
| 351 directLocals[closureData.thisElement] = value; | 352 if (builder.backend.isInterceptorClass(cls.declaration)) { |
| 353 // Only use the extra parameter in intercepted classes. | |
| 354 directLocals[closureData.thisElement] = value; | |
| 355 } | |
| 352 value.instructionType = type; | 356 value.instructionType = type; |
| 353 } | 357 } |
| 354 } | 358 } |
| 355 | 359 |
| 356 bool hasValueForDirectLocal(Element element) { | 360 bool hasValueForDirectLocal(Element element) { |
| 357 assert(element != null); | 361 assert(element != null); |
| 358 assert(isAccessedDirectly(element)); | 362 assert(isAccessedDirectly(element)); |
| 359 return directLocals[element] != null; | 363 return directLocals[element] != null; |
| 360 } | 364 } |
| 361 | 365 |
| (...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 888 FunctionExpression function = functionElement.parseNode(compiler); | 892 FunctionExpression function = functionElement.parseNode(compiler); |
| 889 assert(function != null); | 893 assert(function != null); |
| 890 assert(!function.modifiers.isExternal()); | 894 assert(!function.modifiers.isExternal()); |
| 891 assert(elements[function] != null); | 895 assert(elements[function] != null); |
| 892 openFunction(functionElement, function); | 896 openFunction(functionElement, function); |
| 893 SourceString name = functionElement.name; | 897 SourceString name = functionElement.name; |
| 894 // If [functionElement] is operator== we explicitely add a null | 898 // If [functionElement] is operator== we explicitely add a null |
| 895 // check at the beginning of the method. This is to avoid having | 899 // check at the beginning of the method. This is to avoid having |
| 896 // call sites do the null check. | 900 // call sites do the null check. |
| 897 if (name == const SourceString('==')) { | 901 if (name == const SourceString('==')) { |
| 902 if (functionElement.getEnclosingClass() == compiler.objectClass) { | |
| 903 // We special case [Object.operator==] because we know the | |
| 904 // receiver is not null and therefore can just do an identity | |
| 905 // check on [:this:]. The interceptor classes have their own | |
| 906 // synthesized [:operator==:] method. | |
| 907 HInstruction parameter = parameters.values.first; | |
| 908 HIdentity identity = new HIdentity(graph.thisInstruction, parameter); | |
| 909 add(identity); | |
| 910 HReturn ret = new HReturn(identity); | |
| 911 close(ret).addSuccessor(graph.exit); | |
| 912 return closeFunction(); | |
| 913 } | |
| 898 handleIf( | 914 handleIf( |
| 899 function, | 915 function, |
| 900 () { | 916 () { |
| 901 HParameterValue parameter = parameters.values.first; | 917 HParameterValue parameter = parameters.values.first; |
| 902 push(new HIdentity( | 918 push(new HIdentity( |
| 903 parameter, graph.addConstantNull(constantSystem))); | 919 parameter, graph.addConstantNull(constantSystem))); |
| 904 }, | 920 }, |
| 905 () { | 921 () { |
| 906 HReturn ret = new HReturn( | 922 HReturn ret = new HReturn( |
| 907 graph.addConstantBool(false, constantSystem)); | 923 graph.addConstantBool(false, constantSystem)); |
| (...skipping 1436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2344 | 2360 |
| 2345 String getTargetName(ErroneousElement error, [String prefix]) { | 2361 String getTargetName(ErroneousElement error, [String prefix]) { |
| 2346 String result = error.name.slowToString(); | 2362 String result = error.name.slowToString(); |
| 2347 if (?prefix) { | 2363 if (?prefix) { |
| 2348 result = '$prefix $result'; | 2364 result = '$prefix $result'; |
| 2349 } | 2365 } |
| 2350 return result; | 2366 return result; |
| 2351 } | 2367 } |
| 2352 | 2368 |
| 2353 /** | 2369 /** |
| 2354 * Returns a set of interceptor classes that contain a member whose | 2370 * Returns a set of interceptor classes that contain the given |
| 2355 * signature matches the given [selector]. | 2371 * [selector]. |
| 2356 */ | 2372 */ |
| 2357 Set<ClassElement> getInterceptedClassesOn(Selector selector) { | |
| 2358 return backend.getInterceptedClassesOn(selector); | |
| 2359 } | |
| 2360 | |
| 2361 void generateInstanceGetterWithCompiledReceiver(Send send, | 2373 void generateInstanceGetterWithCompiledReceiver(Send send, |
| 2362 HInstruction receiver) { | 2374 HInstruction receiver) { |
| 2363 assert(Elements.isInstanceSend(send, elements)); | 2375 assert(Elements.isInstanceSend(send, elements)); |
| 2364 // TODO(kasperl): This is a convoluted way of checking if we're | 2376 // TODO(kasperl): This is a convoluted way of checking if we're |
| 2365 // generating code for a compound assignment. If we are, we need | 2377 // generating code for a compound assignment. If we are, we need |
| 2366 // to get the selector from the mapping for the AST selector node. | 2378 // to get the selector from the mapping for the AST selector node. |
| 2367 Selector selector = (send.asSendSet() == null) | 2379 Selector selector = (send.asSendSet() == null) |
| 2368 ? elements.getSelector(send) | 2380 ? elements.getSelector(send) |
| 2369 : elements.getSelector(send.selector); | 2381 : elements.getSelector(send.selector); |
| 2370 assert(selector.isGetter()); | 2382 assert(selector.isGetter()); |
| 2371 SourceString getterName = selector.name; | 2383 SourceString getterName = selector.name; |
| 2372 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 2384 Set<ClassElement> interceptedClasses = |
| 2385 backend.getInterceptedClassesOn(getterName); | |
| 2373 | 2386 |
| 2374 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); | 2387 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); |
| 2375 HInstruction instruction; | 2388 HInstruction instruction; |
| 2376 if (interceptedClasses != null) { | 2389 if (interceptedClasses != null) { |
| 2377 // If we're using an interceptor class, emit a call to the | 2390 // If we're using an interceptor class, emit a call to the |
| 2378 // interceptor method and then the actual dynamic call on the | 2391 // interceptor method and then the actual dynamic call on the |
| 2379 // interceptor object. | 2392 // interceptor object. |
| 2380 instruction = | 2393 instruction = |
| 2381 invokeInterceptor(interceptedClasses, receiver, send); | 2394 invokeInterceptor(interceptedClasses, receiver, send); |
| 2382 instruction = new HInvokeDynamicGetter( | 2395 instruction = new HInvokeDynamicGetter( |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2437 } | 2450 } |
| 2438 | 2451 |
| 2439 void generateInstanceSetterWithCompiledReceiver(Send send, | 2452 void generateInstanceSetterWithCompiledReceiver(Send send, |
| 2440 HInstruction receiver, | 2453 HInstruction receiver, |
| 2441 HInstruction value) { | 2454 HInstruction value) { |
| 2442 assert(Elements.isInstanceSend(send, elements)); | 2455 assert(Elements.isInstanceSend(send, elements)); |
| 2443 Selector selector = elements.getSelector(send); | 2456 Selector selector = elements.getSelector(send); |
| 2444 assert(selector.isSetter()); | 2457 assert(selector.isSetter()); |
| 2445 SourceString setterName = selector.name; | 2458 SourceString setterName = selector.name; |
| 2446 bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); | 2459 bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); |
| 2447 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 2460 Set<ClassElement> interceptedClasses = |
| 2461 backend.getInterceptedClassesOn(setterName); | |
| 2448 if (interceptedClasses != null) { | 2462 if (interceptedClasses != null) { |
| 2449 // If we're using an interceptor class, emit a call to the | 2463 // If we're using an interceptor class, emit a call to the |
| 2450 // getInterceptor method and then the actual dynamic call on the | 2464 // getInterceptor method and then the actual dynamic call on the |
| 2451 // interceptor object. | 2465 // interceptor object. |
| 2452 HInstruction instruction = | 2466 HInstruction instruction = |
| 2453 invokeInterceptor(interceptedClasses, receiver, send); | 2467 invokeInterceptor(interceptedClasses, receiver, send); |
| 2454 instruction = new HInvokeDynamicSetter( | 2468 instruction = new HInvokeDynamicSetter( |
| 2455 selector, null, instruction, receiver, !hasSetter); | 2469 selector, null, instruction, receiver, !hasSetter); |
| 2456 // Add the value as an argument to the setter call on the | 2470 // Add the value as an argument to the setter call on the |
| 2457 // interceptor. | 2471 // interceptor. |
| (...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3094 constantSystem.createInt(selector.invocationMirrorKind); | 3108 constantSystem.createInt(selector.invocationMirrorKind); |
| 3095 | 3109 |
| 3096 pushInvokeHelper5(createInvocationMirror, | 3110 pushInvokeHelper5(createInvocationMirror, |
| 3097 graph.addConstant(nameConstant), | 3111 graph.addConstant(nameConstant), |
| 3098 graph.addConstant(internalNameConstant), | 3112 graph.addConstant(internalNameConstant), |
| 3099 graph.addConstant(kindConstant), | 3113 graph.addConstant(kindConstant), |
| 3100 argumentsInstruction, | 3114 argumentsInstruction, |
| 3101 argumentNamesInstruction, | 3115 argumentNamesInstruction, |
| 3102 HType.UNKNOWN); | 3116 HType.UNKNOWN); |
| 3103 | 3117 |
| 3104 var inputs = <HInstruction>[ | 3118 var inputs = <HInstruction>[target, self]; |
| 3105 target, | 3119 if (backend.isInterceptedMethod(element)) { |
| 3106 self, | 3120 inputs.add(self); |
| 3107 pop()]; | 3121 } |
| 3122 inputs.add(pop()); | |
| 3108 push(new HInvokeSuper(inputs)); | 3123 push(new HInvokeSuper(inputs)); |
| 3109 } | 3124 } |
| 3110 | 3125 |
| 3111 visitSend(Send node) { | 3126 visitSend(Send node) { |
| 3112 Element element = elements[node]; | 3127 Element element = elements[node]; |
| 3113 if (element != null && identical(element, currentElement)) { | 3128 if (element != null && identical(element, currentElement)) { |
| 3114 graph.isRecursiveMethod = true; | 3129 graph.isRecursiveMethod = true; |
| 3115 } | 3130 } |
| 3116 super.visitSend(node); | 3131 super.visitSend(node); |
| 3117 } | 3132 } |
| 3118 | 3133 |
| 3119 visitSuperSend(Send node) { | 3134 visitSuperSend(Send node) { |
| 3120 Selector selector = elements.getSelector(node); | 3135 Selector selector = elements.getSelector(node); |
| 3121 Element element = elements[node]; | 3136 Element element = elements[node]; |
| 3122 if (element == null) return generateSuperNoSuchMethodSend(node); | 3137 if (element == null) return generateSuperNoSuchMethodSend(node); |
| 3123 // TODO(5346): Try to avoid the need for calling [declaration] before | 3138 // TODO(5346): Try to avoid the need for calling [declaration] before |
| 3124 // creating an [HStatic]. | 3139 // creating an [HStatic]. |
| 3125 HInstruction target = new HStatic(element.declaration); | 3140 HInstruction target = new HStatic(element.declaration); |
| 3126 HInstruction context = localsHandler.readThis(); | 3141 HInstruction context = localsHandler.readThis(); |
| 3127 add(target); | 3142 add(target); |
| 3128 var inputs = <HInstruction>[target, context]; | 3143 var inputs = <HInstruction>[target, context]; |
| 3144 if (backend.isInterceptedMethod(element)) { | |
| 3145 inputs.add(context); | |
| 3146 } | |
| 3129 if (node.isPropertyAccess) { | 3147 if (node.isPropertyAccess) { |
| 3130 push(new HInvokeSuper(inputs)); | 3148 push(new HInvokeSuper(inputs)); |
| 3131 } else if (element.isFunction() || element.isGenerativeConstructor()) { | 3149 } else if (element.isFunction() || element.isGenerativeConstructor()) { |
| 3132 // TODO(5347): Try to avoid the need for calling [implementation] before | 3150 // TODO(5347): Try to avoid the need for calling [implementation] before |
| 3133 // calling [addStaticSendArgumentsToList]. | 3151 // calling [addStaticSendArgumentsToList]. |
| 3134 FunctionElement function = element.implementation; | 3152 FunctionElement function = element.implementation; |
| 3135 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, | 3153 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
| 3136 function, inputs); | 3154 function, inputs); |
| 3137 if (!succeeded) { | 3155 if (!succeeded) { |
| 3138 generateWrongArgumentCountError(node, element, node.arguments); | 3156 generateWrongArgumentCountError(node, element, node.arguments); |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3558 visitNewSend(send, type); | 3576 visitNewSend(send, type); |
| 3559 } | 3577 } |
| 3560 } | 3578 } |
| 3561 } | 3579 } |
| 3562 } | 3580 } |
| 3563 | 3581 |
| 3564 HInvokeDynamicMethod buildInvokeDynamic(Node node, | 3582 HInvokeDynamicMethod buildInvokeDynamic(Node node, |
| 3565 Selector selector, | 3583 Selector selector, |
| 3566 HInstruction receiver, | 3584 HInstruction receiver, |
| 3567 List<HInstruction> arguments) { | 3585 List<HInstruction> arguments) { |
| 3568 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 3586 Set<ClassElement> interceptedClasses = |
| 3587 backend.getInterceptedClassesOn(selector.name); | |
| 3569 List<HInstruction> inputs = <HInstruction>[]; | 3588 List<HInstruction> inputs = <HInstruction>[]; |
| 3570 bool isIntercepted = interceptedClasses != null; | 3589 bool isIntercepted = interceptedClasses != null; |
| 3571 if (isIntercepted) { | 3590 if (isIntercepted) { |
| 3572 assert(!interceptedClasses.isEmpty); | 3591 assert(!interceptedClasses.isEmpty); |
| 3573 inputs.add(invokeInterceptor(interceptedClasses, receiver, node)); | 3592 inputs.add(invokeInterceptor(interceptedClasses, receiver, node)); |
| 3574 } | 3593 } |
| 3575 inputs.add(receiver); | 3594 inputs.add(receiver); |
| 3576 inputs.addAll(arguments); | 3595 inputs.addAll(arguments); |
| 3577 return new HInvokeDynamicMethod(selector, inputs, isIntercepted); | 3596 return new HInvokeDynamicMethod(selector, inputs, isIntercepted); |
| 3578 } | 3597 } |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3912 // E <declaredIdentifier> = $iter.current; | 3931 // E <declaredIdentifier> = $iter.current; |
| 3913 // <body> | 3932 // <body> |
| 3914 // } | 3933 // } |
| 3915 | 3934 |
| 3916 // The iterator is shared between initializer, condition and body. | 3935 // The iterator is shared between initializer, condition and body. |
| 3917 HInstruction iterator; | 3936 HInstruction iterator; |
| 3918 void buildInitializer() { | 3937 void buildInitializer() { |
| 3919 SourceString iteratorName = const SourceString("iterator"); | 3938 SourceString iteratorName = const SourceString("iterator"); |
| 3920 Selector selector = | 3939 Selector selector = |
| 3921 new Selector.getter(iteratorName, currentElement.getLibrary()); | 3940 new Selector.getter(iteratorName, currentElement.getLibrary()); |
| 3922 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 3941 Set<ClassElement> interceptedClasses = |
| 3942 backend.getInterceptedClassesOn(selector.name); | |
| 3923 visit(node.expression); | 3943 visit(node.expression); |
| 3924 HInstruction receiver = pop(); | 3944 HInstruction receiver = pop(); |
| 3925 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); | 3945 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); |
| 3926 if (interceptedClasses == null) { | 3946 if (interceptedClasses == null) { |
| 3927 iterator = | 3947 iterator = |
| 3928 new HInvokeDynamicGetter(selector, null, receiver, !hasGetter); | 3948 new HInvokeDynamicGetter(selector, null, receiver, !hasGetter); |
| 3929 } else { | 3949 } else { |
| 3930 HInterceptor interceptor = | 3950 HInterceptor interceptor = |
| 3931 invokeInterceptor(interceptedClasses, receiver, null); | 3951 invokeInterceptor(interceptedClasses, receiver, null); |
| 3932 iterator = | 3952 iterator = |
| (...skipping 1098 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5031 new HSubGraphBlockInformation(elseBranch.graph)); | 5051 new HSubGraphBlockInformation(elseBranch.graph)); |
| 5032 | 5052 |
| 5033 HBasicBlock conditionStartBlock = conditionBranch.block; | 5053 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 5034 conditionStartBlock.setBlockFlow(info, joinBlock); | 5054 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 5035 SubGraph conditionGraph = conditionBranch.graph; | 5055 SubGraph conditionGraph = conditionBranch.graph; |
| 5036 HIf branch = conditionGraph.end.last; | 5056 HIf branch = conditionGraph.end.last; |
| 5037 assert(branch is HIf); | 5057 assert(branch is HIf); |
| 5038 branch.blockInformation = conditionStartBlock.blockFlow; | 5058 branch.blockInformation = conditionStartBlock.blockFlow; |
| 5039 } | 5059 } |
| 5040 } | 5060 } |
| OLD | NEW |