json_pure 1.5.3 → 1.5.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +8 -0
- data/Gemfile +3 -5
- data/Rakefile +34 -5
- data/VERSION +1 -1
- data/bin/prettify_json.rb +12 -39
- data/ext/json/ext/generator/generator.c +62 -22
- data/ext/json/ext/generator/generator.h +5 -2
- data/ext/json/ext/parser/parser.c +496 -285
- data/ext/json/ext/parser/parser.h +5 -1
- data/ext/json/ext/parser/parser.rl +155 -81
- data/java/src/json/ext/Generator.java +5 -5
- data/java/src/json/ext/GeneratorMethods.java +8 -7
- data/java/src/json/ext/GeneratorService.java +5 -4
- data/java/src/json/ext/GeneratorState.java +44 -16
- data/java/src/json/ext/OptionsReader.java +3 -3
- data/java/src/json/ext/Parser.java +399 -117
- data/java/src/json/ext/Parser.rl +118 -38
- data/java/src/json/ext/ParserService.java +4 -3
- data/java/src/json/ext/RuntimeInfo.java +23 -21
- data/java/src/json/ext/Utils.java +2 -2
- data/json.gemspec +17 -17
- data/json_pure.gemspec +22 -16
- data/lib/json.rb +7 -7
- data/lib/json/add/complex.rb +22 -0
- data/lib/json/add/core.rb +9 -9
- data/lib/json/add/rational.rb +22 -0
- data/lib/json/common.rb +50 -38
- data/lib/json/editor.rb +16 -16
- data/lib/json/ext.rb +2 -15
- data/lib/json/pure/generator.rb +18 -3
- data/lib/json/pure/parser.rb +92 -58
- data/lib/json/version.rb +1 -1
- data/tests/test_json.rb +52 -1
- data/tests/test_json_addition.rb +9 -2
- data/tests/test_json_generate.rb +34 -1
- data/tools/fuzz.rb +1 -1
- metadata +70 -51
- data/lib/json/add/rails.rb +0 -8
data/java/src/json/ext/Parser.rl
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
|
3
|
-
*
|
3
|
+
*
|
4
4
|
* Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
|
5
5
|
* for details.
|
6
6
|
*/
|
@@ -29,16 +29,16 @@ import org.jruby.util.ByteList;
|
|
29
29
|
|
30
30
|
/**
|
31
31
|
* The <code>JSON::Ext::Parser</code> class.
|
32
|
-
*
|
32
|
+
*
|
33
33
|
* <p>This is the JSON parser implemented as a Java class. To use it as the
|
34
34
|
* standard parser, set
|
35
35
|
* <pre>JSON.parser = JSON::Ext::Parser</pre>
|
36
36
|
* This is performed for you when you <code>include "json/ext"</code>.
|
37
|
-
*
|
37
|
+
*
|
38
38
|
* <p>This class does not perform the actual parsing, just acts as an interface
|
39
39
|
* to Ruby code. When the {@link #parse()} method is invoked, a
|
40
40
|
* Parser.ParserSession object is instantiated, which handles the process.
|
41
|
-
*
|
41
|
+
*
|
42
42
|
* @author mernen
|
43
43
|
*/
|
44
44
|
public class Parser extends RubyObject {
|
@@ -49,6 +49,7 @@ public class Parser extends RubyObject {
|
|
49
49
|
private int maxNesting;
|
50
50
|
private boolean allowNaN;
|
51
51
|
private boolean symbolizeNames;
|
52
|
+
private boolean quirksMode;
|
52
53
|
private RubyClass objectClass;
|
53
54
|
private RubyClass arrayClass;
|
54
55
|
private RubyHash match_string;
|
@@ -69,7 +70,7 @@ public class Parser extends RubyObject {
|
|
69
70
|
|
70
71
|
/**
|
71
72
|
* Multiple-value return for internal parser methods.
|
72
|
-
*
|
73
|
+
*
|
73
74
|
* <p>All the <code>parse<var>Stuff</var></code> methods return instances of
|
74
75
|
* <code>ParserResult</code> when successful, or <code>null</code> when
|
75
76
|
* there's a problem with the input data.
|
@@ -98,18 +99,18 @@ public class Parser extends RubyObject {
|
|
98
99
|
|
99
100
|
/**
|
100
101
|
* <code>Parser.new(source, opts = {})</code>
|
101
|
-
*
|
102
|
+
*
|
102
103
|
* <p>Creates a new <code>JSON::Ext::Parser</code> instance for the string
|
103
104
|
* <code>source</code>.
|
104
105
|
* It will be configured by the <code>opts</code> Hash.
|
105
106
|
* <code>opts</code> can have the following keys:
|
106
|
-
*
|
107
|
+
*
|
107
108
|
* <dl>
|
108
109
|
* <dt><code>:max_nesting</code>
|
109
110
|
* <dd>The maximum depth of nesting allowed in the parsed data
|
110
111
|
* structures. Disable depth checking with <code>:max_nesting => false|nil|0</code>,
|
111
112
|
* it defaults to 19.
|
112
|
-
*
|
113
|
+
*
|
113
114
|
* <dt><code>:allow_nan</code>
|
114
115
|
* <dd>If set to <code>true</code>, allow <code>NaN</code>,
|
115
116
|
* <code>Infinity</code> and <code>-Infinity</code> in defiance of RFC 4627
|
@@ -118,17 +119,25 @@ public class Parser extends RubyObject {
|
|
118
119
|
* <dt><code>:symbolize_names</code>
|
119
120
|
* <dd>If set to <code>true</code>, returns symbols for the names (keys) in
|
120
121
|
* a JSON object. Otherwise strings are returned, which is also the default.
|
122
|
+
*
|
123
|
+
* <dt><code>:quirks_mode?</code>
|
124
|
+
* <dd>If set to <code>true</code>, if the parse is in quirks_mode, false
|
125
|
+
* otherwise.
|
121
126
|
*
|
122
127
|
* <dt><code>:create_additions</code>
|
123
128
|
* <dd>If set to <code>false</code>, the Parser doesn't create additions
|
124
129
|
* even if a matchin class and <code>create_id</code> was found. This option
|
125
130
|
* defaults to <code>true</code>.
|
126
|
-
*
|
131
|
+
*
|
127
132
|
* <dt><code>:object_class</code>
|
128
133
|
* <dd>Defaults to Hash.
|
129
|
-
*
|
134
|
+
*
|
130
135
|
* <dt><code>:array_class</code>
|
131
136
|
* <dd>Defaults to Array.
|
137
|
+
*
|
138
|
+
* <dt><code>:quirks_mode</code>
|
139
|
+
* <dd>Enables quirks_mode for parser, that is for example parsing single
|
140
|
+
* JSON values instead of documents is possible.
|
132
141
|
* </dl>
|
133
142
|
*/
|
134
143
|
@JRubyMethod(name = "new", required = 1, optional = 1, meta = true)
|
@@ -142,20 +151,25 @@ public class Parser extends RubyObject {
|
|
142
151
|
|
143
152
|
@JRubyMethod(required = 1, optional = 1, visibility = Visibility.PRIVATE)
|
144
153
|
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
|
145
|
-
Ruby runtime
|
146
|
-
|
154
|
+
Ruby runtime = context.getRuntime();
|
155
|
+
if (this.vSource != null) {
|
156
|
+
throw runtime.newTypeError("already initialized instance");
|
157
|
+
}
|
147
158
|
|
148
159
|
OptionsReader opts = new OptionsReader(context, args.length > 1 ? args[1] : null);
|
149
160
|
this.maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
|
150
161
|
this.allowNaN = opts.getBool("allow_nan", false);
|
151
162
|
this.symbolizeNames = opts.getBool("symbolize_names", false);
|
163
|
+
this.quirksMode = opts.getBool("quirks_mode", false);
|
152
164
|
this.createId = opts.getString("create_id", getCreateId(context));
|
153
165
|
this.createAdditions = opts.getBool("create_additions", true);
|
154
166
|
this.objectClass = opts.getClass("object_class", runtime.getHash());
|
155
167
|
this.arrayClass = opts.getClass("array_class", runtime.getArray());
|
156
168
|
this.match_string = opts.getHash("match_string");
|
157
169
|
|
158
|
-
this.vSource =
|
170
|
+
this.vSource = args[0].convertToString();
|
171
|
+
if (!quirksMode) this.vSource = convertEncoding(context, vSource);
|
172
|
+
|
159
173
|
return this;
|
160
174
|
}
|
161
175
|
|
@@ -174,8 +188,8 @@ public class Parser extends RubyObject {
|
|
174
188
|
|
175
189
|
if (info.encodingsSupported()) {
|
176
190
|
RubyEncoding encoding = (RubyEncoding)source.encoding(context);
|
177
|
-
if (encoding != info.ascii8bit) {
|
178
|
-
return (RubyString)source.encode(context, info.utf8);
|
191
|
+
if (encoding != info.ascii8bit.get()) {
|
192
|
+
return (RubyString)source.encode(context, info.utf8.get());
|
179
193
|
}
|
180
194
|
|
181
195
|
String sniffedEncoding = sniffByteList(bl);
|
@@ -186,7 +200,7 @@ public class Parser extends RubyObject {
|
|
186
200
|
String sniffedEncoding = sniffByteList(bl);
|
187
201
|
if (sniffedEncoding == null) return source; // assume UTF-8
|
188
202
|
Ruby runtime = context.getRuntime();
|
189
|
-
return (RubyString)info.jsonModule.
|
203
|
+
return (RubyString)info.jsonModule.get().
|
190
204
|
callMethod(context, "iconv",
|
191
205
|
new IRubyObject[] {
|
192
206
|
runtime.newString("utf-8"),
|
@@ -216,7 +230,7 @@ public class Parser extends RubyObject {
|
|
216
230
|
private RubyString reinterpretEncoding(ThreadContext context,
|
217
231
|
RubyString str, String sniffedEncoding) {
|
218
232
|
RubyEncoding actualEncoding = info.getEncoding(context, sniffedEncoding);
|
219
|
-
RubyEncoding targetEncoding = info.utf8;
|
233
|
+
RubyEncoding targetEncoding = info.utf8.get();
|
220
234
|
RubyString dup = (RubyString)str.dup();
|
221
235
|
dup.force_encoding(context, actualEncoding);
|
222
236
|
return (RubyString)dup.encode_bang(context, targetEncoding);
|
@@ -224,7 +238,7 @@ public class Parser extends RubyObject {
|
|
224
238
|
|
225
239
|
/**
|
226
240
|
* <code>Parser#parse()</code>
|
227
|
-
*
|
241
|
+
*
|
228
242
|
* <p>Parses the current JSON text <code>source</code> and returns the
|
229
243
|
* complete data structure as a result.
|
230
244
|
*/
|
@@ -235,13 +249,32 @@ public class Parser extends RubyObject {
|
|
235
249
|
|
236
250
|
/**
|
237
251
|
* <code>Parser#source()</code>
|
238
|
-
*
|
252
|
+
*
|
239
253
|
* <p>Returns a copy of the current <code>source</code> string, that was
|
240
254
|
* used to construct this Parser.
|
241
255
|
*/
|
242
256
|
@JRubyMethod(name = "source")
|
243
257
|
public IRubyObject source_get() {
|
244
|
-
return
|
258
|
+
return checkAndGetSource().dup();
|
259
|
+
}
|
260
|
+
|
261
|
+
/**
|
262
|
+
* <code>Parser#quirks_mode?()</code>
|
263
|
+
*
|
264
|
+
* <p>If set to <code>true</code>, if the parse is in quirks_mode, false
|
265
|
+
* otherwise.
|
266
|
+
*/
|
267
|
+
@JRubyMethod(name = "quirks_mode?")
|
268
|
+
public IRubyObject quirks_mode_p(ThreadContext context) {
|
269
|
+
return context.getRuntime().newBoolean(quirksMode);
|
270
|
+
}
|
271
|
+
|
272
|
+
public RubyString checkAndGetSource() {
|
273
|
+
if (vSource != null) {
|
274
|
+
return vSource;
|
275
|
+
} else {
|
276
|
+
throw getRuntime().newTypeError("uninitialized instance");
|
277
|
+
}
|
245
278
|
}
|
246
279
|
|
247
280
|
/**
|
@@ -249,13 +282,13 @@ public class Parser extends RubyObject {
|
|
249
282
|
* set to <code>nil</code> or <code>false</code>, and a String if not.
|
250
283
|
*/
|
251
284
|
private RubyString getCreateId(ThreadContext context) {
|
252
|
-
IRubyObject v = info.jsonModule.callMethod(context, "create_id");
|
285
|
+
IRubyObject v = info.jsonModule.get().callMethod(context, "create_id");
|
253
286
|
return v.isTrue() ? v.convertToString() : null;
|
254
287
|
}
|
255
288
|
|
256
289
|
/**
|
257
290
|
* A string parsing session.
|
258
|
-
*
|
291
|
+
*
|
259
292
|
* <p>Once a ParserSession is instantiated, the source string should not
|
260
293
|
* change until the parsing is complete. The ParserSession object assumes
|
261
294
|
* the source {@link RubyString} is still associated to its original
|
@@ -279,7 +312,7 @@ public class Parser extends RubyObject {
|
|
279
312
|
private ParserSession(Parser parser, ThreadContext context) {
|
280
313
|
this.parser = parser;
|
281
314
|
this.context = context;
|
282
|
-
this.byteList = parser.
|
315
|
+
this.byteList = parser.checkAndGetSource().getByteList();
|
283
316
|
this.data = byteList.unsafeBytes();
|
284
317
|
this.decoder = new StringDecoder(context);
|
285
318
|
}
|
@@ -353,7 +386,7 @@ public class Parser extends RubyObject {
|
|
353
386
|
}
|
354
387
|
}
|
355
388
|
action parse_number {
|
356
|
-
if (pe > fpc + 9 &&
|
389
|
+
if (pe > fpc + 9 - (parser.quirksMode ? 1 : 0) &&
|
357
390
|
absSubSequence(fpc, fpc + 9).toString().equals(JSON_MINUS_INFINITY)) {
|
358
391
|
|
359
392
|
if (parser.allowNaN) {
|
@@ -453,7 +486,7 @@ public class Parser extends RubyObject {
|
|
453
486
|
fbreak;
|
454
487
|
}
|
455
488
|
|
456
|
-
main := '-'? ( '0' | [1-9][0-9]* ) ( ^[0-9] @exit );
|
489
|
+
main := '-'? ( '0' | [1-9][0-9]* ) ( ^[0-9]? @exit );
|
457
490
|
}%%
|
458
491
|
|
459
492
|
ParserResult parseInteger(int p, int pe) {
|
@@ -489,7 +522,7 @@ public class Parser extends RubyObject {
|
|
489
522
|
main := '-'?
|
490
523
|
( ( ( '0' | [1-9][0-9]* ) '.' [0-9]+ ( [Ee] [+\-]?[0-9]+ )? )
|
491
524
|
| ( ( '0' | [1-9][0-9]* ) ( [Ee] [+\-]? [0-9]+ ) ) )
|
492
|
-
( ^[0-9Ee.\-] @exit );
|
525
|
+
( ^[0-9Ee.\-]? @exit );
|
493
526
|
}%%
|
494
527
|
|
495
528
|
ParserResult parseFloat(int p, int pe) {
|
@@ -567,7 +600,7 @@ public class Parser extends RubyObject {
|
|
567
600
|
}
|
568
601
|
});
|
569
602
|
} catch (JumpException e) { }
|
570
|
-
if (memoArray[1] != null) {
|
603
|
+
if (memoArray[1] != null) {
|
571
604
|
RubyClass klass = (RubyClass) memoArray[1];
|
572
605
|
if (klass.respondsTo("json_creatable?") &&
|
573
606
|
klass.callMethod(context, "json_creatable?").isTrue()) {
|
@@ -690,15 +723,14 @@ public class Parser extends RubyObject {
|
|
690
723
|
fhold;
|
691
724
|
fbreak;
|
692
725
|
}
|
726
|
+
|
727
|
+
pair = ignore* begin_name >parse_name ignore* name_separator
|
728
|
+
ignore* begin_value >parse_value;
|
729
|
+
next_pair = ignore* value_separator pair;
|
693
730
|
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
begin_value >parse_value;
|
698
|
-
|
699
|
-
main := begin_object
|
700
|
-
(a_pair (ignore* value_separator a_pair)*)?
|
701
|
-
ignore* end_object @exit;
|
731
|
+
main := (
|
732
|
+
begin_object (pair (next_pair)*)? ignore* end_object
|
733
|
+
) @exit;
|
702
734
|
}%%
|
703
735
|
|
704
736
|
ParserResult parseObject(int p, int pe) {
|
@@ -730,7 +762,7 @@ public class Parser extends RubyObject {
|
|
730
762
|
IRubyObject vKlassName = result.op_aref(context, parser.createId);
|
731
763
|
if (!vKlassName.isNil()) {
|
732
764
|
// might throw ArgumentError, we let it propagate
|
733
|
-
IRubyObject klass = parser.info.jsonModule.
|
765
|
+
IRubyObject klass = parser.info.jsonModule.get().
|
734
766
|
callMethod(context, "deep_const_get", vKlassName);
|
735
767
|
if (klass.respondsTo("json_creatable?") &&
|
736
768
|
klass.callMethod(context, "json_creatable?").isTrue()) {
|
@@ -778,7 +810,7 @@ public class Parser extends RubyObject {
|
|
778
810
|
ignore*;
|
779
811
|
}%%
|
780
812
|
|
781
|
-
public IRubyObject
|
813
|
+
public IRubyObject parseStrict() {
|
782
814
|
int cs = EVIL;
|
783
815
|
int p, pe;
|
784
816
|
IRubyObject result = null;
|
@@ -795,6 +827,54 @@ public class Parser extends RubyObject {
|
|
795
827
|
}
|
796
828
|
}
|
797
829
|
|
830
|
+
%%{
|
831
|
+
machine JSON_quirks_mode;
|
832
|
+
include JSON_common;
|
833
|
+
|
834
|
+
write data;
|
835
|
+
|
836
|
+
action parse_value {
|
837
|
+
ParserResult res = parseValue(fpc, pe);
|
838
|
+
if (res == null) {
|
839
|
+
fhold;
|
840
|
+
fbreak;
|
841
|
+
} else {
|
842
|
+
result = res.result;
|
843
|
+
fexec res.p;
|
844
|
+
}
|
845
|
+
}
|
846
|
+
|
847
|
+
main := ignore*
|
848
|
+
( begin_value >parse_value)
|
849
|
+
ignore*;
|
850
|
+
}%%
|
851
|
+
|
852
|
+
public IRubyObject parseQuirksMode() {
|
853
|
+
int cs = EVIL;
|
854
|
+
int p, pe;
|
855
|
+
IRubyObject result = null;
|
856
|
+
|
857
|
+
%% write init;
|
858
|
+
p = byteList.begin();
|
859
|
+
pe = p + byteList.length();
|
860
|
+
%% write exec;
|
861
|
+
|
862
|
+
if (cs >= JSON_quirks_mode_first_final && p == pe) {
|
863
|
+
return result;
|
864
|
+
} else {
|
865
|
+
throw unexpectedToken(p, pe);
|
866
|
+
}
|
867
|
+
}
|
868
|
+
|
869
|
+
public IRubyObject parse() {
|
870
|
+
if (parser.quirksMode) {
|
871
|
+
return parseQuirksMode();
|
872
|
+
} else {
|
873
|
+
return parseStrict();
|
874
|
+
}
|
875
|
+
|
876
|
+
}
|
877
|
+
|
798
878
|
/**
|
799
879
|
* Returns a subsequence of the source ByteList, based on source
|
800
880
|
* array byte offsets (i.e., the ByteList's own begin offset is not
|
@@ -813,7 +893,7 @@ public class Parser extends RubyObject {
|
|
813
893
|
* @param name The constant name
|
814
894
|
*/
|
815
895
|
private IRubyObject getConstant(String name) {
|
816
|
-
return parser.info.jsonModule.getConstant(name);
|
896
|
+
return parser.info.jsonModule.get().getConstant(name);
|
817
897
|
}
|
818
898
|
|
819
899
|
private RaiseException newException(String className, String message) {
|
@@ -1,12 +1,13 @@
|
|
1
1
|
/*
|
2
2
|
* This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
|
3
|
-
*
|
3
|
+
*
|
4
4
|
* Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
|
5
5
|
* for details.
|
6
6
|
*/
|
7
7
|
package json.ext;
|
8
8
|
|
9
9
|
import java.io.IOException;
|
10
|
+
import java.lang.ref.WeakReference;
|
10
11
|
|
11
12
|
import org.jruby.Ruby;
|
12
13
|
import org.jruby.RubyClass;
|
@@ -23,8 +24,8 @@ public class ParserService implements BasicLibraryService {
|
|
23
24
|
runtime.getLoadService().require("json/common");
|
24
25
|
RuntimeInfo info = RuntimeInfo.initRuntime(runtime);
|
25
26
|
|
26
|
-
info.jsonModule = runtime.defineModule("JSON");
|
27
|
-
RubyModule jsonExtModule = info.jsonModule.defineModuleUnder("Ext");
|
27
|
+
info.jsonModule = new WeakReference<RubyModule>(runtime.defineModule("JSON"));
|
28
|
+
RubyModule jsonExtModule = info.jsonModule.get().defineModuleUnder("Ext");
|
28
29
|
RubyClass parserClass =
|
29
30
|
jsonExtModule.defineClassUnder("Parser", runtime.getObject(),
|
30
31
|
Parser.ALLOCATOR);
|
@@ -27,19 +27,21 @@ final class RuntimeInfo {
|
|
27
27
|
private static Map<Ruby, RuntimeInfo> runtimes;
|
28
28
|
|
29
29
|
// these fields are filled by the service loaders
|
30
|
+
// Use WeakReferences so that RuntimeInfo doesn't indirectly hold a hard reference to
|
31
|
+
// the Ruby runtime object, which would cause memory leaks in the runtimes map above.
|
30
32
|
/** JSON */
|
31
|
-
RubyModule jsonModule;
|
33
|
+
WeakReference<RubyModule> jsonModule;
|
32
34
|
/** JSON::Ext::Generator::GeneratorMethods::String::Extend */
|
33
|
-
RubyModule stringExtendModule;
|
35
|
+
WeakReference<RubyModule> stringExtendModule;
|
34
36
|
/** JSON::Ext::Generator::State */
|
35
|
-
RubyClass generatorStateClass;
|
37
|
+
WeakReference<RubyClass> generatorStateClass;
|
36
38
|
/** JSON::SAFE_STATE_PROTOTYPE */
|
37
|
-
GeneratorState safeStatePrototype;
|
39
|
+
WeakReference<GeneratorState> safeStatePrototype;
|
38
40
|
|
39
|
-
final RubyEncoding utf8;
|
40
|
-
final RubyEncoding ascii8bit;
|
41
|
+
final WeakReference<RubyEncoding> utf8;
|
42
|
+
final WeakReference<RubyEncoding> ascii8bit;
|
41
43
|
// other encodings
|
42
|
-
private final Map<String, RubyEncoding
|
44
|
+
private final Map<String, WeakReference<RubyEncoding>> encodings;
|
43
45
|
|
44
46
|
private RuntimeInfo(Ruby runtime) {
|
45
47
|
RubyClass encodingClass = runtime.getEncoding();
|
@@ -49,11 +51,11 @@ final class RuntimeInfo {
|
|
49
51
|
} else {
|
50
52
|
ThreadContext context = runtime.getCurrentContext();
|
51
53
|
|
52
|
-
utf8 = (RubyEncoding)RubyEncoding.find(context,
|
53
|
-
encodingClass, runtime.newString("utf-8"));
|
54
|
-
ascii8bit = (RubyEncoding)RubyEncoding.find(context,
|
55
|
-
encodingClass, runtime.newString("ascii-8bit"));
|
56
|
-
encodings = new HashMap<String, RubyEncoding
|
54
|
+
utf8 = new WeakReference<RubyEncoding>((RubyEncoding)RubyEncoding.find(context,
|
55
|
+
encodingClass, runtime.newString("utf-8")));
|
56
|
+
ascii8bit = new WeakReference<RubyEncoding>((RubyEncoding)RubyEncoding.find(context,
|
57
|
+
encodingClass, runtime.newString("ascii-8bit")));
|
58
|
+
encodings = new HashMap<String, WeakReference<RubyEncoding>>();
|
57
59
|
}
|
58
60
|
}
|
59
61
|
|
@@ -90,30 +92,30 @@ final class RuntimeInfo {
|
|
90
92
|
}
|
91
93
|
|
92
94
|
public boolean encodingsSupported() {
|
93
|
-
return utf8 != null;
|
95
|
+
return utf8 != null && utf8.get() != null;
|
94
96
|
}
|
95
97
|
|
96
98
|
public RubyEncoding getEncoding(ThreadContext context, String name) {
|
97
99
|
synchronized (encodings) {
|
98
|
-
RubyEncoding encoding = encodings.get(name);
|
100
|
+
WeakReference<RubyEncoding> encoding = encodings.get(name);
|
99
101
|
if (encoding == null) {
|
100
102
|
Ruby runtime = context.getRuntime();
|
101
|
-
encoding = (RubyEncoding)RubyEncoding.find(context,
|
102
|
-
runtime.getEncoding(), runtime.newString(name));
|
103
|
+
encoding = new WeakReference<RubyEncoding>((RubyEncoding)RubyEncoding.find(context,
|
104
|
+
runtime.getEncoding(), runtime.newString(name)));
|
103
105
|
encodings.put(name, encoding);
|
104
106
|
}
|
105
|
-
return encoding;
|
107
|
+
return encoding.get();
|
106
108
|
}
|
107
109
|
}
|
108
110
|
|
109
111
|
public GeneratorState getSafeStatePrototype(ThreadContext context) {
|
110
112
|
if (safeStatePrototype == null) {
|
111
|
-
IRubyObject value = jsonModule.getConstant("SAFE_STATE_PROTOTYPE");
|
113
|
+
IRubyObject value = jsonModule.get().getConstant("SAFE_STATE_PROTOTYPE");
|
112
114
|
if (!(value instanceof GeneratorState)) {
|
113
|
-
throw context.getRuntime().newTypeError(value, generatorStateClass);
|
115
|
+
throw context.getRuntime().newTypeError(value, generatorStateClass.get());
|
114
116
|
}
|
115
|
-
safeStatePrototype = (GeneratorState)value;
|
117
|
+
safeStatePrototype = new WeakReference<GeneratorState>((GeneratorState)value);
|
116
118
|
}
|
117
|
-
return safeStatePrototype;
|
119
|
+
return safeStatePrototype.get();
|
118
120
|
}
|
119
121
|
}
|