AsmJsByteCodeGenerator.cpp 147 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeLanguagePch.h"
  6. #ifndef TEMP_DISABLE_ASMJS
  7. #include "ByteCode/Symbol.h"
  8. #include "ByteCode/FuncInfo.h"
  9. #ifdef DBG_DUMP
  10. #include "ByteCode/ByteCodeDumper.h"
  11. #include "ByteCode/AsmJsByteCodeDumper.h"
  12. #endif
  13. #include "ByteCode/ByteCodeWriter.h"
  14. #include "ByteCode/ByteCodeGenerator.h"
  15. #include "ByteCode/AsmJsByteCodeWriter.h"
  16. #include "Language/AsmJsByteCodeGenerator.h"
  17. namespace Js
  18. {
  19. enum EBinaryMathOpCodes: int
  20. {
  21. BMO_ADD,
  22. BMO_SUB,
  23. BMO_MUL,
  24. BMO_DIV,
  25. BMO_REM,
  26. BMO_MAX,
  27. };
  28. enum EBinaryMathOpCodesTypes: int
  29. {
  30. BMOT_Int,
  31. BMOT_UInt,
  32. BMOT_Float,
  33. BMOT_Double,
  34. BMOT_MAX
  35. };
  36. const OpCodeAsmJs BinaryMathOpCodes[BMO_MAX][BMOT_MAX] = {
  37. /*BMO_ADD*/{ OpCodeAsmJs::Add_Int, OpCodeAsmJs::Add_Int, OpCodeAsmJs::Add_Flt, OpCodeAsmJs::Add_Db },
  38. /*BMO_SUB*/{ OpCodeAsmJs::Sub_Int, OpCodeAsmJs::Sub_Int, OpCodeAsmJs::Sub_Flt, OpCodeAsmJs::Sub_Db },
  39. /*BMO_MUL*/{ OpCodeAsmJs::Mul_Int, OpCodeAsmJs::Mul_Int, OpCodeAsmJs::Mul_Flt, OpCodeAsmJs::Mul_Db },
  40. /*BMO_DIV*/{ OpCodeAsmJs::Div_Int, OpCodeAsmJs::Div_UInt,OpCodeAsmJs::Div_Flt, OpCodeAsmJs::Div_Db },
  41. /*BMO_REM*/{ OpCodeAsmJs::Rem_Int, OpCodeAsmJs::Rem_UInt,OpCodeAsmJs::Nop, OpCodeAsmJs::Rem_Db }
  42. };
  43. enum EBinaryComparatorOpCodes: int
  44. {
  45. /*<, <=, >, >=, ==, !=*/
  46. BCO_LT,
  47. BCO_LE,
  48. BCO_GT,
  49. BCO_GE,
  50. BCO_EQ,
  51. BCO_NE,
  52. BCO_MAX,
  53. };
  54. enum EBinaryComparatorOpCodesTypes
  55. {
  56. BCOT_Int,
  57. BCOT_UInt,
  58. BCOT_Float,
  59. BCOT_Double,
  60. BCOT_MAX
  61. };
  62. const OpCodeAsmJs BinaryComparatorOpCodes[BCO_MAX][BCOT_MAX] = {
  63. // int unsigned int double
  64. /*BCO_LT*/{ OpCodeAsmJs::CmLt_Int, OpCodeAsmJs::CmLt_UnInt, OpCodeAsmJs::CmLt_Flt, OpCodeAsmJs::CmLt_Db },
  65. /*BCO_LE*/{ OpCodeAsmJs::CmLe_Int, OpCodeAsmJs::CmLe_UnInt, OpCodeAsmJs::CmLe_Flt, OpCodeAsmJs::CmLe_Db },
  66. /*BCO_GT*/{ OpCodeAsmJs::CmGt_Int, OpCodeAsmJs::CmGt_UnInt, OpCodeAsmJs::CmGt_Flt, OpCodeAsmJs::CmGt_Db },
  67. /*BCO_GE*/{ OpCodeAsmJs::CmGe_Int, OpCodeAsmJs::CmGe_UnInt, OpCodeAsmJs::CmGe_Flt, OpCodeAsmJs::CmGe_Db },
  68. /*BCO_EQ*/{ OpCodeAsmJs::CmEq_Int, OpCodeAsmJs::CmEq_Int, OpCodeAsmJs::CmEq_Flt, OpCodeAsmJs::CmEq_Db },
  69. /*BCO_NE*/{ OpCodeAsmJs::CmNe_Int, OpCodeAsmJs::CmNe_Int, OpCodeAsmJs::CmNe_Flt, OpCodeAsmJs::CmNe_Db },
  70. };
  71. #define CheckNodeLocation(info,type) if(!mFunction->IsValidLocation<type>(&info)){\
  72. throw AsmJsCompilationException( _u("Invalid Node location[%d] "), info.location ); }
  73. AsmJSByteCodeGenerator::AsmJSByteCodeGenerator( AsmJsFunc* func, AsmJsModuleCompiler* compiler ) :
  74. mFunction( func )
  75. , mAllocator(_u("AsmjsByteCode"), compiler->GetScriptContext()->GetThreadContext()->GetPageAllocator(), Throw::OutOfMemory)
  76. , mInfo( mFunction->GetFuncInfo() )
  77. , mCompiler( compiler )
  78. , mByteCodeGenerator(mCompiler->GetByteCodeGenerator())
  79. , mNestedCallCount(0)
  80. , mIsCallLegal(true)
  81. {
  82. mWriter.Create();
  83. const int32 astSize = func->GetFncNode()->sxFnc.astSize/AstBytecodeRatioEstimate;
  84. // Use the temp allocator in bytecode write temp buffer.
  85. mWriter.InitData(&mAllocator, astSize);
  86. #ifdef LOG_BYTECODE_AST_RATIO
  87. // log the max Ast size
  88. Output::Print(_u("Max Ast size: %d"), astSize);
  89. #endif
  90. }
  91. bool AsmJSByteCodeGenerator::BlockHasOwnScope( ParseNode* pnodeBlock )
  92. {
  93. Assert( pnodeBlock->nop == knopBlock );
  94. return pnodeBlock->sxBlock.scope != nullptr && ( !( pnodeBlock->grfpn & fpnSyntheticNode ) );
  95. }
  96. // copy all constants from reg spaces to function body.
  97. void AsmJSByteCodeGenerator::LoadAllConstants()
  98. {
  99. FunctionBody *funcBody = mFunction->GetFuncBody();
  100. funcBody->CreateConstantTable();
  101. Var* table = funcBody->GetConstTable();
  102. table += AsmJsFunctionMemory::RequiredVarConstants - 1; // we do -1 here as the VarConstant count is zero-based calculation
  103. int* intTable = (int*)table;
  104. // int Return Register
  105. *intTable = 0;
  106. intTable++;
  107. JsUtil::BaseDictionary<int, RegSlot, ArenaAllocator, PowerOf2SizePolicy, AsmJsComparer> intMap = mFunction->GetRegisterSpace<int>().GetConstMap();
  108. for (auto it = intMap.GetIterator(); it.IsValid(); it.MoveNext())
  109. {
  110. JsUtil::BaseDictionary<int, RegSlot, ArenaAllocator, PowerOf2SizePolicy, AsmJsComparer>::EntryType &entry = it.Current();
  111. *intTable = entry.Key();
  112. intTable++;
  113. }
  114. float* floatTable = (float*)intTable;
  115. // float Return Register
  116. *floatTable = 0;
  117. floatTable++;
  118. JsUtil::BaseDictionary<float, RegSlot, ArenaAllocator, PowerOf2SizePolicy, AsmJsComparer> floatMap = mFunction->GetRegisterSpace<float>().GetConstMap();
  119. for (auto it = floatMap.GetIterator(); it.IsValid(); it.MoveNext())
  120. {
  121. JsUtil::BaseDictionary<float, RegSlot, ArenaAllocator, PowerOf2SizePolicy, AsmJsComparer>::EntryType &entry = it.Current();
  122. *floatTable = entry.Key();
  123. floatTable++;
  124. }
  125. double* doubleTable = (double*)floatTable;
  126. // double Return Register
  127. *doubleTable = 0;
  128. doubleTable++;
  129. JsUtil::BaseDictionary<double, RegSlot, ArenaAllocator, PowerOf2SizePolicy, AsmJsComparer> doubleMap = mFunction->GetRegisterSpace<double>().GetConstMap();
  130. for (auto it = doubleMap.GetIterator(); it.IsValid(); it.MoveNext())
  131. {
  132. JsUtil::BaseDictionary<double, RegSlot, ArenaAllocator, PowerOf2SizePolicy, AsmJsComparer>::EntryType &entry = it.Current();
  133. *doubleTable = entry.Key();
  134. doubleTable++;
  135. }
  136. // SIMD_JS
  137. if (IsSimdjsEnabled())
  138. {
  139. AsmJsSIMDValue* simdTable = (AsmJsSIMDValue*)doubleTable;
  140. // SIMD return register
  141. simdTable->f64[0] = 0; simdTable->f64[1] = 0;
  142. JsUtil::BaseDictionary<AsmJsSIMDValue, RegSlot, ArenaAllocator, PowerOf2SizePolicy, AsmJsComparer> simdMap = mFunction->GetRegisterSpace<AsmJsSIMDValue>().GetConstMap();
  143. for (auto it = simdMap.GetIterator(); it.IsValid(); it.MoveNext())
  144. {
  145. JsUtil::BaseDictionary<AsmJsSIMDValue, RegSlot, ArenaAllocator, PowerOf2SizePolicy, AsmJsComparer>::EntryType &entry = it.Current();
  146. RegSlot regSlot = entry.Value();
  147. Assert((Var*)simdTable + regSlot < funcBody->GetConstTable() + funcBody->GetConstantCount());
  148. // we cannot do sequential copy since registers are assigned to constants in the order they appear in the code, not per dictionary order.
  149. simdTable[entry.Value()] = entry.Key();
  150. }
  151. }
  152. }
  153. void AsmJSByteCodeGenerator::FinalizeRegisters( FunctionBody* byteCodeFunction )
  154. {
  155. // this value is the number of Var slots needed to allocate all the const
  156. int nbConst =
  157. ((mFunction->GetRegisterSpace<double>().GetConstCount() + 1) * DOUBLE_SLOTS_SPACE) // space required for all double constants + 1 return register reserved
  158. + (int)((mFunction->GetRegisterSpace<float>().GetConstCount() + 1)* FLOAT_SLOTS_SPACE + 0.5 /*ceil*/) // space required for all float constants + 1 return register reserved
  159. + (int)((mFunction->GetRegisterSpace<int>().GetConstCount() + 1) * INT_SLOTS_SPACE + 0.5/*ceil*/) // space required for all int constants + 1 return register reserved
  160. + AsmJsFunctionMemory::RequiredVarConstants;
  161. if (IsSimdjsEnabled())
  162. {
  163. nbConst += (int)((mFunction->GetRegisterSpace<AsmJsSIMDValue>().GetConstCount() + 1) * SIMD_SLOTS_SPACE); // Return register is already reserved in the register space.
  164. }
  165. byteCodeFunction->CheckAndSetConstantCount(nbConst);
  166. // add 3 for each of I0, F0, and D0
  167. RegSlot regCount = mInfo->RegCount() + 3 + AsmJsFunctionMemory::RequiredVarConstants;
  168. if (IsSimdjsEnabled())
  169. {
  170. // 1 return reg for SIMD
  171. regCount++;
  172. }
  173. byteCodeFunction->SetFirstTmpReg(regCount);
  174. }
  175. bool AsmJSByteCodeGenerator::EmitOneFunction()
  176. {
  177. Assert(mFunction->GetFncNode());
  178. Assert(mFunction->GetBodyNode());
  179. AsmJsFunctionCompilation autoCleanup( this );
  180. try
  181. {
  182. ParseNode* pnode = mFunction->GetFncNode();
  183. Assert( pnode && pnode->nop == knopFncDecl );
  184. Assert( mInfo != nullptr );
  185. ByteCodeGenerator* byteCodeGen = GetOldByteCodeGenerator();
  186. MaybeTodo( mInfo->IsFakeGlobalFunction( byteCodeGen->GetFlags() ) );
  187. // Support default arguments ?
  188. MaybeTodo( pnode->sxFnc.HasDefaultArguments() );
  189. FunctionBody* functionBody = mFunction->GetFuncBody();
  190. functionBody->SetStackNestedFunc( false );
  191. FinalizeRegisters(functionBody);
  192. ArenaAllocator* alloc = byteCodeGen->GetAllocator();
  193. mInfo->inlineCacheMap = Anew( alloc, FuncInfo::InlineCacheMap,
  194. alloc,
  195. mInfo->RegCount() // Pass the actual register count. TODO: Check if we can reduce this count
  196. );
  197. mInfo->rootObjectLoadInlineCacheMap = Anew( alloc, FuncInfo::RootObjectInlineCacheIdMap,
  198. alloc,
  199. 10 );
  200. mInfo->rootObjectStoreInlineCacheMap = Anew( alloc, FuncInfo::RootObjectInlineCacheIdMap,
  201. alloc,
  202. 10 );
  203. mInfo->referencedPropertyIdToMapIndex = Anew( alloc, FuncInfo::RootObjectInlineCacheIdMap,
  204. alloc,
  205. 10 );
  206. functionBody->AllocateLiteralRegexArray();
  207. mWriter.Begin(byteCodeGen, functionBody, alloc, true /* byteCodeGen->DoJitLoopBodies( funcInfo )*/, mInfo->hasLoop);
  208. // for now, emit all constant loads at top of function (should instead put in
  209. // closest dominator of uses)
  210. LoadAllConstants();
  211. DefineLabels( );
  212. EmitAsmJsFunctionBody();
  213. // Set that the function is asmjsFunction in functionBody here so that Initialize ExecutionMode call later will check for that and not profile in asmjsMode
  214. functionBody->SetIsAsmJsFunction(true);
  215. functionBody->SetIsAsmjsMode(true);
  216. // Do a uint32 add just to verify that we haven't overflowed the reg slot type.
  217. UInt32Math::Add( mFunction->GetRegisterSpace<int>().GetTotalVarCount(), mFunction->GetRegisterSpace<int>().GetConstCount());
  218. UInt32Math::Add( mFunction->GetRegisterSpace<double>().GetTotalVarCount(), mFunction->GetRegisterSpace<double>().GetConstCount());
  219. UInt32Math::Add( mFunction->GetRegisterSpace<float>().GetTotalVarCount(), mFunction->GetRegisterSpace<float>().GetConstCount());
  220. byteCodeGen->MapCacheIdsToPropertyIds( mInfo );
  221. byteCodeGen->MapReferencedPropertyIds( mInfo );
  222. mWriter.End();
  223. autoCleanup.FinishCompilation();
  224. functionBody->SetInitialDefaultEntryPoint();
  225. #if DBG_DUMP
  226. if( PHASE_DUMP( ByteCodePhase, mInfo->byteCodeFunction ) && Configuration::Global.flags.Verbose )
  227. {
  228. pnode->Dump();
  229. }
  230. if( byteCodeGen->Trace() || PHASE_DUMP( ByteCodePhase, mInfo->byteCodeFunction ) )
  231. {
  232. AsmJsByteCodeDumper::Dump( mFunction, functionBody );
  233. }
  234. #endif
  235. }
  236. catch( AsmJsCompilationException& e )
  237. {
  238. PrintAsmJsCompilationError( e.msg() );
  239. return false;
  240. }
  241. return true;
  242. }
  243. void AsmJSByteCodeGenerator::PrintAsmJsCompilationError(__out_ecount(256) char16* msg)
  244. {
  245. uint offset = mWriter.GetCurrentOffset();
  246. ULONG line = 0;
  247. LONG col = 0;
  248. if (!mFunction->GetFuncBody()->GetLineCharOffset(offset, &line, &col))
  249. {
  250. line = 0;
  251. col = 0;
  252. }
  253. char16 filename[_MAX_FNAME];
  254. char16 ext[_MAX_EXT];
  255. _wsplitpath_s( Configuration::Global.flags.Filename, NULL, 0, NULL, 0, filename, _MAX_FNAME, ext, _MAX_EXT );
  256. LPCOLESTR NoneName = _u("None");
  257. LPCOLESTR moduleName = NoneName;
  258. if(mCompiler->GetModuleFunctionName())
  259. {
  260. moduleName = mCompiler->GetModuleFunctionName()->Psz();
  261. }
  262. AsmJSCompiler::OutputError(mCompiler->GetScriptContext(),
  263. _u("\n%s%s(%d, %d)\n\tAsm.js Compilation Error function : %s::%s\n\t%s\n"),
  264. filename, ext, line + 1, col + 1, moduleName, mFunction->GetName()->Psz(), msg);
  265. }
  266. void AsmJSByteCodeGenerator::DefineLabels()
  267. {
  268. mInfo->singleExit=mWriter.DefineLabel();
  269. SList<ParseNode *>::Iterator iter(&mInfo->targetStatements);
  270. while (iter.Next())
  271. {
  272. ParseNode * node = iter.Data();
  273. node->sxStmt.breakLabel=mWriter.DefineLabel();
  274. node->sxStmt.continueLabel=mWriter.DefineLabel();
  275. node->emitLabels=true;
  276. }
  277. }
  278. void AsmJSByteCodeGenerator::EmitAsmJsFunctionBody()
  279. {
  280. ParseNode *pnodeBody = mFunction->GetBodyNode();
  281. ParseNode *varStmts = pnodeBody;
  282. // Emit local var declarations: Load of constants to variables.
  283. while (varStmts->nop == knopList)
  284. {
  285. ParseNode * pnode = ParserWrapper::GetBinaryLeft(varStmts);
  286. while (pnode && pnode->nop != knopEndCode)
  287. {
  288. ParseNode * decl;
  289. if (pnode->nop == knopList)
  290. {
  291. decl = ParserWrapper::GetBinaryLeft(pnode);
  292. pnode = ParserWrapper::GetBinaryRight(pnode);
  293. }
  294. else
  295. {
  296. decl = pnode;
  297. pnode = nullptr;
  298. }
  299. if (decl->nop != knopVarDecl)
  300. {
  301. goto varDeclEnd;
  302. }
  303. Assert(decl->nop == knopVarDecl);
  304. // since we are parsing the same way we created variables the same time, it is safe to assume these are AsmJsVar*
  305. AsmJsVar* var = (AsmJsVar*)mFunction->FindVar(ParserWrapper::VariableName(decl));
  306. AnalysisAssert(var);
  307. if (var->GetType().isInt())
  308. {
  309. mWriter.AsmInt1Const1(Js::OpCodeAsmJs::Ld_IntConst, var->GetLocation(), var->GetIntInitialiser());
  310. }
  311. else
  312. {
  313. AsmJsVar * initSource = nullptr;
  314. if (decl->sxVar.pnodeInit->nop == knopName)
  315. {
  316. AsmJsSymbol * initSym = mCompiler->LookupIdentifier(decl->sxVar.pnodeInit->name(), mFunction);
  317. if (initSym->GetSymbolType() == AsmJsSymbol::Variable)
  318. {
  319. // in this case we are initializing with value of a constant var
  320. initSource = initSym->Cast<AsmJsVar>();
  321. }
  322. else
  323. {
  324. Assert(initSym->GetSymbolType() == AsmJsSymbol::MathConstant);
  325. Assert(initSym->GetType() == AsmJsType::Double);
  326. AsmJsMathConst* initConst = initSym->Cast<AsmJsMathConst>();
  327. mWriter.AsmReg2(Js::OpCodeAsmJs::Ld_Db, var->GetLocation(), mFunction->GetConstRegister<double>(*initConst->GetVal()));
  328. }
  329. }
  330. else
  331. {
  332. initSource = var;
  333. }
  334. if (initSource)
  335. {
  336. if (var->GetType().isDouble())
  337. {
  338. mWriter.AsmReg2(Js::OpCodeAsmJs::Ld_Db, var->GetLocation(), mFunction->GetConstRegister<double>(initSource->GetDoubleInitialiser()));
  339. }
  340. else if (var->GetType().isFloat())
  341. {
  342. mWriter.AsmReg2(Js::OpCodeAsmJs::Ld_Flt, var->GetLocation(), mFunction->GetConstRegister<float>(initSource->GetFloatInitialiser()));
  343. }
  344. else
  345. {
  346. // SIMD_JS
  347. Assert(var->GetType().isSIMDType());
  348. Js::OpCodeAsmJs opcode = Js::OpCodeAsmJs::Simd128_Ld_F4;
  349. switch (var->GetType().GetWhich())
  350. {
  351. case AsmJsType::Float32x4:
  352. break;
  353. #if 0
  354. case AsmJsType::Float64x2:
  355. opcode = Js::OpCodeAsmJs::Simd128_Ld_D2;
  356. break;
  357. #endif // 0
  358. case AsmJsType::Int32x4:
  359. opcode = Js::OpCodeAsmJs::Simd128_Ld_I4;
  360. break;
  361. case AsmJsType::Int16x8:
  362. opcode = Js::OpCodeAsmJs::Simd128_Ld_I8;
  363. break;
  364. case AsmJsType::Int8x16:
  365. opcode = Js::OpCodeAsmJs::Simd128_Ld_I16;
  366. break;
  367. case AsmJsType::Uint32x4:
  368. opcode = Js::OpCodeAsmJs::Simd128_Ld_U4;
  369. break;
  370. case AsmJsType::Uint16x8:
  371. opcode = Js::OpCodeAsmJs::Simd128_Ld_U8;
  372. break;
  373. case AsmJsType::Uint8x16:
  374. opcode = Js::OpCodeAsmJs::Simd128_Ld_U16;
  375. break;
  376. case AsmJsType::Bool32x4:
  377. opcode = Js::OpCodeAsmJs::Simd128_Ld_B4;
  378. break;
  379. case AsmJsType::Bool16x8:
  380. opcode = Js::OpCodeAsmJs::Simd128_Ld_B8;
  381. break;
  382. case AsmJsType::Bool8x16:
  383. opcode = Js::OpCodeAsmJs::Simd128_Ld_B16;
  384. break;
  385. default:
  386. Assert(UNREACHED);
  387. }
  388. mWriter.AsmReg2(opcode, var->GetLocation(), mFunction->GetConstRegister<AsmJsSIMDValue>(var->GetSimdConstInitialiser()));
  389. }
  390. }
  391. }
  392. }
  393. varStmts = ParserWrapper::GetBinaryRight(varStmts);
  394. }
  395. varDeclEnd:
  396. // Emit a function body. Only explicit returns and the implicit "undef" at the bottom
  397. // get copied to the return register.
  398. while (varStmts->nop == knopList)
  399. {
  400. ParseNode *stmt = ParserWrapper::GetBinaryLeft(varStmts);
  401. EmitTopLevelStatement( stmt );
  402. varStmts = ParserWrapper::GetBinaryRight(varStmts);
  403. }
  404. Assert(!varStmts->CapturesSyms());
  405. // if last statement isn't return, type must be void
  406. if (varStmts->nop != knopReturn)
  407. {
  408. mFunction->CheckAndSetReturnType(AsmJsRetType::Void);
  409. }
  410. EmitTopLevelStatement(varStmts);
  411. }
  412. void AsmJSByteCodeGenerator::EmitTopLevelStatement( ParseNode *stmt )
  413. {
  414. if( stmt->nop == knopFncDecl && stmt->sxFnc.IsDeclaration() )
  415. {
  416. throw AsmJsCompilationException( _u("Cannot declare functions inside asm.js functions") );
  417. }
  418. const EmitExpressionInfo& info = Emit( stmt );
  419. // free tmp register here
  420. mFunction->ReleaseLocationGeneric( &info );
  421. }
  422. EmitExpressionInfo AsmJSByteCodeGenerator::Emit( ParseNode *pnode )
  423. {
  424. if( !pnode )
  425. {
  426. return EmitExpressionInfo( AsmJsType::Void );
  427. }
  428. switch( pnode->nop )
  429. {
  430. case knopReturn:
  431. return EmitReturn( pnode );
  432. case knopList:{
  433. while( pnode && pnode->nop == knopList )
  434. {
  435. const EmitExpressionInfo& info = Emit( ParserWrapper::GetBinaryLeft( pnode ) );
  436. mFunction->ReleaseLocationGeneric( &info );
  437. pnode = ParserWrapper::GetBinaryRight( pnode );
  438. }
  439. return Emit( pnode );
  440. }
  441. case knopComma:{
  442. const EmitExpressionInfo& info = Emit( ParserWrapper::GetBinaryLeft( pnode ) );
  443. mFunction->ReleaseLocationGeneric( &info );
  444. return Emit( ParserWrapper::GetBinaryRight( pnode ) );
  445. }
  446. case knopBlock:
  447. {
  448. EmitExpressionInfo info = Emit(pnode->sxBlock.pnodeStmt);
  449. if (pnode->emitLabels)
  450. {
  451. mWriter.MarkAsmJsLabel(pnode->sxStmt.breakLabel);
  452. }
  453. return info;
  454. }
  455. case knopCall:
  456. return EmitCall( pnode );
  457. case knopPos:
  458. return EmitUnaryPos( pnode );
  459. case knopNeg:
  460. return EmitUnaryNeg( pnode );
  461. case knopNot:
  462. return EmitUnaryNot( pnode );
  463. case knopLogNot:
  464. return EmitUnaryLogNot( pnode );
  465. case knopEq:
  466. return EmitBinaryComparator( pnode, BCO_EQ );
  467. case knopNe:
  468. return EmitBinaryComparator( pnode, BCO_NE );
  469. case knopLt:
  470. return EmitBinaryComparator( pnode, BCO_LT );
  471. case knopLe:
  472. return EmitBinaryComparator( pnode, BCO_LE );
  473. case knopGe:
  474. return EmitBinaryComparator( pnode, BCO_GE );
  475. case knopGt:
  476. return EmitBinaryComparator( pnode, BCO_GT );
  477. case knopOr:
  478. return EmitBinaryInt( pnode, OpCodeAsmJs::Or_Int );
  479. case knopXor:
  480. return EmitBinaryInt( pnode, OpCodeAsmJs::Xor_Int );
  481. case knopAnd:
  482. return EmitBinaryInt( pnode, OpCodeAsmJs::And_Int );
  483. case knopLsh:
  484. return EmitBinaryInt( pnode, OpCodeAsmJs::Shl_Int );
  485. case knopRsh:
  486. return EmitBinaryInt( pnode, OpCodeAsmJs::Shr_Int );
  487. case knopRs2:
  488. return EmitBinaryInt( pnode, OpCodeAsmJs::ShrU_Int );
  489. case knopMod:
  490. return EmitBinaryMultiType( pnode, BMO_REM );
  491. case knopDiv:
  492. return EmitBinaryMultiType( pnode, BMO_DIV );
  493. case knopMul:
  494. return EmitBinaryMultiType( pnode, BMO_MUL );
  495. case knopSub:
  496. return EmitBinaryMultiType( pnode, BMO_SUB );
  497. case knopAdd:
  498. return EmitBinaryMultiType( pnode, BMO_ADD );
  499. case knopName:
  500. case knopStr:
  501. return EmitIdentifier( pnode );
  502. case knopIndex:
  503. return EmitLdArrayBuffer( pnode );
  504. case knopEndCode:
  505. StartStatement(pnode);
  506. if( mFunction->GetReturnType() == AsmJsRetType::Void )
  507. {
  508. mWriter.AsmReg1( Js::OpCodeAsmJs::LdUndef, AsmJsFunctionMemory::ReturnRegister );
  509. }
  510. mWriter.MarkAsmJsLabel( mFunction->GetFuncInfo()->singleExit );
  511. mWriter.EmptyAsm( OpCodeAsmJs::Ret );
  512. EndStatement(pnode);
  513. break;
  514. case knopAsg:
  515. return EmitAssignment( pnode );
  516. case knopFlt:
  517. if (ParserWrapper::IsMinInt(pnode))
  518. {
  519. return EmitExpressionInfo(mFunction->GetConstRegister<int>(INT32_MIN), AsmJsType::Signed);
  520. }
  521. else if (ParserWrapper::IsUnsigned(pnode))
  522. {
  523. return EmitExpressionInfo(mFunction->GetConstRegister<int>((uint32)pnode->sxFlt.dbl), AsmJsType::Unsigned);
  524. }
  525. else if (pnode->sxFlt.maybeInt)
  526. {
  527. throw AsmJsCompilationException(_u("Int literal must be in the range [-2^31, 2^32)"));
  528. }
  529. else
  530. {
  531. return EmitExpressionInfo(mFunction->GetConstRegister<double>(pnode->sxFlt.dbl), AsmJsType::DoubleLit);
  532. }
  533. case knopInt:
  534. if (pnode->sxInt.lw < 0)
  535. {
  536. return EmitExpressionInfo(mFunction->GetConstRegister<int>(pnode->sxInt.lw), AsmJsType::Signed);
  537. }
  538. else
  539. {
  540. return EmitExpressionInfo(mFunction->GetConstRegister<int>(pnode->sxInt.lw), AsmJsType::Fixnum);
  541. }
  542. case knopIf:
  543. return EmitIf( pnode );
  544. case knopQmark:
  545. return EmitQMark( pnode );
  546. case knopSwitch:
  547. return EmitSwitch( pnode );
  548. case knopFor:
  549. MaybeTodo( pnode->sxFor.pnodeInverted != NULL );
  550. {
  551. const EmitExpressionInfo& initInfo = Emit( pnode->sxFor.pnodeInit );
  552. mFunction->ReleaseLocationGeneric( &initInfo );
  553. return EmitLoop( pnode,
  554. pnode->sxFor.pnodeCond,
  555. pnode->sxFor.pnodeBody,
  556. pnode->sxFor.pnodeIncr);
  557. }
  558. break;
  559. case knopWhile:
  560. return EmitLoop( pnode,
  561. pnode->sxWhile.pnodeCond,
  562. pnode->sxWhile.pnodeBody,
  563. nullptr);
  564. case knopDoWhile:
  565. return EmitLoop( pnode,
  566. pnode->sxWhile.pnodeCond,
  567. pnode->sxWhile.pnodeBody,
  568. NULL,
  569. true );
  570. case knopBreak:
  571. Assert( pnode->sxJump.pnodeTarget->emitLabels );
  572. StartStatement(pnode);
  573. mWriter.AsmBr( pnode->sxJump.pnodeTarget->sxStmt.breakLabel );
  574. if( pnode->emitLabels )
  575. {
  576. mWriter.MarkAsmJsLabel( pnode->sxStmt.breakLabel );
  577. }
  578. EndStatement(pnode);
  579. break;
  580. case knopContinue:
  581. Assert( pnode->sxJump.pnodeTarget->emitLabels );
  582. StartStatement(pnode);
  583. mWriter.AsmBr( pnode->sxJump.pnodeTarget->sxStmt.continueLabel );
  584. EndStatement(pnode);
  585. break;
  586. case knopLabel:
  587. break;
  588. case knopVarDecl:
  589. throw AsmJsCompilationException( _u("Variable declaration must happen at the top of the function") );
  590. break;
  591. default:
  592. throw AsmJsCompilationException( _u("Unhandled parse opcode for asm.js") );
  593. break;
  594. }
  595. return EmitExpressionInfo(AsmJsType::Void);
  596. }
  597. EmitExpressionInfo AsmJSByteCodeGenerator::EmitBinaryMultiType( ParseNode * pnode, EBinaryMathOpCodes op )
  598. {
  599. ParseNode* lhs = ParserWrapper::GetBinaryLeft(pnode);
  600. ParseNode* rhs = ParserWrapper::GetBinaryRight(pnode);
  601. EmitExpressionInfo lhsEmit = Emit( lhs );
  602. EmitExpressionInfo rhsEmit = Emit( rhs );
  603. AsmJsType& lType = lhsEmit.type;
  604. AsmJsType& rType = rhsEmit.type;
  605. // don't need coercion inside an a+b+c type expression
  606. if (op == BMO_ADD || op == BMO_SUB)
  607. {
  608. if (lType.GetWhich() == AsmJsType::Intish && (lhs->nop == knopAdd || lhs->nop == knopSub))
  609. {
  610. lType = AsmJsType::Int;
  611. }
  612. if (rType.GetWhich() == AsmJsType::Intish && (rhs->nop == knopAdd || rhs->nop == knopSub))
  613. {
  614. rType = AsmJsType::Int;
  615. }
  616. }
  617. EmitExpressionInfo emitInfo( AsmJsType::Double );
  618. StartStatement(pnode);
  619. if( lType.isInt() && rType.isInt() )
  620. {
  621. CheckNodeLocation( lhsEmit, int );
  622. CheckNodeLocation( rhsEmit, int );
  623. // because fixnum can be either signed or unsigned, use both lhs and rhs to infer sign
  624. auto opType = (lType.isSigned() && rType.isSigned()) ? BMOT_Int : BMOT_UInt;
  625. if (op == BMO_REM || op == BMO_DIV)
  626. {
  627. // div and rem must have explicit sign
  628. if (!(lType.isSigned() && rType.isSigned()) && !(lType.isUnsigned() && rType.isUnsigned()))
  629. {
  630. throw AsmJsCompilationException(_u("arguments to / or %% must both be double?, float?, signed, or unsigned; %s and %s given"), lType.toChars(), rType.toChars());
  631. }
  632. }
  633. // try to reuse tmp register
  634. RegSlot intReg = GetAndReleaseBinaryLocations<int>( &lhsEmit, &rhsEmit );
  635. mWriter.AsmReg3(BinaryMathOpCodes[op][opType], intReg, lhsEmit.location, rhsEmit.location );
  636. emitInfo.location = intReg;
  637. emitInfo.type = AsmJsType::Intish;
  638. }
  639. else if (lType.isMaybeDouble() && rType.isMaybeDouble())
  640. {
  641. CheckNodeLocation( lhsEmit, double );
  642. CheckNodeLocation( rhsEmit, double );
  643. RegSlot dbReg = GetAndReleaseBinaryLocations<double>( &lhsEmit, &rhsEmit );
  644. mWriter.AsmReg3( BinaryMathOpCodes[op][BMOT_Double], dbReg, lhsEmit.location, rhsEmit.location );
  645. emitInfo.location = dbReg;
  646. }
  647. else if (lType.isMaybeFloat() && rType.isMaybeFloat())
  648. {
  649. if (BinaryMathOpCodes[op][BMOT_Float] == OpCodeAsmJs::Nop)
  650. {
  651. throw AsmJsCompilationException(_u("invalid Binary float operation"));
  652. }
  653. CheckNodeLocation(lhsEmit, float);
  654. CheckNodeLocation(rhsEmit, float);
  655. RegSlot floatReg = GetAndReleaseBinaryLocations<float>(&lhsEmit, &rhsEmit);
  656. mWriter.AsmReg3(BinaryMathOpCodes[op][BMOT_Float], floatReg, lhsEmit.location, rhsEmit.location);
  657. emitInfo.location = floatReg;
  658. emitInfo.type = AsmJsType::Floatish;
  659. }
  660. else
  661. {
  662. throw AsmJsCompilationException( _u("Unsupported math operation") );
  663. }
  664. EndStatement(pnode);
  665. return emitInfo;
  666. }
  667. EmitExpressionInfo AsmJSByteCodeGenerator::EmitBinaryInt( ParseNode * pnode, OpCodeAsmJs op )
  668. {
  669. ParseNode* lhs = ParserWrapper::GetBinaryLeft( pnode );
  670. ParseNode* rhs = ParserWrapper::GetBinaryRight( pnode );
  671. const bool isRhs0 = rhs->nop == knopInt && rhs->sxInt.lw == 0;
  672. const bool isOr0Operation = op == OpCodeAsmJs::Or_Int && isRhs0;
  673. if( isOr0Operation && lhs->nop == knopCall )
  674. {
  675. EmitExpressionInfo info = EmitCall(lhs, AsmJsRetType::Signed);
  676. if (!info.type.isIntish())
  677. {
  678. throw AsmJsCompilationException(_u("Invalid type for [| & ^ >> << >>>] left and right operand must be of type intish"));
  679. }
  680. info.type = AsmJsType::Signed;
  681. return info;
  682. }
  683. const EmitExpressionInfo& lhsEmit = Emit( lhs );
  684. const EmitExpressionInfo& rhsEmit = Emit( rhs );
  685. const AsmJsType& lType = lhsEmit.type;
  686. const AsmJsType& rType = rhsEmit.type;
  687. if( !lType.isIntish() || !rType.isIntish() )
  688. {
  689. throw AsmJsCompilationException( _u("Invalid type for [| & ^ >> << >>>] left and right operand must be of type intish") );
  690. }
  691. CheckNodeLocation( lhsEmit, int );
  692. CheckNodeLocation( rhsEmit, int );
  693. StartStatement(pnode);
  694. EmitExpressionInfo emitInfo( AsmJsType::Signed );
  695. if( op == OpCodeAsmJs::ShrU_Int )
  696. {
  697. emitInfo.type = AsmJsType::Unsigned;
  698. }
  699. // ignore this specific operation, useful for non asm.js
  700. if( !isRhs0 || op == OpCodeAsmJs::And_Int )
  701. {
  702. RegSlot dstReg = GetAndReleaseBinaryLocations<int>( &lhsEmit, &rhsEmit );
  703. mWriter.AsmReg3( op, dstReg, lhsEmit.location, rhsEmit.location );
  704. emitInfo.location = dstReg;
  705. }
  706. else
  707. {
  708. mFunction->ReleaseLocation<int>( &rhsEmit );
  709. emitInfo.location = lhsEmit.location;
  710. }
  711. EndStatement(pnode);
  712. return emitInfo;
  713. }
  714. EmitExpressionInfo AsmJSByteCodeGenerator::EmitReturn( ParseNode * pnode )
  715. {
  716. ParseNode* expr = pnode->sxReturn.pnodeExpr;
  717. // return is always the beginning of a statement
  718. AsmJsRetType retType;
  719. EmitExpressionInfo emitInfo( Constants::NoRegister, AsmJsType::Void );
  720. if( !expr )
  721. {
  722. if( !mFunction->CheckAndSetReturnType( AsmJsRetType::Void ) )
  723. {
  724. throw AsmJsCompilationException( _u("Different return type for the function") );
  725. }
  726. retType = AsmJsRetType::Void;
  727. // Make sure we return something
  728. mWriter.AsmReg1(Js::OpCodeAsmJs::LdUndef, AsmJsFunctionMemory::ReturnRegister);
  729. }
  730. else
  731. {
  732. EmitExpressionInfo info = Emit(expr);
  733. StartStatement(pnode);
  734. if (info.type.isSubType(AsmJsType::Double))
  735. {
  736. CheckNodeLocation(info, double);
  737. // get return value from tmp register
  738. mWriter.Conv(OpCodeAsmJs::Return_Db, 0, info.location);
  739. mFunction->ReleaseLocation<double>(&info);
  740. emitInfo.type = AsmJsType::Double;
  741. retType = AsmJsRetType::Double;
  742. }
  743. else if (info.type.isSubType(AsmJsType::Signed))
  744. {
  745. CheckNodeLocation(info, int);
  746. // get return value from tmp register
  747. mWriter.Conv(OpCodeAsmJs::Return_Int, 0, info.location);
  748. mFunction->ReleaseLocation<int>(&info);
  749. emitInfo.type = AsmJsType::Signed;
  750. retType = AsmJsRetType::Signed;
  751. }
  752. else if (info.type.isSubType(AsmJsType::Float))
  753. {
  754. CheckNodeLocation(info, float);
  755. // get return value from tmp register
  756. mWriter.Conv(OpCodeAsmJs::Return_Flt, 0, info.location);
  757. mFunction->ReleaseLocation<float>(&info);
  758. emitInfo.type = AsmJsType::Float;
  759. retType = AsmJsRetType::Float;
  760. }
  761. else if (info.type.isSubType(AsmJsType::Float32x4))
  762. {
  763. CheckNodeLocation(info, AsmJsSIMDValue);
  764. mWriter.Conv(OpCodeAsmJs::Simd128_Return_F4, 0, info.location);
  765. mFunction->ReleaseLocation<AsmJsSIMDValue>(&info);
  766. emitInfo.type = AsmJsType::Float32x4;
  767. retType = AsmJsRetType::Float32x4;
  768. }
  769. else if (info.type.isSubType(AsmJsType::Int32x4))
  770. {
  771. CheckNodeLocation(info, AsmJsSIMDValue);
  772. mWriter.Conv(OpCodeAsmJs::Simd128_Return_I4, 0, info.location);
  773. mFunction->ReleaseLocation<AsmJsSIMDValue>(&info);
  774. emitInfo.type = AsmJsType::Int32x4;
  775. retType = AsmJsRetType::Int32x4;
  776. }
  777. else if (info.type.isSubType(AsmJsType::Bool32x4))
  778. {
  779. CheckNodeLocation(info, AsmJsSIMDValue);
  780. mWriter.Conv(OpCodeAsmJs::Simd128_Return_B4, 0, info.location);
  781. mFunction->ReleaseLocation<AsmJsSIMDValue>(&info);
  782. emitInfo.type = AsmJsType::Bool32x4;
  783. retType = AsmJsRetType::Bool32x4;
  784. }
  785. else if (info.type.isSubType(AsmJsType::Bool16x8))
  786. {
  787. CheckNodeLocation(info, AsmJsSIMDValue);
  788. mWriter.Conv(OpCodeAsmJs::Simd128_Return_B8, 0, info.location);
  789. mFunction->ReleaseLocation<AsmJsSIMDValue>(&info);
  790. emitInfo.type = AsmJsType::Bool16x8;
  791. retType = AsmJsRetType::Bool16x8;
  792. }
  793. else if (info.type.isSubType(AsmJsType::Bool8x16))
  794. {
  795. CheckNodeLocation(info, AsmJsSIMDValue);
  796. mWriter.Conv(OpCodeAsmJs::Simd128_Return_B16, 0, info.location);
  797. mFunction->ReleaseLocation<AsmJsSIMDValue>(&info);
  798. emitInfo.type = AsmJsType::Bool8x16;
  799. retType = AsmJsRetType::Bool8x16;
  800. }
  801. #if 0
  802. else if (info.type.isSubType(AsmJsType::Float64x2))
  803. {
  804. CheckNodeLocation(info, AsmJsSIMDValue);
  805. mWriter.Conv(OpCodeAsmJs::Simd128_Return_D2, 0, info.location);
  806. mFunction->ReleaseLocation<AsmJsSIMDValue>(&info);
  807. emitInfo.type = AsmJsType::Float64x2;
  808. retType = AsmJsRetType::Float64x2;
  809. }
  810. #endif // 0
  811. else if (info.type.isSubType(AsmJsType::Int16x8))
  812. {
  813. CheckNodeLocation(info, AsmJsSIMDValue);
  814. mWriter.Conv(OpCodeAsmJs::Simd128_Return_I8, 0, info.location);
  815. mFunction->ReleaseLocation<AsmJsSIMDValue>(&info);
  816. emitInfo.type = AsmJsType::Int16x8;
  817. retType = AsmJsRetType::Int16x8;
  818. }
  819. else if (info.type.isSubType(AsmJsType::Int8x16))
  820. {
  821. CheckNodeLocation(info, AsmJsSIMDValue);
  822. mWriter.Conv(OpCodeAsmJs::Simd128_Return_I16, 0, info.location);
  823. mFunction->ReleaseLocation<AsmJsSIMDValue>(&info);
  824. emitInfo.type = AsmJsType::Int8x16;
  825. retType = AsmJsRetType::Int8x16;
  826. }
  827. else
  828. {
  829. throw AsmJsCompilationException(_u("Expression for return must be subtype of Signed, Double, or Float"));
  830. }
  831. EndStatement(pnode);
  832. }
  833. // check if we saw another return already with a different type
  834. if (!mFunction->CheckAndSetReturnType(retType))
  835. {
  836. throw AsmJsCompilationException(_u("Different return type for the function %s"), mFunction->GetName()->Psz());
  837. }
  838. mWriter.AsmBr( mFunction->GetFuncInfo()->singleExit );
  839. return emitInfo;
  840. }
  841. bool AsmJSByteCodeGenerator::IsFRound(AsmJsMathFunction* sym)
  842. {
  843. return (sym && sym->GetMathBuiltInFunction() == AsmJSMathBuiltin_fround);
  844. }
  845. bool AsmJSByteCodeGenerator::IsValidSimdFcnRetType(AsmJsSIMDFunction& simdFunction, const AsmJsRetType& expectedType, const AsmJsRetType& retType)
  846. {
  847. // Return types of simd builtins can be coereced to other asmjs types when a valid coercion exists
  848. // e.g.
  849. // float -> double var d = 0.0; d = +float32x4ExtractLane(...)
  850. // signed -> double var d = 0.0; d = +int32x4ExtractLane(...)
  851. // unsigned -> double var d = 0.0; d = +uint32x4ExtractLane(...)
  852. // If a simd built-in is used without coercion, then expectedType is Void.
  853. // All SIMD ops are allowed without coercion except a few that return bool. E.g. b4anyTrue()
  854. // Unsigned and Bools are represented as Signed in AsmJs
  855. if (expectedType == AsmJsRetType::Void)
  856. {
  857. return true;
  858. }
  859. else if (expectedType == retType)
  860. {
  861. Assert(expectedType == AsmJsRetType::Float ||
  862. expectedType == AsmJsRetType::Signed ||
  863. expectedType == AsmJsRetType::Unsigned||
  864. expectedType.toType().isSIMDType() );
  865. return true;
  866. }
  867. else if (expectedType == AsmJsRetType::Double)
  868. {
  869. return (retType == AsmJsRetType::Float ||
  870. retType == AsmJsRetType::Signed ||
  871. retType == AsmJsRetType::Unsigned);
  872. }
  873. else if (expectedType == AsmJsRetType::Signed)
  874. {
  875. //Unsigned and Bools are represented as Signed in AsmJs
  876. return (retType == AsmJsRetType::Unsigned ||
  877. simdFunction.ReturnsBool());
  878. }
  879. return false;
  880. }
  881. // First set of opcode are for External calls, second set is for internal calls
  882. static const OpCodeAsmJs callOpCode[2][7] =
  883. {
  884. {
  885. OpCodeAsmJs::StartCall
  886. , OpCodeAsmJs::Call
  887. , OpCodeAsmJs::ArgOut_Db
  888. , OpCodeAsmJs::ArgOut_Int
  889. , OpCodeAsmJs::Conv_VTD
  890. , OpCodeAsmJs::Conv_VTI
  891. , OpCodeAsmJs::Conv_VTF
  892. },
  893. {
  894. OpCodeAsmJs::I_StartCall
  895. , OpCodeAsmJs::I_Call
  896. , OpCodeAsmJs::I_ArgOut_Db
  897. , OpCodeAsmJs::I_ArgOut_Int
  898. , OpCodeAsmJs::I_Conv_VTD
  899. , OpCodeAsmJs::I_Conv_VTI
  900. , OpCodeAsmJs::I_Conv_VTF
  901. }
  902. };
  903. Js::EmitExpressionInfo AsmJSByteCodeGenerator::EmitCall(ParseNode * pnode, AsmJsRetType expectedType /*= AsmJsType::Void*/)
  904. {
  905. Assert( pnode->nop == knopCall );
  906. ParseNode* identifierNode = pnode->sxCall.pnodeTarget;
  907. RegSlot funcTableIndexRegister = Constants::NoRegister;
  908. // Function table
  909. if( pnode->sxCall.pnodeTarget->nop == knopIndex )
  910. {
  911. identifierNode = ParserWrapper::GetBinaryLeft( pnode->sxCall.pnodeTarget );
  912. ParseNode* indexNode = ParserWrapper::GetBinaryRight( pnode->sxCall.pnodeTarget );
  913. // check for table size annotation
  914. if( indexNode->nop != knopAnd )
  915. {
  916. throw AsmJsCompilationException( _u("Function table call must be of format identifier[expr & NumericLiteral](...)") );
  917. }
  918. ParseNode* tableSizeNode = ParserWrapper::GetBinaryRight( indexNode );
  919. if( tableSizeNode->nop != knopInt )
  920. {
  921. throw AsmJsCompilationException( _u("Function table call must be of format identifier[expr & NumericLiteral](...)") );
  922. }
  923. if (tableSizeNode->sxInt.lw < 0)
  924. {
  925. throw AsmJsCompilationException(_u("Function table size must be positive"));
  926. }
  927. const uint tableSize = tableSizeNode->sxInt.lw+1;
  928. if( !::Math::IsPow2(tableSize) )
  929. {
  930. throw AsmJsCompilationException( _u("Function table size must be a power of 2") );
  931. }
  932. // Check for function table identifier
  933. if( !ParserWrapper::IsNameDeclaration( identifierNode ) )
  934. {
  935. throw AsmJsCompilationException( _u("Function call must be of format identifier(...) or identifier[expr & size](...)") );
  936. }
  937. PropertyName funcName = identifierNode->name();
  938. AsmJsFunctionDeclaration* sym = mCompiler->LookupFunction( funcName );
  939. if( !sym )
  940. {
  941. throw AsmJsCompilationException( _u("Unable to find function table %s"), funcName->Psz() );
  942. }
  943. else
  944. {
  945. if( sym->GetSymbolType() != AsmJsSymbol::FuncPtrTable )
  946. {
  947. throw AsmJsCompilationException( _u("Identifier %s is not a function table"), funcName->Psz() );
  948. }
  949. AsmJsFunctionTable* funcTable = sym->Cast<AsmJsFunctionTable>();
  950. if( funcTable->GetSize() != tableSize )
  951. {
  952. throw AsmJsCompilationException( _u("Trying to load from Function table %s of size [%d] with size [%d]"), funcName->Psz(), funcTable->GetSize(), tableSize );
  953. }
  954. }
  955. const EmitExpressionInfo& indexInfo = Emit( indexNode );
  956. if( !indexInfo.type.isInt() )
  957. {
  958. throw AsmJsCompilationException( _u("Array Buffer View index must be type int") );
  959. }
  960. CheckNodeLocation( indexInfo, int );
  961. funcTableIndexRegister = indexInfo.location;
  962. }
  963. if( !ParserWrapper::IsNameDeclaration( identifierNode ) )
  964. {
  965. throw AsmJsCompilationException( _u("Function call must be of format identifier(...) or identifier[expr & size](...)") );
  966. }
  967. PropertyName funcName = identifierNode->name();
  968. AsmJsFunctionDeclaration* sym = mCompiler->LookupFunction(funcName);
  969. if( !sym )
  970. {
  971. throw AsmJsCompilationException( _u("Undefined function %s"), funcName );
  972. }
  973. if (sym->GetSymbolType() == AsmJsSymbol::SIMDBuiltinFunction)
  974. {
  975. AsmJsSIMDFunction *simdFun = sym->Cast<AsmJsSIMDFunction>();
  976. if (simdFun->IsSimdLoadFunc() || simdFun->IsSimdStoreFunc())
  977. {
  978. return EmitSimdLoadStoreBuiltin(pnode, sym->Cast<AsmJsSIMDFunction>(), expectedType);
  979. }
  980. else
  981. {
  982. return EmitSimdBuiltin(pnode, sym->Cast<AsmJsSIMDFunction>(), expectedType);
  983. }
  984. }
  985. if (IsFRound((AsmJsMathFunction*)sym))
  986. {
  987. expectedType = AsmJsRetType::Float;
  988. }
  989. const bool isFFI = sym->GetSymbolType() == AsmJsSymbol::ImportFunction;
  990. const bool isMathBuiltin = sym->GetSymbolType() == AsmJsSymbol::MathBuiltinFunction;
  991. if( isMathBuiltin )
  992. {
  993. return EmitMathBuiltin( pnode, sym->Cast<AsmJsMathFunction>(), expectedType );
  994. }
  995. // math builtins have different requirements for call-site coercion
  996. if (!sym->CheckAndSetReturnType(expectedType))
  997. {
  998. throw AsmJsCompilationException(_u("Different return type found for function %s"), funcName->Psz());
  999. }
  1000. if (!mIsCallLegal)
  1001. {
  1002. Assert(!isMathBuiltin); // math builtins cannot change heap, so they are specifically excluded from this rule
  1003. throw AsmJsCompilationException(_u("Call is not legal at this location"));
  1004. }
  1005. const int StartCallIndex = 0;
  1006. const int CallIndex = 1;
  1007. const int ArgOut_DbIndex = 2;
  1008. const int ArgOut_IntIndex = 3;
  1009. const int Conv_VTDIndex = 4;
  1010. const int Conv_VTIIndex =5;
  1011. const int Conv_VTFIndex = 6;
  1012. const int funcOpCode = isFFI ? 0 : 1;
  1013. // StartCall
  1014. const ArgSlot argCount = pnode->sxCall.argCount;
  1015. StartStatement(pnode);
  1016. ++mNestedCallCount;
  1017. uint startCallOffset = mWriter.GetCurrentOffset();
  1018. auto startCallChunk = mWriter.GetCurrentChunk();
  1019. uint startCallChunkOffset = startCallChunk->GetCurrentOffset();
  1020. bool patchStartCall = sym->GetArgCount() == Constants::InvalidArgSlot;
  1021. if (patchStartCall)
  1022. {
  1023. // we will not know the types of the arguments for the first call to a deferred function,
  1024. // so we put a placeholder instr in the bytecode and then patch it with correct arg size
  1025. // once we evaluate the arguments
  1026. mWriter.AsmStartCall(callOpCode[funcOpCode][StartCallIndex], Constants::InvalidArgSlot);
  1027. }
  1028. else
  1029. {
  1030. // args size + 1 pointer
  1031. const ArgSlot argByteSize = UInt16Math::Add(sym->GetArgByteSize(argCount), sizeof(Var));
  1032. mWriter.AsmStartCall(callOpCode[funcOpCode][StartCallIndex], argByteSize);
  1033. }
  1034. AutoArrayPtr<AsmJsType> types(nullptr, 0);
  1035. int maxDepthForLevel = mFunction->GetArgOutDepth();
  1036. if( argCount > 0 )
  1037. {
  1038. ParseNode* argNode = pnode->sxCall.pnodeArgs;
  1039. uint16 regSlotLocation = 1;
  1040. types.Set(HeapNewArray( AsmJsType, argCount ), argCount);
  1041. for(ArgSlot i = 0; i < argCount; i++)
  1042. {
  1043. // Get i arg node
  1044. ParseNode* arg = argNode;
  1045. if( argNode->nop == knopList )
  1046. {
  1047. arg = ParserWrapper::GetBinaryLeft( argNode );
  1048. argNode = ParserWrapper::GetBinaryRight( argNode );
  1049. }
  1050. // Emit argument
  1051. const EmitExpressionInfo& argInfo = Emit( arg );
  1052. types[i] = argInfo.type;
  1053. // OutParams i
  1054. if( argInfo.type.isDouble() )
  1055. {
  1056. CheckNodeLocation( argInfo, double );
  1057. if (callOpCode[funcOpCode][ArgOut_DbIndex] == OpCodeAsmJs::ArgOut_Db)
  1058. {
  1059. mWriter.AsmReg2(callOpCode[funcOpCode][ArgOut_DbIndex], regSlotLocation, argInfo.location);
  1060. regSlotLocation++; // in case of external calls this is boxed and converted to a Var
  1061. }
  1062. else
  1063. {
  1064. mWriter.AsmReg2(callOpCode[funcOpCode][ArgOut_DbIndex], regSlotLocation, argInfo.location);
  1065. regSlotLocation += sizeof(double) / sizeof(Var);// in case of internal calls we will pass this arg as double
  1066. }
  1067. mFunction->ReleaseLocation<double>( &argInfo );
  1068. }
  1069. else if (argInfo.type.isFloat())
  1070. {
  1071. CheckNodeLocation(argInfo, float);
  1072. if (isFFI)
  1073. {
  1074. throw AsmJsCompilationException(_u("FFI function %s doesn't support float arguments"), funcName->Psz());
  1075. }
  1076. mWriter.AsmReg2(OpCodeAsmJs::I_ArgOut_Flt, regSlotLocation, argInfo.location);
  1077. regSlotLocation++;
  1078. mFunction->ReleaseLocation<float>(&argInfo);
  1079. }
  1080. else if (argInfo.type.isInt())
  1081. {
  1082. CheckNodeLocation( argInfo, int );
  1083. mWriter.AsmReg2(callOpCode[funcOpCode][ArgOut_IntIndex], regSlotLocation, argInfo.location);
  1084. regSlotLocation++;
  1085. mFunction->ReleaseLocation<int>( &argInfo );
  1086. }
  1087. else if (argInfo.type.isSIMDType())
  1088. {
  1089. if (isFFI)
  1090. {
  1091. throw AsmJsCompilationException(_u("FFI function %s doesn't support SIMD arguments"), funcName->Psz());
  1092. }
  1093. CheckNodeLocation(argInfo, AsmJsSIMDValue);
  1094. OpCodeAsmJs opcode = OpCodeAsmJs::Simd128_I_ArgOut_I4;
  1095. switch (argInfo.type.GetWhich())
  1096. {
  1097. case AsmJsType::Int32x4:
  1098. break;
  1099. case AsmJsType::Float32x4:
  1100. opcode = OpCodeAsmJs::Simd128_I_ArgOut_F4;
  1101. break;
  1102. #if 0
  1103. case AsmJsType::Float64x2:
  1104. opcode = OpCodeAsmJs::Simd128_I_ArgOut_D2;
  1105. break;
  1106. #endif // 0
  1107. case AsmJsType::Int16x8:
  1108. opcode = OpCodeAsmJs::Simd128_I_ArgOut_I8;
  1109. break;
  1110. case AsmJsType::Int8x16:
  1111. opcode = OpCodeAsmJs::Simd128_I_ArgOut_I16;
  1112. break;
  1113. case AsmJsType::Bool32x4:
  1114. opcode = OpCodeAsmJs::Simd128_I_ArgOut_B4;
  1115. break;
  1116. case AsmJsType::Bool16x8:
  1117. opcode = OpCodeAsmJs::Simd128_I_ArgOut_B8;
  1118. break;
  1119. case AsmJsType::Bool8x16:
  1120. opcode = OpCodeAsmJs::Simd128_I_ArgOut_B16;
  1121. break;
  1122. case AsmJsType::Uint32x4:
  1123. case AsmJsType::Uint16x8:
  1124. case AsmJsType::Uint8x16:
  1125. //In Asm.js unsigned SIMD types are not allowed as function arguments or return values.
  1126. throw AsmJsCompilationException(_u("Function %s doesn't support argument of type %s. Argument must be of signed type."), funcName->Psz(), argInfo.type.toChars());
  1127. default:
  1128. Assert(UNREACHED);
  1129. }
  1130. mWriter.AsmReg2(opcode, regSlotLocation, argInfo.location);
  1131. regSlotLocation += sizeof(AsmJsSIMDValue) / sizeof(Var);
  1132. mFunction->ReleaseLocation<AsmJsSIMDValue>(&argInfo);
  1133. }
  1134. else
  1135. {
  1136. throw AsmJsCompilationException(_u("Function %s doesn't support argument of type %s"), funcName->Psz(), argInfo.type.toChars());
  1137. }
  1138. // if there are nested calls, track whichever is the deepest
  1139. if (maxDepthForLevel < mFunction->GetArgOutDepth())
  1140. {
  1141. maxDepthForLevel = mFunction->GetArgOutDepth();
  1142. }
  1143. }
  1144. }
  1145. // Check if this function supports the type of these arguments
  1146. AsmJsRetType retType;
  1147. const bool supported = sym->SupportsArgCall( argCount, types, retType );
  1148. if( !supported )
  1149. {
  1150. throw AsmJsCompilationException( _u("Function %s doesn't support arguments"), funcName->Psz() );
  1151. }
  1152. // need to validate return type again because function might support arguments,
  1153. // but return a different type, i.e.: abs(int) -> int, but expecting double
  1154. // don't validate the return type for foreign import functions
  1155. if( !isFFI && retType != expectedType )
  1156. {
  1157. throw AsmJsCompilationException( _u("Function %s returns different type"), funcName->Psz() );
  1158. }
  1159. const ArgSlot argByteSize = UInt16Math::Add(sym->GetArgByteSize(argCount), sizeof(Var));
  1160. // +1 is for function object
  1161. ArgSlot runtimeArg = UInt16Math::Add(argCount, 1);
  1162. if (funcOpCode == 1) // for non import functions runtimeArg is calculated from argByteSize
  1163. {
  1164. runtimeArg = (ArgSlot)(::ceil((double)(argByteSize / sizeof(Var)))) + 1;
  1165. }
  1166. // +1 is for return address
  1167. maxDepthForLevel += UInt16Math::Add(runtimeArg, 1);
  1168. // Make sure we have enough memory allocated for OutParameters
  1169. if (mNestedCallCount > 1)
  1170. {
  1171. mFunction->SetArgOutDepth(maxDepthForLevel);
  1172. }
  1173. else
  1174. {
  1175. mFunction->SetArgOutDepth(0);
  1176. }
  1177. mFunction->UpdateMaxArgOutDepth(maxDepthForLevel);
  1178. if (patchStartCall)
  1179. {
  1180. uint latestOffset = mWriter.GetCurrentOffset();
  1181. auto latestChunk = mWriter.GetCurrentChunk();
  1182. uint latestChunkOffset = latestChunk->GetCurrentOffset();
  1183. // now that we know the types, we can patch the StartCall instr
  1184. startCallChunk->SetCurrentOffset(startCallChunkOffset);
  1185. mWriter.SetCurrent(startCallOffset, startCallChunk);
  1186. // args size + 1 pointer
  1187. mWriter.AsmStartCall(callOpCode[funcOpCode][StartCallIndex], argByteSize, true /* isPatching */);
  1188. // ... and return to where we left off in the buffer like nothing ever happened
  1189. latestChunk->SetCurrentOffset(latestChunkOffset);
  1190. mWriter.SetCurrent(latestOffset, latestChunk);
  1191. }
  1192. // Load function from env
  1193. switch( sym->GetSymbolType() )
  1194. {
  1195. case AsmJsSymbol::ModuleFunction:
  1196. LoadModuleFunction( AsmJsFunctionMemory::FunctionRegister, sym->GetFunctionIndex() );
  1197. break;
  1198. case AsmJsSymbol::ImportFunction:
  1199. LoadModuleFFI( AsmJsFunctionMemory::FunctionRegister, sym->GetFunctionIndex() );
  1200. break;
  1201. case AsmJsSymbol::FuncPtrTable:
  1202. LoadModuleFunctionTable( AsmJsFunctionMemory::FunctionRegister, sym->GetFunctionIndex(), funcTableIndexRegister );
  1203. mFunction->ReleaseTmpRegister<int>( funcTableIndexRegister );
  1204. break;
  1205. default:
  1206. Assert( false );
  1207. }
  1208. // Call
  1209. mWriter.AsmCall( callOpCode[funcOpCode][CallIndex], AsmJsFunctionMemory::CallReturnRegister, AsmJsFunctionMemory::FunctionRegister, runtimeArg, expectedType );
  1210. // use expected type because return type could be invalid if the function is a FFI
  1211. EmitExpressionInfo info( expectedType.toType() );
  1212. switch( expectedType.which() )
  1213. {
  1214. case AsmJsRetType::Void:
  1215. // do nothing
  1216. break;
  1217. case AsmJsRetType::Signed:
  1218. {
  1219. RegSlot intReg = mFunction->AcquireTmpRegister<int>();
  1220. mWriter.AsmReg2( callOpCode[funcOpCode][Conv_VTIIndex], intReg, AsmJsFunctionMemory::CallReturnRegister );
  1221. info.location = intReg;
  1222. break;
  1223. }
  1224. case AsmJsRetType::Double:
  1225. {
  1226. RegSlot dbReg = mFunction->AcquireTmpRegister<double>();
  1227. mWriter.AsmReg2( callOpCode[funcOpCode][Conv_VTDIndex], dbReg, AsmJsFunctionMemory::CallReturnRegister );
  1228. info.location = dbReg;
  1229. break;
  1230. }
  1231. case AsmJsRetType::Float:
  1232. {
  1233. Assert(!isFFI); //check spec
  1234. RegSlot fltReg = mFunction->AcquireTmpRegister<float>();
  1235. mWriter.AsmReg2(callOpCode[funcOpCode][Conv_VTFIndex], fltReg, AsmJsFunctionMemory::CallReturnRegister);
  1236. info.location = fltReg;
  1237. break;
  1238. }
  1239. case AsmJsRetType::Float32x4:
  1240. {
  1241. Assert(!isFFI);
  1242. RegSlot simdReg = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1243. mWriter.AsmReg2(OpCodeAsmJs::Simd128_I_Conv_VTF4, simdReg, AsmJsFunctionMemory::CallReturnRegister);
  1244. info.location = simdReg;
  1245. break;
  1246. }
  1247. case AsmJsRetType::Int32x4:
  1248. {
  1249. Assert(!isFFI);
  1250. RegSlot simdReg = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1251. mWriter.AsmReg2(OpCodeAsmJs::Simd128_I_Conv_VTI4, simdReg, AsmJsFunctionMemory::CallReturnRegister);
  1252. info.location = simdReg;
  1253. break;
  1254. }
  1255. #if 0
  1256. case AsmJsRetType::Float64x2:
  1257. {
  1258. Assert(!isFFI);
  1259. RegSlot simdReg = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1260. mWriter.AsmReg2(OpCodeAsmJs::Simd128_I_Conv_VTD2, simdReg, AsmJsFunctionMemory::CallReturnRegister);
  1261. info.location = simdReg;
  1262. break;
  1263. }
  1264. #endif // 0
  1265. case AsmJsRetType::Int16x8:
  1266. {
  1267. Assert(!isFFI);
  1268. RegSlot simdReg = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1269. mWriter.AsmReg2(OpCodeAsmJs::Simd128_I_Conv_VTI8, simdReg, AsmJsFunctionMemory::CallReturnRegister);
  1270. info.location = simdReg;
  1271. break;
  1272. }
  1273. case AsmJsRetType::Int8x16:
  1274. {
  1275. Assert(!isFFI);
  1276. RegSlot simdReg = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1277. mWriter.AsmReg2(OpCodeAsmJs::Simd128_I_Conv_VTI16, simdReg, AsmJsFunctionMemory::CallReturnRegister);
  1278. info.location = simdReg;
  1279. break;
  1280. }
  1281. case AsmJsRetType::Uint32x4:
  1282. {
  1283. Assert(!isFFI);
  1284. RegSlot simdReg = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1285. mWriter.AsmReg2(OpCodeAsmJs::Simd128_I_Conv_VTU4, simdReg, AsmJsFunctionMemory::CallReturnRegister);
  1286. info.location = simdReg;
  1287. break;
  1288. }
  1289. case AsmJsRetType::Uint16x8:
  1290. {
  1291. Assert(!isFFI);
  1292. RegSlot simdReg = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1293. mWriter.AsmReg2(OpCodeAsmJs::Simd128_I_Conv_VTU8, simdReg, AsmJsFunctionMemory::CallReturnRegister);
  1294. info.location = simdReg;
  1295. break;
  1296. }
  1297. case AsmJsRetType::Uint8x16:
  1298. {
  1299. Assert(!isFFI);
  1300. RegSlot simdReg = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1301. mWriter.AsmReg2(OpCodeAsmJs::Simd128_I_Conv_VTU16, simdReg, AsmJsFunctionMemory::CallReturnRegister);
  1302. info.location = simdReg;
  1303. break;
  1304. }
  1305. case AsmJsRetType::Bool32x4:
  1306. {
  1307. Assert(!isFFI);
  1308. RegSlot simdReg = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1309. mWriter.AsmReg2(OpCodeAsmJs::Simd128_I_Conv_VTB4, simdReg, AsmJsFunctionMemory::CallReturnRegister);
  1310. info.location = simdReg;
  1311. break;
  1312. }
  1313. case AsmJsRetType::Bool16x8:
  1314. {
  1315. Assert(!isFFI);
  1316. RegSlot simdReg = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1317. mWriter.AsmReg2(OpCodeAsmJs::Simd128_I_Conv_VTB8, simdReg, AsmJsFunctionMemory::CallReturnRegister);
  1318. info.location = simdReg;
  1319. break;
  1320. }
  1321. case AsmJsRetType::Bool8x16:
  1322. {
  1323. Assert(!isFFI);
  1324. RegSlot simdReg = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1325. mWriter.AsmReg2(OpCodeAsmJs::Simd128_I_Conv_VTB16, simdReg, AsmJsFunctionMemory::CallReturnRegister);
  1326. info.location = simdReg;
  1327. break;
  1328. }
  1329. default:
  1330. break;
  1331. }
  1332. EndStatement(pnode);
  1333. --mNestedCallCount;
  1334. Assert(mNestedCallCount >= 0);
  1335. return info;
  1336. }
  1337. EmitExpressionInfo* AsmJSByteCodeGenerator::EmitSimdBuiltinArguments(ParseNode* pnode, AsmJsFunctionDeclaration* func, __out_ecount(pnode->sxCall.argCount) AsmJsType *argsTypes, EmitExpressionInfo *argsInfo)
  1338. {
  1339. const uint16 argCount = pnode->sxCall.argCount;
  1340. Assert(argsTypes);
  1341. Assert(argsInfo);
  1342. if (argCount > 0)
  1343. {
  1344. ParseNode* argNode = pnode->sxCall.pnodeArgs;
  1345. for (ArgSlot i = 0; i < argCount; i++)
  1346. {
  1347. // Get i arg node
  1348. ParseNode* arg = argNode;
  1349. if (argNode->nop == knopList)
  1350. {
  1351. arg = ParserWrapper::GetBinaryLeft(argNode);
  1352. argNode = ParserWrapper::GetBinaryRight(argNode);
  1353. }
  1354. if (func->GetSymbolType() == AsmJsSymbol::SIMDBuiltinFunction)
  1355. {
  1356. AsmJsSIMDFunction *simdFunc = func->Cast<AsmJsSIMDFunction>();
  1357. if (arg->nop == knopCall)
  1358. {
  1359. // REVIEW: Is this exactly according to spec ?
  1360. // This enforces Asm.js rule that all arg calls to user-functions have to be coerced.
  1361. // Generic calls have to be coerced unless used in a SIMD coercion.
  1362. // For example, we cannot do f4add(foo(), bar()), but we can do f4add(f4check(foo()), f4check(bar()))
  1363. //
  1364. // We are only allowed calls as args in similar cases:
  1365. // Float32x4:
  1366. // f4check(foo()); call coercion, any call is allowed
  1367. // f4(fround(), fround(), ...); constructor, only fround is allowed
  1368. // f4add(f4*(..),f4*(..)); operation, only other SIMD functions are allowed (including coercion)
  1369. //
  1370. // Int32x4:
  1371. // i4check(foo()); call coercion, any call is allowed
  1372. // i4add(i4*(), i4*()); operation, only other SIMD functions are allowed (including coercion)
  1373. //
  1374. // Float64x2:
  1375. // similar to Int32x4
  1376. PropertyName argCallTarget = ParserWrapper::VariableName(arg->sxCall.pnodeTarget);
  1377. AsmJsFunctionDeclaration* argCall = mCompiler->LookupFunction(argCallTarget);
  1378. if (!argCall)
  1379. {
  1380. throw AsmJsCompilationException(_u("Undefined function %s."), argCallTarget->Psz());
  1381. }
  1382. EmitExpressionInfo argInfo;
  1383. if (simdFunc->IsTypeCheck())
  1384. {
  1385. // type check. Any call is allowed as argument.
  1386. argInfo = EmitCall(arg, simdFunc->GetReturnType());
  1387. }
  1388. // special case for fround inside some float32x4 operations
  1389. // f4(fround(), ...) , f4splat(fround()), f4.replaceLane(..,..,fround())
  1390. else if ((simdFunc->IsConstructor() && simdFunc->GetSimdBuiltInFunction() == AsmJsSIMDBuiltinFunction::AsmJsSIMDBuiltin_Float32x4) || /*float32x4 all args*/
  1391. simdFunc->GetSimdBuiltInFunction() == AsmJsSIMDBuiltinFunction::AsmJsSIMDBuiltin_float32x4_splat || /*splat all args*/
  1392. (i == 2 && simdFunc->GetSimdBuiltInFunction() == AsmJsSIMDBuiltinFunction::AsmJsSIMDBuiltin_float32x4_replaceLane))
  1393. {
  1394. if (argCall && argCall->GetSymbolType() == AsmJsSymbol::MathBuiltinFunction && IsFRound(argCall->Cast<AsmJsMathFunction>()))
  1395. {
  1396. argInfo = EmitCall(arg, AsmJsRetType::Float);
  1397. }
  1398. else
  1399. {
  1400. throw AsmJsCompilationException(_u("Invalid call as SIMD argument. Expecting fround."));
  1401. }
  1402. }
  1403. else if (argCall->GetSymbolType() == AsmJsSymbol::SIMDBuiltinFunction && argCall->Cast<AsmJsSIMDFunction>()->GetReturnType().toType() == simdFunc->GetArgType(i))
  1404. {
  1405. // any other simd operation. call arguments have to be SIMD operations of expected arg type.
  1406. argInfo = EmitCall(arg, simdFunc->GetArgType(i).toRetType());
  1407. }
  1408. else
  1409. {
  1410. throw AsmJsCompilationException(_u("Invalid call as SIMD argument"));
  1411. }
  1412. argsTypes[i] = argInfo.type;
  1413. argsInfo[i].type = argInfo.type;
  1414. argsInfo[i].location = argInfo.location;
  1415. // arg already emitted
  1416. continue;
  1417. }
  1418. else if (simdFunc->IsFloat32x4Func() && arg->nop == knopFlt)
  1419. {
  1420. // Any floating point constant as float32x4 op arg is considered DoubleLit
  1421. // For all float32x4 operations, if the arg type is DoubleLit, regSlot should be in Float reg space.
  1422. argsTypes[i] = AsmJsType::DoubleLit;
  1423. argsInfo[i].type = AsmJsType::DoubleLit;
  1424. argsInfo[i].location = mFunction->GetConstRegister<float>((float)arg->sxFlt.dbl);
  1425. // no need to emit constant
  1426. continue;
  1427. }
  1428. else if (simdFunc->IsLaneAccessFunc())
  1429. {
  1430. if (i == 0 && !simdFunc->GetArgType(i).isSIMDType())
  1431. {
  1432. throw AsmJsCompilationException(_u("Invalid arguments to ExtractLane/ReplaceLane, SIMD type expected for first argument."));
  1433. }
  1434. if (i == 1) //lane index
  1435. {
  1436. Assert(simdFunc->GetArgType(i) == AsmJsType::Int);
  1437. int lane = (int)arg->sxInt.lw;
  1438. if (arg->nop == knopInt)
  1439. {
  1440. if (lane < 0 || lane >= (int)simdFunc->LanesCount())
  1441. {
  1442. throw AsmJsCompilationException(_u("Invalid arguments to ExtractLane/ReplaceLane, out of range lane indices."));
  1443. }
  1444. }
  1445. else
  1446. {
  1447. throw AsmJsCompilationException(_u("Invalid arguments to extractLane/replaceLane, expecting literals for lane indices."));
  1448. }
  1449. Assert(argCount == 2 || argCount == 3);
  1450. argsTypes[i] = AsmJsType::Int;
  1451. argsInfo[i].type = AsmJsType::Int;
  1452. argsInfo[i].location = mFunction->GetConstRegister<int>((int)lane);
  1453. continue;
  1454. }
  1455. }
  1456. else if ((simdFunc->IsShuffleFunc() || simdFunc->IsSwizzleFunc()) && simdFunc->GetArgType(i) == AsmJsType::Int)
  1457. {
  1458. /* Int args to shuffle/swizzle should be literals and in-range */
  1459. if (arg->nop == knopInt)
  1460. {
  1461. // E.g.
  1462. // f4shuffle(v1, v2, [0-7], [0-7], [0-7], [0-7])
  1463. // f4swizzle(v1, [0-3], [0-3], [0-3], [0-3])
  1464. bool valid = true;
  1465. int32 laneValue = (int) arg->sxInt.lw;
  1466. int argPos = i;
  1467. switch (simdFunc->GetSimdBuiltInFunction())
  1468. {
  1469. case AsmJsSIMDBuiltin_float32x4_shuffle:
  1470. case AsmJsSIMDBuiltin_int32x4_shuffle:
  1471. case AsmJsSIMDBuiltin_uint32x4_shuffle:
  1472. valid = (argPos >= 2 && argPos <= 5) && (laneValue >= 0 && laneValue <= 7);
  1473. break;
  1474. case AsmJsSIMDBuiltin_int16x8_shuffle:
  1475. case AsmJsSIMDBuiltin_uint16x8_shuffle:
  1476. valid = (argPos >= 2 && argPos <= 9) && (laneValue >= 0 && laneValue <= 15);
  1477. break;
  1478. case AsmJsSIMDBuiltin_int8x16_shuffle:
  1479. case AsmJsSIMDBuiltin_uint8x16_shuffle:
  1480. valid = (argPos >= 2 && argPos <= 17) && (laneValue >= 0 && laneValue <= 31);
  1481. break;
  1482. case AsmJsSIMDBuiltin_float64x2_shuffle:
  1483. valid = (argPos >= 2 && argPos <= 3) && (laneValue >= 0 && laneValue <= 3);
  1484. break;
  1485. case AsmJsSIMDBuiltin_float32x4_swizzle:
  1486. case AsmJsSIMDBuiltin_int32x4_swizzle:
  1487. case AsmJsSIMDBuiltin_uint32x4_swizzle:
  1488. valid = (argPos >=1 && argPos <= 4) && (laneValue >= 0 && laneValue <= 3);
  1489. break;
  1490. case AsmJsSIMDBuiltin_int16x8_swizzle:
  1491. case AsmJsSIMDBuiltin_uint16x8_swizzle:
  1492. valid = (argPos >= 1 && argPos <= 8) && (laneValue >= 0 && laneValue <= 7);
  1493. break;
  1494. case AsmJsSIMDBuiltin_int8x16_swizzle:
  1495. case AsmJsSIMDBuiltin_uint8x16_swizzle:
  1496. valid = (argPos >= 1 && argPos <= 16) && (laneValue >= 0 && laneValue <= 15);
  1497. break;
  1498. case AsmJsSIMDBuiltin_float64x2_swizzle:
  1499. valid = (argPos >= 1 && argPos <= 2) && (laneValue >= 0 && laneValue <= 1);
  1500. break;
  1501. default:
  1502. Assert(UNREACHED);
  1503. }
  1504. if (!valid)
  1505. {
  1506. throw AsmJsCompilationException(_u("Invalid arguments to shuffle, out of range lane indices."));
  1507. }
  1508. argsTypes[i] = AsmJsType::Int;
  1509. argsInfo[i].type = AsmJsType::Int;
  1510. argsInfo[i].location = mFunction->GetConstRegister<int>((int)laneValue);
  1511. // no need to emit constant
  1512. continue;
  1513. }
  1514. else
  1515. {
  1516. throw AsmJsCompilationException(_u("Invalid arguments to swizzle/shuffle, expecting literals for lane indices."));
  1517. }
  1518. }
  1519. }
  1520. // Emit argument
  1521. const EmitExpressionInfo& argInfo = Emit(arg);
  1522. argsTypes[i] = argInfo.type;
  1523. argsInfo[i].type = argInfo.type;
  1524. argsInfo[i].location = argInfo.location;
  1525. }
  1526. }
  1527. return argsInfo;
  1528. }
  1529. EmitExpressionInfo AsmJSByteCodeGenerator::EmitSimdBuiltin(ParseNode* pnode, AsmJsSIMDFunction* simdFunction, AsmJsRetType expectedType)
  1530. {
  1531. Assert(pnode->nop == knopCall);
  1532. // StartCall
  1533. const uint16 argCount = pnode->sxCall.argCount;
  1534. AutoArrayPtr<AsmJsType> types(nullptr, 0);
  1535. AutoArrayPtr<EmitExpressionInfo> argsInfo(nullptr, 0);
  1536. if (argCount > 0)
  1537. {
  1538. types.Set(HeapNewArray(AsmJsType, argCount), argCount);
  1539. argsInfo.Set(HeapNewArray(EmitExpressionInfo, argCount), argCount);
  1540. EmitSimdBuiltinArguments(pnode, simdFunction, types, argsInfo);
  1541. }
  1542. AsmJsRetType retType;
  1543. OpCodeAsmJs op;
  1544. const bool supported = simdFunction->SupportsSIMDCall(argCount, types, op, retType);
  1545. if (!supported)
  1546. {
  1547. throw AsmJsCompilationException(_u("SIMD builtin function doesn't support arguments"));
  1548. }
  1549. if (!IsValidSimdFcnRetType(*simdFunction, expectedType, retType))
  1550. {
  1551. throw AsmJsCompilationException(_u("SIMD builtin function returns wrong type"));
  1552. }
  1553. // Release all used location before acquiring a new tmp register
  1554. for (int i = argCount - 1; i >= 0; i--)
  1555. {
  1556. mFunction->ReleaseLocationGeneric(&argsInfo[i]);
  1557. }
  1558. RegSlot dst = Constants::NoRegister;
  1559. AsmJsType dstType = AsmJsType::Void;
  1560. switch (retType.which())
  1561. {
  1562. case AsmJsType::Signed:
  1563. dst = mFunction->AcquireTmpRegister<int>();
  1564. dstType = AsmJsType::Signed;
  1565. break;
  1566. case AsmJsType::Unsigned:
  1567. dst = mFunction->AcquireTmpRegister<int>();
  1568. dstType = AsmJsType::Unsigned;
  1569. break;
  1570. case AsmJsType::Float:
  1571. dst = mFunction->AcquireTmpRegister<float>();
  1572. dstType = AsmJsType::Float;
  1573. break;
  1574. default:
  1575. Assert(retType.toVarType().isSIMD());
  1576. dst = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1577. }
  1578. EmitExpressionInfo emitInfo(dst, retType.toType());
  1579. if (dstType != AsmJsType::Void)
  1580. {
  1581. emitInfo.type = dstType;
  1582. }
  1583. switch (argCount){
  1584. case 1:
  1585. mWriter.AsmReg2(op, dst, argsInfo[0].location);
  1586. break;
  1587. case 2:
  1588. mWriter.AsmReg3(op, dst, argsInfo[0].location, argsInfo[1].location);
  1589. break;
  1590. case 3:
  1591. mWriter.AsmReg4(op, dst, argsInfo[0].location, argsInfo[1].location, argsInfo[2].location);
  1592. break;
  1593. case 4:
  1594. mWriter.AsmReg5(op, dst, argsInfo[0].location, argsInfo[1].location, argsInfo[2].location, argsInfo[3].location);
  1595. break;
  1596. case 5:
  1597. mWriter.AsmReg6(op, dst, argsInfo[0].location, argsInfo[1].location, argsInfo[2].location, argsInfo[3].location, argsInfo[4].location);
  1598. break;
  1599. case 6:
  1600. mWriter.AsmReg7(op, dst, argsInfo[0].location, argsInfo[1].location, argsInfo[2].location, argsInfo[3].location, argsInfo[4].location, argsInfo[5].location);
  1601. break;
  1602. case 8:
  1603. mWriter.AsmReg9(op, dst, argsInfo[0].location, argsInfo[1].location, argsInfo[2].location, argsInfo[3].location, argsInfo[4].location, argsInfo[5].location,
  1604. argsInfo[6].location, argsInfo[7].location);
  1605. break;
  1606. case 9:
  1607. mWriter.AsmReg10(op, dst, argsInfo[0].location, argsInfo[1].location, argsInfo[2].location, argsInfo[3].location, argsInfo[4].location, argsInfo[5].location,
  1608. argsInfo[6].location, argsInfo[7].location, argsInfo[8].location);
  1609. break;
  1610. case 10:
  1611. mWriter.AsmReg11(op, dst, argsInfo[0].location, argsInfo[1].location, argsInfo[2].location, argsInfo[3].location, argsInfo[4].location, argsInfo[5].location,
  1612. argsInfo[6].location, argsInfo[7].location, argsInfo[8].location, argsInfo[9].location);
  1613. break;
  1614. case 16:
  1615. mWriter.AsmReg17(op, dst, argsInfo[0].location, argsInfo[1].location, argsInfo[2].location, argsInfo[3].location, argsInfo[4].location, argsInfo[5].location,
  1616. argsInfo[6].location, argsInfo[7].location, argsInfo[8].location, argsInfo[9].location, argsInfo[10].location, argsInfo[11].location,
  1617. argsInfo[12].location, argsInfo[13].location, argsInfo[14].location, argsInfo[15].location);
  1618. break;
  1619. case 17:
  1620. mWriter.AsmReg18(op, dst, argsInfo[0].location, argsInfo[1].location, argsInfo[2].location, argsInfo[3].location, argsInfo[4].location, argsInfo[5].location,
  1621. argsInfo[6].location, argsInfo[7].location, argsInfo[8].location, argsInfo[9].location, argsInfo[10].location, argsInfo[11].location,
  1622. argsInfo[12].location, argsInfo[13].location, argsInfo[14].location, argsInfo[15].location, argsInfo[16].location);
  1623. break;
  1624. case 18:
  1625. mWriter.AsmReg19(op, dst, argsInfo[0].location, argsInfo[1].location, argsInfo[2].location, argsInfo[3].location, argsInfo[4].location, argsInfo[5].location,
  1626. argsInfo[6].location, argsInfo[7].location, argsInfo[8].location, argsInfo[9].location, argsInfo[10].location, argsInfo[11].location,
  1627. argsInfo[12].location, argsInfo[13].location, argsInfo[14].location, argsInfo[15].location, argsInfo[16].location, argsInfo[17].location);
  1628. break;
  1629. default:
  1630. AssertMsg(UNREACHED, "Wrong argument count to SIMD function");
  1631. }
  1632. return emitInfo;
  1633. }
  1634. EmitExpressionInfo AsmJSByteCodeGenerator::EmitSimdLoadStoreBuiltin(ParseNode* pnode, AsmJsSIMDFunction* simdFunction, AsmJsRetType expectedType)
  1635. {
  1636. Assert(pnode->nop == knopCall);
  1637. Assert(simdFunction->IsSimdLoadFunc() || simdFunction->IsSimdStoreFunc());
  1638. const uint16 argCount = pnode->sxCall.argCount;
  1639. // Check number of arguments
  1640. if ( argCount != simdFunction->GetArgCount())
  1641. {
  1642. throw AsmJsCompilationException(_u("SIMD builtin function doesn't support arguments"));
  1643. }
  1644. ParseNode *argNode = pnode->sxCall.pnodeArgs;
  1645. // Arg1 - tarray
  1646. ParseNode* arrayNameNode = ParserWrapper::GetBinaryLeft(argNode);
  1647. argNode = ParserWrapper::GetBinaryRight(argNode);
  1648. if (!ParserWrapper::IsNameDeclaration(arrayNameNode))
  1649. {
  1650. throw AsmJsCompilationException(_u("Invalid symbol "));
  1651. }
  1652. PropertyName name = arrayNameNode->name();
  1653. AsmJsSymbol* sym = mCompiler->LookupIdentifier(name, mFunction);
  1654. if (!sym || sym->GetSymbolType() != AsmJsSymbol::ArrayView)
  1655. {
  1656. throw AsmJsCompilationException(_u("Invalid identifier %s"), name->Psz());
  1657. }
  1658. AsmJsArrayView* arrayView = sym->Cast<AsmJsArrayView>();
  1659. ArrayBufferView::ViewType viewType = arrayView->GetViewType();
  1660. // Arg2 - index
  1661. ParseNode* indexNode = argNode;
  1662. ParseNode* valueNode = nullptr;
  1663. if (simdFunction->IsSimdStoreFunc())
  1664. {
  1665. indexNode = ParserWrapper::GetBinaryLeft(argNode);
  1666. valueNode = ParserWrapper::GetBinaryRight(argNode);
  1667. }
  1668. OpCodeAsmJs op;
  1669. uint32 indexSlot = 0;
  1670. TypedArrayEmitType emitType = simdFunction->IsSimdLoadFunc() ? TypedArrayEmitType::LoadTypedArray : TypedArrayEmitType::StoreTypedArray;
  1671. // if changeHeap is implemented, calls are illegal in index expression
  1672. bool wasCallLegal = mIsCallLegal;
  1673. mIsCallLegal = !mCompiler->UsesChangeHeap();
  1674. EmitExpressionInfo indexInfo = EmitTypedArrayIndex(indexNode, op, indexSlot, viewType, emitType);
  1675. mIsCallLegal = wasCallLegal;
  1676. EmitExpressionInfo valueInfo = { 0, AsmJsType::Void };
  1677. // convert opcode to const if needed
  1678. OpCodeAsmJs opcode = simdFunction->GetOpcode();
  1679. if (op == OpCodeAsmJs::LdArrConst || op == OpCodeAsmJs::StArrConst)
  1680. {
  1681. switch (opcode)
  1682. {
  1683. case OpCodeAsmJs::Simd128_LdArr_I4:
  1684. opcode = OpCodeAsmJs::Simd128_LdArrConst_I4;
  1685. break;
  1686. case OpCodeAsmJs::Simd128_LdArr_I8:
  1687. opcode = OpCodeAsmJs::Simd128_LdArrConst_I8;
  1688. break;
  1689. case OpCodeAsmJs::Simd128_LdArr_I16:
  1690. opcode = OpCodeAsmJs::Simd128_LdArrConst_I16;
  1691. break;
  1692. case OpCodeAsmJs::Simd128_LdArr_U4:
  1693. opcode = OpCodeAsmJs::Simd128_LdArrConst_U4;
  1694. break;
  1695. case OpCodeAsmJs::Simd128_LdArr_U8:
  1696. opcode = OpCodeAsmJs::Simd128_LdArrConst_U8;
  1697. break;
  1698. case OpCodeAsmJs::Simd128_LdArr_U16:
  1699. opcode = OpCodeAsmJs::Simd128_LdArrConst_U16;
  1700. break;
  1701. case OpCodeAsmJs::Simd128_LdArr_F4:
  1702. opcode = OpCodeAsmJs::Simd128_LdArrConst_F4;
  1703. break;
  1704. #if 0
  1705. case OpCodeAsmJs::Simd128_LdArr_D2:
  1706. opcode = OpCodeAsmJs::Simd128_LdArrConst_D2;
  1707. break;
  1708. #endif // 0
  1709. case OpCodeAsmJs::Simd128_StArr_I4:
  1710. opcode = OpCodeAsmJs::Simd128_StArrConst_I4;
  1711. break;
  1712. case OpCodeAsmJs::Simd128_StArr_I8:
  1713. opcode = OpCodeAsmJs::Simd128_StArrConst_I8;
  1714. break;
  1715. case OpCodeAsmJs::Simd128_StArr_I16:
  1716. opcode = OpCodeAsmJs::Simd128_StArrConst_I16;
  1717. break;
  1718. case OpCodeAsmJs::Simd128_StArr_U4:
  1719. opcode = OpCodeAsmJs::Simd128_StArrConst_U4;
  1720. break;
  1721. case OpCodeAsmJs::Simd128_StArr_U8:
  1722. opcode = OpCodeAsmJs::Simd128_StArrConst_U8;
  1723. break;
  1724. case OpCodeAsmJs::Simd128_StArr_U16:
  1725. opcode = OpCodeAsmJs::Simd128_StArrConst_U16;
  1726. break;
  1727. case OpCodeAsmJs::Simd128_StArr_F4:
  1728. opcode = OpCodeAsmJs::Simd128_StArrConst_F4;
  1729. break;
  1730. #if 0
  1731. case OpCodeAsmJs::Simd128_StArr_D2:
  1732. opcode = OpCodeAsmJs::Simd128_StArrConst_D2;
  1733. break;
  1734. #endif // 0
  1735. default:
  1736. Assert(UNREACHED);
  1737. }
  1738. }
  1739. // Adjust dataWidth
  1740. int8 dataWidth = 0;
  1741. switch (simdFunction->GetSimdBuiltInFunction())
  1742. {
  1743. case AsmJsSIMDBuiltin_float32x4_load1:
  1744. case AsmJsSIMDBuiltin_float32x4_store1:
  1745. case AsmJsSIMDBuiltin_int32x4_load1:
  1746. case AsmJsSIMDBuiltin_int32x4_store1:
  1747. case AsmJsSIMDBuiltin_uint32x4_load1:
  1748. case AsmJsSIMDBuiltin_uint32x4_store1:
  1749. dataWidth = 4;
  1750. break;
  1751. case AsmJsSIMDBuiltin_float64x2_load1:
  1752. case AsmJsSIMDBuiltin_float64x2_store1:
  1753. case AsmJsSIMDBuiltin_float32x4_load2:
  1754. case AsmJsSIMDBuiltin_float32x4_store2:
  1755. case AsmJsSIMDBuiltin_int32x4_load2:
  1756. case AsmJsSIMDBuiltin_int32x4_store2:
  1757. case AsmJsSIMDBuiltin_uint32x4_load2:
  1758. case AsmJsSIMDBuiltin_uint32x4_store2:
  1759. dataWidth = 8;
  1760. break;
  1761. case AsmJsSIMDBuiltin_float32x4_load3:
  1762. case AsmJsSIMDBuiltin_float32x4_store3:
  1763. case AsmJsSIMDBuiltin_int32x4_load3:
  1764. case AsmJsSIMDBuiltin_int32x4_store3:
  1765. case AsmJsSIMDBuiltin_uint32x4_load3:
  1766. case AsmJsSIMDBuiltin_uint32x4_store3:
  1767. dataWidth = 12;
  1768. break;
  1769. case AsmJsSIMDBuiltin_int32x4_load:
  1770. case AsmJsSIMDBuiltin_int32x4_store:
  1771. case AsmJsSIMDBuiltin_float32x4_load:
  1772. case AsmJsSIMDBuiltin_float32x4_store:
  1773. case AsmJsSIMDBuiltin_float64x2_load:
  1774. case AsmJsSIMDBuiltin_float64x2_store:
  1775. case AsmJsSIMDBuiltin_int16x8_load:
  1776. case AsmJsSIMDBuiltin_int16x8_store:
  1777. case AsmJsSIMDBuiltin_int8x16_load:
  1778. case AsmJsSIMDBuiltin_int8x16_store:
  1779. case AsmJsSIMDBuiltin_uint32x4_load:
  1780. case AsmJsSIMDBuiltin_uint32x4_store:
  1781. case AsmJsSIMDBuiltin_uint16x8_load:
  1782. case AsmJsSIMDBuiltin_uint16x8_store:
  1783. case AsmJsSIMDBuiltin_uint8x16_load:
  1784. case AsmJsSIMDBuiltin_uint8x16_store:
  1785. dataWidth = 16;
  1786. break;
  1787. default:
  1788. Assert(UNREACHED);
  1789. }
  1790. EmitExpressionInfo emitInfo;
  1791. if (simdFunction->IsSimdStoreFunc()) //Store
  1792. {
  1793. // Arg3 - Value to Store. Builtin returns the value being stored.
  1794. Assert(valueNode);
  1795. emitInfo = Emit(valueNode);
  1796. if (emitInfo.type != simdFunction->GetArgType(2))
  1797. {
  1798. throw AsmJsCompilationException(_u("Invalid value to SIMD store "));
  1799. }
  1800. // write opcode
  1801. mWriter.AsmSimdTypedArr(opcode, emitInfo.location, indexSlot, dataWidth, viewType);
  1802. }
  1803. else //Load
  1804. {
  1805. emitInfo.location = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  1806. emitInfo.type = simdFunction->GetReturnType().toType();
  1807. mWriter.AsmSimdTypedArr(opcode, emitInfo.location, indexSlot, dataWidth, viewType);
  1808. }
  1809. mFunction->ReleaseLocationGeneric(&indexInfo);
  1810. return emitInfo;
  1811. }
  1812. EmitExpressionInfo AsmJSByteCodeGenerator::EmitMathBuiltin(ParseNode* pnode, AsmJsMathFunction* mathFunction, AsmJsRetType expectedType)
  1813. {
  1814. if (mathFunction->GetMathBuiltInFunction() == AsmJSMathBuiltinFunction::AsmJSMathBuiltin_max || mathFunction->GetMathBuiltInFunction() == AsmJSMathBuiltinFunction::AsmJSMathBuiltin_min)
  1815. {
  1816. return EmitMinMax(pnode, mathFunction, expectedType);
  1817. }
  1818. ++mNestedCallCount;
  1819. const ArgSlot argCount = pnode->sxCall.argCount;
  1820. ParseNode* argNode = pnode->sxCall.pnodeArgs;
  1821. // for fround, if we have a fround(NumericLiteral), we want to just emit Ld_Flt NumericLiteral
  1822. if (argCount == 1 && IsFRound(mathFunction) && ParserWrapper::IsFroundNumericLiteral(argNode))
  1823. {
  1824. Assert(expectedType == AsmJsRetType::Float);
  1825. StartStatement(pnode);
  1826. RegSlot dst = mFunction->AcquireTmpRegister<float>();
  1827. EmitExpressionInfo emitInfo(dst, expectedType.toType());
  1828. if (argNode->nop == knopFlt)
  1829. {
  1830. mWriter.AsmReg2(OpCodeAsmJs::Ld_Flt, dst, mFunction->GetConstRegister<float>((float)argNode->sxFlt.dbl));
  1831. }
  1832. else if (argNode->nop == knopInt)
  1833. {
  1834. mWriter.AsmReg2(OpCodeAsmJs::Ld_Flt, dst, mFunction->GetConstRegister<float>((float)argNode->sxInt.lw));
  1835. }
  1836. else
  1837. {
  1838. Assert(ParserWrapper::IsNegativeZero(argNode));
  1839. mWriter.AsmReg2(OpCodeAsmJs::Ld_Flt, dst, mFunction->GetConstRegister<float>(-0.0f));
  1840. }
  1841. EndStatement(pnode);
  1842. return emitInfo;
  1843. }
  1844. // The logic here is similar to EmitSimdBuiltinArguments()
  1845. // TODO: Maybe outline this to EmitArguments() after RI. Currently it is causing frequent conflicts upon FI.
  1846. AutoArrayPtr<AsmJsType> types(nullptr, 0);
  1847. AutoArrayPtr<EmitExpressionInfo> argsInfo(nullptr, 0);
  1848. int maxDepthForLevel = mFunction->GetArgOutDepth();
  1849. if( argCount > 0 )
  1850. {
  1851. types.Set(HeapNewArray(AsmJsType, argCount), argCount);
  1852. argsInfo.Set(HeapNewArray(EmitExpressionInfo, argCount), argCount);
  1853. for(ArgSlot i = 0; i < argCount; i++)
  1854. {
  1855. // Get i arg node
  1856. ParseNode* arg = argNode;
  1857. // Special case for fround(abs()) call
  1858. if (argNode->nop == knopCall && mathFunction->GetMathBuiltInFunction() == AsmJSMathBuiltinFunction::AsmJSMathBuiltin_fround)
  1859. {
  1860. // Emit argument
  1861. const EmitExpressionInfo& argInfo = EmitCall(arg, AsmJsRetType::Float);
  1862. types[i] = argInfo.type;
  1863. argsInfo[i].type = argInfo.type;
  1864. argsInfo[i].location = argInfo.location;
  1865. }
  1866. else
  1867. {
  1868. if (argNode->nop == knopList)
  1869. {
  1870. arg = ParserWrapper::GetBinaryLeft(argNode);
  1871. argNode = ParserWrapper::GetBinaryRight(argNode);
  1872. }
  1873. // Emit argument
  1874. const EmitExpressionInfo& argInfo = Emit(arg);
  1875. types[i] = argInfo.type;
  1876. argsInfo[i].type = argInfo.type;
  1877. argsInfo[i].location = argInfo.location;
  1878. }
  1879. // if there are nested calls, track whichever is the deepest
  1880. if (maxDepthForLevel < mFunction->GetArgOutDepth())
  1881. {
  1882. maxDepthForLevel = mFunction->GetArgOutDepth();
  1883. }
  1884. }
  1885. }
  1886. StartStatement(pnode);
  1887. // Check if this function supports the type of these arguments
  1888. AsmJsRetType retType;
  1889. OpCodeAsmJs op;
  1890. const bool supported = mathFunction->SupportsMathCall( argCount, types, op, retType );
  1891. if( !supported )
  1892. {
  1893. throw AsmJsCompilationException( _u("Math builtin function doesn't support arguments") );
  1894. }
  1895. // Release all used location before acquiring a new tmp register
  1896. for (int i = argCount - 1; i >= 0 ; i--)
  1897. {
  1898. mFunction->ReleaseLocationGeneric( &argsInfo[i] );
  1899. }
  1900. const int argByteSize = mathFunction->GetArgByteSize(argCount) + sizeof(Var);
  1901. // + 1 is for function object
  1902. int runtimeArg = (int)(::ceil((double)(argByteSize / sizeof(Var)))) + 1;
  1903. // + 1 for return address
  1904. maxDepthForLevel += runtimeArg + 1;
  1905. // Make sure we have enough memory allocated for OutParameters
  1906. if (mNestedCallCount > 1)
  1907. {
  1908. mFunction->SetArgOutDepth(maxDepthForLevel);
  1909. }
  1910. else
  1911. {
  1912. mFunction->SetArgOutDepth(0);
  1913. }
  1914. mFunction->UpdateMaxArgOutDepth(maxDepthForLevel);
  1915. const bool isInt = retType.toType().isInt();
  1916. const bool isFloatish = retType.toType().isFloatish();
  1917. Assert(isInt || isFloatish || retType.toType().isDouble());
  1918. RegSlot dst;
  1919. if( isInt )
  1920. {
  1921. dst = mFunction->AcquireTmpRegister<int>();
  1922. }
  1923. else if (isFloatish)
  1924. {
  1925. dst = mFunction->AcquireTmpRegister<float>();
  1926. }
  1927. else
  1928. {
  1929. dst = mFunction->AcquireTmpRegister<double>();
  1930. }
  1931. EmitExpressionInfo emitInfo(dst, retType.toType());
  1932. switch( argCount )
  1933. {
  1934. case 1:
  1935. mWriter.AsmReg2( op, dst, argsInfo[0].location );
  1936. break;
  1937. case 2:
  1938. mWriter.AsmReg3( op, dst, argsInfo[0].location, argsInfo[1].location );
  1939. break;
  1940. default:
  1941. Assume(UNREACHED);
  1942. }
  1943. #if DBG
  1944. for (int i = 0; i < argCount; i++)
  1945. {
  1946. if (argsInfo[i].type.isSubType(AsmJsType::Floatish))
  1947. {
  1948. CheckNodeLocation(argsInfo[i], float);
  1949. }
  1950. else if (argsInfo[i].type.isSubType(AsmJsType::MaybeDouble))
  1951. {
  1952. CheckNodeLocation(argsInfo[i], double);
  1953. }
  1954. else if (argsInfo[i].type.isSubType(AsmJsType::Intish))
  1955. {
  1956. CheckNodeLocation(argsInfo[i], int);
  1957. }
  1958. }
  1959. #endif
  1960. EndStatement(pnode);
  1961. --mNestedCallCount;
  1962. return emitInfo;
  1963. }
  1964. EmitExpressionInfo AsmJSByteCodeGenerator::EmitMinMax(ParseNode* pnode, AsmJsMathFunction* mathFunction, AsmJsRetType expectedType)
  1965. {
  1966. Assert(mathFunction->GetArgCount() == 2);
  1967. ++mNestedCallCount;
  1968. uint16 argCount = pnode->sxCall.argCount;
  1969. ParseNode* argNode = pnode->sxCall.pnodeArgs;
  1970. if (argCount < 2)
  1971. {
  1972. throw AsmJsCompilationException(_u("Math builtin function doesn't support arguments"));
  1973. }
  1974. AutoArrayPtr<AsmJsType> types(nullptr, 0);
  1975. AutoArrayPtr<EmitExpressionInfo> argsInfo(nullptr, 0);
  1976. types.Set(HeapNewArray(AsmJsType, mathFunction->GetArgCount()), mathFunction->GetArgCount());
  1977. argsInfo.Set(HeapNewArray(EmitExpressionInfo, mathFunction->GetArgCount()), mathFunction->GetArgCount());
  1978. ParseNode * arg = ParserWrapper::GetBinaryLeft(argNode);
  1979. argNode = ParserWrapper::GetBinaryRight(argNode);
  1980. // Emit first arg as arg0
  1981. argsInfo[0] = Emit(arg);
  1982. int maxDepthForLevel = mFunction->GetArgOutDepth();
  1983. types[0] = argsInfo[0].type;
  1984. EmitExpressionInfo dstInfo;
  1985. for (int i = 1; i < argCount; i++)
  1986. {
  1987. if (argNode->nop == knopList)
  1988. {
  1989. arg = ParserWrapper::GetBinaryLeft(argNode);
  1990. argNode = ParserWrapper::GetBinaryRight(argNode);
  1991. }
  1992. else
  1993. {
  1994. arg = argNode;
  1995. }
  1996. // arg1 will always be the next arg in the argList
  1997. argsInfo[1] = Emit(arg);
  1998. types[1] = argsInfo[1].type;
  1999. // if there are nested calls, track whichever is the deepest
  2000. if (maxDepthForLevel < mFunction->GetArgOutDepth())
  2001. {
  2002. maxDepthForLevel = mFunction->GetArgOutDepth();
  2003. }
  2004. // Check if this function supports the type of these arguments
  2005. AsmJsRetType retType;
  2006. OpCodeAsmJs op;
  2007. const bool supported = mathFunction->SupportsMathCall(mathFunction->GetArgCount(), types, op, retType);
  2008. if (!supported)
  2009. {
  2010. throw AsmJsCompilationException(_u("Math builtin function doesn't support arguments"));
  2011. }
  2012. const int argByteSize = mathFunction->GetArgByteSize(argCount) + sizeof(Var);
  2013. // +1 is for function object
  2014. int runtimeArg = (int)(::ceil((double)(argByteSize / sizeof(Var)))) + 1;
  2015. // +1 is for return address
  2016. maxDepthForLevel += runtimeArg + 1;
  2017. // Make sure we have enough memory allocated for OutParameters
  2018. if (mNestedCallCount > 1)
  2019. {
  2020. mFunction->SetArgOutDepth(maxDepthForLevel);
  2021. }
  2022. else
  2023. {
  2024. mFunction->SetArgOutDepth(0);
  2025. }
  2026. mFunction->UpdateMaxArgOutDepth(maxDepthForLevel);
  2027. maxDepthForLevel = 0;
  2028. mFunction->ReleaseLocationGeneric(&argsInfo[1]);
  2029. mFunction->ReleaseLocationGeneric(&argsInfo[0]);
  2030. dstInfo.type = retType.toType();
  2031. if (retType.toType().isSigned())
  2032. {
  2033. dstInfo.location = mFunction->AcquireTmpRegister<int>();
  2034. }
  2035. else
  2036. {
  2037. Assert(retType.toType().isDouble());
  2038. dstInfo.location = mFunction->AcquireTmpRegister<double>();
  2039. }
  2040. mWriter.AsmReg3(op, dstInfo.location, argsInfo[0].location, argsInfo[1].location);
  2041. // for max/min calls with more than 2 arguments, we use the result of previous call for arg0
  2042. argsInfo[0] = dstInfo;
  2043. #if DBG
  2044. for (uint j = 0; j < mathFunction->GetArgCount(); j++)
  2045. {
  2046. if (argsInfo[j].type.isSubType(AsmJsType::MaybeDouble))
  2047. {
  2048. CheckNodeLocation(argsInfo[j], double);
  2049. }
  2050. else if (argsInfo[j].type.isSubType(AsmJsType::Intish))
  2051. {
  2052. CheckNodeLocation(argsInfo[j], int);
  2053. }
  2054. else
  2055. {
  2056. Assert(UNREACHED);
  2057. }
  2058. }
  2059. #endif
  2060. }
  2061. --mNestedCallCount;
  2062. return dstInfo;
  2063. }
  2064. Js::EmitExpressionInfo AsmJSByteCodeGenerator::EmitIdentifier( ParseNode * pnode )
  2065. {
  2066. Assert( ParserWrapper::IsNameDeclaration( pnode ) );
  2067. PropertyName name = pnode->name();
  2068. AsmJsLookupSource::Source source;
  2069. AsmJsSymbol* sym = mCompiler->LookupIdentifier( name, mFunction, &source );
  2070. if( !sym )
  2071. {
  2072. throw AsmJsCompilationException( _u("Undefined identifier %s"), name->Psz() );
  2073. }
  2074. switch( sym->GetSymbolType() )
  2075. {
  2076. case AsmJsSymbol::Variable:
  2077. {
  2078. AsmJsVar * var = sym->Cast<AsmJsVar>();
  2079. if (!var->isMutable())
  2080. {
  2081. // currently const is only allowed for variables at module scope
  2082. Assert(source == AsmJsLookupSource::AsmJsModule);
  2083. EmitExpressionInfo emitInfo(var->GetType());
  2084. if (var->GetVarType().isInt())
  2085. {
  2086. emitInfo.location = mFunction->AcquireTmpRegister<int>();
  2087. mWriter.AsmInt1Const1(Js::OpCodeAsmJs::Ld_IntConst, emitInfo.location, var->GetIntInitialiser());
  2088. }
  2089. else if (var->GetVarType().isFloat())
  2090. {
  2091. emitInfo.location = mFunction->AcquireTmpRegister<float>();
  2092. mWriter.AsmReg2(Js::OpCodeAsmJs::Ld_Flt, emitInfo.location, mFunction->GetConstRegister<float>(var->GetFloatInitialiser()));
  2093. }
  2094. else
  2095. {
  2096. Assert(var->GetVarType().isDouble());
  2097. emitInfo.location = mFunction->AcquireTmpRegister<double>();
  2098. mWriter.AsmReg2(Js::OpCodeAsmJs::Ld_Db, emitInfo.location, mFunction->GetConstRegister<double>(var->GetDoubleInitialiser()));
  2099. }
  2100. return emitInfo;
  2101. }
  2102. // else fall through
  2103. }
  2104. case AsmJsSymbol::Argument:
  2105. case AsmJsSymbol::ConstantImport:
  2106. {
  2107. AsmJsVarBase* var = sym->Cast<AsmJsVarBase>();
  2108. if( source == AsmJsLookupSource::AsmJsFunction )
  2109. {
  2110. return EmitExpressionInfo( var->GetLocation(), var->GetType() );
  2111. }
  2112. else
  2113. {
  2114. Assert( source == AsmJsLookupSource::AsmJsModule );
  2115. EmitExpressionInfo emitInfo(var->GetType());
  2116. if (var->GetVarType().isInt())
  2117. {
  2118. emitInfo.location = mFunction->AcquireTmpRegister<int>();
  2119. LoadModuleInt(emitInfo.location, var->GetLocation());
  2120. }
  2121. else if (var->GetVarType().isFloat())
  2122. {
  2123. emitInfo.location = mFunction->AcquireTmpRegister<float>();
  2124. LoadModuleFloat(emitInfo.location, var->GetLocation());
  2125. }
  2126. else if (var->GetVarType().isDouble())
  2127. {
  2128. emitInfo.location = mFunction->AcquireTmpRegister<double>();
  2129. LoadModuleDouble(emitInfo.location, var->GetLocation());
  2130. }
  2131. else if (var->GetVarType().isSIMD())
  2132. {
  2133. emitInfo.location = mFunction->AcquireTmpRegister<AsmJsSIMDValue>();
  2134. LoadModuleSimd( emitInfo.location, var->GetLocation(), var->GetVarType());
  2135. }
  2136. else
  2137. {
  2138. Assert(UNREACHED);
  2139. }
  2140. return emitInfo;
  2141. }
  2142. break;
  2143. }
  2144. case AsmJsSymbol::MathConstant:
  2145. {
  2146. AsmJsMathConst* mathConst = sym->Cast<AsmJsMathConst>();
  2147. Assert(mathConst->GetType().isDouble());
  2148. RegSlot loc = mFunction->AcquireTmpRegister<double>();
  2149. mWriter.AsmReg2( OpCodeAsmJs::Ld_Db, loc, mFunction->GetConstRegister<double>(*mathConst->GetVal()) );
  2150. return EmitExpressionInfo(loc, AsmJsType::Double);
  2151. }
  2152. case AsmJsSymbol::SIMDBuiltinFunction:
  2153. case AsmJsSymbol::ImportFunction:
  2154. case AsmJsSymbol::FuncPtrTable:
  2155. case AsmJsSymbol::ModuleFunction:
  2156. case AsmJsSymbol::ArrayView:
  2157. case AsmJsSymbol::MathBuiltinFunction:
  2158. default:
  2159. throw AsmJsCompilationException( _u("Cannot use identifier %s in this context"), name->Psz() );
  2160. }
  2161. }
  2162. static const OpCodeAsmJs typedArrayOp[2][2] =
  2163. {
  2164. { OpCodeAsmJs::LdArrConst, OpCodeAsmJs::LdArr },//LoadTypedArray
  2165. { OpCodeAsmJs::StArrConst, OpCodeAsmJs::StArr },//StoreTypedArray
  2166. };
  2167. EmitExpressionInfo AsmJSByteCodeGenerator::EmitTypedArrayIndex(ParseNode* indexNode, OpCodeAsmJs &op, uint32 &indexSlot, ArrayBufferView::ViewType viewType, TypedArrayEmitType emitType)
  2168. {
  2169. mCompiler->SetUsesHeapBuffer(true);
  2170. bool isConst = false;
  2171. uint32 slot = 0;
  2172. if(indexNode->nop == knopName)
  2173. {
  2174. AsmJsSymbol * declSym = mCompiler->LookupIdentifier(indexNode->name(), mFunction);
  2175. if (declSym && !declSym->isMutable() && declSym->GetSymbolType() == AsmJsSymbol::Variable)
  2176. {
  2177. AsmJsVar * definition = declSym->Cast<AsmJsVar>();
  2178. if(definition->GetVarType().isInt())
  2179. {
  2180. slot = (uint32)definition->GetIntInitialiser();
  2181. isConst = true;
  2182. }
  2183. }
  2184. }
  2185. if (indexNode->nop == knopInt || indexNode->nop == knopFlt || isConst)
  2186. {
  2187. // Emit a different opcode for numerical literal
  2188. if (!isConst)
  2189. {
  2190. if (indexNode->nop == knopInt)
  2191. {
  2192. slot = (uint32)indexNode->sxInt.lw;
  2193. }
  2194. else if (ParserWrapper::IsMinInt(indexNode))
  2195. {
  2196. // this is going to be an error, but we can do this to allow it to get same error message as invalid int
  2197. slot = (uint32)INT32_MIN;
  2198. }
  2199. else if (ParserWrapper::IsUnsigned(indexNode))
  2200. {
  2201. slot = (uint32)indexNode->sxFlt.dbl;
  2202. }
  2203. else
  2204. {
  2205. EmitExpressionInfo indexInfo = Emit(indexNode);
  2206. throw AsmJsCompilationException(_u("Array Index must be intish; %s given"), indexInfo.type.toChars());
  2207. }
  2208. }
  2209. // do the right shift now
  2210. switch( viewType )
  2211. {
  2212. case Js::ArrayBufferView::TYPE_INT16:
  2213. case Js::ArrayBufferView::TYPE_UINT16:
  2214. if (slot & 0x80000000)
  2215. {
  2216. throw AsmJsCompilationException(_u("Numeric literal for heap16 must be within 0 <= n < 2^31; %d given"), slot);
  2217. }
  2218. slot <<= 1;
  2219. break;
  2220. case Js::ArrayBufferView::TYPE_INT32:
  2221. case Js::ArrayBufferView::TYPE_UINT32:
  2222. case Js::ArrayBufferView::TYPE_FLOAT32:
  2223. if (slot & 0xC0000000)
  2224. {
  2225. throw AsmJsCompilationException(_u("Numeric literal for heap32 must be within 0 <= n < 2^30; %d given"), slot);
  2226. }
  2227. slot <<= 2;
  2228. break;
  2229. case Js::ArrayBufferView::TYPE_FLOAT64:
  2230. if (slot & 0xE0000000)
  2231. {
  2232. throw AsmJsCompilationException(_u("Numeric literal for heap64 must be within 0 <= n < 2^29; %d given"), slot);
  2233. }
  2234. slot <<= 3;
  2235. break;
  2236. default:
  2237. break;
  2238. }
  2239. mCompiler->UpdateMaxHeapAccess(slot);
  2240. op = typedArrayOp[emitType][0];
  2241. }
  2242. else
  2243. {
  2244. EmitExpressionInfo indexInfo;
  2245. if (indexNode->nop != knopRsh && viewType != Js::ArrayBufferView::TYPE_INT8 && viewType != Js::ArrayBufferView::TYPE_UINT8)
  2246. {
  2247. throw AsmJsCompilationException( _u("index expression isn't shifted; must be an Int8/Uint8 access") );
  2248. }
  2249. int val = 0;
  2250. uint32 mask = (uint32)~0;
  2251. ParseNode* index;
  2252. if (indexNode->nop == knopRsh)
  2253. {
  2254. ParseNode* rhsNode = ParserWrapper::GetBinaryRight(indexNode);
  2255. if (!rhsNode || rhsNode->nop != knopInt)
  2256. {
  2257. throw AsmJsCompilationException(_u("shift amount must be constant"));
  2258. }
  2259. switch (viewType)
  2260. {
  2261. case Js::ArrayBufferView::TYPE_INT8:
  2262. case Js::ArrayBufferView::TYPE_UINT8:
  2263. val = 0;
  2264. mask = (uint32)~0;
  2265. break;
  2266. case Js::ArrayBufferView::TYPE_INT16:
  2267. case Js::ArrayBufferView::TYPE_UINT16:
  2268. val = 1;
  2269. mask = (uint32)~1;
  2270. break;
  2271. case Js::ArrayBufferView::TYPE_INT32:
  2272. case Js::ArrayBufferView::TYPE_UINT32:
  2273. case Js::ArrayBufferView::TYPE_FLOAT32:
  2274. val = 2;
  2275. mask = (uint32)~3;
  2276. break;
  2277. case Js::ArrayBufferView::TYPE_FLOAT64:
  2278. val = 3;
  2279. mask = (uint32)~7;
  2280. break;
  2281. default:
  2282. Assume(UNREACHED);
  2283. }
  2284. if (rhsNode->sxInt.lw != val)
  2285. {
  2286. throw AsmJsCompilationException(_u("shift amount must be %d"), val);
  2287. }
  2288. index = ParserWrapper::GetBinaryLeft(indexNode);
  2289. }
  2290. else
  2291. {
  2292. index = indexNode;
  2293. }
  2294. isConst = false;
  2295. if (index->nop == knopName)
  2296. {
  2297. AsmJsSymbol * declSym = mCompiler->LookupIdentifier(index->name(), mFunction);
  2298. if (declSym && !declSym->isMutable() && declSym->GetSymbolType() == AsmJsSymbol::Variable)
  2299. {
  2300. AsmJsVar * definition = declSym->Cast<AsmJsVar>();
  2301. if (definition->GetVarType().isInt())
  2302. {
  2303. slot = (uint32)definition->GetIntInitialiser();
  2304. slot &= mask;
  2305. op = typedArrayOp[emitType][0];
  2306. isConst = true;
  2307. mCompiler->UpdateMaxHeapAccess(slot);
  2308. }
  2309. }
  2310. }
  2311. if( ParserWrapper::IsUInt( index) )
  2312. {
  2313. slot = ParserWrapper::GetUInt(index);
  2314. slot &= mask;
  2315. op = typedArrayOp[emitType][0];
  2316. mCompiler->UpdateMaxHeapAccess(slot);
  2317. }
  2318. else if (!isConst)
  2319. {
  2320. indexInfo = Emit( index );
  2321. if( !indexInfo.type.isIntish() )
  2322. {
  2323. throw AsmJsCompilationException( _u("Left operand of >> must be intish; %s given"), indexInfo.type.toChars() );
  2324. }
  2325. indexSlot = indexInfo.location;
  2326. op = typedArrayOp[emitType][1];
  2327. return indexInfo;
  2328. }
  2329. }
  2330. indexSlot = slot;
  2331. return EmitExpressionInfo();
  2332. }
  2333. Js::EmitExpressionInfo AsmJSByteCodeGenerator::EmitLdArrayBuffer( ParseNode * pnode )
  2334. {
  2335. ParseNode* arrayNameNode = ParserWrapper::GetBinaryLeft( pnode );
  2336. ParseNode* indexNode = ParserWrapper::GetBinaryRight( pnode );
  2337. if( !ParserWrapper::IsNameDeclaration( arrayNameNode ) )
  2338. {
  2339. throw AsmJsCompilationException( _u("Invalid symbol ") );
  2340. }
  2341. PropertyName name = arrayNameNode->name();
  2342. AsmJsSymbol* sym = mCompiler->LookupIdentifier(name, mFunction);
  2343. if( !sym || sym->GetSymbolType() != AsmJsSymbol::ArrayView )
  2344. {
  2345. throw AsmJsCompilationException( _u("Invalid identifier %s"), name->Psz() );
  2346. }
  2347. AsmJsArrayView* arrayView = sym->Cast<AsmJsArrayView>();
  2348. ArrayBufferView::ViewType viewType = arrayView->GetViewType();
  2349. OpCodeAsmJs op;
  2350. uint32 indexSlot = 0;
  2351. // if changeHeap is implemented, calls are illegal in index expression
  2352. bool wasCallLegal = mIsCallLegal;
  2353. mIsCallLegal = !mCompiler->UsesChangeHeap();
  2354. EmitExpressionInfo indexInfo = EmitTypedArrayIndex(indexNode, op, indexSlot, viewType, LoadTypedArray);
  2355. mIsCallLegal = wasCallLegal;
  2356. mFunction->ReleaseLocationGeneric(&indexInfo);
  2357. EmitExpressionInfo info( arrayView->GetType() );
  2358. if( info.type.isIntish() )
  2359. {
  2360. info.location = mFunction->AcquireTmpRegister<int>();
  2361. }
  2362. else if (info.type.isMaybeFloat())
  2363. {
  2364. info.location = mFunction->AcquireTmpRegister<float>();
  2365. }
  2366. else
  2367. {
  2368. Assert(info.type.isMaybeDouble());
  2369. info.location = mFunction->AcquireTmpRegister<double>();
  2370. }
  2371. mWriter.AsmTypedArr( op, info.location, indexSlot, viewType );
  2372. return info;
  2373. }
  2374. EmitExpressionInfo AsmJSByteCodeGenerator::EmitAssignment( ParseNode * pnode )
  2375. {
  2376. StartStatement(pnode);
  2377. ParseNode* lhs = ParserWrapper::GetBinaryLeft( pnode );
  2378. ParseNode* rhs = ParserWrapper::GetBinaryRight(pnode);
  2379. EmitExpressionInfo rhsEmit;
  2380. if( ParserWrapper::IsNameDeclaration( lhs ) )
  2381. {
  2382. rhsEmit = Emit(rhs);
  2383. const AsmJsType& rType = rhsEmit.type;
  2384. PropertyName name = lhs->name();
  2385. AsmJsLookupSource::Source source;
  2386. AsmJsSymbol* sym = mCompiler->LookupIdentifier( name, mFunction, &source );
  2387. if( !sym )
  2388. {
  2389. throw AsmJsCompilationException( _u("Undefined identifier %s"), name->Psz() );
  2390. }
  2391. if( !sym->isMutable() )
  2392. {
  2393. throw AsmJsCompilationException( _u("Cannot assign to identifier %s"), name->Psz() );
  2394. }
  2395. AsmJsVarBase* var = sym->Cast<AsmJsVarBase>();
  2396. if( !var->GetType().isSuperType( rType ) )
  2397. {
  2398. throw AsmJsCompilationException( _u("Cannot assign this type to identifier %s"), name->Psz() );
  2399. }
  2400. switch( source )
  2401. {
  2402. case Js::AsmJsLookupSource::AsmJsModule:
  2403. if( var->GetVarType().isInt() )
  2404. {
  2405. CheckNodeLocation( rhsEmit, int );
  2406. SetModuleInt( var->GetLocation(), rhsEmit.location );
  2407. }
  2408. else if (var->GetVarType().isFloat())
  2409. {
  2410. CheckNodeLocation(rhsEmit, float);
  2411. SetModuleFloat(var->GetLocation(), rhsEmit.location);
  2412. }
  2413. else if (var->GetVarType().isDouble())
  2414. {
  2415. CheckNodeLocation( rhsEmit, double );
  2416. SetModuleDouble( var->GetLocation(), rhsEmit.location );
  2417. }
  2418. else if (var->GetVarType().isSIMD())
  2419. {
  2420. CheckNodeLocation(rhsEmit, AsmJsSIMDValue);
  2421. SetModuleSimd(var->GetLocation(), rhsEmit.location, var->GetVarType());
  2422. }
  2423. else
  2424. {
  2425. Assert(UNREACHED);
  2426. }
  2427. break;
  2428. case Js::AsmJsLookupSource::AsmJsFunction:
  2429. if( var->GetVarType().isInt() )
  2430. {
  2431. CheckNodeLocation( rhsEmit, int );
  2432. mWriter.AsmReg2( Js::OpCodeAsmJs::Ld_Int, var->GetLocation(), rhsEmit.location );
  2433. }
  2434. else if (var->GetVarType().isFloat())
  2435. {
  2436. CheckNodeLocation(rhsEmit, float);
  2437. mWriter.AsmReg2(Js::OpCodeAsmJs::Ld_Flt, var->GetLocation(), rhsEmit.location);
  2438. }
  2439. else if (var->GetVarType().isDouble())
  2440. {
  2441. CheckNodeLocation( rhsEmit, double );
  2442. mWriter.AsmReg2( Js::OpCodeAsmJs::Ld_Db, var->GetLocation(), rhsEmit.location );
  2443. }
  2444. else if (var->GetVarType().isSIMD())
  2445. {
  2446. CheckNodeLocation(rhsEmit, AsmJsSIMDValue);
  2447. LoadSimd(var->GetLocation(), rhsEmit.location, var->GetVarType());
  2448. }
  2449. else
  2450. {
  2451. Assert(UNREACHED);
  2452. }
  2453. break;
  2454. default:
  2455. break;
  2456. }
  2457. }
  2458. else if( lhs->nop == knopIndex )
  2459. {
  2460. ParseNode* arrayNameNode = ParserWrapper::GetBinaryLeft( lhs );
  2461. ParseNode* indexNode = ParserWrapper::GetBinaryRight( lhs );
  2462. if( !ParserWrapper::IsNameDeclaration( arrayNameNode ) )
  2463. {
  2464. throw AsmJsCompilationException( _u("Invalid symbol ") );
  2465. }
  2466. PropertyName name = arrayNameNode->name();
  2467. AsmJsSymbol* sym = mCompiler->LookupIdentifier(name, mFunction);
  2468. if( !sym || sym->GetSymbolType() != AsmJsSymbol::ArrayView )
  2469. {
  2470. throw AsmJsCompilationException( _u("Invalid identifier %s"), name->Psz() );
  2471. }
  2472. // must emit index expr first in case it has side effects
  2473. AsmJsArrayView* arrayView = sym->Cast<AsmJsArrayView>();
  2474. ArrayBufferView::ViewType viewType = arrayView->GetViewType();
  2475. OpCodeAsmJs op;
  2476. uint32 indexSlot = 0;
  2477. // if changeHeap is implemented, calls are illegal in index expression and on right hand side of assignments
  2478. bool wasCallLegal = mIsCallLegal;
  2479. mIsCallLegal = !mCompiler->UsesChangeHeap();
  2480. EmitExpressionInfo indexInfo = EmitTypedArrayIndex(indexNode, op, indexSlot, viewType, StoreTypedArray);
  2481. rhsEmit = Emit(rhs);
  2482. mIsCallLegal = wasCallLegal;
  2483. if (viewType == ArrayBufferView::TYPE_FLOAT32)
  2484. {
  2485. if (!rhsEmit.type.isFloatish() && !rhsEmit.type.isMaybeDouble())
  2486. {
  2487. throw AsmJsCompilationException(_u("Cannot assign value to TYPE_FLOAT32 ArrayBuffer"));
  2488. }
  2489. // do the conversion to float only for double
  2490. if (rhsEmit.type.isMaybeDouble())
  2491. {
  2492. CheckNodeLocation(rhsEmit, double);
  2493. RegSlot dst = mFunction->AcquireTmpRegister<float>();
  2494. mWriter.AsmReg2(OpCodeAsmJs::Fround_Db, dst, rhsEmit.location);
  2495. mFunction->ReleaseLocation<double>(&rhsEmit);
  2496. rhsEmit.location = dst;
  2497. rhsEmit.type = AsmJsType::Float;
  2498. }
  2499. }
  2500. else if (viewType == ArrayBufferView::TYPE_FLOAT64)
  2501. {
  2502. if (!rhsEmit.type.isMaybeFloat() && !rhsEmit.type.isMaybeDouble())
  2503. {
  2504. throw AsmJsCompilationException(_u("Cannot assign value to TYPE_FLOAT64 ArrayBuffer"));
  2505. }
  2506. // do the conversion to double only for float
  2507. if (rhsEmit.type.isMaybeFloat())
  2508. {
  2509. CheckNodeLocation(rhsEmit, float);
  2510. RegSlot dst = mFunction->AcquireTmpRegister<double>();
  2511. mWriter.AsmReg2(OpCodeAsmJs::Conv_FTD, dst, rhsEmit.location);
  2512. mFunction->ReleaseLocation<float>(&rhsEmit);
  2513. rhsEmit.location = dst;
  2514. rhsEmit.type = AsmJsType::Double;
  2515. }
  2516. }
  2517. else if (!rhsEmit.type.isSubType(arrayView->GetType()))
  2518. {
  2519. throw AsmJsCompilationException( _u("Cannot assign value ArrayBuffer") );
  2520. }
  2521. // to keep tmp registers in order, I need to release rhsEmit.local before indexInfo.location
  2522. mWriter.AsmTypedArr(op, rhsEmit.location, indexSlot, viewType);
  2523. RegSlot rhsReg = rhsEmit.location;
  2524. mFunction->ReleaseLocationGeneric(&rhsEmit);
  2525. mFunction->ReleaseLocationGeneric(&indexInfo);
  2526. RegSlot newRhsReg;
  2527. if (rhsEmit.type.isMaybeDouble())
  2528. {
  2529. newRhsReg = mFunction->AcquireTmpRegister<double>();
  2530. mWriter.AsmReg2(OpCodeAsmJs::Ld_Db, newRhsReg, rhsReg);
  2531. }
  2532. else if (rhsEmit.type.isFloatish())
  2533. {
  2534. newRhsReg = mFunction->AcquireTmpRegister<float>();
  2535. mWriter.AsmReg2(OpCodeAsmJs::Ld_Flt, newRhsReg, rhsReg);
  2536. }
  2537. else
  2538. {
  2539. newRhsReg = mFunction->AcquireTmpRegister<int>();
  2540. mWriter.AsmReg2(OpCodeAsmJs::Ld_Int, newRhsReg, rhsReg);
  2541. }
  2542. rhsEmit.location = newRhsReg;
  2543. }
  2544. else
  2545. {
  2546. throw AsmJsCompilationException( _u("Can only assign to an identifier or an ArrayBufferView") );
  2547. }
  2548. EndStatement(pnode);
  2549. return rhsEmit;
  2550. }
  2551. EmitExpressionInfo AsmJSByteCodeGenerator::EmitBinaryComparator( ParseNode * pnode, EBinaryComparatorOpCodes op )
  2552. {
  2553. ParseNode* lhs = ParserWrapper::GetBinaryLeft( pnode );
  2554. ParseNode* rhs = ParserWrapper::GetBinaryRight( pnode );
  2555. const EmitExpressionInfo& lhsEmit = Emit( lhs );
  2556. EmitExpressionInfo rhsEmit = Emit( rhs );
  2557. const AsmJsType& lType = lhsEmit.type;
  2558. const AsmJsType& rType = rhsEmit.type;
  2559. StartStatement(pnode);
  2560. EmitExpressionInfo emitInfo(AsmJsType::Int);
  2561. OpCodeAsmJs compOp;
  2562. if (lType.isUnsigned() && rType.isUnsigned())
  2563. {
  2564. CheckNodeLocation(lhsEmit, int);
  2565. CheckNodeLocation(rhsEmit, int);
  2566. emitInfo.location = GetAndReleaseBinaryLocations<int>(&lhsEmit, &rhsEmit);
  2567. compOp = BinaryComparatorOpCodes[op][BCOT_UInt];
  2568. }
  2569. else if( lType.isSigned() && rType.isSigned() )
  2570. {
  2571. CheckNodeLocation( lhsEmit, int );
  2572. CheckNodeLocation( rhsEmit, int );
  2573. emitInfo.location = GetAndReleaseBinaryLocations<int>( &lhsEmit, &rhsEmit );
  2574. compOp = BinaryComparatorOpCodes[op][BCOT_Int];
  2575. }
  2576. else if( lType.isDouble() && rType.isDouble() )
  2577. {
  2578. CheckNodeLocation( lhsEmit, double );
  2579. CheckNodeLocation( rhsEmit, double );
  2580. emitInfo.location = mFunction->AcquireTmpRegister<int>();
  2581. mFunction->ReleaseLocation<double>( &rhsEmit );
  2582. mFunction->ReleaseLocation<double>( &lhsEmit );
  2583. compOp = BinaryComparatorOpCodes[op][BCOT_Double];
  2584. }
  2585. else if (lType.isFloat() && rType.isFloat())
  2586. {
  2587. CheckNodeLocation(lhsEmit, float);
  2588. CheckNodeLocation(rhsEmit, float);
  2589. emitInfo.location = mFunction->AcquireTmpRegister<int>();
  2590. mFunction->ReleaseLocation<float>(&rhsEmit);
  2591. mFunction->ReleaseLocation<float>(&lhsEmit);
  2592. compOp = BinaryComparatorOpCodes[op][BCOT_Float];
  2593. }
  2594. else
  2595. {
  2596. throw AsmJsCompilationException( _u("Type not supported for comparison") );
  2597. }
  2598. mWriter.AsmReg3( compOp, emitInfo.location, lhsEmit.location, rhsEmit.location );
  2599. EndStatement(pnode);
  2600. return emitInfo;
  2601. }
  2602. EmitExpressionInfo AsmJSByteCodeGenerator::EmitUnaryPos( ParseNode * pnode )
  2603. {
  2604. ParseNode* rhs = ParserWrapper::GetUnaryNode( pnode );
  2605. EmitExpressionInfo rhsEmit ;
  2606. if (rhs->nop == knopCall)
  2607. {
  2608. rhsEmit = EmitCall(rhs, AsmJsRetType::Double);
  2609. }
  2610. else
  2611. {
  2612. rhsEmit = Emit(rhs);
  2613. }
  2614. const AsmJsType& rType = rhsEmit.type;
  2615. StartStatement(pnode);
  2616. EmitExpressionInfo emitInfo( AsmJsType::Double );
  2617. RegSlot dst;
  2618. if( rType.isUnsigned() )
  2619. {
  2620. CheckNodeLocation( rhsEmit, int );
  2621. dst = mFunction->AcquireTmpRegister<double>();
  2622. mWriter.AsmReg2( OpCodeAsmJs::Conv_UTD, dst, rhsEmit.location );
  2623. mFunction->ReleaseLocation<int>( &rhsEmit );
  2624. }
  2625. else if( rType.isSigned() )
  2626. {
  2627. CheckNodeLocation( rhsEmit, int );
  2628. dst = mFunction->AcquireTmpRegister<double>();
  2629. mWriter.AsmReg2( OpCodeAsmJs::Conv_ITD, dst, rhsEmit.location );
  2630. mFunction->ReleaseLocation<int>( &rhsEmit );
  2631. }
  2632. else if (rType.isMaybeDouble())
  2633. {
  2634. CheckNodeLocation( rhsEmit, double );
  2635. dst = rhsEmit.location;
  2636. }
  2637. else if (rType.isMaybeFloat())
  2638. {
  2639. CheckNodeLocation(rhsEmit, float);
  2640. dst = mFunction->AcquireTmpRegister<double>();
  2641. mWriter.AsmReg2(OpCodeAsmJs::Conv_FTD, dst, rhsEmit.location);
  2642. mFunction->ReleaseLocation<float>(&rhsEmit);
  2643. }
  2644. else
  2645. {
  2646. throw AsmJsCompilationException( _u("Type not supported for unary +") );
  2647. }
  2648. emitInfo.location = dst;
  2649. EndStatement(pnode);
  2650. return emitInfo;
  2651. }
  2652. Js::EmitExpressionInfo AsmJSByteCodeGenerator::EmitUnaryNeg( ParseNode * pnode )
  2653. {
  2654. ParseNode* rhs = ParserWrapper::GetUnaryNode( pnode );
  2655. const EmitExpressionInfo& rhsEmit = Emit( rhs );
  2656. const AsmJsType& rType = rhsEmit.type;
  2657. StartStatement(pnode);
  2658. EmitExpressionInfo emitInfo;
  2659. if( rType.isInt() )
  2660. {
  2661. CheckNodeLocation( rhsEmit, int );
  2662. RegSlot dst = GetAndReleaseUnaryLocations<int>( &rhsEmit );
  2663. emitInfo.type = AsmJsType::Intish;
  2664. mWriter.AsmReg2( OpCodeAsmJs::Neg_Int, dst, rhsEmit.location );
  2665. emitInfo.location = dst;
  2666. }
  2667. else if (rType.isMaybeDouble())
  2668. {
  2669. CheckNodeLocation( rhsEmit, double );
  2670. RegSlot dst = GetAndReleaseUnaryLocations<double>( &rhsEmit );
  2671. emitInfo.type = AsmJsType::Double;
  2672. mWriter.AsmReg2( OpCodeAsmJs::Neg_Db, dst, rhsEmit.location );
  2673. emitInfo.location = dst;
  2674. }
  2675. else if (rType.isMaybeFloat())
  2676. {
  2677. CheckNodeLocation(rhsEmit, float);
  2678. RegSlot dst = GetAndReleaseUnaryLocations<float>(&rhsEmit);
  2679. emitInfo.type = AsmJsType::Floatish;
  2680. mWriter.AsmReg2(OpCodeAsmJs::Neg_Flt, dst, rhsEmit.location);
  2681. emitInfo.location = dst;
  2682. }
  2683. else
  2684. {
  2685. throw AsmJsCompilationException( _u("Type not supported for unary -") );
  2686. }
  2687. EndStatement(pnode);
  2688. return emitInfo;
  2689. }
  2690. Js::EmitExpressionInfo AsmJSByteCodeGenerator::EmitUnaryNot( ParseNode * pnode )
  2691. {
  2692. ParseNode* rhs = ParserWrapper::GetUnaryNode( pnode );
  2693. int count = 1;
  2694. while( rhs->nop == knopNot )
  2695. {
  2696. ++count;
  2697. rhs = ParserWrapper::GetUnaryNode( rhs );
  2698. }
  2699. EmitExpressionInfo rhsEmit = Emit( rhs );
  2700. AsmJsType rType = rhsEmit.type;
  2701. StartStatement(pnode);
  2702. if( count >= 2 && rType.isMaybeDouble() )
  2703. {
  2704. CheckNodeLocation( rhsEmit, double );
  2705. count -= 2;
  2706. RegSlot dst = mFunction->AcquireTmpRegister<int>();
  2707. mWriter.AsmReg2( OpCodeAsmJs::Conv_DTI, dst, rhsEmit.location );
  2708. mFunction->ReleaseLocation<double>( &rhsEmit );
  2709. // allow the converted value to be negated (useful for ~(~~(+x)) )
  2710. rType = AsmJsType::Signed;
  2711. rhsEmit.location = dst;
  2712. }
  2713. if (count >= 2 && rType.isMaybeFloat())
  2714. {
  2715. CheckNodeLocation(rhsEmit, float);
  2716. count -= 2;
  2717. RegSlot dst = mFunction->AcquireTmpRegister<int>();
  2718. mWriter.AsmReg2(OpCodeAsmJs::Conv_FTI, dst, rhsEmit.location);
  2719. mFunction->ReleaseLocation<float>(&rhsEmit);
  2720. // allow the converted value to be negated (useful for ~(~~(fround(x))) )
  2721. rType = AsmJsType::Signed;
  2722. rhsEmit.location = dst;
  2723. }
  2724. if( rType.isIntish() )
  2725. {
  2726. if( count & 1 )
  2727. {
  2728. CheckNodeLocation( rhsEmit, int );
  2729. RegSlot dst = GetAndReleaseUnaryLocations<int>( &rhsEmit );
  2730. // do the conversion only if we have an odd number of the operator
  2731. mWriter.AsmReg2( OpCodeAsmJs::Not_Int, dst, rhsEmit.location );
  2732. rhsEmit.location = dst;
  2733. }
  2734. rhsEmit.type = AsmJsType::Signed;
  2735. }
  2736. else
  2737. {
  2738. throw AsmJsCompilationException( _u("Type not supported for unary ~") );
  2739. }
  2740. EndStatement(pnode);
  2741. return rhsEmit;
  2742. }
  2743. Js::EmitExpressionInfo AsmJSByteCodeGenerator::EmitUnaryLogNot( ParseNode * pnode )
  2744. {
  2745. ParseNode* rhs = ParserWrapper::GetUnaryNode( pnode );
  2746. int count = 1;
  2747. while( rhs->nop == knopLogNot )
  2748. {
  2749. ++count;
  2750. rhs = ParserWrapper::GetUnaryNode( rhs );
  2751. }
  2752. const EmitExpressionInfo& rhsEmit = Emit( rhs );
  2753. const AsmJsType& rType = rhsEmit.type;
  2754. StartStatement(pnode);
  2755. EmitExpressionInfo emitInfo( AsmJsType::Int );
  2756. if( rType.isInt() )
  2757. {
  2758. CheckNodeLocation( rhsEmit, int );
  2759. RegSlot dst = GetAndReleaseUnaryLocations<int>( &rhsEmit );
  2760. if( count & 1 )
  2761. {
  2762. // do the conversion only if we have an odd number of the operator
  2763. mWriter.AsmReg2( OpCodeAsmJs::LogNot_Int, dst, rhsEmit.location );
  2764. }
  2765. else
  2766. {
  2767. // otherwise, make sure the result is 0|1
  2768. mWriter.AsmReg2( OpCodeAsmJs::Conv_ITB, dst, rhsEmit.location );
  2769. }
  2770. emitInfo.location = dst;
  2771. }
  2772. else
  2773. {
  2774. throw AsmJsCompilationException( _u("Type not supported for unary !") );
  2775. }
  2776. EndStatement(pnode);
  2777. return emitInfo;
  2778. }
  2779. EmitExpressionInfo AsmJSByteCodeGenerator::EmitBooleanExpression( ParseNode* expr, Js::ByteCodeLabel trueLabel, Js::ByteCodeLabel falseLabel )
  2780. {
  2781. switch( expr->nop )
  2782. {
  2783. case knopLogNot:{
  2784. const EmitExpressionInfo& info = EmitBooleanExpression( expr->sxUni.pnode1, falseLabel, trueLabel );
  2785. return info;
  2786. break;
  2787. }
  2788. // case knopEq:
  2789. // case knopNe:
  2790. // case knopLt:
  2791. // case knopLe:
  2792. // case knopGe:
  2793. // case knopGt:
  2794. // byteCodeGenerator->StartStatement( expr );
  2795. // EmitBinaryOpnds( expr->sxBin.pnode1, expr->sxBin.pnode2, byteCodeGenerator, funcInfo );
  2796. // funcInfo->ReleaseLoc( expr->sxBin.pnode2 );
  2797. // funcInfo->ReleaseLoc( expr->sxBin.pnode1 );
  2798. // mWriter.BrReg2( nopToOp[expr->nop], trueLabel, expr->sxBin.pnode1->location,
  2799. // expr->sxBin.pnode2->location );
  2800. // mWriter.AsmBr( falseLabel );
  2801. // byteCodeGenerator->EndStatement( expr );
  2802. // break;
  2803. // case knopName:
  2804. // byteCodeGenerator->StartStatement( expr );
  2805. // Emit( expr, byteCodeGenerator, funcInfo, false );
  2806. // mWriter.BrReg1( Js::OpCode::BrTrue_A, trueLabel, expr->location );
  2807. // mWriter.AsmBr( falseLabel );
  2808. // byteCodeGenerator->EndStatement( expr );
  2809. // break;
  2810. default:{
  2811. const EmitExpressionInfo& info = Emit( expr );
  2812. if( !info.type.isInt() )
  2813. {
  2814. throw AsmJsCompilationException( _u("Comparison expressions must be type signed") );
  2815. }
  2816. mWriter.AsmBrReg1( Js::OpCodeAsmJs::BrTrue_Int, trueLabel, info.location );
  2817. mWriter.AsmBr( falseLabel );
  2818. return info;
  2819. break;
  2820. }
  2821. }
  2822. }
  2823. EmitExpressionInfo AsmJSByteCodeGenerator::EmitIf( ParseNode * pnode )
  2824. {
  2825. Js::ByteCodeLabel trueLabel = mWriter.DefineLabel();
  2826. Js::ByteCodeLabel falseLabel = mWriter.DefineLabel();
  2827. const EmitExpressionInfo& boolInfo = EmitBooleanExpression( pnode->sxIf.pnodeCond, trueLabel, falseLabel );
  2828. mFunction->ReleaseLocation<int>( &boolInfo );
  2829. mWriter.MarkAsmJsLabel( trueLabel );
  2830. const EmitExpressionInfo& trueInfo = Emit( pnode->sxIf.pnodeTrue );
  2831. mFunction->ReleaseLocationGeneric( &trueInfo );
  2832. if( pnode->sxIf.pnodeFalse != nullptr )
  2833. {
  2834. // has else clause
  2835. Js::ByteCodeLabel skipLabel = mWriter.DefineLabel();
  2836. // Record the branch bytecode offset
  2837. mWriter.RecordStatementAdjustment( Js::FunctionBody::SAT_FromCurrentToNext );
  2838. // then clause skips else clause
  2839. mWriter.AsmBr( skipLabel );
  2840. // generate code for else clause
  2841. mWriter.MarkAsmJsLabel( falseLabel );
  2842. const EmitExpressionInfo& falseInfo = Emit( pnode->sxIf.pnodeFalse );
  2843. mFunction->ReleaseLocationGeneric( &falseInfo );
  2844. mWriter.MarkAsmJsLabel( skipLabel );
  2845. }
  2846. else
  2847. {
  2848. mWriter.MarkAsmJsLabel( falseLabel );
  2849. }
  2850. if( pnode->emitLabels )
  2851. {
  2852. mWriter.MarkAsmJsLabel( pnode->sxStmt.breakLabel );
  2853. }
  2854. return EmitExpressionInfo( AsmJsType::Void );
  2855. }
  2856. Js::EmitExpressionInfo AsmJSByteCodeGenerator::EmitLoop( ParseNode *loopNode, ParseNode *cond, ParseNode *body, ParseNode *incr, BOOL doWhile /*= false */ )
  2857. {
  2858. // Need to increment loop count whether we are going to profile or not for HasLoop()
  2859. StartStatement(loopNode);
  2860. Js::ByteCodeLabel loopEntrance = mWriter.DefineLabel();
  2861. Js::ByteCodeLabel continuePastLoop = mWriter.DefineLabel();
  2862. uint loopId = mWriter.EnterLoop( loopEntrance );
  2863. loopNode->sxLoop.loopId = loopId;
  2864. EndStatement(loopNode);
  2865. if( doWhile )
  2866. {
  2867. const EmitExpressionInfo& bodyInfo = Emit( body );
  2868. mFunction->ReleaseLocationGeneric( &bodyInfo );
  2869. if( loopNode->emitLabels )
  2870. {
  2871. mWriter.MarkAsmJsLabel( loopNode->sxStmt.continueLabel );
  2872. }
  2873. if( !ByteCodeGenerator::IsFalse( cond ) )
  2874. {
  2875. const EmitExpressionInfo& condInfo = EmitBooleanExpression( cond, loopEntrance, continuePastLoop );
  2876. mFunction->ReleaseLocationGeneric( &condInfo );
  2877. }
  2878. }
  2879. else
  2880. {
  2881. if( cond )
  2882. {
  2883. Js::ByteCodeLabel trueLabel = mWriter.DefineLabel();
  2884. const EmitExpressionInfo& condInfo = EmitBooleanExpression( cond, trueLabel, continuePastLoop );
  2885. mFunction->ReleaseLocationGeneric( &condInfo );
  2886. mWriter.MarkAsmJsLabel( trueLabel );
  2887. }
  2888. const EmitExpressionInfo& bodyInfo = Emit( body );
  2889. mFunction->ReleaseLocationGeneric( &bodyInfo );
  2890. if( loopNode->emitLabels )
  2891. {
  2892. mWriter.MarkAsmJsLabel( loopNode->sxStmt.continueLabel );
  2893. }
  2894. if( incr != NULL )
  2895. {
  2896. const EmitExpressionInfo& incrInfo = Emit( incr );
  2897. mFunction->ReleaseLocationGeneric( &incrInfo );
  2898. }
  2899. mWriter.AsmBr( loopEntrance );
  2900. }
  2901. mWriter.MarkAsmJsLabel( continuePastLoop );
  2902. if( loopNode->emitLabels )
  2903. {
  2904. mWriter.MarkAsmJsLabel( loopNode->sxStmt.breakLabel );
  2905. }
  2906. mWriter.ExitLoop( loopId );
  2907. return EmitExpressionInfo( AsmJsType::Void );
  2908. }
  2909. EmitExpressionInfo AsmJSByteCodeGenerator::EmitQMark( ParseNode * pnode )
  2910. {
  2911. StartStatement(pnode->sxTri.pnode1);
  2912. Js::ByteCodeLabel trueLabel = mWriter.DefineLabel();
  2913. Js::ByteCodeLabel falseLabel = mWriter.DefineLabel();
  2914. Js::ByteCodeLabel skipLabel = mWriter.DefineLabel();
  2915. EndStatement(pnode->sxTri.pnode1);
  2916. const EmitExpressionInfo& boolInfo = EmitBooleanExpression( pnode->sxTri.pnode1, trueLabel, falseLabel );
  2917. mFunction->ReleaseLocationGeneric( &boolInfo );
  2918. RegSlot intReg = mFunction->AcquireTmpRegister<int>();
  2919. RegSlot doubleReg = mFunction->AcquireTmpRegister<double>();
  2920. RegSlot floatReg = mFunction->AcquireTmpRegister<float>();
  2921. EmitExpressionInfo emitInfo( AsmJsType::Void );
  2922. mWriter.MarkAsmJsLabel( trueLabel );
  2923. const EmitExpressionInfo& trueInfo = Emit( pnode->sxTri.pnode2 );
  2924. StartStatement(pnode->sxTri.pnode2);
  2925. if( trueInfo.type.isInt() )
  2926. {
  2927. mWriter.AsmReg2( Js::OpCodeAsmJs::Ld_Int, intReg, trueInfo.location );
  2928. mFunction->ReleaseLocation<int>( &trueInfo );
  2929. mFunction->ReleaseTmpRegister<double>(doubleReg);
  2930. mFunction->ReleaseTmpRegister<float>(floatReg);
  2931. emitInfo.location = intReg;
  2932. emitInfo.type = AsmJsType::Int;
  2933. }
  2934. else if( trueInfo.type.isDouble() )
  2935. {
  2936. mWriter.AsmReg2( Js::OpCodeAsmJs::Ld_Db, doubleReg, trueInfo.location );
  2937. mFunction->ReleaseLocation<double>( &trueInfo );
  2938. mFunction->ReleaseTmpRegister<int>( intReg );
  2939. mFunction->ReleaseTmpRegister<float>(floatReg);
  2940. emitInfo.location = doubleReg;
  2941. emitInfo.type = AsmJsType::Double;
  2942. }
  2943. else if (trueInfo.type.isFloat())
  2944. {
  2945. mWriter.AsmReg2(Js::OpCodeAsmJs::Ld_Flt, floatReg, trueInfo.location);
  2946. mFunction->ReleaseLocation<float>(&trueInfo);
  2947. mFunction->ReleaseTmpRegister<int>(intReg);
  2948. mFunction->ReleaseTmpRegister<double>(doubleReg);
  2949. emitInfo.location = floatReg;
  2950. emitInfo.type = AsmJsType::Float;
  2951. }
  2952. else
  2953. {
  2954. throw AsmJsCompilationException(_u("Conditional expressions must be of type int, double, or float"));
  2955. }
  2956. mWriter.AsmBr( skipLabel );
  2957. EndStatement(pnode->sxTri.pnode2);
  2958. mWriter.MarkAsmJsLabel( falseLabel );
  2959. const EmitExpressionInfo& falseInfo = Emit( pnode->sxTri.pnode3 );
  2960. StartStatement(pnode->sxTri.pnode3);
  2961. if( falseInfo.type.isInt() )
  2962. {
  2963. if( !trueInfo.type.isInt() )
  2964. {
  2965. throw AsmJsCompilationException( _u("Conditional expressions results must be the same type") );
  2966. }
  2967. mWriter.AsmReg2( Js::OpCodeAsmJs::Ld_Int, intReg, falseInfo.location );
  2968. mFunction->ReleaseLocation<int>( &falseInfo );
  2969. }
  2970. else if( falseInfo.type.isDouble() )
  2971. {
  2972. if( !trueInfo.type.isDouble() )
  2973. {
  2974. throw AsmJsCompilationException( _u("Conditional expressions results must be the same type") );
  2975. }
  2976. mWriter.AsmReg2( Js::OpCodeAsmJs::Ld_Db, doubleReg, falseInfo.location );
  2977. mFunction->ReleaseLocation<double>( &falseInfo );
  2978. }
  2979. else if(falseInfo.type.isFloat())
  2980. {
  2981. if (!trueInfo.type.isFloat())
  2982. {
  2983. throw AsmJsCompilationException(_u("Conditional expressions results must be the same type"));
  2984. }
  2985. mWriter.AsmReg2(Js::OpCodeAsmJs::Ld_Flt, floatReg, falseInfo.location);
  2986. mFunction->ReleaseLocation<float>(&falseInfo);
  2987. }
  2988. else
  2989. {
  2990. throw AsmJsCompilationException(_u("Conditional expressions must be of type int, double, or float"));
  2991. }
  2992. mWriter.MarkAsmJsLabel( skipLabel );
  2993. EndStatement(pnode->sxTri.pnode3);
  2994. return emitInfo;
  2995. }
  2996. EmitExpressionInfo AsmJSByteCodeGenerator::EmitSwitch( ParseNode * pnode )
  2997. {
  2998. BOOL fHasDefault = false;
  2999. Assert( pnode->sxSwitch.pnodeVal != NULL );
  3000. const EmitExpressionInfo& valInfo = Emit( pnode->sxSwitch.pnodeVal );
  3001. if( !valInfo.type.isSigned() )
  3002. {
  3003. throw AsmJsCompilationException( _u("Switch value must be type Signed, FixNum") );
  3004. }
  3005. RegSlot regVal = GetAndReleaseUnaryLocations<int>( &valInfo );
  3006. StartStatement(pnode);
  3007. mWriter.AsmReg2(OpCodeAsmJs::BeginSwitch_Int, regVal, valInfo.location);
  3008. EndStatement(pnode);
  3009. // TODO: if all cases are compile-time constants, emit a switch statement in the byte
  3010. // code so the BE can optimize it.
  3011. ParseNode *pnodeCase;
  3012. for( pnodeCase = pnode->sxSwitch.pnodeCases; pnodeCase; pnodeCase = pnodeCase->sxCase.pnodeNext )
  3013. {
  3014. // Jump to the first case body if this one doesn't match. Make sure any side-effects of the case
  3015. // expression take place regardless.
  3016. pnodeCase->sxCase.labelCase = mWriter.DefineLabel();
  3017. if( pnodeCase == pnode->sxSwitch.pnodeDefault )
  3018. {
  3019. fHasDefault = true;
  3020. continue;
  3021. }
  3022. ParseNode* caseExpr = pnodeCase->sxCase.pnodeExpr;
  3023. if ((caseExpr->nop != knopInt || (caseExpr->sxInt.lw >> 31) > 1) && !ParserWrapper::IsMinInt(caseExpr))
  3024. {
  3025. throw AsmJsCompilationException( _u("Switch case value must be int in the range [-2^31, 2^31)") );
  3026. }
  3027. const EmitExpressionInfo& caseExprInfo = Emit( pnodeCase->sxCase.pnodeExpr );
  3028. mWriter.AsmBrReg2( OpCodeAsmJs::Case_Int, pnodeCase->sxCase.labelCase, regVal, caseExprInfo.location );
  3029. // do not need to release location because int constants cannot be released
  3030. }
  3031. // No explicit case value matches. Jump to the default arm (if any) or break out altogether.
  3032. if( fHasDefault )
  3033. {
  3034. mWriter.AsmBr( pnode->sxSwitch.pnodeDefault->sxCase.labelCase, OpCodeAsmJs::EndSwitch_Int );
  3035. }
  3036. else
  3037. {
  3038. if( !pnode->emitLabels )
  3039. {
  3040. pnode->sxStmt.breakLabel = mWriter.DefineLabel();
  3041. }
  3042. mWriter.AsmBr( pnode->sxStmt.breakLabel, OpCodeAsmJs::EndSwitch_Int );
  3043. }
  3044. // Now emit the case arms to which we jump on matching a case value.
  3045. for( pnodeCase = pnode->sxSwitch.pnodeCases; pnodeCase; pnodeCase = pnodeCase->sxCase.pnodeNext )
  3046. {
  3047. mWriter.MarkAsmJsLabel( pnodeCase->sxCase.labelCase );
  3048. const EmitExpressionInfo& caseBodyInfo = Emit( pnodeCase->sxCase.pnodeBody );
  3049. mFunction->ReleaseLocationGeneric( &caseBodyInfo );
  3050. }
  3051. mFunction->ReleaseTmpRegister<int>( regVal );
  3052. if( !fHasDefault || pnode->emitLabels )
  3053. {
  3054. mWriter.MarkAsmJsLabel( pnode->sxStmt.breakLabel );
  3055. }
  3056. return EmitExpressionInfo( AsmJsType::Void );
  3057. }
  3058. void AsmJSByteCodeGenerator::EmitEmptyByteCode(FuncInfo * funcInfo, ByteCodeGenerator * byteCodeGen, ParseNode * functionNode)
  3059. {
  3060. funcInfo->byteCodeFunction->SetGrfscr(byteCodeGen->GetFlags());
  3061. funcInfo->byteCodeFunction->SetSourceInfo(byteCodeGen->GetCurrentSourceIndex(),
  3062. funcInfo->root,
  3063. !!(byteCodeGen->GetFlags() & fscrEvalCode),
  3064. ((byteCodeGen->GetFlags() & fscrDynamicCode) && !(byteCodeGen->GetFlags() & fscrEvalCode)));
  3065. FunctionBody * functionBody = funcInfo->byteCodeFunction->GetFunctionBody();
  3066. class AutoCleanup
  3067. {
  3068. private:
  3069. FunctionBody * mFunctionBody;
  3070. ByteCodeGenerator * mByteCodeGen;
  3071. public:
  3072. AutoCleanup(FunctionBody * functionBody, ByteCodeGenerator * byteCodeGen) : mFunctionBody(functionBody), mByteCodeGen(byteCodeGen)
  3073. {
  3074. }
  3075. void Done()
  3076. {
  3077. mFunctionBody = nullptr;
  3078. }
  3079. ~AutoCleanup()
  3080. {
  3081. if (mFunctionBody)
  3082. {
  3083. mFunctionBody->ResetByteCodeGenState();
  3084. mByteCodeGen->Writer()->Reset();
  3085. }
  3086. }
  3087. } autoCleanup(functionBody, byteCodeGen);
  3088. byteCodeGen->Writer()->Begin(byteCodeGen, functionBody, byteCodeGen->GetAllocator(), false, false);
  3089. byteCodeGen->Writer()->StartStatement(functionNode, 0);
  3090. byteCodeGen->Writer()->Empty(OpCode::Nop);
  3091. byteCodeGen->Writer()->EndStatement(functionNode);
  3092. byteCodeGen->Writer()->End();
  3093. autoCleanup.Done();
  3094. }
  3095. void AsmJSByteCodeGenerator::StartStatement(ParseNode* pnode)
  3096. {
  3097. mWriter.StartStatement(pnode, 0);
  3098. // Output::Print( _u("%*s+%d\n"),tab, " ", pnode->ichMin );
  3099. // ++tab;
  3100. }
  3101. void AsmJSByteCodeGenerator::EndStatement(ParseNode* pnode)
  3102. {
  3103. mWriter.EndStatement(pnode);
  3104. // Output::Print( _u("%*s-%d\n"),tab, " ", pnode->ichMin );
  3105. // --tab;
  3106. }
  3107. // int tab = 0;
  3108. void AsmJSByteCodeGenerator::LoadModuleInt( RegSlot dst, RegSlot index )
  3109. {
  3110. mWriter.AsmSlot(OpCodeAsmJs::LdSlot_Int, dst, AsmJsFunctionMemory::ModuleEnvRegister, index + (int32)(mCompiler->GetIntOffset() / INT_SLOTS_SPACE + 0.5));
  3111. }
  3112. void AsmJSByteCodeGenerator::LoadModuleFloat(RegSlot dst, RegSlot index)
  3113. {
  3114. mWriter.AsmSlot(OpCodeAsmJs::LdSlot_Flt, dst, AsmJsFunctionMemory::ModuleEnvRegister, index + (int32)(mCompiler->GetFloatOffset() / FLOAT_SLOTS_SPACE + 0.5));
  3115. }
  3116. void AsmJSByteCodeGenerator::LoadModuleDouble( RegSlot dst, RegSlot index )
  3117. {
  3118. mWriter.AsmSlot(OpCodeAsmJs::LdSlot_Db, dst, AsmJsFunctionMemory::ModuleEnvRegister, index + mCompiler->GetDoubleOffset() / DOUBLE_SLOTS_SPACE);
  3119. }
  3120. void AsmJSByteCodeGenerator::LoadModuleFFI( RegSlot dst, RegSlot index )
  3121. {
  3122. mWriter.AsmSlot(OpCodeAsmJs::LdSlot, dst, AsmJsFunctionMemory::ModuleEnvRegister, index + mCompiler->GetFFIOffset());
  3123. }
  3124. void AsmJSByteCodeGenerator::LoadModuleFunction( RegSlot dst, RegSlot index )
  3125. {
  3126. mWriter.AsmSlot(OpCodeAsmJs::LdSlot, dst, AsmJsFunctionMemory::ModuleEnvRegister, index + mCompiler->GetFuncOffset());
  3127. }
  3128. void AsmJSByteCodeGenerator::LoadModuleFunctionTable( RegSlot dst, RegSlot FuncTableIndex, RegSlot FuncIndexLocation )
  3129. {
  3130. mWriter.AsmSlot( OpCodeAsmJs::LdSlotArr, AsmJsFunctionMemory::ModuleSlotRegister, AsmJsFunctionMemory::ModuleEnvRegister, FuncTableIndex+mCompiler->GetFuncPtrOffset() );
  3131. mWriter.AsmSlot( OpCodeAsmJs::LdArr_Func, dst, AsmJsFunctionMemory::ModuleSlotRegister, FuncIndexLocation );
  3132. }
  3133. void AsmJSByteCodeGenerator::SetModuleInt( Js::RegSlot dst, RegSlot src )
  3134. {
  3135. mWriter.AsmSlot(OpCodeAsmJs::StSlot_Int, src, AsmJsFunctionMemory::ModuleEnvRegister, dst + (int32)(mCompiler->GetIntOffset() / INT_SLOTS_SPACE + 0.5));
  3136. }
  3137. void AsmJSByteCodeGenerator::SetModuleFloat(Js::RegSlot dst, RegSlot src)
  3138. {
  3139. mWriter.AsmSlot(OpCodeAsmJs::StSlot_Flt, src, AsmJsFunctionMemory::ModuleEnvRegister, dst + (int32)(mCompiler->GetFloatOffset() / FLOAT_SLOTS_SPACE + 0.5));
  3140. }
  3141. void AsmJSByteCodeGenerator::SetModuleDouble( Js::RegSlot dst, RegSlot src )
  3142. {
  3143. mWriter.AsmSlot(OpCodeAsmJs::StSlot_Db, src, AsmJsFunctionMemory::ModuleEnvRegister, dst + mCompiler->GetDoubleOffset() / DOUBLE_SLOTS_SPACE);
  3144. }
  3145. void AsmJSByteCodeGenerator::LoadModuleSimd(RegSlot dst, RegSlot index, AsmJsVarType type)
  3146. {
  3147. OpCodeAsmJs opcode = OpCodeAsmJs::Simd128_LdSlot_I4;
  3148. switch (type.which())
  3149. {
  3150. case AsmJsVarType::Int32x4:
  3151. break;
  3152. case AsmJsVarType::Bool32x4:
  3153. opcode = OpCodeAsmJs::Simd128_LdSlot_B4;
  3154. break;
  3155. case AsmJsVarType::Bool16x8:
  3156. opcode = OpCodeAsmJs::Simd128_LdSlot_B8;
  3157. break;
  3158. case AsmJsVarType::Bool8x16:
  3159. opcode = OpCodeAsmJs::Simd128_LdSlot_B16;
  3160. break;
  3161. case AsmJsVarType::Float32x4:
  3162. opcode = OpCodeAsmJs::Simd128_LdSlot_F4;
  3163. break;
  3164. #if 0
  3165. case AsmJsVarType::Float64x2:
  3166. opcode = OpCodeAsmJs::Simd128_LdSlot_D2;
  3167. break;
  3168. #endif // 0
  3169. case AsmJsVarType::Int16x8:
  3170. opcode = OpCodeAsmJs::Simd128_LdSlot_I8;
  3171. break;
  3172. case AsmJsVarType::Int8x16:
  3173. opcode = OpCodeAsmJs::Simd128_LdSlot_I16;
  3174. break;
  3175. case AsmJsVarType::Uint32x4:
  3176. opcode = OpCodeAsmJs::Simd128_LdSlot_U4;
  3177. break;
  3178. case AsmJsVarType::Uint16x8:
  3179. opcode = OpCodeAsmJs::Simd128_LdSlot_U8;
  3180. break;
  3181. case AsmJsVarType::Uint8x16:
  3182. opcode = OpCodeAsmJs::Simd128_LdSlot_U16;
  3183. break;
  3184. default:
  3185. Assert(UNREACHED);
  3186. }
  3187. mWriter.AsmSlot(opcode, dst, AsmJsFunctionMemory::ModuleEnvRegister, index + mCompiler->GetSimdOffset());
  3188. }
  3189. void AsmJSByteCodeGenerator::SetModuleSimd(RegSlot index, RegSlot src, AsmJsVarType type)
  3190. {
  3191. OpCodeAsmJs opcode = OpCodeAsmJs::Simd128_StSlot_I4;
  3192. switch (type.which())
  3193. {
  3194. case AsmJsVarType::Int32x4:
  3195. break;
  3196. case AsmJsVarType::Bool32x4:
  3197. opcode = OpCodeAsmJs::Simd128_StSlot_B4;
  3198. break;
  3199. case AsmJsVarType::Bool16x8:
  3200. opcode = OpCodeAsmJs::Simd128_StSlot_B8;
  3201. break;
  3202. case AsmJsVarType::Bool8x16:
  3203. opcode = OpCodeAsmJs::Simd128_StSlot_B16;
  3204. break;
  3205. case AsmJsVarType::Float32x4:
  3206. opcode = OpCodeAsmJs::Simd128_StSlot_F4;
  3207. break;
  3208. #if 0
  3209. case AsmJsVarType::Float64x2:
  3210. opcode = OpCodeAsmJs::Simd128_StSlot_D2;
  3211. break;
  3212. #endif // 0
  3213. case AsmJsVarType::Int16x8:
  3214. opcode = OpCodeAsmJs::Simd128_StSlot_I8;
  3215. break;
  3216. case AsmJsVarType::Int8x16:
  3217. opcode = OpCodeAsmJs::Simd128_StSlot_I16;
  3218. break;
  3219. case AsmJsVarType::Uint32x4:
  3220. opcode = OpCodeAsmJs::Simd128_StSlot_U4;
  3221. break;
  3222. case AsmJsVarType::Uint16x8:
  3223. opcode = OpCodeAsmJs::Simd128_StSlot_U8;
  3224. break;
  3225. case AsmJsVarType::Uint8x16:
  3226. opcode = OpCodeAsmJs::Simd128_StSlot_U16;
  3227. break;
  3228. default:
  3229. Assert(UNREACHED);
  3230. }
  3231. mWriter.AsmSlot(opcode, src, AsmJsFunctionMemory::ModuleEnvRegister, index + mCompiler->GetSimdOffset());
  3232. }
  3233. void AsmJSByteCodeGenerator::LoadSimd(RegSlot dst, RegSlot src, AsmJsVarType type)
  3234. {
  3235. OpCodeAsmJs opcode = OpCodeAsmJs::Simd128_Ld_I4;
  3236. switch (type.which())
  3237. {
  3238. case AsmJsVarType::Int32x4:
  3239. break;
  3240. case AsmJsVarType::Bool32x4:
  3241. opcode = OpCodeAsmJs::Simd128_Ld_B4;
  3242. break;
  3243. case AsmJsVarType::Bool16x8:
  3244. opcode = OpCodeAsmJs::Simd128_Ld_B8;
  3245. break;
  3246. case AsmJsVarType::Bool8x16:
  3247. opcode = OpCodeAsmJs::Simd128_Ld_B16;
  3248. break;
  3249. case AsmJsVarType::Float32x4:
  3250. opcode = OpCodeAsmJs::Simd128_Ld_F4;
  3251. break;
  3252. #if 0
  3253. case AsmJsVarType::Float64x2:
  3254. opcode = OpCodeAsmJs::Simd128_Ld_D2;
  3255. break;
  3256. #endif // 0
  3257. case AsmJsVarType::Int16x8:
  3258. opcode = OpCodeAsmJs::Simd128_Ld_I8;
  3259. break;
  3260. case AsmJsVarType::Int8x16:
  3261. opcode = OpCodeAsmJs::Simd128_Ld_I16;
  3262. break;
  3263. case AsmJsVarType::Uint32x4:
  3264. opcode = OpCodeAsmJs::Simd128_Ld_U4;
  3265. break;
  3266. case AsmJsVarType::Uint16x8:
  3267. opcode = OpCodeAsmJs::Simd128_Ld_U8;
  3268. break;
  3269. case AsmJsVarType::Uint8x16:
  3270. opcode = OpCodeAsmJs::Simd128_Ld_U16;
  3271. break;
  3272. default:
  3273. Assert(UNREACHED);
  3274. }
  3275. mWriter.AsmReg2(opcode, dst, src);
  3276. }
  3277. void AsmJsFunctionCompilation::CleanUp()
  3278. {
  3279. if( mGenerator && mGenerator->mInfo )
  3280. {
  3281. FunctionBody* body = mGenerator->mFunction->GetFuncBody();
  3282. if( body )
  3283. {
  3284. body->ResetByteCodeGenState();
  3285. }
  3286. mGenerator->mWriter.Reset();
  3287. }
  3288. }
  3289. }
  3290. #endif