Esempio n. 1
0
    void TTDebuggerSourceLocation::SetLocation(const TTDebuggerSourceLocation& other)
    {
#if !ENABLE_TTD_DEBUGGING
        AssertMsg(false, "Debugger is not enabled so you shouldn't be calling this");
        this->Clear();
#else
        this->m_etime = other.m_etime;
        this->m_ftime = other.m_ftime;
        this->m_ltime = other.m_ltime;

        this->m_docid = other.m_docid;

        this->m_functionLine = other.m_functionLine;
        this->m_functionColumn = other.m_functionColumn;

        this->m_line = other.m_line;
        this->m_column = other.m_column;

        if(this->m_sourceFile != nullptr)
        {
            delete[] this->m_sourceFile;
        }
        this->m_sourceFile = nullptr;

        if(other.m_sourceFile != nullptr)
        {
            size_t char16Length = wcslen(other.m_sourceFile) + 1;
            size_t byteLength = char16Length * sizeof(char16);

            this->m_sourceFile = new char16[char16Length];
            js_memcpy_s(this->m_sourceFile, byteLength, other.m_sourceFile, byteLength);
        }
#endif
    }
Esempio n. 2
0
Js::Var CreateBuffer(const uint8* buf, uint size, void* user_data)
{
    Context* ctx = (Context*)user_data;
    ArrayBuffer* arrayBuffer = ctx->scriptContext->GetLibrary()->CreateArrayBuffer(size);
    js_memcpy_s(arrayBuffer->GetBuffer(), arrayBuffer->GetByteLength(), buf, size);
    return arrayBuffer;
}
    const StElemInfo *ReadOnlyDynamicProfileInfo::GetStElemInfo(FunctionBody *functionBody, ProfileId stElemId)
    {
        Assert(functionBody);
        Assert(stElemId < functionBody->GetProfiledStElemCount());

        // This data is accessed multiple times. Since the original profile data may be changing on the foreground thread,
        // the first time it's accessed it will be copied from the original profile data (if we're jitting in the
        // background).
        if(!stElemInfo)
        {
            if(backgroundAllocator)
            {
                // Jitting in the background
                StElemInfo *const info = AnewArray(backgroundAllocator, StElemInfo, functionBody->GetProfiledStElemCount());
                js_memcpy_s(
                    info,
                    functionBody->GetProfiledStElemCount() * sizeof(info[0]),
                    profileInfo->GetStElemInfo(),
                    functionBody->GetProfiledStElemCount() * sizeof(info[0]));
                stElemInfo = info;
            }
            else
            {
                // Jitting in the foreground
                stElemInfo = profileInfo->GetStElemInfo();
            }
        }
        return &stElemInfo[stElemId];
    }
Esempio n. 4
0
    bool BigInt::FResize(long clu)
    {
        AssertBiNoVal(this);

        ulong *prglu;

        if (clu <= m_cluMax)
            return true;

        clu += clu;
        if (m_prglu == m_rgluInit)
        {
            if ((INT_MAX / sizeof(ulong) < clu) || (NULL == (prglu = (ulong *)malloc(clu * sizeof(ulong)))))
                return false;
            if (0 < m_clu)
                js_memcpy_s(prglu, clu * sizeof(ulong), m_prglu, m_clu * sizeof(ulong));
        }
        else if (NULL == (prglu = (ulong *)realloc(m_prglu, clu * sizeof(ulong))))
            return false;

        m_prglu = prglu;
        m_cluMax = clu;

        AssertBiNoVal(this);
        return true;
    }
