Skip to content

Commit fc5cf2d

Browse files
committed
Only keep semantic fields in Java, i.e. skip location fields
* Add $YARP_SERIALIZE_ONLY_SEMANTICS_FIELDS to control where to serialize location fields at templating time, this way there is no overhead for either case and nothing to check at runtime. * Add a byte in the header to indicate whether location fields are included as expected. * Fixes #807 * Simplify the build-java CI job now that the FFI backend is available so JRuby can serialize. * Support keeping some location fields which are still needed until there is a replacement
1 parent 0d8d1be commit fc5cf2d

File tree

13 files changed

+88
-66
lines changed

13 files changed

+88
-66
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,22 +116,13 @@ jobs:
116116
JRUBY_OPTS: "--dev"
117117
steps:
118118
- uses: actions/checkout@v3
119-
- name: Set up CRuby
120-
uses: ruby/setup-ruby@v1
121-
with:
122-
ruby-version: 3.2
123-
bundler-cache: true
124-
- name: Serialize fixtures on CRuby
125-
run: bundle exec rake compile test:serialize_fixtures
126119
- name: Set up JRuby
127120
uses: ruby/setup-ruby@v1
128121
with:
129122
ruby-version: jruby
130123
bundler-cache: true
131-
- name: Compile generated Java files
132-
run: bundle exec rake compile
133124
- name: Run Java Loader test
134-
run: JRUBY_OPTS="-J-ea" bundle exec rake test:java_loader
125+
run: YARP_SERIALIZE_ONLY_SEMANTICS_FIELDS=1 JRUBY_OPTS="-J-ea" bundle exec rake test:java_loader
135126

136127
lex-ruby:
137128
runs-on: ubuntu-latest

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
/doc/
77
/pkg/
88
/spec/reports/
9-
/test/yarp/serialized/
109
/top-100-gems/
1110
/tmp/
1211
/vendor/bundle

config.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,6 +1771,7 @@ nodes:
17711771
type: location
17721772
- name: content_loc
17731773
type: location
1774+
semantic_field: true # https://github.com/ruby/yarp/issues/1452
17741775
- name: closing_loc
17751776
type: location
17761777
- name: unescaped
@@ -2091,6 +2092,7 @@ nodes:
20912092
type: location
20922093
- name: content_loc
20932094
type: location
2095+
semantic_field: true # https://github.com/ruby/yarp/issues/1452
20942096
- name: closing_loc
20952097
type: location
20962098
- name: unescaped
@@ -2284,8 +2286,10 @@ nodes:
22842286
kind: StringFlags
22852287
- name: opening_loc
22862288
type: location?
2289+
semantic_field: true # https://github.com/ruby/yarp/issues/1452
22872290
- name: content_loc
22882291
type: location
2292+
semantic_field: true # https://github.com/ruby/yarp/issues/1452
22892293
- name: closing_loc
22902294
type: location?
22912295
- name: unescaped

docs/serialization.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ The header is structured like the following table:
6262
| `1` | major version number |
6363
| `1` | minor version number |
6464
| `1` | patch version number |
65+
| `1` | 1 indicates only semantics fields were serialized, 0 indicates all fields were serialized (including location fields) |
6566
| string | the encoding name |
6667
| varint | number of comments |
6768
| comment* | comments |

lib/yarp/ffi.rb

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,14 @@ def self.with(filepath, &block)
166166
end
167167
end
168168
end
169+
170+
def self.dump_internal(source, source_size, filepath)
171+
YPBuffer.with do |buffer|
172+
metadata = [filepath.bytesize, filepath.b, 0].pack("LA*L") if filepath
173+
yp_parse_serialize(source, source_size, buffer.pointer, metadata)
174+
buffer.read
175+
end
176+
end
169177
end
170178

171179
# Mark the LibRubyParser module as private as it should only be called through
@@ -175,24 +183,15 @@ def self.with(filepath, &block)
175183
# The version constant is set by reading the result of calling yp_version.
176184
VERSION = LibRubyParser.yp_version.read_string
177185

178-
def self.dump_internal(source, source_size, filepath)
179-
LibRubyParser::YPBuffer.with do |buffer|
180-
metadata = [filepath.bytesize, filepath.b, 0].pack("LA*L") if filepath
181-
LibRubyParser.yp_parse_serialize(source, source_size, buffer.pointer, metadata)
182-
buffer.read
183-
end
184-
end
185-
private_class_method :dump_internal
186-
187186
# Mirror the YARP.dump API by using the serialization API.
188187
def self.dump(code, filepath = nil)
189-
dump_internal(code, code.bytesize, filepath)
188+
LibRubyParser.dump_internal(code, code.bytesize, filepath)
190189
end
191190

192191
# Mirror the YARP.dump_file API by using the serialization API.
193192
def self.dump_file(filepath)
194193
LibRubyParser::YPString.with(filepath) do |string|
195-
dump_internal(string.source, string.length, filepath)
194+
LibRubyParser.dump_internal(string.source, string.length, filepath)
196195
end
197196
end
198197

rakelib/serialization.rake

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,34 @@
11
# frozen_string_literal: true
22

