DataView.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. // Implements typed array.
  6. //----------------------------------------------------------------------------
  7. #include "RuntimeLibraryPch.h"
  8. namespace Js
  9. {
  10. Var DataView::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)
  11. {
  12. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  13. ARGUMENTS(args, callInfo);
  14. ScriptContext* scriptContext = function->GetScriptContext();
  15. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  16. Var newTarget = args.GetNewTarget();
  17. bool isCtorSuperCall = JavascriptOperators::GetAndAssertIsConstructorSuperCall(args);
  18. uint32 byteLength = 0;
  19. uint32 mappedLength;
  20. int32 offset = 0;
  21. ArrayBufferBase* arrayBuffer = nullptr;
  22. DataView* dataView;
  23. //1. If NewTarget is undefined, throw a TypeError exception.
  24. if (!(callInfo.Flags & CallFlags_New) || (newTarget && JavascriptOperators::IsUndefinedObject(newTarget)))
  25. {
  26. JavascriptError::ThrowTypeError(scriptContext, JSERR_ClassConstructorCannotBeCalledWithoutNew, _u("DataView"));
  27. }
  28. if (args.Info.Count < 2)
  29. {
  30. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("buffer"));
  31. }
  32. //2. If Type(buffer) is not Object, throw a TypeError exception.
  33. //3. If buffer does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
  34. if (arrayBuffer == nullptr)
  35. {
  36. if (VarIs<ArrayBufferBase>(args[1]))
  37. {
  38. arrayBuffer = VarTo<ArrayBufferBase>(args[1]);
  39. }
  40. else
  41. {
  42. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedArrayBufferObject, _u("buffer"));
  43. }
  44. }
  45. //4. Let offset be ToIndex(byteOffset).
  46. if (args.Info.Count > 2)
  47. {
  48. Var secondArgument = args[2];
  49. offset = ArrayBuffer::ToIndex(secondArgument, JSERR_ArrayLengthConstructIncorrect, scriptContext, ArrayBuffer::MaxArrayBufferLength, false);
  50. }
  51. //5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
  52. if (arrayBuffer->IsDetached())
  53. {
  54. JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray);
  55. }
  56. //6. Let bufferByteLength be the value of buffer's[[ArrayBufferByteLength]] internal slot.
  57. //7. If offset > bufferByteLength, throw a RangeError exception.
  58. byteLength = arrayBuffer->GetByteLength();
  59. if ((uint32)offset > byteLength)
  60. {
  61. JavascriptError::ThrowRangeError(
  62. scriptContext, JSERR_DataView_InvalidArgument, _u("byteOffset"));
  63. }
  64. //8. If byteLength is either not present or is undefined, then
  65. // a. Let viewByteLength be bufferByteLength - offset.
  66. //9. Else,
  67. // a. Let viewByteLength be ToIndex(byteLength).
  68. // b. If offset + viewByteLength > bufferByteLength, throw a RangeError exception.
  69. if (args.Info.Count > 3 && !JavascriptOperators::IsUndefinedObject(args[3]))
  70. {
  71. Var thirdArgument = args[3];
  72. mappedLength = ArrayBuffer::ToIndex(thirdArgument, JSERR_ArrayLengthConstructIncorrect, scriptContext, ArrayBuffer::MaxArrayBufferLength, false);
  73. uint32 viewRange = mappedLength + offset;
  74. if (viewRange > byteLength || viewRange < mappedLength) // overflow indicates out-of-range
  75. {
  76. JavascriptError::ThrowRangeError(
  77. scriptContext, JSERR_DataView_InvalidArgument, _u("byteLength"));
  78. }
  79. }
  80. else
  81. {
  82. mappedLength = byteLength - offset;
  83. }
  84. // Evaluation of the argument(s) above is reentrant and can detach the array.
  85. if (arrayBuffer->IsDetached())
  86. {
  87. JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray);
  88. }
  89. //10. Let O be OrdinaryCreateFromConstructor(NewTarget, "%DataViewPrototype%", [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]]).
  90. //11. Set O's[[DataView]] internal slot to true.
  91. //12. Set O's[[ViewedArrayBuffer]] internal slot to buffer.
  92. //13. Set O's[[ByteLength]] internal slot to viewByteLength.
  93. //14. Set O's[[ByteOffset]] internal slot to offset.
  94. //15. Return O.
  95. dataView = scriptContext->GetLibrary()->CreateDataView(arrayBuffer, offset, mappedLength);
  96. return isCtorSuperCall ?
  97. JavascriptOperators::OrdinaryCreateFromConstructor(VarTo<RecyclableObject>(newTarget), dataView, nullptr, scriptContext) :
  98. dataView;
  99. }
  100. DataView::DataView(ArrayBufferBase* arrayBuffer, uint32 byteoffset, uint32 mappedLength, DynamicType* type)
  101. : ArrayBufferParent(type, mappedLength, arrayBuffer),
  102. byteOffset(byteoffset)
  103. {
  104. buffer = arrayBuffer->GetBuffer() + byteoffset;
  105. }
  106. Var DataView::EntryGetInt8(RecyclableObject* function, CallInfo callInfo, ...)
  107. {
  108. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  109. ARGUMENTS(args, callInfo);
  110. ScriptContext* scriptContext = function->GetScriptContext();
  111. Assert(!(callInfo.Flags & CallFlags_New));
  112. if (args.Info.Count == 0 || !VarIs<DataView>(args[0]))
  113. {
  114. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  115. }
  116. if (args.Info.Count < 2)
  117. {
  118. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  119. }
  120. DataView* dataView = VarTo<DataView>(args[0]);
  121. return dataView->template GetValue<int8>(args[1], _u("DataView.prototype.GetInt8"), FALSE);
  122. }
  123. Var DataView::EntryGetUint8(RecyclableObject* function, CallInfo callInfo, ...)
  124. {
  125. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  126. ARGUMENTS(args, callInfo);
  127. ScriptContext* scriptContext = function->GetScriptContext();
  128. Assert(!(callInfo.Flags & CallFlags_New));
  129. if (args.Info.Count == 0 || !VarIs<DataView>(args[0]))
  130. {
  131. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  132. }
  133. if (args.Info.Count < 2)
  134. {
  135. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  136. }
  137. DataView* dataView = VarTo<DataView>(args[0]);
  138. return dataView->GetValue<uint8>(args[1], _u("DataView.prototype.GetUint8"), FALSE);
  139. }
  140. Var DataView::EntryGetInt16(RecyclableObject* function, CallInfo callInfo, ...)
  141. {
  142. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  143. ARGUMENTS(args, callInfo);
  144. ScriptContext* scriptContext = function->GetScriptContext();
  145. BOOL isLittleEndian = FALSE;
  146. Assert(!(callInfo.Flags & CallFlags_New));
  147. if (args.Info.Count == 0 || !VarIs<DataView>(args[0]))
  148. {
  149. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  150. }
  151. if (args.Info.Count < 2)
  152. {
  153. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  154. }
  155. if (args.Info.Count > 2)
  156. {
  157. isLittleEndian = JavascriptConversion::ToBoolean(args[2], scriptContext);
  158. }
  159. DataView* dataView = VarTo<DataView>(args[0]);
  160. return dataView->GetValue<int16>(args[1], _u("DataView.prototype.GetInt16"), isLittleEndian);
  161. }
  162. Var DataView::EntryGetUint16(RecyclableObject* function, CallInfo callInfo, ...)
  163. {
  164. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  165. ARGUMENTS(args, callInfo);
  166. ScriptContext* scriptContext = function->GetScriptContext();
  167. BOOL isLittleEndian = FALSE;
  168. Assert(!(callInfo.Flags & CallFlags_New));
  169. if (args.Info.Count == 0 || !VarIs<DataView>(args[0]))
  170. {
  171. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  172. }
  173. if (args.Info.Count < 2)
  174. {
  175. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  176. }
  177. if (args.Info.Count > 2)
  178. {
  179. isLittleEndian = JavascriptConversion::ToBoolean(args[2], scriptContext);
  180. }
  181. DataView* dataView = VarTo<DataView>(args[0]);
  182. return dataView->template GetValue<uint16>(args[1], _u("DataView.prototype.GetUint16"), isLittleEndian);
  183. }
  184. Var DataView::EntryGetUint32(RecyclableObject* function, CallInfo callInfo, ...)
  185. {
  186. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  187. ARGUMENTS(args, callInfo);
  188. ScriptContext* scriptContext = function->GetScriptContext();
  189. BOOL isLittleEndian = FALSE;
  190. Assert(!(callInfo.Flags & CallFlags_New));
  191. if (args.Info.Count == 0 || !VarIs<DataView>(args[0]))
  192. {
  193. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  194. }
  195. if (args.Info.Count < 2)
  196. {
  197. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  198. }
  199. if (args.Info.Count > 2)
  200. {
  201. isLittleEndian = JavascriptConversion::ToBoolean(args[2], scriptContext);
  202. }
  203. DataView* dataView = VarTo<DataView>(args[0]);
  204. return dataView->GetValue<uint32>(args[1], _u("DataView.prototype.GetUint32"), isLittleEndian);
  205. }
  206. Var DataView::EntryGetInt32(RecyclableObject* function, CallInfo callInfo, ...)
  207. {
  208. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  209. ARGUMENTS(args, callInfo);
  210. ScriptContext* scriptContext = function->GetScriptContext();
  211. BOOL isLittleEndian = FALSE;
  212. Assert(!(callInfo.Flags & CallFlags_New));
  213. if (args.Info.Count == 0 || !VarIs<DataView>(args[0]))
  214. {
  215. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  216. }
  217. if (args.Info.Count < 2)
  218. {
  219. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  220. }
  221. if (args.Info.Count > 2)
  222. {
  223. isLittleEndian = JavascriptConversion::ToBoolean(args[2], scriptContext);
  224. }
  225. DataView* dataView = VarTo<DataView>(args[0]);
  226. return dataView->GetValue<int32>(args[1], _u("DataView.prototype.GetInt32"), isLittleEndian);
  227. }
  228. Var DataView::EntryGetFloat32(RecyclableObject* function, CallInfo callInfo, ...)
  229. {
  230. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  231. ARGUMENTS(args, callInfo);
  232. ScriptContext* scriptContext = function->GetScriptContext();
  233. BOOL isLittleEndian = FALSE;
  234. Assert(!(callInfo.Flags & CallFlags_New));
  235. if (args.Info.Count == 0 || !VarIs<DataView>(args[0]))
  236. {
  237. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  238. }
  239. if (args.Info.Count < 2)
  240. {
  241. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  242. }
  243. if (args.Info.Count > 2)
  244. {
  245. isLittleEndian = JavascriptConversion::ToBoolean(args[2], scriptContext);
  246. }
  247. DataView* dataView = VarTo<DataView>(args[0]);
  248. return dataView->GetValueWithCheck<float>(args[1], _u("DataView.prototype.GetFloat32"), isLittleEndian);
  249. }
  250. Var DataView::EntryGetFloat64(RecyclableObject* function, CallInfo callInfo, ...)
  251. {
  252. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  253. ARGUMENTS(args, callInfo);
  254. ScriptContext* scriptContext = function->GetScriptContext();
  255. BOOL isLittleEndian = FALSE;
  256. Assert(!(callInfo.Flags & CallFlags_New));
  257. if (args.Info.Count == 0 || !VarIs<DataView>(args[0]))
  258. {
  259. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  260. }
  261. if (args.Info.Count < 2)
  262. {
  263. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  264. }
  265. if (args.Info.Count > 2)
  266. {
  267. isLittleEndian = JavascriptConversion::ToBoolean(args[2], scriptContext);
  268. }
  269. DataView* dataView = VarTo<DataView>(args[0]);
  270. return dataView->GetValueWithCheck<double>(args[1], _u("DataView.prototype.GetFloat64"), isLittleEndian);
  271. }
  272. Var DataView::EntrySetInt8(RecyclableObject* function, CallInfo callInfo, ...)
  273. {
  274. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  275. ARGUMENTS(args, callInfo);
  276. ScriptContext* scriptContext = function->GetScriptContext();
  277. Assert(!(callInfo.Flags & CallFlags_New));
  278. int8 value = 0;
  279. switch (args.Info.Count)
  280. {
  281. case 0:
  282. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  283. break;
  284. case 1:
  285. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  286. break;
  287. default:
  288. if (!VarIs<DataView>(args[0]))
  289. {
  290. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  291. break;
  292. }
  293. if (args.Info.Count > 2)
  294. {
  295. value = JavascriptConversion::ToInt8(args[2], scriptContext);
  296. }
  297. break;
  298. }
  299. DataView* dataView = VarTo<DataView>(args[0]);
  300. dataView->SetValue<int8>(args[1], value, _u("DataView.prototype.SetInt8"));
  301. return scriptContext->GetLibrary()->GetUndefined();
  302. }
  303. Var DataView::EntrySetUint8(RecyclableObject* function, CallInfo callInfo, ...)
  304. {
  305. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  306. ARGUMENTS(args, callInfo);
  307. ScriptContext* scriptContext = function->GetScriptContext();
  308. Assert(!(callInfo.Flags & CallFlags_New));
  309. uint8 value = 0;
  310. switch (args.Info.Count)
  311. {
  312. case 0:
  313. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  314. break;
  315. case 1:
  316. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  317. break;
  318. default:
  319. if (!VarIs<DataView>(args[0]))
  320. {
  321. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  322. break;
  323. }
  324. if (args.Info.Count > 2)
  325. {
  326. value = JavascriptConversion::ToUInt8(args[2], scriptContext);
  327. }
  328. break;
  329. }
  330. DataView* dataView = VarTo<DataView>(args[0]);
  331. dataView->SetValue<uint8>(args[1], value, _u("DataView.prototype.SetUint8"));
  332. return scriptContext->GetLibrary()->GetUndefined();
  333. }
  334. Var DataView::EntrySetInt16(RecyclableObject* function, CallInfo callInfo, ...)
  335. {
  336. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  337. ARGUMENTS(args, callInfo);
  338. ScriptContext* scriptContext = function->GetScriptContext();
  339. Assert(!(callInfo.Flags & CallFlags_New));
  340. BOOL isLittleEndian = FALSE;
  341. int16 value = 0;
  342. switch (args.Info.Count)
  343. {
  344. case 0:
  345. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  346. break;
  347. case 1:
  348. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  349. break;
  350. default:
  351. if (!VarIs<DataView>(args[0]))
  352. {
  353. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  354. break;
  355. }
  356. if (args.Info.Count > 2)
  357. {
  358. if (!JavascriptOperators::IsUndefined(args[2]))
  359. {
  360. value = JavascriptConversion::ToInt16(args[2], scriptContext);
  361. }
  362. if (args.Info.Count > 3)
  363. {
  364. isLittleEndian = JavascriptConversion::ToBoolean(args[3], scriptContext);
  365. }
  366. }
  367. break;
  368. }
  369. DataView* dataView = VarTo<DataView>(args[0]);
  370. dataView->SetValue<int16>(args[1], value, _u("DataView.prototype.SetInt16"), isLittleEndian);
  371. return scriptContext->GetLibrary()->GetUndefined();
  372. }
  373. Var DataView::EntrySetUint16(RecyclableObject* function, CallInfo callInfo, ...)
  374. {
  375. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  376. ARGUMENTS(args, callInfo);
  377. ScriptContext* scriptContext = function->GetScriptContext();
  378. Assert(!(callInfo.Flags & CallFlags_New));
  379. BOOL isLittleEndian = FALSE;
  380. uint16 value = 0;
  381. switch (args.Info.Count)
  382. {
  383. case 0:
  384. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  385. break;
  386. case 1:
  387. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  388. break;
  389. default:
  390. if (!VarIs<DataView>(args[0]))
  391. {
  392. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  393. break;
  394. }
  395. if (args.Info.Count > 2)
  396. {
  397. if (!JavascriptOperators::IsUndefined(args[2]))
  398. {
  399. value = JavascriptConversion::ToUInt16(args[2], scriptContext);
  400. }
  401. if (args.Info.Count > 3)
  402. {
  403. isLittleEndian = JavascriptConversion::ToBoolean(args[3], scriptContext);
  404. }
  405. }
  406. break;
  407. }
  408. DataView* dataView = VarTo<DataView>(args[0]);
  409. dataView->SetValue<uint16>(args[1], value, _u("DataView.prototype.SetUint16"), isLittleEndian);
  410. return scriptContext->GetLibrary()->GetUndefined();
  411. }
  412. Var DataView::EntrySetInt32(RecyclableObject* function, CallInfo callInfo, ...)
  413. {
  414. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  415. ARGUMENTS(args, callInfo);
  416. ScriptContext* scriptContext = function->GetScriptContext();
  417. Assert(!(callInfo.Flags & CallFlags_New));
  418. BOOL isLittleEndian = FALSE;
  419. int32 value = 0;
  420. switch (args.Info.Count)
  421. {
  422. case 0:
  423. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  424. break;
  425. case 1:
  426. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  427. break;
  428. default:
  429. if (!VarIs<DataView>(args[0]))
  430. {
  431. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  432. break;
  433. }
  434. if (args.Info.Count > 2)
  435. {
  436. if (!JavascriptOperators::IsUndefined(args[2]))
  437. {
  438. value = JavascriptConversion::ToInt32(args[2], scriptContext);
  439. }
  440. if (args.Info.Count > 3)
  441. {
  442. isLittleEndian = JavascriptConversion::ToBoolean(args[3], scriptContext);
  443. }
  444. }
  445. break;
  446. }
  447. DataView* dataView = VarTo<DataView>(args[0]);
  448. dataView->SetValue<int32>(args[1], value, _u("DataView.prototype.SetInt32"), isLittleEndian);
  449. return scriptContext->GetLibrary()->GetUndefined();
  450. }
  451. Var DataView::EntrySetUint32(RecyclableObject* function, CallInfo callInfo, ...)
  452. {
  453. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  454. ARGUMENTS(args, callInfo);
  455. ScriptContext* scriptContext = function->GetScriptContext();
  456. Assert(!(callInfo.Flags & CallFlags_New));
  457. BOOL isLittleEndian = FALSE;
  458. uint32 value = 0;
  459. switch (args.Info.Count)
  460. {
  461. case 0:
  462. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  463. break;
  464. case 1:
  465. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  466. break;
  467. default:
  468. if (!VarIs<DataView>(args[0]))
  469. {
  470. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  471. break;
  472. }
  473. if (args.Info.Count > 2)
  474. {
  475. if (!JavascriptOperators::IsUndefined(args[2]))
  476. {
  477. value = JavascriptConversion::ToUInt32(args[2], scriptContext);
  478. }
  479. if (args.Info.Count > 3)
  480. {
  481. isLittleEndian = JavascriptConversion::ToBoolean(args[3], scriptContext);
  482. }
  483. }
  484. break;
  485. }
  486. DataView* dataView = VarTo<DataView>(args[0]);
  487. dataView->SetValue<uint32>(args[1], value, _u("DataView.prototype.SetUint32"), isLittleEndian);
  488. return scriptContext->GetLibrary()->GetUndefined();
  489. }
  490. Var DataView::EntrySetFloat32(RecyclableObject* function, CallInfo callInfo, ...)
  491. {
  492. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  493. ARGUMENTS(args, callInfo);
  494. ScriptContext* scriptContext = function->GetScriptContext();
  495. Assert(!(callInfo.Flags & CallFlags_New));
  496. BOOL isLittleEndian = FALSE;
  497. float value = static_cast<float>(JavascriptNumber::NaN);
  498. switch (args.Info.Count)
  499. {
  500. case 0:
  501. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  502. break;
  503. case 1:
  504. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  505. break;
  506. default:
  507. if (!VarIs<DataView>(args[0]))
  508. {
  509. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  510. break;
  511. }
  512. if (args.Info.Count > 2)
  513. {
  514. if (!JavascriptOperators::IsUndefined(args[2]))
  515. {
  516. value = JavascriptConversion::ToFloat(args[2], scriptContext);
  517. }
  518. if (args.Info.Count > 3)
  519. {
  520. isLittleEndian = JavascriptConversion::ToBoolean(args[3], scriptContext);
  521. }
  522. }
  523. break;
  524. }
  525. DataView* dataView = VarTo<DataView>(args[0]);
  526. dataView->SetValue<float>(args[1], value, _u("DataView.prototype.SetFloat32"), isLittleEndian);
  527. return scriptContext->GetLibrary()->GetUndefined();
  528. }
  529. Var DataView::EntrySetFloat64(RecyclableObject* function, CallInfo callInfo, ...)
  530. {
  531. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  532. ARGUMENTS(args, callInfo);
  533. ScriptContext* scriptContext = function->GetScriptContext();
  534. Assert(!(callInfo.Flags & CallFlags_New));
  535. BOOL isLittleEndian = FALSE;
  536. double value = JavascriptNumber::NaN;
  537. switch (args.Info.Count)
  538. {
  539. case 0:
  540. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  541. break;
  542. case 1:
  543. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
  544. break;
  545. default:
  546. if (!VarIs<DataView>(args[0]))
  547. {
  548. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  549. break;
  550. }
  551. if (args.Info.Count > 2)
  552. {
  553. if (!JavascriptOperators::IsUndefined(args[2]))
  554. {
  555. value = JavascriptConversion::ToNumber(args[2], scriptContext);
  556. }
  557. if (args.Info.Count > 3)
  558. {
  559. isLittleEndian = JavascriptConversion::ToBoolean(args[3], scriptContext);
  560. }
  561. }
  562. break;
  563. }
  564. DataView* dataView = VarTo<DataView>(args[0]);
  565. dataView->SetValue<double>(args[1], value, _u("DataView.prototype.SetFloat64"), isLittleEndian);
  566. return scriptContext->GetLibrary()->GetUndefined();
  567. }
  568. Var DataView::EntryGetterBuffer(RecyclableObject* function, CallInfo callInfo, ...)
  569. {
  570. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  571. ARGUMENTS(args, callInfo);
  572. ScriptContext* scriptContext = function->GetScriptContext();
  573. Assert(!(callInfo.Flags & CallFlags_New));
  574. if (args.Info.Count == 0 || !VarIs<DataView>(args[0]))
  575. {
  576. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  577. }
  578. DataView* dataView = VarTo<DataView>(args[0]);
  579. ArrayBufferBase* arrayBuffer = dataView->GetArrayBuffer();
  580. if (arrayBuffer == nullptr)
  581. {
  582. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedArrayBufferObject);
  583. }
  584. return CrossSite::MarshalVar(scriptContext, arrayBuffer);
  585. }
  586. Var DataView::EntryGetterByteLength(RecyclableObject* function, CallInfo callInfo, ...)
  587. {
  588. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  589. ARGUMENTS(args, callInfo);
  590. ScriptContext* scriptContext = function->GetScriptContext();
  591. Assert(!(callInfo.Flags & CallFlags_New));
  592. if (args.Info.Count == 0 || !VarIs<DataView>(args[0]))
  593. {
  594. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  595. }
  596. DataView* dataView = VarTo<DataView>(args[0]);
  597. ArrayBufferBase* arrayBuffer = dataView->GetArrayBuffer();
  598. if (arrayBuffer == nullptr)
  599. {
  600. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedArrayBufferObject);
  601. }
  602. else if (arrayBuffer->IsDetached())
  603. {
  604. return TaggedInt::ToVarUnchecked(0);
  605. }
  606. return JavascriptNumber::ToVar(dataView->GetLength(), scriptContext);
  607. }
  608. Var DataView::EntryGetterByteOffset(RecyclableObject* function, CallInfo callInfo, ...)
  609. {
  610. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  611. ARGUMENTS(args, callInfo);
  612. ScriptContext* scriptContext = function->GetScriptContext();
  613. Assert(!(callInfo.Flags & CallFlags_New));
  614. if (args.Info.Count == 0 || !VarIs<DataView>(args[0]))
  615. {
  616. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
  617. }
  618. DataView* dataView = VarTo<DataView>(args[0]);
  619. ArrayBufferBase* arrayBuffer = dataView->GetArrayBuffer();
  620. if (arrayBuffer == nullptr)
  621. {
  622. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedArrayBufferObject);
  623. }
  624. else if (arrayBuffer->IsDetached())
  625. {
  626. return TaggedInt::ToVarUnchecked(0);
  627. }
  628. return JavascriptNumber::ToVar(dataView->GetByteOffset(), scriptContext);
  629. }
  630. BOOL DataView::SetItemWithAttributes(uint32 index, Var value, PropertyAttributes attributes)
  631. {
  632. AssertMsg(false, "We don't need a DataView to serve as object's internal array");
  633. return FALSE;
  634. }
  635. void DataView::ClearLengthAndBufferOnDetach()
  636. {
  637. AssertMsg(this->GetArrayBuffer()->IsDetached(), "Array buffer should be detached if we're calling this method");
  638. this->length = 0;
  639. #if INT32VAR
  640. this->buffer = (BYTE*)TaggedInt::ToVarUnchecked(0);
  641. #else
  642. this->buffer = nullptr;
  643. #endif
  644. }
  645. #ifdef _M_ARM
  646. // Provide template specialization (only) for memory access at unaligned float/double address which causes data alignment exception otherwise.
  647. template<>
  648. Var DataView::GetValueWithCheck<float>(Var offset, const char16 *funcName, BOOL isLittleEndian)
  649. {
  650. return this->GetValueWithCheck<float, float UNALIGNED*>(offset, isLittleEndian, funcName);
  651. }
  652. template<>
  653. Var DataView::GetValueWithCheck<double>(Var offset, const char16 *funcName, BOOL isLittleEndian)
  654. {
  655. return this->GetValueWithCheck<double, double UNALIGNED*>(offset, isLittleEndian, funcName);
  656. }
  657. template<>
  658. void DataView::SetValue<float>(Var offset, float value, const char16 *funcName, BOOL isLittleEndian)
  659. {
  660. this->SetValue<float, float UNALIGNED*>(offset, value, isLittleEndian, funcName);
  661. }
  662. template<>
  663. void DataView::SetValue<double>(Var offset, double value, const char16 *funcName, BOOL isLittleEndian)
  664. {
  665. this->SetValue<double, double UNALIGNED*>(offset, value, isLittleEndian, funcName);
  666. }
  667. #endif
  668. }