Mercurial > hg > graal-jvmci-8
comparison graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java @ 7846:91cc98eae8ee
Refactor guard creation methods are not flexible enough to handle two if guards.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Tue, 19 Feb 2013 14:29:12 +0100 |
parents | 0110e781b6fa |
children | 06a7cd6aaf00 |
comparison
equal
deleted
inserted
replaced
7845:0110e781b6fa | 7846:91cc98eae8ee |
---|---|
67 return name; | 67 return name; |
68 } | 68 } |
69 | 69 |
70 private static String specializationId(SpecializationData specialization) { | 70 private static String specializationId(SpecializationData specialization) { |
71 String name = ""; | 71 String name = ""; |
72 if (specialization.getNode().getSpecializations().length > 1) { | 72 NodeData node = specialization.getNode(); |
73 if (node.getSpecializations().length > 1) { | |
73 name = specialization.getMethodName(); | 74 name = specialization.getMethodName(); |
74 if (name.startsWith("do")) { | 75 if (name.startsWith("do")) { |
75 name = name.substring(2); | 76 name = name.substring(2); |
76 } | 77 } |
77 } | 78 } |
190 body.startGroup(); | 191 body.startGroup(); |
191 body.staticReference(singleton.getEnclosingElement().asType(), singleton.getSimpleName().toString()); | 192 body.staticReference(singleton.getEnclosingElement().asType(), singleton.getSimpleName().toString()); |
192 body.string(".").startCall(methodName); | 193 body.string(".").startCall(methodName); |
193 } | 194 } |
194 | 195 |
195 private static String emitExplicitGuards(ProcessorContext context, CodeTreeBuilder body, String prefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, | 196 private static CodeTree createGuardAndCast(ProcessorContext context, CodeTreeBuilder parent, String prefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, |
197 boolean onSpecialization, CodeTree guardedStatements, CodeTree elseStatements) { | |
198 | |
199 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
200 CodeTree implicitGuards = createImplicitGuards(context, parent, prefix, valueSpecialization, guardedSpecialization); | |
201 CodeTree explicitGuards = createExplicitGuards(context, parent, implicitGuards == null ? prefix : null, valueSpecialization, guardedSpecialization, onSpecialization); | |
202 | |
203 int ifCount = 0; | |
204 | |
205 if (implicitGuards != null) { | |
206 builder.startIf(); | |
207 builder.tree(implicitGuards); | |
208 builder.end(); | |
209 builder.startBlock(); | |
210 ifCount++; | |
211 } | |
212 | |
213 if (explicitGuards != null) { | |
214 builder.startIf(); | |
215 builder.tree(explicitGuards); | |
216 builder.end(); | |
217 builder.startBlock(); | |
218 ifCount++; | |
219 } | |
220 | |
221 if (implicitGuards == null && explicitGuards == null && prefix != null && !prefix.isEmpty()) { | |
222 builder.startIf().string(prefix).end().startBlock(); | |
223 ifCount++; | |
224 } | |
225 | |
226 builder.tree(guardedStatements); | |
227 | |
228 builder.end(ifCount); | |
229 if (ifCount > 0 && elseStatements != null) { | |
230 builder.startElseBlock(); | |
231 builder.tree(elseStatements); | |
232 builder.end(); | |
233 } | |
234 | |
235 return builder.getRoot(); | |
236 } | |
237 | |
238 private static CodeTree createExplicitGuards(ProcessorContext context, CodeTreeBuilder parent, String prefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, | |
196 boolean onSpecialization) { | 239 boolean onSpecialization) { |
197 String andOperator = prefix; | 240 CodeTreeBuilder builder = new CodeTreeBuilder(parent); |
241 String andOperator = (prefix != null && !prefix.isEmpty()) ? (prefix + " && ") : ""; | |
198 if (guardedSpecialization.getGuards().length > 0) { | 242 if (guardedSpecialization.getGuards().length > 0) { |
199 // Explicitly specified guards | 243 // Explicitly specified guards |
200 for (SpecializationGuardData guard : guardedSpecialization.getGuards()) { | 244 for (SpecializationGuardData guard : guardedSpecialization.getGuards()) { |
201 if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) { | 245 if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) { |
202 body.string(andOperator); | 246 builder.string(andOperator); |
203 | 247 |
204 startCallOperationMethod(body, guard.getGuardDeclaration()); | 248 startCallOperationMethod(builder, guard.getGuardDeclaration()); |
205 addValueParameterNamesWithCasts(context, body, valueSpecialization, guardedSpecialization); | 249 addValueParameterNamesWithCasts(context, builder, valueSpecialization, guardedSpecialization); |
206 | 250 |
207 body.end().end(); // call | 251 builder.end().end(); // call |
208 andOperator = " && "; | 252 andOperator = " && "; |
209 } | 253 } |
210 } | 254 } |
211 } | 255 } |
212 return andOperator; | 256 |
213 } | 257 return builder.isEmpty() ? null : builder.getRoot(); |
214 | 258 } |
215 private static String emitImplicitGuards(ProcessorContext context, CodeTreeBuilder body, String prefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { | 259 |
260 private static CodeTree createImplicitGuards(ProcessorContext context, CodeTreeBuilder parent, String prefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { | |
216 NodeData node = guardedSpecialization.getNode(); | 261 NodeData node = guardedSpecialization.getNode(); |
217 TypeSystemData typeSystem = node.getTypeSystem(); | 262 TypeSystemData typeSystem = node.getTypeSystem(); |
218 | 263 |
264 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
219 // Implict guards based on method signature | 265 // Implict guards based on method signature |
220 String andOperator = prefix; | 266 String andOperator = (prefix != null && !prefix.isEmpty()) ? (prefix + " && ") : ""; |
221 for (NodeFieldData field : node.getFields()) { | 267 for (NodeFieldData field : node.getFields()) { |
222 ActualParameter guardedParam = guardedSpecialization.findParameter(field.getName()); | 268 ActualParameter guardedParam = guardedSpecialization.findParameter(field.getName()); |
223 ActualParameter valueParam = valueSpecialization.findParameter(field.getName()); | 269 ActualParameter valueParam = valueSpecialization.findParameter(field.getName()); |
224 | 270 |
225 TypeData guardedType = guardedParam.getActualTypeData(typeSystem); | 271 TypeData guardedType = guardedParam.getActualTypeData(typeSystem); |
227 | 273 |
228 if (guardedType.equalsType(valueType) || guardedType.isGeneric()) { | 274 if (guardedType.equalsType(valueType) || guardedType.isGeneric()) { |
229 continue; | 275 continue; |
230 } | 276 } |
231 | 277 |
232 body.string(andOperator); | 278 builder.string(andOperator); |
233 | 279 |
234 body.startGroup(); | 280 builder.startGroup(); |
235 | 281 |
236 if (field.isShortCircuit()) { | 282 if (field.isShortCircuit()) { |
237 ActualParameter shortCircuit = guardedSpecialization.getPreviousParam(guardedParam); | 283 ActualParameter shortCircuit = guardedSpecialization.getPreviousParam(guardedParam); |
238 body.string("("); | 284 builder.string("("); |
239 body.string("!").string(valueName(guardedSpecialization, shortCircuit)); | 285 builder.string("!").string(valueName(guardedSpecialization, shortCircuit)); |
240 body.string(" || "); | 286 builder.string(" || "); |
241 } | 287 } |
242 | 288 |
243 startCallTypeSystemMethod(context, body, guardedSpecialization.getNode(), TypeSystemCodeGenerator.isTypeMethodName(guardedType)); | 289 startCallTypeSystemMethod(context, builder, guardedSpecialization.getNode(), TypeSystemCodeGenerator.isTypeMethodName(guardedType)); |
244 body.string(valueName(guardedSpecialization, guardedParam)); | 290 builder.string(valueName(guardedSpecialization, guardedParam)); |
245 body.end().end(); // call | 291 builder.end().end(); // call |
246 | 292 |
247 if (field.isShortCircuit()) { | 293 if (field.isShortCircuit()) { |
248 body.string(")"); | 294 builder.string(")"); |
249 } | 295 } |
250 | 296 |
251 body.end(); // group | 297 builder.end(); // group |
252 andOperator = " && "; | 298 andOperator = " && "; |
253 } | 299 } |
254 return andOperator; | 300 |
301 return builder.isEmpty() ? null : builder.getRoot(); | |
255 } | 302 } |
256 | 303 |
257 @Override | 304 @Override |
258 protected void createChildren(NodeData node) { | 305 protected void createChildren(NodeData node) { |
259 Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>(); | 306 Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>(); |
466 | 513 |
467 for (int i = 1; i < node.getSpecializations().length; i++) { | 514 for (int i = 1; i < node.getSpecializations().length; i++) { |
468 SpecializationData specialization = node.getSpecializations()[i]; | 515 SpecializationData specialization = node.getSpecializations()[i]; |
469 body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end(); | 516 body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end(); |
470 | 517 |
471 if (specialization.isGeneric()) { | 518 CodeTreeBuilder guarded = new CodeTreeBuilder(body); |
472 body.startIf().string("allowed").end().startBlock(); | 519 guarded.startReturn().startNew(nodeClassName(specialization)); |
473 } else { | 520 guarded.string(THIS_NODE_LOCAL_VAR_NAME); |
474 body.startIf().string("allowed"); | 521 guarded.end().end(); |
475 String prefix = " && "; | 522 |
476 prefix = emitImplicitGuards(getContext(), body, prefix, node.getGenericSpecialization(), specialization); | 523 body.tree(createGuardAndCast(getContext(), body, "allowed", node.getGenericSpecialization(), specialization, true, guarded.getRoot(), null)); |
477 emitExplicitGuards(getContext(), body, prefix, node.getGenericSpecialization(), specialization, true); | |
478 body.end().startBlock(); | |
479 } | |
480 body.startReturn().startNew(nodeClassName(specialization)); | |
481 body.string(THIS_NODE_LOCAL_VAR_NAME); | |
482 body.end().end(); | |
483 body.end(); // block | |
484 } | 524 } |
485 body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); | 525 body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); |
486 | 526 |
487 return method; | 527 return method; |
488 } | 528 } |
522 return Arrays.asList(method); | 562 return Arrays.asList(method); |
523 } | 563 } |
524 } | 564 } |
525 | 565 |
526 private void emitGeneratedGenericSpecialization(CodeTreeBuilder builder, SpecializationData current, SpecializationData next) { | 566 private void emitGeneratedGenericSpecialization(CodeTreeBuilder builder, SpecializationData current, SpecializationData next) { |
567 CodeTreeBuilder invokeMethodBuilder = new CodeTreeBuilder(builder); | |
568 emitInvokeDoMethod(invokeMethodBuilder, current, 0); | |
569 CodeTree invokeMethod = invokeMethodBuilder.getRoot(); | |
570 | |
527 if (next != null) { | 571 if (next != null) { |
528 builder.startIf(); | 572 invokeMethod = createGuardAndCast(getContext(), builder, "", current.getNode().getGenericSpecialization(), current, false, invokeMethod, null); |
529 String prefix = emitImplicitGuards(context, builder, "", current.getNode().getGenericSpecialization(), current); | 573 } |
530 emitExplicitGuards(context, builder, prefix, current.getNode().getGenericSpecialization(), current, false); | 574 |
531 builder.end().startBlock(); | 575 builder.tree(invokeMethod); |
532 } | |
533 | |
534 emitInvokeDoMethod(builder, current, 0); | |
535 | 576 |
536 if (next != null) { | 577 if (next != null) { |
537 builder.end(); | 578 builder.end(); |
538 | 579 |
539 builder.startReturn().startCall(generatedGenericMethodName(next)); | 580 builder.startReturn().startCall(generatedGenericMethodName(next)); |
697 builder.end().end(); | 738 builder.end().end(); |
698 return builder.getRoot(); | 739 return builder.getRoot(); |
699 } | 740 } |
700 | 741 |
701 private void buildFunctionalExecuteMethod(CodeTreeBuilder builder, SpecializationData specialization) { | 742 private void buildFunctionalExecuteMethod(CodeTreeBuilder builder, SpecializationData specialization) { |
743 if (specialization.isUninitialized()) { | |
744 builder.tree(createDeoptimize(builder)); | |
745 } | |
746 | |
747 builder.tree(createExecuteChildren(builder, specialization)); | |
748 | |
749 if (specialization.isUninitialized()) { | |
750 builder.tree(createSpecializeCall(builder, specialization)); | |
751 } | |
752 | |
753 CodeTree executeNode = createExecute(builder, specialization); | |
754 | |
755 SpecializationData next = specialization.findNextSpecialization(); | |
756 CodeTree returnSpecialized = null; | |
757 if (next != null) { | |
758 returnSpecialized = createReturnSpecializeAndExecute(builder, next, null); | |
759 } | |
760 builder.tree(createGuardAndCast(context, builder, "", specialization, specialization, false, executeNode, returnSpecialized)); | |
761 } | |
762 | |
763 private CodeTree createDeoptimize(CodeTreeBuilder parent) { | |
764 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
765 builder.startStatement(); | |
766 builder.startStaticCall(getContext().getTruffleTypes().getTruffleIntrinsics(), "deoptimize").end(); | |
767 builder.end(); | |
768 return builder.getRoot(); | |
769 } | |
770 | |
771 private CodeTree createSpecializeCall(CodeTreeBuilder parent, SpecializationData specialization) { | |
702 NodeData node = specialization.getNode(); | 772 NodeData node = specialization.getNode(); |
703 TypeSystemData typeSystem = node.getTypeSystem(); | 773 |
704 | 774 CodeTreeBuilder builder = new CodeTreeBuilder(parent); |
705 if (specialization.isUninitialized()) { | 775 emitSpecializationListeners(builder, node); |
706 builder.startStatement(); | 776 |
707 builder.startStaticCall(getContext().getTruffleTypes().getTruffleIntrinsics(), "deoptimize").end(); | 777 builder.startStatement(); |
708 builder.end(); | 778 builder.startCall("replace"); |
709 } | 779 if (node.needsRewrites(getContext())) { |
710 | 780 builder.startCall(factoryClassName(node), "specialize"); |
711 for (NodeFieldData field : node.getFields()) { | 781 builder.string("this"); |
712 if (field.getExecutionKind() == ExecutionKind.IGNORE) { | 782 builder.typeLiteral(builder.findMethod().getEnclosingElement().asType()); |
713 continue; | 783 addValueParameterNames(builder, specialization, null, false); |
714 } | 784 builder.end(); // call replace, call specialize |
715 | 785 } else { |
716 ActualParameter parameterType = specialization.findParameter(field.getName()); | 786 builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); |
717 | 787 } |
718 if (parameterType.getActualTypeData(typeSystem).isGeneric()) { | 788 builder.end().end(); |
719 buildGenericValueExecute(builder, specialization, field, null); | 789 return builder.getRoot(); |
720 } else { | 790 } |
721 buildSpecializedValueExecute(builder, specialization, field); | 791 |
722 } | 792 private CodeTree createExecute(CodeTreeBuilder parent, SpecializationData specialization) { |
723 } | 793 NodeData node = specialization.getNode(); |
724 | 794 CodeTreeBuilder builder = new CodeTreeBuilder(parent); |
725 if (specialization.hasDynamicGuards()) { | |
726 builder.startIf(); | |
727 | |
728 String prefix = emitImplicitGuards(getContext(), builder, "", specialization, specialization); | |
729 emitExplicitGuards(getContext(), builder, prefix, specialization, specialization, false); | |
730 builder.end().startBlock(); | |
731 } | |
732 | |
733 if (specialization.getExceptions().length > 0) { | 795 if (specialization.getExceptions().length > 0) { |
734 builder.startTryBlock(); | 796 builder.startTryBlock(); |
735 } | |
736 | |
737 if (specialization.isUninitialized()) { | |
738 emitSpecializationListeners(builder, node); | |
739 | |
740 builder.startStatement(); | |
741 builder.startCall("replace"); | |
742 if (node.needsRewrites(getContext())) { | |
743 builder.startCall(factoryClassName(node), "specialize"); | |
744 builder.string("this"); | |
745 builder.typeLiteral(builder.getRoot().getEnclosingClass().asType()); | |
746 addValueParameterNames(builder, specialization, null, false); | |
747 builder.end(); // call replace, call specialize | |
748 } else { | |
749 builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); | |
750 } | |
751 builder.end().end(); | |
752 } | 797 } |
753 | 798 |
754 if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) { | 799 if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) { |
755 builder.startReturn().startCall(factoryClassName(node), generatedGenericMethodName(null)); | 800 builder.startReturn().startCall(factoryClassName(node), generatedGenericMethodName(null)); |
756 builder.string("this"); | 801 builder.string("this"); |
770 } | 815 } |
771 | 816 |
772 if (specialization.getExceptions().length > 0) { | 817 if (specialization.getExceptions().length > 0) { |
773 for (SpecializationThrowsData exception : specialization.getExceptions()) { | 818 for (SpecializationThrowsData exception : specialization.getExceptions()) { |
774 builder.end().startCatchBlock(exception.getJavaClass(), "ex"); | 819 builder.end().startCatchBlock(exception.getJavaClass(), "ex"); |
775 emitReturnSpecializeAndExecute(builder, exception.getTransitionTo(), null); | 820 builder.tree(createReturnSpecializeAndExecute(parent, exception.getTransitionTo(), null)); |
776 } | 821 } |
777 builder.end(); | 822 builder.end(); |
778 } | 823 } |
779 if (specialization.hasDynamicGuards()) { | 824 return builder.getRoot(); |
780 builder.end().startElseBlock(); | 825 } |
781 emitReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), null); | 826 |
782 builder.end(); | 827 private CodeTree createExecuteChildren(CodeTreeBuilder parent, SpecializationData specialization) { |
783 } | 828 CodeTreeBuilder builder = new CodeTreeBuilder(parent); |
829 for (NodeFieldData field : specialization.getNode().getFields()) { | |
830 if (field.getExecutionKind() == ExecutionKind.IGNORE) { | |
831 continue; | |
832 } | |
833 | |
834 ActualParameter parameterType = specialization.findParameter(field.getName()); | |
835 | |
836 if (parameterType.getActualTypeData(specialization.getNode().getTypeSystem()).isGeneric()) { | |
837 buildGenericValueExecute(builder, specialization, field, null); | |
838 } else { | |
839 buildSpecializedValueExecute(builder, specialization, field); | |
840 } | |
841 } | |
842 return builder.getRoot(); | |
784 } | 843 } |
785 | 844 |
786 private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { | 845 private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { |
787 for (TemplateMethod listener : node.getSpecializationListeners()) { | 846 for (TemplateMethod listener : node.getSpecializationListeners()) { |
788 builder.startStatement(); | 847 builder.startStatement(); |
864 buildGenericValueExecute(builder, specialization.getNode().getGenericSpecialization(), exField, field); | 923 buildGenericValueExecute(builder, specialization.getNode().getGenericSpecialization(), exField, field); |
865 } else if (exField == field) { | 924 } else if (exField == field) { |
866 execute = true; | 925 execute = true; |
867 } | 926 } |
868 } | 927 } |
869 emitReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param.getSpecification()); | 928 builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param.getSpecification())); |
870 builder.end(); // catch block | 929 builder.end(); // catch block |
871 } | 930 } |
872 | 931 |
873 endShortCircuit(builder, shortCircuit); | 932 endShortCircuit(builder, shortCircuit); |
874 builder.newLine(); | 933 builder.newLine(); |
912 if (shortCircuit) { | 971 if (shortCircuit) { |
913 builder.end(); | 972 builder.end(); |
914 } | 973 } |
915 } | 974 } |
916 | 975 |
917 private void emitReturnSpecializeAndExecute(CodeTreeBuilder builder, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) { | 976 private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) { |
918 CodeTreeBuilder specializeCall = CodeTreeBuilder.createBuilder(); | 977 CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); |
919 specializeCall.startCall("specializeAndExecute"); | 978 specializeCall.startCall("specializeAndExecute"); |
920 specializeCall.string(nodeClassName(nextSpecialization) + ".class"); | 979 specializeCall.string(nodeClassName(nextSpecialization) + ".class"); |
921 addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionSpec != null ? exceptionSpec.getName() : null, true); | 980 addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionSpec != null ? exceptionSpec.getName() : null, true); |
922 specializeCall.end().end(); | 981 specializeCall.end().end(); |
923 | 982 |
983 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
924 builder.startReturn(); | 984 builder.startReturn(); |
925 builder.tree(specializeCall.getRoot()); | 985 builder.tree(specializeCall.getRoot()); |
926 builder.end(); | 986 builder.end(); |
987 return builder.getRoot(); | |
927 } | 988 } |
928 | 989 |
929 private void buildSpecializeStateMethod(CodeTypeElement clazz, SpecializationData specialization) { | 990 private void buildSpecializeStateMethod(CodeTypeElement clazz, SpecializationData specialization) { |
930 NodeData node = specialization.getNode(); | 991 NodeData node = specialization.getNode(); |
931 TypeData returnType = specialization.getReturnType().getActualTypeData(node.getTypeSystem()); | 992 TypeData returnType = specialization.getReturnType().getActualTypeData(node.getTypeSystem()); |
940 addValueParameters(method, specialization.getNode().getGenericSpecialization(), true); | 1001 addValueParameters(method, specialization.getNode().getGenericSpecialization(), true); |
941 clazz.add(method); | 1002 clazz.add(method); |
942 | 1003 |
943 CodeTreeBuilder builder = method.createBuilder(); | 1004 CodeTreeBuilder builder = method.createBuilder(); |
944 | 1005 |
945 builder.startStatement(); | 1006 builder.tree(createDeoptimize(builder)); |
946 builder.startStaticCall(getContext().getTruffleTypes().getTruffleIntrinsics(), "deoptimize").end(); | |
947 builder.end(); | |
948 | |
949 emitSpecializationListeners(builder, specialization.getNode()); | 1007 emitSpecializationListeners(builder, specialization.getNode()); |
950 | 1008 |
951 builder.startStatement(); | 1009 builder.startStatement(); |
952 builder.startCall("replace"); | 1010 builder.startCall("replace"); |
953 builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState"); | 1011 builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState"); |