File: | platform/mac/avmshell/../../../core/PoolObject.cpp |
Location: | line 551, column 13 |
Description: | Value stored to 'index' is never read |
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 |
5 | * |
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/ |
10 | * |
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 |
14 | * License. |
15 | * |
16 | * The Original Code is [Open Source Virtual Machine.]. |
17 | * |
18 | * The Initial Developer of the Original Code is |
19 | * Adobe System Incorporated. |
20 | * Portions created by the Initial Developer are Copyright (C) 2004-2006 |
21 | * the Initial Developer. All Rights Reserved. |
22 | * |
23 | * Contributor(s): |
24 | * Adobe AS3 Team |
25 | * |
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. |
37 | * |
38 | * ***** END LICENSE BLOCK ***** */ |
39 | |
40 | |
41 | #include "avmplus.h" |
42 | |
43 | #ifdef VMCFG_NANOJIT |
44 | # include "CodegenLIR.h" |
45 | #endif |
46 | |
47 | namespace avmplus |
48 | { |
49 | // This assert is here to ensure that "GCDouble" is the same |
50 | // bit value as "double"; GCDouble exists solely to provide |
51 | // a GCObject-descended type to satisfy new constraints on List. |
52 | MMGC_STATIC_ASSERT(sizeof(GCDouble) == sizeof(double))typedef ::MMgc::static_assert_MMgc<sizeof (::MMgc::STATIC_ASSERTION_FAILED <(bool)(sizeof(GCDouble) == sizeof(double))>)> MMgc_static_assert_line_52; |
53 | |
54 | PoolObject::PoolObject(AvmCore* core, ScriptBuffer& sb, const uint8_t* startPos, ApiVersion apiVersion) : |
55 | core(core), |
56 | cpool_int(core->GetGC(), 0), |
57 | cpool_uint(core->GetGC(), 0), |
58 | cpool_double(core->GetGC(), 0), |
59 | cpool_ns(core->GetGC(), 0), |
60 | cpool_ns_set(core->GetGC(), 0), |
61 | #ifndef AVMPLUS_64BIT |
62 | cpool_int_atoms(core->GetGC(), 0), |
63 | cpool_uint_atoms(core->GetGC(), 0), |
64 | #endif |
65 | cpool_mn_offsets(core->GetGC(), 0), |
66 | metadata_infos(core->GetGC(), 0), |
67 | m_loadedTraits(MultinameTraitsHashtable::create(core->GetGC())), |
68 | m_cachedTraits(MultinameTraitsHashtable::create(core->GetGC())), |
69 | m_loadedScripts(MultinameMethodInfoHashtable::create(core->GetGC())), |
70 | m_cachedScripts(MultinameMethodInfoHashtable::create(core->GetGC())), |
71 | _code(sb.getImpl()), |
72 | _abcStart(startPos), |
73 | _abcStringStart(NULL__null), |
74 | _abcStringEnd(NULL__null), |
75 | _abcStrings(NULL__null), |
76 | _classes(core->GetGC(), 0), |
77 | _scripts(core->GetGC(), 0), |
78 | _methods(core->GetGC(), 0) |
79 | #ifdef DEBUGGER |
80 | , _method_dmi(core->GetGC(), 0) |
81 | #endif |
82 | , _method_name_indices(core->GetGC(), 0) |
83 | , _apiVersion(apiVersion) |
84 | , _uniqueId(-1) |
85 | #ifdef VMCFG_AOT |
86 | , aotInfo(NULL__null) |
87 | , aotRoot(NULL__null) |
88 | #endif |
89 | { |
90 | version = AvmCore::readU16(&code()[0]) | AvmCore::readU16(&code()[2])<<16; |
91 | core->addLivePool(this); |
92 | } |
93 | |
94 | PoolObject::~PoolObject() |
95 | { |
96 | #ifdef VMCFG_AOT |
97 | if (aotRoot) |
98 | delete aotRoot; |
99 | #endif |
100 | #ifdef VMCFG_NANOJIT |
101 | mmfx_delete( codeMgr )::MMgcDestructTaggedScalarChecked(codeMgr); |
102 | #endif |
103 | } |
104 | |
105 | void PoolObject::dynamicizeStrings() |
106 | { |
107 | if (!MMgc::GC::GetGC(this)->Destroying()) |
108 | { |
109 | // make all strings created so far dynamic, |
110 | // making sure that no pointers into ABC data persist |
111 | // (string 0 is always core->kEmptyString: skip it) |
112 | ConstantStringData* dataP = _abcStrings->data; |
113 | for (uint32_t i = 1; i < constantStringCount; i++) |
114 | { |
115 | ++dataP; |
116 | |
117 | if (dataP->abcPtr >= _abcStringStart && dataP->abcPtr < _abcStringEnd) |
118 | { |
119 | // it's still a raw ABC ptr, not a String |
120 | continue; |
121 | } |
122 | |
123 | Stringp s = dataP->str; |
124 | |
125 | // in theory, only index 0 should be the empty string... but in practice, |
126 | // any index could be empty, and makeDynamic doesn't work on zero-length strings. |
127 | // since that call doesn't have easy access to an AvmCore, do the check here. |
128 | // (s can be null in the obscure case of a fuzzed ABC) |
129 | if (!s || s->isEmpty()) |
130 | { |
131 | // all zero-length strings should be kEmptyString. |
132 | AvmAssert(!s || s == core->kEmptyString)do { } while (0); |
133 | continue; |
134 | } |
135 | |
136 | s->makeDynamic(_abcStringStart, uint32_t(_abcStringEnd - _abcStringStart)); |
137 | } |
138 | } |
139 | } |
140 | |
141 | Namespace* PoolObject::getNamespace(int32_t index) const |
142 | { |
143 | return cpool_ns[index]; |
144 | } |
145 | |
146 | NamespaceSetp PoolObject::getNamespaceSet(int32_t index) const |
147 | { |
148 | return cpool_ns_set[index]; |
149 | } |
150 | |
151 | //////////////////////////////////////////////////////////////////// |
152 | |
153 | boolbool ConstantStringContainer::gcTrace(MMgc::GC* gc, size_t cursor) |
154 | { |
155 | size_t cap = pool->constantStringCount; |
156 | const uint32_t work_increment = 2000/sizeof(void*); |
157 | if (work_increment * cursor >= cap) |
158 | return falsefalse; |
159 | |
160 | size_t work = work_increment; |
161 | boolbool more = truetrue; |
162 | if (work_increment * (cursor + 1) >= cap) { |
163 | work = cap - (work_increment * cursor); |
164 | more = falsefalse; |
165 | } |
166 | |
167 | const uint8_t *start = pool->_abcStringStart; |
168 | const uint8_t *end = pool->_abcStringEnd; |
169 | |
170 | // Skip strings into the ABC data, everything else is a real String pointer |
171 | for ( size_t i=0 ; i < work ; i++ ) { |
172 | ConstantStringData& item = data[(work_increment * cursor) + i]; |
173 | if (item.abcPtr >= start && item.abcPtr < end) |
174 | continue; |
175 | gc->TraceLocation(&item.str); |
176 | } |
177 | return more; |
178 | } |
179 | |
180 | void PoolObject::setupConstantStrings(uint32_t count) |
181 | { |
182 | // Always allocate slot 0 in the data array, which will be |
183 | // initialized to an empty String* in AbcParser::parseCpool(). |
184 | // We also avoid invoking Calloc() with a size of zero, |
185 | // which will cause an assertion to fail. |
186 | // TODO: If there are no strings, we should be able to set |
187 | // data = NULL, size = 0, and avoid calling the allocator. |
188 | // Slot 0 should never be accessed, and the code guards against |
189 | // such accesses generally, but there are presently exceptions. |
190 | // With the guards spread over much code, it is safer to do |
191 | // as we do here. This problem extends to other constant pool |
192 | // entry types, and should be cleaned up. See bug 557684. |
193 | // |
194 | // Be sure to zero the memory or garbage will be touched by |
195 | // the presweep handler that cleans up the string pool, see |
196 | // Bugzilla 574427. |
197 | if (count == 0) |
198 | count = 1; |
199 | // FIXME: worry about overflow in the 'extra' computation |
200 | _abcStrings = ConstantStringContainer::create(core->gc, (count-1) * sizeof(ConstantStringData), this); |
201 | constantStringCount = count; |
202 | } |
203 | |
204 | Stringp PoolObject::getString(int32_t index) const |
205 | { |
206 | ConstantStringData* dataP = _abcStrings->data + index; |
207 | if (dataP->abcPtr >= _abcStringStart && dataP->abcPtr < _abcStringEnd) |
208 | { |
209 | // String not created yet; grab the pointer to the (verified) ABC data |
210 | uint32_t len = AvmCore::readU32(dataP->abcPtr); |
211 | // strict=false for bug-compatibility with swfs with incorrect utf8 encoding of strings |
212 | Stringp s = core->internStringUTF8((const char*) dataP->abcPtr, len, truetrue, falsefalse); |
213 | s->Stick(); // FIXME - Bugzilla 596918: The Stick() call is dodgy. |
214 | dataP->abcPtr = NULL__null; // Important to clear it - what's there is not an RCObject*, don't let WBRC see it |
215 | WBRC(core->gc, _abcStrings, &dataP->str, s)core->gc->privateWriteBarrierRC(_abcStrings, &dataP ->str, (const void *) (s)); |
216 | } |
217 | return dataP->str; |
218 | } |
219 | |
220 | /*static*/ boolbool PoolObject::isLegalDefaultValue(BuiltinType bt, Atom value) |
221 | { |
222 | switch (bt) |
223 | { |
224 | case BUILTIN_any: |
225 | return truetrue; |
226 | |
227 | case BUILTIN_object: |
228 | return (value != undefinedAtom); |
229 | |
230 | case BUILTIN_number: |
231 | return AvmCore::isNumber(value); |
232 | |
233 | case BUILTIN_boolean: |
234 | return AvmCore::isBoolean(value); |
235 | |
236 | case BUILTIN_uint: |
237 | if (AvmCore::isDouble(value)) |
238 | { |
239 | const double d = AvmCore::number_d(value); |
240 | if (d == (uint32_t)d) |
241 | return truetrue; |
242 | } |
243 | |
244 | return atomIsIntptr(value) && atomCanBeUint32(value); |
245 | |
246 | case BUILTIN_int: |
247 | if (AvmCore::isDouble(value)) |
248 | { |
249 | const double d = AvmCore::number_d(value); |
250 | if (d == (int32_t)d) |
251 | return truetrue; |
252 | } |
253 | |
254 | return atomIsIntptr(value) && atomCanBeInt32(value); |
255 | |
256 | case BUILTIN_string: |
257 | return AvmCore::isNull(value) || AvmCore::isString(value); |
258 | |
259 | case BUILTIN_namespace: |
260 | return AvmCore::isNull(value) || AvmCore::isNamespace(value); |
261 | |
262 | default: |
263 | return AvmCore::isNull(value); |
264 | } |
265 | |
266 | //return false; // unreachable |
267 | } |
268 | |
269 | Atom PoolObject::getLegalDefaultValue(const Toplevel* toplevel, uint32_t index, CPoolKind kind, Traits* t) |
270 | { |
271 | // toplevel actually can be null, when resolving the builtin classes... |
272 | // but they should never cause verification errors in functioning builds |
273 | //AvmAssert(toplevel != NULL); |
274 | |
275 | const BuiltinType bt = Traits::getBuiltinType(t); |
276 | uint32_t maxcount = 0; |
277 | Atom value; |
278 | if (index) |
279 | { |
280 | // Look in the cpool specified by kind |
281 | switch (kind) |
282 | { |
283 | case CONSTANT_Int: |
284 | { |
285 | if (index >= (maxcount = constantIntCount)) |
286 | goto range_error; |
287 | const int32_t i = cpool_int[index]; |
288 | #ifdef AVMPLUS_64BIT |
289 | value = core->intToAtom(i); |
290 | AvmAssert(atomIsIntptr(value) && atomCanBeInt32(value))do { } while (0); |
291 | #else |
292 | // LIR relies on the return values from this being "sticky" so it can insert them inline. |
293 | // that's true for everything but int/uints that overflow, so special-case them. |
294 | // @todo this can/should go away when we convert to 64-bit Box atoms. |
295 | if (!cpool_int_atoms.length()) |
296 | { |
297 | cpool_int_atoms.ensureCapacity(constantIntCount); |
298 | for (uint32_t j = 0; j < constantIntCount; ++j) |
299 | cpool_int_atoms.set(j, 0); |
300 | AvmAssert(cpool_int_atoms.length() == constantIntCount)do { } while (0); |
301 | } |
302 | value = (Atom)cpool_int_atoms[index]; |
303 | if (value == 0) |
304 | { |
305 | value = core->intToAtom(i); |
306 | if (AvmCore::isDouble(value)) |
307 | { |
308 | cpool_int_atoms.set(index, value); |
309 | } |
310 | AvmAssert(AvmCore::isNumber(value))do { } while (0); |
311 | } |
312 | else |
313 | { |
314 | AvmAssert(AvmCore::isDouble(value))do { } while (0); |
315 | } |
316 | #endif |
317 | break; |
318 | } |
319 | case CONSTANT_UInt: |
320 | { |
321 | if (index >= (maxcount = constantUIntCount)) |
322 | goto range_error; |
323 | const int32_t u = cpool_uint[index]; |
324 | #ifdef AVMPLUS_64BIT |
325 | value = core->uintToAtom(u); |
326 | AvmAssert(atomIsIntptr(value) && atomCanBeUint32(value))do { } while (0); |
327 | #else |
328 | // LIR relies on the return values from this being "sticky" so it can insert them inline. |
329 | // that's true for everything but int/uints that overflow, so special-case them. |
330 | // @todo this can/should go away when we convert to 64-bit Box atoms. |
331 | if (!cpool_uint_atoms.length()) |
332 | { |
333 | cpool_uint_atoms.ensureCapacity(constantUIntCount); |
334 | for (uint32_t j = 0; j < constantUIntCount; ++j) |
335 | cpool_uint_atoms.set(j, 0); |
336 | AvmAssert(cpool_uint_atoms.length() == constantUIntCount)do { } while (0); |
337 | } |
338 | value = (Atom)cpool_uint_atoms[index]; |
339 | if (value == 0) |
340 | { |
341 | value = core->uintToAtom(u); |
342 | if (AvmCore::isDouble(value)) |
343 | { |
344 | cpool_uint_atoms.set(index, value); |
345 | } |
346 | AvmAssert(AvmCore::isNumber(value))do { } while (0); |
347 | } |
348 | else |
349 | { |
350 | AvmAssert(AvmCore::isDouble(value))do { } while (0); |
351 | } |
352 | #endif |
353 | break; |
354 | } |
355 | case CONSTANT_Double: |
356 | if (index >= (maxcount = constantDoubleCount)) |
357 | goto range_error; |
358 | value = kDoubleType|(uintptr_t)cpool_double[index]; |
359 | break; |
360 | |
361 | case CONSTANT_Utf8: |
362 | if (index >= (maxcount = constantStringCount)) |
363 | goto range_error; |
364 | value = getString(index)->atom(); |
365 | break; |
366 | |
367 | case CONSTANT_True: |
368 | value = trueAtom; |
369 | break; |
370 | |
371 | case CONSTANT_False: |
372 | value = falseAtom; |
373 | break; |
374 | |
375 | case CONSTANT_Namespace: |
376 | case CONSTANT_PackageNamespace: |
377 | case CONSTANT_PackageInternalNs: |
378 | case CONSTANT_ProtectedNamespace: |
379 | case CONSTANT_ExplicitNamespace: |
380 | case CONSTANT_StaticProtectedNs: |
381 | case CONSTANT_PrivateNs: |
382 | if (index >= (maxcount = constantNsCount)) |
383 | goto range_error; |
384 | value = cpool_ns[index]->atom(); |
385 | break; |
386 | |
387 | case CONSTANT_Null: |
388 | value = nullObjectAtom; |
389 | break; |
390 | |
391 | default: |
392 | // Multinames & NamespaceSets are invalid default values. |
393 | goto illegal_default_error; |
394 | } |
395 | } |
396 | else |
397 | { |
398 | switch (bt) |
399 | { |
400 | case BUILTIN_any: |
401 | value = undefinedAtom; |
402 | break; |
403 | case BUILTIN_number: |
404 | value = core->kNaN; |
405 | break; |
406 | case BUILTIN_boolean: |
407 | value = falseAtom; |
408 | break; |
409 | case BUILTIN_int: |
410 | case BUILTIN_uint: |
411 | value = (zeroIntAtom); |
412 | break; |
413 | case BUILTIN_string: |
414 | value = nullStringAtom; |
415 | break; |
416 | case BUILTIN_namespace: |
417 | value = nullNsAtom; |
418 | break; |
419 | case BUILTIN_object: |
420 | default: |
421 | value = nullObjectAtom; |
422 | break; |
423 | } |
424 | } |
425 | |
426 | if (!isLegalDefaultValue(bt, value)) |
427 | goto illegal_default_error; |
428 | |
429 | return value; |
430 | |
431 | illegal_default_error: |
432 | if (toplevel) |
433 | { |
434 | if (t) |
435 | { |
436 | toplevel->throwVerifyError(kIllegalDefaultValue, core->toErrorString(Multiname(t->ns(), t->name()))); |
437 | } |
438 | else |
439 | { |
440 | toplevel->throwVerifyError(kCorruptABCError); |
441 | } |
442 | } |
443 | AvmAssert(!"unhandled verify error")do { } while (0); |
444 | return undefinedAtom; // not reached |
445 | |
446 | range_error: |
447 | if (toplevel) |
448 | toplevel->throwVerifyError(kCpoolIndexRangeError, core->toErrorString(index), core->toErrorString(maxcount)); |
449 | AvmAssert(!"unhandled verify error")do { } while (0); |
450 | return undefinedAtom; // not reached |
451 | } |
452 | |
453 | void PoolObject::parseMultiname(const uint8_t *pos, Multiname& m) const |
454 | { |
455 | // the multiname has already been validated so we don't do |
456 | // any checking here, we just fill in the Multiname object |
457 | // with the information we have parsed. |
458 | |
459 | int32_t index; |
460 | CPoolKind kind = (CPoolKind) *(pos++); |
461 | switch (kind) |
462 | { |
463 | case CONSTANT_Qname: |
464 | case CONSTANT_QnameA: |
465 | { |
466 | // U16 namespace_index |
467 | // U16 name_index |
468 | // parse a multiname with one namespace (aka qname) |
469 | |
470 | index = AvmCore::readU32(pos); |
471 | if (!index) |
472 | m.setAnyNamespace(); |
473 | else |
474 | m.setNamespace(getNamespace(index)); |
475 | |
476 | index = AvmCore::readU32(pos); |
477 | if (!index) |
478 | m.setAnyName(); |
479 | else |
480 | m.setName(getString(index)); |
481 | |
482 | m.setQName(); |
483 | m.setAttr(kind==CONSTANT_QnameA); |
484 | break; |
485 | } |
486 | |
487 | case CONSTANT_RTQname: |
488 | case CONSTANT_RTQnameA: |
489 | { |
490 | // U16 name_index |
491 | // parse a multiname with just a name; ns fetched at runtime |
492 | |
493 | index = AvmCore::readU32(pos); |
494 | if (!index) |
495 | m.setAnyName(); |
496 | else |
497 | m.setName(getString(index)); |
498 | |
499 | m.setQName(); |
500 | m.setRtns(); |
501 | m.setAttr(kind==CONSTANT_RTQnameA); |
502 | break; |
503 | } |
504 | |
505 | case CONSTANT_RTQnameL: |
506 | case CONSTANT_RTQnameLA: |
507 | { |
508 | m.setQName(); |
509 | m.setRtns(); |
510 | m.setRtname(); |
511 | m.setAttr(kind==CONSTANT_RTQnameLA); |
512 | break; |
513 | } |
514 | |
515 | case CONSTANT_Multiname: |
516 | case CONSTANT_MultinameA: |
517 | { |
518 | index = AvmCore::readU32(pos); |
519 | if (!index) |
520 | m.setAnyName(); |
521 | else |
522 | m.setName(getString(index)); |
523 | |
524 | index = AvmCore::readU32(pos); |
525 | AvmAssert(index != 0)do { } while (0); |
526 | m.setNsset(getNamespaceSet(index)); |
527 | m.setAttr(kind==CONSTANT_MultinameA); |
528 | break; |
529 | } |
530 | |
531 | case CONSTANT_MultinameL: |
532 | case CONSTANT_MultinameLA: |
533 | { |
534 | m.setRtname(); |
535 | |
536 | index = AvmCore::readU32(pos); |
537 | AvmAssert(index != 0)do { } while (0); |
538 | m.setNsset(getNamespaceSet(index)); |
539 | |
540 | m.setAttr(kind==CONSTANT_MultinameLA); |
541 | break; |
542 | } |
543 | |
544 | case CONSTANT_TypeName: |
545 | { |
546 | index = AvmCore::readU32(pos); |
547 | // Note that AbcParser ensures that the Multiname we're parsing can't |
548 | // be a CONSTANT_TypeName, thus the recursion here can't be more |
549 | // than a single level deep. |
550 | parseMultiname(_abcStart + cpool_mn_offsets[index], m); |
551 | index = AvmCore::readU32(pos); |
Value stored to 'index' is never read | |
552 | AvmAssert(index==1)do { } while (0); |
553 | m.setTypeParameter(AvmCore::readU32(pos)); |
554 | break; |
555 | } |
556 | |
557 | default: |
558 | AvmAssert(false)do { } while (0); |
559 | } |
560 | |
561 | return; |
562 | } |
563 | |
564 | void PoolObject::resolveBindingNameNoCheck(uint32_t index, Multiname &m, const Toplevel* toplevel) const |
565 | { |
566 | // FIXME: should only assert and not throw, pending correctness verification, see bug https://bugzilla.mozilla.org/show_bug.cgi?id=557541 |
567 | |
568 | if (index == 0 || index >= cpool_mn_offsets.length()) |
569 | { |
570 | if (toplevel) |
571 | toplevel->throwVerifyError(kCpoolIndexRangeError, core->toErrorString(index), core->toErrorString(cpool_mn_offsets.length())); |
572 | AvmAssert(!"unhandled verify error")do { } while (0); |
573 | } |
574 | |
575 | parseMultiname(m, index); |
576 | |
577 | if (!(m.isBinding() && (m.isQName() || isBuiltin))) |
578 | { |
579 | if (toplevel) |
580 | toplevel->throwVerifyError(kCpoolEntryWrongTypeError, core->toErrorString(index)); |
581 | AvmAssert(!"unhandled verify error")do { } while (0); |
582 | } |
583 | } |
584 | |
585 | Traits* PoolObject::resolveTypeName(uint32_t index, const Toplevel* toplevel, boolbool allowVoid/*=false*/) |
586 | { |
587 | // only save the type name for now. verifier will resolve to traits |
588 | if (index == 0) |
589 | { |
590 | return NULL__null; |
591 | } |
592 | |
593 | // check contents is a multiname. in the cpool, and type system, kObjectType means multiname. |
594 | if (index >= cpool_mn_offsets.length()) |
595 | { |
596 | if (toplevel) |
597 | toplevel->throwVerifyError(kCpoolIndexRangeError, core->toErrorString(index), core->toErrorString(cpool_mn_offsets.length())); |
598 | AvmAssert(!"unhandled verify error")do { } while (0); |
599 | } |
600 | |
601 | Multiname m; |
602 | parseMultiname(m, index); |
603 | |
604 | Traits* t = core->domainMgr()->findTraitsInPoolByMultiname(this, m); |
605 | if (t == (Traits*)BIND_AMBIGUOUS) |
606 | { |
607 | if (toplevel) |
608 | toplevel->throwReferenceError(kAmbiguousBindingError, m); |
609 | AvmAssert(!"unhandled verify error")do { } while (0); |
610 | } |
611 | if(m.isParameterizedType()) |
612 | { |
613 | core->stackCheck(const_cast<Toplevel*>(toplevel)); |
614 | Traits* param_traits = resolveTypeName(m.getTypeParameter(), toplevel); |
615 | t = resolveParameterizedType(toplevel, t, param_traits); |
616 | } |
617 | if (!t) |
618 | { |
619 | #ifdef AVMPLUS_VERBOSE |
620 | if (!toplevel || !toplevel->verifyErrorClass()) |
621 | core->console << "class not found: " << m << " index=" << (uint32_t)index << "\n"; |
622 | #endif |
623 | if (toplevel) |
624 | toplevel->throwVerifyError(kClassNotFoundError, core->toErrorString(&m)); |
625 | AvmAssert(!"unhandled verify error")do { } while (0); |
626 | } |
627 | if (!allowVoid && t == VOID_TYPE(core->traits.void_itraits)) |
628 | { |
629 | if (toplevel) |
630 | toplevel->throwVerifyError(kIllegalVoidError); |
631 | AvmAssert(!"unhandled verify error")do { } while (0); |
632 | } |
633 | |
634 | return t; |
635 | } |
636 | |
637 | Traits* PoolObject::resolveParameterizedType(const Toplevel* toplevel, Traits* base, Traits* param_traits) const |
638 | { |
639 | Traits* r = NULL__null; |
640 | if (base == core->traits.vector_itraits) |
641 | { |
642 | // Only vector is parameterizable for now... |
643 | switch (Traits::getBuiltinType(param_traits)) |
644 | { |
645 | case BUILTIN_any: |
646 | r = core->traits.vectorobj_itraits; |
647 | break; |
648 | case BUILTIN_int: |
649 | r = core->traits.vectorint_itraits; |
650 | break; |
651 | case BUILTIN_uint: |
652 | r = core->traits.vectoruint_itraits; |
653 | break; |
654 | case BUILTIN_number: |
655 | r = core->traits.vectordouble_itraits; |
656 | break; |
657 | default: |
658 | { |
659 | PoolObject* pool = param_traits->pool; |
660 | Stringp fullname = VectorClass::makeVectorClassName(core, param_traits); |
661 | r = core->domainMgr()->findTraitsInPoolByNameAndNS(pool, fullname, base->ns()); |
662 | if (!r) |
663 | { |
664 | r = core->traits.vectorobj_itraits->newParameterizedITraits(fullname, base->ns()); |
665 | r->verifyBindings(toplevel); |
666 | core->domainMgr()->addNamedTraits(pool, fullname, base->ns(), r); |
667 | } |
668 | break; |
669 | } |
670 | } |
671 | } |
672 | return r; |
673 | } |
674 | |
675 | // search metadata record at meta_pos for name, return true if present |
676 | boolbool PoolObject::hasMetadataName(const uint8_t* meta_pos, const String* name) |
677 | { |
678 | AvmAssert(meta_pos && name->isInterned())do { } while (0); |
679 | uint32_t metadata_count = AvmCore::readU32(meta_pos); |
680 | for (uint32_t i=0; i < metadata_count; i++) { |
681 | uint32_t metadata_index = AvmCore::readU32(meta_pos); |
682 | const uint8_t* metadata_pos = getMetadataInfoPos(metadata_index); |
683 | if (metadata_pos) { |
684 | uint32_t name_index = AvmCore::readU32(metadata_pos); |
685 | AvmCore::skipU32(metadata_pos, 1); // skip val_count |
686 | if (name_index > 0 && name_index < constantStringCount && |
687 | getString(name_index) == name) |
688 | return truetrue; |
689 | } |
690 | } |
691 | return falsefalse; |
692 | } |
693 | |
694 | void PoolObject::initPrecomputedMultinames() |
695 | { |
696 | if (precompNames == NULL__null) |
697 | { |
698 | MMgc::GC* gc = core->GetGC(); |
699 | uint32_t nNames = cpool_mn_offsets.length(); |
700 | precompNames = ExactStructContainer<HeapMultiname>::create(gc, destroyPrecomputedMultinames, nNames); |
701 | for (uint32_t i=1; i < nNames; i++) { |
702 | Multiname mn; |
703 | parseMultiname(mn, i); |
704 | precompNames->get(i).setMultiname(gc, precompNames, mn); |
705 | } |
706 | } |
707 | } |
708 | |
709 | void PoolObject::destroyPrecomputedMultinames(ExactStructContainer<HeapMultiname>* self) |
710 | { |
711 | // Destroy each HeapMultiname to properly decrement reference counts on |
712 | // RC'd parts of HeapMultiname as soon as possible. |
713 | MMgc::GC* gc = MMgc::GC::GetGC(self); |
714 | Multiname mn; |
715 | uint32_t nNames = self->capacity(); |
716 | for (uint32_t i=1; i < nNames; i++) |
717 | self->get(i).setMultiname(gc, self, mn); |
718 | } |
719 | |
720 | Stringp PoolObject::getMethodInfoName(uint32_t i) |
721 | { |
722 | Stringp name = NULL__null; |
723 | if (core->config.methodNames && (uint32_t(i) < uint32_t(this->_method_name_indices.length()))) |
724 | { |
725 | const int32_t index = this->_method_name_indices[i]; |
726 | if (index >= 0) |
727 | { |
728 | if (hasString(index)) |
729 | name = this->getString(index); |
730 | } |
731 | else |
732 | { |
733 | // Precomputed multinames may not be inited yet, but we'll need them eventually, |
734 | // so go ahead and init them now |
735 | this->initPrecomputedMultinames(); |
736 | const Multiname& mn = precompNames->get(-index); |
737 | StringBuffer sb(core); |
738 | sb << Multiname::Format(&mn); |
739 | name = sb.toString(); |
740 | } |
741 | } |
742 | return name; |
743 | } |
744 | } |