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]); ArrayBuffer* 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); }
Var AsmJsChangeHeapBuffer(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 < 1 || !ArrayBuffer::Is(args[1])) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedArrayBufferObject); } ArrayBuffer* newArrayBuffer = ArrayBuffer::FromVar(args[1]); if (newArrayBuffer->IsDetached() || newArrayBuffer->GetByteLength() & 0xffffff || newArrayBuffer->GetByteLength() <= 0xffffff || newArrayBuffer->GetByteLength() > 0x80000000) { return JavascriptBoolean::ToVar(FALSE, scriptContext); } FrameDisplay* frame = ((ScriptFunction*)function)->GetEnvironment(); Var* moduleArrayBuffer = (Var*)frame->GetItem(0) + AsmJsModuleMemory::MemoryTableBeginOffset; *moduleArrayBuffer = newArrayBuffer; return JavascriptBoolean::ToVar(TRUE, scriptContext); }
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 && RecyclableObject::Is(newTarget); Assert(isCtorSuperCall || !(callInfo.Flags & CallFlags_New) || args[0] == nullptr); uint32 byteLength = 0; uint32 mappedLength; int32 offset = 0; double numberOffset = 0; ArrayBuffer* 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, L"DataView"); } if (args.Info.Count < 2) { JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, L"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)) { HRESULT hr = scriptContext->GetHostScriptContext()->ArrayBufferFromExternalObject(jsArraySource, &arrayBuffer); switch (hr) { case S_OK: case S_FALSE: // 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_InvalidArugment, L"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 (ArrayBuffer::Is(args[1])) { arrayBuffer = ArrayBuffer::FromVar(args[1]); } else { JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_NeedArgument, L"buffer"); } } //4. Let numberOffset be ToNumber(byteOffset). //5. Let offset be ToInteger(numberOffset). //6. ReturnIfAbrupt(offset). //7. If numberOffset <> offset or offset < 0, throw a RangeError exception. if (args.Info.Count > 2) { Var secondArgument = args[2]; numberOffset = JavascriptConversion::ToNumber(secondArgument, scriptContext); offset = JavascriptConversion::ToInt32(numberOffset); if (offset < 0 || numberOffset != offset) { JavascriptError::ThrowRangeError( scriptContext, JSERR_DataView_InvalidArugment, L"byteOffset"); } } //8. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. if (arrayBuffer->IsDetached()) { JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedDataView); } //9. Let bufferByteLength be the value of buffer's[[ArrayBufferByteLength]] internal slot. //10. If offset > bufferByteLength, throw a RangeError exception. byteLength = arrayBuffer->GetByteLength(); if ((uint32)offset > byteLength) { JavascriptError::ThrowRangeError( scriptContext, JSERR_DataView_InvalidArugment, L"byteOffset"); } //11. If byteLength is undefined, then // a. Let viewByteLength be bufferByteLength - offset. //12. Else, // a. Let viewByteLength be ToLength(byteLength). // b. ReturnIfAbrupt(viewLength). // c. If offset + viewByteLength > bufferByteLength, throw a RangeError exception. if (args.Info.Count > 3 && !JavascriptOperators::IsUndefinedObject(args[3])) { Var thirdArgument = args[3]; mappedLength = (uint32)JavascriptConversion::ToLength(thirdArgument, scriptContext); uint32 viewRange = mappedLength + offset; if (viewRange > byteLength || viewRange < mappedLength) // overflow indicates out-of-range { JavascriptError::ThrowRangeError( scriptContext, JSERR_DataView_InvalidArugment, L"byteLength"); } } else { mappedLength = byteLength - offset; } //13. Let O be OrdinaryCreateFromConstructor(NewTarget, "%DataViewPrototype%", [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]]). //14. ReturnIfAbrupt(O). //15. Set O's[[DataView]] internal slot to true. //16. Set O's[[ViewedArrayBuffer]] internal slot to buffer. //17. Set O's[[ByteLength]] internal slot to viewByteLength. //18. Set O's[[ByteOffset]] internal slot to offset. //19. Return O. dataView = scriptContext->GetLibrary()->CreateDataView(arrayBuffer, offset, mappedLength); return isCtorSuperCall ? JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), dataView, nullptr, scriptContext) : dataView; }