<commit_before>/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "avmplus.h"
#include "zlib.h"

// Bugzilla 729336 followup: fix project files to add lzma to search path
#include "../other-licenses/lzma/LzmaLib.h"

// Compiler and architecture dependent byte swapping functions.
//
// Define HAVE_BYTESWAP32 and/or HAVE_BYTESWAP16 on platforms where there are
// instructions or fast idioms for byte swapping backed by compiler intrinsics.
//
// This is not quite a porting API, because we do not abstract byteSwap16()
// and byteSwap32() generally: if fast byte swapping is not available then 
// it's probably faster to use generic in-line byte load/store code.  Hence 
// the code is all here and not in a platform file.
//
// Survey of architectures:
//
//   On x86 there is BSWAP (32-bit) and XCHG (16-bit).
//   On PPC there is supposedly a three-operation sequence that byte swaps 32-bit
//     data [Warren, Hacker's Delight].
//   On MIPS a two-operation sequence of WSBH and ROTR can byte swap a 32-bit word,
//     WSBH can byte swap a halfword by itself.
//   On SH4 a combination of SWAP.B (twice) and SWAP.H should byte swap a 32-bit word,
//     while SWAP.B by itself should byte swap a 16-bit halfword.
//   On ARM there are the REV (32-bit) and REV16 (16-bit) instructions since ARMv6.
//   To my knowledge SPARC has no byte swap instructions.
//
// Survey of compilers:
//
//   MSVC starting with Visual Studio 2005 have _byteswap_ulong, _byteswap_ushort, _byteswap_uint64.
//   GCC starting with 4.3 have __builtin_bswap32 and __builtin_bswap64, must include <byteswap.h>

#if defined VMCFG_IA32 || defined VMCFG_AMD64 || defined VMCFG_PPC || defined VMCFG_MIPS || defined VMCFG_SH4 || defined VMCFG_ARM

#if defined _MSC_VER
#define HAVE_BYTESWAP32
#define HAVE_BYTESWAP16
REALLY_INLINE uint32_t byteSwap32(uint32_t x)
{
    return _byteswap_ulong(x);
}

REALLY_INLINE uint16_t byteSwap16(uint16_t x)
{
    return _byteswap_ushort(x);
}
#endif // _MSC_VER

#if defined __GNUC__ && (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 || __GNUC__ > 4)
#include <byteswap.h>
#define HAVE_BYTESWAP32

REALLY_INLINE uint32_t byteSwap32(uint32_t x)
{
    return __builtin_bswap32(x);
}
#endif // __GNUC__

#endif // Various architectures with byteswap idioms backed by intrinsics

// MAX_BYTEARRAY_STORE_LENGTH is the largest value that can be taken on by m_length,
// strictly less than 2^32.  See constraint in ByteArray::Grower::ReallocBackingStore().
//
// MAX_BYTEARRAY_SHORT_ACCESS_LENGTH is a value no smaller than 4095 and no greater
// than 2^32-1-MAX_BYTEARRAY_STORE_LENGTH.
//
// The purpose of these two limits is to allow relatively efficient bounds checking
// on common ByteArray accesses, see comments on ByteArray::requestBytesForShortRead()
// and ByteArray::requestBytesForShortWrite() for more information.

#define MAX_BYTEARRAY_STORE_LENGTH (MMgc::GCHeap::kMaxObjectSize - MMgc::GCHeap::kBlockSize*2)
#define MAX_BYTEARRAY_SHORT_ACCESS_LENGTH (MMgc::GCHeap::kBlockSize*2 - 1)

namespace avmplus
{
    template <typename T> REALLY_INLINE T min(T a, T b) {
        return (a < b) ? a : b;
    }

    // Rounds a up to nearest integral multiple of b.
    // requires: T is integral type.
    // returns r, where r is least integral multiple of b such that r >= a.
    //
    // Bugzilla 699176: lift to shared header or specialize to uint64_t.
    template <typename T> REALLY_INLINE T roundUpTo(T a, T b) {
        return ((a + (b - 1)) / b) * b;
    }

    // When we might be reading or writing to ourself, use this function
    // apparently SunPro compiler doesn't like combining REALLY_INLINE with static functions in CPP files
    /*static*/
    REALLY_INLINE void move_or_copy(void* dst, const void* src, uint32_t count)
    {
        if ((uintptr_t(dst) - uintptr_t(src)) >= uintptr_t(count))
        {
            VMPI_memcpy(dst, src, count);
        }
        else
        {
            VMPI_memmove(dst, src, count);
        }
    }

