AvmCore.cpp

Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is [Open Source Virtual Machine.].
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Adobe System Incorporated.
00018  * Portions created by the Initial Developer are Copyright (C) 1993-2006
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Adobe AS3 Team
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 
00039 #include "avmplus.h"
00040 #ifdef AVMPLUS_MIR
00041 #include "CodegenMIR.h"
00042 #endif
00043 
00044 #if (defined(_MSC_VER) || defined(__GNUC__)) && (defined(AVMPLUS_IA32) || defined(AVMPLUS_AMD64))
00045     #include <emmintrin.h>
00046 #endif
00047 
00048 namespace avmplus
00049 {
00050     using namespace MMgc;
00051 
00052     BEGIN_NATIVE_CLASSES(AvmCore)
00053         NATIVE_CLASS(abcclass_Object,               ObjectClass,    ScriptObject)
00054         NATIVE_CLASS(abcclass_Class,                ClassClass,     ClassClosure)
00055         NATIVE_CLASS(abcclass_Namespace,            NamespaceClass, Namespace)
00056         NATIVE_CLASS(abcclass_Function,             FunctionClass,  ClassClosure)
00057         NATIVE_CLASS(abcclass_builtin_as_0_MethodClosure,           MethodClosureClass, MethodClosure)
00058 
00059         NATIVE_CLASS(abcclass_Error,                ErrorClass, ErrorObject)
00060 
00061         // The Error subclasses are included in the NATIVE_CLASS map
00062         // so that their [[Call]] action is mapped to [[Construct]]
00063         NATIVE_CLASS(abcclass_DefinitionError,      NativeErrorClass, ErrorObject)
00064         NATIVE_CLASS(abcclass_EvalError,            NativeErrorClass, ErrorObject)
00065         NATIVE_CLASS(abcclass_RangeError,           NativeErrorClass, ErrorObject)
00066         NATIVE_CLASS(abcclass_ReferenceError,       NativeErrorClass, ErrorObject)
00067         NATIVE_CLASS(abcclass_SecurityError,        NativeErrorClass, ErrorObject)
00068         NATIVE_CLASS(abcclass_SyntaxError,          NativeErrorClass, ErrorObject)
00069         NATIVE_CLASS(abcclass_TypeError,            NativeErrorClass, ErrorObject)
00070         NATIVE_CLASS(abcclass_URIError,             NativeErrorClass, ErrorObject)
00071         NATIVE_CLASS(abcclass_VerifyError,          NativeErrorClass, ErrorObject)
00072         NATIVE_CLASS(abcclass_UninitializedError,   NativeErrorClass, ErrorObject)
00073         NATIVE_CLASS(abcclass_ArgumentError,        NativeErrorClass, ErrorObject)
00074 
00075         NATIVE_CLASS(abcclass_String,               StringClass,    String)
00076         NATIVE_CLASS(abcclass_Boolean,          BooleanClass,   bool)
00077         NATIVE_CLASS(abcclass_Number,               NumberClass,    double)
00078         NATIVE_CLASS(abcclass_int,              IntClass,       int)
00079         NATIVE_CLASS(abcclass_uint,             UIntClass,      uint32)
00080         NATIVE_CLASS(abcclass_Math,             MathClass,      double)
00081         NATIVE_CLASS(abcclass_Array,                ArrayClass,     ArrayObject)
00082         NATIVE_CLASS(abcclass_RegExp,               RegExpClass,    RegExpObject)
00083         NATIVE_CLASS(abcclass_Date,             DateClass,      DateObject)
00084 
00085         // Vector
00086         NATIVE_CLASS(abcclass___AS3___vec_Vector_int,     IntVectorClass,      IntVectorObject)     
00087         NATIVE_CLASS(abcclass___AS3___vec_Vector_uint,    UIntVectorClass,     UIntVectorObject)        
00088         NATIVE_CLASS(abcclass___AS3___vec_Vector_double,  DoubleVectorClass,   DoubleVectorObject)  
00089         NATIVE_CLASS(abcclass___AS3___vec_Vector,         VectorClass,         ObjectVectorObject)      
00090         NATIVE_CLASS(abcclass___AS3___vec_Vector_object,  ObjectVectorClass,  ObjectVectorObject)       
00091 
00092         // E4X
00093         NATIVE_CLASS(abcclass_XML,              XMLClass,       XMLObject)
00094         NATIVE_CLASS(abcclass_XMLList,          XMLListClass,   XMLListObject)
00095         NATIVE_CLASS(abcclass_QName,            QNameClass,     QNameObject)
00096     END_NATIVE_CLASSES()
00097 
00098     // don't need toplevel here because we create it manually
00099     BEGIN_NATIVE_SCRIPTS(AvmCore)
00100         NATIVE_SCRIPT(0, Toplevel)
00101     END_NATIVE_SCRIPTS()
00102 
00103     AvmCore::AvmCore(GC *g) : GCRoot(g), console(NULL), gc(g), 
00104 #ifdef AVMPLUS_MIR
00105         mirBuffers(g, 4), 
00106 #endif
00107         gcInterface(g)
00108 #ifdef FEATURE_SAMPLER
00109         ,_sampler(g)
00110 #endif
00111 #ifdef AVMPLUS_WORD_CODE
00112         , lookup_cache_timestamp(1)
00113 #endif
00114     {
00115         // sanity check for all our types
00116         AvmAssert (sizeof(int8) == 1);
00117         AvmAssert (sizeof(uint8) == 1);     
00118         AvmAssert (sizeof(int16) == 2);
00119         AvmAssert (sizeof(uint16) == 2);
00120         AvmAssert (sizeof(int32) == 4);
00121         AvmAssert (sizeof(uint32) == 4);
00122         AvmAssert (sizeof(int64) == 8);
00123         AvmAssert (sizeof(uint64) == 8);
00124         AvmAssert (sizeof(sintptr) == sizeof(void *));
00125         AvmAssert (sizeof(uintptr) == sizeof(void *));
00126         #ifdef AVMPLUS_64BIT
00127         AvmAssert (sizeof(sintptr) == 8);
00128         AvmAssert (sizeof(uintptr) == 8);       
00129         #else
00130         AvmAssert (sizeof(sintptr) == 4);
00131         AvmAssert (sizeof(uintptr) == 4);       
00132         #endif  
00133             
00134         // set default mode flags
00135         #ifdef AVMPLUS_VERBOSE
00136         config.verbose = false;
00137         config.verbose_addrs = false;
00138         #endif
00139 
00140         #ifdef AVMPLUS_ARM
00141         SetMIREnabled(false);
00142         #else
00143         SetMIREnabled(true);
00144         #endif
00145 
00146         #ifdef AVMPLUS_VERIFYALL
00147             config.verifyall = false;
00148         #endif
00149 
00150         #ifdef FEATURE_NANOJIT
00151             config.show_stats = false;
00152             config.tree_opt = false;
00153             config.verbose_live = false;;
00154             config.verbose_exits = false;
00155         #endif
00156 
00157         #ifdef AVMPLUS_MIR
00158             config.dceopt = true;
00159             #ifdef AVMPLUS_VERBOSE
00160             config.bbgraph = false;
00161             #endif
00162         #endif
00163 
00164         #if defined AVMPLUS_MIR || defined FEATURE_NANOJIT
00165             // jit flag forces use of MIR/LIR instead of interpreter
00166             config.jit = false;
00167             config.cseopt = true;
00168 
00169             #if defined(AVMPLUS_IA32) || defined(AVMPLUS_AMD64)
00170             config.sse2 = true;
00171             #endif
00172         #endif
00173 
00174     #ifdef VTUNE
00175             VTuneStatus = CheckVTuneStatus();
00176     #endif // VTUNE
00177 
00178         config.interrupts = false;
00179 
00180         gcInterface.SetCore(this);
00181         resources          = NULL;
00182         xmlEntities        = NULL;
00183         exceptionFrame     = NULL;
00184         exceptionAddr      = NULL;
00185         builtinPool        = NULL;
00186         builtinDomain      = NULL;
00187 
00188         GetGC()->SetGCContextVariable (MMgc::GC::GCV_AVMCORE, this);
00189 
00190         minstack           = 0;
00191 
00192 #ifdef FEATURE_SAMPLER
00193         _sampler.setCore(this);
00194 #endif
00195 
00196         #ifdef DEBUGGER
00197         langID             = -1;
00198         debugger           = NULL;
00199         profiler           = NULL;
00200         passAllExceptionsToDebugger = false;
00201         #endif /* DEBUGGER */
00202 
00203         callStack          = NULL;
00204 
00205 #ifdef FEATURE_SAMPLER
00206         MMgc::m_sampler = sampler();
00207 #endif
00208 
00209         interrupted        = false;
00210 
00211         codeContextAtom    = CONTEXT_NONE;
00212         dxnsAddr           = NULL;
00213         
00214         strings         = NULL;
00215         numStrings      = 0;
00216         namespaces      = NULL;
00217         numNamespaces   = 0;
00218         stringCount     = 0;
00219         deletedCount    = 0;
00220         nsCount         = 0;
00221 
00222         numStrings = 1024; // power of 2
00223         strings = new DRC(Stringp)[numStrings];
00224         memset(strings, 0, numStrings*sizeof(Stringp));
00225 
00226         numNamespaces = 1024;  // power of 2
00227         namespaces = new DRC(Namespacep)[numNamespaces];
00228         memset(namespaces, 0, numNamespaces*sizeof(Namespace*));
00229 
00230         console.setCore(this);
00231         
00232         kEmptyString = constantString("");
00233         kconstructor = constantString("constructor");
00234         kundefined = constantString("undefined");
00235         knull = constantString("null");
00236         ktrue = constantString("true");
00237         kfalse = constantString("false");
00238         ktoString = constantString("toString");
00239         ktoLocaleString = constantString("toLocaleString");
00240         kvalueOf = constantString("valueOf");
00241         klength = constantString("length");
00242 
00243         kobject = constantString("object");
00244         kboolean = constantString("boolean");
00245         knumber = constantString("number");
00246         kstring = constantString("string");
00247         kxml = constantString("xml");
00248         kfunction = constantString("function");
00249         kglobal = constantString("global");
00250         kcallee = constantString("callee");
00251 
00252         kuri = constantString("uri");
00253         kprefix = constantString("prefix");
00254         kNaN = doubleToAtom(MathUtils::nan());
00255         kNeedsDxns = constantString("NeedsDxns");
00256         kAsterisk = constantString("*");
00257         kVersion = constantString("Version");
00258         kVector = constantString("Vector.<");
00259 
00260 #ifdef AVMPLUS_VERBOSE
00261         knewline = newString("\n");
00262         krightbracket = newString("]");
00263         kleftbracket = newString("[");
00264         kcolon = newString(":");
00265         ktabat = newString("\tat ");
00266         kparens = newString("()");
00267 #endif
00268 #if defined AVMPLUS_VERBOSE || defined FEATURE_SAMPLER
00269         kanonymousFunc = newString("<anonymous>");
00270 #endif
00271         for (int i = 0; i < 128; i++)
00272         {
00273             char singleChar = (char)i;
00274             // call newString() with an explicit length of 1; required
00275             // when singleChar==0, because in that case we need a string
00276             // which is a single character with value 0
00277             cachedChars[i] = internString(newString(&singleChar, 1));
00278         }
00279 
00280         booleanStrings[0] = kfalse;
00281         booleanStrings[1] = ktrue;
00282 
00283 #ifdef AVMPLUS_INTERNINT_CACHE
00284         // See code in AvmCore::internInt
00285         for (int i=0 ; i < 256 ; i++ )
00286             index_strings[i] = NULL;
00287 #endif
00288 
00289         // create public namespace 
00290         publicNamespace = internNamespace(newNamespace(kEmptyString));
00291 
00292         #if defined AVMPLUS_MIR && defined(AVMPLUS_VERBOSE)
00293         codegenMethodNames = CodegenMIR::initMethodNames(this);
00294         #endif
00295 
00296         #ifdef FEATURE_JNI
00297         java = NULL;
00298         #endif
00299 #ifdef SUPERWORD_PROFILING
00300         swprofStart();
00301 #endif
00302     }
00303 
00304     AvmCore::~AvmCore()
00305     {       
00306         // Free the numbers and strings tables
00307         delete [] strings;
00308         if (gc) 
00309         {
00310             gc->SetGCContextVariable(GC::GCV_AVMCORE, NULL);
00311         }
00312 
00313         #if defined AVMPLUS_MIR && defined(AVMPLUS_VERBOSE)
00314         delete codegenMethodNames;
00315         #endif
00316 
00317         strings = NULL;
00318 
00319         delete [] namespaces;
00320         namespaces = NULL;
00321 
00322 #ifdef AVMPLUS_MIR
00323         // free all the mir buffers
00324         while(mirBuffers.size() > 0)
00325             mirBuffers.removeFirst()->free();
00326 #endif
00327 #ifdef SUPERWORD_PROFILING
00328         swprofStop();
00329 #endif
00330     }
00331 
00332     void AvmCore::initBuiltinPool()
00333     {
00334         using namespace NativeID;
00335 
00336         // stack allocated array of pointers
00337         AbstractFunction* nativeMethods[builtin_abc_method_count];
00338         NativeClassInfop nativeClasses[builtin_abc_class_count];
00339         NativeScriptInfop nativeScripts[builtin_abc_script_count];
00340 
00341         memset(nativeMethods, 0, sizeof(AbstractFunction*)*builtin_abc_method_count);
00342         memset(nativeClasses, 0, sizeof(NativeClassInfop)*builtin_abc_class_count);
00343         memset(nativeScripts, 0, sizeof(NativeScriptInfop)*builtin_abc_script_count);
00344 
00345         initNativeTables(classEntries, scriptEntries,
00346             nativeMethods, nativeClasses, nativeScripts);
00347 
00348         ScriptBuffer code = ScriptBuffer(new (GetGC()) ReadOnlyScriptBufferImpl (builtin_abc_data, builtin_abc_length));
00349 
00350         builtinDomain = new (GetGC()) Domain(this, NULL);
00351         
00352         builtinPool = parseActionBlock(code, 0, NULL,
00353                                        builtinDomain,
00354                                        nativeMethods,
00355                                        nativeClasses,
00356                                        nativeScripts);
00357 
00358         // whack the the non-interruptable bit on all builtin functions
00359         for(int i=0, size=builtinPool->methods.size(); i<size; i++)
00360             builtinPool->methods[i]->flags |= AbstractFunction::NON_INTERRUPTABLE;
00361 
00362         for(int i=0, size=builtinPool->cinits.size(); i<size; i++)
00363             builtinPool->cinits[i]->flags |= AbstractFunction::NON_INTERRUPTABLE;
00364 
00365         for(int i=0, size=builtinPool->scripts.size(); i<size; i++)
00366             builtinPool->scripts[i]->flags |= AbstractFunction::NON_INTERRUPTABLE;
00367 
00368 #ifdef FEATURE_SAMPLER
00369         // sampling can begin now, requires builtinPool
00370         _sampler.initSampling();
00371 #endif
00372     }
00373     
00374     Toplevel* AvmCore::initTopLevel()
00375     {
00376         Toplevel* toplevel = NULL;
00377         handleActionPool(builtinPool, NULL, toplevel, NULL);
00378         return toplevel;
00379     }
00380 
00381     ScriptEnv* AvmCore::prepareActionPool(PoolObject* pool,
00382                                           DomainEnv* domainEnv,
00383                                           Toplevel*& toplevel,
00384                                           CodeContext* codeContext)
00385     {
00386         AvmAssert(pool != NULL);
00387 
00388         // get the main entry point and its global traits
00389         if (pool->scriptCount == 0)
00390         {
00391             toplevel->verifyErrorClass()->throwError(kMissingEntryPointError);
00392         }
00393 
00394         if (domainEnv == NULL)
00395         {
00396             // create a new DomainEnv based on the builtinDomain
00397             domainEnv = new (GetGC()) DomainEnv(this, builtinDomain, NULL);
00398         }
00399 
00400         AbcEnv* abcEnv = new (GetGC(), AbcEnv::calcExtra(pool)) AbcEnv(pool, domainEnv, codeContext);
00401 
00402         // entry point is the last script in the file
00403         Traits* mainTraits = pool->scripts[pool->scriptCount-1]->declaringTraits;
00404 
00405         // ISSUE can we just make this the public namespace?
00406         ScopeChain* emptyScope = ScopeChain::create(GetGC(), mainTraits->scope, NULL, newNamespace(kEmptyString));
00407 
00408         VTable* object_vtable;
00409         if (toplevel == NULL)
00410         {
00411             // create a temp object vtable to use, since the real one isn't created yet
00412             // later, in OP_newclass, we'll replace with the real Object vtable, so methods
00413             // of Object and Class have the right scope.
00414 
00415             object_vtable = newVTable(traits.object_itraits, NULL, emptyScope, abcEnv, NULL);
00416             object_vtable->resolveSignatures();
00417             mainTraits->sizeofInstance = (uint32_t)getToplevelSize();
00418         }
00419         else
00420         {
00421             object_vtable = toplevel->object_vtable;
00422         }
00423 
00424         // global objects are subclasses of Object
00425         VTable* mainVTable = newVTable(mainTraits, object_vtable, emptyScope, abcEnv, toplevel);
00426         ScriptEnv* main = new (GetGC()) ScriptEnv(mainTraits->init, mainVTable);
00427         mainVTable->init = main;
00428 
00429         if (toplevel == NULL)
00430         {
00431             mainVTable->resolveSignatures();
00432             main->global = toplevel = createToplevel(mainVTable);
00433 
00434             // save toplevel since it was initially null 
00435             mainVTable->toplevel = toplevel;
00436             object_vtable->toplevel = toplevel;
00437             domainEnv->setToplevel(toplevel);
00438 
00439             // create temporary vtable for Class, so we have something for OP_newclass
00440             // to use when it creates Object$ and Class$.  once that happens, we replace
00441             // with the real Class$ vtable.
00442             toplevel->class_vtable = newVTable(traits.class_itraits, 
00443                 object_vtable, emptyScope, abcEnv, toplevel);
00444             toplevel->class_vtable->resolveSignatures();
00445 
00446             traits.function_itraits->resolveSignatures(toplevel);
00447         }
00448 
00449         exportDefs(mainTraits, main);
00450 
00451         // prepare the remaining scriptEnv's
00452         for (int i=0, n=pool->scriptCount-1; i < n; i++)
00453         {
00454             AbstractFunction* script = pool->scripts[i];
00455 
00456             Traits* scriptTraits = script->declaringTraits;
00457             // [ed] 3/24/06 why do we really care if a script is dynamic or not?
00458             //AvmAssert(scriptTraits->needsHashtable);
00459 
00460             VTable* scriptVTable = newVTable(scriptTraits, object_vtable, emptyScope, abcEnv, toplevel);
00461             ScriptEnv* scriptEnv = new (GetGC()) ScriptEnv(scriptTraits->init, scriptVTable);
00462             scriptVTable->init = scriptEnv;
00463             exportDefs(scriptTraits, scriptEnv);
00464         }
00465 
00466         return main;
00467     }
00468 
00469     Atom AvmCore::handleActionPool(PoolObject* pool,
00470                                         DomainEnv* domainEnv,
00471                                         Toplevel* &toplevel,
00472                                         CodeContext* codeContext)
00473     {
00474         bool createdToplevel = (toplevel == NULL);
00475 
00476         ScriptEnv* main = prepareActionPool(pool, domainEnv, toplevel, codeContext);
00477 
00478         if (!createdToplevel)
00479         {
00480             main->initGlobal();
00481         }
00482         
00483         Atom result = 0; // init to zero to make GCC happy
00484         #ifndef DEBUGGER
00485         result = main->coerceEnter(main->global->atom());
00486         #else
00487         TRY(this, kCatchAction_Rethrow)
00488         {
00489             result = main->coerceEnter(main->global->atom());
00490         }
00491         CATCH(Exception *exception)
00492         {
00493             // Re-throw exception
00494             throwException(exception);
00495         }
00496         END_CATCH
00497         END_TRY
00498         #endif
00499 
00500         return result;
00501     }
00502     
00503     void AvmCore::exportDefs(Traits* scriptTraits, ScriptEnv* scriptEnv)
00504     {
00505         DomainEnv* domainEnv = scriptEnv->domainEnv();
00506         AbcEnv* abcEnv = scriptEnv->abcEnv();
00507 
00508         // iterate thru each of the definitions exported by this script
00509         int i=0;
00510         while((i=scriptTraits->next(i)) != 0)
00511         {
00512             // don't need to check for DELETED because we never remove trait bindings
00513             AvmAssert(scriptTraits->keyAt(i) != NULL);
00514             Stringp name = scriptTraits->keyAt(i);
00515             Namespace* ns = scriptTraits->nsAt(i);
00516                 
00517             // not already in the table then export it 
00518             // otherwise we keep the first one that was encountered.
00519             if (!ns->isPrivate())
00520             {               
00521                 if (!domainEnv->getNamedScript(name, ns))
00522                 {
00523                     // add ns/name to global table
00524                     // ISSUE should we filter out Object traits and/or private members?
00525                     #ifdef AVMPLUS_VERBOSE
00526                     if (scriptTraits->pool->verbose)
00527                         console << "exporting " << ns << "::" << name << "\n";
00528                     #endif
00529                     domainEnv->addNamedScript(name, ns, (Binding)scriptEnv);
00530                 }
00531             }
00532             else
00533             {
00534                 if (!abcEnv->privateScriptEnvs.get(name, ns))
00535                 {
00536                     abcEnv->privateScriptEnvs.add(name, ns, (Binding) scriptEnv);
00537                 }
00538             }
00539         }
00540 #ifdef AVMPLUS_WORD_CODE
00541         // Adding scripts to a domain always invalidates the lookup cache.
00542         invalidateLookupCache();
00543 #endif
00544     }
00545 
00546     PoolObject* AvmCore::parseActionBlock(ScriptBuffer code,
00547                                           int /*start*/,
00548                                           Toplevel* toplevel,
00549                                           Domain* domain,
00550                                           AbstractFunction *nativeMethods[],
00551                                           NativeClassInfop nativeClasses[],
00552                                           NativeScriptInfop nativeScripts[],
00553                                           List<Stringp>* include_versions)
00554     {
00555         // parse constants and attributes.
00556         PoolObject* pool = AbcParser::decodeAbc(this,
00557                                                 code,
00558                                                 toplevel,
00559                                                 domain,
00560                                                 nativeMethods,
00561                                                 nativeClasses,
00562                                                 nativeScripts,
00563                                                 include_versions);
00564 
00565         #ifdef DEBUGGER
00566         if (debugger) {
00567             debugger->processAbc(pool, code);
00568         }
00569         #endif /* DEBUGGER */
00570 
00571         return pool;
00572     }
00573     
00574     Atom AvmCore::handleActionBlock(ScriptBuffer code,
00575                                          int start,
00576                                          DomainEnv* domainEnv,
00577                                          Toplevel* &toplevel,
00578                                          AbstractFunction *nativeMethods[],
00579                                          NativeClassInfop nativeClasses[],
00580                                          NativeScriptInfop nativeScripts[],
00581                                          CodeContext *codeContext)
00582     {
00583         resources = new (GetGC()) Hashtable(GetGC());
00584 
00585         // have we parsed this before?
00586         PoolObject* pool;
00587         Atom resourceAtom = resources->get(start+1);
00588         if (resourceAtom != undefinedAtom) 
00589         {
00590             pool = (PoolObject*) resourceAtom;
00591         } 
00592         else 
00593         {
00594             Domain* domain = domainEnv ? domainEnv->getDomain() : builtinDomain;
00595             
00596             // parse constants and attributes.
00597             pool = parseActionBlock(code,
00598                                     start,
00599                                     toplevel,
00600                                     domain,
00601                                     nativeMethods,
00602                                     nativeClasses,
00603                                     nativeScripts);
00604             if (pool != NULL)
00605             {
00606                 resources->put(start+1, pool);
00607             }
00608         }
00609 
00610         return handleActionPool(pool, domainEnv, toplevel, codeContext);
00611     }
00612 
00613     Traits* AvmCore::makeParameterizedITraits(Stringp name, Namespace* ns, Traits* t)
00614     {
00615         Traits* newtraits = newTraits(t, 0, 0, t->sizeofInstance);
00616         newtraits->name = name;
00617         newtraits->ns = ns;
00618         newtraits->slotCount = t->slotCount;
00619         newtraits->methodCount = t->methodCount;
00620         newtraits->needsHashtable = t->needsHashtable;
00621         return newtraits;
00622     }
00623 
00624     Traits* AvmCore::makeParameterizedCTraits(Stringp name, Namespace* ns, Traits* t)
00625     {
00626         Traits* newtraits = newTraits(t->base, 0, 0, t->sizeofInstance);
00627         newtraits->name = name;
00628         newtraits->ns = ns;
00629         newtraits->slotCount = t->base->slotCount;
00630         newtraits->methodCount = t->base->methodCount;
00631         newtraits->needsHashtable = t->needsHashtable;
00632         return newtraits;
00633     }
00634 
00635 /*
00636 11.9.3 The Abstract Equality Comparison Algorithm
00637 The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as
00638 follows:
00639 E4X - 0a. if x is XMLList, call [[Equals]] method of x with argument y and return
00640 E4X - 0b. if y is XMLList, call [[Equals]] method of y with argument x and return
00641 1. If Type(x) is different from Type(y), go to step 14.
00642 E4X - 1a. If x is XML and y is XML
00643     if x.class = text/attribute && y.class == text/attribute, do string compare
00644     else to x.[[Equals]](y)
00645 E4X - 1b If x and y are QName
00646     return uri=uri and localname==localName
00647 E4X - 1c if x and y are Namespaces
00648     return uri == uri
00649 2. If Type(x) is Undefined, return true.
00650 3. If Type(x) is Null, return true.
00651 4. If Type(x) is not Number, go to step 11.
00652 5. If x is NaN, return false.
00653 6. If y is NaN, return false.
00654 7. If x is the same number value as y, return true.
00655 8. If x is +0 and y is -0, return true.
00656 9. If x is -0 and y is +0, return true.
00657 10. Return false.
00658 11. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and
00659 same characters in corresponding positions). Otherwise, return false.
00660 12. If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
00661 13. Return true if x and y refer to the same object or if they refer to objects joined to each other (section 13.1.2).
00662 Otherwise, return false.
00663 
00664 // Different types below here
00665 E4X 14a. if (x is xml) and x.hasSimpleContent = true or (y is xml) and y.hasSimlpeContent = true
00666     return the results of tostring(x) and tostring(y)
00667 
00668 14. If x is null and y is undefined, return true.
00669 15. If x is undefined and y is null, return true.
00670 16. If Type(x) is Number and Type(y) is String,
00671 return the result of the comparison x == ToNumber(y).
00672 17. If Type(x) is String and Type(y) is Number,
00673 return the result of the comparison ToNumber(x) == y.
00674 18. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
00675 19. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
00676 20. If Type(x) is either String or Number and Type(y) is Object,
00677 return the result of the comparison x == ToPrimitive(y).
00678 21. If Type(x) is Object and Type(y) is either String or Number,
00679 return the result of the comparison ToPrimitive(x) == y.
00680 22. Return false.
00681     */
00682 
00683     Atom AvmCore::equals(Atom lhs, Atom rhs)
00684     {
00685         if (isNull(lhs)) lhs = 0;
00686         if (isNull(rhs)) rhs = 0;
00687 
00688         int ltype = (int)(lhs & 7);
00689         int rtype = (int)(rhs & 7);
00690 
00691         // See E4X 11.5.1, pg 53.  
00692         if ((ltype == kObjectType) && (isXMLList(lhs)))
00693             return atomToXMLList (lhs)->_equals (rhs);
00694         else if ((rtype == kObjectType) && (isXMLList(rhs)))
00695             return atomToXMLList (rhs)->_equals (lhs);
00696 
00697         if (ltype == rtype)
00698         {
00699             // same type
00700             switch (ltype)
00701             {
00702             case 0:
00703             case kSpecialType:
00704                 return trueAtom;
00705             case kStringType:
00706                 if (lhs == rhs) return trueAtom;
00707                 return (*atomToString(lhs) == *atomToString(rhs)) ? trueAtom : falseAtom;
00708             case kBooleanType:
00709             case kIntegerType:
00710                 return lhs == rhs ? trueAtom : falseAtom;
00711             case kNamespaceType:
00712                 // E4X 11.5.1, pg 53
00713                 return atomToNamespace(lhs)->EqualTo(atomToNamespace(rhs))? trueAtom : falseAtom;
00714             case kObjectType:
00715             {
00716                 // E4X 11.5.1, pg 53
00717                 if (lhs == rhs)
00718                     return trueAtom;
00719                 if (isXML(lhs) && isXML(rhs))
00720                 {
00721                     XMLObject *x = atomToXMLObject (lhs);
00722                     XMLObject *y = atomToXMLObject (rhs);
00723                     if ((((x->getClass() & (E4XNode::kText | E4XNode::kCDATA | E4XNode::kAttribute))) && y->hasSimpleContent()) ||
00724                         (((y->getClass() & (E4XNode::kText | E4XNode::kCDATA | E4XNode::kAttribute))) && x->hasSimpleContent()))
00725                     {
00726                         return ((*string(lhs) == *string(rhs)) ? trueAtom : falseAtom);
00727                     }   
00728                     else
00729                     {
00730                         return x->getNode()->_equals (this, y->getNode());
00731                     }
00732                 }
00733                 else if (isQName(lhs) && isQName(rhs))
00734                 {
00735                     QNameObject *qn1 = atomToQName (lhs);
00736                     QNameObject *qn2 = atomToQName (rhs);
00737                     return (((qn1->getURI() == qn2->getURI()) && (qn1->getLocalName() == qn2->getLocalName()))? trueAtom : falseAtom);
00738                 }
00739                 else
00740                 {
00741                     return falseAtom;
00742                 }
00743             }
00744             case kDoubleType:
00745                 // C++ portability note -- if either arg is NaN, java == returns false, which matches ECMA.
00746                 return atomToDouble(lhs) == atomToDouble(rhs) ? trueAtom : falseAtom;
00747             }
00748         }
00749         else
00750         {
00751             if (isNullOrUndefined(lhs) && isNullOrUndefined(rhs))
00752                 return trueAtom;
00753             if (ltype == kIntegerType && rtype == kDoubleType)
00754                 return ((double)(lhs>>3)) == atomToDouble(rhs) ? trueAtom : falseAtom;
00755             if (ltype == kDoubleType && rtype == kIntegerType)
00756                 return atomToDouble(lhs) == ((double)(rhs>>3)) ? trueAtom : falseAtom;
00757 
00758             // 16. If Type(x) is Number and Type(y) is String,
00759             // return the result of the comparison x == ToNumber(y).
00760             if (isNumber(lhs) && isString(rhs))
00761                 return equals(lhs, doubleToAtom(number(rhs)));
00762             
00763             // 17. If Type(x) is String and Type(y) is Number,
00764             // return the result of the comparison ToNumber(x) == y.
00765             if (isString(lhs) && isNumber(rhs))
00766                 return equals(doubleToAtom(number(lhs)), rhs);
00767 
00768             // E4X 11.5.1, step 4.  Placed slightly lower then in the spec
00769             // to handle quicker cases earlier.  No cases above should be comparing
00770             // an object to a non-object
00771             if (((ltype == kObjectType) && isXML(lhs) && atomToXMLObject(lhs)->hasSimpleContent()) || 
00772                 ((rtype == kObjectType) && isXML(rhs) && atomToXMLObject(rhs)->hasSimpleContent()))
00773             {
00774                 return ((*string(lhs) == *string(rhs)) ? trueAtom : falseAtom);
00775             }
00776 
00777             // 18. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
00778             if (ltype == kBooleanType)
00779                 return equals(lhs&~7|kIntegerType, rhs);  // equal(toInteger(lhs), rhs)
00780             
00781             // 19. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
00782             if (rtype == kBooleanType)
00783                 return equals(lhs, rhs&~7|kIntegerType);  // equal(lhs, toInteger(rhs))
00784 
00785             // 20. If Type(x) is either String or Number and Type(y) is Object,
00786             // return the result of the comparison x == ToPrimitive(y).
00787 
00788             if ((isString(lhs) || isNumber(lhs)) && rtype == kObjectType)
00789                 return equals(lhs, atomToScriptObject(rhs)->defaultValue());
00790 
00791             // 21. If Type(x) is Object and Type(y) is either String or Number,
00792             // return the result of the comparison ToPrimitive(x) == y.
00793             if ((isString(rhs) || isNumber(rhs)) && ltype == kObjectType)
00794                 return equals(atomToScriptObject(lhs)->defaultValue(), rhs);
00795         }
00796         return falseAtom;
00797     }
00798 
00805     Atom AvmCore::compare(Atom lhs, Atom rhs)
00806     {
00807         // fixme - toprimitive must take number hint, so "7" becomes 7
00808         if ((lhs&7)==kIntegerType && (rhs&7)==kIntegerType)
00809         {
00810             // fast path for integers
00811             return lhs < rhs ? trueAtom : falseAtom;
00812         }
00813 
00814         lhs = primitive(lhs);
00815         rhs = primitive(rhs);
00816         
00817         if (isString(lhs) && isString(rhs))
00818         {
00819             // string compare. todo optimize!
00820             return *string(lhs) < *string(rhs) ? trueAtom : falseAtom;
00821         }
00822 
00823         // numeric compare
00824         double dx = number(lhs);
00825         double dy = number(rhs);
00826         if (MathUtils::isNaN(dx)) return undefinedAtom;
00827         if (MathUtils::isNaN(dy)) return undefinedAtom;
00828         return dx < dy ? trueAtom : falseAtom;
00829     }
00830 
00831     Atom AvmCore::stricteq(Atom lhs, Atom rhs)
00832     {
00833         if (isNull(lhs)) return isNull(rhs) ? trueAtom : falseAtom;
00834         if (isNull(rhs)) return falseAtom; // We already know that lhs is not null
00835 
00836         int ltype = lhs & 7;
00837         int rtype = rhs & 7;
00838         if (ltype == rtype)
00839         {
00840             // same type
00841             switch (ltype)
00842             {
00843             case kSpecialType:
00844                 return trueAtom; // undefined is the only kSpecialType atom 
00845             case kStringType:
00846                 return (lhs==rhs || *string(lhs) == *string(rhs)) ? trueAtom : falseAtom;
00847             case kBooleanType:
00848             case kIntegerType:
00849             case kNamespaceType:
00850                 return lhs == rhs ? trueAtom : falseAtom;
00851             case kObjectType:
00852             {
00853                 if (lhs == rhs)
00854                     return trueAtom;
00855                 if (isXML(lhs) && isXML(rhs))
00856                 {
00857                     E4XNode *lhn = atomToXML (lhs);
00858                     E4XNode *rhn = atomToXML (rhs);
00859                     return ((lhn == rhn) ? trueAtom : falseAtom);
00860                 }
00861                 return falseAtom;
00862             }   
00863             case kDoubleType:
00864                 // C++ portability note -- if either arg is NaN, java == returns false, which matches ECMA.
00865                 return atomToDouble(lhs) == atomToDouble(rhs) ? trueAtom : falseAtom;
00866             }
00867         }
00868         // Sometimes ints can hide in double atoms (neg zero for one)
00869         else if ((ltype == kIntegerType) && (rtype == kDoubleType) || 
00870             (rtype == kIntegerType) && (ltype == kDoubleType))
00871         {
00872             return number(lhs) == number(rhs) ? trueAtom : falseAtom;
00873         }
00874 
00875         return falseAtom;
00876     }
00877 
00883     void AvmCore::throwException(Exception *exception)
00884     {
00885         #ifdef DEBUGGER
00886         if (debugger && !(exception->flags & Exception::SEEN_BY_DEBUGGER))
00887         {
00888             // I'm going to set the SEEN_BY_DEBUGGER flag now, before calling
00889             // filterException(), just to avoid reentrancy problems (we don't
00890             // want to end up back here with the same Exception object and get
00891             // stuck in an infinite loop).
00892             exception->flags |= Exception::SEEN_BY_DEBUGGER;
00893 
00894             bool willBeCaught = willExceptionBeCaught(exception);
00895 
00896             if (passAllExceptionsToDebugger || !willBeCaught)
00897             {
00898                 // filterException() returns 'true' if it somehow let the user know
00899                 // about the exception, 'false' if it ignored the exception.
00900                 if (debugger->filterException(exception, willBeCaught))
00901                     exception->flags |= Exception::SEEN_BY_DEBUGGER;
00902                 else
00903                     exception->flags &= ~Exception::SEEN_BY_DEBUGGER;
00904             }
00905             else
00906             {
00907                 exception->flags &= ~Exception::SEEN_BY_DEBUGGER;
00908             }
00909         }
00910         #endif
00911 
00912         // exceptionFrame should not be NULL; if it is,
00913         // you are missing a TRY/CATCH block around
00914         // a call to an AVM+ method that throws an
00915         // exception.
00916         AvmAssert(exceptionFrame != NULL);
00917         exceptionFrame->throwException(exception);
00918     }
00919     
00925     void AvmCore::throwAtom(Atom atom)
00926     {
00927         throwException(new (GetGC()) Exception(atom
00928 #ifdef DEBUGGER
00929             , this
00930 #endif
00931             ));
00932     }
00933     
00934 #ifdef DEBUGGER
00935     bool AvmCore::willExceptionBeCaught(Exception* exception)
00936     {
00937         ExceptionFrame* ef;
00938 
00939         for (ef = exceptionFrame; ef != NULL; ef = ef->prevFrame)
00940         {
00941             switch (ef->catchAction)
00942             {
00943                 // The CATCH block will consume any exception that occurs, and will not treat it as
00944                 // an error, so exceptions should not be reported to the debugger.
00945                 case kCatchAction_Ignore:
00946                     return true;
00947 
00948                 // The CATCH block will rethrow any exception that occurs; so, we will 'continue',
00949                 // which will take us back to the 'for' loop to keep going up the exception stack,
00950                 // until we find a frame with some other value.
00951                 case kCatchAction_Rethrow:
00952                     continue; // return to the 'for' loop
00953 
00954                 // The CATCH block will treat any exception that occurs as an error -- probably by
00955                 // calling uncaughtException, but possibly by some other means.  So, exceptions
00956                 // should be reported to the debugger.
00957                 case kCatchAction_ReportAsError:
00958                     return false;
00959 
00960                 // This is the unfortunate, but rare, case where we can't tell in advance how the
00961                 // CATCH block will handle exceptions.  In this case, we wil not report the
00962                 // exception to the debugger.
00963                 case kCatchAction_Unknown:
00964                     return true;
00965 
00966                 // The CATCH block will walk up the exception frames that were defined in
00967                 // ActionScript code -- e.g. "try { } catch (e:Error) { }" -- looking for one
00968                 // which catch this exception.  So, we will do the same thing, and only report
00969                 // the error to the debugger if there is no catch block for it.
00970                 case kCatchAction_SearchForActionScriptExceptionHandler:
00971                 {
00972                     CallStackNode* callStackNode;
00973 
00974                     // Walk all the way up the stack, one frame at a time, looking for
00975                     // one which will catch this exception.
00976                     for (callStackNode = callStack; callStackNode; callStackNode = callStackNode->next)
00977                     {
00978                         MethodInfo* info = (MethodInfo*) callStackNode->info;
00979 #ifdef AVMPLUS_WORD_CODE
00980                         ExceptionHandlerTable* exceptions = info->word_code.exceptions;
00981 #else
00982                         ExceptionHandlerTable* exceptions = info->exceptions;
00983 #endif
00984                         if (exceptions != NULL && callStackNode->eip && *callStackNode->eip)
00985                         {
00986                             // Check if this particular frame of the callstack
00987                             // is going to catch the exception.
00988                             if (findExceptionHandlerNoRethrow(info, *callStackNode->eip, exception) != NULL)
00989                                 return true;
00990                         }
00991                     }
00992 
00993                     // No ActionScript handler was found, so the exception is going to be
00994                     // re-thrown; so, 'continue' will get us back to the 'for' loop
00995                     continue;
00996                 }
00997 
00998                 default:
00999                     AvmAssert(false);
01000                     break;
01001             }
01002         }
01003 
01004         return false;
01005     }
01006 
01010     int AvmCore::determineLanguage()
01011     {
01012         if (langID < 0)
01013         {
01014             // @todo system probe to determine language, then return one of our known enums
01015             langID = LANG_en;
01016         }
01017         return langID;
01018     }
01019 
01020     String* AvmCore::findErrorMessage(int errorID,
01021                                       int* mapTable,  /* 2 ints per entry i, i+1 */
01022                                       const char** errorTable,
01023                                       int numErrors)
01024     {
01025         // Above that, we must binary search.
01026         int lo = 0;
01027         int hi = numErrors-1;
01028 
01029         while (lo <= hi) {
01030             int pivot = (lo+hi)>>1;
01031             int testID = mapTable[2*pivot];
01032             if (testID == errorID) {
01033                 lo = pivot;
01034                 break;
01035             } else if (errorID < testID) {
01036                 hi = pivot-1;
01037             } else {
01038                 lo = pivot+1;
01039             }
01040         }
01041 
01042         int index = mapTable[2*lo+1];
01043         int id = mapTable[2*lo];
01044 
01045         if (id == errorID) {
01046             return newString(errorTable[index]);
01047         } else {
01048             return NULL;
01049         }
01050     }
01051 #endif
01052     
01053     String* AvmCore::getErrorMessage(int errorID)
01054     {
01055         Stringp buffer = newString("Error #");
01056         buffer = concatStrings(buffer, internInt(errorID));
01057 
01058         #ifdef DEBUGGER
01059         Stringp out = findErrorMessage(errorID,
01060                                        errorMappingTable,
01061                                        errorConstants[determineLanguage()],
01062                                        kNumErrorConstants);
01063         if (out) 
01064         {
01065             buffer = concatStrings(buffer, newString(": "));
01066             buffer = concatStrings(buffer, out);
01067         }
01068         else
01069         {
01070             AvmAssertMsg(0, "errorID not found in the message table; check ErrorConstants.cpp you may need to regenerate it");
01071         }
01072         #endif
01073 
01074         return buffer;
01075     }
01076 
01077     String* AvmCore::atomToErrorString(Atom a)
01078     {
01079         String* out = NULL;
01080     #ifdef DEBUGGER
01081         out = this->format(a);
01082     #else 
01083         (void)a;
01084         out = kEmptyString;
01085     #endif /* DEBUGGER */
01086         return out;
01087     }
01088 
01089     String* AvmCore::toErrorString(int d)
01090     {
01091         String* s = NULL;
01092     #ifdef DEBUGGER
01093         wchar buffer[256];
01094         buffer[255] = '\0';
01095         int len;
01096         if (MathUtils::convertIntegerToString(d, buffer, len)) 
01097             s = this->newString(buffer);
01098         else
01099             s = kEmptyString;
01100     #else
01101         s = kEmptyString;
01102         (void)d;
01103     #endif /* DEBUGGER */
01104         return s;
01105     }
01106 
01107     String* AvmCore::toErrorString(const char* s)
01108     {
01109         String* out = NULL;
01110     #ifdef DEBUGGER
01111         if (s)
01112             out = this->newString(s);
01113         else
01114             out = kEmptyString;
01115     #else
01116         out = kEmptyString;
01117         (void)s;
01118     #endif /* DEBUGGER */
01119         return out;
01120     }
01121 
01122     String* AvmCore::toErrorString(const wchar* s)
01123     {
01124         String* out = NULL;
01125     #ifdef DEBUGGER
01126         if (s)
01127             out = this->newString(s);
01128         else
01129             out = kEmptyString;
01130     #else
01131         out = kEmptyString;
01132         (void)s;
01133     #endif /* DEBUGGER */
01134         return out;
01135     }
01136 
01137     String* AvmCore::toErrorString(AbstractFunction* m)
01138     {
01139         String* s = NULL;
01140     #ifdef DEBUGGER
01141         if (m) 
01142             s = m->format(this);
01143         else
01144             s = kEmptyString;
01145     #else
01146         s = kEmptyString;
01147         (void)m;
01148     #endif /* DEBUGGER */
01149         return s;
01150     }
01151 
01152     String* AvmCore::toErrorString(const Multiname* n)
01153     {
01154         String* s = NULL;
01155     #ifdef DEBUGGER
01156         if (n) 
01157             s = n->format(this, Multiname::MULTI_FORMAT_NAME_ONLY);
01158         else
01159             s = kEmptyString;
01160     #else
01161         s = kEmptyString;
01162         (void)n;
01163     #endif /* DEBUGGER */
01164         return s;
01165     }
01166 
01167     String* AvmCore::toErrorString(Namespace* ns)
01168     {
01169         String* s = NULL;
01170     #ifdef DEBUGGER
01171         if (ns) 
01172             s = ns->format(this);
01173         else
01174             s = kEmptyString;
01175     #else
01176         s = kEmptyString;
01177         (void)ns;
01178     #endif /* DEBUGGER */
01179         return s;
01180     }
01181 
01182     String* AvmCore::toErrorString(Traits* t)
01183     {
01184         #ifndef DEBUGGER
01185         (void)t;
01186         return kEmptyString;
01187         #else
01188         if (!t)
01189         {
01190             return newString("*");
01191         }
01192 
01193         String* s = NULL;
01194         if (t->base == traits.class_itraits)
01195         {
01196             t = t->itraits;
01197             s = newString("class ");
01198         }
01199         else
01200         {
01201             s = kEmptyString;
01202         }
01203 
01204         if (t->ns != NULL && t->ns != publicNamespace)
01205             s = concatStrings(s, concatStrings(toErrorString(t->ns), newString("."))); 
01206 
01207         if (t->name)
01208             s = concatStrings(s, t->name);
01209         else
01210             s = concatStrings(s, newString("(null)"));
01211         return s;
01212         #endif /* DEBUGGER */
01213     }
01214 
01215     String* AvmCore::formatErrorMessageV( int errorID, Stringp arg1, Stringp arg2, Stringp arg3)
01216     {
01217         Stringp out = NULL;
01218 
01219         Stringp errorMessage = getErrorMessage(errorID);
01220         if (errorMessage)
01221         {
01222             #ifdef DEBUGGER
01223             UTF8String *errorUTF8 = errorMessage->toUTF8String();       
01224             const char *format = errorUTF8->c_str();
01225             
01226             // This block is enclosed in {} to force
01227             // StringBuffer destructor to unwind.
01228             {
01229                 StringBuffer buffer(this);
01230                 buffer.formatP( format, arg1, arg2, arg3);
01231                 out = newString(buffer.c_str());
01232             }
01233             #else   
01234 
01238             (void)arg1; 
01239             (void)arg2; 
01240             (void)arg3; 
01241             out = errorMessage;
01242             #endif /* DEBUGGER*/
01243         }
01244         else
01245         {
01246             AvmAssertMsg(errorMessage != NULL, "contract with getErrorMessage() broken, we should always get a string!");
01247             out = kEmptyString;
01248         }
01249         return out;
01250     }
01251         
01252     void AvmCore::throwErrorV(ClassClosure *type, int errorID, Stringp arg1, Stringp arg2, Stringp arg3)
01253     {
01254         Stringp out = formatErrorMessageV( errorID, arg1, arg2, arg3);
01255 
01256         #ifdef DEBUGGER
01257         if (type == NULL)
01258         {
01259             // print the error message, because we're still bootstrapping
01260             // and the exception type is not yet defined
01261             console << out << "\n";
01262         }
01263         #endif
01264 
01265         Atom args[3] = { nullObjectAtom, out->atom(), intToAtom(errorID) };
01266         throwAtom(type->construct(2, args));
01267     }
01268     
01269     Atom AvmCore::booleanAtom(Atom atom)
01270     {
01271         if (!AvmCore::isNullOrUndefined(atom))
01272         {
01273             switch (atom&7)
01274             {
01275             case kIntegerType:
01276                 {
01277                     Atom i = atom>>3;
01278                     return urshift(i|-i,28)&~7 | kBooleanType;
01279                 }
01280             case kBooleanType:
01281                 return atom;
01282             case kObjectType:
01283             case kNamespaceType:
01284                 return isNull(atom) ? falseAtom : trueAtom;
01285             case kStringType:
01286                 if (isNull(atom)) return falseAtom;
01287                 return (atomToString(atom)->length() > 0) ? trueAtom : falseAtom;
01288             default:
01289                 {
01290                     double d = atomToDouble(atom);
01291                     return !MathUtils::isNaN(d) && d != 0.0 ? trueAtom : falseAtom;
01292                 }
01293             }
01294         }
01295         else
01296         {
01297             return falseAtom;
01298         }
01299     }
01300 
01301     int AvmCore::boolean(Atom atom)
01302     {
01303         if (!AvmCore::isNullOrUndefined(atom))
01304         {
01305             switch (atom&7)
01306             {
01307             case kIntegerType:
01308             case kBooleanType:
01309                 return (atom & ~7) != 0;
01310             case kObjectType:
01311             case kNamespaceType:
01312                 return !isNull(atom);
01313             case kStringType:
01314                 return !isNull(atom) && atomToString(atom)->length() > 0;
01315             default:
01316                 {
01317                     double d = atomToDouble(atom);
01318                     return !MathUtils::isNaN(d) && d != 0.0;
01319                 }
01320             }
01321         }
01322         else
01323         {
01324             return false;
01325         }
01326     }
01327     
01328     /*
01329         ToPrimitive:
01330 
01331         Return a default value for the Object. The default value of an object is
01332         retrieved by calling the internal [[DefaultValue]] method of the object,
01333         passing the optional hint PreferredType. The behaviour of the
01334         [[DefaultValue]] method is defined by this specification for all native
01335         ECMAScript objects (section 8.6.2.6).
01336     */
01337     Atom AvmCore::primitive(Atom atom)
01338     {
01339         return isObject(atom) ? atomToScriptObject(atom)->defaultValue() : atom;
01340     }
01341 
01342     Atom AvmCore::numberAtom(Atom atom)
01343     {
01344         if (!isNull(atom))
01345         {
01346             double value;
01347             switch (atom&7)
01348             {
01349             case kSpecialType:
01350                 return kNaN;
01351             case kStringType:
01352                 value = atomToString(atom)->toNumber();
01353                 break;
01354             default:
01355                 AvmAssert(false);
01356             case kBooleanType:
01357                 return (atom&~7) | kIntegerType;
01358             case kDoubleType:
01359             case kIntegerType:
01360                 return atom;
01361             case kNamespaceType:
01362                 // return ToNumber(namespace->uri)
01363                 value = number(atomToNamespace(atom)->getURI()->atom());
01364                 break;
01365             case kObjectType:
01366                 value = number(atomToScriptObject(atom)->defaultValue());
01367                 break;
01368             }
01369             return doubleToAtom(value);
01370         }
01371         else
01372         {
01373             return 0 | kIntegerType;
01374         }
01375     }
01376     
01377     double AvmCore::number(Atom atom) const
01378     {
01379         int kind = atom&7;
01380 
01381         if (kind == kIntegerType)
01382             return (double) ((sintptr)atom>>3);
01383         if (kind == kDoubleType)
01384             return atomToDouble(atom);
01385 
01386         if (!isNull(atom))
01387         {
01388             switch (kind)
01389             {
01390             case kStringType:
01391                 return atomToString(atom)->toNumber();
01392             case kSpecialType:
01393                 return atomToDouble(kNaN);
01394             case kBooleanType:
01395                 return atom == trueAtom ? 1.0 : 0.0;
01396             case kNamespaceType:
01397                 return number(atomToNamespace(atom)->getURI()->atom());
01398             default: // number
01399             case kObjectType:
01400                 return number(atomToScriptObject(atom)->defaultValue());
01401             }
01402         }
01403         else
01404         {
01405             // ES3 9.3, toNumber(null) == 0
01406             return 0.0;
01407         }
01408     }
01409 
01410     Stringp AvmCore::intern(Atom atom)
01411     {
01412         if (!isNull(atom))
01413         {
01414             switch (atom&7)
01415             {
01416             case kBooleanType:
01417                 return booleanStrings[atom>>3];
01418             case kStringType:
01419                 return internString(atom);
01420             case kNamespaceType:
01421                 return atomToNamespace(atom)->getURI();
01422             case kSpecialType:
01423                 return kundefined;
01424             case kObjectType:
01425                 return intern(atomToScriptObject(atom)->toString());
01426             case kIntegerType:
01427                 return internInt((int)(atom>>3));
01428             case kDoubleType:
01429             default: // number
01430                 return internDouble(atomToDouble(atom));
01431             }
01432         }
01433         else
01434         {
01435             return knull;
01436         }
01437     }
01438 
01439     Namespace* AvmCore::internNamespace(Namespace* ns)
01440     {
01441         if (ns->isPrivate())
01442         {
01443             // only intern namespaces with interned uri's.  this means anonymous
01444             // namespaces with null prefixes are always unique and can't be shared.
01445             return ns;
01446         }
01447 
01448         int i = findNamespace(ns);
01449         if (namespaces[i] == NULL)
01450         {
01451             // first time we've seen this namespace.  intern int
01452             nsCount++;
01453             namespaces[i] = ns;
01454             return ns;
01455         }
01456 
01457         // found the namespace, indexing by URI. return the interned copy.
01458         return namespaces[i];
01459     }
01460 
01461 #ifdef AVMPLUS_VERBOSE
01462     /* static */
01463     void AvmCore::formatMultiname(PrintWriter& out, uint32 index, PoolObject* pool)
01464     {
01465         if (index > 0 && index <= pool->constantMnCount)
01466         {
01467             Multiname name;
01468             pool->parseMultiname(name, index);
01469             out << &name;
01470         }
01471         else
01472         {
01473             out << "invalid multiname index " << index;
01474         }
01475     }
01476 
01477     void AvmCore::formatOpcode(PrintWriter& buffer, const byte *pc, AbcOpcode opcode, ptrdiff_t off, PoolObject* pool)
01478     {
01479         pc++;
01480         switch (opcode)
01481         {
01482         case OP_debugfile:
01483         case OP_pushstring:
01484             {
01485                 buffer << opNames[opcode];
01486                 uint32 index = readU30(pc);
01487                 String *s = format(pool->cpool_string[index]->atom());
01488                 if (index < pool->cpool_string.size())
01489                     buffer << " " << s;
01490                 break;
01491             }
01492         case OP_pushbyte:
01493             buffer << opNames[opcode] << " " << int(int8(*pc));
01494             break;
01495         case OP_pushint:
01496             {
01497                 buffer << opNames[opcode];
01498                 uint32 index = readU30(pc);
01499                 if (index < pool->cpool_int.size())
01500                     buffer << " " << pool->cpool_int[index];
01501                 break;
01502             }
01503         case OP_pushuint:
01504             {
01505                 buffer << opNames[opcode];
01506                 uint32 index = readU30(pc);
01507                 if (index < pool->cpool_uint.size())
01508                     buffer << " " << (double)pool->cpool_uint[index];
01509                 break;
01510             }
01511         case OP_pushdouble:
01512             {
01513                 buffer << opNames[opcode];
01514                 uint32 index = readU30(pc);
01515                 if (index < pool->cpool_double.size())
01516                     buffer << " " << *pool->cpool_double[index];
01517                 break;
01518             }
01519         case OP_pushnamespace:
01520             {
01521                 buffer << opNames[opcode];
01522                 uint32 index = readU30(pc);
01523                 if (index < pool->cpool_ns.size())
01524                 {
01525                     buffer << " " << pool->cpool_ns[index]->getURI();
01526                 }
01527                 break;
01528             }
01529         case OP_getsuper: 
01530         case OP_setsuper: 
01531         case OP_getproperty: 
01532         case OP_setproperty: 
01533         case OP_initproperty: 
01534         case OP_findpropstrict: 
01535         case OP_findproperty:
01536         case OP_finddef:
01537         case OP_deleteproperty: 
01538         case OP_istype: 
01539         case OP_coerce: 
01540         case OP_astype: 
01541             {
01542                 buffer << opNames[opcode] << " ";
01543                 formatMultiname(buffer, readU30(pc), pool);
01544                 break;
01545             }
01546         case OP_callproperty:
01547         case OP_callpropvoid:
01548         case OP_callproplex:
01549         case OP_callsuper:
01550         case OP_callsupervoid:
01551             {
01552                 uint32 index = readU30(pc);
01553                 int argc = readU30(pc);
01554                 buffer << opNames[opcode] << " ";
01555                 formatMultiname(buffer, index, pool);
01556                 buffer << " " << argc;
01557                 break;
01558             }
01559         case OP_callstatic:
01560         case OP_newfunction:
01561             {
01562                 int method_id = readU30(pc);
01563                 AbstractFunction* f = pool->methods[method_id];
01564                 buffer << opNames[opcode] << " method_id=" << method_id;
01565                 if (opcode == OP_callstatic)
01566                 {
01567                     buffer << " argc=" << (int)readU30(pc); // argc
01568                 }
01569                 if (f->name)
01570                     buffer << " " << f->name;
01571                 else
01572                     buffer << " null";
01573                 break;
01574             }
01575 
01576         case OP_newclass: 
01577             {
01578                 uint32_t id = readU30(pc);
01579                 AbstractFunction* c = pool->cinits[id];
01580                 buffer << opNames[opcode] << " " << c;
01581                 break;
01582             }
01583         case OP_lookupswitch:
01584             {
01585                 ptrdiff_t target = off + readS24(pc);
01586                 pc += 3;
01587                 int maxindex = readU30(pc);
01588                 buffer << opNames[opcode] << " default:" << target << " maxcase:"<<maxindex;
01589                 for (int i=0; i <= maxindex; i++)
01590                 {
01591                     target = off + readS24(pc);
01592                     pc += 3;
01593                     buffer << " " << target;
01594                 }
01595                 break;
01596             }
01597             break;
01598 
01599       case OP_ifnlt:
01600       case OP_ifnle:
01601       case OP_ifngt:
01602       case OP_ifnge:         
01603         case OP_jump:
01604         case OP_iftrue:
01605         case OP_iffalse:
01606         case OP_ifeq:
01607         case OP_ifge:
01608         case OP_ifgt:
01609         case OP_ifle:
01610         case OP_iflt:
01611         case OP_ifne:
01612         case OP_ifstricteq:
01613         case OP_ifstrictne:
01614             {
01615                 int imm24 = 0, imm8 = 0;
01616                 unsigned int imm30 = 0, imm30b = 0;
01617                 const byte* p2 = pc-1;
01618                 readOperands(p2, imm30, imm24, imm30b, imm8);
01619                 int insWidth = (int)(p2-pc);
01620 
01621                 ptrdiff_t target = off + insWidth + imm24 + 1;
01622                 buffer << opNames[opcode] << " " << (double)target;
01623                 break;
01624             }
01625         default:
01626             switch (opOperandCount[opcode])
01627             {
01628             default:
01629                 buffer << opNames[opcode];
01630                 break;
01631             case 1:
01632                 {
01633                     buffer << opNames[opcode]
01634                         << ' '
01635                         << (int)readU30(pc);
01636                 }
01637                 break;
01638             case 2:
01639                 {
01640                     int first = readU30(pc);
01641                     int second = readU30(pc);
01642                     buffer << opNames[opcode]
01643                         << ' '
01644                         << first
01645                         << ' '
01646                         << second;
01647                 }
01648                 break;
01649             }
01650         }
01651     }
01652 #endif
01653 
01654     ExceptionHandler* AvmCore::beginCatch(ExceptionFrame *ef,
01655         MethodInfo *info, sintptr pc, Exception *exception)
01656     {
01657         ef->beginCatch();
01658         ExceptionHandler* handler = findExceptionHandler(info,pc,exception);
01659         ef->beginTry(this);
01660         return handler;
01661     }
01662 
01663     ExceptionHandler* AvmCore::findExceptionHandler(MethodInfo *info,
01664                                                     sintptr pc,
01665                                                     Exception *exception)
01666     {
01667         ExceptionHandler* handler = findExceptionHandlerNoRethrow(info, pc, exception);
01668         if (handler)
01669             return handler;
01670 
01671         // We don't have a matching exception.
01672         throwException(exception);
01673         return NULL;// not reached
01674     }
01675 
01676     ExceptionHandler* AvmCore::findExceptionHandlerNoRethrow(MethodInfo *info,
01677                                                              sintptr pc,
01678                                                              Exception *exception)
01679     {
01680         // If this exception is an EXIT_EXCEPTION, it cannot
01681         // be caught by AS code.  Exit immediately.
01682         if (exception->flags & Exception::EXIT_EXCEPTION)
01683         {
01684             return NULL;
01685         }
01686         
01687         // Search the exception table for a catch clause
01688         // such that pc is between "from" and "to" and
01689         // the thrown atom matches the required type.
01690 
01691         // if no handler found, re-throw the exception from here
01692 
01693         //[ed] we only call this from methods with catch blocks, when exceptions != NULL
01694         AvmAssert(info->exceptions != NULL);
01695 #ifdef AVMPLUS_WORD_CODE
01696         // This is hacky and will go away.  If the target method was not jitted, use
01697         // word_code.exceptions, otherwise use info->exceptions.  methods may or may
01698         // not be JITted based on memory, configuration, or heuristics.
01699 
01700         ExceptionHandlerTable* exceptions;
01701         if (info->impl32 == avmplus::interp32 || info->implN == avmplus::interpN)
01702             exceptions = info->word_code.exceptions;
01703         else
01704             exceptions = info->exceptions;
01705         AvmAssert(exceptions != NULL);
01706 #else
01707         ExceptionHandlerTable* exceptions = info->exceptions;
01708 #endif
01709         
01710         int exception_count = exceptions->exception_count;
01711         ExceptionHandler* handler = exceptions->exceptions;
01712         Atom atom = exception->atom;
01713         
01714         while (--exception_count >= 0) 
01715         {
01716             if (pc >= handler->from &&
01717                 pc <  handler->to)
01718             {
01719                 // verifier makes sure type is valid, resolves to Traits*
01720                 if (istype(atom, handler->traits)) 
01721                 {
01722                     #ifdef AVMPLUS_VERBOSE
01723                     if (config.verbose)
01724                     {
01725                         console << "enter " << info << " catch " << handler->traits << '\n';
01726                     }
01727                     #endif // DEBUGGER
01728 
01729                     return handler;
01730                 }
01731             }
01732             handler++;
01733         }
01734 
01735         // We don't have a matching exception.
01736         return NULL;
01737     }
01738 
01739     void AvmCore::increment_d(Atom *ap, int delta)
01740     {
01741         AvmAssert(isNumber(*ap));
01742         if (isInteger(*ap))
01743             *ap = intToAtom(delta+((sint32)((sintptr)*ap>>3)));
01744         else
01745             *ap = doubleToAtom(atomToDouble(*ap)+delta);
01746     }
01747 
01748     void AvmCore::increment_i(Atom *ap, int delta)
01749     {
01750         switch (*ap & 7)
01751         {
01752         case kBooleanType:
01753         case kIntegerType:
01754             *ap = intToAtom(delta+(sint32((sintptr)*ap>>3)));
01755             return;
01756         case kDoubleType:
01757             *ap = intToAtom((int)((sint32)atomToDouble(*ap)+delta));
01758             return;
01759         default:
01760             *ap = intToAtom(integer(*ap)+delta);
01761             return;
01762         }
01763     }
01764 
01765     bool AvmCore::istype(Atom atom, Traits* itraits)
01766     {
01767         if (!itraits)
01768             return true;
01769 
01770         if (isNull(atom))
01771             return itraits == traits.null_itraits;
01772 
01773         Traits* lhs;
01774 
01775         switch (atom&7)
01776         {
01777         case kNamespaceType:
01778             lhs = traits.namespace_itraits;
01779             break;
01780 
01781         case kStringType:
01782             lhs = traits.string_itraits;
01783             break;
01784 
01785         case kBooleanType:
01786             lhs = traits.boolean_itraits;
01787             break;
01788 
01789         case kIntegerType:
01790             // ISSUE need special support for number value ranges
01791             if (itraits == traits.number_itraits)
01792                 return true;
01793 
01794             lhs = traits.int_itraits;
01795             if (itraits == traits.uint_itraits)
01796             {
01797                 return (atom>>3) >= 0;
01798             }
01799 #ifdef AVMPLUS_64BIT
01800             if (itraits == traits.int_itraits)
01801             {
01802                 // this might be a uint
01803                 if ((int64)(atom>>3)!=(int)(atom>>3))
01804                     return false;
01805             }
01806 #endif
01807             break;
01808 
01809         case kDoubleType:
01810             lhs = traits.number_itraits;
01811             // ISSUE there must be a better way...
01812             if (itraits == traits.int_itraits)
01813             {
01814                 double d = atomToDouble(atom);
01815                 int i = MathUtils::real2int(d);
01816                 return d == (double)i;
01817             }
01818             if (itraits == traits.uint_itraits)
01819             {
01820                 double d = atomToDouble(atom);
01821                 // ISSUE use real2int?
01822                 unsigned i = (unsigned)d;
01823                 return d == (double)i;
01824             }
01825             break;
01826 
01827         case kSpecialType:
01828             return itraits == traits.void_itraits;
01829 
01830         case kObjectType: {
01831             lhs = atomToScriptObject(atom)->traits();
01832             break;
01833         }
01834 
01835         default:
01836             // unexpected atom type
01837             AvmAssert(false);
01838             return false;
01839         }
01840 
01841         return lhs->containsInterface(itraits)!=0;
01842     }
01843 
01844     Stringp AvmCore::coerce_s(Atom atom)
01845     {
01846         if (isNullOrUndefined(atom))
01847             return NULL;
01848         return string(atom);
01849     }
01850 
01851     Stringp AvmCore::string(Atom atom)
01852     {
01853         if (!isNull(atom))
01854         {
01855             switch (atom&7)
01856             {
01857             case kNamespaceType:
01858                 return atomToNamespace(atom)->getURI();
01859             case kObjectType:
01860                 return string(atomToScriptObject(atom)->toString());
01861             case kStringType:
01862                 return atomToString(atom);
01863             case kSpecialType:
01864                 return kundefined;
01865             case kBooleanType:
01866                 return booleanStrings[atom>>3];
01867             case kIntegerType:
01868 #ifdef AVMPLUS_64BIT
01869                 return intToString (int(intptr_t(atom)>>3));
01870 #else
01871                 return intToString (int(sint32(atom)>>3));
01872 #endif
01873             case kDoubleType:
01874             default: // number
01875                 return doubleToString(atomToDouble(atom));
01876             }
01877         }
01878         else
01879         {
01880             return knull;
01881         }
01882     }
01883 
01884     void AvmCore::setConsoleStream(OutputStream *stream)
01885     {
01886         console.setOutputStream(stream);
01887     }
01888 
01889     void AvmCore::registerNatives(NativeTableEntryp nativeMap, AbstractFunction *nativeMethods[])
01890     {
01891         while (nativeMap->method_id != -1)
01892         {
01893 #ifdef AVMTHUNK_VERSION
01894             AbstractFunction* f = new (GetGC()) NativeMethod(*nativeMap);
01895 #else
01896             AbstractFunction* f = new (GetGC()) NativeMethod(nativeMap->flags, (NativeMethod::Handler)nativeMap->handler, nativeMap->cookie);
01897 #endif
01898                             
01899             // if we overwrite a native method mapping, something is hosed
01900             AvmAssert(nativeMethods[nativeMap->method_id]==NULL);
01901             nativeMethods[nativeMap->method_id] = f;
01902             nativeMap++;
01903         }
01904     }
01905 
01906     void AvmCore::initNativeTables(NativeClassInfop classEntry,
01907                                   NativeScriptInfop scriptEntry,
01908                                   AbstractFunction *nativeMethods[],
01909                                   NativeClassInfop nativeClasses[],
01910                                   NativeScriptInfop nativeScripts[])
01911     {
01912         while (classEntry->class_id != -1)
01913         {
01914             nativeClasses[classEntry->class_id] = classEntry;
01915             registerNatives(classEntry->nativeMap, nativeMethods);
01916             classEntry++;
01917         }
01918 
01919         while (scriptEntry->script_id != -1)
01920         {
01921             nativeScripts[scriptEntry->script_id] = scriptEntry;
01922             registerNatives(scriptEntry->nativeMap, nativeMethods);
01923             scriptEntry++;
01924         }
01925     }
01926 
01927     bool AvmCore::isXML (Atom atm) 
01928     {
01929         if (!isObject(atm))
01930             return false;
01931 
01932         AvmAssert (!traits.xml_itraits || traits.xml_itraits->final);
01933         Traits *lhs = atomToScriptObject(atm)->traits();
01934         return (lhs == traits.xml_itraits);
01935     }
01936 
01937     bool AvmCore::isDate(Atom atm)
01938     {
01939         if (!isObject(atm))
01940             return false;
01941 
01942         AvmAssert (!traits.date_itraits || traits.date_itraits->final);
01943         Traits *lhs = atomToScriptObject(atm)->traits();
01944         return (lhs == traits.date_itraits);
01945     }
01946 
01947     bool AvmCore::isXMLList (Atom atm) 
01948     {
01949         if (!isObject(atm))
01950             return false;
01951 
01952         AvmAssert (!traits.xmlList_itraits || traits.xmlList_itraits->final);
01953         Traits *lhs = atomToScriptObject(atm)->traits();
01954         return (lhs == traits.xmlList_itraits);
01955     }
01956 
01957     bool AvmCore::isQName (Atom atm)
01958     {
01959         if (!isObject(atm))
01960             return false;
01961 
01962         AvmAssert (!traits.qName_itraits || traits.qName_itraits->final);
01963         Traits *lhs = atomToScriptObject(atm)->traits();
01964         return (lhs == traits.qName_itraits);
01965     }
01966 
01967     bool AvmCore::isDictionary (Atom atm)
01968     {
01969         return isObject(atm) && atomToScriptObject(atm)->vtable->traits->isDictionary;
01970     }
01971 
01972     // Tables are from http://www.w3.org/TR/2004/REC-xml-20040204/#NT-NameChar
01973     // E4X 13.1.2.1, pg 63
01974     /* BaseChar = */
01975     wchar letterTable[] = {
01976         0x0041, 0x005A,
01977         0x0061, 0x007A,
01978         0x00C0, 0x00D6,
01979         0x00D8, 0x00F6,
01980         0x00F8, 0x00FF,
01981         0x0100, 0x0131,
01982         0x0134, 0x013E,
01983         0x0141, 0x0148,
01984         0x014A, 0x017E,
01985         0x0180, 0x01C3,
01986         0x01CD, 0x01F0,
01987         0x01F4, 0x01F5,
01988         0x01FA, 0x0217,
01989         0x0250, 0x02A8,
01990         0x02BB, 0x02C1,
01991         0x0386, 0x0386, // single
01992         0x0388, 0x038A,
01993         0x038C, 0x038C, // single
01994         0x038E, 0x03A1,
01995         0x03A3, 0x03CE,
01996         0x03D0, 0x03D6,
01997         0x03DA, 0x03DA, // single
01998         0x03DC, 0x03DC, // single
01999         0x03DE, 0x03DE, // single
02000         0x03E0, 0x03E0, // single
02001         0x03E2, 0x03F3,
02002         0x0401, 0x040C,
02003         0x040E, 0x044F,
02004         0x0451, 0x045C,
02005         0x045E, 0x0481,
02006         0x0490, 0x04C4,
02007         0x04C7, 0x04C8,
02008         0x04CB, 0x04CC,
02009         0x04D0, 0x04EB,
02010         0x04EE, 0x04F5,
02011         0x04F8, 0x04F9,
02012         0x0531, 0x0556,
02013         0x0559, 0x0559, // single
02014         0x0561, 0x0586,
02015         0x05D0, 0x05EA,
02016         0x05F0, 0x05F2,
02017         0x0621, 0x063A,
02018         0x0641, 0x064A,
02019         0x0671, 0x06B7,
02020         0x06BA, 0x06BE,
02021         0x06C0, 0x06CE,
02022         0x06D0, 0x06D3,
02023         0x06D5, 0x06D5, // single
02024         0x06E5, 0x06E6,
02025         0x0905, 0x0939,
02026         0x093D, 0x093D, // single
02027         0x0958, 0x0961,
02028         0x0985, 0x098C,
02029         0x098F, 0x0990,
02030         0x0993, 0x09A8,
02031         0x09AA, 0x09B0,
02032         0x09B2, 0x09B2, // single
02033         0x09B6, 0x09B9,
02034         0x09DC, 0x09DD,
02035         0x09DF, 0x09E1,
02036         0x09F0, 0x09F1,
02037         0x0A05, 0x0A0A,
02038         0x0A0F, 0x0A10,
02039         0x0A13, 0x0A28,
02040         0x0A2A, 0x0A30,
02041         0x0A32, 0x0A33,
02042         0x0A35, 0x0A36,
02043         0x0A38, 0x0A39,
02044         0x0A59, 0x0A5C,
02045         0x0A5E, 0x0A5E, // single
02046         0x0A72, 0x0A74,
02047         0x0A85, 0x0A8B,
02048         0x0A8D, 0x0A8D, // single
02049         0x0A8F, 0x0A91,
02050         0x0A93, 0x0AA8,
02051         0x0AAA, 0x0AB0,
02052         0x0AB2, 0x0AB3,
02053         0x0AB5, 0x0AB9,
02054         0x0ABD, 0x0ABD, // single
02055         0x0AE0, 0x0AE0, // single
02056         0x0B05, 0x0B0C,
02057         0x0B0F, 0x0B10,
02058         0x0B13, 0x0B28,
02059         0x0B2A, 0x0B30,
02060         0x0B32, 0x0B33,
02061         0x0B36, 0x0B39,
02062         0x0B3D, 0x0B3D, // single
02063         0x0B5C, 0x0B5D,
02064         0x0B5F, 0x0B61,
02065         0x0B85, 0x0B8A,
02066         0x0B8E, 0x0B90, 
02067         0x0B92, 0x0B95,
02068         0x0B99, 0x0B9A,
02069         0x0B9C, 0x0B9C, // single
02070         0x0B9E, 0x0B9F,
02071         0x0BA3, 0x0BA4,
02072         0x0BA8, 0x0BAA,
02073         0x0BAE, 0x0BB5,
02074         0x0BB7, 0x0BB9,
02075         0x0C05, 0x0C0C,
02076         0x0C0E, 0x0C10,
02077         0x0C12, 0x0C28,
02078         0x0C2A, 0x0C33,
02079         0x0C35, 0x0C39,
02080         0x0C60, 0x0C61,
02081         0x0C85, 0x0C8C,
02082         0x0C8E, 0x0C90,
02083         0x0C92, 0x0CA8,
02084         0x0CAA, 0x0CB3,
02085         0x0CB5, 0x0CB9,
02086         0x0CDE, 0x0CDE, // single
02087         0x0CE0, 0x0CE1,
02088         0x0D05, 0x0D0C,
02089         0x0D0E, 0x0D10,
02090         0x0D12, 0x0D28,
02091         0x0D2A, 0x0D39,
02092         0x0D60, 0x0D61,
02093         0x0E01, 0x0E2E,
02094         0x0E30, 0x0E30, //single
02095         0x0E32, 0x0E33,
02096         0x0E40, 0x0E45,
02097         0x0E81, 0x0E82,
02098         0x0E84, 0x0E84, // single
02099         0x0E87, 0x0E88,
02100         0x0E8A, 0x0E8A, // single
02101         0x0E8D, 0x0E8D, // single
02102         0x0E94, 0x0E97,
02103         0x0E99, 0x0E9F,
02104         0x0EA1, 0x0EA3,
02105         0x0EA5, 0x0EA5, // single
02106         0x0EA7, 0x0EA7, // single
02107         0x0EAA, 0x0EAB,
02108         0x0EAD, 0x0EAE,
02109         0x0EB0, 0x0EB0, // single
02110         0x0EB2, 0x0EB3,
02111         0x0EBD, 0x0EBD, // single
02112         0x0EC0, 0x0EC4,
02113         0x0F40, 0x0F47,
02114         0x0F49, 0x0F69,
02115         0x10A0, 0x10C5,
02116         0x10D0, 0x10F6,
02117         0x1100, 0x1100, // single
02118         0x1102, 0x1103,
02119         0x1105, 0x1107,
02120         0x1109, 0x1109, // single
02121         0x110B, 0x110C,
02122         0x110E, 0x1112,
02123         0x113C, 0x113C, // single
02124         0x113E, 0x113E, // single
02125         0x1140, 0x1140, // single
02126         0x114C, 0x114C, // single
02127         0x114E, 0x114E, // single
02128         0x1150, 0x1150, // single
02129         0x1154, 0x1155,
02130         0x1159, 0x1159, // single
02131         0x115F, 0x1161,
02132         0x1163, 0x1163, // single
02133         0x1165, 0x1165, // single
02134         0x1167, 0x1167, // single
02135         0x1169, 0x1169, // single
02136         0x116D, 0x116E,
02137         0x1172, 0x1173,
02138         0x1175, 0x1175, // single
02139         0x119E, 0x119E, // single
02140         0x11A8, 0x11A8, // single
02141         0x11AB, 0x11AB, // single
02142         0x11AE, 0x11AF,
02143         0x11B7, 0x11B8,
02144         0x11BA, 0x11BA, // single
02145         0x11BC, 0x11C2,
02146         0x11EB, 0x11EB, // single
02147         0x11F0, 0x11F0, // single
02148         0x11F9, 0x11F9, // single
02149         0x1E00, 0x1E9B,
02150         0x1EA0, 0x1EF9,
02151         0x1F00, 0x1F15,
02152         0x1F18, 0x1F1D,
02153         0x1F20, 0x1F45,
02154         0x1F48, 0x1F4D,
02155         0x1F50, 0x1F57,
02156         0x1F59, 0x1F59, // single
02157         0x1F5B, 0x1F5B, // single
02158         0x1F5D, 0x1F5D, // single
02159         0x1F5F, 0x1F7D,
02160         0x1F80, 0x1FB4,
02161         0x1FB6, 0x1FBC,
02162         0x1FBE, 0x1FBE, // single
02163         0x1FC2, 0x1FC4,
02164         0x1FC6, 0x1FCC,
02165         0x1FD0, 0x1FD3,
02166         0x1FD6, 0x1FDB,
02167         0x1FE0, 0x1FEC,
02168         0x1FF2, 0x1FF4,
02169         0x1FF6, 0x1FFC,
02170         0x2126, 0x2126, // single
02171         0x212A, 0x212B,
02172         0x212E, 0x212E, // single
02173         0x2180, 0x2182,
02174         0x3041, 0x3094,
02175         0x30A1, 0x30FA,
02176         0x3105, 0x312C,
02177         0xAC00, 0xD7A3,
02178         //[86]      Ideographic    ::=      
02179         0x4E00, 0x9FA5,
02180         0x3007, 0x3007, // single
02181         0x3021, 0x3029
02182         };
02183 
02184     bool AvmCore::isLetter (wchar c)
02185     {
02186         int x = sizeof(letterTable) / (sizeof(wchar));
02187         for (int i = 0; i < x; i += 2)
02188         {
02189             if (c >= letterTable[i] && c <= letterTable[i+1])
02190                 return true;
02191         }
02192         return false;
02193     }
02194 
02195 //[87]      CombiningChar      ::=      
02196     wchar combiningCharTable[] = {
02197         0x0300, 0x0345,
02198         0x0360, 0x0361,
02199         0x0483, 0x0486,
02200         0x0591, 0x05A1,
02201         0x05A3, 0x05B9,
02202         0x05BB, 0x05BD,
02203         0x05BF, 0x05BF, // single
02204         0x05C1, 0x05C2,
02205         0x05C4, 0x05C4, // single
02206         0x064B, 0x0652,
02207         0x0670, 0x0670, // single
02208         0x06D6, 0x06DC,
02209         0x06DD, 0x06DF,
02210         0x06E0, 0x06E4,
02211         0x06E7, 0x06E8,
02212         0x06EA, 0x06ED,
02213         0x0901, 0x0903,
02214         0x093C, 0x093C, // single
02215         0x093E, 0x094C,
02216         0x094D, 0x094D, // single
02217         0x0951, 0x0954,
02218         0x0962, 0x0963,
02219         0x0981, 0x0983,
02220         0x09BC, 0x09BC, // single 
02221         0x09BE, 0x09BE, // single 
02222         0x09BF, 0x09BF, // single 
02223         0x09C0, 0x09C4,
02224         0x09C7, 0x09C8,
02225         0x09CB, 0x09CD,
02226         0x09D7, 0x09D7, // single 
02227         0x09E2, 0x09E3,
02228         0x0A02, 0x0A02, // single 
02229         0x0A3C, 0x0A3C, // single 
02230         0x0A3E, 0x0A3E, // single 
02231         0x0A3F, 0x0A3F, // single 
02232         0x0A40, 0x0A42,
02233         0x0A47, 0x0A48,
02234         0x0A4B, 0x0A4D,
02235         0x0A70, 0x0A71,
02236         0x0A81, 0x0A83,
02237         0x0ABC, 0x0ABC, // single 
02238         0x0ABE, 0x0AC5,
02239         0x0AC7, 0x0AC9,
02240         0x0ACB, 0x0ACD,
02241         0x0B01, 0x0B03,
02242         0x0B3C, 0x0B3C, // single 
02243         0x0B3E, 0x0B43,
02244         0x0B47, 0x0B48,
02245         0x0B4B, 0x0B4D,
02246         0x0B56, 0x0B57,
02247         0x0B82, 0x0B83,
02248         0x0BBE, 0x0BC2,
02249         0x0BC6, 0x0BC8,
02250         0x0BCA, 0x0BCD,
02251         0x0BD7, 0x0BD7, // single 
02252         0x0C01, 0x0C03,
02253         0x0C3E, 0x0C44,
02254         0x0C46, 0x0C48,
02255         0x0C4A, 0x0C4D,
02256         0x0C55, 0x0C56,
02257         0x0C82, 0x0C83,
02258         0x0CBE, 0x0CC4,
02259         0x0CC6, 0x0CC8,
02260         0x0CCA, 0x0CCD,
02261         0x0CD5, 0x0CD6,
02262         0x0D02, 0x0D03,
02263         0x0D3E, 0x0D43,
02264         0x0D46, 0x0D48,
02265         0x0D4A, 0x0D4D,
02266         0x0D57, 0x0D57, // single 
02267         0x0E31, 0x0E31, // single 
02268         0x0E34, 0x0E3A,
02269         0x0E47, 0x0E4E,
02270         0x0EB1, 0x0EB1, // single 
02271         0x0EB4, 0x0EB9,
02272         0x0EBB, 0x0EBC,
02273         0x0EC8, 0x0ECD,
02274         0x0F18, 0x0F19,
02275         0x0F35, 0x0F35, // single 
02276         0x0F37, 0x0F37, // single 
02277         0x0F39, 0x0F39, // single 
02278         0x0F3E, 0x0F3E, // single 
02279         0x0F3F, 0x0F3F, // single 
02280         0x0F71, 0x0F84,
02281         0x0F86, 0x0F8B,
02282         0x0F90, 0x0F95,
02283         0x0F97, 0x0F97, // single 
02284         0x0F99, 0x0FAD,
02285         0x0FB1, 0x0FB7,
02286         0x0FB9, 0x0FB9, // single 
02287         0x20D0, 0x20DC,
02288         0x20E1, 0x20E1, // single 
02289         0x302A, 0x302F,
02290         0x3099, 0x3099, // single 
02291         0x309A, 0x309A // single 
02292         };
02293     bool AvmCore::isCombiningChar (wchar c)
02294     {
02295         int x = sizeof(combiningCharTable) / (sizeof(wchar));
02296         for (int i = 0; i < x; i += 2)
02297         {
02298             if (c >= combiningCharTable[i] && c <= combiningCharTable[i+1])
02299                 return true;
02300         }
02301         return false;
02302     }
02303 
02304 //[88]      Digit      ::=      
02305     wchar digitTable[] = {
02306         0x0030, 0x0039,
02307         0x0660, 0x0669,
02308         0x06F0, 0x06F9,
02309         0x0966, 0x096F,
02310         0x09E6, 0x09EF,
02311         0x0A66, 0x0A6F,
02312         0x0AE6, 0x0AEF,
02313         0x0B66, 0x0B6F,
02314         0x0BE7, 0x0BEF,
02315         0x0C66, 0x0C6F,
02316         0x0CE6, 0x0CEF,
02317         0x0D66, 0x0D6F,
02318         0x0E50, 0x0E59,
02319         0x0ED0, 0x0ED9,
02320         0x0F20, 0x0F29};
02321 
02322     bool AvmCore::isDigit (wchar c)
02323     {
02324         int x = sizeof(digitTable) / (sizeof(wchar));
02325         for (int i = 0; i < x; i += 2)
02326         {
02327             if (c >= digitTable[i] && c <= digitTable[i+1])
02328                 return true;
02329         }
02330         return false;
02331     }
02332 
02333     wchar extenderTable[] = {
02334         0x00B7, 0x00B7, // single 
02335         0x02D0, 0x02D0, // single 
02336         0x02D1, 0x02D1, // single 
02337         0x0387, 0x0387, // single 
02338         0x0640, 0x0640, // single 
02339         0x0E46, 0x0E46, // single 
02340         0x0EC6, 0x0EC6, // single 
02341         0x3005, 0x3005, // single 
02342         0x3031, 0x3035, 
02343         0x309D, 0x309E,
02344         0x30FC, 0x30FE};
02345     bool AvmCore::isExtender (wchar c)
02346     {
02347         int x = sizeof(extenderTable) / (sizeof(wchar));
02348         for (int i = 0; i < x; i += 2)
02349         {
02350             if (c >= extenderTable[i] && c <= extenderTable[i+1])
02351                 return true;
02352         }
02353         return false;
02354     }
02355 
02356     bool AvmCore::isXMLName(Atom arg)
02357     {
02358         if (isNullOrUndefined(arg))
02359             return false;
02360 
02361         Stringp p = string(arg);
02362 
02363         // http://www.w3.org/TR/2004/REC-xml-20040204/#NT-NameChar
02364 
02365         // Name is (Letter | _ or :) followed by arbitrary number of NameChar
02366 
02367         if (!p->length())
02368             return false;
02369 
02370         // According to the Mozilla testcase...
02371         // e4x excludes ':'
02372 
02373         wchar c = (*p)[0];
02374         if (!isLetter (c) && c != '_' /*&& c != ':'*/)
02375             return false;       
02376 
02377         for (int i = 1; i < p->length(); i++)
02378         {
02379             wchar c = (*p)[i];
02380 
02381             if (isDigit(c) || isLetter(c) || (c == '.') || (c == '-') || (c == '_') || /*(c != ':') ||*/
02382                 isCombiningChar (c) || isExtender(c))
02383                 continue;
02384 
02385             return false;
02386         }
02387 
02388         return true;
02389     }
02390 
02391     Stringp AvmCore::ToXMLString (Atom a)
02392     {
02393         if (!isNull(a))
02394         {
02395             switch (a&7)
02396             {
02397             case kStringType:
02398                 return EscapeElementValue (string(a), true);
02399             case kObjectType:
02400             case kNamespaceType:
02401                 if (isXML(a))
02402                 {
02403                     XMLObject *x = atomToXMLObject (a);
02404                     return x->toXMLString();
02405                 }
02406                 else if (isXMLList(a))
02407                 {
02408                     XMLListObject *x = atomToXMLList (a);
02409                     return x->toXMLString();
02410                 }
02411                 else
02412                 {
02413                     // !!@ to primitive (hint string first)
02414                     // !!@ namespace case falls into this as well
02415                     return EscapeElementValue (string(a), true);
02416                 }
02417                 break;
02418             case kSpecialType:
02419                 return kundefined;
02420             case kIntegerType:
02421             case kBooleanType:
02422             case kDoubleType:
02423             default:
02424                 return string(a);
02425             }
02426         }
02427         else
02428         {
02429             return knull;
02430         }
02431     }
02432 
02433     Stringp AvmCore::EscapeElementValue (const Stringp s, bool removeLeadingTrailingWhitespace)
02434     {
02435         StringBuffer output(this);
02436 
02437         int i = 0;
02438         int last = s->length() - 1;
02439         if (removeLeadingTrailingWhitespace)
02440         {
02441             // finding trailing whitespace
02442             while (last >= 0)
02443             {
02444                 if (!String::isSpace ((*s)[last]))
02445                     break;
02446 
02447                 last--;
02448             }
02449 
02450             if (last < 0)
02451                 return kEmptyString;
02452 
02453             // skip leading whitespace
02454             for (i = 0; i <= last; i++)
02455             {
02456                 if (!String::isSpace ((*s)[i]))
02457                     break;
02458             }
02459         }
02460 
02461         while (i <= last)
02462         {
02463             switch ((*s)[i])
02464             {
02465             case '<':
02466                 output << "&lt;";
02467                 break;
02468             case '>':
02469                 output << "&gt;";
02470                 break;
02471             case '&':
02472                 output << "&amp;";
02473                 break;
02474             default:
02475                 output << ((*s)[i]);
02476             }
02477 
02478             i++;
02479         }
02480 
02481         return newString (output.c_str());
02482     }
02483 
02484     Stringp AvmCore::EscapeAttributeValue (Atom v)
02485     {
02486         StringBuffer output(this);
02487 
02488         Stringp s = string (v);
02489 
02490         for (int i = 0; i < s->length(); i++)
02491         {
02492             switch ((*s)[i])
02493             {
02494             case '"':
02495                 output << "&quot;";
02496                 break;
02497             case '<':
02498                 output << "&lt;";
02499                 break;
02500             case '&':
02501                 output << "&amp;";
02502                 break;
02503             case 0x000a:
02504                 output << "&#xA;";
02505                 break;
02506             case 0x000d:
02507                 output << "&#xD;";
02508                 break;
02509             case 0x0009:
02510                 output << "&#x9;";
02511                 break;
02512             default:
02513                 output << ((*s)[i]);
02514             }
02515         }
02516 
02517         return newString (output.c_str());
02518     }
02519 
02520     XMLObject *AvmCore::atomToXMLObject (Atom atm) 
02521     {
02522         if (!isXML (atm))
02523             return 0;
02524 
02525         return (XMLObject*)(atomToScriptObject(atm));
02526     }
02527 
02528     E4XNode *AvmCore::atomToXML (Atom atm) 
02529     {
02530         if (!isXML (atm))
02531             return 0;
02532 
02533         return ((XMLObject*)(atomToScriptObject(atm)))->getNode();
02534     }
02535 
02536     XMLListObject *AvmCore::atomToXMLList (Atom atm) 
02537     {
02538         if (!isXMLList (atm))
02539             return 0;
02540 
02541         return (XMLListObject*)(atomToScriptObject(atm));
02542     }
02543 
02544     QNameObject *AvmCore::atomToQName (Atom atm) 
02545     {
02546         if (!isQName (atm))
02547             return 0;
02548 
02549         return (QNameObject*)(atomToScriptObject(atm));
02550     }
02551 
02552     Stringp AvmCore::_typeof (Atom arg)
02553     {
02554         if (!isNull(arg))
02555         {
02556             switch (arg&7)
02557             {
02558             default:
02559             case kObjectType:
02560                 if (isXML (arg) || isXMLList(arg))
02561                 {
02562                     return kxml;
02563                 }
02564                 else if (isFunction(arg))
02565                 {
02566                     return kfunction; // No special type code for functions, but we need to
02567                                     //  special case to return 'function' here.
02568                 }
02569                 else
02570                 {
02571                     return kobject;
02572                 }
02573 
02574             case kBooleanType:
02575                 return kboolean;
02576 
02577             case kIntegerType:
02578             case kDoubleType:
02579                 return knumber;
02580 
02581             case kSpecialType:
02582                 return kundefined;
02583 
02584             case kStringType:
02585                 return kstring;
02586 
02587             case kNamespaceType:
02588                 return kobject;
02589             }
02590         }
02591         else
02592         {
02593             // typeof(null) = "object"
02594             return kobject;
02595         }
02596     }
02597 
02598     size_t AvmCore::getToplevelSize() const
02599     {
02600         return sizeof(Toplevel);
02601     }
02602     
02603     Toplevel* AvmCore::createToplevel(VTable *vtable)
02604     {
02605         return new (GetGC(), vtable->getExtraSize()) Toplevel(vtable, NULL);
02606     }
02607 
02608     void AvmCore::presweep()
02609     {
02610         // clear out the string table
02611         {
02612             for (int i=0, n=numStrings; i < n; i++)
02613             {
02614                 if (strings[i] > AVMPLUS_STRING_DELETED && !GetGC()->GetMark(strings[i]))
02615                 {
02616                     strings[i] = AVMPLUS_STRING_DELETED;
02617                     deletedCount++;
02618                     stringCount--;
02619                 }
02620             }
02621         }
02622 
02623 
02624         // do the same for the namespaces
02625         {
02626             bool rehashFlag = false;
02627             for (int i=0, n=numNamespaces; i < n; i++)
02628             {
02629                 if (namespaces[i] != NULL && !GetGC()->GetMark(namespaces[i]))
02630                 {
02631                     rehashFlag = true;
02632                     namespaces[i] = NULL;
02633                 }
02634             }
02635 
02636             // if any interned strings were freed, rehash the intern table
02637             // todo - make this less aggressive
02638             if (rehashFlag)
02639                 rehashNamespaces(numNamespaces);
02640         }
02641 
02642 #ifdef FEATURE_SAMPLER
02643         _sampler.presweep();
02644 #endif
02645     }
02646 
02647     void AvmCore::postsweep()
02648     {
02649 #ifdef FEATURE_SAMPLER
02650         _sampler.postsweep();
02651 #endif
02652     }
02653 
02654 
02655     bool wcharEquals(const wchar *s1, const wchar *s2)
02656     {
02657         while (*s1) {
02658             if (*s1 != *s2) {
02659                 return false;
02660             }
02661             s1++;
02662             s2++;
02663         }
02664         return true;
02665     }
02666 
02667     int hashString(const wchar *ptr, int len)
02668     {
02669         int hashCode = 0;
02670         while (len--) {
02671             hashCode = (hashCode >> 28) ^ (hashCode << 4) ^ *ptr++;
02672         }
02673         return hashCode;
02674     }
02675 
02676     int AvmCore::findString(const wchar *s, int len)
02677     {
02678         int m = numStrings;
02679         // 80% load factor
02680         if (5*(stringCount+deletedCount+1) > 4*m) {
02681             if (2*stringCount > m) // 50%
02682                 rehashStrings(m = m << 1);
02683             else
02684                 rehashStrings(m);
02685         }
02686 
02687         // compute the hash function
02688         int hashCode = hashString(s, len);
02689 
02690         int bitMask = m - 1;
02691 
02692         // find the slot to use
02693         int i = (hashCode&0x7FFFFFFF) & bitMask;
02694         int n = 7;
02695         Stringp k;
02696         if (!deletedCount)
02697         {
02698             while ((k=strings[i]) != NULL && !k->FastEquals(s,len)) {
02699                 i = (i + (n++)) & bitMask; // quadratic probe
02700             }
02701         }
02702         else
02703         {
02704             int iFirstDeletedSlot = -1;
02705             while ((k=strings[i]) != NULL)
02706             {
02707                 if (k == AVMPLUS_STRING_DELETED)
02708                 {
02709                     if (iFirstDeletedSlot == -1)
02710                     {
02711                         iFirstDeletedSlot = i;
02712                     }
02713                 }
02714                 else if (k->FastEquals (s, len))
02715                 {
02716                     return i;
02717                 }
02718                 i = (i + (n++)) & bitMask; // quadratic probe
02719             }
02720 
02721             if ((k == NULL) && (iFirstDeletedSlot != -1))
02722                 return iFirstDeletedSlot;
02723 
02724         }
02725         return i;
02726     }
02727 
02733     int AvmCore::findNamespace(const Namespace* ns)
02734     {
02735         int m = numNamespaces;
02736         // 80% load factor
02737         if (nsCount*5 >= 4*m) {
02738             rehashNamespaces(m = m << 1);
02739         }
02740 
02741         // compute the hash function
02742         int hashCode = (int)(((uintptr)ns->getURI())>>3);
02743 
02744         int bitMask = m - 1;
02745 
02746         // find the slot to use
02747         int i = (hashCode&0x7FFFFFFF) & bitMask;
02748         int n = 7;
02749         Namespace* k;
02750         while ((k=namespaces[i]) != NULL && k->m_uri != ns->m_uri ) {
02751             i = (i + (n++)) & bitMask; // quadratic probe
02752         }
02753         return i;
02754     }
02755 
02756     Stringp AvmCore::constantString(const char *s)
02757     {
02758         return internString(newString(s));
02759     }
02760 
02766     Stringp AvmCore::internString(Stringp o)
02767     {
02768         if (o->isInterned())
02769             return o;
02770 
02771         int i = findString(o->c_str(), o->length());
02772         Stringp other;
02773         if ((other=strings[i]) <= AVMPLUS_STRING_DELETED)
02774         {
02775             if (other == AVMPLUS_STRING_DELETED)
02776             {
02777                 deletedCount--;
02778                 AvmAssert(deletedCount >= 0);
02779             }
02780             stringCount++;
02781             strings[i] = o;
02782             o->setInterned(this);
02783             return o;
02784         }
02785         else
02786         {
02787             return other;
02788         }
02789     }
02790 
02791     Stringp AvmCore::internString(Atom atom)
02792     {
02793         AvmAssert(isString(atom));
02794         Stringp s = atomToString(atom);
02795         return s->isInterned() ? s : internString(s);
02796     }
02797 
02798     Stringp AvmCore::internInt(int value)
02799     {
02800 #ifdef AVMPLUS_INTERNINT_CACHE
02801         // This simple cache of interned strings representing integers greatly benefits
02802         // array-heavy code in the interpreter, at least for the time being (2008-08-13).
02803         // But it would be better not to intern integers at all.
02804         //
02805         // #ifdeffed out on 2008-09-15 because the integer lookup optimizations in the
02806         // interpreter ought to make it unnecessary; code should be removed later if it
02807         // is not re-enabled.
02808         
02809         int index = value & 255;
02810         if (value >= 0 && index_strings[index] != NULL && index_strings[index]->value == value)
02811             return index_strings[index]->string;
02812 #endif  
02813         wchar buffer[65];
02814         int len;
02815         MathUtils::convertIntegerToString(value, buffer, len);
02816         Stringp s = internAlloc(buffer, len);
02817 
02818 #ifdef AVMPLUS_INTERNINT_CACHE
02819         if (value >= 0) {
02820             if (index_strings[index] == NULL)
02821                 index_strings[index] = new (GetGC()) IndexString;
02822             index_strings[index]->value = value;
02823             index_strings[index]->string = s;
02824         }
02825 #endif
02826 
02827         return s;
02828 
02829         // This optimized routine below works fine and is faster than calling
02830         // convertIntegerToString but with our support of integer keys in our
02831         // HashTables, this routine is no longer on a critical path.  Save some
02832         // code by leaving it disabled unless we can show a performance gain by
02833         // using it.
02834 #if 0
02835         // optimized case of MathUtils;:convertIntegerToString
02836 
02837         if ((uint32)value == 0x80000000) // MathUtils::convertIntegerToString doesn't deal with this number because you can't negate it.
02838         {
02839             UnicodeUtils::Utf8ToUtf16((uint8*)"-2147483648", 12, buffer, 24);
02840             return internAlloc(buffer, 11);
02841         }
02842 
02843         wchar *src = &buffer[39];
02844         *src-- = '\0';
02845 
02846         if (value == 0)
02847         {
02848             *src-- = '0';
02849         }
02850         else
02851         {
02852             uint32 uVal;
02853             bool negative = (value < 0);
02854             if (negative)
02855                 value = -value;
02856 
02857             uVal = (uint32)value;
02858 
02859             while (uVal != 0)
02860             {
02861                 uint32 j = uVal;
02862                 uVal = uVal / 10;
02863                 j -= (uVal * 10);
02864 
02865                 *src-- = (j + '0');
02866             }
02867 
02868             if (negative)
02869                 *src-- = '-';
02870         }
02871 
02872         return internAlloc(src + 1, &buffer[39] - src - 1);
02873 #endif
02874     }
02875     Stringp AvmCore::internUint32 (uint32 ui)
02876     { 
02877         if (ui & 0x80000000)
02878             return internDouble(ui);
02879         else
02880             return internInt((int)ui);  
02881     } 
02882 
02883     Stringp AvmCore::internDouble(double d)
02884     {
02885         // Bug 192033: Number.MAX_VALUE is 1.79e+308; size temp buffer accordingly
02886         wchar buffer[312];
02887         int len;
02888         MathUtils::convertDoubleToString(d, buffer, len);
02889         return internAlloc(buffer, len);
02890     }
02891 
02892 #ifdef FEATURE_SAMPLER
02893     Stringp AvmCore::findInternedString(const char *cs, int len8)
02894     {
02895         int len16 = UnicodeUtils::Utf8Count((const uint8*)cs, len8);
02896         // use alloca to avoid heap allocations where possible
02897         wchar *buffer = (wchar*) alloca((len16+1)*sizeof(wchar));
02898 
02899         if(!buffer) {
02900             AvmAssertMsg(false, "alloca failed!");
02901             return NULL;
02902         }
02903         
02904         UnicodeUtils::Utf8ToUtf16((const uint8 *)cs, len8, buffer, len16);
02905         buffer[len16] = 0;
02906         int i = findString(buffer, len16);
02907         Stringp other;
02908         if ((other=strings[i]) > AVMPLUS_STRING_DELETED)
02909         {       
02910             return other;
02911         }
02912         return NULL;
02913     }
02914 #endif
02915 
02916     Stringp AvmCore::internAllocUtf8(const byte *cs, int len8)
02917     {
02918         int len16 = UnicodeUtils::Utf8Count((const uint8*)cs, len8);
02919         // use alloca to avoid heap allocations where possible
02920         wchar *buffer = 0;
02921         if (len16 < 1024)
02922             buffer = (wchar*) alloca((len16+1)*sizeof(wchar));
02923         
02924         Stringp s = NULL;
02925         if(!buffer) {
02926             s = new (GetGC()) String((const char *)cs, len8, len16);
02927             buffer = (wchar*)s->c_str();
02928         } else {
02929             UnicodeUtils::Utf8ToUtf16((const uint8 *)cs, len8, buffer, len16);
02930             buffer[len16] = 0;
02931         }
02932 
02933         int i = findString(buffer, len16);
02934         Stringp other;
02935         if ((other=strings[i]) <= AVMPLUS_STRING_DELETED)
02936         {
02937             if (other == AVMPLUS_STRING_DELETED)
02938             {
02939                 deletedCount--;
02940                 AvmAssert(deletedCount >= 0);
02941             }
02942 
02943             stringCount++;
02944             if(!s)
02945                 s = new (GetGC()) String(buffer, len16);
02946             strings[i] = s;
02947             s->setInterned(this);
02948             return s;
02949         }
02950         else
02951         {
02952             // we know the internal buf has not yet been aliased, so it's safe to explicitly free here.
02953             delete s;
02954             return other;
02955         }
02956     }
02957 
02958     Stringp AvmCore::internAlloc(const wchar *s, int len)
02959     {
02960         int i = findString(s, len);
02961         Stringp other;
02962         if ((other=strings[i]) <= AVMPLUS_STRING_DELETED)
02963         {
02964             if (other == AVMPLUS_STRING_DELETED)
02965             {
02966                 deletedCount--;
02967                 AvmAssert(deletedCount >= 0);
02968             }
02969             
02970 #ifdef DEBUGGER         
02971             DRC(Stringp) *oldStrings = strings;
02972 #endif
02973 
02974             other = new (GetGC()) String(s,len);
02975             
02976 #ifdef DEBUGGER
02977             // re-find if String ctor caused rehash
02978             if(strings != oldStrings)
02979                 i = findString(s, len);
02980 #endif
02981             strings[i] = other;
02982             stringCount++;
02983             other->setInterned(this);
02984         }
02985         return other;
02986     }
02987 
02988     void AvmCore::rehashStrings(int newlen)
02989     {
02990         // rehash
02991 
02992         DRC(Stringp) *oldStrings = strings;
02993         int oldStringCount = numStrings;
02994 
02995         strings = new DRC(Stringp)[newlen];
02996         memset(strings, 0, newlen*sizeof(Stringp));
02997         numStrings = newlen;
02998 
02999 #ifdef _DEBUG // debug sanity checks
03000         int oldDeletedCount = deletedCount;
03001         int computedDeleteCount = 0;
03002         int computedStringCount = 0;
03003 #endif
03004 
03005         deletedCount = 0;
03006 
03007         // Inlined and optimized our findString routine.  We know that there
03008         // are no duplicated strings in our intern string table so we don't 
03009         // need to call Equals.  All we need to do is find the first blank
03010         // spot available.
03011         int m = numStrings;
03012         int bitMask = m - 1;
03013 
03014         for (int i=0; i < oldStringCount; i++)
03015         {
03016             Stringp o = oldStrings[i];
03017             if (o > AVMPLUS_STRING_DELETED)
03018             {
03019                 // compute the hash function
03020                 int hashCode = hashString(o->c_str(), o->length());
03021 
03022                 // find the slot to use
03023                 int j = (hashCode&0x7FFFFFFF) & bitMask;
03024                 int n = 7;
03025                 while (strings[j] != NULL) {
03026                     j = (j + (n++)) & bitMask; // quadratic probe
03027                 }
03028 
03029                 strings[j] = o;
03030 #ifdef _DEBUG
03031                 computedStringCount++;
03032 #endif
03033             }
03034 #ifdef _DEBUG
03035             else if (o == AVMPLUS_STRING_DELETED)
03036             {
03037                 computedDeleteCount++;
03038             }
03039 #endif
03040         }
03041 
03042 #ifdef _DEBUG
03043         AvmAssert(computedStringCount == stringCount);
03044         AvmAssert(oldDeletedCount == computedDeleteCount);
03045 #endif
03046 
03047         // Clear oldStrings so it can be collected.
03048         delete [] oldStrings;
03049     }
03050 
03051     void AvmCore::rehashNamespaces(int newlen)
03052     {
03053         // rehash
03054 
03055         DRC(Namespacep) *old = namespaces;
03056         int oldCount = numNamespaces;
03057 
03058         namespaces = new DRC(Namespacep)[newlen];
03059         memset(namespaces, 0, newlen*sizeof(Namespace*));
03060         numNamespaces = newlen;
03061         
03062         for (int i=0; i < oldCount; i++)
03063         {
03064             Namespace* o = old[i];
03065             if (o != NULL)
03066                 namespaces[findNamespace(o)] = o;
03067         }
03068 
03069         // Clear old namespaces table so it can be collected.
03070         delete [] old;
03071     }
03072         
03073     ScriptBufferImpl* AvmCore::newScriptBuffer(size_t size)
03074     {
03075         return new (GetGC(), size) BasicScriptBufferImpl(size);
03076     }
03077     
03078     VTable* AvmCore::newVTable(Traits* traits, VTable* base, ScopeChain* scope,
03079         AbcEnv* abcEnv, Toplevel* toplevel)
03080     {
03081         size_t extraSize = sizeof(MethodEnv*)*(traits->methodCount > 0 ? traits->methodCount-1 : 0);
03082         return new (GetGC(), extraSize) VTable(traits, base, scope, abcEnv, toplevel);
03083     }
03084 
03085     RegExpObject* AvmCore::newRegExp(RegExpClass* regexpClass,
03086                                   Stringp pattern,
03087                                   Stringp options)
03088     {
03089         return new (GetGC(), regexpClass->ivtable()->getExtraSize()) RegExpObject(regexpClass,
03090                                                          pattern, options);
03091     }
03092     
03093     ScriptObject* AvmCore::newObject(VTable *vtable, ScriptObject *delegate)
03094     {
03095         return new (GetGC(), vtable->getExtraSize()) ScriptObject(vtable, delegate);
03096     }
03097 
03098     Namespace* AvmCore::newNamespace(Atom prefix, Atom uri, Namespace::NamespaceType type)
03099     {
03100         // E4X - this is 13.2.3, step 3 - prefix IS specified
03101 
03102         Atom p;
03103         Stringp u;
03104         if (isQName (uri) && !isNull(atomToQName (uri)->getURI()))
03105         {
03106             u = atomToString(atomToQName (uri)->getURI());
03107         }
03108         else
03109         {
03110             u = internString (string (uri));
03111         }
03112         if (u == kEmptyString)
03113         {
03114             if (prefix == undefinedAtom)
03115                 p = kEmptyString->atom();
03116             else if (!string (prefix)->length())
03117                 p = kEmptyString->atom();
03118             else
03119             {
03120                 // !!@ throw correct type error
03121                 //typeErrorClass()->throwError(kConvertUndefinedToObjectError);
03122                 return NULL;
03123             }
03124         }
03125         else if (prefix == undefinedAtom)
03126         {
03127             p = undefinedAtom;
03128         }
03129         else if (prefix != kEmptyString->atom() && !isXMLName (prefix))
03130         {
03131             p = undefinedAtom;
03132         }
03133         else
03134         {
03135             p = internString (string (prefix))->atom();
03136         }
03137 
03138         return new (GetGC()) Namespace(p, u, type);
03139     }
03140 
03141     Namespace* AvmCore::newNamespace(Atom uri, Namespace::NamespaceType type)
03142     {
03143         // prefix and uri must be interned!
03144         // E4X - this is 13.2.2, step 3 - "prefix not specified"
03145 
03146         if (isNamespace (uri))
03147         {
03148             Namespace *ns = atomToNamespace (uri);
03149             return new (GetGC()) Namespace (ns->getPrefix(), ns->getURI(), type);
03150         }
03151         else if (isObject(uri) && isQName (uri) && !isNull(atomToQName (uri)->getURI()))
03152         {
03153             return new (GetGC()) Namespace (undefinedAtom, atomToString(atomToQName (uri)->getURI()), type);
03154         }
03155         else
03156         {
03157             Stringp u = internString (string (uri));
03158             Atom prefix = (u == kEmptyString) ? kEmptyString->atom() : undefinedAtom;
03159             return new (GetGC()) Namespace (prefix, u, type);
03160         }
03161     }
03162 
03163     Namespace* AvmCore::newNamespace(Stringp uri, Namespace::NamespaceType type)
03164     {
03165         uri = internString(uri);
03166         Atom prefix = (uri == kEmptyString) ? kEmptyString->atom() : undefinedAtom;
03167         return new (GetGC()) Namespace(prefix, uri, type);
03168     }
03169 
03170     NamespaceSet* AvmCore::newNamespaceSet(int nsCount)
03171     {
03172         size_t extra = (nsCount >= 1 ? nsCount-1 : 0)*sizeof(Atom);
03173         return new (GetGC(), extra) NamespaceSet(nsCount);
03174     }
03175 
03176     Atom AvmCore::uintToAtom(uint32 n)
03177     {
03178 #ifdef AVMPLUS_64BIT
03179         // We can always fit the value in an Atom
03180         return (((Atom)n)<<3) | kIntegerType;
03181 #else
03182         // As kIntegerType is signed, we can only represent a 28-bit uint in it
03183         if (!(n&0xF0000000)) {
03184             return uint32((n<<3) | kIntegerType);
03185         } else {
03186             return allocDouble(n);
03187         }
03188 #endif
03189     }
03190             
03191     Atom AvmCore::intToAtom(int n)
03192     {
03193 #ifdef AVMPLUS_64BIT
03194         // We can always fi t the value in an Atom
03195         return (((Atom)n)<<3) | kIntegerType;
03196 #else
03197         // handle integer values w/out allocation
03198         int i29 = n << 3;
03199         if ((i29>>3) == n)
03200         {
03201             return uint32(i29 | kIntegerType);;
03202         }
03203         else 
03204         {
03205             return allocDouble(n);
03206         }
03207 #endif
03208     }
03209 
03210 #if defined(AVMPLUS_IA32) || defined(AVMPLUS_AMD64)
03211     // ignore warning that inline asm disables global optimization in this function
03212     #ifdef _MSC_VER
03213     #pragma warning(disable: 4740) 
03214     #endif
03215     Atom AvmCore::doubleToAtom_sse2(double n)
03216     {
03217         // handle integer values w/out allocation
03218         // this logic rounds in the wrong direction for E3, but
03219         // we never use a rounded value, only cleanly converted values.
03220         #if defined(WIN32) || defined(__ICC) 
03221         #ifdef AVMPLUS_AMD64
03222         int32_t id = _mm_cvttsd_si32(_mm_set_sd(n));
03223         if (id == n) {
03224             // make sure its not -0
03225             if (id == 0 && MathUtils::isNegZero(n)) {
03226                 return allocDouble(n);
03227             } else {
03228                 return (intptr_t(id)<<3) | kIntegerType;
03229             }
03230         }
03231         return allocDouble(n);
03232         #else
03233         int id3;
03234         __asm {
03235             movsd xmm0,n
03236             cvttsd2si ecx,xmm0
03237             shl ecx,3       // id<<3
03238             mov eax,ecx
03239             sar ecx,3       // id>>3
03240             cvtsi2sd xmm1,ecx
03241             ucomisd xmm0,xmm1
03242             jne d2a_alloc   // < or >
03243             jp  d2a_alloc   // unordered
03244             mov id3,eax
03245         }
03246 
03247         if (id3 != 0 || !MathUtils::isNegZero(n))
03248         {
03249             return id3 | kIntegerType;
03250         }
03251         else
03252         {
03253             __asm d2a_alloc:
03254             return allocDouble(n);
03255         }
03256         #endif
03257         #elif defined(_MAC) && (defined(AVMPLUS_IA32) || defined(AVMPLUS_AMD64))
03258         int id = _mm_cvttsd_si32(_mm_set_sd(n));
03259         // MacTel is luckily always using SSE2, there
03260         // are no intrinsics to check for unordered 
03261         // mode here using any of the _mm_ucominXXX
03262         // instructions
03263         if (((id<<3)>>3) == n) {
03264             // make sure its not -0
03265             if (id == 0 && MathUtils::isNegZero(n)) {
03266                 return allocDouble(n);
03267             } else {
03268 #ifdef AVMPLUS_64BIT
03269                 return (id<<3) | kIntegerType;
03270 #else
03271                 return uint32((id<<3) | kIntegerType);
03272 #endif
03273 
03274             }
03275         }
03276         return allocDouble(n);
03277         #elif defined(SOLARIS)
03278         return AvmCore::doubleToAtom(n); // This needs to be optimized for solaris.
03279         #elif defined(AVMPLUS_UNIX)
03280         #ifdef __amd64__
03281         int32_t id = _mm_cvttsd_si32(_mm_set_sd(n));
03282         if (id == n) {
03283             // make sure its not -0
03284             if (id == 0 && MathUtils::isNegZero(n)) {
03285                 return allocDouble(n);
03286             } else {
03287                 return (intptr_t(id)<<3) | kIntegerType;
03288             }
03289         }
03290         return allocDouble(n);
03291         #else // __amd64__
03292         int id3;
03293         asm("movups %1, %%xmm0;"
03294             "cvttsd2si %%xmm0, %%ecx;"
03295             "shl $0x3, %%ecx;"
03296             "mov %%ecx, %%eax;"
03297             "sar $0x3, %%ecx;"
03298             "cvtsi2sd %%ecx, %%xmm1;"
03299             "ucomisd %%xmm1, %%xmm0;"
03300             "jne d2a_alloc;"
03301             "jp d2a_alloc;"
03302             "movl %%eax, %0" : "=r" (id3) : "m" (n));
03303 
03304         if (id3 != 0 || !MathUtils::isNegZero(n))
03305         {
03306             return id3 | kIntegerType;
03307         }
03308 
03309         asm("d2a_alloc:");
03310         return allocDouble(n);
03311         #endif // __amd64__
03312         #endif // defined(AVMPLUS_UNIX)
03313     }
03314 #endif
03315 
03316 #ifndef AVMPLUS_AMD64
03317     Atom AvmCore::doubleToAtom(double n)
03318     {
03319         // There is no need for special logic for NaN or +/-Inf since we don't
03320         // ever test for those values in coreplayer.  As far as we're concerned
03321         // they are regular numeric values.
03322 
03323         // handle integer values w/out allocation
03324         #if defined(WIN32) && !defined(_ARM_)
03325         #ifdef AVMPLUS_AMD64
03326         int id = _mm_cvttsd_si32(_mm_set_sd(n));
03327         #else
03328         // this logic rounds in the wrong direction for E3, but
03329         // we never use a rounded value, only cleanly converted values.
03330         int id;
03331         _asm {
03332             fld [n];
03333             fistp [id];
03334         }
03335         #endif
03336         #elif defined(_MAC) && (defined (AVMPLUS_IA32) || defined(AVMPLUS_AMD64))
03337         int id = _mm_cvttsd_si32(_mm_set_sd(n));
03338         #else
03339         int id = MathUtils::real2int(n);
03340         #endif
03341 
03342         // make sure n is integer value that fits in 29 bits
03343         if (((id<<3)>>3) == n)
03344         {
03345             // make sure its not -0
03346             if (id == 0 && MathUtils::isNegZero(n))
03347                 return allocDouble(n);
03348             else
03349             {
03350 #ifdef AVMPLUS_64BIT
03351                 return (id<<3) | kIntegerType;
03352 #else
03353                 return uint32((id<<3) | kIntegerType);
03354 #endif
03355             }
03356         }
03357         else
03358         {
03359             return allocDouble(n);
03360         }
03361     }
03362 #endif // not AVMPLUS_AMD64
03363 
03364 #ifdef AVMPLUS_VERBOSE
03365 
03371     Stringp AvmCore::format(Atom atom)
03372     {
03373         if (!isNull(atom))
03374         {
03375             switch (atom&7)
03376             {
03377             default:
03378             case kNamespaceType:
03379                 return atomToNamespace(atom)->format(this);
03380             case kObjectType:
03381                 return atomToScriptObject(atom)->format(this);
03382             case kStringType:
03383                 {
03384                     Stringp quotes = newString("\"");
03385                     return concatStrings(quotes,
03386                         concatStrings(atomToString((atom&~7)==0 ? kEmptyString->atom() : atom),
03387                                                     quotes));
03388                 }
03389             case kSpecialType:
03390                 return kundefined;
03391             case kBooleanType:
03392                 return booleanStrings[atom>>3];
03393             case kIntegerType:
03394 #ifdef AVMPLUS_64BIT
03395                 return intToString((int)(atom>>3));
03396 #else
03397                 return intToString((int)(sint32(atom)>>3));
03398 #endif
03399             case kDoubleType:
03400                 AvmAssert(atom != kDoubleType); // this would be a null pointer to double
03401                 return doubleToString(atomToDouble(atom));
03402             }
03403         }
03404         else
03405         {
03406             return knull;
03407         }
03408     }
03409 
03410     Stringp AvmCore::formatAtomPtr(Atom atom)
03411     {
03412         wchar buffer[256];
03413         int len;
03414         MathUtils::convertIntegerToString((int)atom, buffer, len, 16);
03415         return new (GetGC()) String(buffer, len);
03416     }
03417 #endif
03418 
03424     Traits* AvmCore::newTraits(Traits *base,
03425                             int nameCount,
03426                             int interfaceDelta,
03427                             uint32 objectSize)
03428     {
03429         int interfaceCount = interfaceDelta;
03430         if (base)
03431             interfaceCount += base->interfaceCount+1; // +1 b/c base is added
03432         int interfaceCapacity = MathUtils::nextPowerOfTwo((5*interfaceCount >> 2) + 1);
03433         size_t extra = interfaceCapacity*sizeof(Traits*);
03434         Traits* traits = new (GetGC(), extra) Traits(this, base,
03435                                               nameCount,
03436                                               interfaceCount,
03437                                               interfaceCapacity,
03438                                               objectSize);
03439         return traits;
03440     }
03441     
03442     Stringp AvmCore::newString(const char *s) const
03443     {
03444         int len = String::Length(s);
03445         int utf16len = UnicodeUtils::Utf8ToUtf16((const uint8*)s, len, NULL, 0);
03446         return new (GetGC()) String(s, len, utf16len);
03447     }
03448 
03449     Stringp AvmCore::newString(const char *s, int len) const
03450     {
03451         int utf16len = UnicodeUtils::Utf8ToUtf16((const uint8*)s, len, NULL, 0);
03452         return new (GetGC()) String(s, len, utf16len);
03453     }
03454 
03455     Stringp AvmCore::newString(const wchar *s) const
03456     {
03457         int len = String::Length(s);
03458         return new (GetGC()) String(s, len);
03459     }
03460 
03461     Stringp AvmCore::concatStrings(Stringp s1, Stringp s2) const
03462     {
03463         if (!s1) s1 = knull;
03464         if (!s2) s2 = knull;
03465         if (s1->length() == 0) {
03466             return s2;
03467         } else if (s2->length() == 0) {
03468             return s1;
03469         }
03470         return new (GetGC()) String(s1, s2);
03471     }
03472 
03473     Stringp AvmCore::intToString(int value)
03474     {
03475         wchar buffer[65];
03476         int len;
03477         MathUtils::convertIntegerToString(value, buffer, len);
03478         return new (GetGC()) String(buffer, len);
03479     }
03480 
03481     Stringp AvmCore::uintToString(uint32 value)
03482     {
03483         wchar buffer[65];
03484         int len;
03485         if (value <= 0x7FFFFFFF)
03486             MathUtils::convertIntegerToString(value, buffer, len);
03487         else
03488             MathUtils::convertDoubleToString(value, buffer, len);
03489         return new (GetGC()) String(buffer, len);
03490     }
03491 
03492     Stringp AvmCore::doubleToString(double d)
03493     {
03494         // Bug 192033: Number.MAX_VALUE is 1.79e+308; size temp buffer accordingly
03495         wchar buffer[312];
03496         int len;
03497         MathUtils::convertDoubleToString(d, buffer, len, MathUtils::DTOSTR_NORMAL,15);
03498         return new (GetGC()) String(buffer, len);
03499     }
03500 
03501     #ifdef DEBUGGER
03502     StackTrace* AvmCore::newStackTrace()
03503     {
03504         int depth = callStack ? callStack->depth : 0;
03505         int extra = depth > 0 ? sizeof(StackTrace::Element) * (depth-1) : 0;
03506         StackTrace* stackTrace = new (GetGC(), extra) StackTrace();
03507         if (stackTrace)
03508         {
03509             stackTrace->depth = depth;
03510             CallStackNode *curr = callStack;
03511             StackTrace::Element *element = stackTrace->elements;
03512             while (curr) {
03513                 element->info     = curr->info;
03514                 element->filename = curr->filename;
03515                 element->linenum  = curr->linenum;
03516                 element++;
03517                 curr = curr->next;
03518             }
03519         }
03520         return stackTrace;
03521     }
03522 
03523     #ifdef _DEBUG
03524     void AvmCore::dumpStackTrace()
03525     {
03526         StringBuffer buffer(this);      
03527         buffer << "Stack Trace:\n" << newStackTrace()->format(this) << '\n';
03528         AvmDebugMsg(false, buffer.c_str());
03529     }
03530     #endif
03531     #endif /* DEBUGGER */
03532 
03533     int AvmCore::integer(Atom atom) const
03534     {
03535         if ((atom & 7) == kIntegerType || (atom&7) == kBooleanType) {
03536             return (int32_t)(atom >> 3);
03537         } else {
03538             // TODO optimize the code below.
03539             double d = number(atom);
03540             return (int32_t)integer_d(d);
03541         }
03542     }
03543 
03544     // static
03545 
03546 #ifndef AVMPLUS_AMD64
03547     int AvmCore::integer_d(double d)
03548     {
03549         // Try a simple case first to see if we have a in-range float value
03550 
03551 #ifdef WIN32 // should be any intel build
03552         // WIN32's real2int returns 0x80000000 if d is not in a valid integer range
03553         int id = MathUtils::real2int (d);
03554         if (id != 0x80000000) 
03555             return id;
03556 #elif AVMPLUS_SPARC
03557         int id = MathUtils::real2int (d);
03558         if (id != 0x7fffffff && id != 0x80000000)
03559             return id;
03560 #endif
03561 
03562         return doubleToInt32(d);
03563     }
03564 #endif // not AVMPLUS_AMD64
03565 
03566 #if defined(AVMPLUS_IA32) || defined(AVMPLUS_AMD64)
03567     int AvmCore::integer_d_sse2(double d)
03568     {
03569         int id;
03570         #ifdef WIN32 
03571         #ifdef AVMPLUS_AMD64
03572         id = _mm_cvttsd_si32(_mm_set_sd(d));
03573         if (id != (int)0x80000000)
03574             return id;
03575         #else
03576         _asm {
03577             cvttsd2si eax,d
03578             mov id,eax
03579         }
03580         if (id != 0x80000000)
03581             return id;
03582         #endif
03583         #elif defined(_MAC) && (defined(AVMPLUS_IA32) || defined(AVMPLUS_AMD64))        
03584         id = _mm_cvttsd_si32(_mm_set_sd(d));
03585         if (id != (int)0x80000000)
03586             return id;
03587         #elif defined(SOLARIS)
03588         #elif AVMPLUS_UNIX
03589         asm("movups %1, %%xmm0;"
03590             "cvttsd2si %%xmm0, %%eax;"
03591             "movl %%eax, %0" : "=r" (id) : "m" (d) : "%eax");
03592         if (id != (int) 0x80000000)
03593             return id;
03594         #endif
03595 
03596         return doubleToInt32(d);
03597     }
03598 #endif // AVMPLUS_IA32 or AVMPLUS_AMD64
03599 
03600 
03601 #if !defined(AVMPLUS_IA32) && !defined(AVMPLUS_AMD64)
03602     int AvmCore::doubleToInt32(double d)
03603     {
03604         // From the ES3 spec, 9.5
03605         //  2.  If Result(1) is NaN, +0, -0, +Inf, or -Inf, return +0.
03606         //  3.  Compute sign(Result(1)) * floor(abs(Result(1))).
03607         //  4.  Compute Result(3) modulo 2^32; that is, a finite integer value k of Number 
03608         //  type with positive sign and less than 2^32 in magnitude such the mathematical 
03609         //  difference of Result(3) and k is mathematically an integer multiple of 2^32.
03610         //  5.  If Result(4) is greater than or equal to 2^31, return Result(4)- 2^32, 
03611         //  otherwise return Result(4).
03612 
03613         // step 2
03614         if (MathUtils::isNaN(d) || MathUtils::isInfinite(d) || d == 0) {
03615             return 0;
03616         }
03617 
03618         // step 3 (round towards 0)
03619         double ad = d < 0.0 ? MathUtils::floor(-d) : MathUtils::floor(d);
03620 
03621         // step 4
03622         if (ad > 4294967295.0)
03623             ad = MathUtils::mod(ad,4294967296.0); // ad %= 0x10000000
03624 
03625         // step 5
03626         if (ad >= (double)2147483648.0)
03627         {
03628             // This case is a large negative number that overflows back to a positive
03629             // number.  This code has been tweaked to work on both Mac and Windows.  Mac
03630             // is particularly sensitive to edge numbers such as 0x80000000 when converting
03631             // doubles to ints).
03632             if (d < 0.0)
03633             {
03634                 int intVal = MathUtils::real2int (ad - 2147483648.0);
03635                 return 0x80000000 - intVal;
03636             }
03637             // This case is a large positive number overflowing to negative.
03638             else
03639             {
03640                 int intVal = MathUtils::real2int (ad - 2147483648.0);
03641                 return 0x80000000 + intVal;
03642             }
03643         }
03644         else
03645         {
03646             return MathUtils::real2int(d < 0.0 ? -ad : ad);
03647         }
03648     }
03649 #else
03650         // From the ES3 spec, 9.5
03651         //  2.  If Result(1) is NaN, +0, -0, +Inf, or -Inf, return +0.
03652         //  3.  Compute sign(Result(1)) * floor(abs(Result(1))).
03653         //  4.  Compute Result(3) modulo 2^32; that is, a finite integer value k of Number 
03654         //  type with positive sign and less than 2^32 in magnitude such the mathematical 
03655         //  difference of Result(3) and k is mathematically an integer multiple of 2^32.
03656         //  5.  If Result(4) is greater than or equal to 2^31, return Result(4)- 2^32, 
03657         //  otherwise return Result(4).
03658 #if defined(AVMPLUS_AMD64)
03659     #define DBLTOINT32_INT64 1
03660 #else
03661     #define DBLTOINT32_INT64 0
03662 #endif
03663     
03664     typedef union {  
03665         double d;
03666         uint64 i;
03667 #if defined(AVMPLUS_IA32) || defined(AVMPLUS_AMD64)     
03668         struct { 
03669             uint32 il, ih;
03670         } i32;
03671 #else
03672 #error("this routine does not work in PowerPC processors");
03673         struct { 
03674             uint32 ih, il;
03675         } i32;
03676 #endif
03677     } double_int;
03678     
03679     #if DBLTOINT32_INT64
03680     int AvmCore::doubleToInt32(double d)
03681     {
03682         double_int du, duh, two32;
03683         uint64 sign_d;
03684         int64 MASK;
03685         uint32 DI_H, u_tmp, expon, shift_amount;
03686     
03687         //  Algorithm Outline 
03688         //  Step 1.  If d is NaN, +/-Inf or |d|>=2^84 or |d|<1, then return 0
03689         //  All of this is implemented based on an exponent comparison.
03690         //  Step 2.  If |d|<2^31, then return (int)d
03691         //  The cast to integer (conversion in RZ mode) returns the correct result.
03692         //  Step 3. If |d|>=2^32, d:=fmod(d, 2^32) is taken  -- but without a call
03693         //  Step 4. If |d|>=2^31, then the fractional bits are cleared before
03694         //  applying the correction by 2^32:  d - sign(d)*2^32
03695         //  Step 5.  Return (int)d
03696         
03697         du.d = d;
03698         DI_H = du.i32.ih;
03699         
03700         u_tmp = (DI_H & 0x7ff00000) - 0x3ff00000;
03701         if(u_tmp >= (0x45300000-0x3ff00000)) {
03702             // d is Nan, +/-Inf or +/-0, or |d|>=2^(32+52) or |d|<1, in which case result=0
03703             return 0;
03704         }
03705         
03706         if(u_tmp < 0x01f00000) {
03707             // |d|<2^31
03708             return int32(d);
03709         }
03710 
03711         if(u_tmp > 0x01f00000) {
03712             // |d|>=2^32
03713             expon = u_tmp >> 20;
03714             shift_amount = expon - 21;
03715             duh.i = du.i;
03716             MASK = 0x8000000000000000ll;
03717             MASK = MASK >> shift_amount;
03718             duh.i &= (uint64)MASK;
03719             du.d -= duh.d;
03720         }
03721         
03722         DI_H = du.i32.ih;
03723         
03724         // eliminate fractional bits
03725         u_tmp = (DI_H & 0x7ff00000);
03726         if(u_tmp >= 0x41e00000) {
03727             // |d|>=2^31
03728             expon = u_tmp >> 20;
03729             shift_amount = expon - (0x3ff - 11);
03730             MASK = 0x8000000000000000ll;
03731             MASK = MASK >> shift_amount;
03732             du.i &= (uint64)MASK;
03733             sign_d = du.i & 0x8000000000000000ull;
03734             two32.i = 0x41f0000000000000ull ^ sign_d;
03735             du.d -= two32.d;
03736         }
03737         
03738         return int32(du.d);
03739     }
03740     #else // DBLTOINT32_INT64
03741     int AvmCore::doubleToInt32(double d)
03742     {
03743         double_int du, duh, two32;
03744         uint32 DI_H, u_tmp, expon, shift_amount;
03745         int32 mask32;
03746     
03747         //  Algorithm Outline 
03748         //  Step 1.  If d is NaN, +/-Inf or |d|>=2^84 or |d|<1, then return 0
03749         //  All of this is implemented based on an exponent comparison.
03750         //  Step 2.  If |d|<2^31, then return (int)d
03751         //  The cast to integer (conversion in RZ mode) returns the correct result.
03752         //  Step 3. If |d|>=2^32, d:=fmod(d, 2^32) is taken  -- but without a call
03753         //  Step 4. If |d|>=2^31, then the fractional bits are cleared before
03754         //  applying the correction by 2^32:  d - sign(d)*2^32
03755         //  Step 5.  Return (int)d
03756        
03757        du.d = d;
03758        DI_H = du.i32.ih;
03759        
03760        u_tmp = (DI_H & 0x7ff00000) - 0x3ff00000;
03761        if(u_tmp >= (0x45300000-0x3ff00000)) {
03762            // d is Nan, +/-Inf or +/-0, or |d|>=2^(32+52) or |d|<1, in which case result=0
03763            return 0;
03764        }
03765        
03766        if(u_tmp < 0x01f00000) {
03767            // |d|<2^31
03768            return int32(d);
03769        }
03770        
03771        if(u_tmp > 0x01f00000) {
03772            // |d|>=2^32
03773            expon = u_tmp >> 20;
03774            shift_amount = expon - 21;
03775            duh.i = du.i;
03776            mask32 = 0x80000000;
03777            if(shift_amount<32) {
03778                mask32 >>= shift_amount;
03779                duh.i32.ih = du.i32.ih & mask32;
03780                duh.i32.il = 0;
03781            }
03782            else {
03783                mask32 >>= (shift_amount-32);
03784                duh.i32.ih = du.i32.ih;
03785                duh.i32.il = du.i32.il & mask32;
03786            }
03787            du.d -= duh.d;
03788        }
03789 
03790         DI_H = du.i32.ih;
03791 
03792         // eliminate fractional bits
03793         u_tmp = (DI_H & 0x7ff00000);
03794         if(u_tmp >= 0x41e00000) {
03795             // |d|>=2^31
03796             expon = u_tmp >> 20;
03797             shift_amount = expon - (0x3ff - 11);
03798             mask32 = 0x80000000;
03799             if(shift_amount<32) {
03800                 mask32 >>= shift_amount;
03801                 du.i32.ih &= mask32;
03802                 du.i32.il = 0;
03803             }
03804             else {
03805                 mask32 >>= (shift_amount-32);
03806                 du.i32.il &= mask32;
03807             }
03808             two32.i32.ih = 0x41f00000 ^ (du.i32.ih & 0x80000000);
03809             two32.i32.il = 0;
03810             du.d -= two32.d;
03811         }
03812 
03813         return int32(du.d);
03814     }
03815    #endif // DBLTOINT32_INT64
03816 #endif // !(defined(AVMPLUS_IA32) || defined(AVMPLUS_AMD64))        
03817 
03818     // This routine is a very specific parser to generate a positive integer from a string.
03819     // The following are supported:
03820     // "0" - one single digit for zero - NOT "00" or any other form of zero
03821     // [1-9]+[0-9]* up to 2^32-2 (4294967294)
03822     // 2^32-1 (4294967295) is not supported (see ECMA quote below).
03823     // The ECMA that we're supporting with this routine is...
03824     // cn:  the ES3 test for a valid array index is 
03825     //  "A property name P (in the form of a string value) is an array index if and 
03826     //  only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 2^32-1."
03827     bool AvmCore::getIndexFromString (Stringp s, uint32 *result)
03828     {
03829         int len = s->length();
03830         if (!len)
03831             return false;
03832 
03833         // Don't support 000000 as 0.
03834         // We don't support 0x1234 as 1234 in hex since string(1234) doesn't equal '0x1234')
03835         // No leading zeros are supported
03836 
03837         // Single 0 is ok
03838         const wchar *c = s->c_str();
03839         if (*c == '0')
03840         {
03841             if (len == 1)
03842             {
03843                 *result = 0;
03844                 return true;
03845             }
03846             else
03847             {
03848                 return false;
03849             }
03850         }
03851         else if ((*c < '0') || (*c > '9'))
03852         {
03853             return false;
03854         }
03855 
03856         // A string that is more than 10 digits (and does not start with 0) 
03857         // will always be greater than 2^32-1 (4294967295) or not a numeric string
03858         if (len > 10)
03859         {
03860             return false;
03861         }
03862 
03863         uint32 res = 0;
03864         int i = 0;
03865         while (i < len)
03866         {
03867             wchar ch = c[i];
03868             if (ch < '0' || ch > '9')
03869                 return false;
03870 
03871             res = res * 10 + (ch - '0');
03872             i++;
03873         }
03874 
03875         *result = res;
03876         // Our input string length is less then 10 digits so we now
03877         // our output is in the valid range up to 999,999,999.
03878         if (len < 10)
03879         {
03880             return true;
03881         }
03882 
03883         // At this point we know our string is 10 characters long and is all numeric 
03884         // characters.  We need to check it to see if it overflows 2^32 and whether it equals
03885         // 2^32-1.  This string comparison works as a numeric comparison since we know our input
03886         // string is also ten numeric digits.
03887 
03888         int comp = String::Compare (c, "4294967295", 10);
03889         return (comp > 0);
03890     }
03891 
03892     CodeContext* AvmCore::codeContext() const
03893     {
03894         if (codeContextAtom == CONTEXT_NONE) {
03895             return NULL;
03896         } else if ((codeContextAtom&7) == CONTEXT_ENV) {
03897             MethodEnv *env = (MethodEnv*)(codeContextAtom&~7);
03898             return env->vtable->abcEnv->codeContext;
03899         } else {
03900             return (CodeContext*)(codeContextAtom&~7);
03901         }
03902     }
03903 
03904 #ifdef AVMPLUS_MIR
03905 
03909     GrowableBuffer* AvmCore::requestMirBuffer()
03910     {
03911         GrowableBuffer* buffer = 0;
03912         if (mirBuffers.size() > 0)
03913             buffer = mirBuffers.removeFirst();
03914         else
03915             buffer = requestNewMirBuffer();
03916         return buffer;
03917     }
03918 
03919     GrowableBuffer* AvmCore::requestNewMirBuffer()
03920     {
03921         return new (GetGC()) GrowableBuffer(GetGC()->GetGCHeap(),true);
03922     }
03923 
03924     void AvmCore::releaseMirBuffer(GrowableBuffer* buffer)
03925     {
03926          buffer->free();  // free the underlying space
03927         mirBuffers.add(buffer);
03928     }
03929 #endif
03930 
03931 #ifdef MMGC_DRC
03932     /*static*/ 
03933     void AvmCore::decrementAtomRegion(Atom *arr, int length)
03934     {
03935         for(int i=0; i < length; i++)
03936         {
03937             Atom a = arr[i];
03938             RCObject *obj = (RCObject*)(a&~7);
03939             if(obj) {
03940                 switch(a&7) {
03941                 case kStringType:
03942                 case kObjectType:
03943                 case kNamespaceType:
03944                     ((RCObject*)(a&~7))->DecrementRef();
03945                     break;
03946                 }
03947             }
03948             arr[i] = 0;
03949         }
03950     }
03951 #endif
03952 
03953     /*static*/ 
03954     void AvmCore::atomWriteBarrier(MMgc::GC *gc, const void *container, Atom *address, Atom atomNew)
03955     { 
03956 #ifdef MMGC_DRC
03957         Atom atom = *address;
03958         if(!isNull(atom)) {
03959             switch(atom&7)
03960             {   
03961                 case kStringType:
03962                 case kObjectType:
03963                 case kNamespaceType:
03964                     MMgc::RCObject *obj = (MMgc::RCObject*)(atom&~7);
03965                     obj->DecrementRef();
03966                     break;
03967             }
03968         }
03969 #endif
03970 
03971         switch(atomNew&7)
03972         {
03973         case kStringType:
03974         case kObjectType:
03975         case kNamespaceType:
03976 #ifdef MMGC_DRC
03977             if(!isNull(atomNew))
03978                 ((MMgc::RCObject*)(atomNew&~7))->IncrementRef();
03979             // fall through
03980 #endif
03981         case kDoubleType:
03982             {
03983                 gc->WriteBarrierNoSubstitute(container, (const void*)atomNew);
03984             }
03985             break;  
03986 
03987         }
03988         *address = atomNew;
03989     }
03990 
03991     Atom AvmCore::gcObjectToAtom(const void* obj)
03992     {
03993 #ifdef _DEBUG
03994         // We get a null obj here through ElementE4XNode::_insert
03995         if (obj)
03996         {
03997             GC* gc = GC::GetGC(obj);
03998             AvmAssert(!gc->IsRCObject(obj));
03999         }
04000 #endif      
04001         // return a non-RC atom, makes atomWriteBarrier do the right thing
04002         return (Atom)obj|kDoubleType;
04003     }
04004 
04005 #if defined AVMPLUS_MIR || defined FEATURE_NANOJIT
04006 
04007     void AvmCore::initMultinameLate(Multiname& name, Atom index)
04008     {
04009         if (isObject(index))
04010         {
04011             ScriptObject* i = atomToScriptObject(index);
04012             if (i->traits() == traits.qName_itraits)
04013             {
04014                 QNameObject* qname = (QNameObject*) i;
04015                 bool attr = name.isAttr();
04016                 qname->getMultiname(name);
04017                 name.setAttr(attr);
04018                 return;
04019             }
04020         }
04021 
04022         name.setName(intern(index));
04023     }       
04024 #endif // MIR or NANOJIT
04025 }

Generated on Sun Oct 12 18:49:50 2008 for Tamarin by  doxygen 1.4.6