DataView.cpp 27 KB

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