Review/comment needed for the new public java.util.Base64 class

Ulf Zibis Ulf.Zibis at CoSoCo.de
Sat Nov 3 20:33:42 UTC 2012


Am 30.10.2012 23:40, schrieb Xueming Shen:
>> I'm "confused" about the order of xxcode() and Xxcoder.
>> In other places e.g. charsets, we have de... before en..., which is also true alphabetical
>>
> should not be an issue. javadoc output should be in alphabetic order. If it is really
> concerns you, I can do a copy/paste:-)

Yes, it doesn't matter much, but would be a nice conform style, so for me "personally" I would like 
the copy/paste:-)

>> - What (should) happen(s), if lineSeparator.length == 0 ?
> do nothing. expected?

I would say, empty line separator should not be allowed, so you might check:
      Objects.requireNonEmpty(lineSeparator);

>>  603         static {
>>  604             Arrays.fill(fromBase64, -1);
>>  605             for (int i = 0; i < Encoder.toBase64.length; i++)
>>  606                 fromBase64[Encoder.toBase64[i]] = i;
>>  607             fromBase64['='] = -2;
>>  608         }
>> This causes the inner Encoder class to be loaded, even if not needed. So maybe move the toBase64 
>> table to the outer class.
>> Have you compared performance with fromBase64 as byte[] (including local 'b' in decode() as byte)?
>
> understood. 

It seems you have mixed 2 tweaks to one. ;-) See additional paragraph at the end ...

> but it appears the hotspot likes it the constant/fixed length lookup
> table is inside encoder. 
Yes, but see my suggestion 12 lines below.

> Same as you suggestion in your previous email to use
> String in source and expand it during runtime. It saves about 500 bytes but slows
> the server vm.

Are you really sure? As it only runs once at class init, JIT should not compile this code.
Executing the bytecode to init the final int[], value for value, by interpreter should not be faster 
as expanding a String source in a loop.

> Those repeating lines of "isURL? ...." is also supposed to be a
> performance tweak to eliminate the array boundary check in loop.

Yep, so I was thinking about:
  653         private final int[] base64;
  654         private final boolean isMIME;
  655
  656         private Decoder(boolean isURL, boolean isMIME) {
  657             base64 = isURL ? fromBase64URL : fromBase64;
  658             this.isMIME = isMIME;
  659         }
.....
  911         private int decodeBuffer(ByteBuffer src, ByteBuffer dst) {
  912             int[] base64 = this.base64; // local copy for performance reasons (but maybe 
superfluous if HotSpot is intelligent enough)
or:
  911         private int decodeBuffer(ByteBuffer src, ByteBuffer dst, int[] base64) {
.....

>> Why you mix the algorithms to check the padding? :
>>  824                         if (b == -2) {   // padding byte
>>  890                     if (b == '=') {
>>
> It is supposed reduce one "if" check for normal base64 character inside the
> loop. I'm not that sure it really helps though.

  925                     if (b == '=') {
--> causes one additional "if" in the _main_ path of the loop, so should be slower for regular input

  859                         if (b == -2) {   // padding byte
--> causes one additional "if" in the _side_ path of the loop, so should only affect irregular input
Maybe the following code is little faster as no loading of the constant '-2' is required:
  858                     if ((b = base64[b]) < 0) {
  859                         if (++b < 0) {   // padding byte '='


Once again (the following was meant for the decode algorithm, not initialisation):
Have you compared performance with fromBase64 as byte[] (including local 'b' in decode() as byte)?
Retrieving the bytes by b = base64[x] then could be done without address-shift and smaller/faster 
LoadB operations could be used by JIT. In an int[] table, the index offset must be shifted by 2 
before. Maybe this doesn't directly affect the performance on x86/IA64 CPU, but wastes space in CPU 
cache for other tasks as a side effect. On ARM architectures I imagine, directly addressing a 
byte-stepped table could be faster than addressing a 4-byte-stepped table. At least the footprint of 
the table would be smaller.

Little nit:
You could delete line 641 for conformity with 629.

-Ulf




More information about the core-libs-dev mailing list