Esempio n. 5
0
    void TTDebuggerSourceLocation::SetLocation(int64 etime, int64 ftime, int64 ltime, Js::FunctionBody* body, ULONG line, LONG column)
    {
#if !ENABLE_TTD_DEBUGGING
        AssertMsg(false, "Debugger is not enabled so you shouldn't be calling this");
        this->Clear();
#else
        this->m_etime = etime;
        this->m_ftime = ftime;
        this->m_ltime = ltime;

        this->m_docid = body->GetUtf8SourceInfo()->GetSourceInfoId();

        this->m_functionLine = body->GetLineNumber();
        this->m_functionColumn = body->GetColumnNumber();

        this->m_line = (uint32)line;
        this->m_column = (uint32)column;

        if(this->m_sourceFile != nullptr)
        {
            delete[] this->m_sourceFile;
        }
        this->m_sourceFile = nullptr;

        const char16* sourceFile = body->GetSourceContextInfo()->url;
        if(sourceFile != nullptr)
        {
            size_t char16Length = wcslen(sourceFile) + 1;
            size_t byteLength = char16Length * sizeof(char16);

            this->m_sourceFile = new char16[char16Length];
            js_memcpy_s(this->m_sourceFile, byteLength, sourceFile, byteLength);
        }
#endif
    }
Esempio n. 6
0
 Utf8SourceInfo*
 Utf8SourceInfo::New(ScriptContext* scriptContext, LPCUTF8 utf8String, int32 length, size_t numBytes, SRCINFO const* srcInfo)
 {
     utf8char_t * newUtf8String = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), utf8char_t, numBytes + 1);
     js_memcpy_s(newUtf8String, numBytes + 1, utf8String, numBytes + 1);
     return NewWithNoCopy(scriptContext, newUtf8String, length, numBytes, srcInfo);
 }
Esempio n. 7
0
    void TTDComparePath::WritePathToConsole(ThreadContext* threadContext, bool printNewline, char16* namebuff) const
    {
        if(this->m_prefix != nullptr)
        {
            this->m_prefix->WritePathToConsole(threadContext, false, namebuff);
        }

        if(this->m_stepKind == StepKind::PropertyData || this->m_stepKind == StepKind::PropertyGetter || this->m_stepKind == StepKind::PropertySetter)
        {
            const Js::PropertyRecord* pRecord = threadContext->GetPropertyName((Js::PropertyId)this->m_step.IndexOrPID);
            js_memcpy_s(namebuff, 256 * sizeof(char16), pRecord->GetBuffer(), pRecord->GetLength() * sizeof(char16));
            namebuff[pRecord->GetLength()] = _u('\0');
        }

        bool isFirst = (this->m_prefix == nullptr);
        switch(this->m_stepKind)
        {
        case StepKind::Empty:
            break;
        case StepKind::Root:
            wprintf(_u("root#%I64i"), this->m_step.IndexOrPID);
            break;
        case StepKind::PropertyData:
            wprintf(_u("%ls%ls"), (isFirst ? _u("") : _u(".")), namebuff);
            break;
        case StepKind::PropertyGetter:
            wprintf(_u("%ls<%ls"), (isFirst ? _u("") : _u(".")), namebuff);
            break;
        case StepKind::PropertySetter:
            wprintf(_u("%ls>%ls"), (isFirst ? _u("") : _u(".")), namebuff);
            break;
        case StepKind::Array:
            wprintf(_u("[%I64i]"), this->m_step.IndexOrPID);
            break;
        case StepKind::Scope:
            wprintf(_u("%ls_scope[%I64i]"), (isFirst ? _u("") : _u(".")), this->m_step.IndexOrPID);
            break;
        case StepKind::SlotArray:
            wprintf(_u("%ls_slots[%I64i]"), (isFirst ? _u("") : _u(".")), this->m_step.IndexOrPID);
            break;
        case StepKind::FunctionBody:
            wprintf(_u("%ls%ls"), (isFirst ? _u("") : _u(".")), this->m_step.OptName);
            break;
        case StepKind::Special:
            wprintf(_u("%ls_%ls"), (isFirst ? _u("") : _u(".")), this->m_step.OptName);
            break;
        case StepKind::SpecialArray:
            wprintf(_u("%ls_%ls[%I64i]"), (isFirst ? _u("") : _u(".")), this->m_step.OptName, this->m_step.IndexOrPID);
            break;
        default:
            TTDAssert(false, "Unknown tag in switch statement!!!");
            break;
        }

        if(printNewline)
        {
            wprintf(_u("\n"));
        }
    }
