mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
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:
parent
a363289951
commit
e66f512b32
61 changed files with 1407 additions and 419 deletions
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ public:
|
|||
return "Function";
|
||||
}
|
||||
|
||||
bool hasInstance(ExecutionState& state, const Value& O);
|
||||
|
||||
protected:
|
||||
LexicalEnvironment* outerEnvironment()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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)), \
|
||||
|
|
|
|||
|
|
@ -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)), \
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
|||
163
src/runtime/GlobalObjectBuiltinSymbol.cpp
Normal file
163
src/runtime/GlobalObjectBuiltinSymbol.cpp
Normal 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)));
|
||||
}
|
||||
}
|
||||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,11 +35,6 @@ class DoubleInSmallValue : public PointerValue {
|
|||
friend class SmallValue;
|
||||
|
||||
public:
|
||||
virtual Type type()
|
||||
{
|
||||
return DoubleInSmallValueType;
|
||||
}
|
||||
|
||||
virtual bool isDoubleInSmallValue() const
|
||||
{
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -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__"));
|
||||
|
|
|
|||
|
|
@ -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__;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -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
33
src/runtime/Symbol.cpp
Normal 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
52
src/runtime/Symbol.h
Normal 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
|
||||
46
src/runtime/SymbolObject.cpp
Normal file
46
src/runtime/SymbolObject.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
52
src/runtime/SymbolObject.h
Normal file
52
src/runtime/SymbolObject.h
Normal 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
|
||||
|
|
@ -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:
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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(®expLastIndexGetterSetterData));
|
||||
// TODO(ES6): Below RegExp data properties is changed to accessor properties of RegExp.prototype in ES6.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue