Implement ES6 Symbol.hasInstance, iterator, toStringTag, toPrimitive and built-ins (#46)

* Implement Array.from
* Disable part of ES6-shim due to wrong implementation

Signed-off-by: seonghyun kim <sh8281.kim@samsung.com>
This commit is contained in:
김승현/Tizen Platform Lab(SR)/Engineer/삼성전자 2018-01-19 15:20:27 +09:00 committed by 양지윤/Tizen Platform Lab(SR)/Engineer/삼성전자
commit e66f512b32
61 changed files with 1407 additions and 419 deletions

View file

@ -29,6 +29,7 @@
#include "runtime/VMInstance.h"
#include "runtime/SandBox.h"
#include "runtime/Environment.h"
#include "runtime/SymbolObject.h"
#include "runtime/ArrayObject.h"
#include "runtime/ErrorObject.h"
#include "runtime/DateObject.h"
@ -63,10 +64,12 @@ DEFINE_CAST(Context);
DEFINE_CAST(SandBox);
DEFINE_CAST(ExecutionState);
DEFINE_CAST(String);
DEFINE_CAST(Symbol);
DEFINE_CAST(PointerValue);
DEFINE_CAST(Object);
DEFINE_CAST(ArrayObject)
DEFINE_CAST(StringObject)
DEFINE_CAST(SymbolObject)
DEFINE_CAST(NumberObject)
DEFINE_CAST(BooleanObject)
DEFINE_CAST(RegExpObject)
@ -188,6 +191,16 @@ std::string StringRef::toStdUTF8String()
return toImpl(this)->toNonGCUTF8StringData();
}
SymbolRef* SymbolRef::create(StringRef* desc)
{
return toRef(new Symbol(toImpl(desc)));
}
StringRef* SymbolRef::description()
{
return toRef(toImpl(this)->description());
}
bool PointerValueRef::isString()
{
return toImpl(this)->isString();
@ -198,6 +211,16 @@ StringRef* PointerValueRef::asString()
return toRef(toImpl(this)->asString());
}
bool PointerValueRef::isSymbol()
{
return toImpl(this)->isSymbol();
}
SymbolRef* PointerValueRef::asSymbol()
{
return toRef(toImpl(this)->asSymbol());
}
bool PointerValueRef::isObject()
{
return toImpl(this)->isString();
@ -238,6 +261,16 @@ StringObjectRef* PointerValueRef::asStringObject()
return toRef(toImpl(this)->asStringObject());
}
bool PointerValueRef::isSymbolObject()
{
return toImpl(this)->isSymbolObject();
}
SymbolObjectRef* PointerValueRef::asSymbolObject()
{
return toRef(toImpl(this)->asSymbolObject());
}
bool PointerValueRef::isNumberObject()
{
return toImpl(this)->isNumberObject();
@ -370,6 +403,7 @@ void VMInstanceRef::clearCachesRelatedWithContext()
imp->m_compiledCodeBlocks.clear();
imp->m_regexpCache.clear();
imp->m_cachedUTC = nullptr;
imp->globalSymbolRegistry().clear();
}
bool VMInstanceRef::addRoot(VMInstanceRef* instanceRef, ValueRef* ptr)
@ -393,6 +427,16 @@ bool VMInstanceRef::removeRoot(VMInstanceRef* instanceRef, ValueRef* ptr)
return toImpl(this)->removeRoot(vptr);
}
SymbolRef* VMInstanceRef::toStringTagSymbol()
{
return toRef(toImpl(this)->globalSymbols().toStringTag);
}
SymbolRef* VMInstanceRef::iteratorSymbol()
{
return toRef(toImpl(this)->globalSymbols().iterator);
}
#ifdef ESCARGOT_ENABLE_PROMISE
ValueRef* VMInstanceRef::drainJobQueue()
{
@ -536,9 +580,12 @@ public:
virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
auto result = m_getOwnPropetyCallback(toRef(&state), toRef(this), toRef(P.toValue(state)));
if (!result.m_value->isEmpty()) {
return ObjectGetResult(toImpl(result.m_value), result.m_isWritable, result.m_isEnumerable, result.m_isConfigurable);
Value PV = P.toPlainValue(state);
if (!PV.isSymbol()) {
auto result = m_getOwnPropetyCallback(toRef(&state), toRef(this), toRef(PV));
if (!result.m_value->isEmpty()) {
return ObjectGetResult(toImpl(result.m_value), result.m_isWritable, result.m_isEnumerable, result.m_isConfigurable);
}
}
return Object::getOwnProperty(state, P);
}
@ -546,21 +593,27 @@ public:
{
// Only value type supported
if (desc.isValuePresent()) {
if (m_defineOwnPropertyCallback(toRef(&state), toRef(this), toRef(P.toValue(state)), toRef(desc.value()))) {
return true;
Value PV = P.toPlainValue(state);
if (!PV.isSymbol()) {
if (m_defineOwnPropertyCallback(toRef(&state), toRef(this), toRef(PV), toRef(desc.value()))) {
return true;
}
}
}
return Object::defineOwnProperty(state, P, desc);
}
virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
auto result = m_getOwnPropetyCallback(toRef(&state), toRef(this), toRef(P.toValue(state)));
if (!result.m_value->isEmpty()) {
return m_deleteOwnPropertyCallback(toRef(&state), toRef(this), toRef(P.toValue(state)));
Value PV = P.toPlainValue(state);
if (!PV.isSymbol()) {
auto result = m_getOwnPropetyCallback(toRef(&state), toRef(this), toRef(P.toPlainValue(state)));
if (!result.m_value->isEmpty()) {
return m_deleteOwnPropertyCallback(toRef(&state), toRef(this), toRef(P.toPlainValue(state)));
}
}
return Object::deleteOwnProperty(state, P);
}
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey = true) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
auto names = m_enumerationCallback(toRef(&state), toRef(this));
for (size_t i = 0; i < names.size(); i++) {
@ -578,7 +631,7 @@ public:
callback(state, this, ObjectPropertyName(state, toImpl(names[i].m_name)), desc, data);
}
Object::enumeration(state, callback, data);
Object::enumeration(state, callback, data, shouldSkipSymbolKey);
}
virtual bool isInlineCacheable()
@ -748,17 +801,6 @@ void ObjectRef::preventExtensions()
toImpl(this)->preventExtensions();
}
// http://www.ecma-international.org/ecma-262/5.1/#sec-8.6.2
const char* ObjectRef::internalClassProperty()
{
return toImpl(this)->internalClassProperty();
}
void ObjectRef::giveInternalClassProperty(const char* name)
{
toImpl(this)->giveInternalClassProperty(name);
}
void* ObjectRef::extraData()
{
return toImpl(this)->extraData();
@ -779,7 +821,7 @@ void ObjectRef::enumerateObjectOwnProperies(ExecutionStateRef* state, const std:
toImpl(this)->enumeration(*toImpl(state), [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
const std::function<bool(ExecutionStateRef * state, ValueRef * propertyName, bool isWritable, bool isEnumerable, bool isConfigurable)>* cb
= (const std::function<bool(ExecutionStateRef * state, ValueRef * propertyName, bool isWritable, bool isEnumerable, bool isConfigurable)>*)data;
return (*cb)(toRef(&state), toRef(name.toValue(state)), desc.isWritable(), desc.isEnumerable(), desc.isConfigurable());
return (*cb)(toRef(&state), toRef(name.toPlainValue(state)), desc.isWritable(), desc.isEnumerable(), desc.isConfigurable());
},
(void*)&cb);
}
@ -1281,7 +1323,9 @@ void ContextRef::setVirtualIdentifierCallback(VirtualIdentifierCallback cb)
ctx->m_virtualIdentifierCallbackPublic = (void*)cb;
ctx->setVirtualIdentifierCallback([](ExecutionState& state, Value name) -> Value {
if (state.context()->m_virtualIdentifierCallbackPublic) {
return toImpl(((VirtualIdentifierCallback)state.context()->m_virtualIdentifierCallbackPublic)(toRef(&state), toRef(name)));
if (!name.isSymbol()) {
return toImpl(((VirtualIdentifierCallback)state.context()->m_virtualIdentifierCallbackPublic)(toRef(&state), toRef(name)));
}
}
return Value(Value::EmptyValue);
});
@ -1533,7 +1577,7 @@ uint32_t ValueRef::toArrayIndex(ExecutionStateRef* state)
return s.asInt32();
else {
ExecutionState* esi = toImpl(state);
return Value(s).toString(*esi)->tryToUseAsArrayIndex();
return Value(s).tryToUseAsArrayIndex(*esi);
}
}
@ -1660,6 +1704,21 @@ StringRef* StringObjectRef::primitiveValue()
return toRef(toImpl(this)->primitiveValue());
}
SymbolObjectRef* SymbolObjectRef::create(ExecutionStateRef* state)
{
return toRef(new SymbolObject(*toImpl(state), new Symbol(String::emptyString)));
}
void SymbolObjectRef::setPrimitiveValue(ExecutionStateRef* state, SymbolRef* value)
{
toImpl(this)->setPrimitiveValue(*toImpl(state), toImpl(value));
}
SymbolRef* SymbolObjectRef::primitiveValue()
{
return toRef(toImpl(this)->primitiveValue());
}
NumberObjectRef* NumberObjectRef::create(ExecutionStateRef* state)
{
return toRef(new NumberObject(*toImpl(state)));

View file

@ -31,6 +31,7 @@ namespace Escargot {
class VMInstanceRef;
class StringRef;
class SymbolRef;
class ValueRef;
class PointerValueRef;
class ObjectRef;
@ -52,6 +53,7 @@ class PromiseObjectRef;
class ErrorObjectRef;
class DateObjectRef;
class StringObjectRef;
class SymbolObjectRef;
class NumberObjectRef;
class BooleanObjectRef;
class RegExpObjectRef;
@ -72,6 +74,8 @@ class PointerValueRef {
public:
bool isString();
StringRef* asString();
bool isSymbol();
SymbolRef* asSymbol();
bool isObject();
ObjectRef* asObject();
bool isFunctionObject();
@ -80,6 +84,8 @@ public:
ArrayObjectRef* asArrayObject();
bool isStringObject();
StringObjectRef* asStringObject();
bool isSymbolObject();
SymbolObjectRef* asSymbolObject();
bool isNumberObject();
NumberObjectRef* asNumberObject();
bool isBooleanObject();
@ -137,6 +143,12 @@ public:
std::string toStdUTF8String();
};
class SymbolRef : public PointerValueRef {
public:
static SymbolRef* create(StringRef* desc);
StringRef* description();
};
class VMInstanceRef {
public:
static VMInstanceRef* create(const char* locale = nullptr, const char* timezone = nullptr);
@ -146,6 +158,9 @@ public:
bool addRoot(VMInstanceRef* instanceRef, ValueRef* ptr);
bool removeRoot(VMInstanceRef* instanceRef, ValueRef* ptr);
SymbolRef* toStringTagSymbol();
SymbolRef* iteratorSymbol();
#ifdef ESCARGOT_ENABLE_PROMISE
// if there is an error, executing will be stopped and returns ErrorValue
// if thres is no job or no error, returns EmptyValue
@ -432,10 +447,6 @@ public:
bool isExtensible();
void preventExtensions();
// http://www.ecma-international.org/ecma-262/5.1/#sec-8.6.2
const char* internalClassProperty();
void giveInternalClassProperty(const char* name);
void* extraData();
void setExtraData(void* e);
@ -619,6 +630,14 @@ public:
StringRef* primitiveValue();
};
class SymbolObjectRef : public ObjectRef {
public:
static SymbolObjectRef* create(ExecutionStateRef* state);
void setPrimitiveValue(ExecutionStateRef* state, SymbolRef* value);
SymbolRef* primitiveValue();
};
class NumberObjectRef : public ObjectRef {
public:
static NumberObjectRef* create(ExecutionStateRef* state);

View file

@ -621,7 +621,7 @@ public:
#ifndef NDEBUG
virtual void dump()
{
printf("get object r%d <- r%d.%s", (int)m_storeRegisterIndex, (int)m_objectRegisterIndex, m_propertyName.string()->toUTF8StringData().data());
printf("get object r%d <- r%d.%s", (int)m_storeRegisterIndex, (int)m_objectRegisterIndex, m_propertyName.plainString()->toUTF8StringData().data());
}
#endif
};
@ -667,7 +667,7 @@ public:
#ifndef NDEBUG
virtual void dump()
{
printf("set object r%d.%s <- r%d", (int)m_objectRegisterIndex, m_propertyName.string()->toUTF8StringData().data(), (int)m_loadRegisterIndex);
printf("set object r%d.%s <- r%d", (int)m_objectRegisterIndex, m_propertyName.plainString()->toUTF8StringData().data(), (int)m_loadRegisterIndex);
}
#endif
};
@ -691,7 +691,7 @@ public:
#ifndef NDEBUG
virtual void dump()
{
printf("get global object r%d <- global.%s", (int)m_registerIndex, m_propertyName.string()->toUTF8StringData().data());
printf("get global object r%d <- global.%s", (int)m_registerIndex, m_propertyName.plainString()->toUTF8StringData().data());
}
#endif
};
@ -716,7 +716,7 @@ public:
#ifndef NDEBUG
virtual void dump()
{
printf("set global object global.%s <- r%d", m_propertyName.string()->toUTF8StringData().data(), (int)m_registerIndex);
printf("set global object global.%s <- r%d", m_propertyName.plainString()->toUTF8StringData().data(), (int)m_registerIndex);
}
#endif
};
@ -1337,11 +1337,6 @@ struct EnumerateObjectData : public PointerValue {
m_idx = 0;
}
virtual Type type()
{
return EnumerateObjectDataType;
}
ObjectStructureChainWithGC m_hiddenClassChain;
Object* m_object;
uint64_t m_originalLength;

View file

