AsmJs.cpp 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. // Portions of this file are copyright 2014 Mozilla Foundation, available under the Apache 2.0 license.
  5. //-------------------------------------------------------------------------------------------------------
  6. //-------------------------------------------------------------------------------------------------------
  7. // Copyright 2014 Mozilla Foundation
  8. //
  9. // Licensed under the Apache License, Version 2.0 (the "License");
  10. // you may not use this file except in compliance with the License.
  11. // You may obtain a copy of the License at
  12. //
  13. // http ://www.apache.org/licenses/LICENSE-2.0
  14. //
  15. // Unless required by applicable law or agreed to in writing, software
  16. // distributed under the License is distributed on an "AS IS" BASIS,
  17. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. // See the License for the specific language governing permissions and
  19. // limitations under the License.
  20. //-------------------------------------------------------------------------------------------------------
  21. #include "RuntimeLanguagePch.h"
  22. #ifdef ASMJS_PLAT
  23. #include "ByteCode/Symbol.h"
  24. #include "ByteCode/FuncInfo.h"
  25. #include "ByteCode/ByteCodeWriter.h"
  26. #include "ByteCode/ByteCodeGenerator.h"
  27. namespace Js
  28. {
  29. bool
  30. AsmJSCompiler::CheckIdentifier(AsmJsModuleCompiler &m, ParseNode *usepn, PropertyName name)
  31. {
  32. if (name == m.GetParser()->names()->arguments || name == m.GetParser()->names()->eval)
  33. {
  34. return m.FailName(usepn, _u("'%s' is not an allowed identifier"), name);
  35. }
  36. return true;
  37. }
  38. bool
  39. AsmJSCompiler::CheckModuleLevelName(AsmJsModuleCompiler &m, ParseNode *usepn, PropertyName name)
  40. {
  41. if (!CheckIdentifier(m, usepn, name))
  42. {
  43. return false;
  44. }
  45. if (name == m.GetModuleFunctionName())
  46. {
  47. return m.FailName(usepn, _u("duplicate name '%s' not allowed"), name);
  48. }
  49. //Check for all the duplicates here.
  50. return true;
  51. }
  52. bool
  53. AsmJSCompiler::CheckFunctionHead(AsmJsModuleCompiler &m, ParseNode *fn, bool isGlobal /*= true*/)
  54. {
  55. ParseNodeFnc * fnc = fn->AsParseNodeFnc();
  56. if (fnc->HasNonSimpleParameterList())
  57. {
  58. return m.Fail(fn, _u("default, rest & destructuring args not allowed"));
  59. }
  60. if (fnc->IsStaticMember())
  61. {
  62. return m.Fail(fn, _u("static functions are not allowed"));
  63. }
  64. if (fnc->IsGenerator())
  65. {
  66. return m.Fail(fn, _u("generator functions are not allowed"));
  67. }
  68. if (fnc->IsAsync())
  69. {
  70. return m.Fail(fn, _u("async functions are not allowed"));
  71. }
  72. if (fnc->IsLambda())
  73. {
  74. return m.Fail(fn, _u("lambda functions are not allowed"));
  75. }
  76. if (!isGlobal && fnc->nestedCount != 0)
  77. {
  78. return m.Fail(fn, _u("closure functions are not allowed"));
  79. }
  80. if (!fnc->IsAsmJsAllowed())
  81. {
  82. return m.Fail(fn, _u("invalid function flags detected"));
  83. }
  84. return true;
  85. }
  86. bool AsmJSCompiler::CheckTypeAnnotation( AsmJsModuleCompiler &m, ParseNode *coercionNode, AsmJSCoercion *coercion,
  87. ParseNode **coercedExpr /*= nullptr */)
  88. {
  89. switch( coercionNode->nop )
  90. {
  91. case knopRsh:
  92. case knopLsh:
  93. case knopXor:
  94. case knopAnd:
  95. case knopOr: {
  96. ParseNode *rhs = ParserWrapper::GetBinaryRight( coercionNode );
  97. *coercion = AsmJS_ToInt32;
  98. if( coercedExpr )
  99. {
  100. if( rhs->nop == knopInt && rhs->AsParseNodeInt()->lw == 0 )
  101. {
  102. if( rhs->nop == knopAnd )
  103. {
  104. // X & 0 == 0;
  105. *coercedExpr = rhs;
  106. }
  107. else
  108. {
  109. // (X|0) == (X^0) == (X<<0) == (X>>0) == X
  110. *coercedExpr = ParserWrapper::GetBinaryLeft( coercionNode );
  111. }
  112. }
  113. else
  114. {
  115. *coercedExpr = coercionNode;
  116. }
  117. }
  118. return true;
  119. }
  120. case knopPos: {
  121. *coercion = AsmJS_ToNumber;
  122. if( coercedExpr )
  123. {
  124. *coercedExpr = ParserWrapper::GetUnaryNode( coercionNode );
  125. }
  126. return true;
  127. }
  128. case knopCall: {
  129. ParseNode* target;
  130. AsmJsFunctionDeclaration* sym;
  131. target = coercionNode->AsParseNodeCall()->pnodeTarget;
  132. if (!target || target->nop != knopName)
  133. {
  134. return m.Fail(coercionNode, _u("Call must be of the form id(...)"));
  135. }
  136. *coercion = AsmJS_FRound;
  137. sym = m.LookupFunction(target->name());
  138. if (!AsmJsMathFunction::IsFround(sym))
  139. {
  140. return m.Fail( coercionNode, _u("call must be to fround coercion") );
  141. }
  142. if( coercedExpr )
  143. {
  144. *coercedExpr = coercionNode->AsParseNodeCall()->pnodeArgs;
  145. }
  146. return true;
  147. }
  148. case knopInt:{
  149. *coercion = AsmJS_ToInt32;
  150. if( coercedExpr )
  151. {
  152. *coercedExpr = coercionNode;
  153. }
  154. return true;
  155. }
  156. case knopFlt:{
  157. if (ParserWrapper::IsMinInt(coercionNode))
  158. {
  159. *coercion = AsmJS_ToInt32;
  160. }
  161. else if (coercionNode->AsParseNodeFloat()->maybeInt)
  162. {
  163. return m.Fail(coercionNode, _u("Integer literal in return must be in range [-2^31, 2^31)"));
  164. }
  165. else
  166. {
  167. *coercion = AsmJS_ToNumber;
  168. }
  169. if( coercedExpr )
  170. {
  171. *coercedExpr = coercionNode ;
  172. }
  173. return true;
  174. }
  175. case knopName:{
  176. // in this case we are returning a constant var from the global scope
  177. AsmJsSymbol * constSymSource = m.LookupIdentifier(coercionNode->name());
  178. if (!constSymSource)
  179. {
  180. return m.Fail(coercionNode, _u("Identifier not globally declared"));
  181. }
  182. if (!AsmJsVar::Is(constSymSource) || constSymSource->isMutable())
  183. {
  184. return m.Fail(coercionNode, _u("Unannotated variables must be constant"));
  185. }
  186. AsmJsVar * constSrc = AsmJsVar::FromSymbol(constSymSource);
  187. if (constSrc->GetType().isSigned())
  188. {
  189. *coercion = AsmJS_ToInt32;
  190. }
  191. else if (constSrc->GetType().isDouble())
  192. {
  193. *coercion = AsmJS_ToNumber;
  194. }
  195. else
  196. {
  197. Assert(constSrc->GetType().isFloat());
  198. *coercion = AsmJS_FRound;
  199. }
  200. if (coercedExpr)
  201. {
  202. *coercedExpr = coercionNode;
  203. }
  204. return true;
  205. }
  206. default:;
  207. }
  208. return m.Fail( coercionNode, _u("must be of the form +x, fround(x) or x|0") );
  209. }
  210. bool
  211. AsmJSCompiler::CheckModuleArgument(AsmJsModuleCompiler &m, ParseNode *arg, PropertyName *name, AsmJsModuleArg::ArgType type)
  212. {
  213. if (!ParserWrapper::IsDefinition(arg))
  214. {
  215. return m.Fail(arg, _u("duplicate argument name not allowed"));
  216. }
  217. if (!CheckIdentifier(m, arg, arg->name()))
  218. {
  219. return false;
  220. }
  221. *name = arg->name();
  222. m.GetByteCodeGenerator()->AssignPropertyId(*name);
  223. AsmJsModuleArg * moduleArg = Anew(m.GetAllocator(), AsmJsModuleArg, *name, type);
  224. if (!m.DefineIdentifier(*name, moduleArg))
  225. {
  226. return m.Fail(arg, _u("duplicate argument name not allowed"));
  227. }
  228. if (!CheckModuleLevelName(m, arg, *name))
  229. {
  230. return false;
  231. }
  232. return true;
  233. }
  234. bool
  235. AsmJSCompiler::CheckModuleArguments(AsmJsModuleCompiler &m, ParseNode *fn)
  236. {
  237. ArgSlot numFormals = 0;
  238. ParseNode *arg1 = ParserWrapper::FunctionArgsList( fn, numFormals );
  239. ParseNode *arg2 = arg1 ? ParserWrapper::NextVar( arg1 ) : nullptr;
  240. ParseNode *arg3 = arg2 ? ParserWrapper::NextVar( arg2 ) : nullptr;
  241. if (numFormals > 3)
  242. {
  243. return m.Fail(fn, _u("asm.js modules takes at most 3 argument"));
  244. }
  245. PropertyName arg1Name = nullptr;
  246. if (numFormals >= 1 && !CheckModuleArgument(m, arg1, &arg1Name, AsmJsModuleArg::ArgType::StdLib))
  247. {
  248. return false;
  249. }
  250. m.InitStdLibArgName(arg1Name);
  251. PropertyName arg2Name = nullptr;
  252. if (numFormals >= 2 && !CheckModuleArgument(m, arg2, &arg2Name, AsmJsModuleArg::ArgType::Import))
  253. {
  254. return false;
  255. }
  256. m.InitForeignArgName(arg2Name);
  257. PropertyName arg3Name = nullptr;
  258. if (numFormals >= 3 && !CheckModuleArgument(m, arg3, &arg3Name, AsmJsModuleArg::ArgType::Heap))
  259. {
  260. return false;
  261. }
  262. m.InitBufferArgName(arg3Name);
  263. return true;
  264. }
  265. bool AsmJSCompiler::CheckGlobalVariableImportExpr( AsmJsModuleCompiler &m, PropertyName varName, AsmJSCoercion coercion, ParseNode *coercedExpr )
  266. {
  267. if( !ParserWrapper::IsDotMember(coercedExpr) )
  268. {
  269. return m.FailName( coercedExpr, _u("invalid import expression for global '%s'"), varName );
  270. }
  271. ParseNode *base = ParserWrapper::DotBase(coercedExpr);
  272. PropertyName field = ParserWrapper::DotMember(coercedExpr);
  273. PropertyName importName = m.GetForeignArgName();
  274. if (!importName || !field)
  275. {
  276. return m.Fail(coercedExpr, _u("cannot import without an asm.js foreign parameter"));
  277. }
  278. m.GetByteCodeGenerator()->AssignPropertyId(field);
  279. if ((base->name() != importName))
  280. {
  281. return m.FailName(coercedExpr, _u("base of import expression must be '%s'"), importName);
  282. }
  283. return m.AddGlobalVarImport(varName, field, coercion);
  284. }
  285. bool AsmJSCompiler::CheckGlobalVariableInitImport( AsmJsModuleCompiler &m, PropertyName varName, ParseNode *initNode, bool isMutable /*= true*/)
  286. {
  287. AsmJSCoercion coercion;
  288. ParseNode *coercedExpr = nullptr;
  289. if( !CheckTypeAnnotation( m, initNode, &coercion, &coercedExpr ) )
  290. {
  291. return false;
  292. }
  293. if ((ParserWrapper::IsFroundNumericLiteral(coercedExpr)) && coercion == AsmJSCoercion::AsmJS_FRound)
  294. {
  295. return m.AddNumericVar(varName, coercedExpr, true, isMutable);
  296. }
  297. return CheckGlobalVariableImportExpr( m, varName, coercion, coercedExpr );
  298. }
  299. bool AsmJSCompiler::CheckNewArrayView( AsmJsModuleCompiler &m, PropertyName varName, ParseNode *newExpr )
  300. {
  301. Assert( newExpr->nop == knopNew );
  302. m.SetUsesHeapBuffer(true);
  303. ParseNode *ctorExpr = newExpr->AsParseNodeCall()->pnodeTarget;
  304. ArrayBufferView::ViewType type;
  305. if( ParserWrapper::IsDotMember(ctorExpr) )
  306. {
  307. ParseNode *base = ParserWrapper::DotBase(ctorExpr);
  308. PropertyName globalName = m.GetStdLibArgName();
  309. if (!globalName)
  310. {
  311. return m.Fail(base, _u("cannot create array view without an asm.js global parameter"));
  312. }
  313. if (!ParserWrapper::IsNameDeclaration(base) || base->name() != globalName)
  314. {
  315. return m.FailName(base, _u("expecting '%s.*Array"), globalName);
  316. }
  317. PropertyName fieldName = ParserWrapper::DotMember(ctorExpr);
  318. if (!fieldName)
  319. {
  320. return m.FailName(ctorExpr, _u("Failed to define array view to var %s"), varName);
  321. }
  322. PropertyId field = fieldName->GetPropertyId();
  323. switch (field)
  324. {
  325. case PropertyIds::Int8Array:
  326. type = ArrayBufferView::TYPE_INT8;
  327. m.AddArrayBuiltinUse(AsmJSTypedArrayBuiltin_Int8Array);
  328. break;
  329. case PropertyIds::Uint8Array:
  330. type = ArrayBufferView::TYPE_UINT8;
  331. m.AddArrayBuiltinUse(AsmJSTypedArrayBuiltin_Uint8Array);
  332. break;
  333. case PropertyIds::Int16Array:
  334. type = ArrayBufferView::TYPE_INT16;
  335. m.AddArrayBuiltinUse(AsmJSTypedArrayBuiltin_Int16Array);
  336. break;
  337. case PropertyIds::Uint16Array:
  338. type = ArrayBufferView::TYPE_UINT16;
  339. m.AddArrayBuiltinUse(AsmJSTypedArrayBuiltin_Uint16Array);
  340. break;
  341. case PropertyIds::Int32Array:
  342. type = ArrayBufferView::TYPE_INT32;
  343. m.AddArrayBuiltinUse(AsmJSTypedArrayBuiltin_Int32Array);
  344. break;
  345. case PropertyIds::Uint32Array:
  346. type = ArrayBufferView::TYPE_UINT32;
  347. m.AddArrayBuiltinUse(AsmJSTypedArrayBuiltin_Uint32Array);
  348. break;
  349. case PropertyIds::Float32Array:
  350. type = ArrayBufferView::TYPE_FLOAT32;
  351. m.AddArrayBuiltinUse(AsmJSTypedArrayBuiltin_Float32Array);
  352. break;
  353. case PropertyIds::Float64Array:
  354. type = ArrayBufferView::TYPE_FLOAT64;
  355. m.AddArrayBuiltinUse(AsmJSTypedArrayBuiltin_Float64Array);
  356. break;
  357. default:
  358. return m.Fail(ctorExpr, _u("could not match typed array name"));
  359. break;
  360. }
  361. }
  362. else if (ctorExpr->nop == knopName)
  363. {
  364. AsmJsSymbol * buffFunc = m.LookupIdentifier(ctorExpr->name());
  365. if (!AsmJsTypedArrayFunction::Is(buffFunc))
  366. {
  367. return m.Fail(ctorExpr, _u("invalid 'new' import"));
  368. }
  369. type = AsmJsTypedArrayFunction::FromSymbol(buffFunc)->GetViewType();
  370. if (type == ArrayBufferView::TYPE_COUNT)
  371. {
  372. return m.Fail(ctorExpr, _u("could not match typed array name"));
  373. }
  374. }
  375. else
  376. {
  377. return m.Fail(newExpr, _u("invalid 'new' import"));
  378. }
  379. ParseNode *bufArg = newExpr->AsParseNodeCall()->pnodeArgs;
  380. if( !bufArg || !ParserWrapper::IsNameDeclaration( bufArg ) )
  381. {
  382. return m.Fail( ctorExpr, _u("array view constructor takes exactly one argument") );
  383. }
  384. PropertyName bufferName = m.GetBufferArgName();
  385. if( !bufferName )
  386. {
  387. return m.Fail( bufArg, _u("cannot create array view without an asm.js heap parameter") );
  388. }
  389. if( bufferName != bufArg->name() )
  390. {
  391. return m.FailName( bufArg, _u("argument to array view constructor must be '%s'"), bufferName );
  392. }
  393. if( !m.AddArrayView( varName, type ) )
  394. {
  395. return m.FailName( ctorExpr, _u("Failed to define array view to var %s"), varName );
  396. }
  397. return true;
  398. }
  399. bool
  400. AsmJSCompiler::CheckGlobalDotImport(AsmJsModuleCompiler &m, PropertyName varName, ParseNode *initNode)
  401. {
  402. ParseNode *base = ParserWrapper::DotBase(initNode);
  403. PropertyName field = ParserWrapper::DotMember(initNode);
  404. if( !field )
  405. {
  406. return m.Fail( initNode, _u("Global import must be in the form c.x where c is stdlib or foreign and x is a string literal") );
  407. }
  408. m.GetByteCodeGenerator()->AssignPropertyId(field);
  409. PropertyName lib = nullptr;
  410. if (ParserWrapper::IsDotMember(base))
  411. {
  412. lib = ParserWrapper::DotMember(base);
  413. base = ParserWrapper::DotBase(base);
  414. if (!lib || lib->GetPropertyId() != PropertyIds::Math)
  415. {
  416. return m.FailName(initNode, _u("'%s' should be Math, as in global.Math.xxxx"), field);
  417. }
  418. }
  419. if( ParserWrapper::IsNameDeclaration(base) && base->name() == m.GetStdLibArgName() )
  420. {
  421. // global.Math.xxx
  422. MathBuiltin mathBuiltin;
  423. if (m.LookupStandardLibraryMathName(field, &mathBuiltin))
  424. {
  425. switch (mathBuiltin.kind)
  426. {
  427. case MathBuiltin::Function:{
  428. auto func = mathBuiltin.u.func;
  429. if (func->GetName() != nullptr)
  430. {
  431. OutputMessage(m.GetScriptContext(), DEIT_ASMJS_FAILED, _u("Warning: Math Builtin already defined for var %s"), func->GetName()->Psz());
  432. }
  433. func->SetName(varName);
  434. if (!m.DefineIdentifier(varName, func))
  435. {
  436. return m.FailName(initNode, _u("Failed to define math builtin function to var %s"), varName);
  437. }
  438. m.AddMathBuiltinUse(func->GetMathBuiltInFunction());
  439. }
  440. break;
  441. case MathBuiltin::Constant:
  442. if (!m.AddNumericConst(varName, mathBuiltin.u.cst))
  443. {
  444. return m.FailName(initNode, _u("Failed to define math constant to var %s"), varName);
  445. }
  446. m.AddMathBuiltinUse(mathBuiltin.mathLibFunctionName);
  447. break;
  448. default:
  449. Assume(UNREACHED);
  450. }
  451. return true;
  452. }
  453. TypedArrayBuiltin arrayBuiltin;
  454. if (m.LookupStandardLibraryArrayName(field, &arrayBuiltin))
  455. {
  456. if (arrayBuiltin.mFunc->GetName() != nullptr)
  457. {
  458. OutputMessage(m.GetScriptContext(), DEIT_ASMJS_FAILED, _u("Warning: Typed array builtin already defined for var %s"), arrayBuiltin.mFunc->GetName()->Psz());
  459. }
  460. arrayBuiltin.mFunc->SetName(varName);
  461. if (!m.DefineIdentifier(varName, arrayBuiltin.mFunc))
  462. {
  463. return m.FailName(initNode, _u("Failed to define typed array builtin function to var %s"), varName);
  464. }
  465. m.AddArrayBuiltinUse(arrayBuiltin.mFunc->GetArrayBuiltInFunction());
  466. return true;
  467. }
  468. return m.FailName(initNode, _u("'%s' is not a standard Math builtin"), field);
  469. }
  470. else if( ParserWrapper::IsNameDeclaration(base) && base->name() == m.GetForeignArgName() )
  471. {
  472. // foreign import
  473. return m.AddModuleFunctionImport( varName, field );
  474. }
  475. return m.Fail(initNode, _u("expecting c.y where c is either the global or foreign parameter"));
  476. }
  477. bool
  478. AsmJSCompiler::CheckModuleGlobal(AsmJsModuleCompiler &m, ParseNode *var)
  479. {
  480. Assert(var->nop == knopVarDecl || var->nop == knopConstDecl);
  481. bool isMutable = var->nop != knopConstDecl;
  482. PropertyName name = var->name();
  483. m.GetByteCodeGenerator()->AssignPropertyId(name);
  484. if (m.LookupIdentifier(name))
  485. {
  486. return m.FailName(var, _u("import variable %s names must be unique"), name);
  487. }
  488. if (!CheckModuleLevelName(m, var, name))
  489. {
  490. return false;
  491. }
  492. if (!var->AsParseNodeVar()->pnodeInit)
  493. {
  494. return m.Fail(var, _u("module import needs initializer"));
  495. }
  496. ParseNode *initNode = var->AsParseNodeVar()->pnodeInit;
  497. if( ParserWrapper::IsNumericLiteral( initNode ) )
  498. {
  499. if (m.AddNumericVar(name, initNode, false, isMutable))
  500. {
  501. return true;
  502. }
  503. else
  504. {
  505. return m.FailName(var, _u("Failed to declare numeric var %s"), name);
  506. }
  507. }
  508. if (initNode->nop == knopOr || initNode->nop == knopPos || initNode->nop == knopCall)
  509. {
  510. return CheckGlobalVariableInitImport(m, name, initNode, isMutable );
  511. }
  512. if( initNode->nop == knopNew )
  513. {
  514. return CheckNewArrayView(m, var->name(), initNode);
  515. }
  516. if (ParserWrapper::IsDotMember(initNode))
  517. {
  518. return CheckGlobalDotImport(m, name, initNode);
  519. }
  520. return m.Fail( initNode, _u("Failed to recognize global variable") );
  521. }
  522. bool
  523. AsmJSCompiler::CheckModuleGlobals(AsmJsModuleCompiler &m)
  524. {
  525. ParseNode *varStmts;
  526. if( !ParserWrapper::ParseVarOrConstStatement( m.GetCurrentParserNode(), &varStmts ) )
  527. {
  528. return false;
  529. }
  530. if (!varStmts)
  531. {
  532. return true;
  533. }
  534. while (varStmts->nop == knopList)
  535. {
  536. ParseNode * pnode = ParserWrapper::GetBinaryLeft(varStmts);
  537. while (pnode && pnode->nop != knopEndCode)
  538. {
  539. ParseNode * decl;
  540. if (pnode->nop == knopList)
  541. {
  542. decl = ParserWrapper::GetBinaryLeft(pnode);
  543. pnode = ParserWrapper::GetBinaryRight(pnode);
  544. }
  545. else
  546. {
  547. decl = pnode;
  548. pnode = nullptr;
  549. }
  550. if (decl->nop == knopFncDecl)
  551. {
  552. goto varDeclEnd;
  553. }
  554. else if (decl->nop != knopConstDecl && decl->nop != knopVarDecl)
  555. {
  556. goto varDeclEnd;
  557. }
  558. if (decl->AsParseNodeVar()->pnodeInit && decl->AsParseNodeVar()->pnodeInit->nop == knopArray)
  559. {
  560. // Assume we reached func tables
  561. goto varDeclEnd;
  562. }
  563. if (!CheckModuleGlobal(m, decl))
  564. {
  565. return false;
  566. }
  567. }
  568. if (ParserWrapper::GetBinaryRight(varStmts)->nop == knopEndCode)
  569. {
  570. // this is an error condition, but CheckFunctionsSequential will figure it out
  571. goto varDeclEnd;
  572. }
  573. varStmts = ParserWrapper::GetBinaryRight(varStmts);
  574. }
  575. varDeclEnd:
  576. // we will collect information on the function tables now and come back to the functions themselves afterwards,
  577. // because function table information is used when processing function bodies
  578. ParseNode * fnNodes = varStmts;
  579. while (fnNodes->nop != knopEndCode && ParserWrapper::GetBinaryLeft(fnNodes)->nop == knopFncDecl)
  580. {
  581. fnNodes = ParserWrapper::GetBinaryRight(fnNodes);
  582. }
  583. if (fnNodes->nop == knopEndCode)
  584. {
  585. // if there are no function tables, we can just initialize count to 0
  586. m.SetFuncPtrTableCount(0);
  587. }
  588. else
  589. {
  590. m.SetCurrentParseNode(fnNodes);
  591. if (!CheckFunctionTables(m))
  592. {
  593. return false;
  594. }
  595. }
  596. // this will move us back to the beginning of the function declarations
  597. m.SetCurrentParseNode(varStmts);
  598. return true;
  599. }
  600. bool AsmJSCompiler::CheckFunction( AsmJsModuleCompiler &m, ParseNodeFnc * fncNode )
  601. {
  602. Assert( fncNode->nop == knopFncDecl );
  603. if( PHASE_TRACE1( Js::ByteCodePhase ) )
  604. {
  605. Output::Print( _u(" Checking Asm function: %s\n"), fncNode->funcInfo->name);
  606. }
  607. if( !CheckFunctionHead( m, fncNode, false ) )
  608. {
  609. return false;
  610. }
  611. AsmJsFunc* func = m.CreateNewFunctionEntry(fncNode);
  612. if (!func)
  613. {
  614. return m.Fail(fncNode, _u(" Error creating function entry"));
  615. }
  616. return true;
  617. }
  618. bool AsmJSCompiler::CheckFunctionsSequential( AsmJsModuleCompiler &m )
  619. {
  620. AsmJSParser& list = m.GetCurrentParserNode();
  621. Assert( list->nop == knopList );
  622. ParseNode* pnode = ParserWrapper::GetBinaryLeft(list);
  623. while (pnode->nop == knopFncDecl)
  624. {
  625. if( !CheckFunction( m, pnode->AsParseNodeFnc() ) )
  626. {
  627. return false;
  628. }
  629. if(ParserWrapper::GetBinaryRight(list)->nop == knopEndCode)
  630. {
  631. break;
  632. }
  633. list = ParserWrapper::GetBinaryRight(list);
  634. pnode = ParserWrapper::GetBinaryLeft(list);
  635. }
  636. m.SetCurrentParseNode( list );
  637. return true;
  638. }
  639. bool AsmJSCompiler::CheckFunctionTables(AsmJsModuleCompiler &m)
  640. {
  641. AsmJSParser& list = m.GetCurrentParserNode();
  642. Assert(list->nop == knopList);
  643. int32 funcPtrTableCount = 0;
  644. while (list->nop != knopEndCode)
  645. {
  646. ParseNode * varStmt = ParserWrapper::GetBinaryLeft(list);
  647. if (varStmt->nop != knopConstDecl && varStmt->nop != knopVarDecl)
  648. {
  649. break;
  650. }
  651. if (!varStmt->AsParseNodeVar()->pnodeInit || varStmt->AsParseNodeVar()->pnodeInit->nop != knopArray)
  652. {
  653. break;
  654. }
  655. const uint tableSize = varStmt->AsParseNodeVar()->pnodeInit->AsParseNodeArrLit()->count;
  656. if (!::Math::IsPow2(tableSize))
  657. {
  658. return m.FailName(varStmt, _u("Function table [%s] size must be a power of 2"), varStmt->name());
  659. }
  660. if (!m.AddFunctionTable(varStmt->name(), tableSize))
  661. {
  662. return m.FailName(varStmt, _u("Unable to create new function table %s"), varStmt->name());
  663. }
  664. AsmJsFunctionTable* ftable = (AsmJsFunctionTable*)m.LookupIdentifier(varStmt->name());
  665. Assert(ftable);
  666. ParseNode* pnode = varStmt->AsParseNodeVar()->pnodeInit->AsParseNodeArrLit()->pnode1;
  667. if (pnode->nop == knopList)
  668. {
  669. pnode = ParserWrapper::GetBinaryLeft(pnode);
  670. }
  671. if (!ParserWrapper::IsNameDeclaration(pnode))
  672. {
  673. return m.FailName(pnode, _u("Invalid element in function table %s"), varStmt->name());
  674. }
  675. ++funcPtrTableCount;
  676. list = ParserWrapper::GetBinaryRight(list);
  677. }
  678. m.SetFuncPtrTableCount(funcPtrTableCount);
  679. m.SetCurrentParseNode(list);
  680. return true;
  681. }
  682. bool AsmJSCompiler::CheckModuleReturn( AsmJsModuleCompiler& m )
  683. {
  684. ParseNode* endStmt = m.GetCurrentParserNode();
  685. if (endStmt->nop != knopList)
  686. {
  687. return m.Fail(endStmt, _u("Module must have a return"));
  688. }
  689. ParseNode* node = ParserWrapper::GetBinaryLeft( endStmt );
  690. ParseNode* endNode = ParserWrapper::GetBinaryRight( endStmt );
  691. if( node->nop != knopReturn || endNode->nop != knopEndCode )
  692. {
  693. return m.Fail( node, _u("Only expression after table functions must be a return") );
  694. }
  695. ParseNode* objNode = node->AsParseNodeReturn()->pnodeExpr;
  696. if ( !objNode )
  697. {
  698. return m.Fail( node, _u( "Module return must be an object or 1 function" ) );
  699. }
  700. if( objNode->nop != knopObject )
  701. {
  702. if( ParserWrapper::IsNameDeclaration( objNode ) )
  703. {
  704. PropertyName name = objNode->name();
  705. AsmJsSymbol* sym = m.LookupIdentifier( name );
  706. if( !sym )
  707. {
  708. return m.FailName( node, _u("Symbol %s not recognized inside module"), name );
  709. }
  710. if (!AsmJsFunc::Is(sym))
  711. {
  712. return m.FailName( node, _u("Symbol %s can only be a function of the module"), name );
  713. }
  714. AsmJsFunc* func = AsmJsFunc::FromSymbol(sym);
  715. if( !m.SetExportFunc( func ) )
  716. {
  717. return m.FailName( node, _u("Error adding return Symbol %s"), name );
  718. }
  719. return true;
  720. }
  721. return m.Fail( node, _u("Module return must be an object or 1 function") );
  722. }
  723. ParseNode* objectElement = ParserWrapper::GetUnaryNode(objNode);
  724. if (!objectElement)
  725. {
  726. return m.Fail(node, _u("Return object must not be empty"));
  727. }
  728. while( objectElement )
  729. {
  730. ParseNode* member = nullptr;
  731. if( objectElement->nop == knopList )
  732. {
  733. member = ParserWrapper::GetBinaryLeft( objectElement );
  734. objectElement = ParserWrapper::GetBinaryRight( objectElement );
  735. }
  736. else if( objectElement->nop == knopMember )
  737. {
  738. member = objectElement;
  739. objectElement = nullptr;
  740. }
  741. else
  742. {
  743. return m.Fail( node, _u("Return object must only contain members") );
  744. }
  745. if( member )
  746. {
  747. ParseNode* field = ParserWrapper::GetBinaryLeft( member );
  748. ParseNode* value = ParserWrapper::GetBinaryRight( member );
  749. if( !ParserWrapper::IsNameDeclaration( field ) || !ParserWrapper::IsNameDeclaration( value ) )
  750. {
  751. return m.Fail( node, _u("Return object member must be fields") );
  752. }
  753. AsmJsSymbol* sym = m.LookupIdentifier( value->name() );
  754. if( !sym )
  755. {
  756. return m.FailName( node, _u("Symbol %s not recognized inside module"), value->name() );
  757. }
  758. if (!AsmJsFunc::Is(sym))
  759. {
  760. return m.FailName(node, _u("Symbol %s can only be a function of the module"), value->name());
  761. }
  762. AsmJsFunc* func = AsmJsFunc::FromSymbol(sym);
  763. if( !m.AddExport( field->name(), func->GetFunctionIndex() ) )
  764. {
  765. return m.FailName( node, _u("Error adding return Symbol %s"), value->name() );
  766. }
  767. }
  768. }
  769. return true;
  770. }
  771. bool AsmJSCompiler::CheckFuncPtrTables( AsmJsModuleCompiler &m )
  772. {
  773. ParseNode *list = m.GetCurrentParserNode();
  774. if (!list)
  775. {
  776. return true;
  777. }
  778. while (list->nop != knopEndCode)
  779. {
  780. ParseNode * varStmt = ParserWrapper::GetBinaryLeft(list);
  781. if (varStmt->nop != knopConstDecl && varStmt->nop != knopVarDecl)
  782. {
  783. break;
  784. }
  785. ParseNode* nodeInit = varStmt->AsParseNodeVar()->pnodeInit;
  786. if( !nodeInit || nodeInit->nop != knopArray )
  787. {
  788. return m.Fail( varStmt, _u("Invalid variable after function declaration") );
  789. }
  790. PropertyName tableName = varStmt->name();
  791. AsmJsSymbol* symFunctionTable = m.LookupIdentifier(tableName);
  792. if( !symFunctionTable)
  793. {
  794. // func table not used in functions disregard it
  795. }
  796. else
  797. {
  798. //Check name
  799. if(!AsmJsFunctionTable::Is(symFunctionTable))
  800. {
  801. return m.FailName( varStmt, _u("Variable %s is already defined"), tableName );
  802. }
  803. AsmJsFunctionTable* table = AsmJsFunctionTable::FromSymbol(symFunctionTable);
  804. if( table->IsDefined() )
  805. {
  806. return m.FailName( varStmt, _u("Multiple declaration of function table %s"), tableName );
  807. }
  808. // Check content of the array
  809. uint count = nodeInit->AsParseNodeArrLit()->count;
  810. if( table->GetSize() != count )
  811. {
  812. return m.FailName( varStmt, _u("Invalid size of function table %s"), tableName );
  813. }
  814. // Set the content of the array in the table
  815. ParseNode* node = nodeInit->AsParseNodeArrLit()->pnode1;
  816. uint i = 0;
  817. while( node )
  818. {
  819. ParseNode* funcNameNode = nullptr;
  820. if( node->nop == knopList )
  821. {
  822. funcNameNode = ParserWrapper::GetBinaryLeft( node );
  823. node = ParserWrapper::GetBinaryRight( node );
  824. }
  825. else
  826. {
  827. Assert( i + 1 == count );
  828. funcNameNode = node;
  829. node = nullptr;
  830. }
  831. if( ParserWrapper::IsNameDeclaration( funcNameNode ) )
  832. {
  833. AsmJsSymbol* sym = m.LookupIdentifier( funcNameNode->name() );
  834. if (!AsmJsFunc::Is(sym))
  835. {
  836. return m.FailName( varStmt, _u("Element in function table %s is not a function"), tableName );
  837. }
  838. AsmJsFunc* func = AsmJsFunc::FromSymbol(sym);
  839. AsmJsRetType retType;
  840. if (!table->SupportsArgCall(func->GetArgCount(), func->GetArgTypeArray(), retType))
  841. {
  842. return m.FailName(funcNameNode, _u("Function signatures in table %s do not match"), tableName);
  843. }
  844. if (!table->CheckAndSetReturnType(func->GetReturnType()))
  845. {
  846. return m.FailName(funcNameNode, _u("Function return types in table %s do not match"), tableName);
  847. }
  848. table->SetModuleFunctionIndex( func->GetFunctionIndex(), i );
  849. ++i;
  850. }
  851. else
  852. {
  853. return m.FailName(funcNameNode, _u("Element in function table %s is not a function name"), tableName);
  854. }
  855. }
  856. table->Define();
  857. }
  858. list = ParserWrapper::GetBinaryRight(list);
  859. }
  860. if( !m.AreAllFuncTableDefined() )
  861. {
  862. return m.Fail(list, _u("Some function table were used but not defined"));
  863. }
  864. m.SetCurrentParseNode(list);
  865. return true;
  866. }
  867. bool AsmJSCompiler::CheckModule( ExclusiveContext *cx, AsmJSParser &parser, ParseNode *stmtList )
  868. {
  869. AsmJsModuleCompiler m( cx, parser );
  870. if( !m.Init() )
  871. {
  872. return false;
  873. }
  874. if( PropertyName moduleFunctionName = ParserWrapper::FunctionName( m.GetModuleFunctionNode() ) )
  875. {
  876. if( !CheckModuleLevelName( m, m.GetModuleFunctionNode(), moduleFunctionName ) )
  877. {
  878. return false;
  879. }
  880. m.InitModuleName( moduleFunctionName );
  881. if( PHASE_TRACE1( Js::ByteCodePhase ) )
  882. {
  883. Output::Print( _u("Asm.Js Module [%s] detected, trying to compile\n"), moduleFunctionName->Psz() );
  884. }
  885. }
  886. m.AccumulateCompileTime(AsmJsCompilation::Module);
  887. if( !CheckFunctionHead( m, m.GetModuleFunctionNode() ) )
  888. {
  889. goto AsmJsCompilationError;
  890. }
  891. if (!CheckModuleArguments(m, m.GetModuleFunctionNode()))
  892. {
  893. goto AsmJsCompilationError;
  894. }
  895. if (!CheckModuleGlobals(m))
  896. {
  897. goto AsmJsCompilationError;
  898. }
  899. m.AccumulateCompileTime(AsmJsCompilation::Module);
  900. if (!CheckFunctionsSequential(m))
  901. {
  902. goto AsmJsCompilationError;
  903. }
  904. m.AccumulateCompileTime();
  905. m.InitMemoryOffsets();
  906. if( !m.CompileAllFunctions() )
  907. {
  908. return false;
  909. }
  910. m.AccumulateCompileTime(AsmJsCompilation::ByteCode);
  911. if (!CheckFuncPtrTables(m))
  912. {
  913. m.RevertAllFunctions();
  914. return false;
  915. }
  916. m.AccumulateCompileTime();
  917. if (!CheckModuleReturn(m))
  918. {
  919. m.RevertAllFunctions();
  920. return false;
  921. }
  922. m.CommitFunctions();
  923. m.CommitModule();
  924. m.AccumulateCompileTime(AsmJsCompilation::Module);
  925. m.PrintCompileTrace();
  926. return true;
  927. AsmJsCompilationError:
  928. ParseNode * moduleNode = m.GetModuleFunctionNode();
  929. if( moduleNode )
  930. {
  931. FunctionBody* body = moduleNode->AsParseNodeFnc()->funcInfo->GetParsedFunctionBody();
  932. body->ResetByteCodeGenState();
  933. }
  934. cx->byteCodeGenerator->Writer()->Reset();
  935. return false;
  936. }
  937. bool AsmJSCompiler::Compile(ExclusiveContext *cx, AsmJSParser parser, ParseNode *stmtList)
  938. {
  939. if (!CheckModule(cx, parser, stmtList))
  940. {
  941. OutputError(cx->scriptContext, _u("Asm.js compilation failed."));
  942. return false;
  943. }
  944. return true;
  945. }
  946. void AsmJSCompiler::OutputError(ScriptContext * scriptContext, const wchar * message, ...)
  947. {
  948. va_list argptr;
  949. va_start(argptr, message);
  950. VOutputMessage(scriptContext, DEIT_ASMJS_FAILED, message, argptr);
  951. }
  952. void AsmJSCompiler::OutputMessage(ScriptContext * scriptContext, const DEBUG_EVENT_INFO_TYPE messageType, const wchar * message, ...)
  953. {
  954. va_list argptr;
  955. va_start(argptr, message);
  956. VOutputMessage(scriptContext, messageType, message, argptr);
  957. }
  958. void AsmJSCompiler::VOutputMessage(ScriptContext * scriptContext, const DEBUG_EVENT_INFO_TYPE messageType, const wchar * message, va_list argptr)
  959. {
  960. char16 buf[2048];
  961. size_t size;
  962. size = _vsnwprintf_s(buf, _countof(buf), _TRUNCATE, message, argptr);
  963. if (size == -1)
  964. {
  965. size = _countof(buf) - 1; // characters written, excluding the terminating null
  966. }
  967. #ifdef ENABLE_SCRIPT_DEBUGGING
  968. scriptContext->RaiseMessageToDebugger(messageType, buf, scriptContext->GetUrl());
  969. #endif
  970. if (PHASE_TRACE1(AsmjsPhase) || PHASE_TESTTRACE1(AsmjsPhase))
  971. {
  972. Output::PrintBuffer(buf, size);
  973. Output::Print(_u("\n"));
  974. Output::Flush();
  975. }
  976. }
  977. }
  978. #endif