这个编译器是Symantec Cafe 4.0带的,编译速度非常快,是javac.exe的100到1000倍,是jikes.exe的4-6倍。不过由于Symantec Cafe不再发展,所以这个编译器也不再更新,有一下问题需要改进。
sj.exe不支持JDK1.4以上,它会检查rt.jar中的类的版本,如下:
00415EF4 . 83FB 2D CMP EBX, 2D
00415EF7 74 29 JE SHORT sj.00415F22
改成如下就可以跳过代码的检查:
00415EF4 . 83FB 2D CMP EBX, 2D
00415EF7 . EB 29 JMP SHORT sj11.00415F22
如果使用wjcompiler.dll,则修改如下地方
21EA4F53:7F 64->90 90
sj.exe在编译文件的时候,如果Classpath中包含的jar文件太大,如
Weblogic 7.0的jar文件,就会出现内存访问异常,经检查在下面的
代码中出现异常:
004A00C8 /$ 89CA MOV EDX, ECX
004A00CA |. 8B4424 04 MOV EAX, [ESP+4]
004A00CE |. 53 PUSH EBX
004A00CF |. 57 PUSH EDI
004A00D0 |. 56 PUSH ESI
004A00D1 |. 83C0 03 ADD EAX, 3
004A00D4 |. 83E0 FC AND EAX, FFFFFFFC
004A00D7 |. 75 05 JNZ SHORT sj11.004A00DE
004A00D9 |. B8 04000000 MOV EAX, 4
004A00DE |> 89C6 MOV ESI, EAX
004A00E0 |. F7D8 NEG EAX
004A00E2 |. 01E0 ADD EAX, ESP
004A00E4 |. 73 28 JNB SHORT sj11.004A010E
004A00E6 |. 89C1 MOV ECX, EAX
004A00E8 |. 89F3 MOV EBX, ESI
004A00EA |> 851C19 /TEST [ECX+EBX], EBX
004A00ED |. 81EB 00100000 |SUB EBX, 1000
004A00F3 |.^ 73 F5 \JNB SHORT sj11.004A00EA
004A00F5 |. 8519 TEST [ECX], EBX
004A00F7 |. 89E9 MOV ECX, EBP
004A00F9 |. 29E1 SUB ECX, ESP
004A00FB |. 2B0A SUB ECX, [EDX]
004A00FD |. 0132 ADD [EDX], ESI ;异常
004A00FF |. 89C4 MOV ESP, EAX
004A0101 |. 01C8 ADD EAX, ECX
004A0103 |. 89E7 MOV EDI, ESP
004A0105 |. 01E6 ADD ESI, ESP
004A0107 |. C1E9 02 SHR ECX, 2
004A010A |. F3:A5 REP MOVSD
004A010C |. EB 02 JMP SHORT sj11.004A0110
004A010E |> 31C0 XOR EAX, EAX
004A0110 |> 5E POP ESI kernel32.77E7EB69
004A0111 |. 5F POP EDI kernel32.77E7EB69
004A0112 |. 5B POP EBX kernel32.77E7EB69
004A0113 \. C3 RETN
经过分析,这段代码是类似在栈中分配内存,由于循环过多,最后导致在还没有
分配内存的栈中访问而导致异常,用以下方法可以解决这个问题,即通过在堆中
分配内存,这样会浪费一些内存,但是既然是编译器,运行完成后就退出,这些
内存马上能够被回收。
004A00C8 /$ FF7424 04 PUSH DWORD PTR [ESP+4] /MemSize = 540000 (5505024.)
004A00CC |. 6A 00 PUSH 0 |Flags = GMEM_FIXED
004A00CE |. E8 5FF80000 CALL \GlobalAlloc
004A00D3 \. C3 RETN
在进行对UTF-8编码方式的源文件进行编译的时候,不能成功。UTF-8的编码方式
通过sj -j .65001的方式来编译,其中65001是Windows中的CP_UTF8。通过检查
代码发现sj使用GetCPInof来获取编码的最大字节数,而在Windows中,CP_UTF8
编码返回的最大字节数是4,而实际应当是3,因此需要把这里修改掉,原代码如下:
004A351D |. 51 PUSH ECX /pCPInfo = 0012F434
004A351E |. 52 PUSH EDX |CodePage = FDE9
004A351F |. FF15 88284000 CALL [<&KERNEL32.GetCPInfo>] \GetCPInfo
004A3525 |. 85C0 TEST EAX, EAX
004A3527 |. 0F84 79010000 JE sj111.004A36A6
004A352D |. 66:8B4C24 1C MOV CX, [ESP+1C]
004A3532 |. 68 02020000 PUSH 202
004A3537 |. 81E1 FFFF0000 AND ECX, 0FFFF
004A353D |. 890D 2C144D00 MOV [4D142C], ECX ; 保存最大字节数
修改后代码为:
004A351D |. 51 PUSH ECX /pCPInfo = 0012F434
004A351E |. 52 PUSH EDX |CodePage = FDE9
004A351F |. FF15 88284000 CALL [<&KERNEL32.GetCPInfo>] \GetCPInfo
004A3525 |. 85C0 TEST EAX, EAX
004A3527 |. 0F84 79010000 JE sj111.004A36A6
004A352D |. 66:8B4C24 1C MOV CX, [ESP+1C]
004A3532 |. 68 02020000 PUSH 202
004A3537 |. 81E1 FFFF0000 AND ECX, 0FFFF
004A353D E9 6EC50000 JMP sj111.004AFAB0 ; 修改后的代码
004A3542 90 NOP
以下代码判断编码方式是否为65001(0xFDE9),如果是就将最大字节数改成3。
004AFAB0 60 PUSHAD
004AFAB1 A1 30144D00 MOV EAX, [4D1430] ; CodePage
004AFAB6 3D E9FD0000 CMP EAX, 0FDE9
004AFABB 75 0C JNZ SHORT sj111.004AFAC9
004AFABD C705 2C144D00 0>MOV DWORD PTR [4D142C], 3 ; MaxBytes
004AFAC7 EB 06 JMP SHORT sj111.004AFACF
004AFAC9 890D 2C144D00 MOV [4D142C], ECX
004AFACF 61 POPAD
004AFAD0 ^ E9 6D3AFFFF JMP sj111.004A3542
然后在进行编码转换的时候需要去掉一个判断,原代码如下:
004A4810 |. 19ED SBB EBP, EBP
004A4812 |. 31C9 XOR ECX, ECX
004A4814 |. 8A0E MOV CL, [ESI]
004A4816 |. 45 INC EBP
004A4817 |. F6444A 01 80 TEST BYTE PTR [EDX+ECX*2+1], 80 ; 判断是否单字节
004A481C |. 74 3B JE SHORT sj111.004A4859
004A481E |. 8B0D 2C144D00 MOV ECX, [4D142C]
004A4824 |. 83F9 02 CMP ECX, 2
004A4827 |. 7C 59 JL SHORT sj111.004A4882
004A4829 |. 8B15 2C144D00 MOV EDX, [4D142C]
004A482F |. 3B5424 1C CMP EDX, [ESP+1C] sj111.004D145C
004A4833 |. 77 4D JA SHORT sj111.004A4882
004A4835 |. 55 PUSH EBP /WideBufSize = 394660 (3753568.)
004A4836 |. 53 PUSH EBX |WideCharBuf = 00000002
004A4837 |. 51 PUSH ECX |StringSize = 12F434 (1242164.)
004A4838 |. 8B0D D8474D00 MOV ECX, [4D47D8] |
004A483E |. 8B15 30144D00 MOV EDX, [4D1430] |
004A4844 |. 56 PUSH ESI |StringToMap = NULL
004A4845 |. 51 PUSH ECX |Options = 0
004A4846 |. 52 PUSH EDX |CodePage = FDE9
004A4847 |. FF15 74284000 CALL [<&KERNEL32.MultiByteToWideChar>>; \MultiByteToWideChar
004A484D |. 85C0 TEST EAX, EAX
可以将004A481C的代码NOP掉,所有的编码都以多字节来处理。
还有在进行转换的时候需要将Options设置为0,这是个全局变量,在4D47D8。
在将UNICODE转换成UTF-8的时候,有一段代码需要修改,原代码如下:
0049FFA1 |. 51 PUSH ECX /pDefaultCharUsed = 00145B87
0049FFA2 |. 56 PUSH ESI |pDefaultChar = NULL
0049FFA3 |. 52 PUSH EDX |MultiByteCount = 7FFA0002 (2147090434.)
0049FFA4 |. 55 PUSH EBP |MultiByteStr = 00145B80
0049FFA5 |. 6A FF PUSH -1 |WideCharCount = FFFFFFFF (-1.)
0049FFA7 |. 8B3D 30144D00 MOV EDI, [4D1430] |
0049FFAD |. 8B5C24 34 MOV EBX, [ESP+34] |sj11.004BEEB5
0049FFB1 |. 53 PUSH EBX |WideCharStr = "tt.java"
0049FFB2 |. 68 20020000 PUSH 220 |Options = WC_COMPOSITECHECK|WC_SEPCHARS
0049FFB7 |. 57 PUSH EDI |CodePage = CP_ACP
0049FFB8 |. FF15 CC284000 CALL [<&KERNEL32.WideCharToMulti>; \WideCharToMultiByte
需要将0049FFA7的CodePage修改成CP_ACP,修改后代码如下:
0049FFA1 |. 51 PUSH ECX /pDefaultCharUsed = 00145B87
0049FFA2 |. 56 PUSH ESI |pDefaultChar = NULL
0049FFA3 |. 52 PUSH EDX |MultiByteCount = 7FFA0002 (2147090434.)
0049FFA4 |. 55 PUSH EBP |MultiByteStr = 00145B80
0049FFA5 |. 6A FF PUSH -1 |WideCharCount = FFFFFFFF (-1.)
0049FFA7 E9 34FB0000 JMP sj11.004AFAE0
0049FFAC 90 NOP
0049FFAD |. 8B5C24 34 MOV EBX, [ESP+34] |sj11.004BEEB5
0049FFB1 |. 53 PUSH EBX |WideCharStr = "tt.java"
0049FFB2 |. 68 20020000 PUSH 220 |Options = WC_COMPOSITECHECK|WC_SEPCHARS
0049FFB7 |. 57 PUSH EDI |CodePage = CP_ACP
0049FFB8 |. FF15 CC284000 CALL [<&KERNEL32.WideCharToMulti>; \WideCharToMultiByte
以下代码判断编码方式是否为65001(0xFDE9),如果是就将CodePage设置为CP_ACP
004AFAE0 60 PUSHAD
004AFAE1 A1 30144D00 MOV EAX, [4D1430]
004AFAE6 3D E9FD0000 CMP EAX, 0FDE9
004AFAEB 75 05 JNZ SHORT sj11.004AFAF2
004AFAED 61 POPAD
004AFAEE 33FF XOR EDI, EDI
004AFAF0 EB 07 JMP SHORT sj11.004AFAF9
004AFAF2 61 POPAD
004AFAF3 8B3D 30144D00 MOV EDI, [4D1430]
004AFAF9 ^ E9 AF04FFFF JMP sj11.0049FFAD