Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gc/default/default.c
Original file line number Diff line number Diff line change
Expand Up @@ -8709,7 +8709,7 @@ heap_ready_to_gc(rb_objspace_t *objspace, rb_heap_t *heap)
static int
ready_to_gc(rb_objspace_t *objspace)
{
if (rb_gc_gc_disabled_global_p() || dont_gc_val() || during_gc) {
if ((!objspace->flags.during_postmortem && rb_gc_gc_disabled_global_p()) || dont_gc_val() || during_gc) {
for (int i = 0; i < HEAP_COUNT; i++) {
rb_heap_t *heap = &heaps[i];
heap_ready_to_gc(objspace, heap);
Expand Down
1 change: 1 addition & 0 deletions insns.def
Original file line number Diff line number Diff line change
Expand Up @@ -1357,6 +1357,7 @@ opt_case_dispatch
(..., VALUE key)
()
// attr rb_snum_t sp_inc = -1;
// attr bool zjit_profile = true;
{
OFFSET dst = vm_case_dispatch(hash, else_offset, key);

Expand Down
12 changes: 12 additions & 0 deletions lib/prism/node_ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -488,5 +488,17 @@ def closing_loc # :nodoc
end_keyword_loc
end
end

class SymbolNode < Node
#: () -> String
def value # :nodoc
content
end

#: () -> Location
def value_loc # :nodoc
content_loc
end
end
# :startdoc:
end
24 changes: 12 additions & 12 deletions lib/prism/translation/parser/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def visit_assoc_node(node)
if key.opening.nil?
builder.match_hash_var([key.unescaped, srange(key.location)])
else
builder.match_hash_var_from_str(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.value_loc)])], token(key.closing_loc))
builder.match_hash_var_from_str(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.content_loc)])], token(key.closing_loc))
end
else
builder.match_hash_var_from_str(token(key.opening_loc), visit_all(key.parts), token(key.closing_loc))
Expand All @@ -151,9 +151,9 @@ def visit_assoc_node(node)
implicit_value = if value.is_a?(CallNode)
builder.call_method(nil, nil, [value.name, srange(value.message_loc)])
elsif value.is_a?(ConstantReadNode)
builder.const([value.name, srange(key.value_loc)])
builder.const([value.name, srange(key.content_loc)])
else
builder.ident([value.name, srange(key.value_loc)]).updated(:lvar)
builder.ident([value.name, srange(key.content_loc)]).updated(:lvar)
end

builder.pair_keyword([key.unescaped, srange(key)], implicit_value)
Expand All @@ -165,13 +165,13 @@ def visit_assoc_node(node)
else
parts =
if key.is_a?(SymbolNode)
value = key.value
if value == ""
content = key.content
if content == ""
[]
elsif value.include?("\n")
string_nodes_from_line_continuations(key.unescaped, value, key.value_loc.start_offset, key.opening)
elsif content.include?("\n")
string_nodes_from_line_continuations(key.unescaped, content, key.content_loc.start_offset, key.opening)
else
[builder.string_internal([key.unescaped, srange(key.value_loc)])]
[builder.string_internal([key.unescaped, srange(key.content_loc)])]
end
else
visit_all(key.parts)
Expand Down Expand Up @@ -1775,12 +1775,12 @@ def visit_symbol_node(node)
end
else
parts =
if node.value == ""
if node.content == ""
[]
elsif node.value.include?("\n")
string_nodes_from_line_continuations(node.unescaped, node.value, node.value_loc.start_offset, node.opening)
elsif node.content.include?("\n")
string_nodes_from_line_continuations(node.unescaped, node.content, node.content_loc.start_offset, node.opening)
else
[builder.string_internal([node.unescaped, srange(node.value_loc)])]
[builder.string_internal([node.unescaped, srange(node.content_loc)])]
end