    //
    // ByteArray
    //
    
    ByteArray::ByteArray(Toplevel* toplevel)
        : DataIOBase()
        , DataInput()
        , DataOutput()
        , m_toplevel(toplevel)
        , m_gc(toplevel->core()->GetGC())
        , m_subscribers(m_gc, 0)
        , m_copyOnWriteOwner(NULL)
        , m_position(0)
        , m_buffer(mmfx_new(Buffer()))
        , m_isShareable(false)
        , m_isLinkWrapper(false)
    {
        static_assert(uint64_t(MAX_BYTEARRAY_STORE_LENGTH) < 0x100000000ULL, "Constraint on MAX_BYTEARRAY_STORE_LENGTH");
        static_assert(MAX_BYTEARRAY_SHORT_ACCESS_LENGTH >= 4095, "Constraint on MAX_BYTEARRAY_SHORT_ACCESS_LENGTH");
        static_assert(uint64_t(MAX_BYTEARRAY_STORE_LENGTH) + uint64_t(MAX_BYTEARRAY_SHORT_ACCESS_LENGTH) < 0x100000000ULL, "Constraints on internal ByteArray constants");
        AvmAssert(m_gc != NULL);

        m_buffer->array = NULL;
        m_buffer->capacity = 0;
        m_buffer->length = 0;
    }


    ByteArray::ByteArray(Toplevel* toplevel, const ByteArray& other)
        : DataIOBase()
        , DataInput()
        , DataOutput()
        , m_toplevel(toplevel)
        , m_gc(toplevel->core()->GetGC())
        , m_subscribers(m_gc, 0)
        , m_copyOnWriteOwner(NULL)
        , m_position(0)
		, m_buffer(other.m_isShareable ? other.m_buffer : mmfx_new(Buffer) )
        , m_isShareable(other.m_isShareable)
        , m_isLinkWrapper(false)
    {
        AvmAssert(m_gc != NULL);
        if (m_isShareable) {
            return;
        }
        m_buffer->capacity = other.m_buffer->capacity;
        m_buffer->length = other.m_buffer->length;
        // only allocate a new array if the other bytearray has data in it
        if (other.m_buffer->array) {
            m_buffer->array = mmfx_new_array_opt(uint8_t, m_buffer->capacity, MMgc::kCanFailAndZero);

            if (!m_buffer->array)
               ThrowMemoryError();
            
            TellGcNewBufferMemory(m_buffer->array, m_buffer->capacity);
            VMPI_memcpy(m_buffer->array, other.m_buffer->array, m_buffer->length);
        }
        else {
            m_buffer->array = NULL;
        }
    }


    ByteArray::ByteArray(Toplevel* toplevel, ByteArray::Buffer* source, bool shareable)
        : DataIOBase()
        , DataInput()
        , DataOutput()
        , m_toplevel(toplevel)
        , m_gc(toplevel->core()->GetGC())
        , m_subscribers(m_gc, 0)
        , m_copyOnWriteOwner(NULL)
        , m_position(0)
        , m_buffer(source)
        , m_isShareable(shareable) 
        , m_isLinkWrapper(false)
    {
    }


    /* virtual */ void ByteArray::Buffer::destroy() 
    {
        if (array)
        {
            AvmAssert(capacity > 0);
            // FIXME: the lack of the following appears to be accidentally correct, because
            // for normal uses array will be NULL in this->destroy()
            // and the Isolate use doesn't signal dependent allocation
            //m_gc->SignalDependentDeallocation(capacity, MMgc::typeByteArray);
            mmfx_delete_array(array);
        }
        mmfx_delete(this);
    }