3-
fixtures = File.expand_path("../test/yarp/fixtures", __dir__)
4-
serialized_dir = File.expand_path("../serialized", fixtures)
3+
task "test:java_loader" do
4+
# Recompile with YARP_SERIALIZE_ONLY_SEMANTICS_FIELDS=1
5+
# Due to some JRuby bug this does not get propagated to the compile task, so require the caller to set the env var
6+
# ENV["YARP_SERIALIZE_ONLY_SEMANTICS_FIELDS"] = "1"
7+
raise "this task requires $SERIALIZE_ONLY_SEMANTICS_FIELDS to be set" unless ENV["YARP_SERIALIZE_ONLY_SEMANTICS_FIELDS"]
8+
9+
Rake::Task["clobber"].invoke
10+
Rake::Task["test:java_loader:internal"].invoke
11+
end
12+
13+
task "test:java_loader:internal" => :compile do
14+
fixtures = File.expand_path("../test/yarp/fixtures", __dir__)
515

6-
desc "Serialize test fixtures and save it to .serialized files"
7-
task "test:serialize_fixtures" do
816
$:.unshift(File.expand_path("../lib", __dir__))
917
require "yarp"
18+
raise "this task requires the FFI backend" unless YARP::BACKEND == :FFI
1019
require "fileutils"
11-
12-
Dir["**/*.txt", base: fixtures].each do |relative|
13-
path = "#{fixtures}/#{relative}"
14-
serialized_path = "#{serialized_dir}/#{relative}"
15-
16-
serialized = YARP.dump_file(path)
17-
FileUtils.mkdir_p(File.dirname(serialized_path))
18-
File.write(serialized_path, serialized)
19-
end
20-
end
21-
22-
task "test:java_loader" do
2320
require 'java'
2421
require_relative '../tmp/yarp.jar'
2522
java_import 'org.yarp.Nodes$Source'
2623

2724
Dir["**/*.txt", base: fixtures].each do |relative|
2825
path = "#{fixtures}/#{relative}"
29-
serialized_path = "#{serialized_dir}/#{relative}"
30-
serialized = File.binread(serialized_path).unpack('c*')
31-
3226
puts
3327
puts path
28+
serialized = YARP.dump_file(path)
3429
source_bytes = File.binread(path).unpack('c*')
3530
source = Source.new(source_bytes.to_java(:byte))
36-
parse_result = org.yarp.Loader.load(serialized, source)
31+
parse_result = org.yarp.Loader.load(serialized.unpack('c*'), source)
3732
puts parse_result.value
3833
end
3934
end