builder.symbol_compose(
Expand Down
22 changes: 11 additions & 11 deletions lib/prism/translation/ripper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ def visit_array_node(node)
visit_words_sep(opening_loc, previous, element)

bounds(element.location)
elements = on_qsymbols_add(elements, on_tstring_content(element.value))
elements = on_qsymbols_add(elements, on_tstring_content(element.content))

previous = element
end
Expand Down Expand Up @@ -853,7 +853,7 @@ def visit_array_node(node)
on_symbols_add(
elements,
if element.is_a?(SymbolNode)
on_word_add(on_word_new, on_tstring_content(element.value))
on_word_add(on_word_new, on_tstring_content(element.content))
else
element.parts.inject(on_word_new) do |word, part|
word_part =
Expand Down Expand Up @@ -2351,8 +2351,8 @@ def visit_hash_pattern_node(node)
if (key = element.key).opening_loc.nil?
visit(key)
else
bounds(key.value_loc)
if (value = key.value).empty?
bounds(key.content_loc)
if (value = key.content).empty?
on_string_content
else
on_string_add(on_string_content, on_tstring_content(value))
Expand Down Expand Up @@ -3841,24 +3841,24 @@ def visit_super_node(node)
def visit_symbol_node(node)
with_string_bounds(node) do
if (opening = node.opening)&.match?(/^%s|['"]:?$/)
bounds(node.value_loc)
bounds(node.content_loc)
content = on_string_content

if !(value = node.value).empty?
if !(value = node.content).empty?
content = on_string_add(content, on_tstring_content(value))
end

bounds(node.location)
on_dyna_symbol(content)
elsif (closing = node.closing) == ":"
bounds(node.location)
on_label("#{node.value}:")
on_label("#{node.content}:")
elsif opening.nil? && node.closing_loc.nil?
bounds(node.value_loc)
on_symbol_literal(visit_token(node.value))
bounds(node.content_loc)
on_symbol_literal(visit_token(node.content))
else
bounds(node.value_loc)
on_symbol_literal(on_symbol(visit_token(node.value)))
bounds(node.content_loc)
on_symbol_literal(on_symbol(visit_token(node.content)))
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/prism/translation/ruby_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1476,7 +1476,7 @@ def visit_super_node(node)
# :foo
# ^^^^
def visit_symbol_node(node)
node.value == "!@" ? s(node, :lit, :"!@") : s(node, :lit, node.unescaped.to_sym)
node.content == "!@" ? s(node, :lit, :"!@") : s(node, :lit, node.unescaped.to_sym)
end

# true
Expand Down
2 changes: 1 addition & 1 deletion prism/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4552,7 +4552,7 @@ nodes:
fields:
- name: opening_loc
type: location?
- name: value_loc
- name: content_loc
type: location
- name: closing_loc
type: location?
Expand Down
10 changes: 5 additions & 5 deletions prism/prism.c
Original file line number Diff line number Diff line change
Expand Up @@ -6900,7 +6900,7 @@ pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
flags,
PM_LOCATION_INIT_NODE(node),
node->opening_loc,
node->value_loc,
node->content_loc,
node->closing_loc,
node->unescaped
);
Expand Down Expand Up @@ -17180,7 +17180,7 @@ pm_slice_is_valid_local(const pm_parser_t *parser, const uint8_t *start, const u
*/
static pm_node_t *
parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_symbol_node_t *key) {
const pm_location_t *value_loc = &((pm_symbol_node_t *) key)->value_loc;
const pm_location_t *value_loc = &((pm_symbol_node_t *) key)->content_loc;
const uint8_t *start = parser->start + PM_LOCATION_START(value_loc);
const uint8_t *end = parser->start + PM_LOCATION_END(value_loc);

Expand Down Expand Up @@ -19136,8 +19136,8 @@ parse_symbol_array(pm_parser_t *parser, uint16_t depth) {
pm_symbol_node_t *cast = (pm_symbol_node_t *) current;
pm_token_t content = {
.type = PM_TOKEN_STRING_CONTENT,
.start = parser->start + cast->value_loc.start,
.end = parser->start + cast->value_loc.start + cast->value_loc.length
.start = parser->start + cast->content_loc.start,
.end = parser->start + cast->content_loc.start + cast->content_loc.length
};

pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->unescaped));
Expand Down Expand Up @@ -20516,7 +20516,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u
pm_interpolated_symbol_node_append(parser->arena, (pm_interpolated_symbol_node_t *) current, string);
} else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
pm_symbol_node_t *cast = (pm_symbol_node_t *) current;
pm_token_t content = { .type = PM_TOKEN_STRING_CONTENT, .start = parser->start + cast->value_loc.start, .end = parser->start + cast->value_loc.start + cast->value_loc.length };
pm_token_t content = { .type = PM_TOKEN_STRING_CONTENT, .start = parser->start + cast->content_loc.start, .end = parser->start + cast->content_loc.start + cast->content_loc.length };
pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->unescaped));
pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
parser_lex(parser);
Expand Down
119 changes: 98 additions & 21 deletions prism_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -7212,20 +7212,80 @@ pm_compile_alias_method_node(rb_iseq_t *iseq, const pm_alias_method_node_t *node
if (popped) PUSH_INSN(ret, *location, pop);
}

