Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
5 : : * This Source Code Form is subject to the terms of the Mozilla Public
6 : : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
11 : : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : : * contributor license agreements. See the NOTICE file distributed
13 : : * with this work for additional information regarding copyright
14 : : * ownership. The ASF licenses this file to you under the Apache
15 : : * License, Version 2.0 (the "License"); you may not use this file
16 : : * except in compliance with the License. You may obtain a copy of
17 : : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : : */
19 : :
20 : :
21 : : #include "classfile.hxx"
22 : :
23 : : #include "codemaker/global.hxx"
24 : : #include "codemaker/options.hxx"
25 : : #include "codemaker/unotype.hxx"
26 : :
27 : : #include "boost/static_assert.hpp"
28 : : #include "osl/diagnose.h"
29 : : #include "rtl/string.h"
30 : : #include "rtl/string.hxx"
31 : : #include "sal/types.h"
32 : :
33 : : #include <map>
34 : : #include <utility>
35 : : #include <vector>
36 : :
37 : : using codemaker::javamaker::ClassFile;
38 : :
39 : : namespace {
40 : :
41 : 3272040 : void appendU1(std::vector< unsigned char > & stream, sal_uInt8 data) {
42 [ + - ]: 3272040 : stream.push_back(static_cast< unsigned char >(data));
43 : 3272040 : }
44 : :
45 : 599302 : void appendU2(std::vector< unsigned char > & stream, sal_uInt16 data) {
46 [ + - ]: 599302 : stream.push_back(static_cast< unsigned char >(data >> 8));
47 [ + - ]: 599302 : stream.push_back(static_cast< unsigned char >(data & 0xFF));
48 : 599302 : }
49 : :
50 : 47508 : void appendU4(std::vector< unsigned char > & stream, sal_uInt32 data) {
51 [ + - ]: 47508 : stream.push_back(static_cast< unsigned char >(data >> 24));
52 [ + - ]: 47508 : stream.push_back(static_cast< unsigned char >((data >> 16) & 0xFF));
53 [ + - ]: 47508 : stream.push_back(static_cast< unsigned char >((data >> 8) & 0xFF));
54 [ + - ]: 47508 : stream.push_back(static_cast< unsigned char >(data & 0xFF));
55 : 47508 : }
56 : :
57 : 58 : void appendU8(std::vector< unsigned char > & stream, sal_uInt64 data) {
58 [ + - ]: 58 : stream.push_back(static_cast< unsigned char >(data >> 56));
59 [ + - ]: 58 : stream.push_back(static_cast< unsigned char >((data >> 48) & 0xFF));
60 [ + - ]: 58 : stream.push_back(static_cast< unsigned char >((data >> 40) & 0xFF));
61 [ + - ]: 58 : stream.push_back(static_cast< unsigned char >((data >> 32) & 0xFF));
62 [ + - ]: 58 : stream.push_back(static_cast< unsigned char >((data >> 24) & 0xFF));
63 [ + - ]: 58 : stream.push_back(static_cast< unsigned char >((data >> 16) & 0xFF));
64 [ + - ]: 58 : stream.push_back(static_cast< unsigned char >((data >> 8) & 0xFF));
65 [ + - ]: 58 : stream.push_back(static_cast< unsigned char >(data & 0xFF));
66 : 58 : }
67 : :
68 : 23672 : void appendStream(
69 : : std::vector< unsigned char > & stream,
70 : : std::vector< unsigned char > const & data)
71 : : {
72 : 23672 : stream.insert(stream.end(), data.begin(), data.end());
73 : 23672 : }
74 : :
75 : 88523 : void write(FileStream & file, void const * buffer, sal_uInt64 size) {
76 [ - + ]: 88523 : if (!file.write(buffer, size)) {
77 : : throw CannotDumpException(
78 : 0 : rtl::OString(RTL_CONSTASCII_STRINGPARAM("Error writing file")));
79 : : }
80 : 88523 : }
81 : :
82 : 62000 : void writeU2(FileStream & file, sal_uInt16 data) {
83 : : unsigned char buf[] = {
84 : : static_cast< unsigned char >(data >> 8),
85 : 62000 : static_cast< unsigned char >(data & 0xFF) };
86 [ + - ]: 62000 : write(file, buf, sizeof buf);
87 : 62000 : }
88 : :
89 : 6200 : void writeU4(FileStream & file, sal_uInt32 data) {
90 : : unsigned char buf[] = {
91 : : static_cast< unsigned char >(data >> 24),
92 : : static_cast< unsigned char >((data >> 16) & 0xFF),
93 : : static_cast< unsigned char >((data >> 8) & 0xFF),
94 : 6200 : static_cast< unsigned char >(data & 0xFF) };
95 [ + - ]: 6200 : write(file, buf, sizeof buf);
96 : 6200 : }
97 : :
98 : 31000 : void writeStream(FileStream & file, std::vector< unsigned char > const & stream)
99 : : {
100 : 31000 : std::vector< unsigned char >::size_type n = stream.size();
101 : : BOOST_STATIC_ASSERT(
102 : : sizeof (std::vector< unsigned char >::size_type)
103 : : <= sizeof (sal_uInt64));
104 : : // both unsigned integral, so sizeof is a practically sufficient
105 : : // approximation of std::numeric_limits<T1>::max() <=
106 : : // std::numeric_limits<T2>::max()
107 [ + + ]: 31000 : if (n != 0) {
108 : 20323 : write(file, &stream[0], static_cast< sal_uInt64 >(n));
109 : : }
110 : 31000 : }
111 : :
112 : : }
113 : :
114 : 13451 : ClassFile::Code::~Code() {}
115 : :
116 : 16957 : void ClassFile::Code::instrAastore() {
117 : : // aastore:
118 : 16957 : appendU1(m_code, 0x53);
119 : 16957 : }
120 : :
121 : 422 : void ClassFile::Code::instrAconstNull() {
122 : : // aconst_null:
123 : 422 : appendU1(m_code, 0x01);
124 : 422 : }
125 : :
126 : 4684 : void ClassFile::Code::instrAnewarray(rtl::OString const & type) {
127 : : // anewarray <indexbyte1> <indexbyte2>:
128 : 4684 : appendU1(m_code, 0xBD);
129 : 4684 : appendU2(m_code, m_classFile.addClassInfo(type));
130 : 4684 : }
131 : :
132 : 4621 : void ClassFile::Code::instrAreturn() {
133 : : // areturn:
134 : 4621 : appendU1(m_code, 0xB0);
135 : 4621 : }
136 : :
137 : 976 : void ClassFile::Code::instrAthrow() {
138 : : // athrow:
139 : 976 : appendU1(m_code, 0xBF);
140 : 976 : }
141 : :
142 : 400 : void ClassFile::Code::instrCheckcast(rtl::OString const & type) {
143 : : // checkcast <indexbyte1> <indexbyte2>:
144 : 400 : appendU1(m_code, 0xC0);
145 : 400 : appendU2(m_code, m_classFile.addClassInfo(type));
146 : 400 : }
147 : :
148 : 39011 : void ClassFile::Code::instrDup() {
149 : : // dup:
150 : 39011 : appendU1(m_code, 0x59);
151 : 39011 : }
152 : :
153 : 4107 : void ClassFile::Code::instrGetstatic(
154 : : rtl::OString const & type, rtl::OString const & name,
155 : : rtl::OString const & descriptor)
156 : : {
157 : : // getstatic <indexbyte1> <indexbyte2>:
158 : 4107 : appendU1(m_code, 0xB2);
159 : 4107 : appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor));
160 : 4107 : }
161 : :
162 : 20 : ClassFile::Code::Branch ClassFile::Code::instrIfAcmpne() {
163 : : // if_acmpne <branchbyte1> <branchbyte2>:
164 : 20 : Branch branch = m_code.size();
165 : 20 : appendU1(m_code, 0xA6);
166 : 20 : appendU2(m_code, 0);
167 : 20 : return branch;
168 : : }
169 : :
170 : 20 : ClassFile::Code::Branch ClassFile::Code::instrIfeq() {
171 : : // ifeq <branchbyte1> <branchbyte2>:
172 : 20 : Branch branch = m_code.size();
173 : 20 : appendU1(m_code, 0x99);
174 : 20 : appendU2(m_code, 0);
175 : 20 : return branch;
176 : : }
177 : :
178 : 622 : ClassFile::Code::Branch ClassFile::Code::instrIfnull() {
179 : : // ifnull <branchbyte1> <branchbyte2>:
180 : 622 : Branch branch = m_code.size();
181 : 622 : appendU1(m_code, 0xC6);
182 : 622 : appendU2(m_code, 0);
183 : 622 : return branch;
184 : : }
185 : :
186 : 20 : void ClassFile::Code::instrInstanceof(rtl::OString const & type) {
187 : : // instanceof <indexbyte1> <indexbyte2>:
188 : 20 : appendU1(m_code, 0xC1);
189 : 20 : appendU2(m_code, m_classFile.addClassInfo(type));
190 : 20 : }
191 : :
192 : 681 : void ClassFile::Code::instrInvokeinterface(
193 : : rtl::OString const & type, rtl::OString const & name,
194 : : rtl::OString const & descriptor, sal_uInt8 args)
195 : : {
196 : : // invokeinterface <indexbyte1> <indexbyte2> <nargs> 0:
197 : 681 : appendU1(m_code, 0xB9);
198 : : appendU2(
199 : 681 : m_code, m_classFile.addInterfaceMethodrefInfo(type, name, descriptor));
200 : 681 : appendU1(m_code, args);
201 : 681 : appendU1(m_code, 0);
202 : 681 : }
203 : :
204 : 25084 : void ClassFile::Code::instrInvokespecial(
205 : : rtl::OString const & type, rtl::OString const & name,
206 : : rtl::OString const & descriptor)
207 : : {
208 : : // invokespecial <indexbyte1> <indexbyte2>:
209 : 25084 : appendU1(m_code, 0xB7);
210 : 25084 : appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor));
211 : 25084 : }
212 : :
213 : 1041 : void ClassFile::Code::instrInvokestatic(
214 : : rtl::OString const & type, rtl::OString const & name,
215 : : rtl::OString const & descriptor)
216 : : {
217 : : // invokestatic <indexbyte1> <indexbyte2>:
218 : 1041 : appendU1(m_code, 0xB8);
219 : 1041 : appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor));
220 : 1041 : }
221 : :
222 : 768 : void ClassFile::Code::instrInvokevirtual(
223 : : rtl::OString const & type, rtl::OString const & name,
224 : : rtl::OString const & descriptor)
225 : : {
226 : : // invokevirtual <indexbyte1> <indexbyte2>:
227 : 768 : appendU1(m_code, 0xB6);
228 : 768 : appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor));
229 : 768 : }
230 : :
231 : 2 : void ClassFile::Code::instrLookupswitch(
232 : : Code const * defaultBlock,
233 : : std::list< std::pair< sal_Int32, Code * > > const & blocks)
234 : : {
235 : : // lookupswitch <0--3 byte pad> <defaultbyte1> <defaultbyte2> <defaultbyte3>
236 : : // <defaultbyte4> <npairs1> <npairs2> <npairs3> <npairs4>
237 : : // <match--offset pairs...>:
238 : 2 : std::list< std::pair< sal_Int32, Code * > >::size_type size = blocks.size();
239 [ - + ]: 2 : if (size > SAL_MAX_INT32) {
240 : : throw CannotDumpException(
241 : : rtl::OString(
242 : : RTL_CONSTASCII_STRINGPARAM(
243 : 0 : "Lookup-switch too large for Java class file format")));
244 : : }
245 : 2 : Position pos1 = m_code.size();
246 : 2 : appendU1(m_code, 0xAB);
247 : 2 : int pad = (pos1 + 1) % 4;
248 [ + + ]: 6 : {for (int i = 0; i < pad; ++i) {
249 : 4 : appendU1(m_code, 0);
250 : : }}
251 : 2 : Position pos2 = pos1 + 1 + pad + 8 + blocks.size() * 8; //FIXME: overflow
252 : 2 : appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1)); //FIXME: overflow
253 : 2 : pos2 += defaultBlock->m_code.size(); //FIXME: overflow
254 : 2 : appendU4(m_code, static_cast< sal_uInt32 >(size));
255 [ + + ]: 152 : {for (std::list< std::pair< sal_Int32, Code * > >::const_iterator i(
256 : 2 : blocks.begin());
257 : 76 : i != blocks.end(); ++i)
258 : : {
259 [ + - ]: 74 : appendU4(m_code, static_cast< sal_uInt32 >(i->first));
260 [ + - ]: 74 : appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1));
261 : : //FIXME: overflow
262 : 74 : pos2 += i->second->m_code.size(); //FIXME: overflow
263 : : }}
264 : 2 : appendStream(m_code, defaultBlock->m_code);
265 [ + + ]: 152 : {for (std::list< std::pair< sal_Int32, Code * > >::const_iterator i(
266 : 2 : blocks.begin());
267 : 76 : i != blocks.end(); ++i)
268 : : {
269 [ + - ]: 74 : appendStream(m_code, i->second->m_code);
270 : : }}
271 : 2 : }
272 : :
273 : 21392 : void ClassFile::Code::instrNew(rtl::OString const & type) {
274 : : // new <indexbyte1> <indexbyte2>:
275 : 21392 : appendU1(m_code, 0xBB);
276 : 21392 : appendU2(m_code, m_classFile.addClassInfo(type));
277 : 21392 : }
278 : :
279 : 67 : void ClassFile::Code::instrNewarray(codemaker::UnoType::Sort sort) {
280 : : OSL_ASSERT(
281 : : sort >= codemaker::UnoType::SORT_BOOLEAN
282 : : && sort <= codemaker::UnoType::SORT_CHAR);
283 : : // newarray <atype>:
284 : 67 : appendU1(m_code, 0xBC);
285 : : static sal_uInt8 const atypes[codemaker::UnoType::SORT_CHAR] = {
286 : : 0x04, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0B, 0x06, 0x07, 0x05 };
287 : 67 : appendU1(m_code, atypes[sort - 1]);
288 : 67 : }
289 : :
290 : 622 : void ClassFile::Code::instrPop() {
291 : : // pop:
292 : 622 : appendU1(m_code, 0x57);
293 : 622 : }
294 : :
295 : 5378 : void ClassFile::Code::instrPutfield(
296 : : rtl::OString const & type, rtl::OString const & name,
297 : : rtl::OString const & descriptor)
298 : : {
299 : : // putfield <indexbyte1> <indexbyte2>:
300 : 5378 : appendU1(m_code, 0xB5);
301 : 5378 : appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor));
302 : 5378 : }
303 : :
304 : 7141 : void ClassFile::Code::instrPutstatic(
305 : : rtl::OString const & type, rtl::OString const & name,
306 : : rtl::OString const & descriptor)
307 : : {
308 : : // putstatic <indexbyte1> <indexbyte2>:
309 : 7141 : appendU1(m_code, 0xB3);
310 : 7141 : appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor));
311 : 7141 : }
312 : :
313 : 8421 : void ClassFile::Code::instrReturn() {
314 : : // return:
315 : 8421 : appendU1(m_code, 0xB1);
316 : 8421 : }
317 : :
318 : 20 : void ClassFile::Code::instrSwap() {
319 : : // swap:
320 : 20 : appendU1(m_code, 0x5F);
321 : 20 : }
322 : :
323 : 407 : void ClassFile::Code::instrTableswitch(
324 : : Code const * defaultBlock, sal_Int32 low,
325 : : std::list< Code * > const & blocks)
326 : : {
327 : : // tableswitch <0--3 byte pad> <defaultbyte1> <defaultbyte2> <defaultbyte3>
328 : : // <defaultbyte4> <lowbyte1> <lowbyte2> <lowbyte3> <lowbyte4> <highbyte1>
329 : : // <highbyte2> <highbyte3> <highbyte4> <jump offsets...>:
330 : 407 : Position pos1 = m_code.size();
331 : 407 : appendU1(m_code, 0xAA);
332 : 407 : int pad = (pos1 + 1) % 4;
333 [ + + ]: 1221 : {for (int i = 0; i < pad; ++i) {
334 : 814 : appendU1(m_code, 0);
335 : : }}
336 : 407 : std::list< Code * >::size_type size = blocks.size();
337 : 407 : Position pos2 = pos1 + 1 + pad + 12 + size * 4; //FIXME: overflow
338 : 407 : sal_uInt32 defaultOffset = static_cast< sal_uInt32 >(pos2 - pos1);
339 : : //FIXME: overflow
340 : 407 : appendU4(m_code, defaultOffset);
341 : 407 : pos2 += defaultBlock->m_code.size(); //FIXME: overflow
342 : 407 : appendU4(m_code, static_cast< sal_uInt32 >(low));
343 : 407 : appendU4(m_code, static_cast< sal_uInt32 >(low + (size - 1)));
344 [ + + ]: 6324 : {for (std::list< Code * >::const_iterator i(blocks.begin());
345 : 3162 : i != blocks.end(); ++i)
346 : : {
347 [ + + ]: 2755 : if (*i == 0) {
348 [ + - ]: 8 : appendU4(m_code, defaultOffset);
349 : : } else {
350 [ + - ]: 2747 : appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1));
351 : : //FIXME: overflow
352 : 2747 : pos2 += (*i)->m_code.size(); //FIXME: overflow
353 : : }
354 : : }}
355 : 407 : appendStream(m_code, defaultBlock->m_code);
356 [ + + ]: 6324 : {for (std::list< Code * >::const_iterator i(blocks.begin());
357 : 3162 : i != blocks.end(); ++i)
358 : : {
359 [ + + ]: 2755 : if (*i != 0) {
360 [ + - ]: 2747 : appendStream(m_code, (*i)->m_code);
361 : : }
362 : : }}
363 : 407 : }
364 : :
365 : 57830 : void ClassFile::Code::loadIntegerConstant(sal_Int32 value) {
366 [ + + ][ + + ]: 57830 : if (value >= -1 && value <= 5) {
367 : : // iconst_<i>:
368 : 45230 : appendU1(m_code, static_cast< sal_uInt8 >(0x02 + value + 1));
369 [ + + ][ + + ]: 12600 : } else if (value >= -128 && value <= 127) {
370 : : // bipush <byte>:
371 : 11914 : appendU1(m_code, 0x10);
372 : 11914 : appendU1(m_code, static_cast< sal_uInt8 >(value));
373 [ + - ][ + + ]: 686 : } else if (value >= -32768 && value <= 32767) {
374 : : // sipush <byte1> <byte2>:
375 : 656 : appendU1(m_code, 0x11);
376 : 656 : appendU2(m_code, static_cast< sal_uInt16 >(value));
377 : : } else {
378 : 30 : ldc(m_classFile.addIntegerInfo(value));
379 : : }
380 : 57830 : }
381 : :
382 : 20003 : void ClassFile::Code::loadStringConstant(rtl::OString const & value) {
383 : 20003 : ldc(m_classFile.addStringInfo(value));
384 : 20003 : }
385 : :
386 : 2546 : void ClassFile::Code::loadLocalInteger(sal_uInt16 index) {
387 : 2546 : accessLocal(index, 0x1A, 0x15); // iload_<n>, iload
388 : 2546 : }
389 : :
390 : 60 : void ClassFile::Code::loadLocalLong(sal_uInt16 index) {
391 : 60 : accessLocal(index, 0x1E, 0x16); // load_<n>, load
392 : 60 : }
393 : :
394 : 32 : void ClassFile::Code::loadLocalFloat(sal_uInt16 index) {
395 : 32 : accessLocal(index, 0x22, 0x17); // load_<n>, load
396 : 32 : }
397 : :
398 : 225 : void ClassFile::Code::loadLocalDouble(sal_uInt16 index) {
399 : 225 : accessLocal(index, 0x26, 0x18); // load_<n>, load
400 : 225 : }
401 : :
402 : 16093 : void ClassFile::Code::loadLocalReference(sal_uInt16 index) {
403 : 16093 : accessLocal(index, 0x2A, 0x19); // aload_<n>, aload
404 : 16093 : }
405 : :
406 : 354 : void ClassFile::Code::storeLocalReference(sal_uInt16 index) {
407 : 354 : accessLocal(index, 0x4B, 0x3A); // astore_<n>, astore
408 : 354 : }
409 : :
410 : 662 : void ClassFile::Code::branchHere(Branch branch) {
411 : 662 : std::vector< unsigned char >::size_type n = m_code.size();
412 : : OSL_ASSERT(n > branch && n - branch <= SAL_MAX_INT16);
413 : 662 : n -= branch;
414 : 662 : m_code[branch + 1] = static_cast< sal_uInt8 >(n >> 8);
415 : 662 : m_code[branch + 2] = static_cast< sal_uInt8 >(n & 0xFF);
416 : 662 : }
417 : :
418 : 426 : void ClassFile::Code::addException(
419 : : Position start, Position end, Position handler, rtl::OString const & type)
420 : : {
421 : : OSL_ASSERT(start < end && end <= m_code.size() && handler <= m_code.size());
422 [ - + ]: 426 : if (m_exceptionTableLength == SAL_MAX_UINT16) {
423 : : throw CannotDumpException(
424 : : rtl::OString(
425 : : RTL_CONSTASCII_STRINGPARAM(
426 : 0 : "Too many exception handlers for Java class file format")));
427 : : }
428 : 426 : ++m_exceptionTableLength;
429 : 426 : appendU2(m_exceptionTable, static_cast< sal_uInt16 >(start));
430 : : //FIXME: overflow
431 : 426 : appendU2(m_exceptionTable, static_cast< sal_uInt16 >(end));
432 : : //FIXME: overflow
433 : 426 : appendU2(m_exceptionTable, static_cast< sal_uInt16 >(handler));
434 : : //FIXME: overflow
435 : 426 : appendU2(m_exceptionTable, m_classFile.addClassInfo(type));
436 : 426 : }
437 : :
438 : 1428 : ClassFile::Code::Position ClassFile::Code::getPosition() const {
439 : 1428 : return m_code.size();
440 : : }
441 : :
442 : 13451 : ClassFile::Code::Code(ClassFile & classFile):
443 [ + - ]: 13451 : m_classFile(classFile), m_exceptionTableLength(0)
444 : 13451 : {}
445 : :
446 : 20033 : void ClassFile::Code::ldc(sal_uInt16 index) {
447 [ + + ]: 20033 : if (index <= 0xFF) {
448 : : // ldc <index>:
449 : 19814 : appendU1(m_code, 0x12);
450 : 19814 : appendU1(m_code, static_cast< sal_uInt8 >(index));
451 : : } else {
452 : : // ldc_w <indexbyte1> <indexbyte2>:
453 : 219 : appendU1(m_code, 0x13);
454 : 219 : appendU2(m_code, index);
455 : : }
456 : 20033 : }
457 : :
458 : 19310 : void ClassFile::Code::accessLocal(
459 : : sal_uInt16 index, sal_uInt8 fastOp, sal_uInt8 normalOp)
460 : : {
461 [ + + ]: 19310 : if (index <= 3) {
462 : : // ...load/store_<n>:
463 : 17486 : appendU1(m_code, static_cast< sal_uInt8 >(fastOp + index));
464 [ + - ]: 1824 : } else if (index <= 0xFF) {
465 : : // ...load/store <index>:
466 : 1824 : appendU1(m_code, normalOp);
467 : 1824 : appendU1(m_code, static_cast< sal_uInt8 >(index));
468 : : } else {
469 : : // wide ...load/store <indexbyte1> <indexbyte2>:
470 : 0 : appendU1(m_code, 0xC4);
471 : 0 : appendU1(m_code, normalOp);
472 : 0 : appendU2(m_code, index);
473 : : }
474 : 19310 : }
475 : :
476 : 6200 : ClassFile::ClassFile(
477 : : AccessFlags accessFlags, rtl::OString const & thisClass,
478 : : rtl::OString const & superClass, rtl::OString const & signature):
479 : : m_constantPoolCount(1), m_accessFlags(accessFlags), m_interfacesCount(0),
480 [ + - ][ + - ]: 6200 : m_fieldsCount(0), m_methodsCount(0), m_attributesCount(0)
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
481 : : {
482 [ + - ]: 6200 : m_thisClass = addClassInfo(thisClass);
483 [ + - ]: 6200 : m_superClass = addClassInfo(superClass);
484 [ + + ]: 6200 : if (!signature.isEmpty()) {
485 : 10 : ++m_attributesCount;
486 : : appendU2(
487 : : m_attributes,
488 [ + - ][ + - ]: 10 : addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Signature"))));
489 [ + - ]: 10 : appendU4(m_attributes, 2);
490 [ + - ][ + - ]: 10 : appendU2(m_attributes, addUtf8Info(signature));
491 : : }
492 : 6200 : }
493 : :
494 : 6200 : ClassFile::~ClassFile() {}
495 : :
496 : 13451 : ClassFile::Code * ClassFile::newCode() {
497 [ + - ]: 13451 : return new Code(*this);
498 : : }
499 : :
500 : 9381 : sal_uInt16 ClassFile::addIntegerInfo(sal_Int32 value) {
501 [ + - ]: 9381 : std::map< sal_Int32, sal_uInt16 >::iterator i(m_integerInfos.find(value));
502 [ + - ][ + + ]: 9381 : if (i != m_integerInfos.end()) {
503 [ + - ]: 138 : return i->second;
504 : : }
505 [ + - ]: 9243 : sal_uInt16 index = nextConstantPoolIndex(1);
506 [ + - ]: 9243 : appendU1(m_constantPool, 3);
507 [ + - ]: 9243 : appendU4(m_constantPool, static_cast< sal_uInt32 >(value));
508 : 9243 : if (!m_integerInfos.insert(
509 [ + - ][ + - ]: 9243 : std::map< sal_Int32, sal_uInt16 >::value_type(value, index)).second)
510 : : {
511 : : OSL_ASSERT(false);
512 : : }
513 : 9381 : return index;
514 : : }
515 : :
516 : 40 : sal_uInt16 ClassFile::addFloatInfo(float value) {
517 [ + - ]: 40 : std::map< float, sal_uInt16 >::iterator i(m_floatInfos.find(value));
518 [ + - ][ - + ]: 40 : if (i != m_floatInfos.end()) {
519 [ # # ]: 0 : return i->second;
520 : : }
521 [ + - ]: 40 : sal_uInt16 index = nextConstantPoolIndex(1);
522 [ + - ]: 40 : appendU1(m_constantPool, 4);
523 : : union { float floatBytes; sal_uInt32 uint32Bytes; } bytes;
524 : 40 : bytes.floatBytes = value;
525 [ + - ]: 40 : appendU4(m_constantPool, bytes.uint32Bytes);
526 : 40 : if (!m_floatInfos.insert(
527 [ + - ][ + - ]: 40 : std::map< float, sal_uInt16 >::value_type(value, index)).second)
528 : : {
529 : : OSL_ASSERT(false);
530 : : }
531 : 40 : return index;
532 : : }
533 : :
534 : 58 : sal_uInt16 ClassFile::addLongInfo(sal_Int64 value) {
535 [ + - ]: 58 : std::map< sal_Int64, sal_uInt16 >::iterator i(m_longInfos.find(value));
536 [ + - ][ - + ]: 58 : if (i != m_longInfos.end()) {
537 [ # # ]: 0 : return i->second;
538 : : }
539 [ + - ]: 58 : sal_uInt16 index = nextConstantPoolIndex(2);
540 [ + - ]: 58 : appendU1(m_constantPool, 5);
541 [ + - ]: 58 : appendU8(m_constantPool, static_cast< sal_uInt64 >(value));
542 : 58 : if (!m_longInfos.insert(
543 [ + - ][ + - ]: 58 : std::map< sal_Int64, sal_uInt16 >::value_type(value, index)).second)
544 : : {
545 : : OSL_ASSERT(false);
546 : : }
547 : 58 : return index;
548 : : }
549 : :
550 : 0 : sal_uInt16 ClassFile::addDoubleInfo(double value) {
551 [ # # ]: 0 : std::map< double, sal_uInt16 >::iterator i(m_doubleInfos.find(value));
552 [ # # ][ # # ]: 0 : if (i != m_doubleInfos.end()) {
553 [ # # ]: 0 : return i->second;
554 : : }
555 [ # # ]: 0 : sal_uInt16 index = nextConstantPoolIndex(2);
556 [ # # ]: 0 : appendU1(m_constantPool, 6);
557 : : union { double doubleBytes; sal_uInt64 uint64Bytes; } bytes;
558 : 0 : bytes.doubleBytes = value;
559 [ # # ]: 0 : appendU8(m_constantPool, bytes.uint64Bytes);
560 : 0 : if (!m_doubleInfos.insert(
561 [ # # ][ # # ]: 0 : std::map< double, sal_uInt16 >::value_type(value, index)).second)
562 : : {
563 : : OSL_ASSERT(false);
564 : : }
565 : 0 : return index;
566 : : }
567 : :
568 : 3586 : void ClassFile::addInterface(rtl::OString const & interface) {
569 [ - + ]: 3586 : if (m_interfacesCount == SAL_MAX_UINT16) {
570 : : throw CannotDumpException(
571 : : rtl::OString(
572 : : RTL_CONSTASCII_STRINGPARAM(
573 : 0 : "Too many interfaces for Java class file format")));
574 : : }
575 : 3586 : ++m_interfacesCount;
576 : 3586 : appendU2(m_interfaces, addClassInfo(interface));
577 : 3586 : }
578 : :
579 : 20160 : void ClassFile::addField(
580 : : AccessFlags accessFlags, rtl::OString const & name,
581 : : rtl::OString const & descriptor, sal_uInt16 constantValueIndex,
582 : : rtl::OString const & signature)
583 : : {
584 [ - + ]: 20160 : if (m_fieldsCount == SAL_MAX_UINT16) {
585 : : throw CannotDumpException(
586 : : rtl::OString(
587 : : RTL_CONSTASCII_STRINGPARAM(
588 : 0 : "Too many fields for Java class file format")));
589 : : }
590 : 20160 : ++m_fieldsCount;
591 : 20160 : appendU2(m_fields, static_cast< sal_uInt16 >(accessFlags));
592 : 20160 : appendU2(m_fields, addUtf8Info(name));
593 : 20160 : appendU2(m_fields, addUtf8Info(descriptor));
594 : : appendU2(
595 : : m_fields,
596 : : ((constantValueIndex == 0 ? 0 : 1)
597 [ + + ]: 20160 : + (signature.isEmpty() ? 0 : 1)));
598 [ + + ]: 20160 : if (constantValueIndex != 0) {
599 : : appendU2(
600 : : m_fields,
601 : : addUtf8Info(
602 [ + - ][ + - ]: 9449 : rtl::OString(RTL_CONSTASCII_STRINGPARAM("ConstantValue"))));
603 : 9449 : appendU4(m_fields, 2);
604 : 9449 : appendU2(m_fields, constantValueIndex);
605 : : }
606 : 20160 : appendSignatureAttribute(m_fields, signature);
607 : 20160 : }
608 : :
609 : 23615 : void ClassFile::addMethod(
610 : : AccessFlags accessFlags, rtl::OString const & name,
611 : : rtl::OString const & descriptor, Code const * code,
612 : : std::vector< rtl::OString > const & exceptions,
613 : : rtl::OString const & signature)
614 : : {
615 [ - + ]: 23615 : if (m_methodsCount == SAL_MAX_UINT16) {
616 : : throw CannotDumpException(
617 : : rtl::OString(
618 : : RTL_CONSTASCII_STRINGPARAM(
619 : 0 : "Too many methods for Java class file format")));
620 : : }
621 : 23615 : ++m_methodsCount;
622 : 23615 : appendU2(m_methods, static_cast< sal_uInt16 >(accessFlags));
623 : 23615 : appendU2(m_methods, addUtf8Info(name));
624 : 23615 : appendU2(m_methods, addUtf8Info(descriptor));
625 : 23615 : std::vector< rtl::OString >::size_type excs = exceptions.size();
626 [ - + ]: 23615 : if (excs > SAL_MAX_UINT16) {
627 : : throw CannotDumpException(
628 : : rtl::OString(
629 : : RTL_CONSTASCII_STRINGPARAM(
630 : : "Too many exception specifications for Java class file"
631 : 0 : " format")));
632 : : }
633 : : appendU2(
634 : : m_methods,
635 : 23615 : ((code == 0 ? 0 : 1) + (exceptions.empty() ? 0 : 1)
636 [ + + ][ + + ]: 23615 : + (signature.isEmpty() ? 0 : 1)));
637 [ + + ]: 23615 : if (code != 0) {
638 : 10221 : std::vector< unsigned char >::size_type codeSize = code->m_code.size();
639 : : std::vector< unsigned char >::size_type exceptionTableSize
640 : 10221 : = code->m_exceptionTable.size();
641 [ - + ][ + - ]: 10221 : if (codeSize > SAL_MAX_UINT32 - (2 + 2 + 4 + 2 + 2)
642 : : || (exceptionTableSize
643 : : > (SAL_MAX_UINT32 - (2 + 2 + 4 + 2 + 2)
644 : : - static_cast< sal_uInt32 >(codeSize))))
645 : : {
646 : : throw CannotDumpException(
647 : : rtl::OString(
648 : : RTL_CONSTASCII_STRINGPARAM(
649 : 0 : "Code block is too big for Java class file format")));
650 : : }
651 : : appendU2(
652 : : m_methods,
653 [ + - ][ + - ]: 10221 : addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Code"))));
654 : : appendU4(
655 : : m_methods,
656 : : (2 + 2 + 4 + static_cast< sal_uInt32 >(codeSize) + 2
657 : 10221 : + static_cast< sal_uInt32 >(exceptionTableSize) + 2));
658 : 10221 : appendU2(m_methods, code->m_maxStack);
659 : 10221 : appendU2(m_methods, code->m_maxLocals);
660 : 10221 : appendU4(m_methods, static_cast< sal_uInt32 >(codeSize));
661 : 10221 : appendStream(m_methods, code->m_code);
662 : 10221 : appendU2(m_methods, code->m_exceptionTableLength);
663 : 10221 : appendStream(m_methods, code->m_exceptionTable);
664 : 10221 : appendU2(m_methods, 0);
665 : : }
666 [ + + ]: 23615 : if (!exceptions.empty()) {
667 : : appendU2(
668 : : m_methods,
669 : : addUtf8Info(
670 [ + - ][ + - ]: 4115 : rtl::OString(RTL_CONSTASCII_STRINGPARAM("Exceptions"))));
671 : : appendU4(
672 : : m_methods,
673 : 4115 : static_cast< sal_uInt32 >(2 + 2 * static_cast< sal_uInt32 >(excs)));
674 : 4115 : appendU2(m_methods, static_cast< sal_uInt16 >(excs));
675 [ + - ][ + + ]: 19780 : for (std::vector< rtl::OString >::const_iterator i(exceptions.begin());
676 : 9890 : i != exceptions.end(); ++i)
677 : : {
678 [ + - ][ + - ]: 5775 : appendU2(m_methods, addClassInfo(*i));
679 : : }
680 : : }
681 : 23615 : appendSignatureAttribute(m_methods, signature);
682 : 23615 : }
683 : :
684 : 6200 : void ClassFile::write(FileStream & file) const {
685 : 6200 : writeU4(file, 0xCAFEBABE);
686 : 6200 : writeU2(file, 0);
687 : 6200 : writeU2(file, 49); // class file version of JRE 1.5
688 : 6200 : writeU2(file, m_constantPoolCount);
689 : 6200 : writeStream(file, m_constantPool);
690 : 6200 : writeU2(file, static_cast< sal_uInt16 >(m_accessFlags));
691 : 6200 : writeU2(file, m_thisClass);
692 : 6200 : writeU2(file, m_superClass);
693 : 6200 : writeU2(file, m_interfacesCount);
694 : 6200 : writeStream(file, m_interfaces);
695 : 6200 : writeU2(file, m_fieldsCount);
696 : 6200 : writeStream(file, m_fields);
697 : 6200 : writeU2(file, m_methodsCount);
698 : 6200 : writeStream(file, m_methods);
699 : 6200 : writeU2(file, m_attributesCount);
700 : 6200 : writeStream(file, m_attributes);
701 : 6200 : }
702 : :
703 : 227419 : sal_uInt16 ClassFile::nextConstantPoolIndex(sal_uInt16 width) {
704 : : OSL_ASSERT(width == 1 || width == 2);
705 [ - + ]: 227419 : if (m_constantPoolCount > SAL_MAX_UINT16 - width) {
706 : : throw CannotDumpException(
707 : : rtl::OString(
708 : : RTL_CONSTASCII_STRINGPARAM(
709 : : "Too many constant pool items for Java class file"
710 : 0 : " format")));
711 : : }
712 : 227419 : sal_uInt16 index = m_constantPoolCount;
713 : 227419 : m_constantPoolCount = m_constantPoolCount + width;
714 : 227419 : return index;
715 : : }
716 : :
717 : 312803 : sal_uInt16 ClassFile::addUtf8Info(rtl::OString const & value) {
718 [ + - ]: 312803 : std::map< rtl::OString, sal_uInt16 >::iterator i(m_utf8Infos.find(value));
719 [ + + ]: 312803 : if (i != m_utf8Infos.end()) {
720 : 188669 : return i->second;
721 : : }
722 [ - + ]: 124134 : if (value.getLength() > SAL_MAX_UINT16) {
723 : : throw CannotDumpException(
724 : : rtl::OString(
725 : : RTL_CONSTASCII_STRINGPARAM(
726 : 0 : "UTF-8 string too long for Java class file format")));
727 : : }
728 [ + - ]: 124134 : sal_uInt16 index = nextConstantPoolIndex(1);
729 [ + - ]: 124134 : appendU1(m_constantPool, 1);
730 [ + - ]: 124134 : appendU2(m_constantPool, static_cast< sal_uInt16 >(value.getLength()));
731 [ + + ]: 2892929 : for (sal_Int32 j = 0; j < value.getLength(); ++j) {
732 [ + - ]: 2768795 : appendU1(m_constantPool, static_cast< sal_uInt8 >(value[j]));
733 : : }
734 : 124134 : if (!m_utf8Infos.insert(
735 : : std::map< rtl::OString, sal_uInt16 >::value_type(value, index)).
736 [ + - ][ + - ]: 124134 : second)
737 : : {
738 : : OSL_ASSERT(false);
739 : : }
740 : 312803 : return index;
741 : : }
742 : :
743 : 92883 : sal_uInt16 ClassFile::addClassInfo(rtl::OString const & type) {
744 [ + - ]: 92883 : sal_uInt16 nameIndex = addUtf8Info(type);
745 : : std::map< sal_uInt16, sal_uInt16 >::iterator i(
746 [ + - ]: 92883 : m_classInfos.find(nameIndex));
747 [ + - ][ + + ]: 92883 : if (i != m_classInfos.end()) {
748 [ + - ]: 61963 : return i->second;
749 : : }
750 [ + - ]: 30920 : sal_uInt16 index = nextConstantPoolIndex(1);
751 [ + - ]: 30920 : appendU1(m_constantPool, 7);
752 [ + - ]: 30920 : appendU2(m_constantPool, nameIndex);
753 : 30920 : if (!m_classInfos.insert(
754 : : std::map< sal_uInt16, sal_uInt16 >::value_type(nameIndex, index)).
755 [ + - ][ + - ]: 30920 : second)
756 : : {
757 : : OSL_ASSERT(false);
758 : : }
759 : 92883 : return index;
760 : : }
761 : :
762 : 20003 : sal_uInt16 ClassFile::addStringInfo(rtl::OString const & value) {
763 [ + - ]: 20003 : sal_uInt16 stringIndex = addUtf8Info(value);
764 : : std::map< sal_uInt16, sal_uInt16 >::iterator i(
765 [ + - ]: 20003 : m_stringInfos.find(stringIndex));
766 [ + - ][ + + ]: 20003 : if (i != m_stringInfos.end()) {
767 [ + - ]: 1390 : return i->second;
768 : : }
769 [ + - ]: 18613 : sal_uInt16 index = nextConstantPoolIndex(1);
770 [ + - ]: 18613 : appendU1(m_constantPool, 8);
771 [ + - ]: 18613 : appendU2(m_constantPool, stringIndex);
772 : 18613 : if (!m_stringInfos.insert(
773 : : std::map< sal_uInt16, sal_uInt16 >::value_type(stringIndex, index)).
774 [ + - ][ + - ]: 18613 : second)
775 : : {
776 : : OSL_ASSERT(false);
777 : : }
778 : 20003 : return index;
779 : : }
780 : :
781 : 16626 : sal_uInt16 ClassFile::addFieldrefInfo(
782 : : rtl::OString const & type, rtl::OString const & name,
783 : : rtl::OString const & descriptor)
784 : : {
785 [ + - ]: 16626 : sal_uInt16 classIndex = addClassInfo(type);
786 [ + - ]: 16626 : sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
787 : : sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
788 : 16626 : | nameAndTypeIndex;
789 [ + - ]: 16626 : std::map< sal_uInt32, sal_uInt16 >::iterator i(m_fieldrefInfos.find(key));
790 [ + - ][ + + ]: 16626 : if (i != m_fieldrefInfos.end()) {
791 [ + - ]: 5274 : return i->second;
792 : : }
793 [ + - ]: 11352 : sal_uInt16 index = nextConstantPoolIndex(1);
794 [ + - ]: 11352 : appendU1(m_constantPool, 9);
795 [ + - ]: 11352 : appendU2(m_constantPool, classIndex);
796 [ + - ]: 11352 : appendU2(m_constantPool, nameAndTypeIndex);
797 : 11352 : if (!m_fieldrefInfos.insert(
798 [ + - ][ + - ]: 11352 : std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
799 : : {
800 : : OSL_ASSERT(false);
801 : : }
802 : 16626 : return index;
803 : : }
804 : :
805 : 26893 : sal_uInt16 ClassFile::addMethodrefInfo(
806 : : rtl::OString const & type, rtl::OString const & name,
807 : : rtl::OString const & descriptor)
808 : : {
809 [ + - ]: 26893 : sal_uInt16 classIndex = addClassInfo(type);
810 [ + - ]: 26893 : sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
811 : : sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
812 : 26893 : | nameAndTypeIndex;
813 [ + - ]: 26893 : std::map< sal_uInt32, sal_uInt16 >::iterator i(m_methodrefInfos.find(key));
814 [ + - ][ + + ]: 26893 : if (i != m_methodrefInfos.end()) {
815 [ + - ]: 16314 : return i->second;
816 : : }
817 [ + - ]: 10579 : sal_uInt16 index = nextConstantPoolIndex(1);
818 [ + - ]: 10579 : appendU1(m_constantPool, 10);
819 [ + - ]: 10579 : appendU2(m_constantPool, classIndex);
820 [ + - ]: 10579 : appendU2(m_constantPool, nameAndTypeIndex);
821 : 10579 : if (!m_methodrefInfos.insert(
822 [ + - ][ + - ]: 10579 : std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
823 : : {
824 : : OSL_ASSERT(false);
825 : : }
826 : 26893 : return index;
827 : : }
828 : :
829 : 681 : sal_uInt16 ClassFile::addInterfaceMethodrefInfo(
830 : : rtl::OString const & type, rtl::OString const & name,
831 : : rtl::OString const & descriptor)
832 : : {
833 [ + - ]: 681 : sal_uInt16 classIndex = addClassInfo(type);
834 [ + - ]: 681 : sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor);
835 : : sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16)
836 : 681 : | nameAndTypeIndex;
837 : : std::map< sal_uInt32, sal_uInt16 >::iterator i(
838 [ + - ]: 681 : m_interfaceMethodrefInfos.find(key));
839 [ + - ][ + + ]: 681 : if (i != m_interfaceMethodrefInfos.end()) {
840 [ + - ]: 59 : return i->second;
841 : : }
842 [ + - ]: 622 : sal_uInt16 index = nextConstantPoolIndex(1);
843 [ + - ]: 622 : appendU1(m_constantPool, 11);
844 [ + - ]: 622 : appendU2(m_constantPool, classIndex);
845 [ + - ]: 622 : appendU2(m_constantPool, nameAndTypeIndex);
846 : 622 : if (!m_interfaceMethodrefInfos.insert(
847 [ + - ][ + - ]: 622 : std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
848 : : {
849 : : OSL_ASSERT(false);
850 : : }
851 : 681 : return index;
852 : : }
853 : :
854 : 44200 : sal_uInt16 ClassFile::addNameAndTypeInfo(
855 : : rtl::OString const & name, rtl::OString const & descriptor)
856 : : {
857 [ + - ]: 44200 : sal_uInt16 nameIndex = addUtf8Info(name);
858 [ + - ]: 44200 : sal_uInt16 descriptorIndex = addUtf8Info(descriptor);
859 : : sal_uInt32 key = (static_cast< sal_uInt32 >(nameIndex) << 16)
860 : 44200 : | descriptorIndex;
861 : : std::map< sal_uInt32, sal_uInt16 >::iterator i(
862 [ + - ]: 44200 : m_nameAndTypeInfos.find(key));
863 [ + - ][ + + ]: 44200 : if (i != m_nameAndTypeInfos.end()) {
864 [ + - ]: 22342 : return i->second;
865 : : }
866 [ + - ]: 21858 : sal_uInt16 index = nextConstantPoolIndex(1);
867 [ + - ]: 21858 : appendU1(m_constantPool, 12);
868 [ + - ]: 21858 : appendU2(m_constantPool, nameIndex);
869 [ + - ]: 21858 : appendU2(m_constantPool, descriptorIndex);
870 : 21858 : if (!m_nameAndTypeInfos.insert(
871 [ + - ][ + - ]: 21858 : std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second)
872 : : {
873 : : OSL_ASSERT(false);
874 : : }
875 : 44200 : return index;
876 : : }
877 : :
878 : 43775 : void ClassFile::appendSignatureAttribute(
879 : : std::vector< unsigned char > & stream, rtl::OString const & signature)
880 : : {
881 [ + + ]: 43775 : if (!signature.isEmpty()) {
882 : : appendU2(
883 : : stream,
884 [ + - ][ + - ]: 81 : addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Signature"))));
885 : 81 : appendU4(stream, 2);
886 : 81 : appendU2(stream, addUtf8Info(signature));
887 : : }
888 : 43775 : }
889 : :
890 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|