1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is [Open Source Virtual Machine.].
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2008
21 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
50 int Str::compareTo(Str
* other
)
52 uint32_t llen
= this->length
;
53 uint32_t rlen
= other
->length
;
54 uint32_t len
= llen
< rlen
? llen
: rlen
;
57 wchar
* limit
= s
+ len
;
58 while (s
< limit
&& *s
== *t
)
61 return int(*s
) - int(*t
);
69 Allocator::Allocator(Compiler
* compiler
)
76 AvmAssert(offsetof(Chunk
, data
) % 8 == 0);
77 // Do not refill yet; the first allocation is likely to be the hashtable
78 // and that's sometimes large, so the first segment would sometimes
82 Allocator::~Allocator()
84 while (current_chunk
!= NULL
)
86 Chunk
* tmp
= current_chunk
;
87 current_chunk
= current_chunk
->prev
;
92 void Allocator::refill(size_t nbytes
)
98 c_8
= new uint8_t[sizeof(Chunk
) + nbytes
- 1];
99 c
->prev
= current_chunk
;
101 current_top
= c
->data
;
102 current_limit
= c
->data
+ nbytes
;
105 void* Allocator::allocSlow(size_t nbytes
)
107 AvmAssert(nbytes
% 8 == 0);
108 if (current_top
+ nbytes
> current_limit
)
110 AvmAssert(current_top
+ nbytes
<= current_limit
);
111 void *p
= current_top
;
112 current_top
+= nbytes
;
116 template<class T
> void SeqBuilder
<T
>::addAtEnd(T item
)
118 Seq
<T
>* e
= ALLOC(Seq
<T
>, (item
));
126 template<class T
> T SeqBuilder
<T
>::dequeue()
128 AvmAssert(items
!= NULL
);
136 // At least Xcode requires explicit instantiation.
138 template class SeqBuilder
<double>;
139 template class SeqBuilder
<int32_t>;
140 template class SeqBuilder
<uint32_t>;
142 template class SeqBuilder
<ABCClassInfo
*>;
143 template class SeqBuilder
<ABCExceptionInfo
*>;
144 template class SeqBuilder
<ABCInstanceInfo
*>;
145 template class SeqBuilder
<ABCMetadataInfo
*>;
146 template class SeqBuilder
<ABCMethodInfo
*>;
147 template class SeqBuilder
<ABCMethodBodyInfo
*>;
148 template class SeqBuilder
<ABCMultinameInfo
*>;
149 template class SeqBuilder
<ABCNamespaceInfo
*>;
150 template class SeqBuilder
<ABCNamespaceSetInfo
*>;
151 template class SeqBuilder
<ABCScriptInfo
*>;
152 template class SeqBuilder
<ABCTrait
*>;
153 template class SeqBuilder
<Binding
*>;
154 template class SeqBuilder
<CaseClause
*>;
155 template class SeqBuilder
<CatchClause
*>;
156 template class SeqBuilder
<DefaultValue
*>;
157 template class SeqBuilder
<Expr
*>;
158 template class SeqBuilder
<FunctionDefn
*>;
159 template class SeqBuilder
<FunctionParam
*>;
160 template class SeqBuilder
<Label
*>;
161 template class SeqBuilder
<LiteralField
*>;
162 template class SeqBuilder
<Namespace
*>;
163 template class SeqBuilder
<NamespaceDefn
*>;
164 template class SeqBuilder
<Stmt
*>;
165 template class SeqBuilder
<Str
*>;
167 StringBuilder::StringBuilder(Compiler
* compiler
)
168 : allocator(compiler
->allocator
)
174 StringBuilder::~StringBuilder()
176 while (chunk
!= NULL
)
180 void StringBuilder::clear()
186 while (chunk
->next
!= NULL
)
190 void StringBuilder::append(StringBuilder
* other
)
192 append(other
->chunk
->next
);
193 append(other
->chunk
->data
, other
->chunk
->data
+ other
->nextchar
);
196 void StringBuilder::append(Str
* other
)
198 append(other
->s
, other
->s
+ other
->length
);
201 void StringBuilder::append(const char* other
)
207 void StringBuilder::append(const wchar
* ptr
, const wchar
* lim
)
215 uint32_t avail
= SBChunk::chunksize
- nextchar
;
216 uint32_t need
= uint32_t(lim
- ptr
);
217 uint32_t k
= min(need
, avail
);
218 VMPI_memcpy(chunk
->data
+ nextchar
, ptr
, k
*sizeof(wchar
));
229 void StringBuilder::append(int c
)
232 append(&c2
, (&c2
) + 1);
235 Str
* StringBuilder::str()
237 if (chunk
->next
== NULL
)
238 return allocator
->compiler
->intern(chunk
->data
, len
);
240 wchar
* buf
= new wchar
[len
];
241 wchar
* p
= copyInto(buf
, chunk
->next
);
242 VMPI_memcpy(p
, chunk
->data
, nextchar
*sizeof(wchar
));
243 Str
* result
= allocator
->compiler
->intern(buf
, len
);
248 char* StringBuilder::chardata()
250 char *buf
= (char*)allocator
->alloc(len
+1);
251 char *p
= copyInto(buf
, chunk
->next
);
252 for ( uint32_t i
=0 ; i
< nextchar
; i
++ )
253 p
[i
] = (char)(chunk
->data
[i
] & 127);
259 void StringBuilder::append(SBChunk
* other
)
263 append(other
->data
, other
->data
+ SBChunk::chunksize
);
267 wchar
* StringBuilder::copyInto(wchar
* buf
, SBChunk
* c
)
274 p
= copyInto(buf
, c
->next
);
275 VMPI_memcpy(p
, c
->data
, SBChunk::chunksize
*sizeof(wchar
));
276 return p
+SBChunk::chunksize
;
279 char* StringBuilder::copyInto(char* buf
, SBChunk
* c
)
286 p
= copyInto(buf
, c
->next
);
287 for ( int i
=0 ; i
< SBChunk::chunksize
; i
++ )
288 p
[i
] = (char)(chunk
->data
[i
] & 127);
289 return p
+SBChunk::chunksize
;
292 void StringBuilder::pushChunk()
295 if (allocator
->free_sbchunks
!= NULL
) {
296 c
= allocator
->free_sbchunks
;
297 allocator
->free_sbchunks
= allocator
->free_sbchunks
->next
;
300 c
= ALLOC(SBChunk
, ());
305 void StringBuilder::popChunk()
309 c
->next
= allocator
->free_sbchunks
;
310 allocator
->free_sbchunks
= c
;
315 char* getn(char* buf
, const Str
* s
, size_t limit
)
317 int chars
= int(s
->length
< limit
-1 ? s
->length
: limit
-1);
320 for ( p
=s
->s
, q
=buf
; chars
>= 0 ; chars
-- )
328 uint32_t hashString(const wchar
* chars
, uint32_t nchars
)
330 // See http://www.cse.yorku.ca/~oz/hash.html; this is the djb2 algorithm
332 for ( uint32_t i
=0 ; i
< nchars
; i
++ )
333 h
= ((h
<< 5) + h
) + chars
[i
];
337 uint32_t lenU30(uint32_t val
)
343 if ( val
< 0x200000 )
345 if ( val
< 0x10000000 )
350 uint8_t* emitU32(uint8_t* out
, uint32_t val
)
355 else if ( val
< 0x4000 ) {
356 *out
++ = (val
& 0x7F) | 0x80;
357 *out
++ = (val
>> 7) & 0x7F;
359 else if ( val
< 0x200000 ) {
360 *out
++ = (val
& 0x7F) | 0x80;
361 *out
++ = ((val
>> 7) & 0x7F) | 0x80;
362 *out
++ = (val
>> 14) & 0x7F;
364 else if ( val
< 0x10000000 ) {
365 *out
++ = (val
& 0x7F) | 0x80;
366 *out
++ = ((val
>> 7) & 0x7F) | 0x80;
367 *out
++ = ((val
>> 14) & 0x7F) | 0x80;
368 *out
++ = (val
>> 21) & 0x7F;
371 *out
++ = (val
& 0x7F) | 0x80;
372 *out
++ = ((val
>> 7) & 0x7F) | 0x80;
373 *out
++ = ((val
>> 14) & 0x7F) | 0x80;
374 *out
++ = ((val
>> 21) & 0x7F) | 0x80;
375 *out
++ = (val
>> 28) & 0x7F;
380 uint8_t* emitDouble(uint8_t* out
, double d
)
383 out
[0] = uint8_t(v
.words
.lsw
);
384 out
[1] = uint8_t(v
.words
.lsw
>> 8);
385 out
[2] = uint8_t(v
.words
.lsw
>> 16);
386 out
[3] = uint8_t(v
.words
.lsw
>> 24);
387 out
[4] = uint8_t(v
.words
.msw
);
388 out
[5] = uint8_t(v
.words
.msw
>> 8);
389 out
[6] = uint8_t(v
.words
.msw
>> 16);
390 out
[7] = uint8_t(v
.words
.msw
>> 24);
394 uint8_t* emitS24(uint8_t* out
, int32_t s
)
397 *out
++ = (s
>> 8) & 255;
398 *out
++ = (s
>> 16) & 255;
402 int32_t readS24(uint8_t* in
)
404 return ((in
[0] | (in
[1] << 8) | (in
[2] << 16)) << 8) >> 8;
407 uint32_t utf8length(Str
* str
)
411 for ( wchar
*s
=str
->s
, *l
=str
->s
+ str
->length
; s
< l
; s
++ ) {
414 else if (*s
<= 0x7FF)
422 // duplicates formatUtf8 below???
423 uint8_t* emitUtf8(uint8_t* out
, Str
* str
)
425 for ( wchar
*s
=str
->s
, *l
=str
->s
+ str
->length
; s
< l
; s
++ ) {
429 else if (c
<= 0x7FF) {
430 *out
++ = 0xC0 | ((c
>> 6) & 0x1F);
431 *out
++ = 0x80 | (c
& 0x3F);
434 *out
++ = 0xE0 | ((c
>> 12) & 0x0F);
435 *out
++ = 0x80 | ((c
>> 6) & 0x3F);
436 *out
++ = 0x80 | (c
& 0x3F);
442 ByteBuffer::ByteBuffer(Allocator
* allocator
, uint32_t increment
)
443 : allocator(allocator
)
444 , increment(increment
)
453 void ByteBuffer::makeRoomSlow(uint32_t nbytes
)
459 uint32_t k
= nbytes
> increment
? nbytes
: increment
;
460 Chunk
* c
= (Chunk
*)allocator
->alloc(sizeof(Chunk
) + k
- 1);
463 limit
= c
->start
+ k
;
464 AvmAssert( (uint32_t)(limit
- out
) >= nbytes
);
472 void ByteBuffer::serialize(uint8_t* b
) const
476 for ( Chunk
* c
= first
; c
!= NULL
; c
= c
->next
) {
477 VMPI_memcpy( b
, c
->start
, c
->end
- c
->start
);
478 b
+= c
->end
- c
->start
;
483 void formatUtf8(char *buf
, size_t bufsiz
, const wchar
* s
)
485 AvmAssert(bufsiz
> 0);
486 char *limit
= buf
+ bufsiz
;
488 while ((c
= *s
++) != 0)
495 else if (c
< 0x800) {
498 *buf
++ = 0xC0 | ((c
>> 6) & 31);
499 *buf
++ = 0x80 | (c
& 63);
501 else if (c
>= 0xD800 && c
<= 0xDBFF) {
503 if (d
>= 0xDC00 && d
<= 0xDCFF) {
507 wchar u
= ((c
>> 6) & 15) + 1;
508 *buf
++ = (char)(0xF0 | (u
>> 2));
509 *buf
++ = 0x80 | ((u
& 3) << 4) | ((c
>> 2) & 15);
510 *buf
++ = 0x80 | ((c
& 3) << 4) | ((d
>> 6) & 15);
511 *buf
++ = 0x80 | (d
& 63);
521 else if (c
>= 0xDC00 && c
<= 0xDCFF) {
530 *buf
++ = 0xE0 | ((c
>> 12) & 15);
531 *buf
++ = 0x80 | ((c
>> 6) & 63);
532 *buf
++ = 0x80 | (c
& 63);
535 AvmAssert(buf
< limit
);