Esempio n. 8
0
    // This will make a copy of the entire buffer
    InternalString *InternalString::New(ArenaAllocator* alloc, const char16* content, charcount_t length)
    {
        size_t bytelength = sizeof(char16) * length;
        DWORD* allocbuffer = (DWORD*)alloc->Alloc(sizeof(DWORD) + bytelength + sizeof(char16));
        allocbuffer[0] = (DWORD) bytelength;

        char16* buffer = (char16*)(allocbuffer+1);
        js_memcpy_s(buffer, bytelength, content, bytelength);
        buffer[length] = L'\0';
        InternalString* newInstance = Anew(alloc, InternalString, buffer, length);
        return newInstance;
    }
Esempio n. 9
0
void
BVFixed::Copy(const BVFixed*bv)
{
    AssertBV(bv);
    Assert(len >= bv->len);

#if 1
    js_memcpy_s(&this->data[0], WordCount() * sizeof(BVUnit), &bv->data[0], bv->WordCount() * sizeof(BVUnit));
#else
    this->for_each(bv, &BVUnit::Copy);
#endif
}
Esempio n. 10
0
    TTDebuggerSourceLocation::TTDebuggerSourceLocation(const TTDebuggerSourceLocation& other)
        : m_etime(other.m_etime), m_ftime(other.m_ftime), m_ltime(other.m_ltime), m_sourceFile(nullptr), m_docid(other.m_docid), m_functionLine(other.m_functionLine), m_functionColumn(other.m_functionColumn), m_line(other.m_line), m_column(other.m_column)
    {
        if(other.m_sourceFile != nullptr)
        {
            size_t char16Length = wcslen(other.m_sourceFile) + 1;
            size_t byteLength = char16Length * sizeof(char16);

            this->m_sourceFile = new char16[char16Length];
            js_memcpy_s(this->m_sourceFile, byteLength, other.m_sourceFile, byteLength);
        }
    }
Esempio n. 11
0
    bool BigInt::FInitFromRglu(ulong *prglu, long clu)
    {
        AssertBi(this);
        Assert(clu >= 0);
        Assert(prglu != 0);

        if (clu > m_cluMax && !FResize(clu))
            return false;
        m_clu = clu;
        if (clu > 0)
            js_memcpy_s(m_prglu, m_clu * sizeof(ulong), prglu, clu * sizeof(ulong));

        AssertBi(this);
        return true;
    }
