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