mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
1222 lines
40 KiB
C
1222 lines
40 KiB
C
/*
|
|
* QuickJS Javascript Engine
|
|
*
|
|
* Copyright (c) 2017-2021 Fabrice Bellard
|
|
* Copyright (c) 2017-2021 Charlie Gordon
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
#include "third_party/quickjs/internal.h"
|
|
|
|
asm(".ident\t\"\\n\\n\
|
|
QuickJS (MIT License)\\n\
|
|
Copyright (c) 2017-2021 Fabrice Bellard\\n\
|
|
Copyright (c) 2017-2021 Charlie Gordon\"");
|
|
asm(".include \"libc/disclaimer.inc\"");
|
|
/* clang-format off */
|
|
|
|
void js_object_data_finalizer(JSRuntime *rt, JSValue val)
|
|
{
|
|
JSObject *p = JS_VALUE_GET_OBJ(val);
|
|
JS_FreeValueRT(rt, p->u.object_data);
|
|
p->u.object_data = JS_UNDEFINED;
|
|
}
|
|
|
|
void js_object_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
|
|
{
|
|
JSObject *p = JS_VALUE_GET_OBJ(val);
|
|
JS_MarkValue(rt, p->u.object_data, mark_func);
|
|
}
|
|
|
|
static JSValue js_object_constructor(JSContext *ctx, JSValueConst new_target,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
JSValue ret;
|
|
if (!JS_IsUndefined(new_target) &&
|
|
JS_VALUE_GET_OBJ(new_target) !=
|
|
JS_VALUE_GET_OBJ(JS_GetActiveFunction(ctx))) {
|
|
ret = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
|
|
} else {
|
|
int tag = JS_VALUE_GET_NORM_TAG(argv[0]);
|
|
switch(tag) {
|
|
case JS_TAG_NULL:
|
|
case JS_TAG_UNDEFINED:
|
|
ret = JS_NewObject(ctx);
|
|
break;
|
|
default:
|
|
ret = JS_ToObject(ctx, argv[0]);
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
|
|
JSAtom prop, JSValueConst desc,
|
|
int flags)
|
|
{
|
|
JSPropertyDescriptor d;
|
|
int ret;
|
|
if (js_obj_to_desc(ctx, &d, desc) < 0)
|
|
return -1;
|
|
ret = JS_DefineProperty(ctx, obj, prop,
|
|
d.value, d.getter, d.setter, d.flags | flags);
|
|
js_free_desc(ctx, &d);
|
|
return ret;
|
|
}
|
|
|
|
static __exception int JS_ObjectDefineProperties(JSContext *ctx,
|
|
JSValueConst obj,
|
|
JSValueConst properties)
|
|
{
|
|
JSValue props, desc;
|
|
JSObject *p;
|
|
JSPropertyEnum *atoms;
|
|
uint32_t len, i;
|
|
int ret = -1;
|
|
if (!JS_IsObject(obj)) {
|
|
JS_ThrowTypeErrorNotAnObject(ctx);
|
|
return -1;
|
|
}
|
|
desc = JS_UNDEFINED;
|
|
props = JS_ToObject(ctx, properties);
|
|
if (JS_IsException(props))
|
|
return -1;
|
|
p = JS_VALUE_GET_OBJ(props);
|
|
if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0)
|
|
goto exception;
|
|
for(i = 0; i < len; i++) {
|
|
JS_FreeValue(ctx, desc);
|
|
desc = JS_GetProperty(ctx, props, atoms[i].atom);
|
|
if (JS_IsException(desc))
|
|
goto exception;
|
|
if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc, JS_PROP_THROW) < 0)
|
|
goto exception;
|
|
}
|
|
ret = 0;
|
|
exception:
|
|
js_free_prop_enum(ctx, atoms, len);
|
|
JS_FreeValue(ctx, props);
|
|
JS_FreeValue(ctx, desc);
|
|
return ret;
|
|
}
|
|
|
|
static JSValue js_object_create(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
JSValueConst proto, props;
|
|
JSValue obj;
|
|
proto = argv[0];
|
|
if (!JS_IsObject(proto) && !JS_IsNull(proto))
|
|
return JS_ThrowTypeError(ctx, "not a prototype");
|
|
obj = JS_NewObjectProto(ctx, proto);
|
|
if (JS_IsException(obj))
|
|
return JS_EXCEPTION;
|
|
props = argv[1];
|
|
if (!JS_IsUndefined(props)) {
|
|
if (JS_ObjectDefineProperties(ctx, obj, props)) {
|
|
JS_FreeValue(ctx, obj);
|
|
return JS_EXCEPTION;
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv, int magic)
|
|
{
|
|
JSValueConst val;
|
|
val = argv[0];
|
|
if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) {
|
|
/* ES6 feature non compatible with ES5.1: primitive types are
|
|
accepted */
|
|
if (magic || JS_VALUE_GET_TAG(val) == JS_TAG_NULL ||
|
|
JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED)
|
|
return JS_ThrowTypeErrorNotAnObject(ctx);
|
|
}
|
|
return JS_GetPrototype(ctx, val);
|
|
}
|
|
|
|
static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
JSValueConst obj;
|
|
obj = argv[0];
|
|
if (JS_SetPrototypeInternal(ctx, obj, argv[1], TRUE) < 0)
|
|
return JS_EXCEPTION;
|
|
return JS_DupValue(ctx, obj);
|
|
}
|
|
|
|
/* magic = 1 if called as Reflect.defineProperty */
|
|
JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv, int magic)
|
|
{
|
|
JSValueConst obj, prop, desc;
|
|
int ret, flags;
|
|
JSAtom atom;
|
|
obj = argv[0];
|
|
prop = argv[1];
|
|
desc = argv[2];
|
|
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
|
|
return JS_ThrowTypeErrorNotAnObject(ctx);
|
|
atom = JS_ValueToAtom(ctx, prop);
|
|
if (UNLIKELY(atom == JS_ATOM_NULL))
|
|
return JS_EXCEPTION;
|
|
flags = 0;
|
|
if (!magic)
|
|
flags |= JS_PROP_THROW;
|
|
ret = JS_DefinePropertyDesc(ctx, obj, atom, desc, flags);
|
|
JS_FreeAtom(ctx, atom);
|
|
if (ret < 0) {
|
|
return JS_EXCEPTION;
|
|
} else if (magic) {
|
|
return JS_NewBool(ctx, ret);
|
|
} else {
|
|
return JS_DupValue(ctx, obj);
|
|
}
|
|
}
|
|
|
|
static JSValue js_object_defineProperties(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
// defineProperties(obj, properties)
|
|
JSValueConst obj = argv[0];
|
|
if (JS_ObjectDefineProperties(ctx, obj, argv[1]))
|
|
return JS_EXCEPTION;
|
|
else
|
|
return JS_DupValue(ctx, obj);
|
|
}
|
|
|
|
/* magic = 1 if called as __defineSetter__ */
|
|
static JSValue js_object___defineGetter__(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv, int magic)
|
|
{
|
|
JSValue obj;
|
|
JSValueConst prop, value, get, set;
|
|
int ret, flags;
|
|
JSAtom atom;
|
|
prop = argv[0];
|
|
value = argv[1];
|
|
obj = JS_ToObject(ctx, this_val);
|
|
if (JS_IsException(obj))
|
|
return JS_EXCEPTION;
|
|
if (check_function(ctx, value)) {
|
|
JS_FreeValue(ctx, obj);
|
|
return JS_EXCEPTION;
|
|
}
|
|
atom = JS_ValueToAtom(ctx, prop);
|
|
if (UNLIKELY(atom == JS_ATOM_NULL)) {
|
|
JS_FreeValue(ctx, obj);
|
|
return JS_EXCEPTION;
|
|
}
|
|
flags = JS_PROP_THROW |
|
|
JS_PROP_HAS_ENUMERABLE | JS_PROP_ENUMERABLE |
|
|
JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE;
|
|
if (magic) {
|
|
get = JS_UNDEFINED;
|
|
set = value;
|
|
flags |= JS_PROP_HAS_SET;
|
|
} else {
|
|
get = value;
|
|
set = JS_UNDEFINED;
|
|
flags |= JS_PROP_HAS_GET;
|
|
}
|
|
ret = JS_DefineProperty(ctx, obj, atom, JS_UNDEFINED, get, set, flags);
|
|
JS_FreeValue(ctx, obj);
|
|
JS_FreeAtom(ctx, atom);
|
|
if (ret < 0) {
|
|
return JS_EXCEPTION;
|
|
} else {
|
|
return JS_UNDEFINED;
|
|
}
|
|
}
|
|
|
|
JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv, int magic)
|
|
{
|
|
JSValueConst prop;
|
|
JSAtom atom;
|
|
JSValue ret, obj;
|
|
JSPropertyDescriptor desc;
|
|
int res, flags;
|
|
if (magic) {
|
|
/* Reflect.getOwnPropertyDescriptor case */
|
|
if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
|
|
return JS_ThrowTypeErrorNotAnObject(ctx);
|
|
obj = JS_DupValue(ctx, argv[0]);
|
|
} else {
|
|
obj = JS_ToObject(ctx, argv[0]);
|
|
if (JS_IsException(obj))
|
|
return obj;
|
|
}
|
|
prop = argv[1];
|
|
atom = JS_ValueToAtom(ctx, prop);
|
|
if (UNLIKELY(atom == JS_ATOM_NULL))
|
|
goto exception;
|
|
ret = JS_UNDEFINED;
|
|
if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
|
|
res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), atom);
|
|
if (res < 0)
|
|
goto exception;
|
|
if (res) {
|
|
ret = JS_NewObject(ctx);
|
|
if (JS_IsException(ret))
|
|
goto exception1;
|
|
flags = JS_PROP_C_W_E | JS_PROP_THROW;
|
|
if (desc.flags & JS_PROP_GETSET) {
|
|
if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, desc.getter), flags) < 0
|
|
|| JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, desc.setter), flags) < 0)
|
|
goto exception1;
|
|
} else {
|
|
if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0
|
|
|| JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
|
|
JS_NewBool(ctx, (desc.flags & JS_PROP_WRITABLE) != 0), flags) < 0)
|
|
goto exception1;
|
|
}
|
|
if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
|
|
JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0), flags) < 0
|
|
|| JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
|
|
JS_NewBool(ctx, (desc.flags & JS_PROP_CONFIGURABLE) != 0), flags) < 0)
|
|
goto exception1;
|
|
js_free_desc(ctx, &desc);
|
|
}
|
|
}
|
|
JS_FreeAtom(ctx, atom);
|
|
JS_FreeValue(ctx, obj);
|
|
return ret;
|
|
exception1:
|
|
js_free_desc(ctx, &desc);
|
|
JS_FreeValue(ctx, ret);
|
|
exception:
|
|
JS_FreeAtom(ctx, atom);
|
|
JS_FreeValue(ctx, obj);
|
|
return JS_EXCEPTION;
|
|
}
|
|
|
|
static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
//getOwnPropertyDescriptors(obj)
|
|
JSValue obj, r;
|
|
JSObject *p;
|
|
JSPropertyEnum *props;
|
|
uint32_t len, i;
|
|
r = JS_UNDEFINED;
|
|
obj = JS_ToObject(ctx, argv[0]);
|
|
if (JS_IsException(obj))
|
|
return JS_EXCEPTION;
|
|
p = JS_VALUE_GET_OBJ(obj);
|
|
if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p,
|
|
JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
|
|
goto exception;
|
|
r = JS_NewObject(ctx);
|
|
if (JS_IsException(r))
|
|
goto exception;
|
|
for(i = 0; i < len; i++) {
|
|
JSValue atomValue, desc;
|
|
JSValueConst args[2];
|
|
atomValue = JS_AtomToValue(ctx, props[i].atom);
|
|
if (JS_IsException(atomValue))
|
|
goto exception;
|
|
args[0] = obj;
|
|
args[1] = atomValue;
|
|
desc = js_object_getOwnPropertyDescriptor(ctx, JS_UNDEFINED, 2, args, 0);
|
|
JS_FreeValue(ctx, atomValue);
|
|
if (JS_IsException(desc))
|
|
goto exception;
|
|
if (!JS_IsUndefined(desc)) {
|
|
if (JS_DefinePropertyValue(ctx, r, props[i].atom, desc,
|
|
JS_PROP_C_W_E | JS_PROP_THROW) < 0)
|
|
goto exception;
|
|
}
|
|
}
|
|
js_free_prop_enum(ctx, props, len);
|
|
JS_FreeValue(ctx, obj);
|
|
return r;
|
|
exception:
|
|
js_free_prop_enum(ctx, props, len);
|
|
JS_FreeValue(ctx, obj);
|
|
JS_FreeValue(ctx, r);
|
|
return JS_EXCEPTION;
|
|
}
|
|
|
|
JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
|
|
{
|
|
int tag = JS_VALUE_GET_NORM_TAG(val);
|
|
JSValue obj;
|
|
switch(tag) {
|
|
default:
|
|
case JS_TAG_NULL:
|
|
case JS_TAG_UNDEFINED:
|
|
return JS_ThrowTypeError(ctx, "cannot convert to object");
|
|
case JS_TAG_OBJECT:
|
|
case JS_TAG_EXCEPTION:
|
|
return JS_DupValue(ctx, val);
|
|
#ifdef CONFIG_BIGNUM
|
|
case JS_TAG_BIG_INT:
|
|
obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
|
|
goto set_value;
|
|
case JS_TAG_BIG_FLOAT:
|
|
obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT);
|
|
goto set_value;
|
|
case JS_TAG_BIG_DECIMAL:
|
|
obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_DECIMAL);
|
|
goto set_value;
|
|
#endif
|
|
case JS_TAG_INT:
|
|
case JS_TAG_FLOAT64:
|
|
obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
|
|
goto set_value;
|
|
case JS_TAG_STRING:
|
|
/* XXX: should call the string constructor */
|
|
{
|
|
JSString *p1 = JS_VALUE_GET_STRING(val);
|
|
obj = JS_NewObjectClass(ctx, JS_CLASS_STRING);
|
|
JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
|
|
}
|
|
goto set_value;
|
|
case JS_TAG_BOOL:
|
|
obj = JS_NewObjectClass(ctx, JS_CLASS_BOOLEAN);
|
|
goto set_value;
|
|
case JS_TAG_SYMBOL:
|
|
obj = JS_NewObjectClass(ctx, JS_CLASS_SYMBOL);
|
|
set_value:
|
|
if (!JS_IsException(obj))
|
|
JS_SetObjectData(ctx, obj, JS_DupValue(ctx, val));
|
|
return obj;
|
|
}
|
|
}
|
|
|
|
JSValue JS_ToObjectFree(JSContext *ctx, JSValue val)
|
|
{
|
|
JSValue obj = JS_ToObject(ctx, val);
|
|
JS_FreeValue(ctx, val);
|
|
return obj;
|
|
}
|
|
|
|
int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d, JSValueConst desc)
|
|
{
|
|
JSValue val, getter, setter;
|
|
int flags;
|
|
if (!JS_IsObject(desc)) {
|
|
JS_ThrowTypeErrorNotAnObject(ctx);
|
|
return -1;
|
|
}
|
|
flags = 0;
|
|
val = JS_UNDEFINED;
|
|
getter = JS_UNDEFINED;
|
|
setter = JS_UNDEFINED;
|
|
if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) {
|
|
JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);
|
|
if (JS_IsException(prop))
|
|
goto fail;
|
|
flags |= JS_PROP_HAS_CONFIGURABLE;
|
|
if (JS_ToBoolFree(ctx, prop))
|
|
flags |= JS_PROP_CONFIGURABLE;
|
|
}
|
|
if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) {
|
|
JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);
|
|
if (JS_IsException(prop))
|
|
goto fail;
|
|
flags |= JS_PROP_HAS_WRITABLE;
|
|
if (JS_ToBoolFree(ctx, prop))
|
|
flags |= JS_PROP_WRITABLE;
|
|
}
|
|
if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) {
|
|
JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable);
|
|
if (JS_IsException(prop))
|
|
goto fail;
|
|
flags |= JS_PROP_HAS_ENUMERABLE;
|
|
if (JS_ToBoolFree(ctx, prop))
|
|
flags |= JS_PROP_ENUMERABLE;
|
|
}
|
|
if (JS_HasProperty(ctx, desc, JS_ATOM_value)) {
|
|
flags |= JS_PROP_HAS_VALUE;
|
|
val = JS_GetProperty(ctx, desc, JS_ATOM_value);
|
|
if (JS_IsException(val))
|
|
goto fail;
|
|
}
|
|
if (JS_HasProperty(ctx, desc, JS_ATOM_get)) {
|
|
flags |= JS_PROP_HAS_GET;
|
|
getter = JS_GetProperty(ctx, desc, JS_ATOM_get);
|
|
if (JS_IsException(getter) ||
|
|
!(JS_IsUndefined(getter) || JS_IsFunction(ctx, getter))) {
|
|
JS_ThrowTypeError(ctx, "invalid getter");
|
|
goto fail;
|
|
}
|
|
}
|
|
if (JS_HasProperty(ctx, desc, JS_ATOM_set)) {
|
|
flags |= JS_PROP_HAS_SET;
|
|
setter = JS_GetProperty(ctx, desc, JS_ATOM_set);
|
|
if (JS_IsException(setter) ||
|
|
!(JS_IsUndefined(setter) || JS_IsFunction(ctx, setter))) {
|
|
JS_ThrowTypeError(ctx, "invalid setter");
|
|
goto fail;
|
|
}
|
|
}
|
|
if ((flags & (JS_PROP_HAS_SET | JS_PROP_HAS_GET)) &&
|
|
(flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) {
|
|
JS_ThrowTypeError(ctx, "cannot have setter/getter and value or writable");
|
|
goto fail;
|
|
}
|
|
d->flags = flags;
|
|
d->value = val;
|
|
d->getter = getter;
|
|
d->setter = setter;
|
|
return 0;
|
|
fail:
|
|
JS_FreeValue(ctx, val);
|
|
JS_FreeValue(ctx, getter);
|
|
JS_FreeValue(ctx, setter);
|
|
return -1;
|
|
}
|
|
|
|
JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1, int flags, int kind)
|
|
{
|
|
JSValue obj, r, val, key, value;
|
|
JSObject *p;
|
|
JSPropertyEnum *atoms;
|
|
uint32_t len, i, j;
|
|
r = JS_UNDEFINED;
|
|
val = JS_UNDEFINED;
|
|
obj = JS_ToObject(ctx, obj1);
|
|
if (JS_IsException(obj))
|
|
return JS_EXCEPTION;
|
|
p = JS_VALUE_GET_OBJ(obj);
|
|
if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, flags & ~JS_GPN_ENUM_ONLY))
|
|
goto exception;
|
|
r = JS_NewArray(ctx);
|
|
if (JS_IsException(r))
|
|
goto exception;
|
|
for(j = i = 0; i < len; i++) {
|
|
JSAtom atom = atoms[i].atom;
|
|
if (flags & JS_GPN_ENUM_ONLY) {
|
|
JSPropertyDescriptor desc;
|
|
int res;
|
|
|
|
/* Check if property is still enumerable */
|
|
res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
|
|
if (res < 0)
|
|
goto exception;
|
|
if (!res)
|
|
continue;
|
|
js_free_desc(ctx, &desc);
|
|
if (!(desc.flags & JS_PROP_ENUMERABLE))
|
|
continue;
|
|
}
|
|
switch(kind) {
|
|
default:
|
|
case JS_ITERATOR_KIND_KEY:
|
|
val = JS_AtomToValue(ctx, atom);
|
|
if (JS_IsException(val))
|
|
goto exception;
|
|
break;
|
|
case JS_ITERATOR_KIND_VALUE:
|
|
val = JS_GetProperty(ctx, obj, atom);
|
|
if (JS_IsException(val))
|
|
goto exception;
|
|
break;
|
|
case JS_ITERATOR_KIND_KEY_AND_VALUE:
|
|
val = JS_NewArray(ctx);
|
|
if (JS_IsException(val))
|
|
goto exception;
|
|
key = JS_AtomToValue(ctx, atom);
|
|
if (JS_IsException(key))
|
|
goto exception1;
|
|
if (JS_CreateDataPropertyUint32(ctx, val, 0, key, JS_PROP_THROW) < 0)
|
|
goto exception1;
|
|
value = JS_GetProperty(ctx, obj, atom);
|
|
if (JS_IsException(value))
|
|
goto exception1;
|
|
if (JS_CreateDataPropertyUint32(ctx, val, 1, value, JS_PROP_THROW) < 0)
|
|
goto exception1;
|
|
break;
|
|
}
|
|
if (JS_CreateDataPropertyUint32(ctx, r, j++, val, 0) < 0)
|
|
goto exception;
|
|
}
|
|
goto done;
|
|
|
|
exception1:
|
|
JS_FreeValue(ctx, val);
|
|
exception:
|
|
JS_FreeValue(ctx, r);
|
|
r = JS_EXCEPTION;
|
|
done:
|
|
js_free_prop_enum(ctx, atoms, len);
|
|
JS_FreeValue(ctx, obj);
|
|
return r;
|
|
}
|
|
|
|
static JSValue js_object_getOwnPropertyNames(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
return JS_GetOwnPropertyNames2(ctx, argv[0],
|
|
JS_GPN_STRING_MASK, JS_ITERATOR_KIND_KEY);
|
|
}
|
|
|
|
static JSValue js_object_getOwnPropertySymbols(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
return JS_GetOwnPropertyNames2(ctx, argv[0],
|
|
JS_GPN_SYMBOL_MASK, JS_ITERATOR_KIND_KEY);
|
|
}
|
|
|
|
JSValue js_object_keys(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv, int kind)
|
|
{
|
|
return JS_GetOwnPropertyNames2(ctx, argv[0],
|
|
JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK, kind);
|
|
}
|
|
|
|
JSValue js_object_isExtensible(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv, int reflect)
|
|
{
|
|
JSValueConst obj;
|
|
int ret;
|
|
obj = argv[0];
|
|
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
|
|
if (reflect)
|
|
return JS_ThrowTypeErrorNotAnObject(ctx);
|
|
else
|
|
return JS_FALSE;
|
|
}
|
|
ret = JS_IsExtensible(ctx, obj);
|
|
if (ret < 0)
|
|
return JS_EXCEPTION;
|
|
else
|
|
return JS_NewBool(ctx, ret);
|
|
}
|
|
|
|
JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv, int reflect)
|
|
{
|
|
JSValueConst obj;
|
|
int ret;
|
|
obj = argv[0];
|
|
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
|
|
if (reflect)
|
|
return JS_ThrowTypeErrorNotAnObject(ctx);
|
|
else
|
|
return JS_DupValue(ctx, obj);
|
|
}
|
|
ret = JS_PreventExtensions(ctx, obj);
|
|
if (ret < 0)
|
|
return JS_EXCEPTION;
|
|
if (reflect) {
|
|
return JS_NewBool(ctx, ret);
|
|
} else {
|
|
if (!ret)
|
|
return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
|
|
return JS_DupValue(ctx, obj);
|
|
}
|
|
}
|
|
|
|
static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
JSValue obj;
|
|
JSAtom atom;
|
|
JSObject *p;
|
|
BOOL ret;
|
|
atom = JS_ValueToAtom(ctx, argv[0]); /* must be done first */
|
|
if (UNLIKELY(atom == JS_ATOM_NULL))
|
|
return JS_EXCEPTION;
|
|
obj = JS_ToObject(ctx, this_val);
|
|
if (JS_IsException(obj)) {
|
|
JS_FreeAtom(ctx, atom);
|
|
return obj;
|
|
}
|
|
p = JS_VALUE_GET_OBJ(obj);
|
|
ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
|
|
JS_FreeAtom(ctx, atom);
|
|
JS_FreeValue(ctx, obj);
|
|
if (ret < 0)
|
|
return JS_EXCEPTION;
|
|
else
|
|
return JS_NewBool(ctx, ret);
|
|
}
|
|
|
|
static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
return JS_ToObject(ctx, this_val);
|
|
}
|
|
|
|
JSValue js_object_toString(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
JSValue obj, tag;
|
|
int is_array;
|
|
JSAtom atom;
|
|
JSObject *p;
|
|
if (JS_IsNull(this_val)) {
|
|
tag = JS_NewString(ctx, "Null");
|
|
} else if (JS_IsUndefined(this_val)) {
|
|
tag = JS_NewString(ctx, "Undefined");
|
|
} else {
|
|
obj = JS_ToObject(ctx, this_val);
|
|
if (JS_IsException(obj))
|
|
return obj;
|
|
is_array = JS_IsArray(ctx, obj);
|
|
if (is_array < 0) {
|
|
JS_FreeValue(ctx, obj);
|
|
return JS_EXCEPTION;
|
|
}
|
|
if (is_array) {
|
|
atom = JS_ATOM_Array;
|
|
} else if (JS_IsFunction(ctx, obj)) {
|
|
atom = JS_ATOM_Function;
|
|
} else {
|
|
p = JS_VALUE_GET_OBJ(obj);
|
|
switch(p->class_id) {
|
|
case JS_CLASS_STRING:
|
|
case JS_CLASS_ARGUMENTS:
|
|
case JS_CLASS_MAPPED_ARGUMENTS:
|
|
case JS_CLASS_ERROR:
|
|
case JS_CLASS_BOOLEAN:
|
|
case JS_CLASS_NUMBER:
|
|
case JS_CLASS_DATE:
|
|
case JS_CLASS_REGEXP:
|
|
atom = ctx->rt->class_array[p->class_id].class_name;
|
|
break;
|
|
default:
|
|
atom = JS_ATOM_Object;
|
|
break;
|
|
}
|
|
}
|
|
tag = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_toStringTag);
|
|
JS_FreeValue(ctx, obj);
|
|
if (JS_IsException(tag))
|
|
return JS_EXCEPTION;
|
|
if (!JS_IsString(tag)) {
|
|
JS_FreeValue(ctx, tag);
|
|
tag = JS_AtomToString(ctx, atom);
|
|
}
|
|
}
|
|
return JS_ConcatString3(ctx, "[object ", tag, "]");
|
|
}
|
|
|
|
static JSValue js_object_toLocaleString(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
return JS_Invoke(ctx, this_val, JS_ATOM_toString, 0, NULL);
|
|
}
|
|
|
|
static JSValue js_object_assign(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
// Object.assign(obj, source1)
|
|
JSValue obj, s;
|
|
int i;
|
|
s = JS_UNDEFINED;
|
|
obj = JS_ToObject(ctx, argv[0]);
|
|
if (JS_IsException(obj))
|
|
goto exception;
|
|
for (i = 1; i < argc; i++) {
|
|
if (!JS_IsNull(argv[i]) && !JS_IsUndefined(argv[i])) {
|
|
s = JS_ToObject(ctx, argv[i]);
|
|
if (JS_IsException(s))
|
|
goto exception;
|
|
if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, TRUE))
|
|
goto exception;
|
|
JS_FreeValue(ctx, s);
|
|
}
|
|
}
|
|
return obj;
|
|
exception:
|
|
JS_FreeValue(ctx, obj);
|
|
JS_FreeValue(ctx, s);
|
|
return JS_EXCEPTION;
|
|
}
|
|
|
|
JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv, int freeze_flag)
|
|
{
|
|
JSValueConst obj = argv[0];
|
|
JSObject *p;
|
|
JSPropertyEnum *props;
|
|
uint32_t len, i;
|
|
int flags, desc_flags, res;
|
|
if (!JS_IsObject(obj))
|
|
return JS_DupValue(ctx, obj);
|
|
res = JS_PreventExtensions(ctx, obj);
|
|
if (res < 0)
|
|
return JS_EXCEPTION;
|
|
if (!res) {
|
|
return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
|
|
}
|
|
p = JS_VALUE_GET_OBJ(obj);
|
|
flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
|
|
if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
|
|
return JS_EXCEPTION;
|
|
for(i = 0; i < len; i++) {
|
|
JSPropertyDescriptor desc;
|
|
JSAtom prop = props[i].atom;
|
|
desc_flags = JS_PROP_THROW | JS_PROP_HAS_CONFIGURABLE;
|
|
if (freeze_flag) {
|
|
res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
|
|
if (res < 0)
|
|
goto exception;
|
|
if (res) {
|
|
if (desc.flags & JS_PROP_WRITABLE)
|
|
desc_flags |= JS_PROP_HAS_WRITABLE;
|
|
js_free_desc(ctx, &desc);
|
|
}
|
|
}
|
|
if (JS_DefineProperty(ctx, obj, prop, JS_UNDEFINED,
|
|
JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0)
|
|
goto exception;
|
|
}
|
|
js_free_prop_enum(ctx, props, len);
|
|
return JS_DupValue(ctx, obj);
|
|
exception:
|
|
js_free_prop_enum(ctx, props, len);
|
|
return JS_EXCEPTION;
|
|
}
|
|
|
|
static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv, int is_frozen)
|
|
{
|
|
JSValueConst obj = argv[0];
|
|
JSObject *p;
|
|
JSPropertyEnum *props;
|
|
uint32_t len, i;
|
|
int flags, res;
|
|
if (!JS_IsObject(obj))
|
|
return JS_TRUE;
|
|
p = JS_VALUE_GET_OBJ(obj);
|
|
flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
|
|
if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
|
|
return JS_EXCEPTION;
|
|
for(i = 0; i < len; i++) {
|
|
JSPropertyDescriptor desc;
|
|
JSAtom prop = props[i].atom;
|
|
res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
|
|
if (res < 0)
|
|
goto exception;
|
|
if (res) {
|
|
js_free_desc(ctx, &desc);
|
|
if ((desc.flags & JS_PROP_CONFIGURABLE)
|
|
|| (is_frozen && (desc.flags & JS_PROP_WRITABLE))) {
|
|
res = FALSE;
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
res = JS_IsExtensible(ctx, obj);
|
|
if (res < 0)
|
|
return JS_EXCEPTION;
|
|
res ^= 1;
|
|
done:
|
|
js_free_prop_enum(ctx, props, len);
|
|
return JS_NewBool(ctx, res);
|
|
exception:
|
|
js_free_prop_enum(ctx, props, len);
|
|
return JS_EXCEPTION;
|
|
}
|
|
|
|
static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
JSValue obj, iter, next_method = JS_UNDEFINED;
|
|
JSValueConst iterable;
|
|
BOOL done;
|
|
/* RequireObjectCoercible() not necessary because it is tested in
|
|
JS_GetIterator() by JS_GetProperty() */
|
|
iterable = argv[0];
|
|
obj = JS_NewObject(ctx);
|
|
if (JS_IsException(obj))
|
|
return obj;
|
|
iter = JS_GetIterator(ctx, iterable, FALSE);
|
|
if (JS_IsException(iter))
|
|
goto fail;
|
|
next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
|
|
if (JS_IsException(next_method))
|
|
goto fail;
|
|
for(;;) {
|
|
JSValue key, value, item;
|
|
item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
|
|
if (JS_IsException(item))
|
|
goto fail;
|
|
if (done) {
|
|
JS_FreeValue(ctx, item);
|
|
break;
|
|
}
|
|
key = JS_UNDEFINED;
|
|
value = JS_UNDEFINED;
|
|
if (!JS_IsObject(item)) {
|
|
JS_ThrowTypeErrorNotAnObject(ctx);
|
|
goto fail1;
|
|
}
|
|
key = JS_GetPropertyUint32(ctx, item, 0);
|
|
if (JS_IsException(key))
|
|
goto fail1;
|
|
value = JS_GetPropertyUint32(ctx, item, 1);
|
|
if (JS_IsException(value)) {
|
|
JS_FreeValue(ctx, key);
|
|
goto fail1;
|
|
}
|
|
if (JS_DefinePropertyValueValue(ctx, obj, key, value,
|
|
JS_PROP_C_W_E | JS_PROP_THROW) < 0) {
|
|
fail1:
|
|
JS_FreeValue(ctx, item);
|
|
goto fail;
|
|
}
|
|
JS_FreeValue(ctx, item);
|
|
}
|
|
JS_FreeValue(ctx, next_method);
|
|
JS_FreeValue(ctx, iter);
|
|
return obj;
|
|
fail:
|
|
if (JS_IsObject(iter)) {
|
|
/* close the iterator object, preserving pending exception */
|
|
JS_IteratorClose(ctx, iter, TRUE);
|
|
}
|
|
JS_FreeValue(ctx, next_method);
|
|
JS_FreeValue(ctx, iter);
|
|
JS_FreeValue(ctx, obj);
|
|
return JS_EXCEPTION;
|
|
}
|
|
|
|
#if 0
|
|
/* Note: corresponds to ECMA spec: CreateDataPropertyOrThrow() */
|
|
static JSValue js_object___setOwnProperty(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
int ret;
|
|
ret = JS_DefinePropertyValueValue(ctx, argv[0], JS_DupValue(ctx, argv[1]),
|
|
JS_DupValue(ctx, argv[2]),
|
|
JS_PROP_C_W_E | JS_PROP_THROW);
|
|
if (ret < 0)
|
|
return JS_EXCEPTION;
|
|
else
|
|
return JS_NewBool(ctx, ret);
|
|
}
|
|
|
|
static JSValue js_object___toObject(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
return JS_ToObject(ctx, argv[0]);
|
|
}
|
|
|
|
static JSValue js_object___toPrimitive(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
int hint = HINT_NONE;
|
|
|
|
if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT)
|
|
hint = JS_VALUE_GET_INT(argv[1]);
|
|
|
|
return JS_ToPrimitive(ctx, argv[0], hint);
|
|
}
|
|
#endif
|
|
|
|
/* return an empty string if not an object */
|
|
static JSValue js_object___getClass(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
JSAtom atom;
|
|
JSObject *p;
|
|
uint32_t tag;
|
|
int class_id;
|
|
|
|
tag = JS_VALUE_GET_NORM_TAG(argv[0]);
|
|
if (tag == JS_TAG_OBJECT) {
|
|
p = JS_VALUE_GET_OBJ(argv[0]);
|
|
class_id = p->class_id;
|
|
if (class_id == JS_CLASS_PROXY && JS_IsFunction(ctx, argv[0]))
|
|
class_id = JS_CLASS_BYTECODE_FUNCTION;
|
|
atom = ctx->rt->class_array[class_id].class_name;
|
|
} else {
|
|
atom = JS_ATOM_empty_string;
|
|
}
|
|
return JS_AtomToString(ctx, atom);
|
|
}
|
|
|
|
static JSValue js_object_is(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
return JS_NewBool(ctx, js_same_value(ctx, argv[0], argv[1]));
|
|
}
|
|
|
|
#if 0
|
|
static JSValue js_object___getObjectData(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
return JS_GetObjectData(ctx, argv[0]);
|
|
}
|
|
|
|
static JSValue js_object___setObjectData(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
if (JS_SetObjectData(ctx, argv[0], JS_DupValue(ctx, argv[1])))
|
|
return JS_EXCEPTION;
|
|
return JS_DupValue(ctx, argv[1]);
|
|
}
|
|
|
|
static JSValue js_object___toPropertyKey(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
return JS_ToPropertyKey(ctx, argv[0]);
|
|
}
|
|
|
|
static JSValue js_object___isObject(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
return JS_NewBool(ctx, JS_IsObject(argv[0]));
|
|
}
|
|
|
|
static JSValue js_object___isSameValueZero(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
return JS_NewBool(ctx, js_same_value_zero(ctx, argv[0], argv[1]));
|
|
}
|
|
|
|
static JSValue js_object___isConstructor(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
return JS_NewBool(ctx, JS_IsConstructor(ctx, argv[0]));
|
|
}
|
|
#endif
|
|
|
|
JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj, JSValueConst defaultConstructor)
|
|
{
|
|
JSValue ctor, species;
|
|
if (!JS_IsObject(obj))
|
|
return JS_ThrowTypeErrorNotAnObject(ctx);
|
|
ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
|
|
if (JS_IsException(ctor))
|
|
return ctor;
|
|
if (JS_IsUndefined(ctor))
|
|
return JS_DupValue(ctx, defaultConstructor);
|
|
if (!JS_IsObject(ctor)) {
|
|
JS_FreeValue(ctx, ctor);
|
|
return JS_ThrowTypeErrorNotAnObject(ctx);
|
|
}
|
|
species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
|
|
JS_FreeValue(ctx, ctor);
|
|
if (JS_IsException(species))
|
|
return species;
|
|
if (JS_IsUndefined(species) || JS_IsNull(species))
|
|
return JS_DupValue(ctx, defaultConstructor);
|
|
if (!JS_IsConstructor(ctx, species)) {
|
|
JS_FreeValue(ctx, species);
|
|
return JS_ThrowTypeError(ctx, "not a constructor");
|
|
}
|
|
return species;
|
|
}
|
|
|
|
#if 0
|
|
static JSValue js_object___speciesConstructor(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
return JS_SpeciesConstructor(ctx, argv[0], argv[1]);
|
|
}
|
|
#endif
|
|
|
|
static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val)
|
|
{
|
|
JSValue val, ret;
|
|
val = JS_ToObject(ctx, this_val);
|
|
if (JS_IsException(val))
|
|
return val;
|
|
ret = JS_GetPrototype(ctx, val);
|
|
JS_FreeValue(ctx, val);
|
|
return ret;
|
|
}
|
|
|
|
static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val,
|
|
JSValueConst proto)
|
|
{
|
|
if (JS_IsUndefined(this_val) || JS_IsNull(this_val))
|
|
return JS_ThrowTypeErrorNotAnObject(ctx);
|
|
if (!JS_IsObject(proto) && !JS_IsNull(proto))
|
|
return JS_UNDEFINED;
|
|
if (JS_SetPrototypeInternal(ctx, this_val, proto, TRUE) < 0)
|
|
return JS_EXCEPTION;
|
|
else
|
|
return JS_UNDEFINED;
|
|
}
|
|
|
|
static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
JSValue obj, v1;
|
|
JSValueConst v;
|
|
int res;
|
|
v = argv[0];
|
|
if (!JS_IsObject(v))
|
|
return JS_FALSE;
|
|
obj = JS_ToObject(ctx, this_val);
|
|
if (JS_IsException(obj))
|
|
return JS_EXCEPTION;
|
|
v1 = JS_DupValue(ctx, v);
|
|
for(;;) {
|
|
v1 = JS_GetPrototypeFree(ctx, v1);
|
|
if (JS_IsException(v1))
|
|
goto exception;
|
|
if (JS_IsNull(v1)) {
|
|
res = FALSE;
|
|
break;
|
|
}
|
|
if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) {
|
|
res = TRUE;
|
|
break;
|
|
}
|
|
/* avoid infinite loop (possible with proxies) */
|
|
if (js_poll_interrupts(ctx))
|
|
goto exception;
|
|
}
|
|
JS_FreeValue(ctx, v1);
|
|
JS_FreeValue(ctx, obj);
|
|
return JS_NewBool(ctx, res);
|
|
exception:
|
|
JS_FreeValue(ctx, v1);
|
|
JS_FreeValue(ctx, obj);
|
|
return JS_EXCEPTION;
|
|
}
|
|
|
|
static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv)
|
|
{
|
|
JSValue obj, res = JS_EXCEPTION;
|
|
JSAtom prop = JS_ATOM_NULL;
|
|
JSPropertyDescriptor desc;
|
|
int has_prop;
|
|
obj = JS_ToObject(ctx, this_val);
|
|
if (JS_IsException(obj))
|
|
goto exception;
|
|
prop = JS_ValueToAtom(ctx, argv[0]);
|
|
if (UNLIKELY(prop == JS_ATOM_NULL))
|
|
goto exception;
|
|
has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
|
|
if (has_prop < 0)
|
|
goto exception;
|
|
if (has_prop) {
|
|
res = JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0);
|
|
js_free_desc(ctx, &desc);
|
|
} else {
|
|
res = JS_FALSE;
|
|
}
|
|
exception:
|
|
JS_FreeAtom(ctx, prop);
|
|
JS_FreeValue(ctx, obj);
|
|
return res;
|
|
}
|
|
|
|
static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val,
|
|
int argc, JSValueConst *argv, int setter)
|
|
{
|
|
JSValue obj, res = JS_EXCEPTION;
|
|
JSAtom prop = JS_ATOM_NULL;
|
|
JSPropertyDescriptor desc;
|
|
int has_prop;
|
|
obj = JS_ToObject(ctx, this_val);
|
|
if (JS_IsException(obj))
|
|
goto exception;
|
|
prop = JS_ValueToAtom(ctx, argv[0]);
|
|
if (UNLIKELY(prop == JS_ATOM_NULL))
|
|
goto exception;
|
|
for (;;) {
|
|
has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
|
|
if (has_prop < 0)
|
|
goto exception;
|
|
if (has_prop) {
|
|
if (desc.flags & JS_PROP_GETSET)
|
|
res = JS_DupValue(ctx, setter ? desc.setter : desc.getter);
|
|
else
|
|
res = JS_UNDEFINED;
|
|
js_free_desc(ctx, &desc);
|
|
break;
|
|
}
|
|
obj = JS_GetPrototypeFree(ctx, obj);
|
|
if (JS_IsException(obj))
|
|
goto exception;
|
|
if (JS_IsNull(obj)) {
|
|
res = JS_UNDEFINED;
|
|
break;
|
|
}
|
|
/* avoid infinite loop (possible with proxies) */
|
|
if (js_poll_interrupts(ctx))
|
|
goto exception;
|
|
}
|
|
exception:
|
|
JS_FreeAtom(ctx, prop);
|
|
JS_FreeValue(ctx, obj);
|
|
return res;
|
|
}
|
|
|
|
static const JSCFunctionListEntry js_object_funcs[] = {
|
|
JS_CFUNC_DEF("create", 2, js_object_create ),
|
|
JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 0 ),
|
|
JS_CFUNC_DEF("setPrototypeOf", 2, js_object_setPrototypeOf ),
|
|
JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 0 ),
|
|
JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ),
|
|
JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ),
|
|
JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ),
|
|
JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ),
|
|
JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ),
|
|
JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ),
|
|
JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 0 ),
|
|
JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 0 ),
|
|
JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 0 ),
|
|
JS_CFUNC_DEF("getOwnPropertyDescriptors", 1, js_object_getOwnPropertyDescriptors ),
|
|
JS_CFUNC_DEF("is", 2, js_object_is ),
|
|
JS_CFUNC_DEF("assign", 2, js_object_assign ),
|
|
JS_CFUNC_MAGIC_DEF("seal", 1, js_object_seal, 0 ),
|
|
JS_CFUNC_MAGIC_DEF("freeze", 1, js_object_seal, 1 ),
|
|
JS_CFUNC_MAGIC_DEF("isSealed", 1, js_object_isSealed, 0 ),
|
|
JS_CFUNC_MAGIC_DEF("isFrozen", 1, js_object_isSealed, 1 ),
|
|
JS_CFUNC_DEF("__getClass", 1, js_object___getClass ),
|
|
//JS_CFUNC_DEF("__isObject", 1, js_object___isObject ),
|
|
//JS_CFUNC_DEF("__isConstructor", 1, js_object___isConstructor ),
|
|
//JS_CFUNC_DEF("__toObject", 1, js_object___toObject ),
|
|
//JS_CFUNC_DEF("__setOwnProperty", 3, js_object___setOwnProperty ),
|
|
//JS_CFUNC_DEF("__toPrimitive", 2, js_object___toPrimitive ),
|
|
//JS_CFUNC_DEF("__toPropertyKey", 1, js_object___toPropertyKey ),
|
|
//JS_CFUNC_DEF("__speciesConstructor", 2, js_object___speciesConstructor ),
|
|
//JS_CFUNC_DEF("__isSameValueZero", 2, js_object___isSameValueZero ),
|
|
//JS_CFUNC_DEF("__getObjectData", 1, js_object___getObjectData ),
|
|
//JS_CFUNC_DEF("__setObjectData", 2, js_object___setObjectData ),
|
|
JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries ),
|
|
};
|
|
|
|
static const JSCFunctionListEntry js_object_proto_funcs[] = {
|
|
JS_CFUNC_DEF("toString", 0, js_object_toString ),
|
|
JS_CFUNC_DEF("toLocaleString", 0, js_object_toLocaleString ),
|
|
JS_CFUNC_DEF("valueOf", 0, js_object_valueOf ),
|
|
JS_CFUNC_DEF("hasOwnProperty", 1, js_object_hasOwnProperty ),
|
|
JS_CFUNC_DEF("isPrototypeOf", 1, js_object_isPrototypeOf ),
|
|
JS_CFUNC_DEF("propertyIsEnumerable", 1, js_object_propertyIsEnumerable ),
|
|
JS_CGETSET_DEF("__proto__", js_object_get___proto__, js_object_set___proto__ ),
|
|
JS_CFUNC_MAGIC_DEF("__defineGetter__", 2, js_object___defineGetter__, 0 ),
|
|
JS_CFUNC_MAGIC_DEF("__defineSetter__", 2, js_object___defineGetter__, 1 ),
|
|
JS_CFUNC_MAGIC_DEF("__lookupGetter__", 1, js_object___lookupGetter__, 0 ),
|
|
JS_CFUNC_MAGIC_DEF("__lookupSetter__", 1, js_object___lookupGetter__, 1 ),
|
|
};
|
|
|
|
void JS_AddIntrinsicObject(JSContext *ctx) {
|
|
JSValueConst obj;
|
|
obj = JS_NewGlobalCConstructor(ctx, "Object", js_object_constructor, 1,
|
|
ctx->class_proto[JS_CLASS_OBJECT]);
|
|
JS_SetPropertyFunctionList(ctx, obj, js_object_funcs, countof(js_object_funcs));
|
|
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_OBJECT],
|
|
js_object_proto_funcs, countof(js_object_proto_funcs));
|
|
}
|