Esempio n. 12
0
    // This will make a copy of the entire buffer
    // Allocated using recycler memory
    InternalString *InternalString::New(Recycler* recycler, const char16* content, charcount_t length)
    {
        size_t bytelength = sizeof(char16) * length;

        // Allocate 3 extra bytes, two for the first DWORD with the size, the third for the null character
        // This is so that we can pretend that internal strings are BSTRs for purposes of clients who want to use
        // it as thus
        const unsigned char offset = sizeof(DWORD)/sizeof(char16);
        InternalString* newInstance = RecyclerNewPlusLeaf(recycler, bytelength + (sizeof(DWORD) + sizeof(char16)), InternalString, nullptr, length, offset);
        DWORD* allocbuffer = (DWORD*) (newInstance + 1);
        allocbuffer[0] = (DWORD) bytelength;
        char16* buffer = (char16*)(allocbuffer + 1);
        js_memcpy_s(buffer, bytelength, content, bytelength);
        buffer[length] = L'\0';
        newInstance->m_content = (const char16*) allocbuffer;

        return newInstance;
    }
    Var JavascriptGeneratorFunction::EntryAsyncFunctionImplementation(RecyclableObject* function, CallInfo callInfo, ...)
    {
        PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
        ARGUMENTS(stackArgs, callInfo);

        ScriptContext* scriptContext = function->GetScriptContext();
        JavascriptLibrary* library = scriptContext->GetLibrary();
        RecyclableObject* prototype = scriptContext->GetLibrary()->GetNull();

        // InterpreterStackFrame takes a pointer to the args, so copy them to the recycler heap
        // and use that buffer for this InterpreterStackFrame.
        Var* argsHeapCopy = RecyclerNewArray(scriptContext->GetRecycler(), Var, stackArgs.Info.Count);
        js_memcpy_s(argsHeapCopy, sizeof(Var) * stackArgs.Info.Count, stackArgs.Values, sizeof(Var) * stackArgs.Info.Count);
        Arguments heapArgs(callInfo, argsHeapCopy);

        JavascriptExceptionObject* e = nullptr;
        JavascriptPromiseResolveOrRejectFunction* resolve;
        JavascriptPromiseResolveOrRejectFunction* reject;
        JavascriptPromiseAsyncSpawnExecutorFunction* executor =
            library->CreatePromiseAsyncSpawnExecutorFunction(
                JavascriptPromise::EntryJavascriptPromiseAsyncSpawnExecutorFunction,
                scriptContext->GetLibrary()->CreateGenerator(heapArgs, JavascriptAsyncFunction::FromVar(function)->GetGeneratorVirtualScriptFunction(), prototype),
                stackArgs[0]);

        JavascriptPromise* promise = library->CreatePromise();
        JavascriptPromise::InitializePromise(promise, &resolve, &reject, scriptContext);

        try
        {
            CALL_FUNCTION(executor, CallInfo(CallFlags_Value, 3), library->GetUndefined(), resolve, reject);
        }
        catch (JavascriptExceptionObject* ex)
        {
            e = ex;
        }

        if (e != nullptr)
        {
            JavascriptPromise::TryRejectWithExceptionObject(e, reject, scriptContext);
        }

        return promise;
    }
Esempio n. 14
0
        void ExternalCallEventLogEntry_ProcessArgs(EventLogEntry* evt, int32 rootDepth, Js::JavascriptFunction* function, uint32 argc, Js::Var* argv, double beginTime, UnlinkableSlabAllocator& alloc)
        {
            ExternalCallEventLogEntry* callEvt = GetInlineEventDataAs<ExternalCallEventLogEntry, EventKind::ExternalCallTag>(evt);
            callEvt->AdditionalInfo = alloc.SlabAllocateStruct<ExternalCallEventLogEntry_AdditionalInfo>();

            callEvt->RootNestingDepth = rootDepth;
            callEvt->ArgCount = argc + 1;

            static_assert(sizeof(TTDVar) == sizeof(Js::Var), "These need to be the same size (and have same bit layout) for this to work!");

            callEvt->ArgArray = alloc.SlabAllocateArray<TTDVar>(callEvt->ArgCount);
            callEvt->ArgArray[0] = static_cast<TTDVar>(function);
            js_memcpy_s(callEvt->ArgArray + 1, (callEvt->ArgCount - 1) * sizeof(TTDVar), argv, argc * sizeof(Js::Var));

            //Initialize this info in case we terminate without completing (e.g. exit(1))
            callEvt->AdditionalInfo->BeginTime = beginTime;
            callEvt->AdditionalInfo->EndTime = -1.0;

            callEvt->ReturnValue = nullptr;
            callEvt->AdditionalInfo->LastNestedEventTime = TTD_EVENT_MAXTIME;
        }
