AsmJsUtils.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  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, UInt16Math::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. Var AsmJsChangeHeapBuffer(RecyclableObject * function, CallInfo callInfo, ...)
  136. {
  137. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  138. ARGUMENTS(args, callInfo);
  139. ScriptContext* scriptContext = function->GetScriptContext();
  140. Assert(!(callInfo.Flags & CallFlags_New));
  141. if (args.Info.Count < 1 || !ArrayBuffer::Is(args[1]))
  142. {
  143. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedArrayBufferObject);
  144. }
  145. ArrayBuffer* newArrayBuffer = ArrayBuffer::FromVar(args[1]);
  146. if (newArrayBuffer->IsDetached() || newArrayBuffer->GetByteLength() & 0xffffff || newArrayBuffer->GetByteLength() <= 0xffffff || newArrayBuffer->GetByteLength() > 0x80000000)
  147. {
  148. return JavascriptBoolean::ToVar(FALSE, scriptContext);
  149. }
  150. FrameDisplay* frame = ((ScriptFunction*)function)->GetEnvironment();
  151. Field(Var)* moduleArrayBuffer = (Field(Var)*)frame->GetItem(0) + AsmJsModuleMemory::MemoryTableBeginOffset;
  152. *moduleArrayBuffer = newArrayBuffer;
  153. return JavascriptBoolean::ToVar(TRUE, scriptContext);
  154. }
  155. #if ENABLE_DEBUG_CONFIG_OPTIONS
  156. int64 ConvertStringToInt64(Var string, ScriptContext* scriptContext)
  157. {
  158. JavascriptString* str = JavascriptString::FromVar(string);
  159. charcount_t length = str->GetLength();
  160. const char16* buf = str->GetString();
  161. int radix = 10;
  162. if (length >= 2 && buf[0] == '0' && buf[1] == 'x')
  163. {
  164. radix = 16;
  165. }
  166. return (int64)_wcstoui64(buf, nullptr, radix);
  167. }
  168. Var CreateI64ReturnObject(int64 val, ScriptContext* scriptContext)
  169. {
  170. Js::Var i64Object = JavascriptOperators::NewJavascriptObjectNoArg(scriptContext);
  171. Var low = JavascriptNumber::ToVar((uint)val, scriptContext);
  172. Var high = JavascriptNumber::ToVar(val >> 32, scriptContext);
  173. PropertyRecord const * lowPropRecord = nullptr;
  174. PropertyRecord const * highPropRecord = nullptr;
  175. scriptContext->GetOrAddPropertyRecord(_u("low"), (int)wcslen(_u("low")), &lowPropRecord);
  176. scriptContext->GetOrAddPropertyRecord(_u("high"), (int)wcslen(_u("high")), &highPropRecord);
  177. JavascriptOperators::OP_SetProperty(i64Object, lowPropRecord->GetPropertyId(), low, scriptContext);
  178. JavascriptOperators::OP_SetProperty(i64Object, highPropRecord->GetPropertyId(), high, scriptContext);
  179. return i64Object;
  180. }
  181. #endif
  182. void * UnboxAsmJsArguments(ScriptFunction* func, Var * origArgs, char * argDst, CallInfo callInfo)
  183. {
  184. void * address = reinterpret_cast<void*>(func->GetEntryPointInfo()->jsMethod);
  185. Assert(address);
  186. AsmJsFunctionInfo* info = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  187. ScriptContext* scriptContext = func->GetScriptContext();
  188. #if ENABLE_DEBUG_CONFIG_OPTIONS
  189. bool allowTestInputs = CONFIG_FLAG(WasmI64);
  190. #endif
  191. AsmJsModuleInfo::EnsureHeapAttached(func);
  192. ArgumentReader reader(&callInfo, origArgs);
  193. uint actualArgCount = reader.Info.Count - 1; // -1 for ScriptFunction
  194. argDst = argDst + MachPtr; // add one first so as to skip the ScriptFunction argument
  195. for (ArgSlot i = 0; i < info->GetArgCount(); i++)
  196. {
  197. if (info->GetArgType(i).isInt())
  198. {
  199. int32 intVal;
  200. if (i < actualArgCount)
  201. {
  202. #if ENABLE_DEBUG_CONFIG_OPTIONS
  203. if (allowTestInputs && JavascriptString::Is(*origArgs))
  204. {
  205. intVal = (int32)ConvertStringToInt64(*origArgs, scriptContext);
  206. }
  207. else
  208. #endif
  209. intVal = JavascriptMath::ToInt32(*origArgs, scriptContext);
  210. }
  211. else
  212. {
  213. intVal = 0;
  214. }
  215. #if TARGET_64
  216. *(int64*)(argDst) = 0;
  217. #endif
  218. *(int32*)argDst = intVal;
  219. argDst = argDst + MachPtr;
  220. }
  221. else if (info->GetArgType(i).isInt64())
  222. {
  223. #if ENABLE_DEBUG_CONFIG_OPTIONS
  224. if (!allowTestInputs)
  225. #endif
  226. {
  227. JavascriptError::ThrowTypeError(scriptContext, WASMERR_InvalidTypeConversion);
  228. }
  229. #if ENABLE_DEBUG_CONFIG_OPTIONS
  230. int64 val;
  231. if (i < actualArgCount)
  232. {
  233. if (JavascriptString::Is(*origArgs))
  234. {
  235. val = ConvertStringToInt64(*origArgs, scriptContext);
  236. }
  237. else if (JavascriptObject::Is(*origArgs))
  238. {
  239. RecyclableObject* object = RecyclableObject::FromVar(*origArgs);
  240. PropertyRecord const * lowPropRecord = nullptr;
  241. PropertyRecord const * highPropRecord = nullptr;
  242. scriptContext->GetOrAddPropertyRecord(_u("low"), (int)wcslen(_u("low")), &lowPropRecord);
  243. scriptContext->GetOrAddPropertyRecord(_u("high"), (int)wcslen(_u("high")), &highPropRecord);
  244. Var low = JavascriptOperators::OP_GetProperty(object, lowPropRecord->GetPropertyId(), scriptContext);
  245. Var high = JavascriptOperators::OP_GetProperty(object, highPropRecord->GetPropertyId(), scriptContext);
  246. uint64 lowVal = JavascriptMath::ToInt32(low, scriptContext);
  247. uint64 highVal = JavascriptMath::ToInt32(high, scriptContext);
  248. val = (highVal << 32) | (lowVal & 0xFFFFFFFF);
  249. }
  250. else
  251. {
  252. int32 intVal = JavascriptMath::ToInt32(*origArgs, scriptContext);
  253. val = (int64)intVal;
  254. }
  255. }
  256. else
  257. {
  258. val = 0;
  259. }
  260. *(int64*)(argDst) = val;
  261. argDst += sizeof(int64);
  262. #endif
  263. }
  264. else if (info->GetArgType(i).isFloat())
  265. {
  266. float floatVal;
  267. if (i < actualArgCount)
  268. {
  269. #if ENABLE_DEBUG_CONFIG_OPTIONS
  270. if (allowTestInputs && JavascriptString::Is(*origArgs))
  271. {
  272. int32 val = (int32)ConvertStringToInt64(*origArgs, scriptContext);
  273. floatVal = *(float*)&val;
  274. }
  275. else
  276. #endif
  277. floatVal = (float)(JavascriptConversion::ToNumber(*origArgs, scriptContext));
  278. }
  279. else
  280. {
  281. floatVal = (float)(JavascriptNumber::NaN);
  282. }
  283. #if TARGET_64
  284. *(int64*)(argDst) = 0;
  285. #endif
  286. *(float*)argDst = floatVal;
  287. argDst = argDst + MachPtr;
  288. }
  289. else if (info->GetArgType(i).isDouble())
  290. {
  291. double doubleVal;
  292. if (i < actualArgCount)
  293. {
  294. #if ENABLE_DEBUG_CONFIG_OPTIONS
  295. if (allowTestInputs && JavascriptString::Is(*origArgs))
  296. {
  297. int64 val = ConvertStringToInt64(*origArgs, scriptContext);
  298. doubleVal = *(double*)&val;
  299. }
  300. else
  301. #endif
  302. doubleVal = JavascriptConversion::ToNumber(*origArgs, scriptContext);
  303. }
  304. else
  305. {
  306. doubleVal = JavascriptNumber::NaN;
  307. }
  308. *(double*)argDst = doubleVal;
  309. argDst = argDst + sizeof(double);
  310. }
  311. else if (info->GetArgType(i).isSIMD())
  312. {
  313. AsmJsVarType argType = info->GetArgType(i);
  314. AsmJsSIMDValue simdVal = {0, 0, 0, 0};
  315. // SIMD values are copied unaligned.
  316. // 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.
  317. switch (argType.which())
  318. {
  319. case AsmJsType::Int32x4:
  320. if (!JavascriptSIMDInt32x4::Is(*origArgs))
  321. {
  322. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdInt32x4TypeMismatch, _u("Int32x4"));
  323. }
  324. simdVal = ((JavascriptSIMDInt32x4*)(*origArgs))->GetValue();
  325. break;
  326. case AsmJsType::Bool32x4:
  327. if (!JavascriptSIMDBool32x4::Is(*origArgs))
  328. {
  329. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdBool32x4TypeMismatch, _u("Bool32x4"));
  330. }
  331. simdVal = ((JavascriptSIMDBool32x4*)(*origArgs))->GetValue();
  332. break;
  333. case AsmJsType::Bool16x8:
  334. if (!JavascriptSIMDBool16x8::Is(*origArgs))
  335. {
  336. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdBool16x8TypeMismatch, _u("Bool16x8"));
  337. }
  338. simdVal = ((JavascriptSIMDBool16x8*)(*origArgs))->GetValue();
  339. break;
  340. case AsmJsType::Bool8x16:
  341. if (!JavascriptSIMDBool8x16::Is(*origArgs))
  342. {
  343. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdBool8x16TypeMismatch, _u("Bool8x16"));
  344. }
  345. simdVal = ((JavascriptSIMDBool8x16*)(*origArgs))->GetValue();
  346. break;
  347. case AsmJsType::Float32x4:
  348. if (!JavascriptSIMDFloat32x4::Is(*origArgs))
  349. {
  350. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdFloat32x4TypeMismatch, _u("Float32x4"));
  351. }
  352. simdVal = ((JavascriptSIMDFloat32x4*)(*origArgs))->GetValue();
  353. break;
  354. case AsmJsType::Float64x2:
  355. if (!JavascriptSIMDFloat64x2::Is(*origArgs))
  356. {
  357. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdFloat64x2TypeMismatch, _u("Float64x2"));
  358. }
  359. simdVal = ((JavascriptSIMDFloat64x2*)(*origArgs))->GetValue();
  360. break;
  361. case AsmJsType::Int16x8:
  362. if (!JavascriptSIMDInt16x8::Is(*origArgs))
  363. {
  364. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdInt16x8TypeMismatch, _u("Int16x8"));
  365. }
  366. simdVal = ((JavascriptSIMDInt16x8*)(*origArgs))->GetValue();
  367. break;
  368. case AsmJsType::Int8x16:
  369. if (!JavascriptSIMDInt8x16::Is(*origArgs))
  370. {
  371. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdInt8x16TypeMismatch, _u("Int8x16"));
  372. }
  373. simdVal = ((JavascriptSIMDInt8x16*)(*origArgs))->GetValue();
  374. break;
  375. case AsmJsType::Uint32x4:
  376. if (!JavascriptSIMDUint32x4::Is(*origArgs))
  377. {
  378. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdUint32x4TypeMismatch, _u("Uint32x4"));
  379. }
  380. simdVal = ((JavascriptSIMDUint32x4*)(*origArgs))->GetValue();
  381. break;
  382. case AsmJsType::Uint16x8:
  383. if (!JavascriptSIMDUint16x8::Is(*origArgs))
  384. {
  385. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdUint16x8TypeMismatch, _u("Uint16x8"));
  386. }
  387. simdVal = ((JavascriptSIMDUint16x8*)(*origArgs))->GetValue();
  388. break;
  389. case AsmJsType::Uint8x16:
  390. if (!JavascriptSIMDUint8x16::Is(*origArgs))
  391. {
  392. JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdUint8x16TypeMismatch, _u("Uint8x16"));
  393. }
  394. simdVal = ((JavascriptSIMDUint8x16*)(*origArgs))->GetValue();
  395. break;
  396. default:
  397. Assert(UNREACHED);
  398. }
  399. *(AsmJsSIMDValue*)argDst = simdVal;
  400. argDst = argDst + sizeof(AsmJsSIMDValue);
  401. }
  402. else
  403. {
  404. Assert(UNREACHED);
  405. }
  406. ++origArgs;
  407. }
  408. // for convenience, lets take the opportunity to return the asm.js entrypoint address
  409. return address;
  410. }
  411. #if _M_X64
  412. // returns an array containing the size of each argument
  413. uint *GetArgsSizesArray(ScriptFunction* func)
  414. {
  415. AsmJsFunctionInfo* info = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  416. return info->GetArgsSizesArray();
  417. }
  418. int GetStackSizeForAsmJsUnboxing(ScriptFunction* func)
  419. {
  420. AsmJsFunctionInfo* info = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  421. int argSize = info->GetArgByteSize() + MachPtr;
  422. argSize = ::Math::Align<int32>(argSize, 16);
  423. if (argSize < 32)
  424. {
  425. argSize = 32; // convention is to always allocate spill space for rcx,rdx,r8,r9
  426. }
  427. PROBE_STACK_CALL(func->GetScriptContext(), func, argSize + Js::Constants::MinStackDefault);
  428. return argSize;
  429. }
  430. Var BoxAsmJsReturnValue(ScriptFunction* func, int64 intRetVal, double doubleRetVal, float floatRetVal, __m128 simdRetVal)
  431. {
  432. // ExternalEntryPoint doesn't know the return value, so it will send garbage for everything except actual return type
  433. Var returnValue = nullptr;
  434. // make call and convert primitive type back to Var
  435. AsmJsFunctionInfo* info = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  436. ScriptContext* scriptContext = func->GetScriptContext();
  437. switch (info->GetReturnType().which())
  438. {
  439. case AsmJsRetType::Void:
  440. returnValue = JavascriptOperators::OP_LdUndef(scriptContext);
  441. break;
  442. case AsmJsRetType::Signed:
  443. {
  444. returnValue = JavascriptNumber::ToVar((int)intRetVal, scriptContext);
  445. break;
  446. }
  447. case AsmJsRetType::Int64:
  448. {
  449. #if ENABLE_DEBUG_CONFIG_OPTIONS
  450. if (CONFIG_FLAG(WasmI64))
  451. {
  452. returnValue = CreateI64ReturnObject(intRetVal, scriptContext);
  453. break;
  454. }
  455. #endif
  456. JavascriptError::ThrowTypeError(scriptContext, WASMERR_InvalidTypeConversion);
  457. }
  458. case AsmJsRetType::Double:
  459. {
  460. returnValue = JavascriptNumber::NewWithCheck(doubleRetVal, scriptContext);
  461. break;
  462. }
  463. case AsmJsRetType::Float:
  464. {
  465. returnValue = JavascriptNumber::NewWithCheck(floatRetVal, scriptContext);
  466. break;
  467. }
  468. case AsmJsRetType::Float32x4:
  469. {
  470. X86SIMDValue simdVal;
  471. simdVal.m128_value = simdRetVal;
  472. returnValue = JavascriptSIMDFloat32x4::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  473. break;
  474. }
  475. case AsmJsRetType::Int32x4:
  476. {
  477. X86SIMDValue simdVal;
  478. simdVal.m128_value = simdRetVal;
  479. returnValue = JavascriptSIMDInt32x4::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  480. break;
  481. }
  482. case AsmJsRetType::Bool32x4:
  483. {
  484. X86SIMDValue simdVal;
  485. simdVal.m128_value = simdRetVal;
  486. returnValue = JavascriptSIMDBool32x4::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  487. break;
  488. }
  489. case AsmJsRetType::Bool16x8:
  490. {
  491. X86SIMDValue simdVal;
  492. simdVal.m128_value = simdRetVal;
  493. returnValue = JavascriptSIMDBool16x8::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  494. break;
  495. }
  496. case AsmJsRetType::Bool8x16:
  497. {
  498. X86SIMDValue simdVal;
  499. simdVal.m128_value = simdRetVal;
  500. returnValue = JavascriptSIMDBool8x16::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  501. break;
  502. }
  503. case AsmJsRetType::Float64x2:
  504. {
  505. X86SIMDValue simdVal;
  506. simdVal.m128_value = simdRetVal;
  507. returnValue = JavascriptSIMDFloat64x2::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  508. break;
  509. }
  510. case AsmJsRetType::Int16x8:
  511. {
  512. X86SIMDValue simdVal;
  513. simdVal.m128_value = simdRetVal;
  514. returnValue = JavascriptSIMDInt16x8::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  515. break;
  516. }
  517. case AsmJsRetType::Int8x16:
  518. {
  519. X86SIMDValue simdVal;
  520. simdVal.m128_value = simdRetVal;
  521. returnValue = JavascriptSIMDInt8x16::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  522. break;
  523. }
  524. case AsmJsRetType::Uint32x4:
  525. {
  526. X86SIMDValue simdVal;
  527. simdVal.m128_value = simdRetVal;
  528. returnValue = JavascriptSIMDUint32x4::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  529. break;
  530. }
  531. case AsmJsRetType::Uint16x8:
  532. {
  533. X86SIMDValue simdVal;
  534. simdVal.m128_value = simdRetVal;
  535. returnValue = JavascriptSIMDUint16x8::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  536. break;
  537. }
  538. case AsmJsRetType::Uint8x16:
  539. {
  540. X86SIMDValue simdVal;
  541. simdVal.m128_value = simdRetVal;
  542. returnValue = JavascriptSIMDUint8x16::New(&X86SIMDValue::ToSIMDValue(simdVal), scriptContext);
  543. break;
  544. }
  545. default:
  546. Assume(UNREACHED);
  547. }
  548. return returnValue;
  549. }
  550. #elif _M_IX86
  551. Var AsmJsExternalEntryPoint(RecyclableObject* entryObject, CallInfo callInfo, ...)
  552. {
  553. ARGUMENTS(args, callInfo);
  554. ScriptFunction* func = (ScriptFunction*)entryObject;
  555. FunctionBody* body = func->GetFunctionBody();
  556. AsmJsFunctionInfo* info = body->GetAsmJsFunctionInfo();
  557. int argSize = info->GetArgByteSize();
  558. void* dst;
  559. Var returnValue = 0;
  560. // TODO (michhol): wasm, heap should not ever be detached
  561. AsmJsModuleInfo::EnsureHeapAttached(func);
  562. argSize = ::Math::Align<int32>(argSize, 8);
  563. // Allocate stack space for args
  564. PROBE_STACK_CALL(func->GetScriptContext(), func, argSize + Js::Constants::MinStackDefault);
  565. dst = _alloca(argSize);
  566. const void * asmJSEntryPoint = UnboxAsmJsArguments(func, args.Values + 1, ((char*)dst) - MachPtr, callInfo);
  567. // make call and convert primitive type back to Var
  568. switch (info->GetReturnType().which())
  569. {
  570. case AsmJsRetType::Void:
  571. __asm
  572. {
  573. mov ecx, asmJSEntryPoint
  574. #ifdef _CONTROL_FLOW_GUARD
  575. call[__guard_check_icall_fptr]
  576. #endif
  577. push func
  578. call ecx
  579. }
  580. returnValue = JavascriptOperators::OP_LdUndef(func->GetScriptContext());
  581. break;
  582. case AsmJsRetType::Signed:{
  583. int32 ival = 0;
  584. __asm
  585. {
  586. mov ecx, asmJSEntryPoint
  587. #ifdef _CONTROL_FLOW_GUARD
  588. call[__guard_check_icall_fptr]
  589. #endif
  590. push func
  591. call ecx
  592. mov ival, eax
  593. }
  594. returnValue = JavascriptNumber::ToVar(ival, func->GetScriptContext());
  595. break;
  596. }
  597. case AsmJsRetType::Int64:
  598. {
  599. int32 iLow = 0, iHigh = 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. mov iLow, eax;
  609. mov iHigh, edx;
  610. }
  611. #if ENABLE_DEBUG_CONFIG_OPTIONS
  612. if (CONFIG_FLAG(WasmI64))
  613. {
  614. returnValue = CreateI64ReturnObject((int64)iLow | ((int64)iHigh << 32), func->GetScriptContext());
  615. break;
  616. }
  617. #endif
  618. JavascriptError::ThrowTypeError(func->GetScriptContext(), WASMERR_InvalidTypeConversion);
  619. }
  620. case AsmJsRetType::Double:{
  621. double dval = 0;
  622. __asm
  623. {
  624. mov ecx, asmJSEntryPoint
  625. #ifdef _CONTROL_FLOW_GUARD
  626. call[__guard_check_icall_fptr]
  627. #endif
  628. push func
  629. call ecx
  630. movsd dval, xmm0
  631. }
  632. returnValue = JavascriptNumber::NewWithCheck(dval, func->GetScriptContext());
  633. break;
  634. }
  635. case AsmJsRetType::Float:{
  636. float fval = 0;
  637. __asm
  638. {
  639. mov ecx, asmJSEntryPoint
  640. #ifdef _CONTROL_FLOW_GUARD
  641. call[__guard_check_icall_fptr]
  642. #endif
  643. push func
  644. call ecx
  645. movss fval, xmm0
  646. }
  647. returnValue = JavascriptNumber::NewWithCheck((double)fval, func->GetScriptContext());
  648. break;
  649. }
  650. case AsmJsRetType::Int32x4:
  651. AsmJsSIMDValue simdVal;
  652. simdVal.Zero();
  653. __asm
  654. {
  655. mov ecx, asmJSEntryPoint
  656. #ifdef _CONTROL_FLOW_GUARD
  657. call[__guard_check_icall_fptr]
  658. #endif
  659. push func
  660. call ecx
  661. movups simdVal, xmm0
  662. }
  663. returnValue = JavascriptSIMDInt32x4::New(&simdVal, func->GetScriptContext());
  664. break;
  665. case AsmJsRetType::Bool32x4:
  666. simdVal.Zero();
  667. __asm
  668. {
  669. mov ecx, asmJSEntryPoint
  670. #ifdef _CONTROL_FLOW_GUARD
  671. call[__guard_check_icall_fptr]
  672. #endif
  673. push func
  674. call ecx
  675. movups simdVal, xmm0
  676. }
  677. returnValue = JavascriptSIMDBool32x4::New(&simdVal, func->GetScriptContext());
  678. break;
  679. case AsmJsRetType::Bool16x8:
  680. simdVal.Zero();
  681. __asm
  682. {
  683. mov ecx, asmJSEntryPoint
  684. #ifdef _CONTROL_FLOW_GUARD
  685. call[__guard_check_icall_fptr]
  686. #endif
  687. push func
  688. call ecx
  689. movups simdVal, xmm0
  690. }
  691. returnValue = JavascriptSIMDBool16x8::New(&simdVal, func->GetScriptContext());
  692. break;
  693. case AsmJsRetType::Bool8x16:
  694. simdVal.Zero();
  695. __asm
  696. {
  697. mov ecx, asmJSEntryPoint
  698. #ifdef _CONTROL_FLOW_GUARD
  699. call[__guard_check_icall_fptr]
  700. #endif
  701. push func
  702. call ecx
  703. movups simdVal, xmm0
  704. }
  705. returnValue = JavascriptSIMDBool8x16::New(&simdVal, func->GetScriptContext());
  706. break;
  707. case AsmJsRetType::Float32x4:
  708. simdVal.Zero();
  709. __asm
  710. {
  711. mov ecx, asmJSEntryPoint
  712. #ifdef _CONTROL_FLOW_GUARD
  713. call[__guard_check_icall_fptr]
  714. #endif
  715. push func
  716. call ecx
  717. movups simdVal, xmm0
  718. }
  719. returnValue = JavascriptSIMDFloat32x4::New(&simdVal, func->GetScriptContext());
  720. break;
  721. case AsmJsRetType::Float64x2:
  722. simdVal.Zero();
  723. __asm
  724. {
  725. mov ecx, asmJSEntryPoint
  726. #ifdef _CONTROL_FLOW_GUARD
  727. call[__guard_check_icall_fptr]
  728. #endif
  729. push func
  730. call ecx
  731. movups simdVal, xmm0
  732. }
  733. returnValue = JavascriptSIMDFloat64x2::New(&simdVal, func->GetScriptContext());
  734. break;
  735. case AsmJsRetType::Int16x8:
  736. simdVal.Zero();
  737. __asm
  738. {
  739. mov ecx, asmJSEntryPoint
  740. #ifdef _CONTROL_FLOW_GUARD
  741. call[__guard_check_icall_fptr]
  742. #endif
  743. push func
  744. call ecx
  745. movups simdVal, xmm0
  746. }
  747. returnValue = JavascriptSIMDInt16x8::New(&simdVal, func->GetScriptContext());
  748. break;
  749. case AsmJsRetType::Int8x16:
  750. simdVal.Zero();
  751. __asm
  752. {
  753. mov ecx, asmJSEntryPoint
  754. #ifdef _CONTROL_FLOW_GUARD
  755. call[__guard_check_icall_fptr]
  756. #endif
  757. push func
  758. call ecx
  759. movups simdVal, xmm0
  760. }
  761. returnValue = JavascriptSIMDInt8x16::New(&simdVal, func->GetScriptContext());
  762. break;
  763. case AsmJsRetType::Uint32x4:
  764. simdVal.Zero();
  765. __asm
  766. {
  767. mov ecx, asmJSEntryPoint
  768. #ifdef _CONTROL_FLOW_GUARD
  769. call[__guard_check_icall_fptr]
  770. #endif
  771. push func
  772. call ecx
  773. movups simdVal, xmm0
  774. }
  775. returnValue = JavascriptSIMDUint32x4::New(&simdVal, func->GetScriptContext());
  776. break;
  777. case AsmJsRetType::Uint16x8:
  778. simdVal.Zero();
  779. __asm
  780. {
  781. mov ecx, asmJSEntryPoint
  782. #ifdef _CONTROL_FLOW_GUARD
  783. call[__guard_check_icall_fptr]
  784. #endif
  785. push func
  786. call ecx
  787. movups simdVal, xmm0
  788. }
  789. returnValue = JavascriptSIMDUint16x8::New(&simdVal, func->GetScriptContext());
  790. break;
  791. case AsmJsRetType::Uint8x16:
  792. simdVal.Zero();
  793. __asm
  794. {
  795. mov ecx, asmJSEntryPoint
  796. #ifdef _CONTROL_FLOW_GUARD
  797. call[__guard_check_icall_fptr]
  798. #endif
  799. push func
  800. call ecx
  801. movups simdVal, xmm0
  802. }
  803. returnValue = JavascriptSIMDUint8x16::New(&simdVal, func->GetScriptContext());
  804. break;
  805. default:
  806. Assume(UNREACHED);
  807. }
  808. return returnValue;
  809. }
  810. #endif
  811. }
  812. #endif