/*
* Copyright (c) 2016-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef __EscargotArrayObject__
#define __EscargotArrayObject__
#include "runtime/Object.h"
#include "runtime/ErrorObject.h"
#include "runtime/IteratorObject.h"
namespace Escargot {
#define ESCARGOT_ARRAY_NON_FASTMODE_MIN_SIZE 65536 * 16
#define ESCARGOT_ARRAY_NON_FASTMODE_START_MIN_GAP 1024
class ArrayIteratorObject;
class ArrayObject : public Object {
friend class VMInstance;
friend class Global;
friend class ByteCodeInterpreter;
friend class EnumerateObjectWithDestruction;
friend class EnumerateObjectWithIteration;
friend Value builtinArrayConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget);
friend void initializeCustomAllocators();
friend int getValidValueInArrayObject(void* ptr, GC_mark_custom_result* arr);
public:
explicit ArrayObject(ExecutionState& state);
explicit ArrayObject(ExecutionState& state, Object* proto);
ArrayObject(ExecutionState& state, const uint64_t& size, bool shouldConsiderHole = true);
ArrayObject(ExecutionState& state, Object* proto, const uint64_t& size, bool shouldConsiderHole = true);
ArrayObject(ExecutionState& state, const Value* src, const uint64_t& size);
ArrayObject(ExecutionState& state, Object* proto, const Value* src, const uint64_t& size);
static ArrayObject* createSpreadArray(ExecutionState& state);
virtual bool isInlineCacheable() override
{
return false;
}
virtual ObjectHasPropertyResult hasProperty(ExecutionState& state, const ObjectPropertyName& P) override;
virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override;
virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) override;
void defineOwnPropertyThrowsException(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc)
{
if (!ArrayObject::defineOwnProperty(state, P, desc)) {
throwCannotDefineError(state, P.toObjectStructurePropertyName(state));
}
}
virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override;
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey = true) override;
virtual void sort(ExecutionState& state, int64_t length, const std::function& comp) override;
virtual ObjectGetResult getIndexedProperty(ExecutionState& state, const Value& property, const Value& receiver) override;
virtual ObjectHasPropertyResult hasIndexedProperty(ExecutionState& state, const Value& propertyName) override;
virtual bool setIndexedProperty(ExecutionState& state, const Value& property, const Value& value, const Value& receiver) override;
virtual bool preventExtensions(ExecutionState&) override;
// Use custom allocator for Array object (for Badtime)
void* operator new(size_t size);
void* operator new[](size_t size) = delete;
static void iterateArrays(ExecutionState& state, HeapObjectIteratorCallback callback);
void defineOwnIndexedPropertyWithExpandedLength(ExecutionState& state, const size_t& index, const Value& value)
{
ASSERT(index < arrayLength(state));
if (LIKELY(isFastModeArray())) {
setFastModeArrayValueWithoutExpanding(state, index, value);
} else {
defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(index)), ObjectPropertyDescriptor(value, ObjectPropertyDescriptor::AllPresent));
}
}
protected:
ArrayObject()
: Object()
, m_arrayLength(0)
#if !defined(ESCARGOT_64) || !defined(ESCARGOT_USE_32BIT_IN_64BIT)
, m_fastModeData(nullptr)
#endif
{
// dummy default constructor
// only called by Global::initialize to set tag value
}
private:
ALWAYS_INLINE bool isFastModeArray()
{
if (UNLIKELY(hasRareData())) {
return rareData()->m_isFastModeArrayObject;
}
return true;
}
bool isLengthPropertyWritable()
{
return hasRareData() ? rareData()->m_isArrayObjectLengthWritable : true;
}
void setFastModeArrayValueWithoutExpanding(ExecutionState& state, size_t idx, const Value& v)
{
ASSERT(isFastModeArray());
ASSERT(idx < arrayLength(state));
m_fastModeData[idx] = v;
}
ALWAYS_INLINE uint32_t arrayLength(ExecutionState&)
{
return m_arrayLength;
}
bool setArrayLength(ExecutionState& state, const Value& newLength);
bool setArrayLength(ExecutionState& state, const uint32_t newLength, bool useFitStorage = false, bool considerHole = true);
void convertIntoNonFastMode(ExecutionState& state);
ObjectGetResult getVirtualValue(ExecutionState& state, const ObjectPropertyName& P);
uint32_t m_arrayLength;
#if defined(ESCARGOT_64) && defined(ESCARGOT_USE_32BIT_IN_64BIT)
TightVectorWithNoSize> m_fastModeData;
#else
ObjectPropertyValue* m_fastModeData;
#endif
};
class ArrayPrototypeObject : public ArrayObject {
friend class Global;
public:
explicit ArrayPrototypeObject(ExecutionState& state);
private:
ArrayPrototypeObject()
: ArrayObject()
{
// dummy default constructor
// only called by Global::initialize to set tag value
}
};
class ArrayIteratorObject : public IteratorObject {
public:
enum Type {
TypeKey,
TypeValue,
TypeKeyValue
};
ArrayIteratorObject(ExecutionState& state, Object* array, Type type);
virtual bool isArrayIteratorObject() const override
{
return true;
}
virtual std::pair advance(ExecutionState& state) override;
void* operator new(size_t size);
void* operator new[](size_t size) = delete;
private:
Object* m_array;
size_t m_iteratorNextIndex;
Type m_type;
};
} // namespace Escargot
#endif