src/yarp.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14436,6 +14436,7 @@ yp_serialize(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1443614436
yp_buffer_append_u8(buffer, YP_VERSION_MAJOR);
1443714437
yp_buffer_append_u8(buffer, YP_VERSION_MINOR);
1443814438
yp_buffer_append_u8(buffer, YP_VERSION_PATCH);
14439+
yp_buffer_append_u8(buffer, YP_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
1443914440

1444014441
yp_serialize_content(parser, node, buffer);
1444114442
yp_buffer_append_str(buffer, "\0", 1);

templates/include/yarp/ast.h.erb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,6 @@ typedef enum {
111111
} yp_<%= flag.human %>_t;
112112
<%- end -%>
113113

114+
#define YP_SERIALIZE_ONLY_SEMANTICS_FIELDS <%= YARP::SERIALIZE_ONLY_SEMANTICS_FIELDS %>
115+
114116
#endif // YARP_AST_H

templates/java/org/yarp/Loader.java.erb

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,16 @@ public class Loader {
6565
}
6666

6767
private ParseResult load() {
68-
expect((byte) 'Y');
69-
expect((byte) 'A');
70-
expect((byte) 'R');
71-
expect((byte) 'P');
68+
expect((byte) 'Y', "incorrect YARP header");
69+
expect((byte) 'A', "incorrect YARP header");
70+
expect((byte) 'R', "incorrect YARP header");
71+
expect((byte) 'P', "incorrect YARP header");
7272

73-
expect((byte) 0);
74-
expect((byte) 12);
75-
expect((byte) 0);
73+
expect((byte) 0, "YARP version does not match");
74+
expect((byte) 12, "YARP version does not match");
75+
expect((byte) 0, "YARP version does not match");
76+
77+
expect((byte) 1, "Loader.java requires no location fields in the serialized output");
7678

7779
// This loads the name of the encoding. We don't actually do anything
7880
// with it just yet.
@@ -265,7 +267,7 @@ public class Loader {
265267
case <%= index + 1 %>:
266268
<%-
267269
params = node.needs_serialized_length? ? ["buffer.getInt()"] : []
268-
params.concat node.fields.map { |field|
270+
params.concat node.semantic_fields.map { |field|
269271
case field
270272
when YARP::NodeField then "#{field.java_cast}loadNode()"
271273
when YARP::OptionalNodeField then "#{field.java_cast}loadOptionalNode()"
@@ -290,10 +292,10 @@ public class Loader {
290292
}
291293
}
292294

293-
private void expect(byte value) {
295+
private void expect(byte value, String error) {
294296
byte b = buffer.get();
295297
if (b != value) {
296-
throw new Error("Expected " + value + " but was " + b + " at position " + buffer.position());
298+
throw new Error("Deserialization error: " + error + " (expected " + value + " but was " + b + " at position " + buffer.position() + ")");
297299
}
298300
}
299301

templates/java/org/yarp/Nodes.java.erb

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ public abstract class Nodes {
177177
<%- if node.needs_serialized_length? -%>
178178
public final int serializedLength;
179179
<%- end -%>
180-
<%- node.fields.each do |field| -%>
180+
<%- node.semantic_fields.each do |field| -%>
181181
<%- if field.class.name.include?('Optional') -%>
182182
/** optional (can be null) */
183183
<%- end -%>
@@ -186,29 +186,27 @@ public abstract class Nodes {
186186

187187
<%-
188188
params = node.needs_serialized_length? ? ["int serializedLength"] : []
189-
params.concat node.fields.map { |field| "#{field.java_type} #{field.name}" }
189+
params.concat node.semantic_fields.map { |field| "#{field.java_type} #{field.name}" }
190190
params.concat ["int startOffset", "int length"]
191191
-%>
192192
public <%=node.name -%>(<%= params.join(", ") %>) {
193193
super(startOffset, length);
194194
<%- if node.needs_serialized_length? -%>
195195
this.serializedLength = serializedLength;
196196
<%- end -%>
197-
<%- node.fields.each do |field| -%>
197+
<%- node.semantic_fields.each do |field| -%>
198198
this.<%= field.name %> = <%= field.name %>;
199199
<%- end -%>
200200
}
201201
<%# methods for flags -%>
202-
<%- node.fields.each do |field| -%>
203-
<%- if field.is_a?(YARP::FlagsField) -%>
202+
<%- node.semantic_fields.grep(YARP::FlagsField).each do |field| -%>
204203
<%- flags.find { |flag| flag.name == field.kind }.tap { |flag| raise "Expected to find #{field.kind}" unless flag }.values.each do |value| -%>
205204

206205
public boolean is<%= value.camelcase %>() {
207206
return <%= field.kind %>.is<%= value.camelcase %>(this.<%= field.name %>);
208207
}
209208
<%- end -%>
210209
<%- end -%>
211-
<%- end -%>
212210
<%# potential override of setNewLineFlag() -%>
213211
<%- if node.newline == false -%>
214212

@@ -220,7 +218,7 @@ public abstract class Nodes {
220218

221219
@Override
222220
public void setNewLineFlag(Source source, boolean[] newlineMarked) {
223-
<%- field = node.fields.find { |f| f.name == node.newline } or raise node.newline -%>
221+
<%- field = node.semantic_fields.find { |f| f.name == node.newline } or raise node.newline -%>
224222
<%- case field -%>
225223
<%- when YARP::NodeField, YARP::OptionalNodeField -%>
226224
this.<%= field.name %>.setNewLineFlag(source, newlineMarked);
@@ -235,7 +233,7 @@ public abstract class Nodes {
235233
<%- end -%>
236234

237235
public <T> void visitChildNodes(AbstractNodeVisitor<T> visitor) {
238-
<%- node.fields.each do |field| -%>
236+
<%- node.semantic_fields.each do |field| -%>
239237
<%- case field -%>
240238
<%- when YARP::NodeListField -%>
241239
for (Nodes.Node child : this.<%= field.name %>) {
@@ -252,15 +250,15 @@ public abstract class Nodes {
252250
}
253251

254252
public Node[] childNodes() {
255-
<%- if node.fields.none?(YARP::NodeListField) and node.fields.none?(YARP::NodeKindField) -%>
253+
<%- if node.semantic_fields.none?(YARP::NodeListField) and node.semantic_fields.none?(YARP::NodeKindField) -%>
256254
return EMPTY_ARRAY;
257-
<%- elsif node.fields.one?(YARP::NodeListField) and node.fields.none?(YARP::NodeKindField) -%>
258-
return this.<%= node.fields.grep(YARP::NodeListField).first.name %>;
259-
<%- elsif node.fields.none?(YARP::NodeListField) -%>
260-
return new Node[] { <%= node.fields.grep(YARP::NodeKindField).map { |field| "this.#{field.name}" }.join(', ') %> };
255+
<%- elsif node.semantic_fields.one?(YARP::NodeListField) and node.semantic_fields.none?(YARP::NodeKindField) -%>
256+
return this.<%= node.semantic_fields.grep(YARP::NodeListField).first.name %>;
257+
<%- elsif node.semantic_fields.none?(YARP::NodeListField) -%>
258+
return new Node[] { <%= node.semantic_fields.grep(YARP::NodeKindField).map { |field| "this.#{field.name}" }.join(', ') %> };
261259
<%- else -%>
262260
ArrayList<Node> childNodes = new ArrayList<>();
263-
<%- node.fields.each do |field| -%>
261+
<%- node.semantic_fields.each do |field| -%>
264262
<%- case field -%>
265263
<%- when YARP::NodeField, YARP::OptionalNodeField -%>
266264
childNodes.add(this.<%= field.name %>);

0 commit comments

Comments
 (0)