static inline void
pm_compile_and_node(rb_iseq_t *iseq, const pm_and_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
/**
* Compile a chain of and nodes or a chain of or nodes that has been flattened
* into source order, so that `a && b && c` is passed as the nodes
* `[a, a && b, b, a && b && c, c]`. Even indices hold the operands, and odd
* indices hold the operator nodes between them. Prism parses `a && b && c` as
* `(a && b) && c`, so pm_compile_and_node and pm_compile_or_node flatten the
* chain by walking left operands iteratively, which keeps the C stack depth
* independent of the length of the chain.
*
* Every operator in the chain branches to one shared end label. The peephole
* optimizer threads a branch to a label that is followed by another branch one
* link at a time, so a label per operator makes compilation quadratic in the
* length of the chain.
*/
static void
pm_compile_logical_chain(rb_iseq_t *iseq, size_t size, const pm_node_t **nodes, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
const pm_node_type_t type = PM_NODE_TYPE(nodes[1]);
LABEL *end_label = NEW_LABEL(location->line);

PM_COMPILE_NOT_POPPED(node->left);
if (!popped) PUSH_INSN(ret, *location, dup);
PUSH_INSNL(ret, *location, branchunless, end_label);
for (size_t index = 0; index + 1 < size; index += 2) {
PM_COMPILE_NOT_POPPED(nodes[index]);

if (!popped) PUSH_INSN(ret, *location, pop);
PM_COMPILE(node->right);
/* Each operator node starts where its left operand does, so every
* operator node in the chain is on the same line. */
const pm_node_location_t operator_location = {
.line = location->line,
.node_id = nodes[index + 1]->node_id
};

if (!popped) PUSH_INSN(ret, operator_location, dup);
if (type == PM_AND_NODE)
{
PUSH_INSNL(ret, operator_location, branchunless, end_label);
}
else {
PUSH_INSNL(ret, operator_location, branchif, end_label);
}
if (!popped) PUSH_INSN(ret, operator_location, pop);
}

PM_COMPILE(nodes[size - 1]);
PUSH_LABEL(ret, end_label);
}

static void
pm_compile_and_node(rb_iseq_t *iseq, const pm_and_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
const pm_node_t *cursor = (const pm_node_t *) node;
size_t size = 1;

while (PM_NODE_TYPE_P(cursor, PM_AND_NODE)) {
cursor = ((const pm_and_node_t *) cursor)->left;
size += 2;
}

VALUE handle = 0;
const pm_node_t **nodes = ALLOCV_N(const pm_node_t *, handle, size);

cursor = (const pm_node_t *) node;
size_t index = size;

while (PM_NODE_TYPE_P(cursor, PM_AND_NODE)) {
const pm_and_node_t *cast = (const pm_and_node_t *) cursor;
nodes[--index] = cast->right;
nodes[--index] = cursor;
cursor = cast->left;
}

nodes[0] = cursor;
pm_compile_logical_chain(iseq, size, nodes, location, ret, popped, scope_node);
ALLOCV_END(handle);
}

static inline void
pm_compile_array_node(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list_t *elements, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
Expand Down Expand Up @@ -8414,6 +8474,35 @@ pm_compile_next_node(rb_iseq_t *iseq, const pm_next_node_t *node, const pm_node_
}
}

static void
pm_compile_or_node(rb_iseq_t *iseq, const pm_or_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
const pm_node_t *cursor = (const pm_node_t *) node;
size_t size = 1;

while (PM_NODE_TYPE_P(cursor, PM_OR_NODE)) {
cursor = ((const pm_or_node_t *) cursor)->left;
size += 2;
}

VALUE handle = 0;
const pm_node_t **nodes = ALLOCV_N(const pm_node_t *, handle, size);

cursor = (const pm_node_t *) node;
size_t index = size;

while (PM_NODE_TYPE_P(cursor, PM_OR_NODE)) {
const pm_or_node_t *cast = (const pm_or_node_t *) cursor;
nodes[--index] = cast->right;
nodes[--index] = cursor;
cursor = cast->left;
}

nodes[0] = cursor;
pm_compile_logical_chain(iseq, size, nodes, location, ret, popped, scope_node);
ALLOCV_END(handle);
}

static inline void
pm_compile_redo_node(rb_iseq_t *iseq, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
Expand Down Expand Up @@ -10090,23 +10179,11 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,

return;
}
case PM_OR_NODE: {
case PM_OR_NODE:
// a or b
// ^^^^^^
const pm_or_node_t *cast = (const pm_or_node_t *) node;

LABEL *end_label = NEW_LABEL(location.line);
PM_COMPILE_NOT_POPPED(cast->left);

if (!popped) PUSH_INSN(ret, location, dup);
PUSH_INSNL(ret, location, branchif, end_label);

if (!popped) PUSH_INSN(ret, location, pop);
PM_COMPILE(cast->right);
PUSH_LABEL(ret, end_label);

pm_compile_or_node(iseq, (const pm_or_node_t *) node, &location, ret, popped, scope_node);
return;
}
case PM_OPTIONAL_PARAMETER_NODE: {
// def foo(bar = 1); end
// ^^^^^^^
Expand Down
6 changes: 6 additions & 0 deletions test/ruby/test_compile_prism.rb
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,9 @@ def self.bar(*) = Array(*)
def test_AndNode
assert_prism_eval("true && 1")
assert_prism_eval("false && 1")
assert_prism_eval("true && 1 && 2")
assert_prism_eval("true && nil && 2")
assert_prism_eval("a = []; a.push(1) && a.push(2) && nil && a.push(3); a")
end

def test_CaseNode
Expand Down Expand Up @@ -1000,6 +1003,9 @@ def test_IfNode
def test_OrNode
assert_prism_eval("true || 1")
assert_prism_eval("false || 1")
assert_prism_eval("nil || false || 1")
assert_prism_eval("nil || 1 || 2")
assert_prism_eval("a = []; a.push(1).empty? || nil || a.push(2) || a.push(3); a")
end

def test_UnlessNode
Expand Down
Loading