@ -322,12 +322,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState& state, ByteCodeBlock* byteC
if (LIKELY(willBeObject.isObject() && (v = willBeObject.asPointerValue())->hasTag(g_arrayObjectTag))) {
ArrayObject* arr = (ArrayObject*)v;
if (LIKELY(arr->isFastModeArray())) {
uint32_t idx;
if (LIKELY(property.isUInt32()))
idx = property.asUInt32();
else {
idx = property.toString(state)->tryToUseAsArrayIndex();
}
uint32_t idx = property.tryToUseAsArrayIndex(state);
if (LIKELY(idx != Value::InvalidArrayIndexValue)) {
if (LIKELY(idx < arr->getArrayLength(state))) {
const Value& v = arr->m_fastModeData[idx];
@ -350,12 +345,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState& state, ByteCodeBlock* byteC
if (LIKELY(willBeObject.isObject() && (willBeObject.asPointerValue())->hasTag(g_arrayObjectTag))) {
ArrayObject* arr = willBeObject.asObject()->asArrayObject();
if (LIKELY(arr->isFastModeArray())) {
uint32_t idx;
if (LIKELY(property.isUInt32()))
idx = property.asUInt32();
else {
idx = property.toString(state)->tryToUseAsArrayIndex();
}
uint32_t idx = property.tryToUseAsArrayIndex(state);
if (LIKELY(idx != Value::InvalidArrayIndexValue)) {
uint32_t len = arr->getArrayLength(state);
if (UNLIKELY(len <= idx)) {
@ -587,7 +577,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState& state, ByteCodeBlock* byteC
const Value& property = registerFile[code->m_propertyRegisterIndex];
ObjectPropertyName objPropName = ObjectPropertyName(state, property);
// http://www.ecma-international.org/ecma-262/6.0/#sec-__proto__-property-names-in-object-initializers
if (property.toString(state)->equals("__proto__")) {
if (property.isString() && property.asString()->equals("__proto__")) {
willBeObject.asObject()->setPrototype(state, registerFile[code->m_loadRegisterIndex]);
} else {
willBeObject.asObject()->defineOwnProperty(state, objPropName, ObjectPropertyDescriptor(registerFile[code->m_loadRegisterIndex], ObjectPropertyDescriptor::AllPresent));
@ -660,6 +650,8 @@ Value ByteCodeInterpreter::interpret(ExecutionState& state, ByteCodeBlock* byteC
PointerValue* p = val.asPointerValue();
if (p->isFunctionObject()) {
val = state.context()->staticStrings().function.string();
} else if (p->isSymbol()) {
val = state.context()->staticStrings().symbol.string();
} else {
val = state.context()->staticStrings().object.string();
}
@ -1089,22 +1081,7 @@ NEVER_INLINE Value ByteCodeInterpreter::instanceOfOperation(ExecutionState& stat
if (!right.isFunction()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, errorMessage_InstanceOf_NotFunction);
}
if (left.isObject()) {
FunctionObject* C = right.asFunction();
Value P = C->getFunctionPrototype(state);
Value O = left.asObject()->getPrototype(state);
if (P.isObject()) {
while (O.isObject()) {
if (P.asObject() == O.asObject()) {
return Value(true);
}
O = O.asObject()->getPrototype(state);
}
} else {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, errorMessage_InstanceOf_InvalidPrototypeProperty);
}
}
return Value(false);
return Value(right.asFunction()->hasInstance(state, left));
}
NEVER_INLINE void ByteCodeInterpreter::deleteOperation(ExecutionState& state, LexicalEnvironment* env, UnaryDelete* code, Value* registerFile)
@ -1492,16 +1469,16 @@ NEVER_INLINE EnumerateObjectData* ByteCodeInterpreter::executeEnumerateObject(Ex
target.asObject()->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
EData* eData = (EData*)data;
if (desc.isEnumerable()) {
String* key = name.toValue(state).toString(state);
String* key = name.toPlainValue(state).toString(state);
auto iter = eData->keyStringSet->find(key);
if (iter == eData->keyStringSet->end()) {
eData->keyStringSet->insert(key);
eData->data->m_keys.pushBack(name.toValue(state));
eData->data->m_keys.pushBack(name.toPlainValue(state));
}
} else if (self == eData->obj) {
// 12.6.4 The values of [[Enumerable]] attributes are not considered
// when determining if a property of a prototype object is shadowed by a previous object on the prototype chain.
String* key = name.toValue(state).toString(state);
String* key = name.toPlainValue(state).toString(state);
ASSERT(eData->keyStringSet->find(key) == eData->keyStringSet->end());
eData->keyStringSet->insert(key);
}
@ -1517,7 +1494,7 @@ NEVER_INLINE EnumerateObjectData* ByteCodeInterpreter::executeEnumerateObject(Ex
target.asObject()->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
if (desc.isEnumerable()) {
EData* eData = (EData*)data;
eData->data->m_keys[(*eData->idx)++] = name.toValue(state);
eData->data->m_keys[(*eData->idx)++] = name.toPlainValue(state);
}
return true;
},
@ -1582,11 +1559,11 @@ NEVER_INLINE Value ByteCodeInterpreter::getGlobalObjectSlowCase(ExecutionState&
return res.value(state, go);
} else {
if (UNLIKELY((bool)state.context()->virtualIdentifierCallback())) {
Value virtialIdResult = state.context()->virtualIdentifierCallback()(state, code->m_propertyName.string());
Value virtialIdResult = state.context()->virtualIdentifierCallback()(state, code->m_propertyName.plainString());
if (!virtialIdResult.isEmpty())
return virtialIdResult;
}
ErrorObject::throwBuiltinError(state, ErrorObject::ReferenceError, code->m_propertyName.string(), false, String::emptyString, errorMessage_IsNotDefined);
ErrorObject::throwBuiltinError(state, ErrorObject::ReferenceError, code->m_propertyName.plainString(), false, String::emptyString, errorMessage_IsNotDefined);
}
} else {
const ObjectStructureItem& item = go->structure()->readProperty(state, idx);
@ -1629,7 +1606,7 @@ NEVER_INLINE void ByteCodeInterpreter::setGlobalObjectSlowCase(ExecutionState& s
size_t idx = go->structure()->findProperty(state, code->m_propertyName);
if (UNLIKELY(idx == SIZE_MAX)) {
if (UNLIKELY(state.inStrictMode())) {
ErrorObject::throwBuiltinError(state, ErrorObject::ReferenceError, code->m_propertyName.string(), false, String::emptyString, errorMessage_IsNotDefined);
ErrorObject::throwBuiltinError(state, ErrorObject::ReferenceError, code->m_propertyName.plainString(), false, String::emptyString, errorMessage_IsNotDefined);
}
VirtualIdDisabler d(state.context());
go->setThrowsExceptionWhenStrictMode(state, ObjectPropertyName(state, code->m_propertyName), value, go);

View file

@ -162,12 +162,7 @@ ArgumentsObject::ArgumentsObject(ExecutionState& state, FunctionEnvironmentRecor
ObjectGetResult ArgumentsObject::getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
uint64_t idx;
if (LIKELY(P.isUIntType())) {
idx = P.uintValue();
} else {
idx = P.string(state)->tryToUseAsIndex();
}
uint64_t idx = P.tryToUseAsIndex();
if (LIKELY(idx != Value::InvalidIndexValue)) {
if (idx < m_argumentPropertyInfo.size()) {
Value val = m_argumentPropertyInfo[idx].first;
@ -185,12 +180,7 @@ ObjectGetResult ArgumentsObject::getOwnProperty(ExecutionState& state, const Obj
bool ArgumentsObject::defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
uint64_t idx;
if (LIKELY(P.isUIntType())) {
idx = P.uintValue();
} else {
idx = P.string(state)->tryToUseAsIndex();
}
uint64_t idx = P.tryToUseAsIndex();
if (LIKELY(idx != Value::InvalidIndexValue)) {
if (idx < m_argumentPropertyInfo.size()) {
Value val = m_argumentPropertyInfo[idx].first;
@ -251,12 +241,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionState& state, const ObjectPrope
bool ArgumentsObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
uint64_t idx;
if (LIKELY(P.isUIntType())) {
idx = P.uintValue();
} else {
idx = P.string(state)->tryToUseAsIndex();
}
uint64_t idx = P.tryToUseAsIndex();
if (LIKELY(idx != Value::InvalidIndexValue)) {
if (idx < m_argumentPropertyInfo.size()) {
Value val = m_argumentPropertyInfo[idx].first;
@ -269,7 +254,7 @@ bool ArgumentsObject::deleteOwnProperty(ExecutionState& state, const ObjectPrope
return Object::deleteOwnProperty(state, P);
}
void ArgumentsObject::enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data)
void ArgumentsObject::enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey)
{
for (size_t i = 0; i < m_argumentPropertyInfo.size(); i++) {
Value v = m_argumentPropertyInfo[i].first;
@ -279,17 +264,12 @@ void ArgumentsObject::enumeration(ExecutionState& state, bool (*callback)(Execut
}
}
}
Object::enumeration(state, callback, data);
Object::enumeration(state, callback, data, shouldSkipSymbolKey);
}
ObjectGetResult ArgumentsObject::getIndexedProperty(ExecutionState& state, const Value& property)
{
uint64_t idx;
if (LIKELY(property.isUInt32())) {
idx = property.asUInt32();
} else {
idx = property.toString(state)->tryToUseAsIndex();
}
Value::ValueIndex idx = property.tryToUseAsIndex(state);
if (LIKELY(idx != Value::InvalidIndexValue)) {
if (idx < m_argumentPropertyInfo.size()) {
Value val = m_argumentPropertyInfo[idx].first;
@ -307,12 +287,7 @@ ObjectGetResult ArgumentsObject::getIndexedProperty(ExecutionState& state, const
bool ArgumentsObject::setIndexedProperty(ExecutionState& state, const Value& property, const Value& value)
{
uint64_t idx;
if (LIKELY(property.isUInt32())) {
idx = property.asUInt32();
} else {
idx = property.toString(state)->tryToUseAsIndex();
}
Value::ValueIndex idx = property.tryToUseAsIndex(state);
if (LIKELY(idx != Value::InvalidIndexValue)) {
if (idx < m_argumentPropertyInfo.size()) {
Value val = m_argumentPropertyInfo[idx].first;

View file

@ -34,7 +34,7 @@ public:
virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data);
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey = true);
virtual ObjectGetResult getIndexedProperty(ExecutionState& state, const Value& property);
virtual bool setIndexedProperty(ExecutionState& state, const Value& property, const Value& value);
// http://www.ecma-international.org/ecma-262/5.1/#sec-8.6.2

View file

@ -16,6 +16,7 @@
#include "Escargot.h"
#include "ArrayObject.h"
#include "ErrorObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "util/Util.h"
@ -36,6 +37,21 @@ ArrayObject::ArrayObject(ExecutionState& state)
}
}
ArrayObject::ArrayObject(ExecutionState& state, double length)
: ArrayObject(state)
{
// If length is -0, let length be +0.
if (length == 0 && std::signbit(length)) {
length = +0.0;
}
// If length>2^32-1, throw a RangeError exception.
if (length > ((1LL << 32LL) - 1LL)) {
ErrorObject::throwBuiltinError(state, ErrorObject::RangeError, errorMessage_GlobalObject_InvalidArrayLength);
}
defineOwnProperty(state, ObjectPropertyName(state, state.context()->staticStrings().length), ObjectPropertyDescriptor(Value(length),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::NonEnumerablePresent | ObjectPropertyDescriptor::NonConfigurablePresent)));
}
ObjectGetResult ArrayObject::getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
ObjectGetResult v = getFastModeValue(state, P);
@ -52,12 +68,7 @@ bool ArrayObject::defineOwnProperty(ExecutionState& state, const ObjectPropertyN
return true;
}
uint64_t idx;
if (LIKELY(P.isUIntType())) {
idx = P.uintValue();
} else {
idx = P.string(state)->tryToUseAsArrayIndex();
}
uint64_t idx = P.tryToUseAsArrayIndex();
auto oldLenDesc = structure()->readProperty(state, (size_t)0);
uint32_t oldLen = getArrayLength(state);
@ -71,7 +82,7 @@ bool ArrayObject::defineOwnProperty(ExecutionState& state, const ObjectPropertyN
return setArrayLength(state, idx + 1);
}
return true;
} else if (P.string(state)->equals(state.context()->staticStrings().length.string())) {
} else if (P.toPropertyName(state).equals(state.context()->staticStrings().length.string())) {
// See 3.a ~ 3.n on http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.5.1
if (desc.isValuePresent()) {
ObjectPropertyDescriptor newLenDesc(desc);
@ -153,12 +164,7 @@ bool ArrayObject::defineOwnProperty(ExecutionState& state, const ObjectPropertyN
bool ArrayObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
if (LIKELY(isFastModeArray())) {
uint64_t idx;
if (LIKELY(P.isUIntType())) {
idx = P.uintValue();
} else {
idx = P.string(state)->tryToUseAsArrayIndex();
}
uint64_t idx = P.tryToUseAsArrayIndex();
if (LIKELY(idx != Value::InvalidArrayIndexValue)) {
uint64_t len = getArrayLength(state);
if (idx < len) {
@ -171,7 +177,7 @@ bool ArrayObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyN
return Object::deleteOwnProperty(state, P);
}
void ArrayObject::enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
void ArrayObject::enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
if (LIKELY(isFastModeArray())) {
size_t len = getArrayLength(state);
@ -184,7 +190,7 @@ void ArrayObject::enumeration(ExecutionState& state, bool (*callback)(ExecutionS
}
}
}
Object::enumeration(state, callback, data);
Object::enumeration(state, callback, data, shouldSkipSymbolKey);
}
void ArrayObject::sort(ExecutionState& state, const std::function<bool(const Value& a, const Value& b)>& comp)
@ -316,12 +322,7 @@ bool ArrayObject::setArrayLength(ExecutionState& state, const uint64_t& newLengt
ObjectGetResult ArrayObject::getFastModeValue(ExecutionState& state, const ObjectPropertyName& P)
{
if (LIKELY(isFastModeArray())) {
uint64_t idx;
if (LIKELY(P.isUIntType())) {
idx = P.uintValue();
} else {
idx = P.string(state)->tryToUseAsArrayIndex();
}
uint64_t idx = P.tryToUseAsArrayIndex();
if (LIKELY(idx != Value::InvalidArrayIndexValue)) {
if (LIKELY(idx < getArrayLength(state))) {
Value v = m_fastModeData[idx];
@ -338,12 +339,7 @@ ObjectGetResult ArrayObject::getFastModeValue(ExecutionState& state, const Objec
bool ArrayObject::setFastModeValue(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc)
{
if (LIKELY(isFastModeArray())) {
uint64_t idx;
if (LIKELY(P.isUIntType())) {
idx = P.uintValue();
} else {
idx = P.string(state)->tryToUseAsArrayIndex();
}
uint64_t idx = P.tryToUseAsArrayIndex();
if (LIKELY(idx != Value::InvalidArrayIndexValue)) {
uint32_t len = getArrayLength(state);
if (len > idx && !m_fastModeData[idx].isEmpty()) {
@ -383,12 +379,7 @@ bool ArrayObject::setFastModeValue(ExecutionState& state, const ObjectPropertyNa
ObjectGetResult ArrayObject::getIndexedProperty(ExecutionState& state, const Value& property)
{
if (LIKELY(isFastModeArray())) {
uint64_t idx;
if (LIKELY(property.isUInt32())) {
idx = property.asUInt32();
} else {
idx = property.toString(state)->tryToUseAsArrayIndex();
}
uint32_t idx = property.tryToUseAsArrayIndex(state);
if (LIKELY(idx != Value::InvalidArrayIndexValue)) {
if (LIKELY(idx < getArrayLength(state))) {
Value v = m_fastModeData[idx];
@ -405,12 +396,7 @@ ObjectGetResult ArrayObject::getIndexedProperty(ExecutionState& state, const Val
bool ArrayObject::setIndexedProperty(ExecutionState& state, const Value& property, const Value& value)
{
if (LIKELY(isFastModeArray())) {
uint64_t idx;
if (LIKELY(property.isUInt32())) {
idx = property.asUInt32();
} else {
idx = property.toString(state)->tryToUseAsArrayIndex();
}
uint32_t idx = property.tryToUseAsArrayIndex(state);
if (LIKELY(idx != Value::InvalidArrayIndexValue)) {
uint32_t len = getArrayLength(state);
if (UNLIKELY(len <= idx)) {
@ -428,11 +414,6 @@ bool ArrayObject::setIndexedProperty(ExecutionState& state, const Value& propert
return set(state, ObjectPropertyName(state, property), value, this);
}
IteratorObject* ArrayObject::iterator(ExecutionState& state)
{
return new ArrayIteratorObject(state, this, ArrayIteratorObject::TypeValue);
}
ArrayIteratorObject::ArrayIteratorObject(ExecutionState& state, Object* a, Type type)
: IteratorObject(state)
, m_array(a)
@ -475,7 +456,7 @@ std::pair<Value, bool> ArrayIteratorObject::advance(ExecutionState& state)
// Let len be the value of a's [[ArrayLength]] internal slot.
// Else,
// Let len be ? ToLength(? Get(a, "length")).
auto len = a->length(state);
auto len = a->lengthES6(state);
// If index ≥ len, then
if (index >= len) {

View file

@ -41,6 +41,7 @@ class ArrayObject : public Object {
public:
ArrayObject(ExecutionState& state);
ArrayObject(ExecutionState& state, double size); // http://www.ecma-international.org/ecma-262/7.0/index.html#sec-arraycreate
virtual bool isArrayObject() const
{
return true;
@ -55,7 +56,7 @@ public:
}
}
virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey = true) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual uint64_t length(ExecutionState& state)
{
return getArrayLength(state);
@ -78,8 +79,6 @@ public:
return "Array";
}
virtual IteratorObject* iterator(ExecutionState& state) override;
protected:
ALWAYS_INLINE bool isFastModeArray()
{

View file

@ -61,8 +61,8 @@ AtomicString::AtomicString(ExecutionState& ec, String* name)
AtomicString::AtomicString(Context* c, const StringView& sv)
{
size_t v = sv.getTagInFirstDataArea();
if (v > POINTER_VALUE_STRING_TAG_IN_DATA) {
m_string = (String*)(v & ~POINTER_VALUE_STRING_TAG_IN_DATA);
if (v > POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA) {
m_string = (String*)(v & ~POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA);
return;
}
@ -75,10 +75,10 @@ AtomicString::AtomicString(Context* c, const StringView& sv)
ec->insert(newSv);
ASSERT(ec->find(newSv) != ec->end());
m_string = newSv;
str.m_tag = (size_t)POINTER_VALUE_STRING_TAG_IN_DATA | (size_t)m_string;
str.m_tag = (size_t)POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA | (size_t)m_string;
} else {
m_string = iter.operator*();
str.m_tag = (size_t)POINTER_VALUE_STRING_TAG_IN_DATA | (size_t)m_string;
str.m_tag = (size_t)POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA | (size_t)m_string;
}
}
@ -90,8 +90,8 @@ AtomicString::AtomicString(Context* c, String* name)
void AtomicString::init(AtomicStringMap* ec, String* name)
{
size_t v = name->getTagInFirstDataArea();
if (v > POINTER_VALUE_STRING_TAG_IN_DATA) {
m_string = (String*)(v & ~POINTER_VALUE_STRING_TAG_IN_DATA);
if (v > POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA) {
m_string = (String*)(v & ~POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA);
return;
}
auto iter = ec->find(name);
@ -99,10 +99,10 @@ void AtomicString::init(AtomicStringMap* ec, String* name)
ec->insert(name);
ASSERT(ec->find(name) != ec->end());
m_string = name;
name->m_tag = (size_t)POINTER_VALUE_STRING_TAG_IN_DATA | (size_t)m_string;
name->m_tag = (size_t)POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA | (size_t)m_string;
} else {
m_string = iter.operator*();
name->m_tag = (size_t)POINTER_VALUE_STRING_TAG_IN_DATA | (size_t)m_string;
name->m_tag = (size_t)POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA | (size_t)m_string;
}
}
}

View file

@ -50,6 +50,7 @@ Context::Context(VMInstance* instance)
m_defaultStructureForBindedFunctionObject = m_instance->m_defaultStructureForBindedFunctionObject;
m_defaultStructureForArrayObject = m_instance->m_defaultStructureForArrayObject;
m_defaultStructureForStringObject = m_instance->m_defaultStructureForStringObject;
m_defaultStructureForSymbolObject = m_instance->m_defaultStructureForSymbolObject;
m_defaultStructureForRegExpObject = m_instance->m_defaultStructureForRegExpObject;
m_defaultStructureForArgumentsObject = m_instance->m_defaultStructureForArgumentsObject;
m_defaultStructureForArgumentsObjectInStrictMode = m_instance->m_defaultStructureForArgumentsObjectInStrictMode;

View file

@ -131,6 +131,11 @@ public:
return m_defaultStructureForStringObject;
}
ObjectStructure* defaultStructureForSymbolObject()
{
return m_defaultStructureForSymbolObject;
}
ObjectStructure* defaultStructureForRegExpObject()
{
return m_defaultStructureForRegExpObject;
@ -205,6 +210,7 @@ protected:
ObjectStructure* m_defaultStructureForBindedFunctionObject;
ObjectStructure* m_defaultStructureForArrayObject;
ObjectStructure* m_defaultStructureForStringObject;
ObjectStructure* m_defaultStructureForSymbolObject;
ObjectStructure* m_defaultStructureForRegExpObject;
ObjectStructure* m_defaultStructureForArgumentsObject;
ObjectStructure* m_defaultStructureForArgumentsObjectInStrictMode;

View file

@ -79,8 +79,10 @@ const char* errorMessage_GlobalObject_InvalidArrayLength = "Invalid array length
const char* errorMessage_GlobalObject_DetachedBuffer = "%s: Detached buffer cannot be used here";
const char* errorMessage_GlobalObject_ConstructorRequiresNew = "Constructor requires 'new'";
const char* errorMessage_GlobalObject_CalledOnIncompatibleReceiver = "%s: called on incompatible receiver";
const char* errorMessage_GlobalObject_IllegalFirstArgument = "%s: illegal first argument";
const char* errorMessage_String_InvalidStringLength = "Invalid string length";
void ErrorObject::throwBuiltinError(ExecutionState& state, Code code, String* objectName, bool prototoype, String* functionName, const char* templateString)
{
StringBuilder replacerBuilder;

View file

@ -81,6 +81,7 @@ extern const char* errorMessage_GlobalObject_InvalidArrayLength;
extern const char* errorMessage_GlobalObject_DetachedBuffer;
extern const char* errorMessage_GlobalObject_ConstructorRequiresNew;
extern const char* errorMessage_GlobalObject_CalledOnIncompatibleReceiver;
extern const char* errorMessage_GlobalObject_IllegalFirstArgument;
extern const char* errorMessage_String_InvalidStringLength;
class ErrorObject : public Object {

View file

@ -135,6 +135,26 @@ FunctionObject::FunctionObject(ExecutionState& state, CodeBlock* codeBlock, Stri
setPrototype(state, state.context()->globalObject()->functionPrototype());
}
bool FunctionObject::hasInstance(ExecutionState& state, const Value& left)
{
if (left.isObject()) {
FunctionObject* C = this;
Value P = C->getFunctionPrototype(state);
Value O = left.asObject()->getPrototype(state);
if (P.isObject()) {
while (O.isObject()) {
if (P.asObject() == O.asObject()) {
return true;
}
O = O.asObject()->getPrototype(state);
}
} else {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, errorMessage_InstanceOf_InvalidPrototypeProperty);
}
}
return false;
}
NEVER_INLINE void FunctionObject::generateBytecodeBlock(ExecutionState& state)
{
Vector<CodeBlock*, GCUtil::gc_malloc_ignore_off_page_allocator<CodeBlock*>>& v = state.context()->compiledCodeBlocks();

View file

@ -101,6 +101,8 @@ public:
return "Function";
}
bool hasInstance(ExecutionState& state, const Value& O);
protected:
LexicalEnvironment* outerEnvironment()
{

View file

@ -32,7 +32,11 @@ namespace Escargot {
#ifdef ESCARGOT_SHELL
static Value builtinPrint(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
puts(argv[0].toString(state)->toUTF8StringData().data());
if (argv[0].isSymbol()) {
puts(argv[0].asSymbol()->getSymbolDescriptiveString()->toNonGCUTF8StringData().data());
} else {
puts(argv[0].toString(state)->toNonGCUTF8StringData().data());
}
return Value();
}
@ -168,7 +172,7 @@ ObjectGetResult GlobalObject::getOwnProperty(ExecutionState& state, const Object
}
target = target->getPrototypeObject();
}
Value virtialIdResult = state.context()->virtualIdentifierCallback()(state, P.string(state));
Value virtialIdResult = state.context()->virtualIdentifierCallback()(state, P.toPlainValue(state));
if (!virtialIdResult.isEmpty())
return ObjectGetResult(virtialIdResult, true, true, true);
}

View file

@ -55,9 +55,6 @@ public:
m_structure = m_structure->convertToWithFastAccess(state);
m_throwTypeError = nullptr;
m_throwerGetterSetterData = nullptr;
// http://www.ecma-international.org/ecma-262/5.1/#sec-8.6.2
giveInternalClassProperty("global");
}
virtual bool isGlobalObject() const
@ -71,6 +68,7 @@ public:
installObject(state);
installIterator(state);
installError(state);
installSymbol(state);
installString(state);
installNumber(state);
installBoolean(state);
@ -99,6 +97,7 @@ public:
void installFunction(ExecutionState& state);
void installObject(ExecutionState& state);
void installError(ExecutionState& state);
void installSymbol(ExecutionState& state);
void installString(ExecutionState& state);
void installNumber(ExecutionState& state);
void installBoolean(ExecutionState& state);
@ -129,6 +128,11 @@ public:
Value eval(ExecutionState& state, const Value& arg);
Value evalLocal(ExecutionState& state, const Value& arg, Value thisValue, InterpretedCodeBlock* parentCodeBlock);
virtual const char* internalClassProperty()
{
return "global";
}
FunctionObject* object()
{
return m_object;
@ -234,6 +238,15 @@ public:
return m_numberPrototype;
}
FunctionObject* symbol()
{
return m_symbol;
}
Object* symbolPrototype()
{
return m_symbolPrototype;
}
FunctionObject* array()
{
return m_array;
@ -550,6 +563,9 @@ protected:
FunctionObject* m_number;
Object* m_numberPrototype;
FunctionObject* m_symbol;
Object* m_symbolPrototype;
FunctionObject* m_array;
Object* m_arrayPrototype;
Object* m_arrayIteratorPrototype;

View file

@ -17,6 +17,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "ArrayObject.h"
#include "ToStringRecursionPreventer.h"
@ -79,6 +80,143 @@ static Value builtinArrayIsArray(ExecutionState& state, Value thisValue, size_t
return Value(false);
}
static Value builtinArrayFrom(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
// Array.from ( items [ , mapfn [ , thisArg ] ] )#
Value items = argv[0];
Value mapfn;
if (argc > 1) {
mapfn = argv[1];
}
Value thisArg;
if (argc > 2) {
thisArg = argv[2];
}
// Let C be the this value.
Value C = thisValue;
// If mapfn is undefined, let mapping be false.
Value T;
bool mapping = true;
if (mapfn.isUndefined()) {
mapping = false;
} else {
// If IsCallable(mapfn) is false, throw a TypeError exception.
if (!mapfn.isFunction()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "argument map function should be undefined or function");
}
// If thisArg was supplied, let T be thisArg; else let T be undefined.
T = thisArg;
// Let mapping be true.
}
// Let usingIterator be ? GetMethod(items, @@iterator).
items = items.toObject(state);
Value usingIterator = items.asObject()->get(state, ObjectPropertyName(state, state.context()->vmInstance()->globalSymbols().iterator)).value(state, items);
// If usingIterator is not undefined, then
if (!usingIterator.isUndefinedOrNull()) {
Object* A;
// If IsConstructor(C) is true, then
if (C.isFunction() && C.asFunction()->isConstructor()) {
// Let A be ? Construct(C).
A = C.asFunction()->newInstance(state, 0, nullptr);
} else {
// Let A be ArrayCreate(0).
A = new ArrayObject(state);
}
// Let iterator be ? GetIterator(items, usingIterator).
// Let iterator be ? Call(method, obj).
Value willIterator = FunctionObject::call(state, usingIterator, items, 0, nullptr);
// If Type(iterator) is not Object, throw a TypeError exception.
if (!willIterator.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Got invalid Iterator");
}
Object* iterator = willIterator.asObject();
// Let k be 0.
double k = 0;
// Repeat
while (true) {
// If k ≥ 2^53-1, then
if (k >= ((1LL << 53LL) - 1LL)) {
// Let error be Completion{[[Type]]: throw, [[Value]]: a newly created TypeError object, [[Target]]: empty}.
// Return ? IteratorClose(iterator, error).
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Got invalid index");
}
// Let Pk be ! ToString(k).
ObjectPropertyName pk(state, Value(k));
// Let next be ? IteratorStep(iterator).
std::pair<Value, bool> next = iterator->iteratorNext(state);
// If next is false, then
if (next.second) {
// Perform ? Set(A, "length", k, true).
A->setThrowsException(state, ObjectPropertyName(state, state.context()->staticStrings().length), Value(k), A);
// Return A.
return A;
}
// Let nextValue be ? IteratorValue(next).
const Value& nextValue = next.first;
Value mappedValue;
// If mapping is true, then
if (mapping) {
// Let mappedValue be Call(mapfn, T, « nextValue, k »).
// If mappedValue is an abrupt completion, return ? IteratorClose(iterator, mappedValue).
// Let mappedValue be mappedValue.[[Value]].
Value argv[] = { nextValue, Value(k) };
mappedValue = mapfn.asFunction()->call(state, T, 2, argv);
} else {
mappedValue = nextValue;
}
// Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue).
A->defineOwnPropertyThrowsException(state, pk, ObjectPropertyDescriptor(mappedValue, ObjectPropertyDescriptor::AllPresent));
// Increase k by 1.
k++;
}
}
// NOTE: items is not an Iterable so assume it is an array-like object.
// Let arrayLike be ! ToObject(items).
Object* arrayLike = items.toObject(state);
// Let len be ? ToLength(? Get(arrayLike, "length")).
auto len = arrayLike->lengthES6(state);
// If IsConstructor(C) is true, then
Object* A;
if (C.isFunction() && C.asFunction()->isConstructor()) {
// Let A be ? Construct(C, « len »).
Value vlen(len);
A = C.asFunction()->newInstance(state, 1, &vlen);
} else {
// Else,
// Let A be ? ArrayCreate(len).
A = new ArrayObject(state, len);
}
// Let k be 0.
double k = 0;
// Repeat, while k < len
while (k < len) {
// Let Pk be ! ToString(k).
ObjectPropertyName Pk(state, Value(k));
// Let kValue be ? Get(arrayLike, Pk).
Value kValue = arrayLike->get(state, Pk).value(state, arrayLike);
// If mapping is true, then
Value mappedValue;
if (mapping) {
// Let mappedValue be ? Call(mapfn, T, « kValue, k »).
Value argv[] = { kValue, Value(k) };
mappedValue = mapfn.asFunction()->call(state, T, 2, argv);
} else {
// Else, let mappedValue be kValue.
mappedValue = kValue;
}
// Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
A->defineOwnPropertyThrowsException(state, Pk, ObjectPropertyDescriptor(mappedValue, ObjectPropertyDescriptor::AllPresent));
// Increase k by 1.
k++;
}
// Perform ? Set(A, "length", len, true).
A->setThrowsException(state, ObjectPropertyName(state, state.context()->staticStrings().length), Value(len), A);
// Return A.
return A;
}
static Value builtinArrayJoin(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
RESOLVE_THIS_BINDING_TO_OBJECT(thisBinded, Array, join);
@ -1272,14 +1410,11 @@ static Value builtinArrayKeys(ExecutionState& state, Value thisValue, size_t arg
return M->keys(state);
}
// disable due to compatibility issues.
/*
static Value builtinArrayValues(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
RESOLVE_THIS_BINDING_TO_OBJECT(M, Array, values);
return M->values(state);
}
*/
static Value builtinArrayEntries(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
@ -1313,6 +1448,9 @@ void GlobalObject::installArray(ExecutionState& state)
m_array->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().isArray),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().isArray, builtinArrayIsArray, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_array->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().from),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().from, builtinArrayFrom, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_arrayPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().concat),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().concat, builtinArrayConcat, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_arrayPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().forEach),
@ -1357,9 +1495,15 @@ void GlobalObject::installArray(ExecutionState& state)
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().unshift, builtinArrayUnshift, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_arrayPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().keys),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().keys, builtinArrayKeys, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// disable due to compatibility issues.
// m_arrayPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().values),
// ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().values, builtinArrayValues, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
FunctionObject* values = new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().values, builtinArrayValues, 0, nullptr, NativeFunctionInfo::Strict));
m_arrayPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().values),
ObjectPropertyDescriptor(values, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_arrayPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, state.context()->vmInstance()->globalSymbols().iterator),
ObjectPropertyDescriptor(values,
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_arrayPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().entries),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().entries, builtinArrayEntries, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
@ -1370,6 +1514,8 @@ void GlobalObject::installArray(ExecutionState& state)
m_arrayIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().next),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().next, builtinArrayIteratorNext, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_arrayIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(String::fromASCII("Array Iterator")), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().Array),
ObjectPropertyDescriptor(m_array, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

View file

@ -19,6 +19,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "TypedArrayObject.h"
#include "DataViewObject.h"
@ -158,7 +159,8 @@ void GlobalObject::installDataView(ExecutionState& state)
m_dataViewPrototype->setPrototype(state, m_objectPrototype);
m_dataView->setFunctionPrototype(state, m_dataViewPrototype);
m_dataViewPrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().constructor), ObjectPropertyDescriptor(m_dataView, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_dataViewPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(state.context()->staticStrings().DataView.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
#define DATAVIEW_DEFINE_GETTER(Name) \
m_dataViewPrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().get##Name), \
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().get##Name, builtinDataViewGet##Name, 1, nullptr, NativeFunctionInfo::Strict)), \

View file

@ -17,6 +17,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "DateObject.h"
#include "ErrorObject.h"
@ -468,6 +469,37 @@ static Value builtinDateGetTimezoneOffset(ExecutionState& state, Value thisValue
return Value(thisObject->asDateObject()->getTimezoneOffset(state));
}
static Value builtinDateToPrimitive(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
// Let O be the this value.
Value O = thisValue;
// If Type(O) is not Object, throw a TypeError exception.
if (!O.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, state.context()->staticStrings().Date.string(), true,
state.context()->staticStrings().toPrimitive.string(), errorMessage_GlobalObject_ThisNotObject);
}
bool tryFirstIsString;
// If hint is the String value "string" or the String value "default", then
if (argv[0].isString() && (argv[0].asString()->equals("string") || argv[0].asString()->equals("default"))) {
// Let tryFirst be "string".
tryFirstIsString = true;
} else if (argv[0].isString() && argv[0].asString()->equals("number")) {
// Else if hint is the String value "number", then
// Let tryFirst be "number".
tryFirstIsString = false;
} else {
// Else, throw a TypeError exception.
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, state.context()->staticStrings().Date.string(), true,
state.context()->staticStrings().toPrimitive.string(), errorMessage_GlobalObject_IllegalFirstArgument);
}
// Return ? OrdinaryToPrimitive(O, tryFirst).
if (tryFirstIsString) {
return O.ordinaryToPrimitive(state, Value::PreferString);
} else {
return O.ordinaryToPrimitive(state, Value::PreferNumber);
}
}
void GlobalObject::installDate(ExecutionState& state)
{
m_date = new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().Date, builtinDateConstructor, 7, [](ExecutionState& state, CodeBlock* codeBlock, size_t argc, Value* argv) -> Object* {
@ -541,7 +573,8 @@ void GlobalObject::installDate(ExecutionState& state)
m_datePrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().getTimezoneOffset),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().getTimezoneOffset, builtinDateGetTimezoneOffset, 0, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_datePrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toPrimitive)),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(AtomicString(state, String::fromASCII("[Symbol.toPrimitive]")), builtinDateToPrimitive, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
#define DATE_DEFINE_GETTER(dname, unused1, unused2, unused3) \
m_datePrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().get##dname), \
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().get##dname, builtinDateGet##dname, 0, nullptr, NativeFunctionInfo::Strict)), \

View file

@ -17,6 +17,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "parser/ScriptParser.h"
#include "parser/esprima_cpp/esprima.h"
#include "runtime/Environment.h"
@ -206,6 +207,14 @@ static Value builtinFunctionBind(ExecutionState& state, Value thisValue, size_t
return new FunctionObject(state, cb, builder.finalize(&state), FunctionObject::ForBind::__ForBind__);
}
static Value builtinFunctionHasInstanceOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
if (!thisValue.isFunction()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, errorMessage_InstanceOf_NotFunction);
}
return Value(thisValue.asFunction()->hasInstance(state, argv[0]));
}
void GlobalObject::installFunction(ExecutionState& state)
{
FunctionObject* emptyFunction = new FunctionObject(state, new CodeBlock(state.context(), NativeFunctionInfo(state.context()->staticStrings().Function, builtinFunctionEmptyFunction, 1, nullptr, 0)),
@ -242,6 +251,9 @@ void GlobalObject::installFunction(ExecutionState& state)
m_functionPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().bind),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().bind, builtinFunctionBind, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_functionPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().hasInstance)),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(AtomicString(state, String::fromASCII("[Symbol.hasInstance]")), builtinFunctionHasInstanceOf, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NonWritablePresent | ObjectPropertyDescriptor::NonConfigurablePresent)));
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().Function),
ObjectPropertyDescriptor(m_function, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
}

View file

@ -17,12 +17,24 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "ToStringRecursionPreventer.h"
namespace Escargot {
static Value builtinIteratorIterator(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
return thisValue;
}
void GlobalObject::installIterator(ExecutionState& state)
{
m_iteratorPrototype = new Object(state);
m_iteratorPrototype->markThisObjectDontNeedStructureTransitionTable(state);
FunctionObject* fn = new FunctionObject(state, NativeFunctionInfo(AtomicString(state, String::fromASCII("[Symbol.iterator]")), builtinIteratorIterator, 0, nullptr, NativeFunctionInfo::Strict));
m_iteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, state.context()->vmInstance()->globalSymbols().iterator),
ObjectPropertyDescriptor(fn,
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
}
}

View file

@ -17,6 +17,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "StringObject.h"
#include "ArrayObject.h"
#include "TypedArrayObject.h"
@ -264,7 +265,7 @@ static Value builtinJSONParse(ExecutionState& state, Value thisValue, size_t arg
}
}
}
Value arguments[] = { name.toValue(state), val };
Value arguments[] = { name.toPlainValue(state), val };
return FunctionObject::call(state, reviver, holder, 2, arguments);
};
return Walk(root, ObjectPropertyName(state, String::emptyString));
@ -299,7 +300,7 @@ static Value builtinJSONStringify(ExecutionState& state, Value thisValue, size_t
std::vector<Value::ValueIndex> indexes;
arrObject->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& P, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool { //Value key, HiddenClassPropertyInfo* propertyInfo) {
Value::ValueIndex idx = P.toValue(state).toIndex(state);
Value::ValueIndex idx = P.toPlainValue(state).toIndex(state);
if (idx != Value::InvalidIndexValue) {
std::vector<Value::ValueIndex>* indexes = (std::vector<Value::ValueIndex>*)data;
indexes->push_back(idx);
@ -325,7 +326,7 @@ static Value builtinJSONStringify(ExecutionState& state, Value thisValue, size_t
bool flag = false;
for (size_t i = 0; i < propertyList.size(); i++) {
ObjectPropertyName& v = propertyList[i];
if (*v.string(state) == *item) {
if (v.toPropertyName(state).equals(item)) {
flag = true;
break;
}
@ -377,13 +378,13 @@ static Value builtinJSONStringify(ExecutionState& state, Value thisValue, size_t
Object* valObj = value.asPointerValue()->asObject();
Value toJson = valObj->get(state, ObjectPropertyName(state, strings->toJSON)).value(state, valObj);
if (toJson.isPointerValue() && toJson.asPointerValue()->isFunctionObject()) {
Value arguments[] = { key.toValue(state) };
Value arguments[] = { key.toPlainValue(state) };
value = FunctionObject::call(state, toJson, value, 1, arguments);
}
}
if (replacerFunc != NULL) {
Value arguments[] = { key.toValue(state), value };
Value arguments[] = { key.toPlainValue(state), value };
value = FunctionObject::call(state, replacerFunc, holder, 2, arguments);
}
@ -426,7 +427,7 @@ static Value builtinJSONStringify(ExecutionState& state, Value thisValue, size_t
};
Quote = [&](ObjectPropertyName value) -> String* {
String* str = value.string(state);
String* str = value.toPropertyName(state).plainString();
StringBuilder product;
product.appendChar('"');
@ -630,8 +631,10 @@ static Value builtinJSONStringify(ExecutionState& state, Value thisValue, size_t
void GlobalObject::installJSON(ExecutionState& state)
{
m_json = new Object(state);
m_json->giveInternalClassProperty("JSON");
m_json->markThisObjectDontNeedStructureTransitionTable(state);
m_json->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(state.context()->staticStrings().JSON.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().JSON),
ObjectPropertyDescriptor(m_json, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

View file

@ -17,6 +17,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "MapObject.h"
#include "ToStringRecursionPreventer.h"
@ -38,7 +39,7 @@ Value builtinMapConstructor(ExecutionState& state, Value thisValue, size_t argc,
}
// If iterable is either undefined or null, let iter be undefined.
Value adder;
IteratorObject* iter = nullptr;
Object* iter = nullptr;
if (iterable.isUndefinedOrNull()) {
iterable = Value();
} else {
@ -64,7 +65,7 @@ Value builtinMapConstructor(ExecutionState& state, Value thisValue, size_t argc,
// Repeat
while (true) {
// Let next be ? IteratorStep(iter).
auto next = iter->advance(state);
auto next = iter->iteratorNext(state);
// If next is false(done is true), return map.
if (next.second) {
return map;
@ -234,8 +235,15 @@ void GlobalObject::installMap(ExecutionState& state)
m_mapPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().values),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().values, builtinMapValues, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
auto entFn = new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().entries, builtinMapEntries, 0, nullptr, NativeFunctionInfo::Strict));
m_mapPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().entries),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().entries, builtinMapEntries, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
ObjectPropertyDescriptor(entFn, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_mapPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, state.context()->vmInstance()->globalSymbols().iterator),
ObjectPropertyDescriptor(entFn, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
m_mapPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(state.context()->staticStrings().Map.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
JSGetterSetter gs(
new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().function, builtinMapSizeGetter, 0, nullptr, NativeFunctionInfo::Strict)),
@ -249,6 +257,10 @@ void GlobalObject::installMap(ExecutionState& state)
m_mapIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().next),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().next, builtinMapIteratorNext, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_mapIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(String::fromASCII("Map Iterator")), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
m_map->setFunctionPrototype(state, m_mapPrototype);
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().Map),
ObjectPropertyDescriptor(m_map, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

View file

@ -17,6 +17,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "StringObject.h"
#include <math.h>
@ -252,9 +253,11 @@ static Value builtinMathExp(ExecutionState& state, Value thisValue, size_t argc,
void GlobalObject::installMath(ExecutionState& state)
{
m_math = new Object(state);
m_math->giveInternalClassProperty("Math");
m_math->markThisObjectDontNeedStructureTransitionTable(state);
m_math->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(state.context()->staticStrings().Math.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
// initialize math object: $20.2.1.6 Math.PI
const StaticStrings* strings = &state.context()->staticStrings();
m_math->defineOwnPropertyThrowsException(state, strings->PI, ObjectPropertyDescriptor(Value(3.1415926535897932), ObjectPropertyDescriptor::ValuePresent));

View file

@ -17,6 +17,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "ArrayObject.h"
namespace Escargot {
@ -71,19 +72,24 @@ static Value builtinObjectToString(ExecutionState& state, Value thisValue, size_
Object* thisObject = thisValue.toObject(state);
StringBuilder builder;
builder.appendString("[object ");
builder.appendString(thisObject->internalClassProperty());
Value toStringTag = thisObject->get(state, ObjectPropertyName(state, state.context()->vmInstance()->globalSymbols().toStringTag)).value(state, thisObject);
if (toStringTag.isString()) {
builder.appendString(toStringTag.asString());
} else {
builder.appendString(thisObject->internalClassProperty());
}
builder.appendString("]");
return AtomicString(state, builder.finalize()).string();
}
static Value builtinObjectHasOwnProperty(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
String* keyString = argv[0].toPrimitive(state, Value::PrimitiveTypeHint::PreferString).toString(state);
Value key = argv[0].toPrimitive(state, Value::PrimitiveTypeHint::PreferString);
Object* obj = thisValue.toObject(state);
return Value(obj->hasOwnProperty(state, ObjectPropertyName(state, keyString)));
return Value(obj->hasOwnProperty(state, ObjectPropertyName(state, key)));
}
inline Value objectDefineProperties(ExecutionState& state, Value object, Value properties)
static Value objectDefineProperties(ExecutionState& state, Value object, Value properties)
{
const StaticStrings* strings = &state.context()->staticStrings();
if (!object.isObject())
@ -101,7 +107,7 @@ inline Value objectDefineProperties(ExecutionState& state, Value object, Value p
}
return true;
},
&descriptors);
&descriptors, false);
for (auto it : descriptors) {
object.asObject()->defineOwnPropertyThrowsException(state, it.first, it.second);
}
@ -179,8 +185,8 @@ static Value builtinObjectIsPrototypeOf(ExecutionState& state, Value thisValue,
static Value builtinObjectPropertyIsEnumerable(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
// Let P be ToString(V).
Value P = argv[0].toString(state);
// Let P be toPropertyKey(V).
Value P = argv[0].toPropertyKey(state);
// Let O be the result of calling ToObject passing the this value as the argument.
RESOLVE_THIS_BINDING_TO_OBJECT(O, Object, propertyIsEnumerable);
@ -283,7 +289,7 @@ static Value builtinObjectGetOwnPropertyDescriptor(ExecutionState& state, Value
Object* O = argv[0].asObject();
// Let name be ToString(P).
Value name = argv[1].toString(state);
Value name = argv[1];
// Let desc be the result of calling the [[GetOwnProperty]] internal method of O with argument name.
ObjectGetResult desc = O->getOwnProperty(state, ObjectPropertyName(state, name));
@ -315,7 +321,7 @@ static Value builtinObjectGetOwnPropertyNames(ExecutionState& state, Value thisV
O->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& P, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
Data* a = (Data*)data;
// Let name be the String value that is the name of P.
Value name = P.string(state);
Value name = P.toPlainValue(state).toString(state);
// Call the [[DefineOwnProperty]] internal method of array with arguments ToString(n), the PropertyDescriptor {[[Value]]: name, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
a->array->defineOwnProperty(state, ObjectPropertyName(state, Value((*a->n))), ObjectPropertyDescriptor(name, ObjectPropertyDescriptor::AllPresent));
// Increment n by 1.
@ -328,6 +334,40 @@ static Value builtinObjectGetOwnPropertyNames(ExecutionState& state, Value thisV
return array;
}
static Value builtinObjectGetOwnPropertySymbols(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
Object* O = argv[0].toObject(state);
// Let array be the result of creating a new object as if by the expression new Array () where Array is the standard built-in constructor with that name.
ArrayObject* array = new ArrayObject(state);
// Let n be 0.
size_t n = 0;
struct Data {
ArrayObject* array;
size_t* n;
} data;
data.array = array;
data.n = &n;
// For each named own property P of O
O->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& P, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
Data* a = (Data*)data;
// Let name be the String value that is the name of P.
Value name = P.toPlainValue(state);
if (name.isSymbol()) {
// Call the [[DefineOwnProperty]] internal method of array with arguments ToString(n), the PropertyDescriptor {[[Value]]: name, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
a->array->defineOwnProperty(state, ObjectPropertyName(state, Value((*a->n))), ObjectPropertyDescriptor(name, ObjectPropertyDescriptor::AllPresent));
// Increment n by 1.
(*a->n)++;
}
return true;
},
&data, false);
// Return array.
return array;
}
static Value builtinObjectIsExtensible(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
// If Type(O) is not Object throw a TypeError exception.
@ -426,7 +466,7 @@ static Value builtinObjectKeys(ExecutionState& state, Value thisValue, size_t ar
if (desc.isEnumerable()) {
Data* aData = (Data*)data;
// Call the [[DefineOwnProperty]] internal method of array with arguments ToString(index), the PropertyDescriptor {[[Value]]: P, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
aData->array->defineOwnProperty(state, ObjectPropertyName(state, Value(*aData->index)), ObjectPropertyDescriptor(Value(P.string(state)), ObjectPropertyDescriptor::AllPresent));
aData->array->defineOwnProperty(state, ObjectPropertyName(state, Value(*aData->index)), ObjectPropertyDescriptor(Value(P.toPlainValue(state).toString(state)), ObjectPropertyDescriptor::AllPresent));
// Increment index by 1.
(*aData->index)++;
}
@ -562,6 +602,10 @@ void GlobalObject::installObject(ExecutionState& state)
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings.getOwnPropertyNames, builtinObjectGetOwnPropertyNames, 1, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_object->defineOwnProperty(state, ObjectPropertyName(strings.getOwnPropertySymbols),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings.getOwnPropertySymbols, builtinObjectGetOwnPropertySymbols, 1, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
// 19.1.2.9 Object.getPrototypeOf ( O )
m_object->defineOwnProperty(state, ObjectPropertyName(strings.getPrototypeOf),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings.getPrototypeOf, builtinObjectGetPrototypeOf, 1, nullptr, NativeFunctionInfo::Strict)),

View file

@ -19,6 +19,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "PromiseObject.h"
#include "ArrayObject.h"
#include "JobQueue.h"
@ -451,6 +452,8 @@ void GlobalObject::installPromise(ExecutionState& state)
m_promisePrototype->markThisObjectDontNeedStructureTransitionTable(state);
m_promisePrototype->setPrototype(state, m_objectPrototype);
m_promisePrototype->defineOwnProperty(state, ObjectPropertyName(strings->constructor), ObjectPropertyDescriptor(m_promise, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_promisePrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(state.context()->staticStrings().Promise.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
// $25.4.4.1 Promise.all(iterable);
m_promise->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->all),

View file

@ -17,6 +17,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "RegExpObject.h"
#include "ArrayObject.h"
#include "GlobalRegExpFunctionObject.h"
@ -48,7 +49,7 @@ static Value builtinRegExpConstructor(ExecutionState& state, Value thisValue, si
static Value builtinRegExpExec(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, RegExp, test);
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, RegExp, exec);
if (!thisObject->isRegExpObject()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, state.context()->staticStrings().RegExp.string(), true, state.context()->staticStrings().exec.string(), errorMessage_GlobalObject_ThisNotRegExpObject);
}

View file

@ -17,6 +17,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "SetObject.h"
#include "ToStringRecursionPreventer.h"
@ -40,7 +41,7 @@ Value builtinSetConstructor(ExecutionState& state, Value thisValue, size_t argc,
}
// If iterable is either undefined or null, let iter be undefined.
Value adder;
IteratorObject* iter = nullptr;
Object* iter = nullptr;
if (iterable.isUndefinedOrNull()) {
iterable = Value();
} else {
@ -66,7 +67,7 @@ Value builtinSetConstructor(ExecutionState& state, Value thisValue, size_t argc,
// Repeat
while (true) {
// Let next be ? IteratorStep(iter).
auto next = iter->advance(state);
auto next = iter->iteratorNext(state);
// If next is false, return set.
if (next.second) {
return set;
@ -203,13 +204,19 @@ void GlobalObject::installSet(ExecutionState& state)
m_setPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().forEach),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().forEach, builtinSetForEach, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
auto values = ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().values, builtinSetValues, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent));
auto valuesFn = new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().values, builtinSetValues, 0, nullptr, NativeFunctionInfo::Strict));
auto values = ObjectPropertyDescriptor(valuesFn, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent));
m_setPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().values), values);
m_setPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().keys), values);
m_setPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().entries),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().entries, builtinSetEntries, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_setPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, state.context()->vmInstance()->globalSymbols().iterator),
ObjectPropertyDescriptor(valuesFn, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
m_setPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(state.context()->staticStrings().Set.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
JSGetterSetter gs(
new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().function, builtinSetSizeGetter, 0, nullptr, NativeFunctionInfo::Strict)),
Value(Value::EmptyValue));
@ -222,6 +229,9 @@ void GlobalObject::installSet(ExecutionState& state)
m_setIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().next),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().next, builtinSetIteratorNext, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_setIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(String::fromASCII("Set Iterator")), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
m_set->setFunctionPrototype(state, m_setPrototype);
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().Set),
ObjectPropertyDescriptor(m_set, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

View file

@ -17,6 +17,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "StringObject.h"
#include "ErrorObject.h"
#include "RegExpObject.h"
@ -41,6 +42,10 @@ static Value builtinStringConstructor(ExecutionState& state, Value thisValue, si
if (argc == 0)
return String::emptyString;
Value value = argv[0];
// If NewTarget is undefined and Type(value) is Symbol, return SymbolDescriptiveString(value).
if (value.isSymbol()) {
return value.asSymbol()->getSymbolDescriptiveString();
}
return value.toString(state);
}
}
@ -405,7 +410,6 @@ static Value builtinStringSplit(ExecutionState& state, Value thisValue, size_t a
// 1, 2, 3
RESOLVE_THIS_BINDING_TO_STRING(S, String, split);
ArrayObject* A = new ArrayObject(state);
// 4, 5
size_t lengthA = 0;
size_t lim;
@ -885,6 +889,16 @@ static Value builtinStringIteratorNext(ExecutionState& state, Value thisValue, s
return iter->next(state);
}
static Value builtinStringIterator(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
// Let O be ? RequireObjectCoercible(this value).
Value O = thisValue.toObject(state);
// Let S be ? ToString(O).
String* S = O.toString(state);
// Return CreateStringIterator(S).
return new StringIteratorObject(state, S);
}
void GlobalObject::installString(ExecutionState& state)
{
const StaticStrings* strings = &state.context()->staticStrings();
@ -980,6 +994,10 @@ void GlobalObject::installString(ExecutionState& state)
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->includes, builtinStringIncludes, 1, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, state.context()->vmInstance()->globalSymbols().iterator),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(AtomicString(state, String::fromASCII("[Symbol.iterator]")), builtinStringIterator, 0, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
m_string->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->fromCharCode),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->fromCharCode, builtinStringFromCharCode, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
@ -991,6 +1009,9 @@ void GlobalObject::installString(ExecutionState& state)
m_stringIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().next),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().next, builtinStringIteratorNext, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_stringIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(String::fromASCII("String Iterator")), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
defineOwnProperty(state, ObjectPropertyName(strings->String),
ObjectPropertyDescriptor(m_string, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
}

View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2018-present Samsung Electronics Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "SymbolObject.h"
#include "ToStringRecursionPreventer.h"
namespace Escargot {
Value builtinSymbolConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
// If NewTarget is not undefined, throw a TypeError exception.
if (isNewExpression) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "illegal constructor Symbol");
}
String* descString = String::emptyString;
// If description is undefined, let descString be undefined.
if (argc == 0 || argv[0].isUndefined()) {
} else {
// Else, let descString be ? ToString(description).
descString = argv[0].toString(state);
}
// Return a new unique Symbol value whose [[Description]] value is descString.
return new Symbol(descString);
}
#define RESOLVE_THIS_BINDING_TO_SYMBOL(NAME, OBJ, BUILT_IN_METHOD) \
Symbol* NAME = nullptr; \
if (thisValue.isObject()) { \
if (!thisValue.asObject()->isSymbolObject()) { \
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), errorMessage_GlobalObject_CalledOnIncompatibleReceiver); \
} \
NAME = thisValue.asObject()->asSymbolObject()->primitiveValue(); \
} else if (thisValue.isSymbol()) { \
NAME = thisValue.asSymbol(); \
} else { \
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), errorMessage_GlobalObject_CalledOnIncompatibleReceiver); \
}
Value builtinSymbolToString(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
RESOLVE_THIS_BINDING_TO_SYMBOL(S, Symbol, toString);
return S->getSymbolDescriptiveString();
}
Value builtinSymbolValueOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
RESOLVE_THIS_BINDING_TO_SYMBOL(S, Symbol, valueOf);
return Value(S);
}
Value builtinSymbolToPrimitive(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
RESOLVE_THIS_BINDING_TO_SYMBOL(S, Symbol, toPrimitive);
return Value(S);
}
Value builtinSymbolFor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
// Let stringKey be ? ToString(key).
String* stringKey = argv[0].toString(state);
// For each element e of the GlobalSymbolRegistry List,
auto& list = state.context()->vmInstance()->globalSymbolRegistry();
for (size_t i = 0; i < list.size(); i++) {
// If SameValue(e.[[Key]], stringKey) is true, return e.[[Symbol]].
if (list[i].key->equals(stringKey)) {
return list[i].symbol;
}
}
// Assert: GlobalSymbolRegistry does not currently contain an entry for stringKey.
// Let newSymbol be a new unique Symbol value whose [[Description]] value is stringKey.
Symbol* newSymbol = new Symbol(stringKey);
// Append the Record { [[Key]]: stringKey, [[Symbol]]: newSymbol } to the GlobalSymbolRegistry List.
GlobalSymbolRegistryItem item;
item.key = stringKey;
item.symbol = newSymbol;
list.pushBack(item);
// Return newSymbol.
return newSymbol;
}
Value builtinSymbolKeyFor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
// If Type(sym) is not Symbol, throw a TypeError exception.
if (!argv[0].isSymbol()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, errorMessage_GlobalObject_IllegalFirstArgument);
}
Symbol* sym = argv[0].asSymbol();
// For each element e of the GlobalSymbolRegistry List (see 19.4.2.1),
auto& list = state.context()->vmInstance()->globalSymbolRegistry();
for (size_t i = 0; i < list.size(); i++) {
// If SameValue(e.[[Symbol]], sym) is true, return e.[[Key]].
if (list[i].symbol == sym) {
return list[i].key;
}
}
// Assert: GlobalSymbolRegistry does not currently contain an entry for sym.
// Return undefined.
return Value();
}
void GlobalObject::installSymbol(ExecutionState& state)
{
m_symbol = new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().Symbol, builtinSymbolConstructor, 0, [](ExecutionState& state, CodeBlock* codeBlock, size_t argc, Value* argv) -> Object* {
return new Object(state);
}),
FunctionObject::__ForBuiltin__);
m_symbol->markThisObjectDontNeedStructureTransitionTable(state);
m_symbol->setPrototype(state, m_functionPrototype);
m_symbol->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().stringFor),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().stringFor, builtinSymbolFor, 1, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_symbol->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().keyFor),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().keyFor, builtinSymbolKeyFor, 1, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_symbolPrototype = m_objectPrototype;
m_symbolPrototype = new Object(state);
m_symbolPrototype->markThisObjectDontNeedStructureTransitionTable(state);
m_symbolPrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().constructor), ObjectPropertyDescriptor(m_symbol, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_symbolPrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().toString),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().toString, builtinSymbolToString, 0, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_symbolPrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().valueOf),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().valueOf, builtinSymbolValueOf, 0, nullptr, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_symbolPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toPrimitive)),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(AtomicString(state, String::fromASCII("[Symbol.toPrimitive]")), builtinSymbolToPrimitive, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
m_symbolPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(state.context()->staticStrings().Symbol.string(), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
#define DECLARE_GLOBAL_SYMBOLS(name) \
m_symbol->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().name), ObjectPropertyDescriptor(Value(state.context()->vmInstance()->globalSymbols().name), \
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NonEnumerablePresent | ObjectPropertyDescriptor::NonWritablePresent | ObjectPropertyDescriptor::NonConfigurablePresent)));
DEFINE_GLOBAL_SYMBOLS(DECLARE_GLOBAL_SYMBOLS);
m_symbol->setFunctionPrototype(state, m_symbolPrototype);
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().Symbol),
ObjectPropertyDescriptor(m_symbol, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
}
}

View file

@ -19,6 +19,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "TypedArrayObject.h"
#include "IteratorObject.h"
#include "interpreter/ByteCode.h"
@ -537,6 +538,18 @@ static Value builtinTypedArrayEntries(ExecutionState& state, Value thisValue, si
return M->entries(state);
}
static Value builtinTypedArrayGetToStringTag(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
{
Value O = thisValue;
if (!O.isObject()) {
return Value();
}
if (O.asObject() && O.asObject()->isTypedArrayObject()) {
return Value(String::fromASCII(O.asObject()->internalClassProperty()));
}
return Value();
}
void GlobalObject::installTypedArray(ExecutionState& state)
{
m_arrayBuffer = new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().ArrayBuffer, builtinArrayBufferConstructor, 1, [](ExecutionState& state, CodeBlock* codeBlock, size_t argc, Value* argv) -> Object* {
@ -553,6 +566,9 @@ void GlobalObject::installTypedArray(ExecutionState& state)
m_arrayBufferPrototype = new ArrayBufferObject(state);
m_arrayBufferPrototype->setPrototype(state, m_objectPrototype);
m_arrayBufferPrototype->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().constructor), ObjectPropertyDescriptor(m_arrayBuffer, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_arrayBufferPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(state.context()->staticStrings().ArrayBuffer.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
const StaticStrings* strings = &state.context()->staticStrings();
@ -589,11 +605,23 @@ void GlobalObject::installTypedArray(ExecutionState& state)
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->lastIndexOf, builtinTypedArrayLastIndexOf, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
typedArrayPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().keys),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().keys, builtinTypedArrayKeys, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
typedArrayPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().values),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().values, builtinTypedArrayValues, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
typedArrayPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().entries),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().entries, builtinTypedArrayEntries, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
auto valuesFn = new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().values, builtinTypedArrayValues, 0, nullptr, NativeFunctionInfo::Strict));
typedArrayPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().values),
ObjectPropertyDescriptor(valuesFn, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
typedArrayPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, state.context()->vmInstance()->globalSymbols().iterator),
ObjectPropertyDescriptor(valuesFn,
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
{
JSGetterSetter gs(
new FunctionObject(state, NativeFunctionInfo(AtomicString(state, String::fromASCII("get [Symbol.toStringTag]")), builtinTypedArrayGetToStringTag, 0, nullptr, NativeFunctionInfo::Strict)),
Value(Value::EmptyValue));
ObjectPropertyDescriptor desc(gs, ObjectPropertyDescriptor::ConfigurablePresent);
typedArrayPrototype->defineOwnProperty(state, ObjectPropertyName(state, state.context()->vmInstance()->globalSymbols().toStringTag), desc);
}
{
JSGetterSetter gs(
new FunctionObject(state, NativeFunctionInfo(strings->getbyteLength, builtinTypedArrayByteLengthGetter, 0, nullptr, NativeFunctionInfo::Strict)),

View file

@ -17,6 +17,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "WeakMapObject.h"
#include "IteratorObject.h"
#include "ToStringRecursionPreventer.h"
@ -39,7 +40,7 @@ Value builtinWeakMapConstructor(ExecutionState& state, Value thisValue, size_t a
}
// If iterable is either undefined or null, let iter be undefined.
Value adder;
IteratorObject* iter = nullptr;
Object* iter = nullptr;
if (iterable.isUndefinedOrNull()) {
iterable = Value();
} else {
@ -65,7 +66,7 @@ Value builtinWeakMapConstructor(ExecutionState& state, Value thisValue, size_t a
// Repeat
while (true) {
// Let next be ? IteratorStep(iter).
auto next = iter->advance(state);
auto next = iter->iteratorNext(state);
// If next is false(done is true), return map.
if (next.second) {
return map;
@ -167,6 +168,9 @@ void GlobalObject::installWeakMap(ExecutionState& state)
m_weakMapPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().set),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().set, builtinWeakMapSet, 2, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_weakMapPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(state.context()->staticStrings().WeakMap.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
m_weakMap->setFunctionPrototype(state, m_weakMapPrototype);
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().WeakMap),
ObjectPropertyDescriptor(m_weakMap, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

View file

@ -17,6 +17,7 @@
#include "Escargot.h"
#include "GlobalObject.h"
#include "Context.h"
#include "VMInstance.h"
#include "WeakSetObject.h"
#include "IteratorObject.h"
#include "ToStringRecursionPreventer.h"
@ -41,7 +42,7 @@ Value builtinWeakSetConstructor(ExecutionState& state, Value thisValue, size_t a
}
// If iterable is either undefined or null, let iter be undefined.
Value adder;
IteratorObject* iter = nullptr;
Object* iter = nullptr;
if (iterable.isUndefinedOrNull()) {
iterable = Value();
} else {
@ -67,7 +68,7 @@ Value builtinWeakSetConstructor(ExecutionState& state, Value thisValue, size_t a
// Repeat
while (true) {
// Let next be ? IteratorStep(iter).
auto next = iter->advance(state);
auto next = iter->iteratorNext(state);
// If next is false, return set.
if (next.second) {
return set;
@ -142,6 +143,9 @@ void GlobalObject::installWeakSet(ExecutionState& state)
m_weakSetPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().add),
ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().add, builtinWeakSetAdd, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_weakSetPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(state.context()->staticStrings().WeakSet.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
m_weakSet->setFunctionPrototype(state, m_weakSetPrototype);
defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().WeakSet),
ObjectPropertyDescriptor(m_weakSet, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));

View file

@ -142,11 +142,6 @@ MapIteratorObject* MapObject::entries(ExecutionState& state)
return new MapIteratorObject(state, this, MapIteratorObject::TypeKeyValue);
}
IteratorObject* MapObject::iterator(ExecutionState& state)
{
return new MapIteratorObject(state, this, MapIteratorObject::TypeKeyValue);
}
MapIteratorObject::MapIteratorObject(ExecutionState& state, MapObject* map, Type type)
: IteratorObject(state)
, m_map(map)

View file

@ -52,7 +52,6 @@ public:
MapIteratorObject* values(ExecutionState& state);
MapIteratorObject* keys(ExecutionState& state);
MapIteratorObject* entries(ExecutionState& state);
virtual IteratorObject* iterator(ExecutionState& state) override;
void* operator new(size_t size);
void* operator new[](size_t size) = delete;

View file

@ -26,6 +26,36 @@
namespace Escargot {
PropertyName::PropertyName(ExecutionState& state, const Value& valueIn)
{
Value value = valueIn.toPrimitive(state, Value::PreferString);
if (UNLIKELY(value.isSymbol())) {
m_data = (size_t)value.asSymbol();
return;
}
String* string = value.toString(state);
StringBufferAccessData data = string->bufferAccessData();
if (data.length == 0) {
m_data = ((size_t)AtomicString().string()) | PROPERTY_NAME_ATOMIC_STRING_VIAS;
return;
}
bool needsRemainNormalString = false;
char16_t c = data.has8BitContent ? ((LChar*)data.buffer)[0] : ((char16_t*)data.buffer)[0];
if ((c == '.' || (c >= '0' && c <= '9')) && data.length > 16) {
needsRemainNormalString = true;
}
if (UNLIKELY(needsRemainNormalString)) {
m_data = (size_t)string;
} else {
if (c < ESCARGOT_ASCII_TABLE_MAX && (data.length == 1)) {
m_data = ((size_t)state.context()->staticStrings().asciiTable[c].string()) | PROPERTY_NAME_ATOMIC_STRING_VIAS;
} else {
m_data = ((size_t)AtomicString(state, string).string()) | PROPERTY_NAME_ATOMIC_STRING_VIAS;
}
}
}
size_t g_objectRareDataTag;
ObjectRareData::ObjectRareData(Object* obj)
@ -40,7 +70,6 @@ ObjectRareData::ObjectRareData(Object* obj)
m_shouldUpdateEnumerateObjectData = false;
m_isInArrayObjectDefineOwnProperty = false;
m_hasNonWritableLastIndexRegexpObject = false;
m_internalClassName = nullptr;
m_extraData = nullptr;
#ifdef ESCARGOT_ENABLE_PROMISE
m_internalSlot = nullptr;
@ -404,7 +433,7 @@ ObjectGetResult Object::getOwnProperty(ExecutionState& state, const ObjectProper
bool Object::defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
if (UNLIKELY(isEverSetAsPrototypeObject())) {
if (UNLIKELY(!state.context()->vmInstance()->didSomePrototypeObjectDefineIndexedProperty() && isIndexString(P.string(state)))) {
if (UNLIKELY(!state.context()->vmInstance()->didSomePrototypeObjectDefineIndexedProperty() && P.isIndexString())) {
state.context()->vmInstance()->somePrototypeObjectDefineIndexedProperty(state);
}
}
@ -637,11 +666,14 @@ bool Object::deleteOwnProperty(ExecutionState& state, const ObjectPropertyName&
return true;
}
void Object::enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
void Object::enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
size_t cnt = m_structure->propertyCount();
for (size_t i = 0; i < cnt; i++) {
const ObjectStructureItem& item = m_structure->readProperty(state, i);
if (shouldSkipSymbolKey && item.m_propertyName.isSymbol()) {
continue;
}
if (!callback(state, this, ObjectPropertyName(state, item.m_propertyName), item.m_descriptor, data)) {
break;
}
@ -653,10 +685,10 @@ ValueVector Object::getOwnPropertyKeys(ExecutionState& state)
ValueVector result;
enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
ValueVector* result = (ValueVector*)data;
result->pushBack(name.toValue(state));
result->pushBack(name.toPlainValue(state));
return true;
},
&result);
&result, false);
return result;
}
@ -743,30 +775,30 @@ bool Object::set(ExecutionState& state, const ObjectPropertyName& propertyName,
void Object::setThrowsException(ExecutionState& state, const ObjectPropertyName& P, const Value& v, const Value& receiver)
{
if (UNLIKELY(!set(state, P, v, receiver))) {
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.string(state), false, String::emptyString, errorMessage_DefineProperty_NotWritable);
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.toExceptionString(), false, String::emptyString, errorMessage_DefineProperty_NotWritable);
}
}
void Object::setThrowsExceptionWhenStrictMode(ExecutionState& state, const ObjectPropertyName& P, const Value& v, const Value& receiver)
{
if (UNLIKELY(!set(state, P, v, receiver)) && state.inStrictMode()) {
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.string(state), false, String::emptyString, errorMessage_DefineProperty_NotWritable);
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.toExceptionString(), false, String::emptyString, errorMessage_DefineProperty_NotWritable);
}
}
void Object::throwCannotDefineError(ExecutionState& state, const PropertyName& P)
{
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.string(), false, String::emptyString, errorMessage_DefineProperty_RedefineNotConfigurable);
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.toExceptionString(), false, String::emptyString, errorMessage_DefineProperty_RedefineNotConfigurable);
}
void Object::throwCannotWriteError(ExecutionState& state, const PropertyName& P)
{
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.string(), false, String::emptyString, errorMessage_DefineProperty_NotWritable);
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.toExceptionString(), false, String::emptyString, errorMessage_DefineProperty_NotWritable);
}
void Object::throwCannotDeleteError(ExecutionState& state, const PropertyName& P)
{
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.string(), false, String::emptyString, errorMessage_DefineProperty_NotConfigurable);
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, P.toExceptionString(), false, String::emptyString, errorMessage_DefineProperty_NotConfigurable);
}
void Object::deleteOwnProperty(ExecutionState& state, size_t idx)
@ -785,6 +817,11 @@ uint64_t Object::length(ExecutionState& state)
return get(state, state.context()->staticStrings().length).value(state, this).toUint32(state);
}
double Object::lengthES6(ExecutionState& state)
{
return get(state, state.context()->staticStrings().length).value(state, this).toLength(state);
}
bool Object::nextIndexForward(ExecutionState& state, Object* obj, const double cur, const double end, const bool skipUndefined, double& nextIndex)
{
@ -807,7 +844,7 @@ bool Object::nextIndexForward(ExecutionState& state, Object* obj, const double c
uint64_t index;
Data* e = (Data*)data;
double* ret = e->ret;
Value key = name.toValue(state);
Value key = name.toPlainValue(state);
if ((index = key.toArrayIndex(state)) != Value::InvalidArrayIndexValue) {
if (*e->skipUndefined && self->get(state, name).value(state, self).isUndefined()) {
return true;
@ -849,7 +886,7 @@ bool Object::nextIndexBackward(ExecutionState& state, Object* obj, const double
uint64_t index;
Data* e = (Data*)data;
double* ret = e->ret;
Value key = name.toValue(state);
Value key = name.toPlainValue(state);
if ((index = key.toArrayIndex(state)) != Value::InvalidArrayIndexValue) {
if (*e->skipUndefined && self->get(state, name).value(state, self).isUndefined()) {
return true;
@ -988,4 +1025,31 @@ IteratorObject* Object::entries(ExecutionState& state)
{
return new ArrayIteratorObject(state, this, ArrayIteratorObject::TypeKeyValue);
}
Object* Object::iterator(ExecutionState& state)
{
Value v = get(state, ObjectPropertyName(state, state.context()->vmInstance()->globalSymbols().iterator)).value(state, this);
if (!v.isFunction()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "object is not iterable");
}
v = v.asFunction()->call(state, this, 0, nullptr);
if (!v.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "object is not iterable");
}
return v.asObject();
}
std::pair<Value, bool> Object::iteratorNext(ExecutionState& state)
{
Value mayBeFn = get(state, ObjectPropertyName(state.context()->staticStrings().next)).value(state, this);
Value returnValue = FunctionObject::call(state, mayBeFn, this, 0, nullptr);
if (!returnValue.isObject()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "iterator next function returns illegal value");
}
Value done = returnValue.asObject()->get(state, ObjectPropertyName(state.context()->staticStrings().done)).value(state, returnValue);
Value value = returnValue.asObject()->get(state, ObjectPropertyName(state.context()->staticStrings().value)).value(state, returnValue);
return std::make_pair(value, done.toBoolean(state));
}
}

View file

@ -46,7 +46,6 @@ struct ObjectRareData : public PointerValue {
bool m_shouldUpdateEnumerateObjectData : 1;
bool m_isInArrayObjectDefineOwnProperty : 1;
bool m_hasNonWritableLastIndexRegexpObject : 1;
const char* m_internalClassName;
void* m_extraData;
Object* m_prototype;
#ifdef ESCARGOT_ENABLE_PROMISE
@ -54,11 +53,6 @@ struct ObjectRareData : public PointerValue {
#endif
ObjectRareData(Object* obj);
virtual Type type()
{
return ObjectRareDataType;
}
void* operator new(size_t size);
void* operator new[](size_t size) = delete;
};
@ -72,7 +66,7 @@ public:
m_value.m_uint = v.asUInt32();
} else {
m_isUIntType = false;
m_value.m_name = PropertyName(state, v.toString(state));
m_value.m_name = PropertyName(state, v);
}
}
@ -105,6 +99,15 @@ public:
return m_value.m_uint;
}
bool isIndexString() const
{
if (isUIntType()) {
return true;
} else {
return propertyName().isIndexString();
}
}
PropertyName toPropertyName(ExecutionState& state) const
{
if (isUIntType()) {
@ -113,17 +116,37 @@ public:
return propertyName();
}
String* string(ExecutionState& state) const
uint64_t tryToUseAsIndex() const
{
return toPropertyName(state).string();
if (LIKELY(isUIntType())) {
return m_value.m_uint;
}
return propertyName().tryToUseAsIndex();
}
Value toValue(ExecutionState& state) const
uint64_t tryToUseAsArrayIndex() const
{
if (LIKELY(isUIntType())) {
return m_value.m_uint;
}
return propertyName().tryToUseAsArrayIndex();
}
Value toPlainValue(ExecutionState& state) const
{
if (isUIntType()) {
return Value(uintValue());
} else {
return Value(string(state));
return propertyName().toValue();
}
}
String* toExceptionString() const
{
if (isUIntType()) {
return String::fromDouble(uintValue());
} else {
return propertyName().toExceptionString();
}
}
@ -149,11 +172,6 @@ public:
ASSERT(setter.isEmpty() || setter.isFunction() || setter.isUndefined());
}
virtual Type type()
{
return JSGetterSetterType;
}
virtual bool isJSGetterSetter() const
{
return true;
@ -505,10 +523,6 @@ class Object : public PointerValue {
public:
Object(ExecutionState& state);
static Object* createFunctionPrototypeObject(ExecutionState& state, FunctionObject* function);
virtual Type type()
{
return ObjectType;
}
virtual bool isObject() const
{
@ -623,10 +637,10 @@ public:
virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
// enumeration every property!
// callback function should skip un-Enumerable property if needs
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey = true) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual uint64_t length(ExecutionState& state);
double lengthES6(ExecutionState& state);
bool hasOwnProperty(ExecutionState& state, const ObjectPropertyName& propertyName)
{
@ -712,14 +726,7 @@ public:
// http://www.ecma-international.org/ecma-262/5.1/#sec-8.6.2
virtual const char* internalClassProperty()
{
if (LIKELY(rareData() == nullptr) || LIKELY(rareData()->m_internalClassName == nullptr))
return "Object";
return rareData()->m_internalClassName;
}
virtual void giveInternalClassProperty(const char* name)
{
ensureObjectRareData()->m_internalClassName = name;
return "Object";
}
void* extraData()
@ -772,10 +779,8 @@ public:
IteratorObject* values(ExecutionState& state);
IteratorObject* keys(ExecutionState& state);
IteratorObject* entries(ExecutionState& state);
virtual IteratorObject* iterator(ExecutionState& state) // this matches with Object[@@iterator]
{
return nullptr;
}
Object* iterator(ExecutionState& state);
std::pair<Value, bool> iteratorNext(ExecutionState& state); // http://www.ecma-international.org/ecma-262/7.0/index.html#sec-iteratornext
protected:
Object(ExecutionState& state, size_t defaultSpace, bool initPlainArea);

View file

@ -238,10 +238,11 @@ inline PropertyNameMap& ObjectStructure::propertyNameMap()
inline ObjectStructure* ObjectStructure::addProperty(ExecutionState& state, const PropertyName& name, const ObjectStructurePropertyDescriptor& desc)
{
bool nameIsIndexString = name.isIndexString();
ObjectStructureItem newItem(name, desc);
if (m_isStructureWithFastAccess) {
m_properties.pushBack(newItem);
m_hasIndexPropertyName = m_hasIndexPropertyName | isIndexString(name.string());
m_hasIndexPropertyName = m_hasIndexPropertyName | nameIsIndexString;
propertyNameMap().insert(std::make_pair(name, m_properties.size() - 1));
ObjectStructureWithFastAccess* self = (ObjectStructureWithFastAccess*)this;
ObjectStructureWithFastAccess* newSelf = new ObjectStructureWithFastAccess(state, *self);
@ -261,9 +262,9 @@ inline ObjectStructure* ObjectStructure::addProperty(ExecutionState& state, cons
ObjectStructure* newObjectStructure;
if (newProperties.size() > ESCARGOT_OBJECT_STRUCTURE_ACCESS_CACHE_BUILD_MIN_SIZE)
newObjectStructure = new ObjectStructureWithFastAccess(state, std::move(newProperties), m_hasIndexPropertyName | isIndexString(name.string()));
newObjectStructure = new ObjectStructureWithFastAccess(state, std::move(newProperties), m_hasIndexPropertyName | nameIsIndexString);
else
newObjectStructure = new ObjectStructure(state, std::move(newProperties), m_needsTransitionTable, m_hasIndexPropertyName | isIndexString(name.string()));
newObjectStructure = new ObjectStructure(state, std::move(newProperties), m_needsTransitionTable, m_hasIndexPropertyName | nameIsIndexString);
if (m_needsTransitionTable && !newObjectStructure->isStructureWithFastAccess()) {
ObjectStructureTransitionItem newTransitionItem(name, desc, newObjectStructure);
@ -293,7 +294,7 @@ inline ObjectStructure* ObjectStructure::removeProperty(ExecutionState& state, s
for (size_t i = 0; i < m_properties.size(); i++) {
if (i == pIndex)
continue;
hasIndexString = hasIndexString | isIndexString(m_properties[i].m_propertyName.string());
hasIndexString = hasIndexString | m_properties[i].m_propertyName.isIndexString();
newProperties[newIdx].m_propertyName = m_properties[i].m_propertyName;
newProperties[newIdx].m_descriptor = m_properties[i].m_descriptor;
newIdx++;

View file

@ -20,10 +20,12 @@
namespace Escargot {
class String;
class Symbol;
class Object;
class FunctionObject;
class ArrayObject;
class StringObject;
class SymbolObject;
class NumberObject;
class BooleanObject;
class RegExpObject;
@ -46,7 +48,7 @@ class SetObject;
class WeakMapObject;
class WeakSetObject;
#define POINTER_VALUE_STRING_TAG_IN_DATA 0x3
#define POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA 0x3
// finding what is type of PointerValue operation is used in SmallValue <-> Value and interpreter
// Only Object, String are seen in regular runtime-code
// We figure what type of PointerValue by POINTER_VALUE_STRING_TAG_IN_DATA
@ -55,25 +57,20 @@ class WeakSetObject;
// finding what is type of PointerValue(Object, String) without accessing vtable provides gives better performance
// but, it uses more memory for String type
// POINTER_VALUE_STRING_TAG_IN_DATA is not essential thing for implementing figure type(we can use isObject, isString)
// so, we can remove POINTER_VALUE_STRING_TAG_IN_DATA in very small device future
// so, we can remove POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA in very small device future
class PointerValue : public gc {
public:
enum Type {
StringType,
ObjectType,
ObjectRareDataType,
DoubleInSmallValueType,
JSGetterSetterType,
EnumerateObjectDataType,
};
virtual Type type() = 0;
virtual bool isString() const
{
return false;
}
virtual bool isSymbol() const
{
return false;
}
virtual bool isObject() const
{
return false;
@ -94,6 +91,11 @@ public:
return false;
}
virtual bool isSymbolObject() const
{
return false;
}
virtual bool isNumberObject() const
{
return false;
@ -199,6 +201,12 @@ public:
return (String*)this;
}
Symbol* asSymbol()
{
ASSERT(isSymbol());
return (Symbol*)this;
}
Object* asObject()
{
ASSERT(isObject());
@ -223,6 +231,12 @@ public:
return (StringObject*)this;
}
SymbolObject* asSymbolObject()
{
ASSERT(isSymbolObject());
return (SymbolObject*)this;
}
NumberObject* asNumberObject()
{
ASSERT(isNumberObject());

View file

@ -14,33 +14,5 @@
* limitations under the License.
*/
#include "Escargot.h"
#include "PropertyName.h"
#include "Context.h"
namespace Escargot {
PropertyName::PropertyName(ExecutionState& state, String* string)
{
StringBufferAccessData data = string->bufferAccessData();
if (data.length == 0) {
m_data = ((size_t)AtomicString().string()) | 1;
return;
}
bool needsRemainNormalString = false;
char16_t c = data.has8BitContent ? ((LChar*)data.buffer)[0] : ((char16_t*)data.buffer)[0];
if ((c == '.' || (c >= '0' && c <= '9')) && data.length > 16) {
needsRemainNormalString = true;
}
if (UNLIKELY(needsRemainNormalString)) {
m_data = (size_t)string;
} else {
if (c < ESCARGOT_ASCII_TABLE_MAX && (data.length == 1)) {
m_data = ((size_t)state.context()->staticStrings().asciiTable[c].string()) | 1;
} else {
m_data = ((size_t)AtomicString(state, string).string()) | 1;
}
}
}
}

View file

@ -20,73 +20,148 @@
#include "runtime/AtomicString.h"
#include "runtime/ExecutionState.h"
#include "runtime/String.h"
#include "runtime/Symbol.h"
#include "runtime/Value.h"
namespace Escargot {
#define PROPERTY_NAME_ATOMIC_STRING_VIAS 1
class PropertyName {
public:
PropertyName()
{
m_data = ((size_t)AtomicString().string()) + 1;
ASSERT(m_data);
}
PropertyName(ExecutionState& state, const AtomicString& atomicString)
{
m_data = ((size_t)atomicString.string() + 1);
ASSERT(m_data);
}
PropertyName(const AtomicString& atomicString)
{
m_data = ((size_t)atomicString.string() + 1);
m_data = ((size_t)atomicString.string() + PROPERTY_NAME_ATOMIC_STRING_VIAS);
ASSERT(m_data);
}
PropertyName(ExecutionState& state, String* string);
String* string() const
PropertyName(ExecutionState& state, const Value& value);
size_t hashValue() const
{
if (hasAtomicString()) {
return (String*)(m_data - 1);
} else {
return (String*)m_data;
}
}
AtomicString atomicString(ExecutionState& state)
{
if (hasAtomicString()) {
return AtomicString((String*)(m_data - 1));
} else {
return AtomicString(state, (String*)m_data);
return ((String*)(m_data - PROPERTY_NAME_ATOMIC_STRING_VIAS))->hashValue();
} else if (hasSymbol()) {
return m_data;
}
return ((String*)m_data)->hashValue();
}
ALWAYS_INLINE friend bool operator==(const PropertyName& a, const PropertyName& b);
ALWAYS_INLINE friend bool operator!=(const PropertyName& a, const PropertyName& b);
size_t rawData() const
ALWAYS_INLINE bool isSymbol() const
{
return m_data;
if (hasAtomicString()) {
return false;
}
PointerValue* pa = (PointerValue*)m_data;
if (UNLIKELY(pa->hasTag(g_symbolTag))) {
return true;
}
return false;
}
ALWAYS_INLINE bool hasAtomicString() const
{
return LIKELY(m_data & 1);
return LIKELY(m_data & PROPERTY_NAME_ATOMIC_STRING_VIAS);
}
bool isPlainString() const
{
if (hasAtomicString()) {
return true;
} else if (hasSymbol()) {
return false;
}
return true;
}
String* plainString() const
{
ASSERT(isPlainString());
if (hasAtomicString()) {
return ((String*)(m_data - PROPERTY_NAME_ATOMIC_STRING_VIAS));
}
return ((String*)m_data);
}
bool isIndexString() const
{
return isPlainString() && ::Escargot::isIndexString(plainString());
}
Value toValue() const
{
if (hasAtomicString()) {
return Value((String*)(m_data - PROPERTY_NAME_ATOMIC_STRING_VIAS));
} else {
return Value((PointerValue*)m_data);
}
}
uint64_t tryToUseAsIndex() const
{
if (isPlainString()) {
return plainString()->tryToUseAsIndex();
}
return Value::InvalidIndexValue;
}
uint64_t tryToUseAsArrayIndex() const
{
if (isPlainString()) {
return plainString()->tryToUseAsArrayIndex();
}
return Value::InvalidArrayIndexValue;
}
bool equals(String* s) const
{
if (isPlainString()) {
return plainString()->equals(s);
}
return false;
}
String* toExceptionString() const
{
if (isPlainString()) {
return plainString();
}
return ((Symbol*)m_data)->getSymbolDescriptiveString();
}
protected:
ALWAYS_INLINE bool hasSymbol() const
{
ASSERT(!hasAtomicString());
PointerValue* pa = (PointerValue*)m_data;
if (UNLIKELY(pa->hasTag(g_symbolTag))) {
return true;
}
return false;
}
size_t m_data;
// AtomicString <- saves its (String* | 1)
// String* <- saves pointer
// AtomicString <- saves its (String* | PROPERTY_NAME_ATOMIC_STRING_VIAS)
// String*, Symbol* <- saves pointer
};
ALWAYS_INLINE bool operator==(const PropertyName& a, const PropertyName& b)
{
if (LIKELY(LIKELY(a.hasAtomicString()) && LIKELY(b.hasAtomicString()))) {
bool aa = a.hasAtomicString();
bool ab = b.hasAtomicString();
if (LIKELY(LIKELY(aa) && LIKELY(ab))) {
return a.m_data == b.m_data;
} else {
return a.string()->equals(b.string());
bool sa = !aa && a.hasSymbol();
bool sb = !ab && b.hasSymbol();
if (sa && sb) { // a, b both are symbol
return a.m_data == b.m_data;
} else if (!sa && !sb) { // a, b both are string
return a.plainString()->equals(b.plainString());
} else {
return false;
}
}
}
@ -103,7 +178,7 @@ template <>
struct hash<Escargot::PropertyName> {
size_t operator()(Escargot::PropertyName const& x) const
{
return x.string()->hashValue();
return x.hashValue();
}
};

View file

@ -127,11 +127,6 @@ SetIteratorObject* SetObject::entries(ExecutionState& state)
return new SetIteratorObject(state, this, SetIteratorObject::TypeKeyValue);
}
IteratorObject* SetObject::iterator(ExecutionState& state)
{
return new SetIteratorObject(state, this, SetIteratorObject::TypeValue);
}
SetIteratorObject::SetIteratorObject(ExecutionState& state, SetObject* set, Type type)
: IteratorObject(state)
, m_set(set)

View file

@ -52,8 +52,6 @@ public:
SetIteratorObject* values(ExecutionState& state);
SetIteratorObject* keys(ExecutionState& state);
virtual IteratorObject* iterator(ExecutionState& state) override;
void* operator new(size_t size);
void* operator new[](size_t size) = delete;

View file

@ -35,11 +35,6 @@ class DoubleInSmallValue : public PointerValue {
friend class SmallValue;
public:
virtual Type type()
{
return DoubleInSmallValueType;
}
virtual bool isDoubleInSmallValue() const
{
return true;

View file

@ -32,6 +32,8 @@ void StaticStrings::initStaticStrings(AtomicStringMap* atomicStringMap)
stringStatic.init(atomicStringMap, "static", strlen("static"));
stringCatch.init(atomicStringMap, "catch", strlen("catch"));
stringDelete.init(atomicStringMap, "delete", strlen("delete"));
stringFor.init(atomicStringMap, "for", strlen("for"));
stringDefault.init(atomicStringMap, "default", strlen("default"));
defaultRegExpString.init(atomicStringMap, "(?:)", strlen("(?:)"));
get__proto__.init(atomicStringMap, "get __proto__", strlen("get __proto__"));

View file

@ -66,6 +66,7 @@ namespace Escargot {
F(valueOf) \
F(Array) \
F(isArray) \
F(from) \
F(concat) \
F(forEach) \
F(indexOf) \
@ -222,6 +223,7 @@ namespace Escargot {
F(fromCharCode) \
F(getOwnPropertyDescriptor) \
F(getOwnPropertyNames) \
F(getOwnPropertySymbols) \
F(hasOwnProperty) \
F(imul) \
F(isExtensible) \
@ -338,6 +340,16 @@ namespace Escargot {
F(Set) \
F(WeakMap) \
F(WeakSet) \
F(Symbol) \
F(symbol) \
F(hasInstance) \
F(isConcatSpreadable) \
F(iterator) \
F(species) \
F(toPrimitive) \
F(toStringTag) \
F(unscopables) \
F(keyFor) \
F(load)
@ -356,6 +368,8 @@ public:
AtomicString stringStatic;
AtomicString stringCatch;
AtomicString stringDelete;
AtomicString stringFor;
AtomicString stringDefault;
AtomicString defaultRegExpString;
AtomicString get__proto__;
AtomicString set__proto__;

View file

@ -80,11 +80,7 @@ class String : public PointerValue {
public:
String()
{
m_tag = POINTER_VALUE_STRING_TAG_IN_DATA;
}
virtual Type type()
{
return StringType;
m_tag = POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA;
}
virtual bool isString() const

View file

@ -48,12 +48,7 @@ void* StringObject::operator new(size_t size)
ObjectGetResult StringObject::getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
Value::ValueIndex idx;
if (P.isUIntType()) {
idx = P.uintValue();
} else {
idx = P.string(state)->tryToUseAsIndex();
}
Value::ValueIndex idx = P.tryToUseAsIndex();
if (idx != Value::InvalidIndexValue) {
size_t strLen = m_primitiveValue->length();
if (LIKELY(idx < strLen)) {
@ -79,7 +74,7 @@ bool StringObject::deleteOwnProperty(ExecutionState& state, const ObjectProperty
return Object::deleteOwnProperty(state, P);
}
void StringObject::enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
void StringObject::enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
size_t len = m_primitiveValue->length();
for (size_t i = 0; i < len; i++) {
@ -87,17 +82,12 @@ void StringObject::enumeration(ExecutionState& state, bool (*callback)(Execution
return;
}
}
Object::enumeration(state, callback, data);
Object::enumeration(state, callback, data, shouldSkipSymbolKey);
}
ObjectGetResult StringObject::getIndexedProperty(ExecutionState& state, const Value& property)
{
Value::ValueIndex idx;
if (LIKELY(property.isUInt32())) {
idx = property.asUInt32();
} else {
idx = property.toString(state)->tryToUseAsIndex();
}
Value::ValueIndex idx = property.tryToUseAsIndex(state);
if (idx != Value::InvalidIndexValue) {
size_t strLen = m_primitiveValue->length();
if (LIKELY(idx < strLen)) {
@ -107,11 +97,6 @@ ObjectGetResult StringObject::getIndexedProperty(ExecutionState& state, const Va
return get(state, ObjectPropertyName(state, property));
}
IteratorObject* StringObject::iterator(ExecutionState& state)
{
return new StringIteratorObject(state, m_primitiveValue);
}
StringIteratorObject::StringIteratorObject(ExecutionState& state, String* s)
: IteratorObject(state)
, m_string(s)
@ -162,13 +147,13 @@ std::pair<Value, bool> StringIteratorObject::advance(ExecutionState& state)
// If first < 0xD800 or first > 0xDBFF or position+1 = len, let resultString be the string consisting of the single code unit first.
String* resultString;
if (first < 0xD800 || first > 0xDBFF || (position + 1 == len)) {
resultString = String::fromInt32(first);
resultString = String::fromCharCode(first);
} else {
// Let second be the code unit value at index position+1 in the String S.
auto second = s->charAt(position + 1);
// If second < 0xDC00 or second > 0xDFFF, let resultString be the string consisting of the single code unit first.
if (second < 0xDC00 || second > 0xDFFF) {
resultString = String::fromInt32(first);
resultString = String::fromCharCode(first);
} else {
// Else, let resultString be the string consisting of the code unit first followed by the code unit second.
char16_t s[2] = { first, second };

View file

@ -44,7 +44,7 @@ public:
virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey = true) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE;
virtual ObjectGetResult getIndexedProperty(ExecutionState& state, const Value& property);
virtual uint64_t length(ExecutionState& state)
{
@ -57,8 +57,6 @@ public:
return "String";
}
virtual IteratorObject* iterator(ExecutionState& state) override;
void* operator new(size_t size);
void* operator new[](size_t size) = delete;

33
src/runtime/Symbol.cpp Normal file
View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2018-present Samsung Electronics Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Escargot.h"
#include "Symbol.h"
#include "Value.h"
namespace Escargot {
size_t g_symbolTag;
String* Symbol::getSymbolDescriptiveString() const
{
StringBuilder sb;
sb.appendString("Symbol(");
sb.appendString(description());
sb.appendString(")");
return sb.finalize();
}
}

52
src/runtime/Symbol.h Normal file
View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-present Samsung Electronics Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __EscargotSymbol__
#define __EscargotSymbol__
#include "runtime/PointerValue.h"
namespace Escargot {
extern size_t g_symbolTag;
class Symbol : public PointerValue {
public:
Symbol(String* desc = String::emptyString)
{
m_tag = POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA;
m_description = desc;
}
virtual bool isSymbol() const
{
return true;
}
String* description() const
{
return m_description;
}
String* getSymbolDescriptiveString() const;
protected:
size_t m_tag;
String* m_description;
};
}
#endif

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2018-present Samsung Electronics Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Escargot.h"
#include "SymbolObject.h"
#include "Context.h"
namespace Escargot {
SymbolObject::SymbolObject(ExecutionState& state, Symbol* value)
: Object(state, ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 1, true)
, m_primitiveValue(value)
{
m_structure = state.context()->defaultStructureForSymbolObject();
setPrototype(state, state.context()->globalObject()->symbolPrototype());
}
void* SymbolObject::operator new(size_t size)
{
static bool typeInited = false;
static GC_descr descr;
if (!typeInited) {
GC_word obj_bitmap[GC_BITMAP_SIZE(SymbolObject)] = { 0 };
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(SymbolObject, m_structure));
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(SymbolObject, m_prototype));
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(SymbolObject, m_values));
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(SymbolObject, m_primitiveValue));
descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(SymbolObject));
typeInited = true;
}
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
}
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-present Samsung Electronics Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __EscargotSymbolObject__
#define __EscargotSymbolObject__
#include "runtime/Object.h"
#include "runtime/Symbol.h"
namespace Escargot {
class SymbolObject : public Object {
public:
SymbolObject(ExecutionState& state, Symbol* s);
Symbol* primitiveValue()
{
return m_primitiveValue;
}
virtual bool isSymbolObject() const
{
return true;
}
void setPrimitiveValue(ExecutionState& state, Symbol* data)
{
m_primitiveValue = data;
}
void* operator new(size_t size);
void* operator new[](size_t size) = delete;
protected:
Symbol* m_primitiveValue;
};
}
#endif

View file

@ -237,13 +237,7 @@ public:
virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
uint64_t index;
if (LIKELY(P.isUIntType())) {
index = P.uintValue();
} else {
index = P.string(state)->tryToUseAsIndex();
}
uint64_t index = P.tryToUseAsIndex();
if (LIKELY(Value::InvalidIndexValue != index)) {
if ((unsigned)index < arraylength()) {
unsigned idxPosition = index * typedArrayElementSize;
@ -256,13 +250,7 @@ public:
virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
{
uint64_t index;
if (LIKELY(P.isUIntType())) {
index = P.uintValue();
} else {
index = P.string(state)->tryToUseAsIndex();
}
uint64_t index = P.tryToUseAsIndex();
if (LIKELY(Value::InvalidIndexValue != index)) {
if ((unsigned)index >= arraylength())
return false;
@ -314,12 +302,7 @@ public:
virtual ObjectGetResult getIndexedProperty(ExecutionState& state, const Value& property)
{
uint64_t idx;
if (LIKELY(property.isUInt32())) {
idx = property.asUInt32();
} else {
idx = property.toString(state)->tryToUseAsIndex();
}
Value::ValueIndex idx = property.tryToUseAsIndex(state);
if (LIKELY(idx != Value::InvalidIndexValue)) {
if (LIKELY((unsigned)idx < arraylength())) {
unsigned idxPosition = idx * typedArrayElementSize;
@ -331,13 +314,7 @@ public:
virtual bool setIndexedProperty(ExecutionState& state, const Value& property, const Value& value)
{
int64_t index;
if (LIKELY(property.isInt32())) {
index = property.asInt32();
} else {
index = property.toString(state)->tryToUseAsIndex();
}
Value::ValueIndex index = property.tryToUseAsIndex(state);
if (index < 0) {
return true;
}
@ -351,11 +328,6 @@ public:
return set(state, ObjectPropertyName(state, property), value, this);
}
virtual IteratorObject* iterator(ExecutionState& state) override
{
return new ArrayIteratorObject(state, this, ArrayIteratorObject::TypeValue);
}
protected:
};

View file

@ -25,6 +25,7 @@ namespace Escargot {
extern size_t g_doubleInSmallValueTag;
extern size_t g_objectRareDataTag;
extern size_t g_symbolTag;
Value VMInstance::functionPrototypeNativeGetter(ExecutionState& state, Object* self, const SmallValue& privateDataFromObjectPrivateArea)
{
@ -182,6 +183,13 @@ VMInstance::VMInstance(const char* locale, const char* timezone)
ObjectRareData data(nullptr);
g_objectRareDataTag = *((size_t*)&data);
Symbol sm(nullptr);
g_symbolTag = *((size_t*)&sm);
#define DECLARE_GLOBAL_SYMBOLS(name) m_globalSymbols.name = new Symbol(String::fromASCII("Symbol." #name));
DEFINE_GLOBAL_SYMBOLS(DECLARE_GLOBAL_SYMBOLS);
#undef DECLARE_GLOBAL_SYMBOLS
ExecutionState stateForInit((Context*)nullptr);
ObjectStructure defaultStructureForObject(stateForInit);
@ -238,6 +246,8 @@ VMInstance::VMInstance(const char* locale, const char* timezone)
m_defaultStructureForStringObject = m_defaultStructureForObject->addProperty(stateForInit, m_staticStrings.length, ObjectStructurePropertyDescriptor::createDataButHasNativeGetterSetterDescriptor(&stringLengthGetterSetterData));
m_defaultStructureForSymbolObject = m_defaultStructureForObject;
m_defaultStructureForRegExpObject = m_defaultStructureForObject->addProperty(stateForInit, m_staticStrings.lastIndex,
ObjectStructurePropertyDescriptor::createDataButHasNativeGetterSetterDescriptor(&regexpLastIndexGetterSetterData));
// TODO(ES6): Below RegExp data properties is changed to accessor properties of RegExp.prototype in ES6.

View file

@ -23,6 +23,7 @@
#include "runtime/RegExpObject.h"
#include "runtime/StaticStrings.h"
#include "runtime/String.h"
#include "runtime/Symbol.h"
#include "runtime/ToStringRecursionPreventer.h"
namespace Escargot {
@ -32,6 +33,26 @@ class CodeBlock;
class JobQueue;
class Job;
// TODO species, match, replace, search, split, unscopables, isConcatSpreadable
#define DEFINE_GLOBAL_SYMBOLS(F) \
F(hasInstance) \
F(iterator) \
F(toPrimitive) \
F(toStringTag)
struct GlobalSymbols {
#define DECLARE_GLOBAL_SYMBOLS(name) Symbol* name;
DEFINE_GLOBAL_SYMBOLS(DECLARE_GLOBAL_SYMBOLS);
#undef DECLARE_GLOBAL_SYMBOLS
};
struct GlobalSymbolRegistryItem {
String* key;
Symbol* symbol;
};
typedef Vector<GlobalSymbolRegistryItem, GCUtil::gc_malloc_allocator<GlobalSymbolRegistryItem>> GlobalSymbolRegistryVector;
class VMInstance : public gc {
friend class Context;
friend class VMInstanceRef;
@ -39,6 +60,17 @@ class VMInstance : public gc {
public:
VMInstance(const char* locale = nullptr, const char* timezone = nullptr);
const GlobalSymbols& globalSymbols()
{
return m_globalSymbols;
}
GlobalSymbolRegistryVector& globalSymbolRegistry()
{
return m_globalSymbolRegistry;
}
#ifdef ENABLE_ICU
icu::Locale& locale()
{
@ -142,6 +174,8 @@ public:
protected:
StaticStrings m_staticStrings;
AtomicStringMap m_atomicStringMap;
GlobalSymbols m_globalSymbols;
GlobalSymbolRegistryVector m_globalSymbolRegistry;
Vector<SandBox*, GCUtil::gc_malloc_allocator<SandBox*>> m_sandBoxStack;
std::unordered_map<void*, size_t, std::hash<void*>, std::equal_to<void*>,
GCUtil::gc_malloc_ignore_off_page_allocator<std::pair<void*, size_t>>>
@ -160,6 +194,7 @@ protected:
ObjectStructure* m_defaultStructureForBindedFunctionObject;
ObjectStructure* m_defaultStructureForArrayObject;
ObjectStructure* m_defaultStructureForStringObject;
ObjectStructure* m_defaultStructureForSymbolObject;
ObjectStructure* m_defaultStructureForRegExpObject;
ObjectStructure* m_defaultStructureForArgumentsObject;
ObjectStructure* m_defaultStructureForArgumentsObjectInStrictMode;

View file

@ -17,9 +17,12 @@
#include "Escargot.h"
#include "Value.h"
#include "Context.h"
#include "VMInstance.h"
#include "StaticStrings.h"
#include "Symbol.h"
#include "NumberObject.h"
#include "StringObject.h"
#include "SymbolObject.h"
#include "BooleanObject.h"
#include "ErrorObject.h"
@ -51,6 +54,19 @@ bool Value::isIterable() const
}
#endif
Value Value::toPropertyKey(ExecutionState& state) const
{
// Let key be ? ToPrimitive(argument, hint String).
Value key = toPrimitive(state, Value::PreferString);
// If Type(key) is Symbol, then
if (key.isSymbol()) {
// Return key.
return key;
}
// Return ! ToString(key).
return key.toString(state);
}
String* Value::toStringSlowCase(ExecutionState& ec) const // $7.1.12 ToString
{
ASSERT(!isString());
@ -85,6 +101,9 @@ String* Value::toStringSlowCase(ExecutionState& ec) const // $7.1.12 ToString
return ec.context()->staticStrings().stringTrue.string();
else
return ec.context()->staticStrings().stringFalse.string();
} else if (isSymbol()) {
ErrorObject::throwBuiltinError(ec, ErrorObject::TypeError, "Cannot convert a Symbol value to a string");
ASSERT_NOT_REACHED();
} else {
return toPrimitive(ec, PreferString).toString(ec);
}
@ -99,6 +118,8 @@ Object* Value::toObjectSlowCase(ExecutionState& state) const // $7.1.13 ToObject
object = new BooleanObject(state, toBoolean(state));
} else if (isString()) {
object = new StringObject(state, toString(state));
} else if (isSymbol()) {
object = new SymbolObject(state, asSymbol());
} else if (isNull()) {
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, errorMessage_NullToObject);
} else {
@ -108,7 +129,7 @@ Object* Value::toObjectSlowCase(ExecutionState& state) const // $7.1.13 ToObject
return object;
}
Value Value::toPrimitiveSlowCase(ExecutionState& state, PrimitiveTypeHint preferredType) const // $7.1.1 ToPrimitive
Value Value::ordinaryToPrimitive(ExecutionState& state, PrimitiveTypeHint preferredType) const
{
ASSERT(!isPrimitive());
Object* obj = asObject();
@ -150,6 +171,40 @@ Value Value::toPrimitiveSlowCase(ExecutionState& state, PrimitiveTypeHint prefer
RELEASE_ASSERT_NOT_REACHED();
}
Value Value::toPrimitiveSlowCase(ExecutionState& state, PrimitiveTypeHint preferredType) const // $7.1.1 ToPrimitive
{
// http://www.ecma-international.org/ecma-262/7.0/index.html#sec-toprimitive
// If PreferredType was not passed, let hint be "default".
// Else if PreferredType is hint String, let hint be "string".
// Else PreferredType is hint Number, let hint be "number".
ASSERT(!isPrimitive());
Object* obj = asObject();
// Let exoticToPrim be ? GetMethod(input, @@toPrimitive).
Value exoticToPrim = obj->get(state, ObjectPropertyName(state, state.context()->vmInstance()->globalSymbols().toPrimitive)).value(state, obj);
// If exoticToPrim is not undefined, then
if (!exoticToPrim.isUndefined()) {
// Let result be ? Call(exoticToPrim, input, « hint »).
Value hint;
if (preferredType == PreferNumber) {
hint = state.context()->staticStrings().number.string();
} else if (preferredType == PreferString) {
hint = state.context()->staticStrings().string.string();
} else {
hint = state.context()->staticStrings().stringDefault.string();
}
Value result = FunctionObject::call(state, exoticToPrim, obj, 1, &hint);
// If Type(result) is not Object, return result.
if (!result.isObject()) {
return result;
}
// Throw a TypeError exception.
ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, errorMessage_ObjectToPrimitiveValue);
}
return ordinaryToPrimitive(state, preferredType);
}
bool Value::abstractEqualsToSlowCase(ExecutionState& state, const Value& val) const
{
bool selfIsNumber = isNumber();
@ -174,13 +229,8 @@ bool Value::abstractEqualsToSlowCase(ExecutionState& state, const Value& val) co
bool selfIsPointerValue = isPointerValue();
bool valIsPointerValue = val.isPointerValue();
#ifdef ESCARGOT_32
bool valIsString = valIsPointerValue ? !val.isObject() : false;
bool selfIsString = selfIsPointerValue ? !isObject() : false;
#else
bool valIsString = valIsPointerValue ? val.asPointerValue()->isString() : false;
bool selfIsString = selfIsPointerValue ? asPointerValue()->isString() : false;
#endif
if (selfIsNumber && valIsString) {
// If Type(x) is Number and Type(y) is String,
@ -199,13 +249,13 @@ bool Value::abstractEqualsToSlowCase(ExecutionState& state, const Value& val) co
// If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
// return the result of the comparison ToNumber(x) == y.
return abstractEqualsTo(state, Value(val.toNumber(state)));
} else if ((selfIsString || selfIsNumber) && (valIsPointerValue && !valIsString)) {
} else if ((selfIsString || selfIsNumber || isSymbol()) && (valIsPointerValue && val.asPointerValue()->isObject())) {
// If Type(x) is either String, Number, or Symbol and Type(y) is Object, then
if (val.asPointerValue()->isDateObject())
return abstractEqualsTo(state, val.toPrimitive(state, Value::PreferString));
else
return abstractEqualsTo(state, val.toPrimitive(state));
} else if ((selfIsPointerValue && !selfIsString) && (valIsString || valIsNumber)) {
} else if ((selfIsPointerValue && asPointerValue()->isObject() && !selfIsString) && (valIsString || valIsNumber || val.isSymbol())) {
// If Type(x) is Object and Type(y) is either String, Number, or Symbol, then
if (asPointerValue()->isDateObject())
return toPrimitive(state, Value::PreferString).abstractEqualsTo(state, val);
@ -486,6 +536,9 @@ double Value::toNumberSlowCase(ExecutionState& state) const // $7.1.3 ToNumber
val = std::numeric_limits<double>::quiet_NaN();
}
return val;
} else if (isSymbol()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Cannot convert a Symbol value to a number");
ASSERT_NOT_REACHED();
} else {
return toPrimitive(state).toNumber(state);
}
@ -529,4 +582,20 @@ int32_t Value::toInt32SlowCase(ExecutionState& state) const // $7.1.5 ToInt32
// but testing 'bits' is likely faster) invert the result appropriately.
return bits < 0 ? -result : result;
}
Value::ValueIndex Value::tryToUseAsIndexSlowCase(ExecutionState& ec) const
{
if (isSymbol()) {
return Value::InvalidIndexValue;
}
return toString(ec)->tryToUseAsIndex();
}
uint32_t Value::tryToUseAsArrayIndexSlowCase(ExecutionState& ec) const
{
if (isSymbol()) {
return Value::InvalidArrayIndexValue;
}
return toString(ec)->tryToUseAsArrayIndex();
}
}

View file

@ -155,6 +155,7 @@ public:
inline Object* asObject() const;
inline FunctionObject* asFunction() const;
inline String* asString() const;
inline Symbol* asSymbol() const;
// Querying the type.
inline bool isEmpty() const;
@ -177,8 +178,10 @@ public:
bool isIterable() const;
enum PrimitiveTypeHint { PreferString,
PreferNumber };
PreferNumber,
PreferDefault };
Value toPrimitive(ExecutionState& ec, PrimitiveTypeHint = PreferNumber) const; // $7.1.1 ToPrimitive
Value ordinaryToPrimitive(ExecutionState& ec, PrimitiveTypeHint) const;
inline bool toBoolean(ExecutionState& ec) const; // $7.1.2 ToBoolean
double toNumber(ExecutionState& ec) const; // $7.1.3 ToNumber
double toInteger(ExecutionState& ec) const; // $7.1.4 ToInteger
@ -193,13 +196,15 @@ public:
return toStringSlowCase(ec);
}
Object* toObject(ExecutionState& ec) const; // $7.1.13 ToObject
Value toPropertyKey(ExecutionState& state) const;
enum { InvalidIndexValue = std::numeric_limits<uint32_t>::max() };
typedef uint64_t ValueIndex;
ValueIndex toIndex(ExecutionState& ec) const;
inline ValueIndex tryToUseAsIndex(ExecutionState& ec) const;
enum { InvalidArrayIndexValue = std::numeric_limits<uint32_t>::max() };
inline uint64_t toArrayIndex(ExecutionState& ec) const;
inline uint32_t tryToUseAsArrayIndex(ExecutionState& ec) const;
inline bool abstractEqualsTo(ExecutionState& ec, const Value& val) const;
bool abstractEqualsToSlowCase(ExecutionState& ec, const Value& val) const;
@ -208,6 +213,7 @@ public:
bool equalsToByTheSameValueAlgorithm(ExecutionState& ec, const Value& val) const;
bool equalsToByTheSameValueZeroAlgorithm(ExecutionState& ec, const Value& val) const;
#ifdef ESCARGOT_32
uint32_t tag() const;
int32_t payload() const;
@ -249,12 +255,13 @@ public:
private:
ValueDescriptor u;
double toNumberSlowCase(ExecutionState& ec) const; // $7.1.3 ToNumber
String* toStringSlowCase(ExecutionState& ec) const; // $7.1.12 ToString
Object* toObjectSlowCase(ExecutionState& ec) const; // $7.1.13 ToObject
Value toPrimitiveSlowCase(ExecutionState& ec, PrimitiveTypeHint) const; // $7.1.1 ToPrimitive
int32_t toInt32SlowCase(ExecutionState& ec) const; // $7.1.5 ToInt32
ValueIndex tryToUseAsIndexSlowCase(ExecutionState& ec) const;
uint32_t tryToUseAsArrayIndexSlowCase(ExecutionState& ec) const;
};
typedef Vector<Value, CustomAllocator<Value>> ValueVector;

View file

@ -101,7 +101,7 @@ extern size_t g_objectTag;
inline Value::Value(PointerValue* ptr)
{
// other type of PointerValue(Object) has pointer in first data area
if (ptr->getTagInFirstDataArea() & POINTER_VALUE_STRING_TAG_IN_DATA) {
if (ptr->getTagInFirstDataArea() & POINTER_VALUE_STRING_SYMBOL_TAG_IN_DATA) {
u.asBits.tag = OtherPointerTag;
} else {
u.asBits.tag = ObjectPointerTag;
@ -257,7 +257,12 @@ inline PointerValue* Value::asPointerValue() const
inline bool Value::isString() const
{
return tag() == OtherPointerTag;
return tag() == OtherPointerTag && asPointerValue()->isString();
}
inline bool Value::isSymbol() const
{
return tag() == OtherPointerTag && asPointerValue()->isSymbol();
}
inline String* Value::asString() const
@ -266,6 +271,12 @@ inline String* Value::asString() const
return asPointerValue()->asString();
}
inline Symbol* Value::asSymbol() const
{
ASSERT(isSymbol());
return asPointerValue()->asSymbol();
}
inline bool Value::isObject() const
{
return tag() == ObjectPointerTag;
@ -436,12 +447,23 @@ inline bool Value::isString() const
return isPointerValue() && asPointerValue()->isString();
}
inline bool Value::isSymbol() const
{
return isPointerValue() && asPointerValue()->isSymbol();
}
inline String* Value::asString() const
{
ASSERT(isString());
return asPointerValue()->asString();
}
inline Symbol* Value::asSymbol() const
{
ASSERT(isSymbol());
return asPointerValue()->asSymbol();
}
inline bool Value::isPointerValue() const
{
return !(u.asInt64 & TagMask);
@ -603,11 +625,10 @@ ALWAYS_INLINE double Value::asNumber() const
inline bool Value::isPrimitive() const
{
// return isUndefined() || isNull() || isNumber() || isString() || isBoolean();
#ifdef ESCARGOT_32
return tag() != ObjectPointerTag;
#else
return !isPointerValue() || asPointerValue()->isString();
return isUndefined() || isNull() || isNumber() || isString() || isBoolean() || isSymbol();
#endif
}
@ -717,8 +738,11 @@ inline bool Value::toBoolean(ExecutionState& ec) const // $7.1.2 ToBoolean
return false;
ASSERT(isPointerValue());
if (asPointerValue()->isString())
return asString()->length();
// Symbol, Objects..
return true;
}
@ -751,6 +775,24 @@ inline Value::ValueIndex Value::toIndex(ExecutionState& state) const // $7.1.15
}
}
Value::ValueIndex Value::tryToUseAsIndex(ExecutionState& ec) const
{
if (LIKELY(isUInt32())) {
return asUInt32();
} else {
return tryToUseAsIndexSlowCase(ec);
}
}
uint32_t Value::tryToUseAsArrayIndex(ExecutionState& ec) const
{
if (LIKELY(isUInt32())) {
return asUInt32();
} else {
return tryToUseAsArrayIndexSlowCase(ec);
}
}
inline uint64_t Value::toArrayIndex(ExecutionState& state) const
{
int32_t i;

View file

@ -541,6 +541,7 @@
});
return sym;
};
/*
if (!Type.symbol(Symbol.search)) {
var symbolSearch = defineWellKnownSymbol('search');
var originalSearch = String.prototype.search;
@ -559,6 +560,7 @@
};
overrideNative(String.prototype, 'search', searchShim);
}
if (!Type.symbol(Symbol.replace)) {
var symbolReplace = defineWellKnownSymbol('replace');
var originalReplace = String.prototype.replace;
@ -577,6 +579,7 @@
};
overrideNative(String.prototype, 'replace', replaceShim);
}
if (!Type.symbol(Symbol.split)) {
var symbolSplit = defineWellKnownSymbol('split');
var originalSplit = String.prototype.split;
@ -595,6 +598,7 @@
};
overrideNative(String.prototype, 'split', splitShim);
}
var symbolMatchExists = Type.symbol(Symbol.match);
var stringMatchIgnoresSymbolMatch = symbolMatchExists && (function () {
// Firefox 41, through Nightly 45 has Symbol.match, but String#match ignores it.
@ -622,7 +626,7 @@
return ES.Call(originalMatch, O, [ES.ToString(regexp)]);
};
overrideNative(String.prototype, 'match', matchShim);
}
}*/
}
var wrapConstructor = function wrapConstructor(original, replacement, keysToSkip) {