DataView.cpp 28 KB

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