Esempio n. 15
0
void
BVFixed::CopyBits(const BVFixed * bv, BVIndex i)
{
    AssertBV(bv);
    BVIndex offset = BVUnit::Offset(i);
    BVIndex position = BVUnit::Position(i);
    BVIndex len = bv->WordCount() - position;
    BVIndex copylen = min(WordCount(), len);
    if (offset == 0)
    {
        js_memcpy_s(&this->data[0], copylen * sizeof(BVUnit), &bv->data[BVUnit::Position(i)], copylen * sizeof(BVUnit));
    }
    else
    {
        BVIndex pos = position;
        for (BVIndex j = 0; j < copylen; j++)
        {
            Assert(pos < bv->WordCount());
            this->data[j] = bv->data[pos];
            this->data[j].ShiftRight(offset);

            pos++;
            if (pos >= bv->WordCount())
            {
                break;
            }
            BVUnit temp = bv->data[pos];
            temp.ShiftLeft(BVUnit::BitsPerWord - offset);
            this->data[j].Or(temp);
        }
    }
#if DBG
    for (BVIndex curr = i; curr < i + this->Length(); curr++)
    {
        Assert(this->Test(curr - i) == bv->Test(curr));
    }
#endif
}
    Var JavascriptGeneratorFunction::EntryGeneratorFunctionImplementation(RecyclableObject* function, CallInfo callInfo, ...)
    {
        PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
        ARGUMENTS(stackArgs, callInfo);

        ScriptContext* scriptContext = function->GetScriptContext();
        JavascriptGeneratorFunction* generatorFunction = JavascriptGeneratorFunction::FromVar(function);

        // InterpreterStackFrame takes a pointer to the args, so copy them to the recycler heap
        // and use that buffer for this InterpreterStackFrame.
        Var* argsHeapCopy = RecyclerNewArray(scriptContext->GetRecycler(), Var, stackArgs.Info.Count);
        js_memcpy_s(argsHeapCopy, sizeof(Var) * stackArgs.Info.Count, stackArgs.Values, sizeof(Var) * stackArgs.Info.Count);
        Arguments heapArgs(callInfo, argsHeapCopy);

        DynamicObject* prototype = scriptContext->GetLibrary()->CreateGeneratorConstructorPrototypeObject();
        JavascriptGenerator* generator = scriptContext->GetLibrary()->CreateGenerator(heapArgs, generatorFunction->scriptFunction, prototype);
        // Set the prototype from constructor
        JavascriptOperators::OrdinaryCreateFromConstructor(function, generator, prototype, scriptContext);

        Assert(!(callInfo.Flags & CallFlags_New));

        return generator;
    }
