AsmJSBytecodeGenerator.cpp 132 KB

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