Bug Summary

File:platform/mac/avmshell/../../../core/Traits.cpp
Location:line 614, column 9
Description:Value stored to 'nextSlotOffset' is never read

Annotated Source Code

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) 1993-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
43namespace avmplus
44{
45 using namespace MMgc;
46
47 // -------------------------------------------------------------------
48 // -------------------------------------------------------------------
49 // -------------------------------------------------------------------
50 // -------------------------------------------------------------------
51
52 /*static*/ TraitsBindings* TraitsBindings::alloc(GC* gc,
53 Traits* _owner,
54 TraitsBindingsp _base,
55 MultinameBindingHashtable* _bindings,
56 uint32_t slotCount,
57 uint32_t methodCount,
58 boolbool typesValid)
59 {
60 const uint32_t extra = typesValid ?
61 slotCount * sizeof(SlotInfo) + methodCount * sizeof(MethodInfo) :
62 0;
63
64 TraitsBindings* tb = new (gc, MMgc::kExact, extra) TraitsBindings(_owner, _base, _bindings, slotCount, methodCount, typesValid);
65 if (_base && typesValid)
66 {
67 if (_base->slotCount)
68 {
69 const SlotInfo* src = &_base->getSlots()[0];
70 SlotInfo* dst = &tb->getSlots()[0];
71 VMPI_memcpy::memcpy(dst, src, _base->slotCount * sizeof(SlotInfo));
72 AvmAssert(((_owner->isMachineType()) || (tb->owner->m_sizeofInstance >= _base->owner->m_sizeofInstance)))do { } while (0);
73 }
74 if (_base->methodCount)
75 VMPI_memcpy::memcpy(&tb->getMethods()[0], &_base->getMethods()[0], _base->methodCount * sizeof(MethodInfo));
76 }
77 return tb;
78 }
79
80 void TraitsBindings::gcTraceHook_TraitsBindings(MMgc::GC* gc)
81 {
82 if (m_typesValid)
83 {
84 SlotInfo* slots = getSlots();
85 for ( uint32_t i=0 ; i < slotCount ; i++ )
86 gc->TraceLocation(&slots[i].type);
87 TraitsBindings::BindingMethodInfo* methods = getMethods();
88 for ( uint32_t i=0 ; i < methodCount ; i++ )
89 gc->TraceLocation(&methods[i].f);
90 }
91 }
92
93 Binding TraitsBindings::findBinding(Stringp name) const
94 {
95 for (TraitsBindingsp self = this; self; self = self->base)
96 {
97 const Binding b = self->m_bindings->getName(name);
98 if (b != BIND_NONE)
99 return b;
100 }
101 return BIND_NONE;
102 }
103
104 Binding TraitsBindings::findBinding(Stringp name, Namespacep ns) const
105 {
106 for (TraitsBindingsp self = this; self; self = self->base)
107 {
108 const Binding b = self->m_bindings->get(name, ns);
109 if (b != BIND_NONE)
110 return b;
111 }
112 return BIND_NONE;
113 }
114
115 Binding TraitsBindings::findBinding(Stringp name, NamespaceSetp nsset) const
116 {
117 for (TraitsBindingsp self = this; self; self = self->base)
118 {
119 const Binding b = self->m_bindings->get(name, nsset);
120 if (b != BIND_NONE)
121 return b;
122 }
123 return BIND_NONE;
124 }
125
126 Binding TraitsBindings::findBindingAndDeclarer(const Multiname& mn, Traitsp& declarer) const
127 {
128 if (mn.isBinding())
129 {
130 for (TraitsBindingsp self = this; self; self = self->base)
131 {
132 Namespacep foundns = NULL__null;
133 Binding const b = self->m_bindings->getMulti(mn, foundns);
134 if (b != BIND_NONE)
135 {
136 declarer = self->owner;
137
138 // if the member is 'protected' then we have to do extra work,
139 // as we may have found it in a descendant's protected namespace --
140 // we have to bounce up the inheritance chain and check our parent's
141 // protected namespace.
142 while (foundns == declarer->protectedNamespace)
143 {
144 Traitsp declParent = declarer->base;
145 if (!declParent || declParent->protectedNamespace == NULL__null)
146 break;
147
148 Binding const bp = declParent->getTraitsBindings()->findBinding(mn.getName(), declParent->protectedNamespace);
149 if (bp != b)
150 break;
151
152 // self->owner->core->console<<"bounce "<<declarer<<" to "<<declParent<<"\n";
153 declarer = declParent;
154 foundns = declParent->protectedNamespace;
155 }
156
157 // self->owner->core->console<<"final declarer is "<<declarer<<"\n";
158 return b;
159 }
160 }
161 }
162 declarer = NULL__null;
163 return BIND_NONE;
164 }
165
166 void TraitsBindings::buildSlotDestroyInfo(MMgc::GC* gc, FixedBitSet& slotDestroyInfo, uint32_t slotAreaCount, uint32_t slotAreaSize) const
167 {
168 MMGC_STATIC_ASSERT(kUnusedAtomTag == 0 && kObjectType == 1 && kStringType == 2 && kNamespaceType == 3)typedef ::MMgc::static_assert_MMgc<sizeof (::MMgc::STATIC_ASSERTION_FAILED
<(bool)(kUnusedAtomTag == 0 && kObjectType == 1 &&
kStringType == 2 && kNamespaceType == 3)>)> MMgc_static_assert_line_168
;
169 AvmAssert(slotAreaCount <= slotCount)do { } while (0);
170
171 // not the same as slotCount since a slot of type double
172 // takes two bits (in 32-bit builds). note that the bits are
173 // always 4-byte chunks even in 64-bit builds!
174 const uint32_t bitsNeeded = slotAreaSize / sizeof(uint32_t); // not sizeof(Atom)!
175 AvmAssert(bitsNeeded * sizeof(uint32_t) == slotAreaSize)do { } while (0); // should be even multiple!
176 // allocate one extra bit and use it for "all-zero"
177 slotDestroyInfo.resize(gc, bitsNeeded+1);
178 if (slotAreaSize > 0)
179 {
180 const uint32_t sizeofInstance = this->owner->getSizeOfInstance();
181 const TraitsBindings::SlotInfo* tbs = getSlots() + (slotCount - slotAreaCount);
182 const TraitsBindings::SlotInfo* tbs_end = tbs + slotAreaCount;
183 for ( ; tbs < tbs_end; ++tbs)
184 {
185 // offset is pointed off the end of our object
186 if (isAtomOrRCObjectSlot(tbs->sst()))
187 {
188 //owner->core->console<<"SDI "<<owner<<" "<<sizeofInstance<<" "<<tbs->type<<" "<<tbs->offset()<<"\n";
189 AvmAssert(tbs->offset() >= sizeofInstance)do { } while (0);
190 const uint32_t off = tbs->offset() - sizeofInstance;
191 AvmAssert((off % 4) == 0)do { } while (0);
192 // if slot is "big" then this is the bit of the first 4 bytes. that's fine.
193 slotDestroyInfo.set((off>>2)+1); // +1 to leave room for bit 0
194 slotDestroyInfo.set(0); // bit 0 is "anyset" flag
195 }
196 // otherwise leave the bit zero
197 }
198 }
199 else
200 {
201 AvmAssert(slotAreaCount == 0)do { } while (0);
202 AvmAssert(bitsNeeded == 0)do { } while (0);
203 }
204
205 // if nothing set, blow away what we built and realloc as single clear bit -- smaller and faster
206 if (!slotDestroyInfo.test(0))
207 {
208 slotDestroyInfo.resize(gc, 1);
209 AvmAssert(!slotDestroyInfo.test(0))do { } while (0);
210 }
211 }
212
213 boolbool TraitsBindings::checkOverride(AvmCore* core, MethodInfo* virt, MethodInfo* over) const
214 {
215 if (over == virt)
216 return truetrue;
217
218 MethodSignaturep overms = over->getMethodSignature();
219 MethodSignaturep virtms = virt->getMethodSignature();
220
221 Traits* overTraits = overms->returnTraits();
222 Traits* virtTraits = virtms->returnTraits();
223
224 if (overTraits != virtTraits)
225 {
226#ifdef AVMPLUS_VERBOSE
227 core->console << "\n";
228 core->console << "return types dont match\n";
229 core->console << " virt " << virtTraits << " " << virt << "\n";
230 core->console << " over " << overTraits << " " << over << "\n";
231#endif
232 return falsefalse;
233 }
234
235 if (overms->param_count() != virtms->param_count() ||
236 overms->optional_count() != virtms->optional_count())
237 {
238#ifdef AVMPLUS_VERBOSE
239 core->console << "\n";
240 core->console << "param count mismatch\n";
241 core->console << " virt params=" << virtms->param_count() << " optional=" << virtms->optional_count() << " " << virt << "\n";
242 core->console << " over params=" << overms->param_count() << " optional=" << overms->optional_count() << " " << virt << "\n";
243#endif
244 return falsefalse;
245 }
246
247 // allow subclass param 0 to implement or extend base param 0
248 virtTraits = virtms->paramTraits(0);
249 if (!owner->subtypeof(virtTraits) || !Traits::isMachineCompatible(this->owner, virtTraits))
250 {
251 if (!this->owner->isMachineType() && virtTraits == core->traits.object_itraits)
252 {
253 over->setUnboxThis();
254 }
255 else
256 {
257 #ifdef AVMPLUS_VERBOSE
258 core->console << "\n";
259 core->console << "param 0 incompatible\n";
260 core->console << " virt " << virtTraits << " " << virt << "\n";
261 core->console << " over " << this->owner << " " << over << "\n";
262 #endif
263 return falsefalse;
264 }
265 }
266
267 for (int k=1, p=overms->param_count(); k <= p; k++)
268 {
269 overTraits = overms->paramTraits(k);
270 virtTraits = virtms->paramTraits(k);
271 if (overTraits != virtTraits)
272 {
273 #ifdef AVMPLUS_VERBOSE
274 core->console << "\n";
275 core->console << "param " << k << " incompatible\n";
276 core->console << " virt " << virtTraits << " " << virt << "\n";
277 core->console << " over " << overTraits << " " << over << "\n";
278 #endif
279 return falsefalse;
280 }
281 }
282
283 if (virt->unboxThis())
284 {
285 // the _unboxThis flag is sticky, all the way down the inheritance tree
286 over->setUnboxThis();
287 }
288
289 return truetrue;
290 }
291
292 static boolbool isCompatibleOverrideKind(BindingKind baseKind, BindingKind overKind)
293 {
294 static const uint8_t kCompatibleBindingKinds[8] =
295 {
296 0, // BKIND_NONE
297 (1<<BKIND_METHOD), // BKIND_METHOD
298 0, // BKIND_VAR
299 0, // BKIND_CONST
300 0, // unused
301 (1<<BKIND_GET) | (1<<BKIND_SET) | (1<<BKIND_GETSET), // BKIND_GET
302 (1<<BKIND_GET) | (1<<BKIND_SET) | (1<<BKIND_GETSET), // BKIND_SET
303 (1<<BKIND_GET) | (1<<BKIND_SET) | (1<<BKIND_GETSET) // BKIND_GETSET
304 };
305 return (kCompatibleBindingKinds[baseKind] & (1<<overKind)) != 0;
306 }
307
308 boolbool TraitsBindings::checkLegalInterfaces(AvmCore* core) const
309 {
310 // make sure every interface method is implemented
311 for (InterfaceIterator ifc_iter(this); ifc_iter.hasNext();)
312 {
313 Traits* ifc = ifc_iter.next();
314
315 // don't need to bother checking interfaces in our parent.
316 if (this->base && this->base->owner->subtypeof(ifc))
317 continue;
318
319 TraitsBindingsp ifcd = ifc->getTraitsBindings();
320 StTraitsBindingsIterator iter(ifcd);
321 while (iter.next())
322 {
323 Stringp name = iter.key();
324 if (!name) continue;
325 Namespacep ns = iter.ns();
326 Binding iBinding = iter.value();
327 const BindingKind iBindingKind = AvmCore::bindingKind(iBinding);
328
329 Binding cBinding = this->findBinding(name, ns);
330 if (!isCompatibleOverrideKind(iBindingKind, AvmCore::bindingKind(cBinding)))
331 {
332 // Try again with public namespace that matches the version of the current traits
333 const Binding pBinding = this->findBinding(name, core->getPublicNamespace(owner->pool));
334 if (isCompatibleOverrideKind(iBindingKind, AvmCore::bindingKind(pBinding)))
335 cBinding = pBinding;
336 }
337
338 if (iBinding == cBinding)
339 continue;
340
341 if (!isCompatibleOverrideKind(iBindingKind, AvmCore::bindingKind(cBinding)))
342 return falsefalse;
343
344 switch (iBindingKind)
345 {
346 default:
347 {
348 AvmAssert(0)do { } while (0); // interfaces shouldn't have anything but methods, getters, and setters
349 return falsefalse;
350 }
351 case BKIND_METHOD:
352 {
353 MethodInfo* virt = ifcd->getMethods()[AvmCore::bindingToMethodId(iBinding)].f;
354 MethodInfo* over = this->getMethods()[AvmCore::bindingToMethodId(cBinding)].f;
355 if (!checkOverride(core, virt, over))
356 return falsefalse;
357 break;
358 }
359 case BKIND_GET:
360 case BKIND_SET:
361 case BKIND_GETSET:
362 {
363 // check getter & setter overrides
364 if (AvmCore::hasGetterBinding(iBinding))
365 {
366 if (!AvmCore::hasGetterBinding(cBinding))
367 return falsefalse;
368
369 MethodInfo* virt = ifcd->getMethods()[AvmCore::bindingToGetterId(iBinding)].f;
370 MethodInfo* over = this->getMethods()[AvmCore::bindingToGetterId(cBinding)].f;
371 if (!checkOverride(core, virt, over))
372 return falsefalse;
373 }
374
375 if (AvmCore::hasSetterBinding(iBinding))
376 {
377 if (!AvmCore::hasSetterBinding(cBinding))
378 return falsefalse;
379
380 MethodInfo* virt = ifcd->getMethod(AvmCore::bindingToSetterId(iBinding));
381 MethodInfo* over = this->getMethod(AvmCore::bindingToSetterId(cBinding));
382 if (!checkOverride(core, virt, over))
383 return falsefalse;
384 }
385 }
386 break;
387 } // switch
388 } // for j
389 } // for tbi
390 return truetrue;
391 }
392
393 void TraitsBindings::fixOneInterfaceBindings(Traitsp ifc)
394 {
395 AvmAssert(!owner->isInterface())do { } while (0);
396
397 TraitsBindingsp ifcd = ifc->getTraitsBindings();
398 StTraitsBindingsIterator iter(ifcd);
399 while (iter.next())
400 {
401 Stringp name = iter.key();
402 if (!name) continue;
403 Namespacep ns = iter.ns();
404 Binding iBinding = iter.value();
405 const BindingKind iBindingKind = AvmCore::bindingKind(iBinding);
406 const Binding cBinding = this->findBinding(name, ns);
407 if (!isCompatibleOverrideKind(iBindingKind, AvmCore::bindingKind(cBinding)))
408 {
409 // Try again with public namespace that matches the version of the current traits
410 const Binding pBinding = this->findBinding(name, ifc->core->getPublicNamespace(owner->pool));
411 if (isCompatibleOverrideKind(iBindingKind, AvmCore::bindingKind(pBinding)))
412 {
413 this->m_bindings->add(name, ns, pBinding);
414 }
415 }
416 }
417 }
418
419 void Traits::addVersionedBindings(MultinameBindingHashtable* bindings,
420 Stringp name,
421 NamespaceSetp nss,
422 Binding binding) const
423 {
424 // find the lowest version within the active series.
425 ApiVersion apiVersion = kApiVersion_VM_INTERNAL;
426 for (NamespaceSetIterator iter(nss); iter.hasNext();)
427 {
428 Namespacep ns = iter.next();
429 ApiVersion a = core->getValidApiVersion(ns->getApiVersion());
430 if (a < apiVersion)
431 apiVersion = a;
432 }
433 Namespacep ns = core->getVersionedNamespace(nss->nsAt(0), apiVersion);
434 bindings->add(name, ns, binding);
435 }
436
437 // -------------------------------------------------------------------
438 // -------------------------------------------------------------------
439
440 TraitsMetadata::MetadataPtr TraitsMetadata::getSlotMetadataPos(uint32_t i, PoolObject*& residingPool) const
441 {
442 AvmAssert(i < slotCount)do { } while (0);
443 residingPool = NULL__null;
444 for (TraitsMetadatap self = this; self && (i < self->slotCount); self = self->base)
445 {
446 MetadataPtr pos = self->slotMetadataPos[i];
447 if (pos)
448 {
449 residingPool = self->residingPool;
450 return pos;
451 }
452 }
453 return NULL__null;
454 }
455
456 TraitsMetadata::MetadataPtr TraitsMetadata::getMethodMetadataPos(uint32_t i, PoolObject*& residingPool) const
457 {
458 AvmAssert(i < methodCount)do { } while (0);
459 residingPool = NULL__null;
460 for (TraitsMetadatap self = this; self && (i < self->methodCount); self = self->base)
461 {
462 MetadataPtr pos = self->methodMetadataPos[i];
463 if (pos)
464 {
465 residingPool = self->residingPool;
466 return pos;
467 }
468 }
469 return NULL__null;
470 }
471
472 // -------------------------------------------------------------------
473 // -------------------------------------------------------------------
474
475 Traits::Traits(PoolObject* _pool,
476 Traits* _base,
477 uint16_t _sizeofInstance,
478 uint16_t _offsetofSlots,
479 TraitsPosPtr traitsPos,
480 TraitsPosType posType)
481 : core(_pool->core)
482 , base(_base)
483 , pool(_pool)
484 , m_traitsPos(traitsPos)
485 , m_tbref(_pool->core->GetGC()->emptyWeakRef)
486 , m_tmref(_pool->core->GetGC()->emptyWeakRef)
487 , m_sizeofInstance(_sizeofInstance)
488 , m_offsetofSlots(_offsetofSlots)
489 , builtinType(BUILTIN_none)
490 , m_posType(uint8_t(posType))
491 // Assume builtins initialize this correctly. This is verified
492 // by checkCustomConstruct() in MethodEnv.cpp.
493 , hasCustomConstruct(0)
494#ifdef VMCFG_AOT
495 , m_interfaceBindingFunction(NULL__null)
496#endif
497 {
498 AvmAssert(m_tbref->isNull())do { } while (0);
499 AvmAssert(m_tmref->isNull())do { } while (0);
500 AvmAssert(BUILTIN_COUNT <= 32)do { } while (0);
501 AvmAssert(m_slotDestroyInfo.allocatedSize() == 0)do { } while (0);
502#ifdef _DEBUG
503 switch (posType)
504 {
505 case TRAITSTYPE_NVA:
506 case TRAITSTYPE_RT:
507 AvmAssert(m_traitsPos == 0)do { } while (0);
508 break;
509 default:
510 AvmAssert(m_traitsPos != 0)do { } while (0);
511 break;
512 }
513#endif
514 build_primary_supertypes();
515 build_secondary_supertypes();
516 }
517
518 /*static*/ Traits* Traits::newTraits(PoolObject* pool,
519 Traits *base,
520 uint16_t objectSize,
521 uint16_t offsetOfSlots,
522 TraitsPosPtr traitsPos,
523 TraitsPosType posType)
524 {
525 AvmAssert(posType != TRAITSTYPE_CATCH)do { } while (0);
526 AvmAssert(pool != NULL)do { } while (0);
527 Traits* traits = new (pool->core->GetGC(), MMgc::kExact) Traits(pool, base, objectSize, offsetOfSlots, traitsPos, posType);
528 return traits;
529 }
530
531 /*static*/ Traits* Traits::newCatchTraits(const Toplevel* toplevel, PoolObject* pool, TraitsPosPtr traitsPos, Stringp name, Namespacep ns)
532 {
533 AvmAssert(pool != NULL)do { } while (0);
534 Traits* traits = new (pool->core->GetGC(), MMgc::kExact) Traits(pool, NULL__null, sizeof(ScriptObject), sizeof(ScriptObject), traitsPos, TRAITSTYPE_CATCH);
535 traits->final = truetrue;
536 traits->set_names(ns, name);
537 traits->verifyBindings(toplevel);
538 traits->resolveSignatures(toplevel);
539 return traits;
540 }
541
542 Traits* Traits::_newParameterizedTraits(Stringp name, Namespacep ns, Traits* _base)
543 {
544 Traits* newtraits = Traits::newTraits(this->pool, _base, this->getSizeOfInstance(), this->m_offsetofSlots, NULL__null, TRAITSTYPE_RT);
545 newtraits->m_needsHashtable = this->m_needsHashtable;
546 newtraits->set_names(ns, name);
547 return newtraits;
548 }
549
550 TraitsPosPtr Traits::traitsPosStart() const
551 {
552 TraitsPosPtr pos = m_traitsPos;
553 switch (posType())
554 {
555 case TRAITSTYPE_INTERFACE:
556 case TRAITSTYPE_INSTANCE:
557 pos = skipToInstanceInitPos(pos);
558 // fall thru, no break
559
560 case TRAITSTYPE_CLASS:
561 case TRAITSTYPE_SCRIPT:
562 AvmCore::skipU32(pos, 1); // skip in init_index
563 break;
564
565 case TRAITSTYPE_ACTIVATION:
566 // nothing to do
567 break;
568
569 case TRAITSTYPE_CATCH:
570 case TRAITSTYPE_NVA:
571 case TRAITSTYPE_RT:
572 pos = NULL__null;
573 break;
574 }
575 return pos;
576 }
577
578 TraitsPosPtr Traits::skipToInstanceInitPos(TraitsPosPtr pos) const
579 {
580 AvmAssert(isInstanceType() && pos != NULL)do { } while (0);
581 AvmCore::skipU32(pos, 2); // skip the QName & base traits
582 const uint8_t theflags = *pos++;
583 const boolbool hasProtected = (theflags & 8) != 0;
584 if (hasProtected)
585 {
586 AvmCore::skipU32(pos);
587 }
588 const uint32_t interfaceCount = AvmCore::readU32(pos);
589 AvmCore::skipU32(pos, interfaceCount);
590 return pos;
591 }
592
593 static boolbool is8ByteSlot(Traits* slotTE)
594 {
595 #ifdef AVMPLUS_64BIT
596 const uint32_t BIG_TYPE_MASK = ~((1U<<BUILTIN_int) | (1U<<BUILTIN_uint) | (1U<<BUILTIN_boolean));
597 #else
598 const uint32_t BIG_TYPE_MASK = (1U<<BUILTIN_number);
599 #endif
600
601 return ((1 << Traits::getBuiltinType(slotTE)) & BIG_TYPE_MASK) != 0;
602 }
603
604 // Sun compilers don't allow static and REALLY_INLINE
605 /*static*/ REALLY_INLINEinline __attribute__((always_inline)) int32_t pad8(int32_t nextSlotOffset)
606 {
607 // 8-aligned, 8-byte field
608 if (nextSlotOffset & 7)
609 {
610 AvmAssert((nextSlotOffset % 4) == 0)do { } while (0); // should always be a multiple of 4
611 nextSlotOffset += 4;
612 }
613 int32_t slotOffset = nextSlotOffset;
614 nextSlotOffset += 8;
Value stored to 'nextSlotOffset' is never read
615 return slotOffset;
616 }
617
618 SlotStorageType valueStorageType(BuiltinType bt)
619 {
620 switch (bt)
621 {
622 case BUILTIN_int: return SST_int32;
623 case BUILTIN_uint: return SST_uint32;
624 case BUILTIN_number: return SST_double;
625 case BUILTIN_boolean: return SST_bool32;
626 case BUILTIN_void: return SST_atom;
627 case BUILTIN_any: return SST_atom;
628 case BUILTIN_object: return SST_atom;
629 case BUILTIN_string: return SST_string;
630 case BUILTIN_namespace: return SST_namespace;
631 default: return SST_scriptobject;
632 }
633 }
634
635 REALLY_INLINEinline __attribute__((always_inline)) SlotStorageType slotStorageType(BuiltinType bt)
636 {
637 AvmAssert(bt != BUILTIN_void)do { } while (0); // actual slots cannot be type void.
638 return valueStorageType(bt);
639 }
640
641 // Sun compilers don't allow static and REALLY_INLINE
642 /*static*/ REALLY_INLINEinline __attribute__((always_inline)) boolbool isPointerSlot(Traits* slotTE)
643 {
644 BuiltinType bt = Traits::getBuiltinType(slotTE);
645 AvmAssert(bt != BUILTIN_void)do { } while (0);
646
647 MMGC_STATIC_ASSERT(BUILTIN_COUNT < (sizeof(int) * 8))typedef ::MMgc::static_assert_MMgc<sizeof (::MMgc::STATIC_ASSERTION_FAILED
<(bool)(BUILTIN_COUNT < (sizeof(int) * 8))>)> MMgc_static_assert_line_647
;
648 int const IS_POINTER = ~((1<<BUILTIN_int)|(1<<BUILTIN_uint)|(1<<BUILTIN_number)|(1<<BUILTIN_boolean));
649
650 return ((1 << bt) & IS_POINTER) != 0;
651 }
652
653 // the logic for assigning slot id's is used in several places, so it's now collapsed here
654 // rather than redundantly sprinkled thru several bits of code.
655 class SlotIdCalcer
656 {
657 private:
658 uint32_t m_slotCount;
659 boolbool m_earlySlotBinding;
660 public:
661 SlotIdCalcer(uint32_t _baseSlotCount, boolbool _earlySlotBinding) :
662 m_slotCount(_baseSlotCount),
663 m_earlySlotBinding(_earlySlotBinding)
664 {
665 }
666
667 uint32_t calc_id(uint32_t id)
668 {
669 if (!id || !m_earlySlotBinding)
670 {
671 id = ++m_slotCount;
672 }
673 if (m_slotCount < id)
674 m_slotCount = id;
675 return id - 1;
676 }
677
678 uint32_t slotCount() const { return m_slotCount; }
679 boolbool earlySlotBinding() const { return m_earlySlotBinding; }
680 };
681
682 struct NameEntry
683 {
684 const uint8_t* meta_pos;
685 uint32_t qni, id, info, value_index;
686 CPoolKind value_kind;
687 TraitKind kind;
688 uint8_t tag;
689
690 void readNameEntry(const uint8_t*& pos);
691 };
692
693 void NameEntry::readNameEntry(const uint8_t*& pos)
694 {
695 qni = AvmCore::readU32(pos);
696 tag = *pos++;
697 kind = (TraitKind) (tag & 0x0f);
698 value_kind = CONSTANT_unused_0x00;
699 value_index = 0;
700
701 // Read in the trait entry.
702 switch (kind)
703 {
704 case TRAIT_Slot:
705 case TRAIT_Const:
706 id = AvmCore::readU32(pos); // slot id
707 info = AvmCore::readU32(pos); // value type
708 value_index = AvmCore::readU32(pos); // value index
709 if (value_index)
710 value_kind = (CPoolKind)*pos++; // value kind
711 break;
712 case TRAIT_Class:
713 id = AvmCore::readU32(pos); // slot id
714 info = AvmCore::readU32(pos); // classinfo
715 break;
716 case TRAIT_Getter:
717 case TRAIT_Setter:
718 case TRAIT_Method:
719 AvmCore::skipU32(pos); // disp id (never used)
720 id = AvmCore::readU32(pos); // method index
721 info = 0;
722 break;
723 default:
724 // unsupported traits type -- can't happen, caught in AbcParser::parseTraits
725 AvmAssert(0)do { } while (0);
726 break;
727 }
728 meta_pos = pos;
729 if (tag & ATTR_metadata)
730 {
731 uint32_t metaCount = AvmCore::readU32(pos);
732 AvmCore::skipU32(pos, metaCount);
733 }
734 }
735
736 boolbool Traits::allowEarlyBinding() const
737 {
738 // the compiler can early bind to a type's slots when it's defined
739 // or when the base class came from another abc file and has zero slots
740 // this ensures you cant use the early opcodes to access an external type's
741 // private members.
742 TraitsBindingsp tb = this->base ? this->base->getTraitsBindings() : NULL__null;
743 while (tb != NULL__null && tb->slotCount > 0)
744 {
745 if (tb->owner->pool != this->pool && tb->slotCount > 0)
746 {
747 return falsefalse;
748 }
749 tb = tb->base;
750 }
751 return truetrue;
752 }
753
754 void Traits::buildBindings(TraitsBindingsp basetb,
755 MultinameBindingHashtable* bindings,
756 uint32_t& slotCount,
757 uint32_t& methodCount,
758 SlotSizeInfo* slotSizeInfo,
759 const Toplevel* toplevel) const
760 {
761 const uint8_t* pos = traitsPosStart();
762
763 const uint32_t baseSlotCount = basetb ? basetb->slotCount : 0;
764 const uint32_t baseMethodCount = basetb ? basetb->methodCount : 0;
765
766 //slotCount = baseSlotCount;
767 methodCount = baseMethodCount;
768
769 SlotIdCalcer sic(baseSlotCount, this->allowEarlyBinding());
770
771#ifdef _DEBUG
772 uint32_t pointerSlots = 0;
773#endif
774
775 NameEntry ne;
776 const uint32_t nameCount = pos ? AvmCore::readU32(pos) : 0;
777 for (uint32_t i = 0; i < nameCount; i++)
778 {
779 ne.readNameEntry(pos);
780 Multiname mn;
781 this->pool->resolveBindingNameNoCheck(ne.qni, mn, toplevel);
782 Stringp name = mn.getName();
783 Namespacep ns;
784 NamespaceSetp compat_nss;
785 if (mn.namespaceCount() > 1) {
786 ns = mn.getNsset()->nsAt(0);
787 compat_nss = mn.getNsset();
788 }
789 else {
790 ns = mn.getNamespace();
791 compat_nss = NamespaceSet::create(core->GetGC(), ns);
792 }
793
794 switch (ne.kind)
795 {
796 case TRAIT_Slot:
797 case TRAIT_Const:
798 case TRAIT_Class:
799 {
800 uint32_t slot_id = sic.calc_id(ne.id);
801 if (toplevel)
802 {
803 AvmAssert(!this->m_resolved)do { } while (0);
804
805 // when we resolve, we must do some additional verification checks... these were formerly
806 // done in AbcParser::parseTraits but require the base class to be resolved first, so we
807 // now defer it to here.
808
809 // illegal raw slot id -- reject IF we are early binding. (theoretically it's always illegal,
810 // but won't cause any problems if earlySlotBinding=false, and rejecting in this case
811 // will break existing content.)
812 if (ne.id > nameCount && sic.earlySlotBinding())
813 toplevel->throwVerifyError(kCorruptABCError);
814
815 // slots are final.
816 if (basetb && slot_id < basetb->slotCount)
817 toplevel->throwVerifyError(kIllegalOverrideError, core->toErrorString(mn), core->toErrorString(base));
818
819 // a slot cannot override anything else.
820 if (bindings->get(name, ns) != BIND_NONE)
821 toplevel->throwVerifyError(kCorruptABCError);
822
823 // In theory we should reject duplicate slots here;
824 // in practice we don't, as it causes problems with some existing content
825 //if (basetb->findBinding(name, ns) != BIND_NONE)
826 // toplevel->throwVerifyError(kIllegalOverrideError, toplevel->core()->toErrorString(qn), toplevel->core()->toErrorString(this));
827
828 // Interfaces cannot have slots.
829 if (this->isInterface())
830 toplevel->throwVerifyError(kIllegalSlotError, core->toErrorString(this));
831
832 }
833 // these assertions are commented out because the new lazy-init code can
834 // fire them inapppriately -- they all indicate malformed ABC, but they
835 // *can* occur on a pre-resolve build of TraitsBindings. We'll just let
836 // them slide by since we check for them all at resolve time.
837 // AvmAssert(!(ne.id > nameCount)); // unhandled verify error
838 // AvmAssert(!(basetb && slot_id < basetb->slotCount)); // unhandled verify error
839 // AvmAssert(!(bindings->get(name, ns) != BIND_NONE)); // unhandled verify error
840 addVersionedBindings(bindings, name, compat_nss, AvmCore::makeSlotBinding(slot_id, ne.kind==TRAIT_Slot ? BKIND_VAR : BKIND_CONST));
841 if (slotSizeInfo != NULL__null)
842 {
843 // only do this if we need it -- doing it too early could cause us to reference a not-yet-loaded
844 // type which we don't need yet, causing an unnecessary verification failure
845 Traitsp slotType = (ne.kind == TRAIT_Class) ?
846 pool->getClassTraits(ne.info) :
847 pool->resolveTypeName(ne.info, toplevel);
848 if (!isPointerSlot(slotType))
849 {
850 if (is8ByteSlot(slotType))
851 slotSizeInfo->nonPointer64BitSlotCount += 1;
852 else
853 slotSizeInfo->nonPointer32BitSlotCount += 1;
854 }
855 else
856 {
857#ifdef _DEBUG
858 pointerSlots += 1;
859#endif
860 }
861 }
862 break;
863 }
864 case TRAIT_Method:
865 {
866 Binding baseBinding = this->getOverride(basetb, ns, name, ne.tag, toplevel);
867 if (baseBinding == BIND_NONE)
868 {
869 addVersionedBindings(bindings, name, compat_nss, AvmCore::makeMGSBinding(methodCount, BKIND_METHOD));
870 // accessors require 2 vtable slots, methods only need 1.
871 methodCount += 1;
872 }
873 else if (AvmCore::isMethodBinding(baseBinding))
874 {
875 // something got overridden, need new name entry for this subclass
876 // but keep the existing disp_id
877 addVersionedBindings(bindings, name, compat_nss, baseBinding);
878 }
879 else
880 {
881 if (toplevel)
882 toplevel->throwVerifyError(kCorruptABCError);
883 AvmAssert(!"unhandled verify error")do { } while (0);
884 }
885 break;
886 }
887 case TRAIT_Getter:
888 case TRAIT_Setter:
889 {
890 // if nothing already is defined in this class, use base class in case getter/setter has already been defined.
891 Binding baseBinding = bindings->get(name, ns);
892 if (baseBinding == BIND_NONE)
893 baseBinding = this->getOverride(basetb, ns, name, ne.tag, toplevel);
894
895 const BindingKind us = (ne.kind == TRAIT_Getter) ? BKIND_GET : BKIND_SET;
896 const BindingKind them = (ne.kind == TRAIT_Getter) ? BKIND_SET : BKIND_GET;
897 if (baseBinding == BIND_NONE)
898 {
899 addVersionedBindings(bindings, name, compat_nss, AvmCore::makeMGSBinding(methodCount, us));
900 // accessors require 2 vtable slots, methods only need 1.
901 methodCount += 2;
902 }
903 else if (AvmCore::isAccessorBinding(baseBinding))
904 {
905 // something maybe got overridden, need new name entry for this subclass
906 // but keep the existing disp_id
907 // both get & set bindings use the get id. set_id = get_id + 1.
908 if (AvmCore::bindingKind(baseBinding) == them)
909 {
910 baseBinding = AvmCore::makeGetSetBinding(baseBinding);
911 }
912 addVersionedBindings(bindings, name, compat_nss, baseBinding);
913 }
914 else
915 {
916 if (toplevel)
917 toplevel->throwVerifyError(kCorruptABCError);
918 AvmAssert(!"unhandled verify error")do { } while (0);
919 }
920 break;
921 }
922
923 default:
924 // unsupported traits type -- can't happen, caught in AbcParser::parseTraits
925 AvmAssert(0)do { } while (0);
926 break;
927 }
928 } // for i
929 slotCount = sic.slotCount();
930 if (slotSizeInfo)
931 {
932 uint32_t const c = slotSizeInfo->nonPointer32BitSlotCount + slotSizeInfo->nonPointer64BitSlotCount + baseSlotCount;
933 // We calculate this at the end because we might have a sparse slot table...
934 // the unused slots will be, well, unused, but we still have to reserve space
935 // for them to guard against pathological code.
936 slotSizeInfo->pointerSlotCount = slotCount - c;
937 // Don't do this assertion: if this situation occurs, we'll catch it (and throw
938 // a VerifyError) in finishSlotsAndMethods; asserting here will just spoil acceptance test runs.
939 // AvmAssert(slotSizeInfo->pointerSlotCount >= pointerSlots);
940 }
941 }
942
943 namespace
944 {
945 // Don't mess with the order of the members of the
946 // following struct.
947 //
948 // This struct is never actually instantiated, it is
949 // only used to determine the default padding that C++
950 // compiler will insert between 32 bit member variables and
951 // 64 bit member variables.
952 struct GlueClassTest_Slots
953 {
954 int32_t m_intSlot;
955 double m_numberSlot;
956 int32_t m_otherIntSlot;
957 void* m_ptrSlot;
958 };
959 static const boolbool align8ByteSlots = (offsetof(GlueClassTest_Slots, m_numberSlot)__builtin_offsetof(GlueClassTest_Slots, m_numberSlot) == 8);
960 static const boolbool alignPointersTo8Bytes = (offsetof(GlueClassTest_Slots, m_ptrSlot)__builtin_offsetof(GlueClassTest_Slots, m_ptrSlot) == 24);
961 static const boolbool is64Bit = sizeof(void*) == 8;
962 }
963
964 // Sun compilers don't allow static and REALLY_INLINE
965 /*static*/ REALLY_INLINEinline __attribute__((always_inline)) int32_t computeSlotOffset(Traits* slotType, int32_t& next32BitSlotOffset, int32_t& nextPointerSlotOffset, int32_t& next64BitSlotOffset)
966 {
967 if (isPointerSlot(slotType))
968 {
969 int32_t const result = nextPointerSlotOffset;
970 nextPointerSlotOffset += sizeof(void*);
971 return result;
972 }
973 else if (is8ByteSlot(slotType))
974 {
975 int32_t const result = next64BitSlotOffset;
976 next64BitSlotOffset += 8;
977 return result;
978 }
979 else
980 {
981 int32_t const result = next32BitSlotOffset;
982 next32BitSlotOffset += 4;
983 return result;
984 }
985 }
986
987 void Traits::computeNonNativeSlotAreaCountAndSize(TraitsBindings* tb, uint32_t& slotCount, uint32_t& size) const
988 {
989 const TraitsBindings* prevBindings = tb;
990 const TraitsBindings* currBindings = tb->base;
991 uint32_t thisSize = getSizeOfInstance();
992 while ((currBindings != NULL__null) && (currBindings->owner->getSizeOfInstance() == thisSize))
993 {
994 const TraitsBindings* baseBindings = currBindings->base;
995 AvmAssert((baseBindings == 0) || (baseBindings->owner->getSizeOfInstance() <= thisSize))do { } while (0); (void)baseBindings;
996 prevBindings = currBindings;
997 currBindings = currBindings->base;
998 }
999
1000 // currBindings is first ancestor class that is native with at least one slot or native member variable
1001 // or null if there is no native ancenstor class
1002
1003 if (currBindings == NULL__null)
1004 {
1005 // We could not find a ancestor class that is native.
1006 slotCount = tb->slotCount;
1007 size = tb->m_slotSize;
1008 }
1009 else if (currBindings == tb->base)
1010 {
1011 AvmAssert(tb->base != NULL)do { } while (0);
1012 AvmAssert((tb->base->slotCount == 0) || (tb->base->owner->getSizeOfInstance() <= thisSize))do { } while (0);
1013 // "this" is a native class.
1014 slotCount = 0;
1015 size = 0;
1016 }
1017 else
1018 {
1019 AvmAssert(tb->base != NULL)do { } while (0);
1020 AvmAssert(currBindings != NULL)do { } while (0);
1021 AvmAssert(currBindings->owner->getSizeOfInstance() <= thisSize)do { } while (0);
1022 AvmAssert(tb->slotCount >= prevBindings->slotCount)do { } while (0);
1023 AvmAssert(tb->m_slotSize >= prevBindings->m_slotSize)do { } while (0);
1024 slotCount = tb->slotCount - prevBindings->slotCount;
1025 size = tb->m_slotSize - prevBindings->m_slotSize;
1026 }
1027 }
1028
1029 uint32_t Traits::finishSlotsAndMethods(TraitsBindingsp basetb,
1030 TraitsBindings* tb,
1031 const Toplevel* toplevel,
1032 const SlotSizeInfo& sizeInfo) const
1033 {
1034 const uint8_t* pos = traitsPosStart();
1035
1036 SlotIdCalcer sic(basetb ? basetb->slotCount : 0, this->allowEarlyBinding());
1037
1038 /*
1039 A word of caution about calculating slot layout:
1040
1041 Say you have two classes like so:
1042
1043 class A { ... };
1044 class B : public A { int32 foo; };
1045
1046 You might assume that sizeof(B) > sizeof(A).
1047
1048 However... if the contents of A are
1049
1050 class A { char foo[9]; };
1051 class B : public A { int32 bar; };
1052
1053 The compiler may decide that sizeof(A) should be rounded
1054 up to the nearest pointer-sized boundary (e.g. if it
1055 contains virtual methods)... so for a 64-bit build,
1056 sizeof(A) could be 16. So sizeof(B) is 20, right?
1057
1058 Nope! Not necesssarily. Apparently GCC is clever enough to
1059 realize that there is enough unused (and appropriately aligned)
1060 space at the end of A to fit the extra fields in B...
1061 so sizeof(A) == sizeof(B) == 16.
1062
1063 Similarly, we could have
1064
1065 class A { char foo[9]; };
1066 class B : public A { int32 bar[3]; };
1067
1068 which could yield sizeof(A) == 16, sizeof(B) == 24, which violates
1069 the previously-assumed invariant of (sizeof(B)-sizeof(A)>=slotsize(B)).
1070
1071 (Note that this behavior is theoretically possible on 32-bit builds as well,
1072 but since the slots only contain 32-bit-or-larger fields, there can't ever be
1073 enough properly-aligned padding for this to happen.)
1074
1075 Anyway, the point of this digression is to point out that you can't ever assume
1076 that our slotArea starts "after" our parent; there might be overlap. m_offsetofSlots
1077 is computed for all native classes using C++ offsetof(), and thus correctly
1078 accounts for any overlap of this sort. See bugzilla 655300 for more info.
1079
1080 */
1081
1082 int32_t slotAreaStart = m_offsetofSlots;
1083 if (slotAreaStart == 0 && base != NULL__null)
1084 {
1085 // 0 means "put the slots at the end of my immediate parent"
1086 slotAreaStart = base->getHashtableOffset() ?
1087 base->getHashtableOffset() :
1088 base->getTotalSize();
1089 }
1090
1091
1092 int32_t next32BitSlotOffset = slotAreaStart;
1093 int32_t endOf32BitSlots = next32BitSlotOffset + (sizeInfo.nonPointer32BitSlotCount * 4);
1094 int32_t nextPointerSlotOffset = alignPointersTo8Bytes && (sizeInfo.pointerSlotCount != 0) ? pad8(endOf32BitSlots) : endOf32BitSlots;
1095 int32_t endOfPointerSlots = nextPointerSlotOffset + (sizeInfo.pointerSlotCount * sizeof(void*));
1096 int32_t next64BitSlotOffset = align8ByteSlots && (sizeInfo.nonPointer64BitSlotCount != 0) ? pad8(endOfPointerSlots) : endOfPointerSlots;
1097 int32_t endOf64BitSlots = next64BitSlotOffset + (sizeInfo.nonPointer64BitSlotCount * 8);
1098
1099 NameEntry ne;
1100 const uint32_t nameCount = pos ? AvmCore::readU32(pos) : 0;
1101 for (uint32_t i = 0; i < nameCount; i++)
1102 {
1103 AvmAssert(next32BitSlotOffset <= endOf32BitSlots)do { } while (0);
1104 AvmAssert(nextPointerSlotOffset <= endOfPointerSlots)do { } while (0);
1105 AvmAssert(next64BitSlotOffset <= endOf64BitSlots)do { } while (0); (void)endOf64BitSlots;
1106 ne.readNameEntry(pos);
1107 Multiname mn;
1108 this->pool->resolveBindingNameNoCheck(ne.qni, mn, toplevel);
1109 Namespacep ns = mn.getNamespace();
1110 Stringp name = mn.getName();
1111 // NOTE only one versioned namespace from the set needed here
1112
1113 switch (ne.kind)
1114 {
1115 case TRAIT_Slot:
1116 case TRAIT_Const:
1117 case TRAIT_Class:
1118 {
1119 uint32_t slotid = sic.calc_id(ne.id);
1120 if (slotid >= tb->slotCount || tb->getSlotOffset(slotid) > 0)
1121 {
1122 if (toplevel)
1123 toplevel->throwVerifyError(kCorruptABCError);
1124 AvmAssert(!"unhandled verify error")do { } while (0);
1125 }
1126 // note, for TRAIT_Class, AbcParser::parseTraits has already verified that pool->cinits[ne.info] is not null
1127 Traitsp slotType = (ne.kind == TRAIT_Class) ?
1128 pool->getClassTraits(ne.info) :
1129 pool->resolveTypeName(ne.info, toplevel);
1130 uint32_t slotOffset = computeSlotOffset(slotType, next32BitSlotOffset, nextPointerSlotOffset, next64BitSlotOffset);
1131 AvmAssert(slotOffset >= sizeof(ScriptObject))do { } while (0);
1132 tb->setSlotInfo(slotid, slotType, slotStorageType(getBuiltinType(slotType)), slotOffset);
1133 break;
1134 }
1135 case TRAIT_Getter:
1136 case TRAIT_Setter:
1137 case TRAIT_Method:
1138 {
1139 const Binding b = tb->m_bindings->get(name, ns);
1140 if (b != BIND_NONE)
1141 {
1142 const uint32_t disp_id = uint32_t(uintptr_t(b) >> 3) + (ne.kind == TRAIT_Setter);
1143 Binding base = this->getOverride(basetb, ns, name, ne.tag, toplevel);
1144 if (AvmCore::isMethodBinding(base)
1145 || (AvmCore::hasGetterBinding(base) && (ne.kind == TRAIT_Getter))
1146 || (AvmCore::hasSetterBinding(base) && (ne.kind == TRAIT_Setter))) {
1147 ensureNonFinal(basetb->getMethod(disp_id), toplevel);
1148 }
1149 MethodInfo* f = this->pool->getMethodInfo(ne.id);
1150 //AvmAssert(f->declaringTraits() == this);
1151 tb->setMethodInfo(disp_id, f);
1152 }
1153 else
1154 {
1155 // This should only be BIND_NONE if the attribute was elided via Api Versioning.
1156 AvmAssert(!core->isValidApiVersion(ns->getApiVersion()))do { } while (0);
1157 }
1158 break;
1159 }
1160
1161 default:
1162 // unsupported traits type -- can't happen, caught in AbcParser::parseTraits
1163 AvmAssert(0)do { } while (0);
1164 break;
1165 }
1166 } // for i
1167
1168 // check for sparse slot table -- anything not specified will default to * (but we must allocate space for it)
1169 for (uint32_t i = 0; i < tb->slotCount; i++)
1170 {
1171 if (tb->getSlotOffset(i) > 0)
1172 continue;
1173
1174 #ifdef AVMPLUS_VERBOSE
1175 if (pool->isVerbose(VB_traits))
1176 {
1177 core->console << "WARNING: slot " << i+1 << " on " << this << " not defined by compiler. Using *\n";
1178 }
1179 #endif
1180
1181 const Traitsp slotType = NULL__null;
1182 const uint32_t slotOffset = nextPointerSlotOffset;
1183 nextPointerSlotOffset += sizeof(void*);
1184 AvmAssert(slotOffset >= sizeof(ScriptObject))do { } while (0);
1185 tb->setSlotInfo(i, slotType, SST_atom, slotOffset);
1186 }
1187 if (!(next32BitSlotOffset == endOf32BitSlots &&
1188 nextPointerSlotOffset == endOfPointerSlots &&
1189 next64BitSlotOffset == endOf64BitSlots &&
1190 endOf64BitSlots >= slotAreaStart))
1191 {
1192 // Verify that we used exactly the space we predicted; if not, we may
1193 // have a fuzzed file that duplicate slots in certain orders. This is unacceptable,
1194 // as it may allow access to the same memory location with different type expectations.
1195 if (toplevel)
1196 toplevel->throwVerifyError(kCorruptABCError);
1197 AvmAssert(!"unhandled verify error")do { } while (0);
1198 }
1199 return endOf64BitSlots - slotAreaStart;
1200 }
1201
1202 static const uint8_t* skipToInterfaceCount(const uint8_t* pos)
1203 {
1204 AvmAssert(pos != NULL)do { } while (0);
1205 AvmCore::skipU32(pos, 2); // skip the QName + basetraits
1206 const uint8_t theflags = *pos++;
1207 if (theflags & 8)
1208 AvmCore::skipU32(pos); // skip protected namespace
1209 return pos;
1210 }
1211
1212 // Apps often have many interfaces redundantly listed, so first time thru,
1213 // eliminate redundant ones. We do this by only adding new interfaces to
1214 // the "seen" list and only traversing new super-interfaces. An interface
1215 // is NEW if our base class does not implement it.
1216 uint32_t Traits::countNewInterfaces(GCList<Traits>& seen)
1217 {
1218 // each Traits* added to this list is rooted via Domain and PoolObject,
1219 // so it is okay for this Stack to be opaque to the GC.
1220 Stack<Traits*> pending;
1221 pending.add(this);
1222 while (!pending.isEmpty()) {
1223 Traits* t = pending.pop();
1224 const uint8_t* pos = skipToInterfaceCount(t->m_traitsPos);
1225 const uint32_t interfaceCount = AvmCore::readU32(pos);
1226 for (uint32_t j = 0; j < interfaceCount; j++) {
1227 // we know all interfaces have been resolved already, it is done
1228 // before traits construction in AbcParser::parseInstanceInfos().
1229 Traitsp intf = t->pool->resolveTypeName(pos, NULL__null);
1230 AvmAssert(intf && intf->isInterface() && intf->base == NULL)do { } while (0);
1231 // an interface can "extend" multiple other interfaces, so we must recurse here.
1232 if ((!base || !base->subtypeof(intf)) && seen.indexOf(intf) < 0) {
1233 seen.add(intf);
1234 pending.add(intf);
1235 }
1236 }
1237 }
1238 return seen.length();
1239 }
1240
1241 static uint8_t calcLog2(uint32_t cap)
1242 {
1243 uint8_t capLog = 1; // start with at least 2 entries
1244 while ((1U<<capLog) < cap)
1245 {
1246 ++capLog;
1247 }
1248 AvmAssert((1U<<capLog) >= cap)do { } while (0);
1249 return capLog;
1250 }
1251
1252 TraitsBindings* Traits::_buildTraitsBindings(const Toplevel* toplevel, boolbool includeTypes)
1253 {
1254#ifdef AVMPLUS_VERBOSE
1255 if (pool->isVerbose(VB_traits))
1256 {
1257 core->console << "Generate TraitsBindings for "<<this<<"\n";
1258 }
1259#endif
1260
1261 TraitsBindings* thisData = NULL__null;
1262
1263 // if we know the cap we need, go there right away, otherwise start at small power of 2
1264 // this saves tremendously on subsequent builds of this set of bindings since we don't have to
1265 // waste time growing the MNHT as we build it
1266 const int32_t bindingCap = m_bindingCapLog2 ? (1 << m_bindingCapLog2) : 2;
1267
1268 MMgc::GC* gc = core->GetGC();
1269 MultinameBindingHashtable* bindings = MultinameBindingHashtable::create(gc, bindingCap);
1270 AvmAssert(bindings->numQuads == bindingCap)do { } while (0);
1271
1272 if (this->posType() == TRAITSTYPE_CATCH)
1273 {
1274 const uint8_t* pos = m_traitsPos;
1275
1276 Traits* t = this->pool->resolveTypeName(pos, toplevel);
1277
1278 // this assumes we save name/ns in all builds, not just verbose
1279 NamespaceSetp nss = NamespaceSet::create(core->GetGC(), this->ns());
1280 NamespaceSetp compat_nss = nss;
1281 addVersionedBindings(bindings, this->name(), compat_nss, AvmCore::makeSlotBinding(0, BKIND_VAR));
1282 // bindings just need room for one slot binding
1283 thisData = TraitsBindings::alloc(gc, this, /*base*/NULL__null, bindings, /*slotCount*/1, /*methodCount*/0, truetrue);
1284 thisData->setSlotInfo(0, t, slotStorageType(getBuiltinType(t)), this->m_sizeofInstance);
1285 thisData->m_slotSize = is8ByteSlot(t) ? 8 : 4;
1286 }
1287 else
1288 {
1289 TraitsBindingsp basetb = this->base ? this->base->getTraitsBindings() : NULL__null;
1290
1291 // Copy protected traits from base class into new protected namespace
1292 if (basetb && base->protectedNamespace && this->protectedNamespace)
1293 {
1294 StTraitsBindingsIterator iter(basetb);
1295 while (iter.next())
1296 {
1297 if (!iter.key()) continue;
1298 if (iter.ns() == base->protectedNamespace)
1299 {
1300 bindings->add(iter.key(), this->protectedNamespace, iter.value());
1301 }
1302 }
1303 }
1304
1305 SlotSizeInfo _slotSizeInfo;
1306 SlotSizeInfo* slotSizeInfo = includeTypes ? &_slotSizeInfo : NULL__null;
1307
1308 uint32_t slotCount = 0;
1309 uint32_t methodCount = 0;
1310 buildBindings(basetb, bindings, slotCount, methodCount, slotSizeInfo, toplevel);
1311
1312 thisData = TraitsBindings::alloc(gc, this, basetb, bindings, slotCount, methodCount, includeTypes);
1313 if (slotSizeInfo)
1314 {
1315 thisData->m_slotSize = finishSlotsAndMethods(basetb, thisData, toplevel, *slotSizeInfo);
1316 if (basetb)
1317 thisData->m_slotSize += basetb->m_slotSize;
1318 }
1319
1320 if (!isInterface() && m_implementsNewInterfaces) {
1321 // fix up interface bindings
1322 for (InterfaceIterator it(this); it.hasNext(); ) {
1323 Traits* t = it.next();
1324 if (!base || !base->subtypeof(t)) {
1325 // new interface not implemented in base.
1326 thisData->fixOneInterfaceBindings(t);
1327 }
1328 }
1329 }
1330 }
1331
1332 // hashtable (if we have one) must start on pointer-sized boundary...
1333 // much easier to always round slotsize up unconditionally rather than
1334 // only for cases with hashtable, so that's what we'll do. (MMgc currently
1335 // allocate in 8-byte increments anyway, so we're not really losing any space.)
1336 // (only really necessary to do this if we calced slotSizeInfo, but simpler & harmless
1337 // to just do it unconditionally)
1338 thisData->m_slotSize = (thisData->m_slotSize + (sizeof(uintptr_t)-1)) & ~(sizeof(uintptr_t)-1);
1339
1340 // remember the cap we need
1341 if (m_bindingCapLog2 == 0)
1342 m_bindingCapLog2 = calcLog2(thisData->m_bindings->numQuads); // remember capacity, not count
1343 AvmAssert(m_bindingCapLog2 > 0)do { } while (0);
1344
1345#ifdef AVMPLUS_VERBOSE
1346 if (pool->isVerbose(VB_traits))
1347 {
1348 core->console << this << " bindings\n";
1349 StTraitsBindingsIterator iter(thisData);
1350 while (iter.next())
1351 {
1352 core->console << iter.key() << ":" << (uint32_t)(uintptr_t)(iter.value()) << "\n";
1353 }
1354 core->console << this << " end bindings \n";
1355 }
1356#endif
1357
1358 AvmAssert(m_tbref->isNull())do { } while (0);
1359 m_tbref = thisData->GetWeakRef();
1360 core->tbCache()->add(thisData);
1361 return thisData;
1362 }
1363
1364 TraitsMetadata* Traits::_buildTraitsMetadata()
1365 {
1366#ifdef AVMPLUS_VERBOSE
1367 if (pool->isVerbose(VB_traits))
1368 {
1369 core->console << "Generate TraitsMetadata for "<<this<<"\n";
1370 }
1371#endif
1372 TraitsBindingsp td = this->getTraitsBindings();
1373
1374 MMgc::GC* gc = core->GetGC();
1375
1376 TraitsMetadatap basetm = this->base ? this->base->getTraitsMetadata() : NULL__null;
1377
1378 const uint32_t extra = td->slotCount * sizeof(TraitsMetadata::MetadataPtr) + td->methodCount * sizeof(TraitsMetadata::MetadataPtr);
1379
1380 TraitsMetadata* tm = TraitsMetadata::create(gc, extra, basetm, this->pool, this->metadata_pos, td->slotCount, td->methodCount);
1381 tm->slotMetadataPos = (TraitsMetadata::MetadataPtr*)(tm + 1);
1382 tm->methodMetadataPos = (TraitsMetadata::MetadataPtr*)(tm->slotMetadataPos + tm->slotCount);
1383
1384 const uint8_t* pos = traitsPosStart();
1385 const uint32_t nameCount = pos ? AvmCore::readU32(pos) : 0;
1386 SlotIdCalcer sic(td->base ? td->base->slotCount : 0, this->allowEarlyBinding());
1387 NameEntry ne;
1388 for (uint32_t i = 0; i < nameCount; i++)
1389 {
1390 ne.readNameEntry(pos);
1391 switch (ne.kind)
1392 {
1393 case TRAIT_Class:
1394 AvmAssert(0)do { } while (0);
1395 // classes shouldn't have metadata, but just fall thru just in case
1396 case TRAIT_Slot:
1397 case TRAIT_Const:
1398 {
1399 const uint32_t slot_id = sic.calc_id(ne.id);
1400 if (ne.tag & ATTR_metadata)
1401 tm->slotMetadataPos[slot_id] = ne.meta_pos;
1402 break;
1403 }
1404 case TRAIT_Getter:
1405 case TRAIT_Setter:
1406 case TRAIT_Method:
1407 {
1408 if (ne.tag & ATTR_metadata)
1409 {
1410 Multiname qn;
1411 // passing NULL for toplevel here, since it's only used if a verification error occurs --
1412 // but if there was one, we would have encountered it during AbcParser::parseTraits.
1413 this->pool->resolveBindingNameNoCheck(ne.qni, qn, /*toplevel*/NULL__null);
1414 const Binding b = td->findBinding(qn.getName(), qn.getNamespace());
1415 AvmAssert(b != BIND_NONE)do { } while (0);
1416 const uint32_t disp_id = uint32_t(uintptr_t(b) >> 3) + (ne.kind == TRAIT_Setter);
1417 tm->methodMetadataPos[disp_id] = ne.meta_pos;
1418 }
1419 break;
1420 }
1421
1422 default:
1423 // unsupported traits type -- can't happen, caught in AbcParser::parseTraits
1424 AvmAssert(0)do { } while (0);
1425 break;
1426 }
1427 } // for i
1428
1429 AvmAssert(m_tmref->isNull())do { } while (0);
1430 m_tmref = tm->GetWeakRef();
1431 core->tmCache()->add(tm);
1432 return tm;
1433 }
1434
1435 /**
1436 * add t to pending[] ahead of any existing entries that are
1437 * subtypes or implementers of t, so that when we iterate through
1438 * pending[] we will traverse the inheritance DAG top-down.
1439 */
1440 void insertSupertype(Traits* t, GCList<Traits> &pending)
1441 {
1442 uint32_t i = 0;
1443 for (uint32_t n = pending.length(); i < n; i++) {
1444 if (pending[i]->subtypeof(t)) {
1445 pending.insert(i, t);
1446 return;
1447 }
1448 }
1449 pending.add(t);
1450 }
1451
1452 /**
1453 * resolve this traits signatures by visiting all supertypes in
1454 * top-down toplogical order, then resolving our own signatures. The top-down
1455 * order ensures that we resolve base classes and interfaces first, while
1456 * avoiding recursion.
1457 */
1458 void Traits::resolveSignatures(const Toplevel* toplevel)
1459 {
1460 // toplevel actually can be null, when resolving the builtin classes...
1461 // but they should never cause verification errors in functioning builds
1462 if (m_resolved)
1463 return;
1464
1465 GCList<Traits> pending(core->gc, kListInitialCapacity);
1466 // copy primary supertypes into pending.
1467 // primary_supertypes[] is already in top-down order.
1468 for (int32_t i = 0; i < MAX_PRIMARY_SUPERTYPE; i++) {
1469 Traits* t = m_primary_supertypes[i];
1470 if (t == NULL__null || t == this)
1471 break;
1472 if (!t->m_resolved)
1473 pending.add(t);
1474 }
1475
1476 // copy other base types, and interfaces, into pending[] by
1477 // and maintaining the partial ordering that each type's bases and
1478 // interfaces are visited before that type itself is visited.
1479 for (Traits** st = m_secondary_supertypes; *st != NULL__null; st++) {
1480 Traits* t = *st;
1481 if (t != this && !t->m_resolved)
1482 insertSupertype(t, pending);
1483 }
1484
1485 for (uint32_t i = 0, n = pending.length(); i < n; i++) {
1486 AvmAssert(!pending[i]->m_resolved)do { } while (0);
1487 pending[i]->resolveSignaturesSelf(toplevel);
1488 }
1489
1490 this->resolveSignaturesSelf(toplevel);
1491 }
1492
1493 void Traits::verifyBindings(const Toplevel* toplevel)
1494 {
1495 // builtin Traits get called before a Toplevel is created, so they
1496 // get a free pass. Everyone else better pass a good value.
1497 AvmAssert(toplevel != NULL || pool->isBuiltin)do { } while (0);
1498
1499#ifdef DEBUG
1500 AvmAssert(!m_bindingsVerified)do { } while (0);
1501 // make sure our supertypes have verified their bindings. (must be done before calling _buildTraitsBindings)
1502 for (Traits* t = this->base; t != NULL__null; t = t->base)
1503 AvmAssert(t->m_bindingsVerified)do { } while (0);
1504 for (Traits** st = this->m_secondary_supertypes; *st != NULL__null; st++)
1505 AvmAssert(*st == this || (*st)->m_bindingsVerified)do { } while (0);
1506#endif
1507
1508 AvmAssert(m_tbref == core->GetGC()->emptyWeakRef)do { } while (0);
1509 // force buildTraitsBindings to run now, so that any errors will
1510 // also be reported now, instead of later when called on a QCache
1511 // miss, when we don't have a valid Toplevel* for exception-throwing context.
1512 _buildTraitsBindings(toplevel, /*includeTypes*/falsefalse);
1513#ifdef DEBUG
1514 this->m_bindingsVerified = truetrue;
1515#endif
1516 }
1517
1518 /**
1519 * This must be called before any method is verified or any
1520 * instances are created. It is not done eagerly in AbcParser
1521 * because doing so would prevent circular type references between
1522 * slots of cooperating classes.
1523 *
1524 * Resolve the type and position/width of each slot.
1525 */
1526 void Traits::resolveSignaturesSelf(const Toplevel* toplevel)
1527 {
1528 // builtin Traits get called before a Toplevel is created, so they
1529 // get a free pass. Everyone else better pass a good value.
1530 AvmAssert(toplevel != NULL || pool->isBuiltin)do { } while (0);
1531
1532 AvmAssert(m_bindingsVerified)do { } while (0);
1533
1534#ifdef DEBUG
1535 AvmAssert(!m_resolved)do { } while (0);
1536 // make sure our supertypes are resolved. (must be done before calling _buildTraitsBindings)
1537 for (Traits* t = this->base; t != NULL__null; t = t->base)
1538 AvmAssert(t->m_resolved)do { } while (0);
1539 for (Traits** st = this->m_secondary_supertypes; *st != NULL__null; st++)
1540 AvmAssert(*st == this || (*st)->m_resolved)do { } while (0);
1541#endif
1542
1543 // we might already have one -- if so, toss it
1544 m_tbref = core->GetGC()->emptyWeakRef;
1545 TraitsBindings* tb = _buildTraitsBindings(toplevel, /*includeTypes*/truetrue);
1546 genInitBody(toplevel, tb);
1547
1548 // leave m_tmref as empty, we don't need it yet
1549
1550 uint32_t slotAreaSize = 0;
1551 uint32_t slotAreaCount = 0;
1552
1553 switch (posType())
1554 {
1555 case TRAITSTYPE_INTERFACE:
1556 case TRAITSTYPE_INSTANCE:
1557 case TRAITSTYPE_CLASS:
1558 case TRAITSTYPE_SCRIPT:
1559 case TRAITSTYPE_ACTIVATION:
1560 case TRAITSTYPE_CATCH:
1561 computeNonNativeSlotAreaCountAndSize(tb, slotAreaCount, slotAreaSize);
1562 m_totalSize = getSizeOfInstance() + slotAreaSize;
1563 break;
1564 case TRAITSTYPE_NVA:
1565 case TRAITSTYPE_RT:
1566 m_totalSize = getSizeOfInstance();
1567 break;
1568 }
1569 AvmAssert(m_totalSize >= m_sizeofInstance)do { } while (0);
1570 if (m_needsHashtable || (base && base->base && base->m_hashTableOffset && !isXMLType()))
1571 {
1572 // round up total size to multiple of pointer size.
1573 m_totalSize = ((m_totalSize+(sizeof(uintptr_t)-1))&~(sizeof(uintptr_t)-1));
1574 m_hashTableOffset = m_totalSize;
1575 m_totalSize += sizeof(InlineHashtable);
1576 AvmAssert(builtinType == BUILTIN_boolean ? true : (m_hashTableOffset & 3) == 0)do { } while (0);
1577 AvmAssert((m_hashTableOffset & (sizeof(uintptr_t)-1)) == 0)do { } while (0);
1578 AvmAssert((m_totalSize & (sizeof(uintptr_t)-1)) == 0)do { } while (0);
1579 }
1580
1581 // make sure all the methods have resolved types
1582 if (tb->methodCount)
1583 {
1584 const TraitsBindings::BindingMethodInfo* tbm = tb->getMethods();
1585 const TraitsBindings::BindingMethodInfo* tbm_end = tbm + tb->methodCount;
1586 for ( ; tbm < tbm_end; ++tbm)
1587 {
1588 // don't assert: could be null if only one of a get/set pair is implemented
1589 //AvmAssert(tbm->f != NULL);
1590 if (tbm->f != NULL__null)
1591 {
1592 tbm->f->resolveSignature(toplevel);
1593 }
1594 }
1595 }
1596
1597 if (this->init != NULL__null)
1598 this->init->resolveSignature(toplevel);
1599
1600 boolbool legal = truetrue;
1601 TraitsBindingsp tbbase = tb->base; // might be null
1602
1603 if (tbbase && tbbase->methodCount > 0)
1604 {
1605 // check concrete overrides
1606 const TraitsBindings::BindingMethodInfo* basetbm = tbbase->getMethods();
1607 const TraitsBindings::BindingMethodInfo* basetbm_end = basetbm + tbbase->methodCount;
1608 const TraitsBindings::BindingMethodInfo* tbm = tb->getMethods();
1609 for ( ; basetbm < basetbm_end; ++basetbm, ++tbm)
1610 {
1611 if (basetbm->f != NULL__null && basetbm->f != tbm->f)
1612 legal &= tb->checkOverride(core, basetbm->f, tbm->f);
1613 }
1614 }
1615
1616 if (legal && !this->isInterface())
1617 {
1618 legal &= tb->checkLegalInterfaces(core);
1619 }
1620
1621 if (!legal)
1622 {
1623 AvmAssert(!m_resolved)do { } while (0);
1624 Multiname qname(ns(), name());
1625 if (toplevel)
1626 toplevel->throwVerifyError(kIllegalOverrideError, core->toErrorString(&qname), core->toErrorString(this));
1627#ifdef VMCFG_VERIFYALL
1628 else {
1629 if (core->config.verifyonly)
1630 core->console << "ILLEGAL OVERRIDE\n";
1631 }
1632#endif
1633 AvmAssert(!"unhandled verify error")do { } while (0);
1634 }
1635
1636 tb->buildSlotDestroyInfo(core->GetGC(), m_slotDestroyInfo, slotAreaCount, slotAreaSize);
1637
1638 m_resolved = truetrue;
1639#ifdef AVMPLUS_VERBOSE
1640 if (pool->isVerbose(VB_traits)) {
1641 core->console << "Resolved ";
1642 printExtended(core->console) << "\n";
1643 }
1644#endif
1645 }
1646
1647#ifdef AVMPLUS_VERBOSE
1648 PrintWriter& Traits::printExtended(PrintWriter& pw)
1649 {
1650 const char* desc = NULL__null;
1651 switch (posType()) {
1652 case TRAITSTYPE_INTERFACE:
1653 desc = "interface"; break;
1654 case TRAITSTYPE_INSTANCE:
1655 desc = "instance"; break;
1656 case TRAITSTYPE_CLASS:
1657 desc = "class"; break;
1658 case TRAITSTYPE_SCRIPT:
1659 desc = "script"; break;
1660 case TRAITSTYPE_ACTIVATION:
1661 desc = "activation"; break;
1662 case TRAITSTYPE_CATCH:
1663 desc = "catch"; break;
1664 case TRAITSTYPE_NVA: // null/void/any
1665 desc = "singleton"; break;
1666 case TRAITSTYPE_RT:
1667 desc = "rt"; break;
1668 default:
1669 AvmAssert(false)do { } while (0);
1670 }
1671 const char* domainString = core->identifyDomain(pool->domain);
1672 pw << ns() << "::" << name() << ", type:" << desc << ",domain:";
1673 if (domainString) {
1674 pw << domainString;
1675 } else {
1676 // not a well known domain, print the address to help distinguish distinct domains
1677 pw << "@" << hexAddr((intptr_t)(Domain*)pool->domain);
1678 }
1679 return pw;
1680 }
1681
1682#endif
1683
1684
1685#ifdef VMCFG_AOT
1686 static inline void hookUpActivationTraitsInitMethodForTraitsMethod(AvmCore* core, MethodInfo* m)
1687 {
1688 AvmAssert(m->needActivation())do { } while (0);
1689
1690 const AOTInfo* aotInfo = m->pool()->aotInfo;
1691 Traits* activationTraits = m->activationTraits();
1692 AvmAssert(activationTraits != NULL)do { } while (0);
1693 AvmAssert(m->method_id() < aotInfo->nActivationTraits)do { } while (0);
1694 AvmAssert(aotInfo->activationTraits != NULL)do { } while (0);
1695 AvmAssert(aotInfo->activationTraits[m->method_id()] == activationTraits)do { } while (0);
1696 AvmAssert(aotInfo->activationInfo != NULL)do { } while (0);
1697
1698 // See comment in initActivationTraits about why this can be called more than once per Traits
1699 if (activationTraits->init == NULL__null) {
1700 if (aotInfo->activationInfo[m->method_id()].initHandler) {
1701 // NativeMethodInfo.handler is a union of
1702 // pointer to function and pointer to member function.
1703 // Zero the structure so that the entire thing is
1704 // initialized.
1705 // See bugzilla#647660
1706 NativeMethodInfo compiledMethodInfo = {0};
1707 compiledMethodInfo.thunker = aotThunker;
1708 AvmThunkNativeHandler nhandler;
1709 nhandler.function = aotInfo->activationInfo[m->method_id()].initHandler;
1710 activationTraits->init = MethodInfo::create(core->GetGC(), MethodInfo::kInitMethodStub, activationTraits, &compiledMethodInfo, nhandler, aotInfo->activationInfo[m->method_id()].initMethodId);
1711 }
1712 // The following comes from Verifier::write() TODO: refactor so we can share this code
1713 const ScopeTypeChain *scope = m->activationScope();
1714 if (scope == NULL__null) {
1715 scope = m->declaringScope()->cloneWithNewTraits(core->GetGC(), activationTraits);
1716 activationTraits->setDeclaringScopes(scope);
1717 m->init_activationScope(scope);
1718 }
1719 }
1720 }
1721
1722 void Traits::initActivationTraits()
1723 {
1724 // Note: this can be called multiple times per Traits from initScript, which must call this in case it's needed
1725 // but is itself called once per Toplevel
1726 const uint8_t* pos = traitsPosStart();
1727
1728 if (this->init->needActivation()) {
1729 hookUpActivationTraitsInitMethodForTraitsMethod(core, this->init);
1730 }
1731
1732 NameEntry ne;
1733 const uint32_t nameCount = pos ? AvmCore::readU32(pos) : 0;
1734 for (uint32_t i = 0; i < nameCount; i++)
1735 {
1736 ne.readNameEntry(pos);
1737
1738 switch (ne.kind)
1739 {
1740 case TRAIT_Slot:
1741 case TRAIT_Const:
1742 case TRAIT_Class:
1743 break;
1744 case TRAIT_Method:
1745 case TRAIT_Getter:
1746 case TRAIT_Setter:
1747 {
1748 MethodInfo* m = pool->getMethodInfo(ne.id);
1749 if (m->needActivation()) {
1750 hookUpActivationTraitsInitMethodForTraitsMethod(core, m);
1751 }
1752 break;
1753 }
1754 default:
1755 // unsupported traits type -- can't happen, caught in AbcParser::parseTraits
1756 AvmAssert(0)do { } while (0);
1757 break;
1758 }
1759 }
1760 }
1761#endif
1762
1763 // static
1764 boolbool Traits::isMachineCompatible(const Traits* a, const Traits* b)
1765 {
1766 return (a == b) ||
1767 // *, Object, and Void are each represented as Atom
1768 ((!a || a->builtinType == BUILTIN_object || a->builtinType == BUILTIN_void) &&
1769 (!b || b->builtinType == BUILTIN_object || b->builtinType == BUILTIN_void)) ||
1770 // all other non-pointer types have unique representations
1771 (a && b && !a->isMachineType() && !b->isMachineType());
1772 }
1773
1774 PrintWriter& Traits::print(PrintWriter& prw, boolbool includeAllNamespaces) const
1775 {
1776 if (name() != NULL__null) {
1777 Multiname::print(prw, ns(), name(), falsefalse, !includeAllNamespaces);
1778 } else {
1779 prw << "Traits@" << asAtomHex((Atom)this);
1780 }
1781 return prw;
1782 }
1783
1784 void Traits::genInitBody(const Toplevel* toplevel, TraitsBindings* tb)
1785 {
1786#if defined(VMCFG_AOT)
1787 if (this->init && this->init->isAotCompiled())
1788 return;
1789#endif
1790
1791 struct ValidateInitVisitor: public InitVisitor
1792 {
1793 boolbool hasDefaults;
1794 ValidateInitVisitor() : hasDefaults(falsefalse) {}
1795 virtual ~ValidateInitVisitor() {}
1796 void defaultVal(Atom, uint32_t, Traits*)
1797 {
1798 hasDefaults = truetrue;
1799 }
1800 };
1801 ValidateInitVisitor visitor;
1802 visitInitBody(&visitor, toplevel, tb);
1803
1804 // if initialization code gen is required, create a new method body and write it to traits->init->body_pos
1805 if (visitor.hasDefaults && !this->init)
1806 {
1807 // Make a do-nothing init method.
1808 this->init = MethodInfo::create(core->gc, MethodInfo::kInitMethodStub, this);
1809 AvmAssert(this->init->declaringTraits() == this)do { } while (0);
1810 static const uint8_t body[] = {
1811 2, // max_stack
1812 1, // local_count
1813 1, // init_scope_depth
1814 1, // max_scope_depth
1815 1, // code_length
1816 (uint8_t)OP_returnvoid, // code
1817 0 // exception_count
1818 // the verifier and interpreter don't read the activation traits so stop here
1819 };
1820
1821 // The synthetic MethodInfo points directly to the static const ABC above.
1822 this->init->set_abc_body_pos(body);
1823 }
1824 }
1825
1826 void Traits::visitInitBody(InitVisitor *visitor, const Toplevel* toplevel, const TraitsBindings* tb)
1827 {
1828 const uint8_t* pos = traitsPosStart();
1829 SlotIdCalcer sic(tb->base ? tb->base->slotCount : 0, this->allowEarlyBinding());
1830 NameEntry ne;
1831 const uint32_t nameCount = pos ? AvmCore::readU32(pos) : 0;
1832 for (uint32_t i = 0; i < nameCount; i++)
1833 {
1834 ne.readNameEntry(pos);
1835 switch (ne.kind)
1836 {
1837 case TRAIT_Slot:
1838 case TRAIT_Const:
1839 case TRAIT_Class:
1840 {
1841 uint32_t slotid = sic.calc_id(ne.id);
1842 // note, for TRAIT_Class, AbcParser::parseTraits has already verified that pool->cinits[ne.info] is not null
1843 Traitsp slotType = (ne.kind == TRAIT_Class) ?
1844 pool->getClassTraits(ne.info) :
1845 pool->resolveTypeName(ne.info, NULL__null);
1846 uint32_t value_index = ne.value_index;
1847 CPoolKind kind = ne.value_kind;
1848 Atom value = pool->getLegalDefaultValue(toplevel, value_index, kind, slotType);
1849 switch (Traits::getBuiltinType(slotType))
1850 {
1851 case BUILTIN_any:
1852 case BUILTIN_object:
1853 if (value == 0)
1854 continue;
1855 break;
1856 case BUILTIN_number:
1857 if (AvmCore::number_d(value) == 0)
1858 continue;
1859 break;
1860 case BUILTIN_boolean:
1861 AvmAssert((uintptr_t(falseAtom)>>3) == 0)do { } while (0);
1862 if (value == falseAtom)
1863 continue;
1864 AvmAssert(value == trueAtom)do { } while (0);
1865 break;
1866 case BUILTIN_uint:
1867 case BUILTIN_int:
1868 if (value == (zeroIntAtom))
1869 continue;
1870 break;
1871 case BUILTIN_namespace:
1872 case BUILTIN_string:
1873 default:
1874 if (AvmCore::isNull(value))
1875 continue;
1876 break;
1877 }
1878 visitor->defaultVal(value, slotid, slotType);
1879 break;
1880 }
1881 }
1882 } // for i
1883 }
1884
1885 void Traits::destroyInstance(ScriptObject* obj) const
1886 {
1887 AvmAssert(m_resolved)do { } while (0);
1888
1889 InlineHashtable* ht = m_hashTableOffset ? obj->getTableNoInit() : NULL__null;
1890
1891 // start by clearing native space to zero (except baseclasses)
1892 union {
1893 char* p_8;
1894 uint32_t* p;
1895 };
1896 p_8 = (char*)obj + sizeof(AvmPlusScriptableObject);
1897 AvmAssert((uintptr_t(p) % sizeof(uint32_t)) == 0)do { } while (0);
1898
1899 if (!m_slotDestroyInfo.test(0))
1900 {
1901 AvmAssert(m_slotDestroyInfo.cap() == 1)do { } while (0);
1902 AvmAssert(m_totalSize >= (sizeof(AvmPlusScriptableObject) + (ht ? sizeof(InlineHashtable) : 0)))do { } while (0);
1903 uint32_t sizeToZero = m_totalSize - (sizeof(AvmPlusScriptableObject) + (ht ? sizeof(InlineHashtable) : 0));
1904 AvmAssert((sizeToZero % sizeof(uint32_t)) == 0)do { } while (0); // we assume all sizes are multiples of sizeof(uint32_t)
1905
1906 // no RCObjects, so just zero it all... my, that was easy
1907 VMPI_memset::memset(p, 0, sizeToZero);
1908 }
1909 else
1910 {
1911 uint32_t sizeToZero = m_sizeofInstance - uint32_t(sizeof(AvmPlusScriptableObject));
1912 AvmAssert((sizeToZero % sizeof(uint32_t)) == 0)do { } while (0); // we assume all sizes are multiples of sizeof(uint32_t)
1913 VMPI_memset::memset(p, 0, sizeToZero);
1914 p += (sizeToZero / sizeof(uint32_t));
1915
1916 AvmAssert(m_slotDestroyInfo.cap() >= 1)do { } while (0);
1917 AvmAssert((uintptr_t(p) % sizeof(uint32_t)) == 0)do { } while (0);
1918
1919 const uint32_t slotAreaSize = getSlotAreaSize();
1920 const uint32_t bitsUsed = slotAreaSize / sizeof(uint32_t); // not sizeof(Atom)!
1921 for (uint32_t bit = 1; bit <= bitsUsed; bit++)
1922 {
1923 if (m_slotDestroyInfo.test(bit))
1924 {
1925 #ifdef AVMPLUS_64BIT
1926 AvmAssert((uintptr_t(p) & 7) == 0)do { } while (0); // we had better be on an 8-byte boundary...
1927 #endif
1928 Atom a = *(const Atom*)p;
1929 RCObject* rc = NULL__null;
1930 if (atomKind(a)((avmplus::Atom)((uintptr_t(a) & 7))) <= kNamespaceType)
1931 {
1932 rc = (RCObject*)atomPtr(a)((void*)(uintptr_t(a) & ~7));
1933 if (rc)
1934 {
1935 AvmAssert(GC::GetGC(obj)->IsRCObject(rc))do { } while (0);
1936 rc->DecrementRef();
1937 }
1938 }
1939 }
1940 *p++ = 0;
1941 }
1942 }
1943
1944 // finally, zap the hashtable (if any)
1945 if(ht)
1946 {
1947 ht->destroy();
1948 }
1949 //for DictionaryObject also zero out the
1950 //hashtable pointer stored at the offset address;
1951 if(isDictionary())
1952 {
1953 union {
1954 char* p_8;
1955 uintptr_t* ptr;
1956 };
1957 p_8 = (char*)obj + m_hashTableOffset;
1958 *ptr = 0;
1959 }
1960 }
1961
1962 void Traits::traceSlots(MMgc::GC* gc, ScriptObject* obj) const
1963 {
1964 if (m_slotDestroyInfo.test(0))
1965 {
1966 const uint32_t slotAreaSize = getSlotAreaSize();
1967 union {
1968 char* p_8;
1969 uint32_t* p;
1970 };
1971 p_8 = (char*)obj + m_sizeofInstance;
1972
1973 AvmAssert(m_slotDestroyInfo.cap() >= 1)do { } while (0);
1974 AvmAssert((uintptr_t(p) & 3) == 0)do { } while (0);
1975 const uint32_t bitsUsed = slotAreaSize / sizeof(uint32_t); // not sizeof(Atom)!
1976
1977 traceSlotsFromBitmap(gc, p, m_slotDestroyInfo, bitsUsed);
1978 }
1979 }
1980
1981 // OPTIMIZEME: We can do better than traceInfo.test, which is probably
1982 // going to be about a dozen instructions on interesting architectures.
1983 // A fairly trivial optimization would be to provide an API on FixedBitSet
1984 // that provides uint32_t values representing sets of 32 bits, and
1985 // make the loop here doubly nested. That would also allow us to skip
1986 // quickly areas of objects that have all non-pointer data.
1987
1988 void Traits::traceSlotsFromBitmap(MMgc::GC* gc, uint32_t* p, const FixedBitSet& traceInfo, uint32_t bitsUsed) const
1989 {
1990 for (uint32_t bit = 1; bit <= bitsUsed; bit++)
1991 {
1992 if (traceInfo.test(bit))
1993 {
1994#ifdef AVMPLUS_64BIT
1995 AvmAssert((uintptr_t(p) & 7) == 0)do { } while (0); // we had better be on an 8-byte boundary...
1996#endif
1997 avmplus::Atom a = *(const avmplus::Atom*)p;
1998 if (atomKind(a)((avmplus::Atom)((uintptr_t(a) & 7))) <= avmplus::AtomConstants::kNamespaceType)
1999 {
2000 // This includes untagged pointers to String, Namespace, ScriptObject.
2001 AvmAssert(atomPtr(a) == NULL || gc->IsRCObject(atomPtr(a)))do { } while (0);
2002 gc->TracePointer(atomPtr(a)((void*)(uintptr_t(a) & ~7)) HEAP_GRAPH_ARG((uintptr_t*)p));
2003 }
2004 else if (atomKind(a)((avmplus::Atom)((uintptr_t(a) & 7))) == avmplus::AtomConstants::kDoubleType)
2005 {
2006 AvmAssert(atomPtr(a) != NULL)do { } while (0);
2007 gc->TracePointer(atomPtr(a)((void*)(uintptr_t(a) & ~7)) HEAP_GRAPH_ARG((uintptr_t*)p));
2008 }
2009 }
2010 p++;
2011 }
2012 }
2013
2014 Stringp Traits::formatClassName()
2015 {
2016#ifdef VMCFG_CACHE_GQCN
2017 if (_fullname != NULL__null)
2018 return _fullname;
2019#endif
2020
2021 Multiname qname(ns(), name());
2022 qname.setQName();
2023 StringBuffer buffer(core);
2024 buffer << qname;
2025 int length = buffer.length();
2026 if (length && buffer.c_str()[length-1] == '$')
2027 {
2028 length--;
2029 }
2030#ifndef VMCFG_CACHE_GQCN
2031 Stringp _fullname;
2032#endif
2033 _fullname = core->newStringUTF8(buffer.c_str(), length);
2034 return _fullname;
2035 }
2036
2037
2038 Binding Traits::getOverride(TraitsBindingsp basetb, Namespacep ns, Stringp name, int tag, const Toplevel* toplevel) const
2039 {
2040 Binding baseBinding = BIND_NONE;
2041 if (base)
2042 {
2043 const Namespacep lookupNS = (protectedNamespace == ns && base->protectedNamespace) ? (Namespacep)base->protectedNamespace : ns;
2044 AvmAssert(basetb != NULL)do { } while (0);
2045 baseBinding = basetb->findBinding(name, lookupNS);
2046 }
2047 const BindingKind baseBindingKind = AvmCore::bindingKind(baseBinding);
2048
2049 const TraitKind kind = TraitKind(tag & 0x0f);
2050 // some extra-picky compilers will complain about the values being out of
2051 // range for the comparison (if we use "kind") even with explicit int casting.
2052 // so recycle the expression for the assert.
2053 AvmAssert((tag & 0x0f) >= 0 && (tag & 0x0f) < TRAIT_COUNT)do { } while (0);
2054
2055 static const uint8_t kDesiredKind[TRAIT_COUNT] =
2056 {
2057 BKIND_NONE, // TRAIT_Slot
2058 BKIND_METHOD, // TRAIT_Method
2059 BKIND_GET, // TRAIT_Getter
2060 BKIND_SET, // TRAIT_Setter
2061 BKIND_NONE, // TRAIT_Class
2062 BKIND_NONE, // TRAIT_Function
2063 BKIND_NONE // TRAIT_Const
2064 };
2065
2066 const BindingKind desiredKind = BindingKind(kDesiredKind[kind]);
2067 const uint8_t dkMask = uint8_t(1 << desiredKind);
2068
2069 // given baseBindingKind, what are legal desiredKinds?
2070 static const uint8_t kLegalBaseKinds[8] =
2071 {
2072 (1<<BKIND_METHOD) | (1<<BKIND_GET) | (1<<BKIND_SET), // BKIND_NONE
2073 (1<<BKIND_METHOD), // BKIND_METHOD
2074 0, // BKIND_VAR
2075 0, // BKIND_CONST
2076 0, // unused
2077 (1<<BKIND_GET) | (1<<BKIND_SET), // BKIND_GET
2078 (1<<BKIND_GET) | (1<<BKIND_SET), // BKIND_SET
2079 (1<<BKIND_GET) | (1<<BKIND_SET) // BKIND_GETSET
2080 };
2081
2082 // given baseBindingKind, which desiredKinds *require* override?
2083 static const uint8_t kOverrideRequired[8] =
2084 {
2085 0, // BKIND_NONE
2086 (1<<BKIND_METHOD), // BKIND_METHOD
2087 0, // BKIND_VAR
2088 0, // BKIND_CONST
2089 0, // unused
2090 (1<<BKIND_GET), // BKIND_GET
2091 (1<<BKIND_SET), // BKIND_SET
2092 (1<<BKIND_GET) | (1<<BKIND_SET) // BKIND_GETSET
2093 };
2094
2095 if ((kLegalBaseKinds[baseBindingKind] & dkMask) == 0)
2096 goto failure;
2097
2098 if (((kOverrideRequired[baseBindingKind] & dkMask) ? ATTR_override : 0) != (tag & ATTR_override))
2099 goto failure;
2100
2101 return baseBinding;
2102
2103failure:
2104
2105#ifdef AVMPLUS_VERBOSE
2106 if (pool->isVerbose(VB_traits) || pool->core->config.verifyonly)
2107 core->console << "illegal override in "<< this << ": " << Multiname(ns,name) <<"\n";
2108#endif
2109 if (toplevel)
2110 toplevel->throwVerifyError(kIllegalOverrideError, toplevel->core()->toErrorString(Multiname(ns,name)), toplevel->core()->toErrorString(this));
2111 AvmAssert(!"unhandled verify error")do { } while (0);
2112 return BIND_NONE;
2113 }
2114
2115 void Traits::ensureNonFinal(MethodInfo* minfo, const Toplevel* toplevel) const
2116 {
2117 if (!minfo->isFinal())
2118 return;
2119#ifdef AVMPLUS_VERBOSE
2120 if (pool->isVerbose(VB_traits))
2121 core->console << "illegal override of final "<< minfo << " in " << this <<"\n";
2122#endif
2123 toplevel->throwVerifyError(kIllegalOverrideError, toplevel->core()->toErrorString(minfo), toplevel->core()->toErrorString(this));
2124 AvmAssert(!"unhandled verify error")do { } while (0);
2125 }
2126
2127 TraitsBindings* FASTCALL__attribute__((fastcall)) Traits::_getTraitsBindings()
2128 {
2129 AvmAssert(m_bindingsVerified)do { } while (0);
2130 TraitsBindings* tb = _buildTraitsBindings(/*toplevel*/NULL__null, /*includeTypes*/m_resolved);
2131 return tb;
2132 }
2133
2134 TraitsMetadata* FASTCALL__attribute__((fastcall)) Traits::_getTraitsMetadata()
2135 {
2136 TraitsMetadata* tm = _buildTraitsMetadata();
2137 return tm;
2138 }
2139
2140 // Count supertypes in the given list, like strlen().
2141 static uint32_t countSupertypes(Traits** list)
2142 {
2143 uint32_t n = 0;
2144 for (Traits** t = list; *t != NULL__null; t++)
2145 n++;
2146 return n;
2147 }
2148
2149 // Initialize the m_primary_supertypes array by copying down the entries
2150 // from our base class (if it exists), and adding this traits if there is room.
2151 void Traits::build_primary_supertypes()
2152 {
2153 MMGC_STATIC_ASSERT(offsetof(Traits, m_primary_supertypes) + sizeof(m_primary_supertypes) < 256)typedef ::MMgc::static_assert_MMgc<sizeof (::MMgc::STATIC_ASSERTION_FAILED
<(bool)(__builtin_offsetof(Traits, m_primary_supertypes) +
sizeof(m_primary_supertypes) < 256)>)> MMgc_static_assert_line_2153
;
2154 MMGC_STATIC_ASSERT(offsetof(Traits, m_supertype_cache) < 256)typedef ::MMgc::static_assert_MMgc<sizeof (::MMgc::STATIC_ASSERTION_FAILED
<(bool)(__builtin_offsetof(Traits, m_supertype_cache) <
256)>)> MMgc_static_assert_line_2154
;
2155
2156 // compute m_supertype_offset and fill in m_primary_supertypes
2157 if (!base) {
2158 // class roots and interfaces
2159 m_supertype_offset = isInterface() ? offsetof(Traits, m_supertype_cache)__builtin_offsetof(Traits, m_supertype_cache) : offsetof(Traits, m_primary_supertypes)__builtin_offsetof(Traits, m_primary_supertypes);
2160 WB(core->gc, this, &m_primary_supertypes[0], this)core->gc->privateWriteBarrier(this, &m_primary_supertypes
[0], (const void *) (this))
;
2161 } else {
2162 // single inherited classes
2163 AvmAssert(!isInterface())do { } while (0);
2164 for (int i=0; i < MAX_PRIMARY_SUPERTYPE; i++)
2165 WB(core->gc, this, &m_primary_supertypes[i], base->m_primary_supertypes[i])core->gc->privateWriteBarrier(this, &m_primary_supertypes
[i], (const void *) (base->m_primary_supertypes[i]))
;
2166 size_t off = base->m_supertype_offset;
2167 if (off != offsetof(Traits, m_supertype_cache)__builtin_offsetof(Traits, m_supertype_cache) &&
2168 (off += sizeof(Traits*)) - offsetof(Traits, m_primary_supertypes)__builtin_offsetof(Traits, m_primary_supertypes) < sizeof(m_primary_supertypes)) {
2169 AvmAssert(off == (uint8_t) off)do { } while (0);
2170 m_supertype_offset = uint8_t(off);
2171 WB(core->gc, this, (Traits*)(uintptr_t(this)+off), this)core->gc->privateWriteBarrier(this, (Traits*)(uintptr_t
(this)+off), (const void *) (this))
;
2172 } else {
2173 // Inheritance is too deep to add this traits to m_primary_supertypes.
2174 // Make this traits "secondary", set m_supertype_offset to the cache.
2175 m_supertype_offset = offsetof(Traits, m_supertype_cache)__builtin_offsetof(Traits, m_supertype_cache);
2176 }
2177 }
2178 }
2179
2180 // Initialize the m_secondary_supertypes array as follows:
2181 // * if this traits adds a new interface, create a new list with all
2182 // the entries from the base class, plus the base class itself,
2183 // plus the new interfaces
2184 // * if we do not add new interfaces and there's no base class,
2185 // use the empty list.
2186 // * if there is a base class, and the base class is primary, just
2187 // copy base->m_secondary_supertypes (containing any base interfaces)
2188 // * otherwise create a new secondary_supertypes list with everything
2189 // from the base class, plus the base class itself. Install this list
2190 // back in the base class so it can be shared by other leaf classes.
2191 //
2192 // allocSupertypeList returns un-scanned memory as we expect the
2193 // super types to be otherwise reachable to the GC, we also use
2194 // WB_SKIP to tell the GC we're skipping the WB on purpose.
2195 void Traits::build_secondary_supertypes()
2196 {
2197 MMgc::GC* gc = core->GetGC();
2198 GCList<Traits> seen(gc, kListInitialCapacity);
2199 uint32_t count;
2200 if (!isInstanceType() || (count = countNewInterfaces(seen)) == 0) {
2201 // no new interfaces, attempt to share the base type's secondary list
2202 if (!base) {
2203 WB(gc, this, &this->m_secondary_supertypes, core->_emptySupertypeList)gc->privateWriteBarrier(this, &this->m_secondary_supertypes
, (const void *) (core->_emptySupertypeList))
;
2204 } else {
2205 Traits** base_list = base->m_secondary_supertypes;
2206 // If we require base in our secondary_supertypes list, so will other
2207 // sibling leaf types. Try to share the seconary_supertypes list by
2208 // inserting base at position 0.
2209 if (base->isPrimary() || base_list[0] == base) {
2210 // just copy the base list.
2211 WB(gc, this, &this->m_secondary_supertypes, base_list)gc->privateWriteBarrier(this, &this->m_secondary_supertypes
, (const void *) (base_list))
;
2212 } else {
2213 // must prepend base to base_list, save the copy on this type and base.
2214 count = countSupertypes(base_list);
2215 Traits** list = allocSupertypeList(gc, count + 1);
2216 WB_SKIP(gc, list, list, base)*(list) = base;
2217 for (uint32_t i=0; i < count; i++)
2218 WB_SKIP(gc, list, list+i+1, base_list[i])*(list+i+1) = base_list[i];
2219 WB(gc, base, &base->m_secondary_supertypes, list)gc->privateWriteBarrier(base, &base->m_secondary_supertypes
, (const void *) (list))
;
2220 WB(gc, this, &this->m_secondary_supertypes, list)gc->privateWriteBarrier(this, &this->m_secondary_supertypes
, (const void *) (list))
;
2221 }
2222 }
2223 } else {
2224 // this type implements new interfaces so we need a new list
2225 this->m_implementsNewInterfaces = truetrue;
2226 if (base && !base->isPrimary() && base->m_secondary_supertypes[0] != base) {
2227 seen.add(base);
2228 count++;
2229 }
2230 Traits** list;
2231 uint32_t baseCount = base ? countSupertypes(base->m_secondary_supertypes) : 0;
2232 if (baseCount > 0) {
2233 uint32_t total = count + baseCount;
2234 list = allocSupertypeList(gc, total);
2235 for (Traits **d = list, **s = base->m_secondary_supertypes; *s != NULL__null; s++, d++)
2236 WB_SKIP(gc, list, d, *s)*(d) = *s;
2237 } else {
2238 list = allocSupertypeList(gc, count);
2239 }
2240 WB(gc, this, &this->m_secondary_supertypes, list)gc->privateWriteBarrier(this, &this->m_secondary_supertypes
, (const void *) (list))
;
2241 for (uint32_t i=0; i < count; i++) {
2242 WB_SKIP(gc, list, list+baseCount+i, seen[i])*(list+baseCount+i) = seen[i];
2243 }
2244 }
2245
2246#ifdef DEBUG
2247 // sanity check to make sure we don't have any duplicate supertypes.
2248 GCList<Traits> supertypes(gc, kListInitialCapacity);
2249 for (int i = 0; i < MAX_PRIMARY_SUPERTYPE; i++) {
2250 Traits* t = m_primary_supertypes[i];
2251 if (t != NULL__null) {
2252 if (supertypes.indexOf(t) != -1) {
2253 core->console << "t " << this << " dup primary " << t << "\n";
2254 AvmAssert(false)do { } while (0);
2255 }
2256 supertypes.add(t);
2257 }
2258 }
2259 for (Traits** st = m_secondary_supertypes; *st != NULL__null; st++) {
2260 Traits* t = *st;
2261 if (supertypes.indexOf(t) != -1) {
2262 core->console << "t " << this << " dup secondary " << t << "\n";
2263 AvmAssert(false)do { } while (0);
2264 }
2265 supertypes.add(t);
2266 }
2267#endif
2268 }
2269
2270 // search interfaces and bases that didn't fit in m_primary_supertypes,
2271 // and cache positive/negative results
2272 boolbool Traits::secondary_subtypeof(Traits* t)
2273 {
2274 for (Traits** s = m_secondary_supertypes; *s != NULL__null; s++) {
2275 if (t == *s) {
2276 m_supertype_cache = t;
2277 return truetrue;
2278 }
2279 }
2280 m_supertype_neg_cache = t;
2281 return falsefalse;
2282 }
2283
2284 // create a new supertype list of the given length
2285 Traits** Traits::allocSupertypeList(GC* gc, uint32_t size)
2286 {
2287 // kContainsPointer left off on purpose, see comments in header.
2288 return (Traits**) gc->Alloc((size+1) * sizeof(Traits*), MMgc::GC::kZero);
2289 }
2290
2291 // Returns true if a value of type rhs can be assigned to a variable
2292 // or parameter of type lhs without modifying the representation of the value.
2293 // It is not just a subtypeof test, for example int is a subtype of Object
2294 // but they use different representations.
2295 boolbool Traits::canAssign(Traits* lhs, Traits* rhs)
2296 {
2297 if (!Traits::isMachineCompatible(lhs,rhs)) {
2298 // no machine type is assignment-compatible with any other
2299 return falsefalse;
2300 }
2301
2302 if (!lhs)
2303 return truetrue;
2304
2305 // type on right must be same class or subclass of type on left.
2306 Traits* t = rhs;
2307 while (t != lhs && t != NULL__null)
2308 t = t->base;
2309 return t != NULL__null;
2310 }
2311
2312 // Return the slot type (if slot), return type (if getter), or NULL.
2313 Traits* Traits::readBinding(Traits* traits, Binding b)
2314 {
2315 AvmAssert((!traits && AvmCore::bindingKind(b) == BKIND_NONE) ||do { } while (0)
2316 (traits && traits->isResolved()))do { } while (0);
2317 switch (AvmCore::bindingKind(b))
2318 {
2319 default:
2320 AvmAssert(false)do { } while (0); // internal error - illegal binding type
2321 case BKIND_GET:
2322 case BKIND_GETSET:
2323 {
2324 int m = AvmCore::bindingToGetterId(b);
2325 MethodInfo *f = traits->getTraitsBindings()->getMethod(m);
2326 MethodSignaturep fms = f->getMethodSignature();
2327 return fms->returnTraits();
2328 }
2329 case BKIND_SET:
2330 // TODO lookup type here. get/set must have same type.
2331 case BKIND_NONE:
2332 // dont know what this is
2333 // fall through
2334 case BKIND_METHOD:
2335 // extracted method or dynamic data, don't know which
2336 return NULL__null;
2337 case BKIND_VAR:
2338 case BKIND_CONST:
2339 return traits->getTraitsBindings()->getSlotTraits(AvmCore::bindingToSlotId(b));
2340 }
2341 }
2342
2343}