Esempio n. 17
0
LeakReport::UrlRecord *
LeakReport::LogUrl(char16 const * url, void * globalObject)
{
    UrlRecord * record = NoCheckHeapNewStruct(UrlRecord);

    size_t length = wcslen(url) + 1; // Add 1 for the NULL.
    char16* urlCopy = NoCheckHeapNewArray(char16, length);
    js_memcpy_s(urlCopy, (length - 1) * sizeof(char16), url, (length - 1) * sizeof(char16));
    urlCopy[length - 1] = _u('\0');

    record->url = urlCopy;
#if _MSC_VER
    record->time = _time64(NULL);
#else
    record->time = time(NULL);
#endif
    record->tid = ::GetCurrentThreadId();
    record->next = nullptr;
    record->scriptEngine = nullptr;
    record->globalObject = globalObject;

    AutoCriticalSection autocs(&s_cs);
    if (LeakReport::urlRecordHead == nullptr)
    {
        Assert(LeakReport::urlRecordTail == nullptr);
        LeakReport::urlRecordHead = record;
        LeakReport::urlRecordTail = record;
    }
    else
    {
        LeakReport::urlRecordTail->next = record;
        LeakReport::urlRecordTail = record;
    }

    return record;
}
void InterpreterThunkEmitter::NewThunkBlock()
{
    Assert(this->thunkCount == 0);
    BYTE* buffer;
    BYTE* currentBuffer;
    DWORD bufferSize = BlockSize;
    DWORD thunkCount = 0;

    allocation = emitBufferManager.AllocateBuffer(bufferSize, &buffer, /*readWrite*/ true);
    currentBuffer = buffer;

#ifdef _M_X64
    PrologEncoder prologEncoder(allocator);
    prologEncoder.EncodeSmallProlog(PrologSize, StackAllocSize);
    DWORD pdataSize = prologEncoder.SizeOfPData();
#elif defined(_M_ARM32_OR_ARM64)
    DWORD pdataSize = sizeof(RUNTIME_FUNCTION);
#else
    DWORD pdataSize = 0;
#endif
    DWORD bytesRemaining = bufferSize;
    DWORD bytesWritten = 0;
    DWORD epilogSize = sizeof(Epilog);

    // Ensure there is space for PDATA at the end
    BYTE* pdataStart = currentBuffer + (bufferSize - Math::Align(pdataSize, EMIT_BUFFER_ALIGNMENT));
    BYTE* epilogStart = pdataStart - Math::Align(epilogSize, EMIT_BUFFER_ALIGNMENT);

    // Copy the thunk buffer and modify it.
    js_memcpy_s(currentBuffer, bytesRemaining, InterpreterThunk, HeaderSize);
    EncodeInterpreterThunk(currentBuffer, buffer, HeaderSize, epilogStart, epilogSize);
    currentBuffer += HeaderSize;
    bytesRemaining -= HeaderSize;

    // Copy call buffer
    DWORD callSize = sizeof(Call);
    while(currentBuffer < epilogStart - callSize)
    {
        js_memcpy_s(currentBuffer, bytesRemaining, Call, callSize);
#if _M_ARM
        int offset = (epilogStart - (currentBuffer + JmpOffset));
        Assert(offset >= 0);
        DWORD encodedOffset = EncoderMD::BranchOffset_T2_24(offset);
        DWORD encodedBranch = /*opcode=*/ 0x9000F000 | encodedOffset;
        Emit(currentBuffer, JmpOffset, encodedBranch);
#elif _M_ARM64
        int64 offset = (epilogStart - (currentBuffer + JmpOffset));
        Assert(offset >= 0);
        DWORD encodedOffset = EncoderMD::BranchOffset_26(offset);
        DWORD encodedBranch = /*opcode=*/ 0x14000000 | encodedOffset;
        Emit(currentBuffer, JmpOffset, encodedBranch);
#else
        // jump requires an offset from the end of the jump instruction.
        int offset = (int)(epilogStart - (currentBuffer + JmpOffset + sizeof(int)));
        Assert(offset >= 0);
        Emit(currentBuffer, JmpOffset, offset);
#endif
        currentBuffer += callSize;
        bytesRemaining -= callSize;
        thunkCount++;
    }

    // Fill any gap till start of epilog
    bytesWritten = FillDebugBreak(currentBuffer, (DWORD)(epilogStart - currentBuffer));
    bytesRemaining -= bytesWritten;
    currentBuffer += bytesWritten;

    // Copy epilog
    bytesWritten = CopyWithAlignment(currentBuffer, bytesRemaining, Epilog, epilogSize, EMIT_BUFFER_ALIGNMENT);
    currentBuffer += bytesWritten;
    bytesRemaining -= bytesWritten;

    // Generate and register PDATA
#if PDATA_ENABLED
    BYTE* epilogEnd = epilogStart + epilogSize;
    DWORD functionSize = (DWORD)(epilogEnd - buffer);
    Assert(pdataStart == currentBuffer);
#ifdef _M_X64
    Assert(bytesRemaining >= pdataSize);
    BYTE* pdata = prologEncoder.Finalize(buffer, functionSize, pdataStart);
    bytesWritten = CopyWithAlignment(pdataStart, bytesRemaining, pdata, pdataSize, EMIT_BUFFER_ALIGNMENT);
#elif defined(_M_ARM32_OR_ARM64)
    RUNTIME_FUNCTION pdata;
    GeneratePdata(buffer, functionSize, &pdata);
    bytesWritten = CopyWithAlignment(pdataStart, bytesRemaining, (const BYTE*)&pdata, pdataSize, EMIT_BUFFER_ALIGNMENT);
#endif
    void* pdataTable;
    PDataManager::RegisterPdata((PRUNTIME_FUNCTION) pdataStart, (ULONG_PTR) buffer, (ULONG_PTR) epilogEnd, &pdataTable);
#endif
    if (!emitBufferManager.CommitReadWriteBufferForInterpreter(allocation, buffer, bufferSize))
    {
        Js::Throw::OutOfMemory();
    }

    // Call to set VALID flag for CFG check
    ThreadContext::GetContextForCurrentThread()->SetValidCallTargetForCFG(buffer);

    // Update object state only at the end when everything has succeeded - and no exceptions can be thrown.
    ThunkBlock* block = this->thunkBlocks.PrependNode(allocator, buffer);
    UNREFERENCED_PARAMETER(block);
#if PDATA_ENABLED
    block->SetPdata(pdataTable);
#endif
    this->thunkCount = thunkCount;
    this->thunkBuffer = buffer;
}
Esempio n. 19
0
    // SharedArrayBuffer.prototype.slice
    Var SharedArrayBuffer::EntrySlice(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'");

        Assert(!(callInfo.Flags & CallFlags_New));

        if (!SharedArrayBuffer::Is(args[0]))
        {
            JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedSharedArrayBufferObject);
        }

        JavascriptLibrary* library = scriptContext->GetLibrary();
        SharedArrayBuffer* currentBuffer = SharedArrayBuffer::FromVar(args[0]);

        int64 currentLen = (int64)currentBuffer->GetByteLength();
        int64 start = 0, end = 0;
        int64 newLen = 0;

        // If no start or end arguments, use the entire length
        if (args.Info.Count < 2)
        {
            newLen = currentLen;
        }
        else
        {
            start = JavascriptArray::GetIndexFromVar(args[1], currentLen, scriptContext);

            // If no end argument, use length as the end
            if (args.Info.Count < 3 || args[2] == library->GetUndefined())
            {
                end = currentLen;
            }
            else
            {
                end = JavascriptArray::GetIndexFromVar(args[2], currentLen, scriptContext);
            }

            newLen = end > start ? end - start : 0;
        }

        // We can't have allocated an SharedArrayBuffer with byteLength > MaxArrayBufferLength.
        // start and end are clamped to valid indices, so the new length also cannot exceed MaxArrayBufferLength.
        // Therefore, should be safe to cast down newLen to uint32.
        Assert(newLen < MaxSharedArrayBufferLength);
        uint32 newbyteLength = static_cast<uint32>(newLen);

        SharedArrayBuffer* newBuffer = nullptr;

        if (scriptContext->GetConfig()->IsES6SpeciesEnabled())
        {
            Var constructorVar = JavascriptOperators::SpeciesConstructor(currentBuffer, scriptContext->GetLibrary()->GetSharedArrayBufferConstructor(), scriptContext);

            JavascriptFunction* constructor = JavascriptFunction::FromVar(constructorVar);

            Js::Var constructorArgs[] = { constructor, JavascriptNumber::ToVar(newbyteLength, scriptContext) };
            Js::CallInfo constructorCallInfo(Js::CallFlags_New, _countof(constructorArgs));
            Js::Var newVar = JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext);

            if (!SharedArrayBuffer::Is(newVar))
            {
                JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedSharedArrayBufferObject);
            }

            newBuffer = SharedArrayBuffer::FromVar(newVar);

            if (newBuffer == currentBuffer)
            {
                JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedSharedArrayBufferObject);
            }

            if (newBuffer->GetByteLength() < newbyteLength)
            {
                JavascriptError::ThrowTypeError(scriptContext, JSERR_ArgumentOutOfRange, _u("SharedArrayBuffer.prototype.slice"));
            }
        }
        else
        {
            newBuffer = library->CreateSharedArrayBuffer(newbyteLength);
        }

        Assert(newBuffer);
        Assert(newBuffer->GetByteLength() >= newbyteLength);

        // Don't bother doing memcpy if we aren't copying any elements
        if (newbyteLength > 0)
        {
            AssertMsg(currentBuffer->GetBuffer() != nullptr, "buffer must not be null when we copy from it");

            js_memcpy_s(newBuffer->GetBuffer(), newbyteLength, currentBuffer->GetBuffer() + start, newbyteLength);
        }

        return newBuffer;
    }