From e96f6126f27c097d8148da143bb18edbe4180a61 Mon Sep 17 00:00:00 2001 From: Ufuk Kayserilioglu Date: Wed, 13 Dec 2023 01:54:01 +0200 Subject: [PATCH] [ruby/prism] Fix hash deopt based on contents The previous implementation of hash deopt was based on clearing the static literal flag on a hash node if the element that was being added was an array, hash or range node, or if the element was not a static literal in the first place. However, this is not correct. First of all, the elements added to a hash node will primarily be assoc nodes, but never array, hash or range nodes. Secondly, the static literal flag is set on assoc nodes, only if the value in an assoc node is a static literal, so the key is never checked. As a result, the static literal flag on a hash node would never be cleared if the key wasn't a static literal. This commit fixes this by clearing the static literal flag if: 1. the element is not an assoc node, 2. the element is an assoc node, but the key is not a static literal, or 3. the element is an assoc node, the key is a static literal, but assoc node (and thus the value in assoc node) is not a static literal. https://github.com/ruby/prism/commit/7f67109b36 --- prism/prism.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/prism/prism.c b/prism/prism.c index f4a47f8b5b..4b15f65859 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -3348,9 +3348,15 @@ static inline void pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) { pm_node_list_append(&hash->elements, element); - // If the element is not a static literal, then the hash is not a static - // literal. Turn that flag off. - if (PM_NODE_TYPE_P(element, PM_ARRAY_NODE) || PM_NODE_TYPE_P(element, PM_HASH_NODE) || PM_NODE_TYPE_P(element, PM_RANGE_NODE) || !PM_NODE_FLAG_P(element, PM_NODE_FLAG_STATIC_LITERAL)) { + bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE); + if (static_literal) { + pm_assoc_node_t *assoc = (pm_assoc_node_t *) element; + static_literal = !PM_NODE_TYPE_P(assoc->key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_HASH_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_RANGE_NODE); + static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL); + static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL); + } + + if (!static_literal) { pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL); } }