December 6th, 2010

This one is largely a response to the impressive performance of the JSON decoder in blooddy_crypto. It was clearly better performing than my own, but I’ve made a large round of optimizations to keep up with the library. I was able to improve the performance over as3corelib a few more notches, reaching 8x faster on large objects. Admittedly, blooddy_crypto’s decoder performs better in some of my own tests (good work BlooDHounD!). My encoder is still much faster though.

Unlike blooddy_crypto, the source is provided, it’s written in Flash 9-compatible AS3, and it is pretty much bug free (blooddy_crypto doesn’t pass the barrage of tests in TestJson.as).

There’s also a new encoder, JsonEncoderAsync. It’s probably one of the more surreal pieces of code I’ve written, but it can work asynchronously and it’s pretty fast.

EDIT: Couple interesting notes. I tried using apparat again to gain access to the alchemy memory bytecodes. They still didn’t perform well. It’s surprising, but it seems like array access on a ByteArray in a local variable is still faster than those bytecodes (EDIT 2: turns out they are not, but the performance boost is pretty modest). Other ByteArray operations, like readInt, performed even worse than my already low expectations, so I removed them entirely.

Also, stack underflow errors (which came up once during testing) seem to be related to errors in catch statements outside of debug mode.

Joa: I wanted to be sure, so I used apparat’s dump to check and I clearly found a GetByte opcode in the function using readUnsignedByte, and no apparent references to readUnsignedByte. I’ll try to send you something later.

1. Nan, -Infinity, Infinity must be encoded as null
2. your encoder doesn’t check for objects cross links which can lead to infinite loop.
3. there’s no support for class instances
4. if an object is Dictionary no exception is thrown
5. in strings “/” must be encoded as “/”
6. no Vectors support
7. functions are not ignored
8. symbols with char code less than 32 must be encoded in u0000 format

1. Nan, -Infinity, Infinity must be encoded as null
Obviously not valid JSON, but also not valid input. I left them in because it seemed better than to throw an error. Still, based on your comment I added an extra flag to throw an error on invalid numbers. Replacing them with null could be confusing or cause problems.

2. your encoder doesn’t check for objects cross links which can lead to infinite loop.
I suppose that’s a valid concern, but the way I see it valid input should be given. The only reason I’d detect it is to give a more verbose error message.

3. there’s no support for class instances
No there isn’t, this was intentional. See my comments below.

4. if an object is Dictionary no exception is thrown
I allow data that can be reached by a for..in loop (including dynamic classes and Dictionaries) to be accepted as input. It’s a little out of the scope of the library, but there are some reasons (URLVariables comes to mind) to allow it.

5. in strings “/” must be encoded as “/”
They only need to be decoded, it’s acceptable to not encode them this way. I favored the situation that would allow a smaller output size.

6. no Vectors support
Supporting them would break compatibility with Flash 9, which I’m not willing to do at this time.

7. functions are not ignored
Another case of invalid input. Ignoring them would be ignoring a problem with input.

8. symbols with char code less than 32 must be encoded in u0000 format
Yes, you’re right. Thank you. Also, watch out for 0x7F (DEL), even the as3corelib encoder doesn’t support that one.

A lot of these are intentional design decisions. The encoders and decoders are not here to replace AMF, but to support JSON effectively in situations where AMF isn’t viable, and act as a counterpart to Javascript JSON parsing. This leads to the data being less tightly integrated with code, but that’s what using JSON means.