    /* virtual */ ByteArray::Buffer::~Buffer() 
    {<commit_msg>Bug 798493: Incorrect updating of ByteArray when passed between worker threads (p=michsmi,r=jasowill)    Integrate CL 1122494<commit_after>/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "avmplus.h"
#include "zlib.h"

// Bugzilla 729336 followup: fix project files to add lzma to search path
#include "../other-licenses/lzma/LzmaLib.h"

// Compiler and architecture dependent byte swapping functions.
//
// Define HAVE_BYTESWAP32 and/or HAVE_BYTESWAP16 on platforms where there are
// instructions or fast idioms for byte swapping backed by compiler intrinsics.
//
// This is not quite a porting API, because we do not abstract byteSwap16()
// and byteSwap32() generally: if fast byte swapping is not available then 
// it's probably faster to use generic in-line byte load/store code.  Hence 
// the code is all here and not in a platform file.
//
// Survey of architectures:
//
//   On x86 there is BSWAP (32-bit) and XCHG (16-bit).
//   On PPC there is supposedly a three-operation sequence that byte swaps 32-bit
//     data [Warren, Hacker's Delight].
//   On MIPS a two-operation sequence of WSBH and ROTR can byte swap a 32-bit word,
//     WSBH can byte swap a halfword by itself.
//   On SH4 a combination of SWAP.B (twice) and SWAP.H should byte swap a 32-bit word,
//     while SWAP.B by itself should byte swap a 16-bit halfword.
//   On ARM there are the REV (32-bit) and REV16 (16-bit) instructions since ARMv6.
//   To my knowledge SPARC has no byte swap instructions.
//
// Survey of compilers:
//
//   MSVC starting with Visual Studio 2005 have _byteswap_ulong, _byteswap_ushort, _byteswap_uint64.
//   GCC starting with 4.3 have __builtin_bswap32 and __builtin_bswap64, must include <byteswap.h>

#if defined VMCFG_IA32 || defined VMCFG_AMD64 || defined VMCFG_PPC || defined VMCFG_MIPS || defined VMCFG_SH4 || defined VMCFG_ARM

#if defined _MSC_VER
#define HAVE_BYTESWAP32
#define HAVE_BYTESWAP16
REALLY_INLINE uint32_t byteSwap32(uint32_t x)
{
    return _byteswap_ulong(x);
}

REALLY_INLINE uint16_t byteSwap16(uint16_t x)
{
    return _byteswap_ushort(x);
}
#endif // _MSC_VER

#if defined __GNUC__ && (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 || __GNUC__ > 4)
#include <byteswap.h>
#define HAVE_BYTESWAP32

REALLY_INLINE uint32_t byteSwap32(uint32_t x)
{
    return __builtin_bswap32(x);
}
#endif // __GNUC__

#endif // Various architectures with byteswap idioms backed by intrinsics

// MAX_BYTEARRAY_STORE_LENGTH is the largest value that can be taken on by m_length,
// strictly less than 2^32.  See constraint in ByteArray::Grower::ReallocBackingStore().
//
// MAX_BYTEARRAY_SHORT_ACCESS_LENGTH is a value no smaller than 4095 and no greater
// than 2^32-1-MAX_BYTEARRAY_STORE_LENGTH.
//
// The purpose of these two limits is to allow relatively efficient bounds checking
// on common ByteArray accesses, see comments on ByteArray::requestBytesForShortRead()
// and ByteArray::requestBytesForShortWrite() for more information.

#define MAX_BYTEARRAY_STORE_LENGTH (MMgc::GCHeap::kMaxObjectSize - MMgc::GCHeap::kBlockSize*2)
#define MAX_BYTEARRAY_SHORT_ACCESS_LENGTH (MMgc::GCHeap::kBlockSize*2 - 1)

namespace avmplus
{
    template <typename T> REALLY_INLINE T min(T a, T b) {
        return (a < b) ? a : b;
    }

    // Rounds a up to nearest integral multiple of b.
    // requires: T is integral type.
    // returns r, where r is least integral multiple of b such that r >= a.
    //
    // Bugzilla 699176: lift to shared header or specialize to uint64_t.
    template <typename T> REALLY_INLINE T roundUpTo(T a, T b) {
        return ((a + (b - 1)) / b) * b;
    }

    // When we might be reading or writing to ourself, use this function
    // apparently SunPro compiler doesn't like combining REALLY_INLINE with static functions in CPP files
    /*static*/
    REALLY_INLINE void move_or_copy(void* dst, const void* src, uint32_t count)
    {
        if ((uintptr_t(dst) - uintptr_t(src)) >= uintptr_t(count))
        {
            VMPI_memcpy(dst, src, count);
        }
        else
        {
            VMPI_memmove(dst, src, count);
        }
    }

    //
    // ByteArray
    //
    
    ByteArray::ByteArray(Toplevel* toplevel)
        : DataIOBase()
        , DataInput()
        , DataOutput()
        , m_toplevel(toplevel)
        , m_gc(toplevel->core()->GetGC())
        , m_subscribers(m_gc, 0)
        , m_copyOnWriteOwner(NULL)
        , m_position(0)
        , m_buffer(mmfx_new(Buffer()))
        , m_isShareable(false)
        , m_isLinkWrapper(false)
    {
        static_assert(uint64_t(MAX_BYTEARRAY_STORE_LENGTH) < 0x100000000ULL, "Constraint on MAX_BYTEARRAY_STORE_LENGTH");
        static_assert(MAX_BYTEARRAY_SHORT_ACCESS_LENGTH >= 4095, "Constraint on MAX_BYTEARRAY_SHORT_ACCESS_LENGTH");
        static_assert(uint64_t(MAX_BYTEARRAY_STORE_LENGTH) + uint64_t(MAX_BYTEARRAY_SHORT_ACCESS_LENGTH) < 0x100000000ULL, "Constraints on internal ByteArray constants");
        AvmAssert(m_gc != NULL);

        m_buffer->array = NULL;
        m_buffer->capacity = 0;
        m_buffer->length = 0;
    }


    ByteArray::ByteArray(Toplevel* toplevel, const ByteArray& other)
        : DataIOBase()
        , DataInput()
        , DataOutput()
        , m_toplevel(toplevel)
        , m_gc(toplevel->core()->GetGC())
        , m_subscribers(m_gc, 0)
        , m_copyOnWriteOwner(NULL)
        , m_position(0)
		, m_buffer(other.m_isShareable ? other.m_buffer : mmfx_new(Buffer) )
        , m_isShareable(other.m_isShareable)
        , m_isLinkWrapper(false)
    {
        AvmAssert(m_gc != NULL);
        if (m_isShareable) {
            return;
        }
        m_buffer->capacity = other.m_buffer->capacity;
        m_buffer->length = other.m_buffer->length;
        // only allocate a new array if the other bytearray has data in it
        if (other.m_buffer->array) {
            m_buffer->array = mmfx_new_array_opt(uint8_t, m_buffer->capacity, MMgc::kCanFailAndZero);

            if (!m_buffer->array)
               ThrowMemoryError();
            
            TellGcNewBufferMemory(m_buffer->array, m_buffer->capacity);
            VMPI_memcpy(m_buffer->array, other.m_buffer->array, m_buffer->length);
        }
        else {
            m_buffer->array = NULL;
        }
    }


    ByteArray::ByteArray(Toplevel* toplevel, ByteArray::Buffer* source, bool shareable)
        : DataIOBase()
        , DataInput()
        , DataOutput()
        , m_toplevel(toplevel)
        , m_gc(toplevel->core()->GetGC())
        , m_subscribers(m_gc, 0)
        , m_copyOnWriteOwner(NULL)
        , m_position(0)
        , m_buffer(source)
        , m_isShareable(shareable) 
        , m_isLinkWrapper(false)
    {
		// Note that this constructor is only used when receiving a ByteArray from another worker
		if (!m_isShareable) {
			// If we made a copy of the ByteArray (i.e. it's not sharable), then we should account for the memory that we're about to receive.
			// (until now, it's been sitting in the message queue, not assigned to any GC)
			TellGcNewBufferMemory(m_buffer->array, m_buffer->capacity);
		}
    }


    /* virtual */ void ByteArray::Buffer::destroy() 
    {
        if (array)
        {
            AvmAssert(capacity > 0);
            // FIXME: the lack of the following appears to be accidentally correct, because
            // for normal uses array will be NULL in this->destroy()
            // and the Isolate use doesn't signal dependent allocation
            //m_gc->SignalDependentDeallocation(capacity, MMgc::typeByteArray);
            mmfx_delete_array(array);
        }
        mmfx_delete(this);
    }

    /* virtual */ ByteArray::Buffer::~Buffer() 
    {
{'fraction_non_alphanumeric': 0.10275348234531909, 'fraction_numerical': 0.02105604146420473, 'mean_word_length': 2.825526641883519, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2721050', 'n_tokens_mistral': 5311, 'n_tokens_neox': 4971, 'n_words': 1414}