Skip to content

Commit 44b177c

Browse files
committed
optimize codegen
1 parent 0c3505d commit 44b177c

File tree

5 files changed

+58
-58
lines changed

5 files changed

+58
-58
lines changed

src/main/java/com/jsoniter/BenchmarkRunner.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
package com.jsoniter;
22

33

4-
import com.dslplatform.json.BoolConverter;
54
import com.dslplatform.json.DslJson;
6-
import com.dslplatform.json.JsonReader;
75
import org.openjdk.jmh.Main;
86
import org.openjdk.jmh.annotations.*;
97
import org.openjdk.jmh.infra.Blackhole;
108

119
import java.io.IOException;
12-
import java.util.List;
1310

1411
@State(Scope.Thread)
1512
public class BenchmarkRunner {

src/main/java/com/jsoniter/Codegen.java

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ private static String genObjectUsingHash(Class clazz, String cacheKey) {
182182
if (clazz.getFields().length == 0) {
183183
StringBuilder lines = new StringBuilder();
184184
append(lines, "public static Object decode_(com.jsoniter.Jsoniter iter) {");
185+
append(lines, "if (iter.readNull()) { return null; }");
185186
append(lines, "{{clazz}} obj = {{newInst}};");
186187
append(lines, "iter.skip();");
187188
append(lines, "return obj;");
@@ -190,10 +191,11 @@ private static String genObjectUsingHash(Class clazz, String cacheKey) {
190191
}
191192
StringBuilder lines = new StringBuilder();
192193
append(lines, "public static Object decode_(com.jsoniter.Jsoniter iter) {");
194+
append(lines, "if (iter.readNull()) { return null; }");
193195
append(lines, "{{clazz}} obj = {{newInst}};");
194-
append(lines, "if (iter.readByte() != '{') { throw new RuntimeException();}");
195-
append(lines, "if (iter.nextToken() != '\"') { throw new RuntimeException();}");
196+
append(lines, "if (!com.jsoniter.CodegenAccess.readObjectStart(iter)) { return obj; }");
196197
append(lines, "switch (iter.readObjectFieldAsHash()) {");
198+
HashSet<Integer> knownHashes = new HashSet<Integer>();
197199
for (Field field : clazz.getFields()) {
198200
long hash = 0x811c9dc5;
199201
for (byte b : field.getName().getBytes()) {
@@ -205,15 +207,20 @@ private static String genObjectUsingHash(Class clazz, String cacheKey) {
205207
// hash collision, 0 can not be used as sentinel
206208
return genObject(clazz, cacheKey);
207209
}
210+
if (knownHashes.contains(intHash)) {
211+
// hash collision with other field can not be used as sentinel
212+
return genObject(clazz, cacheKey);
213+
}
214+
knownHashes.add(intHash);
208215
append(lines, "case " + intHash + ": ");
209216
genField(lines, field, cacheKey);
210217
append(lines, "break;");
211218
}
212219
append(lines, "default:");
213220
append(lines, "iter.skip();");
214221
append(lines, "}");
215-
append(lines, "while (iter.nextToken() == ',') {");
216-
append(lines, "iter.nextToken();");
222+
append(lines, "byte c = 0;");
223+
append(lines, "while ((c = com.jsoniter.CodegenAccess.nextToken(iter)) == ',') {");
217224
append(lines, "switch (iter.readObjectFieldAsHash()) {");
218225
for (Field field : clazz.getFields()) {
219226
long hash = 0x811c9dc5;
@@ -222,17 +229,14 @@ private static String genObjectUsingHash(Class clazz, String cacheKey) {
222229
hash *= 0x1000193;
223230
}
224231
int intHash = (int) hash;
225-
if (intHash == 0) {
226-
// hash collision, 0 can not be used as sentinel
227-
return genObject(clazz, cacheKey);
228-
}
229232
append(lines, "case " + intHash + ": ");
230233
genField(lines, field, cacheKey);
231234
append(lines, "continue;");
232235
}
233236
append(lines, "}");
234237
append(lines, "iter.skip();");
235238
append(lines, "}");
239+
append(lines, "if (c != '}') { com.jsoniter.CodegenAccess.reportIncompleteObject(iter); }");
236240
append(lines, "return obj;");
237241
append(lines, "}");
238242
return lines.toString().replace("{{clazz}}", clazz.getCanonicalName()).replace("{{newInst}}", newInstanceCode);
@@ -250,17 +254,9 @@ private static String genObject(Class clazz, String cacheKey) {
250254
if (newInstanceCode == null) {
251255
newInstanceCode = "new " + clazz.getCanonicalName() + "()";
252256
}
253-
if (trieTree.isEmpty()) {
254-
StringBuilder lines = new StringBuilder();
255-
append(lines, "public static Object decode_(com.jsoniter.Jsoniter iter) {");
256-
append(lines, "{{clazz}} obj = {{newInst}};");
257-
append(lines, "iter.skip();");
258-
append(lines, "return obj;");
259-
append(lines, "}");
260-
return lines.toString().replace("{{clazz}}", clazz.getCanonicalName()).replace("{{newInst}}", newInstanceCode);
261-
}
262257
StringBuilder lines = new StringBuilder();
263258
append(lines, "public static Object decode_(com.jsoniter.Jsoniter iter) {");
259+
append(lines, "if (iter.readNull()) { return null; }");
264260
append(lines, "{{clazz}} obj = {{newInst}};");
265261
append(lines, "for (com.jsoniter.Slice field = iter.readObjectAsSlice(); field != null; field = iter.readObjectAsSlice()) {");
266262
append(lines, "switch (field.len) {");
@@ -458,15 +454,15 @@ private static String genArray(Class clazz) {
458454
append(lines, "return new {{comp}}[0];");
459455
append(lines, "}");
460456
append(lines, "{{comp}} a1 = {{op}};");
461-
append(lines, "if (!com.jsoniter.CodegenAccess.readArrayMiddle(iter)) {");
457+
append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {");
462458
append(lines, "return new {{comp}}[]{ a1 };");
463459
append(lines, "}");
464460
append(lines, "{{comp}} a2 = {{op}};");
465-
append(lines, "if (!com.jsoniter.CodegenAccess.readArrayMiddle(iter)) {");
461+
append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {");
466462
append(lines, "return new {{comp}}[]{ a1, a2 };");
467463
append(lines, "}");
468464
append(lines, "{{comp}} a3 = {{op}};");
469-
append(lines, "if (!com.jsoniter.CodegenAccess.readArrayMiddle(iter)) {");
465+
append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {");
470466
append(lines, "return new {{comp}}[]{ a1, a2, a3 };");
471467
append(lines, "}");
472468
append(lines, "{{comp}} a4 = ({{comp}}) {{op}};");
@@ -476,7 +472,7 @@ private static String genArray(Class clazz) {
476472
append(lines, "arr[2] = a3;");
477473
append(lines, "arr[3] = a4;");
478474
append(lines, "int i = 4;");
479-
append(lines, "while (com.jsoniter.CodegenAccess.readArrayMiddle(iter)) {");
475+
append(lines, "while (com.jsoniter.CodegenAccess.nextToken(iter) == ',') {");
480476
append(lines, "if (i == arr.length) {");
481477
append(lines, "{{comp}}[] newArr = new {{comp}}[arr.length * 2];");
482478
append(lines, "System.arraycopy(arr, 0, newArr, 0, arr.length);");
@@ -500,20 +496,20 @@ private static String genCollectionWithCapacity(Class clazz, Type compType) {
500496
append(lines, "return new {{clazz}}(0);");
501497
append(lines, "}");
502498
append(lines, "Object a1 = {{op}};");
503-
append(lines, "if (!com.jsoniter.CodegenAccess.readArrayMiddle(iter)) {");
499+
append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {");
504500
append(lines, "{{clazz}} obj = new {{clazz}}(1);");
505501
append(lines, "obj.add(a1);");
506502
append(lines, "return obj;");
507503
append(lines, "}");
508504
append(lines, "Object a2 = {{op}};");
509-
append(lines, "if (!com.jsoniter.CodegenAccess.readArrayMiddle(iter)) {");
505+
append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {");
510506
append(lines, "{{clazz}} obj = new {{clazz}}(2);");
511507
append(lines, "obj.add(a1);");
512508
append(lines, "obj.add(a2);");
513509
append(lines, "return obj;");
514510
append(lines, "}");
515511
append(lines, "Object a3 = {{op}};");
516-
append(lines, "if (!com.jsoniter.CodegenAccess.readArrayMiddle(iter)) {");
512+
append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {");
517513
append(lines, "{{clazz}} obj = new {{clazz}}(3);");
518514
append(lines, "obj.add(a1);");
519515
append(lines, "obj.add(a2);");
@@ -527,7 +523,7 @@ private static String genCollectionWithCapacity(Class clazz, Type compType) {
527523
append(lines, "obj.add(a3);");
528524
append(lines, "obj.add(a4);");
529525
append(lines, "int i = 4;");
530-
append(lines, "while (com.jsoniter.CodegenAccess.readArrayMiddle(iter)) {");
526+
append(lines, "while (com.jsoniter.CodegenAccess.nextToken(iter) == ',') {");
531527
append(lines, "obj.add({{op}});");
532528
append(lines, "}");
533529
append(lines, "return obj;");
@@ -544,20 +540,20 @@ private static String genCollection(Class clazz, Type compType) {
544540
append(lines, "return new {{clazz}}();");
545541
append(lines, "}");
546542
append(lines, "Object a1 = {{op}};");
547-
append(lines, "if (!com.jsoniter.CodegenAccess.readArrayMiddle(iter)) {");
543+
append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {");
548544
append(lines, "{{clazz}} obj = new {{clazz}}();");
549545
append(lines, "obj.add(a1);");
550546
append(lines, "return obj;");
551547
append(lines, "}");
552548
append(lines, "Object a2 = {{op}};");
553-
append(lines, "if (!com.jsoniter.CodegenAccess.readArrayMiddle(iter)) {");
549+
append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {");
554550
append(lines, "{{clazz}} obj = new {{clazz}}();");
555551
append(lines, "obj.add(a1);");
556552
append(lines, "obj.add(a2);");
557553
append(lines, "return obj;");
558554
append(lines, "}");
559555
append(lines, "Object a3 = {{op}};");
560-
append(lines, "if (!com.jsoniter.CodegenAccess.readArrayMiddle(iter)) {");
556+
append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {");
561557
append(lines, "{{clazz}} obj = new {{clazz}}();");
562558
append(lines, "obj.add(a1);");
563559
append(lines, "obj.add(a2);");
@@ -571,7 +567,7 @@ private static String genCollection(Class clazz, Type compType) {
571567
append(lines, "obj.add(a3);");
572568
append(lines, "obj.add(a4);");
573569
append(lines, "int i = 4;");
574-
append(lines, "while (com.jsoniter.CodegenAccess.readArrayMiddle(iter)) {");
570+
append(lines, "while (com.jsoniter.CodegenAccess.nextToken(iter) == ',') {");
575571
append(lines, "obj.add({{op}});");
576572
append(lines, "}");
577573
append(lines, "return obj;");

src/main/java/com/jsoniter/CodegenAccess.java

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
// only uesd by generated code to access decoder
66
public class CodegenAccess {
77

8+
public static byte nextToken(Jsoniter iter) throws IOException {
9+
return iter.nextToken();
10+
}
11+
812
public static final boolean readBoolean(String cacheKey, Jsoniter iter) throws IOException {
913
return Codegen.getBooleanDecoder(cacheKey).decodeBoolean(iter);
1014
}
@@ -35,9 +39,6 @@ public static final <T> T read(String cacheKey, Jsoniter iter) throws IOExceptio
3539

3640
public static boolean readArrayStart(Jsoniter iter) throws IOException {
3741
byte c = iter.readByte();
38-
if (c == 'n') {
39-
return false;
40-
}
4142
if (c != '[') {
4243
throw iter.reportError("readArrayStart", "expect [ or n");
4344
}
@@ -49,17 +50,20 @@ public static boolean readArrayStart(Jsoniter iter) throws IOException {
4950
return true;
5051
}
5152

52-
public static boolean readArrayMiddle(Jsoniter iter) throws IOException {
53-
byte c = iter.nextToken();
54-
if (c == ',') {
55-
iter.skipWhitespaces();
56-
return true;
57-
} else {
58-
if (c != ']') {
59-
throw iter.reportError("readArrayMiddle", "expect ]");
60-
}
61-
iter.skipWhitespaces();
53+
public static boolean readObjectStart(Jsoniter iter) throws IOException {
54+
byte c = iter.readByte();
55+
if (c != '{') {
56+
throw iter.reportError("readObjectStart", "expect { or n");
57+
}
58+
c = iter.nextToken();
59+
if (c == '}') {
6260
return false;
6361
}
62+
iter.unreadByte();
63+
return true;
64+
}
65+
66+
public static void reportIncompleteObject(Jsoniter iter) {
67+
throw iter.reportError("genObject", "expect }");
6468
}
6569
}

src/main/java/com/jsoniter/Jsoniter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,9 @@ public final String readObject() throws IOException {
630630
}
631631

632632
public final int readObjectFieldAsHash() throws IOException {
633+
if (nextToken() != '"') {
634+
throw reportError("readObjectFieldAsHash", "expect \"");
635+
}
633636
long hash = 0x811c9dc5;
634637
for (; ; ) {
635638
for (int i = head; i < tail; i++) {

src/main/java/com/jsoniter/Users.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ public static final class User {
6969

7070
public double longitude;
7171

72-
@JsonAttribute(nullable = true)
73-
public List<String> tags;
74-
75-
@JsonAttribute(nullable = true)
76-
public List<Friend> friends;
72+
// @JsonAttribute(nullable = true)
73+
// public List<String> tags;
74+
//
75+
// @JsonAttribute(nullable = true)
76+
// public List<Friend> friends;
7777

7878
public String greeting;
7979

@@ -104,8 +104,8 @@ public boolean equals(Object o) {
104104
if (address != null ? !address.equals(user.address) : user.address != null) return false;
105105
if (about != null ? !about.equals(user.about) : user.about != null) return false;
106106
if (registered != null ? !registered.equals(user.registered) : user.registered != null) return false;
107-
if (tags != null ? !tags.equals(user.tags) : user.tags != null) return false;
108-
if (friends != null ? !friends.equals(user.friends) : user.friends != null) return false;
107+
// if (tags != null ? !tags.equals(user.tags) : user.tags != null) return false;
108+
// if (friends != null ? !friends.equals(user.friends) : user.friends != null) return false;
109109
if (greeting != null ? !greeting.equals(user.greeting) : user.greeting != null) return false;
110110
return favoriteFruit != null ? favoriteFruit.equals(user.favoriteFruit) : user.favoriteFruit == null;
111111
}
@@ -134,17 +134,17 @@ public int hashCode() {
134134
result = 31 * result + (int) (temp ^ (temp >>> 32));
135135
temp = Double.doubleToLongBits(longitude);
136136
result = 31 * result + (int) (temp ^ (temp >>> 32));
137-
result = 31 * result + (tags != null ? tags.hashCode() : 0);
138-
result = 31 * result + (friends != null ? friends.hashCode() : 0);
137+
// result = 31 * result + (tags != null ? tags.hashCode() : 0);
138+
// result = 31 * result + (friends != null ? friends.hashCode() : 0);
139139
result = 31 * result + (greeting != null ? greeting.hashCode() : 0);
140140
result = 31 * result + (favoriteFruit != null ? favoriteFruit.hashCode() : 0);
141141
return result;
142142
}
143143

144-
@Override
145-
public String toString() {
146-
return "JsonDataObj{" + "_id=" + _id + ", index=" + index + ", guid=" + guid + ", isActive=" + isActive + ", balance=" + balance + ", picture=" + picture + ", age=" + age + ", eyeColor=" + eyeColor + ", name=" + name + ", gender=" + gender + ", company=" + company + ", email=" + email + ", phone=" + phone + ", address=" + address + ", about=" + about + ", registered=" + registered + ", latitude=" + latitude + ", longitude=" + longitude + ", tags=" + tags + ", friends=" + friends + ", greeting=" + greeting + ", favoriteFruit=" + favoriteFruit + '}';
147-
}
144+
// @Override
145+
// public String toString() {
146+
// return "JsonDataObj{" + "_id=" + _id + ", index=" + index + ", guid=" + guid + ", isActive=" + isActive + ", balance=" + balance + ", picture=" + picture + ", age=" + age + ", eyeColor=" + eyeColor + ", name=" + name + ", gender=" + gender + ", company=" + company + ", email=" + email + ", phone=" + phone + ", address=" + address + ", about=" + about + ", registered=" + registered + ", latitude=" + latitude + ", longitude=" + longitude + ", tags=" + tags + ", friends=" + friends + ", greeting=" + greeting + ", favoriteFruit=" + favoriteFruit + '}';
147+
// }
148148
}
149149

150150
@CompiledJson

0 commit comments

Comments
 (0)