AsmJsUtils.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  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. namespace Js
  24. {
  25. bool ParserWrapper::ParseVarOrConstStatement( AsmJSParser &parser, ParseNode **var )
  26. {
  27. Assert( parser );
  28. *var = nullptr;
  29. ParseNode *body = parser->sxFnc.pnodeBody;
  30. if( body )
  31. {
  32. ParseNode* lhs = GetBinaryLeft( body );
  33. ParseNode* rhs = GetBinaryRight( body );
  34. if( rhs && rhs->nop == knopList )
  35. {
  36. AssertMsg( lhs->nop == knopStr, "this should be use asm" );
  37. *var = rhs;
  38. return true;
  39. }
  40. }
  41. return false;
  42. }
  43. bool ParserWrapper::IsDefinition( ParseNode *arg )
  44. {
  45. //TODO, eliminate duplicates
  46. return true;
  47. }
  48. ParseNode* ParserWrapper::NextInList( ParseNode *node )
  49. {
  50. Assert( node->nop == knopList );
  51. return node->sxBin.pnode2;
  52. }
  53. ParseNode* ParserWrapper::NextVar( ParseNode *node )
  54. {
  55. return node->sxVar.pnodeNext;
  56. }
  57. ParseNode* ParserWrapper::FunctionArgsList( ParseNode *node, ArgSlot &numformals )
  58. {
  59. Assert( node->nop == knopFncDecl );
  60. PnFnc func = node->sxFnc;
  61. ParseNode* first = func.pnodeParams;
  62. // throws OOM on uint16 overflow
  63. for( ParseNode* pnode = first; pnode; pnode = pnode->sxVar.pnodeNext, ArgSlotMath::Inc(numformals));
  64. return first;
  65. }
  66. PropertyName ParserWrapper::VariableName( ParseNode *node )
  67. {
  68. return node->name();
  69. }
  70. PropertyName ParserWrapper::FunctionName( ParseNode *node )
  71. {
  72. if( node->nop == knopFncDecl )
  73. {
  74. PnFnc function = node->sxFnc;
  75. if( function.pnodeName && function.pnodeName->nop == knopVarDecl )
  76. {
  77. return function.pnodeName->sxVar.pid;
  78. }
  79. }
  80. return nullptr;
  81. }
  82. ParseNode * ParserWrapper::GetVarDeclList( ParseNode * pnode )
  83. {
  84. ParseNode* varNode = pnode;
  85. while (varNode->nop == knopList)
  86. {
  87. ParseNode * var = GetBinaryLeft(varNode);
  88. if (var->nop == knopVarDecl)
  89. {
  90. return var;
  91. }
  92. else if (var->nop == knopList)
  93. {
  94. var = GetBinaryLeft(var);
  95. if (var->nop == knopVarDecl)
  96. {
  97. return var;
  98. }
  99. }
  100. varNode = GetBinaryRight(varNode);
  101. }
  102. return nullptr;
  103. }
  104. void ParserWrapper::ReachEndVarDeclList( ParseNode** outNode )
  105. {
  106. ParseNode* pnode = *outNode;
  107. // moving down to the last var declaration
  108. while( pnode->nop == knopList )
  109. {
  110. ParseNode* var = GetBinaryLeft( pnode );
  111. if (var->nop == knopVarDecl)
  112. {
  113. pnode = GetBinaryRight( pnode );
  114. continue;
  115. }
  116. else if (var->nop == knopList)
  117. {
  118. var = GetBinaryLeft( var );
  119. if (var->nop == knopVarDecl)
  120. {
  121. pnode = GetBinaryRight( pnode );
  122. continue;
  123. }
  124. }
  125. break;
  126. }
  127. *outNode = pnode;
  128. }
  129. AsmJsCompilationException::AsmJsCompilationException( const char16* _msg, ... )
  130. {
  131. va_list arglist;
  132. va_start( arglist, _msg );
  133. vswprintf_s( msg_, _msg, arglist );
  134. }
  135. #if ENABLE_DEBUG_CONFIG_OPTIONS
  136. int64 ConvertStringToInt64(Var string, ScriptContext* scriptContext)
  137. {
  138. JavascriptString* str = JavascriptString::FromVar(string);
  139. charcount_t length = str->GetLength();
  140. const char16* buf = str->GetString();
  141. int radix = 10;
  142. if (length >= 2 && buf[0] == '0' && buf[1] == 'x')
  143. {
  144. radix = 16;
  145. }
  146. return (int64)_wcstoui64(buf, nullptr, radix);
  147. }
  148. Var CreateI64ReturnObject(int64 val, ScriptContext* scriptContext)
  149. {
  150. Js::Var i64Object = JavascriptOperators::NewJavascriptObjectNoArg(scriptContext);
  151. Var low = JavascriptNumber::ToVar((uint)val, scriptContext);
  152. Var high = JavascriptNumber::ToVar(val >> 32, scriptContext);
  153. JavascriptOperators::OP_SetProperty(i64Object, PropertyIds::low, low, scriptContext);
  154. JavascriptOperators::OP_SetProperty(i64Object, PropertyIds::high, high, scriptContext);
  155. return i64Object;
  156. }
  157. #endif
  158. void * UnboxAsmJsArguments(ScriptFunction* func, Var * origArgs, char * argDst, CallInfo callInfo)
  159. {
  160. void * address = reinterpret_cast<void*>(func->GetEntryPointInfo()->jsMethod);
  161. Assert(address);
  162. AsmJsFunctionInfo* info = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  163. ScriptContext* scriptContext = func->GetScriptContext();
  164. #if ENABLE_DEBUG_CONFIG_OPTIONS
  165. bool allowTestInputs = CONFIG_FLAG(WasmI64);
  166. #endif
  167. ArgumentReader reader(&callInfo, origArgs);
  168. uint actualArgCount = reader.Info.Count - 1; // -1 for ScriptFunction
  169. argDst = argDst + MachPtr; // add one first so as to skip the ScriptFunction argument
  170. for (ArgSlot i = 0; i < info->GetArgCount(); i++)
  171. {
  172. if (info->GetArgType(i).isInt())
  173. {
  174. int32 intVal;
  175. if (i < actualArgCount)
  176. {
  177. #if ENABLE_DEBUG_CONFIG_OPTIONS
  178. if (allowTestInputs && JavascriptString::Is(*origArgs))
  179. {
  180. intVal = (int32)ConvertStringToInt64(*origArgs, scriptContext);
  181. }
  182. else
  183. #endif
  184. intVal = JavascriptMath::ToInt32(*origArgs, scriptContext);
  185. }
  186. else
  187. {
  188. intVal = 0;
  189. }
  190. #if TARGET_64
  191. *(int64*)(argDst) = 0;
  192. #endif
  193. *(int32*)argDst = intVal;
  194. argDst = argDst + MachPtr;
  195. }
  196. else if (info->GetArgType(i).isInt64())
  197. {
  198. #if ENABLE_DEBUG_CONFIG_OPTIONS
  199. if (!allowTestInputs)
  200. #endif
  201. {
  202. JavascriptError::ThrowTypeError(scriptContext, WASMERR_InvalidTypeConversion);
  203. }
  204. #if ENABLE_DEBUG_CONFIG_OPTIONS
  205. int64 val;
  206. if (i < actualArgCount)
  207. {
  208. if (JavascriptString::Is(*origArgs))
  209. {
  210. val = ConvertStringToInt64(*origArgs, scriptContext);
  211. }
  212. else if (JavascriptObject::Is(*origArgs))
  213. {
  214. RecyclableObject* object = RecyclableObject::FromVar(*origArgs);
  215. PropertyRecord const * lowPropRecord = nullptr;
  216. PropertyRecord const * highPropRecord = nullptr;
  217. scriptContext->GetOrAddPropertyRecord(_u("low"), (int)wcslen(_u("low")), &lowPropRecord);
  218. scriptContext->GetOrAddPropertyRecord(_u("high"), (int)wcslen(_u("high")), &highPropRecord);
  219. Var low = JavascriptOperators::OP_GetProperty(object, lowPropRecord->GetPropertyId(), scriptContext);
  220. Var high = JavascriptOperators::OP_GetProperty(object, highPropRecord->GetPropertyId(), scriptContext);
  221. uint64 lowVal = JavascriptMath::ToInt32(low, scriptContext);
  222. uint64 highVal = JavascriptMath::ToInt32(high, scriptContext);
  223. val = (highVal << 32) | (lowVal & 0xFFFFFFFF);
  224. }
  225. else
  226. {
  227. int32 intVal = JavascriptMath::ToInt32(*origArgs, scriptContext);
  228. val = (int64)intVal;
  229. }
  230. }
  231. else
  232. {
  233. val = 0;
  234. }
  235. *(int64*)(argDst) = val;
  236. argDst += sizeof(int64);
  237. #endif
  238. }
  239. else if (info->GetArgType(i).isFloat())
  240. {
  241. float floatVal;
  242. if (i < actualArgCount)
  243. {
  244. #if ENABLE_DEBUG_CONFIG_OPTIONS
  245. if (allowTestInputs && JavascriptString::Is(*origArgs))
  246. {
  247. int32 val = (int32)ConvertStringToInt64(*origArgs, scriptContext);
  248. floatVal = *(float*)&val;
  249. }
  250. else
  251. #endif
  252. floatVal = (float)(JavascriptConversion::ToNumber(*origArgs, scriptContext));
  253. }
  254. else
  255. {
  256. floatVal = (float)(JavascriptNumber::NaN);
  257. }
  258. #if TARGET_64
  259. *(int64*)(argDst) = 0;
  260. #endif
  261. *(float*)argDst = floatVal;
  262. argDst = argDst + MachPtr;
  263. }
  264. else if (info->GetArgType(i).isDouble())
  265. {
  266. double doubleVal;
  267. if (i < actualArgCount)
  268. {
  269. #if ENABLE_DEBUG_CONFIG_OPTIONS
  270. if (allowTestInputs && JavascriptString::Is(*origArgs))
  271. {
  272. int64 val = ConvertStringToInt64(*origArgs, scriptContext);
  273. doubleVal = *(double*)&val;
  274. }
  275. else
  276. #endif
  277. doubleVal = JavascriptConversion::ToNumber(*origArgs, scriptContext);
  278. }
  279. else
  280. {
  281. doubleVal = JavascriptNumber::NaN;
  282. }
  283. *(double*)argDst = doubleVal;
  284. argDst = argDst + sizeof(double);
  285. }
  286. #ifdef ENABLE_SIMDJS
  287. else if (info->GetArgType(i).isSIMD())
  288. {
  289. AsmJsVarType argType = info->GetArgType(i);
  290. AsmJsSIMDValue simdVal = {0, 0, 0, 0};
  291. // SIMD values are copied unaligned.
  292. // SIMD values cannot be implicitly coerced from/to other types. If the SIMD parameter is missing (i.e. Undefined), we throw type error since there is not equivalent SIMD value to coerce to.
  293. switch (argType.which())
  294. {
  295. case AsmJsType::Int32x4:
  296. if (!JavascriptSIMDInt32x4::Is(*origArgs))
  297. {
  298. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdInt32x4TypeMismatch, _u("Int32x4"));
  299. }
  300. simdVal = ((JavascriptSIMDInt32x4*)(*origArgs))->GetValue();
  301. break;
  302. case AsmJsType::Bool32x4:
  303. if (!JavascriptSIMDBool32x4::Is(*origArgs))
  304. {
  305. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdBool32x4TypeMismatch, _u("Bool32x4"));
  306. }
  307. simdVal = ((JavascriptSIMDBool32x4*)(*origArgs))->GetValue();
  308. break;
  309. case AsmJsType::Bool16x8:
  310. if (!JavascriptSIMDBool16x8::Is(*origArgs))
  311. {
  312. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdBool16x8TypeMismatch, _u("Bool16x8"));
  313. }
  314. simdVal = ((JavascriptSIMDBool16x8*)(*origArgs))->GetValue();
  315. break;
  316. case AsmJsType::Bool8x16:
  317. if (!JavascriptSIMDBool8x16::Is(*origArgs))
  318. {
  319. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdBool8x16TypeMismatch, _u("Bool8x16"));
  320. }
  321. simdVal = ((JavascriptSIMDBool8x16*)(*origArgs))->GetValue();
  322. break;
  323. case AsmJsType::Float32x4:
  324. if (!JavascriptSIMDFloat32x4::Is(*origArgs))
  325. {
  326. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdFloat32x4TypeMismatch, _u("Float32x4"));
  327. }
  328. simdVal = ((JavascriptSIMDFloat32x4*)(*origArgs))->GetValue();
  329. break;
  330. case AsmJsType::Float64x2:
  331. if (!JavascriptSIMDFloat64x2::Is(*origArgs))
  332. {
  333. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdFloat64x2TypeMismatch, _u("Float64x2"));
  334. }
  335. simdVal = ((JavascriptSIMDFloat64x2*)(*origArgs))->GetValue();
  336. break;
  337. case AsmJsType::Int16x8:
  338. if (!JavascriptSIMDInt16x8::Is(*origArgs))
  339. {
  340. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdInt16x8TypeMismatch, _u("Int16x8"));
  341. }
  342. simdVal = ((JavascriptSIMDInt16x8*)(*origArgs))->GetValue();
  343. break;
  344. case AsmJsType::Int8x16:
  345. if (!JavascriptSIMDInt8x16::Is(*origArgs))
  346. {
  347. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdInt8x16TypeMismatch, _u("Int8x16"));
  348. }
  349. simdVal = ((JavascriptSIMDInt8x16*)(*origArgs))->GetValue();
  350. break;
  351. case AsmJsType::Uint32x4:
  352. if (!JavascriptSIMDUint32x4::Is(*origArgs))
  353. {
  354. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdUint32x4TypeMismatch, _u("Uint32x4"));
  355. }
  356. simdVal = ((JavascriptSIMDUint32x4*)(*origArgs))->GetValue();
  357. break;
  358. case AsmJsType::Uint16x8:
  359. if (!JavascriptSIMDUint16x8::Is(*origArgs))
  360. {
  361. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdUint16x8TypeMismatch, _u("Uint16x8"));
  362. }
  363. simdVal = ((JavascriptSIMDUint16x8*)(*origArgs))->GetValue();
  364. break;
  365. case AsmJsType::Uint8x16:
  366. if (!JavascriptSIMDUint8x16::Is(*origArgs))
  367. {
  368. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdUint8x16TypeMismatch, _u("Uint8x16"));
  369. }
  370. simdVal = ((JavascriptSIMDUint8x16*)(*origArgs))->GetValue();
  371. break;
  372. default:
  373. Assert(UNREACHED);
  374. }
  375. *(AsmJsSIMDValue*)argDst = simdVal;
  376. argDst = argDst + sizeof(AsmJsSIMDValue);
  377. }
  378. #endif // #ifdef ENABLE_SIMDJS
  379. else
  380. {
  381. Assert(UNREACHED);
  382. }
  383. ++origArgs;
  384. }
  385. AsmJsModuleInfo::EnsureHeapAttached(func);
  386. // for convenience, lets take the opportunity to return the asm.js entrypoint address
  387. return address;
  388. }
  389. #if _M_X64
  390. // returns an array containing the size of each argument
  391. uint *GetArgsSizesArray(ScriptFunction* func)
  392. {
  393. AsmJsFunctionInfo* info = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  394. return info->GetArgsSizesArray();
  395. }
  396. int GetStackSizeForAsmJsUnboxing(ScriptFunction* func)
  397. {
  398. AsmJsFunctionInfo* info = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  399. int argSize = info->GetArgByteSize() + MachPtr;
  400. argSize = ::Math::Align<int32>(argSize, 16);
  401. if (argSize < 32)
  402. {
  403. argSize = 32; // convention is to always allocate spill space for rcx,rdx,r8,r9
  404. }
  405. PROBE_STACK_CALL(func->GetScriptContext(), func, argSize + Js::Constants::MinStackDefault);
  406. return argSize;
  407. }
  408. Var BoxAsmJsReturnValue(ScriptFunction* func, int64 intRetVal, double doubleRetVal, float floatRetVal, __m128 simdRetVal)
  409. {
  410. // ExternalEntryPoint doesn't know the return value, so it will send garbage for everything except actual return type
  411. Var returnValue = nullptr;
  412. // make call and convert primitive type back to Var
  413. AsmJsFunctionInfo* info = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  414. ScriptContext* scriptContext = func->GetScriptContext();
  415. switch (info->GetReturnType().which())
  416. {
  417. case AsmJsRetType::Void:
  418. returnValue = JavascriptOperators::OP_LdUndef(scriptContext);
  419. break;
  420. case AsmJsRetType::Signed:
  421. {
  422. returnValue = JavascriptNumber::ToVar((int)intRetVal, scriptContext);
  423. break;
  424. }
  425. case AsmJsRetType::Int64:
  426. {
  427. #if ENABLE_DEBUG_CONFIG_OPTIONS
  428. if (CONFIG_FLAG(WasmI64))
  429. {
  430. returnValue = CreateI64ReturnObject(intRetVal, scriptContext);
  431. break;
  432. }
  433. #endif
  434. JavascriptError::ThrowTypeError(scriptContext, WASMERR_InvalidTypeConversion);
  435. }
  436. case AsmJsRetType::Double:
  437. {
  438. returnValue = JavascriptNumber::NewWithCheck(doubleRetVal, scriptContext);
  439. break;
  440. }
  441. case AsmJsRetType::Float:
  442. {
  443. returnValue = JavascriptNumber::NewWithCheck(floatRetVal, scriptContext);
  444. break;
  445. }
  446. #ifdef ENABLE_SIMDJS
  447. case AsmJsRetType::Float32x4:
  448. {
  449. X86SIMDValue simdVal;
  450. simdVal.m128_value = simdRetVal;
  451. returnValue = JavascriptSIMDFloat32x4::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  452. break;
  453. }
  454. case AsmJsRetType::Int32x4:
  455. {
  456. X86SIMDValue simdVal;
  457. simdVal.m128_value = simdRetVal;
  458. returnValue = JavascriptSIMDInt32x4::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  459. break;
  460. }
  461. case AsmJsRetType::Bool32x4:
  462. {
  463. X86SIMDValue simdVal;
  464. simdVal.m128_value = simdRetVal;
  465. returnValue = JavascriptSIMDBool32x4::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  466. break;
  467. }
  468. case AsmJsRetType::Bool16x8:
  469. {
  470. X86SIMDValue simdVal;
  471. simdVal.m128_value = simdRetVal;
  472. returnValue = JavascriptSIMDBool16x8::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  473. break;
  474. }
  475. case AsmJsRetType::Bool8x16:
  476. {
  477. X86SIMDValue simdVal;
  478. simdVal.m128_value = simdRetVal;
  479. returnValue = JavascriptSIMDBool8x16::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  480. break;
  481. }
  482. case AsmJsRetType::Float64x2:
  483. {
  484. X86SIMDValue simdVal;
  485. simdVal.m128_value = simdRetVal;
  486. returnValue = JavascriptSIMDFloat64x2::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  487. break;
  488. }
  489. case AsmJsRetType::Int16x8:
  490. {
  491. X86SIMDValue simdVal;
  492. simdVal.m128_value = simdRetVal;
  493. returnValue = JavascriptSIMDInt16x8::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  494. break;
  495. }
  496. case AsmJsRetType::Int8x16:
  497. {
  498. X86SIMDValue simdVal;
  499. simdVal.m128_value = simdRetVal;
  500. returnValue = JavascriptSIMDInt8x16::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  501. break;
  502. }
  503. case AsmJsRetType::Uint32x4:
  504. {
  505. X86SIMDValue simdVal;
  506. simdVal.m128_value = simdRetVal;
  507. returnValue = JavascriptSIMDUint32x4::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  508. break;
  509. }
  510. case AsmJsRetType::Uint16x8:
  511. {
  512. X86SIMDValue simdVal;
  513. simdVal.m128_value = simdRetVal;
  514. returnValue = JavascriptSIMDUint16x8::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  515. break;
  516. }
  517. case AsmJsRetType::Uint8x16:
  518. {
  519. X86SIMDValue simdVal;
  520. simdVal.m128_value = simdRetVal;
  521. returnValue = JavascriptSIMDUint8x16::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  522. break;
  523. }
  524. #endif // #ifdef ENABLE_SIMDJS
  525. default:
  526. Assume(UNREACHED);
  527. }
  528. return returnValue;
  529. }
  530. #elif _M_IX86
  531. Var AsmJsExternalEntryPoint(RecyclableObject* entryObject, CallInfo callInfo, ...)
  532. {
  533. ARGUMENTS(args, callInfo);
  534. ScriptFunction* func = (ScriptFunction*)entryObject;
  535. FunctionBody* body = func->GetFunctionBody();
  536. AsmJsFunctionInfo* info = body->GetAsmJsFunctionInfo();
  537. int argSize = info->GetArgByteSize();
  538. void* dst;
  539. Var returnValue = 0;
  540. argSize = ::Math::Align<int32>(argSize, 8);
  541. // Allocate stack space for args
  542. PROBE_STACK_CALL(func->GetScriptContext(), func, argSize + Js::Constants::MinStackDefault);
  543. dst = _alloca(argSize);
  544. const void * asmJSEntryPoint = UnboxAsmJsArguments(func, args.Values + 1, ((char*)dst) - MachPtr, callInfo);
  545. // make call and convert primitive type back to Var
  546. switch (info->GetReturnType().which())
  547. {
  548. case AsmJsRetType::Void:
  549. __asm
  550. {
  551. mov ecx, asmJSEntryPoint
  552. #ifdef _CONTROL_FLOW_GUARD
  553. call[__guard_check_icall_fptr]
  554. #endif
  555. push func
  556. call ecx
  557. }
  558. returnValue = JavascriptOperators::OP_LdUndef(func->GetScriptContext());
  559. break;
  560. case AsmJsRetType::Signed:{
  561. int32 ival = 0;
  562. __asm
  563. {
  564. mov ecx, asmJSEntryPoint
  565. #ifdef _CONTROL_FLOW_GUARD
  566. call[__guard_check_icall_fptr]
  567. #endif
  568. push func
  569. call ecx
  570. mov ival, eax
  571. }
  572. returnValue = JavascriptNumber::ToVar(ival, func->GetScriptContext());
  573. break;
  574. }
  575. case AsmJsRetType::Int64:
  576. {
  577. int32 iLow = 0, iHigh = 0;
  578. __asm
  579. {
  580. mov ecx, asmJSEntryPoint
  581. #ifdef _CONTROL_FLOW_GUARD
  582. call[__guard_check_icall_fptr]
  583. #endif
  584. push func
  585. call ecx
  586. mov iLow, eax;
  587. mov iHigh, edx;
  588. }
  589. #if ENABLE_DEBUG_CONFIG_OPTIONS
  590. if (CONFIG_FLAG(WasmI64))
  591. {
  592. returnValue = CreateI64ReturnObject((int64)iLow | ((int64)iHigh << 32), func->GetScriptContext());
  593. break;
  594. }
  595. #endif
  596. JavascriptError::ThrowTypeError(func->GetScriptContext(), WASMERR_InvalidTypeConversion);
  597. }
  598. case AsmJsRetType::Double:{
  599. double dval = 0;
  600. __asm
  601. {
  602. mov ecx, asmJSEntryPoint
  603. #ifdef _CONTROL_FLOW_GUARD
  604. call[__guard_check_icall_fptr]
  605. #endif
  606. push func
  607. call ecx
  608. movsd dval, xmm0
  609. }
  610. returnValue = JavascriptNumber::NewWithCheck(dval, func->GetScriptContext());
  611. break;
  612. }
  613. case AsmJsRetType::Float:{
  614. float fval = 0;
  615. __asm
  616. {
  617. mov ecx, asmJSEntryPoint
  618. #ifdef _CONTROL_FLOW_GUARD
  619. call[__guard_check_icall_fptr]
  620. #endif
  621. push func
  622. call ecx
  623. movss fval, xmm0
  624. }
  625. returnValue = JavascriptNumber::NewWithCheck((double)fval, func->GetScriptContext());
  626. break;
  627. }
  628. #ifdef ENABLE_SIMDJS
  629. case AsmJsRetType::Int32x4:
  630. AsmJsSIMDValue simdVal;
  631. simdVal.Zero();
  632. __asm
  633. {
  634. mov ecx, asmJSEntryPoint
  635. #ifdef _CONTROL_FLOW_GUARD
  636. call[__guard_check_icall_fptr]
  637. #endif
  638. push func
  639. call ecx
  640. movups simdVal, xmm0
  641. }
  642. returnValue = JavascriptSIMDInt32x4::New(&simdVal, func->GetScriptContext());
  643. break;
  644. case AsmJsRetType::Bool32x4:
  645. simdVal.Zero();
  646. __asm
  647. {
  648. mov ecx, asmJSEntryPoint
  649. #ifdef _CONTROL_FLOW_GUARD
  650. call[__guard_check_icall_fptr]
  651. #endif
  652. push func
  653. call ecx
  654. movups simdVal, xmm0
  655. }
  656. returnValue = JavascriptSIMDBool32x4::New(&simdVal, func->GetScriptContext());
  657. break;
  658. case AsmJsRetType::Bool16x8:
  659. simdVal.Zero();
  660. __asm
  661. {
  662. mov ecx, asmJSEntryPoint
  663. #ifdef _CONTROL_FLOW_GUARD
  664. call[__guard_check_icall_fptr]
  665. #endif
  666. push func
  667. call ecx
  668. movups simdVal, xmm0
  669. }
  670. returnValue = JavascriptSIMDBool16x8::New(&simdVal, func->GetScriptContext());
  671. break;
  672. case AsmJsRetType::Bool8x16:
  673. simdVal.Zero();
  674. __asm
  675. {
  676. mov ecx, asmJSEntryPoint
  677. #ifdef _CONTROL_FLOW_GUARD
  678. call[__guard_check_icall_fptr]
  679. #endif
  680. push func
  681. call ecx
  682. movups simdVal, xmm0
  683. }
  684. returnValue = JavascriptSIMDBool8x16::New(&simdVal, func->GetScriptContext());
  685. break;
  686. case AsmJsRetType::Float32x4:
  687. simdVal.Zero();
  688. __asm
  689. {
  690. mov ecx, asmJSEntryPoint
  691. #ifdef _CONTROL_FLOW_GUARD
  692. call[__guard_check_icall_fptr]
  693. #endif
  694. push func
  695. call ecx
  696. movups simdVal, xmm0
  697. }
  698. returnValue = JavascriptSIMDFloat32x4::New(&simdVal, func->GetScriptContext());
  699. break;
  700. case AsmJsRetType::Float64x2:
  701. simdVal.Zero();
  702. __asm
  703. {
  704. mov ecx, asmJSEntryPoint
  705. #ifdef _CONTROL_FLOW_GUARD
  706. call[__guard_check_icall_fptr]
  707. #endif
  708. push func
  709. call ecx
  710. movups simdVal, xmm0
  711. }
  712. returnValue = JavascriptSIMDFloat64x2::New(&simdVal, func->GetScriptContext());
  713. break;
  714. case AsmJsRetType::Int16x8:
  715. simdVal.Zero();
  716. __asm
  717. {
  718. mov ecx, asmJSEntryPoint
  719. #ifdef _CONTROL_FLOW_GUARD
  720. call[__guard_check_icall_fptr]
  721. #endif
  722. push func
  723. call ecx
  724. movups simdVal, xmm0
  725. }
  726. returnValue = JavascriptSIMDInt16x8::New(&simdVal, func->GetScriptContext());
  727. break;
  728. case AsmJsRetType::Int8x16:
  729. simdVal.Zero();
  730. __asm
  731. {
  732. mov ecx, asmJSEntryPoint
  733. #ifdef _CONTROL_FLOW_GUARD
  734. call[__guard_check_icall_fptr]
  735. #endif
  736. push func
  737. call ecx
  738. movups simdVal, xmm0
  739. }
  740. returnValue = JavascriptSIMDInt8x16::New(&simdVal, func->GetScriptContext());
  741. break;
  742. case AsmJsRetType::Uint32x4:
  743. simdVal.Zero();
  744. __asm
  745. {
  746. mov ecx, asmJSEntryPoint
  747. #ifdef _CONTROL_FLOW_GUARD
  748. call[__guard_check_icall_fptr]
  749. #endif
  750. push func
  751. call ecx
  752. movups simdVal, xmm0
  753. }
  754. returnValue = JavascriptSIMDUint32x4::New(&simdVal, func->GetScriptContext());
  755. break;
  756. case AsmJsRetType::Uint16x8:
  757. simdVal.Zero();
  758. __asm
  759. {
  760. mov ecx, asmJSEntryPoint
  761. #ifdef _CONTROL_FLOW_GUARD
  762. call[__guard_check_icall_fptr]
  763. #endif
  764. push func
  765. call ecx
  766. movups simdVal, xmm0
  767. }
  768. returnValue = JavascriptSIMDUint16x8::New(&simdVal, func->GetScriptContext());
  769. break;
  770. case AsmJsRetType::Uint8x16:
  771. simdVal.Zero();
  772. __asm
  773. {
  774. mov ecx, asmJSEntryPoint
  775. #ifdef _CONTROL_FLOW_GUARD
  776. call[__guard_check_icall_fptr]
  777. #endif
  778. push func
  779. call ecx
  780. movups simdVal, xmm0
  781. }
  782. returnValue = JavascriptSIMDUint8x16::New(&simdVal, func->GetScriptContext());
  783. break;
  784. #endif // #ifdef ENABLE_SIMDJS
  785. default:
  786. Assume(UNREACHED);
  787. }
  788. return returnValue;
  789. }
  790. #endif
  791. }
  792. #endif