blob: 1d87b7a32eb7823bf91f0d6f485c86750a88fb79 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
// Implements typed array.
//----------------------------------------------------------------------------
#include "RuntimeLibraryPch.h"
namespace Js
{
Var DataView::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
Var newTarget = callInfo.Flags & CallFlags_NewTarget ? args.Values[args.Info.Count] : args[0];
bool isCtorSuperCall = (callInfo.Flags & CallFlags_New) && newTarget != nullptr && !JavascriptOperators::IsUndefined(newTarget);
Assert(isCtorSuperCall || !(callInfo.Flags & CallFlags_New) || args[0] == nullptr);
uint32 byteLength = 0;
uint32 mappedLength;
int32 offset = 0;
ArrayBufferBase* arrayBuffer = nullptr;
DataView* dataView;
//1. If NewTarget is undefined, throw a TypeError exception.
if (!(callInfo.Flags & CallFlags_New) || (newTarget && JavascriptOperators::IsUndefinedObject(newTarget)))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_ClassConstructorCannotBeCalledWithoutNew, _u("DataView"));
}
if (args.Info.Count < 2)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("buffer"));
}
// Currently the only reason we check for an external object is projection related, so it remains under conditional compilation.
RecyclableObject* jsArraySource = NULL;
if (JavascriptOperators::IsObject(args[1]) && JavascriptConversion::ToObject(args[1], scriptContext, &jsArraySource))
{
ArrayBuffer *ab = nullptr;
HRESULT hr = scriptContext->GetHostScriptContext()->ArrayBufferFromExternalObject(jsArraySource, &ab);
switch (hr)
{
case S_OK:
case S_FALSE:
arrayBuffer = ab;
// Both of these cases will be handled by the arrayBuffer null check.
break;
default:
// Any FAILURE HRESULT or unexpected HRESULT.
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_InvalidArgument, _u("buffer"));
break;
}
}
//2. If Type(buffer) is not Object, throw a TypeError exception.
//3. If buffer does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
if (arrayBuffer == nullptr)
{
if (ArrayBufferBase::Is(args[1]))
{
arrayBuffer = ArrayBufferBase::FromVar(args[1]);
}
else
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedArrayBufferObject, _u("buffer"));
}
}
//4. Let offset be ToIndex(byteOffset).
if (args.Info.Count > 2)
{
Var secondArgument = args[2];
offset = ArrayBuffer::ToIndex(secondArgument, JSERR_ArrayLengthConstructIncorrect, scriptContext, ArrayBuffer::MaxArrayBufferLength, false);
}
//5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
if (arrayBuffer->IsDetached())
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray);
}
//6. Let bufferByteLength be the value of buffer's[[ArrayBufferByteLength]] internal slot.
//7. If offset > bufferByteLength, throw a RangeError exception.
byteLength = arrayBuffer->GetByteLength();
if ((uint32)offset > byteLength)
{
JavascriptError::ThrowRangeError(
scriptContext, JSERR_DataView_InvalidArgument, _u("byteOffset"));
}
//8. If byteLength is either not present or is undefined, then
// a. Let viewByteLength be bufferByteLength - offset.
//9. Else,
// a. Let viewByteLength be ToIndex(byteLength).
// b. If offset + viewByteLength > bufferByteLength, throw a RangeError exception.
if (args.Info.Count > 3 && !JavascriptOperators::IsUndefinedObject(args[3]))
{
Var thirdArgument = args[3];
mappedLength = ArrayBuffer::ToIndex(thirdArgument, JSERR_ArrayLengthConstructIncorrect, scriptContext, ArrayBuffer::MaxArrayBufferLength, false);
uint32 viewRange = mappedLength + offset;
if (viewRange > byteLength || viewRange < mappedLength) // overflow indicates out-of-range
{
JavascriptError::ThrowRangeError(
scriptContext, JSERR_DataView_InvalidArgument, _u("byteLength"));
}
}
else
{
mappedLength = byteLength - offset;
}
//10. Let O be OrdinaryCreateFromConstructor(NewTarget, "%DataViewPrototype%", [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]]).
//11. Set O's[[DataView]] internal slot to true.
//12. Set O's[[ViewedArrayBuffer]] internal slot to buffer.
//13. Set O's[[ByteLength]] internal slot to viewByteLength.
//14. Set O's[[ByteOffset]] internal slot to offset.
//15. Return O.
dataView = scriptContext->GetLibrary()->CreateDataView(arrayBuffer, offset, mappedLength);
return isCtorSuperCall ?
JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), dataView, nullptr, scriptContext) :
dataView;
}
DataView::DataView(ArrayBufferBase* arrayBuffer, uint32 byteoffset, uint32 mappedLength, DynamicType* type)
: ArrayBufferParent(type, mappedLength, arrayBuffer),
byteOffset(byteoffset)
{
buffer = arrayBuffer->GetBuffer() + byteoffset;
}
BOOL DataView::Is(Var aValue)
{
return JavascriptOperators::GetTypeId(aValue) == TypeIds_DataView;
}
Var DataView::EntryGetInt8(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 2)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
return dataView->template GetValue<int8>(offset, _u("DataView.prototype.GetInt8"), FALSE);
}
Var DataView::EntryGetUint8(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 2)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
return dataView->GetValue<uint8>(offset, _u("DataView.prototype.GetUint8"), FALSE);
}
Var DataView::EntryGetInt16(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
BOOL isLittleEndian = FALSE;
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 2)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
}
if (args.Info.Count > 2)
{
isLittleEndian = JavascriptConversion::ToBoolean(args[2], scriptContext);
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
return dataView->GetValue<int16>(offset, _u("DataView.prototype.GetInt16"), isLittleEndian);
}
Var DataView::EntryGetUint16(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
BOOL isLittleEndian = FALSE;
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 2)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
}
if (args.Info.Count > 2)
{
isLittleEndian = JavascriptConversion::ToBoolean(args[2], scriptContext);
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
return dataView->template GetValue<uint16>(offset, _u("DataView.prototype.GetUint16"), isLittleEndian);
}
Var DataView::EntryGetUint32(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
BOOL isLittleEndian = FALSE;
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 2)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
}
if (args.Info.Count > 2)
{
isLittleEndian = JavascriptConversion::ToBoolean(args[2], scriptContext);
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
return dataView->GetValue<uint32>(offset, _u("DataView.prototype.GetUint32"), isLittleEndian);
}
Var DataView::EntryGetInt32(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
BOOL isLittleEndian = FALSE;
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 2)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
}
if (args.Info.Count > 2)
{
isLittleEndian = JavascriptConversion::ToBoolean(args[2], scriptContext);
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
return dataView->GetValue<int32>(offset, _u("DataView.prototype.GetInt32"), isLittleEndian);
}
Var DataView::EntryGetFloat32(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
BOOL isLittleEndian = FALSE;
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 2)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
}
if (args.Info.Count > 2)
{
isLittleEndian = JavascriptConversion::ToBoolean(args[2], scriptContext);
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
return dataView->GetValueWithCheck<float>(offset, _u("DataView.prototype.GetFloat32"), isLittleEndian);
}
Var DataView::EntryGetFloat64(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
BOOL isLittleEndian = FALSE;
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 2)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset"));
}
if (args.Info.Count > 2)
{
isLittleEndian = JavascriptConversion::ToBoolean(args[2], scriptContext);
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
return dataView->GetValueWithCheck<double>(offset, _u("DataView.prototype.GetFloat64"), isLittleEndian);
}
Var DataView::EntrySetInt8(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 3)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset or value"));
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
int8 value = JavascriptConversion::ToInt8(args[2], scriptContext);
dataView->SetValue<int8>(offset, value, _u("DataView.prototype.SetInt8"));
return scriptContext->GetLibrary()->GetUndefined();
}
Var DataView::EntrySetUint8(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 3)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset or value"));
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
uint8 value = JavascriptConversion::ToUInt8(args[2], scriptContext);
dataView->SetValue<uint8>(offset, value, _u("DataView.prototype.SetUint8"));
return scriptContext->GetLibrary()->GetUndefined();
}
Var DataView::EntrySetInt16(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
BOOL isLittleEndian = FALSE;
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 3)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset or value"));
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
int16 value = JavascriptConversion::ToInt16(args[2], scriptContext);
if (args.Info.Count > 3)
{
isLittleEndian = JavascriptConversion::ToBoolean(args[3], scriptContext);
}
dataView->SetValue<int16>(offset, value, _u("DataView.prototype.SetInt16"), isLittleEndian);
return scriptContext->GetLibrary()->GetUndefined();
}
Var DataView::EntrySetUint16(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
BOOL isLittleEndian = FALSE;
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 3)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset or value"));
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
uint16 value = JavascriptConversion::ToUInt16(args[2], scriptContext);
if (args.Info.Count > 3)
{
isLittleEndian = JavascriptConversion::ToBoolean(args[3], scriptContext);
}
dataView->SetValue<uint16>(offset, value, _u("DataView.prototype.SetUint16"), isLittleEndian);
return scriptContext->GetLibrary()->GetUndefined();
}
Var DataView::EntrySetInt32(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
BOOL isLittleEndian = FALSE;
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 3)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset or value"));
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
int32 value = JavascriptConversion::ToInt32(args[2], scriptContext);
if (args.Info.Count > 3)
{
isLittleEndian = JavascriptConversion::ToBoolean(args[3], scriptContext);
}
dataView->SetValue<int32>(offset, value, _u("DataView.prototype.SetInt32"), isLittleEndian);
return scriptContext->GetLibrary()->GetUndefined();
}
Var DataView::EntrySetUint32(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
BOOL isLittleEndian = FALSE;
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 3)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset or value"));
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
uint32 value = JavascriptConversion::ToUInt32(args[2], scriptContext);
if (args.Info.Count > 3)
{
isLittleEndian = JavascriptConversion::ToBoolean(args[3], scriptContext);
}
dataView->SetValue<uint32>(offset, value, _u("DataView.prototype.SetUint32"), isLittleEndian);
return scriptContext->GetLibrary()->GetUndefined();
}
Var DataView::EntrySetFloat32(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
BOOL isLittleEndian = FALSE;
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView, _u("offset or value"));
}
if (args.Info.Count < 3)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument);
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
float value = JavascriptConversion::ToFloat(args[2], scriptContext);
if (args.Info.Count > 3)
{
isLittleEndian = JavascriptConversion::ToBoolean(args[3], scriptContext);
}
dataView->SetValue<float>(offset, value, _u("DataView.prototype.SetFloat32"), isLittleEndian);
return scriptContext->GetLibrary()->GetUndefined();
}
Var DataView::EntrySetFloat64(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
BOOL isLittleEndian = FALSE;
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
if (args.Info.Count < 3)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, _u("offset or value"));
}
DataView* dataView = DataView::FromVar(args[0]);
uint32 offset = JavascriptConversion::ToUInt32(args[1], scriptContext);
double value = JavascriptConversion::ToNumber(args[2], scriptContext);
if (args.Info.Count > 3)
{
isLittleEndian = JavascriptConversion::ToBoolean(args[3], scriptContext);
}
dataView->SetValue<double>(offset, value, _u("DataView.prototype.SetFloat64"), isLittleEndian);
return scriptContext->GetLibrary()->GetUndefined();
}
Var DataView::EntryGetterBuffer(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
DataView* dataView = DataView::FromVar(args[0]);
ArrayBufferBase* arrayBuffer = dataView->GetArrayBuffer();
if (arrayBuffer == nullptr)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedArrayBufferObject);
}
return arrayBuffer;
}
Var DataView::EntryGetterByteLength(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
DataView* dataView = DataView::FromVar(args[0]);
ArrayBufferBase* arrayBuffer = dataView->GetArrayBuffer();
if (arrayBuffer == nullptr)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedArrayBufferObject);
}
else if (arrayBuffer->IsDetached())
{
return TaggedInt::ToVarUnchecked(0);
}
return JavascriptNumber::ToVar(dataView->GetLength(), scriptContext);
}
Var DataView::EntryGetterByteOffset(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count == 0 || !DataView::Is(args[0]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView);
}
DataView* dataView = DataView::FromVar(args[0]);
ArrayBufferBase* arrayBuffer = dataView->GetArrayBuffer();
if (arrayBuffer == nullptr)
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedArrayBufferObject);
}
else if (arrayBuffer->IsDetached())
{
return TaggedInt::ToVarUnchecked(0);
}
return JavascriptNumber::ToVar(dataView->GetByteOffset(), scriptContext);
}
BOOL DataView::SetItemWithAttributes(uint32 index, Var value, PropertyAttributes attributes)
{
AssertMsg(false, "We don't need a DataView to serve as object's internal array");
return FALSE;
}
void DataView::ClearLengthAndBufferOnDetach()
{
AssertMsg(this->GetArrayBuffer()->IsDetached(), "Array buffer should be detached if we're calling this method");
this->length = 0;
this->buffer = nullptr;
}
#ifdef _M_ARM
// Provide template specialization (only) for memory access at unaligned float/double address which causes data alignment exception otherwise.
template<>
Var DataView::GetValueWithCheck<float>(uint32 byteOffset, const char16 *funcName, BOOL isLittleEndian)
{
return this->GetValueWithCheck<float, float UNALIGNED*>(byteOffset, isLittleEndian, funcName);
}
template<>
Var DataView::GetValueWithCheck<double>(uint32 byteOffset, const char16 *funcName, BOOL isLittleEndian)
{
return this->GetValueWithCheck<double, double UNALIGNED*>(byteOffset, isLittleEndian, funcName);
}
template<>
void DataView::SetValue<float>(uint32 byteOffset, float value, const char16 *funcName, BOOL isLittleEndian)
{
this->SetValue<float, float UNALIGNED*>(byteOffset, value, isLittleEndian, funcName);
}
template<>
void DataView::SetValue<double>(uint32 byteOffset, double value, const char16 *funcName, BOOL isLittleEndian)
{
this->SetValue<double, double UNALIGNED*>(byteOffset, value, isLittleEndian, funcName);
}
#endif
}