{"id":231049,"date":"2024-05-28T16:14:02","date_gmt":"2024-05-28T23:14:02","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/java\/?p=231049"},"modified":"2024-06-26T10:56:01","modified_gmt":"2024-06-26T17:56:01","slug":"improving-openjdk-scalar-replacement-part-1-3","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/java\/improving-openjdk-scalar-replacement-part-1-3\/","title":{"rendered":"Improving OpenJDK Scalar Replacement &#8211; Part 1\/3"},"content":{"rendered":"<p style=\"text-align: justify;\">Scalar replacement (SR) is a powerful optimization technique in OpenJDK that aims to enhance the performance of Java applications by breaking down complex objects into simpler, more manageable scalar variables. In this three-part blog series, we will delve into the intricacies of scalar replacement and the enhancements we&#8217;ve contributed to the OpenJDK implementation of it. The first post will provide an overview of scalar replacement, explaining its purpose and fundamental mechanisms. The second post will detail the specific improvements we have made. Finally, the third post will present the results of these improvements. Let&#8217;s jump right into it &#8211; and don&#8217;t forget to add comments!<\/p>\n<h1 aria-level=\"1\"><span data-contrast=\"none\">Introduction<\/span><span data-ccp-props=\"{&quot;134245418&quot;:true,&quot;134245529&quot;:true,&quot;335559738&quot;:360,&quot;335559739&quot;:80}\">\u00a0<\/span><\/h2>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The OpenJDK JVM has two Just-In-Time compilers, C1 and C2. C2 is a compiler that applies many optimizations to produce a very efficient compiled version of the program. This blog post series presents an improvement that we contributed to C2 scalar replacement optimization. But before we delve into the details of our contributions, we are going to discuss about three optimizations implemented in C2: <\/span><i><span data-contrast=\"auto\">escape analysis<\/span><\/i><span data-contrast=\"auto\">, <\/span><i><span data-contrast=\"auto\">method inlining,<\/span><\/i><span data-contrast=\"auto\"> and <\/span><i><span data-contrast=\"auto\">scalar replacement<\/span><\/i><span data-contrast=\"auto\">.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Escape analysis (EA) analyzes the code being compiled and decides for each object allocation whether that object might be used outside the current method or thread.<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Method Inlining (MI) is, in very general terms, an optimization that replaces method calls with a copy of the body of the method being called.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6}\">\u00a0<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Scalar replacement (SR) is an optimization which tries to remove object allocations that it considers unnecessary, and it uses information provided by EA and changes made by MI to achieve that. SR removes object allocations by transforming the code to store object\u2019s fields in local variables and using MI to remove the need to invoke methods on objects.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The main benefit of SR may be that it decreases memory allocation rate and pressure on the Garbage Collector (GC). However, there are more benefits. By removing allocations, the method&#8217;s code becomes simpler, which may reveal more optimizations. So, in general, doing scalar replacement is a Good Thing <\/span><sup><span data-contrast=\"auto\">TM<\/span><\/sup><span data-contrast=\"auto\">.<\/span><\/p>\n<p><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6}\">\u00a0<\/span><\/p>\n<h1 aria-level=\"2\"><span data-contrast=\"none\">A Simple Example<\/span><span data-ccp-props=\"{&quot;134245418&quot;:true,&quot;134245529&quot;:true,&quot;335559738&quot;:160,&quot;335559739&quot;:80}\">\u00a0<\/span><\/h2>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">We are going to use the <\/span><i><span data-contrast=\"auto\">Message<\/span><\/i> <span data-contrast=\"auto\">class shown in Listing 1 as the running example in this article. The important things to note in this class are the <\/span><i><span data-contrast=\"auto\">Checksum<\/span><\/i> <span data-contrast=\"auto\">method and the <\/span><i><span data-contrast=\"auto\">content<\/span><\/i><span data-contrast=\"auto\"> field. The <\/span><i><span data-contrast=\"auto\">Checksum<\/span><\/i> <span data-contrast=\"auto\">method iterates on the characters of the <\/span><i><span data-contrast=\"auto\">content<\/span><\/i><span data-contrast=\"auto\"> field and accumulates their integer value, returning that as the checksum of the message list.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6}\">\u00a0<\/span><span data-ccp-props=\"{}\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture1.png\"><img decoding=\"async\" class=\"aligncenter wp-image-231056\" src=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture1-300x290.png\" alt=\"The Message class.\u00a0\" width=\"405\" height=\"391\" srcset=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture1-300x290.png 300w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture1-1024x991.png 1024w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture1-768x743.png 768w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture1-24x24.png 24w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture1.png 1150w\" sizes=\"(max-width: 405px) 100vw, 405px\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><b><span data-contrast=\"auto\">Listing 1:<\/span><\/b><span data-contrast=\"auto\"> The Message class.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Listing 2 shows the <\/span><i><span data-contrast=\"auto\">CompositeChecksum <\/span><\/i><span data-contrast=\"auto\">method. This method iterates on a list of messages and for each message it calls the <\/span><i><span data-contrast=\"auto\">Checksum <\/span><\/i><span data-contrast=\"auto\">method on it. The method accumulates the checksum of all messages and returns it as the composite checksum of the list. This may not be an example of a piece of code written very carefully, but is the kind of code that is often processed by compilers, especially after many transformations have been applied to the code.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6}\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture2.png\"><img decoding=\"async\" class=\"aligncenter wp-image-231059\" src=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture2-300x185.png\" alt=\"The CompositeChecksum method.\u00a0\" width=\"453\" height=\"279\" srcset=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture2-300x185.png 300w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture2-1024x630.png 1024w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture2-768x472.png 768w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture2.png 1356w\" sizes=\"(max-width: 453px) 100vw, 453px\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><b><span data-contrast=\"auto\">Listing 2:<\/span><\/b><span data-contrast=\"auto\"> The CompositeChecksum method.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Listing 3 highlights what is going to happen when MI is performed on this method with respect to the <\/span><i><span data-contrast=\"auto\">Message <\/span><\/i><span data-contrast=\"auto\">class constructor and <\/span><i><span data-contrast=\"auto\">Checksum <\/span><\/i><span data-contrast=\"auto\">method. Note that the constructor of the <\/span><i><span data-contrast=\"auto\">Message <\/span><\/i><span data-contrast=\"auto\">object is going to be copied in the place where the constructor was previously being called and the call to the <\/span><i><span data-contrast=\"auto\">Checksum <\/span><\/i><span data-contrast=\"auto\">method is going to be replaced by the code of the <\/span><i><span data-contrast=\"auto\">Checksum <\/span><\/i><span data-contrast=\"auto\">method itself. Of course, after the code is copied, it is adjusted to still work correctly in the target location.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6}\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture3.png\"><img decoding=\"async\" class=\"aligncenter wp-image-231060\" src=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture3-300x179.png\" alt=\"The CompositeChecksum method during inlining optimization.\" width=\"446\" height=\"266\" srcset=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture3-300x179.png 300w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture3-1024x612.png 1024w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture3-768x459.png 768w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture3.png 1388w\" sizes=\"(max-width: 446px) 100vw, 446px\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><b><span data-contrast=\"auto\">Listing 3:<\/span><\/b><span data-contrast=\"auto\"> The CompositeChecksum method during inlining optimization.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Listing 4 shows the code <\/span><i><span data-contrast=\"auto\">after<\/span><\/i><span data-contrast=\"auto\"> MI has been executed. Note that the object allocation is still happening. The body of the <\/span><i><span data-contrast=\"auto\">Message <\/span><\/i><span data-contrast=\"auto\">and <\/span><i><span data-contrast=\"auto\">Checksum <\/span><\/i><span data-contrast=\"auto\">methods were copied inside the loop, but they still operate on an object, in this case the one pointed to by <\/span><i><span data-contrast=\"auto\">m_ptr<\/span><\/i><span data-contrast=\"auto\"> \u2013 previously these methods used an object pointed to by <\/span><i><span data-contrast=\"auto\">this<\/span><\/i><span data-contrast=\"auto\">. The <\/span><i><span data-contrast=\"auto\">chks<\/span><\/i> <span data-contrast=\"auto\">variable that was local to the <\/span><i><span data-contrast=\"auto\">Checksum <\/span><\/i><span data-contrast=\"auto\">method now is another variable local to the <\/span><i><span data-contrast=\"auto\">CompositeChecksum <\/span><\/i><span data-contrast=\"auto\">loop.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6}\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture4.png\"><img decoding=\"async\" class=\"aligncenter wp-image-231061\" src=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture4-300x193.png\" alt=\"The CompositeChecksum method after inlining optimization.\" width=\"469\" height=\"302\" srcset=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture4-300x193.png 300w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture4-1024x658.png 1024w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture4-768x493.png 768w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture4-1536x986.png 1536w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture4.png 1562w\" sizes=\"(max-width: 469px) 100vw, 469px\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><b><span data-contrast=\"auto\">Listing 4:<\/span><\/b><span data-contrast=\"auto\"> The CompositeChecksum method after inlining optimization.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Note that there is still room for improving the code of the <\/span><i><span data-contrast=\"auto\">CompositeChecksum <\/span><\/i><span data-contrast=\"auto\">method. After performing some more analysis C2 will find that some of the assignments in the code do not really need to be performed. For instance, the assignment of the <\/span><i><span data-contrast=\"auto\">msg<\/span><\/i><span data-contrast=\"auto\"> variable to the <\/span><i><span data-contrast=\"auto\">content<\/span><\/i><span data-contrast=\"auto\"> variable can be eliminated and we can just iterate on <\/span><i><span data-contrast=\"auto\">msg<\/span><\/i><span data-contrast=\"auto\"> itself, instead of <\/span><i><span data-contrast=\"auto\">content<\/span><\/i><span data-contrast=\"auto\">. The same logic applies to the <\/span><i><span data-contrast=\"auto\">chks<\/span><\/i><span data-contrast=\"auto\"> variable: instead of doing the computation on the <\/span><i><span data-contrast=\"auto\">chks<\/span><\/i><span data-contrast=\"auto\"> variable and then later assigning it to <\/span><i><span data-contrast=\"auto\">cs<\/span><\/i><span data-contrast=\"auto\"> and then accumulating into <\/span><i><span data-contrast=\"auto\">checksum<\/span><\/i><span data-contrast=\"auto\"> we can just do the computation directly in the <\/span><i><span data-contrast=\"auto\">checksum<\/span><\/i><span data-contrast=\"auto\"> variable. Listing 5 shows the code after these optimizations.\u00a0<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6}\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture5.png\"><img decoding=\"async\" class=\"aligncenter wp-image-231062\" src=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture5-300x164.png\" alt=\"The CompositeChecksum method after additional optimizations.\u00a0\" width=\"463\" height=\"253\" srcset=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture5-300x164.png 300w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture5-1024x561.png 1024w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture5-768x421.png 768w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture5.png 1512w\" sizes=\"(max-width: 463px) 100vw, 463px\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><b><span data-contrast=\"auto\">Listing 5:<\/span><\/b><span data-contrast=\"auto\"> The CompositeChecksum method after additional optimizations.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2}\">\u00a0<\/span><\/p>\n<p><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">After still some more analysis C2 will note that there are only <\/span><i><span data-contrast=\"auto\">writes<\/span><\/i><span data-contrast=\"auto\"> to the object pointed to by <\/span><i><span data-contrast=\"auto\">m_ptr<\/span><\/i><span data-contrast=\"auto\"> and no code is <\/span><i><span data-contrast=\"auto\">reading<\/span><\/i><span data-contrast=\"auto\"> from it. That observation, together with some other info about the object class, means that this object allocation is not necessary and therefore it can be removed! Listing 6 shows the code after the object allocation is removed.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6}\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture6.png\"><img decoding=\"async\" class=\"aligncenter wp-image-231063\" src=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture6-300x151.png\" alt=\"The CompositeChecksum method after Message allocation is removed.\u00a0\u00a0\" width=\"477\" height=\"240\" srcset=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture6-300x151.png 300w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture6-1024x515.png 1024w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture6-768x386.png 768w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/05\/Picture6.png 1512w\" sizes=\"(max-width: 477px) 100vw, 477px\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><b><span data-contrast=\"auto\">Listing 6:<\/span><\/b><span data-contrast=\"auto\"> The CompositeChecksum method after Message allocation is removed.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2}\">\u00a0<\/span><span data-ccp-props=\"{}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The object allocation removal was only possible because at some point there was no code reading from that object. Scalar replacement is one of the optimizations that replaces loads from objects\u2019 fields with a direct use of the statement (or value) that was last written in the objects\u2019 fields. There are other optimizations that achieve the same effect but usually they work on simple pieces of code, like this example method. Scalar replacement, however, can \u201clook\u201d more thoroughly in the method and find points where these object fields\u2019 writes can be simplified.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6}\">\u00a0<\/span><\/p>\n<h2>Conclusion<\/h2>\n<p style=\"text-align: justify;\">In conclusion, scalar replacement serves as a critical optimization technique within OpenJDK, transforming complex object instances into simpler scalar variables to enhance runtime performance. By eliminating the need for heap allocation and reducing memory overhead, scalar replacement significantly improves execution speed and resource efficiency. Understanding the fundamental mechanisms behind scalar replacement sets the stage <a href=\"https:\/\/devblogs.microsoft.com\/java\/improving-openjdk-scalar-replacement-part-2-3\/\">for the second part of this series<\/a> where we describe the improvements we contributed to OpenJDK&#8217;s scalar replacement implementation.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Scalar replacement (SR) is a powerful optimization technique in OpenJDK that aims to enhance the performance of Java applications by breaking down complex objects into simpler, more manageable scalar variables. In this three-part blog series, we will delve into the intricacies of scalar replacement and the enhancements we&#8217;ve contributed to the OpenJDK implementation of it. [&hellip;]<\/p>\n","protected":false},"author":125793,"featured_media":227205,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"image","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,249],"tags":[817,818,820,319,819],"class_list":["post-231049","post","type-post","status-publish","format-image","has-post-thumbnail","hentry","category-java","category-openjdk","tag-compiler","tag-escape-analysis","tag-just-in-time-compiler","tag-openjdk","tag-scalar-replacement","post_format-post-format-image"],"acf":[],"blog_post_summary":"<p>Scalar replacement (SR) is a powerful optimization technique in OpenJDK that aims to enhance the performance of Java applications by breaking down complex objects into simpler, more manageable scalar variables. In this three-part blog series, we will delve into the intricacies of scalar replacement and the enhancements we&#8217;ve contributed to the OpenJDK implementation of it. [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts\/231049","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/users\/125793"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/comments?post=231049"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts\/231049\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/media\/227205"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/media?parent=231049"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/categories?post=231049"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/tags?post=231049"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}