json 1.5.3 → 1.5.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of json might be problematic. Click here for more details.
- 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 +50 -52
- 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
|
}
|